[polari] userList: Use template for details



commit 8eecccb5cd1cbe9c01f09d62a1f576a6a13a545b
Author: Florian Müllner <fmuellner gnome org>
Date:   Sun Feb 22 04:18:59 2015 +0100

    userList: Use template for details
    
    This is another good candidate for template use, so port this as well.

 data/org.gnome.Polari.data.gresource.xml |    1 +
 data/resources/user-list-details.ui      |   89 +++++++++++
 po/POTFILES.in                           |    1 +
 src/userList.js                          |  251 +++++++++++++++++-------------
 4 files changed, 230 insertions(+), 112 deletions(-)
---
diff --git a/data/org.gnome.Polari.data.gresource.xml b/data/org.gnome.Polari.data.gresource.xml
index 2d00f0d..91c4de2 100644
--- a/data/org.gnome.Polari.data.gresource.xml
+++ b/data/org.gnome.Polari.data.gresource.xml
@@ -7,6 +7,7 @@
     <file alias="join-room-dialog.ui" preprocess="xml-stripblanks">resources/join-room-dialog.ui</file>
     <file alias="main-window.ui" preprocess="xml-stripblanks">resources/main-window.ui</file>
     <file alias="message-user-dialog.ui" preprocess="xml-stripblanks">resources/message-user-dialog.ui</file>
+    <file alias="user-list-details.ui" preprocess="xml-stripblanks">resources/user-list-details.ui</file>
     <file alias="application.css">resources/application.css</file>
   </gresource>
 </gresources>
diff --git a/data/resources/user-list-details.ui b/data/resources/user-list-details.ui
new file mode 100644
index 0000000..7214d7d
--- /dev/null
+++ b/data/resources/user-list-details.ui
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="Gjs_UserListDetails" parent="GtkFrame">
+    <property name="visible">True</property>
+    <property name="hexpand">True</property>
+    <child>
+      <object class="GtkBox" id="box">
+        <property name="orientation">vertical</property>
+        <property name="spacing">6</property>
+        <property name="margin">6</property>
+        <property name="visible">True</property>
+        <child>
+          <object class="GtkBox" id="spinnerBox">
+            <property name="spacing">6</property>
+            <property name="margin">12</property>
+            <property name="hexpand">True</property>
+            <property name="halign">center</property>
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkSpinner" id="spinner">
+                <property name="visible">True</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label1">
+                <property name="label" translatable="yes">Loading details</property>
+                <property name="visible">True</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkGrid" id="detailsGrid">
+            <property name="row_spacing">6</property>
+            <property name="column_spacing">6</property>
+            <property name="hexpand">True</property>
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkLabel" id="fullnameLabel">
+                <property name="ellipsize">end</property>
+                <property name="halign">start</property>
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="width">2</property>
+                <property name="top-attach">0</property>
+                <property name="left-attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="lastHeader">
+                <property name="label" translatable="yes">Last Activity:</property>
+                <property name="valign">start</property>
+                <property name="use_markup">True</property>
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="top-attach">1</property>
+                <property name="left-attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="lastLabel">
+                <property name="valign">end</property>
+                <property name="use_markup">True</property>
+                <property name="wrap">True</property>
+                <property name="hexpand">True</property>
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="top-attach">1</property>
+                <property name="left-attach">1</property>
+              </packing>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkButton" id="messageButton">
+            <property name="label" translatable="yes">Message</property>
+            <property name="margin_top">12</property>
+            <property name="halign">end</property>
+            <property name="hexpand">True</property>
+            <property name="visible">True</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 29ff637..23c6b95 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -7,6 +7,7 @@ data/org.gnome.Polari.gschema.xml
 [type: gettext/glade]data/resources/main-window.ui
 [type: gettext/glade]data/resources/menus.ui
 [type: gettext/glade]data/resources/message-user-dialog.ui
