From 3c672e078443c1d0f065afa4c18f16be5be07724 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Tue, 23 May 2023 19:01:19 -0300 Subject: [PATCH] Move sync indicator into a separate widget And move the new widget into the headerbar itself, instead of the calendars button. --- po/POTFILES.in | 1 + src/gui/gcal-calendar-button.c | 64 ---------- src/gui/gcal-calendar-button.ui | 50 +------- src/gui/gcal-sync-indicator.c | 212 ++++++++++++++++++++++++++++++++ src/gui/gcal-sync-indicator.h | 31 +++++ src/gui/gcal-sync-indicator.ui | 39 ++++++ src/gui/gcal-window.c | 5 + src/gui/gcal-window.ui | 3 + src/gui/gui.gresource.xml | 1 + src/gui/meson.build | 1 + src/theme/style.css | 8 ++ 11 files changed, 303 insertions(+), 112 deletions(-) create mode 100644 src/gui/gcal-sync-indicator.c create mode 100644 src/gui/gcal-sync-indicator.h create mode 100644 src/gui/gcal-sync-indicator.ui diff --git a/po/POTFILES.in b/po/POTFILES.in index e9ed588e..6e48c75f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -31,6 +31,7 @@ src/gui/gcal-meeting-row.c src/gui/gcal-meeting-row.ui src/gui/gcal-quick-add-popover.c src/gui/gcal-quick-add-popover.ui +src/gui/gcal-sync-indicator.ui src/gui/gcal-toolbar-end.ui src/gui/gcal-weather-settings.ui src/gui/gcal-window.c diff --git a/src/gui/gcal-calendar-button.c b/src/gui/gcal-calendar-button.c index 3c2e3b71..0f3a360a 100644 --- a/src/gui/gcal-calendar-button.c +++ b/src/gui/gcal-calendar-button.c @@ -30,16 +30,10 @@ struct _GcalCalendarButton AdwBin parent; GtkWidget *calendar_listbox; - GtkStack *icon_stack; - GtkSpinner *refreshing_spinner; GcalContext *context; - - guint icon_changed_source_id; }; -static gboolean icon_change_timeout_cb (gpointer data); - G_DEFINE_TYPE (GcalCalendarButton, gcal_calendar_button, ADW_TYPE_BIN) enum @@ -136,54 +130,11 @@ remove_calendar (GcalCalendarButton *self, } } -static void -schedule_switch_to_spinner (GcalCalendarButton *self) -{ - if (self->icon_changed_source_id > 0) - return; - - g_debug ("Scheduling synchronization icon update"); - - self->icon_changed_source_id = g_timeout_add (500, icon_change_timeout_cb, self); -} - -static void -schedule_switch_to_success (GcalCalendarButton *self) -{ - g_clear_handle_id (&self->icon_changed_source_id, g_source_remove); - - g_debug ("Switching to success icon"); - - gtk_stack_set_visible_child_name (self->icon_stack, "success"); - - self->icon_changed_source_id = g_timeout_add (2000, icon_change_timeout_cb, self); -} - /* * Callbacks */ -static gboolean -icon_change_timeout_cb (gpointer data) -{ - GcalCalendarButton *self; - GcalManager *manager; - gboolean synchronizing; - - self = GCAL_CALENDAR_BUTTON (data); - manager = gcal_context_get_manager (self->context); - synchronizing = gcal_manager_get_synchronizing (manager); - - g_debug ("Updating calendar icon to spinner"); - - gtk_stack_set_visible_child_name (self->icon_stack, synchronizing ? "spinner" : "icon"); - gtk_spinner_set_spinning (self->refreshing_spinner, synchronizing); - - self->icon_changed_source_id = 0; - return G_SOURCE_REMOVE; -} - static gint listbox_sort_func (GtkListBoxRow *row1, GtkListBoxRow *row2, @@ -228,17 +179,6 @@ on_manager_calendar_removed_cb (GcalManager *manager, remove_calendar (self, calendar); } -static void -on_manager_synchronizing_changed_cb (GcalManager *manager, - GParamSpec *pspec, - GcalCalendarButton *self) -{ - if (gcal_manager_get_synchronizing (manager)) - schedule_switch_to_spinner (self); - else - schedule_switch_to_success (self); -} - static void on_listbox_row_activated_cb (GtkListBox *listbox, GtkListBoxRow *row, @@ -259,7 +199,6 @@ gcal_calendar_button_finalize (GObject *object) { GcalCalendarButton *self = (GcalCalendarButton *)object; - g_clear_handle_id (&self->icon_changed_source_id, g_source_remove); g_clear_object (&self->context); G_OBJECT_CLASS (gcal_calendar_button_parent_class)->finalize (object); @@ -320,7 +259,6 @@ gcal_calendar_button_set_property (GObject *object, g_signal_connect_object (manager, "calendar-added", G_CALLBACK (on_manager_calendar_added_cb), object, 0); g_signal_connect_object (manager, "calendar-removed", G_CALLBACK (on_manager_calendar_removed_cb), object, 0); g_signal_connect_object (manager, "calendar-changed", G_CALLBACK (on_manager_calendar_changed_cb), object, 0); - g_signal_connect_object (manager, "notify::synchronizing", G_CALLBACK (on_manager_synchronizing_changed_cb), object, 0); } break; @@ -355,8 +293,6 @@ gcal_calendar_button_class_init (GcalCalendarButtonClass *klass) gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/gui/gcal-calendar-button.ui"); gtk_widget_class_bind_template_child (widget_class, GcalCalendarButton, calendar_listbox); - gtk_widget_class_bind_template_child (widget_class, GcalCalendarButton, icon_stack); - gtk_widget_class_bind_template_child (widget_class, GcalCalendarButton, refreshing_spinner); gtk_widget_class_bind_template_callback (widget_class, on_listbox_row_activated_cb); } diff --git a/src/gui/gcal-calendar-button.ui b/src/gui/gcal-calendar-button.ui index c77eb5a7..798e30bf 100644 --- a/src/gui/gcal-calendar-button.ui +++ b/src/gui/gcal-calendar-button.ui @@ -4,58 +4,12 @@ Manage your calendars + True + _Calendars popover - - - - crossfade - 250 - - - icon - - - - - _Calendars - True - - - - - pan-down-symbolic - - - - - - - - - spinner - - - Synchronizing remote calendars… - - - - - - - success - - - emblem-ok-symbolic - - - - - - - diff --git a/src/gui/gcal-sync-indicator.c b/src/gui/gcal-sync-indicator.c new file mode 100644 index 00000000..091eb031 --- /dev/null +++ b/src/gui/gcal-sync-indicator.c @@ -0,0 +1,212 @@ +/* + * gcal-sync-indicator.c + * + * Copyright 2023 Georges Basile Stavracas Neto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#define G_LOG_DOMAIN "GcalSyncIndicator" + +#include "gcal-context.h" +#include "gcal-sync-indicator.h" + +struct _GcalSyncIndicator +{ + AdwBin parent_instance; + + GtkSpinner *refreshing_spinner; + GtkStack *stack; + + guint icon_changed_source_id; + + GcalContext *context; +}; + +static gboolean icon_change_timeout_cb (gpointer data); + +G_DEFINE_FINAL_TYPE (GcalSyncIndicator, gcal_sync_indicator, ADW_TYPE_BIN) + +enum +{ + PROP_0, + PROP_CONTEXT, + N_PROPS, +}; + +static GParamSpec *properties [N_PROPS] = { NULL, }; + + +/* + * Auxiliary methods + */ + +static void +schedule_switch_to_spinner (GcalSyncIndicator *self) +{ + if (self->icon_changed_source_id > 0) + return; + + g_debug ("Scheduling synchronization icon update"); + + self->icon_changed_source_id = g_timeout_add (500, icon_change_timeout_cb, self); +} + +static void +schedule_switch_to_success (GcalSyncIndicator *self) +{ + g_clear_handle_id (&self->icon_changed_source_id, g_source_remove); + + g_debug ("Switching to success icon"); + + gtk_stack_set_visible_child_name (self->stack, "success"); + + self->icon_changed_source_id = g_timeout_add (2000, icon_change_timeout_cb, self); +} + + +/* + * Callbacks + */ + +static gboolean +icon_change_timeout_cb (gpointer data) +{ + GcalSyncIndicator *self; + GcalManager *manager; + gboolean synchronizing; + + self = GCAL_SYNC_INDICATOR (data); + manager = gcal_context_get_manager (self->context); + synchronizing = gcal_manager_get_synchronizing (manager); + + g_debug ("Updating calendar icon to spinner"); + + gtk_stack_set_visible_child_name (self->stack, synchronizing ? "spinner" : "empty"); + gtk_spinner_set_spinning (self->refreshing_spinner, synchronizing); + + self->icon_changed_source_id = 0; + return G_SOURCE_REMOVE; +} + +static void +on_manager_synchronizing_changed_cb (GcalManager *manager, + GParamSpec *pspec, + GcalSyncIndicator *self) +{ + if (gcal_manager_get_synchronizing (manager)) + schedule_switch_to_spinner (self); + else + schedule_switch_to_success (self); +} + + +/* + * GObject overrides + */ + +static void +gcal_sync_indicator_finalize (GObject *object) +{ + GcalSyncIndicator *self = (GcalSyncIndicator *)object; + + g_clear_handle_id (&self->icon_changed_source_id, g_source_remove); + g_clear_object (&self->context); + + G_OBJECT_CLASS (gcal_sync_indicator_parent_class)->finalize (object); +} + +static void +gcal_sync_indicator_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GcalSyncIndicator *self = GCAL_SYNC_INDICATOR (object); + + switch (prop_id) + { + case PROP_CONTEXT: + g_value_set_object (value, self->context); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gcal_sync_indicator_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GcalSyncIndicator *self = GCAL_SYNC_INDICATOR (object); + + switch (prop_id) + { + case PROP_CONTEXT: + g_assert (self->context == NULL); + self->context = g_value_dup_object (value); + + g_signal_connect_object (gcal_context_get_manager (self->context), + "notify::synchronizing", + G_CALLBACK (on_manager_synchronizing_changed_cb), + object, + 0); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gcal_sync_indicator_class_init (GcalSyncIndicatorClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = gcal_sync_indicator_finalize; + object_class->get_property = gcal_sync_indicator_get_property; + object_class->set_property = gcal_sync_indicator_set_property; + + /** + * GcalSyncIndicator::context: + * + * The #GcalContext of the application. + */ + properties[PROP_CONTEXT] = g_param_spec_object ("context", + "Context of the application", + "The context of the application", + GCAL_TYPE_CONTEXT, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, N_PROPS, properties); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/gui/gcal-sync-indicator.ui"); + + gtk_widget_class_bind_template_child (widget_class, GcalSyncIndicator, refreshing_spinner); + gtk_widget_class_bind_template_child (widget_class, GcalSyncIndicator, stack); + + gtk_widget_class_set_css_name (widget_class, "syncindicator"); +} + +static void +gcal_sync_indicator_init (GcalSyncIndicator *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} diff --git a/src/gui/gcal-sync-indicator.h b/src/gui/gcal-sync-indicator.h new file mode 100644 index 00000000..d4fe8d6a --- /dev/null +++ b/src/gui/gcal-sync-indicator.h @@ -0,0 +1,31 @@ +/* + * gcal-sync-indicator.h + * + * Copyright 2023 Georges Basile Stavracas Neto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define GCAL_TYPE_SYNC_INDICATOR (gcal_sync_indicator_get_type()) +G_DECLARE_FINAL_TYPE (GcalSyncIndicator, gcal_sync_indicator, GCAL, SYNC_INDICATOR, AdwBin) + +G_END_DECLS diff --git a/src/gui/gcal-sync-indicator.ui b/src/gui/gcal-sync-indicator.ui new file mode 100644 index 00000000..3987dff6 --- /dev/null +++ b/src/gui/gcal-sync-indicator.ui @@ -0,0 +1,39 @@ + + + + diff --git a/src/gui/gcal-window.c b/src/gui/gcal-window.c index dad25238..866521f2 100644 --- a/src/gui/gcal-window.c +++ b/src/gui/gcal-window.c @@ -33,6 +33,7 @@ #include "gcal-month-view.h" #include "gcal-quick-add-popover.h" #include "gcal-search-button.h" +#include "gcal-sync-indicator.h" #include "gcal-timeline.h" #include "gcal-timeline-subscriber.h" #include "gcal-toolbar-end.h" @@ -106,6 +107,7 @@ struct _GcalWindow GtkWidget *agenda_view; GtkWidget *date_chooser; GtkWidget *action_bar; + GcalSyncIndicator *sync_indicator; GcalToolbarEnd *toolbar_end; /* header_bar widets */ @@ -856,6 +858,7 @@ gcal_window_constructed (GObject *object) g_object_bind_property (self, "context", self->date_chooser, "context", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); g_object_bind_property (self, "context", self->event_editor, "context", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); g_object_bind_property (self, "context", self->quick_add_popover, "context", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); + g_object_bind_property (self, "context", self->sync_indicator, "context", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); g_object_bind_property (self, "context", self->toolbar_end, "context", G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE); /* CSS */ @@ -989,6 +992,7 @@ gcal_window_class_init (GcalWindowClass *klass) g_type_ensure (GCAL_TYPE_MANAGER); g_type_ensure (GCAL_TYPE_MONTH_VIEW); g_type_ensure (GCAL_TYPE_QUICK_ADD_POPOVER); + g_type_ensure (GCAL_TYPE_SYNC_INDICATOR); g_type_ensure (GCAL_TYPE_TOOLBAR_END); g_type_ensure (GCAL_TYPE_WEATHER_SETTINGS); g_type_ensure (GCAL_TYPE_WEEK_VIEW); @@ -1046,6 +1050,7 @@ gcal_window_class_init (GcalWindowClass *klass) gtk_widget_class_bind_template_child (widget_class, GcalWindow, quick_add_popover); gtk_widget_class_bind_template_child (widget_class, GcalWindow, calendar_management_dialog); gtk_widget_class_bind_template_child (widget_class, GcalWindow, overlay); + gtk_widget_class_bind_template_child (widget_class, GcalWindow, sync_indicator); gtk_widget_class_bind_template_child (widget_class, GcalWindow, toolbar_end); gtk_widget_class_bind_template_child (widget_class, GcalWindow, views_stack); gtk_widget_class_bind_template_child (widget_class, GcalWindow, views_switcher); diff --git a/src/gui/gcal-window.ui b/src/gui/gcal-window.ui index 5b336c4c..e0f3d96a 100644 --- a/src/gui/gcal-window.ui +++ b/src/gui/gcal-window.ui @@ -113,6 +113,9 @@ + + + diff --git a/src/gui/gui.gresource.xml b/src/gui/gui.gresource.xml index 41e61589..1abfeff8 100644 --- a/src/gui/gui.gresource.xml +++ b/src/gui/gui.gresource.xml @@ -7,6 +7,7 @@ gcal-meeting-row.ui gcal-quick-add-popover.ui gcal-search-button.ui + gcal-sync-indicator.ui gcal-toolbar-end.ui gcal-weather-settings.ui gcal-window.ui diff --git a/src/gui/meson.build b/src/gui/meson.build index 6f167647..9faf7573 100644 --- a/src/gui/meson.build +++ b/src/gui/meson.build @@ -23,6 +23,7 @@ sources += files( 'gcal-overflow-bin-layout.c', 'gcal-quick-add-popover.c', 'gcal-search-button.c', + 'gcal-sync-indicator.c', 'gcal-toolbar-end.c', 'gcal-weather-settings.c', 'gcal-window.c', diff --git a/src/theme/style.css b/src/theme/style.css index f23f935b..ff681e2d 100644 --- a/src/theme/style.css +++ b/src/theme/style.css @@ -409,3 +409,11 @@ datechooser .current-week { menubutton stack > box { border-spacing: 4px; } + +/* + * Sync Indicator + */ + +syncindicator { + padding: 6px; +}