Blame SOURCES/0004-info-Better-support-registered-but-no-subscriptions-.patch

8230d6
From 26bae6e6d9a7968bbc2e189bf72c8d1588135dfa Mon Sep 17 00:00:00 2001
8230d6
From: Ray Strode <rstrode@redhat.com>
8230d6
Date: Sun, 24 Jan 2021 13:59:17 -0500
8230d6
Subject: [PATCH 4/4] info: Better support registered-but-no-subscriptions
8230d6
 cases
8230d6
8230d6
There are cases when the machine can be registered for updates,
8230d6
but not have any active subscriptions. For instance, if the
8230d6
admin runs "subscription-manager register" but fails to pass
8230d6
--auto-attach. As another case, the org may be configured to
8230d6
be in "Simple Content Access" mode where updates don't require
8230d6
specific production subscriptions.
8230d6
8230d6
This commit tries to accomodate those cases better.  If the user
8230d6
is registered, but needs a subscription, the dialog provides a
8230d6
way to attach one.
8230d6
8230d6
If the user is registered and doesn't need a subscription, the
8230d6
dialog now shows an updated message to reflect that fact.
8230d6
---
8230d6
 panels/info/cc-info-overview-panel.c          |  25 +-
8230d6
 panels/info/cc-subscription-details-dialog.c  | 180 ++++++++++++-
8230d6
 panels/info/cc-subscription-details-dialog.ui | 249 +++++++++++++++---
8230d6
 panels/info/info-overview.ui                  |  35 ++-
8230d6
 4 files changed, 431 insertions(+), 58 deletions(-)
8230d6
8230d6
diff --git a/panels/info/cc-info-overview-panel.c b/panels/info/cc-info-overview-panel.c
8230d6
index 65246758e..571654fa0 100644
8230d6
--- a/panels/info/cc-info-overview-panel.c
8230d6
+++ b/panels/info/cc-info-overview-panel.c
8230d6
@@ -49,60 +49,61 @@
8230d6
 #include <gdk/gdkx.h>
8230d6
 #endif
8230d6
 
8230d6
 #include "gsd-disk-space-helper.h"
8230d6
 
8230d6
 #include "cc-info-overview-panel.h"
8230d6
 
8230d6
 
8230d6
 typedef struct {
8230d6
   /* Will be one or 2 GPU name strings, or "Unknown" */
8230d6
   char *hardware_string;
8230d6
 } GraphicsData;
8230d6
 
8230d6
 typedef struct
8230d6
 {
8230d6
   GtkWidget      *system_image;
8230d6
   GtkWidget      *version_label;
8230d6
   GtkWidget      *name_entry;
8230d6
   GtkWidget      *memory_label;
8230d6
   GtkWidget      *processor_label;
8230d6
   GtkWidget      *os_name_label;
8230d6
   GtkWidget      *os_type_label;
8230d6
   GtkWidget      *disk_label;
8230d6
   GtkWidget      *graphics_label;
8230d6
   GtkWidget      *virt_type_label;
8230d6
   GtkWidget      *subscription_stack;
8230d6
   GtkWidget      *details_button;
8230d6
   GtkWidget      *register_button;
8230d6
   GtkWidget      *updates_separator;
8230d6
   GtkWidget      *updates_button;
8230d6
+  GtkWidget      *updates_stack;
8230d6
 
8230d6
   /* Virtualisation labels */
8230d6
   GtkWidget      *label8;
8230d6
   GtkWidget      *grid1;
8230d6
   GtkWidget      *label18;
8230d6
 
8230d6
   char           *gnome_version;
8230d6
   char           *gnome_distributor;
8230d6
   char           *gnome_date;
8230d6
 
8230d6
   GCancellable   *cancellable;
8230d6
   GCancellable   *subscription_cancellable;
8230d6
 
8230d6
   /* Free space */
8230d6
   GList          *primary_mounts;
8230d6
   guint64         total_bytes;
8230d6
 
8230d6
   GraphicsData   *graphics_data;
8230d6
 
8230d6
   GDBusProxy     *subscription_proxy;
8230d6
 } CcInfoOverviewPanelPrivate;
8230d6
 
8230d6
 struct _CcInfoOverviewPanel
8230d6
 {
8230d6
  CcPanel parent_instance;
8230d6
 
8230d6
   /*< private >*/
8230d6
  CcInfoOverviewPanelPrivate *priv;
8230d6
 };
8230d6
 
8230d6
@@ -796,72 +797,85 @@ info_overview_panel_setup_overview (CcInfoOverviewPanel *self)
8230d6
 
8230d6
   os_name_text = get_os_name ();
8230d6
   gtk_label_set_text (GTK_LABEL (priv->os_name_label), os_name_text ? os_name_text : "");
8230d6
 
8230d6
   get_primary_disc_info (self);
8230d6
 
8230d6
   gtk_label_set_markup (GTK_LABEL (priv->graphics_label), priv->graphics_data->hardware_string);
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
 reload_subscription_status (CcInfoOverviewPanel *self)
8230d6
 {
8230d6
   CcInfoOverviewPanelPrivate *priv = cc_info_overview_panel_get_instance_private (self);
8230d6
   GsdSubmanSubscriptionStatus status;
8230d6
 
8230d6
   if (priv->subscription_proxy == NULL)
8230d6
     {
8230d6
       gtk_widget_hide (priv->subscription_stack);
8230d6
       return;
8230d6
     }
8230d6
 
8230d6
   if (!get_subscription_status (priv->subscription_proxy, &status))
8230d6
     {
8230d6
       gtk_widget_hide (priv->subscription_stack);
8230d6
       return;
8230d6
     }
8230d6
 
8230d6
   switch (status)
8230d6
     {
8230d6
     case GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN:
8230d6
-    case GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID:
8230d6
-    case GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED:
8230d6
-    case GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID:
8230d6
       gtk_stack_set_visible_child_name (GTK_STACK (priv->subscription_stack), "not-registered");
8230d6
+      gtk_stack_set_visible_child_name (GTK_STACK (priv->updates_stack), "no-updates");
8230d6
       gtk_widget_set_sensitive (priv->updates_button, FALSE);
8230d6
       break;
8230d6
-
8230d6
+    case GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED:
8230d6
+      gtk_stack_set_visible_child_name (GTK_STACK (priv->subscription_stack), "registered");
8230d6
+      gtk_stack_set_visible_child_name (GTK_STACK (priv->updates_stack), "updates");
8230d6
+      gtk_widget_set_sensitive (priv->updates_button, TRUE);
8230d6
+      break;
8230d6
     case GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID:
8230d6
+    case GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID:
8230d6
       gtk_stack_set_visible_child_name (GTK_STACK (priv->subscription_stack), "registered");
8230d6
+      gtk_stack_set_visible_child_name (GTK_STACK (priv->updates_stack), "updates");
8230d6
       gtk_widget_set_sensitive (priv->updates_button, TRUE);
8230d6
       break;
8230d6
-
8230d6
+    case GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID:
8230d6
+      gtk_stack_set_visible_child_name (GTK_STACK (priv->subscription_stack), "registered");
8230d6
+      gtk_stack_set_visible_child_name (GTK_STACK (priv->updates_stack), "no-updates");
8230d6
+      gtk_widget_set_sensitive (priv->updates_button, FALSE);
8230d6
+      break;
8230d6
+    case GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS:
8230d6
+      gtk_stack_set_visible_child_name (GTK_STACK (priv->subscription_stack), "not-registered");
8230d6
+      gtk_stack_set_visible_child_name (GTK_STACK (priv->updates_stack), "no-updates");
8230d6
+      gtk_widget_set_sensitive (priv->updates_button, FALSE);
8230d6
+      break;
8230d6
     default:
8230d6
       g_assert_not_reached ();
8230d6
       break;
8230d6
     }
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
 on_details_button_clicked (GtkWidget           *widget,
8230d6
                            CcInfoOverviewPanel *self)
8230d6
 {
8230d6
   CcInfoOverviewPanelPrivate *priv = cc_info_overview_panel_get_instance_private (self);
8230d6
   CcSubscriptionDetailsDialog *dialog;
8230d6
   GtkWindow *toplevel;
8230d6
 
8230d6
   dialog = cc_subscription_details_dialog_new (priv->subscription_proxy,
8230d6
                                                priv->subscription_cancellable);
8230d6
   toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self)));
8230d6
   gtk_window_set_transient_for (GTK_WINDOW (dialog), toplevel);
8230d6
 
8230d6
   gtk_dialog_run (GTK_DIALOG (dialog));
8230d6
   gtk_widget_destroy (GTK_WIDGET (dialog));
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
 on_register_button_clicked (GtkWidget           *widget,
8230d6
                             CcInfoOverviewPanel *self)
8230d6
 {
8230d6
   CcInfoOverviewPanelPrivate *priv = cc_info_overview_panel_get_instance_private (self);
8230d6
   CcSubscriptionRegisterDialog *dialog;
8230d6
   GtkWindow *toplevel;
8230d6
@@ -994,60 +1008,61 @@ cc_info_overview_panel_finalize (GObject *object)
8230d6
 
8230d6
   G_OBJECT_CLASS (cc_info_overview_panel_parent_class)->finalize (object);
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
 cc_info_overview_panel_class_init (CcInfoOverviewPanelClass *klass)
8230d6
 {
8230d6
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
8230d6
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
8230d6
 
8230d6
   object_class->finalize = cc_info_overview_panel_finalize;
8230d6
   object_class->dispose = cc_info_overview_panel_dispose;
8230d6
 
8230d6
   gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/info/info-overview.ui");
8230d6
 
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, system_image);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, version_label);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, name_entry);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, memory_label);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, processor_label);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, os_name_label);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, os_type_label);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, disk_label);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, graphics_label);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, virt_type_label);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, subscription_stack);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, details_button);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, register_button);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, updates_separator);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, updates_button);
8230d6
+  gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, updates_stack);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, label8);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, grid1);
8230d6
   gtk_widget_class_bind_template_child_private (widget_class, CcInfoOverviewPanel, label18);
8230d6
 
8230d6
   g_type_ensure (CC_TYPE_HOSTNAME_ENTRY);
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
 cc_info_overview_panel_init (CcInfoOverviewPanel *self)
