[gnome-calendar] new-calendar-page: Use the new discoverer



commit f0060b769970b65bf6ca956a95e91025e32e5124
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Sat Jul 13 16:00:53 2019 -0300

    new-calendar-page: Use the new discoverer
    
    The new discoverer is a vast improvement over the code
    that use used to have here. Right now, we fail to use
    Soup to detect the URL, and that's been reported multiple
    times already.
    
    Use the new web discoverer code, and adjust the UI to
    match the new code. Namely, use a GtkPopover to show
    the credentials widget.
    
    Fixes #380

 data/ui/new-calendar-page.ui                       |  75 ++--
 .../calendar-management/gcal-new-calendar-page.c   | 485 ++++++---------------
 2 files changed, 174 insertions(+), 386 deletions(-)
---
diff --git a/data/ui/new-calendar-page.ui b/data/ui/new-calendar-page.ui
index d7d2d5e6..fae3a5d5 100644
--- a/data/ui/new-calendar-page.ui
+++ b/data/ui/new-calendar-page.ui
@@ -218,41 +218,15 @@
     </child>
   </template>
 
-  <!-- Credentials dialog -->
-  <object class="GtkDialog" id="credentials_dialog">
-    <property name="modal">True</property>
-    <property name="type_hint">dialog</property>
-    <child type="titlebar">
-      <object class="GtkHeaderBar" id="credentials_headerbar">
+  <!-- Credentials popover -->
+  <object class="GtkPopover" id="credentials_popover">
+    <property name="relative-to">calendar_address_entry</property>
+    <property name="position">top</property>
+    <child>
+      <object class="GtkBox">
         <property name="visible">True</property>
-        <property name="title" translatable="yes">Enter your credentials</property>
-        <child>
-          <object class="GtkButton" id="credentials_cancel_button">
-            <property name="label" translatable="yes">Cancel</property>
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <signal name="clicked" handler="on_credential_button_clicked_cb" object="GcalNewCalendarPage" 
swapped="no" />
-          </object>
-        </child>
-        <child>
-          <object class="GtkButton" id="credentials_connect_button">
-            <property name="label" translatable="yes">Connect</property>
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <signal name="clicked" handler="on_credential_button_clicked_cb" object="GcalNewCalendarPage" 
swapped="no" />
-            <style>
-              <class name="suggested-action" />
-            </style>
-          </object>
-          <packing>
-            <property name="pack_type">end</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-    <child internal-child="vbox">
-      <object class="GtkBox" id="credentials-dialog-vbox1">
         <property name="orientation">vertical</property>
+        <property name="margin">12</property>
         <child>
           <object class="GtkGrid" id="credentials_grid">
             <property name="visible">True</property>
@@ -293,7 +267,7 @@
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="hexpand">True</property>
-                <signal name="activate" handler="on_credential_entry_activate_cb" 
object="credentials_dialog" swapped="no" />
+                <signal name="activate" handler="on_credential_entry_activate_cb" 
object="GcalNewCalendarPage" swapped="no" />
               </object>
               <packing>
                 <property name="left_attach">1</property>
@@ -306,7 +280,7 @@
                 <property name="can_focus">True</property>
                 <property name="hexpand">True</property>
                 <property name="visibility">False</property>
-                <signal name="activate" handler="on_credential_entry_activate_cb" 
object="credentials_dialog" swapped="no" />
+                <signal name="activate" handler="on_credential_entry_activate_cb" 
object="GcalNewCalendarPage" swapped="no" />
               </object>
               <packing>
                 <property name="left_attach">1</property>
@@ -314,9 +288,34 @@
               </packing>
             </child>
           </object>
-          <packing>
-            <property name="position">1</property>
-          </packing>
+        </child>
+
+        <child>
+          <object class="GtkBox">
+            <property name="visible">True</property>
+            <property name="spacing">12</property>
+            <child>
+              <object class="GtkButton" id="credentials_cancel_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hexpand">True</property>
+                <property name="label" translatable="yes">Cancel</property>
+                <signal name="clicked" handler="on_credential_button_clicked_cb" 
object="GcalNewCalendarPage" swapped="no" />
+              </object>
+            </child>
+            <child>
+              <object class="GtkButton" id="credentials_connect_button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hexpand">True</property>
+                <property name="label" translatable="yes">Connect</property>
+                <signal name="clicked" handler="on_credential_button_clicked_cb" 
object="GcalNewCalendarPage" swapped="no" />
+                <style>
+                  <class name="suggested-action" />
+                </style>
+              </object>
+            </child>
+          </object>
         </child>
       </object>
     </child>
