feat(window): add file drop support to PlatformWindow interface
Adds OnFileDrop(handler func(paths []string, targetID string)) to PlatformWindow. trackWindow() now wires file drop callbacks to ActionFilesDropped broadcasts. Updates both exported MockWindow and unexported mockWindow with the new method. Wails adapter maps WindowFilesDropped event with DroppedFiles and DropTargetDetails. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1e0b89b94e
commit
23bf0302d3
7 changed files with 80 additions and 0 deletions
|
|
@ -72,3 +72,9 @@ type ActionWindowResized struct {
|
|||
|
||||
type ActionWindowFocused struct{ Name string }
|
||||
type ActionWindowBlurred struct{ Name string }
|
||||
|
||||
type ActionFilesDropped struct {
|
||||
Name string `json:"name"` // window name
|
||||
Paths []string `json:"paths"`
|
||||
TargetID string `json:"targetId,omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ type MockWindow struct {
|
|||
visible, alwaysOnTop bool
|
||||
closed bool
|
||||
eventHandlers []func(WindowEvent)
|
||||
fileDropHandlers []func(paths []string, targetID string)
|
||||
}
|
||||
|
||||
func (w *MockWindow) Name() string { return w.name }
|
||||
|
|
@ -58,3 +59,6 @@ func (w *MockWindow) Hide() { w.visible = fals
|
|||
func (w *MockWindow) Fullscreen() {}
|
||||
func (w *MockWindow) UnFullscreen() {}
|
||||
func (w *MockWindow) OnWindowEvent(handler func(WindowEvent)) { w.eventHandlers = append(w.eventHandlers, handler) }
|
||||
func (w *MockWindow) OnFileDrop(handler func(paths []string, targetID string)) {
|
||||
w.fileDropHandlers = append(w.fileDropHandlers, handler)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ type mockWindow struct {
|
|||
visible, alwaysOnTop bool
|
||||
closed bool
|
||||
eventHandlers []func(WindowEvent)
|
||||
fileDropHandlers []func(paths []string, targetID string)
|
||||
}
|
||||
|
||||
func (w *mockWindow) Name() string { return w.name }
|
||||
|
|
@ -57,6 +58,9 @@ func (w *mockWindow) Hide() { w.visible = fals
|
|||
func (w *mockWindow) Fullscreen() {}
|
||||
func (w *mockWindow) UnFullscreen() {}
|
||||
func (w *mockWindow) OnWindowEvent(handler func(WindowEvent)) { w.eventHandlers = append(w.eventHandlers, handler) }
|
||||
func (w *mockWindow) OnFileDrop(handler func(paths []string, targetID string)) {
|
||||
w.fileDropHandlers = append(w.fileDropHandlers, handler)
|
||||
}
|
||||
|
||||
// emit fires a test event to all registered handlers.
|
||||
func (w *mockWindow) emit(e WindowEvent) {
|
||||
|
|
@ -64,3 +68,10 @@ func (w *mockWindow) emit(e WindowEvent) {
|
|||
h(e)
|
||||
}
|
||||
}
|
||||
|
||||
// emitFileDrop simulates a file drop on the window.
|
||||
func (w *mockWindow) emitFileDrop(paths []string, targetID string) {
|
||||
for _, h := range w.fileDropHandlers {
|
||||
h(paths, targetID)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ type PlatformWindow interface {
|
|||
|
||||
// Events
|
||||
OnWindowEvent(handler func(event WindowEvent))
|
||||
|
||||
// File drop
|
||||
OnFileDrop(handler func(paths []string, targetID string))
|
||||
}
|
||||
|
||||
// WindowEvent is emitted by the backend for window state changes.
|
||||
|
|
|
|||
|
|
@ -168,6 +168,13 @@ func (s *Service) trackWindow(pw PlatformWindow) {
|
|||
_ = s.Core().ACTION(ActionWindowClosed{Name: e.Name})
|
||||
}
|
||||
})
|
||||
pw.OnFileDrop(func(paths []string, targetID string) {
|
||||
_ = s.Core().ACTION(ActionFilesDropped{
|
||||
Name: pw.Name(),
|
||||
Paths: paths,
|
||||
TargetID: targetID,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Service) taskCloseWindow(name string) error {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package window
|
|||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"forge.lthn.ai/core/go/pkg/core"
|
||||
|
|
@ -137,3 +138,39 @@ func TestTaskMaximise_Good(t *testing.T) {
|
|||
info := result.(*WindowInfo)
|
||||
assert.True(t, info.Maximized)
|
||||
}
|
||||
|
||||
func TestFileDrop_Good(t *testing.T) {
|
||||
_, c := newTestWindowService(t)
|
||||
|
||||
// Open a window
|
||||
result, _, _ := c.PERFORM(TaskOpenWindow{
|
||||
Opts: []WindowOption{WithName("drop-test")},
|
||||
})
|
||||
info := result.(WindowInfo)
|
||||
assert.Equal(t, "drop-test", info.Name)
|
||||
|
||||
// Capture broadcast actions
|
||||
var dropped ActionFilesDropped
|
||||
var mu sync.Mutex
|
||||
c.RegisterAction(func(_ *core.Core, msg core.Message) error {
|
||||
if a, ok := msg.(ActionFilesDropped); ok {
|
||||
mu.Lock()
|
||||
dropped = a
|
||||
mu.Unlock()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// Get the mock window and simulate file drop
|
||||
svc := core.MustServiceFor[*Service](c, "window")
|
||||
pw, ok := svc.Manager().Get("drop-test")
|
||||
require.True(t, ok)
|
||||
mw := pw.(*mockWindow)
|
||||
mw.emitFileDrop([]string{"/tmp/file1.txt", "/tmp/file2.txt"}, "upload-zone")
|
||||
|
||||
mu.Lock()
|
||||
assert.Equal(t, "drop-test", dropped.Name)
|
||||
assert.Equal(t, []string{"/tmp/file1.txt", "/tmp/file2.txt"}, dropped.Paths)
|
||||
assert.Equal(t, "upload-zone", dropped.TargetID)
|
||||
mu.Unlock()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,6 +120,18 @@ func (ww *wailsWindow) OnWindowEvent(handler func(event WindowEvent)) {
|
|||
}
|
||||
}
|
||||
|
||||
func (ww *wailsWindow) OnFileDrop(handler func(paths []string, targetID string)) {
|
||||
ww.w.OnWindowEvent(events.Common.WindowFilesDropped, func(event *application.WindowEvent) {
|
||||
files := event.Context().DroppedFiles()
|
||||
details := event.Context().DropTargetDetails()
|
||||
targetID := ""
|
||||
if details != nil {
|
||||
targetID = details.ElementID
|
||||
}
|
||||
handler(files, targetID)
|
||||
})
|
||||
}
|
||||
|
||||
// Ensure wailsWindow satisfies PlatformWindow at compile time.
|
||||
var _ PlatformWindow = (*wailsWindow)(nil)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue