[gnome-software] Add an initial loading panel when there is no metadata



commit 995f9967c1e943760bba40b89462b65ea2bea311
Author: Richard Hughes <richard hughsie com>
Date:   Mon Apr 11 15:24:57 2016 +0100

    Add an initial loading panel when there is no metadata

 po/POTFILES.in                   |    2 +
 src/Makefile.am                  |    3 +
 src/gnome-software.gresource.xml |    1 +
 src/gnome-software.ui            |    8 ++
 src/gs-application.c             |   24 ++++-
 src/gs-shell-loading.c           |  225 ++++++++++++++++++++++++++++++++++++++
 src/gs-shell-loading.h           |   55 +++++++++
 src/gs-shell-loading.ui          |   64 +++++++++++
 src/gs-shell.c                   |   17 +++-
 src/gs-shell.h                   |    2 +
 src/plugins/gs-plugin-steam.c    |    5 +
 11 files changed, 400 insertions(+), 6 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index dcb1383..0f37728 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -59,3 +59,5 @@ src/gs-utils.c
 src/org.gnome.Software.desktop.in
 src/plugins/menu-spec-common.c
 [type: gettext/glade]src/gs-popular-tile.ui
+src/gs-shell-loading.c
+[type: gettext/glade]src/gs-shell-loading.ui
diff --git a/src/Makefile.am b/src/Makefile.am
index 82deb31..6d2a8d4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -47,6 +47,7 @@ UI_FILES =                                            \
        gs-shell-extras.ui                              \
        gs-shell-installed.ui                           \
        gs-shell-moderate.ui                            \
+       gs-shell-loading.ui                             \
        gs-shell-overview.ui                            \
        gs-shell-search.ui                              \
        gs-shell-updates.ui                             \
@@ -177,6 +178,8 @@ gnome_software_SOURCES =                            \
        gs-shell-installed.h                            \
        gs-shell-moderate.c                             \
        gs-shell-moderate.h                             \
+       gs-shell-loading.c                              \
+       gs-shell-loading.h                              \
        gs-shell-overview.c                             \
        gs-shell-overview.h                             \
        gs-shell-updates.c                              \
diff --git a/src/gnome-software.gresource.xml b/src/gnome-software.gresource.xml
index c73be6a..773ce8e 100644
--- a/src/gnome-software.gresource.xml
+++ b/src/gnome-software.gresource.xml
@@ -21,6 +21,7 @@
   <file preprocess="xml-stripblanks">gs-shell-details.ui</file>
   <file preprocess="xml-stripblanks">gs-shell-extras.ui</file>
   <file preprocess="xml-stripblanks">gs-shell-installed.ui</file>
+  <file preprocess="xml-stripblanks">gs-shell-loading.ui</file>
   <file preprocess="xml-stripblanks">gs-shell-moderate.ui</file>
   <file preprocess="xml-stripblanks">gs-shell-overview.ui</file>
   <file preprocess="xml-stripblanks">gs-shell-search.ui</file>
diff --git a/src/gnome-software.ui b/src/gnome-software.ui
index 1d9ddad..857ded6 100644
--- a/src/gnome-software.ui
+++ b/src/gnome-software.ui
@@ -354,6 +354,14 @@
               </packing>
             </child>
             <child>
+              <object class="GsShellLoading" id="shell_loading">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="name">loading</property>
+              </packing>
+            </child>
+            <child>
               <object class="GsShellSearch" id="shell_search">
                 <property name="visible">True</property>
               </object>
diff --git a/src/gs-application.c b/src/gs-application.c
index 872b33c..463813c 100644
--- a/src/gs-application.c
+++ b/src/gs-application.c
@@ -314,9 +314,6 @@ gs_application_initialize_ui (GsApplication *app)
 
        gs_shell_setup (app->shell, app->plugin_loader, app->cancellable);
        gtk_application_add_window (GTK_APPLICATION (app), gs_shell_get_window (app->shell));
-
-       g_signal_connect_swapped (app->shell, "loaded",
-                                 G_CALLBACK (gtk_window_present), gs_shell_get_window (app->shell));
 }
 
 static void
@@ -747,11 +744,30 @@ gs_application_startup (GApplication *application)
 }
 
 static void
