[polari/wip/bastianilso/error-handling: 17/19] Indicate server status in the roomList instead
- From: Bastian Ilsø Hougaard <bastianilso src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [polari/wip/bastianilso/error-handling: 17/19] Indicate server status in the roomList instead
- Date: Thu, 13 Aug 2015 17:19:04 +0000 (UTC)
commit ecd2634fffaa91fb2a15165d320e79f84df9665f
Author: Bastian Ilsø <bastianilso src gnome org>
Date: Sun Aug 2 17:05:24 2015 +0200
Indicate server status in the roomList instead
Instead of displaying notifications when connecting to
a server, use less attention grabbing status indicators in
the roomlist for displaying status of the servers
individually.
src/appNotifications.js | 34 ----------
src/application.js | 38 ++++++++++-
src/chatroomManager.js | 10 +++
src/mainWindow.js | 24 -------
src/roomList.js | 164 ++++++++++++++++++++++++++++++++++++++++++++--
5 files changed, 201 insertions(+), 69 deletions(-)
---
diff --git a/src/appNotifications.js b/src/appNotifications.js
index 694c422..24d6009 100644
--- a/src/appNotifications.js
+++ b/src/appNotifications.js
@@ -89,40 +89,6 @@ const GridOutput = new Lang.Class({
}
});
-const ConnectingNotification = new Lang.Class({
- Name: 'ConnectingNotification',
- Extends: AppNotification,
-
- _init: function(account) {
- this.parent();
-
- this._grid = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL,
- column_spacing: 12 });
-
- this._grid.add(new Gtk.Spinner({ active: true }));
-
- let text = _("Connecting to %s").format(account.display_name);
- let label = new Gtk.Label({ label: text });
- this._grid.add(label);
-
- this.widget.add(this._grid);
- this.widget.show_all();
-
- let id = account.connect('notify::connection-status',
- Lang.bind(this, this._onConnectionStatusChanged));
- this.widget.connect('destroy',
- function() {
- account.disconnect(id);
- });
- },
-
- _onConnectionStatusChanged: function(account) {
- if (account.connection_status == Tp.ConnectionStatus.CONNECTING)
- return;
- this.close();
- }
-});
-
const NotificationQueue = new Lang.Class({
Name: 'NotificationQueue',
diff --git a/src/application.js b/src/application.js
index b7ab206..318e949 100644
--- a/src/application.js
+++ b/src/application.js
@@ -13,7 +13,6 @@ const MainWindow = imports.mainWindow;
const PasteManager = imports.pasteManager;
const Utils = imports.utils;
-
const MAX_RETRIES = 3;
const ConnectionError = {
@@ -77,11 +76,19 @@ const Application = new Lang.Class({
activate: Lang.bind(this, this._onLeaveCurrentRoom),
create_hook: Lang.bind(this, this._leaveRoomCreateHook),
accels: ['<Primary>w'] },
+ { name: 'reconnect-account',
+ parameter_type: GLib.VariantType.new('o') },
{ name: 'user-list',
activate: Lang.bind(this, this._onToggleAction),
create_hook: Lang.bind(this, this._userListCreateHook),
state: GLib.Variant.new('b', false),
accels: ['F9', '<Primary>u'] },
+ { name: 'reconnect-without-encryption',
+ activate: Lang.bind(this, this._onReconnectWithoutEncryption),
+ parameter_type: GLib.VariantType.new('o') },
+ { name: 'edit-connection',
+ activate: Lang.bind(this, this._onEditConnection),
+ parameter_type: GLib.VariantType.new('o') },
{ name: 'connections',
activate: Lang.bind(this, this._onListConnections) },
{ name: 'preferences',
@@ -266,7 +273,6 @@ const Application = new Lang.Class({
time: time,
retry: 0,
originalNick: account.nickname };
-
this._pendingRequests[roomId] = requestData;
this._ensureChannel(requestData);
@@ -299,7 +305,6 @@ const Application = new Lang.Class({
_onEnsureChannel: function(req, res, requestData) {
let account = req.account;
-
try {
req.ensure_channel_finish(res);
} catch (e if e.matches(Tp.Error, Tp.Error.DISCONNECTED)) {
@@ -398,6 +403,33 @@ const Application = new Lang.Class({
}));
},
+ _onEditConnection: function(action, parameter) {
+ let accountPath = parameter.deep_unpack();
+ let factory = Tp.AccountManager.dup().get_factory();
+ let account = factory.ensure_account(accountPath, []);
+ let dialog = new Connections.ConnectionDetailsDialog(account);
+ dialog.widget.transient_for = this._window.window;
+ dialog.widget.connect('response', Lang.bind(this,
+ function(w, response) {
+ w.destroy();
+ }));
+ dialog.widget.show();
+ },
+
+ _onReconnectWithoutEncryption: function(action, parameter) {
+ let accountPath = parameter.deep_unpack();
+ let factory = Tp.AccountManager.dup().get_factory();
+ let account = factory.ensure_account(accountPath, []);
+
+ let sv = { port: GLib.Variant.new('u', 6667) };
+ sv['use-ssl'] = GLib.Variant.new('b', false);
+ let asv = GLib.Variant.new('a{sv}', sv);
+ account.update_parameters_vardict_async(asv, [],
+ Lang.bind(this, function(a, res) {
+ a.update_parameters_vardict_finish(res);
+ }));
+ },
+
_onShowPreferences: function() {
},
diff --git a/src/chatroomManager.js b/src/chatroomManager.js
index 6ec3b95..d43adba 100644
--- a/src/chatroomManager.js
+++ b/src/chatroomManager.js
@@ -65,6 +65,9 @@ const _ChatroomManager = new Lang.Class({
let leaveAction = this._app.lookup_action('leave-room');
leaveAction.connect('activate', Lang.bind(this, this._onLeaveActivated));
+ let reconnectAction = this._app.lookup_action('reconnect-account');
+ reconnectAction.connect('activate', Lang.bind(this, this._onReconnectAccountActivated));
+
this._client = new Client(am, this);
let filters = [];
@@ -150,6 +153,13 @@ const _ChatroomManager = new Lang.Class({
action.activate(parameter);
},
+ _onReconnectAccountActivated: function(action, parameter) {
+ let accountPath = parameter.deep_unpack();
+ let factory = Tp.AccountManager.dup().get_factory();
+ let account = factory.ensure_account(accountPath, []);
+ this._restoreSavedChannels(account);
+ },
+
_onJoinActivated: function(action, parameter) {
let [accountPath, channelName, ] = parameter.deep_unpack();
let factory = Tp.AccountManager.dup().get_factory();
diff --git a/src/mainWindow.js b/src/mainWindow.js
index f53e483..1891e59 100644
--- a/src/mainWindow.js
+++ b/src/mainWindow.js
@@ -54,12 +54,6 @@ const MainWindow = new Lang.Class({
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
);
- this._accountsMonitor = AccountsMonitor.getDefault();
- this._accountsMonitor.connect('account-status-changed',
- Lang.bind(this, this._onAccountChanged));
- this._accountsMonitor.connect('account-added',
- Lang.bind(this, this._onAccountChanged));
-
this._roomManager = ChatroomManager.getDefault();
this._roomManager.connect('active-changed',
Lang.bind(this, this._activeRoomChanged));
@@ -119,24 +113,6 @@ const MainWindow = new Lang.Class({
GLib.Variant.new('ai', this._currentSize));
},
- _onAccountChanged: function(am, account) {
- if (account.connection_status != Tp.ConnectionStatus.CONNECTING)
- return;
-
- if (account._connectingNotification)
- return;
-
- let app = Gio.Application.get_default();
- let notification = new AppNotifications.ConnectingNotification(account);
- app.notificationQueue.addNotification(notification);
-
- account._connectingNotification = notification;
- notification.widget.connect('destroy',
- function() {
- delete account._connectingNotification;
- });
- },
-
_updateDecorations: function() {
let layoutLeft = null;
let layoutRight = null;
diff --git a/src/roomList.js b/src/roomList.js
index f7ee09f..05b7716 100644
--- a/src/roomList.js
+++ b/src/roomList.js
@@ -8,6 +8,8 @@ const Tp = imports.gi.TelepathyGLib;
const ChatroomManager = imports.chatroomManager;
const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+const Connections = imports.connections;
const RoomRow = new Lang.Class({
Name: 'RoomRow',
@@ -118,6 +120,156 @@ const RoomRow = new Lang.Class({
}
});
+const RoomListHeader = new Lang.Class({
+ Name: 'RoomListHeader',
+
+ _init: function(account) {
+ this._account = account;
+
+ this._networkMonitor = Gio.NetworkMonitor.get_default();
+
+ this._app = Gio.Application.get_default();
+ this.widget = new Gtk.Box({ margin_bottom: 4, spacing: 2, hexpand: true,
+ orientation: Gtk.Orientation.HORIZONTAL,
+ visible: true });
+ this.widget.get_style_context().add_class('room-list-header');
+
+ let label = new Gtk.Label({ xalign: 0, margin: 4,
+ hexpand: true,
+ max_width_chars: 15,
+ ellipsize: Pango.EllipsizeMode.END });
+ account.bind_property('display-name', label, 'label',
+ GObject.BindingFlags.SYNC_CREATE);
+ this.widget.add(label);
+
+ this._iconStack = new Gtk.Stack({ vhomogeneous: true, valign: Gtk.Align.CENTER,
+ margin_end: 4 });
+ this._iconStack.transition_type = Gtk.StackTransitionType.CROSSFADE;
+
+ let errorIcon = new Gtk.Button({ image: new Gtk.Image({icon_name: 'dialog-error-symbolic'}),
+ halign: Gtk.Align.END });
+ errorIcon.get_style_context().remove_class('button');
+ errorIcon.connect('clicked', Lang.bind(this, function () {
+ this._popover.show_all();
+ }));
+ this._popover = new Gtk.Popover({ modal: true,
+ position: Gtk.PositionType.BOTTOM });
+ let popoverBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL,
+ margin: 12, spacing: 3 });
+ this._popoverLabel = new Gtk.Label({ wrap: true, max_width_chars: 30,
+ halign: Gtk.Align.START, xalign: 0 });
+ this._popoverTitle = new Gtk.Label({ wrap: true, max_width_chars: 30,
+ use_markup: true, xalign: 0,
+ halign: Gtk.Align.START });
+ this._popoverTitle.label = '<b>' + _("Connection Error") + '</b>';
+ this._popoverButton = new Gtk.Button({ valign: Gtk.Align.CENTER, hexpand: true,
+ margin_top: 15, halign: Gtk.Align.END });
+ this._popoverButton.connect('clicked', Lang.bind(this,
+ function() {
+ this._popover.hide();
+ }));
+ popoverBox.add(this._popoverTitle);
+ popoverBox.add(this._popoverLabel);
+ popoverBox.add(this._popoverButton);
+ this._popover.add(popoverBox);
+ this._popover.relative_to = errorIcon;
+
+ this._iconStack.add_named(errorIcon, 'error');
+
+ let connecting = new Gtk.Spinner({active: true, halign: Gtk.Align.START });
+ this._iconStack.add_named(connecting, 'connecting');
+
+ this._iconStack.add_named(new Gtk.Box({visible: false}), 'none');
+
+ let displayStatus = function(binding) {
+ let status = binding.source.connection_status;
+ let reason = binding.source.connection_status_reason;
+ binding.target.visible_child_name = this._evaluateStatus(status, reason);
+ }
+
+ this._account.connect('notify::connection-status', Lang.bind(this,
this._updateConnectionStatusIcon));
+ this.widget.add(this._iconStack);
+ this.widget.show_all();
+
+ this._updateConnectionStatusIcon();
+
+ },
+
+ _updateConnectionStatusIcon: function() {
+ let status = this._account.connection_status;
+ let reason = this._account.connection_status_reason;
+ let child = 'none';
+
+ if (status == Tp.ConnectionStatus.CONNECTING) {
+ if (this._networkMonitor.network_available)
+ child = 'connecting';
+ } else if (status == Tp.ConnectionStatus.DISCONNECTED &&
+ reason != Tp.ConnectionStatusReason.REQUESTED) {
+
+ child = 'error';
+ switch (this._account.connection_error) {
+
+ case Tp.error_get_dbus_name(Tp.Error.CONNECTION_REFUSED):
+ case Tp.error_get_dbus_name(Tp.Error.NETWORK_ERROR): {
+ this._popoverLabel.label = _("Please check your connection details.")
+
+ this._popoverButton.label = _("Edit Connection");
+ this._popoverButton.action_name = 'app.edit-connection';
+ this._popoverButton.action_target = new GLib.Variant('o',
this._account.get_object_path());
+ break;
+ }
+
+ case Tp.error_get_dbus_name(Tp.Error.CERT_REVOKED):
+ case Tp.error_get_dbus_name(Tp.Error.CERT_INSECURE):
+ case Tp.error_get_dbus_name(Tp.Error.CERT_LIMIT_EXCEEDED):
+ case Tp.error_get_dbus_name(Tp.Error.CERT_INVALID):
+ case Tp.error_get_dbus_name(Tp.Error.ENCRYPTION_ERROR):
+ case Tp.error_get_dbus_name(Tp.Error.CERT_NOT_PROVIDED):
+ case Tp.error_get_dbus_name(Tp.Error.ENCRYPTION_NOT_AVAILABLE):
+ case Tp.error_get_dbus_name(Tp.Error.CERT_UNTRUSTED):
+ case Tp.error_get_dbus_name(Tp.Error.CERT_EXPIRED):
+ case Tp.error_get_dbus_name(Tp.Error.CERT_NOT_ACTIVATED):
+ case Tp.error_get_dbus_name(Tp.Error.CERT_HOSTNAME_MISMATCH):
+ case Tp.error_get_dbus_name(Tp.Error.CERT_FINGERPRINT_MISMATCH):
+ case Tp.error_get_dbus_name(Tp.Error.CERT_SELF_SIGNED): {
+ this._popoverLabel.label = _("The connection is not safe.");
+ this._popoverButton.label = _("Continue Anyway");
+ this._popoverButton.action_name = 'app.reconnect-without-encryption';
+ this._popoverButton.action_target = GLib.Variant.new('o',
this._account.get_object_path());
+ break;
+ }
+
+ case Tp.error_get_dbus_name(Tp.Error.AUTHENTICATION_FAILED): {
+ this._popoverLabel.label = _("Authentication failed.");
+ this._popoverButton.label = _("Try again");
+ this._popoverButton.action_name = 'app.reconnect-account';
+ this._popoverButton.action_target = GLib.Variant.new('o',
this._account.get_object_path());
+ break;
+ }
+
+ case Tp.error_get_dbus_name(Tp.Error.CONNECTION_FAILED):
+ case Tp.error_get_dbus_name(Tp.Error.CONNECTION_LOST):
+ case Tp.error_get_dbus_name(Tp.Error.CONNECTION_REPLACED):
+ case Tp.error_get_dbus_name(Tp.Error.SERVICE_BUSY): {
+ this._popoverLabel.label = _("The server is busy.");
+ this._popoverButton.label = _("Try again");
+ this._popoverButton.action_name = 'app.reconnect-account';
+ this._popoverButton.action_target = GLib.Variant.new('o',
this._account.get_object_path());
+ break;
+ }
+
+ default:
+ this._popoverLabel.label = _("Failed to connect for an unknown reason.");
+ this._popoverButton.label = _("Try again");
+ this._popoverButton.action_name = 'app.reconnect-account';
+ this._popoverButton.action_target = GLib.Variant.new('o',
this._account.get_object_path());
+ break;
+ }
+ }
+ this._iconStack.visible_child_name = child;
+ },
+});
+
const RoomList = new Lang.Class({
Name: 'RoomList',
@@ -132,6 +284,7 @@ const RoomList = new Lang.Class({
this._selectedRows = 0;
this._selectionMode = false;
+
this.widget.connect('row-selected',
Lang.bind(this, this._onRowSelected));
@@ -148,6 +301,7 @@ const RoomList = new Lang.Class({
this._leaveAction.connect('activate',
Lang.bind(this, this._onLeaveActivated));
+
let action;
action = app.lookup_action('next-room');
action.connect('activate', Lang.bind(this,
@@ -281,14 +435,8 @@ const RoomList = new Lang.Class({
if (row.get_header())
return;
- let label = new Gtk.Label({ margin_bottom: 4, xalign: 0,
- max_width_chars: 15,
- ellipsize: Pango.EllipsizeMode.END });
- label.get_style_context().add_class('room-list-header');
-
- account.bind_property('display-name', label, 'label',
- GObject.BindingFlags.SYNC_CREATE);
- row.set_header(label);
+ let roomListHeader = new RoomListHeader(account);
+ row.set_header(roomListHeader.widget);
},
_sort: function(row1, row2) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]