add caption to info screen

This commit is contained in:
Abhinav 2022-11-02 18:19:05 +05:30
parent 364772e52c
commit de3d11d281
6 changed files with 196 additions and 5 deletions

View file

@ -0,0 +1,78 @@
import React, { useState } from 'react';
import constants from 'utils/strings/constants';
import { Col, Form, FormControl } from 'react-bootstrap';
import { Value } from 'components/Container';
import CloseIcon from '@mui/icons-material/Close';
import TickIcon from '@mui/icons-material/Done';
import { Formik } from 'formik';
import * as Yup from 'yup';
import { MAX_CAPTION_SIZE } from 'constants/file';
import { SmallLoadingSpinner } from '../styledComponents/SmallLoadingSpinner';
import { IconButton } from '@mui/material';
export interface formValues {
caption: string;
}
export const CaptionEditForm = ({ caption, saveEdits, discardEdits }) => {
const [loading, setLoading] = useState(false);
const onSubmit = async (values: formValues) => {
try {
setLoading(true);
await saveEdits(values.caption);
} finally {
setLoading(false);
}
};
return (
<Formik<formValues>
initialValues={{ caption }}
validationSchema={Yup.object().shape({
caption: Yup.string()
.required(constants.REQUIRED)
.max(MAX_CAPTION_SIZE, constants.CAPTION_CHARACTER_LIMIT),
})}
validateOnBlur={false}
onSubmit={onSubmit}>
{({ values, errors, handleChange, handleSubmit }) => (
<Form noValidate onSubmit={handleSubmit}>
<Form.Row>
<Form.Group bsPrefix="ente-form-group" as={Col} xs={9}>
<Form.Control
as="textarea"
placeholder={constants.CAPTION}
value={values.caption}
onChange={handleChange('caption')}
isInvalid={Boolean(errors.caption)}
autoFocus
disabled={loading}
/>
<FormControl.Feedback
type="invalid"
style={{ textAlign: 'center' }}>
{errors.caption}
</FormControl.Feedback>
</Form.Group>
<Form.Group bsPrefix="ente-form-group" as={Col} xs={3}>
<Value width={'16.67%'}>
<IconButton type="submit" disabled={loading}>
{loading ? (
<SmallLoadingSpinner />
) : (
<TickIcon />
)}
</IconButton>
<IconButton
onClick={discardEdits}
disabled={loading}>
<CloseIcon />
</IconButton>
</Value>
</Form.Group>
</Form.Row>
</Form>
)}
</Formik>
);
};

View file

@ -0,0 +1,96 @@
import React, { useState } from 'react';
import { updateFilePublicMagicMetadata } from 'services/fileService';
import { EnteFile } from 'types/file';
import constants from 'utils/strings/constants';
import { changeCaption, updateExistingFilePubMetadata } from 'utils/file';
import EditIcon from '@mui/icons-material/Edit';
import { FreeFlowText, Label, Row, Value } from 'components/Container';
import { logError } from 'utils/sentry';
import { IconButton, Typography } from '@mui/material';
import { CaptionEditForm } from './CaptionEditForm';
export const getFileTitle = (filename, extension) => {
if (extension) {
return filename + '.' + extension;
} else {
return filename;
}
};
export function RenderCaption({
shouldDisableEdits,
file,
scheduleUpdate,
}: {
shouldDisableEdits: boolean;
file: EnteFile;
scheduleUpdate: () => void;
}) {
const [caption, setCaption] = useState(
file?.pubMagicMetadata?.data.caption
);
const [isInEditMode, setIsInEditMode] = useState(false);
const openEditMode = () => setIsInEditMode(true);
const closeEditMode = () => setIsInEditMode(false);
const saveEdits = async (newCaption: string) => {
try {
if (file) {
if (caption === newCaption) {
closeEditMode();
return;
}
setCaption(newCaption);
let updatedFile = await changeCaption(file, newCaption);
updatedFile = (
await updateFilePublicMagicMetadata([updatedFile])
)[0];
updateExistingFilePubMetadata(file, updatedFile);
scheduleUpdate();
}
} catch (e) {
logError(e, 'failed to update caption');
} finally {
closeEditMode();
}
};
return (
<>
<Row>
<Label width="30%">{constants.CAPTION}</Label>
{!isInEditMode ? (
<>
<Value width={!shouldDisableEdits ? '60%' : '70%'}>
{caption ? (
<FreeFlowText>{caption}</FreeFlowText>
) : (
<Typography color="text.secondary">
Add a caption
</Typography>
)}
</Value>
{!shouldDisableEdits && (
<Value
width="10%"
style={{
cursor: 'pointer',
marginLeft: '10px',
}}>
<IconButton onClick={openEditMode}>
<EditIcon />
</IconButton>
</Value>
)}
</>
) : (
<CaptionEditForm
caption={caption}
saveEdits={saveEdits}
discardEdits={closeEditMode}
/>
)}
</Row>
</>
);
}

View file

@ -11,6 +11,7 @@ import { AppContext } from 'pages/_app';
import { Location, Metadata } from 'types/upload';
import Photoswipe from 'photoswipe';
import { getEXIFLocation } from 'services/upload/exifService';
import { RenderCaption } from './RenderCaption';
const FileInfoDialog = styled(Dialog)(({ theme }) => ({
zIndex: 1501,
@ -78,11 +79,11 @@ export function FileInfo({
<Typography variant="subtitle" mb={1}>
{constants.METADATA}
</Typography>
{RenderInfoItem(
constants.FILE_ID,
items[photoSwipe?.getCurrentIndex()]?.id
)}
<RenderCaption
shouldDisableEdits={shouldDisableEdits}
file={items[photoSwipe?.getCurrentIndex()]}
scheduleUpdate={scheduleUpdate}
/>
{metadata?.title && (
<RenderFileName
shouldDisableEdits={shouldDisableEdits}

View file

@ -2,6 +2,7 @@ export const MIN_EDITED_CREATION_TIME = new Date(1800, 0, 1);
export const MAX_EDITED_CREATION_TIME = new Date();
export const MAX_EDITED_FILE_NAME_LENGTH = 100;
export const MAX_CAPTION_SIZE = 280;
export const MAX_TRASH_BATCH_SIZE = 1000;
export const TYPE_HEIC = 'heic';

View file

@ -408,6 +408,19 @@ export async function changeFileName(file: EnteFile, editedName: string) {
return file;
}
export async function changeCaption(file: EnteFile, caption: string) {
const updatedPublicMagicMetadataProps: FilePublicMagicMetadataProps = {
caption,
};
file.pubMagicMetadata = await updateMagicMetadataProps(
file.pubMagicMetadata ?? NEW_FILE_MAGIC_METADATA,
file.key,
updatedPublicMagicMetadataProps
);
return file;
}
export function isSharedFile(user: User, file: EnteFile) {
if (!user?.id || !file?.ownerID) {
return false;

View file

@ -435,6 +435,7 @@ const englishConstants = {
INFO: 'Info',
FILE_ID: 'File ID',
FILE_NAME: 'File name',
CAPTION: 'Caption',
CREATION_TIME: 'Creation time',
UPDATED_ON: 'Updated on',
LOCATION: 'Location',
@ -622,6 +623,7 @@ const englishConstants = {
<>File time updation failed for some files, please retry</>
),
FILE_NAME_CHARACTER_LIMIT: '100 characters max',
CAPTION_CHARACTER_LIMIT: '280 characters max',
DATE_TIME_ORIGINAL: 'EXIF:DateTimeOriginal',
DATE_TIME_DIGITIZED: 'EXIF:DateTimeDigitized',