[gnome-contacts] Allow sorting by first name or surname.



commit b3ad2643092ba8679b18cf1e623541f4a574e56a
Author: Niels De Graef <nielsdegraef gmail com>
Date:   Mon Feb 5 21:54:32 2018 +0100

    Allow sorting by first name or surname.
    
    Fixes #54.

 data/ui/contacts-window.ui         | 91 +++++++++++++++++++++++++++++++++++++-
 src/contacts-app.vala              |  2 +-
 src/contacts-contact-list.vala     | 22 +++++++--
 src/contacts-list-pane.vala        |  4 +-
 src/contacts-settings.vala         | 14 +++---
 src/contacts-window.vala           | 17 ++++++-
 src/org.gnome.Contacts.gschema.xml |  8 ++++
 7 files changed, 143 insertions(+), 15 deletions(-)
---
diff --git a/data/ui/contacts-window.ui b/data/ui/contacts-window.ui
index cef3289..e88721c 100644
--- a/data/ui/contacts-window.ui
+++ b/data/ui/contacts-window.ui
@@ -1,7 +1,76 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.15.2 on Thu Aug 15 15:33:02 2013 -->
 <interface>
-  <!-- interface-requires gtk+ 3.10 -->
+  <!-- interface-requires gtk+ 3.22 -->
+  <object class="GtkPopover" id="hamburger_menu_popover">
+    <child>
+      <object class="GtkGrid">
+        <property name="visible">True</property>
+        <property name="row_spacing">6</property>
+        <property name="margin">18</property>
+        <property name="width_request">200</property>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="halign">start</property>
+            <property name="label" translatable="yes">List contacts by:</property>
+            <style>
+              <class name="dim-label"/>
+            </style>
+          </object>
+          <packing>
+            <property name="top_attach">0</property>
+            <property name="width">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkRadioButton" id="sort_on_firstname_button">
+            <property name="visible">True</property>
+            <property name="group">sort_on_firstname_button</property>
+          </object>
+          <packing>
+            <property name="top_attach">1</property>
+            <property name="left_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="halign">start</property>
+            <property name="hexpand">True</property>
+            <property name="label" translatable="yes">First name</property>
+            <property name="mnemonic_widget">sort_on_firstname_button</property>
+          </object>
+          <packing>
+            <property name="top_attach">1</property>
+            <property name="left_attach">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkRadioButton" id="sort_on_surname_button">
+            <property name="visible">True</property>
+            <property name="group">sort_on_firstname_button</property>
+          </object>
+          <packing>
+            <property name="top_attach">2</property>
+            <property name="left_attach">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="halign">start</property>
+            <property name="hexpand">True</property>
+            <property name="label" translatable="yes">Surname</property>
+            <property name="mnemonic_widget">sort_on_surname_button</property>
+          </object>
+          <packing>
+            <property name="top_attach">2</property>
+            <property name="left_attach">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
   <template class="ContactsWindow" parent="GtkApplicationWindow">
     <property name="can_focus">False</property>
     <property name="default_width">800</property>
@@ -50,6 +119,24 @@
                 <property name="pack_type">start</property>
               </packing>
             </child>
+            <child>
+              <object class="GtkMenuButton" id="hamburger_menu_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="focus_on_click">False</property>
+                <property name="popover">hamburger_menu_popover</property>
+                <child>
+                  <object class="GtkImage">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="icon_name">open-menu-symbolic</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="pack_type">end</property>
+              </packing>
+            </child>
             <child>
               <object class="GtkButton" id="select_cancel_button">
                 <property name="visible">False</property>
diff --git a/src/contacts-app.vala b/src/contacts-app.vala
index 3b0224b..b2a0e58 100644
--- a/src/contacts-app.vala
+++ b/src/contacts-app.vala
@@ -226,7 +226,7 @@ public class Contacts.App : Gtk.Application {
   }
 
   private void create_window () {
-    this.window = new Contacts.Window (this, this.contacts_store);
+    this.window = new Contacts.Window (this.settings, this, this.contacts_store);
   }
 
   private void schedule_window_creation () {
diff --git a/src/contacts-contact-list.vala b/src/contacts-contact-list.vala
index fd51d06..2696002 100644
--- a/src/contacts-contact-list.vala
+++ b/src/contacts-contact-list.vala
@@ -102,9 +102,11 @@ public class Contacts.ContactList : ListBox {
 
   private Store store;
 
+  private Settings settings;
+
   public UiState state { get; set; }
 
-  public ContactList (Store store, Query query) {
+  public ContactList (Settings settings, Store store, Query query) {
     this.selection_mode = Gtk.SelectionMode.BROWSE;
     this.store = store;
     this.filter_query = query;
@@ -113,6 +115,9 @@ public class Contacts.ContactList : ListBox {
 
     this.notify["state"].connect (on_ui_state_changed);
 
+    this.settings = settings;
+    this.settings.changed["sort-on-surname"].connect(invalidate_sort);
+
     this.store.added.connect (contact_added_cb);
     this.store.removed.connect (contact_removed_cb);
     foreach (var c in this.store.get_contacts ())
@@ -146,8 +151,19 @@ public class Contacts.ContactList : ListBox {
     if (a.is_favourite != b.is_favourite)
       return a.is_favourite? -1 : 1;
 
-    // Both are (non-)favourites: sort by name
-    return a.display_name.collate (b.display_name);
+    // Both are (non-)favourites: sort by either first name or surname (user preference)
+    unowned string? a_name = this.settings.sort_on_surname? try_get_surname(a) : a.display_name;
+    unowned string? b_name = this.settings.sort_on_surname? try_get_surname(b) : b.display_name;
+
+    return a_name.collate (b_name);
+  }
+
+  private unowned string try_get_surname (Individual indiv) {
+    if (indiv.structured_name != null && indiv.structured_name.family_name != "")
+      return indiv.structured_name.family_name;
+
+    // Fall back to the display_name
+    return indiv.display_name;
   }
 
   private void update_header (ListBoxRow row, ListBoxRow? before) {
diff --git a/src/contacts-list-pane.vala b/src/contacts-list-pane.vala
index 2c60e15..9f4d3f1 100644
--- a/src/contacts-list-pane.vala
+++ b/src/contacts-list-pane.vala
@@ -48,7 +48,7 @@ public class Contacts.ListPane : Frame {
   public signal void delete_contacts (LinkedList<Contact> contacts);
   public signal void contacts_marked (int contacts_marked);
 
-  public ListPane (Store contacts_store) {
+  public ListPane (Settings settings, Store contacts_store) {
     this.store = contacts_store;
     this.notify["state"].connect (on_ui_state_changed);
 
@@ -60,7 +60,7 @@ public class Contacts.ListPane : Frame {
 
 
     // Load the ContactsView and connect the necessary signals
-    this.contacts_list = new ContactList (contacts_store, this.filter_query);
+    this.contacts_list = new ContactList (settings, contacts_store, this.filter_query);
     bind_property ("state", this.contacts_list, "state", BindingFlags.BIDIRECTIONAL | 
BindingFlags.SYNC_CREATE);
     this.contacts_list_container.add (this.contacts_list);
 
diff --git a/src/contacts-settings.vala b/src/contacts-settings.vala
index bfb11b8..1327f2d 100644
--- a/src/contacts-settings.vala
+++ b/src/contacts-settings.vala
@@ -18,15 +18,19 @@
 /**
  * Provides a convenient interface to deal with the settings.
  */
-public class Contacts.Settings {
-  private GLib.Settings settings;
+public class Contacts.Settings : GLib.Settings {
 
   public bool did_initial_setup {
-    get { return settings.get_boolean ("did-initial-setup"); }
-    set { settings.set_boolean ("did-initial-setup", value); }
+    get { return get_boolean ("did-initial-setup"); }
+    set { set_boolean ("did-initial-setup", value); }
+  }
+
+  public bool sort_on_surname {
+    get { return get_boolean ("sort-on-surname"); }
+    set { set_boolean ("sort-on-surname", value); }
   }
 
   public Settings (App app) {
-    this.settings = new GLib.Settings (app.application_id);
+    Object (schema_id: app.application_id);
   }
 }
diff --git a/src/contacts-window.vala b/src/contacts-window.vala
index 1b25885..a43a268 100644
--- a/src/contacts-window.vala
+++ b/src/contacts-window.vala
@@ -40,6 +40,10 @@ public class Contacts.Window : Gtk.ApplicationWindow {
   [GtkChild]
   private Button select_cancel_button;
   [GtkChild]
+  private MenuButton hamburger_menu_button;
+  [GtkChild]
+  private RadioButton sort_on_surname_button;
+  [GtkChild]
   private ToggleButton favorite_button;
   private bool ignore_favorite_button_toggled;
   [GtkChild]
@@ -55,17 +59,25 @@ public class Contacts.Window : Gtk.ApplicationWindow {
 
   public UiState state { get; set; default = UiState.NORMAL; }
 
+  private Settings settings;
+
   public Store store {
     get; construct set;
   }
 
-  public Window (App app, Store contacts_store) {
+  public Window (Settings settings, App app, Store contacts_store) {
     Object (
       application: app,
       show_menubar: false,
       store: contacts_store
     );
 
+    this.settings = settings;
+    this.sort_on_surname_button.active = this.settings.sort_on_surname;
+    this.sort_on_surname_button.toggled.connect (() => {
+        this.settings.sort_on_surname = this.sort_on_surname_button.active;
+      });
+
     this.notify["state"].connect (on_ui_state_changed);
 
     create_contact_pane ();
@@ -90,7 +102,7 @@ public class Contacts.Window : Gtk.ApplicationWindow {
     if (list_pane != null)
       return;
 
-    list_pane = new ListPane (store);
+    list_pane = new ListPane (this.settings, store);
     bind_property ("state", this.list_pane, "state", BindingFlags.BIDIRECTIONAL | BindingFlags.SYNC_CREATE);
     list_pane.selection_changed.connect (list_pane_selection_changed_cb);
     list_pane.link_contacts.connect (list_pane_link_contacts_cb);
@@ -117,6 +129,7 @@ public class Contacts.Window : Gtk.ApplicationWindow {
   private void on_ui_state_changed (Object obj, ParamSpec pspec) {
     // UI when we're not editing of selecting stuff
     this.add_button.visible
+        = this.hamburger_menu_button.visible
         = this.right_header.show_close_button
         = (this.state == UiState.NORMAL || this.state == UiState.SHOWING);
 
diff --git a/src/org.gnome.Contacts.gschema.xml b/src/org.gnome.Contacts.gschema.xml
index 568e6ce..98d2f4e 100644
--- a/src/org.gnome.Contacts.gschema.xml
+++ b/src/org.gnome.Contacts.gschema.xml
@@ -5,5 +5,13 @@
       <summary>First-time setup done.</summary>
       <description>Set to true after the user has run the first-time setup wizard.</description>
     </key>
+    <key name="sort-on-surname" type="b">
+      <default>false</default>
+      <summary>Sort contacts on surname.</summary>
+      <description>
+        If this is set to true, the list of contacts will be sorted on their surnames.
+        Otherwise, it will be sorted on the first names of the contacts.
+      </description>
+    </key>
   </schema>
 </schemalist>


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