Bug 1404193 - enable customizable logo, speech bubble string, and hide the skip button;r=Fischer

MozReview-Commit-ID: 1cHpXouqNCg

--HG--
extra : rebase_source : 4b1a52b2e044f92fed5856a9fc397b6546c11584
This commit is contained in:
gasolin 2017-10-19 13:16:32 +08:00
Родитель 55703dd1f1
Коммит abb89f528c
4 изменённых файлов: 67 добавлений и 10 удалений

Просмотреть файл

@ -49,6 +49,8 @@ Edit `browser/app/profile/firefox.js` and modify `browser.onboarding.newtour` fo
## How to pump tour set version after update tours
We only update the tourset version when we have different **update** tourset. Update the new tourset **does not** require update the tourset version.
The tourset version is used to track the last major tourset change version. The `tourset-version` pref store the major tourset version (ex: `1`) but not the current browser version. When browser update to the next version (ex: 58, 59) the tourset pref is still `1` if we didn't do any major tourset update.
Once the tour set version is updated (ex: `2`), onboarding overlay should show the update tour to the updated user (ex: update from v56 -> v57), even when user has watched the previous tours or preferred to hide the previous tours.
@ -64,3 +66,22 @@ By default, it shows `default` state.
When either tours or notifications are all completed, the icon changes to the `watermark` state.
The icon state is stored in `browser.onboarding.state`.
When `tourset-version` is updated, or when we detect the `tour-type` is changed to `update`, icon state will be changed back to the `default` state.
## Customizable preferences
Here are current support preferences that allow to customize the Onboarding's behavior.
| PREF | DESCRIPTION | DEFAULT |
|-----|-------------|:-----:|
| `browser.onboarding.enabled` | disable onboarding experience entirely | true
| `browser.onboarding.notification.finished` | Decide if we want to hide the notification permanently. | false
| `browser.onboarding.notification.mute-duration-on-first-session-ms` |Notification mute duration. It also effect when the speech bubble is hidden and turned into the blue dot | 300000 (5 Min)
| `browser.onboarding.notification.max-life-time-all-tours-ms` | Notification tours will all hide after this period | 1209600000 (10 Days)
| `browser.onboarding.notification.max-life-time-per-tours-ms` | Per Notification tours will hide and show the next tour after this period | 432000000 (5 Days)
| `browser.onboarding.notification.max-prompt-count-per-tour` | Each tour can only show the specific times in notification bar if user didn't interact with the tour notification. | 8
| `browser.onboarding.newtour` | The tourset of new user tour. | performance,private,screenshots,addons,customize,default
| `browser.onboarding.newtour.tooltip` | The string id which is shown in the new user tour's speech bubble. The preffered length is 2 lines. Should use `%S` to denote Firefox (brand short name) in string, or use `%1$S` if the name shows more than 1 time. | `onboarding.overlay-icon-tooltip2`
| `browser.onboarding.updatetour` | The tourset of new user tour. | performance,library,screenshots,singlesearch,customize,sync
| `browser.onboarding.updatetour.tooltip` | The string id which is shown in the update user tour's speech bubble. The preffered length is 2 lines. Should use `%S` to denote Firefox (brand short name) in string, or use `%1$S` if the name shows shows more than 1 time. | `onboarding.overlay-icon-tooltip-updated2`
| `browser.onboarding.default-icon-src` | The default icon url. Should be svg or at least 64x64 | `chrome://branding/content/icon64.png`
| `browser.onboarding.watermark-icon-src` | The watermark icon url. Should be svg or at least 64x64 | `resource://onboarding/img/watermark.svg`

Просмотреть файл

