mirror of
https://github.com/aditya-K2/gspt.git
synced 2026-01-07 21:13:50 -05:00
175 lines
3.6 KiB
Go
175 lines
3.6 KiB
Go
package ui
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/aditya-K2/tview"
|
|
"github.com/gdamore/tcell/v2"
|
|
)
|
|
|
|
var (
|
|
maxNotifications = 3
|
|
pm sync.Mutex
|
|
notAvailable = -1
|
|
posArr = positionArray{}
|
|
c chan *notification
|
|
)
|
|
|
|
// Start Notification Service
|
|
func InitNotifier() {
|
|
for _m := maxNotifications; _m != 0; _m-- {
|
|
posArr = append(posArr, true)
|
|
}
|
|
c = make(chan *notification, maxNotifications)
|
|
routine()
|
|
}
|
|
|
|
// notification Primitive
|
|
type notification struct {
|
|
*tview.Box
|
|
text string
|
|
position int
|
|
msg chan string
|
|
timer time.Duration
|
|
}
|
|
|
|
// Array for all available positions where the notification can be displayed.
|
|
type positionArray []bool
|
|
|
|
// Check If there is a position available.
|
|
func (p *positionArray) Available() bool {
|
|
var t = false
|
|
pm.Lock()
|
|
for _, v := range *p {
|
|
t = t || v
|
|
}
|
|
pm.Unlock()
|
|
return t
|
|
}
|
|
|
|
func (p *positionArray) GetNextPosition() int {
|
|
pm.Lock()
|
|
v := *p
|
|
for k := range v {
|
|
if v[k] {
|
|
v[k] = false
|
|
pm.Unlock()
|
|
return k
|
|
}
|
|
}
|
|
pm.Unlock()
|
|
return notAvailable
|
|
}
|
|
|
|
// Free a position
|
|
func (p *positionArray) Free(i int) {
|
|
pm.Lock()
|
|
v := *p
|
|
v[i] = true
|
|
pm.Unlock()
|
|
}
|
|
|
|
// Get A Pointer to A Notification Struct
|
|
func newNotificationWithTimer(s string, t time.Duration) *notification {
|
|
return ¬ification{
|
|
Box: tview.NewBox(),
|
|
text: s,
|
|
timer: t,
|
|
msg: nil,
|
|
}
|
|
}
|
|
|
|
// Get A Pointer to A Notification Struct with a close channel
|
|
func newNotificationWithChan(s string, c chan string) *notification {
|
|
return ¬ification{
|
|
Box: tview.NewBox(),
|
|
text: s,
|
|
timer: time.Second,
|
|
msg: c,
|
|
}
|
|
}
|
|
|
|
// Draw Function for the Notification Primitive
|
|
func (self *notification) Draw(screen tcell.Screen) {
|
|
pos := (self.position*3 + self.position + 1)
|
|
|
|
var (
|
|
_, _, COL, _ int = Flex.GetRect()
|
|
TEXTLENGTH int = len(self.text)
|
|
HEIGHT int = 3
|
|
TextPosition int = 1
|
|
)
|
|
|
|
self.Box.SetBackgroundColor(tcell.ColorBlack)
|
|
self.SetRect(COL-(TEXTLENGTH+7), pos, TEXTLENGTH+4, HEIGHT)
|
|
self.DrawForSubclass(screen, self.Box)
|
|
tview.Print(screen, self.text,
|
|
COL-(TEXTLENGTH+5), pos+TextPosition, TEXTLENGTH,
|
|
tview.AlignCenter, tcell.ColorWhite)
|
|
}
|
|
|
|
// this routine checks for available position and sends notification if
|
|
// position is available.
|
|
func routine() {
|
|
go func() {
|
|
for {
|
|
val := <-c
|
|
// Wait until a new position isn't available
|
|
for !posArr.Available() {
|
|
continue
|
|
}
|
|
notify(val)
|
|
}
|
|
}()
|
|
}
|
|
|
|
func notify(n *notification) {
|
|
go func() {
|
|
currentTime := time.Now().String()
|
|
npos := posArr.GetNextPosition()
|
|
// Ensure a position is available.
|
|
if npos == notAvailable {
|
|
for !posArr.Available() {
|
|
}
|
|
npos = posArr.GetNextPosition()
|
|
}
|
|
n.position = npos
|
|
root.AddPage(currentTime, n, false, true)
|
|
App.Draw()
|
|
App.SetFocus(Main)
|
|
if n.msg != nil {
|
|
n.text = <-n.msg
|
|
App.Draw()
|
|
}
|
|
time.Sleep(n.timer)
|
|
root.RemovePage(currentTime)
|
|
posArr.Free(npos)
|
|
App.SetFocus(Main)
|
|
App.Draw()
|
|
}()
|
|
}
|
|
|
|
func SendNotification(format string, args ...any) {
|
|
SendNotificationWithTimer(time.Second, fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
func SendNotificationWithTimer(t time.Duration, format string, args ...any) {
|
|
go func() {
|
|
c <- newNotificationWithTimer(fmt.Sprintf(format, args...), t)
|
|
}()
|
|
}
|
|
|
|
// SendNotificationWithChan sends a notification that won't be closed unless
|
|
// an update message isn't sent over the channel that it returns. The message
|
|
// string received over the channel is then displayed for half a second and the
|
|
// notification is then removed.
|
|
func SendNotificationWithChan(format string, args ...any) chan string {
|
|
close := make(chan string)
|
|
go func() {
|
|
c <- newNotificationWithChan(fmt.Sprintf(format, args...), close)
|
|
}()
|
|
return close
|
|
}
|