summaryrefslogtreecommitdiff
path: root/src/contacts-avatar.vala
blob: 6ab3bb44a01e906a6db96d024879f2e251abf579 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/*
 * Copyright (C) 2011 Alexander Larsson <alexl@redhat.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

using Folks;

/**
 * The Avatar of a Contact is responsible for showing an {@link Folks.Individual}'s
 * avatar, or a fallback if it's not available.
 */
public class Contacts.Avatar : Adw.Bin {

  private unowned Individual? _individual = null;
  public Individual? individual {
    get { return this._individual; }
    set {
      if (this._individual == value)
        return;

      this._individual = value;
      update_individual ();
    }
  }

  private unowned Contact? _contact = null;
  public Contact? contact {
    get { return this._contact; }
    set {
      if (this._contact == value)
        return;

      this._contact = value;
      update_contact ();
    }
  }

  public int avatar_size { get; set; default = 48; }

  construct {
    this.child = new Adw.Avatar (this.avatar_size, "", false);
    bind_property ("avatar-size", this.child, "size", BindingFlags.DEFAULT);
  }

  public Avatar (int size, Individual? individual = null) {
    Object (avatar_size: size, individual: individual);
  }

  public Avatar.for_contact (int size, Contact contact) {
    Object (avatar_size: size, contact: contact);
  }

  private void update_individual () {
    if (this.contact != null)
      return;

    string name = "";
    bool show_initials = false;
    if (this.individual != null) {
      name = find_display_name ();
      // If we don't have a usable name use the display_name
      // to generate the color but don't show any label
      if (name == "") {
        name = this.individual.display_name;
      } else {
        show_initials = true;
      }
    }

    ((Adw.Avatar) this.child).show_initials = show_initials;
    ((Adw.Avatar) this.child).text = name;

    var icon = (this.individual != null)? this.individual.avatar : null;
    this.load_avatar.begin (icon);
  }

  private void update_contact () {
    if (this.individual != null)
      return;

    string name = "";
    bool show_initials = false;
    if (this.contact != null) {
      name = this.contact.fetch_name ();
      // If we don't have a usable name use the display_name
      // to generate the color but don't show any label
      if (name == null)
        name = this.contact.fetch_display_name ();
      else
        show_initials = true;
    }

    ((Adw.Avatar) this.child).show_initials = show_initials;
    ((Adw.Avatar) this.child).text = name;

    var chunk = this.contact.get_most_relevant_chunk ("avatar", true);
    if (chunk == null)
      chunk = this.contact.create_chunk ("avatar", null);
    unowned var avatar_chunk = (AvatarChunk) chunk;
    avatar_chunk.notify["avatar"].connect ((obj, pspec) => {
      this.load_avatar.begin (avatar_chunk.avatar);
    });
    this.load_avatar.begin (avatar_chunk.avatar);
  }

  private async void load_avatar (LoadableIcon? icon) {
    if (icon == null) {
      set_pixbuf (null);
      return;
    }

    try {
      var stream = yield icon.load_async (this.avatar_size, null);
      var pixbuf = yield new Gdk.Pixbuf.from_stream_at_scale_async (stream,
                                                                    this.avatar_size,
                                                                    this.avatar_size,
                                                                    true);
      this.set_pixbuf (pixbuf);
    } catch (Error e) {
      warning ("Couldn't load avatar of '%s': %s", this.individual.display_name, e.message);
    }
  }

  /**
   * Manually set the avatar to the given pixbuf, even if the contact has an avatar.
   */
  public void set_pixbuf (Gdk.Pixbuf? a_pixbuf) {
    var img = (a_pixbuf != null)? Gdk.Texture.for_pixbuf (a_pixbuf) : null;
    ((Adw.Avatar) this.child).set_custom_image (img);
  }

  /* Find a nice name to generate the label and color for the fallback avatar
   * This code is mostly copied from folks, but folks also tries email and phone number
   * as a display name which we don't want to have as a label
   */
  private string find_display_name () {
    unowned Persona primary_persona = null;
    foreach (var p in this.individual.personas) {
      if (p.store.is_primary_store) {
        primary_persona = p;
        break;
      }
    }

    unowned string alias = look_up_alias_for_display_name (primary_persona);
    if (alias != "")
      return alias;

    foreach (var p in this.individual.personas) {
      alias = look_up_alias_for_display_name (p);
      if (alias != "")
        return alias;
    }

    foreach (var p in this.individual.personas) {
      string name = look_up_name_details_for_display_name (p);
      if (name != "")
        return name;
    }
    return "";
  }

  private unowned string look_up_alias_for_display_name (Persona? p) {
    unowned var a = p as AliasDetails;
    if (a != null && a.alias != null)
      return a.alias;

    return "";
  }

  private string look_up_name_details_for_display_name (Persona? p) {
    unowned var n = p as NameDetails;
    if (n != null) {
      if (n.full_name != null && n.full_name != "")
        return n.full_name;
      else if (n.structured_name != null)
        return n.structured_name.to_string ();
      else if (n.nickname != "")
        return n.nickname;
    }

    return "";
  }
}