diff --git a/src/gui/calendar-management/gcal-new-calendar-page.c 
b/src/gui/calendar-management/gcal-new-calendar-page.c
index 0fee8f67..878d542b 100644
--- a/src/gui/calendar-management/gcal-new-calendar-page.c
+++ b/src/gui/calendar-management/gcal-new-calendar-page.c
@@ -26,6 +26,7 @@
 #include "gcal-calendar-management-page.h"
 #include "gcal-debug.h"
 #include "gcal-new-calendar-page.h"
+#include "gcal-source-discoverer.h"
 #include "gcal-utils.h"
 
 #define ENTRY_PROGRESS_TIMEOUT 100 // ms
@@ -41,8 +42,8 @@ struct _GcalNewCalendarPage
   GtkWidget          *cancel_button;
   GtkWidget          *credentials_cancel_button;
   GtkWidget          *credentials_connect_button;
-  GtkWidget          *credentials_dialog;
   GtkEntry           *credentials_password_entry;
+  GtkPopover         *credentials_popover;
   GtkEntry           *credentials_user_entry;
   GtkColorChooser    *local_calendar_color_button;
   GtkEntry           *local_calendar_name_entry;
@@ -50,17 +51,21 @@ struct _GcalNewCalendarPage
   GtkWidget          *web_sources_revealer;
 
   guint               calendar_address_id;
-  gboolean            prompt_password;
-  GList              *remote_sources;
+  GPtrArray          *remote_sources;
   guint               validate_url_resource_id;
 
+  GCancellable       *cancellable;
+
   ESource            *local_source;
 
   GcalContext        *context;
 };
 
+static gboolean      pulse_web_entry                             (gpointer           data);
 
-static gboolean      validate_url_cb                             (GcalNewCalendarPage *self);
+static void          sources_discovered_cb                       (GObject           *source_object,
+                                                                  GAsyncResult      *result,
+                                                                  gpointer           user_data);
 
 static void          gcal_calendar_management_page_iface_init    (GcalCalendarManagementPageInterface 
*iface);
 
@@ -79,86 +84,6 @@ enum
  * Auxiliary methods
  */
 