8230d6
 {
8230d6
   CcInfoOverviewPanelPrivate *priv = cc_info_overview_panel_get_instance_private (self);
8230d6
 
8230d6
   gtk_widget_init_template (GTK_WIDGET (self));
8230d6
 
8230d6
   g_resources_register (cc_info_get_resource ());
8230d6
 
8230d6
   priv->cancellable = g_cancellable_new ();
8230d6
   priv->subscription_cancellable = g_cancellable_new ();
8230d6
 
8230d6
   priv->graphics_data = get_graphics_data ();
8230d6
 
8230d6
   if (does_gnome_software_exist () || does_gpk_update_viewer_exist ())
8230d6
     g_signal_connect (priv->updates_button, "clicked", G_CALLBACK (on_updates_button_clicked), self);
8230d6
   else
8230d6
     gtk_widget_hide (priv->updates_button);
8230d6
 
8230d6
   info_overview_panel_setup_overview (self);
8230d6
   info_overview_panel_setup_virt (self);
8230d6
   info_overview_panel_setup_subscriptions (self);
8230d6
 
8230d6
diff --git a/panels/info/cc-subscription-details-dialog.c b/panels/info/cc-subscription-details-dialog.c
8230d6
index 3d77e6c48..f8e70d751 100644
8230d6
--- a/panels/info/cc-subscription-details-dialog.c
8230d6
+++ b/panels/info/cc-subscription-details-dialog.c
8230d6
@@ -1,420 +1,578 @@
8230d6
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
8230d6
  *
8230d6
  * Copyright 2019  Red Hat, Inc,
8230d6
  *
8230d6
  * This program is free software; you can redistribute it and/or modify
8230d6
  * it under the terms of the GNU General Public License as published by
8230d6
  * the Free Software Foundation; either version 2 of the License, or
8230d6
  * (at your option) any later version.
8230d6
  *
8230d6
  * This program is distributed in the hope that it will be useful,
8230d6
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8230d6
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8230d6
  * GNU General Public License for more details.
8230d6
  *
8230d6
  * You should have received a copy of the GNU General Public License
8230d6
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
8230d6
  *
8230d6
  * Written by: Kalev Lember <klember@redhat.com>
8230d6
  */
8230d6
 
8230d6
 #include "config.h"
8230d6
 
8230d6
 #include <glib.h>
8230d6
 #include <glib/gi18n.h>
8230d6
 #include <gtk/gtk.h>
8230d6
 
8230d6
 #include "cc-subscription-details-dialog.h"
8230d6
+#include "cc-subscription-common.h"
8230d6
 
8230d6
 #define DBUS_TIMEOUT 300000 /* 5 minutes */
8230d6
 
8230d6
 typedef enum {
8230d6
   DIALOG_STATE_SHOW_DETAILS,
8230d6
+  DIALOG_STATE_SUBSCRIBE,
8230d6
+  DIALOG_STATE_SUBSCRIBING,
8230d6
   DIALOG_STATE_UNREGISTER,
8230d6
   DIALOG_STATE_UNREGISTERING
8230d6
 } DialogState;
8230d6
 
8230d6
 struct _CcSubscriptionDetailsDialog
8230d6
 {
8230d6
   GtkDialog     parent_instance;
8230d6
 
8230d6
   DialogState   state;
8230d6
   GCancellable *cancellable;
8230d6
   GDBusProxy   *subscription_proxy;
8230d6
   GPtrArray    *products;
8230d6
 
8230d6
   /* template widgets */
8230d6
   GtkButton    *back_button;
8230d6
   GtkSpinner   *spinner;
8230d6
+  GtkStack     *header_stack;
8230d6
+  GtkButton    *header_subscribe_button;
8230d6
   GtkButton    *header_unregister_button;
8230d6
   GtkRevealer  *notification_revealer;
8230d6
   GtkLabel     *error_label;
8230d6
   GtkStack     *stack;
8230d6
+  GtkStack     *status_stack;
8230d6
   GtkBox       *products_box1;
8230d6
   GtkBox       *products_box2;
8230d6
+  GtkBox       *products_box3;
8230d6
+  GtkButton    *subscribe_button;
8230d6
+  GtkSeparator *separator;
8230d6
   GtkButton    *unregister_button;
8230d6
 };
8230d6
 
8230d6
 G_DEFINE_TYPE (CcSubscriptionDetailsDialog, cc_subscription_details_dialog, GTK_TYPE_DIALOG);
8230d6
 
8230d6
+static void reload_installed_products (CcSubscriptionDetailsDialog *self);
8230d6
+
8230d6
 typedef struct
8230d6
 {
8230d6
   gchar *product_name;
8230d6
   gchar *product_id;
8230d6
   gchar *version;
8230d6
   gchar *arch;
8230d6
   gchar *status;
8230d6
   gchar *starts;
8230d6
   gchar *ends;
8230d6
 } ProductData;
8230d6
 
8230d6
 static void
8230d6
 product_data_free (ProductData *product)
8230d6
 {
8230d6
   g_free (product->product_name);
8230d6
   g_free (product->product_id);
8230d6
   g_free (product->version);
8230d6
   g_free (product->arch);
8230d6
   g_free (product->status);
8230d6
   g_free (product->starts);
8230d6
   g_free (product->ends);
8230d6
   g_free (product);
8230d6
 }
8230d6
 
8230d6
 G_DEFINE_AUTOPTR_CLEANUP_FUNC (ProductData, product_data_free);
8230d6
 
8230d6
 static void
8230d6
 add_product_row (GtkGrid *product_grid, const gchar *name, const gchar *value, gint top_attach)
8230d6
 {
8230d6
   GtkWidget *w;
8230d6
 
8230d6
   w = gtk_label_new (name);
8230d6
   gtk_style_context_add_class (gtk_widget_get_style_context (w), "dim-label");
8230d6
   gtk_grid_attach (product_grid, w, 0, top_attach, 1, 1);
8230d6
   gtk_widget_set_halign (w, GTK_ALIGN_END);
8230d6
   gtk_widget_show (w);
8230d6
 
8230d6
   if (value == NULL)
8230d6
     value = _("Unknown");
8230d6
 
8230d6
   w = gtk_label_new (value);
8230d6
   gtk_grid_attach (product_grid, w, 1, top_attach, 1, 1);
8230d6
   gtk_widget_set_halign (w, GTK_ALIGN_START);
8230d6
   gtk_widget_set_hexpand (w, TRUE);
8230d6
   gtk_widget_show (w);
8230d6
 }
8230d6
 
8230d6
 static GtkWidget *
8230d6
-add_product (CcSubscriptionDetailsDialog *self, ProductData *product)
8230d6
+add_product (CcSubscriptionDetailsDialog *self, ProductData *product, GsdSubmanSubscriptionStatus status)
8230d6
 {
8230d6
   GtkGrid *product_grid;
8230d6
   const gchar *status_text;
8230d6
 
8230d6
   if (g_strcmp0 (product->status, "subscribed") == 0)
8230d6
     status_text = _("Subscribed");
8230d6
+  else if (status == GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED)
8230d6
+    status_text = _("No Specific Subscription");
8230d6
   else
8230d6
-    status_text = _("Not Subscribed (Not supported by a valid subscription.)");
8230d6
+    status_text = _("Not Subscribed");
8230d6
 
8230d6
   product_grid = GTK_GRID (gtk_grid_new ());
8230d6
   gtk_grid_set_column_spacing (product_grid, 12);
8230d6
   gtk_grid_set_row_spacing (product_grid, 6);
8230d6
   gtk_widget_set_margin_top (GTK_WIDGET (product_grid), 18);
8230d6
   gtk_widget_set_margin_bottom (GTK_WIDGET (product_grid), 12);
8230d6
   gtk_widget_show (GTK_WIDGET (product_grid));
8230d6
 
8230d6
   add_product_row (product_grid, _("Product Name"), product->product_name, 0);
8230d6
   add_product_row (product_grid, _("Product ID"), product->product_id, 1);
8230d6
   add_product_row (product_grid, _("Version"), product->version, 2);
8230d6
   add_product_row (product_grid, _("Arch"), product->arch, 3);
8230d6
   add_product_row (product_grid, _("Status"), status_text, 4);
8230d6
-  add_product_row (product_grid, _("Starts"), product->starts, 5);
8230d6
-  add_product_row (product_grid, _("Ends"), product->ends, 6);
8230d6
+
8230d6
+  if (product->starts[0] != '\0' && product->ends[0] != '\0')
8230d6
+    {
8230d6
+      add_product_row (product_grid, _("Starts"), product->starts, 5);
8230d6
+      add_product_row (product_grid, _("Ends"), product->ends, 6);
8230d6
+    }
8230d6
 
8230d6
   return GTK_WIDGET (product_grid);
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
 remove_all_children (GtkContainer *container)
8230d6
 {
8230d6
   g_autoptr(GList) list = gtk_container_get_children (container);
8230d6
 
8230d6
   for (GList *l = list; l != NULL; l = l->next)
8230d6
     gtk_container_remove (container, (GtkWidget *) l->data);
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
 dialog_reload (CcSubscriptionDetailsDialog *self)
8230d6
 {
8230d6
   GtkHeaderBar *header = GTK_HEADER_BAR (gtk_dialog_get_header_bar (GTK_DIALOG (self)));
8230d6
+  GsdSubmanSubscriptionStatus status = GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN;
8230d6
+
8230d6
+  reload_installed_products (self);
8230d6
 
8230d6
   switch (self->state)
8230d6
     {
8230d6
     case DIALOG_STATE_SHOW_DETAILS:
8230d6
       gtk_header_bar_set_show_close_button (header, TRUE);
8230d6
 
8230d6
       gtk_window_set_title (GTK_WINDOW (self), _("Registration Details"));
8230d6
       gtk_widget_set_sensitive (GTK_WIDGET (self->header_unregister_button), TRUE);
8230d6
+      gtk_widget_set_sensitive (GTK_WIDGET (self->header_subscribe_button), TRUE);
8230d6
 
8230d6
       gtk_widget_hide (GTK_WIDGET (self->back_button));
8230d6
-      gtk_widget_hide (GTK_WIDGET (self->header_unregister_button));
8230d6
+      gtk_widget_hide (GTK_WIDGET (self->header_stack));
8230d6
 
8230d6
       gtk_stack_set_visible_child_name (self->stack, "show-details");
8230d6
       break;
8230d6
 
8230d6
+    case DIALOG_STATE_SUBSCRIBE:
8230d6
+      gtk_header_bar_set_show_close_button (header, FALSE);
8230d6
+      gtk_stack_set_visible_child_name (self->header_stack, "subscribe");
8230d6
+      gtk_window_set_title (GTK_WINDOW (self), _("Subscribe System"));
8230d6
+      gtk_widget_set_sensitive (GTK_WIDGET (self->header_subscribe_button), TRUE);
8230d6
+
8230d6
+      gtk_widget_show (GTK_WIDGET (self->back_button));
8230d6
+
8230d6
+      gtk_stack_set_visible_child_name (self->header_stack, "subscribe");
8230d6
+      gtk_widget_show (GTK_WIDGET (self->header_stack));
8230d6
+
8230d6
+      gtk_stack_set_visible_child_name (self->stack, "subscribe");
8230d6
+      break;
8230d6
+
8230d6
+    case DIALOG_STATE_SUBSCRIBING:
8230d6
+      gtk_header_bar_set_show_close_button (header, FALSE);
8230d6
+      gtk_window_set_title (GTK_WINDOW (self), _("Looking For Available Subscriptions…"));
8230d6
+      gtk_widget_set_sensitive (GTK_WIDGET (self->header_subscribe_button), FALSE);
8230d6
+
8230d6
+      gtk_widget_show (GTK_WIDGET (self->back_button));
8230d6
+
8230d6
+      gtk_stack_set_visible_child_name (self->header_stack, "subscribe");
8230d6
+      gtk_widget_show (GTK_WIDGET (self->header_stack));
8230d6
+
8230d6
+      gtk_stack_set_visible_child_name (self->stack, "subscribe");
8230d6
+      break;
8230d6
+
8230d6
     case DIALOG_STATE_UNREGISTER:
8230d6
       gtk_header_bar_set_show_close_button (header, FALSE);
8230d6
 
8230d6
       gtk_window_set_title (GTK_WINDOW (self), _("Unregister System"));
8230d6
       gtk_widget_set_sensitive (GTK_WIDGET (self->header_unregister_button), TRUE);
8230d6
 
8230d6
       gtk_widget_show (GTK_WIDGET (self->back_button));
8230d6
-      gtk_widget_show (GTK_WIDGET (self->header_unregister_button));
8230d6
+
8230d6
+      gtk_stack_set_visible_child_name (self->header_stack, "unregister");
8230d6
+      gtk_widget_show (GTK_WIDGET (self->header_stack));
8230d6
 
8230d6
       gtk_stack_set_visible_child_name (self->stack, "unregister");
8230d6
       break;
8230d6
 
8230d6
     case DIALOG_STATE_UNREGISTERING:
8230d6
       gtk_header_bar_set_show_close_button (header, FALSE);
8230d6
 
8230d6
       gtk_window_set_title (GTK_WINDOW (self), _("Unregistering System…"));
8230d6
       gtk_widget_set_sensitive (GTK_WIDGET (self->header_unregister_button), FALSE);
8230d6
 
8230d6
       gtk_widget_show (GTK_WIDGET (self->back_button));
8230d6
-      gtk_widget_show (GTK_WIDGET (self->header_unregister_button));
8230d6
+
8230d6
+      gtk_stack_set_visible_child_name (self->header_stack, "unregister");
8230d6
+      gtk_widget_show (GTK_WIDGET (self->header_stack));
8230d6
 
8230d6
       gtk_stack_set_visible_child_name (self->stack, "unregister");
8230d6
       break;
8230d6
 
8230d6
     default:
8230d6
       g_assert_not_reached ();
8230d6
       break;
8230d6
     }
8230d6
 
8230d6
   remove_all_children (GTK_CONTAINER (self->products_box1));
8230d6
   remove_all_children (GTK_CONTAINER (self->products_box2));
8230d6
+  remove_all_children (GTK_CONTAINER (self->products_box3));
8230d6
 
8230d6
   if (self->products == NULL || self->products->len == 0)
8230d6
     {
8230d6
       /* the widgets are duplicate to allow sliding between two stack pages */
8230d6
       GtkWidget *w1 = gtk_label_new (_("No installed products detected."));
8230d6
       GtkWidget *w2 = gtk_label_new (_("No installed products detected."));
8230d6
+      GtkWidget *w3 = gtk_label_new (_("No installed products detected."));
8230d6
       gtk_widget_show (w1);
8230d6
       gtk_widget_show (w2);
8230d6
+      gtk_widget_show (w3);
8230d6
       gtk_container_add (GTK_CONTAINER (self->products_box1), w1);
8230d6
       gtk_container_add (GTK_CONTAINER (self->products_box2), w2);
8230d6
+      gtk_container_add (GTK_CONTAINER (self->products_box3), w3);
8230d6
+      gtk_stack_set_visible_child_name (self->status_stack, "no-installed-products");
8230d6
+
8230d6
+      gtk_widget_hide (GTK_WIDGET (self->subscribe_button));
8230d6
+      gtk_widget_hide (GTK_WIDGET (self->separator));
8230d6
       return;
8230d6
     }
8230d6
 
8230d6
+  get_subscription_status (self->subscription_proxy, &status);
8230d6
+
8230d6
   for (guint i = 0; i < self->products->len; i++)
8230d6
     {
8230d6
       ProductData *product = g_ptr_array_index (self->products, i);
8230d6
       /* the widgets are duplicate to allow sliding between two stack pages */
8230d6
-      GtkWidget *w1 = add_product (self, product);
8230d6
-      GtkWidget *w2 = add_product (self, product);
8230d6
+      GtkWidget *w1 = add_product (self, product, status);
8230d6
+      GtkWidget *w2 = add_product (self, product, status);
8230d6
+      GtkWidget *w3 = add_product (self, product, status);
8230d6
       gtk_container_add (GTK_CONTAINER (self->products_box1), w1);
8230d6
       gtk_container_add (GTK_CONTAINER (self->products_box2), w2);
8230d6
+      gtk_container_add (GTK_CONTAINER (self->products_box3), w3);
8230d6
     }
8230d6
+
8230d6
+  switch (status)
8230d6
+    {
8230d6
+    case GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID:
8230d6
+      gtk_stack_set_visible_child_name (self->status_stack, "fully-subscribed");
8230d6
+      gtk_widget_hide (GTK_WIDGET (self->subscribe_button));
8230d6
+      break;
8230d6
+
8230d6
+    case GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID:
8230d6
+      gtk_stack_set_visible_child_name (self->status_stack, "partly-subscribed");
8230d6
+      gtk_widget_show (GTK_WIDGET (self->subscribe_button));
8230d6
+      break;
8230d6
+
8230d6
+    case GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED:
8230d6
+      gtk_stack_set_visible_child_name (self->status_stack, "subscription-not-needed");
8230d6
+      gtk_widget_hide (GTK_WIDGET (self->subscribe_button));
8230d6
+      break;
8230d6
+
8230d6
+    case GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN:
8230d6
+    default:
8230d6
+      gtk_stack_set_visible_child_name (self->status_stack, "not-subscribed");
8230d6
+      gtk_widget_show (GTK_WIDGET (self->subscribe_button));
8230d6
+      break;
8230d6
+    }
8230d6
+
8230d6
+  gtk_widget_set_visible (GTK_WIDGET (self->separator),
8230d6
+                          gtk_widget_get_visible (GTK_WIDGET (self->subscribe_button)));
8230d6
+
8230d6
 }
8230d6
 
8230d6
 static ProductData *
8230d6
 parse_product_variant (GVariant *product_variant)
8230d6
 {
8230d6
   g_autoptr(ProductData) product = g_new0 (ProductData, 1);
8230d6
   g_auto(GVariantDict) dict;
8230d6
 
8230d6
   g_variant_dict_init (&dict, product_variant);
8230d6
 
8230d6
   g_variant_dict_lookup (&dict, "product-name", "s", &product->product_name);
8230d6
   g_variant_dict_lookup (&dict, "product-id", "s", &product->product_id);
8230d6
   g_variant_dict_lookup (&dict, "version", "s", &product->version);
8230d6
   g_variant_dict_lookup (&dict, "arch", "s", &product->arch);
8230d6
   g_variant_dict_lookup (&dict, "status", "s", &product->status);
8230d6
   g_variant_dict_lookup (&dict, "starts", "s", &product->starts);
8230d6
   g_variant_dict_lookup (&dict, "ends", "s", &product->ends);
8230d6
 
8230d6
   return g_steal_pointer (&product);
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
-load_installed_products (CcSubscriptionDetailsDialog *self)
8230d6
+reload_installed_products (CcSubscriptionDetailsDialog *self)
8230d6
 {
8230d6
   GVariantIter iter_array;
8230d6
   GVariant *child;
8230d6
   g_autoptr(GError) error = NULL;
8230d6
   g_autoptr(GVariant) installed_products_variant = NULL;
8230d6
 
8230d6
   installed_products_variant = g_dbus_proxy_get_cached_property (self->subscription_proxy, "InstalledProducts");
8230d6
   if (installed_products_variant == NULL)
8230d6
     {
8230d6
       g_debug ("Unable to get InstalledProducts dbus property");
8230d6
       return;
8230d6
     }
8230d6
 
8230d6
   g_ptr_array_set_size (self->products, 0);
8230d6
 
8230d6
   g_variant_iter_init (&iter_array, installed_products_variant);
8230d6
   while ((child = g_variant_iter_next_value (&iter_array)) != NULL)
8230d6
     {
8230d6
       g_autoptr(GVariant) product_variant = g_steal_pointer (&child);
8230d6
       g_ptr_array_add (self->products, parse_product_variant (product_variant));
8230d6
     }
8230d6
 }
8230d6
 
8230d6
+static void
8230d6
+subscription_done_cb (GObject      *source_object,
8230d6
+                      GAsyncResult *res,
8230d6
+                      gpointer      user_data)
8230d6
+{
8230d6
+  CcSubscriptionDetailsDialog *self = (CcSubscriptionDetailsDialog *) user_data;
8230d6
+  g_autoptr(GVariant) results = NULL;
8230d6
+  g_autoptr(GError) error = NULL;
8230d6
+
8230d6
+  results = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
8230d6
+                                      res,
8230d6
+                                      &error);
8230d6
+  if (results == NULL)
8230d6
+    {
8230d6
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
8230d6
+        return;
8230d6
+
8230d6
+      g_dbus_error_strip_remote_error (error);
8230d6
+      gtk_label_set_text (self->error_label, error->message);
8230d6
+      gtk_revealer_set_reveal_child (self->notification_revealer, TRUE);
8230d6
+
8230d6
+      gtk_spinner_stop (self->spinner);
8230d6
+
8230d6
+      self->state = DIALOG_STATE_SUBSCRIBE;
8230d6
+      dialog_reload (self);
8230d6
+      return;
8230d6
+    }
8230d6
+
8230d6
+  gtk_spinner_stop (self->spinner);
8230d6
+
8230d6
+  self->state = DIALOG_STATE_SHOW_DETAILS;
8230d6
+  dialog_reload (self);
8230d6
+}
8230d6
+
8230d6
+static void
8230d6
+header_subscribe_button_clicked_cb (CcSubscriptionDetailsDialog *self)
8230d6
+{
8230d6
+  gtk_spinner_start (self->spinner);
8230d6
+
8230d6
+  self->state = DIALOG_STATE_SUBSCRIBING;
8230d6
+  dialog_reload (self);
8230d6
+
8230d6
+  g_dbus_proxy_call (self->subscription_proxy,
8230d6
+                     "Attach",
8230d6
+                     NULL,
8230d6
+                     G_DBUS_CALL_FLAGS_NONE,
8230d6
+                     DBUS_TIMEOUT,
8230d6
+                     self->cancellable,
8230d6
+                     subscription_done_cb,
8230d6
+                     self);
8230d6
+}
8230d6
+
8230d6
 static void
8230d6
 unregistration_done_cb (GObject      *source_object,
8230d6
                         GAsyncResult *res,
8230d6
                         gpointer      user_data)
8230d6
 {
8230d6
   CcSubscriptionDetailsDialog *self = (CcSubscriptionDetailsDialog *) user_data;
8230d6
   g_autoptr(GVariant) results = NULL;
8230d6
   g_autoptr(GError) error = NULL;
8230d6
 
8230d6
   results = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
8230d6
                                       res,
8230d6
                                       &error);
8230d6
   if (results == NULL)
8230d6
     {
8230d6
       if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
8230d6
         return;
8230d6
 
8230d6
       g_dbus_error_strip_remote_error (error);
8230d6
       gtk_label_set_text (self->error_label, error->message);
8230d6
       gtk_revealer_set_reveal_child (self->notification_revealer, TRUE);
8230d6
 
8230d6
       gtk_spinner_stop (self->spinner);
8230d6
 
8230d6
       self->state = DIALOG_STATE_UNREGISTER;
8230d6
       dialog_reload (self);
8230d6
       return;
8230d6
     }
8230d6
 
8230d6
   gtk_spinner_stop (self->spinner);
8230d6
 
8230d6
   gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_ACCEPT);
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
 header_unregister_button_clicked_cb (CcSubscriptionDetailsDialog *self)
8230d6
 {
8230d6
   gtk_spinner_start (self->spinner);
8230d6
 
8230d6
   self->state = DIALOG_STATE_UNREGISTERING;
8230d6
   dialog_reload (self);
8230d6
 
8230d6
   g_dbus_proxy_call (self->subscription_proxy,
8230d6
                      "Unregister",
8230d6
                      NULL,
8230d6
                      G_DBUS_CALL_FLAGS_NONE,
8230d6
                      DBUS_TIMEOUT,
8230d6
                      self->cancellable,
8230d6
                      unregistration_done_cb,
8230d6
                      self);
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
 back_button_clicked_cb (CcSubscriptionDetailsDialog *self)
8230d6
 {
8230d6
   gtk_spinner_stop (self->spinner);
8230d6
 
8230d6
   self->state = DIALOG_STATE_SHOW_DETAILS;
8230d6
   dialog_reload (self);
8230d6
 }
8230d6
 
8230d6
+static void
8230d6
+subscribe_button_clicked_cb (CcSubscriptionDetailsDialog *self)
8230d6
+{
8230d6
+  self->state = DIALOG_STATE_SUBSCRIBE;
8230d6
+  dialog_reload (self);
8230d6
+}
8230d6
+
8230d6
 static void
8230d6
 unregister_button_clicked_cb (CcSubscriptionDetailsDialog *self)
8230d6
 {
8230d6
   self->state = DIALOG_STATE_UNREGISTER;
8230d6
   dialog_reload (self);
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
 dismiss_notification (CcSubscriptionDetailsDialog *self)
8230d6
 {
8230d6
   gtk_revealer_set_reveal_child (self->notification_revealer, FALSE);
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
 cc_subscription_details_dialog_init (CcSubscriptionDetailsDialog *self)
8230d6
 {
8230d6
   gtk_widget_init_template (GTK_WIDGET (self));
8230d6
 
8230d6
   self->products = g_ptr_array_new_with_free_func ((GDestroyNotify) product_data_free);
8230d6
   self->state = DIALOG_STATE_SHOW_DETAILS;
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
 cc_subscription_details_dialog_dispose (GObject *obj)
8230d6
 {
8230d6
   CcSubscriptionDetailsDialog *self = (CcSubscriptionDetailsDialog *) obj;
8230d6
 
8230d6
   g_cancellable_cancel (self->cancellable);
8230d6
   g_clear_object (&self->cancellable);
8230d6
   g_clear_object (&self->subscription_proxy);
8230d6
 
8230d6
   G_OBJECT_CLASS (cc_subscription_details_dialog_parent_class)->dispose (obj);
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
 cc_subscription_details_dialog_finalize (GObject *obj)
8230d6
 {
8230d6
   CcSubscriptionDetailsDialog *self = (CcSubscriptionDetailsDialog *) obj;
8230d6
 
8230d6
   g_clear_pointer (&self->products, g_ptr_array_unref);
8230d6
 
8230d6
   G_OBJECT_CLASS (cc_subscription_details_dialog_parent_class)->finalize (obj);
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
 cc_subscription_details_dialog_class_init (CcSubscriptionDetailsDialogClass *klass)
8230d6
 {
8230d6
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
8230d6
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
8230d6
 
8230d6
   object_class->dispose = cc_subscription_details_dialog_dispose;
8230d6
   object_class->finalize = cc_subscription_details_dialog_finalize;
8230d6
 
8230d6
   gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/info/cc-subscription-details-dialog.ui");
8230d6
 
8230d6
   gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, back_button);
8230d6
   gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, spinner);
8230d6
+  gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, header_stack);
8230d6
+  gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, header_subscribe_button);
8230d6
   gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, header_unregister_button);
8230d6
   gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, notification_revealer);
8230d6
   gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, error_label);
8230d6
   gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, stack);
8230d6
+  gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, status_stack);
8230d6
   gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, products_box1);
8230d6
   gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, products_box2);
8230d6
+  gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, products_box3);
8230d6
+  gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, subscribe_button);
8230d6
+  gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, separator);
8230d6
   gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, unregister_button);
8230d6
 
8230d6
   gtk_widget_class_bind_template_callback (widget_class, back_button_clicked_cb);
8230d6
+  gtk_widget_class_bind_template_callback (widget_class, header_subscribe_button_clicked_cb);
8230d6
   gtk_widget_class_bind_template_callback (widget_class, header_unregister_button_clicked_cb);
8230d6
+  gtk_widget_class_bind_template_callback (widget_class, subscribe_button_clicked_cb);
8230d6
   gtk_widget_class_bind_template_callback (widget_class, unregister_button_clicked_cb);
8230d6
   gtk_widget_class_bind_template_callback (widget_class, dismiss_notification);
8230d6
 }
8230d6
 
8230d6
 static void
8230d6
 on_dialog_cancelled (CcSubscriptionDetailsDialog *self)
8230d6
 {
8230d6
   gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_CLOSE);
8230d6
 }
8230d6
 
8230d6
 CcSubscriptionDetailsDialog *
8230d6
 cc_subscription_details_dialog_new (GDBusProxy *subscription_proxy,
8230d6
                                     GCancellable *cancellable)
