소스 검색

add file download location selection option for selected files and single file

Abhinav 1 년 전
부모
커밋
5802db5434

+ 4 - 1
apps/photos/src/components/FilesDownloadProgress.tsx

@@ -128,7 +128,10 @@ export const FilesDownloadProgress: React.FC<FilesDownloadProgressProps> = ({
                 <Notification
                     key={attributes.collectionID}
                     horizontal="left"
-                    sx={{ '&&': { bottom: `${index * 80 + 20}px` } }}
+                    sx={{
+                        '&&': { bottom: `${index * 80 + 20}px` },
+                        zIndex: 1600,
+                    }}
                     open={isFilesDownloadStarted(attributes)}
                     onClose={handleClose(attributes)}
                     keepOpenOnClick

+ 9 - 1
apps/photos/src/components/PhotoFrame.tsx

@@ -11,7 +11,10 @@ import AutoSizer from 'react-virtualized-auto-sizer';
 import PhotoViewer from 'components/PhotoViewer';
 import { TRASH_SECTION } from 'constants/collection';
 import { updateFileMsrcProps, updateFileSrcProps } from 'utils/photoFrame';
-import { SelectedState } from 'types/gallery';
+import {
+    SelectedState,
+    SetFilesDownloadProgressAttributesCreator,
+} from 'types/gallery';
 import { PublicCollectionGalleryContext } from 'utils/publicCollectionGallery';
 import { useRouter } from 'next/router';
 import { logError } from '@ente/shared/sentry';
@@ -62,6 +65,7 @@ interface Props {
     showAppDownloadBanner?: boolean;
     setIsPhotoSwipeOpen?: (value: boolean) => void;
     isInHiddenSection?: boolean;
+    setFilesDownloadProgressAttributesCreator?: SetFilesDownloadProgressAttributesCreator;
 }
 
 const PhotoFrame = ({
@@ -81,6 +85,7 @@ const PhotoFrame = ({
     showAppDownloadBanner,
     setIsPhotoSwipeOpen,
     isInHiddenSection,
+    setFilesDownloadProgressAttributesCreator,
 }: Props) => {
     const [open, setOpen] = useState(false);
     const [currentIndex, setCurrentIndex] = useState<number>(0);
@@ -607,6 +612,9 @@ const PhotoFrame = ({
                 enableDownload={enableDownload}
                 fileToCollectionsMap={fileToCollectionsMap}
                 collectionNameMap={collectionNameMap}
+                setFilesDownloadProgressAttributesCreator={
+                    setFilesDownloadProgressAttributesCreator
+                }
             />
         </Container>
     );

+ 16 - 8
apps/photos/src/components/PhotoViewer/index.tsx

@@ -8,12 +8,12 @@ import {
 } from 'services/collectionService';
 import { EnteFile } from 'types/file';
 import {
-    downloadFile,
     copyFileToClipboard,
     getFileExtension,
     getFileFromURL,
     isSupportedRawFormat,
     isRawFile,
+    downloadSingleFile,
 } from 'utils/file';
 import { logError } from '@ente/shared/sentry';
 
@@ -58,6 +58,7 @@ import isElectron from 'is-electron';
 import ReplayIcon from '@mui/icons-material/Replay';
 import ImageEditorOverlay from './ImageEditorOverlay';
 import EditIcon from '@mui/icons-material/Edit';
+import { SetFilesDownloadProgressAttributesCreator } from 'types/gallery';
 
 interface PhotoswipeFullscreenAPI {
     enter: () => void;
@@ -92,6 +93,7 @@ interface Iprops {
     enableDownload: boolean;
     fileToCollectionsMap: Map<number, number[]>;
     collectionNameMap: Map<number, string>;
+    setFilesDownloadProgressAttributesCreator: SetFilesDownloadProgressAttributesCreator;
 }
 
 function PhotoViewer(props: Iprops) {
@@ -259,7 +261,7 @@ function PhotoViewer(props: Iprops) {
             `download-btn-${item.id}`
         ) as HTMLButtonElement;
         const downloadFile = () => {
-            downloadFileHelper(photoSwipe.currItem);
+            downloadFileHelper(photoSwipe.currItem as unknown as EnteFile);
         };
 
         if (downloadLivePhotoBtn) {
@@ -599,15 +601,17 @@ function PhotoViewer(props: Iprops) {
         setShowImageEditorOverlay(false);
     };
 
-    const downloadFileHelper = async (file) => {
+    const downloadFileHelper = async (file: EnteFile) => {
         if (file && props.enableDownload) {
-            appContext.startLoading();
             try {
-                await downloadFile(file);
+                const setSingleFileDownloadProgress =
+                    props.setFilesDownloadProgressAttributesCreator(
+                        file.metadata.title
+                    );
+                await downloadSingleFile(file, setSingleFileDownloadProgress);
             } catch (e) {
                 // do nothing
             }
-            appContext.finishLoading();
         }
     };
 
@@ -702,7 +706,9 @@ function PhotoViewer(props: Iprops) {
                         onClose={() =>
                             setConversionFailedNotificationOpen(false)
                         }
-                        onClick={() => downloadFileHelper(photoSwipe.currItem)}
+                        onClick={() =>
+                            downloadFileHelper(photoSwipe.currItem as EnteFile)
+                        }
                     />
 
                     <Box
@@ -746,7 +752,9 @@ function PhotoViewer(props: Iprops) {
                                     className="pswp__button pswp__button--custom"
                                     title={t('DOWNLOAD_OPTION')}
                                     onClick={() =>
-                                        downloadFileHelper(photoSwipe.currItem)
+                                        downloadFileHelper(
+                                            photoSwipe.currItem as EnteFile
+                                        )
                                     }>
                                     <DownloadIcon />
                                 </button>

+ 3 - 0
apps/photos/src/pages/gallery/index.tsx

@@ -1165,6 +1165,9 @@ export default function Gallery() {
                             files.length < 30 && !isInSearchMode
                         }
                         isInHiddenSection={isInHiddenSection}
+                        setFilesDownloadProgressAttributesCreator={
+                            setFilesDownloadProgressAttributesCreator
+                        }
                     />
                 )}
                 {selected.count > 0 &&

+ 105 - 5
apps/photos/src/utils/file/index.ts

@@ -1,4 +1,8 @@
-import { SelectedState } from 'types/gallery';
+import {
+    SelectedState,
+    SetFilesDownloadProgressAttributes,
+    SetFilesDownloadProgressAttributesCreator,
+} from 'types/gallery';
 import {
     EnteFile,
     EncryptedEnteFile,
@@ -625,9 +629,96 @@ export function getUniqueFiles(files: EnteFile[]) {
     return uniqueFiles;
 }
 
+export async function downloadFilesWithProgress(
+    files: EnteFile[],
+    downloadDirPath: string,
+    setFilesDownloadProgressAttributes: SetFilesDownloadProgressAttributes
+) {
+    if (!files.length) {
+        return;
+    }
+    const canceller = new AbortController();
+    const increaseSuccess = () => {
+        if (canceller.signal.aborted) return;
+        setFilesDownloadProgressAttributes((prev) => ({
+            ...prev,
+            success: prev.success + 1,
+        }));
+    };
+    const increaseFailed = () => {
+        if (canceller.signal.aborted) return;
+        setFilesDownloadProgressAttributes((prev) => ({
+            ...prev,
+            failed: prev.failed + 1,
+        }));
+    };
+    const isCancelled = () => canceller.signal.aborted;
+
+    setFilesDownloadProgressAttributes({
+        downloadDirPath,
+        success: 0,
+        failed: 0,
+        total: files.length,
+        canceller,
+    });
+
+    if (isElectron()) {
+        await downloadFilesDesktop(
+            files,
+            { increaseSuccess, increaseFailed, isCancelled },
+            downloadDirPath
+        );
+    } else {
+        await downloadFiles(files, {
+            increaseSuccess,
+            increaseFailed,
+            isCancelled,
+        });
+    }
+}
+
+export async function downloadSelectedFiles(
+    files: EnteFile[],
+    setFilesDownloadProgressAttributes: SetFilesDownloadProgressAttributes
+) {
+    if (!files.length) {
+        return;
+    }
+    let downloadDirPath: string;
+    if (isElectron()) {
+        downloadDirPath = await ElectronAPIs.selectDirectory();
+        if (!downloadDirPath) {
+            return;
+        }
+    }
+    await downloadFilesWithProgress(
+        files,
+        downloadDirPath,
+        setFilesDownloadProgressAttributes
+    );
+}
+
+export async function downloadSingleFile(
+    file: EnteFile,
+    setFilesDownloadProgressAttributes: SetFilesDownloadProgressAttributes
+) {
+    let downloadDirPath: string;
+    if (isElectron()) {
+        downloadDirPath = await ElectronAPIs.selectDirectory();
+        if (!downloadDirPath) {
+            return;
+        }
+    }
+    await downloadFilesWithProgress(
+        [file],
+        downloadDirPath,
+        setFilesDownloadProgressAttributes
+    );
+}
+
 export async function downloadFiles(
     files: EnteFile[],
-    progressBarUpdater?: {
+    progressBarUpdater: {
         increaseSuccess: () => void;
         increaseFailed: () => void;
         isCancelled: () => boolean;
@@ -869,7 +960,8 @@ export const handleFileOps = async (
                   files: EnteFile[];
               }
             | ((prev: { files: EnteFile[] }) => { files: EnteFile[] })
-    ) => void
+    ) => void,
+    setFilesDownloadProgressAttributesCreator: SetFilesDownloadProgressAttributesCreator
 ) => {
     switch (ops) {
         case FILE_OPS_TYPE.TRASH:
@@ -881,9 +973,17 @@ export const handleFileOps = async (
         case FILE_OPS_TYPE.HIDE:
             await hideFilesHelper(files, setHiddenFileIds);
             break;
-        case FILE_OPS_TYPE.DOWNLOAD:
-            await downloadFiles(files);
+        case FILE_OPS_TYPE.DOWNLOAD: {
+            const setSelectedFileDownloadProgressAttributes =
+                setFilesDownloadProgressAttributesCreator(
+                    `${files.length} files`
+                );
+            await downloadSelectedFiles(
+                files,
+                setSelectedFileDownloadProgressAttributes
+            );
             break;
+        }
         case FILE_OPS_TYPE.FIX_TIME:
             fixTimeHelper(files, setFixCreationTimeAttributes);
             break;