LCOV - code coverage report
Current view: top level - src/plugins/sms - valent-sms-window.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 58.1 % 363 211
Test Date: 2024-04-23 06:02:46 Functions: 68.4 % 38 26
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 32.7 % 150 49

             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-sms-window"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #include <glib/gi18n.h>
       9                 :             : #include <gtk/gtk.h>
      10                 :             : #include <adwaita.h>
      11                 :             : #include <valent.h>
      12                 :             : 
      13                 :             : #include "valent-contact-row.h"
      14                 :             : #include "valent-message.h"
      15                 :             : #include "valent-sms-conversation.h"
      16                 :             : #include "valent-sms-store.h"
      17                 :             : #include "valent-sms-utils.h"
      18                 :             : #include "valent-sms-window.h"
      19                 :             : #include "valent-message-row.h"
      20                 :             : 
      21                 :             : 
      22                 :             : struct _ValentSmsWindow
      23                 :             : {
      24                 :             :   AdwApplicationWindow    parent_instance;
      25                 :             : 
      26                 :             :   ValentContactStore     *contact_store;
      27                 :             :   ValentSmsStore         *message_store;
      28                 :             : 
      29                 :             :   /* template */
      30                 :             :   AdwNavigationSplitView *content_box;
      31                 :             :   AdwHeaderBar           *content_header;
      32                 :             :   AdwHeaderBar           *sidebar_header;
      33                 :             : 
      34                 :             :   AdwNavigationPage      *content_page;
      35                 :             :   GtkBox                 *content_layout;
      36                 :             :   GtkListBox             *conversation_list;
      37                 :             :   GtkStack               *content;
      38                 :             : 
      39                 :             :   GtkWidget              *message_search;
      40                 :             :   GtkWidget              *message_search_entry;
      41                 :             :   GtkListBox             *message_search_list;
      42                 :             : 
      43                 :             :   GtkWidget              *contact_search;
      44                 :             :   GtkWidget              *contact_search_entry;
      45                 :             :   GtkListBox             *contact_search_list;
      46                 :             :   GtkWidget              *placeholder_contact;
      47                 :             : };
      48                 :             : 
      49   [ +  +  +  - ]:          18 : G_DEFINE_FINAL_TYPE (ValentSmsWindow, valent_sms_window, ADW_TYPE_APPLICATION_WINDOW)
      50                 :             : 
      51                 :             : enum {
      52                 :             :   PROP_0,
      53                 :             :   PROP_CONTACT_STORE,
      54                 :             :   PROP_MESSAGE_STORE,
      55                 :             :   N_PROPERTIES
      56                 :             : };
      57                 :             : 
      58                 :             : static GParamSpec *properties[N_PROPERTIES] = { NULL, };
      59                 :             : 
      60                 :             : enum {
      61                 :             :   SEND_MESSAGE,
      62                 :             :   N_SIGNALS
      63                 :             : };
      64                 :             : 
      65                 :             : static guint signals[N_SIGNALS] = { 0, };
      66                 :             : 
      67                 :             : 
      68                 :             : /*
      69                 :             :  * Generic callback for querying a contact for a widget
      70                 :             :  */
      71                 :             : static void
      72                 :           2 : phone_lookup_cb (ValentContactStore *store,
      73                 :             :                  GAsyncResult       *result,
      74                 :             :                  ValentMessageRow   *row)
      75                 :             : {
      76                 :           4 :   g_autoptr (GError) error = NULL;
      77         [ -  + ]:           2 :   g_autoptr (EContact) contact = NULL;
      78                 :             : 
      79                 :           2 :   contact = valent_sms_contact_from_phone_finish (store, result, &error);
      80                 :             : 
      81         [ -  + ]:           2 :   if (contact == NULL)
      82                 :           0 :       g_warning ("%s(): %s", G_STRFUNC, error->message);
      83                 :             : 
      84         [ +  - ]:           2 :   valent_message_row_set_contact (row, contact);
      85                 :           2 : }
      86                 :             : 
      87                 :             : static void
      88                 :           0 : search_contacts_cb (ValentContactStore *model,
      89                 :             :                     GAsyncResult       *result,
      90                 :             :                     ValentSmsWindow    *window)
      91                 :             : {
      92                 :           0 :   g_autoptr (GError) error = NULL;
      93         [ #  # ]:           0 :   g_autoslist (GObject) contacts = NULL;
      94                 :             : 
      95                 :           0 :   contacts = valent_contact_store_query_finish (model, result, &error);
      96                 :             : 
      97         [ #  # ]:           0 :   for (const GSList *iter = contacts; iter; iter = iter->next)
      98                 :           0 :     valent_list_add_contact (window->contact_search_list, iter->data);
      99                 :             : 
     100         [ #  # ]:           0 :   if (error != NULL)
     101                 :           0 :     g_warning ("%s(): %s", G_STRFUNC, error->message);
     102                 :           0 : }
     103                 :             : 
     104                 :             : static void
     105                 :           0 : search_messages_cb (ValentSmsStore  *store,
     106                 :             :                     GAsyncResult    *result,
     107                 :             :                     ValentSmsWindow *window)
     108                 :             : {
     109                 :           0 :   g_autoptr (GError) error = NULL;
     110         [ #  # ]:           0 :   g_autoptr (GPtrArray) messages = NULL;
     111                 :             : 
     112                 :           0 :   messages = valent_sms_store_find_messages_finish (store, result, &error);
     113                 :             : 
     114         [ #  # ]:           0 :   for (unsigned int i = 0; i < messages->len; i++)
     115                 :             :     {
     116                 :           0 :       ValentMessage *message;
     117                 :           0 :       GtkWidget *row;
     118                 :           0 :       const char *address;
     119                 :             : 
     120                 :           0 :       message = g_ptr_array_index (messages, i);
     121                 :             : 
     122                 :           0 :       row = g_object_new (VALENT_TYPE_MESSAGE_ROW,
     123                 :             :                           "message", message,
     124                 :             :                           NULL);
     125                 :           0 :       gtk_list_box_insert (window->message_search_list, row, -1);
     126                 :             : 
     127         [ #  # ]:           0 :       if ((address = valent_message_get_sender (message)) == NULL)
     128                 :             :         {
     129                 :           0 :           GVariant *metadata;
     130                 :           0 :           g_autoptr (GVariant) addresses = NULL;
     131   [ #  #  #  # ]:           0 :           g_autoptr (GVariant) address_dict = NULL;
     132                 :             : 
     133                 :           0 :           metadata = valent_message_get_metadata (message);
     134                 :             : 
     135         [ #  # ]:           0 :           if (!g_variant_lookup (metadata, "addresses", "@aa{sv}", &addresses))
     136                 :           0 :             continue;
     137                 :             : 
     138         [ #  # ]:           0 :           if (g_variant_n_children (addresses) == 0)
     139                 :           0 :             continue;
     140                 :             : 
     141                 :           0 :           address_dict = g_variant_get_child_value (addresses, 0);
     142                 :             : 
     143         [ #  # ]:           0 :           if (!g_variant_lookup (address_dict, "address", "&s", &address))
     144         [ #  # ]:           0 :             continue;
     145                 :             :         }
     146                 :             : 
     147                 :           0 :       valent_sms_contact_from_phone (window->contact_store,
     148                 :             :                                      address,
     149                 :             :                                      NULL,
     150                 :             :                                      (GAsyncReadyCallback)phone_lookup_cb,
     151                 :             :                                      row);
     152                 :             :     }
     153                 :           0 : }
     154                 :             : 
     155                 :             : /*
     156                 :             :  * Reset search pages in a timeout source
     157                 :             :  */
     158                 :             : static gboolean
     159                 :           0 : reset_search_cb (gpointer data)
     160                 :             : {
     161                 :           0 :   ValentSmsWindow *self = data;
     162                 :             : 
     163         [ #  # ]:           0 :   g_assert (VALENT_IS_SMS_WINDOW (self));
     164                 :             : 
     165                 :           0 :   gtk_editable_set_text (GTK_EDITABLE (self->contact_search_entry), "");
     166                 :           0 :   gtk_editable_set_text (GTK_EDITABLE (self->message_search_entry), "");
     167                 :             : 
     168                 :           0 :   return G_SOURCE_REMOVE;
     169                 :             : }
     170                 :             : 
     171                 :             : /*
     172                 :             :  * Message Search
     173                 :             :  */
     174                 :             : static void
     175                 :           0 : search_header_func (GtkListBoxRow *row,
     176                 :             :                     GtkListBoxRow *before,
     177                 :             :                     gpointer       user_data)
     178                 :             : {
     179         [ #  # ]:           0 :   if (VALENT_IS_MESSAGE_ROW (row))
     180                 :             :     {
     181   [ #  #  #  # ]:           0 :       if (before == NULL || !VALENT_IS_MESSAGE_ROW (before))
     182                 :             :         {
     183                 :           0 :           GtkWidget *label;
     184                 :             : 
     185                 :           0 :           label = g_object_new (GTK_TYPE_LABEL,
     186                 :             :                                 "label",        _("Conversations"),
     187                 :             :                                 "halign",       GTK_ALIGN_START,
     188                 :             :                                 "margin-end",   6,
     189                 :             :                                 "margin-start", 6,
     190                 :             :                                 "margin-top",   6,
     191                 :             :                                 NULL);
     192                 :           0 :           gtk_widget_add_css_class (label, "dim-label");
     193                 :           0 :           gtk_widget_add_css_class (label, "list-header-title");
     194                 :           0 :           gtk_list_box_row_set_header (row, label);
     195                 :             :         }
     196                 :             :     }
     197                 :             : 
     198                 :           0 :   valent_contact_row_header_func (row, before, user_data);
     199                 :           0 : }
     200                 :             : 
     201                 :             : static void
     202                 :           0 : on_message_search_changed (GtkSearchEntry  *entry,
     203                 :             :                            ValentSmsWindow *window)
     204                 :             : {
     205                 :           0 :   GtkWidget *child;
     206                 :           0 :   const char *query_str;
     207                 :           0 :   EBookQuery *queries[2];
     208                 :           0 :   g_autoptr (EBookQuery) query = NULL;
     209         [ #  # ]:           0 :   g_autofree char *sexp = NULL;
     210                 :             : 
     211                 :           0 :   query_str = gtk_editable_get_text (GTK_EDITABLE (entry));
     212                 :             : 
     213                 :             :   /* Clear previous results */
     214         [ #  # ]:           0 :   while ((child = gtk_widget_get_first_child (GTK_WIDGET (window->message_search_list))))
     215                 :           0 :     gtk_list_box_remove (window->message_search_list, child);
     216                 :             : 
     217                 :             :   /* NULL query */
     218         [ #  # ]:           0 :   if (g_strcmp0 (query_str, "") == 0)
     219                 :           0 :     return;
     220                 :             : 
     221                 :             :   /* Search messages */
     222                 :           0 :   valent_sms_store_find_messages (window->message_store,
     223                 :             :                                   query_str,
     224                 :             :                                   NULL,
     225                 :             :                                   (GAsyncReadyCallback)search_messages_cb,
     226                 :             :                                   window);
     227                 :             : 
     228                 :             :   /* Search contacts */
     229                 :           0 :   queries[0] = e_book_query_field_test (E_CONTACT_FULL_NAME,
     230                 :             :                                         E_BOOK_QUERY_CONTAINS,
     231                 :             :                                         query_str);
     232                 :           0 :   queries[1] = e_book_query_field_test (E_CONTACT_TEL,
     233                 :             :                                         E_BOOK_QUERY_CONTAINS,
     234                 :             :                                         query_str);
     235                 :             : 
     236                 :           0 :   query = e_book_query_or (G_N_ELEMENTS (queries), queries, TRUE);
     237                 :           0 :   sexp = e_book_query_to_string (query);
     238                 :             : 
     239                 :           0 :   valent_contact_store_query (window->contact_store,
     240                 :             :                               sexp,
     241                 :             :                               NULL,
     242                 :             :                               (GAsyncReadyCallback)search_contacts_cb,
     243                 :             :                               window);
     244                 :             : }
     245                 :             : 
     246                 :             : static void
     247                 :           0 : on_message_selected (GtkListBox      *box,
     248                 :             :                      GtkListBoxRow   *row,
     249                 :             :                      ValentSmsWindow *self)
     250                 :             : {
     251                 :           0 :   EContact *contact;
     252                 :             : 
     253         [ #  # ]:           0 :   if (VALENT_IS_MESSAGE_ROW (row))
     254                 :             :     {
     255                 :           0 :       ValentMessage *message;
     256                 :             : 
     257                 :           0 :       message = valent_message_row_get_message (VALENT_MESSAGE_ROW (row));
     258                 :           0 :       valent_sms_window_set_active_message (self, message);
     259                 :             : 
     260                 :             :       /* Reset the search after the transition */
     261                 :           0 :       g_timeout_add_seconds (1, reset_search_cb, self);
     262                 :             :     }
     263         [ #  # ]:           0 :   else if (VALENT_IS_CONTACT_ROW (row))
     264                 :             :     {
     265                 :           0 :       contact = valent_contact_row_get_contact (VALENT_CONTACT_ROW (row));
     266                 :           0 :       g_debug ("CONTACT ROW SELECTED %s",
     267                 :             :                (const char *)e_contact_get_const (contact, E_CONTACT_FULL_NAME));
     268                 :             :     }
     269                 :           0 : }
     270                 :             : 
     271                 :             : /*
     272                 :             :  * Contact Search
     273                 :             :  */
     274                 :             : static gboolean
     275                 :           1 : check_number (const char *query)
     276                 :             : {
     277                 :           1 :   static GRegex *is_number = NULL;
     278                 :             : 
     279         [ +  - ]:           1 :   if (is_number == NULL)
     280                 :           1 :     is_number = g_regex_new ("(?!0)[\\d]{3,}", G_REGEX_OPTIMIZE, 0, NULL);
     281                 :             : 
     282                 :           1 :   return g_regex_match (is_number, query, 0, NULL);
     283                 :             : }
     284                 :             : 
     285                 :             : static void
     286                 :           0 : on_contact_selected (GtkListBox      *box,
     287                 :             :                      GtkListBoxRow   *row,
     288                 :             :                      ValentSmsWindow *self)
     289                 :             : {
     290                 :           0 :   const char *address;
     291                 :             : 
     292                 :           0 :   address = valent_contact_row_get_contact_address (VALENT_CONTACT_ROW (row));
     293                 :           0 :   g_debug ("NUMBER SELECTED: %s", address);
     294                 :           0 : }
     295                 :             : 
     296                 :             : static void
     297                 :           1 : on_contact_search_changed (GtkSearchEntry  *entry,
     298                 :             :                            ValentSmsWindow *self)
     299                 :             : {
     300                 :           1 :   const char *query;
     301                 :             : 
     302                 :           1 :   query = gtk_editable_get_text (GTK_EDITABLE (entry));
     303                 :             : 
     304                 :             :   /* If the entry contains a possible phone number... */
     305         [ -  + ]:           1 :   if (check_number (query))
     306                 :             :     {
     307                 :           0 :       EContact *contact;
     308                 :           0 :       g_autofree char *name_label = NULL;
     309                 :             : 
     310                 :           0 :       name_label = g_strdup_printf (_("Send to %s"), query);
     311                 :             : 
     312                 :             :       /* ...ensure we have a dynamic contact for it */
     313         [ #  # ]:           0 :       if (self->placeholder_contact == NULL)
     314                 :             :         {
     315                 :             :           /* Create a dummy contact */
     316                 :           0 :           contact = e_contact_new ();
     317                 :           0 :           e_contact_set (contact, E_CONTACT_FULL_NAME, query);
     318                 :           0 :           e_contact_set (contact, E_CONTACT_PHONE_OTHER, query);
     319                 :             : 
     320                 :             :           /* Create and add a new row */
     321                 :           0 :           self->placeholder_contact = g_object_new (VALENT_TYPE_CONTACT_ROW,
     322                 :             :                                                 "contact",         contact,
     323                 :             :                                                 "contact-name",    name_label,
     324                 :             :                                                 "contact-address", query,
     325                 :             :                                                 NULL);
     326                 :             : 
     327                 :           0 :           gtk_list_box_insert (self->contact_search_list,
     328                 :             :                                self->placeholder_contact,
     329                 :             :                                -1);
     330                 :             :         }
     331                 :             : 
     332                 :             :       /* ...or if we already do, then update it */
     333                 :             :       else
     334                 :             :         {
     335                 :           0 :           g_object_get (self->placeholder_contact, "contact", &contact, NULL);
     336                 :             : 
     337                 :             :           /* Update contact */
     338                 :           0 :           e_contact_set (contact, E_CONTACT_FULL_NAME, query);
     339                 :           0 :           e_contact_set (contact, E_CONTACT_PHONE_OTHER, query);
     340                 :             : 
     341                 :             :           /* Update row */
     342                 :           0 :           g_object_set (self->placeholder_contact,
     343                 :             :                         "contact-name",    name_label,
     344                 :             :                         "contact-address", query,
     345                 :             :                         NULL);
     346                 :             :         }
     347                 :             : 
     348                 :             :       /* Drop the extra ref */
     349         [ #  # ]:           0 :       g_clear_pointer (&contact, g_object_unref);
     350                 :             :     }
     351                 :             : 
     352                 :             :   /* ...otherwise remove the dynamic row if created */
     353         [ -  + ]:           1 :   else if (self->placeholder_contact != NULL)
     354                 :             :     {
     355                 :           0 :       gtk_list_box_remove (self->contact_search_list,
     356                 :             :                            self->placeholder_contact);
     357                 :           0 :       self->placeholder_contact = NULL;
     358                 :             :     }
     359                 :             : 
     360                 :           1 :   gtk_list_box_invalidate_filter (self->contact_search_list);
     361                 :           1 :   gtk_list_box_invalidate_sort (self->contact_search_list);
     362                 :           1 :   gtk_list_box_invalidate_headers (self->contact_search_list);
     363                 :           1 : }
     364                 :             : 
     365                 :             : static gboolean
     366                 :          12 : contact_search_list_filter (ValentContactRow *row,
     367                 :             :                             ValentSmsWindow  *self)
     368                 :             : {
     369                 :          12 :   const char *query;
     370                 :          24 :   g_autofree char *query_folded = NULL;
     371                 :          12 :   g_autofree char *name = NULL;
     372                 :          12 :   const char *address = NULL;
     373                 :             : 
     374                 :             :   /* Always show dynamic contact */
     375         [ -  + ]:          12 :   if G_UNLIKELY (GTK_WIDGET (row) == self->placeholder_contact)
     376                 :             :     return TRUE;
     377                 :             : 
     378                 :          12 :   query = gtk_editable_get_text (GTK_EDITABLE (self->contact_search_entry));
     379                 :             : 
     380         [ +  - ]:          12 :   if (g_strcmp0 (query, "") == 0)
     381                 :             :     return TRUE;
     382                 :             : 
     383                 :           0 :   query_folded = g_utf8_casefold (query, -1);
     384                 :             : 
     385                 :             :   /* Show contact if text is substring of name */
     386                 :           0 :   name = g_utf8_casefold (valent_contact_row_get_contact_name (row), -1);
     387                 :             : 
     388         [ #  # ]:           0 :   if (g_strrstr (name, query_folded) != NULL)
     389                 :             :     return TRUE;
     390                 :             : 
     391                 :             :   /* Show contact if text is substring of number */
     392                 :           0 :   address = valent_contact_row_get_contact_address (row);
     393                 :             : 
     394         [ #  # ]:           0 :   if (g_strrstr (address, query_folded))
     395                 :             :     return TRUE;
     396                 :             : 
     397                 :             :   return FALSE;
     398                 :             : }
     399                 :             : 
     400                 :             : static int
     401                 :          20 : contact_search_list_sort (GtkListBoxRow   *row1,
     402                 :             :                           GtkListBoxRow   *row2,
     403                 :             :                           ValentSmsWindow *self)
     404                 :             : {
     405                 :          20 :   const char *name1;
     406                 :          20 :   const char *name2;
     407                 :             : 
     408         [ +  - ]:          20 :   if G_UNLIKELY (GTK_WIDGET (row1) == self->placeholder_contact)
     409                 :             :     return -1;
     410                 :             : 
     411         [ +  - ]:          20 :   if G_UNLIKELY (GTK_WIDGET (row2) == self->placeholder_contact)
     412                 :             :     return 1;
     413                 :             : 
     414                 :          20 :   name1 = valent_contact_row_get_contact_name (VALENT_CONTACT_ROW (row1));
     415                 :          20 :   name2 = valent_contact_row_get_contact_name (VALENT_CONTACT_ROW (row2));
     416                 :             : 
     417                 :          20 :   return g_utf8_collate (name1, name2);
     418                 :             : }
     419                 :             : 
     420                 :             : static void
     421                 :           2 : refresh_contacts_cb (ValentContactStore *store,
     422                 :             :                      GAsyncResult       *result,
     423                 :             :                      ValentSmsWindow    *self)
     424                 :             : {
     425                 :           2 :   g_autoslist (GObject) contacts = NULL;
     426                 :           2 :   g_autoptr (GError) error = NULL;
     427                 :             : 
     428                 :           2 :   contacts = valent_contact_store_query_finish (store, result, &error);
     429                 :             : 
     430         [ -  + ]:           2 :   if (error != NULL)
     431                 :             :     {
     432                 :           0 :       g_warning ("%s(): %s", G_STRFUNC, error->message);
     433         [ #  # ]:           0 :       return;
     434                 :             :     }
     435                 :             : 
     436         [ +  + ]:           5 :   for (const GSList *iter = contacts; iter; iter = iter->next)
     437                 :           3 :     valent_list_add_contact (self->contact_search_list, iter->data);
     438                 :             : }
     439                 :             : 
     440                 :             : static void
     441                 :           2 : valent_sms_window_refresh_contacts (ValentSmsWindow *self)
     442                 :             : {
     443                 :           2 :   GtkWidget *row;
     444                 :           0 :   g_autoptr (EBookQuery) query = NULL;
     445         [ +  - ]:           2 :   g_autofree char *sexp = NULL;
     446                 :             : 
     447                 :             :   /* Clear the list */
     448         [ +  + ]:           4 :   while ((row = gtk_widget_get_first_child (GTK_WIDGET (self->contact_search_list))))
     449                 :           2 :     gtk_list_box_remove (self->contact_search_list, row);
     450                 :             : 
     451         [ -  + ]:           2 :   if (self->contact_store == NULL)
     452                 :           0 :     return;
     453                 :             : 
     454                 :             :   /* Add the contacts */
     455                 :           2 :   query = e_book_query_vcard_field_exists (EVC_TEL);
     456                 :           2 :   sexp = e_book_query_to_string (query);
     457                 :             : 
     458                 :           2 :   valent_contact_store_query (self->contact_store,
     459                 :             :                               sexp,
     460                 :             :                               NULL,
     461                 :             :                               (GAsyncReadyCallback)refresh_contacts_cb,
     462                 :             :                               self);
     463                 :             : }
     464                 :             : 
     465                 :             : /*
     466                 :             :  * Conversation List
     467                 :             :  */
     468                 :             : static gboolean
     469                 :           0 : on_send_message (GObject         *object,
     470                 :             :                  ValentMessage   *message,
     471                 :             :                  ValentSmsWindow *window)
     472                 :             : {
     473                 :           0 :   gboolean sent;
     474                 :             : 
     475                 :           0 :   g_signal_emit (G_OBJECT (window), signals [SEND_MESSAGE], 0, message, &sent);
     476                 :             : 
     477                 :           0 :   return sent;
     478                 :             : }
     479                 :             : 
     480                 :             : /*
     481                 :             :  * Conversation List Callbacks
     482                 :             :  */
     483                 :             : static GtkWidget *
     484                 :           2 : conversation_list_create (gpointer item,
     485                 :             :                           gpointer user_data)
     486                 :             : {
     487                 :           2 :   ValentSmsWindow *window = VALENT_SMS_WINDOW (user_data);
     488                 :           2 :   ValentMessage *message = VALENT_MESSAGE (item);
     489                 :           2 :   GtkWidget *row;
     490                 :           2 :   GVariant *metadata;
     491                 :           4 :   g_autoptr (GVariant) addresses = NULL;
     492                 :             : 
     493                 :           2 :   row = g_object_new (VALENT_TYPE_MESSAGE_ROW,
     494                 :             :                       "message", message,
     495                 :             :                       NULL);
     496                 :             : 
     497                 :             :   /* TODO: probably a failure of kdeconnect-android, but occasionally a message
     498                 :             :    *       will have no addresses */
     499   [ +  -  +  - ]:           4 :   if ((metadata = valent_message_get_metadata (message)) != NULL &&
     500         [ +  - ]:           4 :       g_variant_lookup (metadata, "addresses", "@aa{sv}", &addresses) &&
     501                 :           2 :       g_variant_n_children (addresses) > 0)
     502                 :             :     {
     503                 :           2 :       g_autoptr (GVariant) participant = NULL;
     504                 :           2 :       const char *address;
     505                 :             : 
     506                 :           2 :       participant = g_variant_get_child_value (addresses, 0);
     507                 :             : 
     508         [ +  - ]:           2 :       if (g_variant_lookup (participant, "address", "&s", &address))
     509                 :             :         {
     510                 :           2 :           valent_sms_contact_from_phone (window->contact_store,
     511                 :             :                                          address,
     512                 :             :                                          NULL,
     513                 :             :                                          (GAsyncReadyCallback)phone_lookup_cb,
     514                 :             :                                          row);
     515                 :             :         }
     516                 :             :     }
     517                 :             : 
     518         [ +  - ]:           2 :   return row;
     519                 :             : }
     520                 :             : 
     521                 :             : static void
     522                 :           2 : conversation_list_populate (ValentSmsWindow *window)
     523                 :             : {
     524                 :           4 :   g_autoptr (GListModel) threads = NULL;
     525                 :             : 
     526         [ +  - ]:           2 :   g_assert (VALENT_IS_SMS_WINDOW (window));
     527                 :             : 
     528                 :           2 :   threads = valent_sms_store_get_summary (window->message_store);
     529         [ +  - ]:           2 :   gtk_list_box_bind_model (window->conversation_list,
     530                 :             :                            threads,
     531                 :             :                            conversation_list_create,
     532                 :             :                            window,
     533                 :             :                            NULL);
     534                 :           2 : }
     535                 :             : 
     536                 :             : static GtkWidget *
     537                 :           1 : valent_sms_window_ensure_conversation (ValentSmsWindow *window,
     538                 :             :                                        int64_t          thread_id)
     539                 :             : {
     540                 :           1 :   GtkWidget *conversation;
     541                 :           2 :   g_autofree char *page_name = NULL;
     542                 :             : 
     543                 :           1 :   page_name = g_strdup_printf ("%"G_GINT64_FORMAT, thread_id);
     544                 :           1 :   conversation = gtk_stack_get_child_by_name (window->content, page_name);
     545                 :             : 
     546         [ +  - ]:           1 :   if (conversation == NULL)
     547                 :             :     {
     548                 :           1 :       conversation = g_object_new (VALENT_TYPE_SMS_CONVERSATION,
     549                 :             :                                    "contact-store", window->contact_store,
     550                 :             :                                    "message-store", window->message_store,
     551                 :             :                                    "thread-id",     thread_id,
     552                 :             :                                    NULL);
     553                 :             : 
     554                 :           1 :       g_object_bind_property (window,       "contact-store",
     555                 :             :                               conversation, "contact-store",
     556                 :             :                               G_BINDING_DEFAULT);
     557                 :             : 
     558                 :           1 :       g_signal_connect_object (conversation,
     559                 :             :                                "send-message",
     560                 :             :                                G_CALLBACK (on_send_message),
     561                 :             :                                window, 0);
     562                 :             : 
     563                 :           1 :       gtk_stack_add_named (window->content, conversation, page_name);
     564                 :             :     }
     565                 :             : 
     566                 :           1 :   return conversation;
     567                 :             : }
     568                 :             : 
     569                 :             : static void
     570                 :           0 : on_conversation_activated (GtkListBox      *box,
     571                 :             :                            GtkListBoxRow   *row,
     572                 :             :                            ValentSmsWindow *self)
     573                 :             : {
     574                 :           0 :   ValentMessageRow *summary;
     575                 :           0 :   int64_t thread_id;
     576                 :             : 
     577                 :             :   /* Deselect */
     578         [ #  # ]:           0 :   if (row == NULL)
     579                 :             :     return;
     580                 :             : 
     581                 :           0 :   summary = VALENT_MESSAGE_ROW (row);
     582                 :           0 :   thread_id = valent_message_row_get_thread_id (summary);
     583                 :             : 
     584                 :           0 :   valent_sms_window_set_active_thread (self, thread_id);
     585                 :           0 :   adw_navigation_split_view_set_show_content (self->content_box, TRUE);
     586                 :             : }
     587                 :             : 
     588                 :             : 
     589                 :             : /*
     590                 :             :  * GActions
     591                 :             :  */
     592                 :             : static void
     593                 :           0 : sms_new_action (GtkWidget  *widget,
     594                 :             :                 const char *action_name,
     595                 :             :                 GVariant   *parameter)
     596                 :             : {
     597                 :           0 :   ValentSmsWindow *self = VALENT_SMS_WINDOW (widget);
     598                 :             : 
     599         [ #  # ]:           0 :   g_assert (VALENT_IS_SMS_WINDOW (self));
     600                 :             : 
     601                 :           0 :   gtk_list_box_select_row (self->conversation_list, NULL);
     602                 :           0 :   adw_navigation_page_set_title (self->content_page, _("New Conversation"));
     603                 :           0 :   gtk_stack_set_visible_child_name (self->content, "contacts");
     604                 :           0 :   gtk_widget_grab_focus (self->contact_search_entry);
     605                 :           0 :   adw_navigation_split_view_set_show_content (self->content_box, TRUE);
     606                 :           0 : }
     607                 :             : 
     608                 :             : static void
     609                 :           0 : sms_search_action (GtkWidget  *widget,
     610                 :             :                    const char *action_name,
     611                 :             :                    GVariant   *parameter)
     612                 :             : {
     613                 :           0 :   ValentSmsWindow *self = VALENT_SMS_WINDOW (widget);
     614                 :             : 
     615         [ #  # ]:           0 :   g_assert (VALENT_IS_SMS_WINDOW (self));
     616                 :             : 
     617                 :           0 :   adw_navigation_page_set_title (self->content_page, _("Search Messages"));
     618                 :           0 :   gtk_stack_set_visible_child_name (self->content, "search");
     619                 :           0 :   gtk_widget_grab_focus (self->message_search_entry);
     620                 :           0 :   adw_navigation_split_view_set_show_content (self->content_box, TRUE);
     621                 :           0 : }
     622                 :             : 
     623                 :             : /*
     624                 :             :  * GObject
     625                 :             :  */
     626                 :             : static void
     627                 :           2 : valent_sms_window_constructed (GObject *object)
     628                 :             : {
     629                 :           2 :   ValentSmsWindow *self = VALENT_SMS_WINDOW (object);
     630                 :             : 
     631         [ +  - ]:           2 :   g_assert (VALENT_IS_CONTACT_STORE (self->contact_store));
     632         [ -  + ]:           2 :   g_assert (VALENT_IS_SMS_STORE (self->message_store));
     633                 :             : 
     634                 :             :   /* Prepare conversation summaries */
     635                 :           2 :   conversation_list_populate (self);
     636                 :             : 
     637                 :           2 :   G_OBJECT_CLASS (valent_sms_window_parent_class)->constructed (object);
     638                 :           2 : }
     639                 :             : 
     640                 :             : static void
     641                 :           2 : valent_sms_window_dispose (GObject *object)
     642                 :             : {
     643                 :           2 :   GtkWidget *widget = GTK_WIDGET (object);
     644                 :             : 
     645                 :           2 :   gtk_widget_dispose_template (widget, VALENT_TYPE_SMS_WINDOW);
     646                 :             : 
     647                 :           2 :   G_OBJECT_CLASS (valent_sms_window_parent_class)->dispose (object);
     648                 :           2 : }
     649                 :             : 
     650                 :             : static void
     651                 :           2 : valent_sms_window_finalize (GObject *object)
     652                 :             : {
     653                 :           2 :   ValentSmsWindow *self = VALENT_SMS_WINDOW (object);
     654                 :             : 
     655         [ +  - ]:           2 :   g_clear_object (&self->contact_store);
     656         [ +  - ]:           2 :   g_clear_object (&self->message_store);
     657                 :             : 
     658                 :           2 :   G_OBJECT_CLASS (valent_sms_window_parent_class)->finalize (object);
     659                 :           2 : }
     660                 :             : 
     661                 :             : static void
     662                 :           2 : valent_sms_window_get_property (GObject    *object,
     663                 :             :                                 guint       prop_id,
     664                 :             :                                 GValue     *value,
     665                 :             :                                 GParamSpec *pspec)
     666                 :             : {
     667                 :           2 :   ValentSmsWindow *self = VALENT_SMS_WINDOW (object);
     668                 :             : 
     669      [ +  +  - ]:           2 :   switch (prop_id)
     670                 :             :     {
     671                 :           1 :     case PROP_CONTACT_STORE:
     672                 :           1 :       g_value_set_object (value, self->contact_store);
     673                 :           1 :       break;
     674                 :             : 
     675                 :           1 :     case PROP_MESSAGE_STORE:
     676                 :           1 :       g_value_set_object (value, self->message_store);
     677                 :           1 :       break;
     678                 :             : 
     679                 :           0 :     default:
     680                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     681                 :             :     }
     682                 :           2 : }
     683                 :             : 
     684                 :             : static void
     685                 :           4 : valent_sms_window_set_property (GObject      *object,
     686                 :             :                                 guint         prop_id,
     687                 :             :                                 const GValue *value,
     688                 :             :                                 GParamSpec   *pspec)
     689                 :             : {
     690                 :           4 :   ValentSmsWindow *self = VALENT_SMS_WINDOW (object);
     691                 :             : 
     692      [ +  +  - ]:           4 :   switch (prop_id)
     693                 :             :     {
     694                 :           2 :     case PROP_CONTACT_STORE:
     695                 :           2 :       valent_sms_window_set_contact_store (self, g_value_get_object (value));
     696                 :           2 :       break;
     697                 :             : 
     698                 :           2 :     case PROP_MESSAGE_STORE:
     699                 :           2 :       g_set_object (&self->message_store, g_value_get_object (value));
     700                 :           2 :       break;
     701                 :             : 
     702                 :           0 :     default:
     703                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     704                 :             :     }
     705                 :           4 : }
     706                 :             : 
     707                 :             : static void
     708                 :           2 : valent_sms_window_class_init (ValentSmsWindowClass *klass)
     709                 :             : {
     710                 :           2 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     711                 :           2 :   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
     712                 :           4 :   g_autoptr (GtkCssProvider) theme = NULL;
     713                 :             : 
     714                 :           2 :   object_class->constructed = valent_sms_window_constructed;
     715                 :           2 :   object_class->dispose = valent_sms_window_dispose;
     716                 :           2 :   object_class->finalize = valent_sms_window_finalize;
     717                 :           2 :   object_class->get_property = valent_sms_window_get_property;
     718                 :           2 :   object_class->set_property = valent_sms_window_set_property;
     719                 :             : 
     720                 :           2 :   gtk_widget_class_set_template_from_resource (widget_class, "/plugins/sms/valent-sms-window.ui");
     721                 :           2 :   gtk_widget_class_bind_template_child (widget_class, ValentSmsWindow, content_box);
     722                 :           2 :   gtk_widget_class_bind_template_child (widget_class, ValentSmsWindow, sidebar_header);
     723                 :             : 
     724                 :           2 :   gtk_widget_class_bind_template_child (widget_class, ValentSmsWindow, content_page);
     725                 :           2 :   gtk_widget_class_bind_template_child (widget_class, ValentSmsWindow, content_header);
     726                 :           2 :   gtk_widget_class_bind_template_child (widget_class, ValentSmsWindow, content_layout);
     727                 :             : 
     728                 :           2 :   gtk_widget_class_bind_template_child (widget_class, ValentSmsWindow, conversation_list);
     729                 :           2 :   gtk_widget_class_bind_template_child (widget_class, ValentSmsWindow, content);
     730                 :           2 :   gtk_widget_class_bind_template_callback (widget_class, on_conversation_activated);
     731                 :             : 
     732                 :             :   /* Message Search */
     733                 :           2 :   gtk_widget_class_bind_template_child (widget_class, ValentSmsWindow, message_search);
     734                 :           2 :   gtk_widget_class_bind_template_child (widget_class, ValentSmsWindow, message_search_entry);
     735                 :           2 :   gtk_widget_class_bind_template_child (widget_class, ValentSmsWindow, message_search_list);
     736                 :           2 :   gtk_widget_class_bind_template_callback (widget_class, on_message_search_changed);
     737                 :           2 :   gtk_widget_class_bind_template_callback (widget_class, on_message_selected);
     738                 :             : 
     739                 :             :   /* Contact Search */
     740                 :           2 :   gtk_widget_class_bind_template_child (widget_class, ValentSmsWindow, contact_search);
     741                 :           2 :   gtk_widget_class_bind_template_child (widget_class, ValentSmsWindow, contact_search_entry);
     742                 :           2 :   gtk_widget_class_bind_template_child (widget_class, ValentSmsWindow, contact_search_list);
     743                 :           2 :   gtk_widget_class_bind_template_callback (widget_class, on_contact_search_changed);
     744                 :           2 :   gtk_widget_class_bind_template_callback (widget_class, on_contact_selected);
     745                 :             : 
     746                 :           2 :   gtk_widget_class_install_action (widget_class, "sms.new", NULL, sms_new_action);
     747                 :           2 :   gtk_widget_class_install_action (widget_class, "sms.search", NULL, sms_search_action);
     748                 :             : 
     749                 :             :   /**
     750                 :             :    * ValentSmsWindow:contact-store:
     751                 :             :    *
     752                 :             :    * The `ValentContactStore` providing contacts for the window.
     753                 :             :    */
     754                 :           4 :   properties [PROP_CONTACT_STORE] =
     755                 :           2 :     g_param_spec_object ("contact-store", NULL, NULL,
     756                 :             :                          VALENT_TYPE_CONTACT_STORE,
     757                 :             :                          (G_PARAM_READWRITE |
     758                 :             :                           G_PARAM_CONSTRUCT_ONLY |
     759                 :             :                           G_PARAM_EXPLICIT_NOTIFY |
     760                 :             :                           G_PARAM_STATIC_STRINGS));
     761                 :             : 
     762                 :             :   /**
     763                 :             :    * ValentSmsWindow:message-store:
     764                 :             :    *
     765                 :             :    * The `ValentSmsStore` providing messages for the window.
     766                 :             :    */
     767                 :           4 :   properties [PROP_MESSAGE_STORE] =
     768                 :           2 :     g_param_spec_object ("message-store", NULL, NULL,
     769                 :             :                          VALENT_TYPE_SMS_STORE,
     770                 :             :                          (G_PARAM_READWRITE |
     771                 :             :                           G_PARAM_CONSTRUCT_ONLY |
     772                 :             :                           G_PARAM_EXPLICIT_NOTIFY |
     773                 :             :                           G_PARAM_STATIC_STRINGS));
     774                 :             : 
     775                 :           2 :   g_object_class_install_properties (object_class, N_PROPERTIES, properties);
     776                 :             : 
     777                 :             :   /**
     778                 :             :    * ValentSmsWindow::send-message:
     779                 :             :    * @window: a `ValentSmsWindow`
     780                 :             :    * @message: a `ValentMessage`
     781                 :             :    *
     782                 :             :    * The `ValentSmsWindow`::send-message signal is emitted when a child
     783                 :             :    * `ValentSmsConversation` emits `ValentSmsConversation`::send-message.
     784                 :             :    *
     785                 :             :    * The signal handler should return a boolean indicating success, although
     786                 :             :    * this only indicates the request was sent to the device.
     787                 :             :    */
     788                 :           4 :   signals [SEND_MESSAGE] =
     789                 :           2 :     g_signal_new ("send-message",
     790                 :             :                   G_TYPE_FROM_CLASS (klass),
     791                 :             :                   G_SIGNAL_RUN_LAST,
     792                 :             :                   0,
     793                 :             :                   g_signal_accumulator_first_wins, NULL, NULL,
     794                 :             :                   G_TYPE_BOOLEAN, 1, VALENT_TYPE_MESSAGE);
     795                 :             : 
     796                 :             :   /* Custom CSS */
     797                 :           2 :   theme = gtk_css_provider_new ();
     798                 :           2 :   gtk_css_provider_load_from_resource (theme, "/plugins/sms/sms.css");
     799         [ +  - ]:           2 :   gtk_style_context_add_provider_for_display (gdk_display_get_default (),
     800                 :             :                                               GTK_STYLE_PROVIDER (theme),
     801                 :             :                                               GTK_STYLE_PROVIDER_PRIORITY_USER);
     802                 :           2 : }
     803                 :             : 
     804                 :             : static void
     805                 :           2 : valent_sms_window_init (ValentSmsWindow *self)
     806                 :             : {
     807                 :           2 :   gtk_widget_init_template (GTK_WIDGET (self));
     808                 :             : 
     809                 :           2 :   gtk_list_box_set_header_func (self->message_search_list,
     810                 :             :                                 search_header_func,
     811                 :             :                                 self, NULL);
     812                 :             : 
     813                 :             :   /* Contacts */
     814                 :           2 :   gtk_list_box_set_filter_func (self->contact_search_list,
     815                 :             :                                 (GtkListBoxFilterFunc)contact_search_list_filter,
     816                 :             :                                 self,
     817                 :             :                                 NULL);
     818                 :             : 
     819                 :           2 :   gtk_list_box_set_sort_func (self->contact_search_list,
     820                 :             :                               (GtkListBoxSortFunc)contact_search_list_sort,
     821                 :             :                               self,
     822                 :             :                               NULL);
     823                 :             : 
     824                 :           2 :   gtk_list_box_set_header_func (self->contact_search_list,
     825                 :             :                                 valent_contact_row_header_func,
     826                 :             :                                 self,
     827                 :             :                                 NULL);
     828                 :           2 : }
     829                 :             : 
     830                 :             : /**
     831                 :             :  * valent_sms_window_get_contact_store:
     832                 :             :  * @window: a `ValentSmsWindow`
     833                 :             :  *
     834                 :             :  * Get the `ValentContactStore` providing contacts for @window.
     835                 :             :  *
     836                 :             :  * Returns: (transfer none) (nullable): a `ValentContactStore`
     837                 :             :  */
     838                 :             : ValentContactStore *
     839                 :           1 : valent_sms_window_get_contact_store (ValentSmsWindow *window)
     840                 :             : {
     841         [ +  - ]:           1 :   g_return_val_if_fail (VALENT_IS_SMS_WINDOW (window), NULL);
     842                 :             : 
     843                 :           1 :   return window->contact_store;
     844                 :             : }
     845                 :             : 
     846                 :             : /**
     847                 :             :  * valent_sms_window_set_contact_store:
     848                 :             :  * @window: a `ValentSmsWindow`
     849                 :             :  * @store: a `ValentContactStore`
     850                 :             :  *
     851                 :             :  * Set the `ValentContactStore` providing contacts for @window.
     852                 :             :  */
     853                 :             : void
     854                 :           2 : valent_sms_window_set_contact_store (ValentSmsWindow    *window,
     855                 :             :                                      ValentContactStore *store)
     856                 :             : {
     857         [ +  - ]:           2 :   g_return_if_fail (VALENT_IS_SMS_WINDOW (window));
     858   [ +  -  -  + ]:           2 :   g_return_if_fail (store == NULL || VALENT_IS_CONTACT_STORE (store));
     859                 :             : 
     860         [ +  - ]:           2 :   if (!g_set_object (&window->contact_store, store))
     861                 :             :     return;
     862                 :             : 
     863                 :           2 :   valent_sms_window_refresh_contacts (window);
     864                 :           2 :   g_object_notify_by_pspec (G_OBJECT (window), properties[PROP_CONTACT_STORE]);
     865                 :             : }
     866                 :             : 
     867                 :             : /**
     868                 :             :  * valent_sms_window_get_sms_store:
     869                 :             :  * @window: a `ValentSmsWindow`
     870                 :             :  *
     871                 :             :  * Get the `ValentSmsStore` providing messages for @window.
     872                 :             :  *
     873                 :             :  * Returns: (transfer none) (nullable): a `ValentSmsStore`
     874                 :             :  */
     875                 :             : ValentSmsStore *
     876                 :           1 : valent_sms_window_get_message_store (ValentSmsWindow *window)
     877                 :             : {
     878         [ +  - ]:           1 :   g_return_val_if_fail (VALENT_IS_SMS_WINDOW (window), NULL);
     879                 :             : 
     880                 :           1 :   return window->message_store;
     881                 :             : }
     882                 :             : 
     883                 :             : /**
     884                 :             :  * valent_sms_window_search_contacts:
     885                 :             :  * @window: a `ValentSmsWindow`
     886                 :             :  * @query: query string
     887                 :             :  *
     888                 :             :  * Switch the contact view and search for @query.
     889                 :             :  */
     890                 :             : void
     891                 :           2 : valent_sms_window_search_contacts (ValentSmsWindow *window,
     892                 :             :                                    const char      *query)
     893                 :             : {
     894         [ +  - ]:           2 :   g_return_if_fail (VALENT_IS_SMS_WINDOW (window));
     895         [ -  + ]:           2 :   g_return_if_fail (query != NULL);
     896                 :             : 
     897                 :           2 :   gtk_list_box_select_row (window->conversation_list, NULL);
     898                 :             : 
     899                 :           2 :   adw_navigation_page_set_title (window->content_page, _("New Conversation"));
     900                 :           2 :   gtk_stack_set_visible_child_name (window->content, "contacts");
     901                 :           2 :   gtk_widget_grab_focus (window->contact_search_entry);
     902                 :           2 :   adw_navigation_split_view_set_show_content (window->content_box, TRUE);
     903                 :             : 
     904                 :           2 :   gtk_editable_set_text (GTK_EDITABLE (window->contact_search_entry), query);
     905                 :             : }
     906                 :             : 
     907                 :             : /**
     908                 :             :  * valent_sms_window_search_messages:
     909                 :             :  * @window: a `ValentSmsWindow`
     910                 :             :  * @query: query string
     911                 :             :  *
     912                 :             :  * Switch the search view and search for @query.
     913                 :             :  */
     914                 :             : void
     915                 :           1 : valent_sms_window_search_messages (ValentSmsWindow *window,
     916                 :             :                                    const char      *query)
     917                 :             : {
     918         [ +  - ]:           1 :   g_return_if_fail (VALENT_IS_SMS_WINDOW (window));
     919         [ -  + ]:           1 :   g_return_if_fail (query != NULL);
     920                 :             : 
     921                 :           1 :   adw_navigation_page_set_title (window->content_page, _("Search Messages"));
     922                 :           1 :   gtk_stack_set_visible_child_name (window->content, "search");
     923                 :           1 :   gtk_widget_grab_focus (window->message_search_entry);
     924                 :           1 :   adw_navigation_split_view_set_show_content (window->content_box, TRUE);
     925                 :             : 
     926                 :           1 :   gtk_editable_set_text (GTK_EDITABLE (window->message_search_entry), query);
     927                 :             : }
     928                 :             : 
     929                 :             : /**
     930                 :             :  * valent_sms_window_set_active_message:
     931                 :             :  * @window: a `ValentSmsWindow`
     932                 :             :  * @message: a `ValentMessage`
     933                 :             :  *
     934                 :             :  * Set the active conversation to the thread of @message scroll to @message.
     935                 :             :  */
     936                 :             : void
     937                 :           0 : valent_sms_window_set_active_message (ValentSmsWindow *window,
     938                 :             :                                       ValentMessage   *message)
     939                 :             : {
     940                 :           0 :   GtkWidget *widget;
     941                 :           0 :   ValentSmsConversation *conversation;
     942                 :           0 :   int64_t thread_id;
     943                 :             : 
     944         [ #  # ]:           0 :   g_return_if_fail (VALENT_IS_SMS_WINDOW (window));
     945                 :             : 
     946                 :             :   /* Select the conversation */
     947                 :           0 :   thread_id = valent_message_get_thread_id (message);
     948                 :           0 :   valent_sms_window_set_active_thread (window, thread_id);
     949                 :             : 
     950                 :             :   /* Get the conversation */
     951                 :           0 :   widget = valent_sms_window_ensure_conversation (window, thread_id);
     952                 :           0 :   conversation = VALENT_SMS_CONVERSATION (widget);
     953                 :             : 
     954                 :           0 :   valent_sms_conversation_scroll_to_message (conversation, message);
     955                 :             : }
     956                 :             : 
     957                 :             : /**
     958                 :             :  * valent_sms_window_set_active_thread:
     959                 :             :  * @window: a `ValentSmsWindow`
     960                 :             :  * @thread_id: a thread id
     961                 :             :  *
     962                 :             :  * Set the active conversation
     963                 :             :  */
     964                 :             : void
     965                 :           1 : valent_sms_window_set_active_thread (ValentSmsWindow *window,
     966                 :             :                                      int64_t          thread_id)
     967                 :             : {
     968                 :           1 :   GtkWidget *conversation;
     969                 :           1 :   const char *title;
     970                 :             : 
     971         [ +  - ]:           1 :   g_return_if_fail (VALENT_IS_SMS_WINDOW (window));
     972         [ -  + ]:           1 :   g_return_if_fail (thread_id >= 0);
     973                 :             : 
     974                 :             :   /* Ensure a conversation widget exists */
     975                 :           1 :   conversation = valent_sms_window_ensure_conversation (window, thread_id);
     976                 :             : 
     977                 :             :   /* Set the header title */
     978                 :           1 :   title = valent_sms_conversation_get_title (VALENT_SMS_CONVERSATION (conversation));
     979                 :           1 :   adw_navigation_page_set_title (window->content_page, title);
     980                 :             : 
     981                 :             :   /* Switch to conversation widget */
     982                 :           1 :   gtk_stack_set_visible_child (window->content, conversation);
     983                 :             : }
     984                 :             : 
        

Generated by: LCOV version 2.0-1