[gnome-initial-setup/wip/pwithnall/misc-fixes: 54/70] password: Add eye icons to toggle password visibility




commit 3ceb67b2c41703f05da8bcb77d6dabaef51eaed7
Author: Philip Chimento <philip endlessm com>
Date:   Tue Aug 6 11:45:19 2019 -0700

    password: Add eye icons to toggle password visibility
    
    User research shows that allowing users to view the password that
    they've typed, reduces how often passwords are forgotten, especially for
    users who are unaccustomed to creating and typing passwords.
    
    https://www.nngroup.com/articles/password-creation/ has some more
    interesting reading on this.
    
    This commit adds a "peek" icon to the password entries based on the one
    in GTK 4.
    
    In most prior art, the peek icons are placed in the secondary position
    and we therefore remove the caps lock warning icon and the weak password
    warning icon. The caps lock warning, for better or for worse, seems to
    be considered obsolete by upstream if there is a peek icon. The weak
    password warning is redundant since there is already text below the
    entry saying the same thing. The confirm entry also has a checkmark icon
    shown when the passwords match, which we move outside of the entry, to
    the right-hand side of it.
    
    https://gitlab.gnome.org/GNOME/gnome-initial-setup/issues/81
    https://phabricator.endlessm.com/T27460

 .../pages/password/gis-password-page.c             | 60 ++++++++++++++++------
 .../pages/password/gis-password-page.ui            | 19 +++++++
 .../scalable/status/eye-not-looking-symbolic.svg   |  3 ++
 .../status/eye-open-negative-filled-symbolic.svg   | 26 ++++++++++
 .../pages/password/password.gresource.xml          |  2 +
 5 files changed, 94 insertions(+), 16 deletions(-)
---
diff --git a/gnome-initial-setup/pages/password/gis-password-page.c 
b/gnome-initial-setup/pages/password/gis-password-page.c
index 097befc4..c5fac592 100644
--- a/gnome-initial-setup/pages/password/gis-password-page.c
+++ b/gnome-initial-setup/pages/password/gis-password-page.c
@@ -46,6 +46,7 @@ struct _GisPasswordPagePrivate
   GtkWidget *password_strength;
   GtkWidget *password_explanation;
   GtkWidget *confirm_explanation;
+  GtkWidget *confirm_checkmark;
   GtkWidget *reminder_entry;
   GtkWidget *header;
 
@@ -255,20 +256,18 @@ validate (GisPasswordPage *page)
   priv->valid_confirm = FALSE;
 
   priv->valid_password = (strlen (password) && strength_level > 1);
-  if (priv->valid_password) {
-    set_entry_validation_checkmark (GTK_ENTRY (priv->password_entry));
-    clear_entry_validation_error (GTK_ENTRY (priv->password_entry));
-  } else {
-    set_entry_validation_error (GTK_ENTRY (priv->password_entry), _("This is a weak password."));
-  }
 
   if (strlen (password) > 0 && strlen (verify) > 0) {
     priv->valid_confirm = (strcmp (password, verify) == 0);
     if (!priv->valid_confirm) {
       gtk_label_set_label (GTK_LABEL (priv->confirm_explanation), _("The passwords do not match."));
+      gtk_image_set_from_icon_name (GTK_IMAGE (priv->confirm_checkmark), NULL,
+                                    GTK_ICON_SIZE_BUTTON);
     }
     else {
-      set_entry_validation_checkmark (GTK_ENTRY (priv->confirm_entry));
+      gtk_image_set_from_icon_name (GTK_IMAGE (priv->confirm_checkmark),
+                                    "object-select-symbolic",
+                                    GTK_ICON_SIZE_BUTTON);
     }
   }
 
@@ -318,6 +317,37 @@ on_focusout (GisPasswordPage *page)
   return FALSE;
 }
 
