diff --git a/src/components/UploadProgress/dialog.tsx b/src/components/UploadProgress/dialog.tsx index 2bfdec3f7..cae758c9f 100644 --- a/src/components/UploadProgress/dialog.tsx +++ b/src/components/UploadProgress/dialog.tsx @@ -1,7 +1,7 @@ import { DialogContent } from '@mui/material'; import constants from 'utils/strings/constants'; -import { UPLOAD_STAGES, FileUploadResults } from 'constants/upload'; -import React from 'react'; +import { UPLOAD_STAGES, UPLOAD_RESULT } from 'constants/upload'; +import React, { useContext, useMemo } from 'react'; import { UploadProgressFooter } from './footer'; import { UploadProgressHeader } from './header'; import { InProgressSection } from './inProgressSection'; @@ -9,49 +9,46 @@ import { ResultSection } from './resultSection'; import { NotUploadSectionHeader } from './styledComponents'; import { getOSSpecificDesktopAppDownloadLink } from 'utils/common'; import DialogBoxBase from 'components/DialogBox/base'; -export function UploadProgressDialog({ - handleClose, - setExpanded, - expanded, - fileProgressStatuses, - sectionInfo, - fileUploadResultMap, - filesNotUploaded, - ...props -}) { +import UploadProgressContext from 'contexts/uploadProgress'; + +export function UploadProgressDialog() { + const { open, onClose, uploadStage, finishedUploads } = useContext( + UploadProgressContext + ); + + const hasUnUploadedFiles = useMemo(() => { + if ( + finishedUploads.get(UPLOAD_RESULT.ALREADY_UPLOADED).length > 0 || + finishedUploads.get(UPLOAD_RESULT.BLOCKED).length > 0 || + finishedUploads.get(UPLOAD_RESULT.FAILED).length > 0 || + finishedUploads.get(UPLOAD_RESULT.LARGER_THAN_AVAILABLE_STORAGE) + .length > 0 || + finishedUploads.get(UPLOAD_RESULT.TOO_LARGE).length > 0 || + finishedUploads.get(UPLOAD_RESULT.UNSUPPORTED).length > 0 + ) { + return true; + } else { + return false; + } + }, [finishedUploads]); + return ( - - - {(props.uploadStage === UPLOAD_STAGES.UPLOADING || - props.uploadStage === UPLOAD_STAGES.FINISH) && ( + + + {(uploadStage === UPLOAD_STAGES.UPLOADING || + uploadStage === UPLOAD_STAGES.FINISH) && ( - {props.uploadStage === UPLOAD_STAGES.UPLOADING && ( - + {uploadStage === UPLOAD_STAGES.UPLOADING && ( + )} - {props.uploadStage === UPLOAD_STAGES.FINISH && - filesNotUploaded && ( + {uploadStage === UPLOAD_STAGES.FINISH && + hasUnUploadedFiles && ( {constants.FILE_NOT_UPLOADED_LIST} )} )} - {props.uploadStage === UPLOAD_STAGES.FINISH && ( - - )} + {uploadStage === UPLOAD_STAGES.FINISH && } ); } diff --git a/src/components/UploadProgress/footer.tsx b/src/components/UploadProgress/footer.tsx index c1d73b8a9..ddcc3bd4a 100644 --- a/src/components/UploadProgress/footer.tsx +++ b/src/components/UploadProgress/footer.tsx @@ -1,25 +1,27 @@ import { Button, DialogActions } from '@mui/material'; -import { UPLOAD_STAGES, FileUploadResults } from 'constants/upload'; -import React from 'react'; +import { UPLOAD_STAGES, UPLOAD_RESULT } from 'constants/upload'; +import React, { useContext } from 'react'; import constants from 'utils/strings/constants'; -export function UploadProgressFooter({ - uploadStage, - fileUploadResultMap, - retryFailed, - closeModal, -}) { +import UploadProgressContext from 'contexts/uploadProgress'; + +export function UploadProgressFooter() { + const { uploadStage, finishedUploads, retryFailed, onClose } = useContext( + UploadProgressContext + ); + return ( {uploadStage === UPLOAD_STAGES.FINISH && - (fileUploadResultMap?.get(FileUploadResults.FAILED)?.length > - 0 || - fileUploadResultMap?.get(FileUploadResults.BLOCKED)?.length > - 0 ? ( + (finishedUploads?.get(UPLOAD_RESULT.FAILED)?.length > 0 || + finishedUploads?.get(UPLOAD_RESULT.BLOCKED)?.length > 0 ? ( ) : ( - ))} diff --git a/src/components/UploadProgress/header.tsx b/src/components/UploadProgress/header.tsx index 5f888a101..430790c89 100644 --- a/src/components/UploadProgress/header.tsx +++ b/src/components/UploadProgress/header.tsx @@ -2,24 +2,11 @@ import React from 'react'; import { UploadProgressBar } from './progressBar'; import { UploadProgressTitle } from './title'; -export function UploadProgressHeader({ - uploadStage, - setExpanded, - expanded, - handleClose, - fileCounter, - now, -}) { +export function UploadProgressHeader() { return ( <> - - + + ); } diff --git a/src/components/UploadProgress/inProgressSection.tsx b/src/components/UploadProgress/inProgressSection.tsx index 3cfea4a33..418c2ed69 100644 --- a/src/components/UploadProgress/inProgressSection.tsx +++ b/src/components/UploadProgress/inProgressSection.tsx @@ -1,37 +1,35 @@ -import React from 'react'; +import React, { useContext } from 'react'; import FileList from 'components/FileList'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { InProgressItemContainer } from './styledComponents'; -import { FileProgresses } from '.'; import { SectionInfo, UploadProgressSection, UploadProgressSectionContent, UploadProgressSectionTitle, } from './section'; +import UploadProgressContext from 'contexts/uploadProgress'; +import constants from 'utils/strings/constants'; -export interface InProgressProps { - filenames: Map; - sectionTitle: string; - fileProgressStatuses: FileProgresses[]; - sectionInfo?: any; -} -export const InProgressSection = (props: InProgressProps) => { - const fileList = props.fileProgressStatuses ?? []; +export const InProgressSection = () => { + const { inProgressUploads, hasLivePhotos, uploadFileNames } = useContext( + UploadProgressContext + ); + const fileList = inProgressUploads ?? []; return ( }> - {props.sectionTitle} + {constants.INPROGRESS_UPLOADS} - {props.sectionInfo && ( - {props.sectionInfo} + {hasLivePhotos && ( + {constants.LIVE_PHOTOS_DETECTED} )} ( - - {props.filenames.get(fileID)} + fileList={fileList.map(({ localFileID, progress }) => ( + + {uploadFileNames.get(localFileID)} {`-`} {`${progress}%`} diff --git a/src/components/UploadProgress/index.tsx b/src/components/UploadProgress/index.tsx index 017f57442..f75e33826 100644 --- a/src/components/UploadProgress/index.tsx +++ b/src/components/UploadProgress/index.tsx @@ -1,64 +1,71 @@ import { UploadProgressDialog } from './dialog'; import { MinimizedUploadProgress } from './minimized'; -import React, { useContext, useState } from 'react'; +import React, { useContext, useMemo, useState } from 'react'; import constants from 'utils/strings/constants'; -import { FileUploadResults, UPLOAD_STAGES } from 'constants/upload'; +import { UPLOAD_STAGES } from 'constants/upload'; import { AppContext } from 'pages/_app'; import { dialogCloseHandler } from 'components/DialogBox/base'; +import { + UploadFileNames, + UploadCounter, + InProgressUploads, + InProgressUpload, + FinishedUploads, + SegregatedFinishedUploads, +} from 'types/upload/ui'; +import UploadProgressContext from 'contexts/uploadProgress'; interface Props { - fileCounter; - uploadStage; - now; - closeModal; - retryFailed; - fileProgress: Map; - filenames: Map; - show; - uploadResult: Map; + open: boolean; + onClose: () => void; + uploadCounter: UploadCounter; + uploadStage: UPLOAD_STAGES; + percentComplete: number; + retryFailed: () => void; + inProgressUploads: InProgressUploads; + uploadFileNames: UploadFileNames; + finishedUploads: FinishedUploads; hasLivePhotos: boolean; cancelUploads: () => void; } -export interface FileProgresses { - fileID: number; - progress: number; -} -export default function UploadProgress(props: Props) { +export default function UploadProgress({ + open, + uploadCounter, + uploadStage, + percentComplete, + retryFailed, + uploadFileNames, + hasLivePhotos, + ...props +}: Props) { const appContext = useContext(AppContext); const [expanded, setExpanded] = useState(true); - const fileProgressStatuses = [] as FileProgresses[]; - const fileUploadResultMap = new Map(); - let filesNotUploaded = false; - let sectionInfo = null; - if (props.fileProgress) { - for (const [localID, progress] of props.fileProgress) { - fileProgressStatuses.push({ - fileID: localID, - progress, - }); - } - } - if (props.uploadResult) { - for (const [localID, progress] of props.uploadResult) { - if (!fileUploadResultMap.has(progress)) { - fileUploadResultMap.set(progress, []); - } - if ( - progress !== FileUploadResults.UPLOADED && - progress !== FileUploadResults.UPLOADED_WITH_STATIC_THUMBNAIL - ) { - filesNotUploaded = true; - } - const fileList = fileUploadResultMap.get(progress); - fileUploadResultMap.set(progress, [...fileList, localID]); + const inProgressUploads = useMemo( + () => + [...props.inProgressUploads.entries()].map( + ([localFileID, progress]) => + ({ + localFileID, + progress, + } as InProgressUpload) + ), + + [props.inProgressUploads] + ); + + const finishedUploads = useMemo(() => { + const finishedUploads = new Map() as SegregatedFinishedUploads; + for (const [localID, result] of props.finishedUploads) { + if (!finishedUploads.has(result)) { + finishedUploads.set(result, []); + } + finishedUploads.get(result).push(localID); } - } - if (props.hasLivePhotos) { - sectionInfo = constants.LIVE_PHOTOS_DETECTED; - } + return finishedUploads; + }, [props.finishedUploads]); function confirmCancelUpload() { appContext.setDialogMessage({ @@ -78,10 +85,10 @@ export default function UploadProgress(props: Props) { } function onClose() { - if (props.uploadStage !== UPLOAD_STAGES.FINISH) { + if (uploadStage !== UPLOAD_STAGES.FINISH) { confirmCancelUpload(); } else { - props.closeModal(); + props.onClose(); } } @@ -90,26 +97,22 @@ export default function UploadProgress(props: Props) { }); return ( - <> - {expanded ? ( - - ) : ( - - )} - + + {expanded ? : } + ); } diff --git a/src/components/UploadProgress/minimized.tsx b/src/components/UploadProgress/minimized.tsx index 5e6f6a3ec..c314dcd98 100644 --- a/src/components/UploadProgress/minimized.tsx +++ b/src/components/UploadProgress/minimized.tsx @@ -13,7 +13,7 @@ export function MinimizedUploadProgress(props) { sx={{ width: '360px', }}> - + ); diff --git a/src/components/UploadProgress/progressBar.tsx b/src/components/UploadProgress/progressBar.tsx index c5e55593b..43684eda6 100644 --- a/src/components/UploadProgress/progressBar.tsx +++ b/src/components/UploadProgress/progressBar.tsx @@ -1,8 +1,10 @@ -import React from 'react'; +import React, { useContext } from 'react'; import { LinearProgress, Divider, Box } from '@mui/material'; import { UPLOAD_STAGES } from 'constants/upload'; +import UploadProgressContext from 'contexts/uploadProgress'; -export function UploadProgressBar({ uploadStage, now }) { +export function UploadProgressBar() { + const { uploadStage, percentComplete } = useContext(UploadProgressContext); return ( {(uploadStage === UPLOAD_STAGES.READING_GOOGLE_METADATA_FILES || @@ -15,7 +17,7 @@ export function UploadProgressBar({ uploadStage, now }) { backgroundColor: 'transparent', }} variant="determinate" - value={now} + value={percentComplete} /> diff --git a/src/components/UploadProgress/resultSection.tsx b/src/components/UploadProgress/resultSection.tsx index f45fe8b24..052670d27 100644 --- a/src/components/UploadProgress/resultSection.tsx +++ b/src/components/UploadProgress/resultSection.tsx @@ -1,25 +1,28 @@ -import React from 'react'; +import React, { useContext } from 'react'; import FileList from 'components/FileList'; import { Typography } from '@mui/material'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { ResultItemContainer } from './styledComponents'; -import { FileUploadResults } from 'constants/upload'; +import { UPLOAD_RESULT } from 'constants/upload'; import { SectionInfo, UploadProgressSection, UploadProgressSectionContent, UploadProgressSectionTitle, } from './section'; +import UploadProgressContext from 'contexts/uploadProgress'; export interface ResultSectionProps { - filenames: Map; - fileUploadResultMap: Map; - fileUploadResult: FileUploadResults; + uploadResult: UPLOAD_RESULT; sectionTitle: any; sectionInfo?: any; } export const ResultSection = (props: ResultSectionProps) => { - const fileList = props.fileUploadResultMap?.get(props.fileUploadResult); + const { finishedUploads, uploadFileNames } = useContext( + UploadProgressContext + ); + const fileList = finishedUploads.get(props.uploadResult); + if (!fileList?.length) { return <>; } @@ -35,7 +38,7 @@ export const ResultSection = (props: ResultSectionProps) => { ( - {props.filenames.get(fileID)} + {uploadFileNames.get(fileID)} ))} /> diff --git a/src/components/UploadProgress/title.tsx b/src/components/UploadProgress/title.tsx index 1ddac4e4b..031c62b3a 100644 --- a/src/components/UploadProgress/title.tsx +++ b/src/components/UploadProgress/title.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useContext } from 'react'; import Close from '@mui/icons-material/Close'; import { DialogTitle, @@ -13,6 +13,7 @@ import { UPLOAD_STAGES } from 'constants/upload'; import constants from 'utils/strings/constants'; import { MaximizeIcon } from 'components/icons/Maximize'; import { MinimizeIcon } from 'components/icons/Minimize'; +import UploadProgressContext from 'contexts/uploadProgress'; const IconButtonWithBG = styled(IconButton)(({ theme }) => ({ backgroundColor: theme.palette.secondary.main, @@ -33,24 +34,22 @@ line-height: 36px; ); -function UploadProgressSubtitleText(props) { +function UploadProgressSubtitleText() { + const { uploadStage, uploadCounter } = useContext(UploadProgressContext); + return ( - {props.uploadStage === UPLOAD_STAGES.UPLOADING - ? constants.UPLOAD_STAGE_MESSAGE[props.uploadStage]( - props.fileCounter - ) - : constants.UPLOAD_STAGE_MESSAGE[props.uploadStage]} + {uploadStage === UPLOAD_STAGES.UPLOADING + ? constants.UPLOAD_STAGE_MESSAGE[uploadStage](uploadCounter) + : constants.UPLOAD_STAGE_MESSAGE[uploadStage]} ); } -export function UploadProgressTitle({ - setExpanded, - expanded, - handleClose, - ...props -}) { +export function UploadProgressTitle() { + const { setExpanded, onClose, expanded } = useContext( + UploadProgressContext + ); const toggleExpanded = () => setExpanded((expanded) => !expanded); return ( @@ -58,14 +57,14 @@ export function UploadProgressTitle({ - + {expanded ? : } - + diff --git a/src/components/pages/gallery/Upload.tsx b/src/components/pages/gallery/Upload.tsx index 3e15b1f3e..f5cfa2ab5 100644 --- a/src/components/pages/gallery/Upload.tsx +++ b/src/components/pages/gallery/Upload.tsx @@ -19,7 +19,6 @@ import { METADATA_FOLDER_NAME } from 'constants/export'; import { CustomError } from 'utils/error'; import { Collection } from 'types/collection'; import { SetLoading, SetFiles } from 'types/gallery'; -import { FileUploadResults, UPLOAD_STAGES } from 'constants/upload'; import { ElectronFile, FileWithCollection } from 'types/upload'; import UploadTypeSelector from '../../UploadTypeSelector'; import Router from 'next/router'; @@ -27,6 +26,13 @@ import { isCanvasBlocked } from 'utils/upload/isCanvasBlocked'; import { downloadApp } from 'utils/common'; import DiscFullIcon from '@mui/icons-material/DiscFull'; import { NotificationAttributes } from 'types/Notification'; +import { + UploadFileNames, + InProgressUploads, + UploadCounter, + FinishedUploads, +} from 'types/upload/ui'; +import { UPLOAD_STAGES } from 'constants/upload'; const FIRST_ALBUM_NAME = 'My First Album'; @@ -74,16 +80,13 @@ const NULL_ANALYSIS_RESULT = { }; export default function Upload(props: Props) { - const [progressView, setProgressView] = useState(false); - const [uploadStage, setUploadStage] = useState( - UPLOAD_STAGES.START - ); - const [filenames, setFilenames] = useState(new Map()); - const [fileCounter, setFileCounter] = useState({ finished: 0, total: 0 }); - const [fileProgress, setFileProgress] = useState(new Map()); - const [uploadResult, setUploadResult] = useState( - new Map() - ); + const [uploadProgressView, setUploadProgressView] = useState(false); + const [uploadStage, setUploadStage] = useState(); + const [uploadFileNames, setUploadFileNames] = useState(); + const [uploadCounter, setUploadCounter] = useState(); + const [inProgressUploads, setInProgressUploads] = + useState(); + const [finishedUploads, setFinishedUploads] = useState(); const [percentComplete, setPercentComplete] = useState(0); const [hasLivePhotos, setHasLivePhotos] = useState(false); @@ -103,11 +106,11 @@ export default function Upload(props: Props) { UploadManager.initUploader( { setPercentComplete, - setFileCounter, - setFileProgress, - setUploadResult, + setUploadCounter, + setInProgressUploads, + setFinishedUploads, setUploadStage, - setFilenames, + setUploadFilenames: setUploadFileNames, setHasLivePhotos, }, props.setFiles @@ -171,12 +174,12 @@ export default function Upload(props: Props) { const uploadInit = function () { setUploadStage(UPLOAD_STAGES.START); - setFileCounter({ finished: 0, total: 0 }); - setFileProgress(new Map()); - setUploadResult(new Map()); + setUploadCounter({ finished: 0, total: 0 }); + setInProgressUploads(new Map()); + setFinishedUploads(new Map()); setPercentComplete(0); props.closeCollectionSelector(); - setProgressView(true); + setUploadProgressView(true); }; const resumeDesktopUpload = async ( @@ -307,7 +310,7 @@ export default function Upload(props: Props) { ); } } catch (e) { - setProgressView(false); + setUploadProgressView(false); logError(e, 'Failed to create album'); appContext.setDialogMessage({ title: constants.ERROR, @@ -354,7 +357,7 @@ export default function Upload(props: Props) { ); } catch (err) { showUserFacingError(err.message); - setProgressView(false); + setUploadProgressView(false); throw err; } finally { props.setUploadInProgress(false); @@ -371,7 +374,7 @@ export default function Upload(props: Props) { } catch (err) { showUserFacingError(err.message); - setProgressView(false); + setUploadProgressView(false); } finally { props.setUploadInProgress(false); props.syncWithRemote(); @@ -494,7 +497,7 @@ export default function Upload(props: Props) { }; const cancelUploads = async () => { - setProgressView(false); + setUploadProgressView(false); if (isElectron()) { ImportService.cancelRemainingUploads(); } @@ -502,6 +505,8 @@ export default function Upload(props: Props) { Router.reload(); }; + const closeUploadProgress = () => setUploadProgressView(false); + return ( <> setProgressView(false)} retryFailed={retryFailed} - uploadResult={uploadResult} + finishedUploads={finishedUploads} cancelUploads={cancelUploads} /> diff --git a/src/constants/upload/index.ts b/src/constants/upload/index.ts index f2bf84b90..2c9d7a4e6 100644 --- a/src/constants/upload/index.ts +++ b/src/constants/upload/index.ts @@ -31,7 +31,7 @@ export enum UPLOAD_STAGES { FINISH, } -export enum FileUploadResults { +export enum UPLOAD_RESULT { FAILED, ALREADY_UPLOADED, UNSUPPORTED, diff --git a/src/contexts/uploadProgress.tsx b/src/contexts/uploadProgress.tsx new file mode 100644 index 000000000..3571383f3 --- /dev/null +++ b/src/contexts/uploadProgress.tsx @@ -0,0 +1,43 @@ +import { DialogProps } from '@mui/material'; +import { UPLOAD_STAGES } from 'constants/upload'; +import { createContext } from 'react'; +import { + UploadCounter, + InProgressUpload, + UploadFileNames, + SegregatedFinishedUploads, +} from 'types/upload/ui'; + +interface UploadProgressContextType { + open: boolean; + onClose: DialogProps['onClose']; + uploadCounter: UploadCounter; + uploadStage: UPLOAD_STAGES; + percentComplete: number; + retryFailed: () => void; + inProgressUploads: InProgressUpload[]; + uploadFileNames: UploadFileNames; + finishedUploads: SegregatedFinishedUploads; + hasLivePhotos: boolean; + expanded: boolean; + setExpanded: React.Dispatch>; +} +const defaultUploadProgressContext: UploadProgressContextType = { + open: null, + onClose: () => null, + uploadCounter: null, + uploadStage: null, + percentComplete: null, + retryFailed: () => null, + inProgressUploads: null, + uploadFileNames: null, + finishedUploads: null, + hasLivePhotos: null, + expanded: null, + setExpanded: () => null, +}; +const UploadProgressContext = createContext( + defaultUploadProgressContext +); + +export default UploadProgressContext; diff --git a/src/services/upload/uiService.ts b/src/services/upload/uiService.ts index dbdc47a82..4217c238f 100644 --- a/src/services/upload/uiService.ts +++ b/src/services/upload/uiService.ts @@ -1,16 +1,16 @@ import { - FileUploadResults, + UPLOAD_RESULT, RANDOM_PERCENTAGE_PROGRESS_FOR_PUT, UPLOAD_STAGES, } from 'constants/upload'; -import { ProgressUpdater } from 'types/upload'; +import { ProgressUpdater } from 'types/upload/ui'; class UIService { private perFileProgress: number; private filesUploaded: number; private totalFileCount: number; - private fileProgress: Map; - private uploadResult: Map; + private inProgressUploads: Map; + private finishedUploads: Map; private progressUpdater: ProgressUpdater; init(progressUpdater: ProgressUpdater) { @@ -20,8 +20,8 @@ class UIService { reset(count: number) { this.setTotalFileCount(count); this.filesUploaded = 0; - this.fileProgress = new Map(); - this.uploadResult = new Map(); + this.inProgressUploads = new Map(); + this.finishedUploads = new Map(); this.updateProgressBarUI(); } @@ -31,7 +31,7 @@ class UIService { } setFileProgress(key: number, progress: number) { - this.fileProgress.set(key, progress); + this.inProgressUploads.set(key, progress); this.updateProgressBarUI(); } @@ -44,7 +44,7 @@ class UIService { } setFilenames(filenames: Map) { - this.progressUpdater.setFilenames(filenames); + this.progressUpdater.setUploadFilenames(filenames); } setHasLivePhoto(hasLivePhoto: boolean) { @@ -56,18 +56,18 @@ class UIService { this.updateProgressBarUI(); } - moveFileToResultList(key: number, uploadResult: FileUploadResults) { - this.uploadResult.set(key, uploadResult); - this.fileProgress.delete(key); + moveFileToResultList(key: number, uploadResult: UPLOAD_RESULT) { + this.finishedUploads.set(key, uploadResult); + this.inProgressUploads.delete(key); this.updateProgressBarUI(); } updateProgressBarUI() { const { setPercentComplete, - setFileCounter, - setFileProgress, - setUploadResult, + setUploadCounter: setFileCounter, + setInProgressUploads, + setFinishedUploads, } = this.progressUpdater; setFileCounter({ finished: this.filesUploaded, @@ -75,10 +75,10 @@ class UIService { }); let percentComplete = this.perFileProgress * - (this.uploadResult.size || this.filesUploaded); - if (this.fileProgress) { + (this.finishedUploads.size || this.filesUploaded); + if (this.inProgressUploads) { // eslint-disable-next-line @typescript-eslint/no-unused-vars - for (const [_, progress] of this.fileProgress) { + for (const [_, progress] of this.inProgressUploads) { // filter negative indicator values during percentComplete calculation if (progress < 0) { continue; @@ -88,8 +88,8 @@ class UIService { } setPercentComplete(percentComplete); - setFileProgress(this.fileProgress); - setUploadResult(this.uploadResult); + setInProgressUploads(this.inProgressUploads); + setFinishedUploads(this.finishedUploads); } trackUploadProgress( @@ -108,7 +108,7 @@ class UIService { return { cancel, onUploadProgress: (event) => { - this.fileProgress.set( + this.inProgressUploads.set( fileLocalID, Math.min( Math.round( diff --git a/src/services/upload/uploadManager.ts b/src/services/upload/uploadManager.ts index 8fbc6fd36..ff4ba89d9 100644 --- a/src/services/upload/uploadManager.ts +++ b/src/services/upload/uploadManager.ts @@ -26,12 +26,11 @@ import { MetadataAndFileTypeInfoMap, ParsedMetadataJSON, ParsedMetadataJSONMap, - ProgressUpdater, } from 'types/upload'; import { - UPLOAD_STAGES, - FileUploadResults, + UPLOAD_RESULT, MAX_FILE_SIZE_SUPPORTED, + UPLOAD_STAGES, } from 'constants/upload'; import { ComlinkWorker } from 'utils/comlink'; import { FILE_TYPE } from 'constants/file'; @@ -39,6 +38,7 @@ import uiService from './uiService'; import { logUploadInfo } from 'utils/upload'; import isElectron from 'is-electron'; import ImportService from 'services/importService'; +import { ProgressUpdater } from 'types/upload/ui'; const MAX_CONCURRENT_UPLOADS = 4; const FILE_UPLOAD_COMPLETED = 100; @@ -350,7 +350,7 @@ class UploadManager { } async postUploadTask( - fileUploadResult: FileUploadResults, + fileUploadResult: UPLOAD_RESULT, uploadedFile: EnteFile, skipDecryption: boolean, fileWithCollection: FileWithCollection @@ -359,9 +359,9 @@ class UploadManager { logUploadInfo(`uploadedFile ${JSON.stringify(uploadedFile)}`); if ( - (fileUploadResult === FileUploadResults.UPLOADED || + (fileUploadResult === UPLOAD_RESULT.UPLOADED || fileUploadResult === - FileUploadResults.UPLOADED_WITH_STATIC_THUMBNAIL) && + UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL) && !skipDecryption ) { const decryptedFile = await decryptFile( @@ -387,8 +387,8 @@ class UploadManager { .push(decryptedFile); } if ( - fileUploadResult === FileUploadResults.FAILED || - fileUploadResult === FileUploadResults.BLOCKED + fileUploadResult === UPLOAD_RESULT.FAILED || + fileUploadResult === UPLOAD_RESULT.BLOCKED ) { this.failedFiles.push(fileWithCollection); } diff --git a/src/services/upload/uploader.ts b/src/services/upload/uploader.ts index b1cffab53..23c6335ce 100644 --- a/src/services/upload/uploader.ts +++ b/src/services/upload/uploader.ts @@ -10,7 +10,7 @@ import UploadHttpClient from './uploadHttpClient'; import UIService from './uiService'; import UploadService from './uploadService'; import { FILE_TYPE } from 'constants/file'; -import { FileUploadResults, MAX_FILE_SIZE_SUPPORTED } from 'constants/upload'; +import { UPLOAD_RESULT, MAX_FILE_SIZE_SUPPORTED } from 'constants/upload'; import { FileWithCollection, BackupedFile, UploadFile } from 'types/upload'; import { logUploadInfo } from 'utils/upload'; import { convertBytesToHumanReadable } from 'utils/billing'; @@ -18,7 +18,7 @@ import { sleep } from 'utils/common'; import { addToCollection } from 'services/collectionService'; interface UploadResponse { - fileUploadResult: FileUploadResults; + fileUploadResult: UPLOAD_RESULT; uploadedFile?: EnteFile; skipDecryption?: boolean; } @@ -41,7 +41,7 @@ export default async function uploader( try { const fileSize = UploadService.getAssetSize(uploadAsset); if (fileSize >= MAX_FILE_SIZE_SUPPORTED) { - return { fileUploadResult: FileUploadResults.TOO_LARGE }; + return { fileUploadResult: UPLOAD_RESULT.TOO_LARGE }; } if (fileTypeInfo.fileType === FILE_TYPE.OTHERS) { throw Error(CustomError.UNSUPPORTED_FILE_FORMAT); @@ -52,7 +52,7 @@ export default async function uploader( if (fileAlreadyInCollection(existingFilesInCollection, metadata)) { logUploadInfo(`skipped upload for ${fileNameSize}`); - return { fileUploadResult: FileUploadResults.ALREADY_UPLOADED }; + return { fileUploadResult: UPLOAD_RESULT.ALREADY_UPLOADED }; } const sameFileInOtherCollection = findSameFileInOtherCollection( @@ -68,7 +68,7 @@ export default async function uploader( resultFile.collectionID = collection.id; await addToCollection(collection, [resultFile]); return { - fileUploadResult: FileUploadResults.UPLOADED, + fileUploadResult: UPLOAD_RESULT.UPLOADED, uploadedFile: resultFile, skipDecryption: true, }; @@ -82,7 +82,7 @@ export default async function uploader( fileAlreadyInCollection(existingFiles, metadata) ) { logUploadInfo(`deduped upload for ${fileNameSize}`); - return { fileUploadResult: FileUploadResults.ALREADY_UPLOADED }; + return { fileUploadResult: UPLOAD_RESULT.ALREADY_UPLOADED }; } logUploadInfo(`reading asset ${fileNameSize}`); @@ -125,8 +125,8 @@ export default async function uploader( return { fileUploadResult: metadata.hasStaticThumbnail - ? FileUploadResults.UPLOADED_WITH_STATIC_THUMBNAIL - : FileUploadResults.UPLOADED, + ? UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL + : UPLOAD_RESULT.UPLOADED, uploadedFile: uploadedFile, }; } catch (e) { @@ -140,16 +140,16 @@ export default async function uploader( const error = handleUploadError(e); switch (error.message) { case CustomError.ETAG_MISSING: - return { fileUploadResult: FileUploadResults.BLOCKED }; + return { fileUploadResult: UPLOAD_RESULT.BLOCKED }; case CustomError.UNSUPPORTED_FILE_FORMAT: - return { fileUploadResult: FileUploadResults.UNSUPPORTED }; + return { fileUploadResult: UPLOAD_RESULT.UNSUPPORTED }; case CustomError.FILE_TOO_LARGE: return { fileUploadResult: - FileUploadResults.LARGER_THAN_AVAILABLE_STORAGE, + UPLOAD_RESULT.LARGER_THAN_AVAILABLE_STORAGE, }; default: - return { fileUploadResult: FileUploadResults.FAILED }; + return { fileUploadResult: UPLOAD_RESULT.FAILED }; } } } diff --git a/src/types/upload/index.ts b/src/types/upload/index.ts index 66a54b824..076ac7fff 100644 --- a/src/types/upload/index.ts +++ b/src/types/upload/index.ts @@ -1,5 +1,4 @@ import { FILE_TYPE } from 'constants/file'; -import { UPLOAD_STAGES } from 'constants/upload'; import { Collection } from 'types/collection'; import { fileAttribute } from 'types/file'; @@ -56,21 +55,6 @@ export interface FileTypeInfo { videoType?: string; } -export interface ProgressUpdater { - setPercentComplete: React.Dispatch>; - setFileCounter: React.Dispatch< - React.SetStateAction<{ - finished: number; - total: number; - }> - >; - setUploadStage: React.Dispatch>; - setFileProgress: React.Dispatch>>; - setUploadResult: React.Dispatch>>; - setFilenames: React.Dispatch>>; - setHasLivePhotos: React.Dispatch>; -} - /* * ElectronFile is a custom interface that is used to represent * any file on disk as a File-like object in the Electron desktop app. diff --git a/src/types/upload/ui.ts b/src/types/upload/ui.ts new file mode 100644 index 000000000..edb9014bb --- /dev/null +++ b/src/types/upload/ui.ts @@ -0,0 +1,40 @@ +import { UPLOAD_RESULT, UPLOAD_STAGES } from 'constants/upload'; + +export type FileID = number; +export type FileName = string; + +export type PercentageUploaded = number; +export type UploadFileNames = Map; + +export interface UploadCounter { + finished: number; + total: number; +} + +export interface InProgressUpload { + localFileID: FileID; + progress: PercentageUploaded; +} + +export interface FinishedUpload { + localFileID: FileID; + result: UPLOAD_RESULT; +} + +export type InProgressUploads = Map; + +export type FinishedUploads = Map; + +export type SegregatedFinishedUploads = Map; + +export interface ProgressUpdater { + setPercentComplete: React.Dispatch>; + setUploadCounter: React.Dispatch>; + setUploadStage: React.Dispatch>; + setInProgressUploads: React.Dispatch< + React.SetStateAction + >; + setFinishedUploads: React.Dispatch>; + setUploadFilenames: React.Dispatch>; + setHasLivePhotos: React.Dispatch>; +}