[gnome-software] Add a dialog that can be used to get authentication data



commit 94fee7ee93dee72bcfcca421de3859080bd66a01
Author: Richard Hughes <richard hughsie com>
Date:   Fri Jun 10 15:51:49 2016 +0100

    Add a dialog that can be used to get authentication data

 po/POTFILES.in                   |    2 +
 src/Makefile.am                  |    3 +
 src/gnome-software.gresource.xml |    1 +
 src/gs-auth-dialog.c             |  332 +++++++++++++++++++++++++++++++++++
 src/gs-auth-dialog.h             |   45 +++++
 src/gs-auth-dialog.ui            |  360 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 743 insertions(+), 0 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index c1800b6..f87752f 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -12,6 +12,8 @@ src/gs-application.c
 src/gs-app-row.c
 [type: gettext/glade]src/gs-app-row.ui
 src/gs-app-tile.c
+src/gs-auth-dialog.c
+[type: gettext/glade]src/gs-auth-dialog.ui
 src/gs-category.c
 src/gs-dbus-helper.c
 src/gs-feature-tile.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 3fbb5fa..86e2e7b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -49,6 +49,7 @@ UI_FILES =                                            \
        gs-app-folder-dialog.ui                         \
        gs-app-row.ui                                   \
        gs-app-tile.ui                                  \
+       gs-auth-dialog.ui                               \
        gs-category-tile.ui                             \
        gs-feature-tile.ui                              \
        gs-first-run-dialog.ui                          \
@@ -142,6 +143,8 @@ gnome_software_SOURCES =                            \
        gs-app-list-private.h                           \
        gs-auth.c                                       \
        gs-auth.h                                       \
+       gs-auth-dialog.c                                \
+       gs-auth-dialog.h                                \
        gs-category.c                                   \
        gs-category.h                                   \
        gs-category-private.h                           \
diff --git a/src/gnome-software.gresource.xml b/src/gnome-software.gresource.xml
index 773ce8e..23a127a 100644
--- a/src/gnome-software.gresource.xml
+++ b/src/gnome-software.gresource.xml
@@ -7,6 +7,7 @@
   <file preprocess="xml-stripblanks">gs-app-folder-dialog.ui</file>
   <file preprocess="xml-stripblanks">gs-app-row.ui</file>
   <file preprocess="xml-stripblanks">gs-app-tile.ui</file>
+  <file preprocess="xml-stripblanks">gs-auth-dialog.ui</file>
   <file preprocess="xml-stripblanks">gs-category-tile.ui</file>
   <file preprocess="xml-stripblanks">gs-feature-tile.ui</file>
   <file preprocess="xml-stripblanks">gs-first-run-dialog.ui</file>
