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

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