1package control
2
3import (
4 "context"
5 "log"
6 "os"
7
8 "github.com/bnema/dumber/internal/services"
9 "github.com/bnema/dumber/pkg/webkit"
10)
11
12// NavigationController manages navigation functionality
13type NavigationController struct {
14 parserService *services.ParserService
15 browserService *services.BrowserService
16 webView *webkit.WebView
17 zoomController *ZoomController
18}
19
20// NewNavigationController creates a new navigation controller
21func NewNavigationController(
22 parserService *services.ParserService,
23 browserService *services.BrowserService,
24 webView *webkit.WebView,
25 zoomController *ZoomController,
26) *NavigationController {
27 return &NavigationController{
28 parserService: parserService,
29 browserService: browserService,
30 webView: webView,
31 zoomController: zoomController,
32 }
33}
34
35// NavigateToURL parses input and navigates to the resulting URL
36func (n *NavigationController) NavigateToURL(input string) error {
37 ctx := context.Background()
38 result, err := n.parserService.ParseInput(ctx, input)
39 if err != nil {
40 return err
41 }
42
43 // Record navigation in browser service
44 if _, navErr := n.browserService.Navigate(ctx, result.URL); navErr != nil {
45 log.Printf("Warning: failed to navigate to %s: %v", result.URL, navErr)
46 }
47
48 var (
49 zoomLevel float64
50 haveZoom bool
51 )
52 if n.browserService != nil {
53 if level, err := n.browserService.GetZoomLevel(ctx, result.URL); err == nil {
54 zoomLevel = level
55 haveZoom = true
56 if n.webView != nil {
57 if n.webView.UsesDomZoom() {
58 if err := n.webView.SeedDomZoom(zoomLevel); err != nil {
59 log.Printf("Warning: failed to seed DOM zoom for %s: %v", result.URL, err)
60 }
61 } else {
62 n.webView.RunOnMainThread(func() {
63 if err := n.webView.SetZoom(zoomLevel); err != nil {
64 log.Printf("Warning: failed to prime native zoom for %s: %v", result.URL, err)
65 }
66 })
67 }
68 }
69 } else {
70 log.Printf("Warning: failed to lookup zoom for %s: %v", result.URL, err)
71 }
72 }
73
74 // Load URL in WebView
75 if err := n.webView.LoadURL(result.URL); err != nil {
76 return err
77 }
78
79 // Apply zoom for the new URL using the cached level when available.
80 if n.zoomController != nil {
81 if haveZoom {
82 n.zoomController.ApplyZoomForURLWithLevel(result.URL, zoomLevel, false)
83 } else {
84 n.zoomController.ApplyZoomForURL(result.URL)
85 }
86 }
87
88 return nil
89}
90
91// HandleBrowseCommand processes the browse command line argument
92func (n *NavigationController) HandleBrowseCommand() {
93 if len(os.Args) >= 3 && os.Args[1] == "browse" {
94 log.Printf("Browse command detected: %s", os.Args[2])
95 ctx := context.Background()
96 result, err := n.parserService.ParseInput(ctx, os.Args[2])
97 if err == nil {
98 log.Printf("Parsed input → URL: %s", result.URL)
99 if _, navErr := n.browserService.Navigate(ctx, result.URL); navErr != nil {
100 log.Printf("Warning: failed to navigate to %s: %v", result.URL, navErr)
101 }
102 if n.webView != nil {
103 log.Printf("Loading URL in WebView: %s", result.URL)
104 var (
105 zoomLevel float64
106 haveZoom bool
107 )
108 if n.browserService != nil {
109 if level, err := n.browserService.GetZoomLevel(ctx, result.URL); err == nil {
110 zoomLevel = level
111 haveZoom = true
112 if n.webView.UsesDomZoom() {
113 if err := n.webView.SeedDomZoom(zoomLevel); err != nil {
114 log.Printf("Warning: failed to seed DOM zoom for %s: %v", result.URL, err)
115 }
116 } else {
117 n.webView.RunOnMainThread(func() {
118 if err := n.webView.SetZoom(zoomLevel); err != nil {
119 log.Printf("Warning: failed to prime native zoom for %s: %v", result.URL, err)
120 }
121 })
122 }
123 } else {
124 log.Printf("Warning: failed to lookup zoom for %s: %v", result.URL, err)
125 }
126 }
127 if err := n.webView.LoadURL(result.URL); err != nil {
128 log.Printf("Warning: failed to load URL: %v", err)
129 }
130 if n.zoomController != nil {
131 if haveZoom {
132 n.zoomController.ApplyZoomForURLWithLevel(result.URL, zoomLevel, false)
133 } else {
134 n.zoomController.ApplyZoomForURL(result.URL)
135 }
136 }
137 }
138 }
139 }
140}
141
142// Detach releases the associated WebView to avoid calls after destruction.
143func (n *NavigationController) Detach() {
144 if n == nil {
145 return
146 }
147 n.webView = nil
148}