notifications: Add buttons to Calendar.NotificationMessage via actions
Since we also want to show the buttons in the calendar move the code to add buttons/actions from `MessageTray.NotificationBanner` to `Calendar.NotificationMessage`. As nothing uses custom buttons that aren't backed by actions anymore, remove that bit of the public API. Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/7099 Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3173>
This commit is contained in:
parent
7ff5f4ea51
commit
d44adf3b78
@ -14,12 +14,12 @@ $notification_banner_width: 34em;
|
|||||||
@if $contrast == 'high' {
|
@if $contrast == 'high' {
|
||||||
@include draw_hc_inset();
|
@include draw_hc_inset();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.notification-actions {
|
|
||||||
spacing: 0;
|
.notification-buttons-bin {
|
||||||
}
|
spacing: 0;
|
||||||
|
}
|
||||||
.notification-button {
|
|
||||||
@extend %bubble_button;
|
.notification-button {
|
||||||
}
|
@extend %bubble_button;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ 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}`;
|
||||||
|
|
||||||
@ -782,11 +783,19 @@ class NotificationMessage extends MessageList.Message {
|
|||||||
});
|
});
|
||||||
notification.connectObject(
|
notification.connectObject(
|
||||||
'updated', this._onUpdated.bind(this),
|
'updated', this._onUpdated.bind(this),
|
||||||
|
'action-added', (_, action) => this._addAction(action),
|
||||||
|
'action-removed', (_, action) => this._removeAction(action),
|
||||||
|
|
||||||
'destroy', () => {
|
'destroy', () => {
|
||||||
this.notification = null;
|
this.notification = null;
|
||||||
if (!this._closed)
|
if (!this._closed)
|
||||||
this.close();
|
this.close();
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
|
this._actions = new Map();
|
||||||
|
this.notification.actions.forEach(action => {
|
||||||
|
this._addAction(action);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_getIcon() {
|
_getIcon() {
|
||||||
@ -815,6 +824,36 @@ class NotificationMessage extends MessageList.Message {
|
|||||||
canClose() {
|
canClose() {
|
||||||
return true;
|
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(
|
const NotificationSection = GObject.registerClass(
|
||||||
|
@ -469,7 +469,7 @@ export const Message = GObject.registerClass({
|
|||||||
});
|
});
|
||||||
vbox.add_child(hbox);
|
vbox.add_child(hbox);
|
||||||
|
|
||||||
this._actionBin = new St.Widget({
|
this._actionBin = new St.Bin({
|
||||||
layout_manager: new ScaleLayout(),
|
layout_manager: new ScaleLayout(),
|
||||||
visible: false,
|
visible: false,
|
||||||
});
|
});
|
||||||
@ -557,17 +557,8 @@ export const Message = GObject.registerClass({
|
|||||||
}
|
}
|
||||||
|
|
||||||
setActionArea(actor) {
|
setActionArea(actor) {
|
||||||
if (actor == null) {
|
this._actionBin.child = actor;
|
||||||
if (this._actionBin.get_n_children() > 0)
|
this._actionBin.visible = actor && this.expanded;
|
||||||
this._actionBin.get_child_at_index(0).destroy();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._actionBin.get_n_children() > 0)
|
|
||||||
throw new Error('Message already has an action area');
|
|
||||||
|
|
||||||
this._actionBin.add_child(actor);
|
|
||||||
this._actionBin.visible = this.expanded;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addMediaControl(iconName, callback) {
|
addMediaControl(iconName, callback) {
|
||||||
@ -583,7 +574,7 @@ export const Message = GObject.registerClass({
|
|||||||
expand(animate) {
|
expand(animate) {
|
||||||
this.expanded = true;
|
this.expanded = true;
|
||||||
|
|
||||||
this._actionBin.visible = this._actionBin.get_n_children() > 0;
|
this._actionBin.visible = !!this._actionBin.child;
|
||||||
|
|
||||||
const duration = animate ? MessageTray.ANIMATION_TIME : 0;
|
const duration = animate ? MessageTray.ANIMATION_TIME : 0;
|
||||||
this._bodyStack.ease_property('@layout.expansion', 1, {
|
this._bodyStack.ease_property('@layout.expansion', 1, {
|
||||||
|
@ -27,7 +27,6 @@ const LONGER_HIDE_TIMEOUT = 600;
|
|||||||
|
|
||||||
const MAX_NOTIFICATIONS_IN_QUEUE = 3;
|
const MAX_NOTIFICATIONS_IN_QUEUE = 3;
|
||||||
const MAX_NOTIFICATIONS_PER_SOURCE = 3;
|
const MAX_NOTIFICATIONS_PER_SOURCE = 3;
|
||||||
const MAX_NOTIFICATION_BUTTONS = 3;
|
|
||||||
|
|
||||||
// We delay hiding of the tray if the mouse is within MOUSE_LEFT_ACTOR_THRESHOLD
|
// We delay hiding of the tray if the mouse is within MOUSE_LEFT_ACTOR_THRESHOLD
|
||||||
// range from the point where it left the tray.
|
// range from the point where it left the tray.
|
||||||
@ -498,7 +497,18 @@ export const Notification = GObject.registerClass({
|
|||||||
// @label: the label for the action's button
|
// @label: the label for the action's button
|
||||||
// @callback: the callback for the action
|
// @callback: the callback for the action
|
||||||
addAction(label, callback) {
|
addAction(label, callback) {
|
||||||
const action = new Action(label, callback);
|
const action = new Action(label, () => {
|
||||||
|
callback();
|
||||||
|
|
||||||
|
// We don't hide a resident notification when the user invokes one of its actions,
|
||||||
|
// because it is common for such notifications to update themselves with new
|
||||||
|
// information based on the action. We'd like to display the updated information
|
||||||
|
// in place, rather than pop-up a new notification.
|
||||||
|
if (this.resident)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.destroy();
|
||||||
|
});
|
||||||
this.actions.push(action);
|
this.actions.push(action);
|
||||||
this.emit('action-added', action);
|
this.emit('action-added', action);
|
||||||
}
|
}
|
||||||
@ -557,7 +567,13 @@ export const Notification = GObject.registerClass({
|
|||||||
activate() {
|
activate() {
|
||||||
this.emit('activated');
|
this.emit('activated');
|
||||||
|
|
||||||
if (!this.resident)
|
// We don't hide a resident notification when the user invokes one of its actions,
|
||||||
|
// because it is common for such notifications to update themselves with new
|
||||||
|
// information based on the action. We'd like to display the updated information
|
||||||
|
// in place, rather than pop-up a new notification.
|
||||||
|
if (this.resident)
|
||||||
|
return;
|
||||||
|
|
||||||
this.destroy();
|
this.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -579,10 +595,6 @@ export const NotificationBanner = GObject.registerClass({
|
|||||||
this.can_focus = false;
|
this.can_focus = false;
|
||||||
this.add_style_class_name('notification-banner');
|
this.add_style_class_name('notification-banner');
|
||||||
|
|
||||||
this._buttonBox = null;
|
|
||||||
|
|
||||||
this._addActions();
|
|
||||||
|
|
||||||
this.notification.connectObject('activated', () => {
|
this.notification.connectObject('activated', () => {
|
||||||
// We hide all types of notifications once the user clicks on
|
// We hide all types of notifications once the user clicks on
|
||||||
// them because the common outcome of clicking should be the
|
// them because the common outcome of clicking should be the
|
||||||
@ -591,64 +603,6 @@ export const NotificationBanner = GObject.registerClass({
|
|||||||
this.emit('done-displaying');
|
this.emit('done-displaying');
|
||||||
}, this);
|
}, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onUpdated(n, clear) {
|
|
||||||
super._onUpdated(n, clear);
|
|
||||||
|
|
||||||
if (clear) {
|
|
||||||
this.setActionArea(null);
|
|
||||||
this._buttonBox = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._addActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
_addActions() {
|
|
||||||
this.notification.actions.forEach(action => {
|
|
||||||
this.addAction(action.label, () => action.activate());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
addButton(button, callback) {
|
|
||||||
if (!this._buttonBox) {
|
|
||||||
this._buttonBox = new St.BoxLayout({
|
|
||||||
style_class: 'notification-actions',
|
|
||||||
x_expand: true,
|
|
||||||
});
|
|
||||||
this.setActionArea(this._buttonBox);
|
|
||||||
global.focus_manager.add_group(this._buttonBox);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._buttonBox.get_n_children() >= MAX_NOTIFICATION_BUTTONS)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
this._buttonBox.add_child(button);
|
|
||||||
button.connect('clicked', () => {
|
|
||||||
callback();
|
|
||||||
|
|
||||||
if (!this.notification.resident) {
|
|
||||||
// We don't hide a resident notification when the user invokes one of its actions,
|
|
||||||
// because it is common for such notifications to update themselves with new
|
|
||||||
// information based on the action. We'd like to display the updated information
|
|
||||||
// in place, rather than pop-up a new notification.
|
|
||||||
this.emit('done-displaying');
|
|
||||||
this.notification.destroy();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
addAction(label, callback) {
|
|
||||||
const button = new St.Button({
|
|
||||||
style_class: 'notification-button',
|
|
||||||
label,
|
|
||||||
x_expand: true,
|
|
||||||
can_focus: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.addButton(button, callback);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const Source = GObject.registerClass({
|
export const Source = GObject.registerClass({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user