-static ESource*
-duplicate_source (ESource *source)
-{
-  ESourceExtension *ext;
-  ESource *new_source;
-
-  g_assert (source && E_IS_SOURCE (source));
-
-  new_source = e_source_new (NULL, NULL, NULL);
-  e_source_set_parent (new_source, "local");
-
-  ext = e_source_get_extension (new_source, E_SOURCE_EXTENSION_CALENDAR);
-  e_source_backend_set_backend_name (E_SOURCE_BACKEND (ext), "local");
-
-  /* Copy Authentication data */
-  if (e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION))
-    {
-      ESourceAuthentication *new_auth, *parent_auth;
-
-      parent_auth = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
-      new_auth = e_source_get_extension (new_source, E_SOURCE_EXTENSION_AUTHENTICATION);
-
-      e_source_authentication_set_host (new_auth, e_source_authentication_get_host (parent_auth));
-      e_source_authentication_set_method (new_auth, e_source_authentication_get_method (parent_auth));
-      e_source_authentication_set_port (new_auth, e_source_authentication_get_port (parent_auth));
-      e_source_authentication_set_user (new_auth, e_source_authentication_get_user (parent_auth));
-      e_source_authentication_set_proxy_uid (new_auth, e_source_authentication_get_proxy_uid (parent_auth));
-    }
-
-  /* Copy Webdav data */
-  if (e_source_has_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND))
-    {
-      ESourceWebdav *new_webdav, *parent_webdav;
-
-      parent_webdav = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-      new_webdav = e_source_get_extension (new_source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-
-      e_source_webdav_set_display_name (new_webdav, e_source_webdav_get_display_name (parent_webdav));
-      e_source_webdav_set_resource_path (new_webdav, e_source_webdav_get_resource_path (parent_webdav));
-      e_source_webdav_set_resource_query (new_webdav, e_source_webdav_get_resource_query (parent_webdav));
-      e_source_webdav_set_email_address (new_webdav, e_source_webdav_get_email_address (parent_webdav));
-      e_source_webdav_set_ssl_trust (new_webdav, e_source_webdav_get_ssl_trust (parent_webdav));
-
-      e_source_set_parent (new_source, "webcal-stub");
-      e_source_backend_set_backend_name (E_SOURCE_BACKEND (ext), "webcal");
-    }
-
-  return new_source;
-}
-
-static gint
-prompt_credentials (GcalNewCalendarPage  *self,
-                    gchar               **username,
-                    gchar               **password)
-{
-  gint response;
-
-  /* Cleanup last credentials */
-  gtk_entry_set_text (self->credentials_password_entry, "");
-  gtk_entry_set_text (self->credentials_user_entry, "");
-
-  gtk_widget_grab_focus (GTK_WIDGET (self->credentials_user_entry));
-
-  /* Show the dialog, then destroy it */
-  response = gtk_dialog_run (GTK_DIALOG (self->credentials_dialog));
-
-  if (response == GTK_RESPONSE_OK)
-    {
-      if (username)
-        *username = g_strdup (gtk_entry_get_text (self->credentials_user_entry));
-
-      if (password)
-        *password = g_strdup (gtk_entry_get_text (self->credentials_password_entry));
-    }
-
-  gtk_widget_hide (self->credentials_dialog);
-
-  return response;
-}
-
 static gchar*
 calendar_path_to_name_suggestion (GFile *file)
 {
@@ -246,6 +171,67 @@ update_local_source (GcalNewCalendarPage *self)
   update_add_button (self);
 }
 
+static void
+toggle_url_entry_pulsing (GcalNewCalendarPage *self,
+                          gboolean             pulsing)
+{
+  gtk_entry_set_progress_fraction (self->calendar_address_entry, 0);
+
+  if (pulsing && self->calendar_address_id == 0)
+    self->calendar_address_id = g_timeout_add (ENTRY_PROGRESS_TIMEOUT, pulse_web_entry, self);
+  else if (!pulsing && self->calendar_address_id != 0)
+    g_clear_handle_id (&self->calendar_address_id, g_source_remove);
+}
+
+static void
+set_url_entry_error (GcalNewCalendarPage *self,
+                     gboolean             error)
+{
+  GtkStyleContext *context;
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (self->calendar_address_entry));
+
+  if (error)
+    gtk_style_context_add_class (context, "error");
+  else
+    gtk_style_context_remove_class (context, "error");
+}
+
+static void
+discover_sources (GcalNewCalendarPage *self)
+{
+  const gchar *username;
+  const gchar *password;
+  const gchar *url;
+
+  GCAL_ENTRY;
+
+  self->validate_url_resource_id = 0;
+
+  url = gtk_entry_get_text (self->calendar_address_entry);
+  username = gtk_entry_get_text (self->credentials_user_entry);
+  password = gtk_entry_get_text (self->credentials_password_entry);
+
+  gcal_discover_sources_from_uri (url,
+                                  username,
+                                  password,
+                                  self->cancellable,
+                                  sources_discovered_cb,
+                                  self);
+
+  toggle_url_entry_pulsing (self, TRUE);
+
+  GCAL_EXIT;
+}
+
+static void
+popdown_credentials_popover (GcalNewCalendarPage *self)
+{
+  gtk_entry_set_text (self->credentials_user_entry, "");
+  gtk_entry_set_text (self->credentials_password_entry, "");
+
+  gtk_popover_popdown (self->credentials_popover);
+}
 
 /*
  * Callbacks
@@ -294,284 +280,75 @@ on_file_chooser_button_file_set_cb (GtkFileChooser      *chooser,
 }
 
 static gboolean
-pulse_web_entry (GcalNewCalendarPage *self)
+pulse_web_entry (gpointer data)
 {
-  gtk_entry_progress_pulse (self->calendar_address_entry);
-
-  self->calendar_address_id = g_timeout_add (ENTRY_PROGRESS_TIMEOUT, (GSourceFunc) pulse_web_entry, self);
+  GcalNewCalendarPage *self = data;
 
+  gtk_entry_progress_pulse (self->calendar_address_entry);
   return G_SOURCE_CONTINUE;
 }
 
 static void
-on_check_activated_cb (GtkWidget           *check,
-                       GParamSpec          *spec,
-                       GcalNewCalendarPage *self)
+sources_discovered_cb (GObject      *source_object,
+                       GAsyncResult *result,
+                       gpointer      user_data)
 {
-  GtkWidget *row;
-  ESource *source;
-
-  row = gtk_widget_get_parent (check);
-  source = g_object_get_data (G_OBJECT (row), "source");
-
-  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)))
-    self->remote_sources = g_list_prepend (self->remote_sources, source);
-  else
-    self->remote_sources = g_list_remove (self->remote_sources, source);
-
-  update_add_button (self);
-}
+  GcalNewCalendarPage *self;
+  g_autoptr (GPtrArray) sources = NULL;
+  g_autoptr (GError) error = NULL;
 
-static void
-discover_sources_cb (GObject      *source,
-                     GAsyncResult *result,
-                     gpointer      user_data)
-{
-  GcalNewCalendarPage  *self;
-  GSList *discovered_sources;
-  GSList *user_addresses;
-  GSList *aux;
-  GError *error;
+  GCAL_ENTRY;
 
   self = GCAL_NEW_CALENDAR_PAGE (user_data);
-  error = NULL;
-
-  /* Stop the pulsing entry */
-  if (self->calendar_address_id != 0)
-    {
-      gtk_entry_set_progress_fraction (GTK_ENTRY (self->calendar_address_entry), 0);
-      g_source_remove (self->calendar_address_id);
-      self->calendar_address_id = 0;
-    }
+  sources = gcal_discover_sources_from_uri_finish (result, &error);
 
