[geary/cherry-pick-3e7a9dac] Merge branch 'mjog/550-always-show-images-not-saved' into 'mainline'



commit 8f429defc113a5902c60ef826aa0b39ca6a3e4d9
Author: Michael Gratton <mike vee net>
Date:   Fri Oct 25 04:24:50 2019 +0000

    Merge branch 'mjog/550-always-show-images-not-saved' into 'mainline'
    
    Always show images pref not saved
    
    Closes #550
    
    See merge request GNOME/geary!345
    
    (cherry picked from commit 3e7a9daccc4b1751b949675074add53939b41be5)
    
    0c563cf1 Fix ContactStoreImpl not saving flags removed from a contact
    0cf5ab73 Merge contacts when harvesting them
    058ea2fa Update Contact::load_remote_resources with engine contact flags
    10ddff2e Trivial docs update

 src/client/application/application-contact.vala    | 34 +++++++---
 .../conversation-viewer/conversation-message.vala  |  6 +-
 src/engine/api/geary-contact.vala                  | 10 ++-
 src/engine/common/common-contact-harvester.vala    | 76 ++++++++++++++++------
 src/engine/common/common-contact-store-impl.vala   | 31 ++-------
 .../common/common-contact-harvester-test.vala      | 20 +++---
 .../common/common-contact-store-impl-test.vala     | 18 ++++-
 7 files changed, 126 insertions(+), 69 deletions(-)
---
diff --git a/src/client/application/application-contact.vala b/src/client/application/application-contact.vala
index 2cb9cb4a..6b7d2d89 100644
--- a/src/client/application/application-contact.vala
+++ b/src/client/application/application-contact.vala
@@ -74,12 +74,15 @@ public class Application.Contact : Geary.BaseObject {
     /** The Folks individual for the contact, if any. */
     internal Folks.Individual? individual { get; private set; }
 
+    /** The Engine contact, if any. */
+    private Geary.Contact? engine = null;
+
     private weak ContactStore store;
 
 
     private Contact(ContactStore store, Folks.Individual? source) {
         this.store = store;
-        update_individual(source);
+        update_from_individual(source);
         update();
     }
 
@@ -92,15 +95,20 @@ public class Application.Contact : Geary.BaseObject {
                                 string display_name,
                                 Geary.Contact source) {
         this(store, null);
-        Geary.RFC822.MailboxAddress mailbox = source.get_rfc822_address();
+        this.engine = source;
+        this.engine.flags.added.connect(on_engine_flags_changed);
+        this.engine.flags.removed.connect(on_engine_flags_changed);
         update_name(display_name);
-        this._email_addresses = Geary.Collection.single(mailbox);
-        this.load_remote_resources = source.flags.always_load_remote_images();
+        update_from_engine();
     }
 
     ~Contact() {
         // Disconnect from signals if any
-        update_individual(null);
+        update_from_individual(null);
+        if (this.engine != null) {
+            this.engine.flags.added.disconnect(on_engine_flags_changed);
+            this.engine.flags.removed.disconnect(on_engine_flags_changed);
+        }
     }
 
     /**
@@ -201,7 +209,7 @@ public class Application.Contact : Geary.BaseObject {
             );
         }
 
-        update_individual(individual);
+        update_from_individual(individual);
         update();
         changed();
 
@@ -309,7 +317,7 @@ public class Application.Contact : Geary.BaseObject {
             Geary.RFC822.MailboxAddress.is_valid_address(name);
     }
 
-    private void update_individual(Folks.Individual? replacement) {
+    private void update_from_individual(Folks.Individual? replacement) {
         if (this.individual != null) {
             this.individual.notify.disconnect(this.on_individual_notify);
             this.individual.removed.disconnect(this.on_individual_removed);
@@ -323,6 +331,12 @@ public class Application.Contact : Geary.BaseObject {
         }
     }
 
+    private void update_from_engine() {
+        Geary.RFC822.MailboxAddress mailbox = this.engine.get_rfc822_address();
+        this._email_addresses = Geary.Collection.single(mailbox);
+        this.load_remote_resources = this.engine.flags.always_load_remote_images();
+    }
+
     private void update() {
         if (this.individual != null) {
             update_name(this.individual.display_name);
@@ -353,7 +367,7 @@ public class Application.Contact : Geary.BaseObject {
             }
         }
 
-        update_individual(replacement);
+        update_from_individual(replacement);
         update();
         changed();
     }
@@ -367,4 +381,8 @@ public class Application.Contact : Geary.BaseObject {
         this.update_replacement.begin(replacement);
     }
 
+    private void on_engine_flags_changed() {
+        update_from_engine();
+    }
+
 }
diff --git a/src/client/conversation-viewer/conversation-message.vala 
b/src/client/conversation-viewer/conversation-message.vala
index dc249191..1ea6e8c8 100644
--- a/src/client/conversation-viewer/conversation-message.vala
+++ b/src/client/conversation-viewer/conversation-message.vala
@@ -338,7 +338,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
     /** Fired when the user clicks a internal link in the email. */
     public signal void internal_link_activated(int y);
 
-    /** Fired when the user requests remote images be loaded. */
+    /** Fired when the email should be flagged for remote image loading. */
     public signal void flag_remote_images();
 
     /** Fired when the user saves an inline displayed image. */
@@ -970,14 +970,14 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
         );
     }
 
