Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add override metadata #259

Merged
merged 3 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion web/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.4.81",
"version": "0.4.82",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
8 changes: 8 additions & 0 deletions web/src/core/exif-metadata/override-exif-metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const overrideExifMetadata = () => {
const overridableMetadata: { [key: string]: string }[] = JSON.parse(localStorage.getItem('overridableMetadata') || '[]');
const overrideMetadataIndex: number | null = JSON.parse(localStorage.getItem('overrideMetadataIndex') || 'null');
const metadata = overrideMetadataIndex == null ? null : overridableMetadata.length > overrideMetadataIndex ? overridableMetadata[overrideMetadataIndex] : null;
return metadata;
};

export default overrideExifMetadata;
23 changes: 13 additions & 10 deletions web/src/core/photo.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { load } from 'exifreader';
import ExifMetadata from './exif-metadata/exif-metadata';
import thumbnail from './drawing/thumbnail';
import overrideExifMetadata from './exif-metadata/override-exif-metadata';

/**
* Represents a photo.
Expand Down Expand Up @@ -39,7 +40,7 @@ class Photo {
*/
public get make(): string {
if (localStorage.getItem('showCameraMaker') === 'false') return '';
return localStorage.getItem('overrideCameraMaker') || this.metadata.make || '';
return overrideExifMetadata()?.make || this.metadata.make || '';
}

/**
Expand All @@ -48,7 +49,7 @@ class Photo {
*/
public get model(): string {
if (localStorage.getItem('showCameraModel') === 'false') return '';
return localStorage.getItem('overrideCameraModel') || this.metadata.model || '';
return overrideExifMetadata()?.model || this.metadata.model || '';
}

/**
Expand All @@ -57,7 +58,7 @@ class Photo {
*/
public get lensModel(): string {
if (localStorage.getItem('showLensModel') === 'false') return '';
return localStorage.getItem('overrideLensModel') || this.metadata.lensModel || '';
return overrideExifMetadata()?.lensModel || this.metadata.lensModel || '';
}

/**
Expand All @@ -66,44 +67,46 @@ class Photo {
*/
public get focalLength(): string {
if (localStorage.getItem('focalLengthRatioMode') === 'true') {
const focalLength = parseFloat(this.metadata?.focalLength?.replace(' mm', '') || '0');
const focalLength = parseFloat(overrideExifMetadata()?.focalLength?.replace(' mm', '') || this.metadata?.focalLength?.replace(' mm', '') || '0');
return (focalLength * parseFloat(localStorage.getItem('focalLengthRatio') || '1')).toFixed(0) + 'mm';
}
return localStorage.getItem('focalLength35mmMode') === 'false' ? this.metadata.focalLength || '' : this.metadata.focalLengthIn35mm || '';
return localStorage.getItem('focalLength35mmMode') === 'false'
? overrideExifMetadata()?.focalLength || this.metadata.focalLength || ''
: overrideExifMetadata()?.focalLengthIn35mm || this.metadata.focalLengthIn35mm || '';
}

/**
* Returns the F number of the camera that took the photo.
* @example 'F4'
*/
public get fNumber(): string {
return this.metadata.fNumber || '';
return overrideExifMetadata()?.fNumber || this.metadata.fNumber || '';
}

/**
* Returns the ISO of the camera that took the photo.
* @example 'ISO100'
*/
public get iso(): string {
return this.metadata.iso || '';
return overrideExifMetadata()?.iso || this.metadata.iso || '';
}

/**
* Returns the exposure time of the camera that took the photo.
* @example '1/100s'
*/
public get exposureTime(): string {
return this.metadata.exposureTime || '';
return overrideExifMetadata()?.exposureTime || this.metadata.exposureTime || '';
}