-  if (!e_webdav_discover_sources_finish (E_SOURCE (source), result, NULL, NULL, &discovered_sources, 
&user_addresses,
-                                        &error))
+  if (error)
     {
-      /* Don't add an source with errors */
-      gtk_widget_set_sensitive (self->add_button, FALSE);
-
-      /*
-       * If it's the first try and things went wrong, retry with the user
-       * credentials. Also, it checks for the error code, since we don't
-       * really want to retry things on unavailable servers.
-       */
-      if (!self->prompt_password &&
-          (error->code == 14 ||
-           error->code == 401 ||
-           error->code == 403 ||
-           error->code == 405))
+      if (g_error_matches (error,
+                           GCAL_SOURCE_DISCOVERER_ERROR,
+                           GCAL_SOURCE_DISCOVERER_ERROR_UNAUTHORIZED))
         {
-          self->prompt_password = TRUE;
-          validate_url_cb (self);
+          g_debug ("Unauthorized, asking for credentials...");
+          gtk_popover_popup (self->credentials_popover);
         }
       else
         {
-          g_debug ("Error: %s", error->message);
+          g_warning ("Error finding sources: %s", error->message);
+          toggle_url_entry_pulsing (self, FALSE);
         }
-
-      g_error_free (error);
-      return;
+      GCAL_RETURN ();
     }
 
