[gnome-software] repos dialog: Rewrite according to latest mockups



commit 93847b414b8cc776d3f5f52af1cba36b6cc614fe
Author: Kalev Lember <klember redhat com>
Date:   Wed Feb 14 22:18:22 2018 +0100

    repos dialog: Rewrite according to latest mockups
    
    
https://raw.githubusercontent.com/gnome-design-team/gnome-mockups-software/master/wireframes/software-sources.png

 po/POTFILES.in             |   2 +
 src/gs-repos-dialog-row.c  | 274 ++++++++++++++++++++++++---
 src/gs-repos-dialog-row.h  |  19 +-
 src/gs-repos-dialog-row.ui | 119 ++++++++++--
 src/gs-repos-dialog.c      | 448 ++++++++++++++++++++++++---------------------
 src/gs-repos-dialog.ui     | 369 ++++---------------------------------
 6 files changed, 646 insertions(+), 585 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5e439a0a..d9baa51c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -49,6 +49,8 @@ src/gs-removal-dialog.c
 src/gs-removal-dialog.ui
 src/gs-repos-dialog.c
 src/gs-repos-dialog.ui
+src/gs-repos-dialog-row.c
+src/gs-repos-dialog-row.ui
 src/gs-review-dialog.c
 src/gs-review-dialog.ui
 src/gs-review-histogram.ui
diff --git a/src/gs-repos-dialog-row.c b/src/gs-repos-dialog-row.c
index d48b5522..70b8fe92 100644
--- a/src/gs-repos-dialog-row.c
+++ b/src/gs-repos-dialog-row.c
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *
- * Copyright (C) 2015 Kalev Lember <klember redhat com>
+ * Copyright (C) 2015-2018 Kalev Lember <klember redhat com>
  *
  * Licensed under the GNU General Public License Version 2
  *
@@ -23,15 +23,23 @@
 
 #include "gs-repos-dialog-row.h"
 
-struct _GsReposDialogRow
-{
-       GtkListBoxRow    parent_instance;
+#include <glib/gi18n.h>
 
+typedef struct
+{
+       GsApp           *repo;
        GtkWidget       *active_switch;
+       GtkWidget       *button;
        GtkWidget       *name_label;
        GtkWidget       *comment_label;
-       GtkWidget       *description_label;
-};
+       GtkWidget       *details_revealer;
+       GtkWidget       *status_label;
+       GtkWidget       *url_title_label;
+       GtkWidget       *url_value_label;
+       guint            refresh_idle_id;
+} GsReposDialogRowPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (GsReposDialogRow, gs_repos_dialog_row, GTK_TYPE_LIST_BOX_ROW)
 
 enum {
        PROP_0,
@@ -39,50 +47,221 @@ enum {
        PROP_LAST
 };
 
-G_DEFINE_TYPE (GsReposDialogRow, gs_repos_dialog_row, GTK_TYPE_LIST_BOX_ROW)
+enum {
+       SIGNAL_BUTTON_CLICKED,
+       SIGNAL_LAST
+};
+
+static guint signals [SIGNAL_LAST] = { 0 };
 
 void
 gs_repos_dialog_row_set_switch_enabled (GsReposDialogRow *row,
                                         gboolean switch_enabled)
 {
-       gtk_widget_set_visible (row->active_switch, switch_enabled);
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+       gtk_widget_set_visible (priv->active_switch, switch_enabled);
 }
 
 void
 gs_repos_dialog_row_set_switch_active (GsReposDialogRow *row,
                                        gboolean switch_active)
 {
-       gtk_switch_set_active (GTK_SWITCH (row->active_switch), switch_active);
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+       gtk_switch_set_active (GTK_SWITCH (priv->active_switch), switch_active);
 }
 
 void
 gs_repos_dialog_row_set_name (GsReposDialogRow *row, const gchar *name)
 {
-       gtk_label_set_text (GTK_LABEL (row->name_label), name);
-       gtk_widget_set_visible (row->name_label, name != NULL);
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+
+       gtk_label_set_text (GTK_LABEL (priv->name_label), name);
+       gtk_widget_set_visible (priv->name_label, name != NULL);
 }
 
 void
 gs_repos_dialog_row_set_comment (GsReposDialogRow *row, const gchar *comment)
 {
-       gtk_label_set_markup (GTK_LABEL (row->comment_label), comment);
-       gtk_widget_set_visible (row->comment_label, comment != NULL);
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+
+       gtk_label_set_markup (GTK_LABEL (priv->comment_label), comment);
+       gtk_widget_set_visible (priv->comment_label, comment != NULL);
+}
+
+void
+gs_repos_dialog_row_set_url (GsReposDialogRow *row, const gchar *url)
+{
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+
+       gtk_label_set_text (GTK_LABEL (priv->url_value_label), url);
+       gtk_widget_set_visible (priv->url_value_label, url != NULL);
+       gtk_widget_set_visible (priv->url_title_label, url != NULL);
+}
+
+static gboolean
+repo_supports_removal (GsApp *repo)
+{
+       const gchar *management_plugin = gs_app_get_management_plugin (repo);
+
+       /* can't remove a repo, only enable/disable existing ones */
+       if (g_strcmp0 (management_plugin, "fwupd") == 0 ||
+           g_strcmp0 (management_plugin, "packagekit") == 0)
+               return FALSE;
+
+       return TRUE;
+}
+
+static void
+refresh_ui (GsReposDialogRow *row)
+{
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+
+       if (priv->repo == NULL) {
+               gtk_widget_set_visible (priv->button, FALSE);
+               return;
+       }
+
+       gtk_widget_set_visible (priv->button, TRUE);
 
-       /* make the name bold */
-       if (comment != NULL) {
-               PangoAttrList *attr_list = pango_attr_list_new ();
-               pango_attr_list_insert (attr_list,
-                                       pango_attr_weight_new (PANGO_WEIGHT_BOLD));
-               gtk_label_set_attributes (GTK_LABEL (row->name_label), attr_list);
-               pango_attr_list_unref (attr_list);
+       /* set button text */
+       switch (gs_app_get_state (priv->repo)) {
+       case AS_APP_STATE_AVAILABLE:
+       case AS_APP_STATE_AVAILABLE_LOCAL:
+               /* TRANSLATORS: this is a button in the software repositories
+                  dialog for enabling a repo */
+               gtk_button_set_label (GTK_BUTTON (priv->button), _("_Enable"));
+               /* enable button */
+               gtk_widget_set_sensitive (priv->button, TRUE);
+               break;
+       case AS_APP_STATE_INSTALLED:
+               if (repo_supports_removal (priv->repo)) {
+                       /* TRANSLATORS: this is a button in the software repositories dialog
+                          for removing a repo. The ellipsis indicates that further
+                          steps are required */
+                       gtk_button_set_label (GTK_BUTTON (priv->button), _("_Remove…"));
+               } else {
+                       /* TRANSLATORS: this is a button in the software repositories dialog
+                          for disabling a repo. The ellipsis indicates that further
+                          steps are required */
+                       gtk_button_set_label (GTK_BUTTON (priv->button), _("_Disable…"));
+               }
+               /* enable button */
+               gtk_widget_set_sensitive (priv->button, TRUE);
+               break;
+       case AS_APP_STATE_INSTALLING:
+               /* TRANSLATORS: this is a button in the software repositories dialog
+                  that shows the status of a repo being enabled */
+               gtk_button_set_label (GTK_BUTTON (priv->button), _("Enabling"));
+               /* disable button */
+               gtk_widget_set_sensitive (priv->button, FALSE);
+               break;
+       case AS_APP_STATE_REMOVING:
+               if (repo_supports_removal (priv->repo)) {
+                       /* TRANSLATORS: this is a button in the software repositories dialog
+                          that shows the status of a repo being removed */
+                       gtk_button_set_label (GTK_BUTTON (priv->button), _("Removing"));
+               } else {
+                       /* TRANSLATORS: this is a button in the software repositories dialog
+                          that shows the status of a repo being disabled */
+                       gtk_button_set_label (GTK_BUTTON (priv->button), _("Disabling"));
+               }
+               /* disable button */
+               gtk_widget_set_sensitive (priv->button, FALSE);
+               break;
+       default:
+               break;
        }
+
+       /* set enabled/disabled label */
+       switch (gs_app_get_state (priv->repo)) {
+       case AS_APP_STATE_INSTALLED:
+               /* TRANSLATORS: this is a label in the software repositories
+                  dialog that indicates that a repo is enabled. */
+               gtk_label_set_text (GTK_LABEL (priv->status_label), _("Enabled"));
+               break;
+       case AS_APP_STATE_AVAILABLE:
+       case AS_APP_STATE_AVAILABLE_LOCAL:
+               /* TRANSLATORS: this is a label in the software repositories
+                  dialog that indicates that a repo is disabled. */
+               gtk_label_set_text (GTK_LABEL (priv->status_label), _("Disabled"));
+               break;
+       default:
+               break;
+       }
+}
+
+static gboolean
+refresh_idle (gpointer user_data)
+{
+       g_autoptr(GsReposDialogRow) row = (GsReposDialogRow *) user_data;
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+
+       refresh_ui (row);
+
+       priv->refresh_idle_id = 0;
+       return G_SOURCE_REMOVE;
+}
+
+static void
+repo_state_changed_cb (GsApp *repo, GParamSpec *pspec, GsReposDialogRow *row)
+{
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+
+       if (priv->refresh_idle_id > 0)
+               return;
+       priv->refresh_idle_id = g_idle_add (refresh_idle, g_object_ref (row));
+}
+
+void
+gs_repos_dialog_row_set_repo (GsReposDialogRow *row, GsApp *repo)
+{
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+
+       g_assert (priv->repo == NULL);
+
+       priv->repo = g_object_ref (repo);
+       g_signal_connect_object (priv->repo, "notify::state",
+                                G_CALLBACK (repo_state_changed_cb),
+                                row, 0);
+       refresh_ui (row);
+}
+
+GsApp *
+gs_repos_dialog_row_get_repo (GsReposDialogRow *row)
+{
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+       return priv->repo;
+}
+
+void
+gs_repos_dialog_row_show_details (GsReposDialogRow *row)
+{
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+
+       gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
+       gtk_revealer_set_reveal_child (GTK_REVEALER (priv->details_revealer), TRUE);
+}
+
+void
+gs_repos_dialog_row_hide_details (GsReposDialogRow *row)
+{
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+
+       gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), TRUE);
+       gtk_revealer_set_reveal_child (GTK_REVEALER (priv->details_revealer), FALSE);
 }
 
 void
