messageTray: Make addButton/addAction take a callback

This is a much simpler API for consumers to manage.

https://bugzilla.gnome.org/show_bug.cgi?id=710137
This commit is contained in:
Jasper St. Pierre 2013-10-13 23:06:09 -04:00
parent 5f081b8f8d
commit 43f4682ec4
5 changed files with 99 additions and 137 deletions

View File

@ -1095,22 +1095,16 @@ const RoomInviteNotification = new Lang.Class({
* for example. */ * for example. */
this.addBody(_("%s is inviting you to join %s").format(inviter.get_alias(), channel.get_identifier())); this.addBody(_("%s is inviting you to join %s").format(inviter.get_alias(), channel.get_identifier()));
this.addAction('decline', _("Decline")); this.addAction(_("Decline"), Lang.bind(this, function() {
this.addAction('accept', _("Accept")); dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, '', function(src, result) {
src.leave_channels_finish(result);
this.connect('action-invoked', Lang.bind(this, function(self, action) { });
switch (action) { this.destroy();
case 'decline': }));
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, this.addAction(_("Accept"), Lang.bind(this, function() {
'', function(src, result) { dispatchOp.handle_with_time_async('', global.get_current_time(), function(src, result) {
src.leave_channels_finish(result)}); src.handle_with_time_finish(result);
break; });
case 'accept':
dispatchOp.handle_with_time_async('', global.get_current_time(),
function(src, result) {
src.handle_with_time_finish(result)});
break;
}
this.destroy(); this.destroy();
})); }));
} }
@ -1136,23 +1130,17 @@ const AudioVideoNotification = new Lang.Class({
this.setUrgency(MessageTray.Urgency.CRITICAL); this.setUrgency(MessageTray.Urgency.CRITICAL);
this.addAction('reject', _("Decline")); this.addAction(_("Decline"), Lang.bind(this, function() {
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, '', function(src, result) {
src.leave_channels_finish(result);
});
this.destroy();
}));
/* translators: this is a button label (verb), not a noun */ /* translators: this is a button label (verb), not a noun */
this.addAction('answer', _("Answer")); this.addAction(_("Answer"), Lang.bind(this, function() {
dispatchOp.handle_with_time_async('', global.get_current_time(), function(src, result) {
this.connect('action-invoked', Lang.bind(this, function(self, action) { src.handle_with_time_finish(result);
switch (action) { });
case 'reject':
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE,
'', function(src, result) {
src.leave_channels_finish(result)});
break;
case 'answer':
dispatchOp.handle_with_time_async('', global.get_current_time(),
function(src, result) {
src.handle_with_time_finish(result)});
break;
}
this.destroy(); this.destroy();
})); }));
} }
@ -1176,22 +1164,16 @@ const FileTransferNotification = new Lang.Class({
{ customContent: true }); { customContent: true });
this.setResident(true); this.setResident(true);
this.addAction('decline', _("Decline")); this.addAction(_("Decline"), Lang.bind(this, function() {
this.addAction('accept', _("Accept")); dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, '', function(src, result) {
src.leave_channels_finish(result);
this.connect('action-invoked', Lang.bind(this, function(self, action) { });
switch (action) { this.destroy();
case 'decline': }));
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, this.addAction(_("Accept"), Lang.bind(this, function() {
'', function(src, result) { dispatchOp.handle_with_time_async('', global.get_current_time(), function(src, result) {
src.leave_channels_finish(result)}); src.handle_with_time_finish(result);
break; });
case 'accept':
dispatchOp.handle_with_time_async('', global.get_current_time(),
function(src, result) {
src.handle_with_time_finish(result)});
break;
}
this.destroy(); this.destroy();
})); }));
} }
@ -1239,27 +1221,20 @@ const SubscriptionRequestNotification = new Lang.Class({
this.addActor(layout); this.addActor(layout);
this.addAction('decline', _("Decline")); this.addAction(_("Decline"), Lang.bind(this, function() {
this.addAction('accept', _("Accept"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
switch (action) {
case 'decline':
contact.remove_async(function(src, result) { contact.remove_async(function(src, result) {
src.remove_finish(result)}); src.remove_finish(result);
break; });
case 'accept': }));
this.addAction(_("Accept"), Lang.bind(this, function() {
// Authorize the contact and request to see his status as well // Authorize the contact and request to see his status as well
contact.authorize_publication_async(function(src, result) { contact.authorize_publication_async(function(src, result) {
src.authorize_publication_finish(result)}); src.authorize_publication_finish(result);
});
contact.request_subscription_async('', function(src, result) { contact.request_subscription_async('', function(src, result) {
src.request_subscription_finish(result)}); src.request_subscription_finish(result);
break; });
}
// rely on _subscriptionStatesChangedCb to destroy the
// notification
})); }));
this._changedId = contact.connect('subscription-states-changed', this._changedId = contact.connect('subscription-states-changed',
@ -1358,18 +1333,11 @@ const AccountNotification = new Lang.Class({
this._account = account; this._account = account;
this.addAction('view', _("View account")); this.addAction(_("View account"), Lang.bind(this, function() {
this.connect('action-invoked', Lang.bind(this, function(self, action) {
switch (action) {
case 'view':
let cmd = 'empathy-accounts --select-account=' + let cmd = 'empathy-accounts --select-account=' +
account.get_path_suffix(); account.get_path_suffix();
let app_info = Gio.app_info_create_from_commandline(cmd, null, 0); let app_info = Gio.app_info_create_from_commandline(cmd, null, 0);
app_info.launch([], global.create_app_launch_context()); app_info.launch([], global.create_app_launch_context());
break;
}
this.destroy();
})); }));
this._enabledId = account.connect('notify::enabled', this._enabledId = account.connect('notify::enabled',

View File

@ -835,7 +835,7 @@ const Notification = new Lang.Class({
} }
}, },
addButton: function(id, button) { addButton: function(button, callback) {
if (!this._buttonBox) { if (!this._buttonBox) {
let box = new St.BoxLayout({ style_class: 'notification-actions' }); let box = new St.BoxLayout({ style_class: 'notification-actions' });
this.setActionArea(box, { x_expand: false, this.setActionArea(box, { x_expand: false,
@ -848,27 +848,36 @@ const Notification = new Lang.Class({
} }
this._buttonBox.add(button); this._buttonBox.add(button);
button.connect('clicked', Lang.bind(this, this._onActionInvoked, id)); button.connect('clicked', Lang.bind(this, function() {
callback();
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.
this.emit('done-displaying');
this.destroy();
}
}));
this.updated(); this.updated();
return button; return button;
}, },
// addAction: // addAction:
// @id: the action ID
// @label: the label for the action's button // @label: the label for the action's button
// @callback: the callback for the action
// //
// Adds a button with the given @label to the notification. All // Adds a button with the given @label to the notification. All
// action buttons will appear in a single row at the bottom of // action buttons will appear in a single row at the bottom of
// the notification. // the notification.
// addAction: function(label, callback) {
// If the button is clicked, the notification will emit the
// %action-invoked signal with @id as a parameter
addAction: function(id, label) {
let button = new St.Button({ style_class: 'notification-button', let button = new St.Button({ style_class: 'notification-button',
label: label, label: label,
can_focus: true }); can_focus: true });
return this.addButton(id, button);
return this.addButton(button, callback);
}, },
setUrgency: function(urgency) { setUrgency: function(urgency) {
@ -1111,18 +1120,6 @@ const Notification = new Lang.Class({
this.actor.add_style_class_name('notification-unexpanded'); this.actor.add_style_class_name('notification-unexpanded');
}, },
_onActionInvoked: function(actor, mouseButtonClicked, id) {
this.emit('action-invoked', id);
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.
this.emit('done-displaying');
this.destroy();
}
},
_onClicked: function() { _onClicked: function() {
this.emit('clicked'); this.emit('clicked');
// We hide all types of notifications once the user clicks on them because the common // We hide all types of notifications once the user clicks on them because the common

View File

@ -389,10 +389,6 @@ const NotificationDaemon = new Lang.Class({
} }
this._emitNotificationClosed(ndata.id, notificationClosedReason); this._emitNotificationClosed(ndata.id, notificationClosedReason);
})); }));
notification.connect('action-invoked', Lang.bind(this,
function(n, actionId) {
this._emitActionInvoked(ndata.id, actionId);
}));
} }
// Mark music notifications so they can be shown in the screen shield // Mark music notifications so they can be shown in the screen shield
@ -432,12 +428,13 @@ const NotificationDaemon = new Lang.Class({
for (let i = 0; i < actions.length - 1; i += 2) { for (let i = 0; i < actions.length - 1; i += 2) {
let [actionId, label] = [actions[i], actions[i+1]]; let [actionId, label] = [actions[i], actions[i+1]];
if (actionId == 'default') { if (actionId == 'default') {
notification.connect('clicked', Lang.bind(this, notification.connect('clicked', Lang.bind(this, function() {
function() {
this._emitActionInvoked(ndata.id, "default"); this._emitActionInvoked(ndata.id, "default");
})); }));
} else { } else {
notification.addButton(actionId, this._makeButton(id, label, useActionIcons)); notification.addButton(this._makeButton(id, label, useActionIcons), Lang.bind(this, function() {
this._emitActionInvoked(ndata.id, actionId);
}));
} }
} }
} }
@ -659,7 +656,7 @@ const Source = new Lang.Class({
this.parent(title); this.parent(title);
}, },
open: function(notification) { open: function() {
this.openApp(); this.openApp();
this.destroyNonResidentNotifications(); this.destroyNonResidentNotifications();
}, },

View File

@ -78,10 +78,8 @@ const ShellInfo = new Lang.Class({
} }
this._undoCallback = undoCallback; this._undoCallback = undoCallback;
if (undoCallback) { if (undoCallback)
notification.addAction('system-undo', _("Undo")); notification.addAction(_("Undo"), Lang.bind(this, this._onUndoClicked));
notification.connect('action-invoked', Lang.bind(this, this._onUndoClicked));
}
this._source.notify(notification); this._source.notify(notification);
} }

View File

@ -207,26 +207,26 @@ const PinNotification = new Lang.Class({
let key = event.get_key_symbol(); let key = event.get_key_symbol();
if (key == Clutter.KEY_Return) { if (key == Clutter.KEY_Return) {
if (this._canActivateOkButton()) if (this._canActivateOkButton())
this.emit('action-invoked', 'ok'); this._ok();
return true; return true;
} else if (key == Clutter.KEY_Escape) { } else if (key == Clutter.KEY_Escape) {
this.emit('action-invoked', 'cancel'); this._cancel();
return true; return true;
} }
return false; return false;
})); }));
this.addActor(this._entry); this.addActor(this._entry);
let okButton = this.addAction('ok', _("OK")); let okButton = this.addAction(_("OK"), Lang.bind(this, this._ok));
this.addAction('cancel', _("Cancel")); this.addAction(_("Cancel"), Lang.bind(this, this._cancel));
okButton.reactive = this._canActivateOkButton(); okButton.reactive = this._canActivateOkButton();
this._entry.clutter_text.connect('text-changed', Lang.bind(this, function() { this._entry.clutter_text.connect('text-changed', Lang.bind(this, function() {
okButton.reactive = this._canActivateOkButton(); okButton.reactive = this._canActivateOkButton();
})); }));
},
this.connect('action-invoked', Lang.bind(this, function(self, action) { _ok: function() {
if (action == 'ok') {
if (this._numeric) { if (this._numeric) {
let num = parseInt(this._entry.text); let num = parseInt(this._entry.text);
if (isNaN(num)) { if (isNaN(num)) {
@ -235,16 +235,18 @@ const PinNotification = new Lang.Class({
num = -1; num = -1;
} }
this._applet.agent_reply_passkey(this._devicePath, num); this._applet.agent_reply_passkey(this._devicePath, num);
} else
this._applet.agent_reply_pincode(this._devicePath, this._entry.text);
} else { } else {
this._applet.agent_reply_pincode(this._devicePath, this._entry.text);
}
this.destroy();
},
_cancel: function() {
if (this._numeric) if (this._numeric)
this._applet.agent_reply_passkey(this._devicePath, -1); this._applet.agent_reply_passkey(this._devicePath, -1);
else else
this._applet.agent_reply_pincode(this._devicePath, null); this._applet.agent_reply_pincode(this._devicePath, null);
}
this.destroy(); this.destroy();
}));
}, },
_canActivateOkButton: function() { _canActivateOkButton: function() {