Merge pull request #906 from ente-io/uncategorised

Uncategorised
This commit is contained in:
Abhinav Kumar 2023-02-03 11:51:19 +05:30 committed by GitHub
commit 2173484e1d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 313 additions and 104 deletions

View file

@ -10,9 +10,13 @@ interface Iprops {
action: CollectionActions,
loader?: boolean
) => (...args: any[]) => Promise<void>;
downloadOptionText?: string;
}
export function FavoritiesCollectionOption({ handleCollectionAction }: Iprops) {
export function OnlyDownloadCollectionOption({
handleCollectionAction,
downloadOptionText = constants.DOWNLOAD,
}: Iprops) {
return (
<OverflowMenuOption
startIcon={<FileDownloadOutlinedIcon />}
@ -20,7 +24,7 @@ export function FavoritiesCollectionOption({ handleCollectionAction }: Iprops) {
CollectionActions.CONFIRM_DOWNLOAD,
false
)}>
{constants.DOWNLOAD_COLLECTION}
{downloadOptionText}
</OverflowMenuOption>
);
}

View file

@ -25,6 +25,7 @@ export function QuickOptions({
{!(
collectionSummaryType === CollectionSummaryType.trash ||
collectionSummaryType === CollectionSummaryType.favorites ||
collectionSummaryType === CollectionSummaryType.uncategorized ||
collectionSummaryType === CollectionSummaryType.incomingShare
) && (
<Tooltip
@ -51,7 +52,10 @@ export function QuickOptions({
title={
collectionSummaryType ===
CollectionSummaryType.favorites
? constants.DOWNLOAD_FAVOURITES
? constants.DOWNLOAD_FAVORITES
: collectionSummaryType ===
CollectionSummaryType.uncategorized
? constants.DOWNLOAD_UNCATEGORIZED
: constants.DOWNLOAD_COLLECTION
}>
<IconButton

View file

@ -18,7 +18,7 @@ import OverflowMenu from 'components/OverflowMenu/menu';
import { CollectionSummaryType } from 'constants/collection';
import { TrashCollectionOption } from './TrashCollectionOption';
import { SharedCollectionOption } from './SharedCollectionOption';
import { FavoritiesCollectionOption } from './FavoritiesCollectionOption';
import { OnlyDownloadCollectionOption } from './OnlyDownloadCollectionOption';
import { QuickOptions } from './QuickOptions';
import MoreHoriz from '@mui/icons-material/MoreHoriz';
import { HorizontalFlex } from 'components/Container';
@ -39,7 +39,8 @@ export enum CollectionActions {
ARCHIVE,
UNARCHIVE,
CONFIRM_DELETE,
DELETE,
DELETE_WITH_FILES,
DELETE_BUT_KEEP_FILES,
SHOW_SHARE_DIALOG,
CONFIRM_EMPTY_TRASH,
EMPTY_TRASH,
@ -87,8 +88,11 @@ const CollectionOptions = (props: CollectionOptionsProps) => {
case CollectionActions.CONFIRM_DELETE:
callback = confirmDeleteCollection;
break;
case CollectionActions.DELETE:
callback = deleteCollection;
case CollectionActions.DELETE_WITH_FILES:
callback = deleteCollectionAlongWithFiles;
break;
case CollectionActions.DELETE_BUT_KEEP_FILES:
callback = deleteCollectionButKeepFiles;
break;
case CollectionActions.SHOW_SHARE_DIALOG:
callback = showCollectionShareModal;
@ -137,8 +141,13 @@ const CollectionOptions = (props: CollectionOptionsProps) => {
}
};
const deleteCollection = async () => {
await CollectionAPI.deleteCollection(activeCollection.id);
const deleteCollectionAlongWithFiles = async () => {
await CollectionAPI.deleteCollection(activeCollection.id, false);
redirectToAll();
};
const deleteCollectionButKeepFiles = async () => {
await CollectionAPI.deleteCollection(activeCollection.id, true);
redirectToAll();
};
@ -177,12 +186,21 @@ const CollectionOptions = (props: CollectionOptionsProps) => {
const confirmDeleteCollection = () => {
setDialogMessage({
title: constants.DELETE_COLLECTION_TITLE,
content: constants.DELETE_COLLECTION_MESSAGE,
content: constants.DELETE_COLLECTION_MESSAGE(),
proceed: {
text: constants.DELETE_COLLECTION,
action: handleCollectionAction(CollectionActions.DELETE),
text: constants.DELETE_PHOTOS,
action: handleCollectionAction(
CollectionActions.DELETE_WITH_FILES
),
variant: 'danger',
},
secondary: {
text: constants.KEEP_PHOTOS,
action: handleCollectionAction(
CollectionActions.DELETE_BUT_KEEP_FILES
),
variant: 'primary',
},
close: {
text: constants.CANCEL,
},
@ -250,8 +268,15 @@ const CollectionOptions = (props: CollectionOptionsProps) => {
/>
) : collectionSummaryType ===
CollectionSummaryType.favorites ? (
<FavoritiesCollectionOption
<OnlyDownloadCollectionOption
handleCollectionAction={handleCollectionAction}
downloadOptionText={constants.DOWNLOAD_FAVORITES}
/>
) : collectionSummaryType ===
CollectionSummaryType.uncategorized ? (
<OnlyDownloadCollectionOption
handleCollectionAction={handleCollectionAction}
downloadOptionText={constants.DOWNLOAD_UNCATEGORIZED}
/>
) : collectionSummaryType ===
CollectionSummaryType.incomingShare ? (

View file

@ -96,6 +96,18 @@ export default function DialogBox({
{attributes.proceed.text}
</Button>
)}
{attributes.secondary && (
<Button
size="large"
color={attributes.secondary?.variant}
onClick={() => {
attributes.secondary.action();
onClose();
}}
disabled={attributes.secondary.disabled}>
{attributes.secondary.text}
</Button>
)}
</>
</DialogActions>
)}

View file

@ -31,7 +31,7 @@ export function OverflowMenuOption({
<MenuItem
onClick={handleClick}
sx={{
width: 220,
minWidth: 220,
color: (theme) => theme.palette[color].main,
padding: 1.5,
'& .MuiSvgIcon-root': {

View file

@ -66,7 +66,7 @@ interface Props {
deletedFileIds?: Set<number>;
setDeletedFileIds?: (value: Set<number>) => void;
activeCollection: number;
isSharedCollection?: boolean;
isIncomingSharedCollection?: boolean;
enableDownload?: boolean;
isDeduplicating?: boolean;
resetSearch?: () => void;
@ -95,7 +95,7 @@ const PhotoFrame = ({
deletedFileIds,
setDeletedFileIds,
activeCollection,
isSharedCollection,
isIncomingSharedCollection,
enableDownload,
isDeduplicating,
}: Props) => {
@ -179,7 +179,10 @@ const PhotoFrame = ({
return false;
}
if (isSharedFile(user, item) && !isSharedCollection) {
if (
isSharedFile(user, item) &&
!isIncomingSharedCollection
) {
return false;
}
if (activeCollection === TRASH_SECTION && !item.isTrashed) {
@ -501,7 +504,7 @@ const PhotoFrame = ({
file={files[index]}
updateURL={updateURL(files[index].id)}
onClick={onThumbnailClick(index)}
selectable={!isSharedCollection}
selectable={!isIncomingSharedCollection}
onSelect={handleSelect(files[index].id, index)}
selected={
selected.collectionID === activeCollection &&
@ -683,7 +686,10 @@ const PhotoFrame = ({
return (
<>
{!isFirstLoad && files.length === 0 && !isInSearchMode ? (
{!isFirstLoad &&
files.length === 0 &&
!isInSearchMode &&
activeCollection === ALL_SECTION ? (
<EmptyScreen openUploader={openUploader} />
) : (
<Container>
@ -713,7 +719,7 @@ const PhotoFrame = ({
favItemIds={favItemIds}
deletedFileIds={deletedFileIds}
setDeletedFileIds={setDeletedFileIds}
isSharedCollection={isSharedCollection}
isIncomingSharedCollection={isIncomingSharedCollection}
isTrashCollection={activeCollection === TRASH_SECTION}
enableDownload={enableDownload}
isSourceLoaded={isSourceLoaded}

View file

@ -68,7 +68,7 @@ interface Iprops {
favItemIds: Set<number>;
deletedFileIds: Set<number>;
setDeletedFileIds?: (value: Set<number>) => void;
isSharedCollection: boolean;
isIncomingSharedCollection: boolean;
isTrashCollection: boolean;
enableDownload: boolean;
isSourceLoaded: boolean;
@ -393,7 +393,11 @@ function PhotoViewer(props: Iprops) {
};
const confirmTrashFile = (file: EnteFile) => {
if (!file || props.isSharedCollection || props.isTrashCollection) {
if (
!file ||
props.isIncomingSharedCollection ||
props.isTrashCollection
) {
return;
}
appContext.setDialogMessage(getTrashFileMessage(() => trashFile(file)));
@ -571,7 +575,7 @@ function PhotoViewer(props: Iprops) {
<ContentCopy fontSize="small" />
</button>
)}
{!props.isSharedCollection &&
{!props.isIncomingSharedCollection &&
!props.isTrashCollection && (
<button
className="pswp__button pswp__button--custom"
@ -593,7 +597,7 @@ function PhotoViewer(props: Iprops) {
title={constants.TOGGLE_FULLSCREEN}
/>
{!props.isSharedCollection && (
{!props.isIncomingSharedCollection && (
<button
className="pswp__button pswp__button--custom"
title={constants.INFO_OPTION}
@ -601,7 +605,7 @@ function PhotoViewer(props: Iprops) {
<InfoIcon fontSize="small" />
</button>
)}
{!props.isSharedCollection &&
{!props.isIncomingSharedCollection &&
!props.isTrashCollection && (
<button
title={
@ -652,7 +656,7 @@ function PhotoViewer(props: Iprops) {
</div>
<FileInfo
isTrashCollection={props.isTrashCollection}
shouldDisableEdits={props.isSharedCollection}
shouldDisableEdits={props.isIncomingSharedCollection}
showInfo={showInfo}
handleCloseInfo={handleCloseInfo}
file={photoSwipe?.currItem as EnteFile}

View file

@ -20,12 +20,11 @@ const ShortcutButton: FC<ButtonProps<'button', Iprops>> = ({
sx={{ fontWeight: 'normal' }}
{...props}>
{label}
{count > 0 && (
<Box sx={{ color: 'text.secondary' }}>
<DotSeparator />
{count}
</Box>
)}
<Box sx={{ color: 'text.secondary' }}>
<DotSeparator />
{count}
</Box>
</SidebarButton>
);
};

View file

@ -1,11 +1,17 @@
import React, { useContext } from 'react';
import React, { useContext, useState, useEffect } from 'react';
import constants from 'utils/strings/constants';
import { GalleryContext } from 'pages/gallery';
import { ARCHIVE_SECTION, TRASH_SECTION } from 'constants/collection';
import {
ARCHIVE_SECTION,
DUMMY_UNCATEGORIZED_SECTION,
TRASH_SECTION,
} from 'constants/collection';
import { CollectionSummaries } from 'types/collection';
import ShortcutButton from './ShortcutButton';
import DeleteOutline from '@mui/icons-material/DeleteOutline';
import ArchiveOutlined from '@mui/icons-material/ArchiveOutlined';
import CategoryIcon from '@mui/icons-material/Category';
import { getUncategorizedCollection } from 'services/collectionService';
interface Iprops {
closeSidebar: () => void;
collectionSummaries: CollectionSummaries;
@ -16,6 +22,24 @@ export default function ShortcutSection({
collectionSummaries,
}: Iprops) {
const galleryContext = useContext(GalleryContext);
const [uncategorizedCollectionId, setUncategorizedCollectionID] =
useState<number>();
useEffect(() => {
const main = async () => {
const unCategorizedCollection = await getUncategorizedCollection();
if (unCategorizedCollection) {
setUncategorizedCollectionID(unCategorizedCollection.id);
} else {
setUncategorizedCollectionID(DUMMY_UNCATEGORIZED_SECTION);
}
};
main();
}, []);
const openUncategorizedSection = () => {
galleryContext.setActiveCollection(uncategorizedCollectionId);
closeSidebar();
};
const openTrashSection = () => {
galleryContext.setActiveCollection(TRASH_SECTION);
@ -26,9 +50,17 @@ export default function ShortcutSection({
galleryContext.setActiveCollection(ARCHIVE_SECTION);
closeSidebar();
};
return (
<>
<ShortcutButton
startIcon={<CategoryIcon />}
label={constants.UNCATEGORIZED}
onClick={openUncategorizedSection}
count={
collectionSummaries.get(uncategorizedCollectionId)
?.fileCount
}
/>
<ShortcutButton
startIcon={<DeleteOutline />}
label={constants.TRASH}

View file

@ -40,6 +40,7 @@ interface Props {
unArchiveFilesHelper: () => void;
activeCollection: number;
isFavoriteCollection: boolean;
isUncategorizedCollection: boolean;
}
const SelectedFileOptions = ({
@ -58,6 +59,7 @@ const SelectedFileOptions = ({
unArchiveFilesHelper,
activeCollection,
isFavoriteCollection,
isUncategorizedCollection,
}: Props) => {
const { setDialogMessage } = useContext(AppContext);
const addToCollection = () =>
@ -94,13 +96,13 @@ const SelectedFileOptions = ({
const removeFromCollectionHandler = () =>
setDialogMessage({
title: constants.CONFIRM_REMOVE,
title: constants.REMOVE_FROM_COLLECTION,
content: constants.CONFIRM_REMOVE_MESSAGE(),
proceed: {
action: removeFromCollectionHelper,
text: constants.REMOVE,
variant: 'danger',
text: constants.YES_REMOVE,
variant: 'primary',
},
close: { text: constants.CANCEL },
});
@ -138,6 +140,19 @@ const SelectedFileOptions = ({
</IconButton>
</Tooltip>
</>
) : isUncategorizedCollection ? (
<>
<Tooltip title={constants.MOVE}>
<IconButton onClick={moveToCollection}>
<MoveIcon />
</IconButton>
</Tooltip>
<Tooltip title={constants.DELETE}>
<IconButton onClick={trashHandler}>
<DeleteIcon />
</IconButton>
</Tooltip>
</>
) : (
<>
<Tooltip title={constants.FIX_CREATION_TIME}>

View file

@ -1,11 +1,12 @@
export const ARCHIVE_SECTION = -1;
export const TRASH_SECTION = -2;
export const DUMMY_UNCATEGORIZED_SECTION = -3;
export const ALL_SECTION = 0;
export enum CollectionType {
folder = 'folder',
favorites = 'favorites',
album = 'album',
uncategorized = 'uncategorized',
}
export enum CollectionSummaryType {
@ -14,6 +15,7 @@ export enum CollectionSummaryType {
album = 'album',
archive = 'archive',
trash = 'trash',
uncategorized = 'uncategorized',
all = 'all',
outgoingShare = 'outgoingShare',
incomingShare = 'incomingShare',
@ -26,6 +28,9 @@ export enum COLLECTION_SORT_BY {
UPDATION_TIME_DESCENDING,
}
export const UNCATEGORIZED_COLLECTION_NAME = 'Uncategorized';
export const FAVORITE_COLLECTION_NAME = 'Favorites';
export const COLLECTION_SHARE_DEFAULT_VALID_DURATION =
10 * 24 * 60 * 60 * 1000 * 1000;
export const COLLECTION_SHARE_DEFAULT_DEVICE_LIMIT = 4;
@ -41,12 +46,14 @@ export const COLLECTION_SORT_ORDER = new Map([
[CollectionSummaryType.archived, 2],
[CollectionSummaryType.archive, 3],
[CollectionSummaryType.trash, 4],
[CollectionSummaryType.uncategorized, 4],
]);
export const SYSTEM_COLLECTION_TYPES = new Set([
CollectionSummaryType.all,
CollectionSummaryType.archive,
CollectionSummaryType.trash,
CollectionSummaryType.uncategorized,
]);
export const UPLOAD_NOT_ALLOWED_COLLECTION_TYPES = new Set([
@ -54,6 +61,7 @@ export const UPLOAD_NOT_ALLOWED_COLLECTION_TYPES = new Set([
CollectionSummaryType.archive,
CollectionSummaryType.incomingShare,
CollectionSummaryType.trash,
CollectionSummaryType.uncategorized,
]);
export const OPTIONS_NOT_HAVING_COLLECTION_TYPES = new Set([
@ -64,4 +72,5 @@ export const OPTIONS_NOT_HAVING_COLLECTION_TYPES = new Set([
export const HIDE_FROM_COLLECTION_BAR_TYPES = new Set([
CollectionSummaryType.trash,
CollectionSummaryType.archive,
CollectionSummaryType.uncategorized,
]);

View file

@ -60,18 +60,19 @@ import Uploader from 'components/Upload/Uploader';
import {
ALL_SECTION,
ARCHIVE_SECTION,
CollectionSummaryType,
CollectionType,
DUMMY_UNCATEGORIZED_SECTION,
TRASH_SECTION,
UNCATEGORIZED_COLLECTION_NAME,
} from 'constants/collection';
import { AppContext } from 'pages/_app';
import { CustomError, ServerErrorCodes } from 'utils/error';
import { PAGES } from 'constants/pages';
import {
COLLECTION_OPS_TYPE,
isSharedCollection,
handleCollectionOps,
getSelectedCollection,
isFavoriteCollection,
getArchivedCollections,
hasNonSystemCollections,
} from 'utils/collection';
@ -326,6 +327,8 @@ export default function Gallery() {
collectionURL += constants.ARCHIVE;
} else if (activeCollection === TRASH_SECTION) {
collectionURL += constants.TRASH;
} else if (activeCollection === DUMMY_UNCATEGORIZED_SECTION) {
collectionURL += UNCATEGORIZED_COLLECTION_NAME;
} else {
collectionURL += activeCollection;
}
@ -408,7 +411,7 @@ export default function Gallery() {
const archivedCollections = getArchivedCollections(collections);
setArchivedCollections(archivedCollections);
const collectionSummaries = getCollectionSummaries(
const collectionSummaries = await getCollectionSummaries(
user,
collections,
files,
@ -724,10 +727,10 @@ export default function Gallery() {
deletedFileIds={deletedFileIds}
setDeletedFileIds={setDeletedFileIds}
activeCollection={activeCollection}
isSharedCollection={isSharedCollection(
activeCollection,
collections
)}
isIncomingSharedCollection={
collectionSummaries.get(activeCollection)?.type ===
CollectionSummaryType.incomingShare
}
enableDownload={true}
resetSearch={resetSearch}
/>
@ -773,10 +776,15 @@ export default function Gallery() {
count={selected.count}
clearSelection={clearSelection}
activeCollection={activeCollection}
isFavoriteCollection={isFavoriteCollection(
activeCollection,
collections
)}
isFavoriteCollection={
collectionSummaries.get(activeCollection)
?.type === CollectionSummaryType.favorites
}
isUncategorizedCollection={
collectionSummaries.get(activeCollection)
?.type ===
CollectionSummaryType.uncategorized
}
/>
)}
</FullScreenDropZone>

View file

@ -410,7 +410,7 @@ export default function PublicCollectionGallery() {
selected={{ count: 0, collectionID: null }}
isFirstLoad={true}
activeCollection={ALL_SECTION}
isSharedCollection
isIncomingSharedCollection
enableDownload={
publicCollection?.publicURLs?.[0]?.enableDownload ??
true

View file

@ -19,7 +19,6 @@ import {
AddToCollectionRequest,
MoveToCollectionRequest,
EncryptedFileKey,
RemoveFromCollectionRequest,
CreatePublicAccessTokenRequest,
PublicURL,
UpdatePublicURL,
@ -38,6 +37,9 @@ import {
COLLECTION_SORT_ORDER,
ALL_SECTION,
CollectionSummaryType,
UNCATEGORIZED_COLLECTION_NAME,
FAVORITE_COLLECTION_NAME,
DUMMY_UNCATEGORIZED_SECTION,
} from 'constants/collection';
import {
NEW_COLLECTION_MAGIC_METADATA,
@ -55,6 +57,7 @@ import {
isSharedOnlyViaLink,
} from 'utils/collection';
import ComlinkCryptoWorker from 'utils/comlink/ComlinkCryptoWorker';
import { getLocalFiles } from './fileService';
const ENDPOINT = getEndpoint();
const COLLECTION_TABLE = 'collections';
@ -359,7 +362,7 @@ export const addToFavorites = async (file: EnteFile) => {
let favCollection = await getFavCollection();
if (!favCollection) {
favCollection = await createCollection(
'Favorites',
FAVORITE_COLLECTION_NAME,
CollectionType.favorites
);
const localCollections = await getLocalCollections();
@ -492,20 +495,60 @@ const encryptWithNewCollectionKey = async (
};
export const removeFromCollection = async (
collectionID: number,
files: EnteFile[]
toRemoveFiles: EnteFile[],
allFiles?: EnteFile[]
) => {
try {
const token = getToken();
const request: RemoveFromCollectionRequest = {
collectionID: collectionID,
fileIDs: files.map((file) => file.id),
};
if (!allFiles) {
allFiles = await getLocalFiles();
}
await HTTPService.post(
`${ENDPOINT}/collections/v2/remove-files`,
request,
null,
{ 'X-Auth-Token': token }
const toRemoveFilesIds = new Set(toRemoveFiles.map((f) => f.id));
const toRemoveFilesCopiesInOtherCollections = allFiles.filter((f) => {
if (f.collectionID === collectionID) {
return false;
}
return toRemoveFilesIds.has(f.id);
});
const groupiedFiles = groupFilesBasedOnCollectionID(
toRemoveFilesCopiesInOtherCollections
);
const collections = await getLocalCollections();
const collectionsMap = new Map(collections.map((c) => [c.id, c]));
for (const [toMoveCollectionID, files] of groupiedFiles.entries()) {
const toMoveFiles = files.filter((f) => {
if (toRemoveFilesIds.has(f.id)) {
toRemoveFilesIds.delete(f.id);
return true;
}
return false;
});
if (toMoveFiles.length === 0) {
continue;
}
await moveToCollection(
collectionsMap.get(toMoveCollectionID),
collectionID,
toMoveFiles
);
}
const leftFiles = toRemoveFiles.filter((f) =>
toRemoveFilesIds.has(f.id)
);
if (leftFiles.length === 0) {
return;
}
let uncategorizedCollection = await getUncategorizedCollection();
if (!uncategorizedCollection) {
uncategorizedCollection = await createUnCategorizedCollection();
}
await moveToCollection(
uncategorizedCollection,
collectionID,
leftFiles
);
} catch (e) {
logError(e, 'remove from collection failed ');
@ -513,14 +556,24 @@ export const removeFromCollection = async (
}
};
export const deleteCollection = async (collectionID: number) => {
export const deleteCollection = async (
collectionID: number,
keepFiles: boolean
) => {
try {
if (keepFiles) {
const allFiles = await getLocalFiles();
const collectionFiles = allFiles.filter((file) => {
return file.collectionID === collectionID;
});
await removeFromCollection(collectionID, collectionFiles, allFiles);
}
const token = getToken();
await HTTPService.delete(
`${ENDPOINT}/collections/v2/${collectionID}`,
null,
`${ENDPOINT}/collections/v3/${collectionID}`,
null,
{ collectionID, keepFiles },
{ 'X-Auth-Token': token }
);
} catch (e) {
@ -817,12 +870,12 @@ function compareCollectionsLatestFile(first: EnteFile, second: EnteFile) {
}
}
export function getCollectionSummaries(
export async function getCollectionSummaries(
user: User,
collections: Collection[],
files: EnteFile[],
archivedCollections: Set<number>
): CollectionSummaries {
): Promise<CollectionSummaries> {
const collectionSummaries: CollectionSummaries = new Map();
const collectionLatestFiles = getCollectionLatestFiles(
files,
@ -834,12 +887,15 @@ export function getCollectionSummaries(
);
for (const collection of collections) {
if (collectionFilesCount.get(collection.id)) {
if (
collectionFilesCount.get(collection.id) ||
collection.type === CollectionType.uncategorized
) {
collectionSummaries.set(collection.id, {
id: collection.id,
name: collection.name,
latestFile: collectionLatestFiles.get(collection.id),
fileCount: collectionFilesCount.get(collection.id),
fileCount: collectionFilesCount.get(collection.id) ?? 0,
updationTime: collection.updationTime,
type: isIncomingShare(collection, user)
? CollectionSummaryType.incomingShare
@ -853,6 +909,16 @@ export function getCollectionSummaries(
});
}
}
const uncategorizedCollection = await getUncategorizedCollection(
collections
);
if (!uncategorizedCollection) {
collectionSummaries.set(
DUMMY_UNCATEGORIZED_SECTION,
getDummyUncategorizedCollectionSummaries()
);
}
collectionSummaries.set(
ALL_SECTION,
getAllCollectionSummaries(collectionFilesCount, collectionLatestFiles)
@ -920,6 +986,17 @@ function getAllCollectionSummaries(
};
}
function getDummyUncategorizedCollectionSummaries(): CollectionSummary {
return {
id: ALL_SECTION,
name: UNCATEGORIZED_COLLECTION_NAME,
type: CollectionSummaryType.uncategorized,
latestFile: null,
fileCount: 0,
updationTime: 0,
};
}
function getArchivedCollectionSummaries(
collectionFilesCount: CollectionFilesCount,
collectionsLatestFile: CollectionLatestFiles
@ -947,3 +1024,23 @@ function getTrashedCollectionSummaries(
updationTime: collectionsLatestFile.get(TRASH_SECTION)?.updationTime,
};
}
export async function getUncategorizedCollection(
collections?: Collection[]
): Promise<Collection> {
if (!collections) {
collections = await getLocalCollections();
}
const uncategorizedCollection = collections.find(
(collection) => collection.type === CollectionType.uncategorized
);
return uncategorizedCollection;
}
export async function createUnCategorizedCollection() {
return createCollection(
UNCATEGORIZED_COLLECTION_NAME,
CollectionType.uncategorized
);
}

View file

@ -37,7 +37,6 @@ export interface Collection
> {
key: string;
name: string;
isSharedCollection?: boolean;
magicMetadata: CollectionMagicMetadata;
}

View file

@ -17,6 +17,12 @@ export interface DialogBoxAttributes {
variant: ButtonProps['color'];
disabled?: boolean;
};
secondary?: {
text: string;
action: () => void;
variant: ButtonProps['color'];
disabled?: boolean;
};
}
export type SetDialogBoxAttributes = React.Dispatch<

View file

@ -20,7 +20,6 @@ import {
} from 'types/collection';
import {
CollectionSummaryType,
CollectionType,
HIDE_FROM_COLLECTION_BAR_TYPES,
OPTIONS_NOT_HAVING_COLLECTION_TYPES,
SYSTEM_COLLECTION_TYPES,
@ -77,31 +76,6 @@ export function getSelectedCollection(
return collections.find((collection) => collection.id === collectionID);
}
export function isSharedCollection(
collectionID: number,
collections: Collection[]
) {
const user: User = getData(LS_KEYS.USER);
const collection = getSelectedCollection(collectionID, collections);
if (!collection) {
return false;
}
return collection?.owner.id !== user.id;
}
export function isFavoriteCollection(
collectionID: number,
collections: Collection[]
) {
const collection = getSelectedCollection(collectionID, collections);
if (!collection) {
return false;
} else {
return collection.type === CollectionType.favorites;
}
}
export async function downloadAllCollectionFiles(collectionID: number) {
try {
const allFiles = await getLocalFiles();
@ -204,7 +178,10 @@ export const getArchivedCollections = (collections: Collection[]) => {
export const hasNonSystemCollections = (
collectionSummaries: CollectionSummaries
) => {
return collectionSummaries?.size > 3;
for (const collectionSummary of collectionSummaries.values()) {
if (!isSystemCollection(collectionSummary.type)) return true;
}
return false;
};
export const isUploadAllowedCollection = (type: CollectionSummaryType) => {

View file

@ -140,7 +140,8 @@ const englishConstants = {
CREATE: 'Create',
DOWNLOAD: 'Download',
DOWNLOAD_OPTION: 'Download (D)',
DOWNLOAD_FAVOURITES: 'Download favourites',
DOWNLOAD_FAVORITES: 'Download favorites',
DOWNLOAD_UNCATEGORIZED: 'Download uncategorized',
COPY_OPTION: 'Copy as PNG (Ctrl/Cmd - C)',
TOGGLE_FULLSCREEN: 'Toggle fullscreen (F)',
ZOOM_IN_OUT: 'Zoom in/out',
@ -368,8 +369,15 @@ const englishConstants = {
DELETE_COLLECTION_TITLE: 'Delete album?',
DELETE_COLLECTION: 'Delete album',
DELETE_COLLECTION_FAILED: 'Album deletion failed, please try again',
DELETE_COLLECTION_MESSAGE:
'Files that are unique to this album will be moved to trash, and this album would be deleted.',
DELETE_COLLECTION_MESSAGE: () => (
<p>
Also delete the photos (and videos) present in this album from
<span style={{ color: '#fff' }}> all </span> other albums they are
part of?
</p>
),
DELETE_PHOTOS: 'Delete photos',
KEEP_PHOTOS: 'Keep photos',
SHARE: 'Share',
SHARE_COLLECTION: 'Share album',
SHARE_WITH_PEOPLE: 'Share with your loved ones',
@ -587,6 +595,8 @@ const englishConstants = {
THUMBNAIL_GENERATION_FAILED_INFO:
'These files were uploaded, but unfortunately we could not generate the thumbnails for them.',
UPLOAD_TO_COLLECTION: 'Upload to album',
UNCATEGORIZED: 'Uncategorized',
MOVE_TO_UNCATEGORIZED: 'Move to uncategorized',
ARCHIVE: 'Archive',
ARCHIVE_COLLECTION: 'Archive album',
ARCHIVE_SECTION_NAME: 'Archive',
@ -598,7 +608,9 @@ const englishConstants = {
ADD: 'Add',
SORT: 'Sort',
REMOVE: 'Remove',
YES_REMOVE: 'Yes, remove',
CONFIRM_REMOVE: 'Confirm removal',
REMOVE_FROM_COLLECTION: 'Remove from album',
TRASH: 'Trash',
MOVE_TO_TRASH: 'Move to trash',
TRASH_FILES_MESSAGE:
@ -622,9 +634,9 @@ const englishConstants = {
'You will leave the album, and it will stop being visible to you.',
CONFIRM_REMOVE_MESSAGE: () => (
<>
<p>Are you sure you want to remove these files from the album?</p>
<p>
All files that are unique to this album will be moved to trash
Selected items will be removed from this album. Items which are
only in this album will be moved to Uncategorized.
</p>
</>
),