8230d6
 {
8230d6
   CcSubscriptionDetailsDialog *self;
8230d6
 
8230d6
   self = g_object_new (CC_TYPE_SUBSCRIPTION_DETAILS_DIALOG, "use-header-bar", TRUE, NULL);
8230d6
   self->subscription_proxy = g_object_ref (subscription_proxy);
8230d6
   self->cancellable = g_object_ref (cancellable);
8230d6
 
8230d6
   g_signal_connect_object (G_OBJECT (self->cancellable),
8230d6
                            "cancelled",
8230d6
                            G_CALLBACK (on_dialog_cancelled),
8230d6
                            self,
8230d6
                            G_CONNECT_SWAPPED);
8230d6
 
8230d6
-  load_installed_products (self);
8230d6
   dialog_reload (self);
8230d6
 
8230d6
   return self;
8230d6
 }
8230d6
diff --git a/panels/info/cc-subscription-details-dialog.ui b/panels/info/cc-subscription-details-dialog.ui
8230d6
index 6f0b16930..6cdfc1220 100644
8230d6
--- a/panels/info/cc-subscription-details-dialog.ui
8230d6
+++ b/panels/info/cc-subscription-details-dialog.ui
8230d6
@@ -6,75 +6,106 @@
8230d6
     <property name="modal">True</property>