@ -22,9 +22,10 @@ const PROMPT_COUNT_PREF = "browser.onboarding.notification.prompt-count";
const ONBOARDING_DIALOG_ID = "onboarding-overlay-dialog";
const ONBOARDING_MIN_WIDTH_PX = 960;
const SPEECH_BUBBLE_MIN_WIDTH_PX = 1130;
const SPEECH_BUBBLE_NEWTOUR_STRING_ID = "onboarding.overlay-icon-tooltip2";
const SPEECH_BUBBLE_UPDATETOUR_STRING_ID = "onboarding.overlay-icon-tooltip-updated2";
const ICON_STATE_WATERMARK = "watermark";
const ICON_STATE_DEFAULT = "default";
/**
* Add any number of tours, key is the tourId, value should follow the format below
* "tourId": { // The short tour id which could be saved in pref
@ -1130,6 +1131,11 @@ class Onboarding {
_renderOverlay() {
let div = this._window.document.createElement("div");
div.id = "onboarding-overlay";
let skipButtonMarkup = "";
if (!Services.prefs.getBoolPref("browser.onboarding.skip-tour-button.hide", false)) {
let label = this._bundle.GetStringFromName("onboarding.skip-tour-button-label");
skipButtonMarkup = `<button id="onboarding-skip-tour-button" class="onboarding-action-button">${label}</button>`;
}
// We use `innerHTML` for more friendly reading.
// The security should be fine because this is not from an external input.
div.innerHTML = `
@ -1139,7 +1145,7 @@ class Onboarding {
<ul id="onboarding-tour-list" role="tablist"></ul>
</nav>
<footer id="onboarding-footer">
<button id="onboarding-skip-tour-button" class="onboarding-action-button"></button>
${skipButtonMarkup}
</footer>
<button id="onboarding-overlay-close-btn" class="onboarding-close-btn"></button>
</div>
@ -1147,9 +1153,6 @@ class Onboarding {
this._dialog = div.querySelector(`[role="dialog"]`);
this._dialog.id = ONBOARDING_DIALOG_ID;
div.querySelector("#onboarding-skip-tour-button").textContent =
this._bundle.GetStringFromName("onboarding.skip-tour-button-label");
div.querySelector("#onboarding-header").textContent =
this._bundle.GetStringFromName("onboarding.overlay-title2");
let closeBtn = div.querySelector("#onboarding-overlay-close-btn");
@ -1160,9 +1163,25 @@ class Onboarding {
_renderOverlayButton() {
let button = this._window.document.createElement("button");
let tooltipStringId = this._tourType === "new" ?
"onboarding.overlay-icon-tooltip2" : "onboarding.overlay-icon-tooltip-updated2";
let tooltip = this._bundle.formatStringFromName(tooltipStringId, [BRAND_SHORT_NAME], 1);
// support customize speech bubble string via pref
let tooltipStringPrefId = "";
let defaultTourStringId = "";
if (this._tourType === "new") {
tooltipStringPrefId = "browser.onboarding.newtour.tooltip";
defaultTourStringId = SPEECH_BUBBLE_NEWTOUR_STRING_ID;
} else {
tooltipStringPrefId = "browser.onboarding.updatetour.tooltip";
defaultTourStringId = SPEECH_BUBBLE_UPDATETOUR_STRING_ID;
}
let tooltip = "";
try {
let tooltipStringId = Services.prefs.getStringPref(tooltipStringPrefId, defaultTourStringId);
tooltip = this._bundle.formatStringFromName(tooltipStringId, [BRAND_SHORT_NAME], 1);
} catch (e) {
Cu.reportError(`the provided ${tooltipStringPrefId} string is in wrong format `, e);
// fallback to defaultTourStringId to proceed
tooltip = this._bundle.formatStringFromName(defaultTourStringId, [BRAND_SHORT_NAME], 1);
}
button.setAttribute("aria-label", tooltip);
button.id = "onboarding-overlay-button";
button.setAttribute("aria-haspopup", true);
@ -1170,12 +1189,14 @@ class Onboarding {
let defaultImg = this._window.document.createElement("img");
defaultImg.id = "onboarding-overlay-button-icon";
defaultImg.setAttribute("role", "presentation");
defaultImg.src = "chrome://branding/content/icon64.png";
defaultImg.src = Services.prefs.getStringPref("browser.onboarding.default-icon-src",
"chrome://branding/content/icon64.png");
button.appendChild(defaultImg);
let watermarkImg = this._window.document.createElement("img");
watermarkImg.id = "onboarding-overlay-button-watermark-icon";
watermarkImg.setAttribute("role", "presentation");
watermarkImg.src = "resource://onboarding/img/watermark.svg";
watermarkImg.src = Services.prefs.getStringPref("browser.onboarding.watermark-icon-src",
"resource://onboarding/img/watermark.svg");
button.appendChild(watermarkImg);
return button;
}

Просмотреть файл

@ -26,3 +26,17 @@ add_task(async function test_skip_onboarding_tours() {
await BrowserTestUtils.removeTab(tab);
});
add_task(async function test_hide_skip_button_via_perf() {
resetOnboardingDefaultState();
Preferences.set("browser.onboarding.skip-tour-button.hide", true);
let tab = await openTab(ABOUT_NEWTAB_URL);
await promiseOnboardingOverlayLoaded(tab.linkedBrowser);
await BrowserTestUtils.synthesizeMouseAtCenter("#onboarding-overlay-button", {}, tab.linkedBrowser);
await promiseOnboardingOverlayOpened(tab.linkedBrowser);
ok(!content.document.querySelector("#onboarding-skip-tour-button"), "should not render the skip button");
await BrowserTestUtils.removeTab(tab);
});

Просмотреть файл

@ -40,6 +40,7 @@ function resetOnboardingDefaultState() {
Preferences.reset("browser.onboarding.notification.last-time-of-changing-tour-sec");
Preferences.reset("browser.onboarding.notification.prompt-count");
Preferences.reset("browser.onboarding.notification.tour-ids-queue");
Preferences.reset("browser.onboarding.skip-tour-button.hide");
TOUR_IDs.forEach(id => Preferences.reset(`browser.onboarding.tour.${id}.completed`));
UPDATE_TOUR_IDs.forEach(id => Preferences.reset(`browser.onboarding.tour.${id}.completed`));
}