[gnome-calendar] weather: Rework weather management



commit 499db7bfd49454caa12625413b843a7837463bbb
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Sat Jan 27 20:36:29 2018 -0200

    weather: Rework weather management
    
    This commit brings a few changes that I was too lazy to
    split in different commits:
    
     * Remove a few useless arguments in the GcalWeatherService API
     * Move the weather management code from GcalWindow to GcalWeatherSettings
     * A few style changes

 data/calendar.gresource.xml         |   1 +
 data/meson.build                    |   1 +
 data/ui/weather-settings.ui         |  77 +++++++
 data/ui/window.ui                   |  71 +------
 src/gcal-application.c              |  14 +-
 src/gcal-window.c                   | 279 +++----------------------
 src/meson.build                     |   1 +
 src/views/gcal-week-header.c        |   7 +-
 src/views/gcal-week-view.c          |  22 +-
 src/weather/gcal-weather-service.c  |  49 ++---
 src/weather/gcal-weather-service.h  |  11 +-
 src/weather/gcal-weather-settings.c | 391 ++++++++++++++++++++++++++++++++++++
 src/weather/gcal-weather-settings.h |  36 ++++
 13 files changed, 568 insertions(+), 392 deletions(-)
---
diff --git a/data/calendar.gresource.xml b/data/calendar.gresource.xml
index 40d081d1..5f8d36c7 100644
--- a/data/calendar.gresource.xml
+++ b/data/calendar.gresource.xml
@@ -16,6 +16,7 @@
     <file alias="search-view.ui" compressed="true">ui/search-view.ui</file>
     <file alias="source-dialog.ui" compressed="true">ui/source-dialog.ui</file>
     <file alias="time-selector.ui" compressed="true">ui/time-selector.ui</file>
+    <file alias="weather-settings.ui" compressed="true">ui/weather-settings.ui</file>
     <file alias="week-header.ui" compressed="true">ui/week-header.ui</file>
     <file alias="week-view.ui" compressed="true">ui/week-view.ui</file>
     <file alias="window.ui" compressed="true">ui/window.ui</file>
diff --git a/data/meson.build b/data/meson.build
index 4c5e0a7c..3418fd11 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -63,6 +63,7 @@ resource_data = files(
   'ui/search-view.ui',
   'ui/source-dialog.ui',
   'ui/time-selector.ui',
+  'ui/weather-settings.ui',
   'ui/week-header.ui',
   'ui/week-view.ui',
   'ui/window.ui',
diff --git a/data/ui/weather-settings.ui b/data/ui/weather-settings.ui
new file mode 100644
index 00000000..086a5f73
--- /dev/null
+++ b/data/ui/weather-settings.ui
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.14"/>
+  <template class="GcalWeatherSettings" parent="GtkBox">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="orientation">vertical</property>
+    <property name="margin">12</property>
+    <property name="spacing">6</property>
+    <child>
+      <object class="GtkModelButton">
+        <property name="text" translatable="yes">_Weather</property>
+        <property name="menu-name">main-menu</property>
+        <property name="inverted">True</property>
+        <property name="centered">True</property>
+        <property name="visible">True</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="spacing">18</property>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="xalign">0.0</property>
+            <property name="label" translatable="yes">Show Weather</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkSwitch" id="show_weather_switch">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <signal name="notify::active" handler="on_show_weather_changed_cb" object="GcalWeatherSettings" 
swapped="no" />
+          </object>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkBox" id="weather_auto_location_box">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="spacing">18</property>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="xalign">0.0</property>
+            <property name="label" translatable="yes">Automatic Location</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkSwitch" id="weather_auto_location_switch">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <signal name="notify::active" handler="on_weather_auto_location_changed_cb" 
object="GcalWeatherSettings" swapped="no" />
+          </object>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GWeatherLocationEntry" id="weather_location_entry">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="primary_icon_name">edit-find-symbolic</property>
+        <property name="primary_icon_activatable">False</property>
+        <property name="primary_icon_sensitive">False</property>
+        <signal name="changed" handler="on_weather_location_searchbox_changed_cb" 
object="GcalWeatherSettings" swapped="no" />
+        <signal name="activate" handler="on_weather_location_searchbox_changed_cb" 
object="GcalWeatherSettings" swapped="no" />
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/data/ui/window.ui b/data/ui/window.ui
index d20cf845..3acfd176 100644
--- a/data/ui/window.ui
+++ b/data/ui/window.ui
@@ -417,78 +417,9 @@
 
         <!-- Weather -->
         <child>
-          <object class="GtkBox">
+          <object class="GcalWeatherSettings" id="weather_settings">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="orientation">vertical</property>
-            <property name="margin">12</property>
-            <property name="spacing">6</property>
-            <child>
-              <object class="GtkModelButton">
-                <property name="text" translatable="yes">_Weather</property>
-                <property name="menu-name">main-menu</property>
-                <property name="inverted">True</property>
-                <property name="centered">True</property>
-                <property name="visible">True</property>
-              </object>
-            </child>
-            <child>
-              <object class="GtkBox">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="spacing">18</property>
-                <child>
-                  <object class="GtkLabel">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="hexpand">True</property>
-                    <property name="xalign">0.0</property>
-                    <property name="label" translatable="yes">Show Weather</property>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkSwitch" id="show_weather_switch">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <signal name="notify::active" handler="on_show_weather_changed_cb" object="GcalWindow" 
swapped="no" />
-                  </object>
-                </child>
-              </object>
-            </child>
-            <child>
-              <object class="GtkBox" id="weather_auto_location_box">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="spacing">18</property>
-                <child>
-                  <object class="GtkLabel">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="hexpand">True</property>
-                    <property name="xalign">0.0</property>
-                    <property name="label" translatable="yes">Automatic Location</property>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkSwitch" id="weather_auto_location_switch">
-                    <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <signal name="notify::active" handler="on_weather_auto_location_changed_cb" 
object="GcalWindow" swapped="no" />
-                  </object>
-                </child>
-              </object>
-            </child>
-            <child>
-              <object class="GWeatherLocationEntry" id="weather_location_entry">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="primary_icon_name">edit-find-symbolic</property>
-                <property name="primary_icon_activatable">False</property>
-                <property name="primary_icon_sensitive">False</property>
-                <signal name="changed" handler="on_weather_location_searchbox_changed_cb" 
object="GcalWindow" swapped="no" />
-                <signal name="activate" handler="on_weather_location_searchbox_changed_cb" 
object="GcalWindow" swapped="no" />
-              </object>
-            </child>
           </object>
           <packing>
             <property name="name">weather-menu</property>
diff --git a/src/gcal-application.c b/src/gcal-application.c
index 30d6e2df..bb0c3ccd 100644
--- a/src/gcal-application.c
+++ b/src/gcal-application.c
@@ -50,11 +50,7 @@ struct _GcalApplication
   gchar              *uuid;
   icaltimetype       *initial_date;
 
-  /* Weather service exists as long as #GcalApplication.
-   * However, it only runs if #GcalApplicatoin->window
-   * is available.
-   */
-  GcalWeatherService *weather_service; /* owned */
+  GcalWeatherService *weather_service;
 
   GcalShellSearchProvider *search_provider;
 };
