1package control
2
3import (
4 "context"
5 "fmt"
6 "log"
7
8 "github.com/bnema/dumber/pkg/webkit"
9 "github.com/bnema/dumber/services"
10)
11
12// ZoomController manages zoom functionality for the WebView
13type ZoomController struct {
14 currentURL string
15 lastZoomDomain string
16 programmaticChange bool
17 browserService *services.BrowserService
18 webView *webkit.WebView
19}
20
21// WebViewInterface defines the interface for WebView zoom operations
22type WebViewInterface interface {
23 GetCurrentURL() string
24 SetZoom(level float64) error
25 InjectScript(script string) error
26 RegisterZoomChangedHandler(handler func(float64))
27 RegisterURIChangedHandler(handler func(string))
28}
29
30// NewZoomController creates a new zoom controller
31func NewZoomController(browserService *services.BrowserService, webView *webkit.WebView) *ZoomController {
32 return &ZoomController{
33 currentURL: "dumb://homepage",
34 browserService: browserService,
35 webView: webView,
36 }
37}
38
39// RegisterHandlers sets up the zoom-related event handlers
40func (z *ZoomController) RegisterHandlers() {
41 z.webView.RegisterZoomChangedHandler(z.handleZoomChange)
42 z.webView.RegisterURIChangedHandler(z.handleURIChange)
43}
44
45// handleURIChange responds to URL changes and applies saved zoom levels
46func (z *ZoomController) handleURIChange(url string) {
47 z.currentURL = url
48 if url == "" {
49 return
50 }
51 ctx := context.Background()
52 currentDomain := services.ZoomKeyForLog(url)
53
54 if zoomLevel, err := z.browserService.GetZoomLevel(ctx, url); err == nil {
55 z.programmaticChange = true
56 if err := z.webView.SetZoom(zoomLevel); err == nil {
57 log.Printf("[zoom] loaded %.2f for %s", zoomLevel, currentDomain)
58
59 // Only show toast when entering a new domain (not on first load)
60 if currentDomain != z.lastZoomDomain && z.lastZoomDomain != "" {
61 z.showZoomToast(zoomLevel)
62 }
63 z.lastZoomDomain = currentDomain
64 }
65 z.programmaticChange = false
66 }
67}
68
69// handleZoomChange responds to zoom level changes and persists them
70func (z *ZoomController) handleZoomChange(level float64) {
71 url := z.webView.GetCurrentURL()
72 if url == "" {
73 return
74 }
75 ctx := context.Background()
76 if err := z.browserService.SetZoomLevel(ctx, url, level); err != nil {
77 log.Printf("[zoom] failed to save level %.2f for %s: %v", level, url, err)
78 return
79 }
80 key := services.ZoomKeyForLog(url)
81 log.Printf("[zoom] saved %.2f for %s", level, key)
82
83 // Only show toast for user-initiated zoom changes, not programmatic ones
84 if !z.programmaticChange {
85 z.showZoomToast(level)
86 }
87}
88
89// showZoomToast displays a zoom level notification
90func (z *ZoomController) showZoomToast(level float64) {
91 js := fmt.Sprintf(`try {
92 if (typeof window.__dumber_showZoomToast === 'function') {
93 window.__dumber_showZoomToast(%f);
94 } else {
95 console.warn('[dumber] Zoom toast function not available yet');
96 }
97 } catch(e) {
98 console.error('[dumber] Zoom toast error:', e);
99 }`, level)
100 if err := z.webView.InjectScript(js); err != nil {
101 log.Printf("[zoom] failed to show toast: %v", err)
102 }
103}
104
105// ApplyInitialZoom sets the initial zoom level for the current URL
106func (z *ZoomController) ApplyInitialZoom() {
107 ctx := context.Background()
108 url := z.webView.GetCurrentURL()
109 if url == "" {
110 url = "dumb://homepage"
111 }
112 if zoomLevel, err := z.browserService.GetZoomLevel(ctx, url); err == nil {
113 z.programmaticChange = true
114 if err := z.webView.SetZoom(zoomLevel); err != nil {
115 log.Printf("Warning: failed to set initial zoom: %v", err)
116 } else {
117 key := services.ZoomKeyForLog(url)
118 log.Printf("[zoom] loaded %.2f for %s", zoomLevel, key)
119 }
120 z.programmaticChange = false
121 }
122}
123
124// ApplyZoomForURL applies zoom for a specific URL (used for navigation)
125func (z *ZoomController) ApplyZoomForURL(url string) {
126 ctx := context.Background()
127 if zoomLevel, err := z.browserService.GetZoomLevel(ctx, url); err == nil {
128 z.programmaticChange = true
129 if err := z.webView.SetZoom(zoomLevel); err != nil {
130 log.Printf("Warning: failed to set zoom: %v", err)
131 } else {
132 key := services.ZoomKeyForLog(url)
133 log.Printf("[zoom] loaded %.2f for %s", zoomLevel, key)
134 }
135 z.programmaticChange = false
136 }
137}