package mainwindow import ( "cloudsave/cmd/gui/window/about" "cloudsave/cmd/gui/window/credential" "cloudsave/cmd/gui/window/loading" syncdialog "cloudsave/cmd/gui/window/sync" "cloudsave/pkg/data" "cloudsave/pkg/remote" "cloudsave/pkg/remote/client" "cloudsave/pkg/repository" "cloudsave/pkg/sync" "cloudsave/pkg/tools/iterator" "fmt" "os" "path/filepath" "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/dialog" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" ) type ( ExtraLabel struct { *widget.Label id string } ) func (e *ExtraLabel) SetID(id string) { e.id = id } func Make(a fyne.App, d *data.Service) fyne.Window { w := a.NewWindow("CloudSave") w.Resize(fyne.NewSize(1000, 700)) w.CenterOnScreen() games, err := d.AllGames() if err != nil { d := dialog.NewError(fmt.Errorf("failed to load datastore: %w", err), w) d.Show() d.SetOnClosed(func() { os.Exit(1) }) } list := widget.NewList( func() int { return len(games) }, func() fyne.CanvasObject { return &ExtraLabel{Label: widget.NewLabel("")} }, func(i widget.ListItemID, o fyne.CanvasObject) { o.(*ExtraLabel).SetText(games[i].Name) o.(*ExtraLabel).SetID(games[i].ID) }) list.OnSelected = func(id widget.ListItemID) { fmt.Println(id) } toolbar := widget.NewToolbar( widget.NewToolbarAction(theme.FolderNewIcon(), func() { folderSelection := dialog.NewFolderOpen(func(lu fyne.ListableURI, err error) { if err != nil { d := dialog.NewError(fmt.Errorf("failed to open window: %w", err), w) d.Show() return } if lu == nil { return } confirmDialog := dialog.NewConfirm("Add", "Do you want to add and scan '"+lu.Path()+"'?", func(accepted bool) { if !accepted { return } name := filepath.Base(lu.Path()) loadingDialog := loading.Make("Scanning directory", w) loadingDialog.Show() go func() { gameID, err := d.Add(name, lu.Path(), "") if err != nil { fyne.Do(func() { d := dialog.NewError(fmt.Errorf("failed to create metadata the directory: %w", err), w) d.Show() loadingDialog.Hide() }) return } _, err = d.Scan(gameID) if err != nil { fyne.Do(func() { d := dialog.NewError(fmt.Errorf("failed to scan the directory: %w", err), w) d.Show() loadingDialog.Hide() }) return } games, err = d.AllGames() if err != nil { fyne.Do(func() { d := dialog.NewError(fmt.Errorf("failed to load datastore: %w", err), w) d.Show() loadingDialog.Hide() }) return } fyne.Do(func() { list.Refresh() loadingDialog.Hide() }) }() }, w) confirmDialog.Show() }, w) folderSelection.Show() }), widget.NewToolbarSeparator(), widget.NewToolbarAction(theme.UploadIcon(), func() { doSync(d, w) }), widget.NewToolbarSpacer(), widget.NewToolbarAction(theme.HelpIcon(), func() { aboutWindow := about.Make(a) aboutWindow.Show() }), ) content := container.NewBorder(toolbar, nil, nil, nil, list) w.SetContent(content) return w } func doSync(d *data.Service, w fyne.Window) { rs, err := remote.All() if err != nil { d := dialog.NewError(fmt.Errorf("failed to load datastore: %w", err), w) d.Show() return } it := iterator.New(rs) if it.IsEmpty() { dialog.NewInformation("Sync", "no remote configured", w).Show() return } dialog := credential.Make(it.Value().URL, syncing(it, d, w), w) dialog.Show() } func syncing(it *iterator.Iterator[remote.Remote], d *data.Service, w fyne.Window) func(bool, string, string) { return func(b bool, username, password string) { if b { r := it.Value() cli := client.New(r.URL, username, password) if err := cli.Ping(); err != nil { dialog.NewError(fmt.Errorf("failed to connect to the server: %w", err), w).Show() return } syncDialog := syncdialog.Make(0, w) syncDialog.Show() s := sync.NewSyncer(cli, d) var errg error s.SetStateCallback(func(s sync.State, g repository.Metadata) { switch s { case sync.FetchingMetdata: fyne.Do(func() { syncDialog.UpdateLabel(fmt.Sprintf("%s: fetching metadata from repository", g.Name)) }) case sync.Pushing: fyne.Do(func() { syncDialog.UpdateLabel(fmt.Sprintf("%s: pushing data to the server", g.Name)) }) case sync.Pulling: fyne.Do(func() { syncDialog.UpdateLabel(fmt.Sprintf("%s: pull data from the server", g.Name)) }) case sync.UpToDate: fyne.Do(func() { syncDialog.UpdateLabel(fmt.Sprintf("%s: already up-to-date", g.Name)) }) case sync.Pushed: fyne.Do(func() { syncDialog.UpdateLabel(fmt.Sprintf("%s: pushed", g.Name)) }) case sync.Pulled: fyne.Do(func() { syncDialog.UpdateLabel(fmt.Sprintf("%s: pulled", g.Name)) }) case sync.Done: fyne.Do(func() { syncDialog.Dismiss() if errg == nil { dialog.NewInformation("Sync", "The sync ended sucessfully!", w).Show() } }) } }) s.SetErrorCallback(func(err error, g repository.Metadata) { errg = err fyne.Do(func() { dialog.NewError(err, w).Show() }) }) go s.Sync() } } }