@@ -431,11 +427,9 @@ gcal_application_init (GcalApplication *self)
   self->manager = gcal_manager_new ();
   g_signal_connect_swapped (self->manager, "source-added", G_CALLBACK (process_sources), self);
   g_signal_connect_swapped (self->manager, "source-changed", G_CALLBACK (process_sources), self);
-  self->weather_service = gcal_weather_service_new (NULL, /* in prep. for configurable time zones */
-                                                    GCAL_WEATHER_FORECAST_MAX_DAYS_DFLT,
-                                                    GCAL_WEATHER_CHECK_INTERVAL_NEW_DFLT,
-                                                    GCAL_WEATHER_CHECK_INTERVAL_RENEW_DFLT,
-                                                    GCAL_WEATHER_VALID_TIMESPAN_DFLT);
+
+  self->weather_service = gcal_weather_service_new ();
+
   self->search_provider = gcal_shell_search_provider_new ();
   gcal_shell_search_provider_connect (self->search_provider, self->manager);
 }
diff --git a/src/gcal-window.c b/src/gcal-window.c
index c01c2adc..f1efd5db 100644
--- a/src/gcal-window.c
+++ b/src/gcal-window.c
@@ -30,6 +30,7 @@
 #include "gcal-search-view.h"
 #include "gcal-source-dialog.h"
 #include "gcal-view.h"
+#include "gcal-weather-settings.h"
 #include "gcal-week-view.h"
 #include "gcal-window.h"
 #include "gcal-year-view.h"
@@ -163,11 +164,8 @@ struct _GcalWindow
   gint                open_edit_dialog_timeout_id;
 
   /* weather management */
-  GcalWeatherService *weather_service;
-  GtkSwitch          *show_weather_switch;
-  GtkSwitch          *weather_auto_location_switch;
-  GtkBox             *weather_auto_location_box;
-  GtkWidget          *weather_location_entry;
+  GcalWeatherService  *weather_service;
+  GcalWeatherSettings *weather_settings;
 
   /* temp to keep event_creation */
   gboolean            open_edit_dialog;
@@ -216,21 +214,6 @@ static void          on_toggle_search_bar_activated              (GSimpleAction
                                                                   GVariant           *param,
                                                                   gpointer            user_data);
 