+[type: gettext/glade]data/resources/user-list-details.ui
 src/application.js
 src/appNotifications.js
 src/chatView.js
diff --git a/src/userList.js b/src/userList.js
index f46593b..d81c3ad 100644
--- a/src/userList.js
+++ b/src/userList.js
@@ -1,6 +1,7 @@
 const Gdk = imports.gi.Gdk;
 const Gio = imports.gi.Gio;
 const GLib = imports.gi.GLib;
+const GObject = imports.gi.GObject;
 const Gtk = imports.gi.Gtk;
 const Pango = imports.gi.Pango;
 const Tp = imports.gi.TelepathyGLib;
@@ -9,6 +10,8 @@ const ChatroomManager = imports.chatroomManager;
 const Lang = imports.lang;
 const Mainloop = imports.mainloop;
 
+const READWRITE = GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE;
+
 const MAX_USERS_SHOWN = 8;
 
 const UserListPopover = new Lang.Class({
@@ -106,94 +109,74 @@ const UserListPopover = new Lang.Class({
     }
 });
 
-const UserListRow = new Lang.Class({
-    Name: 'UserListRow',
-
-    _init: function(user) {
-        this._createWidget(user);
-
-        this.widget.user = user;
-
-        this.widget.connect('unmap', Lang.bind(this, function() {
-            this._revealer.reveal_child = false;
-        }));
-        this.widget.connect('state-flags-changed',
-                            Lang.bind(this, this._updateArrowVisibility));
-
-        this._revealer.connect('notify::reveal-child',
-                               Lang.bind(this, this._onExpandedChanged));
+const UserListDetails = new Lang.Class({
+    Name: 'UserListDetails',
+    Extends: Gtk.Frame,
+    Template: 'resource:///org/gnome/Polari/user-list-details.ui',
+    InternalChildren: ['spinnerBox',
+                       'spinner',
+                       'detailsGrid',
+                       'fullnameLabel',
+                       'lastHeader',
+                       'lastLabel',
+                       'messageButton'],
+    Properties: { 'expanded': GObject.ParamSpec.boolean('expanded',
+                                                        'expanded',
+                                                        'expanded',
+                                                        READWRITE,
+                                                        false)},
+
+    _init: function(params) {
+        this._user = params.user;
+        delete params.user;
+
+        this._expanded = false;
+
+        this.parent(params);
+
+        this._messageButton.connect('clicked',
+                                    Lang.bind(this, this._onButtonClicked));
+        this._user.connection.connect('notify::self-contact',
+                                      Lang.bind(this, this._updateButtonVisibility));
+        this._updateButtonVisibility();
+        this._detailsGrid.hide();
     },
 
-    get expand() {
-        return this._revealer.reveal_child;
+    get expanded() {
+        return this._expanded;
     },
 
-    set expand(expand) {
-        this._ensureDetails();
-        this._revealer.reveal_child = expand;
-    },
+    set expanded(v) {
+        if (v == this._expanded)
+            return;
 
-    _createWidget: function(user) {
-        this.widget = new Gtk.ListBoxRow();
+        this._expanded = v;
 
-        let vbox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
-        this.widget.add(vbox);
+        if (this._expanded)
+            this._expand();
+        else
+            this._unexpand();
 
-        let hbox = new Gtk.Box({ margin: 4, spacing: 4 });
-        this._arrow = new Gtk.Arrow({ arrow_type: Gtk.ArrowType.RIGHT,
-                                      no_show_all: true });
-        hbox.add(new Gtk.Image({ icon_name: 'avatar-default-symbolic' }));
-        hbox.add(new Gtk.Label({ label: user.alias,
-                                 halign: Gtk.Align.START,
-                                 hexpand: true,
-                                 ellipsize: Pango.EllipsizeMode.END }));
-        hbox.add(this._arrow);
-        vbox.add(hbox);
+        this.notify('expanded');
+    },
 
-        this._revealer = new Gtk.Revealer({ reveal_child: false });
-        vbox.add(this._revealer);
+    _expand: function() {
+        let prevDetails = this._fullnameLabel.label != '';
+        this._detailsGrid.visible = prevDetails;
+        this._spinnerBox.visible = !prevDetails;
+        this._spinner.start();
 
-        this.widget.show_all();
+        this._cancellable = new Gio.Cancellable();
+        this._user.request_contact_info_async(this._cancellable,
+                                              Lang.bind(this, this._onContactInfoReady));
     },
 
-    _ensureDetails: function() {
-        if (this._revealer.get_child())
-            return;
-
-        let frame = new Gtk.Frame({ hexpand: true });
-
-        let box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL,
-                                spacing: 6, margin: 6 });
-        frame.add(box);
-
-        this._spinnerBox = new Gtk.Box({ spacing: 6, margin: 12,
-                                         hexpand: true,
-                                         halign: Gtk.Align.CENTER });
-        this._spinner = new Gtk.Spinner();
-        this._spinnerBox.add(this._spinner);
-        this._spinnerBox.add(new Gtk.Label({ label: _("Loading details") }));
-        box.add(this._spinnerBox);
-
-        this._detailsGrid = new Gtk.Grid({ row_spacing: 6, column_spacing: 6,
-                                           hexpand: true });
-        box.add(this._detailsGrid);
-
-        let user = this.widget.user;
-        if (user != user.connection.self_contact) {
-            let button = new Gtk.Button({ label: _("Message"),
-                                          margin_top: 12,
-                                          hexpand: true,
-                                          halign: Gtk.Align.END });
-            button.connect('clicked', Lang.bind(this, this._onButtonClicked));
-            user.connection.connect('notify::self-contact', function() {
-                if (user == user.connection.self_contact)
-                    button.destroy();
-            });
-            box.add(button);
-        }
+    _unexpand: function() {
+        this._spinner.stop();
 
-        this._revealer.add(frame);
-        frame.show_all();
+        if (this._cancellable)
+            this._cancellable.cancel();
+        this._cancellable = null;
     },
 
     _formatLast: function(seconds) {
@@ -228,7 +211,7 @@ const UserListRow = new Lang.Class({
 
     _onContactInfoReady: function(c, res) {
         let fn, last;
-        let info = this.widget.user.get_contact_info();
+        let info = this._user.get_contact_info();
         for (let i = 0; i < info.length; i++) {
             if (info[i].field_name == 'fn')
                 fn = info[i].field_value[0];
@@ -237,47 +220,105 @@ const UserListRow = new Lang.Class({
         }
 
         if (!fn)
-            fn = this.widget.user.alias;
-
-        this._detailsGrid.foreach(function(w) { w.destroy(); });
+            fn = this._user.alias;
 
-        let row = 0;
-        let w = new Gtk.Label({ label: fn, ellipsize: Pango.EllipsizeMode.END,
-                                halign: Gtk.Align.START });
-        this._detailsGrid.attach(w, 0, row++, 2, 1);
+        this._fullnameLabel.label = fn;
 
         if (last) {
+            this._lastHeader.label = '<small>' + _("Last Activity:") + '</small>';
+            this._lastHeader.show();
 
-            w = new Gtk.Label({ label: '<small>' + _("Last Activity:") + '</small>',
-                                use_markup: true,
-                                valign: Gtk.Align.START });
-            this._detailsGrid.attach(w, 0, row, 1, 1);
-
-            w = new Gtk.Label({ label: '<small>' + this._formatLast(last) + '</small>',
-                                use_markup: true,
-                                wrap: true,
-                                hexpand: true });
-            this._detailsGrid.attach(w, 1, row++, 1, 1);
+            this._lastLabel.label = '<small>' + this._formatLast(last) + '</small>';
+            this._lastLabel.show();
+        } else {
+            this._lastHeader.hide();
+            this._lastLabel.hide();
         }
 
-        this._detailsGrid.show_all();
-
         this._spinner.stop();
         this._spinnerBox.hide();
+        this._detailsGrid.show();
     },
 
     _onButtonClicked: function() {
-        let account = this.widget.user.connection.get_account();
+        let account = this._user.connection.get_account();
 
         let app = Gio.Application.get_default();
         let action = app.lookup_action('message-user');
         let time = Gtk.get_current_event().get_time();
         action.activate(GLib.Variant.new('(ssu)',
                                          [ account.get_object_path(),
-                                           this.widget.user.alias,
+                                           this._user.alias,
                                            time ]));
     },
 
+    _updateButtonVisibility: function() {
+        let visible = this._user != this._user.connection.self_contact;
+        this._messageButton.visible = visible;
+    }
+});
+
+const UserListRow = new Lang.Class({
+    Name: 'UserListRow',
+
+    _init: function(user) {
+        this._createWidget(user);
+
+        this.widget.user = user;
+
+        this.widget.connect('unmap', Lang.bind(this, function() {
+            this._revealer.reveal_child = false;
+        }));
+        this.widget.connect('state-flags-changed',
+                            Lang.bind(this, this._updateArrowVisibility));
+
+        this._revealer.connect('notify::reveal-child',
+                               Lang.bind(this, this._onExpandedChanged));
+    },
+
+    get expand() {
+        return this._revealer.reveal_child;
+    },
+
+    set expand(expand) {
+        if (expand)
+            this._ensureDetails();
+        this._revealer.reveal_child = expand;
+    },
+
+    _createWidget: function(user) {
+        this.widget = new Gtk.ListBoxRow();
+
+        let vbox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
+        this.widget.add(vbox);
+
+        let hbox = new Gtk.Box({ margin: 4, spacing: 4 });
+        this._arrow = new Gtk.Arrow({ arrow_type: Gtk.ArrowType.RIGHT,
+                                      no_show_all: true });
+        hbox.add(new Gtk.Image({ icon_name: 'avatar-default-symbolic' }));
+        hbox.add(new Gtk.Label({ label: user.alias,
+                                 halign: Gtk.Align.START,
+                                 hexpand: true,
+                                 ellipsize: Pango.EllipsizeMode.END }));
+        hbox.add(this._arrow);
+        vbox.add(hbox);
+
+        this._revealer = new Gtk.Revealer({ reveal_child: false });
+        vbox.add(this._revealer);
+
+        this.widget.show_all();
+    },
+
+    _ensureDetails: function() {
+        if (this._revealer.get_child())
+            return;
+
+        let details = new UserListDetails({ user: this.widget.user })
+        this._revealer.bind_property('reveal-child', details, 'expanded', 0);
+
+        this._revealer.add(details);
+    },
+
     _updateArrowVisibility: function() {
         let flags = this.widget.get_state_flags();
         this._arrow.visible = this.expand ||
@@ -289,24 +330,10 @@ const UserListRow = new Lang.Class({
         if (this._revealer.reveal_child) {
             this.widget.get_style_context().add_class('expanded');
             this._arrow.arrow_type = Gtk.ArrowType.DOWN;
-
-            let prevDetails = this._detailsGrid.get_children().length > 0;
-            this._spinnerBox.visible = !prevDetails;
-            this._spinner.start();
-
-            this._cancellable = new Gio.Cancellable();
-            this.widget.user.request_contact_info_async(this._cancellable,
-                                                        Lang.bind(this, this._onContactInfoReady));
         } else {
             this.widget.get_style_context().remove_class('expanded');
             this._arrow.arrow_type = Gtk.ArrowType.RIGHT;
             this._updateArrowVisibility();
-
-            this._spinner.stop();
-
-            if (this._cancellable)
-                this._cancellable.cancel();
-            this._cancellable = null;
         }
     }
 });


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