From 65c136f4ed920996e63845b683c42d94f33a5054 Mon Sep 17 00:00:00 2001 From: Andreas Brauchli Date: Wed, 17 Sep 2014 15:32:13 -1000 Subject: [PATCH] Calendar: Show multi-day event continuation Currently, multi-day events are shown as individual appointments on each day. This patch ellipsizes multi-day events to indicate continuation on the prior or following day (or other time-period.) The time label spot is now replaced by a box layout that contains the prefix ellipsis label, the time label and the postfix ellipsis label. In order to keep the alignment, ellipses are merely invisible (zero opacity) when hidden. The ellipses are styled using the events-day-time-ellipses class which, by default, take the color of the event text. When RTL is used, the box contents are adjusted accordingly (clutter does that for us). An event spanning three days now displays "...All Day..." in the calendar on the second day. https://bugzilla.gnome.org/show_bug.cgi?id=727302 --- data/theme/gnome-shell.css | 4 +++ js/ui/calendar.js | 73 +++++++++++++++++++++++++++++--------- 2 files changed, 60 insertions(+), 17 deletions(-) diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index bb5d2c468..10ceb34c8 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -1494,6 +1494,10 @@ StScrollBar StButton#vhandle:active { text-align: right; } +.events-day-time-ellipses { + color: rgba(153, 153, 153, 1.0); +} + .events-day-time:rtl { text-align: left; } diff --git a/js/ui/calendar.js b/js/ui/calendar.js index db6cb2c3f..3899ecb81 100644 --- a/js/ui/calendar.js +++ b/js/ui/calendar.js @@ -13,6 +13,13 @@ const Shell = imports.gi.Shell; const MSECS_IN_DAY = 24 * 60 * 60 * 1000; const SHOW_WEEKDATE_KEY = 'show-weekdate'; +const ELLIPSIS_CHAR = '\u2026'; +const EventEllipses = { + NONE: 0, + BEFORE: 1 << 0, + AFTER: 1 << 1, + BOTH: ~0 +}; // alias to prevent xgettext from picking up strings translated in GTK+ const gtk30_ = Gettext_gtk30.gettext; @@ -59,19 +66,33 @@ function _getEndOfDay(date) { return ret; } -function _formatEventTime(event, clockFormat) { +function _ellipsizeEventTime(event, periodBegin, periodEnd) { + if (event.allDay) + return EventEllipses.NONE; + + let ret = EventEllipses.NONE; + if (event.date < periodBegin) + ret = EventEllipses.BEFORE; + if (event.end > periodEnd) + ret |= EventEllipses.AFTER; + return ret; +} + +function _formatEventTime(event, clockFormat, periodBegin, periodEnd) { let ret; - if (event.allDay) { + let allDay = (event.allDay || (event.date <= periodBegin && event.end >= periodEnd)); + if (allDay) { /* Translators: Shown in calendar event list for all day events * Keep it short, best if you can use less then 10 characters */ ret = C_("event list time", "All Day"); } else { + let date = event.date >= periodBegin ? event.date : event.end; switch (clockFormat) { case '24h': /* Translators: Shown in calendar event list, if 24h format, \u2236 is a ratio character, similar to : */ - ret = event.date.toLocaleFormat(C_("event list time", "%H\u2236%M")); + ret = date.toLocaleFormat(C_("event list time", "%H\u2236%M")); break; default: @@ -80,7 +101,7 @@ function _formatEventTime(event, clockFormat) { /* Translators: Shown in calendar event list, if 12h format, \u2236 is a ratio character, similar to : and \u2009 is a thin space */ - ret = event.date.toLocaleFormat(C_("event list time", "%l\u2236%M\u2009%p")); + ret = date.toLocaleFormat(C_("event list time", "%l\u2236%M\u2009%p")); break; } } @@ -722,12 +743,16 @@ const EventsList = new Lang.Class({ this._eventSource.connect('changed', Lang.bind(this, this._update)); }, - _addEvent: function(event, index, includeDayName) { + _addEvent: function(event, index, includeDayName, periodBegin, periodEnd) { let dayString; - if (includeDayName) - dayString = _getEventDayAbbreviation(event.date.getDay()); - else + if (includeDayName) { + if (event.date >= periodBegin) + dayString = _getEventDayAbbreviation(event.date.getDay()); + else /* show event end day if it began earlier */ + dayString = _getEventDayAbbreviation(event.end.getDay()); + } else { dayString = ''; + } let dayLabel = new St.Label({ style_class: 'events-day-dayname', text: dayString, @@ -740,16 +765,31 @@ const EventsList = new Lang.Class({ let layout = this.actor.layout_manager; layout.attach(dayLabel, rtl ? 2 : 0, index, 1, 1); - let clockFormat = this._desktopSettings.get_string(CLOCK_FORMAT_KEY); - let timeString = _formatEventTime(event, clockFormat); + let timeString = _formatEventTime(event, clockFormat, periodBegin, periodEnd); let timeLabel = new St.Label({ style_class: 'events-day-time', text: timeString, y_align: Clutter.ActorAlign.START }); timeLabel.clutter_text.line_wrap = false; timeLabel.clutter_text.ellipsize = false; - layout.attach(timeLabel, 1, index, 1, 1); + let ellipses = _ellipsizeEventTime(event, periodBegin, periodEnd); + let preEllipsisLabel = new St.Label({ style_class: 'events-day-time-ellipses', + text: ELLIPSIS_CHAR, + y_align: Clutter.ActorAlign.START }); + let postEllipsisLabel = new St.Label({ style_class: 'events-day-time-ellipses', + text: ELLIPSIS_CHAR, + y_align: Clutter.ActorAlign.START }); + if (!(ellipses & EventEllipses.BEFORE)) + preEllipsisLabel.opacity = 0; + if (!(ellipses & EventEllipses.AFTER)) + postEllipsisLabel.opacity = 0; + + let timeLabelBoxLayout = new St.BoxLayout(); + timeLabelBoxLayout.add(preEllipsisLabel); + timeLabelBoxLayout.add(timeLabel); + timeLabelBoxLayout.add(postEllipsisLabel); + layout.attach(timeLabelBoxLayout, 1, index, 1, 1); let titleLabel = new St.Label({ style_class: 'events-day-task', text: event.summary, @@ -760,8 +800,8 @@ const EventsList = new Lang.Class({ layout.attach(titleLabel, rtl ? 0 : 2, index, 1, 1); }, - _addPeriod: function(header, index, begin, end, includeDayName, showNothingScheduled) { - let events = this._eventSource.getEvents(begin, end); + _addPeriod: function(header, index, periodBegin, periodEnd, includeDayName, showNothingScheduled) { + let events = this._eventSource.getEvents(periodBegin, periodEnd); if (events.length == 0 && !showNothingScheduled) return index; @@ -772,15 +812,14 @@ const EventsList = new Lang.Class({ index++; for (let n = 0; n < events.length; n++) { - this._addEvent(events[n], index, includeDayName); + this._addEvent(events[n], index, includeDayName, periodBegin, periodEnd); index++; } if (events.length == 0 && showNothingScheduled) { - let now = new Date(); /* Translators: Text to show if there are no events */ - let nothingEvent = new CalendarEvent(now, now, _("Nothing Scheduled"), true); - this._addEvent(nothingEvent, index, false); + let nothingEvent = new CalendarEvent(periodBegin, periodBegin, _("Nothing Scheduled"), true); + this._addEvent(nothingEvent, index, false, periodBegin, periodEnd); index++; }