-
Notifications
You must be signed in to change notification settings - Fork 1
/
progress.go
121 lines (97 loc) · 2.28 KB
/
progress.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package widget
import (
"context"
"sort"
"time"
"github.com/gdamore/tcell/v2"
"github.com/env25/mpdlrc/internal/client"
"github.com/env25/mpdlrc/internal/events"
"github.com/env25/mpdlrc/internal/panics"
"github.com/env25/mpdlrc/internal/styles"
"github.com/env25/mpdlrc/internal/timerpool"
)
var _ Widget = &Progress{}
// Progress is [Widget] implementing a progress bar.
type Progress struct {
common
}
type progressData struct {
Playing bool
Elapsed time.Duration
Duration time.Duration
elapsedX int
totalX int
}
// Update updates the widget after an event.
func (w *Progress) Update(ctx context.Context, ev tcell.Event) {
defer panics.Handle(ctx)
switch ev.(type) {
case *tcell.EventResize:
w.resize()
case *client.PlayerEvent:
// no-op
default:
return
}
w.mu.Lock()
defer w.mu.Unlock()
vx, _ := w.Size()
data := client.DataFromContext(ctx)
d := &progressData{
Playing: data.State() == "play",
Elapsed: data.Elapsed(),
Duration: data.Duration(),
totalX: vx,
}
d.Elapsed += time.Since(ev.When())
d.Duration = d.Duration / time.Duration(vx)
d.elapsedX = sort.Search(d.totalX, func(i int) bool { return time.Duration(i)*d.Duration >= d.Elapsed })
w.update(ctx, d)
}
func (w *Progress) update(ctx context.Context, d *progressData) {
go events.PostFunc(ctx, func() { w.draw(d) })
if !d.Playing || d.elapsedX+1 >= d.totalX {
return
}
timer := timerpool.Get(d.Duration)
go func() {
defer panics.Handle(ctx)
select {
case <-ctx.Done():
timerpool.Put(timer, false)
return
case <-timer.C:
timerpool.Put(timer, true)
}
w.mu.Lock()
defer w.mu.Unlock()
d.elapsedX++
w.update(ctx, d)
}()
}
func (w *Progress) draw(d *progressData) {
w.mu.Lock()
defer w.mu.Unlock()
w.Fill(' ', styles.Default())
{
r := styles.RuneBorderUpper
s := styles.Border()
for x := 0; x < d.totalX; x++ {
w.SetContent(x, 0, r, nil, s)
}
}
for x := 0; x < d.elapsedX; x++ {
w.SetContent(x, 1, '=', nil, styles.Default().Bold(true))
}
w.SetContent(d.elapsedX, 1, '>', nil, styles.Default().Bold(true))
for x := d.elapsedX + 1; x < d.totalX; x++ {
w.SetContent(x, 1, '-', nil, styles.Default().Dim(true))
}
{
r := styles.RuneBorderLower
s := styles.Border()
for x := 0; x < d.totalX; x++ {
w.SetContent(x, 2, r, nil, s)
}
}
}