[gnome-initial-setup] password: design changes



commit 59be1ba5fec4a40229704a39c6f305ab3f04030d
Author: Ondrej Holy <oholy redhat com>
Date:   Wed Apr 16 16:00:22 2014 +0200

    password: design changes
    
    Design changes are done according mockup. It corresponds with
    User Accounts panel in Gnome Control Center.
    
    Use checkmarks to indicate correct values instead of checkmarks.
    Alignment of hints is changed. Hints are dimmed and dynamic.
    User-friendy passwords hints are introduced.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=702129

 .../pages/password/gis-password-page.c             |  172 +++++++++-----------
 .../pages/password/gis-password-page.ui            |   59 ++++++--
 gnome-initial-setup/pages/password/pw-utils.c      |   75 +++++++---
 3 files changed, 181 insertions(+), 125 deletions(-)
---
diff --git a/gnome-initial-setup/pages/password/gis-password-page.c 
b/gnome-initial-setup/pages/password/gis-password-page.c
index 1df9a14..20144fd 100644
--- a/gnome-initial-setup/pages/password/gis-password-page.c
+++ b/gnome-initial-setup/pages/password/gis-password-page.c
@@ -36,14 +36,18 @@
 #include <glib/gi18n.h>
 #include <gio/gio.h>
 
+#define VALIDATION_TIMEOUT 600
+
 struct _GisPasswordPagePrivate
 {
   GtkWidget *password_entry;
   GtkWidget *confirm_entry;
   GtkWidget *password_strength;
+  GtkWidget *password_explanation;
+  GtkWidget *confirm_explanation;
   gboolean valid_confirm;
-  const gchar *password_reason;
-  guint reason_timeout;
+  gboolean valid_password;
+  guint timeout_id;
   const gchar *username;
 };
 typedef struct _GisPasswordPagePrivate GisPasswordPagePrivate;
@@ -54,7 +58,8 @@ static gboolean
 page_validate (GisPasswordPage *page)
 {
   GisPasswordPagePrivate *priv = gis_password_page_get_instance_private (page);
-  return priv->valid_confirm;
+
+  return priv->valid_confirm && priv->valid_password;
 }
 
 static void
@@ -98,122 +103,89 @@ gis_password_page_save_data (GisPage *gis_page)
 }
 
 static gboolean
