Merge branch 'main' into continuous-sync

This commit is contained in:
Abhinav 2023-02-23 15:52:17 +05:30
commit 6224125732
14 changed files with 166 additions and 72 deletions

View file

@ -9,5 +9,5 @@ const buildPrettierCommand = (filenames) =>
`yarn prettier --write --ignore-unknown ${filenames.join(' ')}`; `yarn prettier --write --ignore-unknown ${filenames.join(' ')}`;
module.exports = { module.exports = {
'*.{js,jsx,ts,tsx}': [buildEslintCommand, buildPrettierCommand], 'src/**/*.{js,jsx,ts,tsx}': [buildEslintCommand, buildPrettierCommand],
}; };

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

View file

@ -1,21 +1,28 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { Button, styled, Typography } from '@mui/material'; import { Button, Stack, styled, Typography } from '@mui/material';
import constants from 'utils/strings/constants'; import constants from 'utils/strings/constants';
import { DeduplicateContext } from 'pages/deduplicate'; import { DeduplicateContext } from 'pages/deduplicate';
import VerticallyCentered from './Container'; import VerticallyCentered, { FlexWrapper } from './Container';
import { Box } from '@mui/material';
import uploadManager from 'services/upload/uploadManager'; import uploadManager from 'services/upload/uploadManager';
import AddPhotoAlternateIcon from '@mui/icons-material/AddPhotoAlternateOutlined';
import FolderIcon from '@mui/icons-material/FolderOutlined';
import { UploadTypeSelectorIntent } from 'types/gallery';
const Wrapper = styled(VerticallyCentered)` const Wrapper = styled(Box)`
& > svg { display: flex;
filter: drop-shadow(3px 3px 5px rgba(45, 194, 98, 0.5)); flex-direction: column;
} align-items: center;
text-align: center;
`;
const NonDraggableImage = styled('img')`
pointer-events: none;
`; `;
export default function EmptyScreen({ openUploader }) { export default function EmptyScreen({ openUploader }) {
const deduplicateContext = useContext(DeduplicateContext); const deduplicateContext = useContext(DeduplicateContext);
return ( return deduplicateContext.isOnDeduplicatePage ? (
<Wrapper> <VerticallyCentered>
{deduplicateContext.isOnDeduplicatePage ? (
<div <div
style={{ style={{
color: '#a6a6a6', color: '#a6a6a6',
@ -23,34 +30,74 @@ export default function EmptyScreen({ openUploader }) {
}}> }}>
{constants.NO_DUPLICATES_FOUND} {constants.NO_DUPLICATES_FOUND}
</div> </div>
</VerticallyCentered>
) : ( ) : (
<> <Wrapper>
<img <Stack
height={150} sx={{
src="/images/gallery-locked/1x.png" flex: 'none',
srcSet="/images/gallery-locked/2x.png 2x, pt: 1.5,
/images/gallery-locked/3x.png 3x" pb: 1.5,
/> }}>
<Typography color="text.secondary" mt={2}> <VerticallyCentered sx={{ flex: 'none' }}>
{constants.UPLOAD_FIRST_PHOTO_DESCRIPTION()} {constants.WELCOME_TO_ENTE()}
</VerticallyCentered>
<Typography variant="body1" mt={3.5} color="text.secondary">
{constants.WHERE_YOUR_BEST_PHOTOS_LIVE}
</Typography> </Typography>
</Stack>
<NonDraggableImage
height={287.57}
src="/images/empty-state/ente_duck.png"
srcSet="/images/empty-state/ente_duck@2x.png,
/images/empty-state/ente_duck@3x.png"
/>
<span <VerticallyCentered paddingTop={1.5} paddingBottom={1.5}>
<Button
style={{ style={{
cursor: cursor:
!uploadManager.shouldAllowNewUpload() && !uploadManager.shouldAllowNewUpload() &&
'not-allowed', 'not-allowed',
}}> }}
<Button
color="accent" color="accent"
onClick={openUploader} onClick={() =>
openUploader(UploadTypeSelectorIntent.normalUpload)
}
disabled={!uploadManager.shouldAllowNewUpload()} disabled={!uploadManager.shouldAllowNewUpload()}
sx={{ mt: 4 }}> sx={{
mt: 1.5,
p: 1,
width: 320,
borderRadius: 0.5,
}}>
<FlexWrapper sx={{ gap: 1 }} justifyContent="center">
<AddPhotoAlternateIcon />
{constants.UPLOAD_FIRST_PHOTO} {constants.UPLOAD_FIRST_PHOTO}
</FlexWrapper>
</Button> </Button>
</span> <Button
</> style={{
)} cursor:
!uploadManager.shouldAllowNewUpload() &&
'not-allowed',
}}
onClick={() =>
openUploader(UploadTypeSelectorIntent.import)
}
disabled={!uploadManager.shouldAllowNewUpload()}
sx={{
mt: 1.5,
p: 1,
width: 320,
borderRadius: 0.5,
}}>
<FlexWrapper sx={{ gap: 1 }} justifyContent="center">
<FolderIcon />
{constants.IMPORT_YOUR_FOLDERS}
</FlexWrapper>
</Button>
</VerticallyCentered>
</Wrapper> </Wrapper>
); );
} }

View file

@ -3,6 +3,7 @@ import { styled } from '@mui/material';
const LogoImage = styled('img')` const LogoImage = styled('img')`
margin: 3px 0; margin: 3px 0;
pointer-events: none;
`; `;
export function EnteLogo(props) { export function EnteLogo(props) {

View file

@ -58,6 +58,7 @@ interface Props {
) => void; ) => void;
selected: SelectedState; selected: SelectedState;
isFirstLoad?; isFirstLoad?;
hasPersonalFiles?;
openUploader?; openUploader?;
isInSearchMode?: boolean; isInSearchMode?: boolean;
search?: Search; search?: Search;
@ -79,6 +80,7 @@ const PhotoFrame = ({
setSelected, setSelected,
selected, selected,
isFirstLoad, isFirstLoad,
hasPersonalFiles,
openUploader, openUploader,
isInSearchMode, isInSearchMode,
search, search,
@ -109,7 +111,6 @@ const PhotoFrame = ({
const updateRequired = useRef(false); const updateRequired = useRef(false);
const [filteredData, setFilteredData] = useState<EnteFile[]>([]); const [filteredData, setFilteredData] = useState<EnteFile[]>([]);
useEffect(() => { useEffect(() => {
const user: User = getData(LS_KEYS.USER); const user: User = getData(LS_KEYS.USER);
setUser(user); setUser(user);
@ -654,7 +655,7 @@ const PhotoFrame = ({
return ( return (
<> <>
{!isFirstLoad && {!isFirstLoad &&
files.length === 0 && !hasPersonalFiles &&
!isInSearchMode && !isInSearchMode &&
activeCollection === ALL_SECTION ? ( activeCollection === ALL_SECTION ? (
<EmptyScreen openUploader={openUploader} /> <EmptyScreen openUploader={openUploader} />

View file

@ -4,6 +4,7 @@ import FileUploadOutlinedIcon from '@mui/icons-material/FileUploadOutlined';
import { Button } from '@mui/material'; import { Button } from '@mui/material';
import constants from 'utils/strings/constants'; import constants from 'utils/strings/constants';
import uploadManager from 'services/upload/uploadManager'; import uploadManager from 'services/upload/uploadManager';
import { UploadTypeSelectorIntent } from 'types/gallery';
const Wrapper = styled('div')<{ $disableShrink: boolean }>` const Wrapper = styled('div')<{ $disableShrink: boolean }>`
display: flex; display: flex;
@ -27,7 +28,7 @@ const Wrapper = styled('div')<{ $disableShrink: boolean }>`
`; `;
interface Iprops { interface Iprops {
openUploader: () => void; openUploader: (intent?: UploadTypeSelectorIntent) => void;
text?: string; text?: string;
color?: ButtonProps['color']; color?: ButtonProps['color'];
disableShrink?: boolean; disableShrink?: boolean;
@ -40,6 +41,8 @@ function UploadButton({
disableShrink, disableShrink,
icon, icon,
}: Iprops) { }: Iprops) {
const onClickHandler = () => openUploader();
return ( return (
<Wrapper <Wrapper
$disableShrink={disableShrink} $disableShrink={disableShrink}
@ -47,7 +50,7 @@ function UploadButton({
cursor: !uploadManager.shouldAllowNewUpload() && 'not-allowed', cursor: !uploadManager.shouldAllowNewUpload() && 'not-allowed',
}}> }}>
<Button <Button
onClick={openUploader} onClick={onClickHandler}
disabled={!uploadManager.shouldAllowNewUpload()} disabled={!uploadManager.shouldAllowNewUpload()}
className="desktop-button" className="desktop-button"
color={color ?? 'secondary'} color={color ?? 'secondary'}
@ -56,7 +59,7 @@ function UploadButton({
</Button> </Button>
<IconButton <IconButton
onClick={openUploader} onClick={onClickHandler}
disabled={!uploadManager.shouldAllowNewUpload()} disabled={!uploadManager.shouldAllowNewUpload()}
className="mobile-button"> className="mobile-button">
<FileUploadOutlinedIcon /> <FileUploadOutlinedIcon />

View file

@ -10,14 +10,14 @@ import DialogTitleWithCloseButton, {
import { Box, Dialog, Stack, Typography } from '@mui/material'; import { Box, Dialog, Stack, Typography } from '@mui/material';
import { PublicCollectionGalleryContext } from 'utils/publicCollectionGallery'; import { PublicCollectionGalleryContext } from 'utils/publicCollectionGallery';
import { isMobileOrTable } from 'utils/common/deviceDetection'; import { isMobileOrTable } from 'utils/common/deviceDetection';
import { UploadTypeSelectorIntent } from 'types/gallery';
interface Iprops { interface Iprops {
onClose: () => void; onClose: () => void;
show: boolean; show: boolean;
uploadFiles: () => void; uploadFiles: () => void;
uploadFolders: () => void; uploadFolders: () => void;
uploadGoogleTakeoutZips: () => void; uploadGoogleTakeoutZips: () => void;
hideZipUploadOption?: boolean; uploadTypeSelectorIntent: UploadTypeSelectorIntent;
} }
export default function UploadTypeSelector({ export default function UploadTypeSelector({
onClose, onClose,
@ -25,7 +25,7 @@ export default function UploadTypeSelector({
uploadFiles, uploadFiles,
uploadFolders, uploadFolders,
uploadGoogleTakeoutZips, uploadGoogleTakeoutZips,
hideZipUploadOption, uploadTypeSelectorIntent,
}: Iprops) { }: Iprops) {
const publicCollectionGalleryContext = useContext( const publicCollectionGalleryContext = useContext(
PublicCollectionGalleryContext PublicCollectionGalleryContext
@ -55,23 +55,31 @@ export default function UploadTypeSelector({
}} }}
onClose={dialogCloseHandler({ onClose })}> onClose={dialogCloseHandler({ onClose })}>
<DialogTitleWithCloseButton onClose={onClose}> <DialogTitleWithCloseButton onClose={onClose}>
{publicCollectionGalleryContext.accessedThroughSharedURL {uploadTypeSelectorIntent ===
UploadTypeSelectorIntent.collectPhotos
? constants.SELECT_PHOTOS ? constants.SELECT_PHOTOS
: uploadTypeSelectorIntent ===
UploadTypeSelectorIntent.import
? constants.IMPORT
: constants.UPLOAD} : constants.UPLOAD}
</DialogTitleWithCloseButton> </DialogTitleWithCloseButton>
<Box p={1.5} pt={0.5}> <Box p={1.5} pt={0.5}>
<Stack spacing={0.5}> <Stack spacing={0.5}>
{uploadTypeSelectorIntent !==
UploadTypeSelectorIntent.import && (
<UploadTypeOption <UploadTypeOption
onClick={uploadFiles} onClick={uploadFiles}
startIcon={<FileUploadIcon />}> startIcon={<FileUploadIcon />}>
{constants.UPLOAD_FILES} {constants.UPLOAD_FILES}
</UploadTypeOption> </UploadTypeOption>
)}
<UploadTypeOption <UploadTypeOption
onClick={uploadFolders} onClick={uploadFolders}
startIcon={<FolderUploadIcon />}> startIcon={<FolderUploadIcon />}>
{constants.UPLOAD_DIRS} {constants.UPLOAD_DIRS}
</UploadTypeOption> </UploadTypeOption>
{!hideZipUploadOption && ( {uploadTypeSelectorIntent !==
UploadTypeSelectorIntent.collectPhotos && (
<UploadTypeOption <UploadTypeOption
onClick={uploadGoogleTakeoutZips} onClick={uploadGoogleTakeoutZips}
startIcon={<GoogleIcon />}> startIcon={<GoogleIcon />}>

View file

@ -59,7 +59,7 @@ import {
getPublicCollectionUploaderName, getPublicCollectionUploaderName,
savePublicCollectionUploaderName, savePublicCollectionUploaderName,
} from 'services/publicCollectionService'; } from 'services/publicCollectionService';
import { UploadTypeSelectorIntent } from 'types/gallery';
const FIRST_ALBUM_NAME = 'My First Album'; const FIRST_ALBUM_NAME = 'My First Album';
interface Props { interface Props {
@ -81,8 +81,8 @@ interface Props {
webFolderSelectorFiles: File[]; webFolderSelectorFiles: File[];
webFileSelectorFiles: File[]; webFileSelectorFiles: File[];
dragAndDropFiles: File[]; dragAndDropFiles: File[];
zipUploadDisabled?: boolean;
uploadCollection?: Collection; uploadCollection?: Collection;
uploadTypeSelectorIntent: UploadTypeSelectorIntent;
} }
export default function Uploader(props: Props) { export default function Uploader(props: Props) {
@ -752,7 +752,7 @@ export default function Uploader(props: Props) {
uploadFiles={handleFileUpload} uploadFiles={handleFileUpload}
uploadFolders={handleFolderUpload} uploadFolders={handleFolderUpload}
uploadGoogleTakeoutZips={handleZipUpload} uploadGoogleTakeoutZips={handleZipUpload}
hideZipUploadOption={props.zipUploadDisabled} uploadTypeSelectorIntent={props.uploadTypeSelectorIntent}
/> />
<UploadProgress <UploadProgress
open={uploadProgressView} open={uploadProgressView}

View file

@ -88,7 +88,11 @@ import FixCreationTime, {
} from 'components/FixCreationTime'; } from 'components/FixCreationTime';
import { Collection, CollectionSummaries } from 'types/collection'; import { Collection, CollectionSummaries } from 'types/collection';
import { EnteFile } from 'types/file'; import { EnteFile } from 'types/file';
import { GalleryContextType, SelectedState } from 'types/gallery'; import {
GalleryContextType,
SelectedState,
UploadTypeSelectorIntent,
} from 'types/gallery';
import { VISIBILITY_STATE } from 'types/magicMetadata'; import { VISIBILITY_STATE } from 'types/magicMetadata';
import Collections from 'components/Collections'; import Collections from 'components/Collections';
import { GalleryNavbar } from 'components/pages/gallery/Navbar'; import { GalleryNavbar } from 'components/pages/gallery/Navbar';
@ -103,6 +107,7 @@ import { CenteredFlex } from 'components/Container';
import { checkConnectivity } from 'utils/error/ui'; import { checkConnectivity } from 'utils/error/ui';
import { SYNC_INTERVAL_IN_MICROSECONDS } from 'constants/gallery'; import { SYNC_INTERVAL_IN_MICROSECONDS } from 'constants/gallery';
import ElectronService from 'services/electron/common'; import ElectronService from 'services/electron/common';
import uploadManager from 'services/upload/uploadManager';
export const DeadCenter = styled('div')` export const DeadCenter = styled('div')`
flex: 1; flex: 1;
@ -137,6 +142,7 @@ export default function Gallery() {
const [isFirstLoad, setIsFirstLoad] = useState(false); const [isFirstLoad, setIsFirstLoad] = useState(false);
const [isFirstFetch, setIsFirstFetch] = useState(false); const [isFirstFetch, setIsFirstFetch] = useState(false);
const [hasPersonalFiles, setHasPersonalFiles] = useState(false);
const [selected, setSelected] = useState<SelectedState>({ const [selected, setSelected] = useState<SelectedState>({
ownCount: 0, ownCount: 0,
count: 0, count: 0,
@ -200,6 +206,10 @@ export default function Gallery() {
const showPlanSelectorModal = () => setPlanModalView(true); const showPlanSelectorModal = () => setPlanModalView(true);
const [uploadTypeSelectorView, setUploadTypeSelectorView] = useState(false); const [uploadTypeSelectorView, setUploadTypeSelectorView] = useState(false);
const [uploadTypeSelectorIntent, setUploadTypeSelectorIntent] =
useState<UploadTypeSelectorIntent>(
UploadTypeSelectorIntent.normalUpload
);
const [sidebarView, setSidebarView] = useState(false); const [sidebarView, setSidebarView] = useState(false);
@ -383,6 +393,11 @@ export default function Gallery() {
archivedCollections archivedCollections
); );
setCollectionSummaries(collectionSummaries); setCollectionSummaries(collectionSummaries);
const incomingShareFiles = files.filter(
(file) => file.ownerID !== user.id
);
const hasPersonalFiles = files.length - incomingShareFiles.length > 0;
setHasPersonalFiles(hasPersonalFiles);
}; };
const clearSelection = function () { const clearSelection = function () {
@ -560,8 +575,12 @@ export default function Gallery() {
finishLoading(); finishLoading();
}; };
const openUploader = () => { const openUploader = (intent = UploadTypeSelectorIntent.normalUpload) => {
if (!uploadManager.shouldAllowNewUpload()) {
return;
}
setUploadTypeSelectorView(true); setUploadTypeSelectorView(true);
setUploadTypeSelectorIntent(intent);
}; };
const closeCollectionSelector = () => { const closeCollectionSelector = () => {
@ -659,6 +678,7 @@ export default function Gallery() {
null, null,
false false
)} )}
uploadTypeSelectorIntent={uploadTypeSelectorIntent}
setLoading={setBlockingLoad} setLoading={setBlockingLoad}
setCollectionNamerAttributes={setCollectionNamerAttributes} setCollectionNamerAttributes={setCollectionNamerAttributes}
setShouldDisableDropzone={setShouldDisableDropzone} setShouldDisableDropzone={setShouldDisableDropzone}
@ -689,6 +709,7 @@ export default function Gallery() {
setSelected={setSelected} setSelected={setSelected}
selected={selected} selected={selected}
isFirstLoad={isFirstLoad} isFirstLoad={isFirstLoad}
hasPersonalFiles={hasPersonalFiles}
openUploader={openUploader} openUploader={openUploader}
isInSearchMode={isInSearchMode} isInSearchMode={isInSearchMode}
search={search} search={search}

View file

@ -48,6 +48,7 @@ import UploadButton from 'components/Upload/UploadButton';
import bs58 from 'bs58'; import bs58 from 'bs58';
import AddPhotoAlternateOutlined from '@mui/icons-material/AddPhotoAlternateOutlined'; import AddPhotoAlternateOutlined from '@mui/icons-material/AddPhotoAlternateOutlined';
import ComlinkCryptoWorker from 'utils/comlink/ComlinkCryptoWorker'; import ComlinkCryptoWorker from 'utils/comlink/ComlinkCryptoWorker';
import { UploadTypeSelectorIntent } from 'types/gallery';
const Loader = () => ( const Loader = () => (
<VerticallyCentered> <VerticallyCentered>
@ -440,7 +441,9 @@ export default function PublicCollectionGallery() {
showUploadFilesDialog={openFileSelector} showUploadFilesDialog={openFileSelector}
showUploadDirsDialog={openFolderSelector} showUploadDirsDialog={openFolderSelector}
showSessionExpiredMessage={showPublicLinkExpiredMessage} showSessionExpiredMessage={showPublicLinkExpiredMessage}
zipUploadDisabled uploadTypeSelectorIntent={
UploadTypeSelectorIntent.collectPhotos
}
/> />
</FullScreenDropZone> </FullScreenDropZone>
</PublicCollectionGalleryContext.Provider> </PublicCollectionGalleryContext.Provider>

View file

@ -20,7 +20,11 @@ export type MergedSourceURL = {
original: string; original: string;
converted: string; converted: string;
}; };
export enum UploadTypeSelectorIntent {
normalUpload,
import,
collectPhotos,
}
export type GalleryContextType = { export type GalleryContextType = {
thumbs: Map<number, string>; thumbs: Map<number, string>;
files: Map<number, MergedSourceURL>; files: Map<number, MergedSourceURL>;

View file

@ -6,7 +6,7 @@ import React from 'react';
import { SuggestionType } from 'types/search'; import { SuggestionType } from 'types/search';
import { formatNumberWithCommas } from '.'; import { formatNumberWithCommas } from '.';
import { FACE_SEARCH_PRIVACY_POLICY_LINK } from 'constants/urls'; import { FACE_SEARCH_PRIVACY_POLICY_LINK } from 'constants/urls';
import { EnteLogo } from 'components/EnteLogo';
/** /**
* Global English constants. * Global English constants.
*/ */
@ -94,6 +94,15 @@ const englishConstants = {
recover your data without a recovery key. recover your data without a recovery key.
</> </>
), ),
WELCOME_TO_ENTE: () => (
<>
<Typography variant="h3" color="text.secondary" mb={1}>
Welcome to <EnteLogo />
</Typography>
<h2>End to end encrypted photo storage and sharing</h2>
</>
),
WHERE_YOUR_BEST_PHOTOS_LIVE: 'Where your best photos live',
KEY_GENERATION_IN_PROGRESS_MESSAGE: 'Generating encryption keys...', KEY_GENERATION_IN_PROGRESS_MESSAGE: 'Generating encryption keys...',
PASSPHRASE_HINT: 'Password', PASSPHRASE_HINT: 'Password',
CONFIRM_PASSPHRASE: 'Confirm password', CONFIRM_PASSPHRASE: 'Confirm password',
@ -110,6 +119,7 @@ const englishConstants = {
NO: 'No', NO: 'No',
NOTHING_HERE: 'Nothing to see here yet 👀', NOTHING_HERE: 'Nothing to see here yet 👀',
UPLOAD: 'Upload', UPLOAD: 'Upload',
IMPORT: 'Import',
ADD_MORE_PHOTOS: 'Add more photos', ADD_MORE_PHOTOS: 'Add more photos',
ADD_PHOTOS: 'Add photos', ADD_PHOTOS: 'Add photos',
SELECT_PHOTOS: 'Select photos', SELECT_PHOTOS: 'Select photos',
@ -153,12 +163,8 @@ const englishConstants = {
NO_INTERNET_CONNECTION: NO_INTERNET_CONNECTION:
'Please check your internet connection and try again', 'Please check your internet connection and try again',
TITLE: 'ente Photos', TITLE: 'ente Photos',
UPLOAD_FIRST_PHOTO_DESCRIPTION: () => ( UPLOAD_FIRST_PHOTO: 'Upload your first photo',
<> IMPORT_YOUR_FOLDERS: 'Import your folders',
Preserve your first memory with <strong> ente </strong>
</>
),
UPLOAD_FIRST_PHOTO: 'Preserve',
UPLOAD_DROPZONE_MESSAGE: 'Drop to backup your files', UPLOAD_DROPZONE_MESSAGE: 'Drop to backup your files',
WATCH_FOLDER_DROPZONE_MESSAGE: 'Drop to add watched folder', WATCH_FOLDER_DROPZONE_MESSAGE: 'Drop to add watched folder',
TRASH_FILES_TITLE: 'Delete files?', TRASH_FILES_TITLE: 'Delete files?',