-  /* Add a success icon to the entry */
-  gtk_entry_set_icon_from_icon_name (GTK_ENTRY (self->calendar_address_entry), GTK_ENTRY_ICON_SECONDARY,
-                                     "emblem-ok-symbolic");
-
-  /* Remove previous results */
-  g_list_free_full (gtk_container_get_children (GTK_CONTAINER (self->web_sources_listbox)),
-                    (GDestroyNotify) gtk_widget_destroy);
-
-  /* Show the list of calendars */
-  gtk_revealer_set_reveal_child (GTK_REVEALER (self->web_sources_revealer), TRUE);
-  gtk_widget_show (self->web_sources_revealer);
-
-  /* TODO: show a list of calendars */
-  for (aux = discovered_sources; aux != NULL; aux = aux->next)
-    {
-      g_autoptr (SoupURI) soup_uri = NULL;
-      EWebDAVDiscoveredSource *discovered_source;
-      const gchar *resource_path = NULL;
-
-      discovered_source = aux->data;
-
-      soup_uri = soup_uri_new (discovered_source->href);
-
-      /* Get the new resource path from the uri */
-      resource_path = soup_uri_get_path (soup_uri);
-
-      if (soup_uri)
-        {
-          ESourceSelectable *selectable;
-          ESourceWebdav *webdav;
-          GtkWidget *row, *check;
-          ESource *new_source;
-
-
-          /* build up the new source */
-          new_source = duplicate_source (E_SOURCE (source));
-          e_source_set_display_name (E_SOURCE (new_source), discovered_source->display_name);
-
-          webdav = e_source_get_extension (new_source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-          e_source_webdav_set_resource_path (webdav, resource_path);
-          e_source_webdav_set_display_name (webdav, discovered_source->display_name);
-
-          if (user_addresses)
-            e_source_webdav_set_email_address (webdav, user_addresses->data);
+  g_debug ("Found %u sources", sources->len);
 
-          /* Setup the color */
-          selectable = e_source_get_extension (new_source, E_SOURCE_EXTENSION_CALENDAR);
-          e_source_selectable_set_color (selectable, discovered_source->color);
-
-          /* create the new row */
-          row = gtk_list_box_row_new ();
-
-          check = gtk_check_button_new ();
-          gtk_button_set_label (GTK_BUTTON (check), discovered_source->display_name);
-          g_signal_connect (check, "notify::active", G_CALLBACK (on_check_activated_cb), self);
-
-          gtk_container_add (GTK_CONTAINER (row), check);
-          gtk_container_add (GTK_CONTAINER (self->web_sources_listbox), row);
+  self->remote_sources = g_steal_pointer (&sources);
+  update_add_button (self);
 
-          g_object_set_data (G_OBJECT (row), "parent-source", source);
-          g_object_set_data (G_OBJECT (row), "source", new_source);
+  toggle_url_entry_pulsing (self, FALSE);
 
-          gtk_widget_show_all (row);
-        }
-    }
-
-  /* Free things up */
-  e_webdav_discover_free_discovered_sources (discovered_sources);
-  g_slist_free_full (user_addresses, g_free);
+  GCAL_EXIT;
 }
 
 static gboolean