/**
* Returns the date the photo was taken.
* @example '2021-01-01T00:00:00.000+09:00'
*/
public get takenAt(): string {
if (!this.metadata.takenAt) return '';
if (!overrideExifMetadata()?.takenAt && !this.metadata.takenAt) return '';

const takenAt = new Date(this.metadata.takenAt);
const takenAt = new Date(overrideExifMetadata()?.takenAt || this.metadata.takenAt!);
switch (localStorage.getItem('dateNotation') || '2001/01/01 01:01:01') {
case '2001/01/01 01:01:01':
return `${takenAt.getFullYear()}/${(takenAt.getMonth() + 1).toString().padStart(2, '0')}/${takenAt.getDate().toString().padStart(2, '0')} ${takenAt
Expand Down
12 changes: 12 additions & 0 deletions web/src/icons/pencil.icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Icon } from 'konsta/react';
import { LuPencilLine } from 'react-icons/lu';

interface PencilIconProps {
size?: number;
}

const PencilIcon = ({ size }: PencilIconProps) => {
return <Icon ios={<LuPencilLine size={size} />} />;
};

export default PencilIcon;
17 changes: 10 additions & 7 deletions web/src/locales/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@
"ja": "日本語",
"ko": "한국어",

"make": "Camera Maker",
"model": "Camera Model",
"lens": "Lens Model",
"focal": "Focal Length",
"focal-35mm": "Focal Length 35mm",
"name": "Name",
"make": "Camera maker",
"model": "Camera model",
"lens": "Lens model",
"focal": "Focal length",
"focal-35mm": "Focal length 35mm",
"aperture": "Aperture",
"shutter": "Shutter Speed",
"shutter": "Shutter speed",
"iso": "ISO",
"taken-at": "Taken At",
"taken-at": "Taken at",

"drag-and-drop-photos-here": "Drag and drop photos here",

Expand Down Expand Up @@ -74,6 +75,8 @@
"root.settings.override-camera-maker": "Override Camera Maker",
"root.settings.override-camera-model": "Override Camera Model",
"root.settings.override-lens-model": "Override Lens Model",
"root.settings.select-overridable-metadata": "Select Overridable Metadata",
"root.settings.create-metadata": "Create Metadata",

"privacy-policy": "Privacy Policy",
"term-and-conditions": "Term and Conditions",
Expand Down
3 changes: 3 additions & 0 deletions web/src/locales/translations/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"ja": "日本語",
"ko": "한국어",

"name": "名前",
"make": "カメラメーカー",
"model": "カメラモデル",
"lens": "レンズモデル",
Expand Down Expand Up @@ -74,6 +75,8 @@
"root.settings.override-camera-maker": "カメラメーカーを上書き",
"root.settings.override-camera-model": "カメラモデルを上書き",
"root.settings.override-lens-model": "レンズモデルを上書き",
"root.settings.select-overridable-metadata": "上書き可能なメタデータを選択",
"root.settings.create-metadata": "メタデータを作成",

"privacy-policy": "プライバシーポリシー",
"term-and-conditions": "利用規約",
Expand Down
3 changes: 3 additions & 0 deletions web/src/locales/translations/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"ja": "日本語",
"ko": "한국어",

"name": "이름",
"make": "카메라 제조사",
"model": "카메라 모델",
"lens": "렌즈 모델",
Expand Down Expand Up @@ -75,6 +76,8 @@
"root.settings.override-camera-maker": "카메라 제조사 전역 변경",
"root.settings.override-camera-model": "카메라 모델 전역 변경",
"root.settings.override-lens-model": "렌즈 모델 전역 변경",
"root.settings.select-overridable-metadata": "전역 변경할 메타데이터 선택",
"root.settings.create-metadata": "메타데이터 생성",

"privacy-policy": "개인정보 처리방침",
"term-and-conditions": "이용약관",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ListButton } from 'konsta/react';
import { useTranslation } from 'react-i18next';
import { useStore } from '../../../store';
import AddIcon from '../../../icons/add.icon';

const AddOverridableMetadataButton = () => {
const { t } = useTranslation();
const { setAddOverridableMetadataPopup } = useStore();

return (
<ListButton onClick={() => setAddOverridableMetadataPopup(true)}>
<AddIcon size={18} />
<div style={{ width: 4 }} />
{t('root.settings.create-metadata')}
</ListButton>
);
};

export default AddOverridableMetadataButton;
85 changes: 85 additions & 0 deletions web/src/pages/metadata/components/add-override-metadata.popup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { Link, List, ListButton, ListInput, Navbar, Page, Popup } from 'konsta/react';
import { useStore } from '../../../store';
import { useTranslation } from 'react-i18next';
import { useEffect, useState } from 'react';

const AddOverrideMetadataPopup = () => {
const { t } = useTranslation();
const { addOverridableMetadataPopup, setAddOverridableMetadataPopup, setOverridableMetadata, overridableMetadata } = useStore();

const [name, setName] = useState('');
const [make, setMake] = useState('');
const [model, setModel] = useState('');
const [lens, setLens] = useState('');
const [focalLength, setFocalLength] = useState('');
const [focalLengthIn35mm, setFocalLengthIn35mm] = useState('');
const [aperture, setAperture] = useState('');
const [iso, setIso] = useState('');
const [shutter, setShutter] = useState('');
const [takenAt, setTakenAt] = useState('');

useEffect(() => {
setName('');
setMake('');
setModel('');
setLens('');
setFocalLength('');
setFocalLengthIn35mm('');
setAperture('');
setIso('');
setShutter('');
setTakenAt('');
}, [addOverridableMetadataPopup]);

const onCreateMetadata = () => {
if (!name) return;

setOverridableMetadata([
...overridableMetadata,
{
name,
make,
model,
lensModel: lens,
focalLength,
focalLengthIn35mm,
fNumber: aperture,
iso,
exposureTime: shutter,
takenAt,
},
]);

setAddOverridableMetadataPopup(false);
};

return (
<Popup opened={addOverridableMetadataPopup} onBackdropClick={() => setAddOverridableMetadataPopup(false)}>
<Page>
<Navbar
title={t('root.settings.create-metadata')}
right={
<Link navbar onClick={() => setAddOverridableMetadataPopup(false)}>
{t('close')}
</Link>
}
/>
<List strongIos inset>
<ListInput label={t('name') + '*'} type="text" value={name} onChange={(e) => setName(e.target.value)} />
<ListInput label={t('make')} type="text" value={make} onChange={(e) => setMake(e.target.value)} />
<ListInput label={t('model')} type="text" value={model} onChange={(e) => setModel(e.target.value)} />
<ListInput label={t('lens')} type="text" value={lens} onChange={(e) => setLens(e.target.value)} />
<ListInput label={t('focal') + ' (ex. 35mm)'} type="text" value={focalLength} onChange={(e) => setFocalLength(e.target.value)} />
<ListInput label={t('focal-35mm') + ' (ex. 50mm)'} type="text" value={focalLengthIn35mm} onChange={(e) => setFocalLengthIn35mm(e.target.value)} />
<ListInput label={t('aperture') + ' (ex. F2.8)'} type="text" value={aperture} onChange={(e) => setAperture(e.target.value)} />
<ListInput label={t('iso') + ' (ex. ISO1200)'} type="text" value={iso} onChange={(e) => setIso(e.target.value)} />
<ListInput label={t('shutter') + ' (ex. 1/200s)'} type="text" value={shutter} onChange={(e) => setShutter(e.target.value)} />
<ListInput label={t('taken-at') + ' (ex. 2024-05-06T08:35:38.223+09:00)'} type="text" value={takenAt} onChange={(e) => setTakenAt(e.target.value)} />
<ListButton onClick={onCreateMetadata}>{t('root.settings.create-metadata')}</ListButton>
</List>
</Page>
</Popup>
);
};

export default AddOverrideMetadataPopup;
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ListItem } from 'konsta/react';
import { useStore } from '../../../store';
import RemoveOneMetadataButton from './remove-one-metadata.button';

const OverridableMetadataList = () => {
const { overridableMetadata } = useStore();

return (
<>
{overridableMetadata.map((metadata, index) => (
<ListItem
key={index}
title={metadata.name}
text={`${metadata.make} ${metadata.model} ${metadata.lensModel} ${metadata.focalLength} ${metadata.focalLengthIn35mm} ${metadata.fNumber} ${metadata.iso} ${metadata.exposureTime} ${metadata.takenAt}`}
footer={
<div className="flex space-x-1 mt-1">
<RemoveOneMetadataButton index={index} />
</div>
}
/>
))}
</>
);
};

export default OverridableMetadataList;
31 changes: 31 additions & 0 deletions web/src/pages/metadata/components/remove-one-metadata.button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { IoTrashOutline } from 'react-icons/io5';
import { useStore } from '../../../store';
import { Button, Icon } from 'konsta/react';

interface RemoveOneMetadataButtonProps {
index: number;
}

const RemoveOneMetadataButton: React.FC<RemoveOneMetadataButtonProps> = ({ index }) => {
const { overridableMetadata, setOverridableMetadata, overrideMetadataIndex, setOverrideMetadataIndex } = useStore();

return (
<div className="w-10">
<Button
className="k-color-brand-red"
onClick={() => {
const newMetadata = overridableMetadata.filter((_, i) => i !== index);
setOverridableMetadata(newMetadata);

if (overrideMetadataIndex === index) {
setOverrideMetadataIndex(null);
}
}}
>
<Icon ios={<IoTrashOutline className="w-5 h-5" />} />
</Button>
</div>
);
};

export default RemoveOneMetadataButton;
28 changes: 28 additions & 0 deletions web/src/pages/metadata/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { List, Navbar, NavbarBackLink, Page } from 'konsta/react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import OverridableMetadataList from './components/overridable-metadata.list-item';
import AddOverridableMetadataButton from './components/add-overridable-metadata.button';
import AddOverrideMetadataPopup from './components/add-override-metadata.popup';

const MetadataPage = () => {
const navigator = useNavigate();
const { t } = useTranslation();

return (
<>
<Page>
<Navbar title={t('root.settings.create-metadata')} left={<NavbarBackLink text={t('back')} onClick={() => navigator(-1)} />} />

<List strong inset>
<OverridableMetadataList />
<AddOverridableMetadataButton />
</List>

<AddOverrideMetadataPopup />
</Page>
</>
);
};

export default MetadataPage;
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ListItem } from 'konsta/react';
import { useTranslation } from 'react-i18next';
import PencilIcon from '../../../icons/pencil.icon';
import { useNavigate } from 'react-router-dom';

const CreateOverrideMetadataListItem = () => {
const navigate = useNavigate();
const { t } = useTranslation();

return <ListItem media={<PencilIcon size={26} />} title={t('root.settings.create-metadata')} link onClick={() => navigate('/metadata')} />;
};

export default CreateOverrideMetadataListItem;
Loading