@ledgerhq/live-common
Version:
Common ground for the Ledger Live apps
141 lines • 5.87 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.useAppsRunner = void 0;
exports.useNotEnoughMemoryToInstall = useNotEnoughMemoryToInstall;
exports.useAppsSections = useAppsSections;
exports.useAppInstallProgress = useAppInstallProgress;
exports.useAppInstallNeedsDeps = useAppInstallNeedsDeps;
exports.useAppUninstallNeedsDeps = useAppUninstallNeedsDeps;
const react_1 = require("react");
const filtering_1 = require("./filtering");
const logic_1 = require("./logic");
const runner_1 = require("./runner");
const featureFlags_1 = require("../featureFlags");
// use for React apps. support dynamic change of the state.
const useAppsRunner = (listResult, exec, appsToRestore) => {
// $FlowFixMe for ledger-live-mobile older react/flow version
const [state, dispatch] = (0, react_1.useReducer)(logic_1.reducer, null, () => (0, logic_1.initState)(listResult, appsToRestore));
const nextAppOp = (0, react_1.useMemo)(() => (0, logic_1.getNextAppOp)(state), [state]);
const appOp = state.currentAppOp || nextAppOp;
(0, react_1.useEffect)(() => {
dispatch({
type: "reset",
initialState: (0, logic_1.initState)(listResult, appsToRestore),
});
}, [listResult, appsToRestore]);
(0, react_1.useEffect)(() => {
if (appOp) {
const sub = (0, runner_1.runAppOp)({ state, appOp, exec }).subscribe(event => {
dispatch({
type: "onRunnerEvent",
event,
});
});
return () => {
sub.unsubscribe();
};
} // we only want to redo the effect on appOp changes here
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [listResult, appOp, exec]);
return [state, dispatch];
};
exports.useAppsRunner = useAppsRunner;
function useNotEnoughMemoryToInstall(state, name) {
return (0, react_1.useMemo)(() => (0, logic_1.isOutOfMemoryState)((0, logic_1.predictOptimisticState)((0, logic_1.reducer)(state, {
type: "install",
name,
}))), [name, state]);
}
function useAppsSections(state, opts) {
const { updateAllQueue, appByName, installed, installQueue, apps } = state;
const appsUpdating = (0, react_1.useMemo)(() => updateAllQueue.map(name => appByName[name]).filter(Boolean), [appByName, updateAllQueue]);
const updatableAppList = (0, react_1.useMemo)(() => apps.filter(({ name }) => installed.some(i => i.name === name && !i.updated)), [apps, installed]);
const { getFeature, isFeature } = (0, featureFlags_1.useFeatureFlags)();
const update = appsUpdating.length > 0 ? appsUpdating : updatableAppList;
const filterParam = (0, react_1.useMemo)(() => ({
query: opts.query,
installedApps: installed,
type: [opts.appFilter],
getFeature,
isFeature,
}), [getFeature, installed, isFeature, opts.appFilter, opts.query]);
const catalog = (0, filtering_1.useSortedFilteredApps)(apps, filterParam, opts.sort);
const installedAppList = (0, filtering_1.useSortedFilteredApps)(apps, {
query: opts.query,
installedApps: installed,
installQueue,
type: ["installed"],
getFeature,
isFeature,
}, {
type: "default",
order: "asc",
});
const device = installedAppList.sort(({ name: _name }, { name }) => {
// place install queue on top of list
// with the app being installed at the top
let pos1 = installQueue.indexOf(_name);
let pos2 = installQueue.indexOf(name);
pos1 = pos1 < 0 ? Number.MAX_VALUE : pos1;
pos2 = pos2 < 0 ? Number.MAX_VALUE : pos2;
return pos1 - pos2;
});
return {
update,
catalog,
device,
};
}
function useAppInstallProgress(state, name) {
const { currentProgressSubject, currentAppOp } = state;
const [progress, setProgress] = (0, react_1.useState)(0);
(0, react_1.useEffect)(() => {
if (!currentAppOp || !currentProgressSubject || currentAppOp.name !== name) {
setProgress(0);
return;
}
const sub = currentProgressSubject.subscribe(setProgress);
return () => sub.unsubscribe();
}, [currentProgressSubject, currentAppOp, name]);
if (currentProgressSubject && currentAppOp && currentAppOp.name === name) {
return progress;
}
return 0;
}
// if the app needs deps to be installed, we want to display a modal
// this should returns all params the modal also need (so we don't do things twice)
function useAppInstallNeedsDeps(state, app) {
const { appByName, installed: installedList, installQueue } = state;
const res = (0, react_1.useMemo)(() => {
const dependencies = (app.dependencies || [])
.map(name => appByName[name])
.filter(dep => dep &&
!installedList.some(app => app.name === dep.name) &&
!installQueue.includes(dep.name));
if (dependencies.length) {
return {
app,
dependencies,
};
}
return null;
}, [appByName, app, installQueue, installedList]);
return res;
}
// if the app needs deps to be installed, we want to display a modal
// this should returns all params the modal also need (so we don't do things twice)
function useAppUninstallNeedsDeps(state, app) {
const { apps, installed } = state;
const res = (0, react_1.useMemo)(() => {
const dependents = apps.filter(a => installed.some(i => i.name === a.name) && a.dependencies.includes(app.name));
if (dependents.length) {
return {
dependents,
app,
};
}
return null;
}, [app, apps, installed]);
return res;
}
//# sourceMappingURL=react.js.map