-gs_repos_dialog_row_set_description (GsReposDialogRow *row, const gchar *description)
+gs_repos_dialog_row_show_status (GsReposDialogRow *row)
 {
-       gtk_label_set_markup (GTK_LABEL (row->description_label), description);
-       gtk_widget_set_visible (row->description_label, description != NULL);
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+       gtk_widget_set_visible (priv->status_label, TRUE);
+}
+
+static void
+button_clicked_cb (GtkWidget *widget, GsReposDialogRow *row)
+{
+       g_signal_emit (row, signals[SIGNAL_BUTTON_CLICKED], 0);
 }
 
 static void
@@ -96,7 +275,9 @@ gs_repos_dialog_switch_active_cb (GtkSwitch *active_switch,
 gboolean
 gs_repos_dialog_row_get_switch_active (GsReposDialogRow *row)
 {
-       return gtk_switch_get_active (GTK_SWITCH (row->active_switch));
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+
+       return gtk_switch_get_active (GTK_SWITCH (priv->active_switch));
 }
 
 static void
@@ -117,12 +298,35 @@ gs_repos_dialog_row_get_property (GObject *object,
        }
 }
 
+static void
+gs_repos_dialog_row_destroy (GtkWidget *object)
+{
+       GsReposDialogRow *row = GS_REPOS_DIALOG_ROW (object);
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+
+       if (priv->repo != NULL) {
+               g_signal_handlers_disconnect_by_func (priv->repo, repo_state_changed_cb, row);
+               g_clear_object (&priv->repo);
+       }
+
+       if (priv->refresh_idle_id != 0) {
+               g_source_remove (priv->refresh_idle_id);
+               priv->refresh_idle_id = 0;
+       }
+
+       GTK_WIDGET_CLASS (gs_repos_dialog_row_parent_class)->destroy (object);
+}
+
 static void
 gs_repos_dialog_row_init (GsReposDialogRow *row)
 {
+       GsReposDialogRowPrivate *priv = gs_repos_dialog_row_get_instance_private (row);
+
        gtk_widget_init_template (GTK_WIDGET (row));
-       g_signal_connect (row->active_switch, "notify::active",
+       g_signal_connect (priv->active_switch, "notify::active",
                          G_CALLBACK (gs_repos_dialog_switch_active_cb), row);
+       g_signal_connect (priv->button, "clicked",
+                         G_CALLBACK (button_clicked_cb), row);
 }
 
 static void
@@ -133,17 +337,29 @@ gs_repos_dialog_row_class_init (GsReposDialogRowClass *klass)
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
        object_class->get_property = gs_repos_dialog_row_get_property;
+       widget_class->destroy = gs_repos_dialog_row_destroy;
 
        pspec = g_param_spec_string ("switch-active", NULL, NULL, FALSE,
                                     G_PARAM_READABLE);
        g_object_class_install_property (object_class, PROP_SWITCH_ACTIVE, pspec);
 
+       signals [SIGNAL_BUTTON_CLICKED] =
+               g_signal_new ("button-clicked",
+                             G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET (GsReposDialogRowClass, button_clicked),
+                             NULL, NULL, g_cclosure_marshal_VOID__VOID,
+                             G_TYPE_NONE, 0);
+
        gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/Software/gs-repos-dialog-row.ui");
 
-       gtk_widget_class_bind_template_child (widget_class, GsReposDialogRow, active_switch);
-       gtk_widget_class_bind_template_child (widget_class, GsReposDialogRow, name_label);
-       gtk_widget_class_bind_template_child (widget_class, GsReposDialogRow, comment_label);
-       gtk_widget_class_bind_template_child (widget_class, GsReposDialogRow, description_label);
+       gtk_widget_class_bind_template_child_private (widget_class, GsReposDialogRow, active_switch);
+       gtk_widget_class_bind_template_child_private (widget_class, GsReposDialogRow, button);
+       gtk_widget_class_bind_template_child_private (widget_class, GsReposDialogRow, name_label);
+       gtk_widget_class_bind_template_child_private (widget_class, GsReposDialogRow, comment_label);
+       gtk_widget_class_bind_template_child_private (widget_class, GsReposDialogRow, details_revealer);
+       gtk_widget_class_bind_template_child_private (widget_class, GsReposDialogRow, status_label);
+       gtk_widget_class_bind_template_child_private (widget_class, GsReposDialogRow, url_title_label);
+       gtk_widget_class_bind_template_child_private (widget_class, GsReposDialogRow, url_value_label);
 }
 
 GtkWidget *