8230d6
     <property name="destroy_with_parent">True</property>
8230d6
     <property name="type_hint">dialog</property>
8230d6
     <property name="title" translatable="yes">Registration Details</property>
8230d6
     <property name="use_header_bar">1</property>
8230d6
     <child internal-child="headerbar">
8230d6
       <object class="GtkHeaderBar">
8230d6
         <property name="visible">True</property>
8230d6
         <property name="can_focus">False</property>
8230d6
         <property name="show_close_button">False</property>
8230d6
         <child>
8230d6
           <object class="GtkButton" id="back_button">
8230d6
             <property name="visible">True</property>
8230d6
             <property name="can_focus">True</property>
8230d6
             <property name="receives_default">True</property>
8230d6
             <property name="valign">center</property>
8230d6
             <signal name="clicked" handler="back_button_clicked_cb" object="CcSubscriptionDetailsDialog" swapped="yes"/>
8230d6
             <child>
8230d6
               <object class="GtkImage">
8230d6
                 <property name="visible">True</property>
8230d6
                 <property name="can_focus">False</property>
8230d6
                 <property name="icon_name">go-previous-symbolic</property>
8230d6
               </object>
8230d6
             </child>
8230d6
             <style>
8230d6
               <class name="image-button"/>
8230d6
             </style>
8230d6
           </object>
8230d6
         </child>
8230d6
         <child>
8230d6
-          <object class="GtkButton" id="header_unregister_button">
8230d6
-            <property name="label" translatable="yes">_Unregister</property>
8230d6
+          <object class="GtkStack" id="header_stack">
8230d6
             <property name="visible">True</property>
8230d6
-            <property name="can_focus">True</property>
8230d6
-            <property name="can_default">True</property>
8230d6
-            <property name="has_default">True</property>
8230d6
-            <property name="receives_default">True</property>
8230d6
-            <property name="use_action_appearance">False</property>
8230d6
-            <property name="use_underline">True</property>
8230d6
-            <property name="valign">center</property>
8230d6
-            <signal name="clicked" handler="header_unregister_button_clicked_cb" object="CcSubscriptionDetailsDialog" swapped="yes"/>
8230d6
-            <style>
8230d6
-              <class name="text-button"/>
8230d6
-              <class name="destructive-action"/>
8230d6
-            </style>
8230d6
+            <property name="can_focus">False</property>
8230d6
+            <property name="transition-type">slide-left-right</property>
8230d6
+            <child>
8230d6
+              <object class="GtkButton" id="header_unregister_button">
8230d6
+                <property name="label" translatable="yes">_Unregister</property>
8230d6
+                <property name="visible">True</property>
8230d6
+                <property name="can_focus">True</property>
8230d6
+                <property name="can_default">True</property>
8230d6
+                <property name="has_default">True</property>
8230d6
+                <property name="receives_default">True</property>
8230d6
+                <property name="use_action_appearance">False</property>
8230d6
+                <property name="use_underline">True</property>
8230d6
+                <property name="valign">center</property>
8230d6
+                <signal name="clicked" handler="header_unregister_button_clicked_cb" object="CcSubscriptionDetailsDialog" swapped="yes"/>
8230d6
+                <style>
8230d6
+                  <class name="text-button"/>
8230d6
+                  <class name="destructive-action"/>
8230d6
+                </style>
8230d6
+              </object>
8230d6
+              <packing>
8230d6
+                <property name="name">unregister</property>
8230d6
+              </packing>
8230d6
+            </child>
8230d6
+            <child>
8230d6
+              <object class="GtkButton" id="header_subscribe_button">
8230d6
+                <property name="label" translatable="yes">_Subscribe</property>
8230d6
+                <property name="visible">True</property>
8230d6
+                <property name="can_focus">True</property>
8230d6
+                <property name="can_default">True</property>
8230d6
+                <property name="has_default">True</property>
8230d6
+                <property name="receives_default">True</property>
8230d6
+                <property name="use_action_appearance">False</property>
8230d6
+                <property name="use_underline">True</property>
8230d6
+                <property name="valign">center</property>
8230d6
+                <signal name="clicked" handler="header_subscribe_button_clicked_cb" object="CcSubscriptionDetailsDialog" swapped="yes"/>
8230d6
+                <style>
8230d6
+                  <class name="text-button"/>
8230d6
+                  <class name="suggested-action"/>
8230d6
+                </style>
8230d6
+              </object>
8230d6
+              <packing>
8230d6
+                <property name="name">subscribe</property>
8230d6
+              </packing>
8230d6
+            </child>
8230d6
           </object>
8230d6
           <packing>
8230d6
             <property name="pack_type">end</property>
8230d6
           </packing>
8230d6
         </child>
8230d6
         <child>
8230d6
           <object class="GtkSpinner" id="spinner">
8230d6
             <property name="visible">True</property>
8230d6
             <property name="can_focus">False</property>
8230d6
             <property name="valign">center</property>
8230d6
             <property name="margin_start">6</property>
8230d6
             <property name="margin_end">6</property>
8230d6
           </object>
8230d6
           <packing>
8230d6
             <property name="pack_type">end</property>
8230d6
           </packing>
8230d6
         </child>
8230d6
       </object>
8230d6
     </child>
8230d6
     <child internal-child="vbox">
8230d6
       <object class="GtkBox">
8230d6
         <property name="visible">True</property>
8230d6
         <property name="can_focus">False</property>
8230d6
         <property name="orientation">vertical</property>
8230d6
         <property name="border_width">0</property>
8230d6
         <child>
8230d6
           <object class="GtkOverlay" id="overlay">
8230d6
             <property name="visible">True</property>
8230d6
             <child type="overlay">
8230d6
               <object class="GtkRevealer" id="notification_revealer">
8230d6
@@ -120,129 +151,275 @@
8230d6
                             <property name="label">Unable to reach developers.redhat.com. Please try again later.</property>
8230d6
                           </object>
8230d6
                         </child>
8230d6
                       </object>
8230d6
                     </child>
8230d6
                     <child>
8230d6
                       <object class="GtkButton" id="dismiss_button">
8230d6
                         <property name="visible">True</property>
8230d6
                         <property name="valign">start</property>
8230d6
                         <signal name="clicked" handler="dismiss_notification" object="CcSubscriptionDetailsDialog" swapped="yes"/>
8230d6
                         <style>
8230d6
                           <class name="flat"/>
8230d6
                         </style>
8230d6
                         <child>
8230d6
                           <object class="GtkImage">
8230d6
                             <property name="visible">True</property>
8230d6
                             <property name="icon_name">window-close-symbolic</property>
8230d6
                           </object>
8230d6
                         </child>
8230d6
                       </object>
8230d6
                     </child>
8230d6
                   </object>
8230d6
                 </child>
8230d6
               </object>
8230d6
             </child>
8230d6
             <child>
8230d6
               <object class="GtkStack" id="stack">
8230d6
                 <property name="visible">True</property>
8230d6
                 <property name="can_focus">False</property>
8230d6
                 <property name="transition-type">slide-left-right</property>
