Don't set Individual.is-favourite when updating from Personas
[platform/upstream/folks.git] / folks / individual.vala
index 9ef912e..d20bc3d 100644 (file)
@@ -25,7 +25,7 @@ using Folks;
 /**
  * Trust level for an {@link Individual} for use in the UI.
  *
- * @since 0.1.16
+ * @since 0.1.15
  */
 public enum Folks.TrustLevel
 {
@@ -40,7 +40,7 @@ public enum Folks.TrustLevel
    * {@link Persona} would have this trust level, since someone else could
    * easily spoof the link-local XMPP {@link Persona}'s identity.
    *
-   * @since 0.1.16
+   * @since 0.1.15
    */
   NONE,
 
@@ -54,7 +54,7 @@ public enum Folks.TrustLevel
    * Note that this doesn't guarantee that the user who behind each
    * {@link Persona} is who they claim to be.
    *
-   * @since 0.1.16
+   * @since 0.1.15
    */
   PERSONAS
 }
@@ -95,7 +95,7 @@ public class Folks.Individual : Object,
    * Clients should ''not'' allow linking of Individuals who have a trust level
    * of {@link TrustLevel.NONE}.
    *
-   * @since 0.1.16
+   * @since 0.1.15
    */
   public TrustLevel trust_level { get; private set; }
 
@@ -149,11 +149,28 @@ public class Folks.Individual : Object,
             return;
 
           this._alias = value;
+
+          /* First, try to write it to only the writeable Personas… */
+          bool alias_changed = false;
           this._persona_list.foreach ((p) =>
             {
               if (p is Alias && ((Persona) p).store.is_writeable == true)
-                ((Alias) p).alias = value;
+                {
+                  ((Alias) p).alias = value;
+                  alias_changed = true;
+                }
             });
+
+          /* â€¦but if there are no writeable Personas, we have to fall back to
+           * writing it to every Persona. */
+          if (alias_changed == false)
+            {
+              this._persona_list.foreach ((p) =>
+                {
+                  if (p is Alias)
+                    ((Alias) p).alias = value;
+                });
+            }
         }
     }
 
@@ -172,11 +189,20 @@ public class Folks.Individual : Object,
           if (this._is_favourite == value)
             return;
 
+          debug ("Setting '%s' favourite status to %s", this.id,
+              value ? "TRUE" : "FALSE");
+
           this._is_favourite = value;
           this._persona_list.foreach ((p) =>
             {
-              if (p is Favourite && ((Persona) p).store.is_writeable == true)
-                ((Favourite) p).is_favourite = value;
+              if (p is Favourite)
+                {
+                  SignalHandler.block_by_func (p,
+                      (void*) this.notify_is_favourite_cb, this);
+                  ((Favourite) p).is_favourite = value;
+                  SignalHandler.unblock_by_func (p,
+                      (void*) this.notify_is_favourite_cb, this);
+                }
             });
         }
     }
