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 @@
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 @@