From 64aadeece3c72de8bb627e8bc9df268f8ce04ffb Mon Sep 17 00:00:00 2001 From: Julian Sparber Date: Fri, 10 May 2024 10:05:45 +0200 Subject: [PATCH] messages: Move message widgets from calendar.js to messageList.js The widgets `NotificationMessage` and `NotificationSection` in `calendar.js` aren't used only by the calendar. Move the two widget to messageList.js since once we add by-source grouping for messages (which will happen in a future commit) we need a much tighter coupling between them and the rest of the MessageList. In future the `NotificationSection` will need to be removed to make expanding of groups work. This also removes a circular import of files: `calender.js` imports `messageTray.js` and it imports `calender.js`. Part-of: --- js/ui/calendar.js | 147 +------------------------------------------ js/ui/messageList.js | 144 ++++++++++++++++++++++++++++++++++++++++++ js/ui/messageTray.js | 3 +- 3 files changed, 146 insertions(+), 148 deletions(-) diff --git a/js/ui/calendar.js b/js/ui/calendar.js index 4cc079bbc..57847278e 100644 --- a/js/ui/calendar.js +++ b/js/ui/calendar.js @@ -7,7 +7,6 @@ import St from 'gi://St'; import * as Main from './main.js'; import * as MessageList from './messageList.js'; -import * as MessageTray from './messageTray.js'; import * as Mpris from './mpris.js'; import * as PopupMenu from './popupMenu.js'; import {ensureActorVisibleInScrollView} from '../misc/animationUtils.js'; @@ -16,7 +15,6 @@ import {formatDateWithCFormatString} from '../misc/dateUtils.js'; import {loadInterfaceXML} from '../misc/fileUtils.js'; const SHOW_WEEKDATE_KEY = 'show-weekdate'; -const MAX_NOTIFICATION_BUTTONS = 3; const NC_ = (context, str) => `${context}\u0004${str}`; @@ -763,149 +761,6 @@ export const Calendar = GObject.registerClass({ } }); -export const NotificationMessage = GObject.registerClass( -class NotificationMessage extends MessageList.Message { - constructor(notification) { - super(notification.source); - - this.notification = notification; - - this.connect('close', () => { - this._closed = true; - if (this.notification) - this.notification.destroy(MessageTray.NotificationDestroyedReason.DISMISSED); - }); - notification.connectObject( - 'action-added', (_, action) => this._addAction(action), - 'action-removed', (_, action) => this._removeAction(action), - 'destroy', () => { - this.notification = null; - if (!this._closed) - this.close(); - }, this); - - notification.bind_property('title', - this, 'title', - GObject.BindingFlags.SYNC_CREATE); - notification.bind_property('body', - this, 'body', - GObject.BindingFlags.SYNC_CREATE); - notification.bind_property('use-body-markup', - this, 'use-body-markup', - GObject.BindingFlags.SYNC_CREATE); - notification.bind_property('datetime', - this, 'datetime', - GObject.BindingFlags.SYNC_CREATE); - notification.bind_property('gicon', - this, 'icon', - GObject.BindingFlags.SYNC_CREATE); - - this._actions = new Map(); - this.notification.actions.forEach(action => { - this._addAction(action); - }); - } - - vfunc_clicked() { - this.notification.activate(); - } - - canClose() { - return true; - } - - _addAction(action) { - if (!this._buttonBox) { - this._buttonBox = new St.BoxLayout({ - x_expand: true, - style_class: 'notification-buttons-bin', - }); - this.setActionArea(this._buttonBox); - global.focus_manager.add_group(this._buttonBox); - } - - if (this._buttonBox.get_n_children() >= MAX_NOTIFICATION_BUTTONS) - return; - - const button = new St.Button({ - style_class: 'notification-button', - x_expand: true, - label: action.label, - }); - - button.connect('clicked', () => action.activate()); - - this._actions.set(action, button); - this._buttonBox.add_child(button); - } - - _removeAction(action) { - this._actions.get(action)?.destroy(); - this._actions.delete(action); - } -}); - -const NotificationSection = GObject.registerClass( -class NotificationSection extends MessageList.MessageListSection { - _init() { - super._init(); - - this._nUrgent = 0; - - Main.messageTray.connect('source-added', this._sourceAdded.bind(this)); - Main.messageTray.getSources().forEach(source => { - this._sourceAdded(Main.messageTray, source); - }); - } - - get allowed() { - return Main.sessionMode.hasNotifications && - !Main.sessionMode.isGreeter; - } - - _sourceAdded(tray, source) { - source.connectObject('notification-added', - this._onNotificationAdded.bind(this), this); - } - - _onNotificationAdded(source, notification) { - let message = new NotificationMessage(notification); - - let isUrgent = notification.urgency === MessageTray.Urgency.CRITICAL; - - notification.connectObject( - 'destroy', () => { - if (isUrgent) - this._nUrgent--; - }, - 'notify::datetime', () => { - // The datetime property changes whenever the notification is updated - this.moveMessage(message, isUrgent ? 0 : this._nUrgent, this.mapped); - }, this); - - if (isUrgent) { - // Keep track of urgent notifications to keep them on top - this._nUrgent++; - } else if (this.mapped) { - // Only acknowledge non-urgent notifications in case it - // has important actions that are inaccessible when not - // shown as banner - notification.acknowledged = true; - } - - let index = isUrgent ? 0 : this._nUrgent; - this.addMessageAtIndex(message, index, this.mapped); - } - - vfunc_map() { - this._messages.forEach(message => { - if (message.notification.urgency !== MessageTray.Urgency.CRITICAL) - message.notification.acknowledged = true; - }); - super.vfunc_map(); - } -}); - const Placeholder = GObject.registerClass( class Placeholder extends St.BoxLayout { _init() { @@ -1025,7 +880,7 @@ class CalendarMessageList extends St.Widget { this._mediaSection = new Mpris.MediaSection(); this._addSection(this._mediaSection); - this._notificationSection = new NotificationSection(); + this._notificationSection = new MessageList.NotificationSection(); this._addSection(this._notificationSection); Main.sessionMode.connect('updated', this._sync.bind(this)); diff --git a/js/ui/messageList.js b/js/ui/messageList.js index 2b8793f85..ac3ab542f 100644 --- a/js/ui/messageList.js +++ b/js/ui/messageList.js @@ -14,6 +14,7 @@ import * as MessageTray from './messageTray.js'; import * as Util from '../misc/util.js'; import {formatTimeSpan} from '../misc/dateUtils.js'; +const MAX_NOTIFICATION_BUTTONS = 3; const MESSAGE_ANIMATION_TIME = 100; const DEFAULT_EXPAND_LINES = 6; @@ -656,6 +657,88 @@ export const Message = GObject.registerClass({ } }); +export const NotificationMessage = GObject.registerClass( +class NotificationMessage extends Message { + constructor(notification) { + super(notification.source); + + this.notification = notification; + + this.connect('close', () => { + this._closed = true; + if (this.notification) + this.notification.destroy(MessageTray.NotificationDestroyedReason.DISMISSED); + }); + notification.connectObject( + 'action-added', (_, action) => this._addAction(action), + 'action-removed', (_, action) => this._removeAction(action), + 'destroy', () => { + this.notification = null; + if (!this._closed) + this.close(); + }, this); + + notification.bind_property('title', + this, 'title', + GObject.BindingFlags.SYNC_CREATE); + notification.bind_property('body', + this, 'body', + GObject.BindingFlags.SYNC_CREATE); + notification.bind_property('use-body-markup', + this, 'use-body-markup', + GObject.BindingFlags.SYNC_CREATE); + notification.bind_property('datetime', + this, 'datetime', + GObject.BindingFlags.SYNC_CREATE); + notification.bind_property('gicon', + this, 'icon', + GObject.BindingFlags.SYNC_CREATE); + + this._actions = new Map(); + this.notification.actions.forEach(action => { + this._addAction(action); + }); + } + + vfunc_clicked() { + this.notification.activate(); + } + + canClose() { + return true; + } + + _addAction(action) { + if (!this._buttonBox) { + this._buttonBox = new St.BoxLayout({ + x_expand: true, + style_class: 'notification-buttons-bin', + }); + this.setActionArea(this._buttonBox); + global.focus_manager.add_group(this._buttonBox); + } + + if (this._buttonBox.get_n_children() >= MAX_NOTIFICATION_BUTTONS) + return; + + const button = new St.Button({ + style_class: 'notification-button', + x_expand: true, + label: action.label, + }); + + button.connect('clicked', () => action.activate()); + + this._actions.set(action, button); + this._buttonBox.add_child(button); + } + + _removeAction(action) { + this._actions.get(action)?.destroy(); + this._actions.delete(action); + } +}); + export const MessageListSection = GObject.registerClass({ Properties: { 'can-clear': GObject.ParamSpec.boolean( @@ -864,3 +947,64 @@ export const MessageListSection = GObject.registerClass({ this.visible = this.allowed && this._shouldShow(); } }); + +export const NotificationSection = GObject.registerClass( +class NotificationSection extends MessageListSection { + _init() { + super._init(); + + this._nUrgent = 0; + + Main.messageTray.connect('source-added', this._sourceAdded.bind(this)); + Main.messageTray.getSources().forEach(source => { + this._sourceAdded(Main.messageTray, source); + }); + } + + get allowed() { + return Main.sessionMode.hasNotifications && + !Main.sessionMode.isGreeter; + } + + _sourceAdded(tray, source) { + source.connectObject('notification-added', + this._onNotificationAdded.bind(this), this); + } + + _onNotificationAdded(source, notification) { + let message = new NotificationMessage(notification); + + let isUrgent = notification.urgency === MessageTray.Urgency.CRITICAL; + + notification.connectObject( + 'destroy', () => { + if (isUrgent) + this._nUrgent--; + }, + 'notify::datetime', () => { + // The datetime property changes whenever the notification is updated + this.moveMessage(message, isUrgent ? 0 : this._nUrgent, this.mapped); + }, this); + + if (isUrgent) { + // Keep track of urgent notifications to keep them on top + this._nUrgent++; + } else if (this.mapped) { + // Only acknowledge non-urgent notifications in case it + // has important actions that are inaccessible when not + // shown as banner + notification.acknowledged = true; + } + + let index = isUrgent ? 0 : this._nUrgent; + this.addMessageAtIndex(message, index, this.mapped); + } + + vfunc_map() { + this._messages.forEach(message => { + if (message.notification.urgency !== MessageTray.Urgency.CRITICAL) + message.notification.acknowledged = true; + }); + super.vfunc_map(); + } +}); diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js index c13a3fdb7..fde74b08d 100644 --- a/js/ui/messageTray.js +++ b/js/ui/messageTray.js @@ -6,7 +6,6 @@ import Meta from 'gi://Meta'; import Shell from 'gi://Shell'; import St from 'gi://St'; -import * as Calendar from './calendar.js'; import * as GnomeSession from '../misc/gnomeSession.js'; import * as Layout from './layout.js'; import * as Main from './main.js'; @@ -1119,7 +1118,7 @@ export const MessageTray = GObject.registerClass({ this.idleMonitor.add_user_active_watch(this._onIdleMonitorBecameActive.bind(this)); } - this._banner = new Calendar.NotificationMessage(this._notification); + this._banner = new MessageList.NotificationMessage(this._notification); this._banner.can_focus = false; this._banner._header.expandButton.visible = false; this._banner.add_style_class_name('notification-banner');