-reason_timeout_cb (gpointer data)
+validate (GisPasswordPage *page)
 {
-  GisPasswordPage *page = GIS_PASSWORD_PAGE (data);
   GisPasswordPagePrivate *priv = gis_password_page_get_instance_private (page);
   const gchar *password;
   const gchar *verify;
-
-  password = gtk_entry_get_text (GTK_ENTRY (priv->password_entry));
-  verify = gtk_entry_get_text (GTK_ENTRY (priv->confirm_entry));
-
-  if (strlen (password) == 0)
-    set_entry_validation_error (GTK_ENTRY (priv->password_entry), _("No password"));
-  else
-    set_entry_validation_error (GTK_ENTRY (priv->password_entry), priv->password_reason);
-
-  if (strlen (verify) > 0 && !priv->valid_confirm)
-    set_entry_validation_error (GTK_ENTRY (priv->confirm_entry), _("Passwords do not match"));
-
-  priv->reason_timeout = 0;
-
-  return G_SOURCE_REMOVE;
-}
-
-static void
-refresh_reason_timeout (GisPasswordPage *page)
-{
-  GisPasswordPagePrivate *priv = gis_password_page_get_instance_private (page);
-
-  if (priv->reason_timeout != 0)
-    g_source_remove (priv->reason_timeout);
-
-  priv->reason_timeout = g_timeout_add (600, reason_timeout_cb, page);
-}
-
-static void
-update_valid_confirm (GisPasswordPage *page)
-{
-  GisPasswordPagePrivate *priv = gis_password_page_get_instance_private (page);
-  const gchar *password, *verify;
-
-  password = gtk_entry_get_text (GTK_ENTRY (priv->password_entry));
-  verify = gtk_entry_get_text (GTK_ENTRY (priv->confirm_entry));
-
-  priv->valid_confirm = strcmp (password, verify) == 0;
-}
-
-static void
-update_password_entries (GisPasswordPage *page)
-{
-  GisPasswordPagePrivate *priv = gis_password_page_get_instance_private (page);
-  const gchar *password;
-  gdouble strength;
   gint strength_level;
   const gchar *hint;
-  const gchar *long_hint = NULL;
+  const gchar *long_hint;
+
+  if (priv->timeout_id != 0) {
+    g_source_remove (priv->timeout_id);
+    priv->timeout_id = 0;
+  }
 
   password = gtk_entry_get_text (GTK_ENTRY (priv->password_entry));
+  verify = gtk_entry_get_text (GTK_ENTRY (priv->confirm_entry));
 
-  strength = pw_strength (password, NULL, priv->username, &hint, &long_hint, &strength_level);
+  pw_strength (password, NULL, priv->username, &hint, &long_hint, &strength_level);
   gtk_level_bar_set_value (GTK_LEVEL_BAR (priv->password_strength), strength_level);
-
-  if (strength == 0.0) {
-    priv->password_reason = long_hint ? long_hint : hint;
+  gtk_label_set_label (GTK_LABEL (priv->password_explanation), long_hint);
+
+  priv->valid_password = (strength_level > 0);
+  if (priv->valid_password)
+    set_entry_validation_checkmark (GTK_ENTRY (priv->password_entry));
+
+  priv->valid_confirm = (strcmp (password, verify) == 0);
+  if (strlen (password) > 0 && strlen (verify) > 0) {
+    if (!priv->valid_confirm) {
+      gtk_label_set_label (GTK_LABEL (priv->confirm_explanation),
+                           _("The passwords do not match."));
+    }
+    else {
+      gtk_label_set_label (GTK_LABEL (priv->confirm_explanation), "");
+      set_entry_validation_checkmark (GTK_ENTRY (priv->confirm_entry));
+    }
   }
-  update_valid_confirm (page);
 
-  if (priv->valid_confirm)
-    clear_entry_validation_error (GTK_ENTRY (priv->password_entry));
-
-  gtk_widget_set_sensitive (priv->confirm_entry, TRUE);
+  update_page_validation (page);
 
-  refresh_reason_timeout (page);
+  return FALSE;
 }
 
 static gboolean
-password_entry_focus_out (GtkWidget      *widget,
-                          GdkEventFocus  *event,
-                          GisPasswordPage *page)
+on_focusout (GisPasswordPage *page)
 {
-  GisPasswordPagePrivate *priv = gis_password_page_get_instance_private (page);
-
-  if (priv->reason_timeout != 0) {
-    g_source_remove (priv->reason_timeout);
-    priv->reason_timeout = 0;
-  }
+  validate (page);
 
   return FALSE;
 }
 
-static gboolean
-confirm_entry_focus_out (GtkWidget      *widget,
-                         GdkEventFocus  *event,
-                         GisPasswordPage *page)
+static void
+password_changed (GtkWidget      *w,
+                  GParamSpec     *pspec,
+                  GisPasswordPage *page)
 {
   GisPasswordPagePrivate *priv = gis_password_page_get_instance_private (page);
-  GtkEntry *entry = GTK_ENTRY (widget);
-  const gchar *verify;
 
-  verify = gtk_entry_get_text (entry);
+  clear_entry_validation_error (GTK_ENTRY (w));
+  clear_entry_validation_error (GTK_ENTRY (priv->confirm_entry));
 
-  if (strlen (verify) > 0 && !priv->valid_confirm)
-    set_entry_validation_error (entry, _("Passwords do not match"));
-  else
-    clear_entry_validation_error (entry);
+  priv->valid_password = FALSE;
+  update_page_validation (page);
 
-  return FALSE;
+  if (priv->timeout_id != 0)
+    g_source_remove (priv->timeout_id);
+  priv->timeout_id = g_timeout_add (VALIDATION_TIMEOUT, (GSourceFunc)validate, page);
 }
 
 static void
-password_changed (GtkWidget      *w,
-                  GParamSpec     *pspec,
-                  GisPasswordPage *page)
+confirm_changed (GtkWidget      *w,
+                 GParamSpec     *pspec,
+                 GisPasswordPage *page)
 {
+  GisPasswordPagePrivate *priv = gis_password_page_get_instance_private (page);
+
   clear_entry_validation_error (GTK_ENTRY (w));
-  update_password_entries (page);
+
+  priv->valid_confirm = FALSE;
   update_page_validation (page);
+
+  if (priv->timeout_id != 0)
+    g_source_remove (priv->timeout_id);
+  priv->timeout_id = g_timeout_add (VALIDATION_TIMEOUT, (GSourceFunc)validate, page);
 }
 
 static void
@@ -226,6 +198,11 @@ username_changed (GObject *obj, GParamSpec *pspec, GisPasswordPage *page)
     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));
+
+  validate (page);
 }
 
 static void
@@ -238,17 +215,24 @@ gis_password_page_constructed (GObject *object)
 
   g_signal_connect (priv->password_entry, "notify::text",
                     G_CALLBACK (password_changed), page);
+  g_signal_connect_swapped (priv->password_entry, "focus-out-event",
+                            G_CALLBACK (on_focusout), page);
+  g_signal_connect_swapped (priv->password_entry, "activate",
+                            G_CALLBACK (validate), page);
+
   g_signal_connect (priv->confirm_entry, "notify::text",
-                    G_CALLBACK (password_changed), page);
-  g_signal_connect_after (priv->password_entry, "focus-out-event",
-                          G_CALLBACK (password_entry_focus_out), page);
-  g_signal_connect_after (priv->confirm_entry, "focus-out-event",
-                          G_CALLBACK (confirm_entry_focus_out), page);
+                    G_CALLBACK (confirm_changed), page);
+  g_signal_connect_swapped (priv->confirm_entry, "focus-out-event",
+                            G_CALLBACK (on_focusout), page);
+  g_signal_connect_swapped (priv->confirm_entry, "activate",
+                            G_CALLBACK (validate), page);
 
   g_signal_connect (GIS_PAGE (page)->driver, "notify::username",
                     G_CALLBACK (username_changed), page);
+  g_signal_connect_swapped (priv->confirm_entry, "activate",
+                            G_CALLBACK (validate), page);
 
-  update_page_validation (page);
+  validate (page);
 
   gtk_widget_show (GTK_WIDGET (page));
 }
@@ -270,6 +254,8 @@ gis_password_page_class_init (GisPasswordPageClass *klass)
   gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisPasswordPage, password_entry);
   gtk_widget_class_bind_template_child_private (GTK_WIDGET_CLASS (klass), GisPasswordPage, confirm_entry);
   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);
 
   page_class->page_id = PAGE_ID;
   page_class->locale_changed = gis_password_page_locale_changed;
diff --git a/gnome-initial-setup/pages/password/gis-password-page.ui 
b/gnome-initial-setup/pages/password/gis-password-page.ui
index 9d03457..494463e 100644
--- a/gnome-initial-setup/pages/password/gis-password-page.ui
+++ b/gnome-initial-setup/pages/password/gis-password-page.ui
@@ -55,7 +55,7 @@
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <property name="column_spacing">12</property>
-            <property name="row_spacing">12</property>
+            <property name="row_spacing">6</property>
             <property name="margin_top">54</property>
             <child>
               <object class="GtkLabel" id="password_label">
@@ -63,7 +63,7 @@
                 <property name="can_focus">False</property>
                 <property name="halign">end</property>
                 <property name="xalign">1</property>