8230d6
+                <child>
8230d6
+                  <object class="GtkBox">
8230d6
+                    <property name="visible">True</property>
8230d6
+                    <property name="orientation">vertical</property>
8230d6
+                    <property name="margin_top">24</property>
8230d6
+                    <property name="margin_start">32</property>
8230d6
+                    <property name="margin_end">12</property>
8230d6
+                    <property name="margin_bottom">12</property>
8230d6
+                    <child>
8230d6
+                      <object class="GtkStack" id="status_stack">
8230d6
+                         <property name="visible">True</property>
8230d6
+                         <property name="can_focus">False</property>
8230d6
+                         <child>
8230d6
+                           <object class="GtkLabel">
8230d6
+                             <property name="visible">True</property>
8230d6
+                             <property name="can_focus">False</property>
8230d6
+                             <property name="label" translatable="yes">This system is subscribed to receive software updates.</property>
8230d6
+                             <property name="width_chars">45</property>
8230d6
+                             <property name="max_width_chars">45</property>
8230d6
+                             <property name="xalign">0</property>
8230d6
+                             <property name="halign">start</property>
8230d6
+                             <property name="wrap">True</property>
8230d6
+                             <style>
8230d6
+                               <class name="dim-label"/>
8230d6
+                             </style>
8230d6
+                           </object>
8230d6
+                           <packing>
8230d6
+                             <property name="name">fully-subscribed</property>
8230d6
+                           </packing>
8230d6
+                         </child>
8230d6
+                         <child>
8230d6
+                           <object class="GtkLabel">
8230d6
+                             <property name="visible">True</property>
8230d6
+                             <property name="can_focus">False</property>
8230d6
+                             <property name="label" translatable="yes">This system lacks subscriptions to receive updates for some installed software.</property>
8230d6
+                             <property name="width_chars">45</property>
8230d6
+                             <property name="max_width_chars">45</property>
8230d6
+                             <property name="xalign">0</property>
8230d6
+                             <property name="halign">start</property>
8230d6
+                             <property name="wrap">True</property>
8230d6
+                             <style>
8230d6
+                               <class name="dim-label"/>
8230d6
+                             </style>
8230d6
+                           </object>
8230d6
+                           <packing>
8230d6
+                             <property name="name">partly-subscribed</property>
8230d6
+                           </packing>
8230d6
+                         </child>
8230d6
+                         <child>
8230d6
+                           <object class="GtkLabel">
8230d6
+                             <property name="visible">True</property>
8230d6
+                             <property name="can_focus">False</property>
8230d6
+                             <property name="label" translatable="yes">This system lacks subscriptions to receive software updates.</property>
8230d6
+                             <property name="width_chars">45</property>
8230d6
+                             <property name="max_width_chars">45</property>
8230d6
+                             <property name="xalign">0</property>
8230d6
+                             <property name="halign">start</property>
8230d6
+                             <property name="wrap">True</property>
8230d6
+                             <style>
8230d6
+                               <class name="dim-label"/>
8230d6
+                             </style>
8230d6
+                           </object>
8230d6
+                           <packing>
8230d6
+                             <property name="name">not-subscribed</property>
8230d6
+                           </packing>
8230d6
+                         </child>
8230d6
+                         <child>
8230d6
+                           <object class="GtkLabel">
8230d6
+                             <property name="visible">True</property>
8230d6
+                             <property name="can_focus">False</property>
8230d6
+                             <property name="label" translatable="yes">This system is registered to receive software updates.</property>
8230d6
+                             <property name="width_chars">45</property>
8230d6
+                             <property name="max_width_chars">45</property>
8230d6
+                             <property name="xalign">0</property>
8230d6
+                             <property name="halign">start</property>
8230d6
+                             <property name="wrap">True</property>
8230d6
+                             <style>
8230d6
+                               <class name="dim-label"/>
8230d6
+                             </style>
8230d6
+                           </object>
8230d6
+                           <packing>
8230d6
+                             <property name="name">subscription-not-needed</property>
8230d6
+                           </packing>
8230d6
+                         </child>
8230d6
+                         <child>
8230d6
+                           <object class="GtkLabel">
8230d6
+                             <property name="visible">True</property>
8230d6
+                             <property name="can_focus">False</property>
8230d6
+                             <property name="label" translatable="yes">This system has no supported software installed.</property>
8230d6
+                             <property name="width_chars">45</property>
8230d6
+                             <property name="max_width_chars">45</property>
8230d6
+                             <property name="xalign">0</property>
8230d6
+                             <property name="halign">start</property>
8230d6
+                             <property name="wrap">True</property>
8230d6
+                             <style>
8230d6
+                               <class name="dim-label"/>
8230d6
+                             </style>
8230d6
+                           </object>
8230d6
+                           <packing>
8230d6
+                             <property name="name">no-installed-products</property>
8230d6
+                           </packing>
8230d6
+                         </child>
8230d6
+                      </object>
8230d6
+                    </child>
8230d6
+                    <child>
8230d6
+                      <object class="GtkBox" id="products_box1">
8230d6
+                        <property name="visible">True</property>
8230d6
+                        <property name="orientation">vertical</property>
8230d6
+                        <property name="hexpand">True</property>
8230d6
+                        <property name="margin_top">6</property>
8230d6
+                        <property name="margin_bottom">6</property>
8230d6
+                      </object>
8230d6
+                    </child>
8230d6
+                    <child>
8230d6
+                      <object class="GtkBox">
8230d6
+                        <property name="visible">True</property>
8230d6
+                        <property name="can_focus">False</property>
8230d6
+                        <property name="orientation">horizontal</property>
8230d6
+                        <property name="spacing">12</property>
8230d6
+                        <property name="halign">end</property>
8230d6
+                        <child>
8230d6
+                          <object class="GtkButton" id="unregister_button">
8230d6
+                            <property name="label" translatable="yes">_Unregister…</property>
8230d6
+                            <property name="can_focus">True</property>
8230d6
+                            <property name="use_underline">True</property>
8230d6
+                            <property name="receives_default">True</property>
8230d6
+                            <property name="use_action_appearance">False</property>
8230d6
+                            <property name="halign">end</property>
8230d6
+                            <property name="visible">True</property>
8230d6
+                            <signal name="clicked" handler="unregister_button_clicked_cb" object="CcSubscriptionDetailsDialog" swapped="yes"/>
8230d6
+                            <style>
8230d6
+                              <class name="text-button"/>
8230d6
+                              <class name="destructive-action"/>
8230d6
+                            </style>
8230d6
+                          </object>
8230d6
+                        </child>
8230d6
+                        <child>
8230d6
+                          <object class="GtkSeparator" id="separator">
8230d6
+                            <property name="visible">True</property>
8230d6
+                          </object>
8230d6
+                        </child>
8230d6
+                        <child>
8230d6
+                          <object class="GtkButton" id="subscribe_button">
8230d6
+                            <property name="label" translatable="yes">_Subscribe…</property>
8230d6
+                            <property name="can_focus">True</property>
8230d6
+                            <property name="use_underline">True</property>
8230d6
+                            <property name="receives_default">True</property>
8230d6
+                            <property name="use_action_appearance">False</property>
8230d6
+                            <property name="halign">end</property>
8230d6
+                            <property name="visible">True</property>
8230d6
+                            <signal name="clicked" handler="subscribe_button_clicked_cb" object="CcSubscriptionDetailsDialog" swapped="yes"/>
8230d6
+                            <style>
8230d6
+                              <class name="text-button"/>
8230d6
+                              <class name="suggested-action"/>
8230d6
+                            </style>
8230d6
+                          </object>
8230d6
+                        </child>
8230d6
+                      </object>
8230d6
+                    </child>
8230d6
+                  </object>
8230d6
+                  <packing>
8230d6
+                    <property name="name">show-details</property>
8230d6
+                  </packing>
8230d6
+                </child>
8230d6
                 <child>
8230d6
                   <object class="GtkBox">
8230d6
                     <property name="visible">True</property>
8230d6
                     <property name="orientation">vertical</property>
8230d6
                     <property name="margin_top">24</property>
8230d6
                     <property name="margin_start">32</property>
8230d6
                     <property name="margin_end">32</property>
8230d6
                     <property name="margin_bottom">20</property>
8230d6
                     <child>
8230d6
                       <object class="GtkLabel">
8230d6
                         <property name="visible">True</property>
8230d6
                         <property name="can_focus">False</property>
8230d6
-                        <property name="label" translatable="yes">Registration with Red Hat allows this system to receive software updates.</property>
8230d6
+                        <property name="label" translatable="yes">Subscribing with Red Hat will allow this system to receive software updates.</property>
8230d6
                         <property name="width_chars">45</property>
8230d6
                         <property name="max_width_chars">45</property>
8230d6
                         <property name="xalign">0</property>
8230d6
                         <property name="halign">start</property>
8230d6
                         <property name="wrap">True</property>
8230d6
-                        <style>
8230d6
-                          <class name="dim-label"/>
8230d6
-                        </style>
8230d6
                       </object>
8230d6
                     </child>
8230d6
                     <child>
