From 7c047f230686296de9c7e71ec30e35618c7b0bd1 Mon Sep 17 00:00:00 2001 From: Rushikesh Tote Date: Fri, 25 Mar 2022 14:32:33 +0530 Subject: [PATCH] rendering file sizes and count --- src/components/PhotoFrame.tsx | 11 +- src/components/PhotoList.tsx | 135 +++++++++++++++++++------ src/constants/gallery/index.ts | 1 + src/pages/deduplicate/index.tsx | 1 + src/types/file/index.ts | 1 + src/types/gallery/index.ts | 4 + src/utils/photoList/index.ts | 9 ++ src/utils/strings/englishConstants.tsx | 2 + 8 files changed, 134 insertions(+), 30 deletions(-) create mode 100644 src/utils/photoList/index.ts diff --git a/src/components/PhotoFrame.tsx b/src/components/PhotoFrame.tsx index 6a12beaf3..d9e7a929f 100644 --- a/src/components/PhotoFrame.tsx +++ b/src/components/PhotoFrame.tsx @@ -18,7 +18,13 @@ import { import { isSharedFile } from 'utils/file'; import { isPlaybackPossible } from 'utils/photoFrame'; import { PhotoList } from './PhotoList'; -import { SetFiles, SelectedState, Search, setSearchStats } from 'types/gallery'; +import { + SetFiles, + SelectedState, + Search, + setSearchStats, + DeduplicatingType, +} from 'types/gallery'; import { FILE_TYPE } from 'constants/file'; import PublicCollectionDownloadManager from 'services/publicCollectionDownloadManager'; import { PublicCollectionGalleryContext } from 'utils/publicCollectionGallery'; @@ -70,6 +76,7 @@ interface Props { activeCollection: number; isSharedCollection: boolean; enableDownload: boolean; + deduplicating?: DeduplicatingType; } type SourceURL = { @@ -93,6 +100,7 @@ const PhotoFrame = ({ activeCollection, isSharedCollection, enableDownload, + deduplicating, }: Props) => { const [open, setOpen] = useState(false); const [currentIndex, setCurrentIndex] = useState(0); @@ -580,6 +588,7 @@ const PhotoFrame = ({ files.length < 30 && !isInSearchMode } resetFetching={resetFetching} + deduplicating={deduplicating} /> )} diff --git a/src/components/PhotoList.tsx b/src/components/PhotoList.tsx index 598edb891..27d809aea 100644 --- a/src/components/PhotoList.tsx +++ b/src/components/PhotoList.tsx @@ -9,11 +9,14 @@ import { DATE_CONTAINER_HEIGHT, GAP_BTW_TILES, SPACE_BTW_DATES, + SIZE_AND_COUNT_CONTAINER_HEIGHT, } from 'constants/gallery'; import constants from 'utils/strings/constants'; import { PublicCollectionGalleryContext } from 'utils/publicCollectionGallery'; import { ENTE_WEBSITE_LINK } from 'constants/urls'; import { getVariantColor, ButtonVariant } from './pages/gallery/LinkButton'; +import { getReadableSizeFromBytes } from 'utils/photoList'; +import { DeduplicatingType } from 'types/gallery'; const A_DAY = 24 * 60 * 60 * 1000; const NO_OF_PAGES = 2; @@ -22,6 +25,7 @@ const FOOTER_HEIGHT = 90; enum ITEM_TYPE { TIME = 'TIME', TILE = 'TILE', + SIZE_AND_CNT = 'SIZE_AND_CNT', OTHER = 'OTHER', } @@ -38,6 +42,8 @@ interface TimeStampListItem { item?: any; id?: string; height?: number; + fileSize?: number; + fileCount?: number; } const ListItem = styled.div` @@ -85,6 +91,18 @@ const DateContainer = styled.div<{ span: number }>` height: ${DATE_CONTAINER_HEIGHT}px; `; +const SizeAndCountContainer = styled.div<{ span: number }>` + user-select: none; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + grid-column: span ${(props) => props.span}; + display: flex; + align-items: center; + margin-top: 1rem; + height: ${SIZE_AND_COUNT_CONTAINER_HEIGHT}px; +`; + const FooterContainer = styled.div<{ span: number }>` font-size: 14px; margin-bottom: 0.75rem; @@ -122,6 +140,7 @@ interface Props { getThumbnail: (files: EnteFile[], index: number) => JSX.Element; activeCollection: number; resetFetching: () => void; + deduplicating?: DeduplicatingType; } export function PhotoList({ @@ -132,6 +151,7 @@ export function PhotoList({ getThumbnail, activeCollection, resetFetching, + deduplicating, }: Props) { const timeStampListRef = useRef([]); const timeStampList = timeStampListRef?.current ?? []; @@ -158,6 +178,81 @@ export function PhotoList({ useEffect(() => { let timeStampList: TimeStampListItem[] = []; + if (deduplicating) { + groupByFileSize(timeStampList); + } else { + groupByTime(timeStampList); + } + + if (!skipMerge && !deduplicating) { + timeStampList = mergeTimeStampList(timeStampList, columns); + } + if (timeStampList.length === 0) { + timeStampList.push(getEmptyListItem()); + } + if ( + showAppDownloadBanner || + publicCollectionGalleryContext.accessedThroughSharedURL + ) { + timeStampList.push(getVacuumItem(timeStampList)); + if (publicCollectionGalleryContext.accessedThroughSharedURL) { + timeStampList.push(getAlbumsFooter()); + } else { + timeStampList.push(getAppDownloadFooter()); + } + } + + timeStampListRef.current = timeStampList; + filteredDataCopyRef.current = filteredData; + refreshList(); + }, [ + width, + height, + filteredData, + showAppDownloadBanner, + publicCollectionGalleryContext.accessedThroughSharedURL, + ]); + + const groupByFileSize = (timeStampList: TimeStampListItem[]) => { + let index = 0; + + while (index < filteredData.length) { + const file = filteredData[index]; + const currentFileSize = file.file.size; + const currentCreationTime = file.metadata.creationTime; + let lastFileIndex = index; + + while (lastFileIndex < filteredData.length) { + if ( + filteredData[lastFileIndex].file.size !== currentFileSize || + (deduplicating.clubByTime && + filteredData[lastFileIndex].metadata.creationTime !== + currentCreationTime) + ) { + break; + } + lastFileIndex++; + } + lastFileIndex--; + timeStampList.push({ + itemType: ITEM_TYPE.SIZE_AND_CNT, + fileSize: currentFileSize, + fileCount: lastFileIndex - index + 1, + }); + + while (index <= lastFileIndex) { + const tileSize = Math.min(columns, lastFileIndex - index + 1); + timeStampList.push({ + itemType: ITEM_TYPE.TILE, + items: filteredData.slice(index, index + tileSize), + itemStartIndex: index, + }); + index += tileSize; + } + } + }; + + const groupByTime = (timeStampList: TimeStampListItem[]) => { let listItemIndex = 0; let currentDate = -1; @@ -205,35 +300,7 @@ export function PhotoList({ }); } }); - - if (!skipMerge) { - timeStampList = mergeTimeStampList(timeStampList, columns); - } - if (timeStampList.length === 0) { - timeStampList.push(getEmptyListItem()); - } - if ( - showAppDownloadBanner || - publicCollectionGalleryContext.accessedThroughSharedURL - ) { - timeStampList.push(getVacuumItem(timeStampList)); - if (publicCollectionGalleryContext.accessedThroughSharedURL) { - timeStampList.push(getAlbumsFooter()); - } else { - timeStampList.push(getAppDownloadFooter()); - } - } - - timeStampListRef.current = timeStampList; - filteredDataCopyRef.current = filteredData; - refreshList(); - }, [ - width, - height, - filteredData, - showAppDownloadBanner, - publicCollectionGalleryContext.accessedThroughSharedURL, - ]); + }; const isSameDay = (first, second) => first.getFullYear() === second.getFullYear() && @@ -386,6 +453,8 @@ export function PhotoList({ switch (timeStampList[index].itemType) { case ITEM_TYPE.TIME: return DATE_CONTAINER_HEIGHT; + case ITEM_TYPE.SIZE_AND_CNT: + return SIZE_AND_COUNT_CONTAINER_HEIGHT; case ITEM_TYPE.TILE: return listItemHeight; default: @@ -425,6 +494,14 @@ export function PhotoList({ {listItem.date} ); + case ITEM_TYPE.SIZE_AND_CNT: + return ( + + {listItem.fileCount} {constants.FILES},{' '} + {getReadableSizeFromBytes(listItem.fileSize)}{' '} + {constants.EACH} + + ); case ITEM_TYPE.OTHER: return listItem.item; default: { diff --git a/src/constants/gallery/index.ts b/src/constants/gallery/index.ts index be5c385f4..70c84e445 100644 --- a/src/constants/gallery/index.ts +++ b/src/constants/gallery/index.ts @@ -1,5 +1,6 @@ export const GAP_BTW_TILES = 4; export const DATE_CONTAINER_HEIGHT = 48; +export const SIZE_AND_COUNT_CONTAINER_HEIGHT = 72; export const IMAGE_CONTAINER_MAX_HEIGHT = 200; export const IMAGE_CONTAINER_MAX_WIDTH = IMAGE_CONTAINER_MAX_HEIGHT - GAP_BTW_TILES; diff --git a/src/pages/deduplicate/index.tsx b/src/pages/deduplicate/index.tsx index e4d1ae9f0..51d4bbace 100644 --- a/src/pages/deduplicate/index.tsx +++ b/src/pages/deduplicate/index.tsx @@ -257,6 +257,7 @@ export default function Deduplicate() { activeCollection={ALL_SECTION} isSharedCollection={false} enableDownload={true} + deduplicating={{ clubByTime: clubByTime }} /> ) : ( { + const sizes = ['B', 'KB', 'MB', 'GB']; + let currSize = 0; + while (bytes >= 1024 && currSize < sizes.length) { + bytes /= 1024; + currSize++; + } + return `${bytes.toFixed(2)} ${sizes[currSize]}`; +}; diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx index 1f3cb0d3d..f3e868e1e 100644 --- a/src/utils/strings/englishConstants.tsx +++ b/src/utils/strings/englishConstants.tsx @@ -692,6 +692,8 @@ const englishConstants = { DEDUPLICATE_FILES: 'deduplicate files', NO_DUPLICATES_FOUND: "you've no duplicate files that can be cleared", CLUB_BY_CAPTURE_TIME: 'club by capture time', + FILES: 'files', + EACH: 'each', }; export default englishConstants;