diff --git a/src/gs-repos-dialog-row.h b/src/gs-repos-dialog-row.h
index 88a7cf2f..8f49dd28 100644
--- a/src/gs-repos-dialog-row.h
+++ b/src/gs-repos-dialog-row.h
@@ -22,13 +22,20 @@
 #ifndef GS_REPOS_DIALOG_ROW_H
 #define GS_REPOS_DIALOG_ROW_H
 
+#include "gnome-software-private.h"
 #include <gtk/gtk.h>
 
 G_BEGIN_DECLS
 
 #define GS_TYPE_REPOS_DIALOG_ROW (gs_repos_dialog_row_get_type ())
 
-G_DECLARE_FINAL_TYPE (GsReposDialogRow, gs_repos_dialog_row, GS, REPOS_DIALOG_ROW, GtkListBoxRow)
+G_DECLARE_DERIVABLE_TYPE (GsReposDialogRow, gs_repos_dialog_row, GS, REPOS_DIALOG_ROW, GtkListBoxRow)
+
+struct _GsReposDialogRowClass
+{
+       GtkListBoxRowClass        parent_class;
+       void                    (*button_clicked)       (GsReposDialogRow       *row);
+};
 
 GtkWidget      *gs_repos_dialog_row_new                (void);
 void            gs_repos_dialog_row_set_switch_enabled (GsReposDialogRow       *row,
@@ -40,8 +47,14 @@ void          gs_repos_dialog_row_set_name           (GsReposDialogRow       *row,
                                                         const gchar            *name);
 void            gs_repos_dialog_row_set_comment        (GsReposDialogRow       *row,
                                                         const gchar            *comment);
-void            gs_repos_dialog_row_set_description    (GsReposDialogRow       *row,
-                                                        const gchar            *description);
+void            gs_repos_dialog_row_set_url            (GsReposDialogRow       *row,
+                                                        const gchar            *url);
+void            gs_repos_dialog_row_set_repo           (GsReposDialogRow       *row,
+                                                        GsApp                  *repo);
+GsApp          *gs_repos_dialog_row_get_repo           (GsReposDialogRow       *row);
+void            gs_repos_dialog_row_show_details       (GsReposDialogRow       *row);
+void            gs_repos_dialog_row_hide_details       (GsReposDialogRow       *row);
+void            gs_repos_dialog_row_show_status        (GsReposDialogRow       *row);
 
 G_END_DECLS
 
diff --git a/src/gs-repos-dialog-row.ui b/src/gs-repos-dialog-row.ui
index 318db606..9b6c4226 100644
--- a/src/gs-repos-dialog-row.ui
+++ b/src/gs-repos-dialog-row.ui
@@ -18,10 +18,31 @@
             <property name="orientation">vertical</property>
             <property name="spacing">4</property>
             <child>
-              <object class="GtkLabel" id="name_label">
+              <object class="GtkBox" id="hbox">
                 <property name="visible">True</property>
-                <property name="halign">start</property>
-                <property name="ellipsize">end</property>
+                <property name="orientation">horizontal</property>
+                <property name="spacing">4</property>
+                <child>
+                  <object class="GtkLabel" id="name_label">
+                    <property name="visible">True</property>
+                    <property name="halign">start</property>
+                    <property name="ellipsize">end</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="status_label">
+                    <property name="visible">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="pack-type">end</property>
+                  </packing>
+                </child>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -34,6 +55,9 @@
                 <property name="halign">start</property>
                 <property name="xalign">0</property>
                 <property name="wrap">True</property>
+                <style>
+                  <class name="dim-label"/>
+                </style>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -41,19 +65,84 @@
               </packing>
             </child>
             <child>
-              <object class="GtkLabel" id="description_label">
+              <object class="GtkRevealer" id="details_revealer">
                 <property name="visible">True</property>
-                <property name="halign">start</property>
-                <property name="xalign">0</property>
-                <property name="wrap">True</property>
-                <style>
-                  <class name="dim-label"/>
-                </style>
+                <property name="transition-type">slide-down</property>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">4</property>
+                    <child>
+                      <object class="GtkBox" id="url_box">
+                        <property name="visible">True</property>
+                        <property name="orientation">horizontal</property>
+                        <property name="spacing">8</property>
+                        <child>
+                          <object class="GtkLabel" id="url_title_label">
+                            <property name="visible">True</property>
+                            <property name="halign">start</property>
+                            <property name="valign">start</property>
+                            <property name="label" translatable="yes">URL</property>
+                            <style>
+                              <class name="dim-label"/>
+                            </style>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkLabel" id="url_value_label">
+                            <property name="visible">True</property>
+                            <property name="halign">start</property>
+                            <property name="valign">start</property>
+                            <property name="ellipsize">end</property>
+                            <style>
+                              <class name="dim-label"/>
+                            </style>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkBox">
+                        <property name="visible">True</property>
+                        <property name="orientation">horizontal</property>
+                        <property name="spacing">8</property>
+                        <child>
+                          <object class="GtkButton" id="button">
+                            <property name="visible">True</property>
+                            <property name="use_underline">True</property>
+                            <property name="width_request">105</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">True</property>
+                            <property name="halign">start</property>
+                            <property name="valign">start</property>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
               </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-              </packing>
             </child>
           </object>
           <packing>
@@ -66,7 +155,7 @@
             <property name="visible">False</property>
             <property name="can_focus">True</property>
             <property name="halign">end</property>
-            <property name="valign">start</property>
+            <property name="valign">center</property>
           </object>
           <packing>
             <property name="expand">False</property>
diff --git a/src/gs-repos-dialog.c b/src/gs-repos-dialog.c
index 28c88af2..733d2673 100644
--- a/src/gs-repos-dialog.c
+++ b/src/gs-repos-dialog.c
@@ -2,6 +2,7 @@
  *
  * Copyright (C) 2013-2017 Richard Hughes <richard hughsie com>
  * Copyright (C) 2013 Matthias Clasen <mclasen redhat com>
+ * Copyright (C) 2014-2018 Kalev Lember <klember redhat com>
  *
  * Licensed under the GNU General Public License Version 2
  *
@@ -22,13 +23,13 @@
 
 #include "config.h"
 
-#include <glib/gi18n.h>
+#include "gs-repos-dialog.h"
 
 #include "gnome-software-private.h"
-#include "gs-repos-dialog.h"
+#include "gs-common.h"
 #include "gs-os-release.h"
 #include "gs-repos-dialog-row.h"
-#include "gs-common.h"
+#include <glib/gi18n.h>
 
 struct _GsReposDialog
 {
@@ -38,16 +39,12 @@ struct _GsReposDialog
 
        GCancellable    *cancellable;
        GsPluginLoader  *plugin_loader;
-       GtkWidget       *button_back;
        GtkWidget       *frame_third_party;
-       GtkWidget       *grid_noresults;
-       GtkWidget       *label2;
+       GtkWidget       *label_description;
        GtkWidget       *label_empty;
        GtkWidget       *label_header;
        GtkWidget       *listbox;
-       GtkWidget       *listbox_apps;
        GtkWidget       *row_third_party;
-       GtkWidget       *scrolledwindow_apps;
        GtkWidget       *spinner;
        GtkWidget       *stack;
 };
@@ -56,119 +53,281 @@ G_DEFINE_TYPE (GsReposDialog, gs_repos_dialog, GTK_TYPE_DIALOG)
 
 typedef struct {
        GsReposDialog   *dialog;
+       GsApp           *repo;
        GsPluginAction   action;
-} InstallData;
+} InstallRemoveData;
 
 static void
