324 lines
7.8 KiB
Go
324 lines
7.8 KiB
Go
package widgets
|
|
|
|
import (
|
|
"ArinDash/util"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/mum4k/termdash/cell"
|
|
"github.com/mum4k/termdash/keyboard"
|
|
"github.com/mum4k/termdash/terminal/terminalapi"
|
|
"github.com/mum4k/termdash/widgetapi"
|
|
"github.com/mum4k/termdash/widgets/text"
|
|
)
|
|
|
|
const moodsFile = "moods.json"
|
|
|
|
type YearMoodOptions struct {
|
|
}
|
|
|
|
func YearMood() YearMoodOptions {
|
|
widgetOptions["YearMoodOptions"] = createYearMood
|
|
return YearMoodOptions{}
|
|
}
|
|
|
|
func createYearMood(ctx context.Context, _ terminalapi.Terminal, _ interface{}) widgetapi.Widget {
|
|
widget := util.PanicOnErrorWithResult(NewMoodText())
|
|
|
|
go util.Periodic(ctx, 1*time.Hour, func() error {
|
|
widget.selectedMonth = time.Now().Month()
|
|
widget.selectedDay = time.Now().Day()
|
|
return widget.drawTable()
|
|
})
|
|
|
|
return widget
|
|
}
|
|
|
|
func (widget *MoodText) drawTable() error {
|
|
days := moods()
|
|
|
|
widget.Reset()
|
|
|
|
if err := widget.Write(" "); err != nil {
|
|
return err
|
|
}
|
|
for m := range 12 {
|
|
mood := moodToColor(widget.moodMonth(m + 1))
|
|
if err := widget.Write(fmt.Sprintf("%2s", time.Month(m + 1).String()[0:3]), text.WriteCellOpts(cell.BgColor(mood), cell.FgColor(cell.ColorWhite))); err != nil {
|
|
return err
|
|
}
|
|
if m < 11 {
|
|
if err := widget.Write(" "); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
if err := widget.Write("\n"); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
for day := range 31 {
|
|
for month := range 12 {
|
|
date := time.Date(time.Now().Year(), time.Month(month+1), day+1, 0, 0, 0, 0, time.UTC)
|
|
if date.Month() != time.Month(month+1) {
|
|
if err := widget.Write(" "); err != nil {
|
|
return err
|
|
}
|
|
continue
|
|
}
|
|
cellOptions := make([]cell.Option, 0)
|
|
weekday := time.Date(time.Now().Year(), time.Month(month+1), day+1, 0, 0, 0, 0, time.UTC).Weekday()
|
|
if weekday == time.Saturday || weekday == time.Sunday {
|
|
cellOptions = append(cellOptions, cell.Dim())
|
|
}
|
|
cellOptions = append(cellOptions, cell.FgColor(cell.ColorWhite))
|
|
cellOptions = append(cellOptions, cell.Bold())
|
|
mood := days[strconv.Itoa(time.Now().Year())][strconv.Itoa(month+1)][strconv.Itoa(day+1)]
|
|
cellOptions = append(cellOptions, cell.BgColor(moodToColor(mood)))
|
|
|
|
if day+1 == widget.selectedDay && time.Month(month+1) == widget.selectedMonth {
|
|
if err := widget.Write(">", text.WriteCellOpts(append(cellOptions, cell.Blink())...)); err != nil {
|
|
return err
|
|
}
|
|
if err := widget.Write(fmt.Sprintf("%2d", day+1), text.WriteCellOpts(cellOptions...)); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
if err := widget.Write(fmt.Sprintf(" %2d", day+1), text.WriteCellOpts(cellOptions...)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if time.Now().Day() == day+1 && time.Now().Month() == time.Month(month+1) {
|
|
if err := widget.Write("<", text.WriteCellOpts(cellOptions...)); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
if err := widget.Write(" ", text.WriteCellOpts(cellOptions...)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if month+1 < 12 {
|
|
if err := widget.Write(" "); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
if err := widget.Write("\n"); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if err := widget.Write("\n"); err != nil {
|
|
return err
|
|
}
|
|
for k, v := range totalMoodPercents() {
|
|
if v == 0 {
|
|
continue
|
|
}
|
|
amount := int(59 * v)
|
|
if amount == 0 {
|
|
amount = 1
|
|
}
|
|
if err := widget.Write(strings.Repeat("█", amount), text.WriteCellOpts(cell.BgColor(cell.ColorGray), cell.FgColor(moodToColor(k)))); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if err := widget.Write("\n\n"); err != nil {
|
|
return err
|
|
}
|
|
if err := widget.Write("<-=delete 1=idk(purple) 2=meh(yellow) 3=great(green) other=bad(red)", text.WriteCellOpts(cell.FgColor(cell.ColorGray))); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func moods() map[string]map[string]map[string]int {
|
|
moods := make(map[string]map[string]map[string]int)
|
|
file, err := os.ReadFile(moodsFile)
|
|
if err == nil {
|
|
if err := json.Unmarshal(file, &moods); err != nil {
|
|
panic(err)
|
|
}
|
|
} else {
|
|
initMoods, _ := json.Marshal(moods)
|
|
if err := os.WriteFile(moodsFile, initMoods, 0644); err != nil {
|
|
// ignore
|
|
}
|
|
}
|
|
return moods
|
|
}
|
|
|
|
func moodToColor(mood int) cell.Color {
|
|
switch mood {
|
|
case 1:
|
|
return cell.ColorPurple
|
|
case 2:
|
|
return cell.ColorYellow
|
|
case 3:
|
|
return cell.ColorGreen
|
|
case -1:
|
|
return cell.ColorRed
|
|
default:
|
|
return cell.ColorGray
|
|
}
|
|
}
|
|
|
|
func totalMoodPercents() map[int]float64 {
|
|
m := moods()
|
|
now := time.Now()
|
|
currentYear := strconv.Itoa(now.Year())
|
|
|
|
// Initialize percentages for all known moods
|
|
percents := map[int]float64{
|
|
1: 0.0, // idk
|
|
2: 0.0, // meh
|
|
3: 0.0, // great
|
|
-1: 0.0, // bad
|
|
0: 0.0, // no mood recorded
|
|
}
|
|
|
|
// Calculate total days in the current year
|
|
firstDay := time.Date(now.Year(), time.January, 1, 0, 0, 0, 0, time.UTC)
|
|
nextYear := time.Date(now.Year()+1, time.January, 1, 0, 0, 0, 0, time.UTC)
|
|
totalDaysInYear := int(nextYear.Sub(firstDay).Hours() / 24)
|
|
|
|
yearData, ok := m[currentYear]
|
|
if !ok {
|
|
percents[0] = 1.0
|
|
return percents
|
|
}
|
|
|
|
counts := make(map[int]int)
|
|
recordedDaysCount := 0
|
|
|
|
for _, monthData := range yearData {
|
|
for _, mood := range monthData {
|
|
if mood == 0 {
|
|
continue
|
|
}
|
|
counts[mood]++
|
|
recordedDaysCount++
|
|
}
|
|
}
|
|
|
|
// Any day that doesn't have a recorded mood (1, 2, 3, or -1) is counted as 0
|
|
counts[0] = totalDaysInYear - recordedDaysCount
|
|
|
|
for mood := range percents {
|
|
if count, exists := counts[mood]; exists {
|
|
percents[mood] = float64(count) / float64(totalDaysInYear)
|
|
}
|
|
}
|
|
|
|
return percents
|
|
}
|
|
|
|
func (widget *MoodText) moodMonth(month int) int {
|
|
days := moods()[strconv.Itoa(time.Now().Year())][strconv.Itoa(month)]
|
|
|
|
counts := make(map[int]int)
|
|
mostFrequentMood := 0
|
|
maxCount := 0
|
|
|
|
for _, mood := range days {
|
|
if mood == 0 {
|
|
continue
|
|
}
|
|
|
|
counts[mood]++
|
|
if counts[mood] > maxCount {
|
|
maxCount = counts[mood]
|
|
mostFrequentMood = mood
|
|
}
|
|
}
|
|
return mostFrequentMood
|
|
}
|
|
|
|
type MoodText struct {
|
|
*text.Text
|
|
selectedMonth time.Month
|
|
selectedDay int
|
|
}
|
|
|
|
func NewMoodText(opts ...text.Option) (*MoodText, error) {
|
|
t, err := text.New(opts...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &MoodText{Text: t}, nil
|
|
}
|
|
|
|
func (widget *MoodText) Keyboard(k *terminalapi.Keyboard, _ *widgetapi.EventMeta) error {
|
|
switch k.Key {
|
|
case keyboard.KeyEsc, keyboard.KeyCtrlC:
|
|
break
|
|
case keyboard.KeyArrowUp:
|
|
if widget.selectedDay == 1 {
|
|
widget.selectedDay = 31
|
|
} else {
|
|
widget.selectedDay--
|
|
}
|
|
break
|
|
case keyboard.KeyArrowDown:
|
|
if widget.selectedDay == 31 {
|
|
widget.selectedDay = 1
|
|
} else {
|
|
widget.selectedDay++
|
|
}
|
|
break
|
|
case keyboard.KeyArrowLeft:
|
|
if widget.selectedMonth == 1 {
|
|
widget.selectedMonth = 12
|
|
} else {
|
|
widget.selectedMonth--
|
|
}
|
|
break
|
|
case keyboard.KeyArrowRight:
|
|
if widget.selectedMonth == 12 {
|
|
widget.selectedMonth = 1
|
|
} else {
|
|
widget.selectedMonth++
|
|
}
|
|
break
|
|
case keyboard.KeyBackspace, keyboard.KeyBackspace2:
|
|
widget.WriteMood(0)
|
|
case '1':
|
|
widget.WriteMood(1)
|
|
case '2':
|
|
widget.WriteMood(2)
|
|
case '3':
|
|
widget.WriteMood(3)
|
|
default:
|
|
widget.WriteMood(-1)
|
|
}
|
|
return widget.drawTable()
|
|
}
|
|
|
|
func (widget *MoodText) WriteMood(mood int) error {
|
|
m := moods()
|
|
if m[strconv.Itoa(time.Now().Year())] == nil {
|
|
m[strconv.Itoa(time.Now().Year())] = make(map[string]map[string]int)
|
|
}
|
|
if m[strconv.Itoa(time.Now().Year())][strconv.Itoa(int(widget.selectedMonth))] == nil {
|
|
m[strconv.Itoa(time.Now().Year())][strconv.Itoa(int(widget.selectedMonth))] = make(map[string]int)
|
|
}
|
|
m[strconv.Itoa(time.Now().Year())][strconv.Itoa(int(widget.selectedMonth))][strconv.Itoa(widget.selectedDay)] = mood
|
|
newMoods, err := json.MarshalIndent(m, "", " ")
|
|
if err != nil {
|
|
return widget.Write(fmt.Sprintf("Error: %s", err.Error()), text.WriteCellOpts(cell.FgColor(cell.ColorRed)))
|
|
|
|
}
|
|
if err := os.WriteFile(moodsFile, newMoods, 0644); err != nil {
|
|
return widget.Write(fmt.Sprintf("Error: %s", err.Error()), text.WriteCellOpts(cell.FgColor(cell.ColorRed)))
|
|
}
|
|
return nil
|
|
}
|