Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-3.0-or-later
2 : : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
3 : :
4 : : #define G_LOG_DOMAIN "valent-message-row"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <adwaita.h>
9 : : #include <glib/gi18n.h>
10 : : #include <gtk/gtk.h>
11 : : #include <libebook-contacts/libebook-contacts.h>
12 : : #include <valent.h>
13 : :
14 : : #include "valent-date-label.h"
15 : : #include "valent-ui-utils-private.h"
16 : :
17 : : #include "valent-message-row.h"
18 : :
19 : : struct _ValentMessageRow
20 : : {
21 : : GtkListBoxRow parent_instance;
22 : :
23 : : ValentMessage *message;
24 : : EContact *contact;
25 : :
26 : : /* template */
27 : : GtkWidget *avatar;
28 : : GtkWidget *date_label;
29 : : GtkWidget *title_label;
30 : : GtkWidget *subtitle_label;
31 : : };
32 : :
33 [ + + + - ]: 17 : G_DEFINE_FINAL_TYPE (ValentMessageRow, valent_message_row, GTK_TYPE_LIST_BOX_ROW)
34 : :
35 : : typedef enum {
36 : : PROP_CONTACT = 1,
37 : : PROP_MESSAGE,
38 : : } ValentMessageRowProperty;
39 : :
40 : : static GParamSpec *properties[PROP_MESSAGE + 1] = { NULL, };
41 : :
42 : : static char *
43 : 4 : _valent_message_get_excerpt (ValentMessageRow *self,
44 : : ValentMessage *message)
45 : : {
46 : 4 : const char *body = NULL;
47 : :
48 [ + + ]: 4 : if (message != NULL)
49 : 2 : body = valent_message_get_text (message);
50 : :
51 [ + - + - ]: 2 : if (body != NULL && *body != '\0')
52 : : {
53 : 4 : g_auto (GStrv) parts = g_strsplit (body, "\n", 2);
54 : :
55 [ + + ]: 2 : if (valent_message_get_box (message) == VALENT_MESSAGE_BOX_SENT)
56 : 1 : return g_strdup_printf (_("You: %s"), parts[0]);
57 : :
58 [ - + ]: 2 : return g_strdup (parts[0]);
59 : : }
60 : :
61 [ - + ]: 2 : return g_strdup (body);
62 : : }
63 : :
64 : : static void
65 : 4 : valent_message_row_sync (ValentMessageRow *row)
66 : : {
67 [ + - ]: 4 : g_assert (VALENT_IS_MESSAGE_ROW (row));
68 : :
69 [ + + - + ]: 4 : if (row->message != NULL && !valent_message_get_read (row->message))
70 : : {
71 : 0 : gtk_widget_add_css_class (row->title_label, "unread");
72 : 0 : gtk_widget_add_css_class (row->subtitle_label, "unread");
73 : : }
74 : : else
75 : : {
76 : 4 : gtk_widget_remove_css_class (row->title_label, "unread");
77 : 4 : gtk_widget_remove_css_class (row->subtitle_label, "unread");
78 : : }
79 : 4 : }
80 : :
81 : : /*
82 : : * GObject
83 : : */
84 : : static void
85 : 2 : valent_message_row_finalize (GObject *object)
86 : : {
87 : 2 : ValentMessageRow *self = VALENT_MESSAGE_ROW (object);
88 : :
89 [ + - ]: 2 : g_clear_object (&self->contact);
90 [ + - ]: 2 : g_clear_object (&self->message);
91 : :
92 : 2 : G_OBJECT_CLASS (valent_message_row_parent_class)->finalize (object);
93 : 2 : }
94 : :
95 : : static void
96 : 34 : valent_message_row_get_property (GObject *object,
97 : : guint prop_id,
98 : : GValue *value,
99 : : GParamSpec *pspec)
100 : : {
101 : 34 : ValentMessageRow *self = VALENT_MESSAGE_ROW (object);
102 : :
103 [ + + - ]: 34 : switch ((ValentMessageRowProperty)prop_id)
104 : : {
105 : 21 : case PROP_CONTACT:
106 : 21 : g_value_set_object (value, self->contact);
107 : 21 : break;
108 : :
109 : 13 : case PROP_MESSAGE:
110 : 13 : g_value_set_object (value, self->message);
111 : 13 : break;
112 : :
113 : 0 : default:
114 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
115 : : }
116 : 34 : }
117 : :
118 : : static void
119 : 4 : valent_message_row_set_property (GObject *object,
120 : : guint prop_id,
121 : : const GValue *value,
122 : : GParamSpec *pspec)
123 : : {
124 : 4 : ValentMessageRow *self = VALENT_MESSAGE_ROW (object);
125 : :
126 [ + + - ]: 4 : switch ((ValentMessageRowProperty)prop_id)
127 : : {
128 : 2 : case PROP_CONTACT:
129 : 2 : valent_message_row_set_contact (self, g_value_get_object (value));
130 : 2 : break;
131 : :
132 : 2 : case PROP_MESSAGE:
133 : 2 : valent_message_row_set_message (self, g_value_get_object (value));
134 : 2 : break;
135 : :
136 : 0 : default:
137 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
138 : : }
139 : 4 : }
140 : :
141 : : static void
142 : 2 : valent_message_row_class_init (ValentMessageRowClass *klass)
143 : : {
144 : 2 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
145 : 2 : GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
146 : :
147 : 2 : object_class->finalize = valent_message_row_finalize;
148 : 2 : object_class->get_property = valent_message_row_get_property;
149 : 2 : object_class->set_property = valent_message_row_set_property;
150 : :
151 : 2 : gtk_widget_class_set_template_from_resource (widget_class, "/plugins/gnome/valent-message-row.ui");
152 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentMessageRow, avatar);
153 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentMessageRow, title_label);
154 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentMessageRow, subtitle_label);
155 : 2 : gtk_widget_class_bind_template_child (widget_class, ValentMessageRow, date_label);
156 : 2 : gtk_widget_class_bind_template_callback (widget_class, _valent_message_get_excerpt);
157 : 2 : gtk_widget_class_bind_template_callback (widget_class, valent_contact_to_paintable);
158 : :
159 : : /**
160 : : * ValentMessageRow:contact:
161 : : *
162 : : * The `EContact` that sent this message.
163 : : */
164 : 4 : properties [PROP_CONTACT] =
165 : 2 : g_param_spec_object ("contact", NULL, NULL,
166 : : E_TYPE_CONTACT,
167 : : (G_PARAM_READWRITE |
168 : : G_PARAM_CONSTRUCT |
169 : : G_PARAM_EXPLICIT_NOTIFY |
170 : : G_PARAM_STATIC_STRINGS));
171 : :
172 : : /**
173 : : * ValentMessageRow:message:
174 : : *
175 : : * The message this row displays.
176 : : */
177 : 4 : properties [PROP_MESSAGE] =
178 : 2 : g_param_spec_object ("message", NULL, NULL,
179 : : VALENT_TYPE_MESSAGE,
180 : : (G_PARAM_READWRITE |
181 : : G_PARAM_CONSTRUCT |
182 : : G_PARAM_EXPLICIT_NOTIFY |
183 : : G_PARAM_STATIC_STRINGS));
184 : :
185 : 2 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
186 : :
187 : 2 : g_type_ensure (VALENT_TYPE_DATE_LABEL);
188 : 2 : }
189 : :
190 : : static void
191 : 2 : valent_message_row_init (ValentMessageRow *self)
192 : : {
193 : 2 : gtk_widget_init_template (GTK_WIDGET (self));
194 : 2 : }
195 : :
196 : : /**
197 : : * valent_message_row_new:
198 : : * @message: (nullable): a `ValentMessage`
199 : : * @contact: (nullable): a `EContact`
200 : : *
201 : : * Create a new message row for @contact and @message.
202 : : *
203 : : * Returns: a `ValentMessageRow`
204 : : */
205 : : GtkWidget *
206 : 1 : valent_message_row_new (ValentMessage *message,
207 : : EContact *contact)
208 : : {
209 : 1 : return g_object_new (VALENT_TYPE_MESSAGE_ROW,
210 : : "contact", contact,
211 : : "message", message,
212 : : NULL);
213 : : }
214 : :
215 : : /**
216 : : * valent_message_row_get_contact:
217 : : * @row: a `ValentMessageRow`
218 : : *
219 : : * Get the contact.
220 : : *
221 : : * Returns: (transfer none) (nullable): a `ValentContact`
222 : : */
223 : : EContact *
224 : 1 : valent_message_row_get_contact (ValentMessageRow *row)
225 : : {
226 [ + - ]: 1 : g_return_val_if_fail (VALENT_IS_MESSAGE_ROW (row), NULL);
227 : :
228 : 1 : return row->contact;
229 : : }
230 : :
231 : : /**
232 : : * valent_message_row_set_contact:
233 : : * @row: a `ValentMessageRow`
234 : : * @contact: a `ValentContact`
235 : : *
236 : : * Set or update the contact.
237 : : */
238 : : void
239 : 3 : valent_message_row_set_contact (ValentMessageRow *row,
240 : : EContact *contact)
241 : : {
242 [ + - ]: 3 : g_return_if_fail (VALENT_IS_MESSAGE_ROW (row));
243 [ + + + - : 3 : g_return_if_fail (contact == NULL || E_IS_CONTACT (contact));
- + - - ]
244 : :
245 [ + + ]: 3 : if (g_set_object (&row->contact, contact))
246 : : {
247 : 2 : valent_message_row_sync (row);
248 : 2 : g_object_notify_by_pspec (G_OBJECT (row), properties [PROP_CONTACT]);
249 : : }
250 : : }
251 : :
252 : : /**
253 : : * valent_message_row_get_message:
254 : : * @row: a `ValentMessageRow`
255 : : *
256 : : * Get the message.
257 : : *
258 : : * Returns: (transfer none): a `ValentMessage`
259 : : */
260 : : ValentMessage *
261 : 1 : valent_message_row_get_message (ValentMessageRow *row)
262 : : {
263 [ + - ]: 1 : g_return_val_if_fail (VALENT_IS_MESSAGE_ROW (row), NULL);
264 : :
265 : 1 : return row->message;
266 : : }
267 : :
268 : : /**
269 : : * valent_message_row_set_message:
270 : : * @row: a `ValentMessageRow`
271 : : * @message: a `ValentMessage`
272 : : *
273 : : * Set or update the message.
274 : : */
275 : : void
276 : 2 : valent_message_row_set_message (ValentMessageRow *row,
277 : : ValentMessage *message)
278 : : {
279 [ + - ]: 2 : g_return_if_fail (VALENT_IS_MESSAGE_ROW (row));
280 [ + - - + ]: 2 : g_return_if_fail (message == NULL || VALENT_IS_MESSAGE (message));
281 : :
282 [ + - ]: 2 : if (row->message == message)
283 : : return;
284 : :
285 [ - + ]: 2 : if (row->message != NULL)
286 : : {
287 : 0 : g_signal_handlers_disconnect_by_func (row->message,
288 : : valent_message_row_sync,
289 : : row);
290 [ # # ]: 0 : g_clear_object (&row->message);
291 : : }
292 : :
293 [ + - ]: 2 : if (message != NULL)
294 : : {
295 : 2 : row->message = g_object_ref (message);
296 : 2 : g_signal_connect_object (row->message,
297 : : "notify::read",
298 : : G_CALLBACK (valent_message_row_sync),
299 : : row,
300 : : G_CONNECT_SWAPPED);
301 : : }
302 : :
303 : 2 : valent_message_row_sync (row);
304 : 2 : g_object_notify_by_pspec (G_OBJECT (row), properties [PROP_MESSAGE]);
305 : : }
306 : :
|