diff --git a/src/gs-auth-dialog.c b/src/gs-auth-dialog.c
new file mode 100644
index 0000000..62c1681
--- /dev/null
+++ b/src/gs-auth-dialog.c
@@ -0,0 +1,332 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "gs-auth.h"
+#include "gs-auth-dialog.h"
+#include "gs-common.h"
+
+struct _GsAuthDialog
+{
+       GtkDialog        parent_instance;
+
+       GCancellable    *cancellable;
+       GsPluginLoader  *plugin_loader;
+       GsApp           *app;
+       GsAuth          *auth;
+       GtkWidget       *box_error;
+       GtkWidget       *button_cancel;
+       GtkWidget       *button_continue;
+       GtkWidget       *checkbutton_remember;
+       GtkWidget       *entry_password;
+       GtkWidget       *entry_pin;
+       GtkWidget       *entry_username;
+       GtkWidget       *image_vendor;
+       GtkWidget       *label_error;
+       GtkWidget       *label_title;
+       GtkWidget       *radiobutton_already;
+       GtkWidget       *radiobutton_lost_pwd;
+       GtkWidget       *radiobutton_register;
+       GtkWidget       *stack;
+};
+
+G_DEFINE_TYPE (GsAuthDialog, gs_auth_dialog, GTK_TYPE_DIALOG)
+
+static void
+gs_auth_dialog_check_ui (GsAuthDialog *dialog)
+{
+       g_autofree gchar *title = NULL;
+       const gchar *tmp;
+       const gchar *username = gtk_entry_get_text (GTK_ENTRY (dialog->entry_username));
+       const gchar *password = gtk_entry_get_text (GTK_ENTRY (dialog->entry_password));
+
+       /* set the header */
+       tmp = gs_auth_get_provider_name (dialog->auth);
+       if (tmp == NULL) {
+               /* TRANSLATORS: this is when the service name is not known */
+               title = g_strdup (_("To continue you need to sign in."));
+               gtk_label_set_label (GTK_LABEL (dialog->label_title), title);
+       } else {
+               /* TRANSLATORS: the %s is a service name, e.g. "Ubuntu One" */
+               title = g_strdup_printf (_("To continue you need to sign in to %s."), tmp);
+               gtk_label_set_label (GTK_LABEL (dialog->label_title), title);
+       }
+
+       /* set the vendor image */
+       tmp = gs_auth_get_provider_logo (dialog->auth);
+       if (tmp == NULL) {
+               gtk_widget_hide (dialog->image_vendor);
+       } else {
+               gtk_image_set_from_file (GTK_IMAGE (dialog->image_vendor), tmp);
+               gtk_widget_show (dialog->image_vendor);
+       }
+
+       /* need username and password to continue for known account */
+       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->radiobutton_already))) {
+               gtk_widget_set_sensitive (dialog->button_continue,
+                                         username[0] != '\0' && password[0] != '\0');
+               gtk_widget_set_sensitive (dialog->checkbutton_remember, TRUE);
+       } else {
+               gtk_entry_set_text (GTK_ENTRY (dialog->entry_password), "");
+               gtk_widget_set_sensitive (dialog->button_continue,
+                                         username[0] != '\0');
+               gtk_widget_set_sensitive (dialog->checkbutton_remember, FALSE);
+       }
+}
+
+static void
+gs_auth_dialog_cancel_button_cb (GtkWidget *widget, GsAuthDialog *dialog)
+{
+       gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
+}
+
+static void
+gs_auth_dialog_authenticate_cb (GObject *source,
+                               GAsyncResult *res,
+                               gpointer user_data)
+{
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
+       GsAuthDialog *dialog = GS_AUTH_DIALOG (user_data);
+       g_autoptr(GError) error = NULL;
+
+       /* we failed */
+       if (!gs_plugin_loader_app_action_finish (plugin_loader, res, &error)) {
+               const gchar *url;
+
+               /* have we been given a link */
+               url = gs_utils_get_error_value (error);
+               if (url != NULL) {
+                       g_autoptr(GError) error_local = NULL;
+                       g_debug ("showing link in: %s", error->message);
+                       if (!gtk_show_uri (NULL, url, GDK_CURRENT_TIME, &error_local)) {
+                               g_warning ("failed to show URI %s: %s",
+                                          url, error_local->message);
+                       }
+                       return;
+               }
+
+               g_warning ("failed to authenticate: %s", error->message);
+               gtk_label_set_label (GTK_LABEL (dialog->label_error), error->message);
+               gtk_widget_set_visible (dialog->box_error, TRUE);
+               return;
+       }
+
+       /* we didn't get authenticated */
+       if (!gs_auth_has_flag (dialog->auth, GS_AUTH_FLAG_VALID)) {
+               return;
+       }
+
+       /* success */
+       gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+}
+
+static void
+gs_auth_dialog_continue_button_cb (GtkWidget *widget, GsAuthDialog *dialog)
+{
+       GsPluginLoaderAction action = GS_AUTH_ACTION_LOGIN;
+
+       /* alternate actions */
+       if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->radiobutton_lost_pwd)))
+               action = GS_AUTH_ACTION_LOST_PASSWORD;
+       else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->radiobutton_register)))
+               action = GS_AUTH_ACTION_REGISTER;
+       gs_plugin_loader_auth_action_async (dialog->plugin_loader,
+                                           dialog->auth,
+                                           action,
+                                           dialog->cancellable,
+                                           gs_auth_dialog_authenticate_cb,
+                                           dialog);
+}
+
+static void
+gs_auth_dialog_setup (GsAuthDialog *dialog)
+{
+
+       /* update widgets with known values */
+       if (gs_auth_get_username (dialog->auth) != NULL) {
+               gtk_entry_set_text (GTK_ENTRY (dialog->entry_username),
+                                   gs_auth_get_username (dialog->auth));
+       }
+       if (gs_auth_get_password (dialog->auth) != NULL) {
+               gtk_entry_set_text (GTK_ENTRY (dialog->entry_password),
+                                   gs_auth_get_password (dialog->auth));
+       }
+
+       /* refresh UI */
+       gs_auth_dialog_check_ui (dialog);
+}
+
+static void
+gs_auth_dialog_notify_username_cb (GtkEntry *entry,
+                                  GParamSpec *pspec,
+                                  GsAuthDialog *dialog)
+{
+       gs_auth_set_username (dialog->auth, gtk_entry_get_text (entry));
+       gs_auth_dialog_check_ui (dialog);
+}
+
+static void
+gs_auth_dialog_notify_password_cb (GtkEntry *entry,
+                                  GParamSpec *pspec,
+                                  GsAuthDialog *dialog)
+{
+       gs_auth_set_password (dialog->auth, gtk_entry_get_text (entry));
+       gs_auth_dialog_check_ui (dialog);
+}
+
+static void
+gs_auth_dialog_notify_pin_cb (GtkEntry *entry,
+                             GParamSpec *pspec,
+                             GsAuthDialog *dialog)
+{
+       gs_auth_set_pin (dialog->auth, gtk_entry_get_text (entry));
+       gs_auth_dialog_check_ui (dialog);
+}
+
+static void
+gs_auth_dialog_toggled_cb (GtkToggleButton *togglebutton, GsAuthDialog *dialog)
+{
+       gs_auth_dialog_check_ui (dialog);
+}
+
+static void
+gs_auth_dialog_remember_cb (GtkToggleButton *togglebutton, GsAuthDialog *dialog)
+{
+       if (gtk_toggle_button_get_active (togglebutton))
+               gs_auth_add_flags (dialog->auth, GS_AUTH_FLAG_REMEMBER);
+       gs_auth_dialog_check_ui (dialog);
+}
+
+static void
+gs_auth_dialog_dispose (GObject *object)
+{
+       GsAuthDialog *dialog = GS_AUTH_DIALOG (object);
+
+       g_clear_object (&dialog->plugin_loader);
+       g_clear_object (&dialog->app);
+       g_clear_object (&dialog->auth);
+
+       if (dialog->cancellable != NULL) {
+               g_cancellable_cancel (dialog->cancellable);
+               g_clear_object (&dialog->cancellable);
+       }
+
+       G_OBJECT_CLASS (gs_auth_dialog_parent_class)->dispose (object);
+}
+
+static void
+gs_auth_dialog_init (GsAuthDialog *dialog)
+{
+       gtk_widget_init_template (GTK_WIDGET (dialog));
+
+       dialog->cancellable = g_cancellable_new ();
+
+       g_signal_connect (dialog->entry_username, "notify::text",
+                         G_CALLBACK (gs_auth_dialog_notify_username_cb), dialog);
+       g_signal_connect (dialog->entry_password, "notify::text",
+                         G_CALLBACK (gs_auth_dialog_notify_password_cb), dialog);
+       g_signal_connect (dialog->entry_pin, "notify::text",
+                         G_CALLBACK (gs_auth_dialog_notify_pin_cb), dialog);
+       g_signal_connect (dialog->checkbutton_remember, "toggled",
+                         G_CALLBACK (gs_auth_dialog_remember_cb), dialog);
+       g_signal_connect (dialog->radiobutton_already, "toggled",
+                         G_CALLBACK (gs_auth_dialog_toggled_cb), dialog);
+       g_signal_connect (dialog->radiobutton_register, "toggled",
+                         G_CALLBACK (gs_auth_dialog_toggled_cb), dialog);
+       g_signal_connect (dialog->radiobutton_lost_pwd, "toggled",
+                         G_CALLBACK (gs_auth_dialog_toggled_cb), dialog);
+       g_signal_connect (dialog->button_cancel, "clicked",
+                         G_CALLBACK (gs_auth_dialog_cancel_button_cb), dialog);
+       g_signal_connect (dialog->button_continue, "clicked",
+                         G_CALLBACK (gs_auth_dialog_continue_button_cb), dialog);
+}
+
+static void
+gs_auth_dialog_class_init (GsAuthDialogClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+       object_class->dispose = gs_auth_dialog_dispose;
+
+       gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Software/gs-auth-dialog.ui");
+
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, box_error);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, button_cancel);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, button_continue);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, checkbutton_remember);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, entry_password);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, entry_pin);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, entry_username);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, image_vendor);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, label_error);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, label_title);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, radiobutton_already);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, radiobutton_lost_pwd);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, radiobutton_register);
+       gtk_widget_class_bind_template_child (widget_class, GsAuthDialog, stack);
+}
+
+GtkWidget *
+gs_auth_dialog_new (GsPluginLoader *plugin_loader,
+                   GsApp *app,
+                   const gchar *provider_id,
+                   GError **error)
+{
+       GsAuthDialog *dialog;
+       GsAuth *auth;
+
+       /* get the authentication provider */
+       if (provider_id == NULL) {
+               g_set_error (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_FAILED,
+                            "no auth-provider given for %s",
+                            gs_app_get_id (app));
+               return NULL;
+       }
+       auth = gs_plugin_loader_get_auth_by_id (plugin_loader, provider_id);
+       if (auth == NULL) {
+               g_set_error (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_NOT_SUPPORTED,
+                            "no auth-provider %s for %s",
+                            provider_id, gs_app_get_id (app));
+               return NULL;
+       }
+
+       /* create dialog */
+       dialog = g_object_new (GS_TYPE_AUTH_DIALOG,
+                              "use-header-bar", TRUE,
+                              NULL);
+       dialog->plugin_loader = g_object_ref (plugin_loader);
+       dialog->app = g_object_ref (app);
+       dialog->auth = g_object_ref (auth);
+       gs_auth_dialog_setup (dialog);
+
+       return GTK_WIDGET (dialog);
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-auth-dialog.h b/src/gs-auth-dialog.h
new file mode 100644
index 0000000..5487c2b
--- /dev/null
+++ b/src/gs-auth-dialog.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef GS_AUTH_DIALOG_H
+#define GS_AUTH_DIALOG_H
+
+#include <gtk/gtk.h>
+
+#include "gs-app.h"
+#include "gs-plugin-loader.h"
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_AUTH_DIALOG (gs_auth_dialog_get_type ())
+
+G_DECLARE_FINAL_TYPE (GsAuthDialog, gs_auth_dialog, GS, AUTH_DIALOG, GtkDialog)
+
+GtkWidget      *gs_auth_dialog_new             (GsPluginLoader *plugin_loader,
+                                                GsApp          *app,
+                                                const gchar    *provider_id,
+                                                GError         **error);
+
+G_END_DECLS
+
+#endif /* GS_AUTH_DIALOG_H */
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-auth-dialog.ui b/src/gs-auth-dialog.ui
new file mode 100644
index 0000000..ce5a411
--- /dev/null
+++ b/src/gs-auth-dialog.ui
@@ -0,0 +1,360 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.20.0 -->
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <template class="GsAuthDialog" parent="GtkDialog">
+    <property name="can_focus">False</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="type_hint">dialog</property>
+    <property name="deletable">False</property>
+    <child internal-child="vbox">
+      <object class="GtkBox">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox">
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="border_width">21</property>
+            <property name="row_spacing">9</property>
+            <property name="column_spacing">21</property>
+            <child>
+              <object class="GtkStack" id="stack">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="transition_type">crossfade</property>
+                <child>
+                  <object class="GtkGrid">
+                    <property name="name">intro</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="halign">start</property>
+                    <property name="valign">start</property>
+                    <property name="row_spacing">9</property>
+                    <property name="column_spacing">9</property>
+                    <child>
+                      <object class="GtkLabel" id="label_title">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="halign">start</property>
+                        <property name="label">To continue you need an %NAME% account.</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="halign">end</property>
+                        <property name="label" translatable="yes">Email address</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="entry_username">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="margin_bottom">15</property>
+                        <property name="input_purpose">email</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkRadioButton" id="radiobutton_already">
+                        <property name="label" translatable="yes">I have an account already</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="halign">start</property>
+                        <property name="active">True</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">2</property>
+                        <property name="width">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="halign">end</property>
+                        <property name="label" translatable="yes">Password</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="entry_password">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="input_purpose">password</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkRadioButton" id="radiobutton_register">
+                        <property name="label" translatable="yes">I want to register for an account 
now</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="halign">start</property>
+                        <property name="active">True</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">radiobutton_already</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">5</property>
+                        <property name="width">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkRadioButton" id="radiobutton_lost_pwd">
+                        <property name="label" translatable="yes">I have forgotten my password</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="halign">start</property>
+                        <property name="active">True</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">radiobutton_already</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">6</property>
+                        <property name="width">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">4</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="checkbutton_remember">
+                        <property name="label" translatable="yes">Sign in automatically next time</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="active">True</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">4</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="name">page0</property>
+                    <property name="title" translatable="yes">page0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkGrid">
+                    <property name="name">2fa</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="row_spacing">9</property>
+                    <property name="column_spacing">9</property>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="halign">start</property>
+                        <property name="label" translatable="yes">Enter your one-time pin for two-factor 
authentication.</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="halign">end</property>
+                        <property name="label" translatable="yes">PIN</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkEntry" id="entry_pin">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="input_purpose">password</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="name">page1</property>
+                    <property name="title" translatable="yes">page1</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkImage" id="image_vendor">
+                <property name="can_focus">False</property>
+                <property name="halign">start</property>
+                <property name="valign">start</property>
+                <property name="stock">gtk-floppy</property>
+                <property name="icon_size">6</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+                <property name="height">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="box_error">
+                <property name="can_focus">False</property>
+                <property name="spacing">6</property>
+                <child>
+                  <object class="GtkImage">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="halign">end</property>
+                    <property name="valign">start</property>
+                    <property name="icon_name">dialog-warning-symbolic</property>
+                    <property name="use_fallback">True</property>
+                    <property name="icon_size">5</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label_error">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="halign">start</property>
+                    <property name="label">The supplied credentials were not correct</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child type="titlebar">
+      <object class="GtkHeaderBar">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="title">Authenticate</property>
+        <child>
+          <object class="GtkButton" id="button_cancel">
+            <property name="label">gtk-cancel</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="use_stock">True</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkButton" id="button_continue">
+            <property name="label" translatable="yes">Continue</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <style>
+              <class name="suggested-action"/>
+            </style>
+          </object>
+          <packing>
+            <property name="pack_type">end</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </template>
+  <object class="GtkSizeGroup" id="sizegroup_buttons">
+    <widgets>
+      <widget name="button_continue"/>
+      <widget name="button_cancel"/>
+    </widgets>
+  </object>
+</interface>


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