-install_data_free (InstallData *install_data)
+install_remove_data_free (InstallRemoveData *data)
 {
-       g_clear_object (&install_data->dialog);
-       g_slice_free (InstallData, install_data);
+       g_clear_object (&data->dialog);
+       g_clear_object (&data->repo);
+       g_slice_free (InstallRemoveData, data);
 }
 
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(InstallRemoveData, install_remove_data_free);
+
 static void reload_sources (GsReposDialog *dialog);
 static void reload_third_party_repo (GsReposDialog *dialog);
 static void refresh_third_party_repo (GsReposDialog *dialog);
 
 static gchar *
-get_source_installed_text (GPtrArray *sources)
+get_repo_installed_text (GsApp *repo)
 {
+       GPtrArray *related;
        guint cnt_addon = 0;
        guint cnt_apps = 0;
        g_autofree gchar *addons_text = NULL;
        g_autofree gchar *apps_text = NULL;
 
-       /* split up the types */
-       for (guint j = 0; j < sources->len; j++) {
-               GsApp *app = g_ptr_array_index (sources, j);
-               GPtrArray *related = gs_app_get_related (app);
-               for (guint i = 0; i < related->len; i++) {
-                       GsApp *app_tmp = g_ptr_array_index (related, i);
-                       switch (gs_app_get_kind (app_tmp)) {
-                       case AS_APP_KIND_WEB_APP:
-                       case AS_APP_KIND_DESKTOP:
-                               cnt_apps++;
-                               break;
-                       case AS_APP_KIND_FONT:
-                       case AS_APP_KIND_CODEC:
-                       case AS_APP_KIND_INPUT_METHOD:
-                       case AS_APP_KIND_ADDON:
-                               cnt_addon++;
-                               break;
-                       default:
-                               break;
-                       }
+       related = gs_app_get_related (repo);
+       for (guint i = 0; i < related->len; i++) {
+               GsApp *app_tmp = g_ptr_array_index (related, i);
+               switch (gs_app_get_kind (app_tmp)) {
+               case AS_APP_KIND_WEB_APP:
+               case AS_APP_KIND_DESKTOP:
+                       cnt_apps++;
+                       break;
+               case AS_APP_KIND_FONT:
+               case AS_APP_KIND_CODEC:
+               case AS_APP_KIND_INPUT_METHOD:
+               case AS_APP_KIND_ADDON:
+                       cnt_addon++;
+                       break;
+               default:
+                       break;
                }
        }
 
-       /* nothing! */
        if (cnt_apps == 0 && cnt_addon == 0) {
-               /* TRANSLATORS: This string describes a software repository that
-                  has no software installed from it. */
-               return g_strdup (_("No applications or addons installed; other software might still be"));
+               /* nothing! */
+               return NULL;
        }
        if (cnt_addon == 0) {
                /* TRANSLATORS: This string is used to construct the 'X applications
                   installed' sentence, describing a software repository. */
                return g_strdup_printf (ngettext ("%u application installed",
-                                                 "%u applications installed",
-                                                 cnt_apps), cnt_apps);
+                                                 "%u applications installed",
+                                                 cnt_apps), cnt_apps);
        }
        if (cnt_apps == 0) {
                /* TRANSLATORS: This string is used to construct the 'X add-ons
                   installed' sentence, describing a software repository. */
                return g_strdup_printf (ngettext ("%u add-on installed",
-                                                 "%u add-ons installed",
-                                                 cnt_addon), cnt_addon);
+                                                 "%u add-ons installed",
+                                                 cnt_addon), cnt_addon);
        }
 
        /* TRANSLATORS: This string is used to construct the 'X applications
           and y add-ons installed' sentence, describing a software repository.
           The correct form here depends on the number of applications. */
        apps_text = g_strdup_printf (ngettext ("%u application",
-                                              "%u applications",
-                                              cnt_apps), cnt_apps);
+                                              "%u applications",
+                                              cnt_apps), cnt_apps);
        /* TRANSLATORS: This string is used to construct the 'X applications
           and y add-ons installed' sentence, describing a software repository.
           The correct form here depends on the number of add-ons. */
        addons_text = g_strdup_printf (ngettext ("%u add-on",
-                                                "%u add-ons",
-                                                cnt_addon), cnt_addon);
+                                                "%u add-ons",
+                                                cnt_addon), cnt_addon);
        /* TRANSLATORS: This string is used to construct the 'X applications
           and y add-ons installed' sentence, describing a software repository.
           The correct form here depends on the total number of
           applications and add-ons. */
        return g_strdup_printf (ngettext ("%s and %s installed",
-                                         "%s and %s installed",
-                                         cnt_apps + cnt_addon),
-                                         apps_text, addons_text);
+                                         "%s and %s installed",
+                                         cnt_apps + cnt_addon),
+                                         apps_text, addons_text);
+}
+
+static gboolean
+repo_supports_removal (GsApp *repo)
+{
+       const gchar *management_plugin = gs_app_get_management_plugin (repo);
+
+       /* can't remove a repo, only enable/disable existing ones */
+       if (g_strcmp0 (management_plugin, "fwupd") == 0 ||
+           g_strcmp0 (management_plugin, "packagekit") == 0)
+               return FALSE;
+
+       return TRUE;
+}
+
+static void
+repo_enabled_cb (GObject *source,
+                 GAsyncResult *res,
+                 gpointer user_data)
+{
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
+       g_autoptr(InstallRemoveData) install_remove_data = (InstallRemoveData *) user_data;
+       g_autoptr(GError) error = NULL;
+       const gchar *action_str;
+
+       action_str = gs_plugin_action_to_string (install_remove_data->action);
+
+       if (!gs_plugin_loader_job_action_finish (plugin_loader, res, &error)) {
+               if (g_error_matches (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_CANCELLED)) {
+                       g_debug ("repo %s cancelled", action_str);
+                       return;
+               }
+
+               g_warning ("failed to %s repo: %s", action_str, error->message);
+               return;
+       }
+
+       g_debug ("finished %s repo %s", action_str, gs_app_get_id (install_remove_data->repo));
+}
+
+static void
+enable_repo (GsReposDialog *dialog, GsApp *repo)
+{
+       InstallRemoveData *install_data;
+       g_autoptr(GsPluginJob) plugin_job = NULL;
+
+       install_data = g_slice_new0 (InstallRemoveData);
+       install_data->action = GS_PLUGIN_ACTION_INSTALL;
+       install_data->repo = g_object_ref (repo);
+       install_data->dialog = g_object_ref (dialog);
+
+       g_debug ("enabling repo %s", gs_app_get_id (install_data->repo));
+       plugin_job = gs_plugin_job_newv (install_data->action,
+                                        "app", repo,
+                                        NULL);
+       gs_plugin_loader_job_process_async (dialog->plugin_loader, plugin_job,
+                                           dialog->cancellable,
+                                           repo_enabled_cb,
+                                           install_data);
+}
+
+static void
+remove_repo_response_cb (GtkDialog *confirm_dialog,
+                         gint response,
+                         gpointer user_data)
+{
+       g_autoptr(InstallRemoveData) remove_data = (InstallRemoveData *) user_data;
+       GsReposDialog *dialog = remove_data->dialog;
+       g_autoptr(GsPluginJob) plugin_job = NULL;
+
+       /* unmap the dialog */
+       gtk_widget_destroy (GTK_WIDGET (confirm_dialog));
+
+       /* not agreed */
+       if (response != GTK_RESPONSE_OK)
+               return;
+
+       g_debug ("removing repo %s", gs_app_get_id (remove_data->repo));
+       plugin_job = gs_plugin_job_newv (remove_data->action,
+                                        "app", remove_data->repo,
+                                        NULL);
+       gs_plugin_loader_job_process_async (dialog->plugin_loader, plugin_job,
+                                           dialog->cancellable,
+                                           repo_enabled_cb,
+                                           g_steal_pointer (&remove_data));
+}
+
+static void
+remove_confirm_repo (GsReposDialog *dialog, GsApp *repo)
+{
+       InstallRemoveData *remove_data;
+       GtkWidget *confirm_dialog;
+       g_autofree gchar *message = NULL;
+       g_autofree gchar *title = NULL;
+
+       remove_data = g_slice_new0 (InstallRemoveData);
+       remove_data->action = GS_PLUGIN_ACTION_REMOVE;
+       remove_data->repo = g_object_ref (repo);
+       remove_data->dialog = g_object_ref (dialog);
+
+       if (repo_supports_removal (repo)) {
+               /* TRANSLATORS: this is a prompt message, and '%s' is a
+                * repository name, e.g. 'GNOME Nightly' */
+               title = g_strdup_printf (_("Remove “%s”?"),
+                                        gs_app_get_name (repo));
+       } else {
+               /* TRANSLATORS: this is a prompt message, and '%s' is a
+                * repository name, e.g. 'GNOME Nightly' */
+               title = g_strdup_printf (_("Disable “%s”?"),
+                                        gs_app_get_name (repo));
+       }
+       /* TRANSLATORS: longer dialog text */
+       message = g_strdup (_("Software that has been installed from this "
+                             "repository will no longer receive updates, "
+                             "including security fixes."));
+
+       /* ask for confirmation */
+       confirm_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog),
+                                                GTK_DIALOG_MODAL,
+                                                GTK_MESSAGE_QUESTION,
+                                                GTK_BUTTONS_CANCEL,
+                                                "%s", title);
+       gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (confirm_dialog),
+                                                 "%s", message);
+
+       if (repo_supports_removal (repo)) {
+               /* TRANSLATORS: this is button text to remove the repo */
+               gtk_dialog_add_button (GTK_DIALOG (confirm_dialog), _("Remove"), GTK_RESPONSE_OK);
+       } else {
+               /* TRANSLATORS: this is button text to remove the repo */
+               gtk_dialog_add_button (GTK_DIALOG (confirm_dialog), _("Disable"), GTK_RESPONSE_OK);
+       }
+
+       /* handle this async */
+       g_signal_connect (confirm_dialog, "response",
+                         G_CALLBACK (remove_repo_response_cb), remove_data);
+
+       gtk_window_set_modal (GTK_WINDOW (confirm_dialog), TRUE);
+       gtk_window_present (GTK_WINDOW (confirm_dialog));
 }
 
 static void
