detached 4c2047b

Merge pull request #41 from bnema/feat/loading-skeleton-splash

feat(ui): add themed LoadingSkeleton overlay
commit
4c2047bb5b15e6512f853ea187be8c3f1cdeb890
author
bnema · · 2025-12-27 13:47 UTC
committer
GitHub · · 2025-12-27 13:47 UTC
merge of
dd5a7db + 91fd2f6 · diff against the first parent
signature
GPG UnverifiedB5690EEEBB952194 The key is unknown
13 files · +1991 -26
M .mockery.yaml +1 -0
@@ -51,5 +51,6 @@ packages:
5151 PaneViewFactory: {}
5252 PanedWidget: {}
5353 ProgressBarWidget: {}
54+ SpinnerWidget: {}
5455 Widget: {}
5556 WidgetFactory: {}
@@ -51,5 +51,6 @@ packages:
51 PaneViewFactory: {}51 PaneViewFactory: {}
52 PanedWidget: {}52 PanedWidget: {}
53 ProgressBarWidget: {}53 ProgressBarWidget: {}
54+ SpinnerWidget: {}
54 Widget: {}55 Widget: {}
55 WidgetFactory: {}56 WidgetFactory: {}
M internal/ui/app.go +9 -0
@@ -827,6 +827,15 @@ func (a *App) initCoordinators(ctx context.Context) {
827827 a.MarkDirty()
828828 })
829829
830+ // Hide loading skeleton once the WebView paints
831+ a.contentCoord.SetOnWebViewShown(func(paneID entity.PaneID) {
832+ if wsView := a.activeWorkspaceView(); wsView != nil {
833+ if pv := wsView.GetPaneView(paneID); pv != nil {
834+ pv.HideLoadingSkeleton()
835+ }
836+ }
837+ })
838+
830839 // 5. Keyboard Dispatcher
831840 a.kbDispatcher = dispatcher.NewKeyboardDispatcher(
832841 ctx,
@@ -827,6 +827,15 @@ func (a *App) initCoordinators(ctx context.Context) {
827 a.MarkDirty()827 a.MarkDirty()
828 })828 })
829 829
830+ // Hide loading skeleton once the WebView paints
831+ a.contentCoord.SetOnWebViewShown(func(paneID entity.PaneID) {
832+ if wsView := a.activeWorkspaceView(); wsView != nil {
833+ if pv := wsView.GetPaneView(paneID); pv != nil {
834+ pv.HideLoadingSkeleton()
835+ }
836+ }
837+ })
838+
830 // 5. Keyboard Dispatcher839 // 5. Keyboard Dispatcher
831 a.kbDispatcher = dispatcher.NewKeyboardDispatcher(840 a.kbDispatcher = dispatcher.NewKeyboardDispatcher(
832 ctx,841 ctx,
A internal/ui/component/loading_skeleton.go +98 -0
@@ -0,0 +1,98 @@
1+package component
2+
3+import (
4+ "strings"
5+
6+ "github.com/bnema/dumber/internal/ui/layout"
7+ "github.com/jwijenbergh/puregotk/v4/gtk"
8+)
9+
10+// LoadingSkeleton displays a themed loading placeholder.
11+// It is intended to be embedded as an overlay while primary content is loading.
12+type LoadingSkeleton struct {
13+ container layout.BoxWidget
14+ content layout.BoxWidget
15+ spinner layout.SpinnerWidget
16+ label layout.LabelWidget
17+}
18+
19+const loadingSkeletonSpacing = 6
20+
21+func NewLoadingSkeleton(factory layout.WidgetFactory) *LoadingSkeleton {
22+ container := factory.NewBox(layout.OrientationVertical, 0)
23+ container.SetHexpand(true)
24+ container.SetVexpand(true)
25+ container.SetHalign(gtk.AlignFillValue)
26+ container.SetValign(gtk.AlignFillValue)
27+ container.SetCanFocus(false)
28+ container.SetCanTarget(false)
29+ container.AddCssClass("loading-skeleton")
30+
31+ content := factory.NewBox(layout.OrientationVertical, loadingSkeletonSpacing)
32+ content.SetHalign(gtk.AlignCenterValue)
33+ content.SetValign(gtk.AlignCenterValue)
34+ content.SetCanFocus(false)
35+ content.SetCanTarget(false)
36+ content.AddCssClass("loading-skeleton-content")
37+
38+ spinner := factory.NewSpinner()
39+ spinner.SetHalign(gtk.AlignCenterValue)
40+ spinner.SetValign(gtk.AlignCenterValue)
41+ spinner.SetCanFocus(false)
42+ spinner.SetCanTarget(false)
43+ spinner.SetSizeRequest(32, 32)
44+ spinner.AddCssClass("loading-skeleton-spinner")
45+
46+ text := "Loading..."
47+ label := factory.NewLabel(text)
48+ label.SetHalign(gtk.AlignCenterValue)
49+ label.SetValign(gtk.AlignCenterValue)
50+ label.SetCanFocus(false)
51+ label.SetCanTarget(false)
52+ label.AddCssClass("loading-skeleton-text")
53+
54+ content.Append(spinner)
55+ content.Append(label)
56+ container.Append(content)
57+
58+ ls := &LoadingSkeleton{
59+ container: container,
60+ content: content,
61+ spinner: spinner,
62+ label: label,
63+ }
64+ ls.SetVisible(true)
65+ return ls
66+}
67+
68+func (ls *LoadingSkeleton) Widget() layout.Widget {
69+ if ls == nil {
70+ return nil
71+ }
72+ return ls.container
73+}
74+
75+func (ls *LoadingSkeleton) SetText(text string) {
76+ if ls == nil || ls.label == nil {
77+ return
78+ }
79+ trimmed := strings.TrimSpace(text)
80+ if trimmed == "" {
81+ trimmed = "Loading..."
82+ }
83+ ls.label.SetText(trimmed)
84+}
85+
86+func (ls *LoadingSkeleton) SetVisible(visible bool) {
87+ if ls == nil || ls.container == nil {
88+ return
89+ }
90+ ls.container.SetVisible(visible)
91+ if ls.spinner != nil {
92+ if visible {
93+ ls.spinner.Start()
94+ } else {
95+ ls.spinner.Stop()
96+ }
97+ }
98+}
@@ -0,0 +1,98 @@
1+package component
2+
3+import (
4+ "strings"
5+
6+ "github.com/bnema/dumber/internal/ui/layout"
7+ "github.com/jwijenbergh/puregotk/v4/gtk"
8+)
9+
10+// LoadingSkeleton displays a themed loading placeholder.
11+// It is intended to be embedded as an overlay while primary content is loading.
12+type LoadingSkeleton struct {
13+ container layout.BoxWidget
14+ content layout.BoxWidget
15+ spinner layout.SpinnerWidget
16+ label layout.LabelWidget
17+}
18+
19+const loadingSkeletonSpacing = 6
20+
21+func NewLoadingSkeleton(factory layout.WidgetFactory) *LoadingSkeleton {
22+ container := factory.NewBox(layout.OrientationVertical, 0)
23+ container.SetHexpand(true)
24+ container.SetVexpand(true)
25+ container.SetHalign(gtk.AlignFillValue)
26+ container.SetValign(gtk.AlignFillValue)
27+ container.SetCanFocus(false)
28+ container.SetCanTarget(false)
29+ container.AddCssClass("loading-skeleton")
30+
31+ content := factory.NewBox(layout.OrientationVertical, loadingSkeletonSpacing)
32+ content.SetHalign(gtk.AlignCenterValue)
33+ content.SetValign(gtk.AlignCenterValue)
34+ content.SetCanFocus(false)
35+ content.SetCanTarget(false)
36+ content.AddCssClass("loading-skeleton-content")
37+
38+ spinner := factory.NewSpinner()
39+ spinner.SetHalign(gtk.AlignCenterValue)
40+ spinner.SetValign(gtk.AlignCenterValue)
41+ spinner.SetCanFocus(false)
42+ spinner.SetCanTarget(false)
43+ spinner.SetSizeRequest(32, 32)
44+ spinner.AddCssClass("loading-skeleton-spinner")
45+
46+ text := "Loading..."
47+ label := factory.NewLabel(text)
48+ label.SetHalign(gtk.AlignCenterValue)
49+ label.SetValign(gtk.AlignCenterValue)
50+ label.SetCanFocus(false)
51+ label.SetCanTarget(false)
52+ label.AddCssClass("loading-skeleton-text")
53+
54+ content.Append(spinner)
55+ content.Append(label)
56+ container.Append(content)
57+
58+ ls := &LoadingSkeleton{
59+ container: container,
60+ content: content,
61+ spinner: spinner,
62+ label: label,
63+ }
64+ ls.SetVisible(true)
65+ return ls
66+}
67+
68+func (ls *LoadingSkeleton) Widget() layout.Widget {
69+ if ls == nil {
70+ return nil
71+ }
72+ return ls.container
73+}
74+
75+func (ls *LoadingSkeleton) SetText(text string) {
76+ if ls == nil || ls.label == nil {
77+ return
78+ }
79+ trimmed := strings.TrimSpace(text)
80+ if trimmed == "" {
81+ trimmed = "Loading..."
82+ }
83+ ls.label.SetText(trimmed)
84+}
85+
86+func (ls *LoadingSkeleton) SetVisible(visible bool) {
87+ if ls == nil || ls.container == nil {
88+ return
89+ }
90+ ls.container.SetVisible(visible)
91+ if ls.spinner != nil {
92+ if visible {
93+ ls.spinner.Start()
94+ } else {
95+ ls.spinner.Stop()
96+ }
97+ }
98+}
A internal/ui/component/loading_skeleton_test.go +170 -0
@@ -0,0 +1,170 @@
1+package component_test
2+
3+import (
4+ "testing"
5+
6+ "github.com/stretchr/testify/mock"
7+ "github.com/stretchr/testify/require"
8+
9+ "github.com/bnema/dumber/internal/ui/component"
10+ "github.com/bnema/dumber/internal/ui/layout"
11+ "github.com/bnema/dumber/internal/ui/layout/mocks"
12+)
13+
14+func TestNewLoadingSkeleton_ShowsAndStartsSpinner(t *testing.T) {
15+ mockFactory := mocks.NewMockWidgetFactory(t)
16+ mockContainer := mocks.NewMockBoxWidget(t)
17+ mockContent := mocks.NewMockBoxWidget(t)
18+ mockSpinner := mocks.NewMockSpinnerWidget(t)
19+ mockLabel := mocks.NewMockLabelWidget(t)
20+
21+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockContainer).Once()
22+ mockContainer.EXPECT().SetHexpand(true).Once()
23+ mockContainer.EXPECT().SetVexpand(true).Once()
24+ mockContainer.EXPECT().SetHalign(mock.Anything).Once()
25+ mockContainer.EXPECT().SetValign(mock.Anything).Once()
26+ mockContainer.EXPECT().SetCanFocus(false).Once()
27+ mockContainer.EXPECT().SetCanTarget(false).Once()
28+ mockContainer.EXPECT().AddCssClass("loading-skeleton").Once()
29+
30+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 6).Return(mockContent).Once()
31+ mockContent.EXPECT().SetHalign(mock.Anything).Once()
32+ mockContent.EXPECT().SetValign(mock.Anything).Once()
33+ mockContent.EXPECT().SetCanFocus(false).Once()
34+ mockContent.EXPECT().SetCanTarget(false).Once()
35+ mockContent.EXPECT().AddCssClass("loading-skeleton-content").Once()
36+
37+ mockFactory.EXPECT().NewSpinner().Return(mockSpinner).Once()
38+ mockSpinner.EXPECT().SetHalign(mock.Anything).Once()
39+ mockSpinner.EXPECT().SetValign(mock.Anything).Once()
40+ mockSpinner.EXPECT().SetCanFocus(false).Once()
41+ mockSpinner.EXPECT().SetCanTarget(false).Once()
42+ mockSpinner.EXPECT().SetSizeRequest(32, 32).Once()
43+ mockSpinner.EXPECT().AddCssClass("loading-skeleton-spinner").Once()
44+
45+ mockFactory.EXPECT().NewLabel("Loading...").Return(mockLabel).Once()
46+ mockLabel.EXPECT().SetHalign(mock.Anything).Once()
47+ mockLabel.EXPECT().SetValign(mock.Anything).Once()
48+ mockLabel.EXPECT().SetCanFocus(false).Once()
49+ mockLabel.EXPECT().SetCanTarget(false).Once()
50+ mockLabel.EXPECT().AddCssClass("loading-skeleton-text").Once()
51+
52+ mockContent.EXPECT().Append(mockSpinner).Once()
53+ mockContent.EXPECT().Append(mockLabel).Once()
54+ mockContainer.EXPECT().Append(mockContent).Once()
55+
56+ // NewLoadingSkeleton ends by calling SetVisible(true).
57+ mockContainer.EXPECT().SetVisible(true).Once()
58+ mockSpinner.EXPECT().Start().Once()
59+
60+ ls := component.NewLoadingSkeleton(mockFactory)
61+ require.NotNil(t, ls)
62+}
63+
64+func TestLoadingSkeleton_SetText_TrimsAndDefaults(t *testing.T) {
65+ mockFactory := mocks.NewMockWidgetFactory(t)
66+ mockContainer := mocks.NewMockBoxWidget(t)
67+ mockContent := mocks.NewMockBoxWidget(t)
68+ mockSpinner := mocks.NewMockSpinnerWidget(t)
69+ mockLabel := mocks.NewMockLabelWidget(t)
70+
71+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockContainer).Once()
72+ mockContainer.EXPECT().SetHexpand(true).Once()
73+ mockContainer.EXPECT().SetVexpand(true).Once()
74+ mockContainer.EXPECT().SetHalign(mock.Anything).Once()
75+ mockContainer.EXPECT().SetValign(mock.Anything).Once()
76+ mockContainer.EXPECT().SetCanFocus(false).Once()
77+ mockContainer.EXPECT().SetCanTarget(false).Once()
78+ mockContainer.EXPECT().AddCssClass("loading-skeleton").Once()
79+
80+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 6).Return(mockContent).Once()
81+ mockContent.EXPECT().SetHalign(mock.Anything).Once()
82+ mockContent.EXPECT().SetValign(mock.Anything).Once()
83+ mockContent.EXPECT().SetCanFocus(false).Once()
84+ mockContent.EXPECT().SetCanTarget(false).Once()
85+ mockContent.EXPECT().AddCssClass("loading-skeleton-content").Once()
86+
87+ mockFactory.EXPECT().NewSpinner().Return(mockSpinner).Once()
88+ mockSpinner.EXPECT().SetHalign(mock.Anything).Once()
89+ mockSpinner.EXPECT().SetValign(mock.Anything).Once()
90+ mockSpinner.EXPECT().SetCanFocus(false).Once()
91+ mockSpinner.EXPECT().SetCanTarget(false).Once()
92+ mockSpinner.EXPECT().SetSizeRequest(32, 32).Once()
93+ mockSpinner.EXPECT().AddCssClass("loading-skeleton-spinner").Once()
94+
95+ mockFactory.EXPECT().NewLabel("Loading...").Return(mockLabel).Once()
96+ mockLabel.EXPECT().SetHalign(mock.Anything).Once()
97+ mockLabel.EXPECT().SetValign(mock.Anything).Once()
98+ mockLabel.EXPECT().SetCanFocus(false).Once()
99+ mockLabel.EXPECT().SetCanTarget(false).Once()
100+ mockLabel.EXPECT().AddCssClass("loading-skeleton-text").Once()
101+
102+ mockContent.EXPECT().Append(mockSpinner).Once()
103+ mockContent.EXPECT().Append(mockLabel).Once()
104+ mockContainer.EXPECT().Append(mockContent).Once()
105+
106+ mockContainer.EXPECT().SetVisible(true).Once()
107+ mockSpinner.EXPECT().Start().Once()
108+
109+ ls := component.NewLoadingSkeleton(mockFactory)
110+ require.NotNil(t, ls)
111+
112+ mockLabel.EXPECT().SetText("Hello").Once()
113+ ls.SetText(" Hello\n")
114+
115+ mockLabel.EXPECT().SetText("Loading...").Once()
116+ ls.SetText(" \t ")
117+}
118+
119+func TestLoadingSkeleton_SetVisible_StopsSpinnerWhenHidden(t *testing.T) {
120+ mockFactory := mocks.NewMockWidgetFactory(t)
121+ mockContainer := mocks.NewMockBoxWidget(t)
122+ mockContent := mocks.NewMockBoxWidget(t)
123+ mockSpinner := mocks.NewMockSpinnerWidget(t)
124+ mockLabel := mocks.NewMockLabelWidget(t)
125+
126+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockContainer).Once()
127+ mockContainer.EXPECT().SetHexpand(true).Once()
128+ mockContainer.EXPECT().SetVexpand(true).Once()
129+ mockContainer.EXPECT().SetHalign(mock.Anything).Once()
130+ mockContainer.EXPECT().SetValign(mock.Anything).Once()
131+ mockContainer.EXPECT().SetCanFocus(false).Once()
132+ mockContainer.EXPECT().SetCanTarget(false).Once()
133+ mockContainer.EXPECT().AddCssClass("loading-skeleton").Once()
134+
135+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 6).Return(mockContent).Once()
136+ mockContent.EXPECT().SetHalign(mock.Anything).Once()
137+ mockContent.EXPECT().SetValign(mock.Anything).Once()
138+ mockContent.EXPECT().SetCanFocus(false).Once()
139+ mockContent.EXPECT().SetCanTarget(false).Once()
140+ mockContent.EXPECT().AddCssClass("loading-skeleton-content").Once()
141+
142+ mockFactory.EXPECT().NewSpinner().Return(mockSpinner).Once()
143+ mockSpinner.EXPECT().SetHalign(mock.Anything).Once()
144+ mockSpinner.EXPECT().SetValign(mock.Anything).Once()
145+ mockSpinner.EXPECT().SetCanFocus(false).Once()
146+ mockSpinner.EXPECT().SetCanTarget(false).Once()
147+ mockSpinner.EXPECT().SetSizeRequest(32, 32).Once()
148+ mockSpinner.EXPECT().AddCssClass("loading-skeleton-spinner").Once()
149+
150+ mockFactory.EXPECT().NewLabel("Loading...").Return(mockLabel).Once()
151+ mockLabel.EXPECT().SetHalign(mock.Anything).Once()
152+ mockLabel.EXPECT().SetValign(mock.Anything).Once()
153+ mockLabel.EXPECT().SetCanFocus(false).Once()
154+ mockLabel.EXPECT().SetCanTarget(false).Once()
155+ mockLabel.EXPECT().AddCssClass("loading-skeleton-text").Once()
156+
157+ mockContent.EXPECT().Append(mockSpinner).Once()
158+ mockContent.EXPECT().Append(mockLabel).Once()
159+ mockContainer.EXPECT().Append(mockContent).Once()
160+
161+ mockContainer.EXPECT().SetVisible(true).Once()
162+ mockSpinner.EXPECT().Start().Once()
163+
164+ ls := component.NewLoadingSkeleton(mockFactory)
165+ require.NotNil(t, ls)
166+
167+ mockContainer.EXPECT().SetVisible(false).Once()
168+ mockSpinner.EXPECT().Stop().Once()
169+ ls.SetVisible(false)
170+}
@@ -0,0 +1,170 @@
1+package component_test
2+
3+import (
4+ "testing"
5+
6+ "github.com/stretchr/testify/mock"
7+ "github.com/stretchr/testify/require"
8+
9+ "github.com/bnema/dumber/internal/ui/component"
10+ "github.com/bnema/dumber/internal/ui/layout"
11+ "github.com/bnema/dumber/internal/ui/layout/mocks"
12+)
13+
14+func TestNewLoadingSkeleton_ShowsAndStartsSpinner(t *testing.T) {
15+ mockFactory := mocks.NewMockWidgetFactory(t)
16+ mockContainer := mocks.NewMockBoxWidget(t)
17+ mockContent := mocks.NewMockBoxWidget(t)
18+ mockSpinner := mocks.NewMockSpinnerWidget(t)
19+ mockLabel := mocks.NewMockLabelWidget(t)
20+
21+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockContainer).Once()
22+ mockContainer.EXPECT().SetHexpand(true).Once()
23+ mockContainer.EXPECT().SetVexpand(true).Once()
24+ mockContainer.EXPECT().SetHalign(mock.Anything).Once()
25+ mockContainer.EXPECT().SetValign(mock.Anything).Once()
26+ mockContainer.EXPECT().SetCanFocus(false).Once()
27+ mockContainer.EXPECT().SetCanTarget(false).Once()
28+ mockContainer.EXPECT().AddCssClass("loading-skeleton").Once()
29+
30+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 6).Return(mockContent).Once()
31+ mockContent.EXPECT().SetHalign(mock.Anything).Once()
32+ mockContent.EXPECT().SetValign(mock.Anything).Once()
33+ mockContent.EXPECT().SetCanFocus(false).Once()
34+ mockContent.EXPECT().SetCanTarget(false).Once()
35+ mockContent.EXPECT().AddCssClass("loading-skeleton-content").Once()
36+
37+ mockFactory.EXPECT().NewSpinner().Return(mockSpinner).Once()
38+ mockSpinner.EXPECT().SetHalign(mock.Anything).Once()
39+ mockSpinner.EXPECT().SetValign(mock.Anything).Once()
40+ mockSpinner.EXPECT().SetCanFocus(false).Once()
41+ mockSpinner.EXPECT().SetCanTarget(false).Once()
42+ mockSpinner.EXPECT().SetSizeRequest(32, 32).Once()
43+ mockSpinner.EXPECT().AddCssClass("loading-skeleton-spinner").Once()
44+
45+ mockFactory.EXPECT().NewLabel("Loading...").Return(mockLabel).Once()
46+ mockLabel.EXPECT().SetHalign(mock.Anything).Once()
47+ mockLabel.EXPECT().SetValign(mock.Anything).Once()
48+ mockLabel.EXPECT().SetCanFocus(false).Once()
49+ mockLabel.EXPECT().SetCanTarget(false).Once()
50+ mockLabel.EXPECT().AddCssClass("loading-skeleton-text").Once()
51+
52+ mockContent.EXPECT().Append(mockSpinner).Once()
53+ mockContent.EXPECT().Append(mockLabel).Once()
54+ mockContainer.EXPECT().Append(mockContent).Once()
55+
56+ // NewLoadingSkeleton ends by calling SetVisible(true).
57+ mockContainer.EXPECT().SetVisible(true).Once()
58+ mockSpinner.EXPECT().Start().Once()
59+
60+ ls := component.NewLoadingSkeleton(mockFactory)
61+ require.NotNil(t, ls)
62+}
63+
64+func TestLoadingSkeleton_SetText_TrimsAndDefaults(t *testing.T) {
65+ mockFactory := mocks.NewMockWidgetFactory(t)
66+ mockContainer := mocks.NewMockBoxWidget(t)
67+ mockContent := mocks.NewMockBoxWidget(t)
68+ mockSpinner := mocks.NewMockSpinnerWidget(t)
69+ mockLabel := mocks.NewMockLabelWidget(t)
70+
71+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockContainer).Once()
72+ mockContainer.EXPECT().SetHexpand(true).Once()
73+ mockContainer.EXPECT().SetVexpand(true).Once()
74+ mockContainer.EXPECT().SetHalign(mock.Anything).Once()
75+ mockContainer.EXPECT().SetValign(mock.Anything).Once()
76+ mockContainer.EXPECT().SetCanFocus(false).Once()
77+ mockContainer.EXPECT().SetCanTarget(false).Once()
78+ mockContainer.EXPECT().AddCssClass("loading-skeleton").Once()
79+
80+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 6).Return(mockContent).Once()
81+ mockContent.EXPECT().SetHalign(mock.Anything).Once()
82+ mockContent.EXPECT().SetValign(mock.Anything).Once()
83+ mockContent.EXPECT().SetCanFocus(false).Once()
84+ mockContent.EXPECT().SetCanTarget(false).Once()
85+ mockContent.EXPECT().AddCssClass("loading-skeleton-content").Once()
86+
87+ mockFactory.EXPECT().NewSpinner().Return(mockSpinner).Once()
88+ mockSpinner.EXPECT().SetHalign(mock.Anything).Once()
89+ mockSpinner.EXPECT().SetValign(mock.Anything).Once()
90+ mockSpinner.EXPECT().SetCanFocus(false).Once()
91+ mockSpinner.EXPECT().SetCanTarget(false).Once()
92+ mockSpinner.EXPECT().SetSizeRequest(32, 32).Once()
93+ mockSpinner.EXPECT().AddCssClass("loading-skeleton-spinner").Once()
94+
95+ mockFactory.EXPECT().NewLabel("Loading...").Return(mockLabel).Once()
96+ mockLabel.EXPECT().SetHalign(mock.Anything).Once()
97+ mockLabel.EXPECT().SetValign(mock.Anything).Once()
98+ mockLabel.EXPECT().SetCanFocus(false).Once()
99+ mockLabel.EXPECT().SetCanTarget(false).Once()
100+ mockLabel.EXPECT().AddCssClass("loading-skeleton-text").Once()
101+
102+ mockContent.EXPECT().Append(mockSpinner).Once()
103+ mockContent.EXPECT().Append(mockLabel).Once()
104+ mockContainer.EXPECT().Append(mockContent).Once()
105+
106+ mockContainer.EXPECT().SetVisible(true).Once()
107+ mockSpinner.EXPECT().Start().Once()
108+
109+ ls := component.NewLoadingSkeleton(mockFactory)
110+ require.NotNil(t, ls)
111+
112+ mockLabel.EXPECT().SetText("Hello").Once()
113+ ls.SetText(" Hello\n")
114+
115+ mockLabel.EXPECT().SetText("Loading...").Once()
116+ ls.SetText(" \t ")
117+}
118+
119+func TestLoadingSkeleton_SetVisible_StopsSpinnerWhenHidden(t *testing.T) {
120+ mockFactory := mocks.NewMockWidgetFactory(t)
121+ mockContainer := mocks.NewMockBoxWidget(t)
122+ mockContent := mocks.NewMockBoxWidget(t)
123+ mockSpinner := mocks.NewMockSpinnerWidget(t)
124+ mockLabel := mocks.NewMockLabelWidget(t)
125+
126+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockContainer).Once()
127+ mockContainer.EXPECT().SetHexpand(true).Once()
128+ mockContainer.EXPECT().SetVexpand(true).Once()
129+ mockContainer.EXPECT().SetHalign(mock.Anything).Once()
130+ mockContainer.EXPECT().SetValign(mock.Anything).Once()
131+ mockContainer.EXPECT().SetCanFocus(false).Once()
132+ mockContainer.EXPECT().SetCanTarget(false).Once()
133+ mockContainer.EXPECT().AddCssClass("loading-skeleton").Once()
134+
135+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 6).Return(mockContent).Once()
136+ mockContent.EXPECT().SetHalign(mock.Anything).Once()
137+ mockContent.EXPECT().SetValign(mock.Anything).Once()
138+ mockContent.EXPECT().SetCanFocus(false).Once()
139+ mockContent.EXPECT().SetCanTarget(false).Once()
140+ mockContent.EXPECT().AddCssClass("loading-skeleton-content").Once()
141+
142+ mockFactory.EXPECT().NewSpinner().Return(mockSpinner).Once()
143+ mockSpinner.EXPECT().SetHalign(mock.Anything).Once()
144+ mockSpinner.EXPECT().SetValign(mock.Anything).Once()
145+ mockSpinner.EXPECT().SetCanFocus(false).Once()
146+ mockSpinner.EXPECT().SetCanTarget(false).Once()
147+ mockSpinner.EXPECT().SetSizeRequest(32, 32).Once()
148+ mockSpinner.EXPECT().AddCssClass("loading-skeleton-spinner").Once()
149+
150+ mockFactory.EXPECT().NewLabel("Loading...").Return(mockLabel).Once()
151+ mockLabel.EXPECT().SetHalign(mock.Anything).Once()
152+ mockLabel.EXPECT().SetValign(mock.Anything).Once()
153+ mockLabel.EXPECT().SetCanFocus(false).Once()
154+ mockLabel.EXPECT().SetCanTarget(false).Once()
155+ mockLabel.EXPECT().AddCssClass("loading-skeleton-text").Once()
156+
157+ mockContent.EXPECT().Append(mockSpinner).Once()
158+ mockContent.EXPECT().Append(mockLabel).Once()
159+ mockContainer.EXPECT().Append(mockContent).Once()
160+
161+ mockContainer.EXPECT().SetVisible(true).Once()
162+ mockSpinner.EXPECT().Start().Once()
163+
164+ ls := component.NewLoadingSkeleton(mockFactory)
165+ require.NotNil(t, ls)
166+
167+ mockContainer.EXPECT().SetVisible(false).Once()
168+ mockSpinner.EXPECT().Stop().Once()
169+ ls.SetVisible(false)
170+}
M internal/ui/component/pane_view.go +22 -0
@@ -25,6 +25,7 @@ type PaneView struct {
2525 progressBar *ProgressBar // Loading progress indicator
2626 toaster *Toaster // Toast notification overlay
2727 linkStatus *LinkStatusOverlay // Link hover URL overlay
28+ loading *LoadingSkeleton // Placeholder shown until WebView paints
2829 paneID entity.PaneID
2930 isActive bool
3031
@@ -51,6 +52,15 @@ func NewPaneView(factory layout.WidgetFactory, paneID entity.PaneID, webViewWidg
5152 overlay.SetChild(webViewWidget)
5253 }
5354
55+ // Loading skeleton overlay (shown until WebView paints)
56+ loading := NewLoadingSkeleton(factory)
57+ loading.Widget().SetCanFocus(false)
58+ loading.Widget().SetCanTarget(false)
59+ overlay.AddOverlay(loading.Widget())
60+ // Don't let loading affect layout
61+ overlay.SetClipOverlay(loading.Widget(), false)
62+ overlay.SetMeasureOverlay(loading.Widget(), false)
63+
5464 // Create border overlay box (used for active pane indication)
5565 // This is an empty box that gets styled via CSS to show a border
5666 borderBox := factory.NewBox(layout.OrientationVertical, 0)
@@ -75,6 +85,7 @@ func NewPaneView(factory layout.WidgetFactory, paneID entity.PaneID, webViewWidg
7585 webViewWidget: webViewWidget,
7686 borderBox: borderBox,
7787 progressBar: nil, // Created lazily in ensureProgressBar()
88+ loading: loading,
7889 paneID: paneID,
7990 isActive: false,
8091 }
@@ -316,6 +327,17 @@ func (pv *PaneView) SetLoading(loading bool) {
316327 }
317328 }
318329
330+// HideLoadingSkeleton hides the loading skeleton overlay (if present).
331+func (pv *PaneView) HideLoadingSkeleton() {
332+ pv.mu.Lock()
333+ loading := pv.loading
334+ pv.mu.Unlock()
335+
336+ if loading != nil {
337+ loading.SetVisible(false)
338+ }
339+}
340+
319341 // ensureToaster creates the toaster lazily on first use.
320342 // Must be called with write lock held.
321343 func (pv *PaneView) ensureToaster() *Toaster {
@@ -25,6 +25,7 @@ type PaneView struct {
25 progressBar *ProgressBar // Loading progress indicator25 progressBar *ProgressBar // Loading progress indicator
26 toaster *Toaster // Toast notification overlay26 toaster *Toaster // Toast notification overlay
27 linkStatus *LinkStatusOverlay // Link hover URL overlay27 linkStatus *LinkStatusOverlay // Link hover URL overlay
28+ loading *LoadingSkeleton // Placeholder shown until WebView paints
28 paneID entity.PaneID29 paneID entity.PaneID
29 isActive bool30 isActive bool
30 31
@@ -51,6 +52,15 @@ func NewPaneView(factory layout.WidgetFactory, paneID entity.PaneID, webViewWidg
51 overlay.SetChild(webViewWidget)52 overlay.SetChild(webViewWidget)
52 }53 }
53 54
55+ // Loading skeleton overlay (shown until WebView paints)
56+ loading := NewLoadingSkeleton(factory)
57+ loading.Widget().SetCanFocus(false)
58+ loading.Widget().SetCanTarget(false)
59+ overlay.AddOverlay(loading.Widget())
60+ // Don't let loading affect layout
61+ overlay.SetClipOverlay(loading.Widget(), false)
62+ overlay.SetMeasureOverlay(loading.Widget(), false)
63+
54 // Create border overlay box (used for active pane indication)64 // Create border overlay box (used for active pane indication)
55 // This is an empty box that gets styled via CSS to show a border65 // This is an empty box that gets styled via CSS to show a border
56 borderBox := factory.NewBox(layout.OrientationVertical, 0)66 borderBox := factory.NewBox(layout.OrientationVertical, 0)
@@ -75,6 +85,7 @@ func NewPaneView(factory layout.WidgetFactory, paneID entity.PaneID, webViewWidg
75 webViewWidget: webViewWidget,85 webViewWidget: webViewWidget,
76 borderBox: borderBox,86 borderBox: borderBox,
77 progressBar: nil, // Created lazily in ensureProgressBar()87 progressBar: nil, // Created lazily in ensureProgressBar()
88+ loading: loading,
78 paneID: paneID,89 paneID: paneID,
79 isActive: false,90 isActive: false,
80 }91 }
@@ -316,6 +327,17 @@ func (pv *PaneView) SetLoading(loading bool) {
316 }327 }
317 }328 }
318 329
330+// HideLoadingSkeleton hides the loading skeleton overlay (if present).
331+func (pv *PaneView) HideLoadingSkeleton() {
332+ pv.mu.Lock()
333+ loading := pv.loading
334+ pv.mu.Unlock()
335+
336+ if loading != nil {
337+ loading.SetVisible(false)
338+ }
339+}
340+
319 // ensureToaster creates the toaster lazily on first use.341 // ensureToaster creates the toaster lazily on first use.
320 // Must be called with write lock held.342 // Must be called with write lock held.
321 func (pv *PaneView) ensureToaster() *Toaster {343 func (pv *PaneView) ensureToaster() *Toaster {
A internal/ui/component/pane_view_internal_test.go +68 -0
@@ -0,0 +1,68 @@
1+package component
2+
3+import (
4+ "testing"
5+
6+ "github.com/stretchr/testify/mock"
7+
8+ "github.com/bnema/dumber/internal/ui/layout"
9+ "github.com/bnema/dumber/internal/ui/layout/mocks"
10+)
11+
12+func TestPaneView_HideLoadingSkeleton_HidesWhenPresent(t *testing.T) {
13+ mockFactory := mocks.NewMockWidgetFactory(t)
14+ mockContainer := mocks.NewMockBoxWidget(t)
15+ mockContent := mocks.NewMockBoxWidget(t)
16+ mockSpinner := mocks.NewMockSpinnerWidget(t)
17+ mockLabel := mocks.NewMockLabelWidget(t)
18+
19+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockContainer).Once()
20+ mockContainer.EXPECT().SetHexpand(true).Once()
21+ mockContainer.EXPECT().SetVexpand(true).Once()
22+ mockContainer.EXPECT().SetHalign(mock.Anything).Once()
23+ mockContainer.EXPECT().SetValign(mock.Anything).Once()
24+ mockContainer.EXPECT().SetCanFocus(false).Once()
25+ mockContainer.EXPECT().SetCanTarget(false).Once()
26+ mockContainer.EXPECT().AddCssClass("loading-skeleton").Once()
27+
28+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 6).Return(mockContent).Once()
29+ mockContent.EXPECT().SetHalign(mock.Anything).Once()
30+ mockContent.EXPECT().SetValign(mock.Anything).Once()
31+ mockContent.EXPECT().SetCanFocus(false).Once()
32+ mockContent.EXPECT().SetCanTarget(false).Once()
33+ mockContent.EXPECT().AddCssClass("loading-skeleton-content").Once()
34+
35+ mockFactory.EXPECT().NewSpinner().Return(mockSpinner).Once()
36+ mockSpinner.EXPECT().SetHalign(mock.Anything).Once()
37+ mockSpinner.EXPECT().SetValign(mock.Anything).Once()
38+ mockSpinner.EXPECT().SetCanFocus(false).Once()
39+ mockSpinner.EXPECT().SetCanTarget(false).Once()
40+ mockSpinner.EXPECT().SetSizeRequest(32, 32).Once()
41+ mockSpinner.EXPECT().AddCssClass("loading-skeleton-spinner").Once()
42+
43+ mockFactory.EXPECT().NewLabel("Loading...").Return(mockLabel).Once()
44+ mockLabel.EXPECT().SetHalign(mock.Anything).Once()
45+ mockLabel.EXPECT().SetValign(mock.Anything).Once()
46+ mockLabel.EXPECT().SetCanFocus(false).Once()
47+ mockLabel.EXPECT().SetCanTarget(false).Once()
48+ mockLabel.EXPECT().AddCssClass("loading-skeleton-text").Once()
49+
50+ mockContent.EXPECT().Append(mockSpinner).Once()
51+ mockContent.EXPECT().Append(mockLabel).Once()
52+ mockContainer.EXPECT().Append(mockContent).Once()
53+
54+ mockContainer.EXPECT().SetVisible(true).Once()
55+ mockSpinner.EXPECT().Start().Once()
56+ ls := NewLoadingSkeleton(mockFactory)
57+
58+ pv := &PaneView{loading: ls}
59+
60+ mockContainer.EXPECT().SetVisible(false).Once()
61+ mockSpinner.EXPECT().Stop().Once()
62+ pv.HideLoadingSkeleton()
63+}
64+
65+func TestPaneView_HideLoadingSkeleton_NoOpWhenNil(t *testing.T) {
66+ pv := &PaneView{}
67+ pv.HideLoadingSkeleton()
68+}
@@ -0,0 +1,68 @@
1+package component
2+
3+import (
4+ "testing"
5+
6+ "github.com/stretchr/testify/mock"
7+
8+ "github.com/bnema/dumber/internal/ui/layout"
9+ "github.com/bnema/dumber/internal/ui/layout/mocks"
10+)
11+
12+func TestPaneView_HideLoadingSkeleton_HidesWhenPresent(t *testing.T) {
13+ mockFactory := mocks.NewMockWidgetFactory(t)
14+ mockContainer := mocks.NewMockBoxWidget(t)
15+ mockContent := mocks.NewMockBoxWidget(t)
16+ mockSpinner := mocks.NewMockSpinnerWidget(t)
17+ mockLabel := mocks.NewMockLabelWidget(t)
18+
19+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockContainer).Once()
20+ mockContainer.EXPECT().SetHexpand(true).Once()
21+ mockContainer.EXPECT().SetVexpand(true).Once()
22+ mockContainer.EXPECT().SetHalign(mock.Anything).Once()
23+ mockContainer.EXPECT().SetValign(mock.Anything).Once()
24+ mockContainer.EXPECT().SetCanFocus(false).Once()
25+ mockContainer.EXPECT().SetCanTarget(false).Once()
26+ mockContainer.EXPECT().AddCssClass("loading-skeleton").Once()
27+
28+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 6).Return(mockContent).Once()
29+ mockContent.EXPECT().SetHalign(mock.Anything).Once()
30+ mockContent.EXPECT().SetValign(mock.Anything).Once()
31+ mockContent.EXPECT().SetCanFocus(false).Once()
32+ mockContent.EXPECT().SetCanTarget(false).Once()
33+ mockContent.EXPECT().AddCssClass("loading-skeleton-content").Once()
34+
35+ mockFactory.EXPECT().NewSpinner().Return(mockSpinner).Once()
36+ mockSpinner.EXPECT().SetHalign(mock.Anything).Once()
37+ mockSpinner.EXPECT().SetValign(mock.Anything).Once()
38+ mockSpinner.EXPECT().SetCanFocus(false).Once()
39+ mockSpinner.EXPECT().SetCanTarget(false).Once()
40+ mockSpinner.EXPECT().SetSizeRequest(32, 32).Once()
41+ mockSpinner.EXPECT().AddCssClass("loading-skeleton-spinner").Once()
42+
43+ mockFactory.EXPECT().NewLabel("Loading...").Return(mockLabel).Once()
44+ mockLabel.EXPECT().SetHalign(mock.Anything).Once()
45+ mockLabel.EXPECT().SetValign(mock.Anything).Once()
46+ mockLabel.EXPECT().SetCanFocus(false).Once()
47+ mockLabel.EXPECT().SetCanTarget(false).Once()
48+ mockLabel.EXPECT().AddCssClass("loading-skeleton-text").Once()
49+
50+ mockContent.EXPECT().Append(mockSpinner).Once()
51+ mockContent.EXPECT().Append(mockLabel).Once()
52+ mockContainer.EXPECT().Append(mockContent).Once()
53+
54+ mockContainer.EXPECT().SetVisible(true).Once()
55+ mockSpinner.EXPECT().Start().Once()
56+ ls := NewLoadingSkeleton(mockFactory)
57+
58+ pv := &PaneView{loading: ls}
59+
60+ mockContainer.EXPECT().SetVisible(false).Once()
61+ mockSpinner.EXPECT().Stop().Once()
62+ pv.HideLoadingSkeleton()
63+}
64+
65+func TestPaneView_HideLoadingSkeleton_NoOpWhenNil(t *testing.T) {
66+ pv := &PaneView{}
67+ pv.HideLoadingSkeleton()
68+}
M internal/ui/component/pane_view_test.go +103 -21
@@ -4,6 +4,7 @@ import (
44 "testing"
55
66 "github.com/stretchr/testify/assert"
7+ "github.com/stretchr/testify/mock"
78 "github.com/stretchr/testify/require"
89
910 "github.com/bnema/dumber/internal/domain/entity"
@@ -19,6 +20,11 @@ func TestNewPaneView_CreatesOverlay(t *testing.T) {
1920 mockBorderBox := mocks.NewMockBoxWidget(t)
2021 mockWebView := mocks.NewMockWidget(t)
2122
23+ mockLoadingContainer := mocks.NewMockBoxWidget(t)
24+ mockLoadingContent := mocks.NewMockBoxWidget(t)
25+ mockLoadingSpinner := mocks.NewMockSpinnerWidget(t)
26+ mockLoadingLabel := mocks.NewMockLabelWidget(t)
27+
2228 paneID := entity.PaneID("pane-1")
2329
2430 mockFactory.EXPECT().NewOverlay().Return(mockOverlay).Once()
@@ -28,6 +34,8 @@ func TestNewPaneView_CreatesOverlay(t *testing.T) {
2834 mockOverlay.EXPECT().AddCssClass("pane-overlay").Once() // Theme background
2935 mockOverlay.EXPECT().SetChild(mockWebView).Once()
3036
37+ setupLoadingSkeletonMocks(mockFactory, mockOverlay, mockLoadingContainer, mockLoadingContent, mockLoadingSpinner, mockLoadingLabel)
38+
3139 mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockBorderBox).Once()
3240 mockBorderBox.EXPECT().SetCanFocus(false).Once()
3341 mockBorderBox.EXPECT().SetCanTarget(false).Once()
@@ -53,6 +61,11 @@ func TestNewPaneView_NilWebView(t *testing.T) {
5361 mockOverlay := mocks.NewMockOverlayWidget(t)
5462 mockBorderBox := mocks.NewMockBoxWidget(t)
5563
64+ mockLoadingContainer := mocks.NewMockBoxWidget(t)
65+ mockLoadingContent := mocks.NewMockBoxWidget(t)
66+ mockLoadingSpinner := mocks.NewMockSpinnerWidget(t)
67+ mockLoadingLabel := mocks.NewMockLabelWidget(t)
68+
5669 paneID := entity.PaneID("pane-1")
5770
5871 mockFactory.EXPECT().NewOverlay().Return(mockOverlay).Once()
@@ -62,6 +75,8 @@ func TestNewPaneView_NilWebView(t *testing.T) {
6275 mockOverlay.EXPECT().AddCssClass("pane-overlay").Once() // Theme background
6376 // SetChild should NOT be called when webview is nil
6477
78+ setupLoadingSkeletonMocks(mockFactory, mockOverlay, mockLoadingContainer, mockLoadingContent, mockLoadingSpinner, mockLoadingLabel)
79+
6580 mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockBorderBox).Once()
6681 mockBorderBox.EXPECT().SetCanFocus(false).Once()
6782 mockBorderBox.EXPECT().SetCanTarget(false).Once()
@@ -87,7 +102,7 @@ func TestSetActive_True_AddsCSSClass(t *testing.T) {
87102 mockBorderBox := mocks.NewMockBoxWidget(t)
88103 mockWebView := mocks.NewMockWidget(t)
89104
90- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
105+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
91106
92107 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
93108
@@ -108,7 +123,7 @@ func TestSetActive_False_RemovesCSSClass(t *testing.T) {
108123 mockBorderBox := mocks.NewMockBoxWidget(t)
109124 mockWebView := mocks.NewMockWidget(t)
110125
111- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
126+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
112127
113128 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
114129
@@ -133,7 +148,7 @@ func TestSetActive_NoChangeWhenSameState(t *testing.T) {
133148 mockBorderBox := mocks.NewMockBoxWidget(t)
134149 mockWebView := mocks.NewMockWidget(t)
135150
136- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
151+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
137152
138153 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
139154
@@ -152,7 +167,7 @@ func TestPaneID_ReturnsPaneID(t *testing.T) {
152167 mockWebView := mocks.NewMockWidget(t)
153168
154169 paneID := entity.PaneID("test-pane-123")
155- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
170+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
156171
157172 pv := component.NewPaneView(mockFactory, paneID, mockWebView)
158173
@@ -170,7 +185,7 @@ func TestWebViewWidget_ReturnsWebView(t *testing.T) {
170185 mockBorderBox := mocks.NewMockBoxWidget(t)
171186 mockWebView := mocks.NewMockWidget(t)
172187
173- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
188+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
174189
175190 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
176191
@@ -189,7 +204,7 @@ func TestSetWebViewWidget_ReplacesWidget(t *testing.T) {
189204 mockOldWebView := mocks.NewMockWidget(t)
190205 mockNewWebView := mocks.NewMockWidget(t)
191206
192- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockOldWebView)
207+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockOldWebView)
193208
194209 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockOldWebView)
195210
@@ -213,7 +228,7 @@ func TestSetWebViewWidget_FromNil(t *testing.T) {
213228 mockBorderBox := mocks.NewMockBoxWidget(t)
214229 mockNewWebView := mocks.NewMockWidget(t)
215230
216- setupPaneViewMocksNoWebView(mockFactory, mockOverlay, mockBorderBox)
231+ setupPaneViewMocksNoWebView(t, mockFactory, mockOverlay, mockBorderBox)
217232
218233 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), nil)
219234
@@ -236,7 +251,7 @@ func TestGrabFocus_DelegatesToWebView(t *testing.T) {
236251 mockBorderBox := mocks.NewMockBoxWidget(t)
237252 mockWebView := mocks.NewMockWidget(t)
238253
239- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
254+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
240255
241256 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
242257
@@ -255,7 +270,7 @@ func TestGrabFocus_NilWebView_ReturnsFalse(t *testing.T) {
255270 mockOverlay := mocks.NewMockOverlayWidget(t)
256271 mockBorderBox := mocks.NewMockBoxWidget(t)
257272
258- setupPaneViewMocksNoWebView(mockFactory, mockOverlay, mockBorderBox)
273+ setupPaneViewMocksNoWebView(t, mockFactory, mockOverlay, mockBorderBox)
259274
260275 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), nil)
261276
@@ -273,7 +288,7 @@ func TestHasFocus_DelegatesToWebView(t *testing.T) {
273288 mockBorderBox := mocks.NewMockBoxWidget(t)
274289 mockWebView := mocks.NewMockWidget(t)
275290
276- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
291+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
277292
278293 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
279294
@@ -292,7 +307,7 @@ func TestHasFocus_NilWebView_ReturnsFalse(t *testing.T) {
292307 mockOverlay := mocks.NewMockOverlayWidget(t)
293308 mockBorderBox := mocks.NewMockBoxWidget(t)
294309
295- setupPaneViewMocksNoWebView(mockFactory, mockOverlay, mockBorderBox)
310+ setupPaneViewMocksNoWebView(t, mockFactory, mockOverlay, mockBorderBox)
296311
297312 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), nil)
298313
@@ -310,7 +325,7 @@ func TestWidget_ReturnsOverlay(t *testing.T) {
310325 mockBorderBox := mocks.NewMockBoxWidget(t)
311326 mockWebView := mocks.NewMockWidget(t)
312327
313- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
328+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
314329
315330 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
316331
@@ -328,7 +343,7 @@ func TestOverlay_ReturnsOverlayWidget(t *testing.T) {
328343 mockBorderBox := mocks.NewMockBoxWidget(t)
329344 mockWebView := mocks.NewMockWidget(t)
330345
331- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
346+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
332347
333348 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
334349
@@ -346,7 +361,7 @@ func TestShow_DelegatesToOverlay(t *testing.T) {
346361 mockBorderBox := mocks.NewMockBoxWidget(t)
347362 mockWebView := mocks.NewMockWidget(t)
348363
349- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
364+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
350365
351366 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
352367
@@ -365,7 +380,7 @@ func TestHide_DelegatesToOverlay(t *testing.T) {
365380 mockBorderBox := mocks.NewMockBoxWidget(t)
366381 mockWebView := mocks.NewMockWidget(t)
367382
368- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
383+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
369384
370385 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
371386
@@ -384,7 +399,7 @@ func TestSetVisible_DelegatesToOverlay(t *testing.T) {
384399 mockBorderBox := mocks.NewMockBoxWidget(t)
385400 mockWebView := mocks.NewMockWidget(t)
386401
387- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
402+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
388403
389404 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
390405
@@ -403,7 +418,7 @@ func TestIsVisible_DelegatesToOverlay(t *testing.T) {
403418 mockBorderBox := mocks.NewMockBoxWidget(t)
404419 mockWebView := mocks.NewMockWidget(t)
405420
406- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
421+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
407422
408423 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
409424
@@ -423,7 +438,7 @@ func TestAddCssClass_DelegatesToOverlay(t *testing.T) {
423438 mockBorderBox := mocks.NewMockBoxWidget(t)
424439 mockWebView := mocks.NewMockWidget(t)
425440
426- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
441+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
427442
428443 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
429444
@@ -442,7 +457,7 @@ func TestRemoveCssClass_DelegatesToOverlay(t *testing.T) {
442457 mockBorderBox := mocks.NewMockBoxWidget(t)
443458 mockWebView := mocks.NewMockWidget(t)
444459
445- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
460+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
446461
447462 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
448463
@@ -461,7 +476,7 @@ func TestSetOnFocusIn_SetsCallback(t *testing.T) {
461476 mockBorderBox := mocks.NewMockBoxWidget(t)
462477 mockWebView := mocks.NewMockWidget(t)
463478
464- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
479+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
465480
466481 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
467482
@@ -481,7 +496,7 @@ func TestSetOnFocusOut_SetsCallback(t *testing.T) {
481496 mockBorderBox := mocks.NewMockBoxWidget(t)
482497 mockWebView := mocks.NewMockWidget(t)
483498
484- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)
499+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
485500
486501 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
487502
@@ -494,13 +509,70 @@ func TestSetOnFocusOut_SetsCallback(t *testing.T) {
494509 assert.NotNil(t, pv)
495510 }
496511
512+// Helper function to setup common mock expectations for PaneView creation
513+func setupLoadingSkeletonMocks(
514+ mockFactory *mocks.MockWidgetFactory,
515+ mockOverlay *mocks.MockOverlayWidget,
516+ mockLoadingContainer *mocks.MockBoxWidget,
517+ mockLoadingContent *mocks.MockBoxWidget,
518+ mockLoadingSpinner *mocks.MockSpinnerWidget,
519+ mockLoadingLabel *mocks.MockLabelWidget,
520+) {
521+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockLoadingContainer).Once()
522+ mockLoadingContainer.EXPECT().SetHexpand(true).Maybe()
523+ mockLoadingContainer.EXPECT().SetVexpand(true).Maybe()
524+ mockLoadingContainer.EXPECT().SetHalign(mock.Anything).Maybe()
525+ mockLoadingContainer.EXPECT().SetValign(mock.Anything).Maybe()
526+ mockLoadingContainer.EXPECT().SetCanFocus(false).Maybe()
527+ mockLoadingContainer.EXPECT().SetCanTarget(false).Maybe()
528+ mockLoadingContainer.EXPECT().AddCssClass("loading-skeleton").Maybe()
529+ mockLoadingContainer.EXPECT().SetVisible(true).Maybe()
530+
531+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 6).Return(mockLoadingContent).Once()
532+ mockLoadingContent.EXPECT().SetHalign(mock.Anything).Maybe()
533+ mockLoadingContent.EXPECT().SetValign(mock.Anything).Maybe()
534+ mockLoadingContent.EXPECT().SetCanFocus(false).Maybe()
535+ mockLoadingContent.EXPECT().SetCanTarget(false).Maybe()
536+ mockLoadingContent.EXPECT().AddCssClass("loading-skeleton-content").Maybe()
537+
538+ mockFactory.EXPECT().NewSpinner().Return(mockLoadingSpinner).Once()
539+ mockLoadingSpinner.EXPECT().SetHalign(mock.Anything).Maybe()
540+ mockLoadingSpinner.EXPECT().SetValign(mock.Anything).Maybe()
541+ mockLoadingSpinner.EXPECT().SetCanFocus(false).Maybe()
542+ mockLoadingSpinner.EXPECT().SetCanTarget(false).Maybe()
543+ mockLoadingSpinner.EXPECT().SetSizeRequest(32, 32).Maybe()
544+ mockLoadingSpinner.EXPECT().AddCssClass("loading-skeleton-spinner").Maybe()
545+ mockLoadingSpinner.EXPECT().Start().Maybe()
546+
547+ mockFactory.EXPECT().NewLabel("Loading...").Return(mockLoadingLabel).Once()
548+ mockLoadingLabel.EXPECT().SetHalign(mock.Anything).Maybe()
549+ mockLoadingLabel.EXPECT().SetValign(mock.Anything).Maybe()
550+ mockLoadingLabel.EXPECT().SetCanFocus(false).Maybe()
551+ mockLoadingLabel.EXPECT().SetCanTarget(false).Maybe()
552+ mockLoadingLabel.EXPECT().AddCssClass("loading-skeleton-text").Maybe()
553+
554+ mockLoadingContent.EXPECT().Append(mockLoadingSpinner).Maybe()
555+ mockLoadingContent.EXPECT().Append(mockLoadingLabel).Maybe()
556+ mockLoadingContainer.EXPECT().Append(mockLoadingContent).Maybe()
557+
558+ mockOverlay.EXPECT().AddOverlay(mockLoadingContainer).Once()
559+ mockOverlay.EXPECT().SetClipOverlay(mockLoadingContainer, false).Once()
560+ mockOverlay.EXPECT().SetMeasureOverlay(mockLoadingContainer, false).Once()
561+}
562+
497563 // Helper function to setup common mock expectations for PaneView creation
498564 func setupPaneViewMocks(
565+ t *testing.T,
499566 mockFactory *mocks.MockWidgetFactory,
500567 mockOverlay *mocks.MockOverlayWidget,
501568 mockBorderBox *mocks.MockBoxWidget,
502569 mockWebView *mocks.MockWidget,
503570 ) {
571+ mockLoadingContainer := mocks.NewMockBoxWidget(t)
572+ mockLoadingContent := mocks.NewMockBoxWidget(t)
573+ mockLoadingSpinner := mocks.NewMockSpinnerWidget(t)
574+ mockLoadingLabel := mocks.NewMockLabelWidget(t)
575+
504576 mockFactory.EXPECT().NewOverlay().Return(mockOverlay).Once()
505577 mockOverlay.EXPECT().SetHexpand(true).Once()
506578 mockOverlay.EXPECT().SetVexpand(true).Once()
@@ -508,6 +580,8 @@ func setupPaneViewMocks(
508580 mockOverlay.EXPECT().AddCssClass("pane-overlay").Once() // Theme background
509581 mockOverlay.EXPECT().SetChild(mockWebView).Once()
510582
583+ setupLoadingSkeletonMocks(mockFactory, mockOverlay, mockLoadingContainer, mockLoadingContent, mockLoadingSpinner, mockLoadingLabel)
584+
511585 mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockBorderBox).Once()
512586 mockBorderBox.EXPECT().SetCanFocus(false).Once()
513587 mockBorderBox.EXPECT().SetCanTarget(false).Once()
@@ -520,16 +594,24 @@ func setupPaneViewMocks(
520594 }
521595
522596 func setupPaneViewMocksNoWebView(
597+ t *testing.T,
523598 mockFactory *mocks.MockWidgetFactory,
524599 mockOverlay *mocks.MockOverlayWidget,
525600 mockBorderBox *mocks.MockBoxWidget,
526601 ) {
602+ mockLoadingContainer := mocks.NewMockBoxWidget(t)
603+ mockLoadingContent := mocks.NewMockBoxWidget(t)
604+ mockLoadingSpinner := mocks.NewMockSpinnerWidget(t)
605+ mockLoadingLabel := mocks.NewMockLabelWidget(t)
606+
527607 mockFactory.EXPECT().NewOverlay().Return(mockOverlay).Once()
528608 mockOverlay.EXPECT().SetHexpand(true).Once()
529609 mockOverlay.EXPECT().SetVexpand(true).Once()
530610 mockOverlay.EXPECT().SetVisible(true).Once()
531611 mockOverlay.EXPECT().AddCssClass("pane-overlay").Once() // Theme background
532612
613+ setupLoadingSkeletonMocks(mockFactory, mockOverlay, mockLoadingContainer, mockLoadingContent, mockLoadingSpinner, mockLoadingLabel)
614+
533615 mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockBorderBox).Once()
534616 mockBorderBox.EXPECT().SetCanFocus(false).Once()
535617 mockBorderBox.EXPECT().SetCanTarget(false).Once()
@@ -4,6 +4,7 @@ import (
4 "testing"4 "testing"
5 5
6 "github.com/stretchr/testify/assert"6 "github.com/stretchr/testify/assert"
7+ "github.com/stretchr/testify/mock"
7 "github.com/stretchr/testify/require"8 "github.com/stretchr/testify/require"
8 9
9 "github.com/bnema/dumber/internal/domain/entity"10 "github.com/bnema/dumber/internal/domain/entity"
@@ -19,6 +20,11 @@ func TestNewPaneView_CreatesOverlay(t *testing.T) {
19 mockBorderBox := mocks.NewMockBoxWidget(t)20 mockBorderBox := mocks.NewMockBoxWidget(t)
20 mockWebView := mocks.NewMockWidget(t)21 mockWebView := mocks.NewMockWidget(t)
21 22
23+ mockLoadingContainer := mocks.NewMockBoxWidget(t)
24+ mockLoadingContent := mocks.NewMockBoxWidget(t)
25+ mockLoadingSpinner := mocks.NewMockSpinnerWidget(t)
26+ mockLoadingLabel := mocks.NewMockLabelWidget(t)
27+
22 paneID := entity.PaneID("pane-1")28 paneID := entity.PaneID("pane-1")
23 29
24 mockFactory.EXPECT().NewOverlay().Return(mockOverlay).Once()30 mockFactory.EXPECT().NewOverlay().Return(mockOverlay).Once()
@@ -28,6 +34,8 @@ func TestNewPaneView_CreatesOverlay(t *testing.T) {
28 mockOverlay.EXPECT().AddCssClass("pane-overlay").Once() // Theme background34 mockOverlay.EXPECT().AddCssClass("pane-overlay").Once() // Theme background
29 mockOverlay.EXPECT().SetChild(mockWebView).Once()35 mockOverlay.EXPECT().SetChild(mockWebView).Once()
30 36
37+ setupLoadingSkeletonMocks(mockFactory, mockOverlay, mockLoadingContainer, mockLoadingContent, mockLoadingSpinner, mockLoadingLabel)
38+
31 mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockBorderBox).Once()39 mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockBorderBox).Once()
32 mockBorderBox.EXPECT().SetCanFocus(false).Once()40 mockBorderBox.EXPECT().SetCanFocus(false).Once()
33 mockBorderBox.EXPECT().SetCanTarget(false).Once()41 mockBorderBox.EXPECT().SetCanTarget(false).Once()
@@ -53,6 +61,11 @@ func TestNewPaneView_NilWebView(t *testing.T) {
53 mockOverlay := mocks.NewMockOverlayWidget(t)61 mockOverlay := mocks.NewMockOverlayWidget(t)
54 mockBorderBox := mocks.NewMockBoxWidget(t)62 mockBorderBox := mocks.NewMockBoxWidget(t)
55 63
64+ mockLoadingContainer := mocks.NewMockBoxWidget(t)
65+ mockLoadingContent := mocks.NewMockBoxWidget(t)
66+ mockLoadingSpinner := mocks.NewMockSpinnerWidget(t)
67+ mockLoadingLabel := mocks.NewMockLabelWidget(t)
68+
56 paneID := entity.PaneID("pane-1")69 paneID := entity.PaneID("pane-1")
57 70
58 mockFactory.EXPECT().NewOverlay().Return(mockOverlay).Once()71 mockFactory.EXPECT().NewOverlay().Return(mockOverlay).Once()
@@ -62,6 +75,8 @@ func TestNewPaneView_NilWebView(t *testing.T) {
62 mockOverlay.EXPECT().AddCssClass("pane-overlay").Once() // Theme background75 mockOverlay.EXPECT().AddCssClass("pane-overlay").Once() // Theme background
63 // SetChild should NOT be called when webview is nil76 // SetChild should NOT be called when webview is nil
64 77
78+ setupLoadingSkeletonMocks(mockFactory, mockOverlay, mockLoadingContainer, mockLoadingContent, mockLoadingSpinner, mockLoadingLabel)
79+
65 mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockBorderBox).Once()80 mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockBorderBox).Once()
66 mockBorderBox.EXPECT().SetCanFocus(false).Once()81 mockBorderBox.EXPECT().SetCanFocus(false).Once()
67 mockBorderBox.EXPECT().SetCanTarget(false).Once()82 mockBorderBox.EXPECT().SetCanTarget(false).Once()
@@ -87,7 +102,7 @@ func TestSetActive_True_AddsCSSClass(t *testing.T) {
87 mockBorderBox := mocks.NewMockBoxWidget(t)102 mockBorderBox := mocks.NewMockBoxWidget(t)
88 mockWebView := mocks.NewMockWidget(t)103 mockWebView := mocks.NewMockWidget(t)
89 104
90- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)105+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
91 106
92 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)107 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
93 108
@@ -108,7 +123,7 @@ func TestSetActive_False_RemovesCSSClass(t *testing.T) {
108 mockBorderBox := mocks.NewMockBoxWidget(t)123 mockBorderBox := mocks.NewMockBoxWidget(t)
109 mockWebView := mocks.NewMockWidget(t)124 mockWebView := mocks.NewMockWidget(t)
110 125
111- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)126+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
112 127
113 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)128 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
114 129
@@ -133,7 +148,7 @@ func TestSetActive_NoChangeWhenSameState(t *testing.T) {
133 mockBorderBox := mocks.NewMockBoxWidget(t)148 mockBorderBox := mocks.NewMockBoxWidget(t)
134 mockWebView := mocks.NewMockWidget(t)149 mockWebView := mocks.NewMockWidget(t)
135 150
136- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)151+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
137 152
138 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)153 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
139 154
@@ -152,7 +167,7 @@ func TestPaneID_ReturnsPaneID(t *testing.T) {
152 mockWebView := mocks.NewMockWidget(t)167 mockWebView := mocks.NewMockWidget(t)
153 168
154 paneID := entity.PaneID("test-pane-123")169 paneID := entity.PaneID("test-pane-123")
155- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)170+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
156 171
157 pv := component.NewPaneView(mockFactory, paneID, mockWebView)172 pv := component.NewPaneView(mockFactory, paneID, mockWebView)
158 173
@@ -170,7 +185,7 @@ func TestWebViewWidget_ReturnsWebView(t *testing.T) {
170 mockBorderBox := mocks.NewMockBoxWidget(t)185 mockBorderBox := mocks.NewMockBoxWidget(t)
171 mockWebView := mocks.NewMockWidget(t)186 mockWebView := mocks.NewMockWidget(t)
172 187
173- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)188+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
174 189
175 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)190 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
176 191
@@ -189,7 +204,7 @@ func TestSetWebViewWidget_ReplacesWidget(t *testing.T) {
189 mockOldWebView := mocks.NewMockWidget(t)204 mockOldWebView := mocks.NewMockWidget(t)
190 mockNewWebView := mocks.NewMockWidget(t)205 mockNewWebView := mocks.NewMockWidget(t)
191 206
192- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockOldWebView)207+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockOldWebView)
193 208
194 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockOldWebView)209 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockOldWebView)
195 210
@@ -213,7 +228,7 @@ func TestSetWebViewWidget_FromNil(t *testing.T) {
213 mockBorderBox := mocks.NewMockBoxWidget(t)228 mockBorderBox := mocks.NewMockBoxWidget(t)
214 mockNewWebView := mocks.NewMockWidget(t)229 mockNewWebView := mocks.NewMockWidget(t)
215 230
216- setupPaneViewMocksNoWebView(mockFactory, mockOverlay, mockBorderBox)231+ setupPaneViewMocksNoWebView(t, mockFactory, mockOverlay, mockBorderBox)
217 232
218 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), nil)233 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), nil)
219 234
@@ -236,7 +251,7 @@ func TestGrabFocus_DelegatesToWebView(t *testing.T) {
236 mockBorderBox := mocks.NewMockBoxWidget(t)251 mockBorderBox := mocks.NewMockBoxWidget(t)
237 mockWebView := mocks.NewMockWidget(t)252 mockWebView := mocks.NewMockWidget(t)
238 253
239- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)254+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
240 255
241 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)256 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
242 257
@@ -255,7 +270,7 @@ func TestGrabFocus_NilWebView_ReturnsFalse(t *testing.T) {
255 mockOverlay := mocks.NewMockOverlayWidget(t)270 mockOverlay := mocks.NewMockOverlayWidget(t)
256 mockBorderBox := mocks.NewMockBoxWidget(t)271 mockBorderBox := mocks.NewMockBoxWidget(t)
257 272
258- setupPaneViewMocksNoWebView(mockFactory, mockOverlay, mockBorderBox)273+ setupPaneViewMocksNoWebView(t, mockFactory, mockOverlay, mockBorderBox)
259 274
260 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), nil)275 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), nil)
261 276
@@ -273,7 +288,7 @@ func TestHasFocus_DelegatesToWebView(t *testing.T) {
273 mockBorderBox := mocks.NewMockBoxWidget(t)288 mockBorderBox := mocks.NewMockBoxWidget(t)
274 mockWebView := mocks.NewMockWidget(t)289 mockWebView := mocks.NewMockWidget(t)
275 290
276- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)291+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
277 292
278 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)293 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
279 294
@@ -292,7 +307,7 @@ func TestHasFocus_NilWebView_ReturnsFalse(t *testing.T) {
292 mockOverlay := mocks.NewMockOverlayWidget(t)307 mockOverlay := mocks.NewMockOverlayWidget(t)
293 mockBorderBox := mocks.NewMockBoxWidget(t)308 mockBorderBox := mocks.NewMockBoxWidget(t)
294 309
295- setupPaneViewMocksNoWebView(mockFactory, mockOverlay, mockBorderBox)310+ setupPaneViewMocksNoWebView(t, mockFactory, mockOverlay, mockBorderBox)
296 311
297 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), nil)312 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), nil)
298 313
@@ -310,7 +325,7 @@ func TestWidget_ReturnsOverlay(t *testing.T) {
310 mockBorderBox := mocks.NewMockBoxWidget(t)325 mockBorderBox := mocks.NewMockBoxWidget(t)
311 mockWebView := mocks.NewMockWidget(t)326 mockWebView := mocks.NewMockWidget(t)
312 327
313- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)328+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
314 329
315 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)330 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
316 331
@@ -328,7 +343,7 @@ func TestOverlay_ReturnsOverlayWidget(t *testing.T) {
328 mockBorderBox := mocks.NewMockBoxWidget(t)343 mockBorderBox := mocks.NewMockBoxWidget(t)
329 mockWebView := mocks.NewMockWidget(t)344 mockWebView := mocks.NewMockWidget(t)
330 345
331- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)346+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
332 347
333 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)348 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
334 349
@@ -346,7 +361,7 @@ func TestShow_DelegatesToOverlay(t *testing.T) {
346 mockBorderBox := mocks.NewMockBoxWidget(t)361 mockBorderBox := mocks.NewMockBoxWidget(t)
347 mockWebView := mocks.NewMockWidget(t)362 mockWebView := mocks.NewMockWidget(t)
348 363
349- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)364+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
350 365
351 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)366 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
352 367
@@ -365,7 +380,7 @@ func TestHide_DelegatesToOverlay(t *testing.T) {
365 mockBorderBox := mocks.NewMockBoxWidget(t)380 mockBorderBox := mocks.NewMockBoxWidget(t)
366 mockWebView := mocks.NewMockWidget(t)381 mockWebView := mocks.NewMockWidget(t)
367 382
368- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)383+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
369 384
370 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)385 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
371 386
@@ -384,7 +399,7 @@ func TestSetVisible_DelegatesToOverlay(t *testing.T) {
384 mockBorderBox := mocks.NewMockBoxWidget(t)399 mockBorderBox := mocks.NewMockBoxWidget(t)
385 mockWebView := mocks.NewMockWidget(t)400 mockWebView := mocks.NewMockWidget(t)
386 401
387- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)402+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
388 403
389 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)404 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
390 405
@@ -403,7 +418,7 @@ func TestIsVisible_DelegatesToOverlay(t *testing.T) {
403 mockBorderBox := mocks.NewMockBoxWidget(t)418 mockBorderBox := mocks.NewMockBoxWidget(t)
404 mockWebView := mocks.NewMockWidget(t)419 mockWebView := mocks.NewMockWidget(t)
405 420
406- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)421+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
407 422
408 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)423 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
409 424
@@ -423,7 +438,7 @@ func TestAddCssClass_DelegatesToOverlay(t *testing.T) {
423 mockBorderBox := mocks.NewMockBoxWidget(t)438 mockBorderBox := mocks.NewMockBoxWidget(t)
424 mockWebView := mocks.NewMockWidget(t)439 mockWebView := mocks.NewMockWidget(t)
425 440
426- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)441+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
427 442
428 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)443 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
429 444
@@ -442,7 +457,7 @@ func TestRemoveCssClass_DelegatesToOverlay(t *testing.T) {
442 mockBorderBox := mocks.NewMockBoxWidget(t)457 mockBorderBox := mocks.NewMockBoxWidget(t)
443 mockWebView := mocks.NewMockWidget(t)458 mockWebView := mocks.NewMockWidget(t)
444 459
445- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)460+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
446 461
447 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)462 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
448 463
@@ -461,7 +476,7 @@ func TestSetOnFocusIn_SetsCallback(t *testing.T) {
461 mockBorderBox := mocks.NewMockBoxWidget(t)476 mockBorderBox := mocks.NewMockBoxWidget(t)
462 mockWebView := mocks.NewMockWidget(t)477 mockWebView := mocks.NewMockWidget(t)
463 478
464- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)479+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
465 480
466 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)481 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
467 482
@@ -481,7 +496,7 @@ func TestSetOnFocusOut_SetsCallback(t *testing.T) {
481 mockBorderBox := mocks.NewMockBoxWidget(t)496 mockBorderBox := mocks.NewMockBoxWidget(t)
482 mockWebView := mocks.NewMockWidget(t)497 mockWebView := mocks.NewMockWidget(t)
483 498
484- setupPaneViewMocks(mockFactory, mockOverlay, mockBorderBox, mockWebView)499+ setupPaneViewMocks(t, mockFactory, mockOverlay, mockBorderBox, mockWebView)
485 500
486 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)501 pv := component.NewPaneView(mockFactory, entity.PaneID("pane-1"), mockWebView)
487 502
@@ -494,13 +509,70 @@ func TestSetOnFocusOut_SetsCallback(t *testing.T) {
494 assert.NotNil(t, pv)509 assert.NotNil(t, pv)
495 }510 }
496 511
512+// Helper function to setup common mock expectations for PaneView creation
513+func setupLoadingSkeletonMocks(
514+ mockFactory *mocks.MockWidgetFactory,
515+ mockOverlay *mocks.MockOverlayWidget,
516+ mockLoadingContainer *mocks.MockBoxWidget,
517+ mockLoadingContent *mocks.MockBoxWidget,
518+ mockLoadingSpinner *mocks.MockSpinnerWidget,
519+ mockLoadingLabel *mocks.MockLabelWidget,
520+) {
521+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockLoadingContainer).Once()
522+ mockLoadingContainer.EXPECT().SetHexpand(true).Maybe()
523+ mockLoadingContainer.EXPECT().SetVexpand(true).Maybe()
524+ mockLoadingContainer.EXPECT().SetHalign(mock.Anything).Maybe()
525+ mockLoadingContainer.EXPECT().SetValign(mock.Anything).Maybe()
526+ mockLoadingContainer.EXPECT().SetCanFocus(false).Maybe()
527+ mockLoadingContainer.EXPECT().SetCanTarget(false).Maybe()
528+ mockLoadingContainer.EXPECT().AddCssClass("loading-skeleton").Maybe()
529+ mockLoadingContainer.EXPECT().SetVisible(true).Maybe()
530+
531+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 6).Return(mockLoadingContent).Once()
532+ mockLoadingContent.EXPECT().SetHalign(mock.Anything).Maybe()
533+ mockLoadingContent.EXPECT().SetValign(mock.Anything).Maybe()
534+ mockLoadingContent.EXPECT().SetCanFocus(false).Maybe()
535+ mockLoadingContent.EXPECT().SetCanTarget(false).Maybe()
536+ mockLoadingContent.EXPECT().AddCssClass("loading-skeleton-content").Maybe()
537+
538+ mockFactory.EXPECT().NewSpinner().Return(mockLoadingSpinner).Once()
539+ mockLoadingSpinner.EXPECT().SetHalign(mock.Anything).Maybe()
540+ mockLoadingSpinner.EXPECT().SetValign(mock.Anything).Maybe()
541+ mockLoadingSpinner.EXPECT().SetCanFocus(false).Maybe()
542+ mockLoadingSpinner.EXPECT().SetCanTarget(false).Maybe()
543+ mockLoadingSpinner.EXPECT().SetSizeRequest(32, 32).Maybe()
544+ mockLoadingSpinner.EXPECT().AddCssClass("loading-skeleton-spinner").Maybe()
545+ mockLoadingSpinner.EXPECT().Start().Maybe()
546+
547+ mockFactory.EXPECT().NewLabel("Loading...").Return(mockLoadingLabel).Once()
548+ mockLoadingLabel.EXPECT().SetHalign(mock.Anything).Maybe()
549+ mockLoadingLabel.EXPECT().SetValign(mock.Anything).Maybe()
550+ mockLoadingLabel.EXPECT().SetCanFocus(false).Maybe()
551+ mockLoadingLabel.EXPECT().SetCanTarget(false).Maybe()
552+ mockLoadingLabel.EXPECT().AddCssClass("loading-skeleton-text").Maybe()
553+
554+ mockLoadingContent.EXPECT().Append(mockLoadingSpinner).Maybe()
555+ mockLoadingContent.EXPECT().Append(mockLoadingLabel).Maybe()
556+ mockLoadingContainer.EXPECT().Append(mockLoadingContent).Maybe()
557+
558+ mockOverlay.EXPECT().AddOverlay(mockLoadingContainer).Once()
559+ mockOverlay.EXPECT().SetClipOverlay(mockLoadingContainer, false).Once()
560+ mockOverlay.EXPECT().SetMeasureOverlay(mockLoadingContainer, false).Once()
561+}
562+
497 // Helper function to setup common mock expectations for PaneView creation563 // Helper function to setup common mock expectations for PaneView creation
498 func setupPaneViewMocks(564 func setupPaneViewMocks(
565+ t *testing.T,
499 mockFactory *mocks.MockWidgetFactory,566 mockFactory *mocks.MockWidgetFactory,
500 mockOverlay *mocks.MockOverlayWidget,567 mockOverlay *mocks.MockOverlayWidget,
501 mockBorderBox *mocks.MockBoxWidget,568 mockBorderBox *mocks.MockBoxWidget,
502 mockWebView *mocks.MockWidget,569 mockWebView *mocks.MockWidget,
503 ) {570 ) {
571+ mockLoadingContainer := mocks.NewMockBoxWidget(t)
572+ mockLoadingContent := mocks.NewMockBoxWidget(t)
573+ mockLoadingSpinner := mocks.NewMockSpinnerWidget(t)
574+ mockLoadingLabel := mocks.NewMockLabelWidget(t)
575+
504 mockFactory.EXPECT().NewOverlay().Return(mockOverlay).Once()576 mockFactory.EXPECT().NewOverlay().Return(mockOverlay).Once()
505 mockOverlay.EXPECT().SetHexpand(true).Once()577 mockOverlay.EXPECT().SetHexpand(true).Once()
506 mockOverlay.EXPECT().SetVexpand(true).Once()578 mockOverlay.EXPECT().SetVexpand(true).Once()
@@ -508,6 +580,8 @@ func setupPaneViewMocks(
508 mockOverlay.EXPECT().AddCssClass("pane-overlay").Once() // Theme background580 mockOverlay.EXPECT().AddCssClass("pane-overlay").Once() // Theme background
509 mockOverlay.EXPECT().SetChild(mockWebView).Once()581 mockOverlay.EXPECT().SetChild(mockWebView).Once()
510 582
583+ setupLoadingSkeletonMocks(mockFactory, mockOverlay, mockLoadingContainer, mockLoadingContent, mockLoadingSpinner, mockLoadingLabel)
584+
511 mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockBorderBox).Once()585 mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockBorderBox).Once()
512 mockBorderBox.EXPECT().SetCanFocus(false).Once()586 mockBorderBox.EXPECT().SetCanFocus(false).Once()
513 mockBorderBox.EXPECT().SetCanTarget(false).Once()587 mockBorderBox.EXPECT().SetCanTarget(false).Once()
@@ -520,16 +594,24 @@ func setupPaneViewMocks(
520 }594 }
521 595
522 func setupPaneViewMocksNoWebView(596 func setupPaneViewMocksNoWebView(
597+ t *testing.T,
523 mockFactory *mocks.MockWidgetFactory,598 mockFactory *mocks.MockWidgetFactory,
524 mockOverlay *mocks.MockOverlayWidget,599 mockOverlay *mocks.MockOverlayWidget,
525 mockBorderBox *mocks.MockBoxWidget,600 mockBorderBox *mocks.MockBoxWidget,
526 ) {601 ) {
602+ mockLoadingContainer := mocks.NewMockBoxWidget(t)
603+ mockLoadingContent := mocks.NewMockBoxWidget(t)
604+ mockLoadingSpinner := mocks.NewMockSpinnerWidget(t)
605+ mockLoadingLabel := mocks.NewMockLabelWidget(t)
606+
527 mockFactory.EXPECT().NewOverlay().Return(mockOverlay).Once()607 mockFactory.EXPECT().NewOverlay().Return(mockOverlay).Once()
528 mockOverlay.EXPECT().SetHexpand(true).Once()608 mockOverlay.EXPECT().SetHexpand(true).Once()
529 mockOverlay.EXPECT().SetVexpand(true).Once()609 mockOverlay.EXPECT().SetVexpand(true).Once()
530 mockOverlay.EXPECT().SetVisible(true).Once()610 mockOverlay.EXPECT().SetVisible(true).Once()
531 mockOverlay.EXPECT().AddCssClass("pane-overlay").Once() // Theme background611 mockOverlay.EXPECT().AddCssClass("pane-overlay").Once() // Theme background
532 612
613+ setupLoadingSkeletonMocks(mockFactory, mockOverlay, mockLoadingContainer, mockLoadingContent, mockLoadingSpinner, mockLoadingLabel)
614+
533 mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockBorderBox).Once()615 mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockBorderBox).Once()
534 mockBorderBox.EXPECT().SetCanFocus(false).Once()616 mockBorderBox.EXPECT().SetCanFocus(false).Once()
535 mockBorderBox.EXPECT().SetCanTarget(false).Once()617 mockBorderBox.EXPECT().SetCanTarget(false).Once()
M internal/ui/component/workspace_view_test.go +57 -0
@@ -14,6 +14,56 @@ import (
1414 "github.com/bnema/dumber/internal/ui/layout/mocks"
1515 )
1616
17+func setupLoadingSkeletonMocksWorkspace(
18+ mockFactory *mocks.MockWidgetFactory,
19+ mockOverlay *mocks.MockOverlayWidget,
20+ mockLoadingContainer *mocks.MockBoxWidget,
21+ mockLoadingContent *mocks.MockBoxWidget,
22+ mockLoadingSpinner *mocks.MockSpinnerWidget,
23+ mockLoadingLabel *mocks.MockLabelWidget,
24+) {
25+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockLoadingContainer).Once()
26+ mockLoadingContainer.EXPECT().SetHexpand(true).Maybe()
27+ mockLoadingContainer.EXPECT().SetVexpand(true).Maybe()
28+ mockLoadingContainer.EXPECT().SetHalign(mock.Anything).Maybe()
29+ mockLoadingContainer.EXPECT().SetValign(mock.Anything).Maybe()
30+ mockLoadingContainer.EXPECT().SetCanFocus(false).Maybe()
31+ mockLoadingContainer.EXPECT().SetCanTarget(false).Maybe()
32+ mockLoadingContainer.EXPECT().AddCssClass("loading-skeleton").Maybe()
33+ mockLoadingContainer.EXPECT().SetVisible(true).Maybe()
34+
35+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 6).Return(mockLoadingContent).Once()
36+ mockLoadingContent.EXPECT().SetHalign(mock.Anything).Maybe()
37+ mockLoadingContent.EXPECT().SetValign(mock.Anything).Maybe()
38+ mockLoadingContent.EXPECT().SetCanFocus(false).Maybe()
39+ mockLoadingContent.EXPECT().SetCanTarget(false).Maybe()
40+ mockLoadingContent.EXPECT().AddCssClass("loading-skeleton-content").Maybe()
41+
42+ mockFactory.EXPECT().NewSpinner().Return(mockLoadingSpinner).Once()
43+ mockLoadingSpinner.EXPECT().SetHalign(mock.Anything).Maybe()
44+ mockLoadingSpinner.EXPECT().SetValign(mock.Anything).Maybe()
45+ mockLoadingSpinner.EXPECT().SetCanFocus(false).Maybe()
46+ mockLoadingSpinner.EXPECT().SetCanTarget(false).Maybe()
47+ mockLoadingSpinner.EXPECT().SetSizeRequest(32, 32).Maybe()
48+ mockLoadingSpinner.EXPECT().AddCssClass("loading-skeleton-spinner").Maybe()
49+ mockLoadingSpinner.EXPECT().Start().Maybe()
50+
51+ mockFactory.EXPECT().NewLabel("Loading...").Return(mockLoadingLabel).Once()
52+ mockLoadingLabel.EXPECT().SetHalign(mock.Anything).Maybe()
53+ mockLoadingLabel.EXPECT().SetValign(mock.Anything).Maybe()
54+ mockLoadingLabel.EXPECT().SetCanFocus(false).Maybe()
55+ mockLoadingLabel.EXPECT().SetCanTarget(false).Maybe()
56+ mockLoadingLabel.EXPECT().AddCssClass("loading-skeleton-text").Maybe()
57+
58+ mockLoadingContent.EXPECT().Append(mockLoadingSpinner).Maybe()
59+ mockLoadingContent.EXPECT().Append(mockLoadingLabel).Maybe()
60+ mockLoadingContainer.EXPECT().Append(mockLoadingContent).Maybe()
61+
62+ mockOverlay.EXPECT().AddOverlay(mockLoadingContainer).Once()
63+ mockOverlay.EXPECT().SetClipOverlay(mockLoadingContainer, false).Once()
64+ mockOverlay.EXPECT().SetMeasureOverlay(mockLoadingContainer, false).Once()
65+}
66+
1767 func setupWorkspaceViewBase(t *testing.T, mockFactory *mocks.MockWidgetFactory) (context.Context, *mocks.MockBoxWidget) {
1868 ctx := context.Background()
1969 mockContainer := mocks.NewMockBoxWidget(t)
@@ -37,12 +87,19 @@ func setupWorkspacePaneViewMocks(t *testing.T, mockFactory *mocks.MockWidgetFact
3787 mockOverlay := mocks.NewMockOverlayWidget(t)
3888 mockBorderBox := mocks.NewMockBoxWidget(t)
3989
90+ mockLoadingContainer := mocks.NewMockBoxWidget(t)
91+ mockLoadingContent := mocks.NewMockBoxWidget(t)
92+ mockLoadingSpinner := mocks.NewMockSpinnerWidget(t)
93+ mockLoadingLabel := mocks.NewMockLabelWidget(t)
94+
4095 mockFactory.EXPECT().NewOverlay().Return(mockOverlay).Once()
4196 mockOverlay.EXPECT().SetHexpand(true).Once()
4297 mockOverlay.EXPECT().SetVexpand(true).Once()
4398 mockOverlay.EXPECT().SetVisible(true).Once()
4499 mockOverlay.EXPECT().AddCssClass("pane-overlay").Once()
45100
101+ setupLoadingSkeletonMocksWorkspace(mockFactory, mockOverlay, mockLoadingContainer, mockLoadingContent, mockLoadingSpinner, mockLoadingLabel)
102+
46103 mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockBorderBox).Once()
47104 mockBorderBox.EXPECT().SetCanFocus(false).Once()
48105 mockBorderBox.EXPECT().SetCanTarget(false).Once()
@@ -14,6 +14,56 @@ import (
14 "github.com/bnema/dumber/internal/ui/layout/mocks"14 "github.com/bnema/dumber/internal/ui/layout/mocks"
15 )15 )
16 16
17+func setupLoadingSkeletonMocksWorkspace(
18+ mockFactory *mocks.MockWidgetFactory,
19+ mockOverlay *mocks.MockOverlayWidget,
20+ mockLoadingContainer *mocks.MockBoxWidget,
21+ mockLoadingContent *mocks.MockBoxWidget,
22+ mockLoadingSpinner *mocks.MockSpinnerWidget,
23+ mockLoadingLabel *mocks.MockLabelWidget,
24+) {
25+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockLoadingContainer).Once()
26+ mockLoadingContainer.EXPECT().SetHexpand(true).Maybe()
27+ mockLoadingContainer.EXPECT().SetVexpand(true).Maybe()
28+ mockLoadingContainer.EXPECT().SetHalign(mock.Anything).Maybe()
29+ mockLoadingContainer.EXPECT().SetValign(mock.Anything).Maybe()
30+ mockLoadingContainer.EXPECT().SetCanFocus(false).Maybe()
31+ mockLoadingContainer.EXPECT().SetCanTarget(false).Maybe()
32+ mockLoadingContainer.EXPECT().AddCssClass("loading-skeleton").Maybe()
33+ mockLoadingContainer.EXPECT().SetVisible(true).Maybe()
34+
35+ mockFactory.EXPECT().NewBox(layout.OrientationVertical, 6).Return(mockLoadingContent).Once()
36+ mockLoadingContent.EXPECT().SetHalign(mock.Anything).Maybe()
37+ mockLoadingContent.EXPECT().SetValign(mock.Anything).Maybe()
38+ mockLoadingContent.EXPECT().SetCanFocus(false).Maybe()
39+ mockLoadingContent.EXPECT().SetCanTarget(false).Maybe()
40+ mockLoadingContent.EXPECT().AddCssClass("loading-skeleton-content").Maybe()
41+
42+ mockFactory.EXPECT().NewSpinner().Return(mockLoadingSpinner).Once()
43+ mockLoadingSpinner.EXPECT().SetHalign(mock.Anything).Maybe()
44+ mockLoadingSpinner.EXPECT().SetValign(mock.Anything).Maybe()
45+ mockLoadingSpinner.EXPECT().SetCanFocus(false).Maybe()
46+ mockLoadingSpinner.EXPECT().SetCanTarget(false).Maybe()
47+ mockLoadingSpinner.EXPECT().SetSizeRequest(32, 32).Maybe()
48+ mockLoadingSpinner.EXPECT().AddCssClass("loading-skeleton-spinner").Maybe()
49+ mockLoadingSpinner.EXPECT().Start().Maybe()
50+
51+ mockFactory.EXPECT().NewLabel("Loading...").Return(mockLoadingLabel).Once()
52+ mockLoadingLabel.EXPECT().SetHalign(mock.Anything).Maybe()
53+ mockLoadingLabel.EXPECT().SetValign(mock.Anything).Maybe()
54+ mockLoadingLabel.EXPECT().SetCanFocus(false).Maybe()
55+ mockLoadingLabel.EXPECT().SetCanTarget(false).Maybe()
56+ mockLoadingLabel.EXPECT().AddCssClass("loading-skeleton-text").Maybe()
57+
58+ mockLoadingContent.EXPECT().Append(mockLoadingSpinner).Maybe()
59+ mockLoadingContent.EXPECT().Append(mockLoadingLabel).Maybe()
60+ mockLoadingContainer.EXPECT().Append(mockLoadingContent).Maybe()
61+
62+ mockOverlay.EXPECT().AddOverlay(mockLoadingContainer).Once()
63+ mockOverlay.EXPECT().SetClipOverlay(mockLoadingContainer, false).Once()
64+ mockOverlay.EXPECT().SetMeasureOverlay(mockLoadingContainer, false).Once()
65+}
66+
17 func setupWorkspaceViewBase(t *testing.T, mockFactory *mocks.MockWidgetFactory) (context.Context, *mocks.MockBoxWidget) {67 func setupWorkspaceViewBase(t *testing.T, mockFactory *mocks.MockWidgetFactory) (context.Context, *mocks.MockBoxWidget) {
18 ctx := context.Background()68 ctx := context.Background()
19 mockContainer := mocks.NewMockBoxWidget(t)69 mockContainer := mocks.NewMockBoxWidget(t)
@@ -37,12 +87,19 @@ func setupWorkspacePaneViewMocks(t *testing.T, mockFactory *mocks.MockWidgetFact
37 mockOverlay := mocks.NewMockOverlayWidget(t)87 mockOverlay := mocks.NewMockOverlayWidget(t)
38 mockBorderBox := mocks.NewMockBoxWidget(t)88 mockBorderBox := mocks.NewMockBoxWidget(t)
39 89
90+ mockLoadingContainer := mocks.NewMockBoxWidget(t)
91+ mockLoadingContent := mocks.NewMockBoxWidget(t)
92+ mockLoadingSpinner := mocks.NewMockSpinnerWidget(t)
93+ mockLoadingLabel := mocks.NewMockLabelWidget(t)
94+
40 mockFactory.EXPECT().NewOverlay().Return(mockOverlay).Once()95 mockFactory.EXPECT().NewOverlay().Return(mockOverlay).Once()
41 mockOverlay.EXPECT().SetHexpand(true).Once()96 mockOverlay.EXPECT().SetHexpand(true).Once()
42 mockOverlay.EXPECT().SetVexpand(true).Once()97 mockOverlay.EXPECT().SetVexpand(true).Once()
43 mockOverlay.EXPECT().SetVisible(true).Once()98 mockOverlay.EXPECT().SetVisible(true).Once()
44 mockOverlay.EXPECT().AddCssClass("pane-overlay").Once()99 mockOverlay.EXPECT().AddCssClass("pane-overlay").Once()
45 100
101+ setupLoadingSkeletonMocksWorkspace(mockFactory, mockOverlay, mockLoadingContainer, mockLoadingContent, mockLoadingSpinner, mockLoadingLabel)
102+
46 mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockBorderBox).Once()103 mockFactory.EXPECT().NewBox(layout.OrientationVertical, 0).Return(mockBorderBox).Once()
47 mockBorderBox.EXPECT().SetCanFocus(false).Once()104 mockBorderBox.EXPECT().SetCanFocus(false).Once()
48 mockBorderBox.EXPECT().SetCanTarget(false).Once()105 mockBorderBox.EXPECT().SetCanTarget(false).Once()
M internal/ui/coordinator/content.go +43 -5
@@ -52,6 +52,9 @@ type ContentCoordinator struct {
5252 // Callback when active pane title changes (for window title updates)
5353 onWindowTitleChanged func(title string)
5454
55+ // Callback when the WebView becomes visible (first real commit)
56+ onWebViewShown func(paneID entity.PaneID)
57+
5558 // Gesture action handler for mouse button navigation
5659 gestureActionHandler input.ActionHandler
5760
@@ -119,6 +122,11 @@ func (c *ContentCoordinator) SetOnWindowTitleChanged(fn func(title string)) {
119122 c.onWindowTitleChanged = fn
120123 }
121124
125+// SetOnWebViewShown sets a callback that fires when a pane's WebView is shown.
126+func (c *ContentCoordinator) SetOnWebViewShown(fn func(paneID entity.PaneID)) {
127+ c.onWebViewShown = fn
128+}
129+
122130 // SetGestureActionHandler sets the callback for mouse button navigation gestures.
123131 func (c *ContentCoordinator) SetGestureActionHandler(handler input.ActionHandler) {
124132 c.gestureActionHandler = handler
@@ -674,18 +682,48 @@ func (c *ContentCoordinator) PreloadCachedFavicon(ctx context.Context, paneID en
674682 func (c *ContentCoordinator) onLoadCommitted(ctx context.Context, paneID entity.PaneID, wv *webkit.WebView) {
675683 log := logging.FromContext(ctx)
676684
685+ url := wv.URI()
686+ if url == "" {
687+ return
688+ }
689+
677690 // Show the WebView now that content is being painted
678691 // (WebViews are hidden on creation to avoid white flash)
679- if inner := wv.Widget(); inner != nil {
680- inner.SetVisible(true)
681- log.Debug().Str("pane_id", string(paneID)).Msg("webview shown on load committed")
692+ // Skip showing if this is about:blank but the pane is loading a different URL
693+ // This prevents the brief flash of about:blank during initial navigation
694+ shouldShow := true
695+ if url == "about:blank" {
696+ // Get the pane's intended URI from the workspace
697+ ws, _ := c.getActiveWS()
698+ if ws != nil {
699+ if paneNode := ws.FindPane(paneID); paneNode != nil && paneNode.Pane != nil {
700+ // Don't show about:blank if the pane is supposed to load a different URL
701+ if paneNode.Pane.URI != "" && paneNode.Pane.URI != "about:blank" {
702+ shouldShow = false
703+ log.Debug().
704+ Str("pane_id", string(paneID)).
705+ Str("pane_uri", paneNode.Pane.URI).
706+ Msg("skipping webview show for about:blank (pane loading different URL)")
707+ }
708+ }
709+ }
682710 }
683711
684- url := wv.URI()
685- if url == "" {
712+ if !shouldShow {
713+ // Avoid updating UI/domain state to about:blank when we know the pane is
714+ // navigating to a different URL. This prevents the omnibox/window title from
715+ // briefly showing about:blank on cold start.
686716 return
687717 }
688718
719+ if inner := wv.Widget(); inner != nil {
720+ inner.SetVisible(true)
721+ log.Debug().Str("pane_id", string(paneID)).Str("url", url).Msg("webview shown on load committed")
722+ }
723+ if c.onWebViewShown != nil {
724+ c.onWebViewShown(paneID)
725+ }
726+
689727 // Update domain model with current URI for session snapshots
690728 c.updatePaneURI(paneID, url)
691729
@@ -52,6 +52,9 @@ type ContentCoordinator struct {
52 // Callback when active pane title changes (for window title updates)52 // Callback when active pane title changes (for window title updates)
53 onWindowTitleChanged func(title string)53 onWindowTitleChanged func(title string)
54 54
55+ // Callback when the WebView becomes visible (first real commit)
56+ onWebViewShown func(paneID entity.PaneID)
57+
55 // Gesture action handler for mouse button navigation58 // Gesture action handler for mouse button navigation
56 gestureActionHandler input.ActionHandler59 gestureActionHandler input.ActionHandler
57 60
@@ -119,6 +122,11 @@ func (c *ContentCoordinator) SetOnWindowTitleChanged(fn func(title string)) {
119 c.onWindowTitleChanged = fn122 c.onWindowTitleChanged = fn
120 }123 }
121 124
125+// SetOnWebViewShown sets a callback that fires when a pane's WebView is shown.
126+func (c *ContentCoordinator) SetOnWebViewShown(fn func(paneID entity.PaneID)) {
127+ c.onWebViewShown = fn
128+}
129+
122 // SetGestureActionHandler sets the callback for mouse button navigation gestures.130 // SetGestureActionHandler sets the callback for mouse button navigation gestures.
123 func (c *ContentCoordinator) SetGestureActionHandler(handler input.ActionHandler) {131 func (c *ContentCoordinator) SetGestureActionHandler(handler input.ActionHandler) {
124 c.gestureActionHandler = handler132 c.gestureActionHandler = handler
@@ -674,18 +682,48 @@ func (c *ContentCoordinator) PreloadCachedFavicon(ctx context.Context, paneID en
674 func (c *ContentCoordinator) onLoadCommitted(ctx context.Context, paneID entity.PaneID, wv *webkit.WebView) {682 func (c *ContentCoordinator) onLoadCommitted(ctx context.Context, paneID entity.PaneID, wv *webkit.WebView) {
675 log := logging.FromContext(ctx)683 log := logging.FromContext(ctx)
676 684
685+ url := wv.URI()
686+ if url == "" {
687+ return
688+ }
689+
677 // Show the WebView now that content is being painted690 // Show the WebView now that content is being painted
678 // (WebViews are hidden on creation to avoid white flash)691 // (WebViews are hidden on creation to avoid white flash)
679- if inner := wv.Widget(); inner != nil {692+ // Skip showing if this is about:blank but the pane is loading a different URL
680- inner.SetVisible(true)693+ // This prevents the brief flash of about:blank during initial navigation
681- log.Debug().Str("pane_id", string(paneID)).Msg("webview shown on load committed")694+ shouldShow := true
695+ if url == "about:blank" {
696+ // Get the pane's intended URI from the workspace
697+ ws, _ := c.getActiveWS()
698+ if ws != nil {
699+ if paneNode := ws.FindPane(paneID); paneNode != nil && paneNode.Pane != nil {
700+ // Don't show about:blank if the pane is supposed to load a different URL
701+ if paneNode.Pane.URI != "" && paneNode.Pane.URI != "about:blank" {
702+ shouldShow = false
703+ log.Debug().
704+ Str("pane_id", string(paneID)).
705+ Str("pane_uri", paneNode.Pane.URI).
706+ Msg("skipping webview show for about:blank (pane loading different URL)")
707+ }
708+ }
709+ }
682 }710 }
683 711
684- url := wv.URI()712+ if !shouldShow {
685- if url == "" {713+ // Avoid updating UI/domain state to about:blank when we know the pane is
714+ // navigating to a different URL. This prevents the omnibox/window title from
715+ // briefly showing about:blank on cold start.
686 return716 return
687 }717 }
688 718
719+ if inner := wv.Widget(); inner != nil {
720+ inner.SetVisible(true)
721+ log.Debug().Str("pane_id", string(paneID)).Str("url", url).Msg("webview shown on load committed")
722+ }
723+ if c.onWebViewShown != nil {
724+ c.onWebViewShown(paneID)
725+ }
726+
689 // Update domain model with current URI for session snapshots727 // Update domain model with current URI for session snapshots
690 c.updatePaneURI(paneID, url)728 c.updatePaneURI(paneID, url)
691 729
M internal/ui/layout/gtk_widgets.go +66 -0
@@ -18,6 +18,7 @@ var (
1818 _ ButtonWidget = (*gtkButton)(nil)
1919 _ ImageWidget = (*gtkImage)(nil)
2020 _ ProgressBarWidget = (*gtkProgressBar)(nil)
21+ _ SpinnerWidget = (*gtkSpinner)(nil)
2122 _ WidgetFactory = (*GtkWidgetFactory)(nil)
2223 )
2324
@@ -687,6 +688,66 @@ func (p *gtkProgressBar) ComputePoint(target Widget) (x, y float64, ok bool) {
687688 func (p *gtkProgressBar) SetFraction(fraction float64) { p.inner.SetFraction(fraction) }
688689 func (p *gtkProgressBar) GetFraction() float64 { return p.inner.GetFraction() }
689690
691+// gtkSpinner wraps gtk.Spinner to implement SpinnerWidget.
692+type gtkSpinner struct {
693+ inner *gtk.Spinner
694+}
695+
696+func (s *gtkSpinner) Show() { s.inner.Show() }
697+func (s *gtkSpinner) Hide() { s.inner.Hide() }
698+func (s *gtkSpinner) SetVisible(visible bool) { s.inner.SetVisible(visible) }
699+func (s *gtkSpinner) IsVisible() bool { return s.inner.GetVisible() }
700+func (s *gtkSpinner) GrabFocus() bool { return s.inner.GrabFocus() }
701+func (s *gtkSpinner) HasFocus() bool { return s.inner.HasFocus() }
702+func (s *gtkSpinner) SetCanFocus(canFocus bool) { s.inner.SetCanFocus(canFocus) }
703+func (s *gtkSpinner) SetFocusOnClick(focus bool) { s.inner.SetFocusOnClick(focus) }
704+func (s *gtkSpinner) SetCanTarget(canTarget bool) { s.inner.SetCanTarget(canTarget) }
705+func (s *gtkSpinner) SetHexpand(expand bool) { s.inner.SetHexpand(expand) }
706+func (s *gtkSpinner) SetVexpand(expand bool) { s.inner.SetVexpand(expand) }
707+func (s *gtkSpinner) GetHexpand() bool { return s.inner.GetHexpand() }
708+func (s *gtkSpinner) GetVexpand() bool { return s.inner.GetVexpand() }
709+func (s *gtkSpinner) SetHalign(align gtk.Align) { s.inner.SetHalign(align) }
710+func (s *gtkSpinner) SetValign(align gtk.Align) { s.inner.SetValign(align) }
711+func (s *gtkSpinner) SetSizeRequest(w, h int) { s.inner.SetSizeRequest(w, h) }
712+func (s *gtkSpinner) AddCssClass(class string) { s.inner.AddCssClass(class) }
713+func (s *gtkSpinner) RemoveCssClass(class string) { s.inner.RemoveCssClass(class) }
714+func (s *gtkSpinner) HasCssClass(class string) bool { return s.inner.HasCssClass(class) }
715+func (s *gtkSpinner) Unparent() { s.inner.Unparent() }
716+func (s *gtkSpinner) GtkWidget() *gtk.Widget { return &s.inner.Widget }
717+
718+func (s *gtkSpinner) GetParent() Widget {
719+ parent := s.inner.GetParent()
720+ if parent == nil {
721+ return nil
722+ }
723+ return &gtkWidget{inner: parent}
724+}
725+
726+func (s *gtkSpinner) GetAllocatedWidth() int { return s.inner.GetAllocatedWidth() }
727+func (s *gtkSpinner) GetAllocatedHeight() int { return s.inner.GetAllocatedHeight() }
728+func (s *gtkSpinner) AddController(c *gtk.EventController) { s.inner.AddController(c) }
729+
730+func (s *gtkSpinner) ComputePoint(target Widget) (x, y float64, ok bool) {
731+ srcPoint := &graphene.Point{X: 0, Y: 0}
732+ outPoint := &graphene.Point{}
733+
734+ var targetGtk *gtk.Widget
735+ if target != nil {
736+ targetGtk = target.GtkWidget()
737+ }
738+
739+ ok = s.inner.ComputePoint(targetGtk, srcPoint, outPoint)
740+ if !ok {
741+ return 0, 0, false
742+ }
743+ return float64(outPoint.X), float64(outPoint.Y), true
744+}
745+
746+func (s *gtkSpinner) Start() { s.inner.Start() }
747+func (s *gtkSpinner) Stop() { s.inner.Stop() }
748+func (s *gtkSpinner) SetSpinning(spinning bool) { s.inner.SetSpinning(spinning) }
749+func (s *gtkSpinner) GetSpinning() bool { return s.inner.GetSpinning() }
750+
690751 // GtkWidgetFactory creates real GTK widgets.
691752 type GtkWidgetFactory struct{}
692753
@@ -736,6 +797,11 @@ func (f *GtkWidgetFactory) NewProgressBar() ProgressBarWidget {
736797 return &gtkProgressBar{inner: progressBar}
737798 }
738799
800+func (f *GtkWidgetFactory) NewSpinner() SpinnerWidget {
801+ spinner := gtk.NewSpinner()
802+ return &gtkSpinner{inner: spinner}
803+}
804+
739805 func (f *GtkWidgetFactory) WrapWidget(w *gtk.Widget) Widget {
740806 if w == nil {
741807 return nil
@@ -18,6 +18,7 @@ var (
18 _ ButtonWidget = (*gtkButton)(nil)18 _ ButtonWidget = (*gtkButton)(nil)
19 _ ImageWidget = (*gtkImage)(nil)19 _ ImageWidget = (*gtkImage)(nil)
20 _ ProgressBarWidget = (*gtkProgressBar)(nil)20 _ ProgressBarWidget = (*gtkProgressBar)(nil)
21+ _ SpinnerWidget = (*gtkSpinner)(nil)
21 _ WidgetFactory = (*GtkWidgetFactory)(nil)22 _ WidgetFactory = (*GtkWidgetFactory)(nil)
22 )23 )
23 24
@@ -687,6 +688,66 @@ func (p *gtkProgressBar) ComputePoint(target Widget) (x, y float64, ok bool) {
687 func (p *gtkProgressBar) SetFraction(fraction float64) { p.inner.SetFraction(fraction) }688 func (p *gtkProgressBar) SetFraction(fraction float64) { p.inner.SetFraction(fraction) }
688 func (p *gtkProgressBar) GetFraction() float64 { return p.inner.GetFraction() }689 func (p *gtkProgressBar) GetFraction() float64 { return p.inner.GetFraction() }
689 690
691+// gtkSpinner wraps gtk.Spinner to implement SpinnerWidget.
692+type gtkSpinner struct {
693+ inner *gtk.Spinner
694+}
695+
696+func (s *gtkSpinner) Show() { s.inner.Show() }
697+func (s *gtkSpinner) Hide() { s.inner.Hide() }
698+func (s *gtkSpinner) SetVisible(visible bool) { s.inner.SetVisible(visible) }
699+func (s *gtkSpinner) IsVisible() bool { return s.inner.GetVisible() }
700+func (s *gtkSpinner) GrabFocus() bool { return s.inner.GrabFocus() }
701+func (s *gtkSpinner) HasFocus() bool { return s.inner.HasFocus() }
702+func (s *gtkSpinner) SetCanFocus(canFocus bool) { s.inner.SetCanFocus(canFocus) }
703+func (s *gtkSpinner) SetFocusOnClick(focus bool) { s.inner.SetFocusOnClick(focus) }
704+func (s *gtkSpinner) SetCanTarget(canTarget bool) { s.inner.SetCanTarget(canTarget) }
705+func (s *gtkSpinner) SetHexpand(expand bool) { s.inner.SetHexpand(expand) }
706+func (s *gtkSpinner) SetVexpand(expand bool) { s.inner.SetVexpand(expand) }
707+func (s *gtkSpinner) GetHexpand() bool { return s.inner.GetHexpand() }
708+func (s *gtkSpinner) GetVexpand() bool { return s.inner.GetVexpand() }
709+func (s *gtkSpinner) SetHalign(align gtk.Align) { s.inner.SetHalign(align) }
710+func (s *gtkSpinner) SetValign(align gtk.Align) { s.inner.SetValign(align) }
711+func (s *gtkSpinner) SetSizeRequest(w, h int) { s.inner.SetSizeRequest(w, h) }
712+func (s *gtkSpinner) AddCssClass(class string) { s.inner.AddCssClass(class) }
713+func (s *gtkSpinner) RemoveCssClass(class string) { s.inner.RemoveCssClass(class) }
714+func (s *gtkSpinner) HasCssClass(class string) bool { return s.inner.HasCssClass(class) }
715+func (s *gtkSpinner) Unparent() { s.inner.Unparent() }
716+func (s *gtkSpinner) GtkWidget() *gtk.Widget { return &s.inner.Widget }
717+
718+func (s *gtkSpinner) GetParent() Widget {
719+ parent := s.inner.GetParent()
720+ if parent == nil {
721+ return nil
722+ }
723+ return &gtkWidget{inner: parent}
724+}
725+
726+func (s *gtkSpinner) GetAllocatedWidth() int { return s.inner.GetAllocatedWidth() }
727+func (s *gtkSpinner) GetAllocatedHeight() int { return s.inner.GetAllocatedHeight() }
728+func (s *gtkSpinner) AddController(c *gtk.EventController) { s.inner.AddController(c) }
729+
730+func (s *gtkSpinner) ComputePoint(target Widget) (x, y float64, ok bool) {
731+ srcPoint := &graphene.Point{X: 0, Y: 0}
732+ outPoint := &graphene.Point{}
733+
734+ var targetGtk *gtk.Widget
735+ if target != nil {
736+ targetGtk = target.GtkWidget()
737+ }
738+
739+ ok = s.inner.ComputePoint(targetGtk, srcPoint, outPoint)
740+ if !ok {
741+ return 0, 0, false
742+ }
743+ return float64(outPoint.X), float64(outPoint.Y), true
744+}
745+
746+func (s *gtkSpinner) Start() { s.inner.Start() }
747+func (s *gtkSpinner) Stop() { s.inner.Stop() }
748+func (s *gtkSpinner) SetSpinning(spinning bool) { s.inner.SetSpinning(spinning) }
749+func (s *gtkSpinner) GetSpinning() bool { return s.inner.GetSpinning() }
750+
690 // GtkWidgetFactory creates real GTK widgets.751 // GtkWidgetFactory creates real GTK widgets.
691 type GtkWidgetFactory struct{}752 type GtkWidgetFactory struct{}
692 753
@@ -736,6 +797,11 @@ func (f *GtkWidgetFactory) NewProgressBar() ProgressBarWidget {
736 return &gtkProgressBar{inner: progressBar}797 return &gtkProgressBar{inner: progressBar}
737 }798 }
738 799
800+func (f *GtkWidgetFactory) NewSpinner() SpinnerWidget {
801+ spinner := gtk.NewSpinner()
802+ return &gtkSpinner{inner: spinner}
803+}
804+
739 func (f *GtkWidgetFactory) WrapWidget(w *gtk.Widget) Widget {805 func (f *GtkWidgetFactory) WrapWidget(w *gtk.Widget) Widget {
740 if w == nil {806 if w == nil {
741 return nil807 return nil
M internal/ui/layout/mocks/mocks.go +1325 -0
@@ -11518,6 +11518,1285 @@ func (_c *MockProgressBarWidget_Unparent_Call) RunAndReturn(run func()) *MockPro
1151811518 return _c
1151911519 }
1152011520
11521+// NewMockSpinnerWidget creates a new instance of MockSpinnerWidget. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
11522+// The first argument is typically a *testing.T value.
11523+func NewMockSpinnerWidget(t interface {
11524+ mock.TestingT
11525+ Cleanup(func())
11526+}) *MockSpinnerWidget {
11527+ mock := &MockSpinnerWidget{}
11528+ mock.Mock.Test(t)
11529+
11530+ t.Cleanup(func() { mock.AssertExpectations(t) })
11531+
11532+ return mock
11533+}
11534+
11535+// MockSpinnerWidget is an autogenerated mock type for the SpinnerWidget type
11536+type MockSpinnerWidget struct {
11537+ mock.Mock
11538+}
11539+
11540+type MockSpinnerWidget_Expecter struct {
11541+ mock *mock.Mock
11542+}
11543+
11544+func (_m *MockSpinnerWidget) EXPECT() *MockSpinnerWidget_Expecter {
11545+ return &MockSpinnerWidget_Expecter{mock: &_m.Mock}
11546+}
11547+
11548+// AddController provides a mock function for the type MockSpinnerWidget
11549+func (_mock *MockSpinnerWidget) AddController(controller *gtk.EventController) {
11550+ _mock.Called(controller)
11551+ return
11552+}
11553+
11554+// MockSpinnerWidget_AddController_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddController'
11555+type MockSpinnerWidget_AddController_Call struct {
11556+ *mock.Call
11557+}
11558+
11559+// AddController is a helper method to define mock.On call
11560+// - controller *gtk.EventController
11561+func (_e *MockSpinnerWidget_Expecter) AddController(controller interface{}) *MockSpinnerWidget_AddController_Call {
11562+ return &MockSpinnerWidget_AddController_Call{Call: _e.mock.On("AddController", controller)}
11563+}
11564+
11565+func (_c *MockSpinnerWidget_AddController_Call) Run(run func(controller *gtk.EventController)) *MockSpinnerWidget_AddController_Call {
11566+ _c.Call.Run(func(args mock.Arguments) {
11567+ var arg0 *gtk.EventController
11568+ if args[0] != nil {
11569+ arg0 = args[0].(*gtk.EventController)
11570+ }
11571+ run(
11572+ arg0,
11573+ )
11574+ })
11575+ return _c
11576+}
11577+
11578+func (_c *MockSpinnerWidget_AddController_Call) Return() *MockSpinnerWidget_AddController_Call {
11579+ _c.Call.Return()
11580+ return _c
11581+}
11582+
11583+func (_c *MockSpinnerWidget_AddController_Call) RunAndReturn(run func(controller *gtk.EventController)) *MockSpinnerWidget_AddController_Call {
11584+ _c.Run(run)
11585+ return _c
11586+}
11587+
11588+// AddCssClass provides a mock function for the type MockSpinnerWidget
11589+func (_mock *MockSpinnerWidget) AddCssClass(cssClass string) {
11590+ _mock.Called(cssClass)
11591+ return
11592+}
11593+
11594+// MockSpinnerWidget_AddCssClass_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddCssClass'
11595+type MockSpinnerWidget_AddCssClass_Call struct {
11596+ *mock.Call
11597+}
11598+
11599+// AddCssClass is a helper method to define mock.On call
11600+// - cssClass string
11601+func (_e *MockSpinnerWidget_Expecter) AddCssClass(cssClass interface{}) *MockSpinnerWidget_AddCssClass_Call {
11602+ return &MockSpinnerWidget_AddCssClass_Call{Call: _e.mock.On("AddCssClass", cssClass)}
11603+}
11604+
11605+func (_c *MockSpinnerWidget_AddCssClass_Call) Run(run func(cssClass string)) *MockSpinnerWidget_AddCssClass_Call {
11606+ _c.Call.Run(func(args mock.Arguments) {
11607+ var arg0 string
11608+ if args[0] != nil {
11609+ arg0 = args[0].(string)
11610+ }
11611+ run(
11612+ arg0,
11613+ )
11614+ })
11615+ return _c
11616+}
11617+
11618+func (_c *MockSpinnerWidget_AddCssClass_Call) Return() *MockSpinnerWidget_AddCssClass_Call {
11619+ _c.Call.Return()
11620+ return _c
11621+}
11622+
11623+func (_c *MockSpinnerWidget_AddCssClass_Call) RunAndReturn(run func(cssClass string)) *MockSpinnerWidget_AddCssClass_Call {
11624+ _c.Run(run)
11625+ return _c
11626+}
11627+
11628+// ComputePoint provides a mock function for the type MockSpinnerWidget
11629+func (_mock *MockSpinnerWidget) ComputePoint(target layout.Widget) (float64, float64, bool) {
11630+ ret := _mock.Called(target)
11631+
11632+ if len(ret) == 0 {
11633+ panic("no return value specified for ComputePoint")
11634+ }
11635+
11636+ var r0 float64
11637+ var r1 float64
11638+ var r2 bool
11639+ if returnFunc, ok := ret.Get(0).(func(layout.Widget) (float64, float64, bool)); ok {
11640+ return returnFunc(target)
11641+ }
11642+ if returnFunc, ok := ret.Get(0).(func(layout.Widget) float64); ok {
11643+ r0 = returnFunc(target)
11644+ } else {
11645+ r0 = ret.Get(0).(float64)
11646+ }
11647+ if returnFunc, ok := ret.Get(1).(func(layout.Widget) float64); ok {
11648+ r1 = returnFunc(target)
11649+ } else {
11650+ r1 = ret.Get(1).(float64)
11651+ }
11652+ if returnFunc, ok := ret.Get(2).(func(layout.Widget) bool); ok {
11653+ r2 = returnFunc(target)
11654+ } else {
11655+ r2 = ret.Get(2).(bool)
11656+ }
11657+ return r0, r1, r2
11658+}
11659+
11660+// MockSpinnerWidget_ComputePoint_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ComputePoint'
11661+type MockSpinnerWidget_ComputePoint_Call struct {
11662+ *mock.Call
11663+}
11664+
11665+// ComputePoint is a helper method to define mock.On call
11666+// - target layout.Widget
11667+func (_e *MockSpinnerWidget_Expecter) ComputePoint(target interface{}) *MockSpinnerWidget_ComputePoint_Call {
11668+ return &MockSpinnerWidget_ComputePoint_Call{Call: _e.mock.On("ComputePoint", target)}
11669+}
11670+
11671+func (_c *MockSpinnerWidget_ComputePoint_Call) Run(run func(target layout.Widget)) *MockSpinnerWidget_ComputePoint_Call {
11672+ _c.Call.Run(func(args mock.Arguments) {
11673+ var arg0 layout.Widget
11674+ if args[0] != nil {
11675+ arg0 = args[0].(layout.Widget)
11676+ }
11677+ run(
11678+ arg0,
11679+ )
11680+ })
11681+ return _c
11682+}
11683+
11684+func (_c *MockSpinnerWidget_ComputePoint_Call) Return(x float64, y float64, ok bool) *MockSpinnerWidget_ComputePoint_Call {
11685+ _c.Call.Return(x, y, ok)
11686+ return _c
11687+}
11688+
11689+func (_c *MockSpinnerWidget_ComputePoint_Call) RunAndReturn(run func(target layout.Widget) (float64, float64, bool)) *MockSpinnerWidget_ComputePoint_Call {
11690+ _c.Call.Return(run)
11691+ return _c
11692+}
11693+
11694+// GetAllocatedHeight provides a mock function for the type MockSpinnerWidget
11695+func (_mock *MockSpinnerWidget) GetAllocatedHeight() int {
11696+ ret := _mock.Called()
11697+
11698+ if len(ret) == 0 {
11699+ panic("no return value specified for GetAllocatedHeight")
11700+ }
11701+
11702+ var r0 int
11703+ if returnFunc, ok := ret.Get(0).(func() int); ok {
11704+ r0 = returnFunc()
11705+ } else {
11706+ r0 = ret.Get(0).(int)
11707+ }
11708+ return r0
11709+}
11710+
11711+// MockSpinnerWidget_GetAllocatedHeight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllocatedHeight'
11712+type MockSpinnerWidget_GetAllocatedHeight_Call struct {
11713+ *mock.Call
11714+}
11715+
11716+// GetAllocatedHeight is a helper method to define mock.On call
11717+func (_e *MockSpinnerWidget_Expecter) GetAllocatedHeight() *MockSpinnerWidget_GetAllocatedHeight_Call {
11718+ return &MockSpinnerWidget_GetAllocatedHeight_Call{Call: _e.mock.On("GetAllocatedHeight")}
11719+}
11720+
11721+func (_c *MockSpinnerWidget_GetAllocatedHeight_Call) Run(run func()) *MockSpinnerWidget_GetAllocatedHeight_Call {
11722+ _c.Call.Run(func(args mock.Arguments) {
11723+ run()
11724+ })
11725+ return _c
11726+}
11727+
11728+func (_c *MockSpinnerWidget_GetAllocatedHeight_Call) Return(n int) *MockSpinnerWidget_GetAllocatedHeight_Call {
11729+ _c.Call.Return(n)
11730+ return _c
11731+}
11732+
11733+func (_c *MockSpinnerWidget_GetAllocatedHeight_Call) RunAndReturn(run func() int) *MockSpinnerWidget_GetAllocatedHeight_Call {
11734+ _c.Call.Return(run)
11735+ return _c
11736+}
11737+
11738+// GetAllocatedWidth provides a mock function for the type MockSpinnerWidget
11739+func (_mock *MockSpinnerWidget) GetAllocatedWidth() int {
11740+ ret := _mock.Called()
11741+
11742+ if len(ret) == 0 {
11743+ panic("no return value specified for GetAllocatedWidth")
11744+ }
11745+
11746+ var r0 int
11747+ if returnFunc, ok := ret.Get(0).(func() int); ok {
11748+ r0 = returnFunc()
11749+ } else {
11750+ r0 = ret.Get(0).(int)
11751+ }
11752+ return r0
11753+}
11754+
11755+// MockSpinnerWidget_GetAllocatedWidth_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllocatedWidth'
11756+type MockSpinnerWidget_GetAllocatedWidth_Call struct {
11757+ *mock.Call
11758+}
11759+
11760+// GetAllocatedWidth is a helper method to define mock.On call
11761+func (_e *MockSpinnerWidget_Expecter) GetAllocatedWidth() *MockSpinnerWidget_GetAllocatedWidth_Call {
11762+ return &MockSpinnerWidget_GetAllocatedWidth_Call{Call: _e.mock.On("GetAllocatedWidth")}
11763+}
11764+
11765+func (_c *MockSpinnerWidget_GetAllocatedWidth_Call) Run(run func()) *MockSpinnerWidget_GetAllocatedWidth_Call {
11766+ _c.Call.Run(func(args mock.Arguments) {
11767+ run()
11768+ })
11769+ return _c
11770+}
11771+
11772+func (_c *MockSpinnerWidget_GetAllocatedWidth_Call) Return(n int) *MockSpinnerWidget_GetAllocatedWidth_Call {
11773+ _c.Call.Return(n)
11774+ return _c
11775+}
11776+
11777+func (_c *MockSpinnerWidget_GetAllocatedWidth_Call) RunAndReturn(run func() int) *MockSpinnerWidget_GetAllocatedWidth_Call {
11778+ _c.Call.Return(run)
11779+ return _c
11780+}
11781+
11782+// GetHexpand provides a mock function for the type MockSpinnerWidget
11783+func (_mock *MockSpinnerWidget) GetHexpand() bool {
11784+ ret := _mock.Called()
11785+
11786+ if len(ret) == 0 {
11787+ panic("no return value specified for GetHexpand")
11788+ }
11789+
11790+ var r0 bool
11791+ if returnFunc, ok := ret.Get(0).(func() bool); ok {
11792+ r0 = returnFunc()
11793+ } else {
11794+ r0 = ret.Get(0).(bool)
11795+ }
11796+ return r0
11797+}
11798+
11799+// MockSpinnerWidget_GetHexpand_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetHexpand'
11800+type MockSpinnerWidget_GetHexpand_Call struct {
11801+ *mock.Call
11802+}
11803+
11804+// GetHexpand is a helper method to define mock.On call
11805+func (_e *MockSpinnerWidget_Expecter) GetHexpand() *MockSpinnerWidget_GetHexpand_Call {
11806+ return &MockSpinnerWidget_GetHexpand_Call{Call: _e.mock.On("GetHexpand")}
11807+}
11808+
11809+func (_c *MockSpinnerWidget_GetHexpand_Call) Run(run func()) *MockSpinnerWidget_GetHexpand_Call {
11810+ _c.Call.Run(func(args mock.Arguments) {
11811+ run()
11812+ })
11813+ return _c
11814+}
11815+
11816+func (_c *MockSpinnerWidget_GetHexpand_Call) Return(b bool) *MockSpinnerWidget_GetHexpand_Call {
11817+ _c.Call.Return(b)
11818+ return _c
11819+}
11820+
11821+func (_c *MockSpinnerWidget_GetHexpand_Call) RunAndReturn(run func() bool) *MockSpinnerWidget_GetHexpand_Call {
11822+ _c.Call.Return(run)
11823+ return _c
11824+}
11825+
11826+// GetParent provides a mock function for the type MockSpinnerWidget
11827+func (_mock *MockSpinnerWidget) GetParent() layout.Widget {
11828+ ret := _mock.Called()
11829+
11830+ if len(ret) == 0 {
11831+ panic("no return value specified for GetParent")
11832+ }
11833+
11834+ var r0 layout.Widget
11835+ if returnFunc, ok := ret.Get(0).(func() layout.Widget); ok {
11836+ r0 = returnFunc()
11837+ } else {
11838+ if ret.Get(0) != nil {
11839+ r0 = ret.Get(0).(layout.Widget)
11840+ }
11841+ }
11842+ return r0
11843+}
11844+
11845+// MockSpinnerWidget_GetParent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetParent'
11846+type MockSpinnerWidget_GetParent_Call struct {
11847+ *mock.Call
11848+}
11849+
11850+// GetParent is a helper method to define mock.On call
11851+func (_e *MockSpinnerWidget_Expecter) GetParent() *MockSpinnerWidget_GetParent_Call {
11852+ return &MockSpinnerWidget_GetParent_Call{Call: _e.mock.On("GetParent")}
11853+}
11854+
11855+func (_c *MockSpinnerWidget_GetParent_Call) Run(run func()) *MockSpinnerWidget_GetParent_Call {
11856+ _c.Call.Run(func(args mock.Arguments) {
11857+ run()
11858+ })
11859+ return _c
11860+}
11861+
11862+func (_c *MockSpinnerWidget_GetParent_Call) Return(widget layout.Widget) *MockSpinnerWidget_GetParent_Call {
11863+ _c.Call.Return(widget)
11864+ return _c
11865+}
11866+
11867+func (_c *MockSpinnerWidget_GetParent_Call) RunAndReturn(run func() layout.Widget) *MockSpinnerWidget_GetParent_Call {
11868+ _c.Call.Return(run)
11869+ return _c
11870+}
11871+
11872+// GetSpinning provides a mock function for the type MockSpinnerWidget
11873+func (_mock *MockSpinnerWidget) GetSpinning() bool {
11874+ ret := _mock.Called()
11875+
11876+ if len(ret) == 0 {
11877+ panic("no return value specified for GetSpinning")
11878+ }
11879+
11880+ var r0 bool
11881+ if returnFunc, ok := ret.Get(0).(func() bool); ok {
11882+ r0 = returnFunc()
11883+ } else {
11884+ r0 = ret.Get(0).(bool)
11885+ }
11886+ return r0
11887+}
11888+
11889+// MockSpinnerWidget_GetSpinning_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSpinning'
11890+type MockSpinnerWidget_GetSpinning_Call struct {
11891+ *mock.Call
11892+}
11893+
11894+// GetSpinning is a helper method to define mock.On call
11895+func (_e *MockSpinnerWidget_Expecter) GetSpinning() *MockSpinnerWidget_GetSpinning_Call {
11896+ return &MockSpinnerWidget_GetSpinning_Call{Call: _e.mock.On("GetSpinning")}
11897+}
11898+
11899+func (_c *MockSpinnerWidget_GetSpinning_Call) Run(run func()) *MockSpinnerWidget_GetSpinning_Call {
11900+ _c.Call.Run(func(args mock.Arguments) {
11901+ run()
11902+ })
11903+ return _c
11904+}
11905+
11906+func (_c *MockSpinnerWidget_GetSpinning_Call) Return(b bool) *MockSpinnerWidget_GetSpinning_Call {
11907+ _c.Call.Return(b)
11908+ return _c
11909+}
11910+
11911+func (_c *MockSpinnerWidget_GetSpinning_Call) RunAndReturn(run func() bool) *MockSpinnerWidget_GetSpinning_Call {
11912+ _c.Call.Return(run)
11913+ return _c
11914+}
11915+
11916+// GetVexpand provides a mock function for the type MockSpinnerWidget
11917+func (_mock *MockSpinnerWidget) GetVexpand() bool {
11918+ ret := _mock.Called()
11919+
11920+ if len(ret) == 0 {
11921+ panic("no return value specified for GetVexpand")
11922+ }
11923+
11924+ var r0 bool
11925+ if returnFunc, ok := ret.Get(0).(func() bool); ok {
11926+ r0 = returnFunc()
11927+ } else {
11928+ r0 = ret.Get(0).(bool)
11929+ }
11930+ return r0
11931+}
11932+
11933+// MockSpinnerWidget_GetVexpand_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetVexpand'
11934+type MockSpinnerWidget_GetVexpand_Call struct {
11935+ *mock.Call
11936+}
11937+
11938+// GetVexpand is a helper method to define mock.On call
11939+func (_e *MockSpinnerWidget_Expecter) GetVexpand() *MockSpinnerWidget_GetVexpand_Call {
11940+ return &MockSpinnerWidget_GetVexpand_Call{Call: _e.mock.On("GetVexpand")}
11941+}
11942+
11943+func (_c *MockSpinnerWidget_GetVexpand_Call) Run(run func()) *MockSpinnerWidget_GetVexpand_Call {
11944+ _c.Call.Run(func(args mock.Arguments) {
11945+ run()
11946+ })
11947+ return _c
11948+}
11949+
11950+func (_c *MockSpinnerWidget_GetVexpand_Call) Return(b bool) *MockSpinnerWidget_GetVexpand_Call {
11951+ _c.Call.Return(b)
11952+ return _c
11953+}
11954+
11955+func (_c *MockSpinnerWidget_GetVexpand_Call) RunAndReturn(run func() bool) *MockSpinnerWidget_GetVexpand_Call {
11956+ _c.Call.Return(run)
11957+ return _c
11958+}
11959+
11960+// GrabFocus provides a mock function for the type MockSpinnerWidget
11961+func (_mock *MockSpinnerWidget) GrabFocus() bool {
11962+ ret := _mock.Called()
11963+
11964+ if len(ret) == 0 {
11965+ panic("no return value specified for GrabFocus")
11966+ }
11967+
11968+ var r0 bool
11969+ if returnFunc, ok := ret.Get(0).(func() bool); ok {
11970+ r0 = returnFunc()
11971+ } else {
11972+ r0 = ret.Get(0).(bool)
11973+ }
11974+ return r0
11975+}
11976+
11977+// MockSpinnerWidget_GrabFocus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GrabFocus'
11978+type MockSpinnerWidget_GrabFocus_Call struct {
11979+ *mock.Call
11980+}
11981+
11982+// GrabFocus is a helper method to define mock.On call
11983+func (_e *MockSpinnerWidget_Expecter) GrabFocus() *MockSpinnerWidget_GrabFocus_Call {
11984+ return &MockSpinnerWidget_GrabFocus_Call{Call: _e.mock.On("GrabFocus")}
11985+}
11986+
11987+func (_c *MockSpinnerWidget_GrabFocus_Call) Run(run func()) *MockSpinnerWidget_GrabFocus_Call {
11988+ _c.Call.Run(func(args mock.Arguments) {
11989+ run()
11990+ })
11991+ return _c
11992+}
11993+
11994+func (_c *MockSpinnerWidget_GrabFocus_Call) Return(b bool) *MockSpinnerWidget_GrabFocus_Call {
11995+ _c.Call.Return(b)
11996+ return _c
11997+}
11998+
11999+func (_c *MockSpinnerWidget_GrabFocus_Call) RunAndReturn(run func() bool) *MockSpinnerWidget_GrabFocus_Call {
12000+ _c.Call.Return(run)
12001+ return _c
12002+}
12003+
12004+// GtkWidget provides a mock function for the type MockSpinnerWidget
12005+func (_mock *MockSpinnerWidget) GtkWidget() *gtk.Widget {
12006+ ret := _mock.Called()
12007+
12008+ if len(ret) == 0 {
12009+ panic("no return value specified for GtkWidget")
12010+ }
12011+
12012+ var r0 *gtk.Widget
12013+ if returnFunc, ok := ret.Get(0).(func() *gtk.Widget); ok {
12014+ r0 = returnFunc()
12015+ } else {
12016+ if ret.Get(0) != nil {
12017+ r0 = ret.Get(0).(*gtk.Widget)
12018+ }
12019+ }
12020+ return r0
12021+}
12022+
12023+// MockSpinnerWidget_GtkWidget_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GtkWidget'
12024+type MockSpinnerWidget_GtkWidget_Call struct {
12025+ *mock.Call
12026+}
12027+
12028+// GtkWidget is a helper method to define mock.On call
12029+func (_e *MockSpinnerWidget_Expecter) GtkWidget() *MockSpinnerWidget_GtkWidget_Call {
12030+ return &MockSpinnerWidget_GtkWidget_Call{Call: _e.mock.On("GtkWidget")}
12031+}
12032+
12033+func (_c *MockSpinnerWidget_GtkWidget_Call) Run(run func()) *MockSpinnerWidget_GtkWidget_Call {
12034+ _c.Call.Run(func(args mock.Arguments) {
12035+ run()
12036+ })
12037+ return _c
12038+}
12039+
12040+func (_c *MockSpinnerWidget_GtkWidget_Call) Return(widget *gtk.Widget) *MockSpinnerWidget_GtkWidget_Call {
12041+ _c.Call.Return(widget)
12042+ return _c
12043+}
12044+
12045+func (_c *MockSpinnerWidget_GtkWidget_Call) RunAndReturn(run func() *gtk.Widget) *MockSpinnerWidget_GtkWidget_Call {
12046+ _c.Call.Return(run)
12047+ return _c
12048+}
12049+
12050+// HasCssClass provides a mock function for the type MockSpinnerWidget
12051+func (_mock *MockSpinnerWidget) HasCssClass(cssClass string) bool {
12052+ ret := _mock.Called(cssClass)
12053+
12054+ if len(ret) == 0 {
12055+ panic("no return value specified for HasCssClass")
12056+ }
12057+
12058+ var r0 bool
12059+ if returnFunc, ok := ret.Get(0).(func(string) bool); ok {
12060+ r0 = returnFunc(cssClass)
12061+ } else {
12062+ r0 = ret.Get(0).(bool)
12063+ }
12064+ return r0
12065+}
12066+
12067+// MockSpinnerWidget_HasCssClass_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasCssClass'
12068+type MockSpinnerWidget_HasCssClass_Call struct {
12069+ *mock.Call
12070+}
12071+
12072+// HasCssClass is a helper method to define mock.On call
12073+// - cssClass string
12074+func (_e *MockSpinnerWidget_Expecter) HasCssClass(cssClass interface{}) *MockSpinnerWidget_HasCssClass_Call {
12075+ return &MockSpinnerWidget_HasCssClass_Call{Call: _e.mock.On("HasCssClass", cssClass)}
12076+}
12077+
12078+func (_c *MockSpinnerWidget_HasCssClass_Call) Run(run func(cssClass string)) *MockSpinnerWidget_HasCssClass_Call {
12079+ _c.Call.Run(func(args mock.Arguments) {
12080+ var arg0 string
12081+ if args[0] != nil {
12082+ arg0 = args[0].(string)
12083+ }
12084+ run(
12085+ arg0,
12086+ )
12087+ })
12088+ return _c
12089+}
12090+
12091+func (_c *MockSpinnerWidget_HasCssClass_Call) Return(b bool) *MockSpinnerWidget_HasCssClass_Call {
12092+ _c.Call.Return(b)
12093+ return _c
12094+}
12095+
12096+func (_c *MockSpinnerWidget_HasCssClass_Call) RunAndReturn(run func(cssClass string) bool) *MockSpinnerWidget_HasCssClass_Call {
12097+ _c.Call.Return(run)
12098+ return _c
12099+}
12100+
12101+// HasFocus provides a mock function for the type MockSpinnerWidget
12102+func (_mock *MockSpinnerWidget) HasFocus() bool {
12103+ ret := _mock.Called()
12104+
12105+ if len(ret) == 0 {
12106+ panic("no return value specified for HasFocus")
12107+ }
12108+
12109+ var r0 bool
12110+ if returnFunc, ok := ret.Get(0).(func() bool); ok {
12111+ r0 = returnFunc()
12112+ } else {
12113+ r0 = ret.Get(0).(bool)
12114+ }
12115+ return r0
12116+}
12117+
12118+// MockSpinnerWidget_HasFocus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasFocus'
12119+type MockSpinnerWidget_HasFocus_Call struct {
12120+ *mock.Call
12121+}
12122+
12123+// HasFocus is a helper method to define mock.On call
12124+func (_e *MockSpinnerWidget_Expecter) HasFocus() *MockSpinnerWidget_HasFocus_Call {
12125+ return &MockSpinnerWidget_HasFocus_Call{Call: _e.mock.On("HasFocus")}
12126+}
12127+
12128+func (_c *MockSpinnerWidget_HasFocus_Call) Run(run func()) *MockSpinnerWidget_HasFocus_Call {
12129+ _c.Call.Run(func(args mock.Arguments) {
12130+ run()
12131+ })
12132+ return _c
12133+}
12134+
12135+func (_c *MockSpinnerWidget_HasFocus_Call) Return(b bool) *MockSpinnerWidget_HasFocus_Call {
12136+ _c.Call.Return(b)
12137+ return _c
12138+}
12139+
12140+func (_c *MockSpinnerWidget_HasFocus_Call) RunAndReturn(run func() bool) *MockSpinnerWidget_HasFocus_Call {
12141+ _c.Call.Return(run)
12142+ return _c
12143+}
12144+
12145+// Hide provides a mock function for the type MockSpinnerWidget
12146+func (_mock *MockSpinnerWidget) Hide() {
12147+ _mock.Called()
12148+ return
12149+}
12150+
12151+// MockSpinnerWidget_Hide_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Hide'
12152+type MockSpinnerWidget_Hide_Call struct {
12153+ *mock.Call
12154+}
12155+
12156+// Hide is a helper method to define mock.On call
12157+func (_e *MockSpinnerWidget_Expecter) Hide() *MockSpinnerWidget_Hide_Call {
12158+ return &MockSpinnerWidget_Hide_Call{Call: _e.mock.On("Hide")}
12159+}
12160+
12161+func (_c *MockSpinnerWidget_Hide_Call) Run(run func()) *MockSpinnerWidget_Hide_Call {
12162+ _c.Call.Run(func(args mock.Arguments) {
12163+ run()
12164+ })
12165+ return _c
12166+}
12167+
12168+func (_c *MockSpinnerWidget_Hide_Call) Return() *MockSpinnerWidget_Hide_Call {
12169+ _c.Call.Return()
12170+ return _c
12171+}
12172+
12173+func (_c *MockSpinnerWidget_Hide_Call) RunAndReturn(run func()) *MockSpinnerWidget_Hide_Call {
12174+ _c.Run(run)
12175+ return _c
12176+}
12177+
12178+// IsVisible provides a mock function for the type MockSpinnerWidget
12179+func (_mock *MockSpinnerWidget) IsVisible() bool {
12180+ ret := _mock.Called()
12181+
12182+ if len(ret) == 0 {
12183+ panic("no return value specified for IsVisible")
12184+ }
12185+
12186+ var r0 bool
12187+ if returnFunc, ok := ret.Get(0).(func() bool); ok {
12188+ r0 = returnFunc()
12189+ } else {
12190+ r0 = ret.Get(0).(bool)
12191+ }
12192+ return r0
12193+}
12194+
12195+// MockSpinnerWidget_IsVisible_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsVisible'
12196+type MockSpinnerWidget_IsVisible_Call struct {
12197+ *mock.Call
12198+}
12199+
12200+// IsVisible is a helper method to define mock.On call
12201+func (_e *MockSpinnerWidget_Expecter) IsVisible() *MockSpinnerWidget_IsVisible_Call {
12202+ return &MockSpinnerWidget_IsVisible_Call{Call: _e.mock.On("IsVisible")}
12203+}
12204+
12205+func (_c *MockSpinnerWidget_IsVisible_Call) Run(run func()) *MockSpinnerWidget_IsVisible_Call {
12206+ _c.Call.Run(func(args mock.Arguments) {
12207+ run()
12208+ })
12209+ return _c
12210+}
12211+
12212+func (_c *MockSpinnerWidget_IsVisible_Call) Return(b bool) *MockSpinnerWidget_IsVisible_Call {
12213+ _c.Call.Return(b)
12214+ return _c
12215+}
12216+
12217+func (_c *MockSpinnerWidget_IsVisible_Call) RunAndReturn(run func() bool) *MockSpinnerWidget_IsVisible_Call {
12218+ _c.Call.Return(run)
12219+ return _c
12220+}
12221+
12222+// RemoveCssClass provides a mock function for the type MockSpinnerWidget
12223+func (_mock *MockSpinnerWidget) RemoveCssClass(cssClass string) {
12224+ _mock.Called(cssClass)
12225+ return
12226+}
12227+
12228+// MockSpinnerWidget_RemoveCssClass_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveCssClass'
12229+type MockSpinnerWidget_RemoveCssClass_Call struct {
12230+ *mock.Call
12231+}
12232+
12233+// RemoveCssClass is a helper method to define mock.On call
12234+// - cssClass string
12235+func (_e *MockSpinnerWidget_Expecter) RemoveCssClass(cssClass interface{}) *MockSpinnerWidget_RemoveCssClass_Call {
12236+ return &MockSpinnerWidget_RemoveCssClass_Call{Call: _e.mock.On("RemoveCssClass", cssClass)}
12237+}
12238+
12239+func (_c *MockSpinnerWidget_RemoveCssClass_Call) Run(run func(cssClass string)) *MockSpinnerWidget_RemoveCssClass_Call {
12240+ _c.Call.Run(func(args mock.Arguments) {
12241+ var arg0 string
12242+ if args[0] != nil {
12243+ arg0 = args[0].(string)
12244+ }
12245+ run(
12246+ arg0,
12247+ )
12248+ })
12249+ return _c
12250+}
12251+
12252+func (_c *MockSpinnerWidget_RemoveCssClass_Call) Return() *MockSpinnerWidget_RemoveCssClass_Call {
12253+ _c.Call.Return()
12254+ return _c
12255+}
12256+
12257+func (_c *MockSpinnerWidget_RemoveCssClass_Call) RunAndReturn(run func(cssClass string)) *MockSpinnerWidget_RemoveCssClass_Call {
12258+ _c.Run(run)
12259+ return _c
12260+}
12261+
12262+// SetCanFocus provides a mock function for the type MockSpinnerWidget
12263+func (_mock *MockSpinnerWidget) SetCanFocus(canFocus bool) {
12264+ _mock.Called(canFocus)
12265+ return
12266+}
12267+
12268+// MockSpinnerWidget_SetCanFocus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetCanFocus'
12269+type MockSpinnerWidget_SetCanFocus_Call struct {
12270+ *mock.Call
12271+}
12272+
12273+// SetCanFocus is a helper method to define mock.On call
12274+// - canFocus bool
12275+func (_e *MockSpinnerWidget_Expecter) SetCanFocus(canFocus interface{}) *MockSpinnerWidget_SetCanFocus_Call {
12276+ return &MockSpinnerWidget_SetCanFocus_Call{Call: _e.mock.On("SetCanFocus", canFocus)}
12277+}
12278+
12279+func (_c *MockSpinnerWidget_SetCanFocus_Call) Run(run func(canFocus bool)) *MockSpinnerWidget_SetCanFocus_Call {
12280+ _c.Call.Run(func(args mock.Arguments) {
12281+ var arg0 bool
12282+ if args[0] != nil {
12283+ arg0 = args[0].(bool)
12284+ }
12285+ run(
12286+ arg0,
12287+ )
12288+ })
12289+ return _c
12290+}
12291+
12292+func (_c *MockSpinnerWidget_SetCanFocus_Call) Return() *MockSpinnerWidget_SetCanFocus_Call {
12293+ _c.Call.Return()
12294+ return _c
12295+}
12296+
12297+func (_c *MockSpinnerWidget_SetCanFocus_Call) RunAndReturn(run func(canFocus bool)) *MockSpinnerWidget_SetCanFocus_Call {
12298+ _c.Run(run)
12299+ return _c
12300+}
12301+
12302+// SetCanTarget provides a mock function for the type MockSpinnerWidget
12303+func (_mock *MockSpinnerWidget) SetCanTarget(canTarget bool) {
12304+ _mock.Called(canTarget)
12305+ return
12306+}
12307+
12308+// MockSpinnerWidget_SetCanTarget_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetCanTarget'
12309+type MockSpinnerWidget_SetCanTarget_Call struct {
12310+ *mock.Call
12311+}
12312+
12313+// SetCanTarget is a helper method to define mock.On call
12314+// - canTarget bool
12315+func (_e *MockSpinnerWidget_Expecter) SetCanTarget(canTarget interface{}) *MockSpinnerWidget_SetCanTarget_Call {
12316+ return &MockSpinnerWidget_SetCanTarget_Call{Call: _e.mock.On("SetCanTarget", canTarget)}
12317+}
12318+
12319+func (_c *MockSpinnerWidget_SetCanTarget_Call) Run(run func(canTarget bool)) *MockSpinnerWidget_SetCanTarget_Call {
12320+ _c.Call.Run(func(args mock.Arguments) {
12321+ var arg0 bool
12322+ if args[0] != nil {
12323+ arg0 = args[0].(bool)
12324+ }
12325+ run(
12326+ arg0,
12327+ )
12328+ })
12329+ return _c
12330+}
12331+
12332+func (_c *MockSpinnerWidget_SetCanTarget_Call) Return() *MockSpinnerWidget_SetCanTarget_Call {
12333+ _c.Call.Return()
12334+ return _c
12335+}
12336+
12337+func (_c *MockSpinnerWidget_SetCanTarget_Call) RunAndReturn(run func(canTarget bool)) *MockSpinnerWidget_SetCanTarget_Call {
12338+ _c.Run(run)
12339+ return _c
12340+}
12341+
12342+// SetFocusOnClick provides a mock function for the type MockSpinnerWidget
12343+func (_mock *MockSpinnerWidget) SetFocusOnClick(focusOnClick bool) {
12344+ _mock.Called(focusOnClick)
12345+ return
12346+}
12347+
12348+// MockSpinnerWidget_SetFocusOnClick_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetFocusOnClick'
12349+type MockSpinnerWidget_SetFocusOnClick_Call struct {
12350+ *mock.Call
12351+}
12352+
12353+// SetFocusOnClick is a helper method to define mock.On call
12354+// - focusOnClick bool
12355+func (_e *MockSpinnerWidget_Expecter) SetFocusOnClick(focusOnClick interface{}) *MockSpinnerWidget_SetFocusOnClick_Call {
12356+ return &MockSpinnerWidget_SetFocusOnClick_Call{Call: _e.mock.On("SetFocusOnClick", focusOnClick)}
12357+}
12358+
12359+func (_c *MockSpinnerWidget_SetFocusOnClick_Call) Run(run func(focusOnClick bool)) *MockSpinnerWidget_SetFocusOnClick_Call {
12360+ _c.Call.Run(func(args mock.Arguments) {
12361+ var arg0 bool
12362+ if args[0] != nil {
12363+ arg0 = args[0].(bool)
12364+ }
12365+ run(
12366+ arg0,
12367+ )
12368+ })
12369+ return _c
12370+}
12371+
12372+func (_c *MockSpinnerWidget_SetFocusOnClick_Call) Return() *MockSpinnerWidget_SetFocusOnClick_Call {
12373+ _c.Call.Return()
12374+ return _c
12375+}
12376+
12377+func (_c *MockSpinnerWidget_SetFocusOnClick_Call) RunAndReturn(run func(focusOnClick bool)) *MockSpinnerWidget_SetFocusOnClick_Call {
12378+ _c.Run(run)
12379+ return _c
12380+}
12381+
12382+// SetHalign provides a mock function for the type MockSpinnerWidget
12383+func (_mock *MockSpinnerWidget) SetHalign(align gtk.Align) {
12384+ _mock.Called(align)
12385+ return
12386+}
12387+
12388+// MockSpinnerWidget_SetHalign_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetHalign'
12389+type MockSpinnerWidget_SetHalign_Call struct {
12390+ *mock.Call
12391+}
12392+
12393+// SetHalign is a helper method to define mock.On call
12394+// - align gtk.Align
12395+func (_e *MockSpinnerWidget_Expecter) SetHalign(align interface{}) *MockSpinnerWidget_SetHalign_Call {
12396+ return &MockSpinnerWidget_SetHalign_Call{Call: _e.mock.On("SetHalign", align)}
12397+}
12398+
12399+func (_c *MockSpinnerWidget_SetHalign_Call) Run(run func(align gtk.Align)) *MockSpinnerWidget_SetHalign_Call {
12400+ _c.Call.Run(func(args mock.Arguments) {
12401+ var arg0 gtk.Align
12402+ if args[0] != nil {
12403+ arg0 = args[0].(gtk.Align)
12404+ }
12405+ run(
12406+ arg0,
12407+ )
12408+ })
12409+ return _c
12410+}
12411+
12412+func (_c *MockSpinnerWidget_SetHalign_Call) Return() *MockSpinnerWidget_SetHalign_Call {
12413+ _c.Call.Return()
12414+ return _c
12415+}
12416+
12417+func (_c *MockSpinnerWidget_SetHalign_Call) RunAndReturn(run func(align gtk.Align)) *MockSpinnerWidget_SetHalign_Call {
12418+ _c.Run(run)
12419+ return _c
12420+}
12421+
12422+// SetHexpand provides a mock function for the type MockSpinnerWidget
12423+func (_mock *MockSpinnerWidget) SetHexpand(expand bool) {
12424+ _mock.Called(expand)
12425+ return
12426+}
12427+
12428+// MockSpinnerWidget_SetHexpand_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetHexpand'
12429+type MockSpinnerWidget_SetHexpand_Call struct {
12430+ *mock.Call
12431+}
12432+
12433+// SetHexpand is a helper method to define mock.On call
12434+// - expand bool
12435+func (_e *MockSpinnerWidget_Expecter) SetHexpand(expand interface{}) *MockSpinnerWidget_SetHexpand_Call {
12436+ return &MockSpinnerWidget_SetHexpand_Call{Call: _e.mock.On("SetHexpand", expand)}
12437+}
12438+
12439+func (_c *MockSpinnerWidget_SetHexpand_Call) Run(run func(expand bool)) *MockSpinnerWidget_SetHexpand_Call {
12440+ _c.Call.Run(func(args mock.Arguments) {
12441+ var arg0 bool
12442+ if args[0] != nil {
12443+ arg0 = args[0].(bool)
12444+ }
12445+ run(
12446+ arg0,
12447+ )
12448+ })
12449+ return _c
12450+}
12451+
12452+func (_c *MockSpinnerWidget_SetHexpand_Call) Return() *MockSpinnerWidget_SetHexpand_Call {
12453+ _c.Call.Return()
12454+ return _c
12455+}
12456+
12457+func (_c *MockSpinnerWidget_SetHexpand_Call) RunAndReturn(run func(expand bool)) *MockSpinnerWidget_SetHexpand_Call {
12458+ _c.Run(run)
12459+ return _c
12460+}
12461+
12462+// SetSizeRequest provides a mock function for the type MockSpinnerWidget
12463+func (_mock *MockSpinnerWidget) SetSizeRequest(width int, height int) {
12464+ _mock.Called(width, height)
12465+ return
12466+}
12467+
12468+// MockSpinnerWidget_SetSizeRequest_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetSizeRequest'
12469+type MockSpinnerWidget_SetSizeRequest_Call struct {
12470+ *mock.Call
12471+}
12472+
12473+// SetSizeRequest is a helper method to define mock.On call
12474+// - width int
12475+// - height int
12476+func (_e *MockSpinnerWidget_Expecter) SetSizeRequest(width interface{}, height interface{}) *MockSpinnerWidget_SetSizeRequest_Call {
12477+ return &MockSpinnerWidget_SetSizeRequest_Call{Call: _e.mock.On("SetSizeRequest", width, height)}
12478+}
12479+
12480+func (_c *MockSpinnerWidget_SetSizeRequest_Call) Run(run func(width int, height int)) *MockSpinnerWidget_SetSizeRequest_Call {
12481+ _c.Call.Run(func(args mock.Arguments) {
12482+ var arg0 int
12483+ if args[0] != nil {
12484+ arg0 = args[0].(int)
12485+ }
12486+ var arg1 int
12487+ if args[1] != nil {
12488+ arg1 = args[1].(int)
12489+ }
12490+ run(
12491+ arg0,
12492+ arg1,
12493+ )
12494+ })
12495+ return _c
12496+}
12497+
12498+func (_c *MockSpinnerWidget_SetSizeRequest_Call) Return() *MockSpinnerWidget_SetSizeRequest_Call {
12499+ _c.Call.Return()
12500+ return _c
12501+}
12502+
12503+func (_c *MockSpinnerWidget_SetSizeRequest_Call) RunAndReturn(run func(width int, height int)) *MockSpinnerWidget_SetSizeRequest_Call {
12504+ _c.Run(run)
12505+ return _c
12506+}
12507+
12508+// SetSpinning provides a mock function for the type MockSpinnerWidget
12509+func (_mock *MockSpinnerWidget) SetSpinning(spinning bool) {
12510+ _mock.Called(spinning)
12511+ return
12512+}
12513+
12514+// MockSpinnerWidget_SetSpinning_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetSpinning'
12515+type MockSpinnerWidget_SetSpinning_Call struct {
12516+ *mock.Call
12517+}
12518+
12519+// SetSpinning is a helper method to define mock.On call
12520+// - spinning bool
12521+func (_e *MockSpinnerWidget_Expecter) SetSpinning(spinning interface{}) *MockSpinnerWidget_SetSpinning_Call {
12522+ return &MockSpinnerWidget_SetSpinning_Call{Call: _e.mock.On("SetSpinning", spinning)}
12523+}
12524+
12525+func (_c *MockSpinnerWidget_SetSpinning_Call) Run(run func(spinning bool)) *MockSpinnerWidget_SetSpinning_Call {
12526+ _c.Call.Run(func(args mock.Arguments) {
12527+ var arg0 bool
12528+ if args[0] != nil {
12529+ arg0 = args[0].(bool)
12530+ }
12531+ run(
12532+ arg0,
12533+ )
12534+ })
12535+ return _c
12536+}
12537+
12538+func (_c *MockSpinnerWidget_SetSpinning_Call) Return() *MockSpinnerWidget_SetSpinning_Call {
12539+ _c.Call.Return()
12540+ return _c
12541+}
12542+
12543+func (_c *MockSpinnerWidget_SetSpinning_Call) RunAndReturn(run func(spinning bool)) *MockSpinnerWidget_SetSpinning_Call {
12544+ _c.Run(run)
12545+ return _c
12546+}
12547+
12548+// SetValign provides a mock function for the type MockSpinnerWidget
12549+func (_mock *MockSpinnerWidget) SetValign(align gtk.Align) {
12550+ _mock.Called(align)
12551+ return
12552+}
12553+
12554+// MockSpinnerWidget_SetValign_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetValign'
12555+type MockSpinnerWidget_SetValign_Call struct {
12556+ *mock.Call
12557+}
12558+
12559+// SetValign is a helper method to define mock.On call
12560+// - align gtk.Align
12561+func (_e *MockSpinnerWidget_Expecter) SetValign(align interface{}) *MockSpinnerWidget_SetValign_Call {
12562+ return &MockSpinnerWidget_SetValign_Call{Call: _e.mock.On("SetValign", align)}
12563+}
12564+
12565+func (_c *MockSpinnerWidget_SetValign_Call) Run(run func(align gtk.Align)) *MockSpinnerWidget_SetValign_Call {
12566+ _c.Call.Run(func(args mock.Arguments) {
12567+ var arg0 gtk.Align
12568+ if args[0] != nil {
12569+ arg0 = args[0].(gtk.Align)
12570+ }
12571+ run(
12572+ arg0,
12573+ )
12574+ })
12575+ return _c
12576+}
12577+
12578+func (_c *MockSpinnerWidget_SetValign_Call) Return() *MockSpinnerWidget_SetValign_Call {
12579+ _c.Call.Return()
12580+ return _c
12581+}
12582+
12583+func (_c *MockSpinnerWidget_SetValign_Call) RunAndReturn(run func(align gtk.Align)) *MockSpinnerWidget_SetValign_Call {
12584+ _c.Run(run)
12585+ return _c
12586+}
12587+
12588+// SetVexpand provides a mock function for the type MockSpinnerWidget
12589+func (_mock *MockSpinnerWidget) SetVexpand(expand bool) {
12590+ _mock.Called(expand)
12591+ return
12592+}
12593+
12594+// MockSpinnerWidget_SetVexpand_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetVexpand'
12595+type MockSpinnerWidget_SetVexpand_Call struct {
12596+ *mock.Call
12597+}
12598+
12599+// SetVexpand is a helper method to define mock.On call
12600+// - expand bool
12601+func (_e *MockSpinnerWidget_Expecter) SetVexpand(expand interface{}) *MockSpinnerWidget_SetVexpand_Call {
12602+ return &MockSpinnerWidget_SetVexpand_Call{Call: _e.mock.On("SetVexpand", expand)}
12603+}
12604+
12605+func (_c *MockSpinnerWidget_SetVexpand_Call) Run(run func(expand bool)) *MockSpinnerWidget_SetVexpand_Call {
12606+ _c.Call.Run(func(args mock.Arguments) {
12607+ var arg0 bool
12608+ if args[0] != nil {
12609+ arg0 = args[0].(bool)
12610+ }
12611+ run(
12612+ arg0,
12613+ )
12614+ })
12615+ return _c
12616+}
12617+
12618+func (_c *MockSpinnerWidget_SetVexpand_Call) Return() *MockSpinnerWidget_SetVexpand_Call {
12619+ _c.Call.Return()
12620+ return _c
12621+}
12622+
12623+func (_c *MockSpinnerWidget_SetVexpand_Call) RunAndReturn(run func(expand bool)) *MockSpinnerWidget_SetVexpand_Call {
12624+ _c.Run(run)
12625+ return _c
12626+}
12627+
12628+// SetVisible provides a mock function for the type MockSpinnerWidget
12629+func (_mock *MockSpinnerWidget) SetVisible(visible bool) {
12630+ _mock.Called(visible)
12631+ return
12632+}
12633+
12634+// MockSpinnerWidget_SetVisible_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetVisible'
12635+type MockSpinnerWidget_SetVisible_Call struct {
12636+ *mock.Call
12637+}
12638+
12639+// SetVisible is a helper method to define mock.On call
12640+// - visible bool
12641+func (_e *MockSpinnerWidget_Expecter) SetVisible(visible interface{}) *MockSpinnerWidget_SetVisible_Call {
12642+ return &MockSpinnerWidget_SetVisible_Call{Call: _e.mock.On("SetVisible", visible)}
12643+}
12644+
12645+func (_c *MockSpinnerWidget_SetVisible_Call) Run(run func(visible bool)) *MockSpinnerWidget_SetVisible_Call {
12646+ _c.Call.Run(func(args mock.Arguments) {
12647+ var arg0 bool
12648+ if args[0] != nil {
12649+ arg0 = args[0].(bool)
12650+ }
12651+ run(
12652+ arg0,
12653+ )
12654+ })
12655+ return _c
12656+}
12657+
12658+func (_c *MockSpinnerWidget_SetVisible_Call) Return() *MockSpinnerWidget_SetVisible_Call {
12659+ _c.Call.Return()
12660+ return _c
12661+}
12662+
12663+func (_c *MockSpinnerWidget_SetVisible_Call) RunAndReturn(run func(visible bool)) *MockSpinnerWidget_SetVisible_Call {
12664+ _c.Run(run)
12665+ return _c
12666+}
12667+
12668+// Show provides a mock function for the type MockSpinnerWidget
12669+func (_mock *MockSpinnerWidget) Show() {
12670+ _mock.Called()
12671+ return
12672+}
12673+
12674+// MockSpinnerWidget_Show_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Show'
12675+type MockSpinnerWidget_Show_Call struct {
12676+ *mock.Call
12677+}
12678+
12679+// Show is a helper method to define mock.On call
12680+func (_e *MockSpinnerWidget_Expecter) Show() *MockSpinnerWidget_Show_Call {
12681+ return &MockSpinnerWidget_Show_Call{Call: _e.mock.On("Show")}
12682+}
12683+
12684+func (_c *MockSpinnerWidget_Show_Call) Run(run func()) *MockSpinnerWidget_Show_Call {
12685+ _c.Call.Run(func(args mock.Arguments) {
12686+ run()
12687+ })
12688+ return _c
12689+}
12690+
12691+func (_c *MockSpinnerWidget_Show_Call) Return() *MockSpinnerWidget_Show_Call {
12692+ _c.Call.Return()
12693+ return _c
12694+}
12695+
12696+func (_c *MockSpinnerWidget_Show_Call) RunAndReturn(run func()) *MockSpinnerWidget_Show_Call {
12697+ _c.Run(run)
12698+ return _c
12699+}
12700+
12701+// Start provides a mock function for the type MockSpinnerWidget
12702+func (_mock *MockSpinnerWidget) Start() {
12703+ _mock.Called()
12704+ return
12705+}
12706+
12707+// MockSpinnerWidget_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start'
12708+type MockSpinnerWidget_Start_Call struct {
12709+ *mock.Call
12710+}
12711+
12712+// Start is a helper method to define mock.On call
12713+func (_e *MockSpinnerWidget_Expecter) Start() *MockSpinnerWidget_Start_Call {
12714+ return &MockSpinnerWidget_Start_Call{Call: _e.mock.On("Start")}
12715+}
12716+
12717+func (_c *MockSpinnerWidget_Start_Call) Run(run func()) *MockSpinnerWidget_Start_Call {
12718+ _c.Call.Run(func(args mock.Arguments) {
12719+ run()
12720+ })
12721+ return _c
12722+}
12723+
12724+func (_c *MockSpinnerWidget_Start_Call) Return() *MockSpinnerWidget_Start_Call {
12725+ _c.Call.Return()
12726+ return _c
12727+}
12728+
12729+func (_c *MockSpinnerWidget_Start_Call) RunAndReturn(run func()) *MockSpinnerWidget_Start_Call {
12730+ _c.Run(run)
12731+ return _c
12732+}
12733+
12734+// Stop provides a mock function for the type MockSpinnerWidget
12735+func (_mock *MockSpinnerWidget) Stop() {
12736+ _mock.Called()
12737+ return
12738+}
12739+
12740+// MockSpinnerWidget_Stop_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Stop'
12741+type MockSpinnerWidget_Stop_Call struct {
12742+ *mock.Call
12743+}
12744+
12745+// Stop is a helper method to define mock.On call
12746+func (_e *MockSpinnerWidget_Expecter) Stop() *MockSpinnerWidget_Stop_Call {
12747+ return &MockSpinnerWidget_Stop_Call{Call: _e.mock.On("Stop")}
12748+}
12749+
12750+func (_c *MockSpinnerWidget_Stop_Call) Run(run func()) *MockSpinnerWidget_Stop_Call {
12751+ _c.Call.Run(func(args mock.Arguments) {
12752+ run()
12753+ })
12754+ return _c
12755+}
12756+
12757+func (_c *MockSpinnerWidget_Stop_Call) Return() *MockSpinnerWidget_Stop_Call {
12758+ _c.Call.Return()
12759+ return _c
12760+}
12761+
12762+func (_c *MockSpinnerWidget_Stop_Call) RunAndReturn(run func()) *MockSpinnerWidget_Stop_Call {
12763+ _c.Run(run)
12764+ return _c
12765+}
12766+
12767+// Unparent provides a mock function for the type MockSpinnerWidget
12768+func (_mock *MockSpinnerWidget) Unparent() {
12769+ _mock.Called()
12770+ return
12771+}
12772+
12773+// MockSpinnerWidget_Unparent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unparent'
12774+type MockSpinnerWidget_Unparent_Call struct {
12775+ *mock.Call
12776+}
12777+
12778+// Unparent is a helper method to define mock.On call
12779+func (_e *MockSpinnerWidget_Expecter) Unparent() *MockSpinnerWidget_Unparent_Call {
12780+ return &MockSpinnerWidget_Unparent_Call{Call: _e.mock.On("Unparent")}
12781+}
12782+
12783+func (_c *MockSpinnerWidget_Unparent_Call) Run(run func()) *MockSpinnerWidget_Unparent_Call {
12784+ _c.Call.Run(func(args mock.Arguments) {
12785+ run()
12786+ })
12787+ return _c
12788+}
12789+
12790+func (_c *MockSpinnerWidget_Unparent_Call) Return() *MockSpinnerWidget_Unparent_Call {
12791+ _c.Call.Return()
12792+ return _c
12793+}
12794+
12795+func (_c *MockSpinnerWidget_Unparent_Call) RunAndReturn(run func()) *MockSpinnerWidget_Unparent_Call {
12796+ _c.Run(run)
12797+ return _c
12798+}
12799+
1152112800 // NewMockWidgetFactory creates a new instance of MockWidgetFactory. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
1152212801 // The first argument is typically a *testing.T value.
1152312802 func NewMockWidgetFactory(t interface {
@@ -11894,6 +13173,52 @@ func (_c *MockWidgetFactory_NewProgressBar_Call) RunAndReturn(run func() layout.
1189413173 return _c
1189513174 }
1189613175
13176+// NewSpinner provides a mock function for the type MockWidgetFactory
13177+func (_mock *MockWidgetFactory) NewSpinner() layout.SpinnerWidget {
13178+ ret := _mock.Called()
13179+
13180+ if len(ret) == 0 {
13181+ panic("no return value specified for NewSpinner")
13182+ }
13183+
13184+ var r0 layout.SpinnerWidget
13185+ if returnFunc, ok := ret.Get(0).(func() layout.SpinnerWidget); ok {
13186+ r0 = returnFunc()
13187+ } else {
13188+ if ret.Get(0) != nil {
13189+ r0 = ret.Get(0).(layout.SpinnerWidget)
13190+ }
13191+ }
13192+ return r0
13193+}
13194+
13195+// MockWidgetFactory_NewSpinner_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewSpinner'
13196+type MockWidgetFactory_NewSpinner_Call struct {
13197+ *mock.Call
13198+}
13199+
13200+// NewSpinner is a helper method to define mock.On call
13201+func (_e *MockWidgetFactory_Expecter) NewSpinner() *MockWidgetFactory_NewSpinner_Call {
13202+ return &MockWidgetFactory_NewSpinner_Call{Call: _e.mock.On("NewSpinner")}
13203+}
13204+
13205+func (_c *MockWidgetFactory_NewSpinner_Call) Run(run func()) *MockWidgetFactory_NewSpinner_Call {
13206+ _c.Call.Run(func(args mock.Arguments) {
13207+ run()
13208+ })
13209+ return _c
13210+}
13211+
13212+func (_c *MockWidgetFactory_NewSpinner_Call) Return(spinnerWidget layout.SpinnerWidget) *MockWidgetFactory_NewSpinner_Call {
13213+ _c.Call.Return(spinnerWidget)
13214+ return _c
13215+}
13216+
13217+func (_c *MockWidgetFactory_NewSpinner_Call) RunAndReturn(run func() layout.SpinnerWidget) *MockWidgetFactory_NewSpinner_Call {
13218+ _c.Call.Return(run)
13219+ return _c
13220+}
13221+
1189713222 // WrapWidget provides a mock function for the type MockWidgetFactory
1189813223 func (_mock *MockWidgetFactory) WrapWidget(w *gtk.Widget) layout.Widget {
1189913224 ret := _mock.Called(w)
@@ -11518,6 +11518,1285 @@ func (_c *MockProgressBarWidget_Unparent_Call) RunAndReturn(run func()) *MockPro
11518 return _c11518 return _c
11519 }11519 }
11520 11520
11521+// NewMockSpinnerWidget creates a new instance of MockSpinnerWidget. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
11522+// The first argument is typically a *testing.T value.
11523+func NewMockSpinnerWidget(t interface {
11524+ mock.TestingT
11525+ Cleanup(func())
11526+}) *MockSpinnerWidget {
11527+ mock := &MockSpinnerWidget{}
11528+ mock.Mock.Test(t)
11529+
11530+ t.Cleanup(func() { mock.AssertExpectations(t) })
11531+
11532+ return mock
11533+}
11534+
11535+// MockSpinnerWidget is an autogenerated mock type for the SpinnerWidget type
11536+type MockSpinnerWidget struct {
11537+ mock.Mock
11538+}
11539+
11540+type MockSpinnerWidget_Expecter struct {
11541+ mock *mock.Mock
11542+}
11543+
11544+func (_m *MockSpinnerWidget) EXPECT() *MockSpinnerWidget_Expecter {
11545+ return &MockSpinnerWidget_Expecter{mock: &_m.Mock}
11546+}
11547+
11548+// AddController provides a mock function for the type MockSpinnerWidget
11549+func (_mock *MockSpinnerWidget) AddController(controller *gtk.EventController) {
11550+ _mock.Called(controller)
11551+ return
11552+}
11553+
11554+// MockSpinnerWidget_AddController_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddController'
11555+type MockSpinnerWidget_AddController_Call struct {
11556+ *mock.Call
11557+}
11558+
11559+// AddController is a helper method to define mock.On call
11560+// - controller *gtk.EventController
11561+func (_e *MockSpinnerWidget_Expecter) AddController(controller interface{}) *MockSpinnerWidget_AddController_Call {
11562+ return &MockSpinnerWidget_AddController_Call{Call: _e.mock.On("AddController", controller)}
11563+}
11564+
11565+func (_c *MockSpinnerWidget_AddController_Call) Run(run func(controller *gtk.EventController)) *MockSpinnerWidget_AddController_Call {
11566+ _c.Call.Run(func(args mock.Arguments) {
11567+ var arg0 *gtk.EventController
11568+ if args[0] != nil {
11569+ arg0 = args[0].(*gtk.EventController)
11570+ }
11571+ run(
11572+ arg0,
11573+ )
11574+ })
11575+ return _c
11576+}
11577+
11578+func (_c *MockSpinnerWidget_AddController_Call) Return() *MockSpinnerWidget_AddController_Call {
11579+ _c.Call.Return()
11580+ return _c
11581+}
11582+
11583+func (_c *MockSpinnerWidget_AddController_Call) RunAndReturn(run func(controller *gtk.EventController)) *MockSpinnerWidget_AddController_Call {
11584+ _c.Run(run)
11585+ return _c
11586+}
11587+
11588+// AddCssClass provides a mock function for the type MockSpinnerWidget
11589+func (_mock *MockSpinnerWidget) AddCssClass(cssClass string) {
11590+ _mock.Called(cssClass)
11591+ return
11592+}
11593+
11594+// MockSpinnerWidget_AddCssClass_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddCssClass'
11595+type MockSpinnerWidget_AddCssClass_Call struct {
11596+ *mock.Call
11597+}
11598+
11599+// AddCssClass is a helper method to define mock.On call
11600+// - cssClass string
11601+func (_e *MockSpinnerWidget_Expecter) AddCssClass(cssClass interface{}) *MockSpinnerWidget_AddCssClass_Call {
11602+ return &MockSpinnerWidget_AddCssClass_Call{Call: _e.mock.On("AddCssClass", cssClass)}
11603+}
11604+
11605+func (_c *MockSpinnerWidget_AddCssClass_Call) Run(run func(cssClass string)) *MockSpinnerWidget_AddCssClass_Call {
11606+ _c.Call.Run(func(args mock.Arguments) {
11607+ var arg0 string
11608+ if args[0] != nil {
11609+ arg0 = args[0].(string)
11610+ }
11611+ run(
11612+ arg0,
11613+ )
11614+ })
11615+ return _c
11616+}
11617+
11618+func (_c *MockSpinnerWidget_AddCssClass_Call) Return() *MockSpinnerWidget_AddCssClass_Call {
11619+ _c.Call.Return()
11620+ return _c
11621+}
11622+
11623+func (_c *MockSpinnerWidget_AddCssClass_Call) RunAndReturn(run func(cssClass string)) *MockSpinnerWidget_AddCssClass_Call {
11624+ _c.Run(run)
11625+ return _c
11626+}
11627+
11628+// ComputePoint provides a mock function for the type MockSpinnerWidget
11629+func (_mock *MockSpinnerWidget) ComputePoint(target layout.Widget) (float64, float64, bool) {
11630+ ret := _mock.Called(target)
11631+
11632+ if len(ret) == 0 {
11633+ panic("no return value specified for ComputePoint")
11634+ }
11635+
11636+ var r0 float64
11637+ var r1 float64
11638+ var r2 bool
11639+ if returnFunc, ok := ret.Get(0).(func(layout.Widget) (float64, float64, bool)); ok {
11640+ return returnFunc(target)
11641+ }
11642+ if returnFunc, ok := ret.Get(0).(func(layout.Widget) float64); ok {
11643+ r0 = returnFunc(target)
11644+ } else {
11645+ r0 = ret.Get(0).(float64)
11646+ }
11647+ if returnFunc, ok := ret.Get(1).(func(layout.Widget) float64); ok {
11648+ r1 = returnFunc(target)
11649+ } else {
11650+ r1 = ret.Get(1).(float64)
11651+ }
11652+ if returnFunc, ok := ret.Get(2).(func(layout.Widget) bool); ok {
11653+ r2 = returnFunc(target)
11654+ } else {
11655+ r2 = ret.Get(2).(bool)
11656+ }
11657+ return r0, r1, r2
11658+}
11659+
11660+// MockSpinnerWidget_ComputePoint_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ComputePoint'
11661+type MockSpinnerWidget_ComputePoint_Call struct {
11662+ *mock.Call
11663+}
11664+
11665+// ComputePoint is a helper method to define mock.On call
11666+// - target layout.Widget
11667+func (_e *MockSpinnerWidget_Expecter) ComputePoint(target interface{}) *MockSpinnerWidget_ComputePoint_Call {
11668+ return &MockSpinnerWidget_ComputePoint_Call{Call: _e.mock.On("ComputePoint", target)}
11669+}
11670+
11671+func (_c *MockSpinnerWidget_ComputePoint_Call) Run(run func(target layout.Widget)) *MockSpinnerWidget_ComputePoint_Call {
11672+ _c.Call.Run(func(args mock.Arguments) {
11673+ var arg0 layout.Widget
11674+ if args[0] != nil {
11675+ arg0 = args[0].(layout.Widget)
11676+ }
11677+ run(
11678+ arg0,
11679+ )
11680+ })
11681+ return _c
11682+}
11683+
11684+func (_c *MockSpinnerWidget_ComputePoint_Call) Return(x float64, y float64, ok bool) *MockSpinnerWidget_ComputePoint_Call {
11685+ _c.Call.Return(x, y, ok)
11686+ return _c
11687+}
11688+
11689+func (_c *MockSpinnerWidget_ComputePoint_Call) RunAndReturn(run func(target layout.Widget) (float64, float64, bool)) *MockSpinnerWidget_ComputePoint_Call {
11690+ _c.Call.Return(run)
11691+ return _c
11692+}
11693+
11694+// GetAllocatedHeight provides a mock function for the type MockSpinnerWidget
11695+func (_mock *MockSpinnerWidget) GetAllocatedHeight() int {
11696+ ret := _mock.Called()
11697+
11698+ if len(ret) == 0 {
11699+ panic("no return value specified for GetAllocatedHeight")
11700+ }
11701+
11702+ var r0 int
11703+ if returnFunc, ok := ret.Get(0).(func() int); ok {
11704+ r0 = returnFunc()
11705+ } else {
11706+ r0 = ret.Get(0).(int)
11707+ }
11708+ return r0
11709+}
11710+
11711+// MockSpinnerWidget_GetAllocatedHeight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllocatedHeight'
11712+type MockSpinnerWidget_GetAllocatedHeight_Call struct {
11713+ *mock.Call
11714+}
11715+
11716+// GetAllocatedHeight is a helper method to define mock.On call
11717+func (_e *MockSpinnerWidget_Expecter) GetAllocatedHeight() *MockSpinnerWidget_GetAllocatedHeight_Call {
11718+ return &MockSpinnerWidget_GetAllocatedHeight_Call{Call: _e.mock.On("GetAllocatedHeight")}
11719+}
11720+
11721+func (_c *MockSpinnerWidget_GetAllocatedHeight_Call) Run(run func()) *MockSpinnerWidget_GetAllocatedHeight_Call {
11722+ _c.Call.Run(func(args mock.Arguments) {
11723+ run()
11724+ })
11725+ return _c
11726+}
11727+
11728+func (_c *MockSpinnerWidget_GetAllocatedHeight_Call) Return(n int) *MockSpinnerWidget_GetAllocatedHeight_Call {
11729+ _c.Call.Return(n)
11730+ return _c
11731+}
11732+
11733+func (_c *MockSpinnerWidget_GetAllocatedHeight_Call) RunAndReturn(run func() int) *MockSpinnerWidget_GetAllocatedHeight_Call {
11734+ _c.Call.Return(run)
11735+ return _c
11736+}
11737+
11738+// GetAllocatedWidth provides a mock function for the type MockSpinnerWidget
11739+func (_mock *MockSpinnerWidget) GetAllocatedWidth() int {
11740+ ret := _mock.Called()
11741+
11742+ if len(ret) == 0 {
11743+ panic("no return value specified for GetAllocatedWidth")
11744+ }
11745+
11746+ var r0 int
11747+ if returnFunc, ok := ret.Get(0).(func() int); ok {
11748+ r0 = returnFunc()
11749+ } else {
11750+ r0 = ret.Get(0).(int)
11751+ }
11752+ return r0
11753+}
11754+
11755+// MockSpinnerWidget_GetAllocatedWidth_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetAllocatedWidth'
11756+type MockSpinnerWidget_GetAllocatedWidth_Call struct {
11757+ *mock.Call
11758+}
11759+
11760+// GetAllocatedWidth is a helper method to define mock.On call
11761+func (_e *MockSpinnerWidget_Expecter) GetAllocatedWidth() *MockSpinnerWidget_GetAllocatedWidth_Call {
11762+ return &MockSpinnerWidget_GetAllocatedWidth_Call{Call: _e.mock.On("GetAllocatedWidth")}
11763+}
11764+
11765+func (_c *MockSpinnerWidget_GetAllocatedWidth_Call) Run(run func()) *MockSpinnerWidget_GetAllocatedWidth_Call {
11766+ _c.Call.Run(func(args mock.Arguments) {
11767+ run()
11768+ })
11769+ return _c
11770+}
11771+
11772+func (_c *MockSpinnerWidget_GetAllocatedWidth_Call) Return(n int) *MockSpinnerWidget_GetAllocatedWidth_Call {
11773+ _c.Call.Return(n)
11774+ return _c
11775+}
11776+
11777+func (_c *MockSpinnerWidget_GetAllocatedWidth_Call) RunAndReturn(run func() int) *MockSpinnerWidget_GetAllocatedWidth_Call {
11778+ _c.Call.Return(run)
11779+ return _c
11780+}
11781+
11782+// GetHexpand provides a mock function for the type MockSpinnerWidget
11783+func (_mock *MockSpinnerWidget) GetHexpand() bool {
11784+ ret := _mock.Called()
11785+
11786+ if len(ret) == 0 {
11787+ panic("no return value specified for GetHexpand")
11788+ }
11789+
11790+ var r0 bool
11791+ if returnFunc, ok := ret.Get(0).(func() bool); ok {
11792+ r0 = returnFunc()
11793+ } else {
11794+ r0 = ret.Get(0).(bool)
11795+ }
11796+ return r0
11797+}
11798+
11799+// MockSpinnerWidget_GetHexpand_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetHexpand'
11800+type MockSpinnerWidget_GetHexpand_Call struct {
11801+ *mock.Call
11802+}
11803+
11804+// GetHexpand is a helper method to define mock.On call
11805+func (_e *MockSpinnerWidget_Expecter) GetHexpand() *MockSpinnerWidget_GetHexpand_Call {
11806+ return &MockSpinnerWidget_GetHexpand_Call{Call: _e.mock.On("GetHexpand")}
11807+}
11808+
11809+func (_c *MockSpinnerWidget_GetHexpand_Call) Run(run func()) *MockSpinnerWidget_GetHexpand_Call {
11810+ _c.Call.Run(func(args mock.Arguments) {
11811+ run()
11812+ })
11813+ return _c
11814+}
11815+
11816+func (_c *MockSpinnerWidget_GetHexpand_Call) Return(b bool) *MockSpinnerWidget_GetHexpand_Call {
11817+ _c.Call.Return(b)
11818+ return _c
11819+}
11820+
11821+func (_c *MockSpinnerWidget_GetHexpand_Call) RunAndReturn(run func() bool) *MockSpinnerWidget_GetHexpand_Call {
11822+ _c.Call.Return(run)
11823+ return _c
11824+}
11825+
11826+// GetParent provides a mock function for the type MockSpinnerWidget
11827+func (_mock *MockSpinnerWidget) GetParent() layout.Widget {
11828+ ret := _mock.Called()
11829+
11830+ if len(ret) == 0 {
11831+ panic("no return value specified for GetParent")
11832+ }
11833+
11834+ var r0 layout.Widget
11835+ if returnFunc, ok := ret.Get(0).(func() layout.Widget); ok {
11836+ r0 = returnFunc()
11837+ } else {
11838+ if ret.Get(0) != nil {
11839+ r0 = ret.Get(0).(layout.Widget)
11840+ }
11841+ }
11842+ return r0
11843+}
11844+
11845+// MockSpinnerWidget_GetParent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetParent'
11846+type MockSpinnerWidget_GetParent_Call struct {
11847+ *mock.Call
11848+}
11849+
11850+// GetParent is a helper method to define mock.On call
11851+func (_e *MockSpinnerWidget_Expecter) GetParent() *MockSpinnerWidget_GetParent_Call {
11852+ return &MockSpinnerWidget_GetParent_Call{Call: _e.mock.On("GetParent")}
11853+}
11854+
11855+func (_c *MockSpinnerWidget_GetParent_Call) Run(run func()) *MockSpinnerWidget_GetParent_Call {
11856+ _c.Call.Run(func(args mock.Arguments) {
11857+ run()
11858+ })
11859+ return _c
11860+}
11861+
11862+func (_c *MockSpinnerWidget_GetParent_Call) Return(widget layout.Widget) *MockSpinnerWidget_GetParent_Call {
11863+ _c.Call.Return(widget)
11864+ return _c
11865+}
11866+
11867+func (_c *MockSpinnerWidget_GetParent_Call) RunAndReturn(run func() layout.Widget) *MockSpinnerWidget_GetParent_Call {
11868+ _c.Call.Return(run)
11869+ return _c
11870+}
11871+
11872+// GetSpinning provides a mock function for the type MockSpinnerWidget
11873+func (_mock *MockSpinnerWidget) GetSpinning() bool {
11874+ ret := _mock.Called()
11875+
11876+ if len(ret) == 0 {
11877+ panic("no return value specified for GetSpinning")
11878+ }
11879+
11880+ var r0 bool
11881+ if returnFunc, ok := ret.Get(0).(func() bool); ok {
11882+ r0 = returnFunc()
11883+ } else {
11884+ r0 = ret.Get(0).(bool)
11885+ }
11886+ return r0
11887+}
11888+
11889+// MockSpinnerWidget_GetSpinning_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSpinning'
11890+type MockSpinnerWidget_GetSpinning_Call struct {
11891+ *mock.Call
11892+}
11893+
11894+// GetSpinning is a helper method to define mock.On call
11895+func (_e *MockSpinnerWidget_Expecter) GetSpinning() *MockSpinnerWidget_GetSpinning_Call {
11896+ return &MockSpinnerWidget_GetSpinning_Call{Call: _e.mock.On("GetSpinning")}
11897+}
11898+
11899+func (_c *MockSpinnerWidget_GetSpinning_Call) Run(run func()) *MockSpinnerWidget_GetSpinning_Call {
11900+ _c.Call.Run(func(args mock.Arguments) {
11901+ run()
11902+ })
11903+ return _c
11904+}
11905+
11906+func (_c *MockSpinnerWidget_GetSpinning_Call) Return(b bool) *MockSpinnerWidget_GetSpinning_Call {
11907+ _c.Call.Return(b)
11908+ return _c
11909+}
11910+
11911+func (_c *MockSpinnerWidget_GetSpinning_Call) RunAndReturn(run func() bool) *MockSpinnerWidget_GetSpinning_Call {
11912+ _c.Call.Return(run)
11913+ return _c
11914+}
11915+
11916+// GetVexpand provides a mock function for the type MockSpinnerWidget
11917+func (_mock *MockSpinnerWidget) GetVexpand() bool {
11918+ ret := _mock.Called()
11919+
11920+ if len(ret) == 0 {
11921+ panic("no return value specified for GetVexpand")
11922+ }
11923+
11924+ var r0 bool
11925+ if returnFunc, ok := ret.Get(0).(func() bool); ok {
11926+ r0 = returnFunc()
11927+ } else {
11928+ r0 = ret.Get(0).(bool)
11929+ }
11930+ return r0
11931+}
11932+
11933+// MockSpinnerWidget_GetVexpand_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetVexpand'
11934+type MockSpinnerWidget_GetVexpand_Call struct {
11935+ *mock.Call
11936+}
11937+
11938+// GetVexpand is a helper method to define mock.On call
11939+func (_e *MockSpinnerWidget_Expecter) GetVexpand() *MockSpinnerWidget_GetVexpand_Call {
11940+ return &MockSpinnerWidget_GetVexpand_Call{Call: _e.mock.On("GetVexpand")}
11941+}
11942+
11943+func (_c *MockSpinnerWidget_GetVexpand_Call) Run(run func()) *MockSpinnerWidget_GetVexpand_Call {
11944+ _c.Call.Run(func(args mock.Arguments) {
11945+ run()
11946+ })
11947+ return _c
11948+}
11949+
11950+func (_c *MockSpinnerWidget_GetVexpand_Call) Return(b bool) *MockSpinnerWidget_GetVexpand_Call {
11951+ _c.Call.Return(b)
11952+ return _c
11953+}
11954+
11955+func (_c *MockSpinnerWidget_GetVexpand_Call) RunAndReturn(run func() bool) *MockSpinnerWidget_GetVexpand_Call {
11956+ _c.Call.Return(run)
11957+ return _c
11958+}
11959+
11960+// GrabFocus provides a mock function for the type MockSpinnerWidget
11961+func (_mock *MockSpinnerWidget) GrabFocus() bool {
11962+ ret := _mock.Called()
11963+
11964+ if len(ret) == 0 {
11965+ panic("no return value specified for GrabFocus")
11966+ }
11967+
11968+ var r0 bool
11969+ if returnFunc, ok := ret.Get(0).(func() bool); ok {
11970+ r0 = returnFunc()
11971+ } else {
11972+ r0 = ret.Get(0).(bool)
11973+ }
11974+ return r0
11975+}
11976+
11977+// MockSpinnerWidget_GrabFocus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GrabFocus'
11978+type MockSpinnerWidget_GrabFocus_Call struct {
11979+ *mock.Call
11980+}
11981+
11982+// GrabFocus is a helper method to define mock.On call
11983+func (_e *MockSpinnerWidget_Expecter) GrabFocus() *MockSpinnerWidget_GrabFocus_Call {
11984+ return &MockSpinnerWidget_GrabFocus_Call{Call: _e.mock.On("GrabFocus")}
11985+}
11986+
11987+func (_c *MockSpinnerWidget_GrabFocus_Call) Run(run func()) *MockSpinnerWidget_GrabFocus_Call {
11988+ _c.Call.Run(func(args mock.Arguments) {
11989+ run()
11990+ })
11991+ return _c
11992+}
11993+
11994+func (_c *MockSpinnerWidget_GrabFocus_Call) Return(b bool) *MockSpinnerWidget_GrabFocus_Call {
11995+ _c.Call.Return(b)
11996+ return _c
11997+}
11998+
11999+func (_c *MockSpinnerWidget_GrabFocus_Call) RunAndReturn(run func() bool) *MockSpinnerWidget_GrabFocus_Call {
12000+ _c.Call.Return(run)
12001+ return _c
12002+}
12003+
12004+// GtkWidget provides a mock function for the type MockSpinnerWidget
12005+func (_mock *MockSpinnerWidget) GtkWidget() *gtk.Widget {
12006+ ret := _mock.Called()
12007+
12008+ if len(ret) == 0 {
12009+ panic("no return value specified for GtkWidget")
12010+ }
12011+
12012+ var r0 *gtk.Widget
12013+ if returnFunc, ok := ret.Get(0).(func() *gtk.Widget); ok {
12014+ r0 = returnFunc()
12015+ } else {
12016+ if ret.Get(0) != nil {
12017+ r0 = ret.Get(0).(*gtk.Widget)
12018+ }
12019+ }
12020+ return r0
12021+}
12022+
12023+// MockSpinnerWidget_GtkWidget_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GtkWidget'
12024+type MockSpinnerWidget_GtkWidget_Call struct {
12025+ *mock.Call
12026+}
12027+
12028+// GtkWidget is a helper method to define mock.On call
12029+func (_e *MockSpinnerWidget_Expecter) GtkWidget() *MockSpinnerWidget_GtkWidget_Call {
12030+ return &MockSpinnerWidget_GtkWidget_Call{Call: _e.mock.On("GtkWidget")}
12031+}
12032+
12033+func (_c *MockSpinnerWidget_GtkWidget_Call) Run(run func()) *MockSpinnerWidget_GtkWidget_Call {
12034+ _c.Call.Run(func(args mock.Arguments) {
12035+ run()
12036+ })
12037+ return _c
12038+}
12039+
12040+func (_c *MockSpinnerWidget_GtkWidget_Call) Return(widget *gtk.Widget) *MockSpinnerWidget_GtkWidget_Call {
12041+ _c.Call.Return(widget)
12042+ return _c
12043+}
12044+
12045+func (_c *MockSpinnerWidget_GtkWidget_Call) RunAndReturn(run func() *gtk.Widget) *MockSpinnerWidget_GtkWidget_Call {
12046+ _c.Call.Return(run)
12047+ return _c
12048+}
12049+
12050+// HasCssClass provides a mock function for the type MockSpinnerWidget
12051+func (_mock *MockSpinnerWidget) HasCssClass(cssClass string) bool {
12052+ ret := _mock.Called(cssClass)
12053+
12054+ if len(ret) == 0 {
12055+ panic("no return value specified for HasCssClass")
12056+ }
12057+
12058+ var r0 bool
12059+ if returnFunc, ok := ret.Get(0).(func(string) bool); ok {
12060+ r0 = returnFunc(cssClass)
12061+ } else {
12062+ r0 = ret.Get(0).(bool)
12063+ }
12064+ return r0
12065+}
12066+
12067+// MockSpinnerWidget_HasCssClass_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasCssClass'
12068+type MockSpinnerWidget_HasCssClass_Call struct {
12069+ *mock.Call
12070+}
12071+
12072+// HasCssClass is a helper method to define mock.On call
12073+// - cssClass string
12074+func (_e *MockSpinnerWidget_Expecter) HasCssClass(cssClass interface{}) *MockSpinnerWidget_HasCssClass_Call {
12075+ return &MockSpinnerWidget_HasCssClass_Call{Call: _e.mock.On("HasCssClass", cssClass)}
12076+}
12077+
12078+func (_c *MockSpinnerWidget_HasCssClass_Call) Run(run func(cssClass string)) *MockSpinnerWidget_HasCssClass_Call {
12079+ _c.Call.Run(func(args mock.Arguments) {
12080+ var arg0 string
12081+ if args[0] != nil {
12082+ arg0 = args[0].(string)
12083+ }
12084+ run(
12085+ arg0,
12086+ )
12087+ })
12088+ return _c
12089+}
12090+
12091+func (_c *MockSpinnerWidget_HasCssClass_Call) Return(b bool) *MockSpinnerWidget_HasCssClass_Call {
12092+ _c.Call.Return(b)
12093+ return _c
12094+}
12095+
12096+func (_c *MockSpinnerWidget_HasCssClass_Call) RunAndReturn(run func(cssClass string) bool) *MockSpinnerWidget_HasCssClass_Call {
12097+ _c.Call.Return(run)
12098+ return _c
12099+}
12100+
12101+// HasFocus provides a mock function for the type MockSpinnerWidget
12102+func (_mock *MockSpinnerWidget) HasFocus() bool {
12103+ ret := _mock.Called()
12104+
12105+ if len(ret) == 0 {
12106+ panic("no return value specified for HasFocus")
12107+ }
12108+
12109+ var r0 bool
12110+ if returnFunc, ok := ret.Get(0).(func() bool); ok {
12111+ r0 = returnFunc()
12112+ } else {
12113+ r0 = ret.Get(0).(bool)
12114+ }
12115+ return r0
12116+}
12117+
12118+// MockSpinnerWidget_HasFocus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasFocus'
12119+type MockSpinnerWidget_HasFocus_Call struct {
12120+ *mock.Call
12121+}
12122+
12123+// HasFocus is a helper method to define mock.On call
12124+func (_e *MockSpinnerWidget_Expecter) HasFocus() *MockSpinnerWidget_HasFocus_Call {
12125+ return &MockSpinnerWidget_HasFocus_Call{Call: _e.mock.On("HasFocus")}
12126+}
12127+
12128+func (_c *MockSpinnerWidget_HasFocus_Call) Run(run func()) *MockSpinnerWidget_HasFocus_Call {
12129+ _c.Call.Run(func(args mock.Arguments) {
12130+ run()
12131+ })
12132+ return _c
12133+}
12134+
12135+func (_c *MockSpinnerWidget_HasFocus_Call) Return(b bool) *MockSpinnerWidget_HasFocus_Call {
12136+ _c.Call.Return(b)
12137+ return _c
12138+}
12139+
12140+func (_c *MockSpinnerWidget_HasFocus_Call) RunAndReturn(run func() bool) *MockSpinnerWidget_HasFocus_Call {
12141+ _c.Call.Return(run)
12142+ return _c
12143+}
12144+
12145+// Hide provides a mock function for the type MockSpinnerWidget
12146+func (_mock *MockSpinnerWidget) Hide() {
12147+ _mock.Called()
12148+ return
12149+}
12150+
12151+// MockSpinnerWidget_Hide_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Hide'
12152+type MockSpinnerWidget_Hide_Call struct {
12153+ *mock.Call
12154+}
12155+
12156+// Hide is a helper method to define mock.On call
12157+func (_e *MockSpinnerWidget_Expecter) Hide() *MockSpinnerWidget_Hide_Call {
12158+ return &MockSpinnerWidget_Hide_Call{Call: _e.mock.On("Hide")}
12159+}
12160+
12161+func (_c *MockSpinnerWidget_Hide_Call) Run(run func()) *MockSpinnerWidget_Hide_Call {
12162+ _c.Call.Run(func(args mock.Arguments) {
12163+ run()
12164+ })
12165+ return _c
12166+}
12167+
12168+func (_c *MockSpinnerWidget_Hide_Call) Return() *MockSpinnerWidget_Hide_Call {
12169+ _c.Call.Return()
12170+ return _c
12171+}
12172+
12173+func (_c *MockSpinnerWidget_Hide_Call) RunAndReturn(run func()) *MockSpinnerWidget_Hide_Call {
12174+ _c.Run(run)
12175+ return _c
12176+}
12177+
12178+// IsVisible provides a mock function for the type MockSpinnerWidget
12179+func (_mock *MockSpinnerWidget) IsVisible() bool {
12180+ ret := _mock.Called()
12181+
12182+ if len(ret) == 0 {
12183+ panic("no return value specified for IsVisible")
12184+ }
12185+
12186+ var r0 bool
12187+ if returnFunc, ok := ret.Get(0).(func() bool); ok {
12188+ r0 = returnFunc()
12189+ } else {
12190+ r0 = ret.Get(0).(bool)
12191+ }
12192+ return r0
12193+}
12194+
12195+// MockSpinnerWidget_IsVisible_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsVisible'
12196+type MockSpinnerWidget_IsVisible_Call struct {
12197+ *mock.Call
12198+}
12199+
12200+// IsVisible is a helper method to define mock.On call
12201+func (_e *MockSpinnerWidget_Expecter) IsVisible() *MockSpinnerWidget_IsVisible_Call {
12202+ return &MockSpinnerWidget_IsVisible_Call{Call: _e.mock.On("IsVisible")}
12203+}
12204+
12205+func (_c *MockSpinnerWidget_IsVisible_Call) Run(run func()) *MockSpinnerWidget_IsVisible_Call {
12206+ _c.Call.Run(func(args mock.Arguments) {
12207+ run()
12208+ })
12209+ return _c
12210+}
12211+
12212+func (_c *MockSpinnerWidget_IsVisible_Call) Return(b bool) *MockSpinnerWidget_IsVisible_Call {
12213+ _c.Call.Return(b)
12214+ return _c
12215+}
12216+
12217+func (_c *MockSpinnerWidget_IsVisible_Call) RunAndReturn(run func() bool) *MockSpinnerWidget_IsVisible_Call {
12218+ _c.Call.Return(run)
12219+ return _c
12220+}
12221+
12222+// RemoveCssClass provides a mock function for the type MockSpinnerWidget
12223+func (_mock *MockSpinnerWidget) RemoveCssClass(cssClass string) {
12224+ _mock.Called(cssClass)
12225+ return
12226+}
12227+
12228+// MockSpinnerWidget_RemoveCssClass_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveCssClass'
12229+type MockSpinnerWidget_RemoveCssClass_Call struct {
12230+ *mock.Call
12231+}
12232+
12233+// RemoveCssClass is a helper method to define mock.On call
12234+// - cssClass string
12235+func (_e *MockSpinnerWidget_Expecter) RemoveCssClass(cssClass interface{}) *MockSpinnerWidget_RemoveCssClass_Call {
12236+ return &MockSpinnerWidget_RemoveCssClass_Call{Call: _e.mock.On("RemoveCssClass", cssClass)}
12237+}
12238+
12239+func (_c *MockSpinnerWidget_RemoveCssClass_Call) Run(run func(cssClass string)) *MockSpinnerWidget_RemoveCssClass_Call {
12240+ _c.Call.Run(func(args mock.Arguments) {
12241+ var arg0 string
12242+ if args[0] != nil {
12243+ arg0 = args[0].(string)
12244+ }
12245+ run(
12246+ arg0,
12247+ )
12248+ })
12249+ return _c
12250+}
12251+
12252+func (_c *MockSpinnerWidget_RemoveCssClass_Call) Return() *MockSpinnerWidget_RemoveCssClass_Call {
12253+ _c.Call.Return()
12254+ return _c
12255+}
12256+
12257+func (_c *MockSpinnerWidget_RemoveCssClass_Call) RunAndReturn(run func(cssClass string)) *MockSpinnerWidget_RemoveCssClass_Call {
12258+ _c.Run(run)
12259+ return _c
12260+}
12261+
12262+// SetCanFocus provides a mock function for the type MockSpinnerWidget
12263+func (_mock *MockSpinnerWidget) SetCanFocus(canFocus bool) {
12264+ _mock.Called(canFocus)
12265+ return
12266+}
12267+
12268+// MockSpinnerWidget_SetCanFocus_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetCanFocus'
12269+type MockSpinnerWidget_SetCanFocus_Call struct {
12270+ *mock.Call
12271+}
12272+
12273+// SetCanFocus is a helper method to define mock.On call
12274+// - canFocus bool
12275+func (_e *MockSpinnerWidget_Expecter) SetCanFocus(canFocus interface{}) *MockSpinnerWidget_SetCanFocus_Call {
12276+ return &MockSpinnerWidget_SetCanFocus_Call{Call: _e.mock.On("SetCanFocus", canFocus)}
12277+}
12278+
12279+func (_c *MockSpinnerWidget_SetCanFocus_Call) Run(run func(canFocus bool)) *MockSpinnerWidget_SetCanFocus_Call {
12280+ _c.Call.Run(func(args mock.Arguments) {
12281+ var arg0 bool
12282+ if args[0] != nil {
12283+ arg0 = args[0].(bool)
12284+ }
12285+ run(
12286+ arg0,
12287+ )
12288+ })
12289+ return _c
12290+}
12291+
12292+func (_c *MockSpinnerWidget_SetCanFocus_Call) Return() *MockSpinnerWidget_SetCanFocus_Call {
12293+ _c.Call.Return()
12294+ return _c
12295+}
12296+
12297+func (_c *MockSpinnerWidget_SetCanFocus_Call) RunAndReturn(run func(canFocus bool)) *MockSpinnerWidget_SetCanFocus_Call {
12298+ _c.Run(run)
12299+ return _c
12300+}
12301+
12302+// SetCanTarget provides a mock function for the type MockSpinnerWidget
12303+func (_mock *MockSpinnerWidget) SetCanTarget(canTarget bool) {
12304+ _mock.Called(canTarget)
12305+ return
12306+}
12307+
12308+// MockSpinnerWidget_SetCanTarget_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetCanTarget'
12309+type MockSpinnerWidget_SetCanTarget_Call struct {
12310+ *mock.Call
12311+}
12312+
12313+// SetCanTarget is a helper method to define mock.On call
12314+// - canTarget bool
12315+func (_e *MockSpinnerWidget_Expecter) SetCanTarget(canTarget interface{}) *MockSpinnerWidget_SetCanTarget_Call {
12316+ return &MockSpinnerWidget_SetCanTarget_Call{Call: _e.mock.On("SetCanTarget", canTarget)}
12317+}
12318+
12319+func (_c *MockSpinnerWidget_SetCanTarget_Call) Run(run func(canTarget bool)) *MockSpinnerWidget_SetCanTarget_Call {
12320+ _c.Call.Run(func(args mock.Arguments) {
12321+ var arg0 bool
12322+ if args[0] != nil {
12323+ arg0 = args[0].(bool)
12324+ }
12325+ run(
12326+ arg0,
12327+ )
12328+ })
12329+ return _c
12330+}
12331+
12332+func (_c *MockSpinnerWidget_SetCanTarget_Call) Return() *MockSpinnerWidget_SetCanTarget_Call {
12333+ _c.Call.Return()
12334+ return _c
12335+}
12336+
12337+func (_c *MockSpinnerWidget_SetCanTarget_Call) RunAndReturn(run func(canTarget bool)) *MockSpinnerWidget_SetCanTarget_Call {
12338+ _c.Run(run)
12339+ return _c
12340+}
12341+
12342+// SetFocusOnClick provides a mock function for the type MockSpinnerWidget
12343+func (_mock *MockSpinnerWidget) SetFocusOnClick(focusOnClick bool) {
12344+ _mock.Called(focusOnClick)
12345+ return
12346+}
12347+
12348+// MockSpinnerWidget_SetFocusOnClick_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetFocusOnClick'
12349+type MockSpinnerWidget_SetFocusOnClick_Call struct {
12350+ *mock.Call
12351+}
12352+
12353+// SetFocusOnClick is a helper method to define mock.On call
12354+// - focusOnClick bool
12355+func (_e *MockSpinnerWidget_Expecter) SetFocusOnClick(focusOnClick interface{}) *MockSpinnerWidget_SetFocusOnClick_Call {
12356+ return &MockSpinnerWidget_SetFocusOnClick_Call{Call: _e.mock.On("SetFocusOnClick", focusOnClick)}
12357+}
12358+
12359+func (_c *MockSpinnerWidget_SetFocusOnClick_Call) Run(run func(focusOnClick bool)) *MockSpinnerWidget_SetFocusOnClick_Call {
12360+ _c.Call.Run(func(args mock.Arguments) {
12361+ var arg0 bool
12362+ if args[0] != nil {
12363+ arg0 = args[0].(bool)
12364+ }
12365+ run(
12366+ arg0,
12367+ )
12368+ })
12369+ return _c
12370+}
12371+
12372+func (_c *MockSpinnerWidget_SetFocusOnClick_Call) Return() *MockSpinnerWidget_SetFocusOnClick_Call {
12373+ _c.Call.Return()
12374+ return _c
12375+}
12376+
12377+func (_c *MockSpinnerWidget_SetFocusOnClick_Call) RunAndReturn(run func(focusOnClick bool)) *MockSpinnerWidget_SetFocusOnClick_Call {
12378+ _c.Run(run)
12379+ return _c
12380+}
12381+
12382+// SetHalign provides a mock function for the type MockSpinnerWidget
12383+func (_mock *MockSpinnerWidget) SetHalign(align gtk.Align) {
12384+ _mock.Called(align)
12385+ return
12386+}
12387+
12388+// MockSpinnerWidget_SetHalign_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetHalign'
12389+type MockSpinnerWidget_SetHalign_Call struct {
12390+ *mock.Call
12391+}
12392+
12393+// SetHalign is a helper method to define mock.On call
12394+// - align gtk.Align
12395+func (_e *MockSpinnerWidget_Expecter) SetHalign(align interface{}) *MockSpinnerWidget_SetHalign_Call {
12396+ return &MockSpinnerWidget_SetHalign_Call{Call: _e.mock.On("SetHalign", align)}
12397+}
12398+
12399+func (_c *MockSpinnerWidget_SetHalign_Call) Run(run func(align gtk.Align)) *MockSpinnerWidget_SetHalign_Call {
12400+ _c.Call.Run(func(args mock.Arguments) {
12401+ var arg0 gtk.Align
12402+ if args[0] != nil {
12403+ arg0 = args[0].(gtk.Align)
12404+ }
12405+ run(
12406+ arg0,
12407+ )
12408+ })
12409+ return _c
12410+}
12411+
12412+func (_c *MockSpinnerWidget_SetHalign_Call) Return() *MockSpinnerWidget_SetHalign_Call {
12413+ _c.Call.Return()
12414+ return _c
12415+}
12416+
12417+func (_c *MockSpinnerWidget_SetHalign_Call) RunAndReturn(run func(align gtk.Align)) *MockSpinnerWidget_SetHalign_Call {
12418+ _c.Run(run)
12419+ return _c
12420+}
12421+
12422+// SetHexpand provides a mock function for the type MockSpinnerWidget
12423+func (_mock *MockSpinnerWidget) SetHexpand(expand bool) {
12424+ _mock.Called(expand)
12425+ return
12426+}
12427+
12428+// MockSpinnerWidget_SetHexpand_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetHexpand'
12429+type MockSpinnerWidget_SetHexpand_Call struct {
12430+ *mock.Call
12431+}
12432+
12433+// SetHexpand is a helper method to define mock.On call
12434+// - expand bool
12435+func (_e *MockSpinnerWidget_Expecter) SetHexpand(expand interface{}) *MockSpinnerWidget_SetHexpand_Call {
12436+ return &MockSpinnerWidget_SetHexpand_Call{Call: _e.mock.On("SetHexpand", expand)}
12437+}
12438+
12439+func (_c *MockSpinnerWidget_SetHexpand_Call) Run(run func(expand bool)) *MockSpinnerWidget_SetHexpand_Call {
12440+ _c.Call.Run(func(args mock.Arguments) {
12441+ var arg0 bool
12442+ if args[0] != nil {
12443+ arg0 = args[0].(bool)
12444+ }
12445+ run(
12446+ arg0,
12447+ )
12448+ })
12449+ return _c
12450+}
12451+
12452+func (_c *MockSpinnerWidget_SetHexpand_Call) Return() *MockSpinnerWidget_SetHexpand_Call {
12453+ _c.Call.Return()
12454+ return _c
12455+}
12456+
12457+func (_c *MockSpinnerWidget_SetHexpand_Call) RunAndReturn(run func(expand bool)) *MockSpinnerWidget_SetHexpand_Call {
12458+ _c.Run(run)
12459+ return _c
12460+}
12461+
12462+// SetSizeRequest provides a mock function for the type MockSpinnerWidget
12463+func (_mock *MockSpinnerWidget) SetSizeRequest(width int, height int) {
12464+ _mock.Called(width, height)
12465+ return
12466+}
12467+
12468+// MockSpinnerWidget_SetSizeRequest_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetSizeRequest'
12469+type MockSpinnerWidget_SetSizeRequest_Call struct {
12470+ *mock.Call
12471+}
12472+
12473+// SetSizeRequest is a helper method to define mock.On call
12474+// - width int
12475+// - height int
12476+func (_e *MockSpinnerWidget_Expecter) SetSizeRequest(width interface{}, height interface{}) *MockSpinnerWidget_SetSizeRequest_Call {
12477+ return &MockSpinnerWidget_SetSizeRequest_Call{Call: _e.mock.On("SetSizeRequest", width, height)}
12478+}
12479+
12480+func (_c *MockSpinnerWidget_SetSizeRequest_Call) Run(run func(width int, height int)) *MockSpinnerWidget_SetSizeRequest_Call {
12481+ _c.Call.Run(func(args mock.Arguments) {
12482+ var arg0 int
12483+ if args[0] != nil {
12484+ arg0 = args[0].(int)
12485+ }
12486+ var arg1 int
12487+ if args[1] != nil {
12488+ arg1 = args[1].(int)
12489+ }
12490+ run(
12491+ arg0,
12492+ arg1,
12493+ )
12494+ })
12495+ return _c
12496+}
12497+
12498+func (_c *MockSpinnerWidget_SetSizeRequest_Call) Return() *MockSpinnerWidget_SetSizeRequest_Call {
12499+ _c.Call.Return()
12500+ return _c
12501+}
12502+
12503+func (_c *MockSpinnerWidget_SetSizeRequest_Call) RunAndReturn(run func(width int, height int)) *MockSpinnerWidget_SetSizeRequest_Call {
12504+ _c.Run(run)
12505+ return _c
12506+}
12507+
12508+// SetSpinning provides a mock function for the type MockSpinnerWidget
12509+func (_mock *MockSpinnerWidget) SetSpinning(spinning bool) {
12510+ _mock.Called(spinning)
12511+ return
12512+}
12513+
12514+// MockSpinnerWidget_SetSpinning_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetSpinning'
12515+type MockSpinnerWidget_SetSpinning_Call struct {
12516+ *mock.Call
12517+}
12518+
12519+// SetSpinning is a helper method to define mock.On call
12520+// - spinning bool
12521+func (_e *MockSpinnerWidget_Expecter) SetSpinning(spinning interface{}) *MockSpinnerWidget_SetSpinning_Call {
12522+ return &MockSpinnerWidget_SetSpinning_Call{Call: _e.mock.On("SetSpinning", spinning)}
12523+}
12524+
12525+func (_c *MockSpinnerWidget_SetSpinning_Call) Run(run func(spinning bool)) *MockSpinnerWidget_SetSpinning_Call {
12526+ _c.Call.Run(func(args mock.Arguments) {
12527+ var arg0 bool
12528+ if args[0] != nil {
12529+ arg0 = args[0].(bool)
12530+ }
12531+ run(
12532+ arg0,
12533+ )
12534+ })
12535+ return _c
12536+}
12537+
12538+func (_c *MockSpinnerWidget_SetSpinning_Call) Return() *MockSpinnerWidget_SetSpinning_Call {
12539+ _c.Call.Return()
12540+ return _c
12541+}
12542+
12543+func (_c *MockSpinnerWidget_SetSpinning_Call) RunAndReturn(run func(spinning bool)) *MockSpinnerWidget_SetSpinning_Call {
12544+ _c.Run(run)
12545+ return _c
12546+}
12547+
12548+// SetValign provides a mock function for the type MockSpinnerWidget
12549+func (_mock *MockSpinnerWidget) SetValign(align gtk.Align) {
12550+ _mock.Called(align)
12551+ return
12552+}
12553+
12554+// MockSpinnerWidget_SetValign_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetValign'
12555+type MockSpinnerWidget_SetValign_Call struct {
12556+ *mock.Call
12557+}
12558+
12559+// SetValign is a helper method to define mock.On call
12560+// - align gtk.Align
12561+func (_e *MockSpinnerWidget_Expecter) SetValign(align interface{}) *MockSpinnerWidget_SetValign_Call {
12562+ return &MockSpinnerWidget_SetValign_Call{Call: _e.mock.On("SetValign", align)}
12563+}
12564+
12565+func (_c *MockSpinnerWidget_SetValign_Call) Run(run func(align gtk.Align)) *MockSpinnerWidget_SetValign_Call {
12566+ _c.Call.Run(func(args mock.Arguments) {
12567+ var arg0 gtk.Align
12568+ if args[0] != nil {
12569+ arg0 = args[0].(gtk.Align)
12570+ }
12571+ run(
12572+ arg0,
12573+ )
12574+ })
12575+ return _c
12576+}
12577+
12578+func (_c *MockSpinnerWidget_SetValign_Call) Return() *MockSpinnerWidget_SetValign_Call {
12579+ _c.Call.Return()
12580+ return _c
12581+}
12582+
12583+func (_c *MockSpinnerWidget_SetValign_Call) RunAndReturn(run func(align gtk.Align)) *MockSpinnerWidget_SetValign_Call {
12584+ _c.Run(run)
12585+ return _c
12586+}
12587+
12588+// SetVexpand provides a mock function for the type MockSpinnerWidget
12589+func (_mock *MockSpinnerWidget) SetVexpand(expand bool) {
12590+ _mock.Called(expand)
12591+ return
12592+}
12593+
12594+// MockSpinnerWidget_SetVexpand_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetVexpand'
12595+type MockSpinnerWidget_SetVexpand_Call struct {
12596+ *mock.Call
12597+}
12598+
12599+// SetVexpand is a helper method to define mock.On call
12600+// - expand bool
12601+func (_e *MockSpinnerWidget_Expecter) SetVexpand(expand interface{}) *MockSpinnerWidget_SetVexpand_Call {
12602+ return &MockSpinnerWidget_SetVexpand_Call{Call: _e.mock.On("SetVexpand", expand)}
12603+}
12604+
12605+func (_c *MockSpinnerWidget_SetVexpand_Call) Run(run func(expand bool)) *MockSpinnerWidget_SetVexpand_Call {
12606+ _c.Call.Run(func(args mock.Arguments) {
12607+ var arg0 bool
12608+ if args[0] != nil {
12609+ arg0 = args[0].(bool)
12610+ }
12611+ run(
12612+ arg0,
12613+ )
12614+ })
12615+ return _c
12616+}
12617+
12618+func (_c *MockSpinnerWidget_SetVexpand_Call) Return() *MockSpinnerWidget_SetVexpand_Call {
12619+ _c.Call.Return()
12620+ return _c
12621+}
12622+
12623+func (_c *MockSpinnerWidget_SetVexpand_Call) RunAndReturn(run func(expand bool)) *MockSpinnerWidget_SetVexpand_Call {
12624+ _c.Run(run)
12625+ return _c
12626+}
12627+
12628+// SetVisible provides a mock function for the type MockSpinnerWidget
12629+func (_mock *MockSpinnerWidget) SetVisible(visible bool) {
12630+ _mock.Called(visible)
12631+ return
12632+}
12633+
12634+// MockSpinnerWidget_SetVisible_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetVisible'
12635+type MockSpinnerWidget_SetVisible_Call struct {
12636+ *mock.Call
12637+}
12638+
12639+// SetVisible is a helper method to define mock.On call
12640+// - visible bool
12641+func (_e *MockSpinnerWidget_Expecter) SetVisible(visible interface{}) *MockSpinnerWidget_SetVisible_Call {
12642+ return &MockSpinnerWidget_SetVisible_Call{Call: _e.mock.On("SetVisible", visible)}
12643+}
12644+
12645+func (_c *MockSpinnerWidget_SetVisible_Call) Run(run func(visible bool)) *MockSpinnerWidget_SetVisible_Call {
12646+ _c.Call.Run(func(args mock.Arguments) {
12647+ var arg0 bool
12648+ if args[0] != nil {
12649+ arg0 = args[0].(bool)
12650+ }
12651+ run(
12652+ arg0,
12653+ )
12654+ })
12655+ return _c
12656+}
12657+
12658+func (_c *MockSpinnerWidget_SetVisible_Call) Return() *MockSpinnerWidget_SetVisible_Call {
12659+ _c.Call.Return()
12660+ return _c
12661+}
12662+
12663+func (_c *MockSpinnerWidget_SetVisible_Call) RunAndReturn(run func(visible bool)) *MockSpinnerWidget_SetVisible_Call {
12664+ _c.Run(run)
12665+ return _c
12666+}
12667+
12668+// Show provides a mock function for the type MockSpinnerWidget
12669+func (_mock *MockSpinnerWidget) Show() {
12670+ _mock.Called()
12671+ return
12672+}
12673+
12674+// MockSpinnerWidget_Show_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Show'
12675+type MockSpinnerWidget_Show_Call struct {
12676+ *mock.Call
12677+}
12678+
12679+// Show is a helper method to define mock.On call
12680+func (_e *MockSpinnerWidget_Expecter) Show() *MockSpinnerWidget_Show_Call {
12681+ return &MockSpinnerWidget_Show_Call{Call: _e.mock.On("Show")}
12682+}
12683+
12684+func (_c *MockSpinnerWidget_Show_Call) Run(run func()) *MockSpinnerWidget_Show_Call {
12685+ _c.Call.Run(func(args mock.Arguments) {
12686+ run()
12687+ })
12688+ return _c
12689+}
12690+
12691+func (_c *MockSpinnerWidget_Show_Call) Return() *MockSpinnerWidget_Show_Call {
12692+ _c.Call.Return()
12693+ return _c
12694+}
12695+
12696+func (_c *MockSpinnerWidget_Show_Call) RunAndReturn(run func()) *MockSpinnerWidget_Show_Call {
12697+ _c.Run(run)
12698+ return _c
12699+}
12700+
12701+// Start provides a mock function for the type MockSpinnerWidget
12702+func (_mock *MockSpinnerWidget) Start() {
12703+ _mock.Called()
12704+ return
12705+}
12706+
12707+// MockSpinnerWidget_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start'
12708+type MockSpinnerWidget_Start_Call struct {
12709+ *mock.Call
12710+}
12711+
12712+// Start is a helper method to define mock.On call
12713+func (_e *MockSpinnerWidget_Expecter) Start() *MockSpinnerWidget_Start_Call {
12714+ return &MockSpinnerWidget_Start_Call{Call: _e.mock.On("Start")}
12715+}
12716+
12717+func (_c *MockSpinnerWidget_Start_Call) Run(run func()) *MockSpinnerWidget_Start_Call {
12718+ _c.Call.Run(func(args mock.Arguments) {
12719+ run()
12720+ })
12721+ return _c
12722+}
12723+
12724+func (_c *MockSpinnerWidget_Start_Call) Return() *MockSpinnerWidget_Start_Call {
12725+ _c.Call.Return()
12726+ return _c
12727+}
12728+
12729+func (_c *MockSpinnerWidget_Start_Call) RunAndReturn(run func()) *MockSpinnerWidget_Start_Call {
12730+ _c.Run(run)
12731+ return _c
12732+}
12733+
12734+// Stop provides a mock function for the type MockSpinnerWidget
12735+func (_mock *MockSpinnerWidget) Stop() {
12736+ _mock.Called()
12737+ return
12738+}
12739+
12740+// MockSpinnerWidget_Stop_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Stop'
12741+type MockSpinnerWidget_Stop_Call struct {
12742+ *mock.Call
12743+}
12744+
12745+// Stop is a helper method to define mock.On call
12746+func (_e *MockSpinnerWidget_Expecter) Stop() *MockSpinnerWidget_Stop_Call {
12747+ return &MockSpinnerWidget_Stop_Call{Call: _e.mock.On("Stop")}
12748+}
12749+
12750+func (_c *MockSpinnerWidget_Stop_Call) Run(run func()) *MockSpinnerWidget_Stop_Call {
12751+ _c.Call.Run(func(args mock.Arguments) {
12752+ run()
12753+ })
12754+ return _c
12755+}
12756+
12757+func (_c *MockSpinnerWidget_Stop_Call) Return() *MockSpinnerWidget_Stop_Call {
12758+ _c.Call.Return()
12759+ return _c
12760+}
12761+
12762+func (_c *MockSpinnerWidget_Stop_Call) RunAndReturn(run func()) *MockSpinnerWidget_Stop_Call {
12763+ _c.Run(run)
12764+ return _c
12765+}
12766+
12767+// Unparent provides a mock function for the type MockSpinnerWidget
12768+func (_mock *MockSpinnerWidget) Unparent() {
12769+ _mock.Called()
12770+ return
12771+}
12772+
12773+// MockSpinnerWidget_Unparent_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unparent'
12774+type MockSpinnerWidget_Unparent_Call struct {
12775+ *mock.Call
12776+}
12777+
12778+// Unparent is a helper method to define mock.On call
12779+func (_e *MockSpinnerWidget_Expecter) Unparent() *MockSpinnerWidget_Unparent_Call {
12780+ return &MockSpinnerWidget_Unparent_Call{Call: _e.mock.On("Unparent")}
12781+}
12782+
12783+func (_c *MockSpinnerWidget_Unparent_Call) Run(run func()) *MockSpinnerWidget_Unparent_Call {
12784+ _c.Call.Run(func(args mock.Arguments) {
12785+ run()
12786+ })
12787+ return _c
12788+}
12789+
12790+func (_c *MockSpinnerWidget_Unparent_Call) Return() *MockSpinnerWidget_Unparent_Call {
12791+ _c.Call.Return()
12792+ return _c
12793+}
12794+
12795+func (_c *MockSpinnerWidget_Unparent_Call) RunAndReturn(run func()) *MockSpinnerWidget_Unparent_Call {
12796+ _c.Run(run)
12797+ return _c
12798+}
12799+
11521 // NewMockWidgetFactory creates a new instance of MockWidgetFactory. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.12800 // NewMockWidgetFactory creates a new instance of MockWidgetFactory. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
11522 // The first argument is typically a *testing.T value.12801 // The first argument is typically a *testing.T value.
11523 func NewMockWidgetFactory(t interface {12802 func NewMockWidgetFactory(t interface {
@@ -11894,6 +13173,52 @@ func (_c *MockWidgetFactory_NewProgressBar_Call) RunAndReturn(run func() layout.
11894 return _c13173 return _c
11895 }13174 }
11896 13175
13176+// NewSpinner provides a mock function for the type MockWidgetFactory
13177+func (_mock *MockWidgetFactory) NewSpinner() layout.SpinnerWidget {
13178+ ret := _mock.Called()
13179+
13180+ if len(ret) == 0 {
13181+ panic("no return value specified for NewSpinner")
13182+ }
13183+
13184+ var r0 layout.SpinnerWidget
13185+ if returnFunc, ok := ret.Get(0).(func() layout.SpinnerWidget); ok {
13186+ r0 = returnFunc()
13187+ } else {
13188+ if ret.Get(0) != nil {
13189+ r0 = ret.Get(0).(layout.SpinnerWidget)
13190+ }
13191+ }
13192+ return r0
13193+}
13194+
13195+// MockWidgetFactory_NewSpinner_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewSpinner'
13196+type MockWidgetFactory_NewSpinner_Call struct {
13197+ *mock.Call
13198+}
13199+
13200+// NewSpinner is a helper method to define mock.On call
13201+func (_e *MockWidgetFactory_Expecter) NewSpinner() *MockWidgetFactory_NewSpinner_Call {
13202+ return &MockWidgetFactory_NewSpinner_Call{Call: _e.mock.On("NewSpinner")}
13203+}
13204+
13205+func (_c *MockWidgetFactory_NewSpinner_Call) Run(run func()) *MockWidgetFactory_NewSpinner_Call {
13206+ _c.Call.Run(func(args mock.Arguments) {
13207+ run()
13208+ })
13209+ return _c
13210+}
13211+
13212+func (_c *MockWidgetFactory_NewSpinner_Call) Return(spinnerWidget layout.SpinnerWidget) *MockWidgetFactory_NewSpinner_Call {
13213+ _c.Call.Return(spinnerWidget)
13214+ return _c
13215+}
13216+
13217+func (_c *MockWidgetFactory_NewSpinner_Call) RunAndReturn(run func() layout.SpinnerWidget) *MockWidgetFactory_NewSpinner_Call {
13218+ _c.Call.Return(run)
13219+ return _c
13220+}
13221+
11897 // WrapWidget provides a mock function for the type MockWidgetFactory13222 // WrapWidget provides a mock function for the type MockWidgetFactory
11898 func (_mock *MockWidgetFactory) WrapWidget(w *gtk.Widget) layout.Widget {13223 func (_mock *MockWidgetFactory) WrapWidget(w *gtk.Widget) layout.Widget {
11899 ret := _mock.Called(w)13224 ret := _mock.Called(w)
M internal/ui/layout/widgets.go +11 -0
@@ -211,6 +211,16 @@ type ProgressBarWidget interface {
211211 GetFraction() float64
212212 }
213213
214+// SpinnerWidget wraps gtk.Spinner for displaying indefinite loading.
215+type SpinnerWidget interface {
216+ Widget
217+
218+ Start()
219+ Stop()
220+ SetSpinning(spinning bool)
221+ GetSpinning() bool
222+}
223+
214224 // WidgetFactory creates widget instances.
215225 // This abstraction allows tests to inject mock factories.
216226 type WidgetFactory interface {
@@ -224,6 +234,7 @@ type WidgetFactory interface {
224234 NewButton() ButtonWidget
225235 NewImage() ImageWidget
226236 NewProgressBar() ProgressBarWidget
237+ NewSpinner() SpinnerWidget
227238
228239 // Wrap existing GTK widget
229240 WrapWidget(w *gtk.Widget) Widget
@@ -211,6 +211,16 @@ type ProgressBarWidget interface {
211 GetFraction() float64211 GetFraction() float64
212 }212 }
213 213
214+// SpinnerWidget wraps gtk.Spinner for displaying indefinite loading.
215+type SpinnerWidget interface {
216+ Widget
217+
218+ Start()
219+ Stop()
220+ SetSpinning(spinning bool)
221+ GetSpinning() bool
222+}
223+
214 // WidgetFactory creates widget instances.224 // WidgetFactory creates widget instances.
215 // This abstraction allows tests to inject mock factories.225 // This abstraction allows tests to inject mock factories.
216 type WidgetFactory interface {226 type WidgetFactory interface {
@@ -224,6 +234,7 @@ type WidgetFactory interface {
224 NewButton() ButtonWidget234 NewButton() ButtonWidget
225 NewImage() ImageWidget235 NewImage() ImageWidget
226 NewProgressBar() ProgressBarWidget236 NewProgressBar() ProgressBarWidget
237+ NewSpinner() SpinnerWidget
227 238
228 // Wrap existing GTK widget239 // Wrap existing GTK widget
229 WrapWidget(w *gtk.Widget) Widget240 WrapWidget(w *gtk.Widget) Widget
M internal/ui/theme/css.go +18 -0
@@ -447,6 +447,24 @@ func generatePaneCSS(p Palette) string {
447447 background-color: var(--bg);
448448 }
449449
450+/* Loading skeleton - shown until WebView paints */
451+.loading-skeleton {
452+ background-color: var(--bg);
453+}
454+
455+.loading-skeleton-spinner {
456+ -gtk-icon-size: 32px;
457+ min-width: 32px;
458+ min-height: 32px;
459+}
460+
461+.loading-skeleton-text {
462+ font-family: var(--font-mono);
463+ font-size: 1.5em;
464+ letter-spacing: 0.1em;
465+ color: var(--muted);
466+}
467+
450468 /* Pane border - default transparent */
451469 .pane-border {
452470 border: 0.0625em solid transparent;
@@ -447,6 +447,24 @@ func generatePaneCSS(p Palette) string {
447 background-color: var(--bg);447 background-color: var(--bg);
448 }448 }
449 449
450+/* Loading skeleton - shown until WebView paints */
451+.loading-skeleton {
452+ background-color: var(--bg);
453+}
454+
455+.loading-skeleton-spinner {
456+ -gtk-icon-size: 32px;
457+ min-width: 32px;
458+ min-height: 32px;
459+}
460+
461+.loading-skeleton-text {
462+ font-family: var(--font-mono);
463+ font-size: 1.5em;
464+ letter-spacing: 0.1em;
465+ color: var(--muted);
466+}
467+
450 /* Pane border - default transparent */468 /* Pane border - default transparent */
451 .pane-border {469 .pane-border {
452 border: 0.0625em solid transparent;470 border: 0.0625em solid transparent;

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