[geary/mjog/493-undo-send: 3/6] Implement undoing saved composers



commit d01863b7ee423fa3748dce2ab9cd7742415d0d06
Author: Michael Gratton <mike vee net>
Date:   Tue Nov 12 15:21:26 2019 +1100

    Implement undoing saved composers
    
    Add Application::save_composed_email method and SaveComposerEmail
    command, execute the latter when the former is called. Update
    Composer.Widget::save_and_exit_async to call this as needed instead
    of manually disposing of the widget.

 src/client/application/application-controller.vala | 80 ++++++++++++++++++++++
 src/client/composer/composer-widget.vala           | 30 +++++---
 2 files changed, 101 insertions(+), 9 deletions(-)
---
diff --git a/src/client/application/application-controller.vala 
b/src/client/application/application-controller.vala
index dd6cef15..10668435 100644
--- a/src/client/application/application-controller.vala
+++ b/src/client/application/application-controller.vala
@@ -464,6 +464,27 @@ public class Application.Controller : Geary.BaseObject {
         }
     }
 
+    /** Saves the email in a composer as a draft on the server. */
+    public async void save_composed_email(Composer.Widget composer) {
+        // XXX this doesn't actually do what it says on the tin, since
+        // the composer's draft manager is already saving drafts on
+        // the server. Until we get that saving local-only, this will
+        // only be around for pushing the composer onto the undo stack
+        AccountContext? context = this.accounts.get(
+            composer.account.information
+        );
+        if (context != null) {
+            try {
+                yield context.commands.execute(
+                    new SaveComposerCommand(this, composer),
+                    context.cancellable
+                );
+            } catch (GLib.Error err) {
+                report_problem(new Geary.ProblemReport(err));
+            }
+        }
+    }
+
     /** Queues a composer to be discarded. */
     public async void discard_composed_email(Composer.Widget composer) {
         AccountContext? context = this.accounts.get(
@@ -2739,6 +2760,64 @@ private class Application.SendComposerCommand : ComposerCommand {
 }
 
 
+private class Application.SaveComposerCommand : ComposerCommand {
+
+
+    private const int DESTROY_TIMEOUT_SEC = 30 * 60;
+
+    public override bool can_redo {
+        get { return false; }
+    }
+
+    private Controller controller;
+
+    private Geary.TimeoutManager destroy_timer;
+
+
+    public SaveComposerCommand(Controller controller,
+                               Composer.Widget composer) {
+        base(composer);
+        this.controller = controller;
+
+        this.destroy_timer = new Geary.TimeoutManager.seconds(
+            DESTROY_TIMEOUT_SEC,
+            on_destroy_timeout
+        );
+    }
+
+    public override async void execute(GLib.Cancellable? cancellable)
+        throws GLib.Error {
+        Geary.ComposedEmail email = yield this.composer.get_composed_email();
+        /// Translators: The label for an in-app notification. The
+        /// string substitution is a list of recipients of the email.
+        this.executed_label = _(
+            "Email to %s saved"
+        ).printf(Util.Email.to_short_recipient_display(email));
+        this.destroy_timer.start();
+    }
+
+    public override async void undo(GLib.Cancellable? cancellable)
+        throws GLib.Error {
+        if (this.composer != null) {
+            this.destroy_timer.reset();
+            this.composer.set_enabled(true);
+            this.controller.show_composer(this.composer, null);
+            clear_composer();
+        } else {
+            /// Translators: A label for an in-app notification.
+            this.undone_label = _(
+                "Composer could not be restored"
+            );
+        }
+    }
+
+    private void on_destroy_timeout() {
+        close_composer();
+    }
+
+}
+
+
 private class Application.DiscardComposerCommand : ComposerCommand {
 
 
@@ -2783,6 +2862,7 @@ private class Application.DiscardComposerCommand : ComposerCommand {
             this.controller.show_composer(this.composer, null);
             clear_composer();
         } else {
+            /// Translators: A label for an in-app notification.
             this.undone_label = _(
                 "Composer could not be restored"
             );
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index b4397bcd..a1cc3fa2 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -1613,16 +1613,28 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface {
     private async void save_and_exit_async() {
         this.is_closing = true;
         set_enabled(false);
-        try {
-            yield save_draft();
-        } catch (GLib.Error error) {
-            this.application.controller.report_problem(
-                new Geary.AccountProblemReport(
-                    this.account.information, error
-                )
-            );
+
+        if (!is_blank) {
+            try {
+                yield save_draft();
+            } catch (GLib.Error error) {
+                this.application.controller.report_problem(
+                    new Geary.AccountProblemReport(
+                        this.account.information, error
+                    )
+                );
+            }
+
+            // Pass on to the controller so the draft can be re-opened
+            // on undo
+            if (this.container != null) {
+                this.container.close();
+            }
+            yield this.application.controller.save_composed_email(this);
+        } else {
+            // The composer is blank, so drop the mic and walk away
+            yield close();
         }
-        yield close();
     }
 
     private async void discard_and_exit_async() {


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