-validate_url_cb (GcalNewCalendarPage *self)
+validate_url_cb (gpointer data)
 {
-  ESourceAuthentication *auth;
-  ENamedParameters *credentials;
-  ESourceExtension *ext;
-  ESourceWebdav *webdav;
-  ESource *source;
-  g_autoptr (SoupURI) soup_uri;
-  const gchar *uri;
-  const gchar *host, *path;
-  gboolean is_file;
+  GcalNewCalendarPage *self = data;
+  g_autoptr (SoupURI) uri = NULL;
+  gboolean valid_uri;
 
   GCAL_ENTRY;
 
   self->validate_url_resource_id = 0;
-  soup_uri = NULL;
-  host = path = NULL;
-  is_file = FALSE;
-
-  /* Remove any reminescent ESources cached before */
-  if (self->remote_sources)
-    {
-      g_list_free_full (self->remote_sources, g_object_unref);
-      self->remote_sources = NULL;
-    }
-
-  /* Remove previous results */
-  g_list_free_full (gtk_container_get_children (GTK_CONTAINER (self->web_sources_listbox)),
-                    (GDestroyNotify) gtk_widget_destroy);
-  gtk_revealer_set_reveal_child (GTK_REVEALER (self->web_sources_revealer), FALSE);
 
-  /* Clear the entry icon */
-  gtk_entry_set_icon_from_icon_name (self->calendar_address_entry, GTK_ENTRY_ICON_SECONDARY, NULL);
+  uri = soup_uri_new (gtk_entry_get_text (self->calendar_address_entry));
+  valid_uri = uri != NULL;
 
-  /* Get the hostname and file path from the server */
-  uri = gtk_entry_get_text (self->calendar_address_entry);
-  soup_uri = soup_uri_new (uri);
-  if (!soup_uri)
-    GCAL_RETURN (G_SOURCE_REMOVE);
+  set_url_entry_error (self, !valid_uri);
 
-  host = soup_uri_get_host (soup_uri);
-  path = soup_uri_get_path (soup_uri);
-
-  if (soup_uri_get_scheme (soup_uri) == SOUP_URI_SCHEME_FILE)
-    is_file = TRUE;
-
-  g_debug ("Detected host: '%s', path: '%s'", host, path);
-
-  /* Create the new source and add the needed extensions */
-  source = e_source_new (NULL, NULL, NULL);
-  e_source_set_parent (source, "webcal-stub");
-
-  ext = e_source_get_extension (source, E_SOURCE_EXTENSION_CALENDAR);
-  e_source_backend_set_backend_name (E_SOURCE_BACKEND (ext), "webcal");
-
-  /* Authentication */
-  auth = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
-  e_source_authentication_set_host (auth, host);
-
-  /* Webdav */
-  webdav = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-  e_source_webdav_set_soup_uri (webdav, soup_uri);
-
-  /*
-   * If we're dealing with an absolute file path, there is no need
-   * to check the server for more sources.
-   */
-  if (is_file)
-    {
-      self->remote_sources = g_list_append (self->remote_sources, source);
-      gtk_widget_set_sensitive (self->add_button, source != NULL);
-      GCAL_RETURN (G_SOURCE_REMOVE);
-    }
-
-  /* Pulse the entry while it performs the check */
-  self->calendar_address_id = g_timeout_add (ENTRY_PROGRESS_TIMEOUT, (GSourceFunc) pulse_web_entry, self);
-
-  /*
-   * Try to retrieve the sources without prompting username and password. If
-   * we get any error, then it prompts and retry.
-   */
-  credentials = e_named_parameters_new ();
-
-  if (!self->prompt_password)
-    {
-      g_debug ("Trying to connect without credentials...");
-
-      /* NULL credentials */
-      e_named_parameters_set (credentials, E_SOURCE_CREDENTIAL_USERNAME, NULL);
-      e_named_parameters_set (credentials, E_SOURCE_CREDENTIAL_PASSWORD, NULL);
-
-      e_webdav_discover_sources (source,
-                                 uri,
-                                 E_WEBDAV_DISCOVER_SUPPORTS_EVENTS,
-                                 credentials,
-                                 NULL,
-                                 discover_sources_cb,
-                                 self);
-    }
+  if (valid_uri)
+    discover_sources (self);
   else
-    {
-      g_autofree gchar *password = NULL;
-      g_autofree gchar *user = NULL;
-      gint response;
-
-      g_debug ("No credentials failed, retrying with user credentials...");
-
-      response = prompt_credentials (self, &user, &password);
-
-      g_message ("lalala");
-
-      if (response == GTK_RESPONSE_OK)
-        {
-          e_named_parameters_set (credentials, E_SOURCE_CREDENTIAL_USERNAME, user);
-          e_named_parameters_set (credentials, E_SOURCE_CREDENTIAL_PASSWORD, password);
-
-          e_webdav_discover_sources (source,
-                                     uri,
-                                     E_WEBDAV_DISCOVER_SUPPORTS_EVENTS,
-                                     credentials,
-                                     NULL,
-                                     discover_sources_cb,
-                                     self);
-        }
-    }
-
-  e_named_parameters_free (credentials);
+    g_debug ("Invalid URL passed");
 
   GCAL_RETURN (G_SOURCE_REMOVE);
 }
