Merge pull request #577 from ente-io/collections-redesign-v2

Collections redesign v2
This commit is contained in:
Abhinav Kumar 2022-06-03 14:11:37 +05:30 committed by GitHub
commit 9fe12d1510
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 221 additions and 232 deletions

View file

@ -19,9 +19,7 @@ export default function AllCollectionCard({
<CollectionCard
collectionTile={collectionTile}
latestFile={collectionSummary.latestFile}
onClick={() =>
onCollectionClick(collectionSummary.collectionAttributes.id)
}>
onClick={() => onCollectionClick(collectionSummary.id)}>
<div>
<Typography
css={`
@ -29,7 +27,7 @@ export default function AllCollectionCard({
font-weight: 600;
line-height: 20px;
`}>
{collectionSummary.collectionAttributes.name}
{collectionSummary.name}
</Typography>
<Typography
css={`

View file

@ -25,7 +25,7 @@ export default function AllCollectionContent({
collectionTile={collectionTile}
onCollectionClick={onCollectionClick}
collectionSummary={collectionSummary}
key={collectionSummary.collectionAttributes.id}
key={collectionSummary.id}
/>
))}
</FlexWrapper>

View file

@ -35,7 +35,7 @@ export default function AllCollections(props: Iprops) {
() =>
sortCollectionSummaries(
[...collectionSummaries.values()].filter(
(x) => x.collectionAttributes.type !== CollectionType.system
(x) => x.type !== CollectionType.system
),
collectionSortBy
),

View file

@ -1,11 +1,7 @@
import React from 'react';
import styled, { css } from 'styled-components';
import NavigateNextIcon from '@mui/icons-material/NavigateNext';
export enum SCROLL_DIRECTION {
LEFT = -1,
RIGHT = +1,
}
import { SCROLL_DIRECTION } from 'hooks/useComponentScroll';
const Wrapper = styled.button<{ direction: SCROLL_DIRECTION }>`
position: absolute;
@ -43,9 +39,9 @@ const Wrapper = styled.button<{ direction: SCROLL_DIRECTION }>`
}
`;
const NavigationButton = ({ scrollDirection, ...rest }) => (
const ScrollButton = ({ scrollDirection, ...rest }) => (
<Wrapper direction={scrollDirection} {...rest}>
<NavigateNextIcon />
</Wrapper>
);
export default NavigationButton;
export default ScrollButton;

View file

@ -1,24 +1,23 @@
import NavigationButton, {
SCROLL_DIRECTION,
} from 'components/Collections/CollectionBar/NavigationButton';
import React, { useEffect } from 'react';
import { Collection, CollectionSummaries } from 'types/collection';
import ScrollButton from 'components/Collections/CollectionBar/ScrollButton';
import React, { useEffect, useMemo } from 'react';
import { CollectionSummaries } from 'types/collection';
import constants from 'utils/strings/constants';
import { ALL_SECTION } from 'constants/collection';
import { ALL_SECTION, COLLECTION_SORT_BY } from 'constants/collection';
import { Typography } from '@mui/material';
import {
Hider,
CollectionBarWrapper,
ScrollContainer,
PaddedSpaceBetweenFlex,
CollectionSectionWrapper,
} from 'components/Collections/styledComponents';
import CollectionCardWithActiveIndicator from 'components/Collections/CollectionBar/CollectionCardWithActiveIndicator';
import useComponentScroll from 'hooks/useComponentScroll';
import useComponentScroll, { SCROLL_DIRECTION } from 'hooks/useComponentScroll';
import useWindowSize from 'hooks/useWindowSize';
import LinkButton from 'components/pages/gallery/LinkButton';
import { SpaceBetweenFlex } from 'components/Container';
import { sortCollectionSummaries } from 'services/collectionService';
interface IProps {
collections: Collection[];
activeCollection?: number;
setActiveCollection: (id?: number) => void;
isInSearchMode: boolean;
@ -29,13 +28,23 @@ interface IProps {
export default function CollectionBar(props: IProps) {
const {
activeCollection,
collections,
setActiveCollection,
collectionSummaries,
showAllCollections,
} = props;
const sortedCollectionSummary = useMemo(
() =>
sortCollectionSummaries(
[...collectionSummaries.values()],
COLLECTION_SORT_BY.UPDATION_TIME_DESCENDING
),
[collectionSummaries]
);
const windowSize = useWindowSize();
const {
componentRef,
scrollComponent,
@ -43,12 +52,12 @@ export default function CollectionBar(props: IProps) {
onFarLeft,
onFarRight,
} = useComponentScroll({
dependencies: [windowSize, collections],
dependencies: [windowSize, collectionSummaries],
});
const collectionChipsRef = props.collections.reduce(
(refMap, collection) => {
refMap[collection.id] = React.createRef();
const collectionChipsRef = sortedCollectionSummary.reduce(
(refMap, collectionSummary) => {
refMap[collectionSummary.id] = React.createRef();
return refMap;
},
{}
@ -66,17 +75,20 @@ export default function CollectionBar(props: IProps) {
return (
<Hider hide={props.isInSearchMode}>
<PaddedSpaceBetweenFlex>
<Typography>{constants.ALBUMS}</Typography>
{hasScrollBar && (
<LinkButton onClick={showAllCollections}>
{constants.VIEW_ALL_ALBUMS}
</LinkButton>
)}
</PaddedSpaceBetweenFlex>
<CollectionSectionWrapper>
<SpaceBetweenFlex>
<Typography>{constants.ALBUMS}</Typography>
{hasScrollBar && (
<LinkButton onClick={showAllCollections}>
{constants.VIEW_ALL_ALBUMS}
</LinkButton>
)}
</SpaceBetweenFlex>
</CollectionSectionWrapper>
<CollectionBarWrapper>
{!onFarLeft && (
<NavigationButton
<ScrollButton
scrollDirection={SCROLL_DIRECTION.LEFT}
onClick={scrollComponent(SCROLL_DIRECTION.LEFT)}
/>
@ -88,12 +100,10 @@ export default function CollectionBar(props: IProps) {
onClick={clickHandler(ALL_SECTION)}>
{constants.ALL_SECTION_NAME}
</CollectionCardWithActiveIndicator>
{collections.map((item) => (
{sortedCollectionSummary.map((item) => (
<CollectionCardWithActiveIndicator
key={item.id}
latestFile={
collectionSummaries.get(item.id)?.latestFile
}
latestFile={item.latestFile}
ref={collectionChipsRef[item.id]}
active={activeCollection === item.id}
onClick={clickHandler(item.id)}>
@ -102,7 +112,7 @@ export default function CollectionBar(props: IProps) {
))}
</ScrollContainer>
{!onFarRight && (
<NavigationButton
<ScrollButton
scrollDirection={SCROLL_DIRECTION.RIGHT}
onClick={scrollComponent(SCROLL_DIRECTION.RIGHT)}
/>

View file

@ -1,50 +1,24 @@
import React from 'react';
import { Typography } from '@mui/material';
import React from 'react';
import constants from 'utils/strings/constants';
import { Collection, CollectionSummary } from 'types/collection';
import { PaddedSpaceBetweenFlex } from 'components/Collections/styledComponents';
import CollectionOptions from 'components/Collections/CollectionOptions';
import { SetCollectionNamerAttributes } from 'components/Collections/CollectionNamer';
import { ARCHIVE_SECTION, TRASH_SECTION } from 'constants/collection';
interface Iprops {
activeCollection: Collection;
collectionSummary: CollectionSummary;
setCollectionNamerAttributes: SetCollectionNamerAttributes;
showCollectionShareModal: () => void;
redirectToAll: () => void;
}
export default function collectionInfo(props: Iprops) {
if (!props.collectionSummary) {
return <></>;
}
const {
collectionSummary: { collectionAttributes, fileCount },
} = props;
export function CollectionInfo({ name, fileCount }) {
return (
<PaddedSpaceBetweenFlex>
<div>
<Typography
css={`
font-size: 24px;
font-weight: 600;
line-height: 36px;
`}>
{collectionAttributes.name}
</Typography>
<Typography
css={`
font-size: 14px;
line-height: 20px;
`}>
{constants.PHOTO_COUNT(fileCount)}
</Typography>
</div>
{collectionAttributes.id !== ARCHIVE_SECTION &&
collectionAttributes.id !== TRASH_SECTION && (
<CollectionOptions {...props} />
)}
</PaddedSpaceBetweenFlex>
<div>
<Typography
css={`
font-size: 24px;
font-weight: 600;
line-height: 36px;
`}>
{name}
</Typography>
<Typography
css={`
font-size: 14px;
line-height: 20px;
`}>
{constants.PHOTO_COUNT(fileCount)}
</Typography>
</div>
);
}

View file

@ -0,0 +1,38 @@
import { CollectionInfo } from './CollectionInfo';
import React from 'react';
import { Collection, CollectionSummary } from 'types/collection';
import { CollectionSectionWrapper } from 'components/Collections/styledComponents';
import CollectionOptions from 'components/Collections/CollectionOptions';
import { SetCollectionNamerAttributes } from 'components/Collections/CollectionNamer';
import { CollectionType } from 'constants/collection';
import { SpaceBetweenFlex } from 'components/Container';
interface Iprops {
activeCollection: Collection;
collectionSummary: CollectionSummary;
setCollectionNamerAttributes: SetCollectionNamerAttributes;
showCollectionShareModal: () => void;
redirectToAll: () => void;
}
export default function collectionInfoWithOptions({
collectionSummary,
...props
}: Iprops) {
if (!collectionSummary) {
return <></>;
}
const { name, type, fileCount } = collectionSummary;
return (
<CollectionSectionWrapper>
<SpaceBetweenFlex>
<CollectionInfo name={name} fileCount={fileCount} />
{type !== CollectionType.system &&
type !== CollectionType.favorites && (
<CollectionOptions {...props} />
)}
</SpaceBetweenFlex>
</CollectionSectionWrapper>
);
}

View file

@ -2,7 +2,7 @@ import { Collection, CollectionSummaries } from 'types/collection';
import CollectionBar from 'components/Collections/CollectionBar';
import React, { useEffect, useRef, useState } from 'react';
import AllCollections from 'components/Collections/AllCollections';
import CollectionInfo from 'components/Collections/CollectionInfo';
import CollectionInfoWithOptions from 'components/Collections/CollectionInfoWithOptions';
import { ALL_SECTION } from 'constants/collection';
import CollectionShare from 'components/Collections/CollectionShare';
import { SetCollectionNamerAttributes } from 'components/Collections/CollectionNamer';
@ -45,7 +45,6 @@ export default function Collections(props: Iprops) {
return (
<>
<CollectionBar
collections={collections}
isInSearchMode={isInSearchMode}
activeCollection={activeCollectionID}
setActiveCollection={setActiveCollectionID}
@ -60,7 +59,7 @@ export default function Collections(props: Iprops) {
setActiveCollection={setActiveCollectionID}
/>
<CollectionInfo
<CollectionInfoWithOptions
collectionSummary={collectionSummaries.get(activeCollectionID)}
activeCollection={activeCollection.current}
setCollectionNamerAttributes={setCollectionNamerAttributes}

View file

@ -1,28 +1,19 @@
import { SpaceBetweenFlex } from 'components/Container';
import { IMAGE_CONTAINER_MAX_WIDTH } from 'constants/gallery';
import { PaddedContainer } from 'components/Container';
import styled from 'styled-components';
export const CollectionBarWrapper = styled.div`
export const CollectionBarWrapper = styled(PaddedContainer)`
display: flex;
position: relative;
overflow: hidden;
height: 86px;
width: 100%;
margin: 10px auto;
padding: 0 24px;
@media (max-width: ${IMAGE_CONTAINER_MAX_WIDTH * 4}px) {
padding: 0 4px;
}
border-bottom: 1px solid ${({ theme }) => theme.palette.grey.A200};
`;
export const PaddedSpaceBetweenFlex = styled(SpaceBetweenFlex)`
export const CollectionSectionWrapper = styled(PaddedContainer)`
margin-bottom: 8px;
margin-top: 16px;
padding: 0 24px;
@media (max-width: ${IMAGE_CONTAINER_MAX_WIDTH * 4}px) {
padding: 0 4px;
}
`;
export const ScrollContainer = styled.div`
@ -66,8 +57,7 @@ export const ActiveIndicator = styled.div`
`;
export const Hider = styled.div<{ hide: boolean }>`
opacity: ${(props) => (props.hide ? '0' : '100')};
height: ${(props) => (props.hide ? '0' : 'auto')};
display: ${(props) => (props.hide ? 'none' : 'block')};
`;
export const AllCollectionTile = styled(CollectionTile)`

View file

@ -1,6 +1,7 @@
import { Box } from '@mui/material';
import styled from 'styled-components';
import { default as MuiStyled } from '@mui/styled-engine';
import { IMAGE_CONTAINER_MAX_WIDTH } from 'constants/gallery';
const VerticallyCentered = MuiStyled(Box)`
flex: 1;
@ -90,3 +91,10 @@ export const InvertedIconButton = styled(IconButton)`
background-color: ${({ theme }) => theme.palette.primary.main};
}
`;
export const PaddedContainer = styled(Box)`
padding: 0 24px;
@media (max-width: ${IMAGE_CONTAINER_MAX_WIDTH * 4}px) {
padding: 0 4px;
}
`;

View file

@ -17,6 +17,7 @@ import { ENTE_WEBSITE_LINK } from 'constants/urls';
import { getVariantColor, ButtonVariant } from './pages/gallery/LinkButton';
import { convertBytesToHumanReadable } from 'utils/billing';
import { DeduplicateContext } from 'pages/deduplicate';
import { PaddedContainer } from './Container';
const A_DAY = 24 * 60 * 60 * 1000;
const NO_OF_PAGES = 2;
@ -65,19 +66,17 @@ const getTemplateColumns = (columns: number, groups?: number[]): string => {
}
};
const ListContainer = styled.div<{ columns: number; groups?: number[] }>`
const ListContainer = styled(PaddedContainer)<{
columns: number;
groups?: number[];
}>`
user-select: none;
display: grid;
grid-template-columns: ${({ columns, groups }) =>
getTemplateColumns(columns, groups)};
grid-column-gap: ${GAP_BTW_TILES}px;
padding: 0 24px;
width: 100%;
color: #fff;
@media (max-width: ${IMAGE_CONTAINER_MAX_WIDTH * 4}px) {
padding: 0 4px;
}
`;
const DateContainer = styled.div<{ span: number }>`

View file

@ -49,11 +49,11 @@ function CollectionSelector({
const personalCollectionsOtherThanFrom = [
...collectionSummaries.values(),
]?.filter(
({ collectionAttributes }) =>
collectionAttributes.id !== attributes.fromCollection &&
({ type, id, attributes: collectionAttributes }) =>
id !== attributes.fromCollection &&
collectionAttributes.ownerID === user?.id &&
collectionAttributes.type !== CollectionType.favorites &&
collectionAttributes.type !== CollectionType.system
type !== CollectionType.favorites &&
type !== CollectionType.system
);
if (personalCollectionsOtherThanFrom.length === 0) {
props.onClose();
@ -96,7 +96,7 @@ function CollectionSelector({
collectionTile={CollectionSelectorTile}
onCollectionClick={handleCollectionClick}
collectionSummary={collectionSummary}
key={collectionSummary.collectionAttributes.id}
key={collectionSummary.id}
/>
))}
</FlexWrapper>

View file

@ -1,6 +1,10 @@
import { SCROLL_DIRECTION } from 'components/Collections/CollectionBar/NavigationButton';
import { useRef, useState, useEffect } from 'react';
export enum SCROLL_DIRECTION {
LEFT = -1,
RIGHT = +1,
}
export default function useComponentScroll({
dependencies,
}: {

View file

@ -17,7 +17,6 @@ import {
import styled from 'styled-components';
import {
syncCollections,
getCollectionsAndTheirLatestFile,
getFavItemIds,
getLocalCollections,
getNonEmptyCollections,
@ -91,11 +90,7 @@ import DeleteBtn from 'components/DeleteBtn';
import FixCreationTime, {
FixCreationTimeAttributes,
} from 'components/FixCreationTime';
import {
Collection,
CollectionAndItsLatestFile,
CollectionSummaries,
} from 'types/collection';
import { Collection, CollectionSummaries } from 'types/collection';
import { EnteFile } from 'types/file';
import {
GalleryContextType,
@ -145,8 +140,7 @@ export const GalleryContext = createContext<GalleryContextType>(
export default function Gallery() {
const router = useRouter();
const [collections, setCollections] = useState<Collection[]>([]);
const [collectionsAndTheirLatestFile, setCollectionsAndTheirLatestFile] =
useState<CollectionAndItsLatestFile[]>([]);
const [files, setFiles] = useState<EnteFile[]>(null);
const [favItemIds, setFavItemIds] = useState<Set<number>>();
const [bannerMessage, setBannerMessage] = useState<JSX.Element | string>(
@ -349,11 +343,7 @@ export default function Gallery() {
const nonEmptyCollections = getNonEmptyCollections(collections, files);
setCollections(nonEmptyCollections);
const collectionsAndTheirLatestFile = getCollectionsAndTheirLatestFile(
nonEmptyCollections,
files
);
setCollectionsAndTheirLatestFile(collectionsAndTheirLatestFile);
const collectionSummaries = getCollectionSummaries(
nonEmptyCollections,
files
@ -672,7 +662,7 @@ export default function Gallery() {
setUploadInProgress={setUploadInProgress}
fileRejections={fileRejections}
setFiles={setFiles}
isFirstUpload={collectionsAndTheirLatestFile?.length === 0}
isFirstUpload={collectionSummaries.size === 0}
electronFiles={electronFiles}
setElectronFiles={setElectronFiles}
uploadTypeSelectorView={uploadTypeSelectorView}

View file

@ -13,7 +13,7 @@ import {
syncPublicFiles,
verifyPublicCollectionPassword,
} from 'services/publicCollectionService';
import { Collection, CollectionSummaries } from 'types/collection';
import { Collection } from 'types/collection';
import { EnteFile } from 'types/file';
import { mergeMetadata, sortFiles } from 'utils/file';
import { AppContext } from 'pages/_app';
@ -33,6 +33,8 @@ import SingleInputForm from 'components/SingleInputForm';
import { Card } from 'react-bootstrap';
import { logError } from 'utils/sentry';
import SharedAlbumNavbar from 'components/pages/sharedAlbum/Navbar';
import { CollectionInfo } from 'components/Collections/CollectionInfo';
import { CollectionSectionWrapper } from 'components/Collections/styledComponents';
const Loader = () => (
<VerticallyCentered>
@ -59,8 +61,6 @@ export default function PublicCollectionGallery() {
const router = useRouter();
const [isPasswordProtected, setIsPasswordProtected] =
useState<boolean>(false);
const [collectionSummaries, setCollectionSummaries] =
useState<CollectionSummaries>(new Map());
useEffect(() => {
const currentURL = new URL(window.location.href);
@ -133,7 +133,7 @@ export default function PublicCollectionGallery() {
collection?.publicURLs?.[0]?.passwordEnabled;
setIsPasswordProtected(isPasswordProtected);
setErrorMessage(null);
let files = [];
// remove outdated password, sharer has disabled the password
if (!isPasswordProtected && passwordJWTToken.current) {
passwordJWTToken.current = null;
@ -144,7 +144,7 @@ export default function PublicCollectionGallery() {
(isPasswordProtected && passwordJWTToken.current)
) {
try {
files = await syncPublicFiles(
await syncPublicFiles(
token.current,
passwordJWTToken.current,
collection,
@ -162,18 +162,6 @@ export default function PublicCollectionGallery() {
if (isPasswordProtected && !passwordJWTToken.current) {
await removePublicFiles(collectionUID);
}
collectionSummaries.set(collection.id, {
collectionAttributes: {
name: collection.name,
type: collection.type,
id: collection.id,
updationTime: collection.updationTime,
ownerID: collection.owner.id,
},
latestFile: files[0],
fileCount: files.length,
});
setCollectionSummaries(collectionSummaries);
} catch (e) {
const parsedError = parseSharingErrorCodes(e);
if (
@ -293,6 +281,12 @@ export default function PublicCollectionGallery() {
openReportForm,
}}>
<SharedAlbumNavbar />
<CollectionSectionWrapper>
<CollectionInfo
name={publicCollection.name}
fileCount={publicFiles.length}
/>
</CollectionSectionWrapper>
<PhotoFrame
files={publicFiles}
setFiles={setPublicFiles}
@ -304,7 +298,6 @@ export default function PublicCollectionGallery() {
openUploader={() => null}
isInSearchMode={false}
search={{}}
setSearchStats={() => null}
deleted={[]}
activeCollection={ALL_SECTION}
isSharedCollection

View file

@ -13,7 +13,7 @@ import { CustomError } from 'utils/error';
import { sortFiles, sortFilesIntoCollections } from 'utils/file';
import {
Collection,
CollectionAndItsLatestFile,
CollectionLatestFiles,
AddToCollectionRequest,
MoveToCollectionRequest,
EncryptedFileKey,
@ -34,6 +34,7 @@ import {
import { UpdateMagicMetadataRequest } from 'types/magicMetadata';
import { EncryptionResult } from 'types/upload';
import constants from 'utils/strings/constants';
import { IsArchived } from 'utils/magicMetadata';
const ENDPOINT = getEndpoint();
const COLLECTION_TABLE = 'collections';
@ -204,26 +205,23 @@ export const getCollection = async (
}
};
export const getCollectionsAndTheirLatestFile = (
collections: Collection[],
export const getCollectionLatestFiles = (
files: EnteFile[]
): CollectionAndItsLatestFile[] => {
const latestFile = new Map<number, EnteFile>();
): CollectionLatestFiles => {
const latestFiles = new Map<number, EnteFile>();
files.forEach((file) => {
if (!latestFile.has(file.collectionID)) {
latestFile.set(file.collectionID, file);
if (!latestFiles.has(file.collectionID)) {
latestFiles.set(file.collectionID, file);
}
if (!latestFiles.has(ARCHIVE_SECTION) && IsArchived(file)) {
latestFiles.set(ARCHIVE_SECTION, file);
}
if (!latestFiles.has(TRASH_SECTION) && file.isTrashed) {
latestFiles.set(TRASH_SECTION, file);
}
});
const collectionsAndTheirLatestFile: CollectionAndItsLatestFile[] = [];
for (const collection of collections) {
collectionsAndTheirLatestFile.push({
collection,
file: latestFile.get(collection.id),
});
}
return collectionsAndTheirLatestFile;
return latestFiles;
};
export const getFavItemIds = async (
@ -730,13 +728,10 @@ export function sortCollectionSummaries(
);
case COLLECTION_SORT_BY.UPDATION_TIME_DESCENDING:
return (
b.collectionAttributes.updationTime -
a.collectionAttributes.updationTime
b.attributes.updationTime - a.attributes.updationTime
);
case COLLECTION_SORT_BY.NAME:
return a.collectionAttributes.name.localeCompare(
b.collectionAttributes.name
);
return a.name.localeCompare(b.name);
}
})
);
@ -753,9 +748,9 @@ function compareCollectionsLatestFile(first: EnteFile, second: EnteFile) {
function moveFavCollectionToFront(collectionSummaries: CollectionSummary[]) {
return collectionSummaries.sort((a, b) =>
a.collectionAttributes.type === CollectionType.favorites
a.type === CollectionType.favorites
? -1
: b.collectionAttributes.type === CollectionType.favorites
: b.type === CollectionType.favorites
? 1
: 0
);
@ -766,39 +761,35 @@ export function getCollectionSummaries(
files: EnteFile[]
): CollectionSummaries {
const collectionSummaries: CollectionSummaries = new Map();
const collectionAndTheirLatestFile = getCollectionsAndTheirLatestFile(
collections,
files
);
const collectionAndTheirLatestFileMap = new Map();
for (const collectionAndItsLatestFile of collectionAndTheirLatestFile) {
collectionAndTheirLatestFileMap.set(
collectionAndItsLatestFile.collection.id,
collectionAndItsLatestFile.file
);
}
const collectionLatestFiles = getCollectionLatestFiles(files);
const collectionFilesCount = getCollectionsFileCount(files);
for (const collection of collections) {
collectionSummaries.set(collection.id, {
collectionAttributes: {
id: collection.id,
name: collection.name,
type: collection.type,
id: collection.id,
name: collection.name,
type: collection.type,
latestFile: collectionLatestFiles.get(collection.id),
fileCount: collectionFilesCount.get(collection.id) ?? 0,
attributes: {
updationTime: collection.updationTime,
ownerID: collection.owner.id,
},
latestFile: collectionAndTheirLatestFileMap.get(collection.id),
fileCount: collectionFilesCount.get(collection.id) ?? 0,
});
}
collectionSummaries.set(
ARCHIVE_SECTION,
getArchivedCollectionSummaries(collectionFilesCount)
getArchivedCollectionSummaries(
collectionFilesCount,
collectionLatestFiles
)
);
collectionSummaries.set(
TRASH_SECTION,
getTrashedCollectionSummaries(collectionFilesCount)
getTrashedCollectionSummaries(
collectionFilesCount,
collectionLatestFiles
)
);
return collectionSummaries;
}
@ -813,33 +804,27 @@ function getCollectionsFileCount(files: EnteFile[]): CollectionFilesCount {
}
function getArchivedCollectionSummaries(
collectionFilesCount: CollectionFilesCount
collectionFilesCount: CollectionFilesCount,
collectionsLatestFile: CollectionLatestFiles
) {
return {
collectionAttributes: {
id: ARCHIVE_SECTION,
name: constants.ARCHIVE,
type: CollectionType.system,
updationTime: 0,
ownerID: 0,
},
latestFile: null,
id: TRASH_SECTION,
name: constants.ARCHIVE,
type: CollectionType.system,
latestFile: collectionsLatestFile.get(ARCHIVE_SECTION),
fileCount: collectionFilesCount.get(ARCHIVE_SECTION) ?? 0,
} as CollectionSummary;
}
function getTrashedCollectionSummaries(
collectionFilesCount: CollectionFilesCount
) {
collectionFilesCount: CollectionFilesCount,
collectionsLatestFile: CollectionLatestFiles
): CollectionSummary {
return {
collectionAttributes: {
id: TRASH_SECTION,
name: constants.TRASH,
type: CollectionType.system,
updationTime: 0,
ownerID: 0,
},
latestFile: null,
id: TRASH_SECTION,
name: constants.TRASH,
type: CollectionType.system,
latestFile: collectionsLatestFile.get(TRASH_SECTION),
fileCount: collectionFilesCount.get(TRASH_SECTION) ?? 0,
};
}

View file

@ -73,10 +73,7 @@ export interface collectionAttributes {
pathDecryptionNonce?: string;
}
export interface CollectionAndItsLatestFile {
collection: Collection;
file: EnteFile;
}
export type CollectionLatestFiles = Map<number, EnteFile>;
export interface RemoveFromCollectionRequest {
collectionID: number;
@ -92,16 +89,23 @@ export interface CollectionMagicMetadata
data: CollectionMagicMetadataProps;
}
export interface CollectionSummary {
collectionAttributes: {
id: number;
name: string;
type: CollectionType;
ownerID: number;
updationTime: number;
};
latestFile: EnteFile;
id: number;
name: string;
type: CollectionType;
latestFile?: EnteFile;
fileCount: number;
attributes?: {
ownerID?: number;
updationTime?: number;
};
}
export type CollectionSummaries = Map<number, CollectionSummary>;
export type CollectionFilesCount = Map<number, number>;
export interface CollectionInfo {
id: number;
name: string;
fileCount: number;
type: CollectionType;
}

View file

@ -140,21 +140,22 @@ export function isFileHEIC(mimeType: string) {
}
export function sortFilesIntoCollections(files: EnteFile[]) {
const collectionWiseFiles = new Map<number, EnteFile[]>();
const collectionWiseFiles = new Map<number, EnteFile[]>([
[ARCHIVE_SECTION, []],
[TRASH_SECTION, []],
]);
for (const file of files) {
let collectionID: number;
if (file.isTrashed) {
collectionID = TRASH_SECTION;
} else if (IsArchived(file)) {
collectionID = ARCHIVE_SECTION;
} else {
collectionID = file.collectionID;
}
if (!collectionWiseFiles.has(collectionID)) {
collectionWiseFiles.set(collectionID, []);
if (!collectionWiseFiles.has(file.collectionID)) {
collectionWiseFiles.set(file.collectionID, []);
}
collectionWiseFiles.get(collectionID).push(file);
collectionWiseFiles.get(file.collectionID).push(file);
if (IsArchived(file)) {
collectionWiseFiles.get(ARCHIVE_SECTION).push(file);
}
if (file.isTrashed) {
collectionWiseFiles.get(TRASH_SECTION).push(file);
}
}
return collectionWiseFiles;
}