Skip to content

Commit

Permalink
Show proper progress on receiver side, fixes #20
Browse files Browse the repository at this point in the history
This adds the necessary changes to be able to support full progress on
the receiving side as well as sending side. It also cleans up the
progress codes a lot and unifies the error handling.

Fixes #20
  • Loading branch information
Jacalz committed Dec 27, 2021
1 parent e452528 commit 0251276
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 97 deletions.
79 changes: 0 additions & 79 deletions internal/transport/bridge/progress.go

This file was deleted.

16 changes: 8 additions & 8 deletions internal/transport/bridge/recv.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import (
"fyne.io/fyne/v2/storage"
"fyne.io/fyne/v2/widget"
"github.com/Jacalz/wormhole-gui/v2/internal/transport"
"github.com/Jacalz/wormhole-gui/v2/internal/util"
)

// RecvItem is the item that is being received
type RecvItem struct {
URI fyne.URI
Status string
Name string
URI fyne.URI
Progress *util.ProgressBar
Name string
}

// RecvList is a list of progress bars that track send progress.
Expand All @@ -37,15 +38,15 @@ func (p *RecvList) CreateItem() fyne.CanvasObject {
return container.New(&listLayout{},
widget.NewFileIcon(nil),
&widget.Label{Text: "Waiting for filename...", Wrapping: fyne.TextTruncate},
newRecvProgress(),
util.NewProgressBar(),
)
}

// UpdateItem updates the data in the list.
func (p *RecvList) UpdateItem(i int, item fyne.CanvasObject) {
item.(*fyne.Container).Objects[0].(*widget.FileIcon).SetURI(p.Items[i].URI)
item.(*fyne.Container).Objects[1].(*widget.Label).SetText(p.Items[i].Name)
item.(*fyne.Container).Objects[2].(*fyne.Container).Objects[0].(*recvProgress).setStatus(p.Items[i].Status)
p.Items[i].Progress = item.(*fyne.Container).Objects[2].(*util.ProgressBar)
}

// RemoveItem removes the item at the specified index.
Expand Down Expand Up @@ -90,12 +91,11 @@ func (p *RecvList) NewReceive(code string) {
}()

