1// Package usecase contains application use cases that orchestrate domain logic.
2package usecase
3
4import (
5 "context"
6 "errors"
7 "fmt"
8
9 "github.com/bnema/dumber/internal/application/port"
10)
11
12// PageScrollCommand represents a semantic page scroll action.
13// Each command maps to a fixed pixel delta defined in this package.
14type PageScrollCommand int
15
16const (
17 PageScrollLeft PageScrollCommand = iota // scroll left by small horizontal amount
18 PageScrollRight // scroll right by small horizontal amount
19 PageScrollUp // scroll up by small vertical amount
20 PageScrollDown // scroll down by small vertical amount
21 PageScrollUpFast // scroll up by fast vertical amount
22 PageScrollDownFast // scroll down by fast vertical amount
23)
24
25// Internal fixed pixel defaults for page scroll commands.
26// These are application-layer constants, not user-configurable.
27const (
28 scrollSmallHorizontal = 80
29 scrollSmallVertical = 80
30 scrollFastVertical = 320
31)
32
33// PageScrollUseCase handles semantic page scrolling commands.
34// It maps semantic scroll actions (left, down, up-fast, etc.) to pixel deltas
35// and delegates to the WebView's scroll capability. No UI logic or
36// engine-specific JavaScript exists in this layer.
37type PageScrollUseCase struct{}
38
39// NewPageScrollUseCase creates a new PageScrollUseCase.
40func NewPageScrollUseCase() *PageScrollUseCase {
41 return &PageScrollUseCase{}
42}
43
44// Scroll applies a semantic scroll command to a WebView.
45// It returns an error if the WebView does not support semantic page scrolling
46// (i.e., does not implement port.PageScrollable).
47func (uc *PageScrollUseCase) Scroll(ctx context.Context, wv port.WebView, cmd PageScrollCommand) error {
48 return uc.scroll(ctx, wv, cmd, false)
49}
50
51// ScrollContinuous applies one autonomous held-key step. The pixel policy is
52// identical to Scroll; only lifecycle metadata differs for adapter coalescing.
53func (uc *PageScrollUseCase) ScrollContinuous(ctx context.Context, wv port.WebView, cmd PageScrollCommand) error {
54 return uc.scroll(ctx, wv, cmd, true)
55}
56
57// Stop cancels queued continuous work when the adapter supports cancellation.
58// Adapters such as WebKit that execute each step immediately need no special
59// capability and therefore treat this as a no-op.
60func (*PageScrollUseCase) Stop(ctx context.Context, wv port.WebView) error {
61 if wv == nil {
62 return errors.New("page scroll: nil webview")
63 }
64 if canceler, ok := wv.(port.PageScrollCanceler); ok {
65 canceler.CancelPageScroll(ctx)
66 }
67 return nil
68}
69
70func (*PageScrollUseCase) scroll(ctx context.Context, wv port.WebView, cmd PageScrollCommand, continuous bool) error {
71 if wv == nil {
72 return errors.New("page scroll: nil webview")
73 }
74
75 scroller, ok := wv.(port.PageScrollable)
76 if !ok {
77 return errors.New("page scroll: webview does not support page scrolling")
78 }
79
80 dx, dy := scrollDelta(cmd)
81 req := port.PageScrollRequest{
82 Command: toPortPageScrollCommand(cmd),
83 FallbackDX: dx,
84 FallbackDY: dy,
85 Continuous: continuous,
86 }
87 if err := scroller.ScrollPage(ctx, req); err != nil {
88 return fmt.Errorf("page scroll: %w", err)
89 }
90 return nil
91}
92
93func toPortPageScrollCommand(cmd PageScrollCommand) port.PageScrollCommand {
94 switch cmd {
95 case PageScrollLeft:
96 return port.PageScrollCommandLeft
97 case PageScrollRight:
98 return port.PageScrollCommandRight
99 case PageScrollUp:
100 return port.PageScrollCommandUp
101 case PageScrollDown:
102 return port.PageScrollCommandDown
103 case PageScrollUpFast:
104 return port.PageScrollCommandUpFast
105 case PageScrollDownFast:
106 return port.PageScrollCommandDownFast
107 default:
108 return port.PageScrollCommand(-1)
109 }
110}
111
112// scrollDelta returns the pixel delta for a PageScrollCommand.
113func scrollDelta(cmd PageScrollCommand) (dx, dy int) {
114 switch cmd {
115 case PageScrollLeft:
116 return -scrollSmallHorizontal, 0
117 case PageScrollRight:
118 return scrollSmallHorizontal, 0
119 case PageScrollUp:
120 return 0, -scrollSmallVertical
121 case PageScrollDown:
122 return 0, scrollSmallVertical
123 case PageScrollUpFast:
124 return 0, -scrollFastVertical
125 case PageScrollDownFast:
126 return 0, scrollFastVertical
127 default:
128 return 0, 0
129 }
130}
131
132// String returns a human-readable name for the scroll command.
133func (cmd PageScrollCommand) String() string {
134 switch cmd {
135 case PageScrollLeft:
136 return "left"
137 case PageScrollRight:
138 return "right"
139 case PageScrollUp:
140 return "up"
141 case PageScrollDown:
142 return "down"
143 case PageScrollUpFast:
144 return "up-fast"
145 case PageScrollDownFast:
146 return "down-fast"
147 default:
148 return "unknown"
149 }
150}