@@ -6,7 +6,10 @@ import (
66 "fmt"
77 "optimus/backend/config"
88 "optimus/backend/stat"
9+ "os"
10+ "path/filepath"
911 "runtime/debug"
12+ "strconv"
1013 "strings"
1114 "sync"
1215 "time"
@@ -53,6 +56,73 @@ func (fm *FileManager) HandleFile(fileJson string) (err error) {
5356 return nil
5457}
5558
59+ // SelectFileMeta holds UI-facing metadata returned after a file is selected and
60+ // decoded. The heavy image data stays in Go; only what the frontend needs is
61+ // returned across the IPC bridge.
62+ type SelectFileMeta struct {
63+ ID string `json:"id"`
64+ Filename string `json:"filename"`
65+ Name string `json:"name"`
66+ Size int64 `json:"size"`
67+ }
68+
69+ // SelectFiles opens a native OS file dialog, reads and decodes the selected
70+ // image files, adds them to the FileManager, and returns their metadata for
71+ // the UI. This avoids the unreliable browser <input type="file"> path on macOS.
72+ func (fm * FileManager ) SelectFiles () ([]SelectFileMeta , error ) {
73+ paths , err := runtime .OpenMultipleFilesDialog (fm .ctx , runtime.OpenDialogOptions {
74+ Filters : []runtime.FileFilter {
75+ {DisplayName : "Images (*.jpg, *.jpeg, *.png, *.webp)" , Pattern : "*.jpg;*.jpeg;*.png;*.webp" },
76+ },
77+ })
78+ if err != nil || len (paths ) == 0 {
79+ return nil , err
80+ }
81+
82+ var results []SelectFileMeta
83+ for _ , p := range paths {
84+ data , err := os .ReadFile (p )
85+ if err != nil {
86+ runtime .LogErrorf (fm .ctx , "failed to read file: %s: %v" , p , err )
87+ continue
88+ }
89+ base := filepath .Base (p )
90+ extWithDot := filepath .Ext (base )
91+ ext := strings .ToLower (strings .TrimPrefix (extWithDot , "." ))
92+ name := strings .TrimSuffix (base , extWithDot )
93+ size := int64 (len (data ))
94+ id := name + strconv .FormatInt (size , 10 )
95+
96+ mime := "image/" + ext
97+ if ext == "jpg" {
98+ mime = "image/jpeg"
99+ }
100+
101+ file := & File {
102+ Data : data ,
103+ Ext : ext ,
104+ ID : id ,
105+ MimeType : mime ,
106+ Name : name ,
107+ Size : size ,
108+ }
109+ if err := file .Decode (); err != nil {
110+ runtime .LogErrorf (fm .ctx , "failed to decode file %s: %v" , p , err )
111+ continue
112+ }
113+ fm .Files = append (fm .Files , file )
114+ runtime .LogInfof (fm .ctx , "added file to file manager via dialog: %s" , file .Name )
115+
116+ results = append (results , SelectFileMeta {
117+ ID : id ,
118+ Filename : base ,
119+ Name : name ,
120+ Size : size ,
121+ })
122+ }
123+ return results , nil
124+ }
125+
56126// Clear removes the files in the FileManager.
57127func (fm * FileManager ) Clear () {
58128 fm .Files = nil
0 commit comments