Skip to content

Commit

Permalink
feat: select multiple items
Browse files Browse the repository at this point in the history
  • Loading branch information
kimlimjustin committed Apr 14, 2024
1 parent 9195f0c commit f6dc559
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 13 deletions.
4 changes: 2 additions & 2 deletions src/Components/File/DetailFile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface IDetailFileProps {
metadata: FileMetaData;
handleFileRightClick: (e: MouseEvent<HTMLButtonElement, globalThis.MouseEvent>, path: string) => void;
handleFileDoubleClick: (isDir: boolean, dirName: string) => void;
handleFileSingleClick: (dirName: string) => void;
handleFileSingleClick: (e: MouseEvent<HTMLButtonElement>, dirName: string) => void;
}

const DetailFile = ({ metadata, handleFileRightClick, handleFileDoubleClick, handleFileSingleClick }: IDetailFileProps): JSX.Element => {
Expand All @@ -19,7 +19,7 @@ const DetailFile = ({ metadata, handleFileRightClick, handleFileDoubleClick, han
className="detail-view"
onContextMenu={(e) => handleFileRightClick(e, metadata.file_path)}
onDoubleClick={() => handleFileDoubleClick(!!metadata.is_dir, metadata.file_path)}
onClick={() => handleFileSingleClick(metadata.file_path)}
onClick={(e) => handleFileSingleClick(e, metadata.file_path)}
>
<ThemedSpan className="file-detail-view-basename" componentName="fileDetailViewBaseName">
{metadata.basename}
Expand Down
2 changes: 1 addition & 1 deletion src/Components/File/GridFile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface IGridFileProps {
metadata: FileMetaData;
handleFileRightClick: (e: MouseEvent<HTMLButtonElement, globalThis.MouseEvent>, path: string) => void;
handleFileDoubleClick: (isDir: boolean, dirName: string) => void;
handleFileSingleClick: (dirName: string) => void;
handleFileSingleClick: (e: MouseEvent<HTMLButtonElement>, dirName: string) => void;
}

const GridFile = ({ size, metadata, handleFileRightClick, handleFileDoubleClick, handleFileSingleClick }: IGridFileProps): JSX.Element => {
Expand Down
20 changes: 18 additions & 2 deletions src/Components/File/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { setActiveTab, updateTab } from "../../Store/ActionCreators/TabActionCre
import { IAppState } from "../../Store/Reducers";
import FileMetaData from "../../Typings/fileMetaData";
import { updateSelection } from "../../Store/ActionCreators/SelectionActionCreators";
import { sortFiles } from "../MainView";

export type FileDisplayMode = "GridLarge" | "GridMedium" | "GridSmall" | "Detail";

Expand All @@ -21,9 +22,24 @@ export interface IFileProps {
export const File = ({ mode, metadata }: IFileProps): JSX.Element => {
const dispatch = useDispatch();
const activeTab = useSelector<IAppState, IAppState["tabs"]["activeTab"]>((state) => state.tabs.activeTab);
const selected = useSelector<IAppState, IAppState["selection"]["selected"]>((state) => state.selection.selected);
const allFiles = useSelector<IAppState, IAppState["files"]["files"]>((state) => state.files.files);

const handleFileSingleClick = (filePath: string) => {
dispatch(updateSelection({ selected: [filePath] }));
const handleFileSingleClick = (e: MouseEvent<HTMLButtonElement>, filePath: string) => {
if (e.shiftKey) {
const files = Object.values(allFiles).sort(sortFiles);
const firstSelectedIndex = files.findIndex((file) => file.file_path === selected[0]);
const currentFileIndex = files.findIndex((file) => file.file_path === filePath);
const selectedFiles =
firstSelectedIndex < currentFileIndex
? files.slice(firstSelectedIndex, currentFileIndex + 1)
: files.slice(currentFileIndex, firstSelectedIndex + 1);
dispatch(updateSelection({ selected: selectedFiles.map((file) => file.file_path) }));
} else if (e.ctrlKey)
dispatch(
updateSelection({ selected: selected.includes(filePath) ? selected.filter((path) => path !== filePath) : [...selected, filePath] }),
);
else dispatch(updateSelection({ selected: [filePath] }));
};

const handleFileRightClick = (e: MouseEvent<HTMLButtonElement, globalThis.MouseEvent>, path: string) => {
Expand Down
12 changes: 7 additions & 5 deletions src/Components/MainView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ export interface IMainViewProps {
currentDirectory: string;
}

// Places directories first, sorts files and directories by name
// TODO: Implement sorting by other properties
export const sortFiles = (a: IFile, b: IFile): number => {
if ((!a.is_dir && b.is_dir) || (a.is_dir && !b.is_dir)) return b.is_dir ? 1 : -1; // Simulates xor for is_dir property
return a.basename || "" > b.basename || "" ? 1 : -1;
};

const MainView = ({ currentDirectory }: IMainViewProps) => {
const files = useSelector<IAppState, IAppState["files"]["files"]>((state) => state.files.files);
const filePreview = useSelector<IAppState, IAppState["files"]["filePreview"]>((state) => state.files.filePreview);

// Places directories first, sorts files and directories by name
const sortFiles = (a: IFile, b: IFile): number => {
if ((!a.is_dir && b.is_dir) || (a.is_dir && !b.is_dir)) return b.is_dir ? 1 : -1; // Simulates xor for is_dir property
return a.basename || "" > b.basename || "" ? 1 : -1;
};
return (
<ThemedDiv componentName="mainBox" className="main-box">
<div className="workspace">
Expand Down
16 changes: 13 additions & 3 deletions src/components/Infobar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useEffect } from "react";
import { ThemedDiv, ThemedSpan } from "../Theme";
import { useSelector } from "react-redux";
import { IAppState } from "../../Store/Reducers";
import formatBytes from "../Functions/filesize";

const Infobar = () => {
const files = useSelector<IAppState, IAppState["files"]["files"]>((state) => state.files.files);
Expand All @@ -13,9 +14,18 @@ const Infobar = () => {
{Object.keys(files).length} Items
</ThemedSpan>
{selected.length > 0 ? (
<ThemedSpan componentName="infobarItem" className="infobar-item">
{selected.length} Selected
</ThemedSpan>
<>
<ThemedSpan componentName="infobarItem" className="infobar-item">
{selected.length} Selected
</ThemedSpan>
<ThemedSpan componentName="infobarItem" className="infobar-item">
{selected.every((path) => Object.values(files).some((file) => file.file_path === path) && !files[path].is_dir) ? (
formatBytes(selected.reduce((accum, path) => accum + files[path].size, 0))
) : (
<></>
)}
</ThemedSpan>
</>
) : null}
</ThemedDiv>
<ThemedDiv componentName="infobarRight" className="infobar-right">
Expand Down

0 comments on commit f6dc559

Please sign in to comment.