Added selectAll checkbox to select all files on a day
Signed-off-by: aakankshabhende <aakanksha0407@gmail.com>
This commit is contained in:
parent
9a3c450d34
commit
4a579a93bb
6 changed files with 179 additions and 61 deletions
|
@ -17,12 +17,16 @@ import DownloadManager, {
|
|||
LivePhotoSourceURL,
|
||||
SourceURLs,
|
||||
} from "services/download";
|
||||
import {
|
||||
handleSelectCreator,
|
||||
updateFileMsrcProps,
|
||||
updateFileSrcProps,
|
||||
} from "utils/photoFrame";
|
||||
import { EnteFile } from "types/file";
|
||||
import {
|
||||
SelectedState,
|
||||
SetFilesDownloadProgressAttributesCreator,
|
||||
} from "types/gallery";
|
||||
import { updateFileMsrcProps, updateFileSrcProps } from "utils/photoFrame";
|
||||
import { PhotoList } from "./PhotoList";
|
||||
import { DedupePhotoList } from "./PhotoList/dedupe";
|
||||
import PreviewCard from "./pages/gallery/PreviewCard";
|
||||
|
@ -227,52 +231,12 @@ const PhotoFrame = ({
|
|||
setIsPhotoSwipeOpen?.(true);
|
||||
};
|
||||
|
||||
const handleSelect =
|
||||
(id: number, isOwnFile: boolean, index?: number) =>
|
||||
(checked: boolean) => {
|
||||
if (typeof index !== "undefined") {
|
||||
if (checked) {
|
||||
setRangeStart(index);
|
||||
} else {
|
||||
setRangeStart(undefined);
|
||||
}
|
||||
}
|
||||
setSelected((selected) => {
|
||||
if (selected.collectionID !== activeCollectionID) {
|
||||
selected = { ownCount: 0, count: 0, collectionID: 0 };
|
||||
}
|
||||
const handleSelect = handleSelectCreator(
|
||||
setSelected,
|
||||
activeCollectionID,
|
||||
setRangeStart
|
||||
);
|
||||
|
||||
const handleCounterChange = (count: number) => {
|
||||
if (selected[id] === checked) {
|
||||
return count;
|
||||
}
|
||||
if (checked) {
|
||||
return count + 1;
|
||||
} else {
|
||||
return count - 1;
|
||||
}
|
||||
};
|
||||
|
||||
const handleAllCounterChange = () => {
|
||||
if (isOwnFile) {
|
||||
return {
|
||||
ownCount: handleCounterChange(selected.ownCount),
|
||||
count: handleCounterChange(selected.count),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
count: handleCounterChange(selected.count),
|
||||
};
|
||||
}
|
||||
};
|
||||
return {
|
||||
...selected,
|
||||
[id]: checked,
|
||||
collectionID: activeCollectionID,
|
||||
...handleAllCounterChange(),
|
||||
};
|
||||
});
|
||||
};
|
||||
const onHoverOver = (index: number) => () => {
|
||||
setCurrentHover(index);
|
||||
};
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import { FlexWrapper } from "@ente/shared/components/Container";
|
||||
import { ENTE_WEBSITE_LINK } from "@ente/shared/constants/urls";
|
||||
import { formatDate } from "@ente/shared/time/format";
|
||||
import { convertBytesToHumanReadable } from "@ente/shared/utils/size";
|
||||
import { Box, Link, Typography, styled } from "@mui/material";
|
||||
import { Box, Link, Typography,Checkbox, styled } from "@mui/material";
|
||||
import {
|
||||
DATE_CONTAINER_HEIGHT,
|
||||
GAP_BTW_TILES,
|
||||
|
@ -23,8 +22,10 @@ import {
|
|||
ListChildComponentProps,
|
||||
areEqual,
|
||||
} from "react-window";
|
||||
import { EnteFile } from "types/file";
|
||||
import { PublicCollectionGalleryContext } from "utils/publicCollectionGallery";
|
||||
import { formatDate, getDate, isSameDay } from "@ente/shared/time/format";
|
||||
import { handleSelectCreator } from "utils/photoFrame";
|
||||
import { EnteFile } from "types/file";
|
||||
|
||||
const A_DAY = 24 * 60 * 60 * 1000;
|
||||
const FOOTER_HEIGHT = 90;
|
||||
|
@ -185,6 +186,9 @@ const NothingContainer = styled(ListItemContainer)`
|
|||
justify-content: center;
|
||||
`;
|
||||
|
||||
const SelectAllCheckBoxContainer = styled(Checkbox)<{ margin: number }>`
|
||||
margin-left: ${(props) => props.margin}px;
|
||||
`;
|
||||
interface Props {
|
||||
height: number;
|
||||
width: number;
|
||||
|
@ -265,6 +269,8 @@ export function PhotoList({
|
|||
const shouldRefresh = useRef(false);
|
||||
const listRef = useRef(null);
|
||||
|
||||
const [checkedDates, setCheckedDates] = useState({});
|
||||
|
||||
const fittableColumns = getFractionFittableColumns(width);
|
||||
let columns = Math.floor(fittableColumns);
|
||||
|
||||
|
@ -473,14 +479,6 @@ export function PhotoList({
|
|||
});
|
||||
};
|
||||
|
||||
const isSameDay = (first, second) => {
|
||||
return (
|
||||
first.getFullYear() === second.getFullYear() &&
|
||||
first.getMonth() === second.getMonth() &&
|
||||
first.getDate() === second.getDate()
|
||||
);
|
||||
};
|
||||
|
||||
const getPhotoListHeader = (photoListHeader) => {
|
||||
return {
|
||||
...photoListHeader,
|
||||
|
@ -722,6 +720,62 @@ export function PhotoList({
|
|||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const notSelectedFiles = displayFiles?.filter(
|
||||
(item) => !galleryContext.selectedFile[item.id]
|
||||
);
|
||||
const unselectedDates = [
|
||||
...new Set(notSelectedFiles?.map((item) => getDate(item))), // to get file's date which were manually unselected
|
||||
];
|
||||
|
||||
const localSelectedFiles = displayFiles.filter(
|
||||
// to get files which were manually selected
|
||||
(item) => !unselectedDates.includes(getDate(item))
|
||||
);
|
||||
|
||||
const localSelectedDates = [
|
||||
...new Set(localSelectedFiles?.map((item) => getDate(item))),
|
||||
]; // to get file's date which were manually selected
|
||||
|
||||
unselectedDates.forEach((date) => {
|
||||
setCheckedDates((prev) => ({
|
||||
...prev,
|
||||
[date]: false,
|
||||
})); // To uncheck select all checkbox if any of the file on the date is unselected
|
||||
});
|
||||
|
||||
localSelectedDates.map((date) => {
|
||||
setCheckedDates((prev) => ({
|
||||
...prev,
|
||||
[date]: true,
|
||||
}));
|
||||
// To check select all checkbox if all of the files on the date is selected manually
|
||||
});
|
||||
}, [galleryContext.selectedFile]);
|
||||
|
||||
const handleSelect = handleSelectCreator(
|
||||
galleryContext.setSelectedFiles,
|
||||
activeCollectionID
|
||||
);
|
||||
|
||||
const onChangeSelectAllCheckBox = (date: string) => {
|
||||
const dates = { ...checkedDates, [date]: !checkedDates[date] };
|
||||
const isDateSelected = !checkedDates[date];
|
||||
|
||||
setCheckedDates(dates);
|
||||
|
||||
const filesOnADay = displayFiles?.filter(
|
||||
(item) => getDate(item) === date
|
||||
); // all files on a checked/unchecked day
|
||||
|
||||
filesOnADay.forEach((file) => {
|
||||
handleSelect(
|
||||
file.id,
|
||||
file.ownerID === galleryContext?.user?.id
|
||||
)(isDateSelected);
|
||||
});
|
||||
};
|
||||
|
||||
const renderListItem = (
|
||||
listItem: TimeStampListItem,
|
||||
isScrolling: boolean,
|
||||
|
@ -733,6 +787,15 @@ export function PhotoList({
|
|||
.map((item) => [
|
||||
<DateContainer key={item.date} span={item.span}>
|
||||
{item.date}
|
||||
<SelectAllCheckBoxContainer
|
||||
key={item.date}
|
||||
name={item.date}
|
||||
checked={checkedDates[item.date]}
|
||||
onChange={() =>
|
||||
onChangeSelectAllCheckBox(item.date)
|
||||
}
|
||||
margin={columns}
|
||||
/>
|
||||
</DateContainer>,
|
||||
<div key={`${item.date}-gap`} />,
|
||||
])
|
||||
|
@ -740,6 +803,15 @@ export function PhotoList({
|
|||
) : (
|
||||
<DateContainer span={columns}>
|
||||
{listItem.date}
|
||||
<SelectAllCheckBoxContainer
|
||||
key={listItem.date}
|
||||
name={listItem.date}
|
||||
checked={checkedDates[listItem.date]}
|
||||
onChange={() =>
|
||||
onChangeSelectAllCheckBox(listItem.date)
|
||||
}
|
||||
margin={columns}
|
||||
/>
|
||||
</DateContainer>
|
||||
);
|
||||
case ITEM_TYPE.SIZE_AND_COUNT:
|
||||
|
|
|
@ -163,6 +163,8 @@ const defaultGalleryContext: GalleryContextType = {
|
|||
emailList: null,
|
||||
openHiddenSection: () => null,
|
||||
isClipSearchResult: null,
|
||||
selectedFile: null,
|
||||
setSelectedFiles: () => null,
|
||||
};
|
||||
|
||||
export const GalleryContext = createContext<GalleryContextType>(
|
||||
|
@ -1013,8 +1015,9 @@ export default function Gallery() {
|
|||
emailList,
|
||||
openHiddenSection,
|
||||
isClipSearchResult,
|
||||
}}
|
||||
>
|
||||
selectedFile: selected,
|
||||
setSelectedFiles: setSelected,
|
||||
}}>
|
||||
<FullScreenDropZone
|
||||
getDragAndDropRootProps={getDragAndDropRootProps}
|
||||
>
|
||||
|
|
|
@ -11,6 +11,9 @@ export type SelectedState = {
|
|||
count: number;
|
||||
collectionID: number;
|
||||
};
|
||||
export type SetSelectedState = React.Dispatch<
|
||||
React.SetStateAction<SelectedState>
|
||||
>;
|
||||
export type SetFiles = React.Dispatch<React.SetStateAction<EnteFile[]>>;
|
||||
export type SetCollections = React.Dispatch<React.SetStateAction<Collection[]>>;
|
||||
export type SetLoading = React.Dispatch<React.SetStateAction<boolean>>;
|
||||
|
@ -54,6 +57,8 @@ export type GalleryContextType = {
|
|||
emailList: string[];
|
||||
openHiddenSection: (callback?: () => void) => void;
|
||||
isClipSearchResult: boolean;
|
||||
setSelectedFiles: (value) => void;
|
||||
selectedFile: SelectedState;
|
||||
};
|
||||
|
||||
export enum CollectionSelectorIntent {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { logError } from "@ente/shared/sentry";
|
||||
import { FILE_TYPE } from "constants/file";
|
||||
import { LivePhotoSourceURL, SourceURLs } from "services/download";
|
||||
import { EnteFile } from "types/file";
|
||||
import { logError } from "@ente/shared/sentry";
|
||||
import { LivePhotoSourceURL, SourceURLs } from "services/download";
|
||||
import { SetSelectedState } from "types/gallery";
|
||||
|
||||
const WAIT_FOR_VIDEO_PLAYBACK = 1 * 1000;
|
||||
|
||||
|
@ -129,3 +130,55 @@ export async function updateFileSrcProps(
|
|||
file.src = url as string;
|
||||
}
|
||||
}
|
||||
|
||||
export const handleSelectCreator =
|
||||
(
|
||||
setSelected: SetSelectedState,
|
||||
activeCollectionID: number,
|
||||
setRangeStart?
|
||||
) =>
|
||||
(id: number, isOwnFile: boolean, index?: number) =>
|
||||
(checked: boolean) => {
|
||||
if (typeof index !== 'undefined') {
|
||||
if (checked) {
|
||||
setRangeStart(index);
|
||||
} else {
|
||||
setRangeStart(undefined);
|
||||
}
|
||||
}
|
||||
setSelected((selected) => {
|
||||
if (selected.collectionID !== activeCollectionID) {
|
||||
selected = { ownCount: 0, count: 0, collectionID: 0 };
|
||||
}
|
||||
|
||||
const handleCounterChange = (count: number) => {
|
||||
if (selected[id] === checked) {
|
||||
return count;
|
||||
}
|
||||
if (checked) {
|
||||
return count + 1;
|
||||
} else {
|
||||
return count - 1;
|
||||
}
|
||||
};
|
||||
|
||||
const handleAllCounterChange = () => {
|
||||
if (isOwnFile) {
|
||||
return {
|
||||
ownCount: handleCounterChange(selected.ownCount),
|
||||
count: handleCounterChange(selected.count),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
count: handleCounterChange(selected.count),
|
||||
};
|
||||
}
|
||||
};
|
||||
return {
|
||||
...selected,
|
||||
[id]: checked,
|
||||
collectionID: activeCollectionID,
|
||||
...handleAllCounterChange(),
|
||||
};
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import i18n, { t } from "i18next";
|
||||
|
||||
const A_DAY = 24 * 60 * 60 * 1000;
|
||||
|
||||
const dateTimeFullFormatter1 = new Intl.DateTimeFormat(i18n.language, {
|
||||
weekday: "short",
|
||||
month: "short",
|
||||
|
@ -76,3 +78,22 @@ export function formatDateRelative(date: number) {
|
|||
u as Intl.RelativeTimeFormatUnit,
|
||||
);
|
||||
}
|
||||
|
||||
export const isSameDay = (first, second) => {
|
||||
return (
|
||||
first.getFullYear() === second.getFullYear() &&
|
||||
first.getMonth() === second.getMonth() &&
|
||||
first.getDate() === second.getDate()
|
||||
);
|
||||
};
|
||||
|
||||
export const getDate = (item) => {
|
||||
const currentDate = item.metadata.creationTime / 1000;
|
||||
const date = isSameDay(new Date(currentDate), new Date())
|
||||
? t('TODAY')
|
||||
: isSameDay(new Date(currentDate), new Date(Date.now() - A_DAY))
|
||||
? t('YESTERDAY')
|
||||
: formatDate(currentDate);
|
||||
|
||||
return date;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue