diff --git a/mobile/app/mobile.js b/mobile/app/mobile.js index 27931ae07146..35c85f919375 100644 --- a/mobile/app/mobile.js +++ b/mobile/app/mobile.js @@ -379,6 +379,9 @@ pref("browser.ui.touch.top", 12); pref("browser.ui.touch.bottom", 4); pref("browser.ui.touch.weight.visited", 120); // percentage +// Sync +pref("browser.sync.enabled", true); + // plugins pref("plugin.disable", true); pref("dom.ipc.plugins.enabled", false); diff --git a/mobile/chrome/content/bindings/browser.js b/mobile/chrome/content/bindings/browser.js index f0905c05f427..50399d01613e 100644 --- a/mobile/chrome/content/bindings/browser.js +++ b/mobile/chrome/content/bindings/browser.js @@ -362,7 +362,7 @@ let ContentScroll = { sendAsyncMessage("MozScrolledAreaChanged", { width: width, - height: height, + height: height }); break; diff --git a/mobile/chrome/content/browser.xul b/mobile/chrome/content/browser.xul index 6bd81e59a39b..c346d3144b57 100644 --- a/mobile/chrome/content/browser.xul +++ b/mobile/chrome/content/browser.xul @@ -380,7 +380,7 @@ <toolbarbutton id="tool-console" class="panel-row-button" type="radio" group="1" hidden="true" linkedpanel="console-container"/> #ifndef ANDROID <spacer flex="1"/> - <toolbarbutton id="tool-panel-close" command="cmd_panel"/> + <toolbarbutton id="tool-panel-close" class="panel-close" command="cmd_panel"/> #endif </hbox> <vbox flex="1"> @@ -442,20 +442,20 @@ </setting> #ifdef MOZ_SERVICES_SYNC <settings id="prefs-sync" label="&sync.title;"> - <setting id="sync-connect" title="&sync.notconnected;" type="control"> - <button label="&sync.connect;" oncommand="WeaveGlue.show();" /> + <setting id="sync-autosync" pref="browser.sync.enabled" type="bool" title="&sync.synchronize;" oncommand="WeaveGlue.toggleSyncEnabled();"/> + <setting id="sync-connect" title="&sync.notconnected;" type="control" collapsed="true"> + <button label="&sync.connect;" oncommand="WeaveGlue.open();" /> </setting> - <setting id="sync-connected" title="&sync.connected;" type="control" collapsed="true"> + <setting id="sync-connected" class="setting-group" title="&sync.connected;" type="control" collapsed="true"> <button id="sync-details" label="&sync.details;" type="checkbox" autocheck="true" checked="false" oncommand="WeaveGlue.showDetails();" /> </setting> - <setting id="sync-autosync" type="bool" title="&sync.synchronize;" onchange="WeaveGlue.changeSync();" collapsed="true"/> - <setting id="sync-device" type="string" title="&sync.deviceName;" onchange="WeaveGlue.changeName(this);" collapsed="true"/> - <setting id="sync-disconnect" type="control" collapsed="true"> - <button label="&sync.disconnect;" oncommand="WeaveGlue.disconnect();" /> - </setting> - <setting id="sync-sync" type="control" collapsed="true"> + <setting id="sync-sync" class="setting-subgroup" type="control" collapsed="true"> <button id="sync-syncButton" label="&sync.syncNow;" oncommand="WeaveGlue.sync();"/> </setting> + <setting id="sync-device" class="setting-subgroup" type="string" title="&sync.deviceName;" onchange="WeaveGlue.changeName(this);" collapsed="true"/> + <setting id="sync-disconnect" class="setting-subgroup" type="control" collapsed="true"> + <button label="&sync.disconnect;" oncommand="WeaveGlue.disconnect();" /> + </setting> </settings> #endif <settings id="prefs-privacy" label="&privacy.title;"> @@ -520,47 +520,46 @@ #ifdef MOZ_SERVICES_SYNC <vbox id="syncsetup-container" class="panel-dark window-width window-height" hidden="true"> - <scrollbox align="center" orient="vertical" flex="1"> - <vbox id="syncsetup-jpake" align="center" style="padding: 8px" flex="1"> - <description>&sync.setup.title;</description> + <hbox class="syncsetup-title"> + <description>&sync.setup.title;</description> +#ifndef ANDROID + <spacer flex="1"/> + <toolbarbutton id="tool-syncsetup-close" class="panel-close" oncommand="WeaveGlue.close();"/> +#endif + </hbox> + <scrollbox id="syncsetup-scrollbox" orient="vertical" flex="1"> + <vbox id="syncsetup-jpake" class="syncsetup-page" flex="1"> + <description class="syncsetup-center" flex="1">&sync.setup.jpake;</description> <separator/> - <hbox align="start"> - <description flex="1">&sync.setup.jpake;</description> - </hbox> - <separator/> - <vbox align="center"> - <textbox readonly="true">code</textbox> - <textbox readonly="true">goes</textbox> - <textbox readonly="true">here</textbox> + <vbox align="center" flex="1"> + <description class="syncsetup-code">code</description> + <description class="syncsetup-code">goes</description> + <description class="syncsetup-code">here</description> </vbox> <separator/> - <description style="font-size: 18px; text-decoration: underline" onclick="document.getElementById('syncsetup-jpake').hidden = true; document.getElementById('syncsetup-manual').hidden = false;">&sync.fallback;</description> + <description class="syncsetup-center syncsetup-link" flex="1" onclick="WeaveGlue.openManual();">&sync.fallback;</description> <separator/> <hbox pack="center"> - <button oncommand="WeaveGlue.close();">Cancel</button> + <button oncommand="WeaveGlue.close();">&sync.setup.cancel;</button> </hbox> </vbox> - <vbox id="syncsetup-manual" style="padding: 8px" flex="1" hidden="true"> - <hbox pack="center"> - <description>&sync.setup.title;</description> - </hbox> - <separator/> - <description>&sync.setup.manual;</description> + <vbox id="syncsetup-manual" class="syncsetup-page" flex="1" hidden="true"> + <description class="syncsetup-center">&sync.setup.manual;</description> <separator/> <textbox id="syncsetup-account" placeholder="&sync.account;"/> <textbox id="syncsetup-password" placeholder="&sync.password;" type="password"/> <textbox id="syncsetup-synckey" placeholder="&sync.syncKey;"/> <separator/> - <button id="syncsetup-customserver-checkbox" type="checkbox" class="button-checkbox" pack="start"> + <button id="syncsetup-usecustomserver" type="checkbox" class="button-checkbox" pack="start" oncommand="WeaveGlue.toggleCustomServer();"> <image class="button-image-icon"/> - <description class="prompt-checkbox-label" flex="1">&sync.customServer;</description> + <description class="syncsetup-label" flex="1">&sync.customServer;</description> </button> <textbox id="syncsetup-customserver" placeholder="&sync.serverURL;"/> <separator/> <hbox pack="center"> - <button oncommand="WeaveGlue.close();">Cancel</button> + <button oncommand="WeaveGlue.close();">&sync.setup.cancel;</button> <separator/> - <button oncommand="WeaveGlue.close(); WeaveGlue.connect();">Connect</button> + <button oncommand="WeaveGlue.close(); WeaveGlue.connect();">&sync.setup.connect;</button> </hbox> </vbox> </scrollbox> diff --git a/mobile/chrome/content/sync.js b/mobile/chrome/content/sync.js index f306bd9c6bbd..947dd0f41f75 100644 --- a/mobile/chrome/content/sync.js +++ b/mobile/chrome/content/sync.js @@ -35,6 +35,7 @@ * ***** END LICENSE BLOCK ***** */ let WeaveGlue = { + setupData: null, autoConnect: false, init: function init() { @@ -45,21 +46,21 @@ let WeaveGlue = { this._addListeners(); + this.setupData = { account: "", password: "" , syncKey: "", customServer: "" }; + + let enableSync = Services.prefs.getBoolPref("browser.sync.enabled"); + if (enableSync) + this._elements.connect.collapsed = false; + // Generating keypairs is expensive on mobile, so disable it if (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED) { Weave.Service.keyGenEnabled = false; this.autoConnect = Services.prefs.getBoolPref("services.sync.autoconnect"); - if (this.autoConnect) { + if (enableSync && this.autoConnect) { // Put the settings UI into a state of "connecting..." if we are going to auto-connect - this._elements.connect.collapsed = false; - this._elements.sync.collapsed = false; - this._elements.connect.firstChild.disabled = true; - this._elements.sync.firstChild.disabled = true; - this._elements.connect.setAttribute("title", this._bundle.GetStringFromName("connecting.label")); - this._elements.autosync.value = true; try { this._elements.device.value = Services.prefs.getCharPref("services.sync.client.name"); @@ -68,47 +69,140 @@ let WeaveGlue = { } }, - show: function show() { + open: function open() { // Show the connect UI document.getElementById("syncsetup-container").hidden = false; document.getElementById("syncsetup-jpake").hidden = false; document.getElementById("syncsetup-manual").hidden = true; + + BrowserUI.pushDialog(this); }, + openManual: function openManual() { + // Reset the scroll since the previous page might have been scrolled + let scrollbox = document.getElementById("syncsetup-scrollbox").boxObject.QueryInterface(Ci.nsIScrollBoxObject); + scrollbox.scrollTo(0, 0); + + document.getElementById("syncsetup-jpake").hidden = true; + document.getElementById("syncsetup-manual").hidden = false; + + // Push the current setup data into the UI + if (this.setupData && "account" in this.setupData) { + this._elements.account.value = this.setupData.account; + this._elements.password.value = this.setupData.password; + this._elements.synckey.value = this.setupData.syncKey; + if (this.setupData.customServer && this.setupData.customServer.length) { + this._elements.usecustomserver.checked = true; + this._elements.customserver.disabled = false; + this._elements.customserver.value = this.setupData.customServer; + } else { + this._elements.usecustomserver.checked = false; + this._elements.customserver.disabled = true; + this._elements.customserver.value = ""; + } + } + }, + close: function close() { + let scrollbox = document.getElementById("syncsetup-scrollbox").boxObject.QueryInterface(Ci.nsIScrollBoxObject); + scrollbox.scrollTo(0, 0); + + // Save current setup data + this.setupData = {}; + this.setupData.account = this._elements.account.value; + this.setupData.password = this._elements.password.value; + this.setupData.syncKey = this._elements.synckey.value; + this.setupData.customServer = this._elements.customserver.value; + + // Clear the UI so it's ready for next time + this._elements.account.value = ""; + this._elements.password.value = ""; + this._elements.synckey.value = ""; + this._elements.usecustomserver.checked = false; + this._elements.customserver.disable = true; + this._elements.customserver.value = ""; + // Close the connect UI document.getElementById("syncsetup-container").hidden = true; + BrowserUI.popDialog(); }, + toggleCustomServer: function toggleCustomServer() { + let useCustomServer = this._elements.usecustomserver.checked; + this._elements.customserver.disabled = !useCustomServer; + if (!useCustomServer) + this._elements.customserver.value = ""; + }, + showDetails: function showDetails() { // Show the connect UI detail settings let show = this._elements.details.checked; - this._elements.autosync.collapsed = show; - this._elements.device.collapsed = show; - this._elements.disconnect.collapsed = show; + this._elements.sync.collapsed = !show; + this._elements.device.collapsed = !show; + this._elements.disconnect.collapsed = !show; }, - connect: function connect() { + toggleSyncEnabled: function toggleSyncEnabled() { + let enabled = this._elements.autosync.value; + if (enabled) { + // Attempt to go back online + if (this.setupData) { + if (this.setupData.customServer && this.setupData.customServer.length) + Weave.Service.serverURL = this.setupData.customServer; + Weave.Service.login(Weave.Service.username, this.setupData.password, Weave.Utils.normalizePassphrase(this.setupData.syncKey)); + } else { + // We can't just go back online. We need to be setup again. + this._elements.connected.collapsed = true; + this._elements.connect.collapsed = false; + } + } else { + this._elements.connect.collapsed = true; + this._elements.connected.collapsed = true; + Weave.Service.logout(); + } + + // Close any 'Undo' notification, if one is present + let notification = this._msg.getNotificationWithValue("undo-disconnect"); + if (notification) + notification.close(); + }, + + connect: function connect(aSetupData) { + // Use setup data to pre-configure manual fields + if (aSetupData) + this.setupData = aSetupData; + // Cause the Sync system to reset internals if we seem to be switching accounts - if (this._elements.account.value != Weave.Service.account) + if (this.setupData.account != Weave.Service.account) Weave.Service.startOver(); - // Remove any leftover connection string + // Remove any leftover connection error string this._elements.connect.removeAttribute("desc"); + // Reset the custom server URL, if we have one + if (this.setupData.customServer && this.setupData.customServer.length) + Weave.Service.serverURL = this.setupData.customServer; + // Sync will use the account value and munge it into a username, as needed - Weave.Service.account = this._elements.account.value; - Weave.Service.login(Weave.Service.username, this._elements.password.value, this.normalizePassphrase(this._elements.synckey.value)); + Weave.Service.account = this.setupData.account; + Weave.Service.login(Weave.Service.username, this.setupData.password, Weave.Utils.normalizePassphrase(this.setupData.syncKey)); Weave.Service.persistLogin(); }, disconnect: function disconnect() { + // Save credentials for undo + let undoData = this.setupData; + + // Remove all credentials + this.setupData = null; + Weave.Service.startOver(); + let message = this._bundle.GetStringFromName("notificationDisconnect.label"); let button = this._bundle.GetStringFromName("notificationDisconnect.button"); let buttons = [ { label: button, accessKey: "", - callback: function() { WeaveGlue.connect(); } + callback: function() { WeaveGlue.connect(undoData); } } ]; this.showMessage(message, "undo-disconnect", buttons); @@ -119,8 +213,6 @@ let WeaveGlue = { notification.close(); }, 10000, this); - // TODO: When the notification closes, not from the "undo" button, we should clean up the credentials - Weave.Service.logout(); }, @@ -155,7 +247,7 @@ let WeaveGlue = { // Get all the setting nodes from the add-ons display let elements = {}; - let setupids = ["account", "password", "synckey", "customserver"]; + let setupids = ["account", "password", "synckey", "usecustomserver", "customserver"]; setupids.forEach(function(id) { elements[id] = document.getElementById("syncsetup-" + id); }); @@ -186,27 +278,32 @@ let WeaveGlue = { return; // Make some aliases - let account = this._elements.account; - let password = this._elements.password; - let synckey = this._elements.synckey; let connect = this._elements.connect; let connected = this._elements.connected; let autosync = this._elements.autosync; + let details = this._elements.details; let device = this._elements.device; let disconnect = this._elements.disconnect; let sync = this._elements.sync; - // Make sure the options are in the right state - connect.collapsed = loggedIn; - connected.collapsed = !loggedIn; - sync.collapsed = !loggedIn; + let syncEnabled = this._elements.autosync.value; - if (connected.collapsed) { + // If Sync is not enabled, hide the connection row visibility + if (syncEnabled) { + connect.collapsed = loggedIn; + connected.collapsed = !loggedIn; + } else { + connect.collapsed = true; + connected.collapsed = true; + } + + if (!loggedIn) { connect.setAttribute("title", this._bundle.GetStringFromName("notconnected.label")); - this._elements.details.checked = false; - this._elements.autosync.collapsed = true; - this._elements.device.collapsed = true; - this._elements.disconnect.collapsed = true; + connect.firstChild.disabled = false; + details.checked = false; + sync.collapsed = true; + device.collapsed = true; + disconnect.collapsed = true; } // Check the lock on a timeout because it's set just after notifying @@ -227,13 +324,6 @@ let WeaveGlue = { } }, 0, this); - // Move the disconnect and sync settings out to make connect the last item - let parent = connect.parentNode; - if (!loggedIn) - parent = parent.parentNode; - parent.appendChild(disconnect); - parent.appendChild(sync); - // Dynamically generate some strings let accountStr = this._bundle.formatStringFromName("account.label", [Weave.Service.account], 1); disconnect.setAttribute("title", accountStr); @@ -252,6 +342,24 @@ let WeaveGlue = { else connect.removeAttribute("desc"); + // Init the setup data if we just logged in from an autoConnect + if (!this.setupData && this.autoConnect && aTopic == "weave:service:login:finish") { + this.setupData = {}; + this.setupData.account = Weave.Service.account || ""; + this.setupData.password = Weave.Service.password || ""; + + let pp = Weave.Service.passphrase || ""; + if (pp.length == 20) + pp = Weave.Utils.hyphenatePassphrase(pp); + this.setupData.syncKey = pp; + + let serverURL = Weave.Service.serverURL; + let defaultPrefs = Services.prefs.getDefaultBranch(null); + if (serverURL == defaultPrefs.getCharPref("services.sync.serverURL")) + serverURL = ""; + this.setupData.customServer = serverURL; + } + // Reset the auto-connect flag after the first attempted login if (aTopic == "weave:service:login:finish" || aTopic == "weave:service:login:error") this.autoConnect = false; @@ -291,13 +399,6 @@ let WeaveGlue = { } } - // Load the values for the string inputs - account.value = Weave.Service.account || ""; - password.value = Weave.Service.password || ""; - let pp = Weave.Service.passphrase || ""; - if (pp.length == 20) - pp = this.hyphenatePassphrase(pp); - synckey.value = pp; device.value = Weave.Clients.localName || ""; }, @@ -307,30 +408,11 @@ let WeaveGlue = { aInput.value = Weave.Clients.localName; }, - changeSync: function changeSync() { - // XXX enable/disable sync without actually disconnecting - }, - showMessage: function showMessage(aMsg, aValue, aButtons) { let notification = this._msg.getNotificationWithValue(aValue); if (notification) return; this._msg.appendNotification(aMsg, aValue, "", this._msg.PRIORITY_WARNING_LOW, aButtons); - }, - - hyphenatePassphrase: function(passphrase) { - // Hyphenate a 20 character passphrase in 4 groups of 5 - return passphrase.slice(0, 5) + '-' - + passphrase.slice(5, 10) + '-' - + passphrase.slice(10, 15) + '-' - + passphrase.slice(15, 20); - }, - - normalizePassphrase: function(pp) { - // Remove hyphens as inserted by hyphenatePassphrase() - if (pp.length == 23 && pp[5] == '-' && pp[11] == '-' && pp[17] == '-') - return pp.slice(0, 5) + pp.slice(6, 11) + pp.slice(12, 17) + pp.slice(18, 23); - return pp; } }; diff --git a/mobile/locales/en-US/chrome/sync.dtd b/mobile/locales/en-US/chrome/sync.dtd index 5a2726b7ff19..c0f3a1268568 100644 --- a/mobile/locales/en-US/chrome/sync.dtd +++ b/mobile/locales/en-US/chrome/sync.dtd @@ -17,3 +17,5 @@ <!ENTITY sync.syncKey "Sync Key"> <!ENTITY sync.customServer "Use custom server"> <!ENTITY sync.serverURL "Server URL"> +<!ENTITY sync.setup.connect "Connect"> +<!ENTITY sync.setup.cancel "Cancel"> diff --git a/mobile/themes/core/browser.css b/mobile/themes/core/browser.css index 0ac79a190462..04cc9ec367f1 100644 --- a/mobile/themes/core/browser.css +++ b/mobile/themes/core/browser.css @@ -356,7 +356,7 @@ toolbarbutton.button-control:not([disabled="true"]):hover:active { %ifndef ANDROID /* MAEMO (and desktop) only */ -#tool-panel-close { +.panel-close { min-width: 72px !important; /* 72, not 64 to make up for the negative margin */ max-width: 72px !important; /* 72, not 64 to make up for the negative margin */ min-height: 72px !important; /* 72, not 64 to make up for the negative margin */ @@ -365,19 +365,19 @@ toolbarbutton.button-control:not([disabled="true"]):hover:active { border: none !important; } -#tool-panel-close:hover:active { +.panel-close:hover:active { background-color: #8db8d8 !important; } -#tool-panel-close:hover:active:-moz-locale-dir(ltr) { +.panel-close:hover:active:-moz-locale-dir(ltr) { -moz-border-radius-bottomleft: 6px; } -#tool-panel-close:-moz-locale-dir(rtl) { +.panel-close:-moz-locale-dir(rtl) { list-style-image: url("chrome://browser/skin/images/task-back-rtl-hdpi.png"); } -#tool-panel-close:hover:active:-moz-locale-dir(rtl) { +.panel-close:hover:active:-moz-locale-dir(rtl) { -moz-border-radius-bottomright: 6px; } %endif @@ -1174,6 +1174,19 @@ pageaction:not([image]) > hbox >.pageaction-image { -moz-box-align: center; } +.setting-group > .prefbox { + border-bottom: none; +} + +.setting-subgroup > .prefbox { + border-bottom: none; + -moz-margin-start: 16px; +} + +.setting-subgroup + :not(.setting-subgroup) > .prefbox { + border-top: 1px solid rgb(207,207,207); +} + /* Put setting textboxes on a separate row in portrait */ @media (max-width: 499px) { .setting-integer, @@ -1546,3 +1559,35 @@ pageaction:not([image]) > hbox >.pageaction-image { width: 33.33%; } } + +/* Sync setup ------------------------------------------------------------- */ +.syncsetup-page { + padding: 8px; + background-color: #000; +} + +.syncsetup-center { + text-align: center; +} + +.syncsetup-title { + -moz-box-align: center; +} + +.syncsetup-code { + color: #000; + background-color: #fff; + padding: 0.5em; + -moz-padding-end: 0.25em; + letter-spacing: 0.5em; + text-align: center; + min-width: 8em; +} + +.syncsetup-link { + text-decoration: underline; +} + +.syncsetup-label { + color: #fff; +} diff --git a/mobile/themes/core/platform.css b/mobile/themes/core/platform.css index cd95a08f105a..05315237bd87 100644 --- a/mobile/themes/core/platform.css +++ b/mobile/themes/core/platform.css @@ -94,6 +94,10 @@ textbox.search-bar { background: url("chrome://browser/skin/images/textbox-bg.png") top left repeat-x; } +textbox[disabled="true"] { + background-color: lightgray; +} + /* sidebars spacer --------------------------------------------------------- */ .sidebar-spacer { background-color: #767973; @@ -180,7 +184,8 @@ button:focus > .button-box { border: 1px solid transparent; } -button:not([disabled]):hover:active { +button:not([disabled]):hover:active, +button:not([disabled])[checked="true"] { background-image: url("chrome://browser/skin/images/toggle-off.png"); }