From 4f7fac7166be6b4637ced08dab2a42170cb39ed8 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Thu, 20 Jul 2023 21:29:21 +0200 Subject: [PATCH] Implement editing prototype --- meson.build | 3 + src/IndividualView.vala | 84 ++++++++++++++++++++--- src/MainWindow.vala | 16 +---- src/Widgets/EmailGroup/EmailGroup.vala | 57 +++++++++++++++ src/Widgets/EmailGroup/EmailGroupRow.vala | 42 ++++++++++++ src/Widgets/NameGroup.vala | 51 ++++++++++++++ 6 files changed, 230 insertions(+), 23 deletions(-) create mode 100644 src/Widgets/EmailGroup/EmailGroup.vala create mode 100644 src/Widgets/EmailGroup/EmailGroupRow.vala create mode 100644 src/Widgets/NameGroup.vala diff --git a/meson.build b/meson.build index c319291..210dd27 100644 --- a/meson.build +++ b/meson.build @@ -11,6 +11,9 @@ executable( 'src/MainWindow.vala', 'src/IndividualView.vala', 'src/Widgets/ContactRow.vala', + 'src/Widgets/NameGroup.vala', + 'src/Widgets/EmailGroup/EmailGroup.vala', + 'src/Widgets/EmailGroup/EmailGroupRow.vala', dependencies: [ dependency('folks'), dependency('glib-2.0'), diff --git a/src/IndividualView.vala b/src/IndividualView.vala index adad8bb..a6c2952 100644 --- a/src/IndividualView.vala +++ b/src/IndividualView.vala @@ -18,36 +18,104 @@ * */ -public class Friends.IndividualView : Gtk.Grid { +public class Friends.IndividualView : Gtk.Box { public Folks.Individual? individual { get; set; } + private Gtk.Button edit_button; + private Gtk.ActionBar edit_action_bar; + private NameGroup name_group; + private EmailGroup email_group; + construct { - var placeholder = new Granite.Placeholder (_("No Contact Selected")); + edit_button = new Gtk.Button.from_icon_name ("document-edit") { + visible = false + }; - var individual_name = new Gtk.Label (null) { - ellipsize = Pango.EllipsizeMode.MIDDLE, + var header = new Gtk.HeaderBar () { + show_title_buttons = false, + title_widget = new Gtk.Grid () + }; + header.add_css_class (Granite.STYLE_CLASS_FLAT); + header.pack_end (new Gtk.WindowControls (END)); + header.pack_end (edit_button); + + var placeholder = new Granite.Placeholder (_("No Contact Selected")) { hexpand = true, vexpand = true }; - individual_name.add_css_class (Granite.STYLE_CLASS_H3_LABEL); + + name_group = new NameGroup () { + hexpand = true + }; + + email_group = new EmailGroup (); var details_grid = new Gtk.Grid (); - details_grid.attach (individual_name, 0, 0); + details_grid.attach (name_group, 0, 1); + details_grid.attach (email_group, 0, 2); + + var cancel_button = new Gtk.Button.with_label (_("Cancel")); + + var save_button = new Gtk.Button.with_label (_("Apply")); + + edit_action_bar = new Gtk.ActionBar () { + revealed = false + }; + edit_action_bar.pack_end (save_button); + edit_action_bar.pack_end (cancel_button); var stack = new Gtk.Stack (); stack.add_child (placeholder); stack.add_child (details_grid); - attach (stack, 0, 0); + orientation = VERTICAL; + append (header); + append (stack); + append (edit_action_bar); + add_css_class (Granite.STYLE_CLASS_VIEW); notify["individual"].connect (() => { if (individual != null) { stack.visible_child = details_grid; + edit_button.visible = true; - individual_name.label = individual.display_name; + update_groups.begin (); } else { stack.visible_child = placeholder; + edit_button.visible = false; } }); + + edit_button.clicked.connect (() => { + name_group.start_edit (); + email_group.start_edit (); + edit_button.visible = false; + edit_action_bar.revealed = true; + }); + + cancel_button.clicked.connect (() => finish_edit (false)); + + save_button.clicked.connect (() => finish_edit (true)); + } + + private async void update_groups () { + try { + name_group.name_details = (Folks.NameDetails) yield Folks.IndividualAggregator.dup ().ensure_individual_property_writeable (individual, "full-name"); + } catch (Error e) { + warning ("Failed to get EmailDetails: %s", e.message); + } + + try { + email_group.email_details = (Folks.EmailDetails) yield Folks.IndividualAggregator.dup ().ensure_individual_property_writeable (individual, "email-addresses"); + } catch (Error e) { + warning ("Failed to get EmailDetails: %s", e.message); + } + } + + private void finish_edit (bool save) { + name_group.finish_edit.begin (save); + email_group.finish_edit.begin (save); + edit_button.visible = true; + edit_action_bar.revealed = false; } } diff --git a/src/MainWindow.vala b/src/MainWindow.vala index a3d53d4..9ab25f7 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -39,15 +39,6 @@ public class Friends.MainWindow : Gtk.ApplicationWindow { sidebar_header.add_css_class ("titlebar"); sidebar_header.add_css_class (Granite.STYLE_CLASS_FLAT); - var individualview_header = new Gtk.WindowHandle () { - child = new Gtk.WindowControls (Gtk.PackType.END) { - halign = Gtk.Align.END - } - }; - individualview_header.add_css_class (Granite.STYLE_CLASS_DEFAULT_DECORATION); - individualview_header.add_css_class ("titlebar"); - individualview_header.add_css_class (Granite.STYLE_CLASS_FLAT); - search_entry = new Gtk.SearchEntry () { margin_start = 9, margin_end = 9, @@ -81,16 +72,11 @@ public class Friends.MainWindow : Gtk.ApplicationWindow { var individual_view = new Friends.IndividualView (); - var individual_grid = new Gtk.Grid (); - individual_grid.add_css_class (Granite.STYLE_CLASS_VIEW); - individual_grid.attach (individualview_header, 0, 0); - individual_grid.attach (individual_view, 0, 1); - var paned = new Gtk.Paned (Gtk.Orientation.HORIZONTAL) { start_child = sidebar_grid, resize_start_child = false, shrink_start_child = false, - end_child = individual_grid, + end_child = individual_view, resize_end_child = true, shrink_end_child = false }; diff --git a/src/Widgets/EmailGroup/EmailGroup.vala b/src/Widgets/EmailGroup/EmailGroup.vala new file mode 100644 index 0000000..6c36632 --- /dev/null +++ b/src/Widgets/EmailGroup/EmailGroup.vala @@ -0,0 +1,57 @@ +public class EmailGroup : Gtk.Box { + public Folks.EmailDetails email_details { get; set; } + + private ListStore list_store; + + construct { + list_store = new ListStore (typeof (EmailGroupRow)); + + var header_label = new Granite.HeaderLabel (_("E-Mail Adresses")); + + var list_box = new Gtk.ListBox (); + list_box.bind_model (list_store, (item) => { + return (Gtk.ListBoxRow)item; + }); + + hexpand = true; + halign = CENTER; + orientation = VERTICAL; + append (header_label); + append (list_box); + + notify["email-details"].connect (() => { + list_store.remove_all (); + foreach (var email_address in email_details.email_addresses) { + list_store.append (new EmailGroupRow (email_address)); + } + }); + } + + public void start_edit () { + for (int i = 0; i < list_store.get_n_items (); i++) { + var email_group_row = (EmailGroupRow)list_store.get_item (i); + email_group_row.start_edit (); + } + } + + public async void finish_edit (bool save) { + var new_set = new Gee.TreeSet (); + + for (int i = 0; i < list_store.get_n_items (); i++) { + var email_group_row = (EmailGroupRow)list_store.get_item (i); + email_group_row.finish_edit (save); + + if (save) { + new_set.add (email_group_row.email_field_details); + } + } + + if (save) { + try { + yield email_details.change_email_addresses (new_set); + } catch (Error e) { + warning ("Failed to update email addresses: %s", e.message); + } + } + } +} diff --git a/src/Widgets/EmailGroup/EmailGroupRow.vala b/src/Widgets/EmailGroup/EmailGroupRow.vala new file mode 100644 index 0000000..098bc1d --- /dev/null +++ b/src/Widgets/EmailGroup/EmailGroupRow.vala @@ -0,0 +1,42 @@ +public class EmailGroupRow : Gtk.ListBoxRow { + public Folks.EmailFieldDetails email_field_details { get; set construct; } + + private Gtk.Grid grid; + private Gtk.Label email_address_label; + private Gtk.Entry email_address_entry; + + public EmailGroupRow (Folks.EmailFieldDetails email_field_details) { + Object ( + email_field_details: email_field_details + ); + } + + construct { + var label = new Gtk.Label ("unnamed"); + + email_address_label = new Gtk.Label (email_field_details.value); + + grid = new Gtk.Grid (); + grid.attach (label, 0, 0); + grid.attach (email_address_label, 1, 0); + child = grid; + + email_address_entry = new Gtk.Entry (); + + email_address_label.bind_property ("label", email_address_entry, "text", BIDIRECTIONAL | SYNC_CREATE); + } + + public void start_edit () { + grid.remove (email_address_label); + grid.attach (email_address_entry, 1, 0); + } + + public void finish_edit (bool save) { + if (save) { + email_field_details = new Folks.EmailFieldDetails (email_address_entry.text); + } + + grid.remove (email_address_entry); + grid.attach (email_address_label, 1, 0); + } +} diff --git a/src/Widgets/NameGroup.vala b/src/Widgets/NameGroup.vala new file mode 100644 index 0000000..d375225 --- /dev/null +++ b/src/Widgets/NameGroup.vala @@ -0,0 +1,51 @@ +public class NameGroup : Gtk.Grid { + public Folks.NameDetails name_details { get; set; } + + private Gtk.Label full_name_label; + private Gtk.Entry full_name_entry; + + construct { + var header_label = new Granite.HeaderLabel (_("Name")); + + var description_label = new Gtk.Label (_("Full Name: ")) { + xalign = 1 + }; + + full_name_label = new Gtk.Label ("") { + ellipsize = Pango.EllipsizeMode.MIDDLE + }; + + full_name_entry = new Gtk.Entry (); + + hexpand = true; + halign = CENTER; + attach (header_label, 0, 0, 2, 1); + attach (description_label, 0, 1); + attach (full_name_label, 1, 1); + + full_name_label.bind_property ("label", full_name_entry, "text", BIDIRECTIONAL); + + notify["name-details"].connect (() => { + full_name_label.label = name_details.full_name; + }); + } + + public void start_edit () { + remove (full_name_label); + attach (full_name_entry, 1, 1); + } + + public async void finish_edit (bool save) { + if (save) { + try { + yield name_details.change_full_name (full_name_entry.text); + } catch (Error e) { + warning ("Failed to update full name: %s", e.message); + } + } + + full_name_label.label = name_details.full_name; + remove (full_name_entry); + attach (full_name_label, 1, 1); + } +}