[gnome-software: 7/13] update-dialog: Use a HdyDeck for subviews
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software: 7/13] update-dialog: Use a HdyDeck for subviews
- Date: Tue, 10 Aug 2021 07:25:59 +0000 (UTC)
commit 8db81df769a1541b33d6cb1c6d034f89b537afb6
Author: Adrien Plazas <kekun plazas laposte net>
Date: Wed Aug 4 13:50:58 2021 +0200
update-dialog: Use a HdyDeck for subviews
This simplifies the code a lot and allows back gestures.
src/gs-update-dialog.c | 626 +++---------------------------------------------
src/gs-update-dialog.ui | 198 +--------------
2 files changed, 40 insertions(+), 784 deletions(-)
---
diff --git a/src/gs-update-dialog.c b/src/gs-update-dialog.c
index e2a86f052..f6665cf44 100644
--- a/src/gs-update-dialog.c
+++ b/src/gs-update-dialog.c
@@ -12,238 +12,36 @@
#include <glib/gi18n.h>
#include "gs-update-dialog.h"
+#include "gs-app-details-page.h"
#include "gs-app-row.h"
+#include "gs-os-update-page.h"
#include "gs-update-list.h"
#include "gs-common.h"
-typedef struct {
- gchar *title;
- gchar *stack_page;
- GtkWidget *focus;
-} BackEntry;
-
-typedef enum {
- GS_UPDATE_DIALOG_SECTION_ADDITIONS,
- GS_UPDATE_DIALOG_SECTION_REMOVALS,
- GS_UPDATE_DIALOG_SECTION_UPDATES,
- GS_UPDATE_DIALOG_SECTION_DOWNGRADES,
- GS_UPDATE_DIALOG_SECTION_LAST,
-} GsUpdateDialogSection;
-
struct _GsUpdateDialog
{
HdyWindow parent_instance;
- GQueue *back_entry_stack;
GCancellable *cancellable;
GsPluginLoader *plugin_loader;
- GtkWidget *box_header;
- GtkWidget *button_back;
- GtkWidget *image_icon;
- GtkWidget *label_details;
- GtkWidget *label_name;
- GtkWidget *label_summary;
- GtkWidget *list_boxes[GS_UPDATE_DIALOG_SECTION_LAST];
+ GtkWidget *deck;
GtkWidget *list_box_installed_updates;
- GtkWidget *os_update_description;
- GtkWidget *os_update_box;
- GtkWidget *scrolledwindow;
- GtkWidget *scrolledwindow_details;
GtkWidget *spinner;
GtkWidget *stack;
- GtkWidget *permissions_section_box;
- GtkWidget *permissions_section_content;
};
G_DEFINE_TYPE (GsUpdateDialog, gs_update_dialog, HDY_TYPE_WINDOW)
static void
-save_back_entry (GsUpdateDialog *dialog)
-{
- BackEntry *entry;
-
- entry = g_slice_new0 (BackEntry);
- entry->stack_page = g_strdup (gtk_stack_get_visible_child_name (GTK_STACK (dialog->stack)));
- entry->title = g_strdup (gtk_window_get_title (GTK_WINDOW (dialog)));
-
- entry->focus = gtk_window_get_focus (GTK_WINDOW (dialog));
- if (entry->focus != NULL)
- g_object_add_weak_pointer (G_OBJECT (entry->focus),
- (gpointer *) &entry->focus);
-
- g_queue_push_head (dialog->back_entry_stack, entry);
-}
-
-static void
-back_entry_free (BackEntry *entry)
-{
- if (entry->focus != NULL)
- g_object_remove_weak_pointer (G_OBJECT (entry->focus),
- (gpointer *) &entry->focus);
- g_free (entry->stack_page);
- g_free (entry->title);
- g_slice_free (BackEntry, entry);
-}
-
-static struct {
- GsAppPermissions permission;
- const char *title;
- const char *subtitle;
-} permission_display_data[] = {
- { GS_APP_PERMISSIONS_NETWORK, N_("Network"), N_("Can communicate over the network") },
- { GS_APP_PERMISSIONS_SYSTEM_BUS, N_("System Services"), N_("Can access D-Bus services on the system bus")
},
- { GS_APP_PERMISSIONS_SESSION_BUS, N_("Session Services"), N_("Can access D-Bus services on the session
bus") },
- { GS_APP_PERMISSIONS_DEVICES, N_("Devices"), N_("Can access system device files") },
- { GS_APP_PERMISSIONS_HOME_FULL, N_("Home folder"), N_("Can view, edit and create files") },
- { GS_APP_PERMISSIONS_HOME_READ, N_("Home folder"), N_("Can view files") },
- { GS_APP_PERMISSIONS_FILESYSTEM_FULL, N_("File system"), N_("Can view, edit and create files") },
- { GS_APP_PERMISSIONS_FILESYSTEM_READ, N_("File system"), N_("Can view files") },
- { GS_APP_PERMISSIONS_DOWNLOADS_FULL, N_("Downloads folder"), N_("Can view, edit and create files") },
- { GS_APP_PERMISSIONS_DOWNLOADS_READ, N_("Downloads folder"), N_("Can view files") },
- { GS_APP_PERMISSIONS_SETTINGS, N_("Settings"), N_("Can view and change any settings") },
- { GS_APP_PERMISSIONS_X11, N_("Legacy display system"), N_("Uses an old, insecure display system") },
- { GS_APP_PERMISSIONS_ESCAPE_SANDBOX, N_("Sandbox escape"), N_("Can escape the sandbox and circumvent any
other restrictions") },
-};
-
-static void
-populate_permissions_section (GsUpdateDialog *dialog, GsAppPermissions permissions)
-{
- GList *children;
-
- children = gtk_container_get_children (GTK_CONTAINER (dialog->permissions_section_content));
- for (GList *l = children; l != NULL; l = l->next)
- gtk_widget_destroy (GTK_WIDGET (l->data));
- g_list_free (children);
-
- for (gsize i = 0; i < G_N_ELEMENTS (permission_display_data); i++) {
- GtkWidget *row, *image, *box, *label;
-
- if ((permissions & permission_display_data[i].permission) == 0)
- continue;
-
- row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
- gtk_widget_show (row);
- if ((permission_display_data[i].permission & ~MEDIUM_PERMISSIONS) != 0) {
- gtk_style_context_add_class (gtk_widget_get_style_context (row),
"permission-row-warning");
- }
-
- image = gtk_image_new_from_icon_name ("dialog-warning-symbolic", GTK_ICON_SIZE_MENU);
- if ((permission_display_data[i].permission & ~MEDIUM_PERMISSIONS) == 0)
- gtk_widget_set_opacity (image, 0);
-
- gtk_widget_show (image);
- gtk_container_add (GTK_CONTAINER (row), image);
-
- box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
- gtk_widget_show (box);
- gtk_container_add (GTK_CONTAINER (row), box);
-
- label = gtk_label_new (_(permission_display_data[i].title));
- gtk_label_set_xalign (GTK_LABEL (label), 0);
- gtk_widget_show (label);
- gtk_container_add (GTK_CONTAINER (box), label);
-
- label = gtk_label_new (_(permission_display_data[i].subtitle));
- gtk_label_set_xalign (GTK_LABEL (label), 0);
- gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label");
- gtk_widget_show (label);
- gtk_container_add (GTK_CONTAINER (box), label);
-
- gtk_container_add (GTK_CONTAINER (dialog->permissions_section_content), row);
- }
-}
-
-static void
-set_updates_description_ui (GsUpdateDialog *dialog, GsApp *app)
-{
- AsComponentKind kind;
- g_autoptr(GIcon) icon = NULL;
- guint icon_size;
- const gchar *update_details;
-
- /* set window title */
- kind = gs_app_get_kind (app);
- if (kind == AS_COMPONENT_KIND_GENERIC &&
- gs_app_get_special_kind (app) == GS_APP_SPECIAL_KIND_OS_UPDATE) {
- gtk_window_set_title (GTK_WINDOW (dialog), gs_app_get_name (app));
- } else if (gs_app_get_source_default (app) != NULL &&
- gs_app_get_update_version (app) != NULL) {
- g_autofree gchar *tmp = NULL;
- tmp = g_strdup_printf ("%s %s",
- gs_app_get_source_default (app),
- gs_app_get_update_version (app));
- gtk_window_set_title (GTK_WINDOW (dialog), tmp);
- } else if (gs_app_get_source_default (app) != NULL) {
- gtk_window_set_title (GTK_WINDOW (dialog),
- gs_app_get_source_default (app));
- } else {
- gtk_window_set_title (GTK_WINDOW (dialog),
- gs_app_get_update_version (app));
- }
-
- /* set update header */
- gtk_widget_set_visible (dialog->box_header, kind == AS_COMPONENT_KIND_DESKTOP_APP);
- update_details = gs_app_get_update_details (app);
- if (update_details == NULL) {
- /* TRANSLATORS: this is where the packager did not write
- * a description for the update */
- update_details = _("No update description available.");
- }
- gtk_label_set_label (GTK_LABEL (dialog->label_details), update_details);
- gtk_label_set_label (GTK_LABEL (dialog->label_name), gs_app_get_name (app));
- gtk_label_set_label (GTK_LABEL (dialog->label_summary), gs_app_get_summary (app));
-
- /* set the icon; fall back to 64px if 96px isn’t available, which sometimes
- * happens at 2× scale factor (hi-DPI) */
- icon_size = 96;
- icon = gs_app_get_icon_for_size (app,
- icon_size,
- gtk_widget_get_scale_factor (dialog->image_icon),
- NULL);
- if (icon == NULL) {
- icon_size = 64;
- icon = gs_app_get_icon_for_size (app,
- icon_size,
- gtk_widget_get_scale_factor (dialog->image_icon),
- NULL);
- }
- if (icon == NULL) {
- icon_size = 96;
- icon = gs_app_get_icon_for_size (app,
- icon_size,
- gtk_widget_get_scale_factor (dialog->image_icon),
- "system-component-application");
- }
-
- gtk_image_set_pixel_size (GTK_IMAGE (dialog->image_icon), icon_size);
- gtk_image_set_from_gicon (GTK_IMAGE (dialog->image_icon), icon,
- GTK_ICON_SIZE_INVALID);
-
- /* show the back button if needed */
- gtk_widget_set_visible (dialog->button_back, !g_queue_is_empty (dialog->back_entry_stack));
-
- if (gs_app_has_quirk (app, GS_APP_QUIRK_NEW_PERMISSIONS)) {
- gtk_widget_show (dialog->permissions_section_box);
- populate_permissions_section (dialog, gs_app_get_update_permissions (app));
- } else {
- gtk_widget_hide (dialog->permissions_section_box);
- }
-}
-
-static void
-row_activated_cb (GtkListBox *list_box,
- GtkListBoxRow *row,
- GsUpdateDialog *dialog)
+deck_child_transition_cb (HdyDeck *deck, GParamSpec *pspec, GsUpdateDialog *dialog)
{
- GsApp *app;
-
- app = GS_APP (g_object_get_data (G_OBJECT (gtk_bin_get_child (GTK_BIN (row))), "app"));
+ GtkWidget *child;
- /* save the current stack state for the back button */
- save_back_entry (dialog);
+ if (hdy_deck_get_transition_running (deck))
+ return;
- /* setup package view */
- gs_update_dialog_show_update_details (dialog, app);
+ while ((child = hdy_deck_get_adjacent_child (deck, HDY_NAVIGATION_DIRECTION_FORWARD)))
+ gtk_widget_destroy (child);
}
static void
@@ -255,9 +53,6 @@ installed_updates_row_activated_cb (GtkListBox *list_box,
app = gs_app_row_get_app (GS_APP_ROW (row));
- /* save the current stack state for the back button */
- save_back_entry (dialog);
-
gs_update_dialog_show_update_details (dialog, app);
}
@@ -335,7 +130,6 @@ gs_update_dialog_show_installed_updates (GsUpdateDialog *dialog)
/* TRANSLATORS: this is the title of the installed updates dialog window */
gtk_window_set_title (GTK_WINDOW (dialog), _("Installed Updates"));
- gtk_widget_set_visible (dialog->button_back, !g_queue_is_empty (dialog->back_entry_stack));
gs_start_spinner (GTK_SPINNER (dialog->spinner));
gtk_stack_set_visible_child_name (GTK_STACK (dialog->stack), "spinner");
@@ -361,289 +155,22 @@ unset_focus (GtkWidget *widget)
gtk_window_set_focus (GTK_WINDOW (widget), NULL);
}
-static gchar *
-format_version_update (GsApp *app, GtkTextDirection direction)
-{
- const gchar *tmp;
- const gchar *version_current = NULL;
- const gchar *version_update = NULL;
-
- /* current version */
- tmp = gs_app_get_version (app);
- if (tmp != NULL && tmp[0] != '\0')
- version_current = tmp;
-
- /* update version */
- tmp = gs_app_get_update_version (app);
- if (tmp != NULL && tmp[0] != '\0')
- version_update = tmp;
-
- /* have both */
- if (version_current != NULL && version_update != NULL &&
- g_strcmp0 (version_current, version_update) != 0) {
- switch (direction) {
- case GTK_TEXT_DIR_RTL:
- /* This might look the wrong way round, but that’s
- * because the #GtkLabel this is put in will reverse the
- * text order in RTL, but won’t swap ← for → or
- * vice-versa (the bidi mirroring property of those two
- * arrows is false). So we need to explicitly use ‘←’ in
- * RTL locales, but not change the text order.
- * See section 2 of http://www.unicode.org/L2/L2017/17438-bidi-math-fdbk.html */
- return g_strdup_printf ("%s ← %s",
- version_current,
- version_update);
- case GTK_TEXT_DIR_NONE:
- case GTK_TEXT_DIR_LTR:
- default:
- return g_strdup_printf ("%s → %s",
- version_current,
- version_update);
- }
- }
-
- /* just update */
- if (version_update)
- return g_strdup (version_update);
-
- /* we have nothing, nada, zilch */
- return NULL;
-}
-
-static GtkWidget *
-create_app_row (GsApp *app)
-{
- GtkWidget *row, *label;
-
- row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
- g_object_set_data_full (G_OBJECT (row),
- "app",
- g_object_ref (app),
- g_object_unref);
- label = gtk_label_new (gs_app_get_source_default (app));
- g_object_set (label,
- "margin-start", 20,
- "margin-end", 0,
- "margin-top", 6,
- "margin-bottom", 6,
- "xalign", 0.0,
- "ellipsize", PANGO_ELLIPSIZE_END,
- NULL);
- gtk_widget_set_halign (label, GTK_ALIGN_START);
- gtk_widget_set_hexpand (label, TRUE);
- gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
- gtk_container_add (GTK_CONTAINER (row), label);
- if (gs_app_get_state (app) == GS_APP_STATE_UPDATABLE ||
- gs_app_get_state (app) == GS_APP_STATE_UPDATABLE_LIVE) {
- g_autofree gchar *verstr = format_version_update (app, gtk_widget_get_direction (row));
- label = gtk_label_new (verstr);
- } else {
- label = gtk_label_new (gs_app_get_version (app));
- }
- g_object_set (label,
- "margin-start", 0,
- "margin-end", 20,
- "margin-top", 6,
- "margin-bottom", 6,
- "xalign", 1.0,
- "ellipsize", PANGO_ELLIPSIZE_END,
- NULL);
- gtk_widget_set_halign (label, GTK_ALIGN_END);
- gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
- gtk_container_add (GTK_CONTAINER (row), label);
- gtk_widget_show_all (row);
-
- return row;
-}
-
-static gboolean
-is_downgrade (const gchar *evr1,
- const gchar *evr2)
-{
- gint rc;
- g_autofree gchar *epoch1 = NULL;
- g_autofree gchar *epoch2 = NULL;
- g_autofree gchar *version1 = NULL;
- g_autofree gchar *version2 = NULL;
- g_autofree gchar *release1 = NULL;
- g_autofree gchar *release2 = NULL;
-
- if (evr1 == NULL || evr2 == NULL)
- return FALSE;
-
- /* split into epoch-version-release */
- if (!gs_utils_parse_evr (evr1, &epoch1, &version1, &release1))
- return FALSE;
- if (!gs_utils_parse_evr (evr2, &epoch2, &version2, &release2))
- return FALSE;
-
- /* ignore epoch here as it's a way to make downgrades happen and not
- * part of the semantic version */
-
- /* check version */
- rc = as_vercmp_simple (version1, version2);
- if (rc != 0)
- return rc > 0;
-
- /* check release */
- rc = as_vercmp_simple (release1, release2);
- if (rc != 0)
- return rc > 0;
-
- return FALSE;
-}
-
-static GsUpdateDialogSection
-get_app_section (GsApp *app)
-{
- GsUpdateDialogSection section;
-
- /* Sections:
- * 1. additions
- * 2. removals
- * 3. updates
- * 4. downgrades */
- switch (gs_app_get_state (app)) {
- case GS_APP_STATE_AVAILABLE:
- section = GS_UPDATE_DIALOG_SECTION_ADDITIONS;
- break;
- case GS_APP_STATE_UNAVAILABLE:
- section = GS_UPDATE_DIALOG_SECTION_REMOVALS;
- break;
- case GS_APP_STATE_UPDATABLE:
- case GS_APP_STATE_UPDATABLE_LIVE:
- if (is_downgrade (gs_app_get_version (app),
- gs_app_get_update_version (app)))
- section = GS_UPDATE_DIALOG_SECTION_DOWNGRADES;
- else
- section = GS_UPDATE_DIALOG_SECTION_UPDATES;
- break;
- default:
- g_warning ("get_app_section: unhandled state %s for %s",
- gs_app_state_to_string (gs_app_get_state (app)),
- gs_app_get_unique_id (app));
- section = GS_UPDATE_DIALOG_SECTION_UPDATES;
- break;
- }
-
- return section;
-}
-
-static gint
-os_updates_sort_func (GtkListBoxRow *a,
- GtkListBoxRow *b,
- gpointer user_data)
-{
- GObject *o1 = G_OBJECT (gtk_bin_get_child (GTK_BIN (a)));
- GObject *o2 = G_OBJECT (gtk_bin_get_child (GTK_BIN (b)));
- GsApp *a1 = g_object_get_data (o1, "app");
- GsApp *a2 = g_object_get_data (o2, "app");
- const gchar *key1 = gs_app_get_source_default (a1);
- const gchar *key2 = gs_app_get_source_default (a2);
-
- return g_strcmp0 (key1, key2);
-}
-
-static GtkWidget *
-get_section_header (GsUpdateDialog *dialog, GsUpdateDialogSection section)
-{
- GtkStyleContext *context;
- GtkWidget *header;
- GtkWidget *label;
-
- /* get labels and buttons for everything */
- if (section == GS_UPDATE_DIALOG_SECTION_ADDITIONS) {
- /* TRANSLATORS: This is the header for package additions during
- * a system update */
- label = gtk_label_new (_("Additions"));
- } else if (section == GS_UPDATE_DIALOG_SECTION_REMOVALS) {
- /* TRANSLATORS: This is the header for package removals during
- * a system update */
- label = gtk_label_new (_("Removals"));
- } else if (section == GS_UPDATE_DIALOG_SECTION_UPDATES) {
- /* TRANSLATORS: This is the header for package updates during
- * a system update */
- label = gtk_label_new (_("Updates"));
- } else if (section == GS_UPDATE_DIALOG_SECTION_DOWNGRADES) {
- /* TRANSLATORS: This is the header for package downgrades during
- * a system update */
- label = gtk_label_new (_("Downgrades"));
- } else {
- g_assert_not_reached ();
- }
-
- /* create header */
- header = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
- context = gtk_widget_get_style_context (header);
- gtk_style_context_add_class (context, "app-listbox-header");
-
- /* put label into the header */
- gtk_widget_set_hexpand (label, TRUE);
- gtk_container_add (GTK_CONTAINER (header), label);
- gtk_widget_set_visible (label, TRUE);
- gtk_widget_set_margin_start (label, 6);
- gtk_label_set_xalign (GTK_LABEL (label), 0.0);
- context = gtk_widget_get_style_context (label);
- gtk_style_context_add_class (context, "app-listbox-header-title");
-
- /* success */
- return header;
-}
-
static void
-list_header_func (GtkListBoxRow *row,
- GtkListBoxRow *before,
- gpointer user_data)
+back_clicked_cb (GtkWidget *widget, GsUpdateDialog *dialog)
{
- GsUpdateDialog *dialog = (GsUpdateDialog *) user_data;
- GObject *o = G_OBJECT (gtk_bin_get_child (GTK_BIN (row)));
- GsApp *app = g_object_get_data (o, "app");
- GtkWidget *header = NULL;
-
- if (before == NULL)
- header = get_section_header (dialog, get_app_section (app));
- else
- header = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
- gtk_list_box_row_set_header (row, header);
+ hdy_deck_navigate (HDY_DECK (dialog->deck), HDY_NAVIGATION_DIRECTION_BACK);
}
static void
-create_section (GsUpdateDialog *dialog, GsUpdateDialogSection section)
+app_activated_cb (GtkWidget *widget, GsApp *app, GsUpdateDialog *page)
{
- GtkStyleContext *context;
-
- dialog->list_boxes[section] = gtk_list_box_new ();
- gtk_list_box_set_selection_mode (GTK_LIST_BOX (dialog->list_boxes[section]),
- GTK_SELECTION_NONE);
- gtk_list_box_set_sort_func (GTK_LIST_BOX (dialog->list_boxes[section]),
- os_updates_sort_func,
- dialog, NULL);
- gtk_list_box_set_header_func (GTK_LIST_BOX (dialog->list_boxes[section]),
- list_header_func,
- dialog, NULL);
- g_signal_connect (GTK_LIST_BOX (dialog->list_boxes[section]), "row-activated",
- G_CALLBACK (row_activated_cb), dialog);
- gtk_widget_set_visible (dialog->list_boxes[section], TRUE);
- gtk_widget_set_vexpand (dialog->list_boxes[section], TRUE);
- gtk_container_add (GTK_CONTAINER (dialog->os_update_box), dialog->list_boxes[section]);
- gtk_widget_set_margin_top (dialog->list_boxes[section], 24);
-
- /* reorder the children */
- for (guint i = 0; i < GS_UPDATE_DIALOG_SECTION_LAST; i++) {
- if (dialog->list_boxes[i] == NULL)
- continue;
- gtk_box_reorder_child (GTK_BOX (dialog->os_update_box),
- dialog->list_boxes[i], i);
- }
-
- /* make rounded edges */
- context = gtk_widget_get_style_context (dialog->list_boxes[section]);
- gtk_style_context_add_class (context, "app-updates-section");
+ gs_update_dialog_show_update_details (page, app);
}
void
gs_update_dialog_show_update_details (GsUpdateDialog *dialog, GsApp *app)
{
+ GtkWidget *page;
AsComponentKind kind;
g_autofree gchar *str = NULL;
@@ -651,9 +178,6 @@ gs_update_dialog_show_update_details (GsUpdateDialog *dialog, GsApp *app)
str = gs_app_to_string (app);
g_debug ("%s", str);
- /* set update header */
- set_updates_description_ui (dialog, app);
-
/* workaround a gtk+ issue where the dialog comes up with a label selected,
* https://bugzilla.gnome.org/show_bug.cgi?id=734033 */
unset_focus (GTK_WIDGET (dialog));
@@ -662,79 +186,21 @@ gs_update_dialog_show_update_details (GsUpdateDialog *dialog, GsApp *app)
kind = gs_app_get_kind (app);
if (kind == AS_COMPONENT_KIND_GENERIC &&
gs_app_get_special_kind (app) == GS_APP_SPECIAL_KIND_OS_UPDATE) {
- GsAppList *related;
- GsApp *app_related;
- GsUpdateDialogSection section;
- GtkWidget *row;
-
- gtk_label_set_text (GTK_LABEL (dialog->os_update_description),
- gs_app_get_description (app));
-
- /* clear existing data */
- for (guint i = 0; i < GS_UPDATE_DIALOG_SECTION_LAST; i++) {
- if (dialog->list_boxes[i] == NULL)
- continue;
- gs_container_remove_all (GTK_CONTAINER (dialog->list_boxes[i]));
- }
-
- /* add new apps */
- related = gs_app_get_related (app);
- for (guint i = 0; i < gs_app_list_length (related); i++) {
- app_related = gs_app_list_index (related, i);
-
- section = get_app_section (app_related);
- if (dialog->list_boxes[section] == NULL)
- create_section (dialog, section);
-
- row = create_app_row (app_related);
- gtk_list_box_insert (GTK_LIST_BOX (dialog->list_boxes[section]), row, -1);
- }
- gtk_stack_set_transition_type (GTK_STACK (dialog->stack),
GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT);
- gtk_stack_set_visible_child_name (GTK_STACK (dialog->stack), "os-update-list");
- gtk_stack_set_transition_type (GTK_STACK (dialog->stack), GTK_STACK_TRANSITION_TYPE_NONE);
+ page = gs_os_update_page_new ();
+ gs_os_update_page_set_app (GS_OS_UPDATE_PAGE (page), app);
+ g_signal_connect (page, "app-activated",
+ G_CALLBACK (app_activated_cb), dialog);
} else {
- gtk_stack_set_transition_type (GTK_STACK (dialog->stack),
GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT);
- gtk_stack_set_visible_child_name (GTK_STACK (dialog->stack), "package-details");
- gtk_stack_set_transition_type (GTK_STACK (dialog->stack), GTK_STACK_TRANSITION_TYPE_NONE);
+ page = gs_app_details_page_new ();
+ gs_app_details_page_set_app (GS_APP_DETAILS_PAGE (page), app);
}
-}
-
-static void
-button_back_cb (GtkWidget *widget, GsUpdateDialog *dialog)
-{
- BackEntry *entry;
-
- /* return to the previous view */
- entry = g_queue_pop_head (dialog->back_entry_stack);
- gtk_stack_set_transition_type (GTK_STACK (dialog->stack), GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT);
- gtk_stack_set_visible_child_name (GTK_STACK (dialog->stack), entry->stack_page);
- gtk_stack_set_transition_type (GTK_STACK (dialog->stack), GTK_STACK_TRANSITION_TYPE_NONE);
+ gtk_widget_show (page);
+ g_signal_connect (page, "back-clicked",
+ G_CALLBACK (back_clicked_cb), dialog);
- gtk_window_set_title (GTK_WINDOW (dialog), entry->title);
- if (entry->focus)
- gtk_widget_grab_focus (entry->focus);
- back_entry_free (entry);
-
- gtk_widget_set_visible (dialog->button_back, !g_queue_is_empty (dialog->back_entry_stack));
-}
-
-static void
-scrollbar_mapped_cb (GtkWidget *sb, GtkScrolledWindow *swin)
-{
- GtkWidget *frame;
-
- frame = gtk_bin_get_child (GTK_BIN (gtk_bin_get_child (GTK_BIN (swin))));
-
- if (gtk_widget_get_mapped (GTK_WIDGET (sb))) {
- gtk_scrolled_window_set_shadow_type (swin, GTK_SHADOW_IN);
- if (GTK_IS_FRAME (frame))
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
- } else {
- if (GTK_IS_FRAME (frame))
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
- gtk_scrolled_window_set_shadow_type (swin, GTK_SHADOW_NONE);
- }
+ gtk_container_add (GTK_CONTAINER (dialog->deck), page);
+ hdy_deck_set_visible_child (HDY_DECK (dialog->deck), page);
}
static gboolean
@@ -749,7 +215,7 @@ key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget));
gdk_keymap_add_virtual_modifiers (keymap, &state);
state = state & gtk_accelerator_get_default_mod_mask ();
- is_rtl = gtk_widget_get_direction (dialog->button_back) == GTK_TEXT_DIR_RTL;
+ is_rtl = gtk_widget_get_direction (GTK_WIDGET (dialog)) == GTK_TEXT_DIR_RTL;
if (event->keyval == GDK_KEY_Escape) {
gtk_window_close (GTK_WINDOW (dialog));
@@ -757,13 +223,10 @@ key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
return GDK_EVENT_STOP;
}
- if (!gtk_widget_is_visible (dialog->button_back) || !gtk_widget_is_sensitive (dialog->button_back))
- return GDK_EVENT_PROPAGATE;
-
if ((!is_rtl && state == GDK_MOD1_MASK && event->keyval == GDK_KEY_Left) ||
(is_rtl && state == GDK_MOD1_MASK && event->keyval == GDK_KEY_Right) ||
event->keyval == GDK_KEY_Back) {
- gtk_widget_activate (dialog->button_back);
+ hdy_deck_navigate (HDY_DECK (dialog->deck), HDY_NAVIGATION_DIRECTION_BACK);
return GDK_EVENT_STOP;
}
@@ -777,10 +240,7 @@ button_press_event (GsUpdateDialog *dialog, GdkEventButton *event)
if (event->button != 8)
return GDK_EVENT_PROPAGATE;
- if (!gtk_widget_is_visible (dialog->button_back) || !gtk_widget_is_sensitive (dialog->button_back))
- return GDK_EVENT_PROPAGATE;
-
- gtk_widget_activate (dialog->button_back);
+ hdy_deck_navigate (HDY_DECK (dialog->deck), HDY_NAVIGATION_DIRECTION_BACK);
return GDK_EVENT_STOP;
}
@@ -795,11 +255,6 @@ gs_update_dialog_dispose (GObject *object)
{
GsUpdateDialog *dialog = GS_UPDATE_DIALOG (object);
- if (dialog->back_entry_stack != NULL) {
- g_queue_free_full (dialog->back_entry_stack, (GDestroyNotify) back_entry_free);
- dialog->back_entry_stack = NULL;
- }
-
g_cancellable_cancel (dialog->cancellable);
g_clear_object (&dialog->cancellable);
@@ -811,26 +266,15 @@ gs_update_dialog_dispose (GObject *object)
static void
gs_update_dialog_init (GsUpdateDialog *dialog)
{
- GtkWidget *scrollbar;
-
gtk_widget_init_template (GTK_WIDGET (dialog));
- dialog->back_entry_stack = g_queue_new ();
dialog->cancellable = g_cancellable_new ();
g_signal_connect (GTK_LIST_BOX (dialog->list_box_installed_updates), "row-activated",
G_CALLBACK (installed_updates_row_activated_cb), dialog);
- g_signal_connect (dialog->button_back, "clicked",
- G_CALLBACK (button_back_cb),
- dialog);
-
g_signal_connect_after (dialog, "show", G_CALLBACK (unset_focus), NULL);
- scrollbar = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (dialog->scrolledwindow_details));
- g_signal_connect (scrollbar, "map", G_CALLBACK (scrollbar_mapped_cb), dialog->scrolledwindow_details);
- g_signal_connect (scrollbar, "unmap", G_CALLBACK (scrollbar_mapped_cb),
dialog->scrolledwindow_details);
-
/* global keynav and mouse back button */
g_signal_connect (dialog, "key-press-event",
G_CALLBACK (key_press_event), NULL);
@@ -848,21 +292,11 @@ gs_update_dialog_class_init (GsUpdateDialogClass *klass)
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Software/gs-update-dialog.ui");
- gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, box_header);
- gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, button_back);
- gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, image_icon);
- gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, label_details);
- gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, label_name);
- gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, label_summary);
+ gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, deck);
gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, list_box_installed_updates);
- gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, os_update_description);
- gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, os_update_box);
- gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, scrolledwindow);
- gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, scrolledwindow_details);
gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, spinner);
gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, stack);
- gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, permissions_section_box);
- gtk_widget_class_bind_template_child (widget_class, GsUpdateDialog, permissions_section_content);
+ gtk_widget_class_bind_template_callback (widget_class, deck_child_transition_cb);
}
GtkWidget *
diff --git a/src/gs-update-dialog.ui b/src/gs-update-dialog.ui
index 83562c7c3..42495c343 100644
--- a/src/gs-update-dialog.ui
+++ b/src/gs-update-dialog.ui
@@ -12,6 +12,14 @@
<property name="default-width">640</property>
<property name="default-height">576</property>
+ <child>
+ <object class="HdyDeck" id="deck">
+ <property name="visible">True</property>
+ <property name="can_swipe_back">True</property>
+ <!-- We need both signals to support the animations being disabled, as
+ notify::transition-running isn't emitted in that case. -->
+ <signal name="notify::visible-child" handler="deck_child_transition_cb" swapped="no"/>
+ <signal name="notify::transition-running" handler="deck_child_transition_cb" swapped="no"/>
<child>
<object class="GtkBox">
<property name="visible">True</property>
@@ -21,31 +29,6 @@
<property name="show_close_button">True</property>
<property name="visible">True</property>
<property name="title" bind-source="GsUpdateDialog" bind-property="title"
bind-flags="sync-create"/>
- <child>
- <object class="GtkButton" id="button_back">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="button_back_accessible">
- <property name="accessible-name" translatable="yes">Go back</property>
- </object>
- </child>
- <style>
- <class name="image-button"/>
- </style>
- <child>
- <object class="GtkImage" id="image_update_back">
- <property name="visible">True</property>
- <property name="icon_name">go-previous-symbolic</property>
- <property name="icon_size">1</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="pack-type">start</property>
- </packing>
- </child>
</object>
</child>
<child>
@@ -90,161 +73,6 @@
<property name="name">empty</property>
</packing>
</child>
- <child>
- <object class="GtkBox" id="box7">
- <property name="visible">True</property>
- <property name="margin_start">6</property>
- <property name="margin_end">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">9</property>
- <property name="border_width">5</property>
- <property name="orientation">vertical</property>
- <property name="spacing">9</property>
- <child>
- <object class="GtkBox" id="box_header">
- <property name="visible">True</property>
- <property name="spacing">9</property>
- <child>
- <object class="GtkImage" id="image_icon">
- <property name="visible">True</property>
- <property name="pixel_size">96</property>
- <property name="icon_name">system-component-application</property>
- <property name="icon_size">0</property>
- <style>
- <class name="icon-dropshadow"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkBox" id="box9">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="spacing">3</property>
- <child>
- <object class="GtkLabel" id="label_name">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label">Inkscape</property>
- <property name="selectable">True</property>
- <property name="wrap">True</property>
- <property name="max_width_chars">50</property>
- <property name="width_chars">50</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- <attribute name="scale" value="1.3999999999999999"/>
- </attributes>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="label_summary">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label">Vector based drawing program</property>
- <property name="selectable">True</property>
- <property name="wrap">True</property>
- <property name="max_width_chars">50</property>
- <property name="width_chars">50</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkBox" id="permissions_section_box">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
- <property name="margin_top">12</property>
- <property name="margin_bottom">18</property>
- <child>
- <object class="GtkLabel" id="permissions_section_title">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="halign">start</property>
- <property name="margin_bottom">6</property>
- <property name="label" translatable="yes">Requires additional permissions</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- </child>
- <child>
- <object class="GtkBox" id="permissions_section_content">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="spacing">12</property>
- <property name="margin-start">18</property>
- <property name="margin-end">18</property>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkScrolledWindow" id="scrolledwindow_details">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="vexpand">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="vscrollbar_policy">automatic</property>
- <property name="shadow_type">none</property>
- <child>
- <object class="GtkLabel" id="label_details">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="yalign">0</property>
- <property name="margin">6</property>
- <property name="label">New in kmod 14-1
-* Moo
-* bar</property>
- <property name="wrap">True</property>
- <property name="selectable">True</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="name">package-details</property>
- </packing>
- </child>
- <child>
- <object class="GtkScrolledWindow" id="scrolledwindow">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="vexpand">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="vscrollbar_policy">automatic</property>
- <property name="shadow_type">none</property>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="margin_top">24</property>
- <property name="margin_bottom">18</property>
- <property name="margin_start">18</property>
- <property name="margin_end">18</property>
- <child>
- <object class="GtkLabel" id="os_update_description">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="wrap">True</property>
- </object>
- </child>
- <child>
- <object class="GtkBox" id="os_update_box">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="vexpand">False</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="name">os-update-list</property>
- </packing>
- </child>
<child>
<object class="HdyPreferencesPage">
<property name="visible">True</property>
@@ -271,13 +99,7 @@
</child>
</object>
</child>
+ </object>
+ </child>
</template>
- <object class="GtkSizeGroup" id="sizegroup_update_details">
- <property name="ignore-hidden">False</property>
- <property name="mode">horizontal</property>
- <widgets>
- <widget name="scrolledwindow"/>
- <widget name="scrolledwindow_details"/>
- </widgets>
- </object>
</interface>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]