add upload progress context
This commit is contained in:
parent
b51afc7efe
commit
ae3a68378f
|
@ -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 (
|
||||
<DialogBoxBase maxWidth="xs" open={props.show} onClose={handleClose}>
|
||||
<UploadProgressHeader
|
||||
uploadStage={props.uploadStage}
|
||||
setExpanded={setExpanded}
|
||||
expanded={expanded}
|
||||
handleClose={handleClose}
|
||||
fileCounter={props.fileCounter}
|
||||
now={props.now}
|
||||
/>
|
||||
{(props.uploadStage === UPLOAD_STAGES.UPLOADING ||
|
||||
props.uploadStage === UPLOAD_STAGES.FINISH) && (
|
||||
<DialogBoxBase maxWidth="xs" open={open} onClose={onClose}>
|
||||
<UploadProgressHeader />
|
||||
{(uploadStage === UPLOAD_STAGES.UPLOADING ||
|
||||
uploadStage === UPLOAD_STAGES.FINISH) && (
|
||||
<DialogContent sx={{ '&&&': { px: 0 } }}>
|
||||
{props.uploadStage === UPLOAD_STAGES.UPLOADING && (
|
||||
<InProgressSection
|
||||
filenames={props.filenames}
|
||||
fileProgressStatuses={fileProgressStatuses}
|
||||
sectionTitle={constants.INPROGRESS_UPLOADS}
|
||||
sectionInfo={sectionInfo}
|
||||
/>
|
||||
{uploadStage === UPLOAD_STAGES.UPLOADING && (
|
||||
<InProgressSection />
|
||||
)}
|
||||
|
||||
<ResultSection
|
||||
filenames={props.filenames}
|
||||
fileUploadResultMap={fileUploadResultMap}
|
||||
fileUploadResult={FileUploadResults.UPLOADED}
|
||||
uploadResult={UPLOAD_RESULT.UPLOADED}
|
||||
sectionTitle={constants.SUCCESSFUL_UPLOADS}
|
||||
/>
|
||||
<ResultSection
|
||||
filenames={props.filenames}
|
||||
fileUploadResultMap={fileUploadResultMap}
|
||||
fileUploadResult={
|
||||
FileUploadResults.UPLOADED_WITH_STATIC_THUMBNAIL
|
||||
uploadResult={
|
||||
UPLOAD_RESULT.UPLOADED_WITH_STATIC_THUMBNAIL
|
||||
}
|
||||
sectionTitle={
|
||||
constants.THUMBNAIL_GENERATION_FAILED_UPLOADS
|
||||
|
@ -59,40 +56,32 @@ export function UploadProgressDialog({
|
|||
sectionInfo={constants.THUMBNAIL_GENERATION_FAILED_INFO}
|
||||
/>
|
||||
|
||||
{props.uploadStage === UPLOAD_STAGES.FINISH &&
|
||||
filesNotUploaded && (
|
||||
{uploadStage === UPLOAD_STAGES.FINISH &&
|
||||
hasUnUploadedFiles && (
|
||||
<NotUploadSectionHeader>
|
||||
{constants.FILE_NOT_UPLOADED_LIST}
|
||||
</NotUploadSectionHeader>
|
||||
)}
|
||||
|
||||
<ResultSection
|
||||
filenames={props.filenames}
|
||||
fileUploadResultMap={fileUploadResultMap}
|
||||
fileUploadResult={FileUploadResults.BLOCKED}
|
||||
uploadResult={UPLOAD_RESULT.BLOCKED}
|
||||
sectionTitle={constants.BLOCKED_UPLOADS}
|
||||
sectionInfo={constants.ETAGS_BLOCKED(
|
||||
getOSSpecificDesktopAppDownloadLink()
|
||||
)}
|
||||
/>
|
||||
<ResultSection
|
||||
filenames={props.filenames}
|
||||
fileUploadResultMap={fileUploadResultMap}
|
||||
fileUploadResult={FileUploadResults.FAILED}
|
||||
uploadResult={UPLOAD_RESULT.FAILED}
|
||||
sectionTitle={constants.FAILED_UPLOADS}
|
||||
/>
|
||||
<ResultSection
|
||||
filenames={props.filenames}
|
||||
fileUploadResultMap={fileUploadResultMap}
|
||||
fileUploadResult={FileUploadResults.ALREADY_UPLOADED}
|
||||
uploadResult={UPLOAD_RESULT.ALREADY_UPLOADED}
|
||||
sectionTitle={constants.SKIPPED_FILES}
|
||||
sectionInfo={constants.SKIPPED_INFO}
|
||||
/>
|
||||
<ResultSection
|
||||
filenames={props.filenames}
|
||||
fileUploadResultMap={fileUploadResultMap}
|
||||
fileUploadResult={
|
||||
FileUploadResults.LARGER_THAN_AVAILABLE_STORAGE
|
||||
uploadResult={
|
||||
UPLOAD_RESULT.LARGER_THAN_AVAILABLE_STORAGE
|
||||
}
|
||||
sectionTitle={
|
||||
constants.LARGER_THAN_AVAILABLE_STORAGE_UPLOADS
|
||||
|
@ -102,29 +91,18 @@ export function UploadProgressDialog({
|
|||
}
|
||||
/>
|
||||
<ResultSection
|
||||
filenames={props.filenames}
|
||||
fileUploadResultMap={fileUploadResultMap}
|
||||
fileUploadResult={FileUploadResults.UNSUPPORTED}
|
||||
uploadResult={UPLOAD_RESULT.UNSUPPORTED}
|
||||
sectionTitle={constants.UNSUPPORTED_FILES}
|
||||
sectionInfo={constants.UNSUPPORTED_INFO}
|
||||
/>
|
||||
<ResultSection
|
||||
filenames={props.filenames}
|
||||
fileUploadResultMap={fileUploadResultMap}
|
||||
fileUploadResult={FileUploadResults.TOO_LARGE}
|
||||
uploadResult={UPLOAD_RESULT.TOO_LARGE}
|
||||
sectionTitle={constants.TOO_LARGE_UPLOADS}
|
||||
sectionInfo={constants.TOO_LARGE_INFO}
|
||||
/>
|
||||
</DialogContent>
|
||||
)}
|
||||
{props.uploadStage === UPLOAD_STAGES.FINISH && (
|
||||
<UploadProgressFooter
|
||||
uploadStage={props.uploadStage}
|
||||
retryFailed={props.retryFailed}
|
||||
closeModal={handleClose}
|
||||
fileUploadResultMap={fileUploadResultMap}
|
||||
/>
|
||||
)}
|
||||
{uploadStage === UPLOAD_STAGES.FINISH && <UploadProgressFooter />}
|
||||
</DialogBoxBase>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 (
|
||||
<DialogActions>
|
||||
{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 ? (
|
||||
<Button variant="contained" fullWidth onClick={retryFailed}>
|
||||
{constants.RETRY_FAILED}
|
||||
</Button>
|
||||
) : (
|
||||
<Button variant="contained" fullWidth onClick={closeModal}>
|
||||
<Button
|
||||
variant="contained"
|
||||
fullWidth
|
||||
onClick={() => onClose.bind(null)}>
|
||||
{constants.CLOSE}
|
||||
</Button>
|
||||
))}
|
||||
|
|
|
@ -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 (
|
||||
<>
|
||||
<UploadProgressTitle
|
||||
uploadStage={uploadStage}
|
||||
setExpanded={setExpanded}
|
||||
expanded={expanded}
|
||||
handleClose={handleClose}
|
||||
fileCounter={fileCounter}
|
||||
/>
|
||||
<UploadProgressBar now={now} uploadStage={uploadStage} />
|
||||
<UploadProgressTitle />
|
||||
<UploadProgressBar />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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<number, string>;
|
||||
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 (
|
||||
<UploadProgressSection defaultExpanded>
|
||||
<UploadProgressSectionTitle expandIcon={<ExpandMoreIcon />}>
|
||||
{props.sectionTitle}
|
||||
{constants.INPROGRESS_UPLOADS}
|
||||
</UploadProgressSectionTitle>
|
||||
<UploadProgressSectionContent>
|
||||
{props.sectionInfo && (
|
||||
<SectionInfo>{props.sectionInfo}</SectionInfo>
|
||||
{hasLivePhotos && (
|
||||
<SectionInfo>{constants.LIVE_PHOTOS_DETECTED}</SectionInfo>
|
||||
)}
|
||||
<FileList
|
||||
fileList={fileList.map(({ fileID, progress }) => (
|
||||
<InProgressItemContainer key={fileID}>
|
||||
<span>{props.filenames.get(fileID)}</span>
|
||||
fileList={fileList.map(({ localFileID, progress }) => (
|
||||
<InProgressItemContainer key={localFileID}>
|
||||
<span>{uploadFileNames.get(localFileID)}</span>
|
||||
<span className="separator">{`-`}</span>
|
||||
<span>{`${progress}%`}</span>
|
||||
</InProgressItemContainer>
|
||||
|
|
|
@ -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<number, number>;
|
||||
filenames: Map<number, string>;
|
||||
show;
|
||||
uploadResult: Map<number, FileUploadResults>;
|
||||
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<FileUploadResults, number[]>();
|
||||
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 ? (
|
||||
<UploadProgressDialog
|
||||
handleClose={handleClose}
|
||||
setExpanded={setExpanded}
|
||||
expanded={expanded}
|
||||
fileProgressStatuses={fileProgressStatuses}
|
||||
sectionInfo={sectionInfo}
|
||||
fileUploadResultMap={fileUploadResultMap}
|
||||
filesNotUploaded={filesNotUploaded}
|
||||
{...props}
|
||||
/>
|
||||
) : (
|
||||
<MinimizedUploadProgress
|
||||
setExpanded={setExpanded}
|
||||
expanded={expanded}
|
||||
handleClose={handleClose}
|
||||
{...props}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
<UploadProgressContext.Provider
|
||||
value={{
|
||||
open,
|
||||
onClose: handleClose,
|
||||
uploadCounter,
|
||||
uploadStage,
|
||||
percentComplete,
|
||||
retryFailed,
|
||||
inProgressUploads,
|
||||
uploadFileNames,
|
||||
finishedUploads,
|
||||
hasLivePhotos,
|
||||
expanded,
|
||||
setExpanded,
|
||||
}}>
|
||||
{expanded ? <UploadProgressDialog /> : <MinimizedUploadProgress />}
|
||||
</UploadProgressContext.Provider>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ export function MinimizedUploadProgress(props) {
|
|||
sx={{
|
||||
width: '360px',
|
||||
}}>
|
||||
<UploadProgressHeader {...props} />
|
||||
<UploadProgressHeader />
|
||||
</Paper>
|
||||
</Snackbar>
|
||||
);
|
||||
|
|
|
@ -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 (
|
||||
<Box>
|
||||
{(uploadStage === UPLOAD_STAGES.READING_GOOGLE_METADATA_FILES ||
|
||||
|
@ -15,7 +17,7 @@ export function UploadProgressBar({ uploadStage, now }) {
|
|||
backgroundColor: 'transparent',
|
||||
}}
|
||||
variant="determinate"
|
||||
value={now}
|
||||
value={percentComplete}
|
||||
/>
|
||||
<Divider />
|
||||
</>
|
||||
|
|
|
@ -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<number, string>;
|
||||
fileUploadResultMap: Map<FileUploadResults, number[]>;
|
||||
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) => {
|
|||
<FileList
|
||||
fileList={fileList.map((fileID) => (
|
||||
<ResultItemContainer key={fileID}>
|
||||
{props.filenames.get(fileID)}
|
||||
{uploadFileNames.get(fileID)}
|
||||
</ResultItemContainer>
|
||||
))}
|
||||
/>
|
||||
|
|
|
@ -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;
|
|||
</Typography>
|
||||
);
|
||||
|
||||
function UploadProgressSubtitleText(props) {
|
||||
function UploadProgressSubtitleText() {
|
||||
const { uploadStage, uploadCounter } = useContext(UploadProgressContext);
|
||||
|
||||
return (
|
||||
<Typography color="text.secondary">
|
||||
{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]}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
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({
|
|||
<SpaceBetweenFlex>
|
||||
<Box>
|
||||
<UploadProgressTitleText expanded={expanded} />
|
||||
<UploadProgressSubtitleText {...props} />
|
||||
<UploadProgressSubtitleText />
|
||||
</Box>
|
||||
<Box>
|
||||
<Stack direction={'row'} spacing={1}>
|
||||
<IconButtonWithBG onClick={toggleExpanded}>
|
||||
{expanded ? <MinimizeIcon /> : <MaximizeIcon />}
|
||||
</IconButtonWithBG>
|
||||
<IconButtonWithBG onClick={handleClose}>
|
||||
<IconButtonWithBG onClick={onClose.bind(null)}>
|
||||
<Close />
|
||||
</IconButtonWithBG>
|
||||
</Stack>
|
||||
|
|
|
@ -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>(
|
||||
UPLOAD_STAGES.START
|
||||
);
|
||||
const [filenames, setFilenames] = useState(new Map<number, string>());
|
||||
const [fileCounter, setFileCounter] = useState({ finished: 0, total: 0 });
|
||||
const [fileProgress, setFileProgress] = useState(new Map<number, number>());
|
||||
const [uploadResult, setUploadResult] = useState(
|
||||
new Map<number, FileUploadResults>()
|
||||
);
|
||||
const [uploadProgressView, setUploadProgressView] = useState(false);
|
||||
const [uploadStage, setUploadStage] = useState<UPLOAD_STAGES>();
|
||||
const [uploadFileNames, setUploadFileNames] = useState<UploadFileNames>();
|
||||
const [uploadCounter, setUploadCounter] = useState<UploadCounter>();
|
||||
const [inProgressUploads, setInProgressUploads] =
|
||||
useState<InProgressUploads>();
|
||||
const [finishedUploads, setFinishedUploads] = useState<FinishedUploads>();
|
||||
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<number, number>());
|
||||
setUploadResult(new Map<number, number>());
|
||||
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 (
|
||||
<>
|
||||
<UploadStrategyChoiceModal
|
||||
|
@ -532,16 +537,16 @@ export default function Upload(props: Props) {
|
|||
}
|
||||
/>
|
||||
<UploadProgress
|
||||
now={percentComplete}
|
||||
filenames={filenames}
|
||||
fileCounter={fileCounter}
|
||||
open={uploadProgressView}
|
||||
onClose={closeUploadProgress}
|
||||
percentComplete={percentComplete}
|
||||
uploadFileNames={uploadFileNames}
|
||||
uploadCounter={uploadCounter}
|
||||
uploadStage={uploadStage}
|
||||
fileProgress={fileProgress}
|
||||
inProgressUploads={inProgressUploads}
|
||||
hasLivePhotos={hasLivePhotos}
|
||||
show={progressView}
|
||||
closeModal={() => setProgressView(false)}
|
||||
retryFailed={retryFailed}
|
||||
uploadResult={uploadResult}
|
||||
finishedUploads={finishedUploads}
|
||||
cancelUploads={cancelUploads}
|
||||
/>
|
||||
</>
|
||||
|
|
|
@ -31,7 +31,7 @@ export enum UPLOAD_STAGES {
|
|||
FINISH,
|
||||
}
|
||||
|
||||
export enum FileUploadResults {
|
||||
export enum UPLOAD_RESULT {
|
||||
FAILED,
|
||||
ALREADY_UPLOADED,
|
||||
UNSUPPORTED,
|
||||
|
|
43
src/contexts/uploadProgress.tsx
Normal file
43
src/contexts/uploadProgress.tsx
Normal file
|
@ -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<React.SetStateAction<boolean>>;
|
||||
}
|
||||
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<UploadProgressContextType>(
|
||||
defaultUploadProgressContext
|
||||
);
|
||||
|
||||
export default UploadProgressContext;
|
|
@ -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<number, number>;
|
||||
private uploadResult: Map<number, FileUploadResults>;
|
||||
private inProgressUploads: Map<number, number>;
|
||||
private finishedUploads: Map<number, UPLOAD_RESULT>;
|
||||
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<number, number>();
|
||||
this.uploadResult = new Map<number, FileUploadResults>();
|
||||
this.inProgressUploads = new Map<number, number>();
|
||||
this.finishedUploads = new Map<number, UPLOAD_RESULT>();
|
||||
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<number, string>) {
|
||||
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(
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<React.SetStateAction<number>>;
|
||||
setFileCounter: React.Dispatch<
|
||||
React.SetStateAction<{
|
||||
finished: number;
|
||||
total: number;
|
||||
}>
|
||||
>;
|
||||
setUploadStage: React.Dispatch<React.SetStateAction<UPLOAD_STAGES>>;
|
||||
setFileProgress: React.Dispatch<React.SetStateAction<Map<number, number>>>;
|
||||
setUploadResult: React.Dispatch<React.SetStateAction<Map<number, number>>>;
|
||||
setFilenames: React.Dispatch<React.SetStateAction<Map<number, string>>>;
|
||||
setHasLivePhotos: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
/*
|
||||
* ElectronFile is a custom interface that is used to represent
|
||||
* any file on disk as a File-like object in the Electron desktop app.
|
||||
|
|
40
src/types/upload/ui.ts
Normal file
40
src/types/upload/ui.ts
Normal file
|
@ -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<FileID, FileName>;
|
||||
|
||||
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<FileID, PercentageUploaded>;
|
||||
|
||||
export type FinishedUploads = Map<FileID, UPLOAD_RESULT>;
|
||||
|
||||
export type SegregatedFinishedUploads = Map<UPLOAD_RESULT, FileID[]>;
|
||||
|
||||
export interface ProgressUpdater {
|
||||
setPercentComplete: React.Dispatch<React.SetStateAction<number>>;
|
||||
setUploadCounter: React.Dispatch<React.SetStateAction<UploadCounter>>;
|
||||
setUploadStage: React.Dispatch<React.SetStateAction<UPLOAD_STAGES>>;
|
||||
setInProgressUploads: React.Dispatch<
|
||||
React.SetStateAction<InProgressUploads>
|
||||
>;
|
||||
setFinishedUploads: React.Dispatch<React.SetStateAction<FinishedUploads>>;
|
||||
setUploadFilenames: React.Dispatch<React.SetStateAction<UploadFileNames>>;
|
||||
setHasLivePhotos: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
}
|
Loading…
Reference in a new issue