+static void
+on_entry_icon_press (GtkEntry            *entry,
+                     GtkEntryIconPosition icon_pos,
+                     GdkEvent            *event G_GNUC_UNUSED,
+                     gpointer             data G_GNUC_UNUSED)
+{
+  if (icon_pos != GTK_ENTRY_ICON_SECONDARY)
+    return;
+
+  /* We show the eye icon with a slash through it when the password is not
+   * visible, which is consistent with how gnome-shell works in
+   * StPasswordEntry.
+   */
+  if (gtk_entry_get_visibility (entry))
+    {
+      gtk_entry_set_visibility (entry, FALSE);
+      gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY,
+                                         "eye-not-looking-symbolic");
+      gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY,
+                                       _("Show password"));
+    }
+  else
+    {
+      gtk_entry_set_visibility (entry, TRUE);
+      gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY,
+                                         "eye-open-negative-filled-symbolic");
+      gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY,
+                                       _("Hide password"));
+    }
+}
+
 static void
 reminder_changed (GtkWidget       *w,
                   GParamSpec      *pspec,
@@ -333,9 +363,6 @@ password_changed (GtkWidget      *w,
 {
   GisPasswordPagePrivate *priv = gis_password_page_get_instance_private (page);
 
-  clear_entry_validation_error (GTK_ENTRY (w));
-  clear_entry_validation_error (GTK_ENTRY (priv->confirm_entry));
-
   priv->valid_password = FALSE;
   update_page_validation (page);
 
@@ -351,8 +378,6 @@ confirm_changed (GtkWidget      *w,
 {
   GisPasswordPagePrivate *priv = gis_password_page_get_instance_private (page);
 
-  clear_entry_validation_error (GTK_ENTRY (w));
-
   priv->valid_confirm = FALSE;
   update_page_validation (page);
 
@@ -371,10 +396,7 @@ username_or_passwordless_changed (GisPasswordPage *page)
   if (priv->parent_mode || (priv->username && !passwordless))
     gtk_widget_show (GTK_WIDGET (page));
   else
-    gtk_widget_hide (GTK_WIDGET (page));  
-
-  clear_entry_validation_error (GTK_ENTRY (priv->password_entry));
-  clear_entry_validation_error (GTK_ENTRY (priv->confirm_entry));
+    gtk_widget_hide (GTK_WIDGET (page));
 
   validate (page);
 }
@@ -414,6 +436,9 @@ gis_password_page_constructed (GObject *object)
                             G_CALLBACK (on_focusout), page);
   g_signal_connect_swapped (priv->password_entry, "activate",
                             G_CALLBACK (confirm), page);
+  g_signal_connect (priv->password_entry, "icon-press",
+                    G_CALLBACK (on_entry_icon_press), NULL);
+
   g_signal_connect (priv->reminder_entry, "notify::text",
                       G_CALLBACK (reminder_changed), page);
 
@@ -423,6 +448,8 @@ gis_password_page_constructed (GObject *object)
                             G_CALLBACK (on_focusout), page);
   g_signal_connect_swapped (priv->confirm_entry, "activate",
                             G_CALLBACK (confirm), page);
+  g_signal_connect (priv->confirm_entry, "icon-press",
+                    G_CALLBACK (on_entry_icon_press), NULL);
 
   g_signal_connect_swapped (GIS_PAGE (page)->driver, "notify::username",
                             G_CALLBACK (username_or_passwordless_changed), page);
@@ -536,6 +563,7 @@ gis_password_page_class_init (GisPasswordPageClass *klass)
   gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisPasswordPage, 
password_strength);
   gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisPasswordPage, 
password_explanation);
   gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisPasswordPage, 
confirm_explanation);
+  gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisPasswordPage, 
confirm_checkmark);
   gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisPasswordPage, reminder_entry);
   gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisPasswordPage, header);
 
diff --git a/gnome-initial-setup/pages/password/gis-password-page.ui 
b/gnome-initial-setup/pages/password/gis-password-page.ui
index cb991728..dd0faa59 100644
--- a/gnome-initial-setup/pages/password/gis-password-page.ui
+++ b/gnome-initial-setup/pages/password/gis-password-page.ui
@@ -49,6 +49,9 @@
                 <property name="visibility">False</property>
                 <property name="invisible_char">●</property>
                 <property name="invisible_char_set">True</property>
+                <property name="secondary_icon_name">eye-not-looking-symbolic</property>
+                <property name="secondary_icon_tooltip_text">Show password</property>
+                <property name="caps_lock_warning">False</property>
               </object>
               <packing>
                 <property name="left_attach">1</property>
@@ -81,6 +84,9 @@
                 <property name="visibility">False</property>
                 <property name="invisible_char">●</property>
                 <property name="invisible_char_set">True</property>
+                <property name="secondary_icon_name">eye-not-looking-symbolic</property>
+                <property name="secondary_icon_tooltip_text">Show password</property>
+                <property name="caps_lock_warning">False</property>
               </object>
               <packing>
                 <property name="left_attach">1</property>
@@ -89,6 +95,19 @@
                 <property name="height">1</property>
               </packing>
             </child>
+            <child>
+              <object class="GtkImage" id="confirm_checkmark">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="width_request">16</property>
+              </object>
+              <packing>
+                <property name="left_attach">2</property>
+                <property name="top_attach">3</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
             <child>
               <object class="GtkLevelBar" id="password_strength">
                 <property name="visible">True</property>
