Merge branch 'main' into continuous-sync
This commit is contained in:
commit
6224125732
|
@ -9,5 +9,5 @@ const buildPrettierCommand = (filenames) =>
|
|||
`yarn prettier --write --ignore-unknown ${filenames.join(' ')}`;
|
||||
|
||||
module.exports = {
|
||||
'*.{js,jsx,ts,tsx}': [buildEslintCommand, buildPrettierCommand],
|
||||
'src/**/*.{js,jsx,ts,tsx}': [buildEslintCommand, buildPrettierCommand],
|
||||
};
|
||||
|
|
BIN
public/images/empty-state/ente_duck.png
Normal file
BIN
public/images/empty-state/ente_duck.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
BIN
public/images/empty-state/ente_duck@2x.png
Normal file
BIN
public/images/empty-state/ente_duck@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 87 KiB |
BIN
public/images/empty-state/ente_duck@3x.png
Normal file
BIN
public/images/empty-state/ente_duck@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 140 KiB |
|
@ -1,56 +1,103 @@
|
|||
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 { 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 AddPhotoAlternateIcon from '@mui/icons-material/AddPhotoAlternateOutlined';
|
||||
import FolderIcon from '@mui/icons-material/FolderOutlined';
|
||||
import { UploadTypeSelectorIntent } from 'types/gallery';
|
||||
|
||||
const Wrapper = styled(VerticallyCentered)`
|
||||
& > svg {
|
||||
filter: drop-shadow(3px 3px 5px rgba(45, 194, 98, 0.5));
|
||||
}
|
||||
const Wrapper = styled(Box)`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
`;
|
||||
const NonDraggableImage = styled('img')`
|
||||
pointer-events: none;
|
||||
`;
|
||||
|
||||
export default function EmptyScreen({ openUploader }) {
|
||||
const deduplicateContext = useContext(DeduplicateContext);
|
||||
return (
|
||||
return deduplicateContext.isOnDeduplicatePage ? (
|
||||
<VerticallyCentered>
|
||||
<div
|
||||
style={{
|
||||
color: '#a6a6a6',
|
||||
fontSize: '18px',
|
||||
}}>
|
||||
{constants.NO_DUPLICATES_FOUND}
|
||||
</div>
|
||||
</VerticallyCentered>
|
||||
) : (
|
||||
<Wrapper>
|
||||
{deduplicateContext.isOnDeduplicatePage ? (
|
||||
<div
|
||||
style={{
|
||||
color: '#a6a6a6',
|
||||
fontSize: '18px',
|
||||
}}>
|
||||
{constants.NO_DUPLICATES_FOUND}
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<img
|
||||
height={150}
|
||||
src="/images/gallery-locked/1x.png"
|
||||
srcSet="/images/gallery-locked/2x.png 2x,
|
||||
/images/gallery-locked/3x.png 3x"
|
||||
/>
|
||||
<Typography color="text.secondary" mt={2}>
|
||||
{constants.UPLOAD_FIRST_PHOTO_DESCRIPTION()}
|
||||
</Typography>
|
||||
<Stack
|
||||
sx={{
|
||||
flex: 'none',
|
||||
pt: 1.5,
|
||||
pb: 1.5,
|
||||
}}>
|
||||
<VerticallyCentered sx={{ flex: 'none' }}>
|
||||
{constants.WELCOME_TO_ENTE()}
|
||||
</VerticallyCentered>
|
||||
<Typography variant="body1" mt={3.5} color="text.secondary">
|
||||
{constants.WHERE_YOUR_BEST_PHOTOS_LIVE}
|
||||
</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
|
||||
style={{
|
||||
cursor:
|
||||
!uploadManager.shouldAllowNewUpload() &&
|
||||
'not-allowed',
|
||||
}}>
|
||||
<Button
|
||||
color="accent"
|
||||
onClick={openUploader}
|
||||
disabled={!uploadManager.shouldAllowNewUpload()}
|
||||
sx={{ mt: 4 }}>
|
||||
{constants.UPLOAD_FIRST_PHOTO}
|
||||
</Button>
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
<VerticallyCentered paddingTop={1.5} paddingBottom={1.5}>
|
||||
<Button
|
||||
style={{
|
||||
cursor:
|
||||
!uploadManager.shouldAllowNewUpload() &&
|
||||
'not-allowed',
|
||||
}}
|
||||
color="accent"
|
||||
onClick={() =>
|
||||
openUploader(UploadTypeSelectorIntent.normalUpload)
|
||||
}
|
||||
disabled={!uploadManager.shouldAllowNewUpload()}
|
||||
sx={{
|
||||
mt: 1.5,
|
||||
p: 1,
|
||||
width: 320,
|
||||
borderRadius: 0.5,
|
||||
}}>
|
||||
<FlexWrapper sx={{ gap: 1 }} justifyContent="center">
|
||||
<AddPhotoAlternateIcon />
|
||||
{constants.UPLOAD_FIRST_PHOTO}
|
||||
</FlexWrapper>
|
||||
</Button>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { styled } from '@mui/material';
|
|||
|
||||
const LogoImage = styled('img')`
|
||||
margin: 3px 0;
|
||||
pointer-events: none;
|
||||
`;
|
||||
|
||||
export function EnteLogo(props) {
|
||||
|
|
|
@ -58,6 +58,7 @@ interface Props {
|
|||
) => void;
|
||||
selected: SelectedState;
|
||||
isFirstLoad?;
|
||||
hasPersonalFiles?;
|
||||
openUploader?;
|
||||
isInSearchMode?: boolean;
|
||||
search?: Search;
|
||||
|
@ -79,6 +80,7 @@ const PhotoFrame = ({
|
|||
setSelected,
|
||||
selected,
|
||||
isFirstLoad,
|
||||
hasPersonalFiles,
|
||||
openUploader,
|
||||
isInSearchMode,
|
||||
search,
|
||||
|
@ -109,7 +111,6 @@ const PhotoFrame = ({
|
|||
const updateRequired = useRef(false);
|
||||
|
||||
const [filteredData, setFilteredData] = useState<EnteFile[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const user: User = getData(LS_KEYS.USER);
|
||||
setUser(user);
|
||||
|
@ -654,7 +655,7 @@ const PhotoFrame = ({
|
|||
return (
|
||||
<>
|
||||
{!isFirstLoad &&
|
||||
files.length === 0 &&
|
||||
!hasPersonalFiles &&
|
||||
!isInSearchMode &&
|
||||
activeCollection === ALL_SECTION ? (
|
||||
<EmptyScreen openUploader={openUploader} />
|
||||
|
|
|
@ -4,6 +4,7 @@ import FileUploadOutlinedIcon from '@mui/icons-material/FileUploadOutlined';
|
|||
import { Button } from '@mui/material';
|
||||
import constants from 'utils/strings/constants';
|
||||
import uploadManager from 'services/upload/uploadManager';
|
||||
import { UploadTypeSelectorIntent } from 'types/gallery';
|
||||
|
||||
const Wrapper = styled('div')<{ $disableShrink: boolean }>`
|
||||
display: flex;
|
||||
|
@ -27,7 +28,7 @@ const Wrapper = styled('div')<{ $disableShrink: boolean }>`
|
|||
`;
|
||||
|
||||
interface Iprops {
|
||||
openUploader: () => void;
|
||||
openUploader: (intent?: UploadTypeSelectorIntent) => void;
|
||||
text?: string;
|
||||
color?: ButtonProps['color'];
|
||||
disableShrink?: boolean;
|
||||
|
@ -40,6 +41,8 @@ function UploadButton({
|
|||
disableShrink,
|
||||
icon,
|
||||
}: Iprops) {
|
||||
const onClickHandler = () => openUploader();
|
||||
|
||||
return (
|
||||
<Wrapper
|
||||
$disableShrink={disableShrink}
|
||||
|
@ -47,7 +50,7 @@ function UploadButton({
|
|||
cursor: !uploadManager.shouldAllowNewUpload() && 'not-allowed',
|
||||
}}>
|
||||
<Button
|
||||
onClick={openUploader}
|
||||
onClick={onClickHandler}
|
||||
disabled={!uploadManager.shouldAllowNewUpload()}
|
||||
className="desktop-button"
|
||||
color={color ?? 'secondary'}
|
||||
|
@ -56,7 +59,7 @@ function UploadButton({
|
|||
</Button>
|
||||
|
||||
<IconButton
|
||||
onClick={openUploader}
|
||||
onClick={onClickHandler}
|
||||
disabled={!uploadManager.shouldAllowNewUpload()}
|
||||
className="mobile-button">
|
||||
<FileUploadOutlinedIcon />
|
||||
|
|
|
@ -10,14 +10,14 @@ import DialogTitleWithCloseButton, {
|
|||
import { Box, Dialog, Stack, Typography } from '@mui/material';
|
||||
import { PublicCollectionGalleryContext } from 'utils/publicCollectionGallery';
|
||||
import { isMobileOrTable } from 'utils/common/deviceDetection';
|
||||
|
||||
import { UploadTypeSelectorIntent } from 'types/gallery';
|
||||
interface Iprops {
|
||||
onClose: () => void;
|
||||
show: boolean;
|
||||
uploadFiles: () => void;
|
||||
uploadFolders: () => void;
|
||||
uploadGoogleTakeoutZips: () => void;
|
||||
hideZipUploadOption?: boolean;
|
||||
uploadTypeSelectorIntent: UploadTypeSelectorIntent;
|
||||
}
|
||||
export default function UploadTypeSelector({
|
||||
onClose,
|
||||
|
@ -25,7 +25,7 @@ export default function UploadTypeSelector({
|
|||
uploadFiles,
|
||||
uploadFolders,
|
||||
uploadGoogleTakeoutZips,
|
||||
hideZipUploadOption,
|
||||
uploadTypeSelectorIntent,
|
||||
}: Iprops) {
|
||||
const publicCollectionGalleryContext = useContext(
|
||||
PublicCollectionGalleryContext
|
||||
|
@ -55,23 +55,31 @@ export default function UploadTypeSelector({
|
|||
}}
|
||||
onClose={dialogCloseHandler({ onClose })}>
|
||||
<DialogTitleWithCloseButton onClose={onClose}>
|
||||
{publicCollectionGalleryContext.accessedThroughSharedURL
|
||||
{uploadTypeSelectorIntent ===
|
||||
UploadTypeSelectorIntent.collectPhotos
|
||||
? constants.SELECT_PHOTOS
|
||||
: uploadTypeSelectorIntent ===
|
||||
UploadTypeSelectorIntent.import
|
||||
? constants.IMPORT
|
||||
: constants.UPLOAD}
|
||||
</DialogTitleWithCloseButton>
|
||||
<Box p={1.5} pt={0.5}>
|
||||
<Stack spacing={0.5}>
|
||||
<UploadTypeOption
|
||||
onClick={uploadFiles}
|
||||
startIcon={<FileUploadIcon />}>
|
||||
{constants.UPLOAD_FILES}
|
||||
</UploadTypeOption>
|
||||
{uploadTypeSelectorIntent !==
|
||||
UploadTypeSelectorIntent.import && (
|
||||
<UploadTypeOption
|
||||
onClick={uploadFiles}
|
||||
startIcon={<FileUploadIcon />}>
|
||||
{constants.UPLOAD_FILES}
|
||||
</UploadTypeOption>
|
||||
)}
|
||||
<UploadTypeOption
|
||||
onClick={uploadFolders}
|
||||
startIcon={<FolderUploadIcon />}>
|
||||
{constants.UPLOAD_DIRS}
|
||||
</UploadTypeOption>
|
||||
{!hideZipUploadOption && (
|
||||
{uploadTypeSelectorIntent !==
|
||||
UploadTypeSelectorIntent.collectPhotos && (
|
||||
<UploadTypeOption
|
||||
onClick={uploadGoogleTakeoutZips}
|
||||
startIcon={<GoogleIcon />}>
|
||||
|
|
|
@ -59,7 +59,7 @@ import {
|
|||
getPublicCollectionUploaderName,
|
||||
savePublicCollectionUploaderName,
|
||||
} from 'services/publicCollectionService';
|
||||
|
||||
import { UploadTypeSelectorIntent } from 'types/gallery';
|
||||
const FIRST_ALBUM_NAME = 'My First Album';
|
||||
|
||||
interface Props {
|
||||
|
@ -81,8 +81,8 @@ interface Props {
|
|||
webFolderSelectorFiles: File[];
|
||||
webFileSelectorFiles: File[];
|
||||
dragAndDropFiles: File[];
|
||||
zipUploadDisabled?: boolean;
|
||||
uploadCollection?: Collection;
|
||||
uploadTypeSelectorIntent: UploadTypeSelectorIntent;
|
||||
}
|
||||
|
||||
export default function Uploader(props: Props) {
|
||||
|
@ -752,7 +752,7 @@ export default function Uploader(props: Props) {
|
|||
uploadFiles={handleFileUpload}
|
||||
uploadFolders={handleFolderUpload}
|
||||
uploadGoogleTakeoutZips={handleZipUpload}
|
||||
hideZipUploadOption={props.zipUploadDisabled}
|
||||
uploadTypeSelectorIntent={props.uploadTypeSelectorIntent}
|
||||
/>
|
||||
<UploadProgress
|
||||
open={uploadProgressView}
|
||||
|
|
|
@ -88,7 +88,11 @@ import FixCreationTime, {
|
|||
} from 'components/FixCreationTime';
|
||||
import { Collection, CollectionSummaries } from 'types/collection';
|
||||
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 Collections from 'components/Collections';
|
||||
import { GalleryNavbar } from 'components/pages/gallery/Navbar';
|
||||
|
@ -103,6 +107,7 @@ import { CenteredFlex } from 'components/Container';
|
|||
import { checkConnectivity } from 'utils/error/ui';
|
||||
import { SYNC_INTERVAL_IN_MICROSECONDS } from 'constants/gallery';
|
||||
import ElectronService from 'services/electron/common';
|
||||
import uploadManager from 'services/upload/uploadManager';
|
||||
|
||||
export const DeadCenter = styled('div')`
|
||||
flex: 1;
|
||||
|
@ -137,6 +142,7 @@ export default function Gallery() {
|
|||
|
||||
const [isFirstLoad, setIsFirstLoad] = useState(false);
|
||||
const [isFirstFetch, setIsFirstFetch] = useState(false);
|
||||
const [hasPersonalFiles, setHasPersonalFiles] = useState(false);
|
||||
const [selected, setSelected] = useState<SelectedState>({
|
||||
ownCount: 0,
|
||||
count: 0,
|
||||
|
@ -200,6 +206,10 @@ export default function Gallery() {
|
|||
const showPlanSelectorModal = () => setPlanModalView(true);
|
||||
|
||||
const [uploadTypeSelectorView, setUploadTypeSelectorView] = useState(false);
|
||||
const [uploadTypeSelectorIntent, setUploadTypeSelectorIntent] =
|
||||
useState<UploadTypeSelectorIntent>(
|
||||
UploadTypeSelectorIntent.normalUpload
|
||||
);
|
||||
|
||||
const [sidebarView, setSidebarView] = useState(false);
|
||||
|
||||
|
@ -383,6 +393,11 @@ export default function Gallery() {
|
|||
archivedCollections
|
||||
);
|
||||
setCollectionSummaries(collectionSummaries);
|
||||
const incomingShareFiles = files.filter(
|
||||
(file) => file.ownerID !== user.id
|
||||
);
|
||||
const hasPersonalFiles = files.length - incomingShareFiles.length > 0;
|
||||
setHasPersonalFiles(hasPersonalFiles);
|
||||
};
|
||||
|
||||
const clearSelection = function () {
|
||||
|
@ -560,8 +575,12 @@ export default function Gallery() {
|
|||
finishLoading();
|
||||
};
|
||||
|
||||
const openUploader = () => {
|
||||
const openUploader = (intent = UploadTypeSelectorIntent.normalUpload) => {
|
||||
if (!uploadManager.shouldAllowNewUpload()) {
|
||||
return;
|
||||
}
|
||||
setUploadTypeSelectorView(true);
|
||||
setUploadTypeSelectorIntent(intent);
|
||||
};
|
||||
|
||||
const closeCollectionSelector = () => {
|
||||
|
@ -659,6 +678,7 @@ export default function Gallery() {
|
|||
null,
|
||||
false
|
||||
)}
|
||||
uploadTypeSelectorIntent={uploadTypeSelectorIntent}
|
||||
setLoading={setBlockingLoad}
|
||||
setCollectionNamerAttributes={setCollectionNamerAttributes}
|
||||
setShouldDisableDropzone={setShouldDisableDropzone}
|
||||
|
@ -689,6 +709,7 @@ export default function Gallery() {
|
|||
setSelected={setSelected}
|
||||
selected={selected}
|
||||
isFirstLoad={isFirstLoad}
|
||||
hasPersonalFiles={hasPersonalFiles}
|
||||
openUploader={openUploader}
|
||||
isInSearchMode={isInSearchMode}
|
||||
search={search}
|
||||
|
|
|
@ -48,6 +48,7 @@ import UploadButton from 'components/Upload/UploadButton';
|
|||
import bs58 from 'bs58';
|
||||
import AddPhotoAlternateOutlined from '@mui/icons-material/AddPhotoAlternateOutlined';
|
||||
import ComlinkCryptoWorker from 'utils/comlink/ComlinkCryptoWorker';
|
||||
import { UploadTypeSelectorIntent } from 'types/gallery';
|
||||
|
||||
const Loader = () => (
|
||||
<VerticallyCentered>
|
||||
|
@ -440,7 +441,9 @@ export default function PublicCollectionGallery() {
|
|||
showUploadFilesDialog={openFileSelector}
|
||||
showUploadDirsDialog={openFolderSelector}
|
||||
showSessionExpiredMessage={showPublicLinkExpiredMessage}
|
||||
zipUploadDisabled
|
||||
uploadTypeSelectorIntent={
|
||||
UploadTypeSelectorIntent.collectPhotos
|
||||
}
|
||||
/>
|
||||
</FullScreenDropZone>
|
||||
</PublicCollectionGalleryContext.Provider>
|
||||
|
|
|
@ -20,7 +20,11 @@ export type MergedSourceURL = {
|
|||
original: string;
|
||||
converted: string;
|
||||
};
|
||||
|
||||
export enum UploadTypeSelectorIntent {
|
||||
normalUpload,
|
||||
import,
|
||||
collectPhotos,
|
||||
}
|
||||
export type GalleryContextType = {
|
||||
thumbs: Map<number, string>;
|
||||
files: Map<number, MergedSourceURL>;
|
||||
|
|
|
@ -6,7 +6,7 @@ import React from 'react';
|
|||
import { SuggestionType } from 'types/search';
|
||||
import { formatNumberWithCommas } from '.';
|
||||
import { FACE_SEARCH_PRIVACY_POLICY_LINK } from 'constants/urls';
|
||||
|
||||
import { EnteLogo } from 'components/EnteLogo';
|
||||
/**
|
||||
* Global English constants.
|
||||
*/
|
||||
|
@ -94,6 +94,15 @@ const englishConstants = {
|
|||
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...',
|
||||
PASSPHRASE_HINT: 'Password',
|
||||
CONFIRM_PASSPHRASE: 'Confirm password',
|
||||
|
@ -110,6 +119,7 @@ const englishConstants = {
|
|||
NO: 'No',
|
||||
NOTHING_HERE: 'Nothing to see here yet 👀',
|
||||
UPLOAD: 'Upload',
|
||||
IMPORT: 'Import',
|
||||
ADD_MORE_PHOTOS: 'Add more photos',
|
||||
ADD_PHOTOS: 'Add photos',
|
||||
SELECT_PHOTOS: 'Select photos',
|
||||
|
@ -153,12 +163,8 @@ const englishConstants = {
|
|||
NO_INTERNET_CONNECTION:
|
||||
'Please check your internet connection and try again',
|
||||
TITLE: 'ente Photos',
|
||||
UPLOAD_FIRST_PHOTO_DESCRIPTION: () => (
|
||||
<>
|
||||
Preserve your first memory with <strong> ente </strong>
|
||||
</>
|
||||
),
|
||||
UPLOAD_FIRST_PHOTO: 'Preserve',
|
||||
UPLOAD_FIRST_PHOTO: 'Upload your first photo',
|
||||
IMPORT_YOUR_FOLDERS: 'Import your folders',
|
||||
UPLOAD_DROPZONE_MESSAGE: 'Drop to backup your files',
|
||||
WATCH_FOLDER_DROPZONE_MESSAGE: 'Drop to add watched folder',
|
||||
TRASH_FILES_TITLE: 'Delete files?',
|
||||
|
|
Loading…
Reference in a new issue