switch back to qt
Some checks failed
CloudSave/pipeline/head There was a failure building this commit
Some checks failed
CloudSave/pipeline/head There was a failure building this commit
This commit is contained in:
@@ -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()
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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()
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user