rendering file sizes and count
This commit is contained in:
parent
b8e33fa13e
commit
7c047f2306
|
@ -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<number>(0);
|
||||
|
@ -580,6 +588,7 @@ const PhotoFrame = ({
|
|||
files.length < 30 && !isInSearchMode
|
||||
}
|
||||
resetFetching={resetFetching}
|
||||
deduplicating={deduplicating}
|
||||
/>
|
||||
)}
|
||||
</AutoSizer>
|
||||
|
|
|
@ -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}
|
||||
</DateContainer>
|
||||
);
|
||||
case ITEM_TYPE.SIZE_AND_CNT:
|
||||
return (
|
||||
<SizeAndCountContainer span={columns}>
|
||||
{listItem.fileCount} {constants.FILES},{' '}
|
||||
{getReadableSizeFromBytes(listItem.fileSize)}{' '}
|
||||
{constants.EACH}
|
||||
</SizeAndCountContainer>
|
||||
);
|
||||
case ITEM_TYPE.OTHER:
|
||||
return listItem.item;
|
||||
default: {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -257,6 +257,7 @@ export default function Deduplicate() {
|
|||
activeCollection={ALL_SECTION}
|
||||
isSharedCollection={false}
|
||||
enableDownload={true}
|
||||
deduplicating={{ clubByTime: clubByTime }}
|
||||
/>
|
||||
) : (
|
||||
<b
|
||||
|
|
|
@ -5,6 +5,7 @@ export interface fileAttribute {
|
|||
encryptedData?: DataStream | Uint8Array;
|
||||
objectKey?: string;
|
||||
decryptionHeader: string;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
export interface MagicMetadataCore {
|
||||
|
|
|
@ -41,3 +41,7 @@ export interface NotificationAttributes {
|
|||
message: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface DeduplicatingType {
|
||||
clubByTime: boolean;
|
||||
}
|
||||
|
|
9
src/utils/photoList/index.ts
Normal file
9
src/utils/photoList/index.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
export const getReadableSizeFromBytes = (bytes: number) => {
|
||||
const sizes = ['B', 'KB', 'MB', 'GB'];
|
||||
let currSize = 0;
|
||||
while (bytes >= 1024 && currSize < sizes.length) {
|
||||
bytes /= 1024;
|
||||
currSize++;
|
||||
}
|
||||
return `${bytes.toFixed(2)} ${sizes[currSize]}`;
|
||||
};
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue