From a7631d271544ac60e65503440b420d9ef05c5b8c Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 12 Sep 2023 13:40:08 +0530 Subject: [PATCH 01/10] add download determinant circular progress bar component with label --- .../CircularProgressWithLabel.tsx | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 apps/photos/src/components/PhotoViewer/styledComponents/CircularProgressWithLabel.tsx diff --git a/apps/photos/src/components/PhotoViewer/styledComponents/CircularProgressWithLabel.tsx b/apps/photos/src/components/PhotoViewer/styledComponents/CircularProgressWithLabel.tsx new file mode 100644 index 000000000..63608dc04 --- /dev/null +++ b/apps/photos/src/components/PhotoViewer/styledComponents/CircularProgressWithLabel.tsx @@ -0,0 +1,40 @@ +import { + CircularProgressProps, + Box, + CircularProgress, + Typography, +} from '@mui/material'; +import { Overlay } from 'components/Container'; + +function CircularProgressWithLabel( + props: CircularProgressProps & { value: number } +) { + return ( + + + + {`${Math.round( + props.value + )}%`} + + + ); +} + +export default CircularProgressWithLabel; From 707d4dfd697ebd974e8d0298f45bacfab7b884f8 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 12 Sep 2023 13:45:51 +0530 Subject: [PATCH 02/10] adds download progress tracker --- apps/photos/src/services/downloadManager.ts | 38 ++++++++++++++++++- .../publicCollectionDownloadManager.ts | 34 +++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/apps/photos/src/services/downloadManager.ts b/apps/photos/src/services/downloadManager.ts index 405be64f5..1c9441903 100644 --- a/apps/photos/src/services/downloadManager.ts +++ b/apps/photos/src/services/downloadManager.ts @@ -27,6 +27,14 @@ class DownloadManager { >(); private thumbnailObjectURLPromise = new Map>(); + private fileDownloadProgress = new Map(); + + private progressUpdater: (value: Map) => void; + + setProgressUpdater(progressUpdater: (value: Map) => void) { + this.progressUpdater = progressUpdater; + } + private async getThumbnailCache() { try { const thumbnailCache = await CacheStorageService.open( @@ -180,6 +188,7 @@ class DownloadManager { if (!token) { return null; } + const onDownloadProgress = this.trackDownloadProgress(file.id); if ( file.metadata.fileType === FILE_TYPE.IMAGE || file.metadata.fileType === FILE_TYPE.LIVE_PHOTO @@ -189,7 +198,11 @@ class DownloadManager { getFileURL(file.id), null, { 'X-Auth-Token': token }, - { responseType: 'arraybuffer', timeout } + { + responseType: 'arraybuffer', + timeout, + onDownloadProgress, + } ) ); if (typeof resp.data === 'undefined') { @@ -226,6 +239,10 @@ class DownloadManager { }) ); const reader = resp.body.getReader(); + + const contentLength = +resp.headers.get('Content-Length'); + let downloadedBytes = 0; + const stream = new ReadableStream({ async start(controller) { try { @@ -246,6 +263,11 @@ class DownloadManager { try { // Is there more data to read? if (!done) { + downloadedBytes += value.byteLength; + onDownloadProgress({ + loaded: downloadedBytes, + total: contentLength, + }); const buffer = new Uint8Array( data.byteLength + value.byteLength ); @@ -363,6 +385,20 @@ class DownloadManager { throw e; } } + + trackDownloadProgress = (fileID: number) => { + return (event: { loaded: number; total: number }) => { + if (event.loaded === event.total) { + this.fileDownloadProgress.delete(fileID); + } else { + this.fileDownloadProgress.set( + fileID, + Math.round((event.loaded * 100) / event.total) + ); + } + this.progressUpdater(new Map(this.fileDownloadProgress)); + }; + }; } export default new DownloadManager(); diff --git a/apps/photos/src/services/publicCollectionDownloadManager.ts b/apps/photos/src/services/publicCollectionDownloadManager.ts index 569bb8a53..a5a19082c 100644 --- a/apps/photos/src/services/publicCollectionDownloadManager.ts +++ b/apps/photos/src/services/publicCollectionDownloadManager.ts @@ -25,6 +25,14 @@ class PublicCollectionDownloadManager { >(); private thumbnailObjectURLPromise = new Map>(); + private fileDownloadProgress = new Map(); + + private progressUpdater: (value: Map) => void; + + setProgressUpdater(progressUpdater: (value: Map) => void) { + this.progressUpdater = progressUpdater; + } + private async getThumbnailCache() { try { const thumbnailCache = await CacheStorageService.open( @@ -182,6 +190,8 @@ class PublicCollectionDownloadManager { if (!token) { return null; } + const onDownloadProgress = this.trackDownloadProgress(file.id); + if ( file.metadata.fileType === FILE_TYPE.IMAGE || file.metadata.fileType === FILE_TYPE.LIVE_PHOTO @@ -193,6 +203,7 @@ class PublicCollectionDownloadManager { 'X-Auth-Access-Token': token, ...(passwordToken && { 'X-Auth-Access-Token-JWT': passwordToken, + onDownloadProgress, }), }, { responseType: 'arraybuffer' } @@ -216,6 +227,10 @@ class PublicCollectionDownloadManager { }, }); const reader = resp.body.getReader(); + + const contentLength = +resp.headers.get('Content-Length'); + let downloadedBytes = 0; + const stream = new ReadableStream({ async start(controller) { const decryptionHeader = await cryptoWorker.fromB64( @@ -234,6 +249,11 @@ class PublicCollectionDownloadManager { reader.read().then(async ({ done, value }) => { // Is there more data to read? if (!done) { + downloadedBytes += value.byteLength; + onDownloadProgress({ + loaded: downloadedBytes, + total: contentLength, + }); const buffer = new Uint8Array( data.byteLength + value.byteLength ); @@ -275,6 +295,20 @@ class PublicCollectionDownloadManager { }); return stream; } + + trackDownloadProgress = (fileID: number) => { + return (event: { loaded: number; total: number }) => { + if (event.loaded === event.total) { + this.fileDownloadProgress.delete(fileID); + } else { + this.fileDownloadProgress.set( + fileID, + Math.round((event.loaded * 100) / event.total) + ); + } + this.progressUpdater(new Map(this.fileDownloadProgress)); + }; + }; } export default new PublicCollectionDownloadManager(); From 23a47cefd6711f3c650783f54d3eb6b067f8f68d Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 12 Sep 2023 13:51:20 +0530 Subject: [PATCH 03/10] move absolute centering logic to photoFrame and added logic to spinner for post and pre download step --- .../src/components/PhotoViewer/index.tsx | 45 ++++++++++++++++++- .../CircularProgressWithLabel.tsx | 12 +---- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/apps/photos/src/components/PhotoViewer/index.tsx b/apps/photos/src/components/PhotoViewer/index.tsx index 580e69c16..e1fcfd9ba 100644 --- a/apps/photos/src/components/PhotoViewer/index.tsx +++ b/apps/photos/src/components/PhotoViewer/index.tsx @@ -35,7 +35,7 @@ import ChevronRight from '@mui/icons-material/ChevronRight'; import DeleteIcon from '@mui/icons-material/Delete'; import { trashFiles } from 'services/fileService'; import { getTrashFileMessage } from 'utils/ui'; -import { styled } from '@mui/material'; +import { Box, styled } from '@mui/material'; import { addLocalLog } from 'utils/logging'; import ContentCopy from '@mui/icons-material/ContentCopy'; import ChevronLeft from '@mui/icons-material/ChevronLeft'; @@ -45,6 +45,10 @@ import { getFileType } from 'services/typeDetectionService'; import { ConversionFailedNotification } from './styledComponents/ConversionFailedNotification'; import { GalleryContext } from 'pages/gallery'; import { ConvertBtn } from './styledComponents/ConvertBtn'; +import downloadManager from 'services/downloadManager'; +import publicCollectionDownloadManager from 'services/publicCollectionDownloadManager'; +import CircularProgressWithLabel from './styledComponents/CircularProgressWithLabel'; +import EnteSpinner from 'components/EnteSpinner'; interface PhotoswipeFullscreenAPI { enter: () => void; @@ -117,6 +121,24 @@ function PhotoViewer(props: Iprops) { setConversionFailedNotificationOpen, ] = useState(false); + const [fileDownloadProgress, setFileDownloadProgress] = useState< + Map + >(new Map()); + + useEffect(() => { + if (publicCollectionGalleryContext.accessedThroughSharedURL) { + publicCollectionDownloadManager.setProgressUpdater( + setFileDownloadProgress + ); + } else { + downloadManager.setProgressUpdater(setFileDownloadProgress); + } + }, []); + + useEffect(() => { + console.log(fileDownloadProgress); + }, [fileDownloadProgress]); + useEffect(() => { if (!pswpElement) return; if (isOpen) { @@ -620,6 +642,27 @@ function PhotoViewer(props: Iprops) { )} + + {fileDownloadProgress.has( + (photoSwipe?.currItem as EnteFile)?.id + ) ? ( + + ) : ( + !isSourceLoaded && + )} + +
diff --git a/apps/photos/src/components/PhotoViewer/styledComponents/CircularProgressWithLabel.tsx b/apps/photos/src/components/PhotoViewer/styledComponents/CircularProgressWithLabel.tsx index 63608dc04..8b47f1101 100644 --- a/apps/photos/src/components/PhotoViewer/styledComponents/CircularProgressWithLabel.tsx +++ b/apps/photos/src/components/PhotoViewer/styledComponents/CircularProgressWithLabel.tsx @@ -1,6 +1,5 @@ import { CircularProgressProps, - Box, CircularProgress, Typography, } from '@mui/material'; @@ -10,14 +9,7 @@ function CircularProgressWithLabel( props: CircularProgressProps & { value: number } ) { return ( - + <> - + ); } From 8860104f77454fcb61a61380b5bca5b6a4bee5fc Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 12 Sep 2023 14:39:42 +0530 Subject: [PATCH 04/10] remove progress bar shown by thumbnail --- apps/photos/src/utils/photoFrame/index.ts | 30 ++--------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/apps/photos/src/utils/photoFrame/index.ts b/apps/photos/src/utils/photoFrame/index.ts index 59bdd8cb5..428dd58f3 100644 --- a/apps/photos/src/utils/photoFrame/index.ts +++ b/apps/photos/src/utils/photoFrame/index.ts @@ -40,36 +40,10 @@ export async function pauseVideo(livePhotoVideo, livePhotoImage) { export function updateFileMsrcProps(file: EnteFile, url: string) { file.msrc = url; + file.src = url; file.isSourceLoaded = false; file.conversionFailed = false; file.isConverted = false; - if (file.metadata.fileType === FILE_TYPE.VIDEO) { - file.html = ` -
- -
- Loading... -
-
- `; - } else if (file.metadata.fileType === FILE_TYPE.LIVE_PHOTO) { - file.html = ` -
- -
- Loading... -
-
- `; - } else if (file.metadata.fileType === FILE_TYPE.IMAGE) { - file.src = url; - } else { - logError( - Error(`unknown file type - ${file.metadata.fileType}`), - 'Unknown file type' - ); - file.src = url; - } } export async function updateFileSrcProps( @@ -119,9 +93,9 @@ export async function updateFileSrcProps( file.originalVideoURL = originalVideoURL; file.isConverted = isConverted; file.conversionFailed = conversionFailed; + file.src = null; if (!isPlayable) { - file.src = file.msrc; return; } From b9a8cf95fd89bc251aee26007eb894afcc0c97ed Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 12 Sep 2023 14:41:06 +0530 Subject: [PATCH 05/10] remove console log --- apps/photos/src/components/PhotoViewer/index.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/photos/src/components/PhotoViewer/index.tsx b/apps/photos/src/components/PhotoViewer/index.tsx index e1fcfd9ba..fe4e0eb0a 100644 --- a/apps/photos/src/components/PhotoViewer/index.tsx +++ b/apps/photos/src/components/PhotoViewer/index.tsx @@ -135,10 +135,6 @@ function PhotoViewer(props: Iprops) { } }, []); - useEffect(() => { - console.log(fileDownloadProgress); - }, [fileDownloadProgress]); - useEffect(() => { if (!pswpElement) return; if (isOpen) { From 193b6f42a1992400757a17bb471f1cb07d9002be Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 13 Sep 2023 01:47:24 +0530 Subject: [PATCH 06/10] fix convert causing black screen --- apps/photos/src/utils/photoFrame/index.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/photos/src/utils/photoFrame/index.ts b/apps/photos/src/utils/photoFrame/index.ts index 428dd58f3..3010104a2 100644 --- a/apps/photos/src/utils/photoFrame/index.ts +++ b/apps/photos/src/utils/photoFrame/index.ts @@ -40,10 +40,20 @@ export async function pauseVideo(livePhotoVideo, livePhotoImage) { export function updateFileMsrcProps(file: EnteFile, url: string) { file.msrc = url; - file.src = url; file.isSourceLoaded = false; file.conversionFailed = false; file.isConverted = false; + file.src = null; + file.html = null; + if (file.metadata.fileType === FILE_TYPE.IMAGE) { + file.src = url; + } else { + file.html = ` +
+ +
+ `; + } } export async function updateFileSrcProps( From b7ef45b41eb600cf1943ce9106914cf4a9a0cf53 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Wed, 13 Sep 2023 01:51:24 +0530 Subject: [PATCH 07/10] remove loading bar for download --- apps/photos/src/components/PhotoFrame.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/photos/src/components/PhotoFrame.tsx b/apps/photos/src/components/PhotoFrame.tsx index 838db20b3..0459b3dfc 100644 --- a/apps/photos/src/components/PhotoFrame.tsx +++ b/apps/photos/src/components/PhotoFrame.tsx @@ -13,7 +13,6 @@ import { MergedSourceURL, SelectedState } from 'types/gallery'; import PublicCollectionDownloadManager from 'services/publicCollectionDownloadManager'; import { PublicCollectionGalleryContext } from 'utils/publicCollectionGallery'; import { useRouter } from 'next/router'; -import { AppContext } from 'pages/_app'; import { logError } from 'utils/sentry'; import { addLogLine } from 'utils/logging'; import PhotoSwipe from 'photoswipe'; @@ -75,7 +74,6 @@ const PhotoFrame = ({ const [currentIndex, setCurrentIndex] = useState(0); const [fetching, setFetching] = useState<{ [k: number]: boolean }>({}); const galleryContext = useContext(GalleryContext); - const appContext = useContext(AppContext); const publicCollectionGalleryContext = useContext( PublicCollectionGalleryContext ); @@ -468,7 +466,6 @@ const PhotoFrame = ({ addLogLine( `[${item.id}] gallery context cache miss, calling downloadManager to get file` ); - appContext.startLoading(); let downloadedURL: { original: string[]; converted: string[]; @@ -484,7 +481,6 @@ const PhotoFrame = ({ } else { downloadedURL = await DownloadManager.getFile(item, true); } - appContext.finishLoading(); const mergedURL: MergedSourceURL = { original: downloadedURL.original.join(','), converted: downloadedURL.converted.join(','), From b42ff6315bc7c998cdd4c9846b7cc5083881f3d4 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 14 Sep 2023 12:08:50 +0530 Subject: [PATCH 08/10] update livePhoto icon in photoViewer --- apps/photos/src/components/LivePhotoBtn.tsx | 12 ------------ apps/photos/src/components/PhotoViewer/index.tsx | 7 +++++-- .../PhotoViewer/styledComponents/LivePhotoBtn.tsx | 2 +- 3 files changed, 6 insertions(+), 15 deletions(-) delete mode 100644 apps/photos/src/components/LivePhotoBtn.tsx diff --git a/apps/photos/src/components/LivePhotoBtn.tsx b/apps/photos/src/components/LivePhotoBtn.tsx deleted file mode 100644 index bb1976db9..000000000 --- a/apps/photos/src/components/LivePhotoBtn.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; - -export const livePhotoBtnHTML = ( - - - - -); diff --git a/apps/photos/src/components/PhotoViewer/index.tsx b/apps/photos/src/components/PhotoViewer/index.tsx index fe4e0eb0a..4db0d5e7e 100644 --- a/apps/photos/src/components/PhotoViewer/index.tsx +++ b/apps/photos/src/components/PhotoViewer/index.tsx @@ -13,7 +13,6 @@ import { getFileExtension, getFileFromURL, } from 'utils/file'; -import { livePhotoBtnHTML } from 'components/LivePhotoBtn'; import { logError } from 'utils/sentry'; import { FILE_TYPE } from 'constants/file'; @@ -49,6 +48,8 @@ import downloadManager from 'services/downloadManager'; import publicCollectionDownloadManager from 'services/publicCollectionDownloadManager'; import CircularProgressWithLabel from './styledComponents/CircularProgressWithLabel'; import EnteSpinner from 'components/EnteSpinner'; +import AlbumOutlined from '@mui/icons-material/AlbumOutlined'; +import { FlexWrapper } from 'components/Container'; interface PhotoswipeFullscreenAPI { enter: () => void; @@ -622,7 +623,9 @@ function PhotoViewer(props: Iprops) { onMouseEnter={livePhotoBtnOptions.show} onMouseLeave={livePhotoBtnOptions.hide} disabled={livePhotoBtnOptions.loading}> - {livePhotoBtnHTML} {t('LIVE')} + + {} {t('LIVE')} + )} ( + )} downloadFileHelper(photoSwipe.currItem)} /> {showConvertBtn && ( - - {t('CONVERT')} - + + + )} ( -