diff options
author | Niels De Graef <nielsdegraef@gmail.com> | 2022-08-17 00:31:07 +0200 |
---|---|---|
committer | Niels De Graef <nielsdegraef@gmail.com> | 2022-08-17 01:25:56 +0200 |
commit | 83aa3cebdcdc22591fd4c693630ce2cf6bd525a5 (patch) | |
tree | b9a832f7adc62a536197999fa8ea5bcdc63d01df /src | |
parent | 7a4aa6227830680ab790e2de314aa7b7e6e15da5 (diff) | |
download | gnome-contacts-83aa3cebdcdc22591fd4c693630ce2cf6bd525a5.tar.gz |
Add a GtkFilter and GtkSorter for Personas
This allows us to split off the logic for filtering and sorting personas
from the generic `Utils` namespace, and allows us to expand on our
GListModel usage, which allows for some bigger cleanups planned ahead.
Diffstat (limited to 'src')
-rw-r--r-- | src/contacts-contact-sheet.vala | 14 | ||||
-rw-r--r-- | src/contacts-linked-personas-dialog.vala | 87 | ||||
-rw-r--r-- | src/contacts-persona-filter.vala | 52 | ||||
-rw-r--r-- | src/contacts-persona-sorter.vala | 57 | ||||
-rw-r--r-- | src/contacts-utils.vala | 38 | ||||
-rw-r--r-- | src/meson.build | 2 |
6 files changed, 170 insertions, 80 deletions
diff --git a/src/contacts-contact-sheet.vala b/src/contacts-contact-sheet.vala index b6e71bb..1b0eecf 100644 --- a/src/contacts-contact-sheet.vala +++ b/src/contacts-contact-sheet.vala @@ -133,19 +133,21 @@ public class Contacts.ContactSheet : Gtk.Grid { this.last_row++; - var personas = Utils.get_personas_for_display (this.individual); - /* Cause personas are sorted properly I can do this */ - for (int i = 0; i < personas.get_n_items (); i++) { - var p = (Persona) personas.get_item (i); + var personas = Utils.personas_as_list_model (individual); + var personas_filtered = new Gtk.FilterListModel (personas, new PersonaFilter ()); + var personas_sorted = new Gtk.SortListModel (personas_filtered, new PersonaSorter ()); + + for (int i = 0; i < personas_sorted.get_n_items (); i++) { + var persona = (Persona) personas_sorted.get_item (i); int persona_store_pos = this.last_row; if (i > 0) { - this.attach (create_persona_store_label (p), 0, this.last_row, 3); + this.attach (create_persona_store_label (persona), 0, this.last_row, 3); this.last_row++; } foreach (unowned var prop in SORTED_PROPERTIES) - add_row_for_property (p, prop); + add_row_for_property (persona, prop); // Nothing to show in the persona: don't mention it bool is_empty_persona = (this.last_row == persona_store_pos + 1); diff --git a/src/contacts-linked-personas-dialog.vala b/src/contacts-linked-personas-dialog.vala index b66e94c..7d87095 100644 --- a/src/contacts-linked-personas-dialog.vala +++ b/src/contacts-linked-personas-dialog.vala @@ -39,46 +39,51 @@ public class Contacts.LinkedPersonasDialog : Gtk.Dialog { this.linked_accounts_view.set_header_func (add_separator); // loading personas for display - var personas = Contacts.Utils.get_personas_for_display (individual); - for (int i = 1; i < personas.get_n_items (); i++) { - var p = (Persona) personas.get_item (i); - var row_grid = new Gtk.Grid (); - - var image_frame = new Avatar (AVATAR_SIZE, individual); - image_frame.set_hexpand (false); - image_frame.margin_top = 6; - image_frame.margin_bottom = 6; - image_frame.margin_start = 6; - image_frame.margin_end = 12; - row_grid.attach (image_frame, 0, 0, 1, 2); - - var display_name = new Gtk.Label (""); - display_name.set_halign (Gtk.Align.START); - display_name.set_valign (Gtk.Align.END); - display_name.set_hexpand (true); - display_name.set_markup (Markup.printf_escaped ("<span font='bold'>%s</span>", p.display_id)); - - row_grid.attach (display_name, 1, 0, 1, 1); - - var store_name = new Gtk.Label (Contacts.Utils.format_persona_store_name_for_contact (p)); - store_name.set_halign (Gtk.Align.START); - store_name.set_valign (Gtk.Align.START); - store_name.set_hexpand (true); - store_name.get_style_context ().add_class ("dim-label"); - row_grid.attach (store_name, 1, 1, 1, 1); - - var button = new Gtk.Button.with_label (_("Unlink")); - button.margin_end = 6; - button.set_valign (Gtk.Align.CENTER); - // button.get_child ().margin = 1; XXX - row_grid.attach (button, 2, 0, 1, 2); - - /* signal */ - button.clicked.connect (() => { - // TODO: handly unlinking - }); - - this.linked_accounts_view.append (row_grid); - } + var personas = Utils.personas_as_list_model (individual); + var personas_filtered = new Gtk.FilterListModel (personas, new PersonaFilter ()); + var personas_sorted = new Gtk.SortListModel (personas_filtered, new PersonaSorter ()); + this.linked_accounts_view.bind_model (personas_sorted, create_row_for_persona); + } + + private Gtk.Widget create_row_for_persona (GLib.Object item) { + unowned var persona = (Persona) item; + + var row_grid = new Gtk.Grid (); + + var image_frame = new Avatar (AVATAR_SIZE, individual); + image_frame.set_hexpand (false); + image_frame.margin_top = 6; + image_frame.margin_bottom = 6; + image_frame.margin_start = 6; + image_frame.margin_end = 12; + row_grid.attach (image_frame, 0, 0, 1, 2); + + var display_name = new Gtk.Label (""); + display_name.set_halign (Gtk.Align.START); + display_name.set_valign (Gtk.Align.END); + display_name.set_hexpand (true); + display_name.set_markup (Markup.printf_escaped ("<span font='bold'>%s</span>", persona.display_id)); + + row_grid.attach (display_name, 1, 0, 1, 1); + + var store_name = new Gtk.Label (Contacts.Utils.format_persona_store_name_for_contact (persona)); + store_name.set_halign (Gtk.Align.START); + store_name.set_valign (Gtk.Align.START); + store_name.set_hexpand (true); + store_name.get_style_context ().add_class ("dim-label"); + row_grid.attach (store_name, 1, 1, 1, 1); + + var button = new Gtk.Button.with_label (_("Unlink")); + button.margin_end = 6; + button.set_valign (Gtk.Align.CENTER); + // button.get_child ().margin = 1; XXX + row_grid.attach (button, 2, 0, 1, 2); + + /* signal */ + button.clicked.connect (() => { + // TODO: handly unlinking + }); + + return row_grid; } } diff --git a/src/contacts-persona-filter.vala b/src/contacts-persona-filter.vala new file mode 100644 index 0000000..fa5cb4b --- /dev/null +++ b/src/contacts-persona-filter.vala @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2022 Niels De Graef <nielsdegraef@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using Folks; + +/** + * A custom GtkFilter to filter out {@link Folks.Persona}s, for example to + * exclude certain types of persona stores. + */ +public class Contacts.PersonaFilter : Gtk.Filter { + + public string[] ignored_store_types { + get { return this._ignored_store_types; } + set { + if (value == null && this.ignored_store_types == null) + return; + if (GLib.strv_equal (this._ignored_store_types, value)) + return; + // notify ignored-store-types + } + } + private string[] _ignored_store_types = { "key-file", }; + + public override bool match (GLib.Object? item) { + unowned var persona = item as Persona; + return_val_if_fail (persona != null, false); + + return match_persona_store_type (persona); + } + + private bool match_persona_store_type (Persona persona) { + return !(persona.store.type_id in this.ignored_store_types); + } + + public override Gtk.FilterMatch get_strictness () { + return Gtk.FilterMatch.SOME; + } +} diff --git a/src/contacts-persona-sorter.vala b/src/contacts-persona-sorter.vala new file mode 100644 index 0000000..4ba4006 --- /dev/null +++ b/src/contacts-persona-sorter.vala @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 Niels De Graef <nielsdegraef@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using Folks; + +/** + * A customer sorter that provides a consistent way of sorting + * {@link Folks.Persona}s within the whole application. + */ +public class Contacts.PersonaSorter : Gtk.Sorter { + + public override Gtk.SorterOrder get_order () { + return Gtk.SorterOrder.PARTIAL; + } + + public override Gtk.Ordering compare (Object? item1, Object? item2) { + unowned var persona_1 = (Persona) item1; + unowned var persona_2 = (Persona) item2; + unowned var store_1 = persona_1.store; + unowned var store_2 = persona_2.store; + + // In the same store, sort Google 'other' contacts last + if (store_1 == store_2) { + if (!Utils.persona_is_google (persona_1)) + return Gtk.Ordering.EQUAL; + + var p1_is_other = Utils.persona_is_google_other (persona_1); + if (p1_is_other != Utils.persona_is_google_other (persona_2)) + return p1_is_other? Gtk.Ordering.LARGER : Gtk.Ordering.SMALLER; + } + + // Sort primary stores before others + if (store_1.is_primary_store != store_2.is_primary_store) + return (store_1.is_primary_store)? Gtk.Ordering.SMALLER : Gtk.Ordering.LARGER; + + // E-D-S stores get prioritized + if ((store_1.type_id == "eds") != (store_2.type_id == "eds")) + return (store_1.type_id == "eds")? Gtk.Ordering.SMALLER : Gtk.Ordering.LARGER; + + // Normal case: use alphabetical sorting + return Gtk.Ordering.from_cmpfunc (strcmp (store_1.id, store_2.id)); + } +} diff --git a/src/contacts-utils.vala b/src/contacts-utils.vala index 012b8db..ad82833 100644 --- a/src/contacts-utils.vala +++ b/src/contacts-utils.vala @@ -264,39 +264,11 @@ namespace Contacts.Utils { return false; } - public ListModel get_personas_for_display (Individual individual) { - var persona_list = new ListStore(typeof(Persona)); + public ListModel personas_as_list_model (Individual individual) { + var personas = new ListStore (typeof(Persona)); foreach (var persona in individual.personas) - if (persona.store.type_id != "key-file") - persona_list.append (persona); - - persona_list.sort ((a, b) => { - unowned var store_a = ((Persona) a).store; - unowned var store_b = ((Persona) b).store; - - // In the same store, sort Google 'other' contacts last - if (store_a == store_b) { - if (!persona_is_google ((Persona) a)) - return 0; - - var a_is_other = persona_is_google_other ((Persona) a); - if (a_is_other != persona_is_google_other ((Persona) b)) - return a_is_other? 1 : -1; - } - - // Sort primary stores before others - if (store_a.is_primary_store != store_b.is_primary_store) - return (store_a.is_primary_store)? -1 : 1; - - // E-D-S stores get prioritized - if ((store_a.type_id == "eds") != (store_b.type_id == "eds")) - return (store_a.type_id == "eds")? -1 : 1; - - // Normal case: use alphabetical sorting - return strcmp (store_a.id, store_b.id); - }); - - return persona_list; + personas.append (persona); + return personas; } public Persona? find_primary_persona (Individual individual) { @@ -365,7 +337,7 @@ namespace Contacts.Utils { return all_unlinkable; } - private bool persona_is_google (Persona persona) { + public bool persona_is_google (Persona persona) { return persona.store.type_id == "eds" && esource_uid_is_google (persona.store.id); } diff --git a/src/meson.build b/src/meson.build index 0710d4a..96d455f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -17,6 +17,8 @@ libcontacts_sources = files( 'contacts-link-operation.vala', 'contacts-operation.vala', 'contacts-operation-list.vala', + 'contacts-persona-filter.vala', + 'contacts-persona-sorter.vala', 'contacts-query-filter.vala', 'contacts-store.vala', 'contacts-typeset.vala', |