-static void          on_weather_location_searchbox_changed_cb    (GWeatherLocationEntry *entry,
-                                                                  GcalWindow            *self);
-
-static void          on_show_weather_changed_cb                  (GtkSwitch          *wswitch,
-                                                                  GParamSpec         *pspec,
-                                                                  GcalWindow         *self);
-
-static void          on_weather_auto_location_changed_cb         (GtkSwitch          *lswitch,
-                                                                  GParamSpec         *pspec,
-                                                                  GcalWindow         *self);
-
-static void          update_menu_weather_sensitivity             (GcalWindow         *self);
-
-static void          load_weather_settings                       (GcalWindow         *self);
-
 G_DEFINE_TYPE (GcalWindow, gcal_window, GTK_TYPE_APPLICATION_WINDOW)
 
 static const GActionEntry actions[] = {
@@ -265,139 +248,6 @@ hide_search_view_on_click_outside (GcalWindow     *window,
   return GDK_EVENT_PROPAGATE;
 }
 
-static GWeatherLocation*
-get_checked_fixed_location (GcalWindow *self)
-{
-  g_autoptr (GWeatherLocation) location;
-
-  location = gweather_location_entry_get_location (GWEATHER_LOCATION_ENTRY (self->weather_location_entry));
-
-  /*
-   * NOTE: This check feels shabby. However, I couldn't find a better
-   * one without iterating the model. has-custom-text does not work
-   * properly. Lets go with it for now.
-   */
-  if (location && gweather_location_get_name (location))
-    return g_steal_pointer (&location);
-
-  return NULL;
-}
-
-static void
-load_weather_settings (GcalWindow *self)
-{
-  g_autoptr (GVariant) location = NULL;
-  g_autoptr (GVariant) value = NULL;
-  g_autofree gchar *location_name = NULL;
-  GSettings *settings;
-  gboolean show_weather;
-  gboolean auto_location;
-
-  settings = gcal_manager_get_settings (self->manager);
-  value = g_settings_get_value (settings, "weather-settings");
-
-  g_variant_get (value, "(bbsmv)",
-                 &show_weather,
-                 &auto_location,
-                 &location_name,
-                 &location);
-
-  g_signal_handlers_block_by_func (self->show_weather_switch, on_show_weather_changed_cb, self);
-  g_signal_handlers_block_by_func (self->weather_auto_location_switch, on_weather_auto_location_changed_cb, 
self);
-  g_signal_handlers_block_by_func (self->weather_location_entry, on_weather_location_searchbox_changed_cb, 
self);
-
-  gtk_switch_set_active (self->show_weather_switch, show_weather);
-  gtk_switch_set_active (self->weather_auto_location_switch, auto_location);
-
-  if (!location && !auto_location)
-    {
-      GtkStyleContext *context;
-
-      context = gtk_widget_get_style_context (GTK_WIDGET (self->weather_location_entry));
-      gtk_entry_set_text (GTK_ENTRY (self->weather_location_entry), location_name);
-      gtk_style_context_add_class (context, "error");
-    }
-  else
-    {
-      g_autoptr (GWeatherLocation) weather_location;
-      GWeatherLocation *world;
-
-      world = gweather_location_get_world ();
-      weather_location = gweather_location_deserialize (world, location);
-
-      gweather_location_entry_set_location (GWEATHER_LOCATION_ENTRY (self->weather_location_entry), 
weather_location);
-    }
-
-  g_signal_handlers_unblock_by_func (self->show_weather_switch, on_show_weather_changed_cb, self);
-  g_signal_handlers_unblock_by_func (self->weather_auto_location_switch, 
on_weather_auto_location_changed_cb, self);
-  g_signal_handlers_unblock_by_func (self->weather_location_entry, on_weather_location_searchbox_changed_cb, 
self);
-}
-
-static void
-manage_weather_service (GcalWindow *self)
-{
-  g_autoptr (GWeatherLocation) location = NULL;
-
-  gcal_weather_service_stop (self->weather_service);
-
-  if (!gtk_switch_get_active (self->show_weather_switch))
-    return;
-
-  if (gtk_switch_get_active (self->weather_auto_location_switch))
-    {
-      gcal_weather_service_run (self->weather_service, NULL);
-      return;
-    }
-
-  location = get_checked_fixed_location (self);
-  if (!location)
-    {
-      /* TODO: this one should get reported to users */
-      g_warning ("Unknown location '%s' selected", gtk_entry_get_text (GTK_ENTRY 
(self->weather_location_entry)));
-      return;
-    }
-
-  gcal_weather_service_run (self->weather_service, location);
-}
-
-static void
-save_weather_settings (GcalWindow *self)
-{
-  g_autoptr (GWeatherLocation) location;
-  GSettings *settings;
-  GVariant *value;
-  GVariant *vlocation;
-  gboolean res;
-
-  location = gweather_location_entry_get_location (GWEATHER_LOCATION_ENTRY (self->weather_location_entry));
-  vlocation = location ? gweather_location_serialize (location) : NULL;
-
-  settings = gcal_manager_get_settings (self->manager);
-  value = g_variant_new ("(bbsmv)",
-                         gtk_switch_get_active (self->show_weather_switch),
-                         gtk_switch_get_active (self->weather_auto_location_switch),
-                         gtk_entry_get_text (GTK_ENTRY (self->weather_location_entry)),
-                         vlocation);
-
-  res = g_settings_set_value (settings, "weather-settings", value);
-
-  if (!res)
-    g_warning ("Could not persist weather settings");
-}
-
-static void
-update_menu_weather_sensitivity (GcalWindow *self)
-{
-  gboolean weather_enabled;
-  gboolean autoloc_enabled;
-
-  weather_enabled = gtk_switch_get_active (self->show_weather_switch);
-  autoloc_enabled = gtk_switch_get_active (self->weather_auto_location_switch);
-
-  gtk_widget_set_sensitive (GTK_WIDGET (self->weather_auto_location_switch), weather_enabled);
-  gtk_widget_set_sensitive (GTK_WIDGET (self->weather_location_entry), weather_enabled && !autoloc_enabled);
-}
-
 static void
 update_today_button_sensitive (GcalWindow *window)
 {
@@ -1112,20 +962,6 @@ window_state_changed (GtkWidget *widget,
   return FALSE;
 }
 
-static void
-on_show_weather_changed_cb (GtkSwitch  *wswitch,
-                            GParamSpec *pspec,
-                            GcalWindow *self)
-{
-  save_weather_settings (self);
-
-  if (!gtk_switch_get_active (wswitch))
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->menu_button), FALSE);
-
-  update_menu_weather_sensitivity (self);
-  manage_weather_service (self);
-}
-
 static void
 on_popover_menu_visible_cb (GtkWidget  *widget,
                             GParamSpec *pspec,
@@ -1134,48 +970,6 @@ on_popover_menu_visible_cb (GtkWidget  *widget,
   gtk_stack_set_visible_child_name (GTK_STACK (self->win_menu_stack), "main-menu");
 }
 
-static void
-on_weather_auto_location_changed_cb (GtkSwitch  *lswitch,
-                                     GParamSpec *pspec,
-                                     GcalWindow *self)
-{
-  save_weather_settings (self);
-
-  if (gtk_switch_get_active (lswitch))
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->menu_button), FALSE);
-
-  update_menu_weather_sensitivity (self);
-  manage_weather_service (self);
-}
-
-static void
-on_weather_location_searchbox_changed_cb (GWeatherLocationEntry *entry,
-                                          GcalWindow            *self)
-{
-  GtkStyleContext  *context;
-  GWeatherLocation *location;
-  gboolean auto_location;
-
-  save_weather_settings (self);
-
-  context = gtk_widget_get_style_context (self->weather_location_entry);
-  auto_location = gtk_switch_get_active (self->weather_auto_location_switch);
-  location = get_checked_fixed_location (self);
-
-  if (!location && !auto_location)
-    {
-      gtk_style_context_add_class (context, "error");
-    }
-  else
-    {
-      gtk_style_context_remove_class (context, "error");
-
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->menu_button), FALSE);
-      manage_weather_service (self);
-      gweather_location_unref (location);
-    }
-}
-
 static void
 edit_event (GcalQuickAddPopover *popover,
             GcalEvent           *event,
@@ -1482,17 +1276,16 @@ gcal_window_set_property (GObject      *object,
     case PROP_ACTIVE_VIEW:
       self->active_view = g_value_get_enum (value);
       gtk_widget_show (self->views[self->active_view]);
-      gtk_stack_set_visible_child (GTK_STACK (self->views_stack),
-                                   self->views[self->active_view]);
-      return;
+      gtk_stack_set_visible_child (GTK_STACK (self->views_stack), self->views[self->active_view]);
+      break;
 
     case PROP_ACTIVE_DATE:
       update_active_date (GCAL_WINDOW (object), g_value_dup_boxed (value));
-      return;
+      break;
 
     case PROP_NEW_EVENT_MODE:
       set_new_event_mode (GCAL_WINDOW (object), g_value_get_boolean (value));
-      return;
+      break;
 
     case PROP_MANAGER:
       if (g_set_object (&self->manager, g_value_get_object (value)))
@@ -1524,20 +1317,7 @@ gcal_window_set_property (GObject      *object,
 
           g_object_notify (object, "manager");
         }
-      return;
-
-    case PROP_WEATHER_SERVICE:
-      {
-        GcalWeatherService *service; /* unowned */
-
-        service = GCAL_WEATHER_SERVICE (g_value_get_object (value));
-        g_return_if_fail (service != NULL);
-
-        g_return_if_fail (self->weather_service == NULL);
-        self->weather_service = (GcalWeatherService*) g_object_ref (service);
-        g_object_notify (object, "weather-service");
-        return ;
-      }
+      break;
 
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -1558,23 +1338,23 @@ gcal_window_get_property (GObject    *object,
     {
     case PROP_ACTIVE_VIEW:
       g_value_set_enum (value, self->active_view);
-      return;
+      break;
 
     case PROP_MANAGER:
       g_value_set_object (value, self->manager);
-      return;
+      break;
 
     case PROP_WEATHER_SERVICE:
       g_value_set_object (value, self->weather_service);
-      return;
+      break;
 
     case PROP_ACTIVE_DATE:
       g_value_set_boxed (value, self->active_date);
-      return;
+      break;
 
     case PROP_NEW_EVENT_MODE:
       g_value_set_boolean (value, self->new_event_mode);
-      return;
+      break;
 
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -1610,8 +1390,9 @@ gcal_window_class_init (GcalWindowClass *klass)
   g_type_ensure (GCAL_TYPE_QUICK_ADD_POPOVER);
   g_type_ensure (GCAL_TYPE_SEARCH_VIEW);
   g_type_ensure (GCAL_TYPE_SOURCE_DIALOG);
-  g_type_ensure (GCAL_TYPE_WEEK_VIEW);
   g_type_ensure (GCAL_TYPE_WEATHER_SERVICE);
+  g_type_ensure (GCAL_TYPE_WEATHER_SETTINGS);
+  g_type_ensure (GCAL_TYPE_WEEK_VIEW);
   g_type_ensure (GCAL_TYPE_YEAR_VIEW);
 
   object_class = G_OBJECT_CLASS (klass);
@@ -1652,7 +1433,7 @@ gcal_window_class_init (GcalWindowClass *klass)
                                                           "The weather service object",
                                                           "The weather service object",
                                                           GCAL_TYPE_WEATHER_SERVICE,
-                                                          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | 
G_PARAM_STATIC_STRINGS);
+                                                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
   g_object_class_install_properties (object_class, N_PROPS, properties);
 
@@ -1675,15 +1456,12 @@ gcal_window_class_init (GcalWindowClass *klass)
   gtk_widget_class_bind_template_child (widget_class, GcalWindow, source_dialog);
   gtk_widget_class_bind_template_child (widget_class, GcalWindow, search_entry);
   gtk_widget_class_bind_template_child (widget_class, GcalWindow, search_view);
-  gtk_widget_class_bind_template_child (widget_class, GcalWindow, show_weather_switch);
   gtk_widget_class_bind_template_child (widget_class, GcalWindow, today_button);
   gtk_widget_class_bind_template_child (widget_class, GcalWindow, views_overlay);
   gtk_widget_class_bind_template_child (widget_class, GcalWindow, views_stack);
   gtk_widget_class_bind_template_child (widget_class, GcalWindow, views_switcher);
-  gtk_widget_class_bind_template_child (widget_class, GcalWindow, weather_auto_location_box);
-  gtk_widget_class_bind_template_child (widget_class, GcalWindow, weather_auto_location_switch);
-  gtk_widget_class_bind_template_child (widget_class, GcalWindow, weather_location_entry);
   gtk_widget_class_bind_template_child (widget_class, GcalWindow, win_menu_stack);
+  gtk_widget_class_bind_template_child (widget_class, GcalWindow, weather_settings);
   gtk_widget_class_bind_template_child (widget_class, GcalWindow, week_view);
   gtk_widget_class_bind_template_child (widget_class, GcalWindow, year_view);
 
@@ -1701,9 +1479,6 @@ gcal_window_class_init (GcalWindowClass *klass)
   gtk_widget_class_bind_template_callback (widget_class, date_updated);
 
   gtk_widget_class_bind_template_callback (widget_class, on_popover_menu_visible_cb);
-  gtk_widget_class_bind_template_callback (widget_class, on_show_weather_changed_cb);
-  gtk_widget_class_bind_template_callback (widget_class, on_weather_auto_location_changed_cb);
-  gtk_widget_class_bind_template_callback (widget_class, on_weather_location_searchbox_changed_cb);
 
   /* Event removal related */
   gtk_widget_class_bind_template_callback (widget_class, hide_notification);
@@ -1741,6 +1516,9 @@ gcal_window_init (GcalWindow *self)
                                    G_N_ELEMENTS (actions),
                                    self);
 
+  app = g_application_get_default ();
+  self->weather_service = gcal_application_get_weather_service (GCAL_APPLICATION (app));
+
   gtk_widget_init_template (GTK_WIDGET (self));
 
   /* source dialog */
@@ -1789,16 +1567,17 @@ gcal_window_init (GcalWindow *self)
    */
   g_object_bind_property (self, "manager", self->edit_dialog, "manager", G_BINDING_DEFAULT);
   g_object_bind_property (self, "manager", self->source_dialog, "manager", G_BINDING_DEFAULT);
+  g_object_bind_property (self, "manager", self->weather_settings, "manager", G_BINDING_DEFAULT);
   g_object_bind_property (self, "manager", self->week_view, "manager", G_BINDING_DEFAULT);
   g_object_bind_property (self, "manager", self->month_view, "manager", G_BINDING_DEFAULT);
   g_object_bind_property (self, "manager", self->year_view, "manager", G_BINDING_DEFAULT);
   g_object_bind_property (self, "manager", self->quick_add_popover, "manager", G_BINDING_DEFAULT);
-  g_object_bind_property (self, "weather-service", self->month_view, "weather-service", G_BINDING_DEFAULT);
-  g_object_bind_property (self, "weather-service", self->year_view, "weather-service", G_BINDING_DEFAULT);
+  g_object_bind_property (self, "weather-service", self->weather_settings, "weather-service", 
G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
+  g_object_bind_property (self, "weather-service", self->month_view, "weather-service", G_BINDING_DEFAULT | 
G_BINDING_SYNC_CREATE);
+  g_object_bind_property (self, "weather-service", self->week_view, "weather-service", G_BINDING_DEFAULT | 
G_BINDING_SYNC_CREATE);
+  g_object_bind_property (self, "weather-service", self->year_view, "weather-service", G_BINDING_DEFAULT | 
G_BINDING_SYNC_CREATE);
 
   /* setup accels */
-  app = g_application_get_default ();
-
   gcal_window_add_accelerator (app, "win.change-view(-1)",   "<Ctrl>Page_Down");
   gcal_window_add_accelerator (app, "win.change-view(-2)",   "<Ctrl>Page_Up");
   gcal_window_add_accelerator (app, "win.change-view(1)",    "<Ctrl>1")
@@ -1820,15 +1599,12 @@ GtkWidget*
 gcal_window_new_with_date (GcalApplication *app,
                            icaltimetype    *date)
 {
-  GcalWeatherService *weather_service;
   GcalManager *manager;
   GcalWindow *win;
 
-  weather_service = gcal_application_get_weather_service (GCAL_APPLICATION (app));
   manager = gcal_application_get_manager (GCAL_APPLICATION (app));
   win = g_object_new (GCAL_TYPE_WINDOW,
                       "application", GTK_APPLICATION (app),
-                      "weather-service", weather_service,
                       "manager", manager,
                       "active-date", date,
                       NULL);
@@ -1836,11 +1612,6 @@ gcal_window_new_with_date (GcalApplication *app,
   /* loading size */
   load_geometry (win);
 
-  /* Recover weather settings */
-  load_weather_settings (win);
-  update_menu_weather_sensitivity (win);
-  manage_weather_service (win);
-
   return GTK_WIDGET (win);
 }
 
diff --git a/src/meson.build b/src/meson.build
index 869e43c8..b3704065 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -33,6 +33,7 @@ sources = files(
   'views/gcal-year-view.c',
   'weather/gcal-weather-info.c',
   'weather/gcal-weather-service.c',
+  'weather/gcal-weather-settings.c',
   'gcal-application.c',
   'gcal-clock.c',
   'gcal-date-chooser-day.c',
diff --git a/src/views/gcal-week-header.c b/src/views/gcal-week-header.c
index a52ac51d..2e8e922d 100644
--- a/src/views/gcal-week-header.c
+++ b/src/views/gcal-week-header.c
@@ -1674,7 +1674,7 @@ gcal_week_header_init (GcalWeekHeader *self)
   self->selection_end = -1;
   self->dnd_cell = -1;
   self->weather_service = NULL;
-  memset (self->weather_infos, 0, sizeof(self->weather_infos));
+
   gtk_widget_init_template (GTK_WIDGET (self));
 
   /* This is to avoid stray lines when adding and removing events */
@@ -1712,7 +1712,8 @@ gcal_week_header_add_weather_infos (GcalWeekHeader *self,
   gint consumed = 0;
   guint i;
 
-  g_return_val_if_fail (self != NULL, 0);
+  if (!self->active_date)
+    return 0;
 
   week_start_dt = get_start_of_week (self->active_date);
   g_date_set_dmy (&week_start,
@@ -2066,7 +2067,7 @@ gcal_week_header_set_date (GcalWeekHeader *self,
  *           Elements are owned by the widget. Do not modify.
  */
 GSList*
-gcal_week_header_get_shown_weather_infos (GcalWeekHeader  *self)
+gcal_week_header_get_shown_weather_infos (GcalWeekHeader *self)
 {
   g_return_val_if_fail (GCAL_IS_WEEK_HEADER (self), NULL);
   GSList* lst = NULL; /* owned[unowned] */
diff --git a/src/views/gcal-week-view.c b/src/views/gcal-week-view.c
index 77ae920c..a2bcd152 100644
--- a/src/views/gcal-week-view.c
+++ b/src/views/gcal-week-view.c
@@ -546,23 +546,9 @@ gcal_week_view_set_property (GObject       *object,
       break;
 
     case PROP_WEATHER_SERVICE:
-      {
-        GcalWeatherService* weather_service; /* unowned */
-        weather_service = g_value_get_object (value);
-
-        g_return_if_fail (weather_service == NULL || GCAL_IS_WEATHER_SERVICE (weather_service));
-
-        if (self->weather_service != weather_service)
-          {
-            g_set_object (&self->weather_service, weather_service);
-
-            gcal_week_header_set_weather_service (GCAL_WEEK_HEADER (self->header),
-                                                  self->weather_service);
-
-            g_object_notify (object, "weather-service");
-          }
-        break;
-      }
+      if (g_set_object (&self->weather_service, g_value_get_object (value)))
+        g_object_notify (object, "weather-service");
+      break;
 
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -639,6 +625,8 @@ gcal_week_view_init (GcalWeekView *self)
   update_hours_sidebar_size (self);
 
   self->weather_service = NULL;
+
+  g_object_bind_property (self, "weather-service", self->header, "weather-service", G_BINDING_DEFAULT);
 }
 
 /* Public API */
diff --git a/src/weather/gcal-weather-service.c b/src/weather/gcal-weather-service.c
index 3639ffca..99d63d4a 100644
--- a/src/weather/gcal-weather-service.c
+++ b/src/weather/gcal-weather-service.c
@@ -30,6 +30,11 @@
 #include "gcal-weather-service.h"
 
 
+#define GCAL_WEATHER_CHECK_INTERVAL_RENEW_DEFAULT (3 * 60 * 60)  /* seconds */
+#define GCAL_WEATHER_CHECK_INTERVAL_NEW_DEFAULT   (5 * 60)       /* seconds */
+#define GCAL_WEATHER_VALID_TIMESPAN_DEFAULT       (24 * 60 * 60) /* seconds */
+#define GCAL_WEATHER_FORECAST_MAX_DAYS_DEFAULT     3
+
 #define DAY_SECONDS (24 * 60 * 60)
 
 /**
@@ -263,7 +268,7 @@ set_check_interval_new (GcalWeatherService *self,
   self->check_interval_new = interval;
   update_timeout_interval (self);
 
-  g_object_notify ((GObject*) self, "check-interval-new");
+  g_object_notify (G_OBJECT (self), "check-interval-new");
 }
 
 static void
@@ -273,7 +278,7 @@ set_check_interval_renew (GcalWeatherService *self,
   self->check_interval_renew = interval;
   update_timeout_interval (self);
 
-  g_object_notify ((GObject*) self, "check-interval-renew");
+  g_object_notify (G_OBJECT (self), "check-interval-renew");
 }
 
 static gssize
@@ -830,7 +835,7 @@ set_max_days (GcalWeatherService *self,
 
   self->max_days = days;
 
-  g_object_notify ((GObject*) self, "max-days");
+  g_object_notify (G_OBJECT (self), "max-days");
 }
 
 static void
@@ -841,7 +846,7 @@ set_valid_timespan (GcalWeatherService *self,
 
   self->valid_timespan = timespan;
 
-  g_object_notify ((GObject*) self, "valid-timespan");
+  g_object_notify (G_OBJECT (self), "valid-timespan");
 }
 
 static gboolean
@@ -1057,7 +1062,7 @@ gcal_weather_service_class_init (GcalWeatherServiceClass *klass)
                                                       "check-interval-new",
                                                       0,
                                                       G_MAXUINT,
-                                                      GCAL_WEATHER_CHECK_INTERVAL_NEW_DFLT,
+                                                      GCAL_WEATHER_CHECK_INTERVAL_NEW_DEFAULT,
                                                       G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | 
G_PARAM_CONSTRUCT_ONLY));
 
   /**
@@ -1073,7 +1078,7 @@ gcal_weather_service_class_init (GcalWeatherServiceClass *klass)
                                                       "check-interval-renew",
                                                       0,
                                                       G_MAXUINT,
-                                                      GCAL_WEATHER_CHECK_INTERVAL_RENEW_DFLT,
+                                                      GCAL_WEATHER_CHECK_INTERVAL_RENEW_DEFAULT,
                                                       G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | 
G_PARAM_CONSTRUCT_ONLY));
 
   /**
@@ -1088,7 +1093,7 @@ gcal_weather_service_class_init (GcalWeatherServiceClass *klass)
                                                        "valid-timespan",
                                                        0,
                                                        G_MAXINT64,
-                                                       GCAL_WEATHER_VALID_TIMESPAN_DFLT,
+                                                       GCAL_WEATHER_VALID_TIMESPAN_DEFAULT,
                                                        G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | 
G_PARAM_CONSTRUCT_ONLY));
 
 
@@ -1115,13 +1120,14 @@ gcal_weather_service_class_init (GcalWeatherServiceClass *klass)
 static void
 gcal_weather_service_init (GcalWeatherService *self)
 {
-  self->check_interval_new = GCAL_WEATHER_CHECK_INTERVAL_NEW_DFLT;
-  self->check_interval_renew = GCAL_WEATHER_CHECK_INTERVAL_RENEW_DFLT;
+  self->max_days = GCAL_WEATHER_FORECAST_MAX_DAYS_DEFAULT;
+  self->check_interval_new = GCAL_WEATHER_CHECK_INTERVAL_NEW_DEFAULT;
+  self->check_interval_renew = GCAL_WEATHER_CHECK_INTERVAL_RENEW_DEFAULT;
   self->location_cancellable = g_cancellable_new ();
   self->weather_infos_upated = -1;
-  self->valid_timespan = -1;
+  self->valid_timespan = GCAL_WEATHER_VALID_TIMESPAN_DEFAULT;
 
-  self->duration_timer = gcal_timer_new (GCAL_WEATHER_CHECK_INTERVAL_NEW_DFLT);
+  self->duration_timer = gcal_timer_new (GCAL_WEATHER_CHECK_INTERVAL_NEW_DEFAULT);
   gcal_timer_set_callback (self->duration_timer, (GCalTimerFunc) on_duration_timer_timeout, self, NULL);
 
   self->midnight_timer = gcal_timer_new (24 * 60 * 60);
@@ -1135,29 +1141,16 @@ gcal_weather_service_init (GcalWeatherService *self)
 
 /**
  * gcal_weather_service_new:
- * @max_days:       mumber of days to fetch forecasts for.
- * @check_interval_new:   timeout used when fetching new weather reports.
- * @check_interval_renew: timeout used to update valid weather reports.
  *
  * Creates a new #GcalWeatherService. This service listens
  * to location and weather changes and reports them.
  *
  * Returns: (transfer full): A newly created #GcalWeatherService.
  */
-GcalWeatherService *
-gcal_weather_service_new (GTimeZone *time_zone,
-                          guint      max_days,
-                          guint      check_interval_new,
-                          guint      check_interval_renew,
-                          gint64     valid_timespan)
+GcalWeatherService*
+gcal_weather_service_new (void)
 {
-  return g_object_new (GCAL_TYPE_WEATHER_SERVICE,
-                       "time-zone", time_zone,
-                       "max-days", max_days,
-                       "check-interval-new", check_interval_new,
-                       "check-interval-renew", check_interval_renew,
-                       "valid-timespan", valid_timespan,
-                       NULL);
+  return g_object_new (GCAL_TYPE_WEATHER_SERVICE, NULL);
 }
 
 /**
@@ -1199,7 +1192,7 @@ gcal_weather_service_set_time_zone (GcalWeatherService *self,
   /* make sure midnight is timed correctly: */
   schedule_midnight (self);
 
-  g_object_notify ((GObject*) self, "time-zone");
+  g_object_notify (G_OBJECT (self), "time-zone");
 }
 
 /**
diff --git a/src/weather/gcal-weather-service.h b/src/weather/gcal-weather-service.h
index cdcd4258..fb3833a6 100644
--- a/src/weather/gcal-weather-service.h
+++ b/src/weather/gcal-weather-service.h
@@ -27,21 +27,12 @@
 
 G_BEGIN_DECLS
 
-#define GCAL_WEATHER_CHECK_INTERVAL_RENEW_DFLT (3 * 60 * 60)  /* seconds */
-#define GCAL_WEATHER_CHECK_INTERVAL_NEW_DFLT   (5 * 60)       /* seconds */
-#define GCAL_WEATHER_VALID_TIMESPAN_DFLT       (24 * 60 * 60) /* seconds */
-#define GCAL_WEATHER_FORECAST_MAX_DAYS_DFLT     3
-
 #define GCAL_TYPE_WEATHER_SERVICE (gcal_weather_service_get_type())
 
 G_DECLARE_FINAL_TYPE (GcalWeatherService, gcal_weather_service, GCAL, WEATHER_SERVICE, GObject)
 
 
-GcalWeatherService*  gcal_weather_service_new                    (GTimeZone          *time_zone,
-                                                                  guint               max_days,
-                                                                  guint               check_interval_new,
-                                                                  guint               check_interval_renew,
-                                                                  gint64              valid_timespan);
+GcalWeatherService*  gcal_weather_service_new                    (void);
 
 GTimeZone*           gcal_weather_service_get_time_zone          (GcalWeatherService *self);
 
diff --git a/src/weather/gcal-weather-settings.c b/src/weather/gcal-weather-settings.c
new file mode 100644
index 00000000..0fb21aab
--- /dev/null
+++ b/src/weather/gcal-weather-settings.c
@@ -0,0 +1,391 @@
+/* gcal-weather-settings.c
+ *
+ * Copyright © 2018 Georges Basile Stavracas Neto <georges stavracas gmail com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "gcal-manager.h"
+#include "gcal-utils.h"
+#include "gcal-weather-service.h"
+#include "gcal-weather-settings.h"
+
+struct _GcalWeatherSettings
+{
+  GtkBox              parent;
+
+  GtkSwitch          *show_weather_switch;
+  GtkSwitch          *weather_auto_location_switch;
+  GtkWidget          *weather_location_entry;
+
+  GcalManager        *manager;
+
+  GcalWeatherService *weather_service;
+};
+
+
+static void          on_weather_location_searchbox_changed_cb    (GWeatherLocationEntry *entry,
+                                                                  GcalWeatherSettings   *self);
+
+static void          on_show_weather_changed_cb                  (GtkSwitch           *wswitch,
+                                                                  GParamSpec          *pspec,
+                                                                  GcalWeatherSettings *self);
+
+static void          on_weather_auto_location_changed_cb         (GtkSwitch           *lswitch,
+                                                                  GParamSpec          *pspec,
+                                                                  GcalWeatherSettings *self);
+
+G_DEFINE_TYPE (GcalWeatherSettings, gcal_weather_settings, GTK_TYPE_BOX)
+
+enum
+{
+  PROP_0,
+  PROP_MANAGER,
+  PROP_WEATHER_SERVICE,
+  N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS] = { NULL, };
+
+
+/*
+ * Auxiliary methods
+ */
+
+static void
+load_weather_settings (GcalWeatherSettings *self)
+{
+  g_autoptr (GVariant) location = NULL;
+  g_autoptr (GVariant) value = NULL;
+  g_autofree gchar *location_name = NULL;
+  GSettings *settings;
+  gboolean show_weather;
+  gboolean auto_location;
+
+  if (!self->manager)
+    return;
+
+  settings = gcal_manager_get_settings (self->manager);
+  value = g_settings_get_value (settings, "weather-settings");
+
+  g_variant_get (value, "(bbsmv)",
+                 &show_weather,
+                 &auto_location,
+                 &location_name,
+                 &location);
+
+  g_signal_handlers_block_by_func (self->show_weather_switch, on_show_weather_changed_cb, self);
+  g_signal_handlers_block_by_func (self->weather_auto_location_switch, on_weather_auto_location_changed_cb, 
self);
+  g_signal_handlers_block_by_func (self->weather_location_entry, on_weather_location_searchbox_changed_cb, 
self);
+
+  gtk_switch_set_active (self->show_weather_switch, show_weather);
+  gtk_switch_set_active (self->weather_auto_location_switch, auto_location);
+
+  if (!location && !auto_location)
+    {
+      GtkStyleContext *context;
+
+      context = gtk_widget_get_style_context (GTK_WIDGET (self->weather_location_entry));
+      gtk_entry_set_text (GTK_ENTRY (self->weather_location_entry), location_name);
+      gtk_style_context_add_class (context, "error");
+    }
+  else
+    {
+      g_autoptr (GWeatherLocation) weather_location;
+      GWeatherLocation *world;
+
+      world = gweather_location_get_world ();
+      weather_location = gweather_location_deserialize (world, location);
+
+      gweather_location_entry_set_location (GWEATHER_LOCATION_ENTRY (self->weather_location_entry), 
weather_location);
+    }
+
+  g_signal_handlers_unblock_by_func (self->show_weather_switch, on_show_weather_changed_cb, self);
+  g_signal_handlers_unblock_by_func (self->weather_auto_location_switch, 
on_weather_auto_location_changed_cb, self);
+  g_signal_handlers_unblock_by_func (self->weather_location_entry, on_weather_location_searchbox_changed_cb, 
self);
+}
+
+static void
+save_weather_settings (GcalWeatherSettings *self)
+{
+  g_autoptr (GWeatherLocation) location = NULL;
+  GSettings *settings;
+  GVariant *value;
+  GVariant *vlocation;
+  gboolean res;
+
+  if (!self->manager)
+    return;
+
+  location = gweather_location_entry_get_location (GWEATHER_LOCATION_ENTRY (self->weather_location_entry));
+  vlocation = location ? gweather_location_serialize (location) : NULL;
+
+  settings = gcal_manager_get_settings (self->manager);
+  value = g_variant_new ("(bbsmv)",
+                         gtk_switch_get_active (self->show_weather_switch),
+                         gtk_switch_get_active (self->weather_auto_location_switch),
+                         gtk_entry_get_text (GTK_ENTRY (self->weather_location_entry)),
+                         vlocation);
+
+  res = g_settings_set_value (settings, "weather-settings", value);
+
+  if (!res)
+    g_warning ("Could not persist weather settings");
+}
+
+static void
+update_menu_weather_sensitivity (GcalWeatherSettings *self)
+{
+  gboolean weather_enabled;
+  gboolean autoloc_enabled;
+
+  weather_enabled = gtk_switch_get_active (self->show_weather_switch);
+  autoloc_enabled = gtk_switch_get_active (self->weather_auto_location_switch);
+
+  gtk_widget_set_sensitive (GTK_WIDGET (self->weather_auto_location_switch), weather_enabled);
+  gtk_widget_set_sensitive (GTK_WIDGET (self->weather_location_entry), weather_enabled && !autoloc_enabled);
+}
+
+
+static GWeatherLocation*
+get_checked_fixed_location (GcalWeatherSettings *self)
+{
+  g_autoptr (GWeatherLocation) location;
+
+  location = gweather_location_entry_get_location (GWEATHER_LOCATION_ENTRY (self->weather_location_entry));
+
+  /*
+   * NOTE: This check feels shabby. However, I couldn't find a better
+   * one without iterating the model. has-custom-text does not work
+   * properly. Lets go with it for now.
+   */
+  if (location && gweather_location_get_name (location))
+    return g_steal_pointer (&location);
+
+  return NULL;
+}
+
+static void
+manage_weather_service (GcalWeatherSettings *self)
+{
+  g_autoptr (GWeatherLocation) location = NULL;
+
+  gcal_weather_service_stop (self->weather_service);
+
+  if (!gtk_switch_get_active (self->show_weather_switch))
+    return;
+
+  if (gtk_switch_get_active (self->weather_auto_location_switch))
+    {
+      gcal_weather_service_run (self->weather_service, NULL);
+      return;
+    }
+
+  location = get_checked_fixed_location (self);
+  if (!location)
+    {
+      /* TODO: this one should get reported to users */
+      g_warning ("Unknown location '%s' selected", gtk_entry_get_text (GTK_ENTRY 
(self->weather_location_entry)));
+      return;
+    }
+
+  gcal_weather_service_run (self->weather_service, location);
+}
+
+
+/*
+ * Callbacks
+ */
+
+static void
+on_show_weather_changed_cb (GtkSwitch           *wswitch,
+                            GParamSpec          *pspec,
+                            GcalWeatherSettings *self)
+{
+  save_weather_settings (self);
+  update_menu_weather_sensitivity (self);
+  manage_weather_service (self);
+}
+
+
+static void
+on_weather_auto_location_changed_cb (GtkSwitch           *lswitch,
+                                     GParamSpec          *pspec,
+                                     GcalWeatherSettings *self)
+{
+  save_weather_settings (self);
+  update_menu_weather_sensitivity (self);
+  manage_weather_service (self);
+}
+
+static void
+on_weather_location_searchbox_changed_cb (GWeatherLocationEntry *entry,
+                                          GcalWeatherSettings   *self)
+{
+  GtkStyleContext  *context;
+  GWeatherLocation *location;
+  gboolean auto_location;
+
+  save_weather_settings (self);
+
+  context = gtk_widget_get_style_context (self->weather_location_entry);
+  auto_location = gtk_switch_get_active (self->weather_auto_location_switch);
+  location = get_checked_fixed_location (self);
+
+  if (!location && !auto_location)
+    {
+      gtk_style_context_add_class (context, "error");
+    }
+  else
+    {
+      gtk_style_context_remove_class (context, "error");
+      manage_weather_service (self);
+      gweather_location_unref (location);
+    }
+}
+
+
+
+/*
+ * GObject overrides
+ */
+
+static void
+gcal_weather_settings_finalize (GObject *object)
+{
+  GcalWeatherSettings *self = (GcalWeatherSettings *)object;
+
+  g_clear_object (&self->weather_service);
+
+  G_OBJECT_CLASS (gcal_weather_settings_parent_class)->finalize (object);
+}
+
+static void
+gcal_weather_settings_get_property (GObject    *object,
+                                    guint       prop_id,
+                                    GValue     *value,
+                                    GParamSpec *pspec)
+{
+  GcalWeatherSettings *self = GCAL_WEATHER_SETTINGS (object);
+
+  switch (prop_id)
+    {
+    case PROP_MANAGER:
+      g_value_set_object (value, self->manager);
+      break;
+
+    case PROP_WEATHER_SERVICE:
+      g_value_set_object (value, self->weather_service);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gcal_weather_settings_set_property (GObject      *object,
+                                    guint         prop_id,
+                                    const GValue *value,
+                                    GParamSpec   *pspec)
+{
+  GcalWeatherSettings *self = GCAL_WEATHER_SETTINGS (object);
+
+  switch (prop_id)
+    {
+    case PROP_MANAGER:
+      if (g_set_object (&self->manager, g_value_get_object (value)))
+        {
+          load_weather_settings (self);
+          update_menu_weather_sensitivity (self);
+          manage_weather_service (self);
+
+          g_object_notify_by_pspec (object, properties[PROP_MANAGER]);
+        }
+      break;
+
+    case PROP_WEATHER_SERVICE:
+      gcal_weather_settings_set_weather_service (self, g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gcal_weather_settings_class_init (GcalWeatherSettingsClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->finalize = gcal_weather_settings_finalize;
+  object_class->get_property = gcal_weather_settings_get_property;
+  object_class->set_property = gcal_weather_settings_set_property;
+
+  properties[PROP_MANAGER] = g_param_spec_object ("manager",
+                                                  "Manager",
+                                                  "Manager",
+                                                  GCAL_TYPE_MANAGER,
+                                                  G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_WEATHER_SERVICE] = g_param_spec_object ("weather-service",
+                                                          "The weather service object",
+                                                          "The weather service object",
+                                                          GCAL_TYPE_WEATHER_SERVICE,
+                                                          G_PARAM_READWRITE | 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/weather-settings.ui");
+
+  gtk_widget_class_bind_template_child (widget_class, GcalWeatherSettings, show_weather_switch);
+  gtk_widget_class_bind_template_child (widget_class, GcalWeatherSettings, weather_auto_location_switch);
+  gtk_widget_class_bind_template_child (widget_class, GcalWeatherSettings, weather_location_entry);
+
+  gtk_widget_class_bind_template_callback (widget_class, on_show_weather_changed_cb);
+  gtk_widget_class_bind_template_callback (widget_class, on_weather_auto_location_changed_cb);
+  gtk_widget_class_bind_template_callback (widget_class, on_weather_location_searchbox_changed_cb);
+}
+
+static void
+gcal_weather_settings_init (GcalWeatherSettings *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+GcalWeatherService*
+gcal_weather_settings_get_weather_service (GcalWeatherSettings *self)
+{
+  g_return_val_if_fail (GCAL_IS_WEATHER_SETTINGS (self), NULL);
+
+  return self->weather_service;
+}
+
+void
+gcal_weather_settings_set_weather_service (GcalWeatherSettings *self,
+                                           GcalWeatherService  *service)
+{
+  g_return_if_fail (GCAL_IS_WEATHER_SETTINGS (self));
+
+  if (!g_set_object (&self->weather_service, service))
+    return;
+
+  /* Recover weather settings */
+  load_weather_settings (self);
+  update_menu_weather_sensitivity (self);
+  manage_weather_service (self);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_WEATHER_SERVICE]);
+}
diff --git a/src/weather/gcal-weather-settings.h b/src/weather/gcal-weather-settings.h
new file mode 100644
index 00000000..7c4138d9
--- /dev/null
+++ b/src/weather/gcal-weather-settings.h
@@ -0,0 +1,36 @@
+/* gcal-weather-settings.h
+ *
+ * Copyright © 2018 Georges Basile Stavracas Neto <georges stavracas gmail com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "gcal-weather-service.h"
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GCAL_TYPE_WEATHER_SETTINGS (gcal_weather_settings_get_type())
+
+G_DECLARE_FINAL_TYPE (GcalWeatherSettings, gcal_weather_settings, GCAL, WEATHER_SETTINGS, GtkBox)
+
+GcalWeatherService*  gcal_weather_settings_get_weather_service   (GcalWeatherSettings *self);
+
+void                 gcal_weather_settings_set_weather_service   (GcalWeatherSettings *self,
+                                                                  GcalWeatherService  *service);
+
+G_END_DECLS


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]