[geary/wip/714104-refine-account-dialog: 5/5] Implement initial drag and drop for accounts, sender mailbox ordering
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/714104-refine-account-dialog: 5/5] Implement initial drag and drop for accounts, sender mailbox ordering
- Date: Sun, 2 Dec 2018 02:53:10 +0000 (UTC)
commit 6c22f76e5349b1ec81f27e46901167c0d6186c47
Author: Michael Gratton <mike vee net>
Date: Sun Dec 2 13:51:15 2018 +1100
Implement initial drag and drop for accounts, sender mailbox ordering
src/client/accounts/accounts-editor-edit-pane.vala | 72 +++++++++-
src/client/accounts/accounts-editor-list-pane.vala | 147 +++++++++++++++------
src/client/accounts/accounts-editor-row.vala | 75 +++++++++++
ui/geary.css | 21 ++-
4 files changed, 263 insertions(+), 52 deletions(-)
---
diff --git a/src/client/accounts/accounts-editor-edit-pane.vala
b/src/client/accounts/accounts-editor-edit-pane.vala
index 4e8c1c30..bb793d74 100644
--- a/src/client/accounts/accounts-editor-edit-pane.vala
+++ b/src/client/accounts/accounts-editor-edit-pane.vala
@@ -62,9 +62,9 @@ internal class Accounts.EditorEditPane : Gtk.Grid, EditorPane, AccountPane {
this.details_list.add(new NicknameRow(account));
this.senders_list.set_header_func(Editor.seperator_headers);
- foreach (Geary.RFC822.MailboxAddress sender
- in account.get_sender_mailboxes()) {
- this.senders_list.add(new MailboxRow(account, sender));
+ foreach (Geary.RFC822.MailboxAddress sender in
+ account.sender_mailboxes) {
+ this.senders_list.add(new_mailbox_row(sender));
}
this.senders_list.add(new AddMailboxRow());
@@ -173,6 +173,12 @@ internal class Accounts.EditorEditPane : Gtk.Grid, EditorPane, AccountPane {
);
}
+ internal MailboxRow new_mailbox_row(Geary.RFC822.MailboxAddress sender) {
+ MailboxRow row = new MailboxRow(this.account, sender);
+ row.dropped.connect(on_sender_row_dropped);
+ return row;
+ }
+
private void on_account_changed() {
update_header();
}
@@ -181,6 +187,18 @@ internal class Accounts.EditorEditPane : Gtk.Grid, EditorPane, AccountPane {
update_actions();
}
+ private void on_sender_row_dropped(EditorRow source, EditorRow target) {
+ this.commands.execute.begin(
+ new ReorderMailboxCommand(
+ (MailboxRow) source,
+ (MailboxRow) target,
+ this.account,
+ this.senders_list
+ ),
+ null
+ );
+ }
+
[GtkCallback]
private void on_setting_activated(Gtk.ListBoxRow row) {
EditorRow<EditorEditPane>? setting = row as EditorRow<EditorEditPane>;
@@ -309,8 +327,7 @@ private class Accounts.AddMailboxRow : AddRow<EditorEditPane> {
pane.commands.execute.begin(
new AppendMailboxCommand(
(Gtk.ListBox) get_parent(),
- new MailboxRow(
- pane.account,
+ pane.new_mailbox_row(
new Geary.RFC822.MailboxAddress(
popover.display_name,
popover.address
@@ -338,6 +355,7 @@ private class Accounts.MailboxRow : AccountRow<EditorEditPane,Gtk.Label> {
Geary.RFC822.MailboxAddress mailbox) {
base(account, "", new Gtk.Label(""));
this.mailbox = mailbox;
+ enable_drag();
update();
}
@@ -584,6 +602,50 @@ internal class Accounts.UpdateMailboxCommand : Application.Command {
}
+internal class Accounts.ReorderMailboxCommand : Application.Command {
+
+
+ private MailboxRow source;
+ private int source_index;
+ private int target_index;
+
+ private Geary.AccountInformation account;
+ private Gtk.ListBox list;
+
+
+ public ReorderMailboxCommand(MailboxRow source,
+ MailboxRow target,
+ Geary.AccountInformation account,
+ Gtk.ListBox list) {
+ this.source = source;
+ this.source_index = source.get_index();
+ this.target_index = target.get_index();
+
+ this.account = account;
+ this.list = list;
+ }
+
+ public async override void execute(GLib.Cancellable? cancellable)
+ throws GLib.Error {
+ move_source(this.target_index);
+ }
+
+ public async override void undo(GLib.Cancellable? cancellable)
+ throws GLib.Error {
+ move_source(this.source_index);
+ }
+
+ private void move_source(int destination) {
+ this.account.remove_sender(this.source.mailbox);
+ this.account.insert_sender(destination, this.source.mailbox);
+
+ this.list.remove(this.source);
+ this.list.insert(this.source, destination);
+ }
+
+}
+
+
internal class Accounts.RemoveMailboxCommand : Application.Command {
diff --git a/src/client/accounts/accounts-editor-list-pane.vala
b/src/client/accounts/accounts-editor-list-pane.vala
index 3165bb83..bae6576a 100644
--- a/src/client/accounts/accounts-editor-list-pane.vala
+++ b/src/client/accounts/accounts-editor-list-pane.vala
@@ -158,7 +158,9 @@ internal class Accounts.EditorListPane : Gtk.Grid, EditorPane {
private void add_account(Geary.AccountInformation account,
Manager.Status status) {
- this.accounts_list.add(new AccountListRow(account, status));
+ AccountListRow row = new AccountListRow(account, status);
+ row.dropped.connect(on_editor_row_dropped);
+ this.accounts_list.add(row);
}
private void add_notification(InAppNotification notification) {
@@ -216,6 +218,15 @@ internal class Accounts.EditorListPane : Gtk.Grid, EditorPane {
}
}
+ private void on_editor_row_dropped(EditorRow source, EditorRow target) {
+ this.commands.execute.begin(
+ new ReorderAccountCommand(
+ (AccountListRow) source, (AccountListRow) target, this.accounts
+ ),
+ null
+ );
+ }
+
private void on_account_removed(Geary.AccountInformation account) {
AccountListRow? row = get_account_row(account);
if (row != null) {
@@ -225,17 +236,21 @@ internal class Accounts.EditorListPane : Gtk.Grid, EditorPane {
}
private void on_execute(Application.Command command) {
- InAppNotification ian = new InAppNotification(command.executed_label);
- ian.set_button(_("Undo"), "win." + GearyController.ACTION_UNDO);
- add_notification(ian);
+ if (command.executed_label != null) {
+ InAppNotification ian = new InAppNotification(command.executed_label);
+ ian.set_button(_("Undo"), "win." + GearyController.ACTION_UNDO);
+ add_notification(ian);
+ }
update_actions();
}
private void on_undo(Application.Command command) {
- InAppNotification ian = new InAppNotification(command.undone_label);
- ian.set_button(_("Redo"), "win." + GearyController.ACTION_REDO);
- add_notification(ian);
+ if (command.undone_label != null) {
+ InAppNotification ian = new InAppNotification(command.undone_label);
+ ian.set_button(_("Redo"), "win." + GearyController.ACTION_REDO);
+ add_notification(ian);
+ }
update_actions();
}
@@ -267,34 +282,26 @@ internal class Accounts.EditorListPane : Gtk.Grid, EditorPane {
}
-private class Accounts.AccountListRow : EditorRow<EditorListPane> {
-
+private class Accounts.AccountListRow : AccountRow<EditorListPane,Gtk.Grid> {
- internal Geary.AccountInformation account;
+ private Gtk.Label service_label = new Gtk.Label("");
private Gtk.Image unavailable_icon = new Gtk.Image.from_icon_name(
"dialog-warning-symbolic", Gtk.IconSize.BUTTON
);
- private Gtk.Label account_name = new Gtk.Label("");
- private Gtk.Label account_details = new Gtk.Label("");
-
public AccountListRow(Geary.AccountInformation account,
Manager.Status status) {
- this.account = account;
-
- this.account_name.show();
- this.account_name.set_hexpand(true);
- this.account_name.halign = Gtk.Align.START;
+ base(account, "", new Gtk.Grid());
+ enable_drag();
- this.account_details.show();
+ this.value.add(this.unavailable_icon);
+ this.value.add(this.service_label);
- this.layout.add(this.unavailable_icon);
- this.layout.add(this.account_name);
- this.layout.add(this.account_details);
+ this.service_label.show();
this.account.information_changed.connect(on_account_changed);
- update_nickname();
+ update();
update_status(status);
}
@@ -327,24 +334,12 @@ private class Accounts.AccountListRow : EditorRow<EditorListPane> {
}
}
- public void update_nickname() {
+ public override void update() {
string name = this.account.nickname;
if (Geary.String.is_empty(name)) {
name = account.primary_mailbox.to_address_display("", "");
}
- this.account_name.set_text(name);
- }
-
- public void update_status(Manager.Status status) {
- if (status != Manager.Status.UNAVAILABLE) {
- this.unavailable_icon.hide();
- this.set_tooltip_text("");
- } else {
- this.unavailable_icon.show();
- this.set_tooltip_text(
- _("This account has encountered a problem and is unavailable")
- );
- }
+ this.label.set_text(name);
string? details = this.account.service_label;
switch (account.service_provider) {
@@ -360,27 +355,43 @@ private class Accounts.AccountListRow : EditorRow<EditorListPane> {
details = _("Yahoo");
break;
}
- this.account_details.set_text(details);
+ this.service_label.set_text(details);
+ }
+
+ public void update_status(Manager.Status status) {
+ if (status != Manager.Status.UNAVAILABLE) {
+ this.unavailable_icon.hide();
+ this.set_tooltip_text("");
+ } else {
+ this.unavailable_icon.show();
+ this.set_tooltip_text(
+ _("This account has encountered a problem and is unavailable")
+ );
+ }
if (status == Manager.Status.ENABLED) {
- this.account_name.get_style_context().remove_class(
+ this.label.get_style_context().remove_class(
Gtk.STYLE_CLASS_DIM_LABEL
);
- this.account_details.get_style_context().remove_class(
+ this.service_label.get_style_context().remove_class(
Gtk.STYLE_CLASS_DIM_LABEL
);
} else {
- this.account_name.get_style_context().add_class(
+ this.label.get_style_context().add_class(
Gtk.STYLE_CLASS_DIM_LABEL
);
- this.account_details.get_style_context().add_class(
+ this.service_label.get_style_context().add_class(
Gtk.STYLE_CLASS_DIM_LABEL
);
}
}
private void on_account_changed() {
- update_nickname();
+ update();
+ Gtk.ListBox? parent = get_parent() as Gtk.ListBox;
+ if (parent != null) {
+ parent.invalidate_sort();
+ }
}
}
@@ -451,6 +462,56 @@ private class Accounts.AddServiceProviderRow : EditorRow<EditorListPane> {
}
+internal class Accounts.ReorderAccountCommand : Application.Command {
+
+
+ private AccountListRow source;
+ private int source_index;
+ private int target_index;
+
+ private Manager manager;
+
+
+ public ReorderAccountCommand(AccountListRow source,
+ AccountListRow target,
+ Manager manager) {
+ this.source = source;
+ this.source_index = source.get_index();
+ this.target_index = target.get_index();
+
+ this.manager = manager;
+ }
+
+ public async override void execute(GLib.Cancellable? cancellable)
+ throws GLib.Error {
+ move_source(this.target_index);
+ }
+
+ public async override void undo(GLib.Cancellable? cancellable)
+ throws GLib.Error {
+ move_source(this.source_index);
+ }
+
+ private void move_source(int destination) {
+ Gee.List<Geary.AccountInformation> accounts =
+ this.manager.iterable().to_linked_list();
+ accounts.sort(Geary.AccountInformation.compare_ascending);
+ accounts.remove(this.source.account);
+ accounts.insert(destination, this.source.account);
+
+ int ord = 0;
+ foreach (Geary.AccountInformation account in accounts) {
+ if (account.ordinal != ord) {
+ account.ordinal = ord;
+ account.information_changed();
+ }
+ ord++;
+ }
+ }
+
+}
+
+
internal class Accounts.RemoveAccountCommand : Application.Command {
diff --git a/src/client/accounts/accounts-editor-row.vala b/src/client/accounts/accounts-editor-row.vala
index 44336775..681faa48 100644
--- a/src/client/accounts/accounts-editor-row.vala
+++ b/src/client/accounts/accounts-editor-row.vala
@@ -8,9 +8,19 @@
internal class Accounts.EditorRow<PaneType> : Gtk.ListBoxRow {
+ private const string DND_ATOM = "geary-editor-row";
+ private const Gtk.TargetEntry[] DRAG_ENTRIES = {
+ { DND_ATOM, Gtk.TargetFlags.SAME_APP, 0 }
+ };
+
protected Gtk.Grid layout { get; private set; default = new Gtk.Grid(); }
+ private Gtk.Container drag_handle;
+
+
+ public signal void dropped(EditorRow target);
+
public EditorRow() {
get_style_context().add_class("geary-settings");
@@ -19,6 +29,23 @@ internal class Accounts.EditorRow<PaneType> : Gtk.ListBoxRow {
this.layout.show();
add(this.layout);
+ // We'd like to add the drag handle only when needed, but
+ // GNOME/gtk#1495 prevents us from doing so.
+ Gtk.EventBox drag_box = new Gtk.EventBox();
+ drag_box.add(
+ new Gtk.Image.from_icon_name(
+ "open-menu-symbolic", Gtk.IconSize.BUTTON
+ )
+ );
+ this.drag_handle = new Gtk.Grid();
+ this.drag_handle.valign = Gtk.Align.CENTER;
+ this.drag_handle.add(drag_box);
+ this.drag_handle.show_all();
+ this.drag_handle.hide();
+ // Translators: Tooltip for dragging list items
+ this.drag_handle.set_tooltip_text(_("Drag to move this item"));
+ this.layout.add(drag_handle);
+
this.show();
}
@@ -26,6 +53,54 @@ internal class Accounts.EditorRow<PaneType> : Gtk.ListBoxRow {
// No-op by default
}
+ /** Adds a drag handle to the row and enables drag signals. */
+ protected void enable_drag() {
+ Gtk.drag_source_set(
+ this.drag_handle,
+ Gdk.ModifierType.BUTTON1_MASK,
+ DRAG_ENTRIES,
+ Gdk.DragAction.MOVE
+ );
+
+ Gtk.drag_dest_set(
+ this,
+ Gtk.DestDefaults.ALL,
+ DRAG_ENTRIES,
+ Gdk.DragAction.MOVE
+ );
+
+ this.drag_handle.drag_data_get.connect(on_drag_data_get);
+ this.drag_data_received.connect(on_drag_data_received);
+ this.drag_handle.get_style_context().add_class("geary-drag-handle");
+ this.drag_handle.show();
+
+ get_style_context().add_class("geary-draggable");
+ }
+
+
+ private void on_drag_data_get(Gdk.DragContext context,
+ Gtk.SelectionData selection_data,
+ uint info, uint time_) {
+ selection_data.set(
+ Gdk.Atom.intern_static_string(DND_ATOM), 8,
+ get_index().to_string().data
+ );
+ }
+
+ private void on_drag_data_received(Gdk.DragContext context,
+ int x, int y,
+ Gtk.SelectionData selection_data,
+ uint info, uint time_) {
+ int drag_index = int.parse((string) selection_data.get_data());
+ Gtk.ListBox? parent = this.get_parent() as Gtk.ListBox;
+ if (parent != null) {
+ EditorRow? drag_row = parent.get_row_at_index(drag_index) as EditorRow;
+ if (drag_row != null && drag_row != this) {
+ drag_row.dropped(this);
+ }
+ }
+ }
+
}
diff --git a/ui/geary.css b/ui/geary.css
index a9530a26..3cbc9afc 100644
--- a/ui/geary.css
+++ b/ui/geary.css
@@ -208,6 +208,10 @@ row.geary-settings {
padding: 0px;
}
+row.geary-settings image {
+ padding: 0px 6px;
+}
+
row.geary-settings > grid > * {
margin: 18px 6px;
}
@@ -222,11 +226,20 @@ row.geary-settings > grid > *:first-child:dir(rtl) {
margin-right: 18px;
}
-row.geary-settings > grid > image:dir(ltr) {
- margin-right: 6px;
+/* dir pseudo-class used here for required additional specificity */
+row.geary-settings > grid > grid.geary-drag-handle:dir(ltr),
+row.geary-settings > grid > grid.geary-drag-handle:dir(rtl) {
+ margin: 0;
}
-row.geary-settings > grid > image:dir(rtl) {
- margin-left: 6px;
+
+row.geary-settings > grid > grid.geary-drag-handle image:dir(ltr) {
+ padding: 12px;
+ padding-right: 6px;
+}
+
+row.geary-settings > grid > grid.geary-drag-handle image:dir(rtl) {
+ padding: 12px;
+ padding-left: 6px;
}
frame.geary-settings.geary-signature {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]