diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
index 6a55afad6c24a..11dcfb785d97a 100644
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1194,8 +1194,9 @@ pref("browser.smartwindow.insights", "{}");
pref("browser.smartwindow.key", "sk-xblVm-OUfsPY0C1dER1LLQ");
pref("browser.smartwindow.model", "qwen3-235b-a22b-instruct-2507-maas");
pref("browser.smartwindow.chatHistory.loglevel", "Warn");
-pref("browser.smartwindow.skipOnboarding", true);
pref("browser.smartwindow.requireSignIn", false);
+pref("browser.smartwindow.tos", false);
+pref("browser.smartwindow.isfirstrun", false);
// Scripts & Windows prefs
pref("dom.disable_open_during_load", true);
diff --git a/browser/base/content/browser-smart-window.js b/browser/base/content/browser-smart-window.js
index 898350ca3579d..8aab6eea12685 100644
--- a/browser/base/content/browser-smart-window.js
+++ b/browser/base/content/browser-smart-window.js
@@ -8,6 +8,9 @@ var SmartWindow = {
PAGE_URL: Services.io.newURI(
"chrome://browser/content/smartwindow/smartwindow.html"
),
+ FIRST_RUN_URL: Services.io.newURI(
+ "chrome://browser/content/smartwindow/firstrun.html"
+ ),
_initialized: false,
_viewInitialized: false,
@@ -67,7 +70,7 @@ var SmartWindow = {
},
_isSmartPage(browser) {
- return !!browser?.currentURI?.equalsExceptRef(this.PAGE_URL);
+ return !!browser?.currentURI?.equalsExceptRef(this.PAGE_URL) || !!browser?.currentURI?.equalsExceptRef(this.FIRST_RUN_URL);
},
_ensureViewInitialized() {
@@ -92,61 +95,51 @@ var SmartWindow = {
this.toggleSmartWindow();
break;
case "smart-window-switch-smart": {
- const skipOnboarding = Services.prefs.getBoolPref(
- "browser.smartwindow.skipOnboarding",
- true
- );
- const completedOnboarding = Services.prefs.getBoolPref(
- "messaging-system-action.smart-window-tos",
+ const requireSignIn = Services.prefs.getBoolPref(
+ "browser.smartwindow.requireSignIn",
false
);
- if (skipOnboarding || completedOnboarding) {
- const requireSignIn = Services.prefs.getBoolPref(
- "browser.smartwindow.requireSignIn",
- false
+ if (!requireSignIn) {
+ this.toggleSmartWindow();
+ break;
+ }
+ const { UIState } = ChromeUtils.importESModule(
+ "resource://services-sync/UIState.sys.mjs"
+ );
+ const currentState = UIState.get();
+
+ if (currentState.status !== UIState.STATUS_SIGNED_IN) {
+ console.warn(
+ "[Smart Window] User not authenticated, sign in with FxA"
);
- if (requireSignIn) {
- const { UIState } = ChromeUtils.importESModule(
- "resource://services-sync/UIState.sys.mjs"
+ try {
+ const { SpecialMessageActions } = ChromeUtils.importESModule(
+ "resource://messaging-system/lib/SpecialMessageActions.sys.mjs"
+ );
+ // FXA_SMART_WINDOW_SIGNIN_FLOW handles toggling smart window on success
+ // TODO: we should await handleAction and set tos and isfirstrun pref here
+ // instead of SpecialMessageActions
+ SpecialMessageActions.handleAction(
+ {
+ type: "FXA_SMART_WINDOW_SIGNIN_FLOW",
+ data: {
+ entrypoint: "aimode",
+ },
+ },
+ gBrowser.selectedBrowser
+ );
+ break;
+ } catch (error) {
+ console.error(
+ "[Smart Window] Error during FxA sign-in:",
+ error
);
- const currentState = UIState.get();
-
- if (currentState.status !== UIState.STATUS_SIGNED_IN) {
- console.warn(
- "[Smart Window] User not authenticated, sign in with FxA"
- );
-
- try {
- const { SpecialMessageActions } = ChromeUtils.importESModule(
- "resource://messaging-system/lib/SpecialMessageActions.sys.mjs"
- );
- // FXA_SMART_WINDOW_SIGNIN_FLOW handles toggling smart window on success
- SpecialMessageActions.handleAction(
- {
- type: "FXA_SMART_WINDOW_SIGNIN_FLOW",
- data: {
- entrypoint: "aimode",
- },
- },
- gBrowser.selectedBrowser
- );
- break;
- } catch (error) {
- console.error(
- "[Smart Window] Error during FxA sign-in:",
- error
- );
- }
- }
}
-
- this.toggleSmartWindow();
} else {
- this.showOnboarding();
+ this.toggleSmartWindow();
}
-
break;
}
case "smart-window-dev-onboarding":
@@ -187,13 +180,18 @@ var SmartWindow = {
}
},
- showOnboarding() {
- window.openTrustedLinkIn(
- Services.urlFormatter.formatURL(
- "chrome://browser/content/smartwindow/welcome.html"
- ),
- "tab"
- );
+ // Shows Post login first run onboarding
+ async showOnboarding() {
+ return new Promise(resolve => {
+ window.openTrustedLinkIn(
+ Services.urlFormatter.formatURL(
+ "chrome://browser/content/smartwindow/firstrun.html"
+ ),
+ "tab"
+ );
+ // Resolve after a brief delay to ensure the window is opened
+ setTimeout(() => resolve(), 2000);
+ });
},
toggleSmartWindow() {
@@ -223,8 +221,14 @@ var SmartWindow = {
* Can be omitted if not switching from classic to smart
* window mode.
*/
- reconcileUIToSmartWindowState(oldNewTabURL = "") {
+ async reconcileUIToSmartWindowState(oldNewTabURL = "") {
if (this.isSmartWindowActive()) {
+ // Show the first run onboarding first time user switches to smart window mode
+ if (Services.prefs.getBoolPref("browser.smartwindow.isfirstrun", false)) {
+ Services.prefs.setBoolPref("browser.smartwindow.isfirstrun", false);
+ await this.showOnboarding();
+ }
+
// Check if we're on a smart window page
const isSmartWindowPage = this._isSmartPage(gBrowser.selectedBrowser);
diff --git a/browser/components/smartwindow/content/firstrun.html b/browser/components/smartwindow/content/firstrun.html
new file mode 100644
index 0000000000000..e3da9cb7ff6ce
--- /dev/null
+++ b/browser/components/smartwindow/content/firstrun.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Welcome Screen
+
+
+
+
+
+
+
+
+
diff --git a/browser/components/smartwindow/content/firstrun.js b/browser/components/smartwindow/content/firstrun.js
new file mode 100644
index 0000000000000..0bf53b752395e
--- /dev/null
+++ b/browser/components/smartwindow/content/firstrun.js
@@ -0,0 +1,276 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const lazy = {};
+const { topChromeWindow } = window.browsingContext;
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ AboutWelcomeParent: "resource:///actors/AboutWelcomeParent.sys.mjs",
+});
+
+XPCOMUtils.defineLazyPreferenceGetter(
+ lazy,
+ "onboardingConfig",
+ "browser.smartwindow.onboarding.config",
+ JSON.stringify({
+ id: "smart-window-welcome",
+ template: "spotlight",
+ modal: "tab",
+ transitions: true,
+ backdrop: "linear-gradient(0deg, #D9C7F8 0%, #F6EEFC 102.21%)",
+ screens: [
+ {
+ id: "welcome_screen",
+ auto_advance: "additional_button",
+ force_hide_steps_indicator: true,
+ content: {
+ fullscreen: true,
+ hide_secondary_section: "responsive",
+ narrow: true,
+ position: "split",
+ title: {
+ fontWeight: 600,
+ fontSize: "55px",
+ width: "800px",
+ textAlign: "center",
+ raw: "Welcome to Smart Window",
+ },
+ title_style: "fancy shine",
+ text_color: "dark",
+ primary_button: {
+ label: "Next",
+ action: {
+ navigate: true
+ },
+ },
+ },
+ },
+ {
+ id: "CHOOSE_MODEL",
+ force_hide_steps_indicator: true,
+ content: {
+ fullscreen: true,
+ hide_secondary_section: "responsive",
+ narrow: true,
+ position: "split",
+ screen_style: {
+ width: "650px",
+ height: "500px",
+ },
+ title: {
+ raw: "Pick a model to start 1",
+ },
+ subtitle: {
+ raw: "You can switch anytime - and trying a few helps you find the best fit.",
+ },
+ tiles: {
+ type: "single-select",
+ autoTrigger: false,
+ action: {
+ picker: "",
+ },
+ data: [
+ {
+ defaultValue: true,
+ id: "model_1",
+ icon: {
+ background:
+ "center / contain no-repeat url('https://firefox-settings-attachments.cdn.mozilla.net/main-workspace/ms-images/733144c8-a453-49eb-aff7-27a10786fbc1.svg')",
+ marginBlockStart: "8px",
+
+ },
+
+ label: {
+ raw: "Fast & Clear",
+ fontSize: 17,
+ fontWeight: 600,
+ },
+ body: {
+ raw: "Quick answer to everyday questions",
+ color: "var(--text-color-deemphasized)",
+ },
+ action: {
+ type: "SET_PREF",
+ data: {
+ pref: {
+ name: "aidemo.model.choice",
+ value: "model_1",
+ },
+ },
+ },
+ },
+ {
+ id: "model_2",
+ icon: {
+ background:
+ "center / contain no-repeat url('https://firefox-settings-attachments.cdn.mozilla.net/main-workspace/ms-images/733144c8-a453-49eb-aff7-27a10786fbc1.svg')",
+ marginBlockStart: "8px",
+
+ },
+ label: {
+ raw: "Fast & Clear",
+ fontSize: 17,
+ fontWeight: 600,
+ },
+ body: {
+ raw: "Quick answer to everyday questions",
+ color: "var(--text-color-deemphasized)",
+ },
+ action: {
+ type: "SET_PREF",
+ data: {
+ pref: {
+ name: "aidemo.model.choice",
+ value: "model_2",
+ },
+ },
+ },
+ },
+ {
+ id: "model_3",
+ icon: {
+ background:
+ "center / contain no-repeat url('https://firefox-settings-attachments.cdn.mozilla.net/main-workspace/ms-images/733144c8-a453-49eb-aff7-27a10786fbc1.svg')",
+ marginBlockStart: "8px",
+
+ },
+ label: {
+ raw: "Fast & Clear",
+ fontSize: 17,
+ fontWeight: 600,
+ },
+ body: {
+ raw: "Quick answer to everyday questions",
+ color: "var(--text-color-deemphasized)",
+ },
+ action: {
+ type: "SET_PREF",
+ data: {
+ pref: {
+ name: "aidemo.model.choice",
+ value: "model_3",
+ },
+ },
+ },
+ }
+ ]
+ },
+ primary_button: {
+ label: {
+ raw: "Next"
+ },
+ action: {
+ navigate: true
+ }
+ },
+ }
+ },
+ {
+ id: "APPLY_INSIGHTS",
+ content: {
+ position: "center",
+ screen_style: {
+ width: "650px",
+ height: "500px",
+ },
+ title: {
+ raw: "Smarter browsing starts now",
+ },
+ subtitle: {
+ raw: "Get personalized answers fast. Compare info across tabs. Find what you need in your history in your words, not keywords.",
+ },
+ above_button_content: [
+ {
+ type: "image",
+ url: "chrome://browser/content/smartwindow/insights.png",
+ width: "500px",
+ height: "200px"
+ }
+ ],
+ primary_button: {
+ label: {
+ raw: "Back"
+ },
+ action: {
+ navigate: true,
+ goBack: true
+ }
+ },
+ additional_button: {
+ label: "Let's Go",
+ style: "primary",
+ flow: "row",
+ action: {
+ navigate: true
+ }
+ },
+ }
+ }
+ ],
+ })
+);
+
+function addStylesheet(href) {
+ const link = document.head.appendChild(document.createElement("link"));
+ link.rel = "stylesheet";
+ link.href = href;
+}
+
+function renderMultistage(ready) {
+ const AWParent = new lazy.AboutWelcomeParent();
+ const receive = name => data =>
+ AWParent.onContentMessage(
+ `AWPage:${name}`,
+ data,
+ topChromeWindow.gBrowser.selectedBrowser
+ );
+
+ // Expose top level functions expected by the bundle.
+ window.AWGetFeatureConfig = () => JSON.parse(lazy.onboardingConfig);
+ window.AWGetSelectedTheme = receive("GET_SELECTED_THEME");
+ window.AWGetInstalledAddons = receive("GET_INSTALLED_ADDONS");
+ window.AWSelectTheme = data => receive("SELECT_THEME")(data?.toUpperCase());
+ window.AWSendEventTelemetry = receive("TELEMETRY_EVENT");
+
+ window.AWSendToDeviceEmailsSupported = receive(
+ "SEND_TO_DEVICE_EMAILS_SUPPORTED"
+ );
+ window.AWAddScreenImpression = receive("ADD_SCREEN_IMPRESSION");
+ window.AWSendToParent = (name, data) => receive(name)(data);
+ window.AWFinish = () => {
+ window.close();
+ };
+ window.AWWaitForMigrationClose = receive("WAIT_FOR_MIGRATION_CLOSE");
+ window.AWEvaluateScreenTargeting = receive("EVALUATE_SCREEN_TARGETING");
+ window.AWEvaluateAttributeTargeting = receive("EVALUATE_ATTRIBUTE_TARGETING");
+
+ // Update styling to be compatible with about:welcome.
+ addStylesheet("chrome://browser/content/aboutwelcome/aboutwelcome.css");
+
+ document.body.classList.add("onboardingContainer");
+ document.body.id = "multi-stage-message-root";
+ // This value is reported as the "page" in telemetry
+ document.body.dataset.page = "smart-window-welcome";
+ const bundleScript = document.head.appendChild(
+ document.createElement("script")
+ );
+ bundleScript.src =
+ "chrome://browser/content/aboutwelcome/aboutwelcome.bundle.js";
+
+ ready();
+}
+
+// Initialize when DOM is ready
+if (document.readyState === "loading") {
+ document.addEventListener(
+ "DOMContentLoaded",
+ () => renderMultistage(() => { }),
+ { once: true }
+ );
+} else {
+ renderMultistage(() => { });
+}
diff --git a/browser/components/smartwindow/content/insights.png b/browser/components/smartwindow/content/insights.png
new file mode 100644
index 0000000000000..1cb533db4db6d
Binary files /dev/null and b/browser/components/smartwindow/content/insights.png differ
diff --git a/browser/components/smartwindow/content/smartwindow.css b/browser/components/smartwindow/content/smartwindow.css
index a47491aba6c4e..be25bd796a47e 100644
--- a/browser/components/smartwindow/content/smartwindow.css
+++ b/browser/components/smartwindow/content/smartwindow.css
@@ -1255,12 +1255,22 @@ body {
}
#multi-stage-message-root {
+ --background-color-canvas: transparent;
+ /*--single-select-hover-color: #FCFAFE;*/
+ height: 100vh;
.welcome-text {
max-width: 600px;
}
-
.main-content {
- background-color: rgba(247, 230, 251, 1);
+ /*background-color: #FCFAFE;*/
+ }
+
+ .screen {
+ /*background-color: rgba(247, 230, 251, 1);*/
+ }
+
+ .onboardingContainer .tiles-single-select-section.single-select .select-item:hover{
+ background-color: #FCFAFE;
}
}
diff --git a/browser/components/smartwindow/content/welcome.js b/browser/components/smartwindow/content/welcome.js
index 750957a88035d..f9f975d0b9747 100644
--- a/browser/components/smartwindow/content/welcome.js
+++ b/browser/components/smartwindow/content/welcome.js
@@ -57,15 +57,6 @@ XPCOMUtils.defineLazyPreferenceGetter(
dismiss: true,
data: {
actions: [
- {
- type: "SET_PREF",
- data: {
- pref: {
- name: "messaging-system-action.smart-window-tos",
- value: true,
- },
- },
- },
{
data: {
entrypoint: "aimode",
@@ -100,12 +91,6 @@ function addStylesheet(href) {
link.href = href;
}
-// TODO
-// Check if a) is signedIn b) Has FxAccount and not signed in c) doesn't have FxAccount
-// a) Check consent stored in pref `messaging-system-action.smart-window-tos` , if yes toggle to smart window without redirect to account.firefox.com
-// b) and c) Redirect to account.firefox.com for account creation and signin and on success call toggle smart window
-// See GENAI-2201
-
function renderMultistage(ready) {
const AWParent = new lazy.AboutWelcomeParent();
const receive = name => data =>
diff --git a/browser/components/smartwindow/jar.mn b/browser/components/smartwindow/jar.mn
index 34e67304f076b..fb0beaf19d26b 100644
--- a/browser/components/smartwindow/jar.mn
+++ b/browser/components/smartwindow/jar.mn
@@ -23,3 +23,6 @@ browser.jar:
content/browser/smartwindow/utils.mjs (content/utils.mjs)
content/browser/smartwindow/welcome.html (content/welcome.html)
content/browser/smartwindow/welcome.js (content/welcome.js)
+ content/browser/smartwindow/firstrun.html (content/firstrun.html)
+ content/browser/smartwindow/firstrun.js (content/firstrun.js)
+ content/browser/smartwindow/insights.png (content/insights.png)
diff --git a/toolkit/components/messaging-system/lib/SpecialMessageActions.sys.mjs b/toolkit/components/messaging-system/lib/SpecialMessageActions.sys.mjs
index a5937e9a02e3c..1b24fd3faf968 100644
--- a/toolkit/components/messaging-system/lib/SpecialMessageActions.sys.mjs
+++ b/toolkit/components/messaging-system/lib/SpecialMessageActions.sys.mjs
@@ -284,6 +284,7 @@ export const SpecialMessageActions = {
"termsofuse.minimumVersion",
"privacy.trackingprotection.allow_list.baseline.enabled",
"privacy.trackingprotection.allow_list.convenience.enabled",
+ "browser.smartwindow.tos",
];
// Array of prefs that are allowed to be edited when SET_PREF is called on
@@ -756,6 +757,10 @@ export const SpecialMessageActions = {
}
if (await this.fxaSignInFlow(action.data, browser)) {
+ if (!Services.prefs.getBoolPref("browser.smartwindow.tos", false)){
+ Services.prefs.setBoolPref("browser.smartwindow.isfirstrun", true);
+ }
+ Services.prefs.setBoolPref("browser.smartwindow.tos", true);
window.SmartWindow.toggleSmartWindow();
}
break;