@@ -7,10 +7,12 @@ import (
7
7
"image/color"
8
8
"image/draw"
9
9
"math"
10
+ "os"
10
11
"runtime"
11
12
"slices"
12
13
"sort"
13
14
"strconv"
15
+ "strings"
14
16
"sync"
15
17
"sync/atomic"
16
18
@@ -42,6 +44,7 @@ import (
42
44
"github.com/xaionaro-go/streamctl/pkg/streampanel/consts"
43
45
"github.com/xaionaro-go/streamctl/pkg/ximage"
44
46
xfyne "github.com/xaionaro-go/xfyne/widget"
47
+ "github.com/xaionaro-go/xpath"
45
48
"github.com/xaionaro-go/xsync"
46
49
)
47
50
@@ -50,6 +53,9 @@ const (
50
53
dashboardFullUpdatesInterval = 2 * time .Second
51
54
)
52
55
56
+ // TODO: DELETE ME:
57
+ var qualityFilePath = must (xpath .Expand (`~/quality` ))
58
+
53
59
func (p * Panel ) focusDashboardWindow (
54
60
ctx context.Context ,
55
61
) {
@@ -92,6 +98,82 @@ type imageInfo struct {
92
98
Image * image.NRGBA
93
99
}
94
100
101
+ func (w * dashboardWindow ) renderLocalStatus (ctx context.Context ) {
102
+ // TODO: remove the ugly hardcode above, and make it generic (support different use cases)
103
+
104
+ b , err := os .ReadFile (qualityFilePath )
105
+ if err != nil {
106
+ logger .Debugf (ctx , "unable to open the 'quality' file: %v" , err )
107
+ return
108
+ }
109
+ words := strings .Split (strings .Trim (string (b ), "\n \r \t " ), " " )
110
+ if len (words ) != 3 {
111
+ logger .Debugf (ctx , "expected 3 words, but received %d" , len (words ))
112
+ return
113
+ }
114
+
115
+ aQ , err := strconv .ParseInt (words [0 ], 10 , 64 )
116
+ if err != nil {
117
+ logger .Debugf (ctx , "unable to parse aQ '%s': %v" , words [0 ], err )
118
+ return
119
+ }
120
+
121
+ pQ , err := strconv .ParseInt (words [1 ], 10 , 64 )
122
+ if err != nil {
123
+ logger .Debugf (ctx , "unable to parse pQ '%s': %v" , words [0 ], err )
124
+ return
125
+ }
126
+
127
+ wQ , err := strconv .ParseInt (words [2 ], 10 , 64 )
128
+ if err != nil {
129
+ logger .Debugf (ctx , "unable to parse wQ '%s': %v" , words [0 ], err )
130
+ return
131
+ }
132
+
133
+ qToImportance := func (in int64 ) widget.Importance {
134
+ switch {
135
+ case in <= - 5 :
136
+ return widget .DangerImportance
137
+ case in <= 0 :
138
+ return widget .MediumImportance
139
+ default :
140
+ return widget .SuccessImportance
141
+ }
142
+ }
143
+
144
+ qToStr := func (in int64 ) string {
145
+ if in <= - 30 {
146
+ return "DEAD"
147
+ }
148
+ if in <= - 5 {
149
+ return "BAD"
150
+ }
151
+ if in <= 0 {
152
+ return "SO-SO"
153
+ }
154
+ if in > 0 {
155
+ return "GOOD"
156
+ }
157
+ return "UNKNOWN"
158
+ }
159
+
160
+ qToLabel := func (name string , q int64 ) * widget.Label {
161
+ l := widget .NewLabel (name + ":" + qToStr (q ))
162
+ l .Importance = qToImportance (q )
163
+ l .TextStyle .Bold = true
164
+ return l
165
+ }
166
+
167
+ w .localStatus .Objects = []fyne.CanvasObject {
168
+ container .NewHBox (
169
+ layout .NewSpacer (),
170
+ qToLabel ("A" , aQ ),
171
+ qToLabel ("P" , pQ ),
172
+ qToLabel ("W" , wQ ),
173
+ ),
174
+ }
175
+ }
176
+
95
177
func (w * dashboardWindow ) renderStreamStatus (ctx context.Context ) {
96
178
w .streamStatusLocker .Do (ctx , func () {
97
179
streamDClient , ok := w .StreamD .(* client.Client )
@@ -180,6 +262,7 @@ func (p *Panel) newDashboardWindow(
180
262
bgFyne := canvas .NewImageFromImage (bg )
181
263
bgFyne .FillMode = canvas .ImageFillStretch
182
264
265
+ p .localStatus = container .NewStack ()
183
266
p .appStatus = widget .NewLabel ("" )
184
267
obsLabel := widget .NewLabel ("OBS:" )
185
268
obsLabel .Importance = widget .HighImportance
@@ -197,8 +280,13 @@ func (p *Panel) newDashboardWindow(
197
280
if _ , ok := p .StreamD .(* client.Client ); ok {
198
281
appLabel := widget .NewLabel ("App:" )
199
282
appLabel .Importance = widget .HighImportance
200
- streamInfoItems .Add (container .NewHBox (layout .NewSpacer (), appLabel , p .appStatus ))
283
+ streamInfoItems .Add (container .NewHBox (
284
+ layout .NewSpacer (),
285
+ appLabel ,
286
+ p .appStatus ,
287
+ ))
201
288
}
289
+ streamInfoItems .Add (container .NewHBox (layout .NewSpacer (), p .localStatus ))
202
290
streamInfoItems .Add (container .NewHBox (layout .NewSpacer (), obsLabel , w .streamStatus [obs .ID ]))
203
291
streamInfoItems .Add (container .NewHBox (layout .NewSpacer (), twLabel , w .streamStatus [twitch .ID ]))
204
292
streamInfoItems .Add (container .NewHBox (layout .NewSpacer (), kcLabel , w .streamStatus [kick .ID ]))
@@ -575,6 +663,20 @@ func (w *dashboardWindow) startUpdatingNoLock(
575
663
ctx , cancelFunc := context .WithCancel (ctx )
576
664
w .stopUpdatingFunc = cancelFunc
577
665
666
+ w .renderLocalStatus (ctx )
667
+ observability .Go (ctx , func () {
668
+ t := time .NewTicker (2 * time .Second )
669
+ for {
670
+ select {
671
+ case <- ctx .Done ():
672
+ return
673
+ case <- t .C :
674
+ }
675
+
676
+ w .renderLocalStatus (ctx )
677
+ }
678
+ })
679
+
578
680
cfg , err := w .GetStreamDConfig (ctx )
579
681
if err != nil {
580
682
w .DisplayError (fmt .Errorf ("unable to get the current config: %w" , err ))
0 commit comments