Bug 1552227 - OTR: improve UX of 'Add Finderprint' dialog. r=mkmelin,kaie a=jorgk
authorAlessandro Castellani <alessandro@thunderbird.net>
Thu, 04 Jul 2019 21:17:48 -0700
changeset 36111 fa74c9e9b21e6cdce902e8ab0cb2fb6d57479a3a
parent 36110 bc00c0967dbb89e1f494094c98c03aab34182fce
child 36112 decf19e35114551a2f9f5d6296db0e602c83cd4e
push id392
push userclokep@gmail.com
push dateMon, 02 Sep 2019 20:17:19 +0000
reviewersmkmelin, kaie, jorgk
bugs1552227
Bug 1552227 - OTR: improve UX of 'Add Finderprint' dialog. r=mkmelin,kaie a=jorgk
chat/content/otr-add-fingerprint.js
chat/content/otr-add-fingerprint.xul
chat/content/otr/add-finger.ftl
chat/content/otr/otrUI.ftl
chat/themes/jar.mn
chat/themes/otrFingerprintDialog.css
mail/themes/shared/jar.inc.mn
mail/themes/shared/mail/icons/login.svg
--- a/chat/content/otr-add-fingerprint.js
+++ b/chat/content/otr-add-fingerprint.js
@@ -1,47 +1,78 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-const {
-  XPCOMUtils,
-  l10nHelper,
-} = ChromeUtils.import("resource:///modules/imXPCOMUtils.jsm");
-const {OTR} = ChromeUtils.import("resource:///modules/OTR.jsm");
-
-var args = window.arguments[0].wrappedJSObject;
+var {l10nHelper} = ChromeUtils.import("resource:///modules/imXPCOMUtils.jsm");
+var {OTR} = ChromeUtils.import("resource:///modules/OTR.jsm");
 
 var otrAddFinger = {
   async onload() {
-    let title = await document.l10n.formatValue(
-      "otr-add-finger-name-title", {name: args.screenname});
-    document.title = title;
-    document.addEventListener("dialogaccept", () => {
-      return this.add();
+    let args = window.arguments[0].wrappedJSObject;
+
+    this.fingerWarning = document.getElementById("fingerWarning");
+    this.fingerError = document.getElementById("fingerError");
+    this.keyCount = document.getElementById("keyCount");
+
+    let description = await document.l10n.formatValue(
+      "otr-add-finger-description", { name: args.screenname });
+    document.getElementById("otrDescription").textContent = description;
+
+    let warningTooltip =
+      await document.l10n.formatValue("otr-add-finger-tooltip-error");
+    this.fingerWarning.setAttribute("tooltiptext", warningTooltip);
+
+    document.addEventListener("dialogaccept", (event) => {
+      let hex = document.getElementById("fingerprint").value;
+      let context = OTR.getContextFromRecipient(
+        args.account,
+        args.protocol,
+        args.screenname
+      );
+      let finger = OTR.addFingerprint(context, hex);
+      if (finger.isNull()) {
+        event.preventDefault();
+        return;
+      }
+      try {
+        // Ignore the return, this is just a test.
+        OTR.getUIConvFromContext(context);
+      } catch (error) {
+        // We expect that a conversation may not have been started.
+        context = null;
+      }
+      OTR.setTrust(finger, true, context);
     });
-  },
 
-  oninput(e) {
-    e.value = e.value.replace(/[^0-9a-fA-F]/gi, "");
-    document.documentElement.getButton("accept").disabled = (e.value.length != 40);
+    window.sizeToContent();
   },
 
-  add(e) {
-    let hex = document.getElementById("finger").value;
-    let context = OTR.getContextFromRecipient(
-      args.account,
-      args.protocol,
-      args.screenname
-    );
-    let finger = OTR.addFingerprint(context, hex);
-    if (finger.isNull())
-      return;
-    try {
-      // Ignore the return, this is just a test.
-      OTR.getUIConvFromContext(context);
-    } catch (error) {
-      // We expect that a conversation may not have been started.
-      context = null;
+  addBlankSpace(value) {
+    return value.replace(/\s/g, "").trim().replace(/(.{8})/g, "$1 ").trim();
+  },
+
+  oninput(input) {
+    let hex = input.value.replace(/\s/g, "");
+
+    if ((/[^0-9A-F]/gi).test(hex)) {
+      this.keyCount.hidden = true;
+      this.fingerWarning.hidden = false;
+      this.fingerError.hidden = false;
+    } else {
+      this.keyCount.hidden = false;
+      this.fingerWarning.hidden = true;
+      this.fingerError.hidden = true;
     }
-    OTR.setTrust(finger, true, context);
+
+    document.documentElement.getButton("accept").disabled =
+      input.value && !input.validity.valid;
+
+    this.keyCount.value = `${hex.length}/40`;
+    input.value = this.addBlankSpace(input.value);
+
+    window.sizeToContent();
+  },
+
+  onblur(input) {
+    input.value = this.addBlankSpace(input.value);
   },
 };
--- a/chat/content/otr-add-fingerprint.xul
+++ b/chat/content/otr-add-fingerprint.xul
@@ -1,32 +1,64 @@
 <?xml version="1.0" ?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <?xml-stylesheet href="chrome://global/skin/" type="text/css" ?>
+<?xml-stylesheet href="chrome://chat/skin/otrFingerprintDialog.css" type="text/css"?>
 
 <!DOCTYPE dialog>
 
 <dialog id="otrAddFingerDialog"
         data-l10n-id="otr-add-finger"
-        data-l10n-attrs="buttonlabelcancel"
         windowtype="OTR:AddFinger"
         onload="otrAddFinger.onload()"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
         xmlns:html="http://www.w3.org/1999/xhtml"
         buttons="accept,cancel"
         buttondisabledaccept="true">
 
+  <keyset id="mailKeys">
+    <key keycode="VK_ESCAPE" oncommand="window.close();"/>
+  </keyset>
+
   <linkset>
     <html:link rel="localization" href="messenger/otr/add-finger.ftl"/>
   </linkset>
 
   <script src="chrome://chat/content/otr-add-fingerprint.js"/>
-  <vbox flex="1">
-    <label data-l10n-id="otr-add-finger-tooltip" control="name" flex="1"/>
-    <hbox id="fingerBox" align="baseline" flex="1">
-      <label data-l10n-id="otr-add-finger-fingerprint" control="name"/>
-      <textbox id="finger" oninput="otrAddFinger.oninput(this)" flex="1"/>
+  <script src="chrome://global/content/globalOverlay.js"/>
+  <script src="chrome://global/content/editMenuOverlay.js"/>
+  <vbox class="dialog-container" flex="1">
+    <hbox align="center" pack="center" class="header-container">
+      <vbox>
+        <image class="header-icon icon-login"/>
+      </vbox>
+      <vbox flex="1">
+        <description id="otrDescription"/>
+      </vbox>
     </hbox>
+    <hbox class="form-control" align="center">
+      <label data-l10n-id="otr-add-finger-fingerprint"
+             class="label-box"
+             control="fingerprint"/>
+      <hbox class="input-control" align="center" flex="1">
+        <html:input id="fingerprint" type="text"
+                    data-l10n-id="otr-add-finger-input"
+                    class="input-field"
+                    oninput="otrAddFinger.oninput(this);"
+                    onblur="otrAddFinger.onblur(this);"
+                    pattern="[ 0-9a-fA-F]*"
+                    minlength="44"
+                    maxlength="44"/>
+      </hbox>
+      <image id="fingerWarning" class="form-icon icon-warning" hidden="true"/>
+    </hbox>
+    <vbox class="input-helper-container" flex="1" align="end">
+      <label id="fingerError"
+             data-l10n-id="otr-add-finger-tooltip-error"
+             class="msg-error"
+             hidden="true"/>
+      <label id="keyCount" class="input-helper" value="0/40"/>
+    </vbox>
   </vbox>
 </dialog>
--- a/chat/content/otr/add-finger.ftl
+++ b/chat/content/otr/add-finger.ftl
@@ -1,16 +1,17 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 otr-add-finger =
-    .title = Add Fingerprint
-    .buttonlabelcancel = Skip
+    .title = Add OTR Key Fingerprint
 
 # Variables:
 #   $name (String) - name of a chat contact person
-otr-add-finger-name-title = Enter the fingerprint of the OTR key used by { $name }
+# Do not translate 'OTR' (name of an encryption protocol)
+otr-add-finger-description = Enter the OTR key fingerprint for { $name }.
 
-otr-add-finger-fingerprint = Fingerprint
+otr-add-finger-fingerprint = Fingerprint:
+otr-add-finger-tooltip-error = Invalid character entered. Only letters ABCDEF and numbers are allowed
 
-# Do not translate 'OTR' (name of an encryption protocol)
-otr-add-finger-tooltip = If you know the 40 character long HEX fingerprint of your contact's OTR private key, enter it now.
+otr-add-finger-input =
+    .placeholder = The 40 character long OTR key fingerprint
--- a/chat/content/otr/otrUI.ftl
+++ b/chat/content/otr/otrUI.ftl
@@ -15,17 +15,17 @@ auth-success = Verifying your contact's 
 auth-successThem = Your contact has successfully verified your identity. You may want to verify their identity as well by asking your own question.
 auth-fail = Failed to verify your contact's identity.
 auth-waiting = Waiting for contact to complete verification …
 
 finger-verify = Verify
 finger-verify-accessKey = V
 
 # Do not translate 'OTR' (name of an encryption protocol)
-buddycontextmenu-label = Add Contact's OTR Fingerprint
+buddycontextmenu-label = Add OTR Fingerprint
 
 # Variables:
 #   $name (String) - the screen name of a chat contact person
 alert-start = Attempting to start an encrypted conversation with { $name }.
 
 # Variables:
 #   $name (String) - the screen name of a chat contact person
 alert-refresh = Attempting to refresh the encrypted conversation with { $name }.
--- a/chat/themes/jar.mn
+++ b/chat/themes/jar.mn
@@ -16,16 +16,17 @@ chat.jar:
 	skin/classic/chat/unknown-16.png
 	skin/classic/chat/chat-16.png
 	skin/classic/chat/chat-left-16.png
 	skin/classic/chat/conv.css
 	skin/classic/chat/browserRequest.css
 	skin/classic/chat/imtooltip.css
 	skin/classic/chat/status.css
 	skin/classic/chat/otr.css
+	skin/classic/chat/otrFingerprintDialog.css
 	skin/classic/chat/prpl-generic/icon32.png	(icons/prpl-generic-32.png)
 	skin/classic/chat/prpl-generic/icon48.png	(icons/prpl-generic-48.png)
 	skin/classic/chat/prpl-generic/icon.png		(icons/prpl-generic.png)
 	skin/classic/chat/prpl-unknown/icon32.png	(icons/prpl-unknown-32.png)
 	skin/classic/chat/prpl-unknown/icon48.png	(icons/prpl-unknown-48.png)
 	skin/classic/chat/prpl-unknown/icon.png		(icons/prpl-unknown.png)
 	skin/classic/chat/otr-connection-encrypted.svg (icons/otr-connection-encrypted.svg)
 	skin/classic/chat/otr-connection-finished.svg  (icons/otr-connection-finished.svg)
new file mode 100644
--- /dev/null
+++ b/chat/themes/otrFingerprintDialog.css
@@ -0,0 +1,96 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+:root {
+  --text-color: #36385A;
+  --primary-color: #0a84ff;
+  --warning-color: #FF9400;
+  --error-color: #5A0002;
+}
+
+.dialog-container {
+  width: 36em;
+}
+
+.dialog-button-box {
+  margin-top: 5px;
+}
+
+.header-container {
+  margin: 0px 10px 5px;
+}
+
+.label-title {
+  font-weight: bold;
+  margin-bottom: 5px;
+  color: var(--text-color);
+}
+
+.msg-error {
+  color: var(--error-color);
+}
+
+/* Form and input fields */
+
+.form-control {
+  position: relative;
+  margin: 0px 0px 10px;
+}
+
+.input-control {
+  display: flex;
+  align-items: stretch;
+}
+
+.input-field {
+  padding: 5px 30px 5px 6px;
+  flex-grow: 1;
+  margin: 2px 4px;
+}
+
+.input-field:invalid {
+  box-shadow: 0 0 2px 1px var(--warning-color);
+}
+
+.input-helper-container {
+  margin-top: -6px;
+}
+
+.input-helper {
+  font-family: monospace;
+  font-size: 1em;
+  opacity: 0.7;
+}
+
+/* Icons */
+
+.header-icon {
+  -moz-context-properties: fill, stroke-opacity;
+  fill: currentColor;
+  color: var(--primary-color);
+  width: 3.5em;
+  margin: 10px;
+}
+
+.form-icon {
+  cursor: pointer;
+  -moz-context-properties: fill, stroke-opacity;
+  fill: currentColor;
+  margin-left: -26px;
+  margin-right: 10px;
+  color: var(--text-color);
+}
+
+.icon-info {
+  list-style-image: url("chrome://messenger/skin/icons/info.svg");
+}
+
+.icon-warning {
+  list-style-image: url("chrome://global/skin/icons/warning.svg");
+  color: var(--warning-color);
+}
+
+.icon-login {
+  list-style-image: url("chrome://messenger/skin/icons/login.svg");
+}
--- a/mail/themes/shared/jar.inc.mn
+++ b/mail/themes/shared/jar.inc.mn
@@ -52,16 +52,17 @@
   skin/classic/messenger/icons/forward.svg                    (../shared/mail/icons/forward.svg)
   skin/classic/messenger/icons/getmsg.svg                     (../shared/mail/icons/getmsg.svg)
   skin/classic/messenger/icons/goback.svg                     (../shared/mail/icons/goback.svg)
   skin/classic/messenger/icons/goforward.svg                  (../shared/mail/icons/goforward.svg)
   skin/classic/messenger/icons/info.svg                       (../shared/mail/icons/info.svg)
   skin/classic/messenger/icons/join.svg                       (../shared/mail/icons/join.svg)
   skin/classic/messenger/icons/junk.svg                       (../shared/mail/icons/junk.svg)
   skin/classic/messenger/icons/junk-col.svg                   (../shared/mail/icons/junk-col.svg)
+  skin/classic/messenger/icons/login.svg                      (../shared/mail/icons/login.svg)
   skin/classic/messenger/icons/mark.svg                       (../shared/mail/icons/mark.svg)
   skin/classic/messenger/icons/message.svg                    (../shared/mail/icons/message.svg)
   skin/classic/messenger/icons/move-bottom.svg                (../shared/mail/icons/move-bottom.svg)
   skin/classic/messenger/icons/move-down.svg                  (../shared/mail/icons/move-down.svg)
   skin/classic/messenger/icons/move-together.svg              (../shared/mail/icons/move-together.svg)
   skin/classic/messenger/icons/move-top.svg                   (../shared/mail/icons/move-top.svg)
   skin/classic/messenger/icons/move-up.svg                    (../shared/mail/icons/move-up.svg)
   skin/classic/messenger/icons/navigation.svg                 (../shared/mail/icons/navigation.svg)
new file mode 100644
--- /dev/null
+++ b/mail/themes/shared/mail/icons/login.svg
@@ -0,0 +1,4 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill="context-fill" d="M10.992 1a4.009 4.009 0 0 0-4.009 4.008c0 .1.022.187.028.282-.059.05-.119.087-.178.143L5.667 6.6a.366.366 0 0 0 0 .467A1.878 1.878 0 0 0 6 7.5.353.353 0 0 1 6 8l-5 5v1.767a.229.229 0 0 0 .233.233H3.77a.229.229 0 0 0 .23-.233v-.778h.75a.227.227 0 0 0 .233-.228v-.768H5.2s.28 0 .28-.235V12.5h.779s.233-.1.233-.244v-1.271h.855l1.12-1.118H8.7l.467.467c.233.233.233.233.365.233a.437.437 0 0 0 .275-.127l.993-1.273c.034-.053.054-.107.084-.161.036 0 .07.011.107.011a4.008 4.008 0 1 0 0-8.017zM12.5 4.489a1 1 0 1 1 1-1 1 1 0 0 1-1 1z"></path></svg>