Merge pull request #594 from ente-io/collection-title-scroll
Collection title scroll
This commit is contained in:
commit
72a431e22b
|
@ -5,6 +5,7 @@ import { SCROLL_DIRECTION } from 'hooks/useComponentScroll';
|
||||||
|
|
||||||
const Wrapper = styled.button<{ direction: SCROLL_DIRECTION }>`
|
const Wrapper = styled.button<{ direction: SCROLL_DIRECTION }>`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
top: 7px;
|
top: 7px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
width: 50px;
|
width: 50px;
|
||||||
|
|
|
@ -5,10 +5,9 @@ import constants from 'utils/strings/constants';
|
||||||
import { ALL_SECTION, COLLECTION_SORT_BY } from 'constants/collection';
|
import { ALL_SECTION, COLLECTION_SORT_BY } from 'constants/collection';
|
||||||
import { Typography } from '@mui/material';
|
import { Typography } from '@mui/material';
|
||||||
import {
|
import {
|
||||||
Hider,
|
CollectionListBarWrapper,
|
||||||
CollectionBarWrapper,
|
|
||||||
ScrollContainer,
|
ScrollContainer,
|
||||||
CollectionSectionWrapper,
|
CollectionListWrapper,
|
||||||
} from 'components/Collections/styledComponents';
|
} from 'components/Collections/styledComponents';
|
||||||
import CollectionCardWithActiveIndicator from 'components/Collections/CollectionBar/CollectionCardWithActiveIndicator';
|
import CollectionCardWithActiveIndicator from 'components/Collections/CollectionBar/CollectionCardWithActiveIndicator';
|
||||||
import useComponentScroll, { SCROLL_DIRECTION } from 'hooks/useComponentScroll';
|
import useComponentScroll, { SCROLL_DIRECTION } from 'hooks/useComponentScroll';
|
||||||
|
@ -20,15 +19,13 @@ import { sortCollectionSummaries } from 'services/collectionService';
|
||||||
interface IProps {
|
interface IProps {
|
||||||
activeCollection?: number;
|
activeCollection?: number;
|
||||||
setActiveCollection: (id?: number) => void;
|
setActiveCollection: (id?: number) => void;
|
||||||
isInSearchMode: boolean;
|
|
||||||
collectionSummaries: CollectionSummaries;
|
collectionSummaries: CollectionSummaries;
|
||||||
showAllCollections: () => void;
|
showAllCollections: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CollectionBar(props: IProps) {
|
export default function CollectionListBar(props: IProps) {
|
||||||
const {
|
const {
|
||||||
activeCollection,
|
activeCollection,
|
||||||
|
|
||||||
setActiveCollection,
|
setActiveCollection,
|
||||||
collectionSummaries,
|
collectionSummaries,
|
||||||
showAllCollections,
|
showAllCollections,
|
||||||
|
@ -76,21 +73,17 @@ export default function CollectionBar(props: IProps) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Hider hide={props.isInSearchMode}>
|
<CollectionListBarWrapper>
|
||||||
<CollectionSectionWrapper>
|
<SpaceBetweenFlex mb={1}>
|
||||||
<SpaceBetweenFlex>
|
<Typography>{constants.ALBUMS}</Typography>
|
||||||
<Typography fontWeight={'bold'}>
|
{hasScrollBar && (
|
||||||
{constants.ALBUMS}
|
<LinkButton onClick={showAllCollections}>
|
||||||
</Typography>
|
{constants.VIEW_ALL_ALBUMS}
|
||||||
{hasScrollBar && (
|
</LinkButton>
|
||||||
<LinkButton onClick={showAllCollections}>
|
)}
|
||||||
{constants.VIEW_ALL_ALBUMS}
|
</SpaceBetweenFlex>
|
||||||
</LinkButton>
|
|
||||||
)}
|
|
||||||
</SpaceBetweenFlex>
|
|
||||||
</CollectionSectionWrapper>
|
|
||||||
|
|
||||||
<CollectionBarWrapper>
|
<CollectionListWrapper>
|
||||||
{!onFarLeft && (
|
{!onFarLeft && (
|
||||||
<ScrollButton
|
<ScrollButton
|
||||||
scrollDirection={SCROLL_DIRECTION.LEFT}
|
scrollDirection={SCROLL_DIRECTION.LEFT}
|
||||||
|
@ -115,7 +108,7 @@ export default function CollectionBar(props: IProps) {
|
||||||
onClick={scrollComponent(SCROLL_DIRECTION.RIGHT)}
|
onClick={scrollComponent(SCROLL_DIRECTION.RIGHT)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</CollectionBarWrapper>
|
</CollectionListWrapper>
|
||||||
</Hider>
|
</CollectionListBarWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
import { CollectionInfo } from './CollectionInfo';
|
import { CollectionInfo } from './CollectionInfo';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Collection, CollectionSummary } from 'types/collection';
|
import { Collection, CollectionSummary } from 'types/collection';
|
||||||
import {
|
|
||||||
CollectionSectionWrapper,
|
|
||||||
Hider,
|
|
||||||
} from 'components/Collections/styledComponents';
|
|
||||||
import CollectionOptions from 'components/Collections/CollectionOptions';
|
import CollectionOptions from 'components/Collections/CollectionOptions';
|
||||||
import { SetCollectionNamerAttributes } from 'components/Collections/CollectionNamer';
|
import { SetCollectionNamerAttributes } from 'components/Collections/CollectionNamer';
|
||||||
import { SPECIAL_COLLECTION_TYPES } from 'constants/collection';
|
import { SPECIAL_COLLECTION_TYPES } from 'constants/collection';
|
||||||
import { SpaceBetweenFlex } from 'components/Container';
|
import { SpaceBetweenFlex } from 'components/Container';
|
||||||
|
import { CollectionInfoBarWrapper } from './styledComponents';
|
||||||
|
|
||||||
interface Iprops {
|
interface Iprops {
|
||||||
activeCollection: Collection;
|
activeCollection: Collection;
|
||||||
collectionSummary: CollectionSummary;
|
collectionSummary: CollectionSummary;
|
||||||
isInSearchMode: boolean;
|
|
||||||
setCollectionNamerAttributes: SetCollectionNamerAttributes;
|
setCollectionNamerAttributes: SetCollectionNamerAttributes;
|
||||||
showCollectionShareModal: () => void;
|
showCollectionShareModal: () => void;
|
||||||
redirectToAll: () => void;
|
redirectToAll: () => void;
|
||||||
|
@ -37,15 +33,13 @@ export default function CollectionInfoWithOptions({
|
||||||
const { name, type, fileCount } = collectionSummary;
|
const { name, type, fileCount } = collectionSummary;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Hider hide={props.isInSearchMode}>
|
<CollectionInfoBarWrapper>
|
||||||
<CollectionSectionWrapper>
|
<SpaceBetweenFlex>
|
||||||
<SpaceBetweenFlex>
|
<CollectionInfo name={name} fileCount={fileCount} />
|
||||||
<CollectionInfo name={name} fileCount={fileCount} />
|
{!SPECIAL_COLLECTION_TYPES.has(type) && (
|
||||||
{!SPECIAL_COLLECTION_TYPES.has(type) && (
|
<CollectionOptions {...props} />
|
||||||
<CollectionOptions {...props} />
|
)}
|
||||||
)}
|
</SpaceBetweenFlex>
|
||||||
</SpaceBetweenFlex>
|
</CollectionInfoBarWrapper>
|
||||||
</CollectionSectionWrapper>
|
|
||||||
</Hider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import { Collection, CollectionSummaries } from 'types/collection';
|
import { Collection, CollectionSummaries } from 'types/collection';
|
||||||
import CollectionBar from 'components/Collections/CollectionBar';
|
import CollectionListBar from 'components/Collections/CollectionBar';
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import AllCollections from 'components/Collections/AllCollections';
|
import AllCollections from 'components/Collections/AllCollections';
|
||||||
import CollectionInfoWithOptions from 'components/Collections/CollectionInfoWithOptions';
|
import CollectionInfoWithOptions from 'components/Collections/CollectionInfoWithOptions';
|
||||||
import { ALL_SECTION } from 'constants/collection';
|
import { ALL_SECTION } from 'constants/collection';
|
||||||
import CollectionShare from 'components/Collections/CollectionShare';
|
import CollectionShare from 'components/Collections/CollectionShare';
|
||||||
import { SetCollectionNamerAttributes } from 'components/Collections/CollectionNamer';
|
import { SetCollectionNamerAttributes } from 'components/Collections/CollectionNamer';
|
||||||
|
import { ITEM_TYPE, TimeStampListItem } from 'components/PhotoList';
|
||||||
|
|
||||||
interface Iprops {
|
interface Iprops {
|
||||||
collections: Collection[];
|
collections: Collection[];
|
||||||
activeCollectionID?: number;
|
activeCollectionID?: number;
|
||||||
|
@ -13,6 +15,7 @@ interface Iprops {
|
||||||
isInSearchMode: boolean;
|
isInSearchMode: boolean;
|
||||||
collectionSummaries: CollectionSummaries;
|
collectionSummaries: CollectionSummaries;
|
||||||
setCollectionNamerAttributes: SetCollectionNamerAttributes;
|
setCollectionNamerAttributes: SetCollectionNamerAttributes;
|
||||||
|
setPhotoListHeader: (value: TimeStampListItem) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Collections(props: Iprops) {
|
export default function Collections(props: Iprops) {
|
||||||
|
@ -23,6 +26,7 @@ export default function Collections(props: Iprops) {
|
||||||
setActiveCollectionID,
|
setActiveCollectionID,
|
||||||
collectionSummaries,
|
collectionSummaries,
|
||||||
setCollectionNamerAttributes,
|
setCollectionNamerAttributes,
|
||||||
|
setPhotoListHeader,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [allCollectionView, setAllCollectionView] = useState(false);
|
const [allCollectionView, setAllCollectionView] = useState(false);
|
||||||
|
@ -31,6 +35,8 @@ export default function Collections(props: Iprops) {
|
||||||
const collectionsMap = useRef<Map<number, Collection>>(new Map());
|
const collectionsMap = useRef<Map<number, Collection>>(new Map());
|
||||||
const activeCollection = useRef<Collection>(null);
|
const activeCollection = useRef<Collection>(null);
|
||||||
|
|
||||||
|
const shouldBeHidden = isInSearchMode || collectionSummaries?.size <= 3;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
collectionsMap.current = new Map(
|
collectionsMap.current = new Map(
|
||||||
props.collections.map((collection) => [collection.id, collection])
|
props.collections.map((collection) => [collection.id, collection])
|
||||||
|
@ -42,10 +48,38 @@ export default function Collections(props: Iprops) {
|
||||||
collectionsMap.current.get(activeCollectionID);
|
collectionsMap.current.get(activeCollectionID);
|
||||||
}, [activeCollectionID, collections]);
|
}, [activeCollectionID, collections]);
|
||||||
|
|
||||||
|
useEffect(
|
||||||
|
() =>
|
||||||
|
!shouldBeHidden &&
|
||||||
|
setPhotoListHeader({
|
||||||
|
item: (
|
||||||
|
<CollectionInfoWithOptions
|
||||||
|
collectionSummary={collectionSummaries.get(
|
||||||
|
activeCollectionID
|
||||||
|
)}
|
||||||
|
activeCollection={activeCollection.current}
|
||||||
|
setCollectionNamerAttributes={
|
||||||
|
setCollectionNamerAttributes
|
||||||
|
}
|
||||||
|
redirectToAll={() => setActiveCollectionID(ALL_SECTION)}
|
||||||
|
showCollectionShareModal={() =>
|
||||||
|
setCollectionShareModalView(true)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
itemType: ITEM_TYPE.STATIC,
|
||||||
|
height: 80,
|
||||||
|
}),
|
||||||
|
[collectionSummaries, activeCollectionID, shouldBeHidden]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (shouldBeHidden) {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CollectionBar
|
<CollectionListBar
|
||||||
isInSearchMode={isInSearchMode}
|
|
||||||
activeCollection={activeCollectionID}
|
activeCollection={activeCollectionID}
|
||||||
setActiveCollection={setActiveCollectionID}
|
setActiveCollection={setActiveCollectionID}
|
||||||
collectionSummaries={collectionSummaries}
|
collectionSummaries={collectionSummaries}
|
||||||
|
@ -59,16 +93,6 @@ export default function Collections(props: Iprops) {
|
||||||
setActiveCollection={setActiveCollectionID}
|
setActiveCollection={setActiveCollectionID}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<CollectionInfoWithOptions
|
|
||||||
isInSearchMode={isInSearchMode}
|
|
||||||
collectionSummary={collectionSummaries.get(activeCollectionID)}
|
|
||||||
activeCollection={activeCollection.current}
|
|
||||||
setCollectionNamerAttributes={setCollectionNamerAttributes}
|
|
||||||
redirectToAll={() => setActiveCollectionID(ALL_SECTION)}
|
|
||||||
showCollectionShareModal={() =>
|
|
||||||
setCollectionShareModalView(true)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<CollectionShare
|
<CollectionShare
|
||||||
show={collectionShareModalView}
|
show={collectionShareModalView}
|
||||||
onHide={() => setCollectionShareModalView(false)}
|
onHide={() => setCollectionShareModalView(false)}
|
||||||
|
|
|
@ -1,26 +1,28 @@
|
||||||
|
import { Box } from '@mui/material';
|
||||||
import { PaddedContainer } from 'components/Container';
|
import { PaddedContainer } from 'components/Container';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const CollectionBarWrapper = styled(PaddedContainer)`
|
export const CollectionListWrapper = styled(Box)`
|
||||||
display: flex;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 86px;
|
height: 86px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 10px auto;
|
`;
|
||||||
|
|
||||||
|
export const CollectionListBarWrapper = styled(PaddedContainer)`
|
||||||
|
width: 100%;
|
||||||
|
margin: 16px auto;
|
||||||
border-bottom: 1px solid ${({ theme }) => theme.palette.divider};
|
border-bottom: 1px solid ${({ theme }) => theme.palette.divider};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CollectionSectionWrapper = styled(PaddedContainer)`
|
export const CollectionInfoBarWrapper = styled(Box)`
|
||||||
margin-bottom: 8px;
|
margin-bottom: 24px;
|
||||||
margin-top: 16px;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ScrollContainer = styled.div`
|
export const ScrollContainer = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
max-width: 100%;
|
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
display: flex;
|
display: flex;
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -17,20 +17,22 @@ import { ENTE_WEBSITE_LINK } from 'constants/urls';
|
||||||
import { getVariantColor, ButtonVariant } from './pages/gallery/LinkButton';
|
import { getVariantColor, ButtonVariant } from './pages/gallery/LinkButton';
|
||||||
import { convertBytesToHumanReadable } from 'utils/billing';
|
import { convertBytesToHumanReadable } from 'utils/billing';
|
||||||
import { DeduplicateContext } from 'pages/deduplicate';
|
import { DeduplicateContext } from 'pages/deduplicate';
|
||||||
import { PaddedContainer } from './Container';
|
import { FlexWrapper, PaddedContainer } from './Container';
|
||||||
|
import { Typography } from '@mui/material';
|
||||||
|
import { GalleryContext } from 'pages/gallery';
|
||||||
|
|
||||||
const A_DAY = 24 * 60 * 60 * 1000;
|
const A_DAY = 24 * 60 * 60 * 1000;
|
||||||
const NO_OF_PAGES = 2;
|
const NO_OF_PAGES = 2;
|
||||||
const FOOTER_HEIGHT = 90;
|
const FOOTER_HEIGHT = 90;
|
||||||
|
|
||||||
enum ITEM_TYPE {
|
export enum ITEM_TYPE {
|
||||||
TIME = 'TIME',
|
TIME = 'TIME',
|
||||||
TILE = 'TILE',
|
FILE = 'FILE',
|
||||||
SIZE_AND_COUNT = 'SIZE_AND_COUNT',
|
SIZE_AND_COUNT = 'SIZE_AND_COUNT',
|
||||||
OTHER = 'OTHER',
|
STATIC = 'static',
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TimeStampListItem {
|
export interface TimeStampListItem {
|
||||||
itemType: ITEM_TYPE;
|
itemType: ITEM_TYPE;
|
||||||
items?: EnteFile[];
|
items?: EnteFile[];
|
||||||
itemStartIndex?: number;
|
itemStartIndex?: number;
|
||||||
|
@ -79,56 +81,40 @@ const ListContainer = styled(PaddedContainer)<{
|
||||||
color: #fff;
|
color: #fff;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const DateContainer = styled.div<{ span: number }>`
|
const ListItemContainer = styled(FlexWrapper)<{ span: number }>`
|
||||||
|
grid-column: span ${(props) => props.span};
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const DateContainer = styled(ListItemContainer)`
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
grid-column: span ${(props) => props.span};
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: ${DATE_CONTAINER_HEIGHT}px;
|
height: ${DATE_CONTAINER_HEIGHT}px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SizeAndCountContainer = styled.div<{ span: number }>`
|
const SizeAndCountContainer = styled(DateContainer)`
|
||||||
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;
|
margin-top: 1rem;
|
||||||
height: ${SIZE_AND_COUNT_CONTAINER_HEIGHT}px;
|
height: ${SIZE_AND_COUNT_CONTAINER_HEIGHT}px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const FooterContainer = styled.div<{ span: number }>`
|
const FooterContainer = styled(ListItemContainer)`
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin-bottom: 0.75rem;
|
margin-bottom: 0.75rem;
|
||||||
@media (max-width: 540px) {
|
@media (max-width: 540px) {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
color: #979797;
|
color: #979797;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
grid-column: span ${(props) => props.span};
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
& > p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
margin-top: calc(2rem + 20px);
|
margin-top: calc(2rem + 20px);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const NothingContainer = styled.div<{ span: number }>`
|
const NothingContainer = styled(ListItemContainer)`
|
||||||
color: #979797;
|
color: #979797;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
grid-column: span ${(props) => props.span};
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -150,6 +136,7 @@ export function PhotoList({
|
||||||
activeCollection,
|
activeCollection,
|
||||||
resetFetching,
|
resetFetching,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const galleryContext = useContext(GalleryContext);
|
||||||
const timeStampListRef = useRef([]);
|
const timeStampListRef = useRef([]);
|
||||||
const timeStampList = timeStampListRef?.current ?? [];
|
const timeStampList = timeStampListRef?.current ?? [];
|
||||||
const filteredDataCopyRef = useRef([]);
|
const filteredDataCopyRef = useRef([]);
|
||||||
|
@ -176,7 +163,7 @@ export function PhotoList({
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let timeStampList: TimeStampListItem[] = [];
|
let timeStampList: TimeStampListItem[] = [getPhotoListHeader()];
|
||||||
if (deduplicateContext.isOnDeduplicatePage) {
|
if (deduplicateContext.isOnDeduplicatePage) {
|
||||||
skipMerge = true;
|
skipMerge = true;
|
||||||
groupByFileSize(timeStampList);
|
groupByFileSize(timeStampList);
|
||||||
|
@ -244,7 +231,7 @@ export function PhotoList({
|
||||||
while (index <= lastFileIndex) {
|
while (index <= lastFileIndex) {
|
||||||
const tileSize = Math.min(columns, lastFileIndex - index + 1);
|
const tileSize = Math.min(columns, lastFileIndex - index + 1);
|
||||||
timeStampList.push({
|
timeStampList.push({
|
||||||
itemType: ITEM_TYPE.TILE,
|
itemType: ITEM_TYPE.FILE,
|
||||||
items: filteredData.slice(index, index + tileSize),
|
items: filteredData.slice(index, index + tileSize),
|
||||||
itemStartIndex: index,
|
itemStartIndex: index,
|
||||||
});
|
});
|
||||||
|
@ -284,7 +271,7 @@ export function PhotoList({
|
||||||
id: currentDate.toString(),
|
id: currentDate.toString(),
|
||||||
});
|
});
|
||||||
timeStampList.push({
|
timeStampList.push({
|
||||||
itemType: ITEM_TYPE.TILE,
|
itemType: ITEM_TYPE.FILE,
|
||||||
items: [item],
|
items: [item],
|
||||||
itemStartIndex: index,
|
itemStartIndex: index,
|
||||||
});
|
});
|
||||||
|
@ -295,7 +282,7 @@ export function PhotoList({
|
||||||
} else {
|
} else {
|
||||||
listItemIndex = 1;
|
listItemIndex = 1;
|
||||||
timeStampList.push({
|
timeStampList.push({
|
||||||
itemType: ITEM_TYPE.TILE,
|
itemType: ITEM_TYPE.FILE,
|
||||||
items: [item],
|
items: [item],
|
||||||
itemStartIndex: index,
|
itemStartIndex: index,
|
||||||
});
|
});
|
||||||
|
@ -308,9 +295,20 @@ export function PhotoList({
|
||||||
first.getMonth() === second.getMonth() &&
|
first.getMonth() === second.getMonth() &&
|
||||||
first.getDate() === second.getDate();
|
first.getDate() === second.getDate();
|
||||||
|
|
||||||
|
const getPhotoListHeader = () => {
|
||||||
|
return {
|
||||||
|
...galleryContext.photoListHeader,
|
||||||
|
item: (
|
||||||
|
<ListItemContainer span={columns}>
|
||||||
|
{galleryContext.photoListHeader.item}
|
||||||
|
</ListItemContainer>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const getEmptyListItem = () => {
|
const getEmptyListItem = () => {
|
||||||
return {
|
return {
|
||||||
itemType: ITEM_TYPE.OTHER,
|
itemType: ITEM_TYPE.STATIC,
|
||||||
item: (
|
item: (
|
||||||
<NothingContainer span={columns}>
|
<NothingContainer span={columns}>
|
||||||
<div>{constants.NOTHING_HERE}</div>
|
<div>{constants.NOTHING_HERE}</div>
|
||||||
|
@ -333,18 +331,19 @@ export function PhotoList({
|
||||||
return sum;
|
return sum;
|
||||||
})();
|
})();
|
||||||
return {
|
return {
|
||||||
itemType: ITEM_TYPE.OTHER,
|
itemType: ITEM_TYPE.STATIC,
|
||||||
item: <></>,
|
item: <></>,
|
||||||
height: Math.max(height - photoFrameHeight - FOOTER_HEIGHT, 0),
|
height: Math.max(height - photoFrameHeight - FOOTER_HEIGHT, 0),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAppDownloadFooter = () => {
|
const getAppDownloadFooter = () => {
|
||||||
return {
|
return {
|
||||||
itemType: ITEM_TYPE.OTHER,
|
itemType: ITEM_TYPE.STATIC,
|
||||||
height: FOOTER_HEIGHT,
|
height: FOOTER_HEIGHT,
|
||||||
item: (
|
item: (
|
||||||
<FooterContainer span={columns}>
|
<FooterContainer span={columns}>
|
||||||
<p>{constants.INSTALL_MOBILE_APP()}</p>
|
<Typography>{constants.INSTALL_MOBILE_APP()}</Typography>
|
||||||
</FooterContainer>
|
</FooterContainer>
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
@ -352,7 +351,7 @@ export function PhotoList({
|
||||||
|
|
||||||
const getAlbumsFooter = () => {
|
const getAlbumsFooter = () => {
|
||||||
return {
|
return {
|
||||||
itemType: ITEM_TYPE.OTHER,
|
itemType: ITEM_TYPE.STATIC,
|
||||||
height: FOOTER_HEIGHT,
|
height: FOOTER_HEIGHT,
|
||||||
item: (
|
item: (
|
||||||
<FooterContainer span={columns}>
|
<FooterContainer span={columns}>
|
||||||
|
@ -456,7 +455,7 @@ export function PhotoList({
|
||||||
return DATE_CONTAINER_HEIGHT;
|
return DATE_CONTAINER_HEIGHT;
|
||||||
case ITEM_TYPE.SIZE_AND_COUNT:
|
case ITEM_TYPE.SIZE_AND_COUNT:
|
||||||
return SIZE_AND_COUNT_CONTAINER_HEIGHT;
|
return SIZE_AND_COUNT_CONTAINER_HEIGHT;
|
||||||
case ITEM_TYPE.TILE:
|
case ITEM_TYPE.FILE:
|
||||||
return listItemHeight;
|
return listItemHeight;
|
||||||
default:
|
default:
|
||||||
return timeStampList[index].height;
|
return timeStampList[index].height;
|
||||||
|
@ -469,7 +468,7 @@ export function PhotoList({
|
||||||
|
|
||||||
const generateKey = (index) => {
|
const generateKey = (index) => {
|
||||||
switch (timeStampList[index].itemType) {
|
switch (timeStampList[index].itemType) {
|
||||||
case ITEM_TYPE.TILE:
|
case ITEM_TYPE.FILE:
|
||||||
return `${timeStampList[index].items[0].id}-${
|
return `${timeStampList[index].items[0].id}-${
|
||||||
timeStampList[index].items.slice(-1)[0].id
|
timeStampList[index].items.slice(-1)[0].id
|
||||||
}`;
|
}`;
|
||||||
|
@ -503,9 +502,7 @@ export function PhotoList({
|
||||||
{constants.EACH}
|
{constants.EACH}
|
||||||
</SizeAndCountContainer>
|
</SizeAndCountContainer>
|
||||||
);
|
);
|
||||||
case ITEM_TYPE.OTHER:
|
case ITEM_TYPE.FILE: {
|
||||||
return listItem.item;
|
|
||||||
default: {
|
|
||||||
const ret = listItem.items.map((item, idx) =>
|
const ret = listItem.items.map((item, idx) =>
|
||||||
getThumbnail(
|
getThumbnail(
|
||||||
filteredDataCopy,
|
filteredDataCopy,
|
||||||
|
@ -522,6 +519,8 @@ export function PhotoList({
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
return listItem.item;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (!timeStampList?.length) {
|
if (!timeStampList?.length) {
|
||||||
|
|
|
@ -2,8 +2,8 @@ import React from 'react';
|
||||||
import { CollectionInfo } from 'components/Collections/CollectionInfo';
|
import { CollectionInfo } from 'components/Collections/CollectionInfo';
|
||||||
import constants from 'utils/strings/constants';
|
import constants from 'utils/strings/constants';
|
||||||
import { Typography } from '@mui/material';
|
import { Typography } from '@mui/material';
|
||||||
import { CollectionSectionWrapper } from 'components/Collections/styledComponents';
|
|
||||||
import { SearchResultSummary } from 'types/search';
|
import { SearchResultSummary } from 'types/search';
|
||||||
|
import { CollectionInfoBarWrapper } from 'components/Collections/styledComponents';
|
||||||
|
|
||||||
interface Iprops {
|
interface Iprops {
|
||||||
searchResultSummary: SearchResultSummary;
|
searchResultSummary: SearchResultSummary;
|
||||||
|
@ -17,11 +17,11 @@ export default function SearchResultInfo({ searchResultSummary }: Iprops) {
|
||||||
|
|
||||||
console.log(optionName, fileCount);
|
console.log(optionName, fileCount);
|
||||||
return (
|
return (
|
||||||
<CollectionSectionWrapper>
|
<CollectionInfoBarWrapper>
|
||||||
<Typography variant="subtitle" color="text.secondary">
|
<Typography variant="subtitle" color="text.secondary">
|
||||||
{constants.SEARCH_RESULTS}
|
{constants.SEARCH_RESULTS}
|
||||||
</Typography>
|
</Typography>
|
||||||
<CollectionInfo name={optionName} fileCount={fileCount} />
|
<CollectionInfo name={optionName} fileCount={fileCount} />
|
||||||
</CollectionSectionWrapper>
|
</CollectionInfoBarWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,7 @@ import { GalleryNavbar } from 'components/pages/gallery/Navbar';
|
||||||
import { Search, SearchResultSummary } from 'types/search';
|
import { Search, SearchResultSummary } from 'types/search';
|
||||||
import SearchResultInfo from 'components/Search/SearchResultInfo';
|
import SearchResultInfo from 'components/Search/SearchResultInfo';
|
||||||
import { NotificationAttributes } from 'types/Notification';
|
import { NotificationAttributes } from 'types/Notification';
|
||||||
|
import { ITEM_TYPE, TimeStampListItem } from 'components/PhotoList';
|
||||||
|
|
||||||
export const DeadCenter = styled.div`
|
export const DeadCenter = styled.div`
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
@ -126,6 +127,7 @@ const defaultGalleryContext: GalleryContextType = {
|
||||||
syncWithRemote: () => null,
|
syncWithRemote: () => null,
|
||||||
setNotificationAttributes: () => null,
|
setNotificationAttributes: () => null,
|
||||||
setBlockingLoad: () => null,
|
setBlockingLoad: () => null,
|
||||||
|
photoListHeader: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GalleryContext = createContext<GalleryContextType>(
|
export const GalleryContext = createContext<GalleryContextType>(
|
||||||
|
@ -134,7 +136,7 @@ export const GalleryContext = createContext<GalleryContextType>(
|
||||||
|
|
||||||
export default function Gallery() {
|
export default function Gallery() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [collections, setCollections] = useState<Collection[]>([]);
|
const [collections, setCollections] = useState<Collection[]>(null);
|
||||||
|
|
||||||
const [files, setFiles] = useState<EnteFile[]>(null);
|
const [files, setFiles] = useState<EnteFile[]>(null);
|
||||||
const [favItemIds, setFavItemIds] = useState<Set<number>>();
|
const [favItemIds, setFavItemIds] = useState<Set<number>>();
|
||||||
|
@ -176,7 +178,7 @@ export default function Gallery() {
|
||||||
const { startLoading, finishLoading, setDialogMessage, ...appContext } =
|
const { startLoading, finishLoading, setDialogMessage, ...appContext } =
|
||||||
useContext(AppContext);
|
useContext(AppContext);
|
||||||
const [collectionSummaries, setCollectionSummaries] =
|
const [collectionSummaries, setCollectionSummaries] =
|
||||||
useState<CollectionSummaries>(new Map());
|
useState<CollectionSummaries>();
|
||||||
const [activeCollection, setActiveCollection] = useState<number>(undefined);
|
const [activeCollection, setActiveCollection] = useState<number>(undefined);
|
||||||
const [trash, setTrash] = useState<Trash>([]);
|
const [trash, setTrash] = useState<Trash>([]);
|
||||||
const [fixCreationTimeView, setFixCreationTimeView] = useState(false);
|
const [fixCreationTimeView, setFixCreationTimeView] = useState(false);
|
||||||
|
@ -203,6 +205,8 @@ export default function Gallery() {
|
||||||
const closeSidebar = () => setSidebarView(false);
|
const closeSidebar = () => setSidebarView(false);
|
||||||
const openSidebar = () => setSidebarView(true);
|
const openSidebar = () => setSidebarView(true);
|
||||||
const [droppedFiles, setDroppedFiles] = useState([]);
|
const [droppedFiles, setDroppedFiles] = useState([]);
|
||||||
|
const [photoListHeader, setPhotoListHeader] =
|
||||||
|
useState<TimeStampListItem>(null);
|
||||||
|
|
||||||
const showSessionExpiredMessage = () =>
|
const showSessionExpiredMessage = () =>
|
||||||
setDialogMessage({
|
setDialogMessage({
|
||||||
|
@ -240,7 +244,6 @@ export default function Gallery() {
|
||||||
setFiles(sortFiles(files));
|
setFiles(sortFiles(files));
|
||||||
setCollections(collections);
|
setCollections(collections);
|
||||||
setTrash(trash);
|
setTrash(trash);
|
||||||
await setDerivativeState(collections, files);
|
|
||||||
await syncWithRemote(true);
|
await syncWithRemote(true);
|
||||||
setIsFirstLoad(false);
|
setIsFirstLoad(false);
|
||||||
setJustSignedUp(false);
|
setJustSignedUp(false);
|
||||||
|
@ -249,6 +252,10 @@ export default function Gallery() {
|
||||||
main();
|
main();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setDerivativeState(collections, files);
|
||||||
|
}, [collections, files]);
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => collectionSelectorAttributes && setCollectionSelectorView(true),
|
() => collectionSelectorAttributes && setCollectionSelectorView(true),
|
||||||
[collectionSelectorAttributes]
|
[collectionSelectorAttributes]
|
||||||
|
@ -300,6 +307,20 @@ export default function Gallery() {
|
||||||
}
|
}
|
||||||
}, [router.isReady]);
|
}, [router.isReady]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isInSearchMode) {
|
||||||
|
setPhotoListHeader({
|
||||||
|
height: 116,
|
||||||
|
item: (
|
||||||
|
<SearchResultInfo
|
||||||
|
searchResultSummary={searchResultSummary}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
itemType: ITEM_TYPE.STATIC,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [isInSearchMode, searchResultSummary]);
|
||||||
|
|
||||||
const syncWithRemote = async (force = false, silent = false) => {
|
const syncWithRemote = async (force = false, silent = false) => {
|
||||||
if (syncInProgress.current && !force) {
|
if (syncInProgress.current && !force) {
|
||||||
resync.current = true;
|
resync.current = true;
|
||||||
|
@ -319,7 +340,6 @@ export default function Gallery() {
|
||||||
const trash = await syncTrash(collections, setFiles, files);
|
const trash = await syncTrash(collections, setFiles, files);
|
||||||
setTrash(trash);
|
setTrash(trash);
|
||||||
files.push(...getTrashedFiles(trash));
|
files.push(...getTrashedFiles(trash));
|
||||||
await setDerivativeState(collections, files);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(e, 'syncWithRemote failed');
|
logError(e, 'syncWithRemote failed');
|
||||||
switch (e.message) {
|
switch (e.message) {
|
||||||
|
@ -345,17 +365,17 @@ export default function Gallery() {
|
||||||
collections: Collection[],
|
collections: Collection[],
|
||||||
files: EnteFile[]
|
files: EnteFile[]
|
||||||
) => {
|
) => {
|
||||||
|
if (!collections || !files) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const favItemIds = await getFavItemIds(files);
|
const favItemIds = await getFavItemIds(files);
|
||||||
setFavItemIds(favItemIds);
|
setFavItemIds(favItemIds);
|
||||||
const nonEmptyCollections = getNonEmptyCollections(collections, files);
|
const nonEmptyCollections = getNonEmptyCollections(collections, files);
|
||||||
|
|
||||||
setCollections(nonEmptyCollections);
|
|
||||||
|
|
||||||
const collectionSummaries = getCollectionSummaries(
|
const collectionSummaries = getCollectionSummaries(
|
||||||
nonEmptyCollections,
|
nonEmptyCollections,
|
||||||
files
|
files
|
||||||
);
|
);
|
||||||
|
|
||||||
setCollectionSummaries(collectionSummaries);
|
setCollectionSummaries(collectionSummaries);
|
||||||
|
|
||||||
const archivedCollections = getArchivedCollections(nonEmptyCollections);
|
const archivedCollections = getArchivedCollections(nonEmptyCollections);
|
||||||
|
@ -366,7 +386,7 @@ export default function Gallery() {
|
||||||
setSelected({ count: 0, collectionID: 0 });
|
setSelected({ count: 0, collectionID: 0 });
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!files) {
|
if (!files || !collectionSummaries) {
|
||||||
return <div />;
|
return <div />;
|
||||||
}
|
}
|
||||||
const collectionOpsHelper =
|
const collectionOpsHelper =
|
||||||
|
@ -578,6 +598,7 @@ export default function Gallery() {
|
||||||
syncWithRemote,
|
syncWithRemote,
|
||||||
setNotificationAttributes,
|
setNotificationAttributes,
|
||||||
setBlockingLoad,
|
setBlockingLoad,
|
||||||
|
photoListHeader: photoListHeader,
|
||||||
}}>
|
}}>
|
||||||
<FullScreenDropZone
|
<FullScreenDropZone
|
||||||
getRootProps={getRootProps}
|
getRootProps={getRootProps}
|
||||||
|
@ -641,12 +662,8 @@ export default function Gallery() {
|
||||||
setActiveCollectionID={setActiveCollection}
|
setActiveCollectionID={setActiveCollection}
|
||||||
collectionSummaries={collectionSummaries}
|
collectionSummaries={collectionSummaries}
|
||||||
setCollectionNamerAttributes={setCollectionNamerAttributes}
|
setCollectionNamerAttributes={setCollectionNamerAttributes}
|
||||||
|
setPhotoListHeader={setPhotoListHeader}
|
||||||
/>
|
/>
|
||||||
{isInSearchMode && (
|
|
||||||
<SearchResultInfo
|
|
||||||
searchResultSummary={searchResultSummary}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Upload
|
<Upload
|
||||||
syncWithRemote={syncWithRemote}
|
syncWithRemote={syncWithRemote}
|
||||||
|
|
|
@ -34,7 +34,7 @@ import { Card } from 'react-bootstrap';
|
||||||
import { logError } from 'utils/sentry';
|
import { logError } from 'utils/sentry';
|
||||||
import SharedAlbumNavbar from 'components/pages/sharedAlbum/Navbar';
|
import SharedAlbumNavbar from 'components/pages/sharedAlbum/Navbar';
|
||||||
import { CollectionInfo } from 'components/Collections/CollectionInfo';
|
import { CollectionInfo } from 'components/Collections/CollectionInfo';
|
||||||
import { CollectionSectionWrapper } from 'components/Collections/styledComponents';
|
import { CollectionInfoBarWrapper } from 'components/Collections/styledComponents';
|
||||||
|
|
||||||
const Loader = () => (
|
const Loader = () => (
|
||||||
<VerticallyCentered>
|
<VerticallyCentered>
|
||||||
|
@ -280,12 +280,12 @@ export default function PublicCollectionGallery() {
|
||||||
openReportForm,
|
openReportForm,
|
||||||
}}>
|
}}>
|
||||||
<SharedAlbumNavbar />
|
<SharedAlbumNavbar />
|
||||||
<CollectionSectionWrapper>
|
<CollectionInfoBarWrapper>
|
||||||
<CollectionInfo
|
<CollectionInfo
|
||||||
name={publicCollection.name}
|
name={publicCollection.name}
|
||||||
fileCount={publicFiles.length}
|
fileCount={publicFiles.length}
|
||||||
/>
|
/>
|
||||||
</CollectionSectionWrapper>
|
</CollectionInfoBarWrapper>
|
||||||
<PhotoFrame
|
<PhotoFrame
|
||||||
files={publicFiles}
|
files={publicFiles}
|
||||||
setFiles={setPublicFiles}
|
setFiles={setPublicFiles}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { TimeStampListItem } from 'components/PhotoList';
|
||||||
import { Collection } from 'types/collection';
|
import { Collection } from 'types/collection';
|
||||||
import { EnteFile } from 'types/file';
|
import { EnteFile } from 'types/file';
|
||||||
import { NotificationAttributes } from 'types/Notification';
|
import { NotificationAttributes } from 'types/Notification';
|
||||||
|
@ -24,4 +25,5 @@ export type GalleryContextType = {
|
||||||
syncWithRemote: (force?: boolean, silent?: boolean) => Promise<void>;
|
syncWithRemote: (force?: boolean, silent?: boolean) => Promise<void>;
|
||||||
setNotificationAttributes: (attributes: NotificationAttributes) => void;
|
setNotificationAttributes: (attributes: NotificationAttributes) => void;
|
||||||
setBlockingLoad: (value: boolean) => void;
|
setBlockingLoad: (value: boolean) => void;
|
||||||
|
photoListHeader: TimeStampListItem;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue