fune/browser/components/newtab/lib/PrefsFeed.jsm

279 lines
8.6 KiB
JavaScript

/* 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/. */
"use strict";
const { actionCreators: ac, actionTypes: at } = ChromeUtils.importESModule(
"resource://activity-stream/common/Actions.sys.mjs"
);
const { XPCOMUtils } = ChromeUtils.importESModule(
"resource://gre/modules/XPCOMUtils.sys.mjs"
);
const { Prefs } = ChromeUtils.import(
"resource://activity-stream/lib/ActivityStreamPrefs.jsm"
);
const { AppConstants } = ChromeUtils.importESModule(
"resource://gre/modules/AppConstants.sys.mjs"
);
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
Region: "resource://gre/modules/Region.sys.mjs",
});
XPCOMUtils.defineLazyModuleGetters(lazy, {
NimbusFeatures: "resource://nimbus/ExperimentAPI.jsm",
});
class PrefsFeed {
constructor(prefMap) {
this._prefMap = prefMap;
this._prefs = new Prefs();
this.onExperimentUpdated = this.onExperimentUpdated.bind(this);
this.onPocketExperimentUpdated = this.onPocketExperimentUpdated.bind(this);
}
onPrefChanged(name, value) {
const prefItem = this._prefMap.get(name);
if (prefItem) {
this.store.dispatch(
ac[prefItem.skipBroadcast ? "OnlyToMain" : "BroadcastToContent"]({
type: at.PREF_CHANGED,
data: { name, value },
})
);
}
}
_setStringPref(values, key, defaultValue) {
this._setPref(values, key, defaultValue, Services.prefs.getStringPref);
}
_setBoolPref(values, key, defaultValue) {
this._setPref(values, key, defaultValue, Services.prefs.getBoolPref);
}
_setIntPref(values, key, defaultValue) {
this._setPref(values, key, defaultValue, Services.prefs.getIntPref);
}
_setPref(values, key, defaultValue, getPrefFunction) {
let value = getPrefFunction(
`browser.newtabpage.activity-stream.${key}`,
defaultValue
);
values[key] = value;
this._prefMap.set(key, { value });
}
/**
* Handler for when experiment data updates.
*/
onExperimentUpdated(event, reason) {
const value = lazy.NimbusFeatures.newtab.getAllVariables() || {};
this.store.dispatch(
ac.BroadcastToContent({
type: at.PREF_CHANGED,
data: {
name: "featureConfig",
value,
},
})
);
}
/**
* Handler for Pocket specific experiment data updates.
*/
onPocketExperimentUpdated(event, reason) {
const value = lazy.NimbusFeatures.pocketNewtab.getAllVariables() || {};
// Loaded experiments are set up inside init()
if (
reason !== "feature-experiment-loaded" &&
reason !== "feature-rollout-loaded"
) {
this.store.dispatch(
ac.BroadcastToContent({
type: at.PREF_CHANGED,
data: {
name: "pocketConfig",
value,
},
})
);
}
}
init() {
this._prefs.observeBranch(this);
lazy.NimbusFeatures.newtab.onUpdate(this.onExperimentUpdated);
lazy.NimbusFeatures.pocketNewtab.onUpdate(this.onPocketExperimentUpdated);
this._storage = this.store.dbStorage.getDbTable("sectionPrefs");
// Get the initial value of each activity stream pref
const values = {};
for (const name of this._prefMap.keys()) {
values[name] = this._prefs.get(name);
}
// These are not prefs, but are needed to determine stuff in content that can only be
// computed in main process
values.isPrivateBrowsingEnabled = lazy.PrivateBrowsingUtils.enabled;
values.platform = AppConstants.platform;
// Save the geo pref if we have it
if (lazy.Region.home) {
values.region = lazy.Region.home;
this.geo = values.region;
} else if (this.geo !== "") {
// Watch for geo changes and use a dummy value for now
Services.obs.addObserver(this, lazy.Region.REGION_TOPIC);
this.geo = "";
}
// Get the firefox accounts url for links and to send firstrun metrics to.
values.fxa_endpoint = Services.prefs.getStringPref(
"browser.newtabpage.activity-stream.fxaccounts.endpoint",
"https://accounts.firefox.com"
);
// Get the firefox update channel with values as default, nightly, beta or release
values.appUpdateChannel = Services.prefs.getStringPref(
"app.update.channel",
""
);
// Read the pref for search shortcuts top sites experiment from firefox.js and store it
// in our internal list of prefs to watch
let searchTopSiteExperimentPrefValue = Services.prefs.getBoolPref(
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts"
);
values[
"improvesearch.topSiteSearchShortcuts"
] = searchTopSiteExperimentPrefValue;
this._prefMap.set("improvesearch.topSiteSearchShortcuts", {
value: searchTopSiteExperimentPrefValue,
});
values.mayHaveSponsoredTopSites = Services.prefs.getBoolPref(
"browser.topsites.useRemoteSetting"
);
// Read the pref for search hand-off from firefox.js and store it
// in our internal list of prefs to watch
let handoffToAwesomebarPrefValue = Services.prefs.getBoolPref(
"browser.newtabpage.activity-stream.improvesearch.handoffToAwesomebar"
);
values["improvesearch.handoffToAwesomebar"] = handoffToAwesomebarPrefValue;
this._prefMap.set("improvesearch.handoffToAwesomebar", {
value: handoffToAwesomebarPrefValue,
});
// Read the pref for the cached default engine name from firefox.js and
// store it in our internal list of prefs to watch
let placeholderPrefValue = Services.prefs.getStringPref(
"browser.urlbar.placeholderName",
""
);
values["urlbar.placeholderName"] = placeholderPrefValue;
this._prefMap.set("urlbar.placeholderName", {
value: placeholderPrefValue,
});
// Add experiment values and default values
values.featureConfig = lazy.NimbusFeatures.newtab.getAllVariables() || {};
values.pocketConfig =
lazy.NimbusFeatures.pocketNewtab.getAllVariables() || {};
this._setBoolPref(values, "logowordmark.alwaysVisible", false);
this._setBoolPref(values, "feeds.section.topstories", false);
this._setBoolPref(values, "discoverystream.enabled", false);
this._setBoolPref(
values,
"discoverystream.sponsored-collections.enabled",
false
);
this._setBoolPref(values, "discoverystream.isCollectionDismissible", false);
this._setBoolPref(values, "discoverystream.hardcoded-basic-layout", false);
this._setBoolPref(values, "discoverystream.personalization.enabled", false);
this._setBoolPref(values, "discoverystream.personalization.override");
this._setStringPref(
values,
"discoverystream.personalization.modelKeys",
""
);
this._setStringPref(values, "discoverystream.spocs-endpoint", "");
this._setStringPref(values, "discoverystream.spocs-endpoint-query", "");
this._setStringPref(values, "newNewtabExperience.colors", "");
// Set the initial state of all prefs in redux
this.store.dispatch(
ac.BroadcastToContent({
type: at.PREFS_INITIAL_VALUES,
data: values,
meta: {
isStartup: true,
},
})
);
}
uninit() {
this.removeListeners();
}
removeListeners() {
this._prefs.ignoreBranch(this);
lazy.NimbusFeatures.newtab.offUpdate(this.onExperimentUpdated);
lazy.NimbusFeatures.pocketNewtab.offUpdate(this.onPocketExperimentUpdated);
if (this.geo === "") {
Services.obs.removeObserver(this, lazy.Region.REGION_TOPIC);
}
}
async _setIndexedDBPref(id, value) {
const name = id === "topsites" ? id : `feeds.section.${id}`;
try {
await this._storage.set(name, value);
} catch (e) {
console.error("Could not set section preferences.");
}
}
observe(subject, topic, data) {
switch (topic) {
case lazy.Region.REGION_TOPIC:
this.store.dispatch(
ac.BroadcastToContent({
type: at.PREF_CHANGED,
data: { name: "region", value: lazy.Region.home },
})
);
break;
}
}
onAction(action) {
switch (action.type) {
case at.INIT:
this.init();
break;
case at.UNINIT:
this.uninit();
break;
case at.CLEAR_PREF:
Services.prefs.clearUserPref(this._prefs._branchStr + action.data.name);
break;
case at.SET_PREF:
this._prefs.set(action.data.name, action.data.value);
break;
case at.UPDATE_SECTION_PREFS:
this._setIndexedDBPref(action.data.id, action.data.value);
break;
}
}
}
const EXPORTED_SYMBOLS = ["PrefsFeed"];