mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-06-17 08:47:49 +00:00
b7d7ca04e1
* refractor uninstall plugin backend * refractor plugin installation method * Change formatting in browser.py * Manually format main.py * Manually format utilities.py * remove inconsistency * remove unnecessary linebreaks * lol what * last minute pythoning * Fix async missing * lint * more refractor * await forgotten * fix: menu not disappearing after first click * lint * bug: fix double click on uninstall * depricate request installs * basic patch notes viewer, lazy-load settings and store, build frontend as esmodule, add lazy-loaded react-markdown, backend changes to accomodate ESModule frontend * refractor uninstall plugin backend * Change formatting in browser.py * Manually format main.py * Manually format utilities.py * remove unnecessary linebreaks * lol what * last minute pythoning * Fix async missing * rebase onto main * fix error, fix React crash if patch notes are opened before remote version info is loaded Co-authored-by: TrainDoctor <traindoctor@protonmail.com> Co-authored-by: AAGaming <aa@mail.catvibers.me>
163 lines
5.5 KiB
TypeScript
163 lines
5.5 KiB
TypeScript
import { Carousel, DialogButton, Field, Focusable, ProgressBarWithInfo, Spinner, showModal } from 'decky-frontend-lib';
|
|
import { useCallback } from 'react';
|
|
import { Suspense, lazy } from 'react';
|
|
import { useEffect, useState } from 'react';
|
|
import { FaArrowDown } from 'react-icons/fa';
|
|
|
|
import { VerInfo, callUpdaterMethod, finishUpdate } from '../../../../updater';
|
|
import { useDeckyState } from '../../../DeckyState';
|
|
import InlinePatchNotes from '../../../patchnotes/InlinePatchNotes';
|
|
|
|
const MarkdownRenderer = lazy(() => import('../../../Markdown'));
|
|
|
|
// import ReactMarkdown from 'react-markdown'
|
|
// import remarkGfm from 'remark-gfm'
|
|
|
|
function PatchNotesModal({ versionInfo, closeModal }: { versionInfo: VerInfo | null; closeModal?: () => {} }) {
|
|
return (
|
|
<Focusable onCancelButton={closeModal}>
|
|
<Carousel
|
|
fnItemRenderer={(id: number) => (
|
|
<Focusable
|
|
onActivate={() => {}}
|
|
style={{
|
|
marginTop: '40px',
|
|
height: 'calc( 100% - 40px )',
|
|
overflowY: 'scroll',
|
|
display: 'flex',
|
|
justifyContent: 'center',
|
|
margin: '40px',
|
|
}}
|
|
>
|
|
<div>
|
|
<h1>{versionInfo?.all?.[id]?.name}</h1>
|
|
{versionInfo?.all?.[id]?.body ? (
|
|
<Suspense fallback={<Spinner style={{ width: '24', height: '24' }} />}>
|
|
<MarkdownRenderer>{versionInfo.all[id].body}</MarkdownRenderer>
|
|
</Suspense>
|
|
) : (
|
|
'no patch notes for this version'
|
|
)}
|
|
</div>
|
|
</Focusable>
|
|
)}
|
|
fnGetId={(id) => id}
|
|
nNumItems={versionInfo?.all?.length}
|
|
nHeight={window.innerHeight - 150}
|
|
nItemHeight={window.innerHeight - 200}
|
|
nItemMarginX={0}
|
|
initialColumn={0}
|
|
autoFocus={true}
|
|
fnGetColumnWidth={() => window.innerWidth}
|
|
/>
|
|
</Focusable>
|
|
);
|
|
}
|
|
|
|
export default function UpdaterSettings() {
|
|
const { isLoaderUpdating, setIsLoaderUpdating } = useDeckyState();
|
|
|
|
const [versionInfo, setVersionInfo] = useState<VerInfo | null>(null);
|
|
const [checkingForUpdates, setCheckingForUpdates] = useState<boolean>(false);
|
|
const [updateProgress, setUpdateProgress] = useState<number>(-1);
|
|
const [reloading, setReloading] = useState<boolean>(false);
|
|
|
|
useEffect(() => {
|
|
(async () => {
|
|
const res = (await callUpdaterMethod('get_version')) as { result: VerInfo };
|
|
setVersionInfo(res.result);
|
|
})();
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
window.DeckyUpdater = {
|
|
updateProgress: (i) => {
|
|
setUpdateProgress(i);
|
|
setIsLoaderUpdating(true);
|
|
},
|
|
finish: async () => {
|
|
setUpdateProgress(0);
|
|
setReloading(true);
|
|
await finishUpdate();
|
|
},
|
|
};
|
|
}, []);
|
|
|
|
const showPatchNotes = useCallback(() => {
|
|
showModal(<PatchNotesModal versionInfo={versionInfo} />);
|
|
}, [versionInfo]);
|
|
|
|
return (
|
|
<>
|
|
<Field
|
|
onOptionsActionDescription={versionInfo?.all ? 'Patch Notes' : undefined}
|
|
onOptionsButton={versionInfo?.all ? showPatchNotes : undefined}
|
|
label="Updates"
|
|
description={
|
|
versionInfo && (
|
|
<span style={{ whiteSpace: 'pre-line' }}>{`Current version: ${versionInfo.current}\n${
|
|
versionInfo.updatable ? `Latest version: ${versionInfo.remote?.tag_name}` : ''
|
|
}`}</span>
|
|
)
|
|
}
|
|
icon={
|
|
!versionInfo ? (
|
|
<Spinner style={{ width: '1em', height: 20, display: 'block' }} />
|
|
) : (
|
|
<FaArrowDown style={{ display: 'block' }} />
|
|
)
|
|
}
|
|
>
|
|
{updateProgress == -1 && !isLoaderUpdating ? (
|
|
<DialogButton
|
|
disabled={!versionInfo?.updatable || checkingForUpdates}
|
|
onClick={
|
|
!versionInfo?.remote || versionInfo?.remote?.tag_name == versionInfo?.current
|
|
? async () => {
|
|
setCheckingForUpdates(true);
|
|
const res = (await callUpdaterMethod('check_for_updates')) as { result: VerInfo };
|
|
setVersionInfo(res.result);
|
|
setCheckingForUpdates(false);
|
|
}
|
|
: async () => {
|
|
setUpdateProgress(0);
|
|
callUpdaterMethod('do_update');
|
|
}
|
|
}
|
|
>
|
|
{checkingForUpdates
|
|
? 'Checking'
|
|
: !versionInfo?.remote || versionInfo?.remote?.tag_name == versionInfo?.current
|
|
? 'Check For Updates'
|
|
: 'Install Update'}
|
|
</DialogButton>
|
|
) : (
|
|
<ProgressBarWithInfo
|
|
layout="inline"
|
|
bottomSeparator={false}
|
|
nProgress={updateProgress}
|
|
indeterminate={reloading}
|
|
sOperationText={reloading ? 'Reloading' : 'Updating'}
|
|
/>
|
|
)}
|
|
</Field>
|
|
{versionInfo?.remote && (
|
|
<InlinePatchNotes
|
|
title={versionInfo?.remote.name}
|
|
date={new Intl.RelativeTimeFormat('en-US', {
|
|
numeric: 'auto',
|
|
}).format(
|
|
Math.ceil((new Date(versionInfo.remote.published_at).getTime() - new Date().getTime()) / 86400000),
|
|
'day',
|
|
)}
|
|
onClick={showPatchNotes}
|
|
>
|
|
<Suspense fallback={<Spinner style={{ width: '24', height: '24' }} />}>
|
|
<MarkdownRenderer>{versionInfo?.remote.body}</MarkdownRenderer>
|
|
</Suspense>
|
|
</InlinePatchNotes>
|
|
)}
|
|
</>
|
|
);
|
|
}
|