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: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3429>
This commit is contained in:
parent
e77b716793
commit
64aadeece3
@ -7,7 +7,6 @@ import St from 'gi://St';
|
|||||||
|
|
||||||
import * as Main from './main.js';
|
import * as Main from './main.js';
|
||||||
import * as MessageList from './messageList.js';
|
import * as MessageList from './messageList.js';
|
||||||
import * as MessageTray from './messageTray.js';
|
|
||||||
import * as Mpris from './mpris.js';
|
import * as Mpris from './mpris.js';
|
||||||
import * as PopupMenu from './popupMenu.js';
|
import * as PopupMenu from './popupMenu.js';
|
||||||
import {ensureActorVisibleInScrollView} from '../misc/animationUtils.js';
|
import {ensureActorVisibleInScrollView} from '../misc/animationUtils.js';
|
||||||
@ -16,7 +15,6 @@ import {formatDateWithCFormatString} from '../misc/dateUtils.js';
|
|||||||
import {loadInterfaceXML} from '../misc/fileUtils.js';
|
import {loadInterfaceXML} from '../misc/fileUtils.js';
|
||||||
|
|
||||||
const SHOW_WEEKDATE_KEY = 'show-weekdate';
|
const SHOW_WEEKDATE_KEY = 'show-weekdate';
|
||||||
const MAX_NOTIFICATION_BUTTONS = 3;
|
|
||||||
|
|
||||||
const NC_ = (context, str) => `${context}\u0004${str}`;
|
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(
|
const Placeholder = GObject.registerClass(
|
||||||
class Placeholder extends St.BoxLayout {
|
class Placeholder extends St.BoxLayout {
|
||||||
_init() {
|
_init() {
|
||||||
@ -1025,7 +880,7 @@ class CalendarMessageList extends St.Widget {
|
|||||||
this._mediaSection = new Mpris.MediaSection();
|
this._mediaSection = new Mpris.MediaSection();
|
||||||
this._addSection(this._mediaSection);
|
this._addSection(this._mediaSection);
|
||||||
|
|
||||||
this._notificationSection = new NotificationSection();
|
this._notificationSection = new MessageList.NotificationSection();
|
||||||
this._addSection(this._notificationSection);
|
this._addSection(this._notificationSection);
|
||||||
|
|
||||||
Main.sessionMode.connect('updated', this._sync.bind(this));
|
Main.sessionMode.connect('updated', this._sync.bind(this));
|
||||||
|
@ -14,6 +14,7 @@ import * as MessageTray from './messageTray.js';
|
|||||||
import * as Util from '../misc/util.js';
|
import * as Util from '../misc/util.js';
|
||||||
import {formatTimeSpan} from '../misc/dateUtils.js';
|
import {formatTimeSpan} from '../misc/dateUtils.js';
|
||||||
|
|
||||||
|
const MAX_NOTIFICATION_BUTTONS = 3;
|
||||||
const MESSAGE_ANIMATION_TIME = 100;
|
const MESSAGE_ANIMATION_TIME = 100;
|
||||||
|
|
||||||
const DEFAULT_EXPAND_LINES = 6;
|
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({
|
export const MessageListSection = GObject.registerClass({
|
||||||
Properties: {
|
Properties: {
|
||||||
'can-clear': GObject.ParamSpec.boolean(
|
'can-clear': GObject.ParamSpec.boolean(
|
||||||
@ -864,3 +947,64 @@ export const MessageListSection = GObject.registerClass({
|
|||||||
this.visible = this.allowed && this._shouldShow();
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@ -6,7 +6,6 @@ import Meta from 'gi://Meta';
|
|||||||
import Shell from 'gi://Shell';
|
import Shell from 'gi://Shell';
|
||||||
import St from 'gi://St';
|
import St from 'gi://St';
|
||||||
|
|
||||||
import * as Calendar from './calendar.js';
|
|
||||||
import * as GnomeSession from '../misc/gnomeSession.js';
|
import * as GnomeSession from '../misc/gnomeSession.js';
|
||||||
import * as Layout from './layout.js';
|
import * as Layout from './layout.js';
|
||||||
import * as Main from './main.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.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.can_focus = false;
|
||||||
this._banner._header.expandButton.visible = false;
|
this._banner._header.expandButton.visible = false;
|
||||||
this._banner.add_style_class_name('notification-banner');
|
this._banner.add_style_class_name('notification-banner');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user