[gnome-software/91-clicking-screenshots-doesn-t-switch-between-them] gs-screenshot-image: Show spinner when load of image takes long time



commit e64e8581eede0be98cb222ed90deece79ebfdd26
Author: Milan Crha <mcrha redhat com>
Date:   Wed Oct 14 17:18:30 2020 +0200

    gs-screenshot-image: Show spinner when load of image takes long time
    
    Closes https://gitlab.gnome.org/GNOME/gnome-software/-/issues/91
    Closes https://gitlab.gnome.org/GNOME/gnome-software/-/merge_requests/524

 src/gs-screenshot-image.c  | 43 ++++++++++++++++++++-
 src/gs-screenshot-image.ui | 93 ++++++++++++++++++++++++++++------------------
 2 files changed, 98 insertions(+), 38 deletions(-)
---
diff --git a/src/gs-screenshot-image.c b/src/gs-screenshot-image.c
index 0ecba076..86528782 100644
--- a/src/gs-screenshot-image.c
+++ b/src/gs-screenshot-image.c
@@ -15,11 +15,14 @@
 #include "gs-screenshot-image.h"
 #include "gs-common.h"
 
+#define SPINNER_TIMEOUT_SECS 2
+
 struct _GsScreenshotImage
 {
        GtkBin           parent_instance;
 
        AsScreenshot    *screenshot;
+       GtkWidget       *spinner;
        GtkWidget       *stack;
        GtkWidget       *box_error;
        GtkWidget       *image1;
@@ -33,6 +36,7 @@ struct _GsScreenshotImage
        guint            width;
        guint            height;
        guint            scale;
+       guint            load_timeout_id;
        gboolean         showing_image;
 };
 
@@ -58,6 +62,7 @@ gs_screenshot_image_set_error (GsScreenshotImage *ssimg, const gchar *message)
        else
                gtk_widget_show (ssimg->label_error);
        ssimg->showing_image = FALSE;
+       gtk_widget_hide (ssimg->spinner);
 }
 
 static void
@@ -95,6 +100,8 @@ as_screenshot_show_image (GsScreenshotImage *ssimg)
 
        gtk_widget_show (GTK_WIDGET (ssimg));
        ssimg->showing_image = TRUE;
+
+       gtk_widget_hide (ssimg->spinner);
 }
 
 static void