+gs_application_shell_loaded_cb (GsShell *shell, GsApplication *app)
+{
+       gs_shell_set_mode (app->shell, GS_SHELL_MODE_OVERVIEW);
+}
+
+static void
 gs_application_activate (GApplication *application)
 {
+       GsApplication *app = GS_APPLICATION (application);
+
        gs_application_initialize_ui (GS_APPLICATION (application));
-       gs_shell_set_mode (GS_APPLICATION (application)->shell, GS_SHELL_MODE_OVERVIEW);
+
+       /* start metadata loading screen */
+       if (gs_shell_get_mode (app->shell) == GS_SHELL_MODE_UNKNOWN) {
+               g_signal_connect (app->shell, "loaded",
+                                 G_CALLBACK (gs_application_shell_loaded_cb),
+                                 app);
+               gs_shell_set_mode (app->shell, GS_SHELL_MODE_LOADING);
+       } else {
+               gs_shell_set_mode (app->shell, GS_SHELL_MODE_OVERVIEW);
+       }
+
        gs_shell_activate (GS_APPLICATION (application)->shell);
+
        gs_application_show_first_run_dialog (GS_APPLICATION (application));
 }
 
diff --git a/src/gs-shell-loading.c b/src/gs-shell-loading.c
new file mode 100644
index 0000000..2dc0b65
--- /dev/null
+++ b/src/gs-shell-loading.c
@@ -0,0 +1,225 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "gs-app.h"
+#include "gs-shell.h"
+#include "gs-shell-loading.h"
+
+typedef struct {
+       GsPage                   parent_instance;
+
+       GsPluginLoader          *plugin_loader;
+       GCancellable            *cancellable;
+       GsShell                 *shell;
+
+       GtkWidget               *progressbar;
+       GtkWidget               *label;
+} GsShellLoadingPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (GsShellLoading, gs_shell_loading, GS_TYPE_PAGE)
+
+enum {
+       SIGNAL_REFRESHED,
+       SIGNAL_LAST
+};
+
+static guint signals [SIGNAL_LAST] = { 0 };
+
+/**
+ * gs_shell_loading_status_changed_cb:
+ **/
+static void
+gs_shell_loading_status_changed_cb (GsPluginLoader *plugin_loader,
+                                   GsApp *app,
+                                   GsPluginStatus status,
+                                   GsShellLoading *self)
+{
+       GsShellLoadingPrivate *priv = gs_shell_loading_get_instance_private (self);
+
+       /* update label */
+       switch (status) {
+       case GS_PLUGIN_STATUS_DOWNLOADING:
+               gtk_label_set_label (GTK_LABEL (priv->label),
+                                    /* TRANSLATORS: initial start */
+                                    _("Software catalog is being downloaded"));
+               break;
+       default:
+               gtk_label_set_label (GTK_LABEL (priv->label),
+                                    /* TRANSLATORS: initial start */
+                                    _("Software catalog is being loaded"));
+               break;
+       }
+
+       /* update progresbar */
+       if (app != NULL) {
+               gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->progressbar),
+                                              (gdouble) gs_app_get_progress (app) / 100.0f);
+       }
+}
+
+/**
+ * gs_shell_loading_refresh_cb:
+ **/
+static void
+gs_shell_loading_refresh_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object);
+       GsShellLoading *self = GS_SHELL_LOADING (user_data);
+       g_autoptr(GError) error = NULL;
+
+       /* no longer care */
+       g_signal_handlers_disconnect_by_data (plugin_loader, self);
+
+       /* not sure how to handle this */
+       if (!gs_plugin_loader_refresh_finish (plugin_loader, res, &error)) {
+               g_warning ("failed to load metadata: %s", error->message);
+               return;
+       }
+
+       /* UI is good to go */
+       g_signal_emit (self, signals[SIGNAL_REFRESHED], 0);
+}
+
+/**
+ * gs_shell_loading_load:
+ */
+static void
+gs_shell_loading_load (GsShellLoading *self)
+{
+       GsShellLoadingPrivate *priv = gs_shell_loading_get_instance_private (self);
+
+       /* ensure that at least some metadata of any age is present, and also
+        * spin up the plugins enough as to prime caches */
+       gs_plugin_loader_refresh_async (priv->plugin_loader, -1,
+                                       GS_PLUGIN_REFRESH_FLAGS_METADATA,
+                                       priv->cancellable,
+                                       gs_shell_loading_refresh_cb,
+                                       self);
+       g_signal_connect (priv->plugin_loader, "status-changed",
+                         G_CALLBACK (gs_shell_loading_status_changed_cb),
+                         self);
+}
+
+/**
+ * gs_shell_loading_switch_to:
+ **/
+static void
+gs_shell_loading_switch_to (GsPage *page, gboolean scroll_up)
+{
+       GsShellLoading *self = GS_SHELL_LOADING (page);
+       GsShellLoadingPrivate *priv = gs_shell_loading_get_instance_private (self);
+
+       if (gs_shell_get_mode (priv->shell) != GS_SHELL_MODE_LOADING) {
+               g_warning ("Called switch_to(loading) when in mode %s",
+                          gs_shell_get_mode_string (priv->shell));
+               return;
+       }
+       gs_shell_loading_load (self);
+}
+
+/**
+ * gs_shell_loading_setup:
+ */
+void
+gs_shell_loading_setup (GsShellLoading *self,
+                       GsShell *shell,
+                       GsPluginLoader *plugin_loader,
+                       GtkBuilder *builder,
+                       GCancellable *cancellable)
+{
+       GsShellLoadingPrivate *priv = gs_shell_loading_get_instance_private (self);
+
+       g_return_if_fail (GS_IS_SHELL_LOADING (self));
+
+       priv->shell = shell;
+       priv->plugin_loader = g_object_ref (plugin_loader);
+       priv->cancellable = g_object_ref (cancellable);
+
+       /* chain up */
+       gs_page_setup (GS_PAGE (self), shell, plugin_loader, cancellable);
+}
+
+/**
+ * gs_shell_loading_dispose:
+ **/
+static void
+gs_shell_loading_dispose (GObject *object)
+{
+       GsShellLoading *self = GS_SHELL_LOADING (object);
+       GsShellLoadingPrivate *priv = gs_shell_loading_get_instance_private (self);
+
+       g_clear_object (&priv->plugin_loader);
+       g_clear_object (&priv->cancellable);
+
+       G_OBJECT_CLASS (gs_shell_loading_parent_class)->dispose (object);
+}
+
+/**
+ * gs_shell_loading_class_init:
+ **/
+static void
+gs_shell_loading_class_init (GsShellLoadingClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GsPageClass *page_class = GS_PAGE_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+       object_class->dispose = gs_shell_loading_dispose;
+       page_class->switch_to = gs_shell_loading_switch_to;
+
+       signals [SIGNAL_REFRESHED] =
+               g_signal_new ("refreshed",
+                             G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET (GsShellLoadingClass, refreshed),
+                             NULL, NULL, g_cclosure_marshal_VOID__VOID,
+                             G_TYPE_NONE, 0);
+
+       gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Software/gs-shell-loading.ui");
+
+       gtk_widget_class_bind_template_child_private (widget_class, GsShellLoading, progressbar);
+       gtk_widget_class_bind_template_child_private (widget_class, GsShellLoading, label);
+}
+
+/**
+ * gs_shell_loading_init:
+ **/
+static void
+gs_shell_loading_init (GsShellLoading *self)
+{
+       gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+/**
+ * gs_shell_loading_new:
+ **/
+GsShellLoading *
+gs_shell_loading_new (void)
+{
+       GsShellLoading *self;
+       self = g_object_new (GS_TYPE_SHELL_LOADING, NULL);
+       return GS_SHELL_LOADING (self);
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-shell-loading.h b/src/gs-shell-loading.h
new file mode 100644
index 0000000..5808560
--- /dev/null
+++ b/src/gs-shell-loading.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GS_SHELL_LOADING_H
+#define __GS_SHELL_LOADING_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gs-page.h"
+#include "gs-plugin-loader.h"
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_SHELL_LOADING (gs_shell_loading_get_type ())
+
+G_DECLARE_DERIVABLE_TYPE (GsShellLoading, gs_shell_loading, GS, SHELL_LOADING, GsPage)
+
+struct _GsShellLoadingClass
+{
+       GsPageClass              parent_class;
+
+       void    (*refreshed)    (GsShellLoading *self);
+};
+
+GsShellLoading *gs_shell_loading_new           (void);
+void            gs_shell_loading_setup         (GsShellLoading         *self,
+                                                GsShell                *shell,
+                                                GsPluginLoader         *plugin_loader,
+                                                GtkBuilder             *builder,
+                                                GCancellable           *cancellable);
+
+G_END_DECLS
+
+#endif /* __GS_SHELL_LOADING_H */
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-shell-loading.ui b/src/gs-shell-loading.ui
new file mode 100644
index 0000000..d5245ee
--- /dev/null
+++ b/src/gs-shell-loading.ui
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.10"/>
+  <template class="GsShellLoading" parent="GsPage">
+    <child internal-child="accessible">
+      <object class="AtkObject" id="loading-accessible">
+        <property name="accessible-name" translatable="yes">Loading page</property>
+      </object>
+    </child>
+    <child>
+      <object class="GtkBox" id="box">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">48</property>
+        <property name="hexpand">True</property>
+        <property name="vexpand">True</property>
+        <style>
+          <class name="dim-label"/>
+        </style>
+        <child type="center">
+          <object class="GtkBox" id="centerbox">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">12</property>
+            <child>
+              <object class="GtkImage" id="image">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="pixel_size">256</property>
+                <property name="icon_name">org.gnome.Software-symbolic</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkProgressBar" id="progressbar">
+                <property name="visible">True</property>
+                <property name="width_request">480</property>
+                <property name="halign">center</property>
+                <property name="fraction">0.0</property>
+                <property name="margin_top">8</property>
+                <style>
+                  <class name="upgrade-progressbar"/>
+                </style>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Starting up…</property>
+                <attributes>
+                  <attribute name="scale" value="1.4"/>
+                </attributes>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/gs-shell.c b/src/gs-shell.c
index 5f7e95c..6839c7f 100644
--- a/src/gs-shell.c
+++ b/src/gs-shell.c
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *
- * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2013-2016 Richard Hughes <richard hughsie com>
  * Copyright (C) 2013 Matthias Clasen <mclasen redhat com>
  *
  * Licensed under the GNU General Public License Version 2
@@ -30,6 +30,7 @@
 #include "gs-shell-details.h"
 #include "gs-shell-installed.h"
 #include "gs-shell-moderate.h"
+#include "gs-shell-loading.h"
 #include "gs-shell-search.h"
 #include "gs-shell-overview.h"
 #include "gs-shell-updates.h"
@@ -40,6 +41,7 @@
 #include "gs-update-monitor.h"
 
 static const gchar *page_name[] = {
+       "unknown",
        "overview",
        "installed",
        "search",
@@ -48,6 +50,7 @@ static const gchar *page_name[] = {
        "category",
        "extras",
        "moderate",
+       "loading",
 };
 
 typedef struct {
@@ -66,6 +69,7 @@ typedef struct
        GsShellOverview         *shell_overview;
        GsShellInstalled        *shell_installed;
        GsShellModerate         *shell_moderate;
+       GsShellLoading          *shell_loading;
        GsShellSearch           *shell_search;
        GsShellUpdates          *shell_updates;
        GsShellDetails          *shell_details;
@@ -286,6 +290,9 @@ gs_shell_change_mode (GsShell *shell,
        case GS_SHELL_MODE_MODERATE:
                new_page = GS_PAGE (priv->shell_moderate);
                break;
+       case GS_SHELL_MODE_LOADING:
+               new_page = GS_PAGE (priv->shell_loading);
+               break;
        case GS_SHELL_MODE_SEARCH:
                widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "entry_search"));
                text = gtk_entry_get_text (GTK_ENTRY (widget));
@@ -770,6 +777,12 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can
                                 priv->plugin_loader,
                                 priv->builder,
                                 priv->cancellable);
+       priv->shell_loading = GS_SHELL_LOADING (gtk_builder_get_object (priv->builder, "shell_loading"));
+       gs_shell_loading_setup (priv->shell_loading,
+                               shell,
+                               priv->plugin_loader,
+                               priv->builder,
+                               priv->cancellable);
        priv->shell_search = GS_SHELL_SEARCH (gtk_builder_get_object (priv->builder, "shell_search"));
        gs_shell_search_setup (priv->shell_search,
                               shell,
@@ -808,7 +821,7 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can
                          G_CALLBACK (search_changed_handler), shell);
 
        /* load content */
-       g_signal_connect (priv->shell_overview, "refreshed",
+       g_signal_connect (priv->shell_loading, "refreshed",
                          G_CALLBACK (initial_overview_load_done), shell);
 }
 
diff --git a/src/gs-shell.h b/src/gs-shell.h
index 4a68228..ae95209 100644
--- a/src/gs-shell.h
+++ b/src/gs-shell.h
@@ -43,6 +43,7 @@ struct _GsShellClass
 };
 
 typedef enum {
+       GS_SHELL_MODE_UNKNOWN,
        GS_SHELL_MODE_OVERVIEW,
        GS_SHELL_MODE_INSTALLED,
        GS_SHELL_MODE_SEARCH,
@@ -51,6 +52,7 @@ typedef enum {
        GS_SHELL_MODE_CATEGORY,
        GS_SHELL_MODE_EXTRAS,
        GS_SHELL_MODE_MODERATE,
+       GS_SHELL_MODE_LOADING,
        GS_SHELL_MODE_LAST
 } GsShellMode;
 
diff --git a/src/plugins/gs-plugin-steam.c b/src/plugins/gs-plugin-steam.c
index faedb03..b1dc8b1 100644
--- a/src/plugins/gs-plugin-steam.c
+++ b/src/plugins/gs-plugin-steam.c
@@ -698,11 +698,16 @@ gs_plugin_steam_update_store (GsPlugin *plugin, AsStore *store, GPtrArray *apps,
 {
        guint i;
        GHashTable *app;
+       g_autoptr(GsApp) dummy = gs_app_new (NULL);
 
        for (i = 0; i < apps->len; i++) {
                app = g_ptr_array_index (apps, i);
                if (!gs_plugin_steam_update_store_app (plugin, store, app, error))
                        return FALSE;
+
+               /* update progress */
+               gs_app_set_progress (dummy, (gdouble) i * 100.f / (gdouble) apps->len);
+               gs_plugin_status_update (plugin, dummy, GS_PLUGIN_STATUS_DOWNLOADING);
        }
        return TRUE;
 }


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