8230d6
-                      <object class="GtkBox" id="products_box1">
8230d6
+                      <object class="GtkBox" id="products_box2">
8230d6
                         <property name="visible">True</property>
8230d6
                         <property name="orientation">vertical</property>
8230d6
                         <property name="margin_top">6</property>
8230d6
                         <property name="margin_bottom">6</property>
8230d6
                         <property name="hexpand">True</property>
8230d6
                       </object>
8230d6
                     </child>
8230d6
-                    <child>
8230d6
-                      <object class="GtkButton" id="unregister_button">
8230d6
-                        <property name="label" translatable="yes">_Unregister…</property>
8230d6
-                        <property name="can_focus">True</property>
8230d6
-                        <property name="use_underline">True</property>
8230d6
-                        <property name="receives_default">True</property>
8230d6
-                        <property name="use_action_appearance">False</property>
8230d6
-                        <property name="halign">end</property>
8230d6
-                        <property name="visible">True</property>
8230d6
-                        <signal name="clicked" handler="unregister_button_clicked_cb" object="CcSubscriptionDetailsDialog" swapped="yes"/>
8230d6
-                        <style>
8230d6
-                          <class name="text-button"/>
8230d6
-                        </style>
8230d6
-                      </object>
8230d6
-                    </child>
8230d6
                   </object>
8230d6
                   <packing>
8230d6
-                    <property name="name">show-details</property>
8230d6
+                    <property name="name">subscribe</property>
8230d6
                   </packing>
8230d6
                 </child>
8230d6
                 <child>
8230d6
                   <object class="GtkBox">
8230d6
                     <property name="visible">True</property>
8230d6
                     <property name="orientation">vertical</property>
8230d6
                     <property name="margin_top">24</property>
8230d6
                     <property name="margin_start">32</property>
8230d6
                     <property name="margin_end">32</property>
8230d6
                     <property name="margin_bottom">20</property>
8230d6
                     <child>
8230d6
                       <object class="GtkLabel">
8230d6
                         <property name="visible">True</property>
8230d6
                         <property name="can_focus">False</property>
8230d6
                         <property name="label" translatable="yes">Warning: unregistering this system will result in it no longer receiving software updates.</property>
8230d6
                         <property name="width_chars">45</property>
8230d6
                         <property name="max_width_chars">45</property>
8230d6
                         <property name="xalign">0</property>
8230d6
                         <property name="halign">start</property>
8230d6
                         <property name="wrap">True</property>
8230d6
                       </object>
8230d6
                     </child>
8230d6
                     <child>
8230d6
-                      <object class="GtkBox" id="products_box2">
8230d6
+                      <object class="GtkBox" id="products_box3">
8230d6
                         <property name="visible">True</property>
8230d6
                         <property name="orientation">vertical</property>
8230d6
                         <property name="margin_top">6</property>
8230d6
                         <property name="margin_bottom">6</property>
8230d6
                         <property name="hexpand">True</property>
8230d6
                       </object>
8230d6
                     </child>
8230d6
                   </object>
8230d6
                   <packing>
8230d6
                     <property name="name">unregister</property>
8230d6
                   </packing>
8230d6
                 </child>
8230d6
               </object>
8230d6
             </child>
8230d6
           </object>
8230d6
           <packing>
8230d6
             <property name="expand">False</property>
8230d6
             <property name="fill">True</property>
8230d6
             <property name="position">0</property>
8230d6
           </packing>
8230d6
         </child>
8230d6
       </object>
8230d6
     </child>
8230d6
   </template>
8230d6
 </interface>
8230d6
diff --git a/panels/info/info-overview.ui b/panels/info/info-overview.ui
8230d6
index e33ba399a..3ed79712a 100644
8230d6
--- a/panels/info/info-overview.ui
8230d6
+++ b/panels/info/info-overview.ui
8230d6
@@ -366,68 +366,91 @@
8230d6
                     </child>
8230d6
                   </object>
8230d6
                   <packing>
8230d6
                     <property name="name">not-registered</property>
8230d6
                   </packing>
8230d6
                 </child>
8230d6
                 <child>
8230d6
                   <object class="GtkBox">
8230d6
                     <property name="visible">True</property>
8230d6
                     <property name="can_focus">False</property>
8230d6
                     <property name="orientation">horizontal</property>
8230d6
                     <property name="spacing">12</property>
8230d6
                     <child>
8230d6
                       <object class="GtkBox">
8230d6
                         <property name="visible">True</property>
8230d6
                         <property name="can_focus">False</property>
8230d6
                         <property name="orientation">vertical</property>
8230d6
                         <child>
8230d6
                           <object class="GtkLabel">
8230d6
                             <property name="visible">True</property>
8230d6
                             <property name="can_focus">False</property>
8230d6
                             <property name="xalign">0</property>
8230d6
                             <property name="label" translatable="yes">Registered System</property>
8230d6
                             <attributes>
8230d6
                               <attribute name="scale" value="0.95"/>
8230d6
                               <attribute name="weight" value="bold"/>
8230d6
                             </attributes>
8230d6
                           </object>
8230d6
                         </child>
8230d6
                         <child>
8230d6
-                          <object class="GtkLabel">
8230d6
+                          <object class="GtkStack" id="updates_stack">
8230d6
                             <property name="visible">True</property>
8230d6
                             <property name="can_focus">False</property>
8230d6
-                            <property name="xalign">0</property>
8230d6
-                            <property name="label" translatable="yes">System is registered and able to receive software updates.</property>
8230d6
-                            <attributes>
8230d6
-                              <attribute name="scale" value="0.8"/>
8230d6
-                            </attributes>
8230d6
+                            <child>
8230d6
+                              <object class="GtkLabel">
8230d6
+                                <property name="visible">True</property>
8230d6
+                                <property name="can_focus">False</property>
8230d6
+                                <property name="xalign">0</property>
8230d6
+                                <property name="label" translatable="yes">System is registered and able to receive software updates.</property>
8230d6
+                                <attributes>
8230d6
+                                  <attribute name="scale" value="0.8"/>
8230d6
+                                </attributes>
8230d6
+                              </object>
8230d6
+                              <packing>
8230d6
+                                <property name="name">updates</property>
8230d6
+                              </packing>
8230d6
+                            </child>
8230d6
+                            <child>
8230d6
+                              <object class="GtkLabel">
8230d6
+                                <property name="visible">True</property>
8230d6
+                                <property name="can_focus">False</property>
8230d6
+                                <property name="xalign">0</property>
8230d6
+                                <property name="label" translatable="yes">System is registered but is unable to receive all software updates.</property>
8230d6
+                                <attributes>
8230d6
+                                  <attribute name="scale" value="0.8"/>
8230d6
+                                </attributes>
8230d6
+                              </object>
8230d6
+                              <packing>
8230d6
+                                <property name="name">no-updates</property>
8230d6
+                              </packing>
8230d6
+                            </child>
8230d6
                           </object>
8230d6
                         </child>
8230d6
                       </object>
8230d6
                     </child>
8230d6
                     <child>
8230d6
                       <object class="GtkButton" id="details_button">
8230d6
                         <property name="label" translatable="yes">_Details</property>
8230d6
                         <property name="can_focus">True</property>
8230d6
                         <property name="use_underline">True</property>
8230d6
                         <property name="receives_default">True</property>
8230d6
                         <property name="use_action_appearance">False</property>
8230d6
                         <property name="hexpand">True</property>
8230d6
                         <property name="halign">end</property>
8230d6
                         <property name="visible">True</property>
8230d6
                       </object>
8230d6
                     </child>
8230d6
                   </object>
8230d6
                   <packing>
8230d6
                     <property name="name">registered</property>
8230d6
                   </packing>
8230d6
                 </child>
8230d6
               </object>
8230d6
             </child>
8230d6
             <child>
8230d6
               <object class="GtkSeparator" id="updates_separator">
8230d6
                 <property name="visible">True</property>
8230d6
               </object>
8230d6
             </child>
8230d6
             <child>
8230d6
               <object class="GtkButton" id="updates_button">
8230d6
-- 
8230d6
2.28.0
8230d6