github.com/wtfutil/wtf@v0.43.0/modules/gcal/display.go (about)

     1  package gcal
     2  
     3  import (
     4  	"fmt"
     5  	"regexp"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/wtfutil/wtf/utils"
    10  )
    11  
    12  func (widget *Widget) display() {
    13  	widget.Redraw(widget.content)
    14  }
    15  
    16  func (widget *Widget) content() (string, string, bool) {
    17  	title := widget.settings.Title
    18  	calEvents := widget.calEvents
    19  
    20  	if widget.err != nil {
    21  		return title, widget.err.Error(), true
    22  	}
    23  
    24  	if (calEvents == nil) || (len(calEvents) == 0) {
    25  		return title, "No calendar events", false
    26  	}
    27  
    28  	var str string
    29  	var prevEvent *CalEvent
    30  
    31  	if !widget.settings.showDeclined {
    32  		calEvents = widget.removeDeclined(calEvents)
    33  	}
    34  
    35  	for _, calEvent := range calEvents {
    36  		if calEvent.AllDay() && !widget.settings.showAllDay {
    37  			continue
    38  		}
    39  
    40  		ts := calEvent.Timestamp(widget.settings.hourFormat, widget.settings.showEndTime)
    41  		timestamp := fmt.Sprintf("[%s]%s", widget.eventTimeColor(), ts)
    42  		if calEvent.AllDay() {
    43  			timestamp = ""
    44  		}
    45  
    46  		eventTitle := fmt.Sprintf("[%s]%s",
    47  			widget.titleColor(calEvent),
    48  			widget.eventSummary(calEvent, calEvent.ConflictsWith(calEvents)),
    49  		)
    50  
    51  		lineOne := fmt.Sprintf(
    52  			"%s %s %s %s[white]\n",
    53  			widget.dayDivider(calEvent, prevEvent),
    54  			widget.responseIcon(calEvent),
    55  			timestamp,
    56  			eventTitle,
    57  		)
    58  
    59  		str += fmt.Sprintf("%s   %s%s\n",
    60  			lineOne,
    61  			widget.location(calEvent),
    62  			widget.timeUntil(calEvent),
    63  		)
    64  
    65  		if (widget.location(calEvent) != "") || (widget.timeUntil(calEvent) != "") {
    66  			str += "\n"
    67  		}
    68  
    69  		prevEvent = calEvent
    70  	}
    71  
    72  	return title, str, false
    73  }
    74  
    75  func (widget *Widget) dayDivider(event, prevEvent *CalEvent) string {
    76  	var prevStartTime time.Time
    77  
    78  	if prevEvent != nil {
    79  		prevStartTime = prevEvent.Start()
    80  	}
    81  
    82  	// round times to midnight for comparison
    83  	toMidnight := func(t time.Time) time.Time {
    84  		t = t.Local()
    85  		return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
    86  	}
    87  	prevStartDay := toMidnight(prevStartTime)
    88  	eventStartDay := toMidnight(event.Start())
    89  
    90  	if !eventStartDay.Equal(prevStartDay) {
    91  		return fmt.Sprintf("[%s]",
    92  			widget.settings.colors.day) +
    93  			event.Start().Format(utils.FullDateFormat) +
    94  			"\n"
    95  	}
    96  
    97  	return ""
    98  }
    99  
   100  func (widget *Widget) descriptionColor(calEvent *CalEvent) string {
   101  	if calEvent.Past() {
   102  		return widget.settings.colors.past
   103  	}
   104  
   105  	return widget.settings.colors.description
   106  }
   107  
   108  func (widget *Widget) eventTimeColor() string {
   109  	return widget.settings.colors.eventTime
   110  }
   111  
   112  func (widget *Widget) eventSummary(calEvent *CalEvent, conflict bool) string {
   113  	summary := calEvent.event.Summary
   114  
   115  	if calEvent.Now() {
   116  		summary = fmt.Sprintf(
   117  			"%s %s",
   118  			widget.settings.currentIcon,
   119  			summary,
   120  		)
   121  	}
   122  
   123  	if conflict {
   124  		return fmt.Sprintf("%s %s", widget.settings.conflictIcon, summary)
   125  	}
   126  
   127  	return summary
   128  }
   129  
   130  // timeUntil returns the number of hours or days until the event
   131  // If the event is in the past, returns nil
   132  func (widget *Widget) timeUntil(calEvent *CalEvent) string {
   133  	duration := time.Until(calEvent.Start()).Round(time.Minute)
   134  
   135  	if duration < 0 {
   136  		return ""
   137  	}
   138  
   139  	days := duration / (24 * time.Hour)
   140  	duration -= days * (24 * time.Hour)
   141  
   142  	hours := duration / time.Hour
   143  	duration -= hours * time.Hour
   144  
   145  	mins := duration / time.Minute
   146  
   147  	untilStr := ""
   148  
   149  	color := "[lightblue]"
   150  	switch {
   151  	case days > 0:
   152  		untilStr = fmt.Sprintf("%dd", days)
   153  	case hours > 0:
   154  		untilStr = fmt.Sprintf("%dh", hours)
   155  	default:
   156  		untilStr = fmt.Sprintf("%dm", mins)
   157  		if mins < 30 {
   158  			color = "[red]"
   159  		}
   160  	}
   161  
   162  	return color + untilStr + "[white]"
   163  }
   164  
   165  func (widget *Widget) titleColor(calEvent *CalEvent) string {
   166  	color := widget.settings.colors.title
   167  
   168  	for _, untypedArr := range widget.settings.colors.highlights {
   169  		highlightElements := utils.ToStrs(untypedArr.([]interface{}))
   170  
   171  		match, _ := regexp.MatchString(
   172  			strings.ToLower(highlightElements[0]),
   173  			strings.ToLower(calEvent.event.Summary),
   174  		)
   175  
   176  		if match {
   177  			color = highlightElements[1]
   178  		}
   179  	}
   180  
   181  	if calEvent.Past() {
   182  		color = widget.settings.colors.past
   183  	}
   184  
   185  	return color
   186  }
   187  
   188  func (widget *Widget) location(calEvent *CalEvent) string {
   189  	if !widget.settings.withLocation {
   190  		return ""
   191  	}
   192  
   193  	if calEvent.event.Location == "" {
   194  		return ""
   195  	}
   196  
   197  	return fmt.Sprintf(
   198  		"[%s]%s ",
   199  		widget.descriptionColor(calEvent),
   200  		calEvent.event.Location,
   201  	)
   202  }
   203  
   204  func (widget *Widget) responseIcon(calEvent *CalEvent) string {
   205  	if !widget.settings.displayResponseStatus {
   206  		return ""
   207  	}
   208  
   209  	icon := "[gray]"
   210  
   211  	switch calEvent.ResponseFor(widget.settings.email) {
   212  	case "accepted":
   213  		return icon + "✔"
   214  	case "declined":
   215  		return icon + "✘"
   216  	case "needsAction":
   217  		return icon + "?"
   218  	case "tentative":
   219  		return icon + "~"
   220  	default:
   221  		return icon + " "
   222  	}
   223  }
   224  
   225  func (widget *Widget) removeDeclined(events []*CalEvent) []*CalEvent {
   226  	var ret []*CalEvent
   227  	for _, e := range events {
   228  		if e.ResponseFor(widget.settings.email) != "declined" {
   229  			ret = append(ret, e)
   230  		}
   231  	}
   232  	return ret
   233  }