[polari] roomList: Use header popover for connection management



commit 6ef2e57371aab2393918b12a9dfb11744e621685
Author: Isabella Ribeiro <belinhacbr gmail com>
Date:   Sun Jan 24 16:26:19 2016 -0200

    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

 data/resources/room-list-header.ui |   49 +++++++++---
 src/application.js                 |   13 +++
 src/roomList.js                    |  153 +++++++++++++++++++-----------------
 3 files changed, 131 insertions(+), 84 deletions(-)
---
diff --git a/data/resources/room-list-header.ui b/data/resources/room-list-header.ui
index 3a80583..8857ffa 100644
--- a/data/resources/room-list-header.ui
+++ b/data/resources/room-list-header.ui
@@ -1,7 +1,7 @@
 <?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>
diff --git a/src/application.js b/src/application.js
index b433434..eedfeda 100644
--- a/src/application.js
+++ b/src/application.js
@@ -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();
diff --git a/src/roomList.js b/src/roomList.js
index 16670be..18beef4 100644
--- a/src/roomList.js
+++ b/src/roomList.js
@@ -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);
+        }
     },
 });
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]