Skip to content

Commit

Permalink
Bug 1139677 - Display the user's FxA profile image in the Sync Pref p…
Browse files Browse the repository at this point in the history
…ane r=markh,rfeeley
  • Loading branch information
zaach committed Mar 27, 2015
1 parent b7bbc01 commit 8007600
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 41 deletions.
55 changes: 53 additions & 2 deletions browser/components/preferences/in-content/sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ let gSyncPane = {
"weave:service:start-over:finish",
"weave:service:setup-complete",
"weave:service:logout:finish",
FxAccountsCommon.ONVERIFIED_NOTIFICATION];
FxAccountsCommon.ONVERIFIED_NOTIFICATION,
FxAccountsCommon.ON_PROFILE_CHANGE_NOTIFICATION,
];
let migrateTopic = "fxa-migration:state-changed";

// Add the observers now and remove them on unload
Expand Down Expand Up @@ -123,6 +125,8 @@ let gSyncPane = {
}),

this.updateWeavePrefs();

this._initProfileImageUI();
},

_setupEventListeners: function() {
Expand Down Expand Up @@ -224,6 +228,14 @@ let gSyncPane = {
});
},

_initProfileImageUI: function () {
try {
if (Services.prefs.getBoolPref("identity.fxaccounts.profile_image.enabled")) {
document.getElementById("fxaProfileImage").hidden = false;
}
} catch (e) { }
},

updateWeavePrefs: function () {
// 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
Expand All @@ -244,10 +256,11 @@ let gSyncPane = {
}
// determine the fxa status...
this.page = PAGE_PLEASE_WAIT;

fxAccounts.getSignedInUser().then(data => {
if (!data) {
this.page = FXA_PAGE_LOGGED_OUT;
return;
return false;
}
this.page = FXA_PAGE_LOGGED_IN;
// We are logged in locally, but maybe we are in a state where the
Expand Down Expand Up @@ -281,7 +294,36 @@ let gSyncPane = {
for (let checkbox of engines.querySelectorAll("checkbox")) {
checkbox.disabled = enginesListDisabled;
}

// Clear the profile image (if any) of the previously logged in account.
document.getElementById("fxaProfileImage").style.removeProperty("background-image");

// If the account is verified the next promise in the chain will
// fetch profile data.
return data.verified;
}).then(shouldGetProfile => {
if (shouldGetProfile) {
return fxAccounts.getSignedInUserProfile();
}
}).then(data => {
if (data && data.avatar) {
// Make sure the image is available before displaying it,
// as we don't want to overwrite the default profile image
// with a broken/unavailable image
let img = new Image();
img.onload = () => {
let bgImage = "url('" + data.avatar + "')";
document.getElementById("fxaProfileImage").style.backgroundImage = bgImage;
};
img.src = data.avatar;
}
}, err => {
FxAccountsCommon.log.error(err);
}).catch(err => {
// If we get here something's really busted
Cu.reportError(String(err));
});

// If fxAccountEnabled is false and we are in a "not configured" state,
// then fxAccounts is probably fully disabled rather than just unconfigured,
// so handle this case. This block can be removed once we remove support
Expand Down Expand Up @@ -521,6 +563,15 @@ let gSyncPane = {
});
},

openChangeProfileImage: function() {
fxAccounts.promiseAccountsChangeProfileURI("avatar")
.then(url => {
this.openContentInBrowser(url, {
replaceQueryString: true
});
});
},

manageFirefoxAccount: function() {
let url = Services.prefs.getCharPref("identity.fxaccounts.settings.uri");
this.openContentInBrowser(url);
Expand Down
6 changes: 5 additions & 1 deletion browser/components/preferences/in-content/sync.xul
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,11 @@
<!-- logged in and verified and all is good -->
<hbox id="fxaLoginVerified"
align="center">
<label id="fxaEmailAddress1"/>
<hbox align="center">
<image id="fxaProfileImage"
onclick="gSyncPane.openChangeProfileImage();" hidden="true"/>
<label id="fxaEmailAddress1"/>
</hbox>
<spacer flex="1"/>
<button id="verifiedManage"
label="&manage.label;"/>
Expand Down
1 change: 1 addition & 0 deletions browser/themes/linux/jar.mn
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ browser.jar:
skin/classic/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
skin/classic/browser/preferences/in-content/icons.svg (../shared/incontentprefs/icons.svg)
skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
skin/classic/browser/preferences/in-content/default-profile-image.svg (../shared/incontentprefs/default-profile-image.svg)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
skin/classic/browser/preferences/search.css (preferences/search.css)
Expand Down
1 change: 1 addition & 0 deletions browser/themes/osx/jar.mn
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ browser.jar:
skin/classic/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
skin/classic/browser/preferences/in-content/icons.svg (../shared/incontentprefs/icons.svg)
skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
skin/classic/browser/preferences/in-content/default-profile-image.svg (../shared/incontentprefs/default-profile-image.svg)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
skin/classic/browser/preferences/search.css (preferences/search.css)
Expand Down
12 changes: 12 additions & 0 deletions browser/themes/shared/incontentprefs/default-profile-image.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions browser/themes/shared/incontentprefs/preferences.inc.css
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,22 @@ description > html|a {
cursor: pointer;
}

#fxaProfileImage {
width: 60px;
height: 60px;
border-radius: 50%;
border-width: 5px;
border-color: red;
background-image: url(chrome://browser/skin/preferences/in-content/default-profile-image.svg);
background-size: contain;
cursor: pointer;
-moz-margin-end: 15px;
}

#fxaProfileImage:hover {
border-color: blue;
}

#noFxaAccount {
/* Overriding the margins from the base preferences.css theme file.
These overrides can be simplified by fixing bug 1027174 */
Expand Down
1 change: 1 addition & 0 deletions browser/themes/windows/jar.mn
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ browser.jar:
skin/classic/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
skin/classic/browser/preferences/in-content/icons.svg (../shared/incontentprefs/icons.svg)
skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
skin/classic/browser/preferences/in-content/default-profile-image.svg (../shared/incontentprefs/default-profile-image.svg)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
skin/classic/browser/preferences/search.css (preferences/search.css)
Expand Down
60 changes: 36 additions & 24 deletions services/fxaccounts/FxAccounts.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ let publicProperties = [
"localtimeOffsetMsec",
"now",
"promiseAccountsForceSigninURI",
"promiseAccountsChangeProfileURI",
"resendVerificationEmail",
"setSignedInUser",
"signOut",
Expand Down Expand Up @@ -961,6 +962,34 @@ FxAccountsInternal.prototype = {
}).then(result => currentState.resolve(result));
},

// Returns a promise that resolves with the URL to use to change
// the current account's profile image.
// if settingToEdit is set, the profile page should hightlight that setting
// for the user to edit.
promiseAccountsChangeProfileURI: function(settingToEdit = null) {
let url = Services.urlFormatter.formatURLPref("identity.fxaccounts.settings.uri");

if (settingToEdit) {
url += (url.indexOf("?") == -1 ? "?" : "&") +
"setting=" + encodeURIComponent(settingToEdit);
}

if (this._requireHttps() && !/^https:/.test(url)) { // Comment to un-break emacs js-mode highlighting
throw new Error("Firefox Accounts server must use HTTPS");
}
let currentState = this.currentAccountState;
// but we need to append the email address onto a query string.
return this.getSignedInUser().then(accountData => {
if (!accountData) {
return null;
}
let newQueryPortion = url.indexOf("?") == -1 ? "?" : "&";
newQueryPortion += "email=" + encodeURIComponent(accountData.email);
newQueryPortion += "&uid=" + encodeURIComponent(accountData.uid);
return url + newQueryPortion;
}).then(result => currentState.resolve(result));
},

/**
* Get an OAuth token for the user
*
Expand Down Expand Up @@ -1078,30 +1107,13 @@ FxAccountsInternal.prototype = {
getSignedInUserProfile: function () {
let accountState = this.currentAccountState;
return accountState.getProfile()
.then(
(profileData) => {
let profile = JSON.parse(JSON.stringify(profileData));
// profileData doesn't include "verified", but it must be true
// if we've gotten this far.
profile.verified = true;
return accountState.resolve(profile);
},
(error) => {
log.error("Could not retrieve profile data", error);

return this.getSignedInUser().then(data => {
let profile = null;
if (data) {
// If we fail to fetch the profile and have no profile cached
// we resort to using the account data for basic profile data.
profile = {
email: data.email,
uid: data.uid,
verified: data.verified
};
}
return accountState.resolve(profile);
});
.then((profileData) => {
let profile = JSON.parse(JSON.stringify(profileData));
return accountState.resolve(profile);
},
(error) => {
log.error("Could not retrieve profile data", error);
return accountState.reject(error);
})
.then(null, err => this._errorToErrorClass(err));
},
Expand Down
33 changes: 19 additions & 14 deletions services/fxaccounts/tests/xpcshell/test_accounts.js
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,6 @@ add_test(function test_getSignedInUserProfile_ok() {
fxa.getSignedInUserProfile()
.then(result => {
do_check_eq(result.avatar, "image");
do_check_true(result.verified);
run_next_test();
});
});
Expand All @@ -946,34 +945,40 @@ add_test(function test_getSignedInUserProfile_error_uses_account_data() {
};

fxa.getSignedInUserProfile()
.then(result => {
do_check_eq(typeof result.avatar, "undefined");
do_check_eq(result.email, "[email protected]");
.catch(error => {
do_check_eq(error.message, "UNKNOWN_ERROR");
run_next_test();
});
});

});

add_test(function test_getSignedInUserProfile_no_account_data() {
add_test(function test_getSignedInUserProfile_unverified_account() {
let fxa = new MockFxAccounts();
let alice = getTestUser("alice");

fxa.internal.getSignedInUser = function () {
return Promise.resolve({ email: "[email protected]" });
};
fxa.setSignedInUser(alice).then(() => {
let accountState = fxa.internal.currentAccountState;

let accountState = fxa.internal.currentAccountState;
accountState.getProfile = function () {
return Promise.reject("boom");
};
fxa.getSignedInUserProfile()
.catch(error => {
do_check_eq(error.message, "UNVERIFIED_ACCOUNT");
run_next_test();
});
});

});

add_test(function test_getSignedInUserProfile_no_account_data() {
let fxa = new MockFxAccounts();

fxa.internal.getSignedInUser = function () {
return Promise.resolve(null);
};

fxa.getSignedInUserProfile()
.then(result => {
do_check_eq(result, null);
.catch(error => {
do_check_eq(error.message, "NO_ACCOUNT");
run_next_test();
});

Expand Down

0 comments on commit 8007600

Please sign in to comment.