Bug 602685 - Sync UI: Implement easy setup for Fennec (part 2 - basic functionality) [r=mbrubeck]

This commit is contained in:
Mark Finkle 2010-11-22 22:48:55 -05:00
parent 32cbf68dea
commit 8c63ff6cf7
7 changed files with 241 additions and 105 deletions

View File

@ -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);

View File

@ -362,7 +362,7 @@ let ContentScroll = {
sendAsyncMessage("MozScrolledAreaChanged", {
width: width,
height: height,
height: height
});
break;

View File

@ -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>

View File

@ -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;
}
};

View File

@ -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">

View File

@ -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;
}

View File

@ -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");
}