@@ -190,6 +216,7 @@ public class Folks.Individual : Object,
 
       set
         {
+          this._groups = value;
           this._persona_list.foreach ((p) =>
             {
               if (p is Groups && ((Persona) p).store.is_writeable == true)
@@ -223,16 +250,11 @@ public class Folks.Individual : Object,
    * @param added a list of {@link Persona}s which have been added
    * @param removed a list of {@link Persona}s which have been removed
    *
-   * @since 0.1.16
+   * @since 0.1.15
    */
   public signal void personas_changed (GLib.List<Persona>? added,
       GLib.List<Persona>? removed);
 
-  private void notify_groups_cb (Object obj, ParamSpec ps)
-    {
-      this.update_groups ();
-    }
-
   private void notify_alias_cb (Object obj, ParamSpec ps)
     {
       this.update_alias ();
@@ -245,7 +267,6 @@ public class Folks.Individual : Object,
 
   private void persona_group_changed_cb (string group, bool is_member)
     {
-      this.change_group.begin (group, is_member);
       this.update_groups ();
     }
 
@@ -316,7 +337,7 @@ public class Folks.Individual : Object,
         this.personas_changed (null, removed_personas);
 
       if (store != null)
-        this.stores.remove (store);
+        this.stores.unset (store);
 
       if (this._persona_set.size < 1)
         {
@@ -462,6 +483,8 @@ public class Folks.Individual : Object,
     {
       bool favourite = false;
 
+      debug ("Running update_is_favourite() on '%s'", this.id);
+
       this._persona_list.foreach ((p) =>
         {
           if (favourite == false && p is Favourite)
@@ -472,9 +495,14 @@ public class Folks.Individual : Object,
             }
         });
 
-      /* Only notify if the value has changed */
-      if (this.is_favourite != favourite)
-        this.is_favourite = favourite;
+      /* Only notify if the value has changed. We have to set the private member
+       * and notify manually, or we'd end up propagating the new favourite
+       * status back down to all our Personas. */
+      if (this._is_favourite != favourite)
+        {
+          this._is_favourite = favourite;
+          this.notify_property ("is-favourite");
+        }
     }
 
   private void update_alias ()
@@ -482,44 +510,75 @@ public class Folks.Individual : Object,
       string alias = null;
       bool alias_is_display_id = false;
 
+      /* Search for an alias from a writeable Persona, and use it as our first
+       * choice if it's non-empty, since that's where the user-set alias is
+       * stored. */
       foreach (Persona p in this._persona_list)
         {
-          if (p is Alias)
+          if (p is Alias && p.store.is_writeable == true)
             {
               unowned Alias a = (Alias) p;
 
-              if (a.alias == null || a.alias.strip () == "")
-                continue;
-
-              if (alias == null || alias_is_display_id == true)
+              if (a.alias != null && a.alias.strip () != "")
                 {
-                  /* We prefer to not have an alias which is the same as the
-                   * Persona's display-id, since having such an alias implies
-                   * that it's the default. However, we prefer using such an
-                   * alias to using the Persona's UID, which is our ultimate
-                   * fallback (below). */
                   alias = a.alias;
+                  break;
+                }
+            }
+        }
 
-                  if (a.alias == p.display_id)
-                    alias_is_display_id = true;
-                  else if (alias != null)
-                    break;
+      /* Since we can't find a non-empty alias from a writeable backend, try
+       * the aliases from other personas. Use a non-empty alias which isn't
+       * equal to the persona's display ID as our preference. If we can't find
+       * one of those, fall back to one which is equal to the display ID. */
+      if (alias == null)
+        {
+          foreach (Persona p in this._persona_list)
+            {
+              if (p is Alias)
+                {
+                  unowned Alias a = (Alias) p;
+
+                  if (a.alias == null || a.alias.strip () == "")
+                    continue;
+
+                  if (alias == null || alias_is_display_id == true)
+                    {
+                      /* We prefer to not have an alias which is the same as the
+                       * Persona's display-id, since having such an alias
+                       * implies that it's the default. However, we prefer using
+                       * such an alias to using the Persona's UID, which is our
+                       * ultimate fallback (below). */
+                      alias = a.alias;
+
+                      if (a.alias == p.display_id)
+                        alias_is_display_id = true;
+                      else if (alias != null)
+                        break;
+                    }
                 }
             }
         }
 
       if (alias == null)
         {
-          /* We have to pick a UID, since none of the personas have an alias
-           * available. Pick the UID from the first persona in the list. */
-          alias = this._persona_list.data.uid;
-          debug ("No aliases available for individual; using UID instead: %s",
-                   alias);
+          /* We have to pick a display ID, since none of the personas have an
+           * alias available. Pick the display ID from the first persona in the
+           * list. */
+          alias = this._persona_list.data.display_id;
+          debug ("No aliases available for individual; using display ID " +
+              "instead: %s", alias);
         }
 
-      /* only notify if the value has changed */
-      if (this.alias != alias)
-        this.alias = alias;
+      /* Only notify if the value has changed. We have to set the private member
+       * and notify manually, or we'd end up propagating the new alias back
+       * down to all our Personas, even if it's a fallback display ID or
+       * something else undesirable. */
+      if (this._alias != alias)
+        {
+          this._alias = alias;
+          this.notify_property ("alias");
+        }
     }
 
   private void update_avatar ()
@@ -641,7 +700,6 @@ public class Folks.Individual : Object,
       persona.notify["presence-message"].connect (this.notify_presence_cb);
       persona.notify["presence-type"].connect (this.notify_presence_cb);
       persona.notify["is-favourite"].connect (this.notify_is_favourite_cb);
-      persona.notify["groups"].connect (this.notify_groups_cb);
 
       if (persona is Groups)
         {
@@ -659,7 +717,6 @@ public class Folks.Individual : Object,
       persona.notify["presence-type"].disconnect (this.notify_presence_cb);
       persona.notify["is-favourite"].disconnect (
           this.notify_is_favourite_cb);
-      persona.notify["groups"].disconnect (this.notify_groups_cb);
 
       if (persona is Groups)
         {