Commit 6ef2e573 authored by Isabella Ribeiro's avatar Isabella Ribeiro Committed by Florian Müllner

roomList: Use header popover for connection management

We want to move away from a separate connection editor in favor of more direct
connection management. Creating new connections directly from the join dialog
has been possible for a while now, and the room list's headers provide a good
place for exposing connection editing/removal, so rework the existing error
popover to be usable for general connection management in non-error cases
as well.

https://bugzilla.gnome.org/show_bug.cgi?id=761057
parent 687614e5
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="Gjs_RoomListHeader" parent="GtkMenuButton">
<property name="popover">errorPopover</property>
<property name="popover">connectionPopover</property>
<property name="margin-bottom">4</property>
<property name="margin-start">7</property>
<property name="margin-end">7</property>
......@@ -10,6 +10,7 @@
<style>
<class name="room-list-header"/>
<class name="activatable" />
<class name="dim-label" />
</style>
<child>
<object class="GtkBox">
......@@ -61,39 +62,63 @@
</object>
</child>
</template>
<object class="GtkPopover" id="errorPopover">
<object class="GtkPopoverMenu" id="connectionPopover">
<property name="position">bottom</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="margin">12</property>
<property name="spacing">3</property>
<property name="visible">True</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Connection Error</property>
<object class="GtkLabel" id="popoverTitle">
<property name="wrap">True</property>
<property name="max-width-chars">30</property>
<property name="width-chars">15</property>
<property name="xalign">0</property>
<property name="visible">True</property>
<attributes>
<attribute name="weight" value="PANGO_WEIGHT_BOLD"/>
</attributes>
<property name="margin-start">6</property>
<property name="margin-end">6</property>
</object>
</child>
<child>
<object class="GtkLabel" id="popoverLabel">
<object class="GtkLabel" id="popoverStatus">
<property name="wrap">True</property>
<property name="max-width-chars">30</property>
<property name="xalign">0</property>
<property name="visible">True</property>
<property name="margin-start">6</property>
<property name="margin-end">6</property>
</object>
</child>
<child>
<object class="GtkButton" id="popoverButton">
<property name="margin-top">15</property>
<property name="halign">end</property>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
</object>
</child>
<child>
<object class="GtkModelButton" id="popoverReconnect">
<property name="xalign">0</property>
<property name="visible">True</property>
<property name="action-name">app.reconnect-account</property>
<property name="text" translatable="yes">Reconnect</property>
</object>
</child>
<child>
<object class="GtkModelButton" id="popoverRemove">
<property name="xalign">0</property>
<property name="visible">True</property>
<property name="action-name">app.remove-connection</property>
<property name="text" translatable="yes">Remove</property>
</object>
</child>
<child>
<object class="GtkModelButton" id="popoverProperties">
<property name="xalign">0</property>
<property name="visible">True</property>
<property name="action-name">app.edit-connection</property>
<property name="text" translatable="yes">Properties</property>
</object>
</child>
</object>
......
......@@ -84,6 +84,9 @@ const Application = new Lang.Class({
create_hook: Lang.bind(this, this._userListCreateHook),
state: GLib.Variant.new('b', false),
accels: ['F9', '<Primary>u'] },
{ name: 'remove-connection',
activate: Lang.bind(this, this._onRemoveConnection),
parameter_type: GLib.VariantType.new('o') },
{ name: 'edit-connection',
activate: Lang.bind(this, this._onEditConnection),
parameter_type: GLib.VariantType.new('o') },
......@@ -431,6 +434,16 @@ const Application = new Lang.Class({
}));
},
_onRemoveConnection: function(action, parameter){
let accountPath = parameter.deep_unpack();
let factory = Tp.AccountManager.dup().get_factory();
let account = factory.ensure_account(accountPath, []);
account.remove_async(Lang.bind(this,
function(a, res) {
a.remove_finish(res); // TODO: Check for errors
}));
},
_onEditConnection: function(action, parameter) {
let accountPath = parameter.deep_unpack();
let factory = Tp.AccountManager.dup().get_factory();
......
......@@ -163,9 +163,11 @@ const RoomListHeader = new Lang.Class({
Template: 'resource:///org/gnome/Polari/room-list-header.ui',
InternalChildren: ['label',
'iconStack',
'errorPopover',
'popoverLabel',
'popoverButton',
'popoverStatus',
'popoverTitle',
'popoverReconnect',
'popoverRemove',
'popoverProperties',
'spinner'],
_init: function(params) {
......@@ -176,12 +178,10 @@ const RoomListHeader = new Lang.Class({
this._app = Gio.Application.get_default();
this.parent(params);
this._errorPopover.relative_to = this._iconStack;
this._popoverButton.connect('clicked', Lang.bind(this,
function() {
this._errorPopover.hide();
}));
let target = new GLib.Variant('o', this._account.get_object_path());
this._popoverReconnect.action_target = target;
this._popoverRemove.action_target = target;
this._popoverProperties.action_target = target;
let displayNameChangedId =
this._account.connect('notify::display-name',
......@@ -190,8 +190,8 @@ const RoomListHeader = new Lang.Class({
let connectionStatusChangedId =
this._account.connect('notify::connection-status',
Lang.bind(this, this._updateConnectionStatusIcon));
this._updateConnectionStatusIcon();
Lang.bind(this, this._onConnectionStatusChanged));
this._onConnectionStatusChanged();
this.connect('destroy', Lang.bind(this, function() {
this._account.disconnect(displayNameChangedId);
......@@ -214,80 +214,89 @@ const RoomListHeader = new Lang.Class({
this.get_accessible().set_name(accessibleName);
},
_updateConnectionStatusIcon: function() {
_onConnectionStatusChanged: function() {
let status = this._account.connection_status;
let reason = this._account.connection_status_reason;
let isError = (status == Tp.ConnectionStatus.DISCONNECTED &&
reason != Tp.ConnectionStatusReason.REQUESTED);
let child = 'none';
if (status == Tp.ConnectionStatus.CONNECTING) {
if (this._networkMonitor.network_available)
child = 'connecting';
} else if (isError) {
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 = _("Could not make connection in a safe way.");
this._popoverButton.label = _("Edit Connection");
this._popoverButton.action_name = 'app.edit-connection';
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.sensitive = isError;
this._iconStack.visible_child_name = child;
this._spinner.active = (child == 'connecting');
this._popoverTitle.use_markup = isError;
this._popoverStatus.use_markup = !isError;
if (!isError) {
let styleContext = this._popoverStatus.get_style_context();
styleContext.add_class('dim-label');
let params = this._account.dup_parameters_vardict().deep_unpack();
let server = params['server'].deep_unpack();
let accountName = this._account.display_name;
/* Translators: This is an account name followed by a
server address, e.g. "GNOME (irc.gnome.org)" */
let fullTitle = _("%s (%s)").format(accountName, server);
this._popoverTitle.label = (accountName == server) ? accountName : fullTitle;
this._popoverStatus.label = '<sup>' + this._getStatusLabel() + '</sup>';
} else {
let styleContext = this._popoverStatus.get_style_context();
styleContext.remove_class('dim-label');
this._popoverTitle.label = '<b>' + _("Connection Problem") + '</b>';
this._popoverStatus.label = this._getErrorLabel();
}
},
_getStatusLabel: function() {
switch (this._account.connection_status) {
case Tp.ConnectionStatus.CONNECTED:
return _("Connected");
case Tp.ConnectionStatus.CONNECTING:
return _("Connecting...");
case Tp.ConnectionStatus.DISCONNECTED:
return _("Offline");
default:
return _("Unknown");
}
},
_getErrorLabel: function() {
switch (this._account.connection_error) {
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):
return _("Could not connect to %s in a safe way.").format(this._account.display_name);
case Tp.error_get_dbus_name(Tp.Error.AUTHENTICATION_FAILED):
return _("Could not connect to %s. Authentication failed.").format(this._account.display_name);
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):
return _("Could not connect to %s. The server is busy.").format(this._account.display_name);
default:
return _("Could not connect to %s.").format(this._account.display_name);
}
},
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment