wip
Some checks failed
CloudSave/pipeline/head There was a failure building this commit

This commit is contained in:
2025-09-12 01:39:47 +02:00
parent 5f7ca22b8f
commit 57fc77755e
5 changed files with 142 additions and 49 deletions

View File

@@ -55,6 +55,7 @@ func (p *SyncCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{})
fmt.Println() fmt.Println()
pg := progressbar.New(-1) pg := progressbar.New(-1)
pg.Describe("Warming up...")
destroyPg := func() { destroyPg := func() {
pg.Finish() pg.Finish()
pg.Clear() pg.Clear()

View File

@@ -17,7 +17,7 @@ type (
} }
) )
func Make(remoteHostname string, callback func(v bool), w fyne.Window) *CredentialDialog { func Make(remoteHostname string, callback func(ok bool, username, password string), w fyne.Window) *CredentialDialog {
label := canvas.NewText("Connexion to "+remoteHostname, color.Black) label := canvas.NewText("Connexion to "+remoteHostname, color.Black)
inputUsername := widget.NewEntry() inputUsername := widget.NewEntry()
@@ -43,13 +43,11 @@ func Make(remoteHostname string, callback func(v bool), w fyne.Window) *Credenti
} }
d := &CredentialDialog{ d := &CredentialDialog{
FormDialog: dialog.NewForm("Syncing", "Connexion", "Cancel", formItems, callback, w),
inputUsername: inputUsername, inputUsername: inputUsername,
inputPassword: inputPassword, inputPassword: inputPassword,
} }
d.FormDialog = dialog.NewForm("Syncing", "Connexion", "Cancel", formItems, func(b bool) {
callback(b, d.inputUsername.Text, d.inputPassword.Text)
}, w)
return d return d
} }
func (c *CredentialDialog) Credentials() (string, string) {
return c.inputUsername.Text, c.inputPassword.Text
}

View File

@@ -4,10 +4,14 @@ import (
"cloudsave/cmd/gui/window/about" "cloudsave/cmd/gui/window/about"
"cloudsave/cmd/gui/window/credential" "cloudsave/cmd/gui/window/credential"
"cloudsave/cmd/gui/window/loading" "cloudsave/cmd/gui/window/loading"
syncdialog "cloudsave/cmd/gui/window/sync"
"cloudsave/pkg/data" "cloudsave/pkg/data"
"cloudsave/pkg/remote" "cloudsave/pkg/remote"
"cloudsave/pkg/remote/client" "cloudsave/pkg/remote/client"
"cloudsave/pkg/repository"
"cloudsave/pkg/sync" "cloudsave/pkg/sync"
"cloudsave/pkg/tools/iterator"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
@@ -19,6 +23,17 @@ import (
"fyne.io/fyne/v2/widget" "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 { func Make(a fyne.App, d *data.Service) fyne.Window {
w := a.NewWindow("CloudSave") w := a.NewWindow("CloudSave")
w.Resize(fyne.NewSize(1000, 700)) w.Resize(fyne.NewSize(1000, 700))
@@ -38,12 +53,17 @@ func Make(a fyne.App, d *data.Service) fyne.Window {
return len(games) return len(games)
}, },
func() fyne.CanvasObject { func() fyne.CanvasObject {
return widget.NewLabel("template") return &ExtraLabel{Label: widget.NewLabel("")}
}, },
func(i widget.ListItemID, o fyne.CanvasObject) { func(i widget.ListItemID, o fyne.CanvasObject) {
o.(*widget.Label).SetText(games[i].Name) o.(*ExtraLabel).SetText(games[i].Name)
o.(*ExtraLabel).SetID(games[i].ID)
}) })
list.OnSelected = func(id widget.ListItemID) {
fmt.Println(id)
}
toolbar := widget.NewToolbar( toolbar := widget.NewToolbar(
widget.NewToolbarAction(theme.FolderNewIcon(), func() { widget.NewToolbarAction(theme.FolderNewIcon(), func() {
folderSelection := dialog.NewFolderOpen(func(lu fyne.ListableURI, err error) { folderSelection := dialog.NewFolderOpen(func(lu fyne.ListableURI, err error) {
@@ -121,53 +141,85 @@ func Make(a fyne.App, d *data.Service) fyne.Window {
return w return w
} }
func doSync(d *data.Service, w fyne.Window) error { func doSync(d *data.Service, w fyne.Window) {
remotes, err := remote.All() rs, err := remote.All()
if err != nil { if err != nil {
return err d := dialog.NewError(fmt.Errorf("failed to load datastore: %w", err), w)
} d.Show()
i := 0
nextCh := make(chan struct{})
doneCh := make(chan struct{})
var cd *credential.CredentialDialog
go func() {
nextCh <- struct{}{}
}()
for {
select {
case <-doneCh:
return nil
case <-nextCh:
{
cd = credential.Make(remotes[i].URL, func(v bool) {
if !v {
return return
} }
username, password := cd.Credentials() it := iterator.New(rs)
cli := client.New(remotes[i].URL, username, password) if it.IsEmpty() {
dialog.NewInformation("Sync", "no remote configured", w).Show()
sync.NewSyncer(cli, d) return
}
fmt.Println(i) dialog := credential.Make(it.Value().URL, syncing(it, d, w), w)
dialog.Show()
if i < len(remotes) {
go func() {
nextCh <- struct{}{}
}()
} else {
go func() {
doneCh <- struct{}{}
}()
} }
}, w) func syncing(it *iterator.Iterator[remote.Remote], d *data.Service, w fyne.Window) func(bool, string, string) {
cd.Show() 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()
} }
} }
} }

View File

@@ -43,6 +43,7 @@ const (
Pushed Pushed
Pulled Pulled
UpToDate UpToDate
Done
) )
var ( var (
@@ -81,7 +82,7 @@ func (s *Syncer) Sync() {
for _, g := range games { for _, g := range games {
r, err := remote.One(g.ID) r, err := remote.One(g.ID)
if err != nil { if err != nil {
s.errorCallback(fmt.Errorf("%w: %s", ErrDatastore, err), g) continue
} }
if r.URL != s.cli.BaseURL() { if r.URL != s.cli.BaseURL() {
continue continue
@@ -90,6 +91,7 @@ func (s *Syncer) Sync() {
s.errorCallback(err, g) s.errorCallback(err, g)
} }
} }
s.stateCallback(Done, repository.Metadata{})
} }
func (s *Syncer) sync(g repository.Metadata) error { func (s *Syncer) sync(g repository.Metadata) error {

View File

@@ -0,0 +1,40 @@
package iterator
type (
Iterator[T any] struct {
index int
values []T
}
)
func New[T any](values []T) *Iterator[T] {
return &Iterator[T]{
values: values,
}
}
func (it *Iterator[T]) Next() bool {
if len(it.values) == it.index {
return false
}
it.index += 1
return true
}
func (it *Iterator[T]) Value() T {
if len(it.values) == 0 {
var zero T
return zero
}
if len(it.values) == it.index {
var zero T
return zero
}
return it.values[it.index]
}
func (it *Iterator[T]) IsEmpty() bool {
return len(it.values) == 0
}