-add_source (GtkListBox *listbox, GsApp *app)
+repo_button_clicked_cb (GsReposDialogRow *row,
+                        GsReposDialog *dialog)
+{
+        GsApp *repo;
+
+        repo = gs_repos_dialog_row_get_repo (row);
+
+       switch (gs_app_get_state (repo)) {
+       case AS_APP_STATE_AVAILABLE:
+       case AS_APP_STATE_AVAILABLE_LOCAL:
+               enable_repo (dialog, repo);
+               break;
+       case AS_APP_STATE_INSTALLED:
+               remove_confirm_repo (dialog, repo);
+               break;
+       default:
+               g_warning ("repo %s button clicked in unexpected state %s",
+                          gs_app_get_id (repo),
+                          as_app_state_to_string (gs_app_get_state (repo)));
+               break;
+       }
+}
+
+static void
+add_repo (GsReposDialog *dialog, GsApp *app)
 {
        GtkWidget *row;
        g_autofree gchar *text = NULL;
-       g_autoptr(GPtrArray) sources = g_ptr_array_new ();
 
        row = gs_repos_dialog_row_new ();
        gs_repos_dialog_row_set_name (GS_REPOS_DIALOG_ROW (row),
                                      gs_app_get_name (app));
-       g_ptr_array_add (sources, app);
-       text = get_source_installed_text (sources);
-       gs_repos_dialog_row_set_description (GS_REPOS_DIALOG_ROW (row),
-                                            text);
-
-       g_object_set_data_full (G_OBJECT (row), "GsShell::app",
-                               g_object_ref (app),
-                               (GDestroyNotify) g_object_unref);
+       text = get_repo_installed_text (app);
+       gs_repos_dialog_row_set_comment (GS_REPOS_DIALOG_ROW (row), text);
+       gs_repos_dialog_row_set_url (GS_REPOS_DIALOG_ROW (row),
+                                    gs_app_get_url (app, AS_URL_KIND_HOMEPAGE));
+       gs_repos_dialog_row_show_status (GS_REPOS_DIALOG_ROW (row));
+       gs_repos_dialog_row_set_repo (GS_REPOS_DIALOG_ROW (row), app);
 
        g_object_set_data_full (G_OBJECT (row),
                                "sort",
                                g_utf8_casefold (gs_app_get_name (app), -1),
                                g_free);
 
-       gtk_list_box_prepend (listbox, row);
+       g_signal_connect (row, "button-clicked",
+                         G_CALLBACK (repo_button_clicked_cb), dialog);
+
+       gtk_list_box_prepend (GTK_LIST_BOX (dialog->listbox), row);
        gtk_widget_show (row);
 }
 