-                <property name="label" translatable="yes">Choose a _password</property>
+                <property name="label" translatable="yes">_Password</property>
                 <property name="use_underline">True</property>
                 <property name="mnemonic_widget">password_entry</property>
               </object>
@@ -95,7 +95,7 @@
                 <property name="can_focus">False</property>
                 <property name="halign">end</property>
                 <property name="xalign">1</property>
-                <property name="label" translatable="yes">_Confirm password</property>
+                <property name="label" translatable="yes">_Verify</property>
                 <property name="use_underline">True</property>
                 <property name="mnemonic_widget">confirm_entry</property>
               </object>
@@ -111,7 +111,6 @@
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
                 <property name="visibility">False</property>
-                <property name="sensitive">False</property>
                 <property name="invisible_char">●</property>
                 <property name="invisible_char_set">True</property>
               </object>
@@ -123,13 +122,37 @@
               </packing>
             </child>
             <child>
+              <object class="GtkLevelBar" id="password_strength">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">fill</property>
+                <property name="valign">center</property>
+                <property name="max-value">4</property>
+                <property name="mode">discrete</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="password_explanation">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="halign">start</property>
-                <property name="label" translatable="yes">Try to use at least 8 different characters. Mix 
upper and lower case and use a number or two.</property>
+                <property name="xalign">0</property>
+                <property name="yalign">0</property>
+                <property name="label" translatable="yes"></property>
+                <property name="width-chars">35</property>
+                <property name="max-width-chars">35</property>
+                <property name="height-request">50</property>
                 <property name="wrap">True</property>
-                <property name="max-width-chars">30</property>
+                <property name="hexpand">True</property>
+                <property name="wrap_mode">word-char</property>
+                <style>
+                  <class name="dim-label"/>
+                </style>
                 <attributes>
                   <attribute name="scale" value="0.8"/>
                 </attributes>
@@ -142,17 +165,27 @@
               </packing>
             </child>
             <child>
-              <object class="GtkLevelBar" id="password_strength">
+              <object class="GtkLabel" id="confirm_explanation">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="halign">fill</property>
-                <property name="valign">center</property>
-                <property name="max-value">4</property>
-                <property name="mode">discrete</property>
+                <property name="xalign">0</property>
+                <property name="yalign">0</property>
+                <property name="label" translatable="yes"></property>
+                <property name="width-chars">35</property>
+                <property name="max-width-chars">35</property>
+                <property name="wrap">True</property>
+                <property name="hexpand">True</property>
+                <property name="wrap_mode">word-char</property>
+                <style>
+                  <class name="dim-label"/>
+                </style>
+                <attributes>
+                  <attribute name="scale" value="0.8"/>
+                </attributes>
               </object>
               <packing>
                 <property name="left_attach">1</property>
-                <property name="top_attach">1</property>
+                <property name="top_attach">4</property>
                 <property name="width">1</property>
                 <property name="height">1</property>
               </packing>
diff --git a/gnome-initial-setup/pages/password/pw-utils.c b/gnome-initial-setup/pages/password/pw-utils.c
index fb24759..c6e5135 100644
--- a/gnome-initial-setup/pages/password/pw-utils.c
+++ b/gnome-initial-setup/pages/password/pw-utils.c
@@ -73,6 +73,53 @@ pw_generate (void)
         return res;
 }
 