@@ -591,13 +368,12 @@ on_add_button_clicked_cb (GtkWidget           *button,
   /* Commit each new remote source */
   if (self->remote_sources)
     {
-      GList *l;
+      guint i;
 
-      for (l = self->remote_sources; l; l = l->next)
-        gcal_manager_save_source (manager, l->data);
+      for (i = 0; i < self->remote_sources->len; i++)
+        gcal_manager_save_source (manager, g_ptr_array_index (self->remote_sources, i));
 
-      g_list_free_full (self->remote_sources, g_object_unref);
-      self->remote_sources = NULL;
+      g_clear_pointer (&self->remote_sources, g_ptr_array_unref);
     }
 
   gcal_calendar_management_page_switch_page (GCAL_CALENDAR_MANAGEMENT_PAGE (self),
@@ -616,17 +392,20 @@ static void
 on_credential_button_clicked_cb (GtkWidget           *button,
                                  GcalNewCalendarPage *self)
 {
-  if (button == self->credentials_cancel_button)
-    gtk_dialog_response (GTK_DIALOG (self->credentials_dialog), GTK_RESPONSE_CANCEL);
+  if (button == self->credentials_connect_button)
+    discover_sources (self);
   else
-    gtk_dialog_response (GTK_DIALOG (self->credentials_dialog), GTK_RESPONSE_OK);
+    toggle_url_entry_pulsing (self, FALSE);
+
+  popdown_credentials_popover (self);
 }
 
 static void
-on_credential_entry_activate_cb (GtkEntry  *entry,
-                                 GtkDialog *dialog)
+on_credential_entry_activate_cb (GtkEntry            *entry,
+                                 GcalNewCalendarPage *self)
 {
-  gtk_dialog_response (dialog, GTK_RESPONSE_OK);
+  discover_sources (self);
+  popdown_credentials_popover (self);
 }
 
 static void
@@ -646,21 +425,25 @@ on_url_entry_text_changed_cb (GtkEntry            *entry,
       g_clear_handle_id (&self->calendar_address_id, g_source_remove);
     }
 
+  /* Cleanup previous remote sources */
+  g_clear_pointer (&self->remote_sources, g_ptr_array_unref);
+  update_add_button (self);
+
   if (self->validate_url_resource_id != 0)
     g_clear_handle_id (&self->validate_url_resource_id, g_source_remove);
 
-  if (g_utf8_strlen (text, -1) > 0)
+  if (text && g_utf8_strlen (text, -1) > 0)
     {
       /*
        * At first, don't bother the user with the login prompt. Only prompt it when
        * it fails.
        */
-      self->prompt_password = FALSE;
-      self->validate_url_resource_id = g_timeout_add (500, (GSourceFunc) validate_url_cb, self);
+      self->validate_url_resource_id = g_timeout_add (500, validate_url_cb, self);
     }
   else
     {
       gtk_entry_set_progress_fraction (self->calendar_address_entry, 0);
+      set_url_entry_error (self, FALSE);
     }
 
   GCAL_EXIT;
@@ -741,15 +524,15 @@ gcal_new_calendar_page_deactivate (GcalCalendarManagementPage *page)
   gtk_container_remove (GTK_CONTAINER (headerbar), self->add_button);
   gtk_header_bar_set_show_close_button (headerbar, TRUE);
 
-  if (self->remote_sources)
-    {
-      g_list_free_full (self->remote_sources, g_object_unref);
-      self->remote_sources = NULL;
-    }
+  g_clear_object (&self->local_source);
+  g_clear_pointer (&self->remote_sources, g_ptr_array_unref);
+  update_add_button (self);
 
   gtk_entry_set_text (self->local_calendar_name_entry, "");
   gtk_entry_set_text (self->calendar_address_entry, "");
 
+  toggle_url_entry_pulsing (self, FALSE);
+
   GCAL_EXIT;
 }
 
@@ -771,6 +554,10 @@ gcal_new_calendar_page_finalize (GObject *object)
 {
   GcalNewCalendarPage *self = (GcalNewCalendarPage *)object;
 
+  toggle_url_entry_pulsing (self, FALSE);
+
+  g_cancellable_cancel (self->cancellable);
+  g_clear_object (&self->cancellable);
   g_clear_object (&self->context);
 
   G_OBJECT_CLASS (gcal_new_calendar_page_parent_class)->finalize (object);
@@ -836,8 +623,8 @@ gcal_new_calendar_page_class_init (GcalNewCalendarPageClass *klass)
   gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, cancel_button);
   gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, credentials_cancel_button);
   gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, credentials_connect_button);
-  gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, credentials_dialog);
   gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, credentials_password_entry);
+  gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, credentials_popover);
   gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, credentials_user_entry);
   gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, local_calendar_color_button);
   gtk_widget_class_bind_template_child (widget_class, GcalNewCalendarPage, local_calendar_name_entry);
@@ -858,6 +645,8 @@ gcal_new_calendar_page_class_init (GcalNewCalendarPageClass *klass)
 static void
 gcal_new_calendar_page_init (GcalNewCalendarPage *self)
 {
+  self->cancellable = g_cancellable_new ();
+
   gtk_widget_init_template (GTK_WIDGET (self));
 
   gtk_file_filter_set_name (self->calendar_file_filter, _("Calendar files"));


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