@@ -178,7 +337,7 @@ third_party_repo_installed_cb (GObject *source,
                                gpointer user_data)
 {
        GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
-       InstallData *install_data = (InstallData *) user_data;
+       InstallRemoveData *install_data = (InstallRemoveData *) user_data;
        g_autoptr(GError) error = NULL;
 
        if (!gs_plugin_loader_job_action_finish (plugin_loader, res, &error)) {
@@ -197,14 +356,14 @@ third_party_repo_installed_cb (GObject *source,
        }
 
 out:
-       install_data_free (install_data);
+       install_remove_data_free (install_data);
 }
 
 static void
 install_third_party_repo (GsReposDialog *dialog, gboolean install)
 {
        GsPluginAction action;
-       InstallData *install_data;
+       InstallRemoveData *install_data;
        g_autoptr(GsPluginJob) plugin_job = NULL;
 
        if (install && gs_app_get_state (dialog->third_party_repo) == AS_APP_STATE_AVAILABLE) {
@@ -218,7 +377,7 @@ install_third_party_repo (GsReposDialog *dialog, gboolean install)
                return;
        }
 
-       install_data = g_slice_new0 (InstallData);
+       install_data = g_slice_new0 (InstallRemoveData);
        install_data->dialog = g_object_ref (dialog);
        install_data->action = action;
 
@@ -306,9 +465,7 @@ get_sources_cb (GsPluginLoader *plugin_loader,
        gtk_stack_set_visible_child_name (GTK_STACK (dialog->stack), "sources");
        for (guint i = 0; i < gs_app_list_length (list); i++) {
                app = gs_app_list_index (list, i);
-               if (gs_app_get_state (app) != AS_APP_STATE_INSTALLED)
-                       continue;
-               add_source (GTK_LIST_BOX (dialog->listbox), app);
+               add_repo (dialog, app);
        }
 }
 
@@ -350,13 +507,13 @@ reload_sources (GsReposDialog *dialog)
 
        gtk_stack_set_visible_child_name (GTK_STACK (dialog->stack), "waiting");
        gs_start_spinner (GTK_SPINNER (dialog->spinner));
-       gtk_widget_hide (dialog->button_back);
        gs_container_remove_all (GTK_CONTAINER (dialog->listbox));
 
        /* get the list of non-core software repositories */
        plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_GET_SOURCES,
                                         "failure-flags", GS_PLUGIN_FAILURE_FLAGS_NONE,
-                                        "refine-flags", GS_PLUGIN_REFINE_FLAGS_REQUIRE_RELATED,
+                                        "refine-flags", GS_PLUGIN_REFINE_FLAGS_REQUIRE_RELATED |
+                                                        GS_PLUGIN_REFINE_FLAGS_REQUIRE_ORIGIN_HOSTNAME,
                                         NULL);
        gs_plugin_loader_job_process_async (dialog->plugin_loader, plugin_job,
                                            dialog->cancellable,
@@ -424,122 +581,21 @@ list_sort_func (GtkListBoxRow *a,
        return g_strcmp0 (key1, key2);
 }
 
-static void
-add_app (GtkListBox *listbox, GsApp *app)
-{
-       GtkWidget *box;
-       GtkWidget *widget;
-       GtkWidget *row;
-
-       box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
-       gtk_widget_set_margin_top (box, 12);
-       gtk_widget_set_margin_start (box, 12);
-       gtk_widget_set_margin_bottom (box, 12);
-       gtk_widget_set_margin_end (box, 12);
-
-       widget = gtk_label_new (gs_app_get_name (app));
-       gtk_widget_set_halign (widget, GTK_ALIGN_START);
-       gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END);
-       gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0);
-
-       g_object_set_data_full (G_OBJECT (box),
-                               "sort",
-                               g_utf8_casefold (gs_app_get_name (app), -1),
-                               g_free);
-
-       gtk_list_box_prepend (listbox, box);
-       gtk_widget_show (widget);
-       gtk_widget_show (box);
-
-       row = gtk_widget_get_parent (box);
-       gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
-}
-
 static void
 list_row_activated_cb (GtkListBox *list_box,
                       GtkListBoxRow *row,
                       GsReposDialog *dialog)
 {
-       GPtrArray *related;
-       GsApp *app;
-       guint cnt_apps = 0;
-
-       gtk_stack_set_visible_child_name (GTK_STACK (dialog->stack), "details");
+       GtkListBoxRow *other_row;
 
-       gtk_widget_show (dialog->button_back);
+       gs_repos_dialog_row_show_details (GS_REPOS_DIALOG_ROW (row));
 
-       gs_container_remove_all (GTK_CONTAINER (dialog->listbox_apps));
-       app = GS_APP (g_object_get_data (G_OBJECT (row),
-                                        "GsShell::app"));
-       related = gs_app_get_related (app);
-       for (guint i = 0; i < related->len; i++) {
-               GsApp *app_tmp = g_ptr_array_index (related, i);
-               switch (gs_app_get_kind (app_tmp)) {
-               case AS_APP_KIND_DESKTOP:
-                       add_app (GTK_LIST_BOX (dialog->listbox_apps), app_tmp);
-                       cnt_apps++;
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       /* save this */
-       g_object_set_data_full (G_OBJECT (dialog->stack), "GsShell::app",
-                               g_object_ref (app),
-                               (GDestroyNotify) g_object_unref);
-
-       gtk_widget_set_visible (dialog->scrolledwindow_apps, cnt_apps != 0);
-       gtk_widget_set_visible (dialog->label2, cnt_apps != 0);
-       gtk_widget_set_visible (dialog->grid_noresults, cnt_apps == 0);
-}
-
-static void
-back_button_cb (GtkWidget *widget, GsReposDialog *dialog)
-{
-       gtk_widget_hide (dialog->button_back);
-       gtk_stack_set_visible_child_name (GTK_STACK (dialog->stack), "sources");
-}
+       for (guint i = 0; (other_row = gtk_list_box_get_row_at_index (list_box, i)) != NULL; i++) {
+               if (other_row == row)
+                       continue;
 
-static gboolean
-key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
-{
-       GsReposDialog *dialog = (GsReposDialog *) widget;
-       GdkKeymap *keymap;
-       GdkModifierType state;
-       gboolean is_rtl;
-
-       if (!gtk_widget_is_visible (dialog->button_back) || !gtk_widget_is_sensitive (dialog->button_back))
-               return GDK_EVENT_PROPAGATE;
-
-       state = event->state;
-       keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget));
-       gdk_keymap_add_virtual_modifiers (keymap, &state);
-       state = state & gtk_accelerator_get_default_mod_mask ();
-       is_rtl = gtk_widget_get_direction (dialog->button_back) == GTK_TEXT_DIR_RTL;
-
-       if ((!is_rtl && state == GDK_MOD1_MASK && event->keyval == GDK_KEY_Left) ||
-           (is_rtl && state == GDK_MOD1_MASK && event->keyval == GDK_KEY_Right) ||
-           event->keyval == GDK_KEY_Back) {
-               gtk_widget_activate (dialog->button_back);
-               return GDK_EVENT_STOP;
+               gs_repos_dialog_row_hide_details (GS_REPOS_DIALOG_ROW (other_row));
        }
-
-       return GDK_EVENT_PROPAGATE;
-}
-
-static gboolean
-button_press_event (GsReposDialog *dialog, GdkEventButton *event)
-{
-       /* Mouse hardware back button is 8 */
-       if (event->button != 8)
-               return GDK_EVENT_PROPAGATE;
-
-       if (!gtk_widget_is_visible (dialog->button_back) || !gtk_widget_is_sensitive (dialog->button_back))
-               return GDK_EVENT_PROPAGATE;
-
-       gtk_widget_activate (dialog->button_back);
-       return GDK_EVENT_STOP;
 }
 
 static gchar *
@@ -599,7 +655,8 @@ gs_repos_dialog_dispose (GObject *object)
 static void
 gs_repos_dialog_init (GsReposDialog *dialog)
 {
-       g_autofree gchar *label_text = NULL;
+       g_autofree gchar *label_description_text = NULL;
+       g_autofree gchar *label_empty_text = NULL;
        g_autofree gchar *os_name = NULL;
        g_autofree gchar *uri = NULL;
        g_autoptr(GString) str = g_string_new (NULL);
@@ -621,13 +678,11 @@ gs_repos_dialog_init (GsReposDialog *dialog)
        g_signal_connect (dialog->listbox, "row-activated",
                          G_CALLBACK (list_row_activated_cb), dialog);
 
-       gtk_list_box_set_header_func (GTK_LIST_BOX (dialog->listbox_apps),
-                                     list_header_func,
-                                     dialog,
-                                     NULL);
-       gtk_list_box_set_sort_func (GTK_LIST_BOX (dialog->listbox_apps),
-                                   list_sort_func,
-                                   dialog, NULL);
+       /* TRANSLATORS: This is the description text displayed in the Software Repositories dialog.
+          %s gets replaced by the name of the actual distro, e.g. Fedora. */
+       label_description_text = g_strdup_printf (_("These repositories supplement the default software 
provided by %s."),
+                                                 os_name);
+       gtk_label_set_text (GTK_LABEL (dialog->label_description), label_description_text);
 
        /* set up third party repository row */
        g_signal_connect (dialog->row_third_party, "notify::switch-active",
@@ -655,24 +710,13 @@ gs_repos_dialog_init (GsReposDialog *dialog)
                                        _("Find out more…"));
        }
        gs_repos_dialog_row_set_comment (GS_REPOS_DIALOG_ROW (dialog->row_third_party), str->str);
-       gs_repos_dialog_row_set_description (GS_REPOS_DIALOG_ROW (dialog->row_third_party), NULL);
        refresh_third_party_repo (dialog);
 
-       /* TRANSLATORS: This is the text displayed in the Software Repositories
-          dialog when no OS-provided software repositories are enabled. %s gets
-          replaced by the name of the actual distro, e.g. Fedora. */
-       label_text = g_strdup_printf (_("Software repositories can be downloaded from the internet. They give 
you access to additional software that is not provided by %s."),
-                                     os_name);
-       gtk_label_set_text (GTK_LABEL (dialog->label_empty), label_text);
-
-       g_signal_connect (dialog->button_back, "clicked",
-                         G_CALLBACK (back_button_cb), dialog);
-
-       /* global keynav and mouse back button */
-       g_signal_connect (dialog, "key-press-event",
-                         G_CALLBACK (key_press_event), NULL);
-       g_signal_connect (dialog, "button-press-event",
-                         G_CALLBACK (button_press_event), NULL);
+       /* TRANSLATORS: This is the description text displayed in the Software Repositories dialog.
+          %s gets replaced by the name of the actual distro, e.g. Fedora. */
+       label_empty_text = g_strdup_printf (_("These repositories supplement the default software provided by 
%s."),
+                                           os_name);
+       gtk_label_set_text (GTK_LABEL (dialog->label_empty), label_empty_text);
 }
 
 static void
@@ -685,16 +729,12 @@ gs_repos_dialog_class_init (GsReposDialogClass *klass)
 
        gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Software/gs-repos-dialog.ui");
 
-       gtk_widget_class_bind_template_child (widget_class, GsReposDialog, button_back);
        gtk_widget_class_bind_template_child (widget_class, GsReposDialog, frame_third_party);
-       gtk_widget_class_bind_template_child (widget_class, GsReposDialog, grid_noresults);
-       gtk_widget_class_bind_template_child (widget_class, GsReposDialog, label2);
+       gtk_widget_class_bind_template_child (widget_class, GsReposDialog, label_description);
        gtk_widget_class_bind_template_child (widget_class, GsReposDialog, label_empty);
        gtk_widget_class_bind_template_child (widget_class, GsReposDialog, label_header);
        gtk_widget_class_bind_template_child (widget_class, GsReposDialog, listbox);
-       gtk_widget_class_bind_template_child (widget_class, GsReposDialog, listbox_apps);
        gtk_widget_class_bind_template_child (widget_class, GsReposDialog, row_third_party);
-       gtk_widget_class_bind_template_child (widget_class, GsReposDialog, scrolledwindow_apps);
        gtk_widget_class_bind_template_child (widget_class, GsReposDialog, spinner);
        gtk_widget_class_bind_template_child (widget_class, GsReposDialog, stack);
 }
diff --git a/src/gs-repos-dialog.ui b/src/gs-repos-dialog.ui
index dd6d3e1c..6a877086 100644
--- a/src/gs-repos-dialog.ui
+++ b/src/gs-repos-dialog.ui
@@ -13,32 +13,6 @@
     <property name="use_header_bar">1</property>
     <child internal-child="headerbar">
       <object class="GtkHeaderBar">
-        <child>
-          <object class="GtkButton" id="button_back">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
-            <child internal-child="accessible">
-              <object class="AtkObject" id="button_back_accessible">
-                <property name="accessible-name" translatable="yes">Go back</property>
-              </object>
-            </child>
-            <style>
-              <class name="image-button"/>
-            </style>
-            <child>
-              <object class="GtkImage" id="image_back">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="icon_name">go-previous-symbolic</property>
-                <property name="icon_size">1</property>
-              </object>
-            </child>
-          </object>
-          <packing>
-            <property name="pack-type">start</property>
-          </packing>
-        </child>
         <child type="title">
           <object class="GtkLabel" id="label_header">
             <property name="can_focus">False</property>
@@ -100,11 +74,12 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="label_empty">
+                  <object class="GtkLabel" id="label_empty_title">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="justify">center</property>
                     <property name="wrap">True</property>
+                    <property name="label" translatable="yes">No Additional Repositories</property>
                     <property name="max_width_chars">40</property>
                     <property name="halign">center</property>
                     <property name="valign">center</property>
@@ -115,6 +90,22 @@
                     <property name="position">1</property>
                   </packing>
                 </child>
+                <child>
+                  <object class="GtkLabel" id="label_empty">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="justify">center</property>
+                    <property name="wrap">True</property>
+                    <property name="max_width_chars">40</property>
+                    <property name="halign">center</property>
+                    <property name="valign">center</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
               </object>
               <packing>
                 <property name="name">empty</property>
@@ -130,57 +121,14 @@
                 <property name="margin_bottom">32</property>
                 <property name="orientation">vertical</property>
                 <property name="spacing">4</property>
-
-                <child>
-                  <object class="GtkFrame" id="frame_third_party">
-                    <property name="visible">True</property>
-                    <property name="shadow_type">in</property>
-                    <property name="halign">fill</property>
-                    <property name="valign">start</property>
-                    <property name="margin_bottom">16</property>
-                    <child>
-                      <object class="GtkListBox" id="listbox_third_party">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="selection_mode">none</property>
-                        <child>
-                          <object class="GsReposDialogRow" id="row_third_party">
-                            <property name="visible">True</property>
-                            <property name="activatable">False</property>
-                          </object>
-                        </child>
-                      </object>
-                    </child>
-                  </object>
-                </child>
                 <child>
-                  <object class="GtkLabel" id="label1">
+                  <object class="GtkLabel" id="label_description">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="xalign">0</property>
-                    <property name="label" translatable="yes">Additional Repositories</property>
-                    <property name="wrap">True</property>
-                    <property name="max_width_chars">30</property>
-                    <attributes>
-                      <attribute name="weight" value="bold"/>
-                    </attributes>
-                    <style>
-                      <class name="dim-label"/>
-                    </style>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkLabel" id="label3">
-                    <property name="visible">False</property> <!-- Bug #754315 -->
-                    <property name="can_focus">False</property>
-                    <property name="xalign">0</property>
-                    <property name="label" translatable="yes">Removing a source will also remove any 
software you have installed from it.</property>
                     <property name="wrap">True</property>
                     <property name="max_width_chars">30</property>
+                    <property name="margin_bottom">16</property>
                     <style>
                       <class name="dim-label"/>
                     </style>
@@ -191,133 +139,43 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkScrolledWindow" id="scrolledwindow">
+                  <object class="GtkFrame" id="frame_third_party">
                     <property name="visible">True</property>
-                    <property name="can_focus">True</property>
-                    <property name="hscrollbar_policy">never</property>
-                    <property name="vscrollbar_policy">automatic</property>
-                    <property name="shadow_type">none</property>
-                    <property name="margin_top">9</property>
+                    <property name="shadow_type">in</property>
+                    <property name="halign">fill</property>
+                    <property name="valign">start</property>
+                    <property name="margin_bottom">16</property>
                     <child>
-                      <object class="GtkFrame" id="frame">
+                      <object class="GtkListBox" id="listbox_third_party">
                         <property name="visible">True</property>
-                        <property name="shadow_type">in</property>
-                        <property name="halign">fill</property>
-                        <property name="valign">start</property>
+                        <property name="can_focus">False</property>
+                        <property name="selection_mode">none</property>
                         <child>
-                          <object class="GtkListBox" id="listbox">
+                          <object class="GsReposDialogRow" id="row_third_party">
                             <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="selection_mode">none</property>
+                            <property name="activatable">False</property>
                           </object>
                         </child>
                       </object>
                     </child>
                   </object>
-                  <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                  </packing>
                 </child>
-              </object>
-              <packing>
-                <property name="name">sources</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkBox" id="box2">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="margin_start">16</property>
-                <property name="margin_end">16</property>
-                <property name="margin_top">16</property>
-                <property name="margin_bottom">16</property>
-                <property name="orientation">vertical</property>
-                <property name="spacing">4</property>
                 <child>
-                  <object class="GtkGrid" id="grid_noresults">
-                    <property name="visible">True</property>
-                    <property name="hexpand">True</property>
-                    <property name="vexpand">True</property>
-                    <property name="halign">center</property>
-                    <property name="valign">center</property>
-                    <property name="row-spacing">12</property>
-                    <property name="column-spacing">12</property>
-                    <style>
-                      <class name="dim-label"/>
-                    </style>
-                    <child>
-                      <object class="GtkImage" id="image_noresults">
-                        <property name="visible">True</property>
-                        <property name="icon_name">org.gnome.Software-symbolic</property>
-                        <property name="pixel-size">64</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left-attach">0</property>
-                        <property name="top-attach">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="label_noresults">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">No software installed from this 
source</property>
-                        <property name="halign">center</property>
-                        <property name="valign">center</property>
-                        <property name="justify">center</property>
-                        <property name="wrap">True</property>
-                        <property name="max_width_chars">25</property>
-                        <attributes>
-                          <attribute name="scale" value="1.2"/>
-                        </attributes>
-                      </object>
-                      <packing>
-                        <property name="left-attach">0</property>
-                        <property name="top-attach">1</property>
-                      </packing>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkLabel" id="label2">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="xalign">0.5</property>
-                    <property name="label" translatable="yes">Installed from this Source</property>
-                    <property name="wrap">True</property>
-                    <property name="max_width_chars">30</property>
-                    <attributes>
-                      <attribute name="weight" value="bold"/>
-                    </attributes>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkScrolledWindow" id="scrolledwindow_apps">
+                  <object class="GtkScrolledWindow" id="scrolledwindow">
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
                     <property name="hscrollbar_policy">never</property>
                     <property name="vscrollbar_policy">automatic</property>
                     <property name="shadow_type">none</property>
+                    <property name="margin_top">9</property>
                     <child>
-                      <object class="GtkFrame" id="frame_apps">
+                      <object class="GtkFrame" id="frame">
                         <property name="visible">True</property>
                         <property name="shadow_type">in</property>
                         <property name="halign">fill</property>
                         <property name="valign">start</property>
                         <child>
-                          <object class="GtkListBox" id="listbox_apps">
+                          <object class="GtkListBox" id="listbox">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
                             <property name="selection_mode">none</property>
@@ -329,168 +187,11 @@
                   <packing>
                     <property name="expand">True</property>
                     <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkLabel" id="label_details">
-                    <property name="can_focus">False</property>
-                    <property name="xalign">0</property>
-                    <property name="label" translatable="yes">Source Details</property>
-                    <property name="wrap">True</property>
-                    <property name="max_width_chars">30</property>
-                    <attributes>
-                      <attribute name="weight" value="bold"/>
-                    </attributes>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">2</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkGrid" id="grid_details">
-                    <property name="can_focus">False</property>
-                    <property name="halign">center</property>
-                    <property name="valign">start</property>
-                    <property name="row_spacing">3</property>
-                    <property name="column_spacing">24</property>
-                    <property name="row_homogeneous">True</property>
-                    <child>
-                      <object class="GtkLabel" id="label_header_version">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="label" translatable="yes">Version</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">0</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="label_version">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="label">0.12.3</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">0</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="label_header_lastchecked">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="label" translatable="yes">Last Checked</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">2</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="label_header_added">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="label" translatable="yes">Added</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">1</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="label_header_website">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="label" translatable="yes">Website</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">3</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="label_added">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="label">May 12, 2012</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">1</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="label_website">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="label">superrepo.com</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">3</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="label_lastchecked">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="label">January 30, 2014</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">2</property>
-                        <property name="width">1</property>
-                        <property name="height">1</property>
-                      </packing>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">3</property>
                   </packing>
                 </child>
               </object>
               <packing>
-                <property name="name">details</property>
+                <property name="name">sources</property>
               </packing>
             </child>
           </object>


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