@@ -214,6 +221,11 @@ gs_screenshot_image_complete_cb (SoupSession *session,
        g_autoptr(GdkPixbuf) pixbuf = NULL;
        g_autoptr(GInputStream) stream = NULL;
 
+       if (ssimg->load_timeout_id) {
+               g_source_remove (ssimg->load_timeout_id);
+               ssimg->load_timeout_id = 0;
+       }
+
        /* return immediately if the message was cancelled or if we're in destruction */
        if (msg->status_code == SOUP_STATUS_CANCELLED || ssimg->session == NULL)
                return;
@@ -221,12 +233,14 @@ gs_screenshot_image_complete_cb (SoupSession *session,
        if (msg->status_code == SOUP_STATUS_NOT_MODIFIED) {
                g_debug ("screenshot has not been modified");
                as_screenshot_show_image (ssimg);
+               gtk_widget_hide (ssimg->spinner);
                return;
        }
        if (msg->status_code != SOUP_STATUS_OK) {
                 g_warning ("Result of screenshot downloading attempt with "
                           "status code '%u': %s", msg->status_code,
                           msg->reason_phrase);
+               gtk_widget_hide (ssimg->spinner);
                /* if we're already showing an image, then don't set the error
                 * as having an image (even if outdated) is better */
                if (ssimg->showing_image)
@@ -241,8 +255,10 @@ gs_screenshot_image_complete_cb (SoupSession *session,
        stream = g_memory_input_stream_new_from_data (msg->response_body->data,
                                                      msg->response_body->length,
                                                      NULL);
-       if (stream == NULL)
+       if (stream == NULL) {
+               gtk_widget_hide (ssimg->spinner);
                return;
+       }
 
        /* load the image */
        pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, NULL);
@@ -345,6 +361,17 @@ gs_screenshot_soup_msg_set_modified_request (SoupMessage *msg, GFile *file)
                                     mod_date);
 }
 
+static gboolean
+gs_screenshot_show_spinner_cb (gpointer user_data)
+{
+       GsScreenshotImage *ssimg = user_data;
+
+       ssimg->load_timeout_id = 0;
+       gtk_widget_show (ssimg->spinner);
+
+       return FALSE;
+}
+
 void
 gs_screenshot_image_load_async (GsScreenshotImage *ssimg,
                                GCancellable *cancellable)
@@ -473,6 +500,11 @@ gs_screenshot_image_load_async (GsScreenshotImage *ssimg,
                return;
        }
 
+       if (ssimg->load_timeout_id) {
+               g_source_remove (ssimg->load_timeout_id);
+               ssimg->load_timeout_id = 0;
+       }
+
        /* cancel any previous messages */
        if (ssimg->message != NULL) {
                soup_session_cancel_message (ssimg->session,
@@ -495,6 +527,9 @@ gs_screenshot_image_load_async (GsScreenshotImage *ssimg,
                gs_screenshot_soup_msg_set_modified_request (ssimg->message, file);
        }
 
+       ssimg->load_timeout_id = g_timeout_add_seconds (SPINNER_TIMEOUT_SECS,
+               gs_screenshot_show_spinner_cb, ssimg);
+
        /* send async */
        soup_session_queue_message (ssimg->session,
                                    g_object_ref (ssimg->message) /* transfer full */,
@@ -513,6 +548,11 @@ gs_screenshot_image_destroy (GtkWidget *widget)
 {
        GsScreenshotImage *ssimg = GS_SCREENSHOT_IMAGE (widget);
 
+       if (ssimg->load_timeout_id) {
+               g_source_remove (ssimg->load_timeout_id);
+               ssimg->load_timeout_id = 0;
+       }
+
        if (ssimg->message != NULL) {
                soup_session_cancel_message (ssimg->session,
                                             ssimg->message,
@@ -575,6 +615,7 @@ gs_screenshot_image_class_init (GsScreenshotImageClass *klass)
        gtk_widget_class_set_template_from_resource (widget_class,
                                                     "/org/gnome/Software/gs-screenshot-image.ui");
 
+       gtk_widget_class_bind_template_child (widget_class, GsScreenshotImage, spinner);
        gtk_widget_class_bind_template_child (widget_class, GsScreenshotImage, stack);
        gtk_widget_class_bind_template_child (widget_class, GsScreenshotImage, image1);
        gtk_widget_class_bind_template_child (widget_class, GsScreenshotImage, image2);
diff --git a/src/gs-screenshot-image.ui b/src/gs-screenshot-image.ui
index 0dae6e86..94704890 100644
--- a/src/gs-screenshot-image.ui
+++ b/src/gs-screenshot-image.ui
@@ -7,62 +7,81 @@
       <class name="screenshot-image"/>
     </style>
     <child>
-      <object class="GtkStack" id="stack">
+      <object class="GtkOverlay" id="overlay">
         <property name="visible">True</property>
-        <property name="transition-type">crossfade</property>
-        <child>
-          <object class="GtkImage" id="image1">
-            <property name="visible">True</property>
-            <property name="halign">center</property>
-            <property name="valign">center</property>
-            <style>
-              <class name="image1"/>
-            </style>
-          </object>
-          <packing>
-            <property name="name">image1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkImage" id="image2">
+        <property name="halign">fill</property>
+        <property name="valign">fill</property>
+        <child type="overlay">
+          <object class="GtkSpinner" id="spinner">
+            <property name="active">True</property>
             <property name="visible">True</property>
+            <property name="width_request">32</property>
+            <property name="height_request">32</property>
             <property name="halign">center</property>
             <property name="valign">center</property>
-            <style>
-              <class name="image2"/>
-            </style>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
           </object>
-          <packing>
-            <property name="name">image2</property>
-          </packing>
         </child>
         <child>
-          <object class="GtkBox" id="box_error">
+          <object class="GtkStack" id="stack">
             <property name="visible">True</property>
-            <property name="halign">center</property>
-            <property name="valign">center</property>
-            <property name="orientation">vertical</property>
-            <property name="spacing">4</property>
+            <property name="transition-type">crossfade</property>
             <child>
-              <object class="GtkImage" id="image_error">
+              <object class="GtkImage" id="image1">
                 <property name="visible">True</property>
-                <property name="icon-name">dialog-error-symbolic</property>
-                <property name="icon-size">6</property>
-                <property name="pixel-size">48</property>
+                <property name="halign">center</property>
+                <property name="valign">center</property>
+                <style>
+                  <class name="image1"/>
+                </style>
               </object>
+              <packing>
+                <property name="name">image1</property>
+              </packing>
             </child>
             <child>
-              <object class="GtkLabel" id="label_error">
+              <object class="GtkImage" id="image2">
                 <property name="visible">True</property>
+                <property name="halign">center</property>
+                <property name="valign">center</property>
                 <style>
-                  <class name="error-label"/>
+                  <class name="image2"/>
                 </style>
               </object>
+              <packing>
+                <property name="name">image2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="box_error">
+                <property name="visible">True</property>
+                <property name="halign">center</property>
+                <property name="valign">center</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">4</property>
+                <child>
+                  <object class="GtkImage" id="image_error">
+                    <property name="visible">True</property>
+                    <property name="icon-name">dialog-error-symbolic</property>
+                    <property name="icon-size">6</property>
+                    <property name="pixel-size">48</property>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label_error">
+                    <property name="visible">True</property>
+                    <style>
+                      <class name="error-label"/>
+                    </style>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="name">error</property>
+              </packing>
             </child>
           </object>
-          <packing>
-            <property name="name">error</property>
-          </packing>
         </child>
       </object>
     </child>


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