diff --git a/web/src/collection/components/FileBrowserPage/FileLinearList/FileLinearListItem.js b/web/src/collection/components/FileBrowserPage/FileLinearList/FileLinearListItem.js index 6cb9ddf6..970ff82e 100644 --- a/web/src/collection/components/FileBrowserPage/FileLinearList/FileLinearListItem.js +++ b/web/src/collection/components/FileBrowserPage/FileLinearList/FileLinearListItem.js @@ -3,162 +3,91 @@ import clsx from "clsx"; import PropTypes from "prop-types"; import { makeStyles } from "@material-ui/styles"; import { FileType } from "../FileType"; -import VideocamOutlinedIcon from "@material-ui/icons/VideocamOutlined"; -import ScheduleOutlinedIcon from "@material-ui/icons/ScheduleOutlined"; -import EventAvailableOutlinedIcon from "@material-ui/icons/EventAvailableOutlined"; -import VolumeOffOutlinedIcon from "@material-ui/icons/VolumeOffOutlined"; import MoreHorizOutlinedIcon from "@material-ui/icons/MoreHorizOutlined"; -import AttributeText from "../../../../common/components/AttributeText"; import IconButton from "@material-ui/core/IconButton"; -import { - formatBool, - formatDate, - formatDuration, -} from "../../../../common/helpers/format"; import { useIntl } from "react-intl"; -import ExifIcon from "../../../../common/components/icons/ExifIcon"; +import FileSummary from "../../FileSummary"; +import { useMediaQuery } from "@material-ui/core"; +import useTheme from "@material-ui/styles/useTheme"; const useStyles = makeStyles((theme) => ({ - decor: { + container: { marginBottom: theme.spacing(2), backgroundColor: theme.palette.background.paper, borderRadius: 4, borderStyle: "solid", borderWidth: 1, borderColor: theme.palette.border.light, - }, - layout: { display: "flex", alignItems: "center", padding: theme.spacing(3), }, - buttonStyle: { + button: { cursor: "pointer", "&:hover": { borderColor: theme.palette.primary.light, }, }, - icon: { - color: theme.palette.primary.contrastText, - width: theme.spacing(3), - height: theme.spacing(3), - }, - iconContainer: { - backgroundColor: theme.palette.primary.main, - width: theme.spacing(4), - height: theme.spacing(4), - display: "flex", - alignItems: "center", - justifyContent: "center", - }, - fileName: { + summary: { flexGrow: 1, minWidth: 0, - marginLeft: theme.spacing(3), - }, - volume: { - color: theme.palette.action.textInactive, - }, - attr: { - marginLeft: theme.spacing(3), - marginRight: theme.spacing(3), - }, - divider: { - borderLeftStyle: "solid", - borderLeftColor: theme.palette.border.light, - borderLeftWidth: 1, - height: theme.spacing(4), - }, - md: { - [theme.breakpoints.down("md")]: { - display: "none", - }, - }, - sm: { - [theme.breakpoints.down("sm")]: { - display: "none", - }, }, })); -function useMessages(intl) { +/** + * Get i18n text. + */ +function useMessages() { + const intl = useIntl(); return { - attr: { - filename: intl.formatMessage({ id: "file.attr.name" }), - fingerprint: intl.formatMessage({ id: "file.attr.fingerprint" }), - quality: intl.formatMessage({ id: "file.attr.quality" }), - }, + containerLabel: intl.formatMessage({ id: "actions.showFileDetails" }), + moreLabel: intl.formatMessage({ id: "actions.showMoreOptions" }), }; } +/** + * Get screen size. + */ +function useScreenSize() { + const theme = useTheme(); + const medium = useMediaQuery(theme.breakpoints.up("md")); + const large = useMediaQuery(theme.breakpoints.up("lg")); + return { medium, large }; +} + const FileLinearListItem = React.memo(function FpLinearListItem(props) { - const { file, button = false, highlight, onClick, className } = props; - const intl = useIntl(); - const messages = useMessages(intl); + const { + file, + button = false, + highlight, + onClick, + className, + ...other + } = props; + const messages = useMessages(); + const { large, medium } = useScreenSize(); const handleClick = useCallback(() => onClick(file), [file, onClick]); const classes = useStyles(); return (
-
- -
- - -
- -
- -
- -
- -
- - - + + + {medium && } + + {large && } + {large && } + {large && } + + + +
); }); diff --git a/web/src/collection/components/FileComparisonPage/FileComparisonPage.js b/web/src/collection/components/FileComparisonPage/FileComparisonPage.js index 4e14e328..2cc2b0e9 100644 --- a/web/src/collection/components/FileComparisonPage/FileComparisonPage.js +++ b/web/src/collection/components/FileComparisonPage/FileComparisonPage.js @@ -1,11 +1,12 @@ -import React from "react"; +import React, { useCallback } from "react"; import clsx from "clsx"; import PropTypes from "prop-types"; import { makeStyles } from "@material-ui/styles"; import Grid from "@material-ui/core/Grid"; import MotherFile from "./MotherFile/MotherFile"; import MatchFiles from "./MatchFiles/MatchFiles"; -import { useParams } from "react-router-dom"; +import { useHistory, useParams } from "react-router-dom"; +import { routes } from "../../../routing/routes"; const useStyles = makeStyles((theme) => ({ root: { @@ -16,9 +17,16 @@ const useStyles = makeStyles((theme) => ({ function FileComparisonPage(props) { const { className } = props; const classes = useStyles(); - const { id: rawId } = useParams(); + const history = useHistory(); + const { id: rawId, matchFileId } = useParams(); const id = Number(rawId); + const handleMatchFileChange = useCallback( + (newMatchFileId) => + history.push(routes.collection.fileComparisonURL(id, newMatchFileId)), + [id] + ); + return (
@@ -26,7 +34,11 @@ function FileComparisonPage(props) { - +
diff --git a/web/src/collection/components/FileComparisonPage/MatchFiles/MatchFiles.js b/web/src/collection/components/FileComparisonPage/MatchFiles/MatchFiles.js index a319b029..1faf7804 100644 --- a/web/src/collection/components/FileComparisonPage/MatchFiles/MatchFiles.js +++ b/web/src/collection/components/FileComparisonPage/MatchFiles/MatchFiles.js @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useCallback, useEffect } from "react"; import clsx from "clsx"; import PropTypes from "prop-types"; import { makeStyles } from "@material-ui/styles"; @@ -29,6 +29,14 @@ const useStyles = makeStyles((theme) => ({ marginTop: 0, margin: theme.spacing(2), }, + errorMessage: { + minHeight: 150, + ...theme.mixins.title2, + color: theme.palette.action.textInactive, + display: "flex", + alignItems: "center", + justifyContent: "center", + }, })); /** @@ -39,14 +47,21 @@ function useMessages() { return { title: intl.formatMessage({ id: "file.match" }), loadError: intl.formatMessage({ id: "match.load.error" }), + notMatch: intl.formatMessage({ id: "match.notMatch" }), + noMatches: intl.formatMessage({ id: "match.noMatches" }), }; } function MatchFiles(props) { - const { motherFileId, className, ...other } = props; + const { + motherFileId, + matchFileId, + onMatchFileChange, + className, + ...other + } = props; const classes = useStyles(); const messages = useMessages(); - const [selected, setSelected] = useState(0); const { matches, @@ -56,6 +71,23 @@ function MatchFiles(props) { progress, } = useDirectMatches(motherFileId); + // Move to the first element when matches are loaded + useEffect(() => { + if (!hasMore && matches.length > 0 && matchFileId == null) { + onMatchFileChange(matches[0].file.id); + } + }, [hasMore, onMatchFileChange, motherFileId]); + + // Get index of the selected match file + const selected = matches.findIndex((match) => match.file.id === matchFileId); + + const handleSelectionChange = useCallback( + (index) => { + onMatchFileChange(matches[index].file.id); + }, + [hasMore, onMatchFileChange, motherFileId] + ); + let content; if (hasMore) { content = ( @@ -67,7 +99,7 @@ function MatchFiles(props) { progress={progress} /> ); - } else if (matches.length > 0) { + } else if (matches.length > 0 && selected >= 0) { content = (
); } else { - content = null; + const errorMessage = + matches.length === 0 ? messages.noMatches : messages.notMatch; + content =
{errorMessage}
; } return ( @@ -90,7 +124,7 @@ function MatchFiles(props) { )}
@@ -104,6 +138,14 @@ MatchFiles.propTypes = { * Mother file id. */ motherFileId: PropTypes.number.isRequired, + /** + * Match file id. + */ + matchFileId: PropTypes.number, + /** + * Handle match file change. + */ + onMatchFileChange: PropTypes.func.isRequired, className: PropTypes.string, }; diff --git a/web/src/collection/components/FileComparisonPage/MatchFiles/MatchSelector.js b/web/src/collection/components/FileComparisonPage/MatchFiles/MatchSelector.js index 6b327716..2cb492f5 100644 --- a/web/src/collection/components/FileComparisonPage/MatchFiles/MatchSelector.js +++ b/web/src/collection/components/FileComparisonPage/MatchFiles/MatchSelector.js @@ -70,7 +70,7 @@ function MatchSelector(props) { {messages.label}