mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
My calendar view looks quite a bit cleaner with meetings I've said "no" to taken out. This change adds a new option `wtf.mods.gcal.showDeclined`, defaulting to `true`, which controls whether or not the gcal module displays events where your status is "declined". I think as a quality of life feature, this is better off defaulting to `false` (i.e. _don't_ show declined events by default), but when it comes to potentially disrupting other users who've gotten used to the existing setup, I'll leave that decision to you.
240 lines
5.1 KiB
Go
240 lines
5.1 KiB
Go
package gcal
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/senorprogrammer/wtf/wtf"
|
|
)
|
|
|
|
func (widget *Widget) sortedEvents() ([]*CalEvent, []*CalEvent) {
|
|
allDayEvents := []*CalEvent{}
|
|
timedEvents := []*CalEvent{}
|
|
|
|
for _, calEvent := range widget.calEvents {
|
|
if calEvent.AllDay() {
|
|
allDayEvents = append(allDayEvents, calEvent)
|
|
} else {
|
|
timedEvents = append(timedEvents, calEvent)
|
|
}
|
|
}
|
|
|
|
return allDayEvents, timedEvents
|
|
}
|
|
|
|
func (widget *Widget) display() {
|
|
if widget.calEvents == nil || len(widget.calEvents) == 0 {
|
|
return
|
|
}
|
|
|
|
widget.mutex.Lock()
|
|
defer widget.mutex.Unlock()
|
|
|
|
_, timedEvents := widget.sortedEvents()
|
|
widget.View.SetText(widget.contentFrom(timedEvents))
|
|
}
|
|
|
|
func (widget *Widget) contentFrom(calEvents []*CalEvent) string {
|
|
if (calEvents == nil) || (len(calEvents) == 0) {
|
|
return ""
|
|
}
|
|
|
|
var str string
|
|
var prevEvent *CalEvent
|
|
|
|
if !wtf.Config.UBool("wtf.mods.gcal.showDeclined", true) {
|
|
calEvents = removeDeclined(calEvents)
|
|
}
|
|
|
|
for _, calEvent := range calEvents {
|
|
timestamp := fmt.Sprintf("[%s]%s", widget.descriptionColor(calEvent), calEvent.Timestamp())
|
|
|
|
title := fmt.Sprintf("[%s]%s",
|
|
widget.titleColor(calEvent),
|
|
widget.eventSummary(calEvent, calEvent.ConflictsWith(calEvents)),
|
|
)
|
|
|
|
lineOne := fmt.Sprintf(
|
|
"%s %s %s %s[white]\n",
|
|
widget.dayDivider(calEvent, prevEvent),
|
|
widget.responseIcon(calEvent),
|
|
timestamp,
|
|
title,
|
|
)
|
|
|
|
str = str + fmt.Sprintf("%s %s%s\n",
|
|
lineOne,
|
|
widget.location(calEvent),
|
|
widget.timeUntil(calEvent),
|
|
)
|
|
|
|
if (widget.location(calEvent) != "") || (widget.timeUntil(calEvent) != "") {
|
|
str = str + "\n"
|
|
}
|
|
|
|
prevEvent = calEvent
|
|
}
|
|
|
|
return str
|
|
}
|
|
|
|
func (widget *Widget) dayDivider(event, prevEvent *CalEvent) string {
|
|
var prevStartTime time.Time
|
|
|
|
if prevEvent != nil {
|
|
prevStartTime = prevEvent.Start()
|
|
}
|
|
|
|
// round times to midnight for comparison
|
|
toMidnight := func(t time.Time) time.Time {
|
|
t = t.Local()
|
|
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
|
|
}
|
|
prevStartDay := toMidnight(prevStartTime)
|
|
eventStartDay := toMidnight(event.Start())
|
|
|
|
if !eventStartDay.Equal(prevStartDay) {
|
|
|
|
return fmt.Sprintf("[%s::b]",
|
|
wtf.Config.UString("wtf.mods.gcal.colors.day", "forestgreen")) +
|
|
event.Start().Format(wtf.FullDateFormat) +
|
|
"\n"
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func (widget *Widget) descriptionColor(calEvent *CalEvent) string {
|
|
if calEvent.Past() {
|
|
return wtf.Config.UString("wtf.mods.gcal.colors.past", "gray")
|
|
} else {
|
|
return wtf.Config.UString("wtf.mods.gcal.colors.description", "white")
|
|
}
|
|
}
|
|
|
|
func (widget *Widget) eventSummary(calEvent *CalEvent, conflict bool) string {
|
|
summary := calEvent.event.Summary
|
|
|
|
if calEvent.Now() {
|
|
summary = fmt.Sprintf(
|
|
"%s %s",
|
|
wtf.Config.UString("wtf.mods.gcal.currentIcon", "🔸"),
|
|
summary,
|
|
)
|
|
}
|
|
|
|
if conflict {
|
|
return fmt.Sprintf("%s %s", wtf.Config.UString("wtf.mods.gcal.conflictIcon", "🚨"), summary)
|
|
} else {
|
|
return summary
|
|
}
|
|
}
|
|
|
|
// timeUntil returns the number of hours or days until the event
|
|
// If the event is in the past, returns nil
|
|
func (widget *Widget) timeUntil(calEvent *CalEvent) string {
|
|
duration := time.Until(calEvent.Start()).Round(time.Minute)
|
|
|
|
if duration < 0 {
|
|
return ""
|
|
}
|
|
|
|
days := duration / (24 * time.Hour)
|
|
duration -= days * (24 * time.Hour)
|
|
|
|
hours := duration / time.Hour
|
|
duration -= hours * time.Hour
|
|
|
|
mins := duration / time.Minute
|
|
|
|
untilStr := ""
|
|
|
|
color := "[lightblue]"
|
|
if days > 0 {
|
|
untilStr = fmt.Sprintf("%dd", days)
|
|
} else if hours > 0 {
|
|
untilStr = fmt.Sprintf("%dh", hours)
|
|
} else {
|
|
untilStr = fmt.Sprintf("%dm", mins)
|
|
if mins < 30 {
|
|
color = "[red]"
|
|
}
|
|
}
|
|
|
|
return color + untilStr + "[white]"
|
|
}
|
|
|
|
func (widget *Widget) titleColor(calEvent *CalEvent) string {
|
|
color := wtf.Config.UString("wtf.mods.gcal.colors.title", "white")
|
|
|
|
for _, untypedArr := range wtf.Config.UList("wtf.mods.gcal.colors.highlights") {
|
|
highlightElements := wtf.ToStrs(untypedArr.([]interface{}))
|
|
|
|
match, _ := regexp.MatchString(
|
|
strings.ToLower(highlightElements[0]),
|
|
strings.ToLower(calEvent.event.Summary),
|
|
)
|
|
|
|
if match == true {
|
|
color = highlightElements[1]
|
|
}
|
|
}
|
|
|
|
if calEvent.Past() {
|
|
color = wtf.Config.UString("wtf.mods.gcal.colors.past", "gray")
|
|
}
|
|
|
|
return color
|
|
}
|
|
|
|
func (widget *Widget) location(calEvent *CalEvent) string {
|
|
if wtf.Config.UBool("wtf.mods.gcal.displayLocation", true) == false {
|
|
return ""
|
|
}
|
|
|
|
if calEvent.event.Location == "" {
|
|
return ""
|
|
}
|
|
|
|
return fmt.Sprintf(
|
|
"[%s]%s ",
|
|
widget.descriptionColor(calEvent),
|
|
calEvent.event.Location,
|
|
)
|
|
}
|
|
|
|
func (widget *Widget) responseIcon(calEvent *CalEvent) string {
|
|
if false == wtf.Config.UBool("wtf.mods.gcal.displayResponseStatus", true) {
|
|
return ""
|
|
}
|
|
|
|
icon := "[gray]"
|
|
|
|
switch calEvent.ResponseFor(wtf.Config.UString("wtf.mods.gcal.email")) {
|
|
case "accepted":
|
|
return icon + "✔︎"
|
|
case "declined":
|
|
return icon + "✘"
|
|
case "needsAction":
|
|
return icon + "?"
|
|
case "tentative":
|
|
return icon + "~"
|
|
default:
|
|
return icon + " "
|
|
}
|
|
|
|
return " "
|
|
}
|
|
|
|
func removeDeclined(events []*CalEvent) []*CalEvent {
|
|
var ret []*CalEvent
|
|
for _, e := range events {
|
|
if e.ResponseFor(wtf.Config.UString("wtf.mods.gcal.email")) != "declined" {
|
|
ret = append(ret, e)
|
|
}
|
|
}
|
|
return ret
|
|
}
|