diff --git a/bargraph/widget.go b/bargraph/widget.go new file mode 100644 index 00000000..51194638 --- /dev/null +++ b/bargraph/widget.go @@ -0,0 +1,95 @@ +package bargraph + +import ( + "fmt" + "math/rand" + "time" + + "github.com/olebedev/config" + "github.com/senorprogrammer/wtf/wtf" +) + +// Config is a pointer to the global config object +var Config *config.Config + +var started = false +var ok = true + +// Widget define wtf widget to register widget later +type Widget struct { + wtf.GraphWidget + + // time interval for send http request + updateInterval int +} + +// NewWidget Make new instance of widget +func NewWidget() *Widget { + widget := Widget{ + GraphWidget: wtf.NewGraphWidget(" Bar Graph", "bargraph", false), + } + + widget.View.SetWrap(true) + widget.View.SetWordWrap(true) + + return &widget +} + +/* -------------------- Exported Functions -------------------- */ + +// MakeGraph - Load the dead drop stats +func MakeGraph(widget *Widget) { + + //this could come from config + const lineCount = 20 + var stats [lineCount][2]int64 + + for i := lineCount - 1; i >= 0; i-- { + + stats[i][1] = time.Now().AddDate(0, 0, i*-1).Unix() * 1000 + stats[i][0] = int64(rand.Intn(120-5) + 5) + + } + + widget.GraphWidget.BuildBars(20, "🌟", stats[:]) + +} + +// Refresh & update after interval time +func (widget *Widget) Refresh() { + + if widget.Disabled() { + return + } + + if started == false { + // this code should run once + go func() { + for { + time.Sleep(time.Duration(widget.updateInterval) * time.Second) + } + }() + + } + + started = true + + widget.UpdateRefreshedAt() + widget.View.Clear() + + if !ok { + widget.View.SetText( + fmt.Sprint("Error!"), + ) + return + } + + display(widget) + +} + +/* -------------------- Unexported Functions -------------------- */ + +func display(widget *Widget) { + MakeGraph(widget) +} diff --git a/prettyweather/widget.go b/prettyweather/widget.go index 6b838c69..5cb61446 100644 --- a/prettyweather/widget.go +++ b/prettyweather/widget.go @@ -18,6 +18,7 @@ type Widget struct { result string unit string city string + view string } func NewWidget() *Widget { @@ -42,8 +43,10 @@ func (widget *Widget) Refresh() { //this method reads the config and calls wttr.in for pretty weather func (widget *Widget) prettyWeather() { client := &http.Client{} - widget.unit, widget.city = Config.UString("wtf.mods.prettyweather.unit", "m"), Config.UString("wtf.mods.prettyweather.city", "") - req, err := http.NewRequest("GET", "https://wttr.in/"+widget.city+"?0"+"?"+widget.unit, nil) + widget.unit = Config.UString("wtf.mods.prettyweather.unit", "m") + widget.city = Config.UString("wtf.mods.prettyweather.city", "") + widget.view = Config.UString("wtf.mods.prettyweather.view", "0") + req, err := http.NewRequest("GET", "https://wttr.in/"+widget.city+"?"+widget.view+"?"+widget.unit, nil) if err != nil { widget.result = fmt.Sprintf("%s", err.Error()) return diff --git a/wtf.go b/wtf.go index 660e458c..a855089a 100644 --- a/wtf.go +++ b/wtf.go @@ -6,6 +6,7 @@ import ( "os" "time" + "github.com/BillKeenan/wtf/bargraph" "github.com/gdamore/tcell" "github.com/olebedev/config" "github.com/radovskyb/watcher" @@ -186,6 +187,7 @@ func makeWidgets(app *tview.Application, pages *tview.Pages) { clocks.NewWidget(), cmdrunner.NewWidget(), cryptolive.NewWidget(), + bargraph.NewWidget(), gcal.NewWidget(), git.NewWidget(app, pages), github.NewWidget(app, pages), diff --git a/wtf/graph_widget.go b/wtf/graph_widget.go new file mode 100644 index 00000000..84b5a4a7 --- /dev/null +++ b/wtf/graph_widget.go @@ -0,0 +1,160 @@ +package wtf + +import ( + "bytes" + "fmt" + "strings" + "time" + + "github.com/rivo/tview" +) + +type GraphWidget struct { + enabled bool + focusable bool + + Name string + RefreshedAt time.Time + RefreshInt int + View *tview.TextView + + Position + + Data [][2]int64 +} + +// NewGraphWidget initialize your fancy new graph +func NewGraphWidget(name string, configKey string, focusable bool) GraphWidget { + widget := GraphWidget{ + enabled: Config.UBool(fmt.Sprintf("wtf.mods.%s.enabled", configKey), false), + focusable: focusable, + + Name: Config.UString(fmt.Sprintf("wtf.mods.%s.title", configKey), name), + RefreshInt: Config.UInt(fmt.Sprintf("wtf.mods.%s.refreshInterval", configKey)), + } + + widget.Position = NewPosition( + Config.UInt(fmt.Sprintf("wtf.mods.%s.position.top", configKey)), + Config.UInt(fmt.Sprintf("wtf.mods.%s.position.left", configKey)), + Config.UInt(fmt.Sprintf("wtf.mods.%s.position.width", configKey)), + Config.UInt(fmt.Sprintf("wtf.mods.%s.position.height", configKey)), + ) + + widget.addView() + + return widget +} + +func (widget *GraphWidget) BorderColor() string { + if widget.Focusable() { + return Config.UString("wtf.colors.border.focusable", "red") + } + + return Config.UString("wtf.colors.border.normal", "gray") +} + +func (widget *GraphWidget) Disabled() bool { + return !widget.Enabled() +} + +func (widget *GraphWidget) Enabled() bool { + return widget.enabled +} + +func (widget *GraphWidget) Focusable() bool { + return widget.enabled && widget.focusable +} + +func (widget *GraphWidget) RefreshInterval() int { + return widget.RefreshInt +} + +func (widget *GraphWidget) TextView() *tview.TextView { + return widget.View +} + +/* -------------------- Unexported Functions -------------------- */ + +func (widget *GraphWidget) UpdateRefreshedAt() { + widget.RefreshedAt = time.Now() +} + +func (widget *GraphWidget) addView() { + view := tview.NewTextView() + + view.SetBackgroundColor(ColorFor(Config.UString("wtf.colors.background", "black"))) + view.SetBorder(true) + view.SetBorderColor(ColorFor(widget.BorderColor())) + view.SetDynamicColors(true) + view.SetTitle(widget.Name) + view.SetWrap(false) + + widget.View = view +} + +// BuildBars will build a string of * to represent your data of [time][value] +// time should be passed as a int64 +func (widget *GraphWidget) BuildBars(maxStars int, starChar string, data [][2]int64) { + + var buffer bytes.Buffer + + //counter to inintialize min value + var count int + + //store the max value from the array + var maxValue int + + //store the min value from the array + var minValue int + + //just getting min and max values + for i := range data { + + var val = int(data[i][0]) + + //initialize the min value + if count == 0 { + minValue = val + } + count++ + + //update max value + if val > maxValue { + maxValue = val + } + + //update minValue + if val < minValue { + minValue = val + } + + } + + // each number = how many stars? + var starRatio = float64(maxStars) / float64((maxValue - minValue)) + + //build the stars + for i := range data { + var val = int(data[i][0]) + + //how many stars for this one? + var starCount = int(float64((val - minValue)) * starRatio) + + if starCount == 0 { + starCount = 1 + } + //build the actual string + var stars = strings.Repeat(starChar, starCount) + + //parse the time + var t = time.Unix(int64(data[i][1]/1000), 0) + + //write the line + buffer.WriteString(fmt.Sprintf("%s -\t [red]%s[white] - (%d)\n", t.Format("Jan 02, 2006"), stars, val)) + } + + widget.View.SetText(buffer.String()) + +} + +/* -------------------- Exported Functions -------------------- */