go func(code string) {
if err := p.client.NewReceive(code, path); err != nil {
p.Items[index].Status = "Failed"
if err := p.client.NewReceive(code, path, p.Items[index].Progress); err != nil {
p.client.ShowNotification("Receive failed", "An error occurred when receiving the data.")
p.Items[index].Progress.Failed()
dialog.ShowError(err, p.window)
} else {
p.Items[index].Status = "Completed"
p.client.ShowNotification("Receive completed", "The data was received successfully.")
}

Expand Down
20 changes: 14 additions & 6 deletions internal/transport/bridge/send.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import (
"fyne.io/fyne/v2/storage"
"fyne.io/fyne/v2/widget"
"github.com/Jacalz/wormhole-gui/v2/internal/transport"
"github.com/Jacalz/wormhole-gui/v2/internal/util"
)

// SendItem is the item that is being sent.
type SendItem struct {
URI fyne.URI
Progress *sendProgress
Progress *util.ProgressBar
Code string
Name string
}
Expand All @@ -39,7 +40,7 @@ func (p *SendList) CreateItem() fyne.CanvasObject {
widget.NewFileIcon(nil),
&widget.Label{Text: "Waiting for filename...", Wrapping: fyne.TextTruncate},
newCodeDisplay(p.window),
newSendProgress(),
util.NewProgressBar(),
)
}

Expand All @@ -48,7 +49,7 @@ func (p *SendList) UpdateItem(i int, item fyne.CanvasObject) {
item.(*fyne.Container).Objects[0].(*widget.FileIcon).SetURI(p.Items[i].URI)
item.(*fyne.Container).Objects[1].(*widget.Label).SetText(p.Items[i].Name)
item.(*fyne.Container).Objects[2].(*fyne.Container).Objects[0].(*codeDisplay).SetText(p.Items[i].Code)
p.Items[i].Progress = item.(*fyne.Container).Objects[3].(*sendProgress)
p.Items[i].Progress = item.(*fyne.Container).Objects[3].(*util.ProgressBar)
}

// RemoveItem removes the item at the specified index.
Expand Down Expand Up @@ -97,13 +98,15 @@ func (p *SendList) OnFileSelect(file fyne.URIReadCloser, err error) {
go func(i int) {
defer func() {
if err = file.Close(); err != nil {
p.Items[i].Progress.Failed()
fyne.LogError("Error on closing file", err)
}
}()

code, result, err := p.client.NewFileSend(file, p.Items[i].Progress.update)
code, result, err := p.client.NewFileSend(file, p.Items[i].Progress.WithProgress())
if err != nil {
fyne.LogError("Error on sending file", err)
p.Items[i].Progress.Failed()
dialog.ShowError(err, p.window)
return
}
Expand All @@ -113,6 +116,7 @@ func (p *SendList) OnFileSelect(file fyne.URIReadCloser, err error) {

if res := <-result; res.Error != nil {
fyne.LogError("Error on sending file", res.Error)
p.Items[i].Progress.Failed()
dialog.ShowError(res.Error, p.window)
p.client.ShowNotification("File send failed", "An error occurred when sending the file.")
} else if res.OK {
Expand All @@ -134,9 +138,10 @@ func (p *SendList) OnDirSelect(dir fyne.ListableURI, err error) {
p.NewSendItem(dir.Name(), dir)

go func(i int) {
code, result, err := p.client.NewDirSend(dir, p.Items[i].Progress.update)
code, result, err := p.client.NewDirSend(dir, p.Items[i].Progress.WithProgress())
if err != nil {
fyne.LogError("Error on sending directory", err)
p.Items[i].Progress.Failed()
dialog.ShowError(err, p.window)
return
}
Expand All @@ -146,6 +151,7 @@ func (p *SendList) OnDirSelect(dir fyne.ListableURI, err error) {

if res := <-result; res.Error != nil {
fyne.LogError("Error on sending directory", res.Error)
p.Items[i].Progress.Failed()
dialog.ShowError(res.Error, p.window)
p.client.ShowNotification("Directory send failed", "An error occurred when sending the directory.")
} else if res.OK {
Expand All @@ -160,9 +166,10 @@ func (p *SendList) SendText() {

go func(i int) {
if text := <-p.client.ShowTextSendWindow(); text != "" {
code, result, err := p.client.NewTextSend(text, p.Items[i].Progress.update)
code, result, err := p.client.NewTextSend(text, p.Items[i].Progress.WithProgress())
if err != nil {
fyne.LogError("Error on sending text", err)
p.Items[i].Progress.Failed()
dialog.ShowError(err, p.window)
return
}
Expand All @@ -172,6 +179,7 @@ func (p *SendList) SendText() {

if res := <-result; res.Error != nil {
fyne.LogError("Error on sending text", res.Error)
p.Items[i].Progress.Failed()
dialog.ShowError(res.Error, p.window)
p.client.ShowNotification("Text send failed", "An error occurred when sending the text.")
} else if res.OK && p.client.Notifications {
Expand Down
18 changes: 14 additions & 4 deletions internal/transport/receiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

"fyne.io/fyne/v2"
"github.com/Jacalz/wormhole-gui/v2/internal/transport/zip"
"github.com/Jacalz/wormhole-gui/v2/internal/util"
"github.com/psanford/wormhole-william/wormhole"
)

Expand All @@ -24,21 +25,24 @@ func bail(msg *wormhole.IncomingMessage, err error) error {
}

// NewReceive runs a receive using wormhole-william and handles types accordingly.
func (c *Client) NewReceive(code string, pathname chan string) (err error) {
func (c *Client) NewReceive(code string, pathname chan string, progress *util.ProgressBar) (err error) {
msg, err := c.Receive(context.Background(), code)
if err != nil {
pathname <- "fail" // We want to always send a URI, even on fail, in order to not block goroutines.
fyne.LogError("Error on receiving data", err)
return bail(msg, err)
}

progress.Max = float64(msg.TransferBytes64)
contents := io.TeeReader(msg, progress)

if msg.Type == wormhole.TransferText {
pathname <- "text"

text := &bytes.Buffer{}
text.Grow(int(msg.TransferBytes64))

_, err := io.Copy(text, msg)
_, err := io.Copy(text, contents)
if err != nil {
fyne.LogError("Could not copy the received text", err)
return err
Expand Down Expand Up @@ -73,7 +77,7 @@ func (c *Client) NewReceive(code string, pathname chan string) (err error) {
}
}()

_, err = io.Copy(file, msg)
_, err = io.Copy(file, contents)
if err != nil {
fyne.LogError("Error on copying contents to file", err)
return err
Expand All @@ -82,6 +86,9 @@ func (c *Client) NewReceive(code string, pathname chan string) (err error) {
return
}

// We want both the compressed download and the extraction.
progress.Max += float64(msg.UncompressedBytes64)

tmp, err := ioutil.TempFile("", msg.Name+"-*.zip.tmp")
if err != nil {
fyne.LogError("Error on creating tempfile", err)
Expand All @@ -100,7 +107,7 @@ func (c *Client) NewReceive(code string, pathname chan string) (err error) {
}
}()

n, err := io.Copy(tmp, msg)
n, err := io.Copy(tmp, contents)
if err != nil {
fyne.LogError("Error on copying contents to file", err)
return err
Expand All @@ -112,5 +119,8 @@ func (c *Client) NewReceive(code string, pathname chan string) (err error) {
return err
}

// TODO: Can we update this as we extract it, instead of all at once?
progress.Done()

return
}
46 changes: 46 additions & 0 deletions internal/util/progress.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package util

import (
"sync"

"fyne.io/fyne/v2/widget"
"github.com/psanford/wormhole-william/wormhole"
)

// ProgressBar is contains a widget for displaying wormhole send progress.
type ProgressBar struct {
widget.ProgressBar
}

// WithProgress returns a send option to update the progress.
func (p *ProgressBar) WithProgress() wormhole.SendOption {
once := sync.Once{}
return wormhole.WithProgress(func(sent, total int64) {
once.Do(func() { p.Max = float64(total) })
p.SetValue(float64(sent))
})
}

// Write updates the progress of a write operation.
func (p *ProgressBar) Write(written []byte) (int, error) {
p.SetValue(p.Value + float64(len(written)))
return 0, nil
}

// Done sets the value to max to indicate that it is finished.
func (p *ProgressBar) Done() {
p.SetValue(p.Max)
}

// Failed sets the text to indicate a failure.
func (p *ProgressBar) Failed() {
p.TextFormatter = func() string { return "Failed" }
p.Refresh()
}

// NewProgressBar creates a new fyne progress bar and update function for wormhole send.
func NewProgressBar() *ProgressBar {
p := &ProgressBar{}
p.ExtendBaseWidget(p)
return p
}

0 comments on commit 0251276

Please sign in to comment.