mirror of
https://github.com/SteamDeckHomebrew/decky-loader.git
synced 2026-06-17 00:37:49 +00:00
plugin install progress (#614)
* Frontend progress bars * Backend bit * closure is stale i think so no closure for you * Fix formatting of the progress svgs * Reset progress bar when new plugin starts downloading
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { ConfirmModal, Navigation, QuickAccessTab } from '@decky/ui';
|
||||
import { FC, useMemo, useState } from 'react';
|
||||
import { ConfirmModal, Navigation, ProgressBarWithInfo, QuickAccessTab } from '@decky/ui';
|
||||
import { FC, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaCheck, FaDownload } from 'react-icons/fa';
|
||||
|
||||
import { InstallType } from '../../plugin';
|
||||
|
||||
@@ -27,8 +28,42 @@ const MultiplePluginsInstallModal: FC<MultiplePluginsInstallModalProps> = ({
|
||||
closeModal,
|
||||
}) => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [percentage, setPercentage] = useState<number>(0);
|
||||
const [pluginsCompleted, setPluginsCompleted] = useState<string[]>([]);
|
||||
const [pluginInProgress, setInProgress] = useState<string | null>();
|
||||
const [downloadInfo, setDownloadInfo] = useState<string | null>(null);
|
||||
const { t } = useTranslation();
|
||||
|
||||
function updateDownloadState(percent: number, trans_text: string | undefined, trans_info: Record<string, string>) {
|
||||
setPercentage(percent);
|
||||
if (trans_text === undefined) {
|
||||
setDownloadInfo(null);
|
||||
} else {
|
||||
setDownloadInfo(t(trans_text, trans_info));
|
||||
}
|
||||
}
|
||||
|
||||
function startDownload(name: string) {
|
||||
setInProgress(name);
|
||||
setPercentage(0);
|
||||
}
|
||||
|
||||
function finishDownload(name: string) {
|
||||
setPluginsCompleted((list) => [...list, name]);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
DeckyBackend.addEventListener('loader/plugin_download_info', updateDownloadState);
|
||||
DeckyBackend.addEventListener('loader/plugin_download_start', startDownload);
|
||||
DeckyBackend.addEventListener('loader/plugin_download_finish', finishDownload);
|
||||
|
||||
return () => {
|
||||
DeckyBackend.removeEventListener('loader/plugin_download_info', updateDownloadState);
|
||||
DeckyBackend.removeEventListener('loader/plugin_download_start', startDownload);
|
||||
DeckyBackend.removeEventListener('loader/plugin_download_finish', finishDownload);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// used as part of the title translation
|
||||
// if we know all operations are of a specific type, we can show so in the title to make decision easier
|
||||
const installTypeGrouped = useMemo((): TitleTranslationMapping => {
|
||||
@@ -66,7 +101,10 @@ const MultiplePluginsInstallModal: FC<MultiplePluginsInstallModalProps> = ({
|
||||
|
||||
return (
|
||||
<li key={i} style={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<div>{description}</div>
|
||||
<span>
|
||||
{description}{' '}
|
||||
{(pluginsCompleted.includes(name) && <FaCheck />) || (name === pluginInProgress && <FaDownload />)}
|
||||
</span>
|
||||
{hash === 'False' && (
|
||||
<div style={{ color: 'red', paddingLeft: '10px' }}>{t('PluginInstallModal.no_hash')}</div>
|
||||
)}
|
||||
@@ -74,6 +112,17 @@ const MultiplePluginsInstallModal: FC<MultiplePluginsInstallModalProps> = ({
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
{/* TODO: center the progress bar and make it 80% width */}
|
||||
{loading && (
|
||||
<ProgressBarWithInfo
|
||||
// when the key changes, react considers this a new component so resets the progress without the smoothing animation
|
||||
key={pluginInProgress}
|
||||
bottomSeparator="none"
|
||||
focusable={false}
|
||||
nProgress={percentage}
|
||||
sOperationText={downloadInfo}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</ConfirmModal>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ConfirmModal, Navigation, QuickAccessTab } from '@decky/ui';
|
||||
import { FC, useState } from 'react';
|
||||
import { ConfirmModal, Navigation, ProgressBarWithInfo, QuickAccessTab } from '@decky/ui';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import TranslationHelper, { TranslationClass } from '../../utils/TranslationHelper';
|
||||
@@ -24,8 +24,26 @@ const PluginInstallModal: FC<PluginInstallModalProps> = ({
|
||||
closeModal,
|
||||
}) => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [percentage, setPercentage] = useState<number>(0);
|
||||
const [downloadInfo, setDownloadInfo] = useState<string | null>(null);
|
||||
const { t } = useTranslation();
|
||||
|
||||
function updateDownloadState(percent: number, trans_text: string | undefined, trans_info: Record<string, string>) {
|
||||
setPercentage(percent);
|
||||
if (trans_text === undefined) {
|
||||
setDownloadInfo(null);
|
||||
} else {
|
||||
setDownloadInfo(t(trans_text, trans_info));
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
DeckyBackend.addEventListener('loader/plugin_download_info', updateDownloadState);
|
||||
return () => {
|
||||
DeckyBackend.removeEventListener('loader/plugin_download_info', updateDownloadState);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ConfirmModal
|
||||
bOKDisabled={loading}
|
||||
@@ -80,6 +98,14 @@ const PluginInstallModal: FC<PluginInstallModalProps> = ({
|
||||
install_type={installType}
|
||||
/>
|
||||
</div>
|
||||
{loading && (
|
||||
<ProgressBarWithInfo
|
||||
layout="inline"
|
||||
bottomSeparator="none"
|
||||
nProgress={percentage}
|
||||
sOperationText={downloadInfo}
|
||||
/>
|
||||
)}
|
||||
{hash == 'False' && <span style={{ color: 'red' }}>{t('PluginInstallModal.no_hash')}</span>}
|
||||
</ConfirmModal>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user