All checks were successful
check / check (push) Successful in 24s
Add theme preference (light/dark/system) stored in extension state. System mode follows prefers-color-scheme and listens for changes. Dark mode inverts the monochrome palette (white-on-black). Theme selector added to Display section in settings. Closes #125
242 lines
6.6 KiB
JavaScript
242 lines
6.6 KiB
JavaScript
// AutistMask popup entry point.
|
|
// Loads state, initializes views, triggers first render.
|
|
|
|
const { DEBUG } = require("../shared/constants");
|
|
const { state, saveState, loadState } = require("../shared/state");
|
|
const { refreshPrices } = require("../shared/prices");
|
|
const { refreshBalances } = require("../shared/balances");
|
|
const { $, showView } = require("./views/helpers");
|
|
const { applyTheme } = require("./theme");
|
|
|
|
const home = require("./views/home");
|
|
const welcome = require("./views/welcome");
|
|
const addWallet = require("./views/addWallet");
|
|
const addressDetail = require("./views/addressDetail");
|
|
const addressToken = require("./views/addressToken");
|
|
const send = require("./views/send");
|
|
const confirmTx = require("./views/confirmTx");
|
|
const txStatus = require("./views/txStatus");
|
|
const transactionDetail = require("./views/transactionDetail");
|
|
const receive = require("./views/receive");
|
|
const addToken = require("./views/addToken");
|
|
const settings = require("./views/settings");
|
|
const settingsAddToken = require("./views/settingsAddToken");
|
|
const approval = require("./views/approval");
|
|
|
|
function renderWalletList() {
|
|
home.render(ctx);
|
|
}
|
|
|
|
let refreshInFlight = false;
|
|
|
|
async function doRefreshAndRender() {
|
|
if (refreshInFlight) return;
|
|
refreshInFlight = true;
|
|
try {
|
|
await Promise.all([
|
|
refreshPrices(),
|
|
refreshBalances(
|
|
state.wallets,
|
|
state.rpcUrl,
|
|
state.blockscoutUrl,
|
|
state.trackedTokens,
|
|
),
|
|
]);
|
|
state.lastBalanceRefresh = Date.now();
|
|
await saveState();
|
|
renderWalletList();
|
|
} finally {
|
|
refreshInFlight = false;
|
|
}
|
|
}
|
|
|
|
const ctx = {
|
|
renderWalletList,
|
|
doRefreshAndRender,
|
|
showAddWalletView: () => addWallet.show(),
|
|
showAddressDetail: () => addressDetail.show(),
|
|
showAddressToken: () => addressToken.show(),
|
|
showAddTokenView: () => addToken.show(),
|
|
showConfirmTx: (txInfo) => confirmTx.show(txInfo),
|
|
showReceive: () => receive.show(),
|
|
showTransactionDetail: (tx) => transactionDetail.show(tx),
|
|
showSettingsView: () => settings.show(),
|
|
showSettingsAddTokenView: () => settingsAddToken.show(),
|
|
};
|
|
|
|
// Views that can be fully re-rendered from persisted state.
|
|
// All others fall back to the nearest restorable parent.
|
|
const RESTORABLE_VIEWS = new Set([
|
|
"main",
|
|
"address",
|
|
"address-token",
|
|
"receive",
|
|
"settings",
|
|
"settings-addtoken",
|
|
"confirm-tx",
|
|
"transaction",
|
|
"success-tx",
|
|
"error-tx",
|
|
]);
|
|
|
|
function needsAddress(view) {
|
|
return (
|
|
view === "address" ||
|
|
view === "address-token" ||
|
|
view === "receive" ||
|
|
view === "transaction"
|
|
);
|
|
}
|
|
|
|
function hasValidAddress() {
|
|
return (
|
|
state.selectedWallet !== null &&
|
|
state.selectedAddress !== null &&
|
|
state.wallets[state.selectedWallet] &&
|
|
state.wallets[state.selectedWallet].addresses[state.selectedAddress]
|
|
);
|
|
}
|
|
|
|
function restoreView() {
|
|
const view = state.currentView;
|
|
if (!view || !RESTORABLE_VIEWS.has(view)) {
|
|
return fallbackView();
|
|
}
|
|
|
|
if (needsAddress(view) && !hasValidAddress()) {
|
|
return fallbackView();
|
|
}
|
|
|
|
if (view === "address-token" && !state.selectedToken) {
|
|
return fallbackView();
|
|
}
|
|
|
|
switch (view) {
|
|
case "address":
|
|
addressDetail.show();
|
|
break;
|
|
case "address-token":
|
|
addressToken.show();
|
|
break;
|
|
case "receive":
|
|
receive.show();
|
|
break;
|
|
case "settings":
|
|
settings.show();
|
|
break;
|
|
case "settings-addtoken":
|
|
settingsAddToken.show();
|
|
break;
|
|
case "confirm-tx":
|
|
if (state.viewData && state.viewData.pendingTx) {
|
|
confirmTx.restore();
|
|
} else {
|
|
fallbackView();
|
|
}
|
|
break;
|
|
case "transaction":
|
|
if (state.viewData && state.viewData.tx) {
|
|
transactionDetail.render();
|
|
} else {
|
|
fallbackView();
|
|
}
|
|
break;
|
|
case "success-tx":
|
|
if (state.viewData && state.viewData.hash) {
|
|
txStatus.renderSuccess();
|
|
} else {
|
|
fallbackView();
|
|
}
|
|
break;
|
|
case "error-tx":
|
|
if (state.viewData && state.viewData.message) {
|
|
txStatus.renderError();
|
|
} else {
|
|
fallbackView();
|
|
}
|
|
break;
|
|
default:
|
|
fallbackView();
|
|
break;
|
|
}
|
|
}
|
|
|
|
function fallbackView() {
|
|
renderWalletList();
|
|
showView("main");
|
|
}
|
|
|
|
async function init() {
|
|
if (DEBUG) {
|
|
const banner = document.createElement("div");
|
|
banner.id = "debug-banner";
|
|
banner.textContent = "DEBUG / INSECURE";
|
|
banner.style.cssText =
|
|
"background:#c00;color:#fff;text-align:center;font-size:10px;padding:1px 0;font-family:monospace;position:sticky;top:0;z-index:9999;";
|
|
document.body.prepend(banner);
|
|
}
|
|
|
|
await loadState();
|
|
applyTheme(state.theme);
|
|
|
|
// Auto-default active address
|
|
if (
|
|
state.activeAddress === null &&
|
|
state.wallets.length > 0 &&
|
|
state.wallets[0].addresses.length > 0
|
|
) {
|
|
state.activeAddress = state.wallets[0].addresses[0].address;
|
|
await saveState();
|
|
}
|
|
|
|
// Always init approval and txStatus — they may run in the approval popup window
|
|
approval.init(ctx);
|
|
txStatus.init(ctx);
|
|
|
|
// Check for approval mode
|
|
const params = new URLSearchParams(window.location.search);
|
|
const approvalId = params.get("approval");
|
|
if (approvalId) {
|
|
approval.show(approvalId);
|
|
showView("approve-site");
|
|
return;
|
|
}
|
|
|
|
$("btn-settings").addEventListener("click", () => {
|
|
if (
|
|
!document
|
|
.getElementById("view-settings")
|
|
.classList.contains("hidden")
|
|
) {
|
|
renderWalletList();
|
|
showView("main");
|
|
return;
|
|
}
|
|
settings.show();
|
|
});
|
|
|
|
welcome.init(ctx);
|
|
addWallet.init(ctx);
|
|
home.init(ctx);
|
|
addressDetail.init(ctx);
|
|
addressToken.init(ctx);
|
|
send.init(ctx);
|
|
confirmTx.init(ctx);
|
|
transactionDetail.init(ctx);
|
|
receive.init(ctx);
|
|
addToken.init(ctx);
|
|
settings.init(ctx);
|
|
settingsAddToken.init(ctx);
|
|
|
|
if (!state.hasWallet) {
|
|
showView("welcome");
|
|
} else {
|
|
renderWalletList();
|
|
restoreView();
|
|
doRefreshAndRender();
|
|
setInterval(doRefreshAndRender, 10000);
|
|
}
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", init);
|