[gnome-shell] dateMenu: Add "Events" section
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] dateMenu: Add "Events" section
- Date: Fri, 5 Jun 2020 23:11:23 +0000 (UTC)
commit fdd9def9222f5dec61812a8159f5af263ba99b08
Author: Florian Müllner <fmuellner gnome org>
Date: Thu May 14 22:24:36 2020 +0200
dateMenu: Add "Events" section
Events have a clear and obvious connection to the calendar, and similar
to the Clocks and Weather sections there's a strong link to a particular
application.
Adding them as another section to the right-hand side of the calendar
therefore presents a viable alternative to the old events section.
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1282
data/theme/gnome-shell-sass/widgets/_calendar.scss | 26 +++
js/ui/dateMenu.js | 192 +++++++++++++++++++++
2 files changed, 218 insertions(+)
---
diff --git a/data/theme/gnome-shell-sass/widgets/_calendar.scss
b/data/theme/gnome-shell-sass/widgets/_calendar.scss
index e99b8a82e3..70d95193a9 100644
--- a/data/theme/gnome-shell-sass/widgets/_calendar.scss
+++ b/data/theme/gnome-shell-sass/widgets/_calendar.scss
@@ -177,6 +177,32 @@
}
}
+/* Events */
+.events-button {
+ @include notification_bubble;
+ padding: $base_padding * 2;
+
+ .events-box {
+ spacing: $base_spacing;
+ }
+
+ .events-list {
+ spacing: 2 * $base_spacing;
+ }
+
+ .events-title {
+ color: desaturate(darken($fg_color,40%), 10%);
+ font-weight: bold;
+ margin-bottom: $base_margin;
+ }
+
+ .event-time {
+ color: darken($fg_color,20%);
+ font-feature-settings: "tnum";
+ @include fontsize($base_font_size - 1);
+ }
+}
+
/* World clocks */
.world-clocks-button {
@include notification_bubble;
diff --git a/js/ui/dateMenu.js b/js/ui/dateMenu.js
index a98b5eec59..ce0a1f6173 100644
--- a/js/ui/dateMenu.js
+++ b/js/ui/dateMenu.js
@@ -13,7 +13,11 @@ const System = imports.system;
const { loadInterfaceXML } = imports.misc.fileUtils;
+const NC_ = (context, str) => '%s\u0004%s'.format(context, str);
+const T_ = Shell.util_translate_time_string;
+
const MAX_FORECASTS = 5;
+const ELLIPSIS_CHAR = '\u2026';
const ClocksIntegrationIface = loadInterfaceXML('org.gnome.Shell.ClocksIntegration');
const ClocksProxy = Gio.DBusProxy.makeProxyWrapper(ClocksIntegrationIface);
@@ -84,6 +88,188 @@ class TodayButton extends St.Button {
}
});
+var EventsSection = GObject.registerClass(
+class EventsSection extends St.Button {
+ _init() {
+ super._init({
+ style_class: 'events-button',
+ can_focus: true,
+ x_expand: true,
+ child: new St.BoxLayout({
+ style_class: 'events-box',
+ vertical: true,
+ x_expand: true,
+ }),
+ });
+
+ this._startDate = null;
+ this._endDate = null;
+
+ this._eventSource = null;
+ this._calendarApp = null;
+
+ this._title = new St.Label({
+ style_class: 'events-title',
+ });
+ this.child.add_child(this._title);
+
+ this._eventsList = new St.BoxLayout({
+ style_class: 'events-list',
+ vertical: true,
+ x_expand: true,
+ });
+ this.child.add_child(this._eventsList);
+
+ this._appSys = Shell.AppSystem.get_default();
+ this._appSys.connect('installed-changed',
+ this._appInstalledChanged.bind(this));
+ this._appInstalledChanged();
+ }
+
+ setDate(date) {
+ const day = [date.getFullYear(), date.getMonth(), date.getDate()];
+ this._startDate = new Date(...day);
+ this._endDate = new Date(...day, 23, 59, 59, 999);
+
+ this._updateTitle();
+ this._reloadEvents();
+ }
+
+ setEventSource(eventSource) {
+ if (!(eventSource instanceof Calendar.EventSourceBase))
+ throw new Error('Event source is not valid type');
+
+ this._eventSource = eventSource;
+ this._eventSource.connect('changed', this._reloadEvents.bind(this));
+ this._eventSource.connect('notify::has-calendars',
+ this._sync.bind(this));
+ this._sync();
+ }
+
+ _updateTitle() {
+ /* Translators: Shown on calendar heading when selected day occurs on current year */
+ const sameYearFormat = T_(NC_('calendar heading', '%B %-d'));
+
+ /* Translators: Shown on calendar heading when selected day occurs on different year */
+ const otherYearFormat = T_(NC_('calendar heading', '%B %-d %Y'));
+
+ const timeSpanDay = GLib.TIME_SPAN_DAY / 1000;
+ const now = new Date();
+
+ if (this._startDate <= now && now <= this._endDate)
+ this._title.text = _('Today');
+ else if (this._endDate < now && now - this._endDate < timeSpanDay)
+ this._title.text = _('Yesterday');
+ else if (this._startDate > now && this._startDate - now < timeSpanDay)
+ this._title.text = _('Tomorrow');
+ else if (this._startDate.getFullYear() === now.getFullYear())
+ this._title.text = this._startDate.toLocaleFormat(sameYearFormat);
+ else
+ this._title.text = this._startDate.toLocaleFormat(otherYearFormat);
+ }
+
+ _formatEventTime(event) {
+ const allDay = event.allDay ||
+ (event.date <= this._startDate && event.end >= this._endDate);
+
+ let title;
+ if (allDay) {
+ /* Translators: Shown in calendar event list for all day events
+ * Keep it short, best if you can use less then 10 characters
+ */
+ title = C_('event list time', 'All Day');
+ } else {
+ let date = event.date >= this._startDate ? event.date : event.end;
+ title = Util.formatTime(date, { timeOnly: true });
+ }
+
+ const rtl = Clutter.get_default_text_direction() === Clutter.TextDirection.RTL;
+ if (event.date < this._startDate && !event.allDay) {
+ if (rtl)
+ title = '%s%s'.format(title, ELLIPSIS_CHAR);
+ else
+ title = '%s%s'.format(ELLIPSIS_CHAR, title);
+ }
+ if (event.end > this._endDate && !event.allDay) {
+ if (rtl)
+ title = '%s%s'.format(ELLIPSIS_CHAR, title);
+ else
+ title = '%s%s'.format(title, ELLIPSIS_CHAR);
+ }
+ return title;
+ }
+
+ _reloadEvents() {
+ if (this._eventSource.isLoading || this._reloading)
+ return;
+
+ this._reloading = true;
+
+ [...this._eventsList].forEach(c => c.destroy());
+
+ const events =
+ this._eventSource.getEvents(this._startDate, this._endDate);
+
+ for (let event of events) {
+ const box = new St.BoxLayout({
+ style_class: 'event-box',
+ vertical: true,
+ });
+ box.add(new St.Label({
+ text: event.summary,
+ style_class: 'event-summary',
+ }));
+ box.add(new St.Label({
+ text: this._formatEventTime(event),
+ style_class: 'event-time',
+ }));
+ this._eventsList.add_child(box);
+ }
+
+ if (this._eventsList.get_n_children() === 0) {
+ const placeholder = new St.Label({
+ text: _('No Events'),
+ style_class: 'event-placeholder',
+ });
+ this._eventsList.add_child(placeholder);
+ }
+
+ this._reloading = false;
+ this._sync();
+ }
+
+ vfunc_clicked() {
+ Main.overview.hide();
+ Main.panel.closeCalendar();
+
+ let appInfo = this._calendarApp;
+ if (appInfo.get_id() === 'org.gnome.Evolution.desktop') {
+ const app = this._appSys.lookup_app('evolution-calendar.desktop');
+ if (app)
+ appInfo = app.app_info;
+ }
+ appInfo.launch([], global.create_app_launch_context(0, -1));
+ }
+
+ _appInstalledChanged() {
+ const apps = Gio.AppInfo.get_recommended_for_type('text/calendar');
+ if (apps && (apps.length > 0)) {
+ const app = Gio.AppInfo.get_default_for_type('text/calendar', false);
+ const defaultInRecommended = apps.some(a => a.equal(app));
+ this._calendarApp = defaultInRecommended ? app : apps[0];
+ } else {
+ this._calendarApp = null;
+ }
+
+ return this._sync();
+ }
+
+ _sync() {
+ this.visible = this._eventSource && this._eventSource.hasCalendars;
+ this.reactive = this._calendarApp !== null;
+ }
+});
+
var WorldClocksSection = GObject.registerClass(
class WorldClocksSection extends St.Button {
_init() {
@@ -632,6 +818,7 @@ class DateMenuButton extends PanelMenu.Button {
this._calendar.connect('selected-date-changed', (_calendar, datetime) => {
let date = _gDateTimeToDate(datetime);
layout.frozen = !_isToday(date);
+ this._eventsItem.setDate(date);
});
this.menu.connect('open-state-changed', (menu, isOpen) => {
@@ -640,6 +827,7 @@ class DateMenuButton extends PanelMenu.Button {
let now = new Date();
this._calendar.setDate(now);
this._date.setDate(now);
+ this._eventsItem.setDate(now);
}
});
@@ -670,6 +858,9 @@ class DateMenuButton extends PanelMenu.Button {
style_class: 'datemenu-displays-box' });
this._displaysSection.add_actor(displaysBox);
+ this._eventsItem = new EventsSection();
+ displaysBox.add_child(this._eventsItem);
+
this._clocksItem = new WorldClocksSection();
displaysBox.add_child(this._clocksItem);
@@ -695,6 +886,7 @@ class DateMenuButton extends PanelMenu.Button {
this._eventSource.destroy();
this._calendar.setEventSource(eventSource);
+ this._eventsItem.setEventSource(eventSource);
this._eventSource = eventSource;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]