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..8b47f1101
--- /dev/null
+++ b/apps/photos/src/components/PhotoViewer/styledComponents/CircularProgressWithLabel.tsx
@@ -0,0 +1,32 @@
+import {
+ CircularProgressProps,
+ CircularProgress,
+ Typography,
+} from '@mui/material';
+import { Overlay } from 'components/Container';
+
+function CircularProgressWithLabel(
+ props: CircularProgressProps & { value: number }
+) {
+ return (
+ <>
+
+
+ {`${Math.round(
+ props.value
+ )}%`}
+
+ >
+ );
+}
+
+export default CircularProgressWithLabel;
diff --git a/apps/photos/src/components/PhotoViewer/styledComponents/ConvertBtn.tsx b/apps/photos/src/components/PhotoViewer/styledComponents/ConvertBtn.tsx
index ca31c3058..ce078919c 100644
--- a/apps/photos/src/components/PhotoViewer/styledComponents/ConvertBtn.tsx
+++ b/apps/photos/src/components/PhotoViewer/styledComponents/ConvertBtn.tsx
@@ -1,14 +1,9 @@
-import { Button, ButtonProps, styled } from '@mui/material';
-export const ConvertBtn = styled((props: ButtonProps) => (
-
-))`
+import { Paper, styled } from '@mui/material';
+
+export const ConvertBtnContainer = styled(Paper)`
+ border-radius: 4px;
position: absolute;
bottom: 10vh;
left: 2vh;
- outline: none;
- border: none;
- border-radius: 10%;
z-index: 10;
- cursor: ${(props) => (props.disabled ? 'not-allowed' : 'pointer')};
- }
`;
diff --git a/apps/photos/src/components/PhotoViewer/styledComponents/LivePhotoBtn.tsx b/apps/photos/src/components/PhotoViewer/styledComponents/LivePhotoBtn.tsx
index 88637e93b..c8624ee97 100644
--- a/apps/photos/src/components/PhotoViewer/styledComponents/LivePhotoBtn.tsx
+++ b/apps/photos/src/components/PhotoViewer/styledComponents/LivePhotoBtn.tsx
@@ -1,14 +1,10 @@
-import { Button, ButtonProps, styled } from '@mui/material';
-export const LivePhotoBtn = styled((props: ButtonProps) => (
-
-))`
+import { Paper } from '@mui/material';
+import { styled } from '@mui/material/styles';
+
+export const LivePhotoBtnContainer = styled(Paper)`
+ border-radius: 4px;
position: absolute;
- bottom: 6vh;
+ bottom: 10vh;
right: 6vh;
- outline: none;
- border: none;
- border-radius: 10%;
z-index: 10;
- cursor: ${(props) => (props.disabled ? 'not-allowed' : 'pointer')};
- }
`;
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();
diff --git a/apps/photos/src/utils/photoFrame/index.ts b/apps/photos/src/utils/photoFrame/index.ts
index 59bdd8cb5..3010104a2 100644
--- a/apps/photos/src/utils/photoFrame/index.ts
+++ b/apps/photos/src/utils/photoFrame/index.ts
@@ -43,32 +43,16 @@ export function updateFileMsrcProps(file: EnteFile, url: string) {
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 = null;
+ file.html = null;
+ 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;
+ file.html = `
+
+
+
+ `;
}
}
@@ -119,9 +103,9 @@ export async function updateFileSrcProps(
file.originalVideoURL = originalVideoURL;
file.isConverted = isConverted;
file.conversionFailed = conversionFailed;
+ file.src = null;
if (!isPlayable) {
- file.src = file.msrc;
return;
}