diff --git a/gnome-initial-setup/pages/password/icons/scalable/status/eye-not-looking-symbolic.svg 
b/gnome-initial-setup/pages/password/icons/scalable/status/eye-not-looking-symbolic.svg
new file mode 100644
index 00000000..ad75f422
--- /dev/null
+++ b/gnome-initial-setup/pages/password/icons/scalable/status/eye-not-looking-symbolic.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg"; width="16" height="16">
+    <path d="M13.98 1.99a1 1 0 0 0-.687.303l-.984.984A8 8 0 0 0 8 2 8 8 0 0 0 .262 8.01a8 8 0 0 0 2.943 
4.37l-.912.913a1 1 0 1 0 1.414 1.414l11-11a1 1 0 0 0-.727-1.717zM8 4a4 4 0 0 1 2.611.974l-1.42 1.42A2 2 0 0 0 
8 6a2 2 0 0 0-2 2 2 2 0 0 0 .396 1.19l-1.42 1.42A4 4 0 0 1 4 8a4 4 0 0 1 4-4zm7.03 2.209l-3.344 3.343a4 4 0 0 
1-2.127 2.127l-2.28 2.28a8 8 0 0 0 .721.04 8 8 0 0 0 7.738-6.01 8 8 0 0 0-.709-1.78zm-7.53.79a.5.5 0 0 1 
.5.5.5.5 0 0 1-.5.5.5.5 0 0 1-.5-.5.5.5 0 0 1 .5-.5z" fill="#2e3436"/>
+</svg>
diff --git a/gnome-initial-setup/pages/password/icons/scalable/status/eye-open-negative-filled-symbolic.svg 
b/gnome-initial-setup/pages/password/icons/scalable/status/eye-open-negative-filled-symbolic.svg
new file mode 100644
index 00000000..4c9dc284
--- /dev/null
+++ b/gnome-initial-setup/pages/password/icons/scalable/status/eye-open-negative-filled-symbolic.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"; xmlns:dc="http://purl.org/dc/elements/1.1/"; 
xmlns:cc="http://creativecommons.org/ns#"; xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"; 
xmlns:svg="http://www.w3.org/2000/svg"; xmlns="http://www.w3.org/2000/svg"; width="16" viewBox="0 0 16 16" 
version="1.1" id="svg7384" height="16">
+  <metadata id="metadata90">
+    <rdf:RDF>
+      <cc:Work rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+        <dc:title>Gnome Symbolic Icon Theme</dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <title id="title9167">Gnome Symbolic Icon Theme</title>
+  <defs id="defs7386">
+    <linearGradient osb:paint="solid" id="linearGradient7212">
+      <stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop7214"/>
+    </linearGradient>
+  </defs>
+  <g transform="translate(-341.0002,-13.000323)" style="display:inline" id="layer9"/>
+  <g transform="translate(-100,-380.00032)" id="layer1"/>
+  <g transform="translate(-100,-380.00032)" style="display:inline" id="layer10">
+    <path d="m 108,382 a 8,8 0 0 0 -7.73828,6.00977 A 8,8 0 0 0 108,394 8,8 0 0 0 115.73828,387.99023 8,8 0 
0 0 108,382 Z m 0,2 a 4,4 0 0 1 4,4 4,4 0 0 1 -4,4 4,4 0 0 1 -4,-4 4,4 0 0 1 4,-4 z" id="path2314" 
style="opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"/>
+    <path id="path2318" d="m 110,388.00003 a 2,2 0 0 1 -2,2 2,2 0 0 1 -2,-2 2,2 0 0 1 2,-2 2,2 0 0 1 2,2 z" 
style="vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"/>
+  </g>
+  <g transform="translate(-100,-380.00032)" id="g6387"/>
+  <g transform="translate(-100,-380.00032)" id="layer11"/>
+</svg>
diff --git a/gnome-initial-setup/pages/password/password.gresource.xml 
b/gnome-initial-setup/pages/password/password.gresource.xml
index 22cad986..60ed60a2 100644
--- a/gnome-initial-setup/pages/password/password.gresource.xml
+++ b/gnome-initial-setup/pages/password/password.gresource.xml
@@ -3,5 +3,7 @@
   <gresource prefix="/org/gnome/initial-setup">
     <file preprocess="xml-stripblanks" alias="gis-password-page.ui">gis-password-page.ui</file>
     <file alias="gis-password-page.css">gis-password-page.css</file>
+    <file preprocess="xml-stripblanks">icons/scalable/status/eye-not-looking-symbolic.svg</file>
+    <file preprocess="xml-stripblanks">icons/scalable/status/eye-open-negative-filled-symbolic.svg</file>
   </gresource>
 </gresources>


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