-    private void show_images(bool remember) {
+    private void show_images(bool update_email_flag) {
         start_progress_loading();
         this.remote_images_infobar.hide();
         this.load_remote_resources = true;
         this.remote_resources_requested = 0;
         this.remote_resources_loaded = 0;
         this.web_view.load_remote_images();
-        if (remember) {
+        if (update_email_flag) {
             flag_remote_images();
         }
     }
diff --git a/src/engine/api/geary-contact.vala b/src/engine/api/geary-contact.vala
index dfa1c71c..7da8e6ca 100644
--- a/src/engine/api/geary-contact.vala
+++ b/src/engine/api/geary-contact.vala
@@ -60,9 +60,15 @@ public class Geary.Contact : BaseObject {
     }
 
 
+    /** Normalises an email address as for {@link normalized_email}. */
+    public static string normalise_email(string address) {
+        return address.normalize().casefold();
+    }
+
+
     public string normalized_email { get; private set; }
     public string email { get; private set; }
-    public string? real_name { get; private set; }
+    public string? real_name { get; set; }
     public int highest_importance { get; set; }
     public Flags flags { get; set; default = new Flags(); }
 
@@ -70,7 +76,7 @@ public class Geary.Contact : BaseObject {
                    string? real_name,
                    int highest_importance,
                    string? normalized_email = null) {
-        this.normalized_email = normalized_email ?? email.normalize().casefold();
+        this.normalized_email = normalized_email ?? normalise_email(email);
         this.email = email;
         this.real_name = (
             (real_name != email && real_name != normalized_email)
diff --git a/src/engine/common/common-contact-harvester.vala b/src/engine/common/common-contact-harvester.vala
index ec48917d..5fb20646 100644
--- a/src/engine/common/common-contact-harvester.vala
+++ b/src/engine/common/common-contact-harvester.vala
@@ -55,16 +55,28 @@ internal class Geary.ContactHarvesterImpl : BaseObject, ContactHarvester {
             foreach (Email message in messages) {
                 if (message.fields.fulfills(REQUIRED_FIELDS)) {
                     type = Email.Field.ORIGINATORS;
-                    add_contacts(contacts, message.from, type, importance);
+                    yield add_contacts(
+                        contacts, message.from, type, importance, cancellable
+                    );
                     if (message.sender != null) {
-                        add_contact(contacts, message.sender, type, importance);
+                        yield add_contact(
+                            contacts, message.sender, type, importance, cancellable
+                        );
                     }
-                    add_contacts(contacts, message.bcc, type, importance);
+                    yield add_contacts(
+                        contacts, message.bcc, type, importance, cancellable
+                    );
 
                     type = Email.Field.RECEIVERS;
-                    add_contacts(contacts, message.to, type, importance);
-                    add_contacts(contacts, message.cc, type, importance);
-                    add_contacts(contacts, message.bcc, type, importance);
+                    yield add_contacts(
+                        contacts, message.to, type, importance, cancellable
+                    );
+                    yield add_contacts(
+                        contacts, message.cc, type, importance, cancellable
+                    );
+                    yield add_contacts(
+                        contacts, message.bcc, type, importance, cancellable
+                    );
                 }
             }
 
@@ -72,34 +84,56 @@ internal class Geary.ContactHarvesterImpl : BaseObject, ContactHarvester {
         }
     }
 
-    private void add_contacts(Gee.Map<string, Contact> contacts,
-                              RFC822.MailboxAddresses? addresses,
-                              Email.Field type,
-                              int importance) {
+    private async void add_contacts(Gee.Map<string, Contact> contacts,
+                                    RFC822.MailboxAddresses? addresses,
+                                    Email.Field type,
+                                    int importance,
+                                    GLib.Cancellable? cancellable)
+        throws GLib.Error {
         if (addresses != null) {
             foreach (RFC822.MailboxAddress address in addresses) {
-                add_contact(contacts, address, type, importance);
+                yield add_contact(
+                    contacts, address, type, importance, cancellable
+                );
             }
         }
     }
 
-    private inline void add_contact(Gee.Map<string, Contact> contacts,
-                                    RFC822.MailboxAddress address,
-                                    Email.Field type,
-                                    int importance) {
+    private async void add_contact(Gee.Map<string, Contact> contacts,
+                                   RFC822.MailboxAddress address,
+                                   Email.Field type,
+                                   int importance,
+                                   GLib.Cancellable? cancellable)
+        throws GLib.Error {
         if (address.is_valid() && !address.is_spoofed()) {
             if (type == RECEIVERS && address in this.owner_mailboxes) {
                 importance = Contact.Importance.RECEIVED_FROM;
             }
 
-            Contact contact = new Contact.from_rfc822_address(
-                address, importance
-            );
-            Contact? existing = contacts[contact.normalized_email];
-            if (existing == null ||
-                existing.highest_importance < contact.highest_importance) {
+            Contact? contact = contacts[
+                Contact.normalise_email(address.address)
+            ];
+            if (contact == null) {
+                contact = yield this.store.get_by_rfc822(address, cancellable);
+                if (contact == null) {
+                    contact = new Geary.Contact.from_rfc822_address(
+                        address, importance
+                    );
+                }
                 contacts[contact.normalized_email] = contact;
             }
+
+            // Update the contact's name if the current address is at
+            // least equal importance to the existing one so that the
+            // sender's labels are preferred.
+            if (contact.highest_importance <= importance &&
+                !String.is_empty_or_whitespace(address.name)) {
+                contact.real_name = address.name;
+            }
+
+            if (contact.highest_importance < importance) {
+                contact.highest_importance = importance;
+            }
         }
     }
 
diff --git a/src/engine/common/common-contact-store-impl.vala 
b/src/engine/common/common-contact-store-impl.vala
index 1ac675f0..8a3745a3 100644
--- a/src/engine/common/common-contact-store-impl.vala
+++ b/src/engine/common/common-contact-store-impl.vala
@@ -9,14 +9,13 @@
 /**
  * An database-backed implementation of Geary.Contacts
  */
-internal class Geary.ContactStoreImpl : BaseObject, Geary.ContactStore {
+internal class Geary.ContactStoreImpl : ContactStore, BaseObject {
 
 
     private Geary.Db.Database backing;
 
 
     internal ContactStoreImpl(Geary.Db.Database backing) {
-        base_ref();
         this.backing = backing;
     }
 
@@ -158,32 +157,12 @@ internal class Geary.ContactStoreImpl : BaseObject, Geary.ContactStore {
 
             stmt.exec(cancellable);
         } else {
-            // Update existing contact
-
-            // Merge two flags sets together
-            updated.flags.add_all(existing.flags);
-
-            // update remaining fields, careful not to overwrite
-            // non-null real_name with null (but using latest
-            // real_name if supplied) ... email is not updated (it's
-            // how existing was keyed), normalized_email is inserted at
-            // the same time as email, leaving only real_name, flags,
-            // and highest_importance
             Db.Statement stmt = cx.prepare(
                 "UPDATE ContactTable SET real_name=?, flags=?, highest_importance=? WHERE email=?");
-            stmt.bind_string(
-                0, !String.is_empty(updated.real_name) ? updated.real_name : existing.real_name
-            );
-            stmt.bind_string(
-                1, updated.flags.serialize()
-            );
-            stmt.bind_int(
-                2, int.max(updated.highest_importance, existing.highest_importance)
-            );
-            stmt.bind_string(
-                3, updated.email
-            );
-
+            stmt.bind_string(0, updated.real_name);
+            stmt.bind_string(1, updated.flags.serialize());
+            stmt.bind_int(2, updated.highest_importance);
+            stmt.bind_string(3, updated.email);
             stmt.exec(cancellable);
         }
     }
diff --git a/test/engine/common/common-contact-harvester-test.vala 
b/test/engine/common/common-contact-harvester-test.vala
index 9db3f947..02bc73d0 100644
--- a/test/engine/common/common-contact-harvester-test.vala
+++ b/test/engine/common/common-contact-harvester-test.vala
@@ -57,7 +57,8 @@ class Geary.ContactHarvesterImplTest : TestCase {
             SpecialFolderType.INBOX,
             this.senders
         );
-        ExpectedCall call = this.store.expect_call("update_contacts");
+        this.store.expect_call("get_by_rfc822");
+        ExpectedCall update_call = this.store.expect_call("update_contacts");
         this.email.set_receivers(
             new RFC822.MailboxAddresses.single(this.test_address), null, null
         );
@@ -70,7 +71,7 @@ class Geary.ContactHarvesterImplTest : TestCase {
 
         this.store.assert_expectations();
 
-        Gee.Collection<Contact> contacts = call.called_arg<Gee.Collection<Contact>>(0);
+        Gee.Collection<Contact> contacts = update_call.called_arg<Gee.Collection<Contact>>(0);
         assert_int(1, contacts.size, "contacts length");
         Contact? created = Collection.get_first<Contact>(contacts) as Contact;
         assert_non_null(created, "contacts contents");
@@ -105,7 +106,8 @@ class Geary.ContactHarvesterImplTest : TestCase {
             SpecialFolderType.INBOX,
             this.senders
         );
-        ExpectedCall call = this.store.expect_call("update_contacts");
+        this.store.expect_call("get_by_rfc822");
+        ExpectedCall update_call = this.store.expect_call("update_contacts");
         this.email.set_receivers(
             new RFC822.MailboxAddresses.single(this.test_address), null, null
         );
@@ -118,7 +120,7 @@ class Geary.ContactHarvesterImplTest : TestCase {
 
         this.store.assert_expectations();
 
-        Gee.Collection<Contact> contacts = call.called_arg<Gee.Collection<Contact>>(0);
+        Gee.Collection<Contact> contacts = update_call.called_arg<Gee.Collection<Contact>>(0);
         Contact? created = Collection.get_first<Contact>(contacts) as Contact;
         assert_int(
             Contact.Importance.SEEN,
@@ -133,7 +135,8 @@ class Geary.ContactHarvesterImplTest : TestCase {
             SpecialFolderType.SENT,
             this.senders
         );
-        ExpectedCall call = this.store.expect_call("update_contacts");
+        this.store.expect_call("get_by_rfc822");
+        ExpectedCall update_call = this.store.expect_call("update_contacts");
         this.email.set_receivers(
             new RFC822.MailboxAddresses.single(this.test_address), null, null
         );
@@ -146,7 +149,7 @@ class Geary.ContactHarvesterImplTest : TestCase {
 
         this.store.assert_expectations();
 
-        Gee.Collection<Contact> contacts = call.called_arg<Gee.Collection<Contact>>(0);
+        Gee.Collection<Contact> contacts = update_call.called_arg<Gee.Collection<Contact>>(0);
         Contact? created = Collection.get_first<Contact>(contacts) as Contact;
         assert_int(
             Contact.Importance.SENT_TO,
@@ -161,7 +164,8 @@ class Geary.ContactHarvesterImplTest : TestCase {
             SpecialFolderType.SENT,
             this.senders
         );
-        ExpectedCall call = this.store.expect_call("update_contacts");
+        this.store.expect_call("get_by_rfc822");
+        ExpectedCall update_call = this.store.expect_call("update_contacts");
         this.email.set_receivers(
             new RFC822.MailboxAddresses.single(this.sender_address), null, null
         );
@@ -174,7 +178,7 @@ class Geary.ContactHarvesterImplTest : TestCase {
 
         this.store.assert_expectations();
 
-        Gee.Collection<Contact> contacts = call.called_arg<Gee.Collection<Contact>>(0);
+        Gee.Collection<Contact> contacts = update_call.called_arg<Gee.Collection<Contact>>(0);
         Contact? created = Collection.get_first<Contact>(contacts) as Contact;
         assert_int(
             Contact.Importance.RECEIVED_FROM,
diff --git a/test/engine/common/common-contact-store-impl-test.vala 
b/test/engine/common/common-contact-store-impl-test.vala
index b0a323ae..3974c00f 100644
--- a/test/engine/common/common-contact-store-impl-test.vala
+++ b/test/engine/common/common-contact-store-impl-test.vala
@@ -269,7 +269,23 @@ class Geary.ContactStoreImplTest : TestCase {
         assert_string("test example com", updated.normalized_email, "Updated normalized_email");
         assert_string("Updated", updated.real_name, "Updated real_name");
         assert_int(100, updated.highest_importance, "Updated highest_importance");
-        assert_true(updated.flags.always_load_remote_images(), "Updated real_name");
+        assert_true(updated.flags.always_load_remote_images(), "Added flags");
+
+        // Now try removing the flag and ensure it sticks
+        not_updated.flags.remove(Contact.Flags.ALWAYS_LOAD_REMOTE_IMAGES);
+        test_article.update_contacts.begin(
+            Collection.single(not_updated),
+            null,
+            (obj, ret) => { async_complete(ret); }
+        );
+        test_article.update_contacts.end(async_result());
+        test_article.get_by_rfc822.begin(
+            new RFC822.MailboxAddress(null, "Test example com"),
+            null,
+            (obj, ret) => { async_complete(ret); }
+        );
+        Contact? updated_again = test_article.get_by_rfc822.end(async_result());
+        assert_false(updated_again.flags.always_load_remote_images(), "Removed flags");
     }
 
 }


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