mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 1686343 - Ask user to pin Firefox during windows about:welcome onboarding r=pdahiya
Support pin special action and add a new action property to wait for default browser that changes styles and content. Differential Revision: https://phabricator.services.mozilla.com/D105653
This commit is contained in:
parent
d3ac263f8c
commit
f348f8d342
@ -198,6 +198,10 @@ class AboutWelcomeChild extends JSWindowActorChild {
|
||||
defineAs: "AWGetRegion",
|
||||
});
|
||||
|
||||
Cu.exportFunction(this.AWIsDefaultBrowser.bind(this), window, {
|
||||
defineAs: "AWIsDefaultBrowser",
|
||||
});
|
||||
|
||||
Cu.exportFunction(this.AWSelectTheme.bind(this), window, {
|
||||
defineAs: "AWSelectTheme",
|
||||
});
|
||||
@ -338,6 +342,10 @@ class AboutWelcomeChild extends JSWindowActorChild {
|
||||
return this.wrapPromise(getSelectedTheme(this));
|
||||
}
|
||||
|
||||
AWIsDefaultBrowser() {
|
||||
return this.wrapPromise(this.sendQuery("AWPage:IS_DEFAULT_BROWSER"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send Event Telemetry
|
||||
* @param {object} eventData
|
||||
|
@ -267,6 +267,8 @@ class AboutWelcomeParent extends JSWindowActorParent {
|
||||
this.RegionHomeObserver = new RegionHomeObserver(this);
|
||||
}
|
||||
return this.RegionHomeObserver.promiseRegionHome();
|
||||
case "AWPage:IS_DEFAULT_BROWSER":
|
||||
return window.getShellService().isDefaultBrowser();
|
||||
case "AWPage:WAIT_FOR_MIGRATION_CLOSE":
|
||||
return new Promise(resolve =>
|
||||
Services.ww.registerNotification(function observer(subject, topic) {
|
||||
|
@ -453,6 +453,9 @@ class WelcomeScreen extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCom
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleAction = this.handleAction.bind(this);
|
||||
this.state = {
|
||||
alternateContent: ""
|
||||
};
|
||||
}
|
||||
|
||||
handleOpenURL(action, flowParams, UTMTerm) {
|
||||
@ -521,6 +524,23 @@ class WelcomeScreen extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCom
|
||||
await window.AWWaitForMigrationClose();
|
||||
_lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_3__["AboutWelcomeUtils"].sendActionTelemetry(props.messageId, "migrate_close");
|
||||
}
|
||||
} // Wait until we become default browser to continue rest of action.
|
||||
|
||||
|
||||
if (action.waitForDefault) {
|
||||
// Update the UI to show additional "waiting" content.
|
||||
this.setState({
|
||||
alternateContent: "waiting_for_default"
|
||||
}); // Keep checking frequently as we want the UI to be responsive.
|
||||
|
||||
await new Promise(resolve => async function checkDefault() {
|
||||
if (await window.AWIsDefaultBrowser()) {
|
||||
resolve();
|
||||
} else {
|
||||
setTimeout(checkDefault, 100);
|
||||
}
|
||||
}());
|
||||
_lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_3__["AboutWelcomeUtils"].sendActionTelemetry(props.messageId, "default_browser");
|
||||
} // A special tiles.action.theme value indicates we should use the event's value vs provided value.
|
||||
|
||||
|
||||
@ -668,10 +688,16 @@ class WelcomeScreen extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCom
|
||||
}
|
||||
|
||||
render() {
|
||||
// Use the provided content or switch to an alternate one.
|
||||
const {
|
||||
content,
|
||||
topSites
|
||||
} = this.props;
|
||||
|
||||
if (content[this.state.alternateContent]) {
|
||||
Object.assign(content, content[this.state.alternateContent]);
|
||||
}
|
||||
|
||||
const showImportableSitesDisclaimer = content.tiles && content.tiles.type === "topsites" && topSites && topSites.showImportable;
|
||||
return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("main", {
|
||||
className: `screen ${this.props.id}`
|
||||
@ -690,7 +716,7 @@ class WelcomeScreen extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCom
|
||||
className: "primary",
|
||||
value: "primary_button",
|
||||
onClick: this.handleAction
|
||||
}))), content.secondary_button ? this.renderSecondaryCTA() : null, content.help_text && content.help_text.position === "default" ? this.renderHelpText() : null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("nav", {
|
||||
}))), content.help_text && content.help_text.position === "default" ? this.renderHelpText() : null, content.secondary_button ? this.renderSecondaryCTA() : null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("nav", {
|
||||
className: content.help_text && content.help_text.position === "footer" || showImportableSitesDisclaimer ? "steps has-helptext" : "steps",
|
||||
"data-l10n-id": "onboarding-welcome-steps-indicator",
|
||||
"data-l10n-args": `{"current": ${parseInt(this.props.order, 10) + 1}, "total": ${this.props.totalNumberOfScreens}}`
|
||||
|
@ -457,6 +457,12 @@ body {
|
||||
margin: 0; }
|
||||
.onboardingContainer .tiles-media-section.privacy.media {
|
||||
opacity: 0; }
|
||||
.onboardingContainer .tiles-delayed {
|
||||
animation: fadein 0.4s; }
|
||||
|
||||
@keyframes fadein {
|
||||
from {
|
||||
opacity: 0; } }
|
||||
.onboardingContainer button {
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
|
@ -556,6 +556,14 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.tiles-delayed {
|
||||
animation: fadein 0.4s;
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from { opacity: 0; }
|
||||
}
|
||||
|
||||
button {
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
|
@ -136,6 +136,7 @@ export class WelcomeScreen extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleAction = this.handleAction.bind(this);
|
||||
this.state = { alternateContent: "" };
|
||||
}
|
||||
|
||||
handleOpenURL(action, flowParams, UTMTerm) {
|
||||
@ -193,6 +194,25 @@ export class WelcomeScreen extends React.PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
// Wait until we become default browser to continue rest of action.
|
||||
if (action.waitForDefault) {
|
||||
// Update the UI to show additional "waiting" content.
|
||||
this.setState({ alternateContent: "waiting_for_default" });
|
||||
|
||||
// Keep checking frequently as we want the UI to be responsive.
|
||||
await new Promise(resolve =>
|
||||
(async function checkDefault() {
|
||||
if (await window.AWIsDefaultBrowser()) {
|
||||
resolve();
|
||||
} else {
|
||||
setTimeout(checkDefault, 100);
|
||||
}
|
||||
})()
|
||||
);
|
||||
|
||||
AboutWelcomeUtils.sendActionTelemetry(props.messageId, "default_browser");
|
||||
}
|
||||
|
||||
// A special tiles.action.theme value indicates we should use the event's value vs provided value.
|
||||
if (action.theme) {
|
||||
let themeToUse =
|
||||
@ -383,7 +403,12 @@ export class WelcomeScreen extends React.PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
// Use the provided content or switch to an alternate one.
|
||||
const { content, topSites } = this.props;
|
||||
if (content[this.state.alternateContent]) {
|
||||
Object.assign(content, content[this.state.alternateContent]);
|
||||
}
|
||||
|
||||
const showImportableSitesDisclaimer =
|
||||
content.tiles &&
|
||||
content.tiles.type === "topsites" &&
|
||||
@ -416,10 +441,10 @@ export class WelcomeScreen extends React.PureComponent {
|
||||
/>
|
||||
</Localized>
|
||||
</div>
|
||||
{content.secondary_button ? this.renderSecondaryCTA() : null}
|
||||
{content.help_text && content.help_text.position === "default"
|
||||
? this.renderHelpText()
|
||||
: null}
|
||||
{content.secondary_button ? this.renderSecondaryCTA() : null}
|
||||
<nav
|
||||
className={
|
||||
(content.help_text && content.help_text.position === "footer") ||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 105 KiB |
@ -189,10 +189,10 @@ module.exports = function(config) {
|
||||
branches: 70,
|
||||
},
|
||||
"content-src/aboutwelcome/**/*.jsx": {
|
||||
statements: 50,
|
||||
lines: 50,
|
||||
functions: 76,
|
||||
branches: 0,
|
||||
statements: 62,
|
||||
lines: 60,
|
||||
functions: 83,
|
||||
branches: 50,
|
||||
},
|
||||
"content-src/components/**/*.jsx": {
|
||||
statements: 51.1,
|
||||
|
@ -214,5 +214,102 @@ describe("MultiStageAboutWelcome module", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("#handleAction", () => {
|
||||
let SCREEN_PROPS;
|
||||
let TEST_ACTION;
|
||||
beforeEach(() => {
|
||||
SCREEN_PROPS = {
|
||||
content: {
|
||||
primary_button: {
|
||||
action: {},
|
||||
label: "test button",
|
||||
},
|
||||
},
|
||||
navigate: sandbox.stub(),
|
||||
setActiveTheme: sandbox.stub(),
|
||||
UTMTerm: "you_tee_emm",
|
||||
};
|
||||
TEST_ACTION = SCREEN_PROPS.content.primary_button.action;
|
||||
sandbox.stub(AboutWelcomeUtils, "handleUserAction");
|
||||
});
|
||||
it("should handle navigate", () => {
|
||||
TEST_ACTION.navigate = true;
|
||||
const wrapper = mount(<WelcomeScreen {...SCREEN_PROPS} />);
|
||||
|
||||
wrapper.find(".primary").simulate("click");
|
||||
|
||||
assert.calledOnce(SCREEN_PROPS.navigate);
|
||||
});
|
||||
it("should handle theme", () => {
|
||||
TEST_ACTION.theme = "test";
|
||||
const wrapper = mount(<WelcomeScreen {...SCREEN_PROPS} />);
|
||||
|
||||
wrapper.find(".primary").simulate("click");
|
||||
|
||||
assert.calledWith(SCREEN_PROPS.setActiveTheme, "test");
|
||||
});
|
||||
it("should handle SHOW_FIREFOX_ACCOUNTS", () => {
|
||||
TEST_ACTION.type = "SHOW_FIREFOX_ACCOUNTS";
|
||||
const wrapper = mount(<WelcomeScreen {...SCREEN_PROPS} />);
|
||||
|
||||
wrapper.find(".primary").simulate("click");
|
||||
|
||||
assert.calledWith(AboutWelcomeUtils.handleUserAction, {
|
||||
data: {
|
||||
extraParams: {
|
||||
utm_campaign: "firstrun",
|
||||
utm_medium: "referral",
|
||||
utm_source: "activity-stream",
|
||||
utm_term: "aboutwelcome-you_tee_emm-screen",
|
||||
},
|
||||
},
|
||||
type: "SHOW_FIREFOX_ACCOUNTS",
|
||||
});
|
||||
});
|
||||
it("should handle SHOW_MIGRATION_WIZARD", () => {
|
||||
TEST_ACTION.type = "SHOW_MIGRATION_WIZARD";
|
||||
const wrapper = mount(<WelcomeScreen {...SCREEN_PROPS} />);
|
||||
|
||||
wrapper.find(".primary").simulate("click");
|
||||
|
||||
assert.calledWith(AboutWelcomeUtils.handleUserAction, {
|
||||
type: "SHOW_MIGRATION_WIZARD",
|
||||
});
|
||||
});
|
||||
it("should handle waitForDefault", () => {
|
||||
TEST_ACTION.waitForDefault = true;
|
||||
const wrapper = mount(<WelcomeScreen {...SCREEN_PROPS} />);
|
||||
|
||||
wrapper.find(".primary").simulate("click");
|
||||
|
||||
assert.propertyVal(
|
||||
wrapper.state(),
|
||||
"alternateContent",
|
||||
"waiting_for_default"
|
||||
);
|
||||
});
|
||||
});
|
||||
describe("alternate content", () => {
|
||||
const SCREEN_PROPS = {
|
||||
content: {
|
||||
title: "Original",
|
||||
alternate: {
|
||||
title: "Alternate",
|
||||
},
|
||||
},
|
||||
};
|
||||
it("should show original title", () => {
|
||||
const wrapper = mount(<WelcomeScreen {...SCREEN_PROPS} />);
|
||||
|
||||
assert.equal(wrapper.find(".welcome-text").text(), "Original");
|
||||
});
|
||||
it("should show alternate title", () => {
|
||||
const wrapper = mount(<WelcomeScreen {...SCREEN_PROPS} />);
|
||||
|
||||
wrapper.setState({ alternateContent: "alternate" });
|
||||
|
||||
assert.equal(wrapper.find(".welcome-text").text(), "Alternate");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -79,6 +79,23 @@ const SpecialMessageActions = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Pin Firefox to taskbar.
|
||||
*
|
||||
* @param {Window} window Reference to a window object
|
||||
*/
|
||||
pinFirefoxToTaskbar(window) {
|
||||
try {
|
||||
// Currently this only works on certain Windows versions.
|
||||
window
|
||||
.getShellService()
|
||||
.QueryInterface(Ci.nsIWindowsShellService)
|
||||
.pinCurrentAppToTaskbar();
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set browser as the operating system default browser.
|
||||
*
|
||||
@ -229,6 +246,13 @@ const SpecialMessageActions = {
|
||||
action.data.telemetrySource
|
||||
);
|
||||
break;
|
||||
case "PIN_FIREFOX_TO_TASKBAR":
|
||||
this.pinFirefoxToTaskbar(window);
|
||||
break;
|
||||
case "PIN_AND_DEFAULT":
|
||||
this.pinFirefoxToTaskbar(window);
|
||||
this.setDefaultBrowser(window);
|
||||
break;
|
||||
case "SET_DEFAULT_BROWSER":
|
||||
this.setDefaultBrowser(window);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user