Bug 1098661 - Update sync in-content preferences UI to match FxA migration flows. r=adw
☠☠ backed out by a76b8d5ee8dc ☠ ☠
authorMark Hammond <mhammond@skippinet.com.au>
Wed, 17 Dec 2014 15:18:07 +1100
changeset 220238 069da43ec3be3987b2cb875462f99b0c12a5caa8
parent 220237 889224b8a0fdaa3a492d645b407b86ef52ae0f8d
child 220239 1b8f23ce8a7a668e9ede2ca4c2f0c3f20dbb858e
push id53051
push userryanvm@gmail.com
push dateThu, 18 Dec 2014 02:08:11 +0000
treeherdermozilla-inbound@ffb2b4550976 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersadw
bugs1098661
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1098661 - Update sync in-content preferences UI to match FxA migration flows. r=adw
browser/components/preferences/in-content/sync.js
browser/components/preferences/in-content/sync.xul
browser/locales/en-US/chrome/browser/accounts.properties
browser/locales/en-US/chrome/browser/preferences/sync.dtd
browser/themes/shared/incontentprefs/preferences.inc.css
--- a/browser/components/preferences/in-content/sync.js
+++ b/browser/components/preferences/in-content/sync.js
@@ -4,33 +4,38 @@
 
 Components.utils.import("resource://services-sync/main.js");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "FxAccountsCommon", function () {
   return Components.utils.import("resource://gre/modules/FxAccountsCommon.js", {});
 });
 
+XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
+  "resource://gre/modules/FxAccounts.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "fxaMigrator",
+  "resource://services-sync/FxaMigrator.jsm");
+
 const PAGE_NO_ACCOUNT = 0;
 const PAGE_HAS_ACCOUNT = 1;
 const PAGE_NEEDS_UPDATE = 2;
 const PAGE_PLEASE_WAIT = 3;
 const FXA_PAGE_LOGGED_OUT = 4;
 const FXA_PAGE_LOGGED_IN = 5;
 
 // Indexes into the "login status" deck.
 // We are in a successful verified state - everything should work!
 const FXA_LOGIN_VERIFIED = 0;
 // We have logged in to an unverified account.
 const FXA_LOGIN_UNVERIFIED = 1;
 // We are logged in locally, but the server rejected our credentials.
 const FXA_LOGIN_FAILED = 2;
 
 let gSyncPane = {
-  _stringBundle: null,
   prefArray: ["engine.bookmarks", "engine.passwords", "engine.prefs",
               "engine.tabs", "engine.history"],
 
   get page() {
     return document.getElementById("weavePrefsDeck").selectedIndex;
   },
 
   set page(val) {
@@ -86,31 +91,48 @@ let gSyncPane = {
 
   _init: function () {
     let topics = ["weave:service:login:error",
                   "weave:service:login:finish",
                   "weave:service:start-over:finish",
                   "weave:service:setup-complete",
                   "weave:service:logout:finish",
                   FxAccountsCommon.ONVERIFIED_NOTIFICATION];
+    let migrateTopic = "fxa-migration:state-changed";
 
     // Add the observers now and remove them on unload
     //XXXzpao This should use Services.obs.* but Weave's Obs does nice handling
     //        of `this`. Fix in a followup. (bug 583347)
     topics.forEach(function (topic) {
       Weave.Svc.Obs.add(topic, this.updateWeavePrefs, this);
     }, this);
+    // The FxA migration observer is a special case.
+    Weave.Svc.Obs.add(migrateTopic, this.updateMigrationState, this);
+
     window.addEventListener("unload", function() {
       topics.forEach(function (topic) {
         Weave.Svc.Obs.remove(topic, this.updateWeavePrefs, this);
       }, gSyncPane);
+      Weave.Svc.Obs.remove(migrateTopic, this.updateMigrationState, this);
     }, false);
 
-    this._stringBundle =
-      Services.strings.createBundle("chrome://browser/locale/preferences/preferences.properties");
+    // ask the migration module to broadcast its current state (and nothing will
+    // happen if it's not loaded - which is good, as that means no migration
+    // is pending/necessary) - we don't want to suck that module in just to
+    // find there's nothing to do.
+    Services.obs.notifyObservers(null, "fxa-migration:state-request", null);
+
+    XPCOMUtils.defineLazyGetter(this, '_stringBundle', () => {
+      return Services.strings.createBundle("chrome://browser/locale/preferences/preferences.properties");
+    }),
+
+    XPCOMUtils.defineLazyGetter(this, '_accountsStringBundle', () => {
+      return Services.strings.createBundle("chrome://browser/locale/accounts.properties");
+    }),
+
     this.updateWeavePrefs();
   },
 
   _setupEventListeners: function() {
     function setEventListener(aId, aEventType, aCallback)
     {
       document.getElementById(aId)
               .addEventListener(aEventType, aCallback.bind(gSyncPane));
@@ -187,28 +209,38 @@ let gSyncPane = {
     setEventListener("rejectUnlinkFxaAccount", "click", function () {
       gSyncPane.unlinkFirefoxAccount(true);
     });
     setEventListener("fxaSyncComputerName", "change", function () {
       gSyncUtils.changeName(this);
     });
     setEventListener("tosPP-small-ToS", "click", gSyncPane.openToS);
     setEventListener("tosPP-small-PP", "click", gSyncPane.openPrivacyPolicy);
+    setEventListener("sync-migrate-upgrade", "click", function () {
+      let win = Services.wm.getMostRecentWindow("navigator:browser");
+      fxaMigrator.createFxAccount(win);
+    });
+    setEventListener("sync-migrate-forget", "click", function () {
+      fxaMigrator.forgetFxAccount();
+    });
+    setEventListener("sync-migrate-resend", "click", function () {
+      let win = Services.wm.getMostRecentWindow("navigator:browser");
+      fxaMigrator.resendVerificationMail(win);
+    });
   },
 
   updateWeavePrefs: function () {
     let service = Components.classes["@mozilla.org/weave/service;1"]
                   .getService(Components.interfaces.nsISupports)
                   .wrappedJSObject;
     // service.fxAccountsEnabled is false iff sync is already configured for
     // the legacy provider.
     if (service.fxAccountsEnabled) {
       // determine the fxa status...
       this.page = PAGE_PLEASE_WAIT;
-      Components.utils.import("resource://gre/modules/FxAccounts.jsm");
       fxAccounts.getSignedInUser().then(data => {
         if (!data) {
           this.page = FXA_PAGE_LOGGED_OUT;
           return;
         }
         this.page = FXA_PAGE_LOGGED_IN;
         // We are logged in locally, but maybe we are in a state where the
         // server rejected our credentials (eg, password changed on the server)
@@ -257,16 +289,55 @@ let gSyncPane = {
     } else {
       this.page = PAGE_HAS_ACCOUNT;
       document.getElementById("accountName").textContent = Weave.Service.identity.account;
       document.getElementById("syncComputerName").value = Weave.Service.clientsEngine.localName;
       document.getElementById("tosPP-normal").hidden = this._usingCustomServer;
     }
   },
 
+  updateMigrationState: function(subject, state) {
+    let selIndex;
+    switch (state) {
+      case fxaMigrator.STATE_USER_FXA: {
+        let sb = this._accountsStringBundle;
+        let button = document.getElementById("sync-migrate-upgrade");
+        button.setAttribute("label", sb.GetStringFromName("upgradeToFxA.label"));
+        button.setAttribute("accesskey", sb.GetStringFromName("upgradeToFxA.accessKey"));
+        selIndex = 0;
+        break;
+      }
+      case fxaMigrator.STATE_USER_FXA_VERIFIED: {
+        let sb = this._accountsStringBundle;
+        let email = subject.QueryInterface(Components.interfaces.nsISupportsString).data;
+        let label = sb.formatStringFromName("needVerifiedUserLong", [email], 1);
+        let elt = document.getElementById("sync-migrate-verify-label");
+        elt.setAttribute("value", label);
+        // The "resend" button.
+        let button = document.getElementById("sync-migrate-resend");
+        button.setAttribute("label", sb.GetStringFromName("resendVerificationEmail.label"));
+        button.setAttribute("accesskey", sb.GetStringFromName("resendVerificationEmail.accessKey"));
+        // The "forget" button.
+        button = document.getElementById("sync-migrate-forget");
+        button.setAttribute("label", sb.GetStringFromName("forgetMigration.label"));
+        button.setAttribute("accesskey", sb.GetStringFromName("forgetMigration.accessKey"));
+        selIndex = 1;
+        break;
+      }
+      default:
+        if (state) { // |null| is expected, but everything else is not.
+          Cu.reportError("updateMigrationState has unknown state: " + state);
+        }
+        document.getElementById("sync-migration").hidden = true;
+        return;
+    }
+    document.getElementById("sync-migration").hidden = false;
+    document.getElementById("sync-migration-deck").selectedIndex = selIndex;
+  },
+
   startOver: function (showDialog) {
     if (showDialog) {
       let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING +
                   Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_CANCEL + 
                   Services.prompt.BUTTON_POS_1_DEFAULT;
       let buttonChoice =
         Services.prompt.confirmEx(window,
                                   this._stringBundle.GetStringFromName("syncUnlink.title"),
@@ -370,17 +441,16 @@ let gSyncPane = {
   },
 
   manageFirefoxAccount: function() {
     let url = Services.prefs.getCharPref("identity.fxaccounts.settings.uri");
     this.openContentInBrowser(url);
   },
 
   verifyFirefoxAccount: function() {
-    Components.utils.import("resource://gre/modules/FxAccounts.jsm");
     fxAccounts.resendVerificationEmail().then(() => {
       fxAccounts.getSignedInUser().then(data => {
         let sb = this._stringBundle;
         let title = sb.GetStringFromName("firefoxAccountsVerificationSentTitle");
         let heading = sb.formatStringFromName("firefoxAccountsVerificationSentHeading",
                                               [data.email], 1);
         let description = sb.GetStringFromName("firefoxAccountVerificationSentDescription");
 
@@ -425,17 +495,16 @@ let gSyncPane = {
 
       let pressed = prompt.confirmEx(title, body, buttonFlags,
                                      continueLabel, null, null, null, {});
 
       if (pressed != 0) { // 0 is the "continue" button
         return;
       }
     }
-    Cu.import("resource://gre/modules/FxAccounts.jsm");
     fxAccounts.signOut().then(() => {
       this.updateWeavePrefs();
     });
   },
 
   openQuotaDialog: function () {
     let win = Services.wm.getMostRecentWindow("Sync:ViewQuota");
     if (win)
--- a/browser/components/preferences/in-content/sync.xul
+++ b/browser/components/preferences/in-content/sync.xul
@@ -32,16 +32,41 @@
 
 <hbox id="header-sync"
       class="header"
       hidden="true"
       data-category="paneSync">
   <label class="header-name">&paneSync.title;</label>
 </hbox>
 
+<hbox id="sync-migration-container"
+       data-category="paneSync"
+       hidden="true">
+
+  <vbox id="sync-migration" flex="1" hidden="true">
+
+    <deck id="sync-migration-deck">
+      <!-- When we are in the "need FxA user" state -->
+      <hbox align="center">
+        <label>&migrate.upgradeNeeded;</label>
+        <spacer flex="1"/>
+        <button id="sync-migrate-upgrade"/>
+      </hbox>
+
+      <!-- When we are in the "need the user to be verified" state -->
+      <hbox align="center">
+        <label id="sync-migrate-verify-label"/>
+        <spacer flex="1"/>
+        <button id="sync-migrate-forget"/>
+        <button id="sync-migrate-resend"/>
+      </hbox>
+    </deck>
+  </vbox>
+</hbox>
+
 <deck id="weavePrefsDeck" data-category="paneSync" hidden="true">
   <!-- These panels are for the "legacy" sync provider -->
   <vbox id="noAccount" align="center">
     <spacer flex="1"/>
     <description id="syncDesc">
       &weaveDesc.label;
     </description>
     <separator/>
--- a/browser/locales/en-US/chrome/browser/accounts.properties
+++ b/browser/locales/en-US/chrome/browser/accounts.properties
@@ -12,8 +12,11 @@ upgradeToFxA.accessKey = U
 
 # LOCALIZATION NOTE (needVerifiedUserShort, needVerifiedUserLong)
 # %S = Email address of user's Firefox Account
 needVerifiedUserShort = %S not verified
 needVerifiedUserLong = Please click the verification link in the email sent to %S
 
 resendVerificationEmail.label = Resend
 resendVerificationEmail.accessKey = R
+
+forgetMigration.label = Forget
+forgetMigration.accessKey = F
--- a/browser/locales/en-US/chrome/browser/preferences/sync.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/sync.dtd
@@ -73,8 +73,11 @@ both, to better adapt this sentence to t
 <!ENTITY verify.label                "Verify Email">
 <!ENTITY forget.label                "Forget this Email">
 
 <!ENTITY welcome.description "Access your tabs, bookmarks, passwords and more wherever you use &brandShortName;.">
 <!ENTITY welcome.signIn.label "Sign In">
 <!ENTITY welcome.createAccount.label "Create Account">
 
 <!ENTITY welcome.useOldSync.label "Using an older version of Sync?">
+
+<!-- Sync Migration -->
+<!ENTITY migrate.upgradeNeeded      "The sync account system is being discontinued. A new Firefox Account is required to sync.">
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -288,8 +288,25 @@ description > html|a {
   /* Default dialog dimensions */
   height: 20em;
   width: 66ch;
 }
 
 /**
  * End Dialog
  */
+
+/**
+ * Sync migration
+ */
+#sync-migration {
+  border: 1px solid rgba(0, 0, 0, 0.32);
+  background-color: InfoBackground;
+  color: InfoText;
+  text-shadow: none;
+  margin: 5px 0 0 0;
+  animation: fadein 3000ms;
+}
+
+@keyframes fadein {
+  from { opacity: 0; }
+  to   { opacity: 1; }
+}