+static const gchar *
+pw_error_hint (gint error)
+{
+        switch (error) {
+        case PWQ_ERROR_SAME_PASSWORD:
+                return C_("Password hint", "The new password needs to be different from the old one.");
+        case PWQ_ERROR_CASE_CHANGES_ONLY:
+                return C_("Password hint", "Try changing some letters and numbers.");
+        case PWQ_ERROR_TOO_SIMILAR:
+                return C_("Password hint", "Try changing the password a bit more.");
+        case PWQ_ERROR_USER_CHECK:
+                return C_("Password hint", "A password without your user name would be stronger.");
+        case PWQ_ERROR_GECOS_CHECK:
+                return C_("Password hint", "Try to avoid using your name in the password.");
+        case PWQ_ERROR_BAD_WORDS:
+                return C_("Password hint", "Try to avoid some of the words included in the password.");
+        case PWQ_ERROR_ROTATED:
+                return C_("Password hint", "Try changing the password a bit more.");
+        case PWQ_ERROR_CRACKLIB_CHECK:
+                return C_("Password hint", "Try to avoid common words.");
+        case PWQ_ERROR_PALINDROME:
+                return C_("Password hint", "Try to avoid reordering existing words.");
+        case PWQ_ERROR_MIN_DIGITS:
+                return C_("Password hint", "Try to use more numbers.");
+        case PWQ_ERROR_MIN_UPPERS:
+                return C_("Password hint", "Try to use more uppercase letters.");
+        case PWQ_ERROR_MIN_LOWERS:
+                return C_("Password hint", "Try to use more lowercase letters.");
+        case PWQ_ERROR_MIN_OTHERS:
+                return C_("Password hint", "Try to use more special characters, like punctuation.");
+        case PWQ_ERROR_MIN_CLASSES:
+                return C_("Password hint", "Try to use a mixture of letters, numbers and punctuation.");
+        case PWQ_ERROR_MAX_CONSECUTIVE:
+                return C_("Password hint", "Try to avoid repeating the same character.");
+        case PWQ_ERROR_MAX_CLASS_REPEAT:
+                return C_("Password hint", "Try to avoid repeating the same type of character: you need to 
mix up letters, numbers and punctuation.");
+        case PWQ_ERROR_MAX_SEQUENCE:
+                return C_("Password hint", "Try to avoid sequences like 1234 or abcd.");
+        case PWQ_ERROR_MIN_LENGTH:
+                return C_("Password hint", "Try to add more letters, numbers and symbols.");
+        case PWQ_ERROR_EMPTY_PASSWORD:
+                return C_("Password hint", "Mix uppercase and lowercase and use a number or two.");
+        default:
+                return C_("Password hint", "Good password! Adding more letters, numbers and punctuation will 
make it stronger.");
+        }
+}
+
 gdouble
 pw_strength (const gchar  *password,
              const gchar  *old_password,
@@ -89,36 +136,26 @@ pw_strength (const gchar  *password,
                               password, old_password, username,
                               &auxerror);
 
-        if (rv == PWQ_ERROR_MIN_LENGTH) {
-                *hint = C_("Password strength", "Too short");
-                *long_hint = pwquality_strerror (NULL, 0, rv, auxerror);
-                goto out;
-        }
-        else if (rv < 0) {
-                *hint = C_("Password strength", "Not good enough");
-                *long_hint = pwquality_strerror (NULL, 0, rv, auxerror);
-                goto out;
-        }
-
         strength = CLAMP (0.01 * rv, 0.0, 1.0);
-
-        if (strength < 0.50) {
+        if (rv < 0) {
+                *hint = C_("Password strength", "Strength: Weak");
+        }
+        else if (strength < 0.50) {
                 level = 1;
-                *hint = C_("Password strength", "Weak");
+                *hint = C_("Password strength", "Strength: Low");
         } else if (strength < 0.75) {
                 level = 2;
-                *hint = C_("Password strength", "Fair");
+                *hint = C_("Password strength", "Strength: Medium");
         } else if (strength < 0.90) {
                 level = 3;
-                *hint = C_("Password strength", "Good");
+                *hint = C_("Password strength", "Strength: Good");
         } else {
                 level = 4;
-                *hint = C_("Password strength", "Strong");
+                *hint = C_("Password strength", "Strength: High");
         }
 
-        *long_hint = NULL;
+        *long_hint = pw_error_hint (rv);
 
- out:
         if (strength_level)
                 *strength_level = level;
 


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