LCOV - code coverage report
Current view: top level - src/plugins/notification - valent-notification-dialog.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 75.9 % 158 120
Test Date: 2024-03-22 06:22:29 Functions: 88.9 % 18 16
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 48.5 % 66 32

             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-notification-dialog"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #include <glib/gi18n.h>
       9                 :             : #include <gtk/gtk.h>
      10                 :             : #include <valent.h>
      11                 :             : 
      12                 :             : #include "valent-notification-dialog.h"
      13                 :             : 
      14                 :             : 
      15                 :             : struct _ValentNotificationDialog
      16                 :             : {
      17                 :             :   GtkWindow           parent_instance;
      18                 :             : 
      19                 :             :   ValentDevice       *device;
      20                 :             :   ValentNotification *notification;
      21                 :             :   char               *reply_id;
      22                 :             : 
      23                 :             :   /* template */
      24                 :             :   GtkButton          *cancel_button;
      25                 :             :   GtkButton          *reply_button;
      26                 :             :   GtkImage           *icon_image;
      27                 :             :   GtkLabel           *title_label;
      28                 :             :   GtkLabel           *body_label;
      29                 :             :   GtkLabel           *time_label;
      30                 :             :   GtkWidget          *reply_frame;
      31                 :             :   GtkTextView        *reply_entry;
      32                 :             : };
      33                 :             : 
      34   [ +  +  +  - ]:          15 : G_DEFINE_FINAL_TYPE (ValentNotificationDialog, valent_notification_dialog, GTK_TYPE_WINDOW)
      35                 :             : 
      36                 :             : enum {
      37                 :             :   PROP_0,
      38                 :             :   PROP_DEVICE,
      39                 :             :   PROP_NOTIFICATION,
      40                 :             :   PROP_REPLY_ID,
      41                 :             :   N_PROPERTIES
      42                 :             : };
      43                 :             : 
      44                 :             : static GParamSpec *properties[N_PROPERTIES] = { NULL, };
      45                 :             : 
      46                 :             : 
      47                 :             : static void
      48                 :           4 : valent_notification_dialog_sync (ValentNotificationDialog *self)
      49                 :             : {
      50                 :           4 :   gboolean repliable = FALSE;
      51                 :           4 :   gboolean enabled = FALSE;
      52                 :             : 
      53         [ +  - ]:           4 :   g_assert (VALENT_IS_NOTIFICATION_DIALOG (self));
      54                 :             : 
      55                 :             :   /* Check if the notification is repliable */
      56   [ +  +  -  + ]:           4 :   repliable = (self->reply_id != NULL && *self->reply_id != '\0');
      57                 :           4 :   gtk_widget_set_visible (GTK_WIDGET (self->reply_button), repliable);
      58                 :           4 :   gtk_widget_set_visible (GTK_WIDGET (self->reply_frame), repliable);
      59                 :             : 
      60                 :             :   /* If it's repliable, check if the device action is enabled */
      61   [ +  +  -  + ]:           4 :   if (repliable && self->device != NULL)
      62                 :           0 :     enabled = g_action_group_get_action_enabled (G_ACTION_GROUP (self->device),
      63                 :             :                                                  "notification.reply");
      64                 :             : 
      65                 :           4 :   gtk_widget_set_sensitive (GTK_WIDGET (self->reply_entry), enabled);
      66                 :             : 
      67                 :             :   /* If it's enabled, check if a reply is ready to be sent */
      68         [ -  + ]:           4 :   if (enabled)
      69                 :             :     {
      70                 :           0 :       GtkTextBuffer *buffer;
      71                 :             : 
      72                 :           0 :       buffer = gtk_text_view_get_buffer (self->reply_entry);
      73                 :           0 :       enabled = gtk_text_buffer_get_char_count (buffer) > 0;
      74                 :             :     }
      75                 :             : 
      76                 :           4 :   gtk_widget_action_set_enabled (GTK_WIDGET (self),
      77                 :             :                                  "notification.reply",
      78                 :             :                                  enabled);
      79                 :           4 : }
      80                 :             : 
      81                 :             : static void
      82                 :           1 : valent_notification_dialog_set_notification (ValentNotificationDialog *self,
      83                 :             :                                              ValentNotification       *notification)
      84                 :             : {
      85                 :           1 :   GIcon *icon;
      86                 :           1 :   const char *title;
      87                 :           1 :   const char *body;
      88                 :           1 :   gint64 timestamp;
      89                 :             : 
      90         [ +  - ]:           1 :   g_assert (VALENT_IS_NOTIFICATION_DIALOG (self));
      91   [ +  -  -  + ]:           1 :   g_assert (notification == NULL || VALENT_IS_NOTIFICATION (notification));
      92                 :             : 
      93         [ +  - ]:           1 :   if (!g_set_object (&self->notification, notification))
      94                 :             :     return;
      95                 :             : 
      96         [ +  - ]:           1 :   if ((icon = valent_notification_get_icon (self->notification)) != NULL)
      97                 :           1 :     gtk_image_set_from_gicon (self->icon_image, icon);
      98                 :             : 
      99         [ +  - ]:           1 :   if ((title = valent_notification_get_title (self->notification)) != NULL)
     100                 :           1 :     gtk_label_set_label (self->title_label, title);
     101                 :             : 
     102         [ +  - ]:           1 :   if ((body = valent_notification_get_body (self->notification)) != NULL)
     103                 :             :     {
     104                 :           1 :       g_autofree char *label = NULL;
     105                 :             : 
     106                 :           1 :       label = valent_string_to_markup (body);
     107                 :           1 :       gtk_label_set_label (self->body_label, label);
     108                 :             :     }
     109                 :             : 
     110                 :             :       // FIXME: better time string
     111         [ -  + ]:           1 :   if ((timestamp = valent_notification_get_time (self->notification)) != 0)
     112                 :             :     {
     113                 :           1 :       g_autoptr (GDateTime) date = NULL;
     114         [ #  # ]:           0 :       g_autofree char *label = NULL;
     115                 :             : 
     116                 :           0 :       date = g_date_time_new_from_unix_local (timestamp / 1000);
     117                 :           0 :       label = g_date_time_format (date, "%c");
     118                 :           0 :       gtk_label_set_label (self->time_label, label);
     119                 :             :     }
     120                 :             : 
     121                 :           1 :   valent_notification_dialog_sync (self);
     122                 :             : }
     123                 :             : 
     124                 :             : /*
     125                 :             :  * GAction
     126                 :             :  */
     127                 :             : static void
     128                 :           1 : dialog_cancel_action (GtkWidget  *widget,
     129                 :             :                       const char *action_name,
     130                 :             :                       GVariant   *parameter)
     131                 :             : {
     132                 :           1 :   ValentNotificationDialog *self = VALENT_NOTIFICATION_DIALOG (widget);
     133                 :             : 
     134         [ +  - ]:           1 :   g_assert (VALENT_IS_NOTIFICATION_DIALOG (self));
     135                 :             : 
     136                 :           1 :   gtk_window_destroy (GTK_WINDOW (self));
     137                 :           1 : }
     138                 :             : 
     139                 :             : static void
     140                 :           0 : notification_close_action (GtkWidget  *widget,
     141                 :             :                            const char *action_name,
     142                 :             :                            GVariant   *parameter)
     143                 :             : {
     144                 :           0 :   ValentNotificationDialog *self = VALENT_NOTIFICATION_DIALOG (widget);
     145                 :           0 :   const char *id = NULL;
     146                 :             : 
     147         [ #  # ]:           0 :   g_assert (VALENT_IS_NOTIFICATION_DIALOG (self));
     148                 :             : 
     149                 :           0 :   id = valent_notification_get_id (self->notification);
     150                 :           0 :   g_action_group_activate_action (G_ACTION_GROUP (self->device),
     151                 :             :                                   "notification.close",
     152                 :             :                                   g_variant_new_string (id));
     153                 :           0 : }
     154                 :             : 
     155                 :             : static void
     156                 :           0 : notification_reply_action (GtkWidget  *widget,
     157                 :             :                            const char *action_name,
     158                 :             :                            GVariant   *parameter)
     159                 :             : {
     160                 :           0 :   ValentNotificationDialog *self = VALENT_NOTIFICATION_DIALOG (widget);
     161                 :           0 :   g_autofree char *message = NULL;
     162                 :           0 :   GVariant *reply = NULL;
     163                 :           0 :   GtkTextBuffer *buffer;
     164                 :             : 
     165         [ #  # ]:           0 :   if (!g_action_group_get_action_enabled (G_ACTION_GROUP (self->device),
     166                 :             :                                           "notification.reply"))
     167                 :             :     return;
     168                 :             : 
     169                 :           0 :   buffer = gtk_text_view_get_buffer (self->reply_entry);
     170                 :           0 :   g_object_get (buffer, "text", &message, NULL);
     171   [ #  #  #  # ]:           0 :   g_return_if_fail (message != NULL && *message != '\0');
     172                 :             : 
     173                 :           0 :   reply = g_variant_new ("(ssv)", self->reply_id, message,
     174                 :             :                          valent_notification_serialize (self->notification));
     175                 :           0 :   g_action_group_activate_action (G_ACTION_GROUP (self->device),
     176                 :             :                                   "notification.reply",
     177                 :             :                                   reply);
     178                 :           0 :   gtk_window_destroy (GTK_WINDOW (self));
     179                 :             : }
     180                 :             : 
     181                 :             : /*
     182                 :             :  * GObject
     183                 :             :  */
     184                 :             : static void
     185                 :           1 : valent_notification_dialog_dispose (GObject *object)
     186                 :             : {
     187                 :           1 :   GtkWidget *widget = GTK_WIDGET (object);
     188                 :             : 
     189                 :           1 :   gtk_widget_dispose_template (widget, VALENT_TYPE_NOTIFICATION_DIALOG);
     190                 :             : 
     191                 :           1 :   G_OBJECT_CLASS (valent_notification_dialog_parent_class)->dispose (object);
     192                 :           1 : }
     193                 :             : 
     194                 :             : static void
     195                 :           1 : valent_notification_dialog_constructed (GObject *object)
     196                 :             : {
     197                 :           1 :   ValentNotificationDialog *self = VALENT_NOTIFICATION_DIALOG (object);
     198                 :             : 
     199         [ -  + ]:           1 :   if (self->device != NULL)
     200                 :             :     {
     201                 :           0 :       gtk_widget_insert_action_group (GTK_WIDGET (self),
     202                 :             :                                       "device",
     203                 :             :                                       G_ACTION_GROUP (self->device));
     204                 :           0 :       g_signal_connect_object (self->device,
     205                 :             :                                "action-added::notification.reply",
     206                 :             :                                G_CALLBACK (valent_notification_dialog_sync),
     207                 :             :                                self,
     208                 :             :                                G_CONNECT_SWAPPED);
     209                 :           0 :       g_signal_connect_object (self->device,
     210                 :             :                                "action-removed::notification.reply",
     211                 :             :                                G_CALLBACK (valent_notification_dialog_sync),
     212                 :             :                                self,
     213                 :             :                                G_CONNECT_SWAPPED);
     214                 :           0 :       g_signal_connect_object (self->device,
     215                 :             :                                "action-enabled-changed::notification.reply",
     216                 :             :                                G_CALLBACK (valent_notification_dialog_sync),
     217                 :             :                                self,
     218                 :             :                                G_CONNECT_SWAPPED);
     219                 :             :     }
     220                 :             : 
     221                 :           1 :   valent_notification_dialog_sync (self);
     222                 :             : 
     223                 :           1 :   G_OBJECT_CLASS (valent_notification_dialog_parent_class)->constructed (object);
     224                 :           1 : }
     225                 :             : 
     226                 :             : static void
     227                 :           1 : valent_notification_dialog_finalize (GObject *object)
     228                 :             : {
     229                 :           1 :   ValentNotificationDialog *self = VALENT_NOTIFICATION_DIALOG (object);
     230                 :             : 
     231         [ +  - ]:           1 :   g_clear_object (&self->notification);
     232         [ -  + ]:           1 :   g_clear_pointer (&self->reply_id, g_free);
     233                 :             : 
     234                 :           1 :   G_OBJECT_CLASS (valent_notification_dialog_parent_class)->finalize (object);
     235                 :           1 : }
     236                 :             : 
     237                 :             : static void
     238                 :           2 : valent_notification_dialog_get_property (GObject    *object,
     239                 :             :                                          guint       prop_id,
     240                 :             :                                          GValue     *value,
     241                 :             :                                          GParamSpec *pspec)
     242                 :             : {
     243                 :           2 :   ValentNotificationDialog *self = VALENT_NOTIFICATION_DIALOG (object);
     244                 :             : 
     245   [ -  +  +  - ]:           2 :   switch (prop_id)
     246                 :             :     {
     247                 :           0 :     case PROP_DEVICE:
     248                 :           0 :       g_value_set_object (value, self->device);
     249                 :           0 :       break;
     250                 :             : 
     251                 :           1 :     case PROP_NOTIFICATION:
     252                 :           1 :       g_value_set_object (value, self->notification);
     253                 :           1 :       break;
     254                 :             : 
     255                 :           1 :     case PROP_REPLY_ID:
     256                 :           1 :       g_value_set_string (value, self->reply_id);
     257                 :           1 :       break;
     258                 :             : 
     259                 :           0 :     default:
     260                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     261                 :             :     }
     262                 :           2 : }
     263                 :             : 
     264                 :             : static void
     265                 :           3 : valent_notification_dialog_set_property (GObject      *object,
     266                 :             :                                          guint         prop_id,
     267                 :             :                                          const GValue *value,
     268                 :             :                                          GParamSpec   *pspec)
     269                 :             : {
     270                 :           3 :   ValentNotificationDialog *self = VALENT_NOTIFICATION_DIALOG (object);
     271                 :             : 
     272   [ +  +  +  - ]:           3 :   switch (prop_id)
     273                 :             :     {
     274                 :           1 :     case PROP_DEVICE:
     275                 :           1 :       self->device = g_value_get_object (value);
     276                 :           1 :       break;
     277                 :             : 
     278                 :           1 :     case PROP_NOTIFICATION:
     279                 :           1 :       valent_notification_dialog_set_notification (self, g_value_get_object (value));
     280                 :           1 :       break;
     281                 :             : 
     282                 :           1 :     case PROP_REPLY_ID:
     283                 :           1 :       valent_notification_dialog_set_reply_id (self, g_value_get_string (value));
     284                 :           1 :       break;
     285                 :             : 
     286                 :           0 :     default:
     287                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     288                 :             :     }
     289                 :           3 : }
     290                 :             : 
     291                 :             : static void
     292                 :           1 : valent_notification_dialog_class_init (ValentNotificationDialogClass *klass)
     293                 :             : {
     294                 :           1 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     295                 :           1 :   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
     296                 :             : 
     297                 :           1 :   object_class->dispose = valent_notification_dialog_dispose;
     298                 :           1 :   object_class->constructed = valent_notification_dialog_constructed;
     299                 :           1 :   object_class->finalize = valent_notification_dialog_finalize;
     300                 :           1 :   object_class->get_property = valent_notification_dialog_get_property;
     301                 :           1 :   object_class->set_property = valent_notification_dialog_set_property;
     302                 :             : 
     303                 :           1 :   gtk_widget_class_set_template_from_resource (widget_class, "/plugins/notification/valent-notification-dialog.ui");
     304                 :           1 :   gtk_widget_class_bind_template_child (widget_class, ValentNotificationDialog, cancel_button);
     305                 :           1 :   gtk_widget_class_bind_template_child (widget_class, ValentNotificationDialog, reply_button);
     306                 :           1 :   gtk_widget_class_bind_template_child (widget_class, ValentNotificationDialog, icon_image);
     307                 :           1 :   gtk_widget_class_bind_template_child (widget_class, ValentNotificationDialog, title_label);
     308                 :           1 :   gtk_widget_class_bind_template_child (widget_class, ValentNotificationDialog, body_label);
     309                 :           1 :   gtk_widget_class_bind_template_child (widget_class, ValentNotificationDialog, time_label);
     310                 :           1 :   gtk_widget_class_bind_template_child (widget_class, ValentNotificationDialog, reply_frame);
     311                 :           1 :   gtk_widget_class_bind_template_child (widget_class, ValentNotificationDialog, reply_entry);
     312                 :             : 
     313                 :           1 :   gtk_widget_class_install_action (widget_class, "dialog.cancel", NULL, dialog_cancel_action);
     314                 :             : 
     315                 :           1 :   gtk_widget_class_install_action (widget_class, "notification.close", NULL, notification_close_action);
     316                 :           1 :   gtk_widget_class_install_action (widget_class, "notification.reply", NULL, notification_reply_action);
     317                 :             : 
     318                 :             :   /**
     319                 :             :    * ValentNotificationDialog:device:
     320                 :             :    *
     321                 :             :    * The device that owns the notification.
     322                 :             :    */
     323                 :           2 :   properties [PROP_DEVICE] =
     324                 :           1 :     g_param_spec_object ("device", NULL, NULL,
     325                 :             :                          VALENT_TYPE_DEVICE,
     326                 :             :                          (G_PARAM_READWRITE |
     327                 :             :                           G_PARAM_CONSTRUCT_ONLY |
     328                 :             :                           G_PARAM_EXPLICIT_NOTIFY |
     329                 :             :                           G_PARAM_STATIC_STRINGS));
     330                 :             : 
     331                 :             :   /**
     332                 :             :    * ValentNotificationDialog:notification:
     333                 :             :    *
     334                 :             :    * The notification the dialog represents.
     335                 :             :    */
     336                 :           2 :   properties [PROP_NOTIFICATION] =
     337                 :           1 :     g_param_spec_object ("notification", NULL, NULL,
     338                 :             :                          VALENT_TYPE_NOTIFICATION,
     339                 :             :                          (G_PARAM_READWRITE |
     340                 :             :                           G_PARAM_CONSTRUCT_ONLY |
     341                 :             :                           G_PARAM_EXPLICIT_NOTIFY |
     342                 :             :                           G_PARAM_STATIC_STRINGS));
     343                 :             : 
     344                 :             :   /**
     345                 :             :    * ValentNotificationDialog:reply-id:
     346                 :             :    *
     347                 :             :    * The notification reply ID.
     348                 :             :    */
     349                 :           2 :   properties [PROP_REPLY_ID] =
     350                 :           1 :     g_param_spec_string ("reply-id", NULL, NULL,
     351                 :             :                          NULL,
     352                 :             :                          (G_PARAM_READWRITE |
     353                 :             :                           G_PARAM_CONSTRUCT |
     354                 :             :                           G_PARAM_EXPLICIT_NOTIFY |
     355                 :             :                           G_PARAM_STATIC_STRINGS));
     356                 :             : 
     357                 :           1 :   g_object_class_install_properties (object_class, N_PROPERTIES, properties);
     358                 :           1 : }
     359                 :             : 
     360                 :             : static void
     361                 :           1 : valent_notification_dialog_init (ValentNotificationDialog *self)
     362                 :             : {
     363                 :           1 :   gtk_widget_init_template (GTK_WIDGET (self));
     364                 :             : 
     365                 :           1 :   g_signal_connect_object (gtk_text_view_get_buffer (self->reply_entry),
     366                 :             :                            "notify::text",
     367                 :             :                            G_CALLBACK (valent_notification_dialog_sync),
     368                 :             :                            self,
     369                 :             :                            G_CONNECT_SWAPPED);
     370                 :           1 : }
     371                 :             : 
     372                 :             : /**
     373                 :             :  * valent_notification_dialog_get_notification:
     374                 :             :  * @dialog: a `ValentNotificationDialog`
     375                 :             :  *
     376                 :             :  * Get the notification.
     377                 :             :  *
     378                 :             :  * Returns: (transfer none): a `ValentNotification`
     379                 :             :  */
     380                 :             : ValentNotification *
     381                 :           1 : valent_notification_dialog_get_notification (ValentNotificationDialog *dialog)
     382                 :             : {
     383         [ +  - ]:           1 :   g_return_val_if_fail (VALENT_IS_NOTIFICATION_DIALOG (dialog), NULL);
     384                 :             : 
     385                 :           1 :   return dialog->notification;
     386                 :             : }
     387                 :             : 
     388                 :             : /**
     389                 :             :  * valent_notification_dialog_get_reply_id: (get-property reply-id)
     390                 :             :  * @dialog: a `ValentNotificationDialog`
     391                 :             :  *
     392                 :             :  * Get the notification reply ID.
     393                 :             :  *
     394                 :             :  * Returns: (transfer none): the reply ID
     395                 :             :  */
     396                 :             : const char *
     397                 :           2 : valent_notification_dialog_get_reply_id (ValentNotificationDialog *dialog)
     398                 :             : {
     399         [ +  - ]:           2 :   g_return_val_if_fail (VALENT_IS_NOTIFICATION_DIALOG (dialog), NULL);
     400                 :             : 
     401                 :           2 :   return dialog->reply_id;
     402                 :             : }
     403                 :             : 
     404                 :             : /**
     405                 :             :  * valent_notification_dialog_set_reply_id: (set-property reply-id)
     406                 :             :  * @dialog: a `ValentNotificationDialog`
     407                 :             :  * @reply_id: (nullable): a notification reply ID
     408                 :             :  *
     409                 :             :  * Set the notification reply ID.
     410                 :             :  *
     411                 :             :  * If @reply_id is %NULL or empty, the notification can not be replied to.
     412                 :             :  */
     413                 :             : void
     414                 :           2 : valent_notification_dialog_set_reply_id (ValentNotificationDialog *dialog,
     415                 :             :                                          const char               *reply_id)
     416                 :             : {
     417         [ +  - ]:           2 :   g_return_if_fail (VALENT_IS_NOTIFICATION_DIALOG (dialog));
     418                 :             : 
     419         [ +  - ]:           2 :   if (!g_set_str (&dialog->reply_id, reply_id))
     420                 :             :     return;
     421                 :             : 
     422                 :           2 :   valent_notification_dialog_sync (dialog);
     423                 :           2 :   g_object_notify_by_pspec (G_OBJECT (dialog), properties [PROP_REPLY_ID]);
     424                 :             : }
     425                 :             : 
        

Generated by: LCOV version 2.0-1