diff --git a/public/info_icon.png b/public/info_icon.png new file mode 100644 index 000000000..7d0740a8f Binary files /dev/null and b/public/info_icon.png differ diff --git a/src/components/PhotoSwipe/PhotoSwipe.tsx b/src/components/PhotoSwipe/PhotoSwipe.tsx index 2b70acc1b..287d28cca 100644 --- a/src/components/PhotoSwipe/PhotoSwipe.tsx +++ b/src/components/PhotoSwipe/PhotoSwipe.tsx @@ -10,7 +10,14 @@ import { import { File } from 'services/fileService'; import constants from 'utils/strings/constants'; import DownloadManger from 'services/downloadManager'; +import EXIF from 'exif-js'; +import Modal from 'react-bootstrap/Modal'; +import Button from 'react-bootstrap/Button'; +import Form from 'react-bootstrap/Form'; +import styled from 'styled-components'; import events from './events'; +import { formatDateTime } from 'utils/file'; +import { FormCheck } from 'react-bootstrap'; interface Iprops { isOpen: boolean; @@ -24,12 +31,71 @@ interface Iprops { loadingBar: any; } +const LegendContainer = styled.div` + display: flex; + justify-content: space-between; +`; + +const Legend = styled.span` + font-size: 20px; + color: #ddd; + display: inline; +`; + +const Pre = styled.pre` + color: #aaa; + padding: 7px 15px; +`; + +const renderInfoItem = (label: string, value: string | JSX.Element) => ( + <> + {label} + {value} + +); + +function ExifData(props: { exif: any }) { + const { exif } = props; + const [showAll, setShowAll] = useState(false); + + const changeHandler = (e: React.ChangeEvent) => { + setShowAll(e.target.checked); + }; + + const renderAllValues = () => (
{exif.raw}
); + + const renderSelectedValues = () => (<> + {exif?.Make && exif?.Model && renderInfoItem(constants.DEVICE, `${exif.Make} ${exif.Model}`)} + {exif?.ImageWidth && exif?.ImageHeight && renderInfoItem(constants.IMAGE_SIZE, `${exif.ImageWidth} x ${exif.ImageHeight}`)} + {exif?.Flash && renderInfoItem(constants.FLASH, exif.Flash)} + {exif?.FocalLength && renderInfoItem(constants.FOCAL_LENGTH, exif.FocalLength.toString())} + {exif?.ApertureValue && renderInfoItem(constants.APERTURE, exif.ApertureValue.toString())} + {exif?.ISOSpeedRatings && renderInfoItem(constants.ISO, exif.ISOSpeedRatings.toString())} + ); + + return (<> + + {constants.EXIF} + + + + {constants.SHOW_ALL} + + + + {showAll ? renderAllValues() : renderSelectedValues()} + ); +} + function PhotoSwipe(props: Iprops) { const pswpElement = useRef(); const [photoSwipe, setPhotoSwipe] = useState>(); const { isOpen, items } = props; const [isFav, setIsFav] = useState(false); + const [showInfo, setShowInfo] = useState(false); + const [metadata, setMetaData] = useState(null); + const [exif, setExif] = useState(null); const needUpdate = useRef(false); useEffect(() => { @@ -69,14 +135,18 @@ function PhotoSwipe(props: Iprops) { return item.initialZoomLevel < 0.7 ? 1 : 1.5; }, getThumbBoundsFn: (index) => { - const file = items[index]; - const ele = document.getElementById(`thumb-${file.id}`); - if (ele) { - const rect = ele.getBoundingClientRect(); - const pageYScroll = window.pageYOffset || document.documentElement.scrollTop; - return { x: rect.left, y: rect.top + pageYScroll, w: rect.width }; + try { + const file = items[index]; + const ele = document.getElementById(`thumb-${file.id}`); + if (ele) { + const rect = ele.getBoundingClientRect(); + const pageYScroll = window.pageYOffset || document.documentElement.scrollTop; + return { x: rect.left, y: rect.top + pageYScroll, w: rect.width }; + } + return null; + } catch (e) { + return null; } - return null; }, }; const photoSwipe = new Photoswipe( @@ -100,6 +170,7 @@ function PhotoSwipe(props: Iprops) { } }); photoSwipe.listen('beforeChange', updateFavButton); + photoSwipe.listen('resize', checkExifAvailable); photoSwipe.init(); needUpdate.current = false; setPhotoSwipe(photoSwipe); @@ -151,6 +222,37 @@ function PhotoSwipe(props: Iprops) { } }; + const checkExifAvailable = () => { + setExif(null); + setTimeout(() => { + const img = document.querySelector('.pswp__img:not(.pswp__img--placeholder)'); + if (img) { + // @ts-expect-error + EXIF.getData(img, function() { + const exif = EXIF.getAllTags(this); + exif.raw = EXIF.pretty(this); + if (exif.raw) { + setExif(exif); + } + }); + } + }, 100); + }; + + const showExif = () => { + const file:File = items[photoSwipe?.getCurrentIndex()]; + if (file.metadata) { + setMetaData(file.metadata); + setExif(null); + checkExifAvailable(); + setShowInfo(true); + } + }; + + const handleCloseInfo = () => { + setShowInfo(false); + }; + const downloadFile = async (file) => { const { loadingBar } = props; const a = document.createElement('a'); @@ -167,76 +269,119 @@ function PhotoSwipe(props: Iprops) { let { className } = props; className = classnames(['pswp', className]).trim(); return ( -