1package handlers
2
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "unicode/utf8"
8
9 "github.com/bnema/dumber/internal/application/port"
10 "github.com/bnema/dumber/internal/infrastructure/webkit"
11 "github.com/bnema/dumber/internal/infrastructure/webkit/handlers/homepage"
12)
13
14// AccentKeyHandler is implemented by the InsertAccentUseCase to receive
15// key press/release events forwarded from WebView JS via the message bridge.
16//
17// Deprecated: use port.AccentKeyHandler instead. This alias is kept for compatibility.
18type AccentKeyHandler = port.AccentKeyHandler
19
20// Config holds all dependencies for message handlers.
21type Config struct {
22 HistoryUC port.HomepageHistory
23 FavoritesUC port.HomepageFavorites
24 Clipboard port.Clipboard
25 AutoCopyConfig port.AutoCopyConfig
26 SaveConfig func(context.Context, port.WebUIConfig) error // Pre-built by bootstrap (usecase.SaveWebUIConfigUseCase.Execute)
27 // KeybindingsHandler is required (not optional like other handlers) because the WebUI
28 // always needs keybinding read/write support regardless of configuration.
29 KeybindingsHandler *KeybindingsHandler // Pre-built by bootstrap
30 OnClipboardCopied func(textLen int) // Called when auto-copy completes (for toast notification)
31}
32
33// RegisterAll registers all message handlers with the router.
34func RegisterAll(ctx context.Context, router *webkit.MessageRouter, cfg Config) error {
35 // Homepage handlers (history, favorites, folders, tags)
36 if cfg.HistoryUC != nil && cfg.FavoritesUC != nil {
37 if err := homepage.RegisterHandlers(ctx, router, homepage.Config{
38 HistoryUC: cfg.HistoryUC,
39 FavoritesUC: cfg.FavoritesUC,
40 }); err != nil {
41 return err
42 }
43 }
44
45 // Configuration handlers
46 if cfg.SaveConfig != nil {
47 if err := RegisterConfigHandlers(ctx, router, cfg.SaveConfig); err != nil {
48 return err
49 }
50 }
51
52 // Keybindings handlers (always available)
53 if cfg.KeybindingsHandler == nil {
54 return fmt.Errorf("KeybindingsHandler is required")
55 }
56 if err := RegisterKeybindingsHandlers(ctx, router, cfg.KeybindingsHandler); err != nil {
57 return err
58 }
59
60 // Clipboard handlers (for auto-copy on selection feature)
61 if cfg.Clipboard != nil && cfg.AutoCopyConfig != nil {
62 if err := RegisterClipboardHandlers(ctx, router, cfg.Clipboard, cfg.AutoCopyConfig, cfg.OnClipboardCopied); err != nil {
63 return err
64 }
65 }
66
67 return nil
68}
69
70// RegisterAccentHandlers registers accent key press/release handlers with the router.
71// Must be called after the AccentKeyHandler is initialized (i.e., after initAccentPicker).
72func RegisterAccentHandlers(_ context.Context, router *webkit.MessageRouter, handler AccentKeyHandler) error {
73 if router == nil {
74 return fmt.Errorf("RegisterAccentHandlers: router must not be nil")
75 }
76 if handler == nil {
77 return fmt.Errorf("RegisterAccentHandlers: handler must not be nil")
78 }
79
80 if err := router.RegisterHandler("accent_key_press", webkit.MessageHandlerFunc(
81 func(ctx context.Context, _ webkit.WebViewID, payload json.RawMessage) (any, error) {
82 var p struct {
83 Char string `json:"char"`
84 Shift bool `json:"shift"`
85 }
86 if err := json.Unmarshal(payload, &p); err != nil {
87 return nil, err
88 }
89 if r, _ := utf8.DecodeRuneInString(p.Char); r != utf8.RuneError && utf8.RuneCountInString(p.Char) == 1 {
90 handler.OnKeyPressed(ctx, r, p.Shift)
91 }
92 return nil, nil
93 },
94 )); err != nil {
95 return err
96 }
97
98 if err := router.RegisterHandler("accent_key_release", webkit.MessageHandlerFunc(
99 func(ctx context.Context, _ webkit.WebViewID, payload json.RawMessage) (any, error) {
100 var p struct {
101 Char string `json:"char"`
102 }
103 if err := json.Unmarshal(payload, &p); err != nil {
104 return nil, err
105 }
106 if r, _ := utf8.DecodeRuneInString(p.Char); r != utf8.RuneError && utf8.RuneCountInString(p.Char) == 1 {
107 handler.OnKeyReleased(ctx, r)
108 }
109 return nil, nil
110 },
111 )); err != nil {
112 return err
113 }
114
115 return nil
116}