From 5d6183f246eda385954e7f883ab7682eb0e01218 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 11 May 2023 15:34:03 +0530 Subject: [PATCH 01/17] moved migration to be done as part of export starting progress --- apps/photos/src/services/export/index.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/photos/src/services/export/index.ts b/apps/photos/src/services/export/index.ts index 5a87c77b7..9e940fa16 100644 --- a/apps/photos/src/services/export/index.ts +++ b/apps/photos/src/services/export/index.ts @@ -292,6 +292,11 @@ class ExportService { failed: 0, total: 0, }); + if (this.migrationInProgress) { + addLogLine('migration in progress, waiting for it to complete'); + await this.migrationInProgress; + this.migrationInProgress = null; + } } async postExport() { @@ -333,11 +338,6 @@ class ExportService { addLogLine('export not in progress, starting export'); } this.exportInProgress = true; - if (this.migrationInProgress) { - addLogLine('migration in progress, waiting for it to complete'); - await this.migrationInProgress; - this.migrationInProgress = null; - } try { const exportFolder = this.getExportSettings()?.folder; await this.preExport(exportFolder); From ccb8144cf0fafd5b7b3b32bbf217faeea19a62a3 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 11 May 2023 15:35:00 +0530 Subject: [PATCH 02/17] throw migration error --- apps/photos/src/services/export/migration.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/photos/src/services/export/migration.ts b/apps/photos/src/services/export/migration.ts index cec6f7a60..93100a715 100644 --- a/apps/photos/src/services/export/migration.ts +++ b/apps/photos/src/services/export/migration.ts @@ -94,6 +94,7 @@ async function migrateExport( addLogLine(`Record at latest version`); } catch (e) { logError(e, 'export record migration failed'); + throw e; } } From 83a026b2d37a77cb6d3138e35dd8a7520a24c012 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Thu, 11 May 2023 16:08:16 +0530 Subject: [PATCH 03/17] remove unneeded wrapper outdated comments --- apps/photos/src/services/export/index.ts | 7 ++---- apps/photos/src/services/export/migration.ts | 24 +------------------- 2 files changed, 3 insertions(+), 28 deletions(-) diff --git a/apps/photos/src/services/export/index.ts b/apps/photos/src/services/export/index.ts index 9e940fa16..9d0a92315 100644 --- a/apps/photos/src/services/export/index.ts +++ b/apps/photos/src/services/export/index.ts @@ -59,7 +59,7 @@ import { getCollectionNameMap, getNonEmptyPersonalCollections, } from 'utils/collection'; -import { migrateExportJSON } from './migration'; +import { migrateExport } from './migration'; const EXPORT_RECORD_FILE_NAME = 'export_status.json'; @@ -130,10 +130,7 @@ class ExportService { async runMigration(exportDir: string, exportRecord: ExportRecord) { try { addLogLine('running migration'); - this.migrationInProgress = migrateExportJSON( - exportDir, - exportRecord - ); + this.migrationInProgress = migrateExport(exportDir, exportRecord); await this.migrationInProgress; addLogLine('migration completed'); this.migrationInProgress = null; diff --git a/apps/photos/src/services/export/migration.ts b/apps/photos/src/services/export/migration.ts index 93100a715..f0526ef54 100644 --- a/apps/photos/src/services/export/migration.ts +++ b/apps/photos/src/services/export/migration.ts @@ -39,29 +39,7 @@ import { decodeLivePhoto } from 'services/livePhotoService'; import downloadManager from 'services/downloadManager'; import { retryAsyncFunction } from 'utils/network'; -export async function migrateExportJSON( - exportDir: string, - exportRecord: ExportRecord -) { - try { - if (!exportDir) { - return; - } - await migrateExport(exportDir, exportRecord); - } catch (e) { - logError(e, 'migrateExportJSON failed'); - throw e; - } -} - -/* - this function migrates the exportRecord file to apply any schema changes. - currently we apply only a single migration to update file and collection name to newer format - so there is just a if condition check, - later this will be converted to a loop which applies the migration one by one - till the files reaches the latest version -*/ -async function migrateExport( +export async function migrateExport( exportDir: string, exportRecord: ExportRecordV1 | ExportRecordV2 | ExportRecord ) { From a996d13e145b512edb851534d60f79d6029014aa Mon Sep 17 00:00:00 2001 From: Abhinav Date: Fri, 12 May 2023 16:41:08 +0530 Subject: [PATCH 04/17] set sso domain to `web.ente.io` --- apps/photos/src/constants/redirects/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/photos/src/constants/redirects/index.ts b/apps/photos/src/constants/redirects/index.ts index c26424dcf..4773eb93f 100644 --- a/apps/photos/src/constants/redirects/index.ts +++ b/apps/photos/src/constants/redirects/index.ts @@ -5,7 +5,7 @@ export enum REDIRECTS { export const getRedirectURL = (redirect: REDIRECTS) => { // open current app with query param of redirect = roadmap - const url = new URL(window.location.href); + const url = new URL('https://web.ente.io'); url.searchParams.set('redirect', redirect); return url.href; }; From 0efd4f75494bcd14575b5213afdb083108ff3b07 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Fri, 12 May 2023 16:45:42 +0530 Subject: [PATCH 05/17] remove comment --- apps/photos/src/constants/redirects/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/photos/src/constants/redirects/index.ts b/apps/photos/src/constants/redirects/index.ts index 4773eb93f..d88cca89c 100644 --- a/apps/photos/src/constants/redirects/index.ts +++ b/apps/photos/src/constants/redirects/index.ts @@ -4,7 +4,6 @@ export enum REDIRECTS { } export const getRedirectURL = (redirect: REDIRECTS) => { - // open current app with query param of redirect = roadmap const url = new URL('https://web.ente.io'); url.searchParams.set('redirect', redirect); return url.href; From 8387a1a9170cfbeca3d39c7dc3575eb78ba58db5 Mon Sep 17 00:00:00 2001 From: Vishnu Date: Sat, 13 May 2023 20:51:49 +0530 Subject: [PATCH 06/17] Use "ente Photos" as the title for albums --- apps/photos/src/constants/apps/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/photos/src/constants/apps/index.ts b/apps/photos/src/constants/apps/index.ts index ded6d9b59..79e4e1232 100644 --- a/apps/photos/src/constants/apps/index.ts +++ b/apps/photos/src/constants/apps/index.ts @@ -42,7 +42,7 @@ export const getAppNameAndTitle = () => { const albumsURL = new URL(getAlbumsURL()); const authURL = new URL(getAuthURL()); if (currentURL.origin === albumsURL.origin) { - return { name: APPS.ALBUMS, title: 'ente Albums' }; + return { name: APPS.ALBUMS, title: 'ente Photos' }; } else if (currentURL.origin === authURL.origin) { return { name: APPS.AUTH, title: 'ente Auth' }; } else { From 30766a01c5af4e9432e3ff66c66ea0d7f263d105 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 13 May 2023 21:03:40 +0530 Subject: [PATCH 07/17] change Album title --- apps/photos/public/locales/en/translation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/photos/public/locales/en/translation.json b/apps/photos/public/locales/en/translation.json index 2247d4e13..af3ac72aa 100644 --- a/apps/photos/public/locales/en/translation.json +++ b/apps/photos/public/locales/en/translation.json @@ -83,7 +83,7 @@ "PREVIOUS": "Previous (←)", "NEXT": "Next (→)", "TITLE_PHOTOS": "ente Photos", - "TITLE_ALBUMS": "ente Albums", + "TITLE_ALBUMS": "ente Photos", "TITLE_AUTH": "ente Auth", "UPLOAD_FIRST_PHOTO": "Upload your first photo", "IMPORT_YOUR_FOLDERS": "Import your folders", From aae68585bf11fcaaa7638c061af70014aaf196b2 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Sat, 13 May 2023 21:08:51 +0530 Subject: [PATCH 08/17] change translations string --- apps/photos/public/locales/es/translation.json | 2 +- apps/photos/public/locales/fr/translation.json | 2 +- apps/photos/public/locales/it/translation.json | 2 +- apps/photos/public/locales/nl/translation.json | 2 +- apps/photos/public/locales/zh/translation.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/photos/public/locales/es/translation.json b/apps/photos/public/locales/es/translation.json index ab16d15f2..b4b5c8998 100644 --- a/apps/photos/public/locales/es/translation.json +++ b/apps/photos/public/locales/es/translation.json @@ -83,7 +83,7 @@ "PREVIOUS": "Anterior (←)", "NEXT": "Siguiente (→)", "TITLE_PHOTOS": "ente Fotos", - "TITLE_ALBUMS": "ente Álbumes", + "TITLE_ALBUMS": "ente Fotos", "TITLE_AUTH": "ente Auth", "UPLOAD_FIRST_PHOTO": "Carga tu primer archivo", "IMPORT_YOUR_FOLDERS": "Importar tus carpetas", diff --git a/apps/photos/public/locales/fr/translation.json b/apps/photos/public/locales/fr/translation.json index db4f750c8..f2997dbe6 100644 --- a/apps/photos/public/locales/fr/translation.json +++ b/apps/photos/public/locales/fr/translation.json @@ -83,7 +83,7 @@ "PREVIOUS": "Précédent (←)", "NEXT": "Suivant (→)", "TITLE_PHOTOS": "ente Photos", - "TITLE_ALBUMS": "ente Albums", + "TITLE_ALBUMS": "ente Photos", "TITLE_AUTH": "ente Auth", "UPLOAD_FIRST_PHOTO": "Chargez votre 1ere photo", "IMPORT_YOUR_FOLDERS": "Importez vos dossiers", diff --git a/apps/photos/public/locales/it/translation.json b/apps/photos/public/locales/it/translation.json index a1920ddd8..83871b593 100644 --- a/apps/photos/public/locales/it/translation.json +++ b/apps/photos/public/locales/it/translation.json @@ -83,7 +83,7 @@ "PREVIOUS": "Precedente (←)", "NEXT": "Successivo (→)", "TITLE_PHOTOS": "ente Photos", - "TITLE_ALBUMS": "ente Album", + "TITLE_ALBUMS": "ente Photos", "TITLE_AUTH": "ente Auth", "UPLOAD_FIRST_PHOTO": "Carica la tua prima foto", "IMPORT_YOUR_FOLDERS": "Importa una cartella", diff --git a/apps/photos/public/locales/nl/translation.json b/apps/photos/public/locales/nl/translation.json index 6142ba01b..e89caa77a 100644 --- a/apps/photos/public/locales/nl/translation.json +++ b/apps/photos/public/locales/nl/translation.json @@ -83,7 +83,7 @@ "PREVIOUS": "Vorige (←)", "NEXT": "Volgende (→)", "TITLE_PHOTOS": "ente Photos", - "TITLE_ALBUMS": "ente Albums", + "TITLE_ALBUMS": "ente Photos", "TITLE_AUTH": "ente Auth", "UPLOAD_FIRST_PHOTO": "Je eerste foto uploaden", "IMPORT_YOUR_FOLDERS": "Importeer uw mappen", diff --git a/apps/photos/public/locales/zh/translation.json b/apps/photos/public/locales/zh/translation.json index 928aeeb12..355e7cef7 100644 --- a/apps/photos/public/locales/zh/translation.json +++ b/apps/photos/public/locales/zh/translation.json @@ -83,7 +83,7 @@ "PREVIOUS": "上一个 (←)", "NEXT": "下一个 (→)", "TITLE_PHOTOS": "ente 照片", - "TITLE_ALBUMS": "ente 相册", + "TITLE_ALBUMS": "ente 照片", "TITLE_AUTH": "ente 验证器", "UPLOAD_FIRST_PHOTO": "上传您的第一张照片", "IMPORT_YOUR_FOLDERS": "导入您的文件夹", From e8ff51be07dd9dc14210029604bc4aa8bb0da4f1 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Sat, 13 May 2023 15:42:24 +0000 Subject: [PATCH 09/17] New Crowdin translations by GitHub Action --- apps/photos/public/locales/fr/translation.json | 2 +- apps/photos/public/locales/it/translation.json | 2 +- apps/photos/public/locales/nl/translation.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/photos/public/locales/fr/translation.json b/apps/photos/public/locales/fr/translation.json index f2997dbe6..be87597a1 100644 --- a/apps/photos/public/locales/fr/translation.json +++ b/apps/photos/public/locales/fr/translation.json @@ -83,7 +83,7 @@ "PREVIOUS": "Précédent (←)", "NEXT": "Suivant (→)", "TITLE_PHOTOS": "ente Photos", - "TITLE_ALBUMS": "ente Photos", + "TITLE_ALBUMS": "", "TITLE_AUTH": "ente Auth", "UPLOAD_FIRST_PHOTO": "Chargez votre 1ere photo", "IMPORT_YOUR_FOLDERS": "Importez vos dossiers", diff --git a/apps/photos/public/locales/it/translation.json b/apps/photos/public/locales/it/translation.json index 83871b593..76110792b 100644 --- a/apps/photos/public/locales/it/translation.json +++ b/apps/photos/public/locales/it/translation.json @@ -83,7 +83,7 @@ "PREVIOUS": "Precedente (←)", "NEXT": "Successivo (→)", "TITLE_PHOTOS": "ente Photos", - "TITLE_ALBUMS": "ente Photos", + "TITLE_ALBUMS": "", "TITLE_AUTH": "ente Auth", "UPLOAD_FIRST_PHOTO": "Carica la tua prima foto", "IMPORT_YOUR_FOLDERS": "Importa una cartella", diff --git a/apps/photos/public/locales/nl/translation.json b/apps/photos/public/locales/nl/translation.json index e89caa77a..8af19a978 100644 --- a/apps/photos/public/locales/nl/translation.json +++ b/apps/photos/public/locales/nl/translation.json @@ -83,7 +83,7 @@ "PREVIOUS": "Vorige (←)", "NEXT": "Volgende (→)", "TITLE_PHOTOS": "ente Photos", - "TITLE_ALBUMS": "ente Photos", + "TITLE_ALBUMS": "", "TITLE_AUTH": "ente Auth", "UPLOAD_FIRST_PHOTO": "Je eerste foto uploaden", "IMPORT_YOUR_FOLDERS": "Importeer uw mappen", From 033aa73e5d228d4b53554e60d64dfed09ad1eb9d Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Mon, 15 May 2023 01:10:28 +0000 Subject: [PATCH 10/17] New Crowdin translations by GitHub Action --- apps/photos/public/locales/fr/translation.json | 2 +- apps/photos/public/locales/it/translation.json | 2 +- apps/photos/public/locales/nl/translation.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/photos/public/locales/fr/translation.json b/apps/photos/public/locales/fr/translation.json index be87597a1..f2997dbe6 100644 --- a/apps/photos/public/locales/fr/translation.json +++ b/apps/photos/public/locales/fr/translation.json @@ -83,7 +83,7 @@ "PREVIOUS": "Précédent (←)", "NEXT": "Suivant (→)", "TITLE_PHOTOS": "ente Photos", - "TITLE_ALBUMS": "", + "TITLE_ALBUMS": "ente Photos", "TITLE_AUTH": "ente Auth", "UPLOAD_FIRST_PHOTO": "Chargez votre 1ere photo", "IMPORT_YOUR_FOLDERS": "Importez vos dossiers", diff --git a/apps/photos/public/locales/it/translation.json b/apps/photos/public/locales/it/translation.json index 76110792b..83871b593 100644 --- a/apps/photos/public/locales/it/translation.json +++ b/apps/photos/public/locales/it/translation.json @@ -83,7 +83,7 @@ "PREVIOUS": "Precedente (←)", "NEXT": "Successivo (→)", "TITLE_PHOTOS": "ente Photos", - "TITLE_ALBUMS": "", + "TITLE_ALBUMS": "ente Photos", "TITLE_AUTH": "ente Auth", "UPLOAD_FIRST_PHOTO": "Carica la tua prima foto", "IMPORT_YOUR_FOLDERS": "Importa una cartella", diff --git a/apps/photos/public/locales/nl/translation.json b/apps/photos/public/locales/nl/translation.json index 8af19a978..e89caa77a 100644 --- a/apps/photos/public/locales/nl/translation.json +++ b/apps/photos/public/locales/nl/translation.json @@ -83,7 +83,7 @@ "PREVIOUS": "Vorige (←)", "NEXT": "Volgende (→)", "TITLE_PHOTOS": "ente Photos", - "TITLE_ALBUMS": "", + "TITLE_ALBUMS": "ente Photos", "TITLE_AUTH": "ente Auth", "UPLOAD_FIRST_PHOTO": "Je eerste foto uploaden", "IMPORT_YOUR_FOLDERS": "Importeer uw mappen", From cbba799e7bea3ed3eeafe446c59ee0310f24f081 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 May 2023 09:41:48 +0530 Subject: [PATCH 11/17] remove filtration logic from PhotoFrame --- .lintstagedrc.js | 15 -- apps/photos/src/components/PhotoFrame.tsx | 250 ++++------------------ apps/photos/src/components/PhotoList.tsx | 20 +- package.json | 15 +- 4 files changed, 70 insertions(+), 230 deletions(-) delete mode 100644 .lintstagedrc.js diff --git a/.lintstagedrc.js b/.lintstagedrc.js deleted file mode 100644 index fb8d09cd4..000000000 --- a/.lintstagedrc.js +++ /dev/null @@ -1,15 +0,0 @@ -const path = require('path'); - -const buildEslintCommand = (filenames) => - `yarn lint --fix --file ${filenames - .map((f) => path.relative(process.cwd(), f)) - .join(' --file ')} --`; - -const buildPrettierCommand = (filenames) => - `yarn prettier --write --ignore-unknown ${filenames.join(' ')}`; - -module.exports = { - 'apps/**/*.{js,jsx,ts,tsx}': [buildEslintCommand, buildPrettierCommand], - 'packages/**/*.{js,jsx,ts,tsx}': [buildEslintCommand, buildPrettierCommand], - '**/*.{json,css,scss,md,html,yml,yaml}': [buildPrettierCommand], -}; diff --git a/apps/photos/src/components/PhotoFrame.tsx b/apps/photos/src/components/PhotoFrame.tsx index f61a27158..4fb3fe329 100644 --- a/apps/photos/src/components/PhotoFrame.tsx +++ b/apps/photos/src/components/PhotoFrame.tsx @@ -1,17 +1,12 @@ import { GalleryContext } from 'pages/gallery'; import PreviewCard from './pages/gallery/PreviewCard'; -import React, { useContext, useEffect, useRef, useState } from 'react'; +import { useContext, useEffect, useRef, useState } from 'react'; import { EnteFile } from 'types/file'; import { styled } from '@mui/material'; import DownloadManager from 'services/downloadManager'; import AutoSizer from 'react-virtualized-auto-sizer'; import PhotoViewer from 'components/PhotoViewer'; -import { - ALL_SECTION, - ARCHIVE_SECTION, - TRASH_SECTION, -} from 'constants/collection'; -import { isSharedFile } from 'utils/file'; +import { TRASH_SECTION } from 'constants/collection'; import { updateFileMsrcProps, updateFileSrcProps } from 'utils/photoFrame'; import { PhotoList } from './PhotoList'; import { MergedSourceURL, SelectedState } from 'types/gallery'; @@ -19,15 +14,9 @@ import PublicCollectionDownloadManager from 'services/publicCollectionDownloadMa import { PublicCollectionGalleryContext } from 'utils/publicCollectionGallery'; import { useRouter } from 'next/router'; import { AppContext } from 'pages/_app'; -import { DeduplicateContext } from 'pages/deduplicate'; -import { IsArchived } from 'utils/magicMetadata'; -import { isSameDayAnyYear, isInsideBox } from 'utils/search'; -import { Search } from 'types/search'; import { logError } from 'utils/sentry'; import { User } from 'types/user'; import { getData, LS_KEYS } from 'utils/storage/localStorage'; -import { useMemo } from 'react'; -import { Collection } from 'types/collection'; import { addLogLine } from 'utils/logging'; import PhotoSwipe from 'photoswipe'; @@ -48,41 +37,36 @@ const PHOTOSWIPE_HASH_SUFFIX = '&opened'; interface Props { files: EnteFile[]; - collections?: Collection[]; syncWithRemote: () => Promise; favItemIds?: Set; - archivedCollections?: Set; setSelected: ( selected: SelectedState | ((selected: SelectedState) => SelectedState) ) => void; selected: SelectedState; - isInSearchMode?: boolean; - search?: Search; deletedFileIds?: Set; setDeletedFileIds?: (value: Set) => void; activeCollection: number; isIncomingSharedCollection?: boolean; enableDownload?: boolean; - isDeduplicating?: boolean; - resetSearch?: () => void; + fileToCollectionsMap: Map; + collectionNameMap: Map; + showAppDownloadBanner?: boolean; } const PhotoFrame = ({ files, - collections, syncWithRemote, favItemIds, - archivedCollections, setSelected, selected, - isInSearchMode, - search, deletedFileIds, setDeletedFileIds, activeCollection, isIncomingSharedCollection, enableDownload, - isDeduplicating, + fileToCollectionsMap, + collectionNameMap, + showAppDownloadBanner, }: Props) => { const [user, setUser] = useState(null); const [open, setOpen] = useState(false); @@ -90,7 +74,6 @@ const PhotoFrame = ({ const [fetching, setFetching] = useState<{ [k: number]: boolean }>({}); const galleryContext = useContext(GalleryContext); const appContext = useContext(AppContext); - const deduplicateContext = useContext(DeduplicateContext); const publicCollectionGalleryContext = useContext( PublicCollectionGalleryContext ); @@ -103,7 +86,8 @@ const PhotoFrame = ({ const updateInProgress = useRef(false); const updateRequired = useRef(false); - const [filteredData, setFilteredData] = useState([]); + const [displayFiles, setDisplayFiles] = useState([]); + useEffect(() => { const user: User = getData(LS_KEYS.USER); setUser(user); @@ -116,137 +100,33 @@ const PhotoFrame = ({ return; } updateInProgress.current = true; - const idSet = new Set(); - const user: User = getData(LS_KEYS.USER); - const filteredData = files - .filter((item) => { - if ( - deletedFileIds?.has(item.id) && - activeCollection !== TRASH_SECTION - ) { - return false; + const displayFiles = files.map((item) => { + const filteredItem = { + ...item, + w: window.innerWidth, + h: window.innerHeight, + title: item.pubMagicMetadata?.data.caption, + }; + try { + if (galleryContext.thumbs.has(item.id)) { + updateFileMsrcProps( + filteredItem, + galleryContext.thumbs.get(item.id) + ); } - if ( - search?.date && - !isSameDayAnyYear(search.date)( - new Date(item.metadata.creationTime / 1000) - ) - ) { - return false; + if (galleryContext.files.has(item.id)) { + updateFileSrcProps( + filteredItem, + galleryContext.files.get(item.id) + ); } - if ( - search?.location && - !isInsideBox( - { - latitude: item.metadata.latitude, - longitude: item.metadata.longitude, - }, - search.location - ) - ) { - return false; - } - if ( - search?.person && - search.person.files.indexOf(item.id) === -1 - ) { - return false; - } - if ( - search?.thing && - search.thing.files.indexOf(item.id) === -1 - ) { - return false; - } - if ( - search?.text && - search.text.files.indexOf(item.id) === -1 - ) { - return false; - } - if (search?.files && search.files.indexOf(item.id) === -1) { - return false; - } - if ( - !isDeduplicating && - !isInSearchMode && - activeCollection === ALL_SECTION && - (IsArchived(item) || - archivedCollections?.has(item.collectionID)) - ) { - return false; - } - if ( - !isInSearchMode && - activeCollection === ARCHIVE_SECTION && - !IsArchived(item) - ) { - return false; - } - - if ( - (isInSearchMode || - activeCollection !== item.collectionID) && - isSharedFile(user, item) - ) { - return false; - } - if ( - !isInSearchMode && - activeCollection === TRASH_SECTION && - !item.isTrashed - ) { - return false; - } - if ( - (isInSearchMode || - activeCollection !== TRASH_SECTION) && - item.isTrashed - ) { - return false; - } - if (!idSet.has(item.id)) { - if ( - activeCollection === ALL_SECTION || - activeCollection === ARCHIVE_SECTION || - activeCollection === TRASH_SECTION || - isInSearchMode || - activeCollection === item.collectionID - ) { - idSet.add(item.id); - return true; - } - return false; - } - return false; - }) - .map((item) => { - const filteredItem = { - ...item, - w: window.innerWidth, - h: window.innerHeight, - title: item.pubMagicMetadata?.data.caption, - }; - try { - if (galleryContext.thumbs.has(item.id)) { - updateFileMsrcProps( - filteredItem, - galleryContext.thumbs.get(item.id) - ); - } - if (galleryContext.files.has(item.id)) { - updateFileSrcProps( - filteredItem, - galleryContext.files.get(item.id) - ); - } - } catch (e) { - logError(e, 'PhotoFrame url prefill failed'); - } - return filteredItem; - }); - setFilteredData(filteredData); + } catch (e) { + logError(e, 'PhotoFrame url prefill failed'); + } + return filteredItem; + }); + setDisplayFiles(displayFiles); updateInProgress.current = false; if (updateRequired.current) { updateRequired.current = false; @@ -256,45 +136,11 @@ const PhotoFrame = ({ } }; main(); - }, [ - files, - deletedFileIds, - search?.date, - search?.files, - search?.location, - search?.person, - search?.thing, - search?.text, - activeCollection, - ]); + }, [files]); useEffect(() => { setFetching({}); - }, [filteredData]); - - const fileToCollectionsMap = useMemo(() => { - const fileToCollectionsMap = new Map(); - files.forEach((file) => { - if (!fileToCollectionsMap.get(file.id)) { - fileToCollectionsMap.set(file.id, []); - } - fileToCollectionsMap.get(file.id).push(file.collectionID); - }); - return fileToCollectionsMap; - }, [files]); - - const collectionNameMap = useMemo(() => { - if (collections) { - return new Map( - collections.map((collection) => [ - collection.id, - collection.name, - ]) - ); - } else { - return new Map(); - } - }, [collections]); + }, [displayFiles]); useEffect(() => { const currentURL = new URL(window.location.href); @@ -351,7 +197,7 @@ const PhotoFrame = ({ }, [selected]); const updateURL = (index: number) => (id: number, url: string) => { - const file = filteredData[index]; + const file = displayFiles[index]; // this is to prevent outdated updateURL call from updating the wrong file if (file.id !== id) { addLogLine( @@ -377,7 +223,7 @@ const PhotoFrame = ({ id: number, mergedSrcURL: MergedSourceURL ) => { - const file = filteredData[index]; + const file = displayFiles[index]; // this is to prevent outdate updateSrcURL call from updating the wrong file if (file.id !== id) { addLogLine( @@ -471,7 +317,7 @@ const PhotoFrame = ({ (index - i) * direction >= 0; i += direction ) { - checked = checked && !!selected[filteredData[i].id]; + checked = checked && !!selected[displayFiles[i].id]; } for ( let i = rangeStart; @@ -479,13 +325,13 @@ const PhotoFrame = ({ i += direction ) { handleSelect( - filteredData[i].id, - filteredData[i].ownerID === user?.id + displayFiles[i].id, + displayFiles[i].ownerID === user?.id )(!checked); } handleSelect( - filteredData[index].id, - filteredData[index].ownerID === user?.id, + displayFiles[index].id, + displayFiles[index].ownerID === user?.id, index )(!checked); } @@ -653,19 +499,15 @@ const PhotoFrame = ({ width={width} height={height} getThumbnail={getThumbnail} - filteredData={filteredData} + displayFiles={displayFiles} activeCollection={activeCollection} - showAppDownloadBanner={ - files.length < 30 && - !isInSearchMode && - !deduplicateContext.isOnDeduplicatePage - } + showAppDownloadBanner={showAppDownloadBanner} /> )} { let index = 0; - while (index < filteredData.length) { - const file = filteredData[index]; + while (index < displayFiles.length) { + const file = displayFiles[index]; const currentFileSize = deduplicateContext.fileSizeMap.get(file.id); const currentCreationTime = file.metadata.creationTime; let lastFileIndex = index; - while (lastFileIndex < filteredData.length) { + while (lastFileIndex < displayFiles.length) { if ( deduplicateContext.fileSizeMap.get( - filteredData[lastFileIndex].id + displayFiles[lastFileIndex].id ) !== currentFileSize || (deduplicateContext.clubSameTimeFilesOnly && - filteredData[lastFileIndex].metadata.creationTime !== + displayFiles[lastFileIndex].metadata.creationTime !== currentCreationTime) ) { break; @@ -370,7 +370,7 @@ export function PhotoList({ const tileSize = Math.min(columns, lastFileIndex - index + 1); timeStampList.push({ itemType: ITEM_TYPE.FILE, - items: filteredData.slice(index, index + tileSize), + items: displayFiles.slice(index, index + tileSize), itemStartIndex: index, }); index += tileSize; @@ -381,7 +381,7 @@ export function PhotoList({ const groupByTime = (t, timeStampList: TimeStampListItem[]) => { let listItemIndex = 0; let currentDate; - filteredData.forEach((item, index) => { + displayFiles.forEach((item, index) => { if ( !currentDate || !isSameDay( diff --git a/package.json b/package.json index ba0e38eaf..e17a90915 100644 --- a/package.json +++ b/package.json @@ -27,5 +27,18 @@ "workspaces": [ "packages/*", "apps/*" - ] + ], + "lint-staged": { + "apps/**/*.{js,jsx,ts,tsx}": [ + "eslint --fix", + "prettier --write --ignore-unknown" + ], + "packages/**/*.{js,jsx,ts,tsx}": [ + "eslint --fix", + "prettier --write --ignore-unknown" + ], + "**/*.{json,css,scss,md,html,yml,yaml}": [ + "prettier --write --ignore-unknown" + ] + } } From 2b445bfdeec176e1f77cc90c3147fab8938f6408 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 May 2023 09:43:26 +0530 Subject: [PATCH 12/17] disable info shortcut working for incoming shared collection --- .../components/PhotoViewer/FileInfo/index.tsx | 2 +- .../src/components/PhotoViewer/index.tsx | 27 ++++++++++--------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx b/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx index bba8d8df1..a08c9f98f 100644 --- a/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx +++ b/apps/photos/src/components/PhotoViewer/FileInfo/index.tsx @@ -43,7 +43,7 @@ export const FileInfoSidebar = styled((props: DialogProps) => ( }); interface Iprops { - shouldDisableEdits: boolean; + shouldDisableEdits?: boolean; showInfo: boolean; handleCloseInfo: () => void; file: EnteFile; diff --git a/apps/photos/src/components/PhotoViewer/index.tsx b/apps/photos/src/components/PhotoViewer/index.tsx index 42ade735c..c3db9f039 100644 --- a/apps/photos/src/components/PhotoViewer/index.tsx +++ b/apps/photos/src/components/PhotoViewer/index.tsx @@ -133,7 +133,7 @@ function PhotoViewer(props: Iprops) { switch (event.key) { case 'i': case 'I': - setShowInfo(true); + !props.isIncomingSharedCollection && setShowInfo(true); break; case 'Backspace': case 'Delete': @@ -663,18 +663,19 @@ function PhotoViewer(props: Iprops) { - + {!props.isIncomingSharedCollection && ( + + )} ); } From 3ed7f157dff8332a90edc9f9545f96e9a9d2c215 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 May 2023 10:02:13 +0530 Subject: [PATCH 13/17] add utils --- apps/photos/src/utils/collection/index.ts | 11 +++++++++++ apps/photos/src/utils/file/index.ts | 11 +++++++++++ apps/photos/src/utils/ui/index.tsx | 13 +++++++++++++ 3 files changed, 35 insertions(+) diff --git a/apps/photos/src/utils/collection/index.ts b/apps/photos/src/utils/collection/index.ts index ea3921f95..ac2f6d363 100644 --- a/apps/photos/src/utils/collection/index.ts +++ b/apps/photos/src/utils/collection/index.ts @@ -291,3 +291,14 @@ export function getNonEmptyPersonalCollections( ); return personalCollections; } + +export function constructCollectionNameMap( + collections: Collection[] +): Map { + return new Map( + (collections ?? []).map((collection) => [ + collection.id, + collection.name, + ]) + ); +} diff --git a/apps/photos/src/utils/file/index.ts b/apps/photos/src/utils/file/index.ts index 917040985..f9d1d8d66 100644 --- a/apps/photos/src/utils/file/index.ts +++ b/apps/photos/src/utils/file/index.ts @@ -580,3 +580,14 @@ export function getPersonalFiles(files: EnteFile[], user: User) { export function getIDBasedSortedFiles(files: EnteFile[]) { return files.sort((a, b) => a.id - b.id); } + +export function constructFileToCollectionMap(files: EnteFile[]) { + const fileToCollectionsMap = new Map(); + (files ?? []).forEach((file) => { + if (!fileToCollectionsMap.get(file.id)) { + fileToCollectionsMap.set(file.id, []); + } + fileToCollectionsMap.get(file.id).push(file.collectionID); + }); + return fileToCollectionsMap; +} diff --git a/apps/photos/src/utils/ui/index.tsx b/apps/photos/src/utils/ui/index.tsx index d19be0c92..c5fad3a04 100644 --- a/apps/photos/src/utils/ui/index.tsx +++ b/apps/photos/src/utils/ui/index.tsx @@ -8,6 +8,7 @@ import { AppUpdateInfo } from 'types/electron'; import InfoOutlined from '@mui/icons-material/InfoRounded'; import { Trans } from 'react-i18next'; import { Subscription } from 'types/billing'; +import { logoutUser } from 'services/userService'; export const getDownloadAppMessage = (): DialogBoxAttributes => { return { title: t('DOWNLOAD_APP'), @@ -116,3 +117,15 @@ export const getSubscriptionPurchaseSuccessMessage = ( /> ), }); + +export const getSessionExpiredMessage = (): DialogBoxAttributes => ({ + title: t('SESSION_EXPIRED'), + content: t('SESSION_EXPIRED_MESSAGE'), + + nonClosable: true, + proceed: { + text: t('LOGIN'), + action: logoutUser, + variant: 'accent', + }, +}); From a26c2ab3be7e5a592e04741f82bae49feca7c02e Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 May 2023 10:03:02 +0530 Subject: [PATCH 14/17] add hook useMemoSingleThreaded --- .../src/hooks/useMemoSingleThreaded.tsx | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 apps/photos/src/hooks/useMemoSingleThreaded.tsx diff --git a/apps/photos/src/hooks/useMemoSingleThreaded.tsx b/apps/photos/src/hooks/useMemoSingleThreaded.tsx new file mode 100644 index 000000000..c8a75a85f --- /dev/null +++ b/apps/photos/src/hooks/useMemoSingleThreaded.tsx @@ -0,0 +1,38 @@ +import { useEffect, useRef, useState } from 'react'; + +export default function useMemoSingleThreaded( + fn: () => T | Promise, + deps: any[] +): T { + const [result, setResult] = useState(null); + const updateInProgress = useRef(false); + const updateRequired = useRef(false); + useEffect(() => { + const main = async () => { + if (updateInProgress.current) { + updateRequired.current = true; + return; + } + updateInProgress.current = true; + const result = fn(); + if (isPromise(result)) { + const resultValue = await result; + setResult(resultValue); + } else { + setResult(result); + } + updateInProgress.current = false; + if (updateRequired.current) { + updateRequired.current = false; + setTimeout(main, 0); + } + }; + main(); + }, deps); + + return result; +} + +function isPromise(obj: T | Promise): obj is Promise { + return obj && typeof (obj as any).then === 'function'; +} From 9b359c2092c83d7094f629c80d8c6bbb0f07fe16 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 May 2023 10:04:44 +0530 Subject: [PATCH 15/17] move filtration logic to gallery --- apps/photos/src/pages/gallery/index.tsx | 155 +++++++++++++++++++++--- 1 file changed, 136 insertions(+), 19 deletions(-) diff --git a/apps/photos/src/pages/gallery/index.tsx b/apps/photos/src/pages/gallery/index.tsx index c745ef961..b24bda6e1 100644 --- a/apps/photos/src/pages/gallery/index.tsx +++ b/apps/photos/src/pages/gallery/index.tsx @@ -2,6 +2,7 @@ import React, { createContext, useContext, useEffect, + useMemo, useRef, useState, } from 'react'; @@ -35,16 +36,18 @@ import { setIsFirstLogin, setJustSignedUp, } from 'utils/storage'; -import { isTokenValid, logoutUser, validateKey } from 'services/userService'; +import { isTokenValid, validateKey } from 'services/userService'; import { useDropzone } from 'react-dropzone'; import EnteSpinner from 'components/EnteSpinner'; import { LoadingOverlay } from 'components/LoadingOverlay'; import PhotoFrame from 'components/PhotoFrame'; import { changeFilesVisibility, + constructFileToCollectionMap, downloadFiles, getNonTrashedFiles, getSelectedFiles, + isSharedFile, mergeMetadata, sortFiles, } from 'utils/file'; @@ -75,6 +78,7 @@ import { getSelectedCollection, getArchivedCollections, hasNonSystemCollections, + constructCollectionNameMap, } from 'utils/collection'; import { logError } from 'utils/sentry'; import { @@ -111,6 +115,10 @@ import uploadManager from 'services/upload/uploadManager'; import { getToken } from 'utils/common/key'; import ExportModal from 'components/ExportModal'; import GalleryEmptyState from 'components/GalleryEmptyState'; +import { IsArchived } from 'utils/magicMetadata'; +import { isSameDayAnyYear, isInsideBox } from 'utils/search'; +import { getSessionExpiredMessage } from 'utils/ui'; +import useMemoSingleThreaded from 'hooks/useMemoSingleThreaded'; export const DeadCenter = styled('div')` flex: 1; @@ -225,19 +233,6 @@ export default function Gallery() { const [exportModalView, setExportModalView] = useState(false); - const showSessionExpiredMessage = () => - setDialogMessage({ - title: t('SESSION_EXPIRED'), - content: t('SESSION_EXPIRED_MESSAGE'), - - nonClosable: true, - proceed: { - text: t('LOGIN'), - action: logoutUser, - variant: 'accent', - }, - }); - useEffect(() => { appContext.showNavBar(true); const key = getKey(SESSION_KEYS.ENCRYPTION_KEY); @@ -349,6 +344,127 @@ export default function Gallery() { } }, [isInSearchMode, searchResultSummary]); + const filteredData = useMemoSingleThreaded((): EnteFile[] => { + if (!files) { + return []; + } + + const idSet = new Set(); + const user: User = getData(LS_KEYS.USER); + + return files.filter((item) => { + if ( + deletedFileIds?.has(item.id) && + activeCollection !== TRASH_SECTION + ) { + return false; + } + if ( + search?.date && + !isSameDayAnyYear(search.date)( + new Date(item.metadata.creationTime / 1000) + ) + ) { + return false; + } + if ( + search?.location && + !isInsideBox( + { + latitude: item.metadata.latitude, + longitude: item.metadata.longitude, + }, + search.location + ) + ) { + return false; + } + if (search?.person && search.person.files.indexOf(item.id) === -1) { + return false; + } + if (search?.thing && search.thing.files.indexOf(item.id) === -1) { + return false; + } + if (search?.text && search.text.files.indexOf(item.id) === -1) { + return false; + } + if (search?.files && search.files.indexOf(item.id) === -1) { + return false; + } + if ( + !isInSearchMode && + activeCollection === ALL_SECTION && + (IsArchived(item) || + archivedCollections?.has(item.collectionID)) + ) { + return false; + } + if ( + !isInSearchMode && + activeCollection === ARCHIVE_SECTION && + !IsArchived(item) + ) { + return false; + } + + if ( + (isInSearchMode || activeCollection !== item.collectionID) && + isSharedFile(user, item) + ) { + return false; + } + if ( + !isInSearchMode && + activeCollection === TRASH_SECTION && + !item.isTrashed + ) { + return false; + } + if ( + (isInSearchMode || activeCollection !== TRASH_SECTION) && + item.isTrashed + ) { + return false; + } + if (!idSet.has(item.id)) { + if ( + activeCollection === ALL_SECTION || + activeCollection === ARCHIVE_SECTION || + activeCollection === TRASH_SECTION || + isInSearchMode || + activeCollection === item.collectionID + ) { + idSet.add(item.id); + return true; + } + return false; + } + return false; + }); + }, [ + files, + deletedFileIds, + search?.date, + search?.files, + search?.location, + search?.person, + search?.thing, + search?.text, + activeCollection, + ]); + + const fileToCollectionsMap = useMemoSingleThreaded(() => { + return constructFileToCollectionMap(files); + }, [files]); + + const collectionNameMap = useMemo(() => { + return constructCollectionNameMap(collections); + }, [collections]); + + const showSessionExpiredMessage = () => { + setDialogMessage(getSessionExpiredMessage()); + }; + const syncWithRemote = async (force = false, silent = false) => { if (syncInProgress.current && !force) { resync.current = { force, silent }; @@ -735,15 +851,11 @@ export default function Gallery() { ) : ( )} {selected.count > 0 && From 3376df7473c286febea59c1a3492a987668ddc12 Mon Sep 17 00:00:00 2001 From: Abhinav Date: Tue, 16 May 2023 10:06:20 +0530 Subject: [PATCH 16/17] updated dedupe page to use the new updated gallery --- apps/photos/src/pages/deduplicate/index.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/photos/src/pages/deduplicate/index.tsx b/apps/photos/src/pages/deduplicate/index.tsx index 76982341c..dffd8c6b3 100644 --- a/apps/photos/src/pages/deduplicate/index.tsx +++ b/apps/photos/src/pages/deduplicate/index.tsx @@ -3,7 +3,7 @@ import { t } from 'i18next'; import PhotoFrame from 'components/PhotoFrame'; import { ALL_SECTION } from 'constants/collection'; import { AppContext } from 'pages/_app'; -import React, { createContext, useContext, useEffect, useState } from 'react'; +import { createContext, useContext, useEffect, useState } from 'react'; import { getDuplicateFiles, clubDuplicatesByTime, @@ -13,7 +13,7 @@ import { EnteFile } from 'types/file'; import { SelectedState } from 'types/gallery'; import { ServerErrorCodes } from 'utils/error'; -import { getSelectedFiles } from 'utils/file'; +import { constructFileToCollectionMap, getSelectedFiles } from 'utils/file'; import { DeduplicateContextType, DefaultDeduplicateContext, @@ -27,8 +27,8 @@ import { styled } from '@mui/material'; import { syncCollections } from 'services/collectionService'; import EnteSpinner from 'components/EnteSpinner'; import VerticallyCentered from 'components/Container'; -import { Collection } from 'types/collection'; import Typography from '@mui/material/Typography'; +import useMemoSingleThreaded from 'hooks/useMemoSingleThreaded'; export const DeduplicateContext = createContext( DefaultDeduplicateContext @@ -47,7 +47,6 @@ export default function Deduplicate() { setRedirectURL, } = useContext(AppContext); const [duplicateFiles, setDuplicateFiles] = useState(null); - const [collections, setCollection] = useState([]); const [clubSameTimeFilesOnly, setClubSameTimeFilesOnly] = useState(false); const [fileSizeMap, setFileSizeMap] = useState(new Map()); const [collectionNameMap, setCollectionNameMap] = useState( @@ -75,10 +74,13 @@ export default function Deduplicate() { syncWithRemote(); }, [clubSameTimeFilesOnly]); + const fileToCollectionsMap = useMemoSingleThreaded(() => { + return constructFileToCollectionMap(duplicateFiles); + }, [duplicateFiles]); + const syncWithRemote = async () => { startLoading(); const collections = await syncCollections(); - setCollection(collections); const collectionNameMap = new Map(); for (const collection of collections) { collectionNameMap.set(collection.id, collection.name); @@ -189,12 +191,12 @@ export default function Deduplicate() { ) : ( )} Date: Tue, 16 May 2023 10:07:41 +0530 Subject: [PATCH 17/17] update shared-album --- apps/photos/src/pages/shared-albums/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/photos/src/pages/shared-albums/index.tsx b/apps/photos/src/pages/shared-albums/index.tsx index f98a8d57e..2d6929932 100644 --- a/apps/photos/src/pages/shared-albums/index.tsx +++ b/apps/photos/src/pages/shared-albums/index.tsx @@ -406,6 +406,8 @@ export default function PublicCollectionGallery() { publicCollection?.publicURLs?.[0]?.enableDownload ?? true } + fileToCollectionsMap={null} + collectionNameMap={null} /> {blockingLoad && (