Skip to content

Commit

Permalink
Add various UI improvements (#173, #174, #176) (#182)
Browse files Browse the repository at this point in the history
* Handle dense layout

* Add active filters indication (#176)

* Preserve file view type during session (#174)

* Enlarge links hitbox (#173)

* Fix link click handler
  • Loading branch information
stepan-anokhin authored Nov 9, 2020
1 parent d8861fa commit 9fbc231
Show file tree
Hide file tree
Showing 16 changed files with 293 additions and 104 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import TuneIcon from "@material-ui/icons/Tune";
import AddMediaButton from "./AddMediaButton";
import ViewSelector from "./ViewSelector";
import SortSelector from "./SortSelector";
import { View } from "./view";
import SquaredIconButton from "../../../../common/components/SquaredIconButton";
import { useIntl } from "react-intl";
import { FileSort } from "../../../state/FileSort";
import { Badge } from "@material-ui/core";
import FileListType from "../../../state/FileListType";

const useStyles = makeStyles((theme) => ({
actions: {
Expand Down Expand Up @@ -37,13 +38,15 @@ const FileBrowserActions = React.forwardRef(function FingerprintViewActions(
onToggleFilters,
showFiltersControls,
showFiltersRef,
activeFilters,
className,
...other
} = props;
const classes = useStyles();
const intl = useIntl();

return (
<div className={clsx(classes.actions, className)} ref={ref}>
<div className={clsx(classes.actions, className)} ref={ref} {...other}>
<AddMediaButton
onClick={onAddMedia}
variant="contained"
Expand All @@ -61,17 +64,19 @@ const FileBrowserActions = React.forwardRef(function FingerprintViewActions(
onChange={onViewChange}
/>
{showFilters && (
<SquaredIconButton
variant="outlined"
color="secondary"
ref={showFiltersRef}
onClick={onToggleFilters}
className={classes.action}
aria-controls={showFiltersControls}
aria-label={intl.formatMessage({ id: "actions.showFiltersPane" })}
>
<TuneIcon />
</SquaredIconButton>
<Badge badgeContent={activeFilters} color="primary">
<SquaredIconButton
variant="outlined"
color="secondary"
ref={showFiltersRef}
onClick={onToggleFilters}
className={classes.action}
aria-controls={showFiltersControls}
aria-label={intl.formatMessage({ id: "actions.showFiltersPane" })}
>
<TuneIcon />
</SquaredIconButton>
</Badge>
)}
</div>
);
Expand All @@ -87,7 +92,7 @@ FileBrowserActions.propTypes = {
FileSort.duplicates,
]),
onSortChange: PropTypes.func,
view: PropTypes.oneOf([View.list, View.grid]),
view: PropTypes.oneOf([FileListType.linear, FileListType.grid]),
/**
* Callback for switching List or Grid view
*/
Expand All @@ -102,6 +107,10 @@ FileBrowserActions.propTypes = {
* Reference to show filter button
*/
showFiltersRef: PropTypes.any,
/**
* Active filters count that should be displayed.
*/
activeFilters: PropTypes.number,
className: PropTypes.string,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React from "react";
import PropTypes from "prop-types";
import ListIcon from "@material-ui/icons/ViewStream";
import GridIcon from "@material-ui/icons/ViewModule";
import { View } from "./view";
import { useIntl } from "react-intl";
import IconSelect from "../../../../common/components/IconSelect";
import FileListType from "../../../state/FileListType";

function useMessages() {
const intl = useIntl();
Expand All @@ -21,12 +21,12 @@ function ViewSelector(props) {
return (
<IconSelect value={view} onChange={onChange} className={className}>
<IconSelect.Option
value={View.list}
value={FileListType.linear}
icon={ListIcon}
tooltip={messages.useList}
/>
<IconSelect.Option
value={View.grid}
value={FileListType.grid}
icon={GridIcon}
tooltip={messages.useGrid}
/>
Expand All @@ -35,7 +35,7 @@ function ViewSelector(props) {
}

ViewSelector.propTypes = {
view: PropTypes.oneOf([View.list, View.grid]),
view: PropTypes.oneOf([FileListType.linear, FileListType.grid]),
onChange: PropTypes.func,
className: PropTypes.string,
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export { default } from "./FileBrowserActions";
export { View } from "./view";

This file was deleted.

25 changes: 17 additions & 8 deletions web/src/collection/components/FileBrowserPage/FileBrowserPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import clsx from "clsx";
import PropTypes from "prop-types";
import { makeStyles } from "@material-ui/styles";
import ExpandLessIcon from "@material-ui/icons/ExpandLess";
import FileBrowserActions, { View } from "./FileBrowserActions";
import FileBrowserActions from "./FileBrowserActions";
import FilterPane from "./FilterPane";
import SearchTextInput from "./SearchTextInput";
import CategorySelector from "./CategorySelector";
Expand All @@ -26,6 +26,8 @@ import { useHistory, useLocation } from "react-router-dom";
import { routes } from "../../../routing/routes";
import { useIntl } from "react-intl";
import { defaultFilters } from "../../state/reducers";
import FileListType from "../../state/FileListType";
import { changeFileListView } from "../../state/actions";

const useStyles = makeStyles((theme) => ({
container: {
Expand Down Expand Up @@ -112,9 +114,9 @@ const useStyles = makeStyles((theme) => ({

function listComponent(view) {
switch (view) {
case View.list:
case FileListType.linear:
return FileLinearList;
case View.grid:
case FileListType.grid:
return FileGridList;
default:
throw new Error(`Unsupported fingerprints view type: ${view}`);
Expand All @@ -125,7 +127,6 @@ function FileBrowserPage(props) {
const { className } = props;
const classes = useStyles();
const [showFilters, setShowFilters] = useState(false);
const [view, setView] = useState(View.grid);
const collState = useSelector(selectColl);
const error = useSelector(selectError);
const loading = useSelector(selectLoading);
Expand All @@ -136,11 +137,13 @@ function FileBrowserPage(props) {
const [top, setTop] = useState(true);
const topRef = useRef(null);
const history = useHistory();
const view = collState.fileListType;
const List = listComponent(view);
const intl = useIntl();
const showFiltersRef = useRef();
const location = useLocation();
const keepFilters = location.state?.keepFilters;
const activeFilters = FilterPane.useActiveFilters();

useEffect(() => {
if (!keepFilters || collState.neverLoaded) {
Expand Down Expand Up @@ -174,6 +177,11 @@ function FileBrowserPage(props) {
[filters]
);

const handleChangeView = useCallback(
(view) => dispatch(changeFileListView(view)),
[]
);

const scrollTop = useCallback(() => scrollIntoView(topRef), [topRef]);

return (
Expand All @@ -188,12 +196,13 @@ function FileBrowserPage(props) {
sort={filters.sort}
onSortChange={handleChangeSort}
view={view}
onViewChange={setView}
onViewChange={handleChangeView}
onAddMedia={() => console.log("On Add Media")}
showFilters={!showFilters}
onToggleFilters={handleToggleFilters}
className={classes.actions}
showFiltersRef={showFiltersRef}
activeFilters={activeFilters}
/>
</div>
<div className={classes.filters}>
Expand All @@ -213,13 +222,13 @@ function FileBrowserPage(props) {
</div>
<div
className={clsx(classes.dataContainer, {
[classes.gridContainer]: view === View.grid,
[classes.gridContainer]: view === FileListType.grid,
})}
>
<List
className={clsx(classes.data, {
[classes.grid]: view === View.grid,
[classes.list]: view === View.list,
[classes.grid]: view === FileListType.grid,
[classes.list]: view === FileListType.linear,
})}
dense={showFilters}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const FileLinearListItem = React.memo(function FpLinearListItem(props) {
button = false,
highlight,
onClick,
dense,
className,
...other
} = props;
Expand All @@ -81,9 +82,9 @@ const FileLinearListItem = React.memo(function FpLinearListItem(props) {
<FileSummary.Name highlight={highlight} />
{medium && <FileSummary.Fingerprint />}
<FileSummary.Duration />
{large && <FileSummary.CreationDate />}
{large && <FileSummary.HasExif />}
{large && <FileSummary.HasAudio />}
{large && !dense && <FileSummary.CreationDate />}
{large && !dense && <FileSummary.HasExif />}
{large && !dense && <FileSummary.HasAudio />}
<IconButton aria-label={messages.moreLabel}>
<MoreHorizOutlinedIcon />
</IconButton>
Expand All @@ -93,10 +94,26 @@ const FileLinearListItem = React.memo(function FpLinearListItem(props) {
});

FileLinearListItem.propTypes = {
/**
* File to be displayed
*/
file: FileType.isRequired,
/**
* File name substring that should be highlighted.
*/
highlight: PropTypes.string,
/**
* Handle item click action.
*/
button: PropTypes.bool,
/**
* Handle item click.
*/
onClick: PropTypes.func,
/**
* Use dense layout.
*/
dense: PropTypes.bool,
className: PropTypes.string,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import FilterList from "./FilterList";
import { useFilters } from "./useFilters";
import { useIntl } from "react-intl";
import RangeFilter from "./RangeFilter";
import { useSelector } from "react-redux";
import { selectFilters } from "../../../state/selectors";
import objectDiff from "../../../../common/helpers/objectDiff";
import { initialState } from "../../../state";

/**
* Get i18n text
Expand All @@ -17,6 +21,15 @@ function useMessages() {
};
}

/**
* Get count of active filters.
*/
function useActiveFilters() {
const filters = useSelector(selectFilters);
const diff = objectDiff(filters, initialState.filters);
return Number(diff.length);
}

function ContentFilters(props) {
const { className } = props;
const messages = useMessages();
Expand All @@ -38,6 +51,11 @@ function ContentFilters(props) {
);
}

/**
* Hook to get count of active filters.
*/
ContentFilters.useActiveFilters = useActiveFilters;

ContentFilters.propTypes = {
className: PropTypes.string,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,20 @@ function getTabComponent(tab) {
}
}

/**
* Get total count of active filters managed by filter pane.
*/
function useActiveFilters() {
return ContentFilters.useActiveFilters() + MetadataFilters.useActiveFilters();
}

function FilterPane(props) {
const { onSave, onClose, className, ...other } = props;
const classes = useStyles();
const messages = useMessages();
const [tab, setTab] = useState(Tab.content);
const contentFilters = ContentFilters.useActiveFilters();
const metadataFilters = MetadataFilters.useActiveFilters();

const TabComponent = getTabComponent(tab);

Expand All @@ -75,8 +84,18 @@ function FilterPane(props) {
<div className={classes.filters}>
<FilterPaneHeader onClose={onClose} onSave={onSave} autoFocus={true} />
<SelectableTabs value={tab} onChange={setTab} className={classes.tabs}>
<SelectableTab label={messages.content} value={Tab.content} />
<SelectableTab label={messages.metadata} value={Tab.metadata} />
<SelectableTab
label={messages.content}
value={Tab.content}
badge={contentFilters}
badgeColor="primary"
/>
<SelectableTab
label={messages.metadata}
value={Tab.metadata}
badge={metadataFilters}
badgeColor="primary"
/>
<SelectableTab label={messages.presets} value={Tab.presets} />
</SelectableTabs>
<TabComponent />
Expand All @@ -85,6 +104,11 @@ function FilterPane(props) {
);
}

/**
* Hook to get total count of active filters managed by filter pane.
*/
FilterPane.useActiveFilters = useActiveFilters;

FilterPane.propTypes = {
onClose: PropTypes.func,
onSave: PropTypes.func,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,13 @@ FilterPaneHeader.propTypes = {
* Autofocus header when shown
*/
autoFocus: PropTypes.bool,
/**
* Handle close button.
*/
onClose: PropTypes.func,
/**
* Handle save preset button.
*/
onSave: PropTypes.func,
className: PropTypes.string,
"aria-controls": PropTypes.string,
Expand Down
Loading

0 comments on commit 9fbc231

Please sign in to comment.