diff --git a/cmd/gui/main.go b/cmd/gui/main.go deleted file mode 100644 index 1da1ee2..0000000 --- a/cmd/gui/main.go +++ /dev/null @@ -1,46 +0,0 @@ -package main - -import ( - "cloudsave/cmd/gui/window/mainwindow" - "cloudsave/pkg/data" - "cloudsave/pkg/repository" - "fmt" - "os" - "path/filepath" - - "fyne.io/fyne/v2/app" - "fyne.io/fyne/v2/dialog" -) - -func main() { - a := app.NewWithID("com.thelilfrog.CloudSave") - - roaming, err := os.UserConfigDir() - if err != nil { - panic("failed to get user config path: " + err.Error()) - } - - datastorepath := filepath.Join(roaming, "cloudsave", "data") - err = os.MkdirAll(datastorepath, 0740) - if err != nil { - d := dialog.NewError(fmt.Errorf("cannot make the datastore: %w", err), a.NewWindow("CloudSave")) - d.Show() - d.SetOnClosed(func() { - os.Exit(1) - }) - } - - repo, err := repository.NewLazyRepository(datastorepath) - if err != nil { - d := dialog.NewError(fmt.Errorf("cannot make the datastore: %w", err), a.NewWindow("CloudSave")) - d.Show() - d.SetOnClosed(func() { - os.Exit(1) - }) - } - - s := data.NewService(repo) - - w := mainwindow.Make(a, s) - w.ShowAndRun() -} diff --git a/cmd/gui/window/about/about.go b/cmd/gui/window/about/about.go deleted file mode 100644 index 84bee8f..0000000 --- a/cmd/gui/window/about/about.go +++ /dev/null @@ -1,32 +0,0 @@ -package about - -import ( - "cloudsave/pkg/constants" - "image/color" - - "fyne.io/fyne/v2" - "fyne.io/fyne/v2/canvas" - "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/layout" -) - -func Make(a fyne.App) fyne.Window { - w := a.NewWindow("About CloudSave") - w.Resize(fyne.NewSize(400, 200)) - w.CenterOnScreen() - w.SetFixedSize(true) - - title := canvas.NewText("CloudSave", color.Black) - title.Alignment = fyne.TextAlignCenter - title.TextSize = 32 - - version := canvas.NewText("v"+constants.Version, color.Black) - version.Alignment = fyne.TextAlignCenter - version.TextSize = 18 - - c := container.New(layout.NewVBoxLayout(), title, version) - - centered := container.New(layout.NewHBoxLayout(), layout.NewSpacer(), c, layout.NewSpacer()) - w.SetContent(container.New(layout.NewVBoxLayout(), centered)) - return w -} diff --git a/cmd/gui/window/credential/credential.go b/cmd/gui/window/credential/credential.go deleted file mode 100644 index d440127..0000000 --- a/cmd/gui/window/credential/credential.go +++ /dev/null @@ -1,53 +0,0 @@ -package credential - -import ( - "image/color" - - "fyne.io/fyne/v2" - "fyne.io/fyne/v2/canvas" - "fyne.io/fyne/v2/dialog" - "fyne.io/fyne/v2/widget" -) - -type ( - CredentialDialog struct { - *dialog.FormDialog - inputUsername *widget.Entry - inputPassword *widget.Entry - } -) - -func Make(remoteHostname string, callback func(ok bool, username, password string), w fyne.Window) *CredentialDialog { - label := canvas.NewText(remoteHostname, color.Black) - - inputUsername := widget.NewEntry() - inputUsername.SetPlaceHolder("Username") - - inputPassword := widget.NewEntry() - inputPassword.Password = true - inputPassword.SetPlaceHolder("Password") - - formItems := []*widget.FormItem{ - { - Text: "Connexion to ", - Widget: label, - }, - { - Text: "Username", - Widget: inputUsername, - }, - { - Text: "Password", - Widget: inputPassword, - }, - } - - d := &CredentialDialog{ - inputUsername: inputUsername, - inputPassword: inputPassword, - } - d.FormDialog = dialog.NewForm("Syncing", "Connexion", "Cancel", formItems, func(b bool) { - callback(b, d.inputUsername.Text, d.inputPassword.Text) - }, w) - return d -} diff --git a/cmd/gui/window/loading/loading.go b/cmd/gui/window/loading/loading.go deleted file mode 100644 index c10ff7a..0000000 --- a/cmd/gui/window/loading/loading.go +++ /dev/null @@ -1,24 +0,0 @@ -package loading - -import ( - "image/color" - - "fyne.io/fyne/v2" - "fyne.io/fyne/v2/canvas" - "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/dialog" - "fyne.io/fyne/v2/layout" - "fyne.io/fyne/v2/widget" -) - -func Make(msg string, w fyne.Window) *dialog.CustomDialog { - title := canvas.NewText(msg, color.Black) - title.Alignment = fyne.TextAlignCenter - - pg := widget.NewProgressBarInfinite() - - c := container.New(layout.NewVBoxLayout(), title, pg) - d := dialog.NewCustomWithoutButtons("Loading", c, w) - - return d -} diff --git a/cmd/gui/window/mainwindow/mainwindow.go b/cmd/gui/window/mainwindow/mainwindow.go deleted file mode 100644 index e59284e..0000000 --- a/cmd/gui/window/mainwindow/mainwindow.go +++ /dev/null @@ -1,285 +0,0 @@ -package mainwindow - -import ( - "cloudsave/cmd/gui/window/about" - "cloudsave/cmd/gui/window/credential" - "cloudsave/cmd/gui/window/loading" - "cloudsave/cmd/gui/window/properties" - - 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(1200, 700)) - w.CenterOnScreen() - w.SetFixedSize(true) - - defer func() { - if r := recover(); r != nil { - d := dialog.NewError(fmt.Errorf("the application crashed: %s", r), w) - d.Show() - d.SetOnClosed(func() { - os.Exit(1) - }) - } - }() - - 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) { - properties.Make(a, games[id]).Show() - } - - toolbar := widget.NewToolbar( - makeNewButton(d, w, func() { - games, err = d.AllGames() - if err != nil { - fyne.Do(func() { - d := dialog.NewError(fmt.Errorf("failed to load datastore: %w", err), w) - d.Show() - }) - return - } - - fyne.Do(func() { - list.Refresh() - }) - }), - widget.NewToolbarSeparator(), - widget.NewToolbarAction(theme.UploadIcon(), func() { - doSync(d, w) - }), - makeScanButton(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() - } - } -} - -func makeNewButton(d *data.Service, w fyne.Window, callback func()) *widget.ToolbarAction { - return 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 - } - - loadingDialog.Hide() - callback() - }() - }, w) - confirmDialog.Show() - }, w) - folderSelection.Show() - }) -} - -func makeScanButton(d *data.Service, w fyne.Window) *widget.ToolbarAction { - return widget.NewToolbarAction(theme.SearchIcon(), func() { - loadingDialog := loading.Make("Scanning directory", w) - loadingDialog.Show() - - go func() { - datastore, err := d.AllGames() - if err != nil { - fyne.Do(func() { - dialog.NewError(fmt.Errorf("failed to load datastore: %w", err), w) - loadingDialog.Hide() - }) - } - - updated := 0 - - for _, metadata := range datastore { - changed, err := d.Scan(metadata.ID) - if err != nil { - fyne.Do(func() { - dialog.NewError(fmt.Errorf("failed to load datastore: %w", err), w) - loadingDialog.Hide() - }) - return - } - if changed { - updated++ - } - } - - fyne.Do(func() { - loadingDialog.Hide() - if updated == 0 { - dialog.NewInformation("Scan", "Everything is up to date", w).Show() - } else { - dialog.NewInformation("Scan", fmt.Sprintf("%d game updated", updated), w).Show() - } - }) - }() - }) -} diff --git a/cmd/gui/window/properties/properties.go b/cmd/gui/window/properties/properties.go deleted file mode 100644 index 0ad80ab..0000000 --- a/cmd/gui/window/properties/properties.go +++ /dev/null @@ -1,33 +0,0 @@ -package properties - -import ( - "cloudsave/pkg/repository" - "image/color" - "strconv" - - "fyne.io/fyne/v2" - "fyne.io/fyne/v2/canvas" - "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/layout" -) - -func Make(a fyne.App, g repository.Metadata) fyne.Window { - w := a.NewWindow(g.Name) - w.Resize(fyne.NewSize(800, 300)) - w.CenterOnScreen() - w.SetFixedSize(true) - - title := canvas.NewText(g.Name, color.Black) - title.Alignment = fyne.TextAlignCenter - title.TextSize = 32 - - version := canvas.NewText("Version "+strconv.Itoa(g.Version), color.Black) - version.Alignment = fyne.TextAlignCenter - version.TextSize = 18 - - c := container.New(layout.NewVBoxLayout(), title, version) - - centered := container.New(layout.NewHBoxLayout(), layout.NewSpacer(), c, layout.NewSpacer()) - w.SetContent(container.New(layout.NewVBoxLayout(), centered)) - return w -} diff --git a/cmd/gui/window/sync/sync.go b/cmd/gui/window/sync/sync.go deleted file mode 100644 index ee433b0..0000000 --- a/cmd/gui/window/sync/sync.go +++ /dev/null @@ -1,41 +0,0 @@ -package sync - -import ( - "image/color" - - "fyne.io/fyne/v2" - "fyne.io/fyne/v2/canvas" - "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/dialog" - "fyne.io/fyne/v2/layout" - "fyne.io/fyne/v2/widget" -) - -type ( - SyncDialog struct { - *dialog.CustomDialog - label *canvas.Text - pg *widget.ProgressBarInfinite - } -) - -func Make(total int, w fyne.Window) *SyncDialog { - - title := canvas.NewText("Warming up...", color.Black) - title.Alignment = fyne.TextAlignCenter - - pg := widget.NewProgressBarInfinite() - - c := container.New(layout.NewVBoxLayout(), title, pg) - d := &SyncDialog{ - CustomDialog: dialog.NewCustomWithoutButtons("Syncing", c, w), - label: title, - pg: pg, - } - return d -} - -func (s *SyncDialog) UpdateLabel(msg string) { - s.label.Text = msg - s.label.Refresh() -}