mirror of
https://github.com/cloudreve/frontend.git
synced 2025-12-25 19:52:48 +00:00
feat(explorer): always show "Open with" in context menu (https://github.com/cloudreve/cloudreve/issues/2342)
This commit is contained in:
parent
bb3a5f9908
commit
34adaeb5dc
|
|
@ -1,20 +1,10 @@
|
|||
import {
|
||||
Box,
|
||||
Divider,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Menu,
|
||||
MenuItem,
|
||||
styled,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import { useAppDispatch, useAppSelector } from "../../../redux/hooks.ts";
|
||||
import { closeContextMenu } from "../../../redux/fileManagerSlice.ts";
|
||||
import useActionDisplayOpt from "./useActionDisplayOpt.ts";
|
||||
import { Box, Divider, ListItemIcon, ListItemText, Menu, MenuItem, styled, Typography, useTheme } from "@mui/material";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import DeleteOutlined from "../../Icons/DeleteOutlined.tsx";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { closeContextMenu } from "../../../redux/fileManagerSlice.ts";
|
||||
import { CreateNewDialogType } from "../../../redux/globalStateSlice.ts";
|
||||
import { useAppDispatch, useAppSelector } from "../../../redux/hooks.ts";
|
||||
import { downloadFiles } from "../../../redux/thunks/download.ts";
|
||||
import {
|
||||
batchGetDirectLinks,
|
||||
createNew,
|
||||
|
|
@ -30,44 +20,40 @@ import {
|
|||
renameFile,
|
||||
restoreFile,
|
||||
} from "../../../redux/thunks/file.ts";
|
||||
import RenameOutlined from "../../Icons/RenameOutlined.tsx";
|
||||
import BinFullOutlined from "../../Icons/BinFullOutlined.tsx";
|
||||
import { CascadingSubmenu } from "./CascadingMenu.tsx";
|
||||
import HistoryOutlined from "../../Icons/HistoryOutlined.tsx";
|
||||
import CopyOutlined from "../../Icons/CopyOutlined.tsx";
|
||||
import Tag from "../../Icons/Tag.tsx";
|
||||
import TagMenuItems from "./TagMenuItems.tsx";
|
||||
import Download from "../../Icons/Download.tsx";
|
||||
import ShareOutlined from "../../Icons/ShareOutlined.tsx";
|
||||
import FolderLink from "../../Icons/FolderLink.tsx";
|
||||
import { downloadFiles } from "../../../redux/thunks/download.ts";
|
||||
import Info from "../../Icons/Info.tsx";
|
||||
import WrenchSettings from "../../Icons/WrenchSettings.tsx";
|
||||
import Open from "../../Icons/Open.tsx";
|
||||
import { refreshFileList, uploadClicked, uploadFromClipboard } from "../../../redux/thunks/filemanager.ts";
|
||||
import { openViewers } from "../../../redux/thunks/viewer.ts";
|
||||
import AppFolder from "../../Icons/AppFolder.tsx";
|
||||
import OrganizeMenuItems from "./OrganizeMenuItems.tsx";
|
||||
import MoreMenuItems from "./MoreMenuItems.tsx";
|
||||
import OpenWithMenuItems from "./OpenWithMenuItems.tsx";
|
||||
import {
|
||||
refreshFileList,
|
||||
uploadClicked,
|
||||
uploadFromClipboard,
|
||||
} from "../../../redux/thunks/filemanager.ts";
|
||||
import ArrowSync from "../../Icons/ArrowSync.tsx";
|
||||
import FolderAdd from "../../Icons/FolderAdd.tsx";
|
||||
import { CreateNewDialogType } from "../../../redux/globalStateSlice.ts";
|
||||
import FileAdd from "../../Icons/FileAdd.tsx";
|
||||
import NewFileTemplateMenuItems from "./NewFileTemplateMenuItems.tsx";
|
||||
import Upload from "../../Icons/Upload.tsx";
|
||||
import FolderArrowUp from "../../Icons/FolderArrowUp.tsx";
|
||||
import { SelectType } from "../../Uploader/core";
|
||||
import Clipboard from "../../Icons/Clipboard.tsx";
|
||||
import ArchiveArrow from "../../Icons/ArchiveArrow.tsx";
|
||||
import ArrowSync from "../../Icons/ArrowSync.tsx";
|
||||
import BinFullOutlined from "../../Icons/BinFullOutlined.tsx";
|
||||
import Clipboard from "../../Icons/Clipboard.tsx";
|
||||
import CloudDownloadOutlined from "../../Icons/CloudDownloadOutlined.tsx";
|
||||
import CopyOutlined from "../../Icons/CopyOutlined.tsx";
|
||||
import DeleteOutlined from "../../Icons/DeleteOutlined.tsx";
|
||||
import Download from "../../Icons/Download.tsx";
|
||||
import Enter from "../../Icons/Enter.tsx";
|
||||
import FileAdd from "../../Icons/FileAdd.tsx";
|
||||
import FolderAdd from "../../Icons/FolderAdd.tsx";
|
||||
import FolderArrowUp from "../../Icons/FolderArrowUp.tsx";
|
||||
import FolderLink from "../../Icons/FolderLink.tsx";
|
||||
import FolderOutlined from "../../Icons/FolderOutlined.tsx";
|
||||
import HistoryOutlined from "../../Icons/HistoryOutlined.tsx";
|
||||
import Info from "../../Icons/Info.tsx";
|
||||
import LinkOutlined from "../../Icons/LinkOutlined.tsx";
|
||||
import Open from "../../Icons/Open.tsx";
|
||||
import RenameOutlined from "../../Icons/RenameOutlined.tsx";
|
||||
import ShareOutlined from "../../Icons/ShareOutlined.tsx";
|
||||
import Tag from "../../Icons/Tag.tsx";
|
||||
import Upload from "../../Icons/Upload.tsx";
|
||||
import WrenchSettings from "../../Icons/WrenchSettings.tsx";
|
||||
import { SelectType } from "../../Uploader/core";
|
||||
import { CascadingSubmenu } from "./CascadingMenu.tsx";
|
||||
import MoreMenuItems from "./MoreMenuItems.tsx";
|
||||
import NewFileTemplateMenuItems from "./NewFileTemplateMenuItems.tsx";
|
||||
import OpenWithMenuItems from "./OpenWithMenuItems.tsx";
|
||||
import OrganizeMenuItems from "./OrganizeMenuItems.tsx";
|
||||
import TagMenuItems from "./TagMenuItems.tsx";
|
||||
import useActionDisplayOpt from "./useActionDisplayOpt.ts";
|
||||
|
||||
export const SquareMenu = styled(Menu)(() => ({
|
||||
"& .MuiPaper-root": {
|
||||
|
|
@ -75,13 +61,11 @@ export const SquareMenu = styled(Menu)(() => ({
|
|||
},
|
||||
}));
|
||||
|
||||
export const SquareMenuItem = styled(MenuItem)<{ hoverColor?: string }>(
|
||||
({ theme, hoverColor }) => ({
|
||||
"&:hover .MuiListItemIcon-root": {
|
||||
color: hoverColor ?? theme.palette.primary.main,
|
||||
},
|
||||
}),
|
||||
);
|
||||
export const SquareMenuItem = styled(MenuItem)<{ hoverColor?: string }>(({ theme, hoverColor }) => ({
|
||||
"&:hover .MuiListItemIcon-root": {
|
||||
color: hoverColor ?? theme.palette.primary.main,
|
||||
},
|
||||
}));
|
||||
|
||||
export const DenseDivider = styled(Divider)(() => ({
|
||||
margin: "4px 0 !important",
|
||||
|
|
@ -90,14 +74,9 @@ export const DenseDivider = styled(Divider)(() => ({
|
|||
export const EmptyMenu = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Box
|
||||
sx={{ py: 0.5, px: 1, display: "flex", alignItems: "center" }}
|
||||
color={"text.secondary"}
|
||||
>
|
||||
<Box sx={{ py: 0.5, px: 1, display: "flex", alignItems: "center" }} color={"text.secondary"}>
|
||||
<Info sx={{ mr: 1 }} />
|
||||
<Typography variant="body2">
|
||||
{t("fileManager.noActionsCanBeDone")}
|
||||
</Typography>
|
||||
<Typography variant="body2">{t("fileManager.noActionsCanBeDone")}</Typography>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
|
@ -110,44 +89,29 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const theme = useTheme();
|
||||
const contextMenuOpen = useAppSelector(
|
||||
(state) => state.fileManager[fmIndex].contextMenuOpen,
|
||||
);
|
||||
const contextMenuType = useAppSelector(
|
||||
(state) => state.fileManager[fmIndex].contextMenuType,
|
||||
);
|
||||
const contextMenuPos = useAppSelector(
|
||||
(state) => state.fileManager[fmIndex].contextMenuPos,
|
||||
);
|
||||
const selected = useAppSelector(
|
||||
(state) => state.fileManager[fmIndex].selected,
|
||||
);
|
||||
const targetOverwrite = useAppSelector(
|
||||
(state) => state.fileManager[fmIndex].contextMenuTargets,
|
||||
);
|
||||
const contextMenuOpen = useAppSelector((state) => state.fileManager[fmIndex].contextMenuOpen);
|
||||
const contextMenuType = useAppSelector((state) => state.fileManager[fmIndex].contextMenuType);
|
||||
const contextMenuPos = useAppSelector((state) => state.fileManager[fmIndex].contextMenuPos);
|
||||
const selected = useAppSelector((state) => state.fileManager[fmIndex].selected);
|
||||
const targetOverwrite = useAppSelector((state) => state.fileManager[fmIndex].contextMenuTargets);
|
||||
|
||||
const targets = useMemo(() => {
|
||||
const targetsMap = targetOverwrite ?? selected;
|
||||
return Object.keys(targetsMap).map((key) => targetsMap[key]);
|
||||
}, [targetOverwrite, selected]);
|
||||
|
||||
const parent = useAppSelector(
|
||||
(state) => state.fileManager[fmIndex].list?.parent,
|
||||
);
|
||||
const parent = useAppSelector((state) => state.fileManager[fmIndex].list?.parent);
|
||||
|
||||
const displayOpt = useActionDisplayOpt(
|
||||
targets,
|
||||
contextMenuType,
|
||||
parent,
|
||||
fmIndex,
|
||||
);
|
||||
const displayOpt = useActionDisplayOpt(targets, contextMenuType, parent, fmIndex);
|
||||
const onClose = useCallback(() => {
|
||||
dispatch(closeContextMenu({ index: fmIndex, value: undefined }));
|
||||
}, [dispatch]);
|
||||
|
||||
const showOpenWithCascading = displayOpt.showOpenWithCascading && displayOpt.showOpenWithCascading();
|
||||
const showOpenWith = displayOpt.showOpenWith && displayOpt.showOpenWith();
|
||||
let part1 =
|
||||
displayOpt.showOpen ||
|
||||
showOpenWithCascading ||
|
||||
showOpenWith ||
|
||||
displayOpt.showEnter ||
|
||||
displayOpt.showDownload ||
|
||||
|
|
@ -163,16 +127,9 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
displayOpt.showCopy ||
|
||||
displayOpt.showDirectLink;
|
||||
let part3 =
|
||||
displayOpt.showTags ||
|
||||
displayOpt.showOrganize ||
|
||||
displayOpt.showMore ||
|
||||
displayOpt.showNewFileFromTemplate;
|
||||
let part4 =
|
||||
displayOpt.showInfo ||
|
||||
displayOpt.showGoToParent ||
|
||||
displayOpt.showGoToSharedLink;
|
||||
let part5 =
|
||||
displayOpt.showRestore || displayOpt.showDelete || displayOpt.showRefresh;
|
||||
displayOpt.showTags || displayOpt.showOrganize || displayOpt.showMore || displayOpt.showNewFileFromTemplate;
|
||||
let part4 = displayOpt.showInfo || displayOpt.showGoToParent || displayOpt.showGoToSharedLink;
|
||||
let part5 = displayOpt.showRestore || displayOpt.showDelete || displayOpt.showRefresh;
|
||||
const showDivider1 = part1 && part2;
|
||||
const showDivider2 = part2 && part3;
|
||||
const showDivider3 = part3 && part4;
|
||||
|
|
@ -181,15 +138,11 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
const part1Elements = part1 ? (
|
||||
<>
|
||||
{displayOpt.showUpload && (
|
||||
<SquareMenuItem
|
||||
onClick={() => dispatch(uploadClicked(0, SelectType.File))}
|
||||
>
|
||||
<SquareMenuItem onClick={() => dispatch(uploadClicked(0, SelectType.File))}>
|
||||
<ListItemIcon>
|
||||
<Upload fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
{t("application:fileManager.uploadFiles")}
|
||||
</ListItemText>
|
||||
<ListItemText>{t("application:fileManager.uploadFiles")}</ListItemText>
|
||||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showEnter && (
|
||||
|
|
@ -201,15 +154,11 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showUpload && (
|
||||
<SquareMenuItem
|
||||
onClick={() => dispatch(uploadClicked(0, SelectType.Directory))}
|
||||
>
|
||||
<SquareMenuItem onClick={() => dispatch(uploadClicked(0, SelectType.Directory))}>
|
||||
<ListItemIcon>
|
||||
<FolderArrowUp fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
{t("application:fileManager.uploadFolder")}
|
||||
</ListItemText>
|
||||
<ListItemText>{t("application:fileManager.uploadFolder")}</ListItemText>
|
||||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showUpload && (
|
||||
|
|
@ -217,9 +166,7 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
<ListItemIcon>
|
||||
<Clipboard fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
{t("application:uploader.uploadFromClipboard")}
|
||||
</ListItemText>
|
||||
<ListItemText>{t("application:uploader.uploadFromClipboard")}</ListItemText>
|
||||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showRemoteDownload && (
|
||||
|
|
@ -227,22 +174,18 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
<ListItemIcon>
|
||||
<CloudDownloadOutlined fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
{t("application:fileManager.newRemoteDownloads")}
|
||||
</ListItemText>
|
||||
<ListItemText>{t("application:fileManager.newRemoteDownloads")}</ListItemText>
|
||||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showOpen && (
|
||||
<SquareMenuItem
|
||||
onClick={() => dispatch(openViewers(fmIndex, targets[0]))}
|
||||
>
|
||||
<SquareMenuItem onClick={() => dispatch(openViewers(fmIndex, targets[0]))}>
|
||||
<ListItemIcon>
|
||||
<Open fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t("application:fileManager.open")}</ListItemText>
|
||||
</SquareMenuItem>
|
||||
)}
|
||||
{showOpenWith && (
|
||||
{showOpenWithCascading && (
|
||||
<CascadingSubmenu
|
||||
popupId={"openWith"}
|
||||
title={t("application:fileManager.openWith")}
|
||||
|
|
@ -251,10 +194,16 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
<OpenWithMenuItems displayOpt={displayOpt} targets={targets} />
|
||||
</CascadingSubmenu>
|
||||
)}
|
||||
{showOpenWith && (
|
||||
<SquareMenuItem onClick={() => dispatch(openViewers(fmIndex, targets[0], targets[0].size, undefined, true))}>
|
||||
<ListItemIcon>
|
||||
<AppFolder fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>{t("application:fileManager.openWith")}</ListItemText>
|
||||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showDownload && (
|
||||
<SquareMenuItem
|
||||
onClick={() => dispatch(downloadFiles(fmIndex, targets))}
|
||||
>
|
||||
<SquareMenuItem onClick={() => dispatch(downloadFiles(fmIndex, targets))}>
|
||||
<ListItemIcon>
|
||||
<Download fontSize="small" />
|
||||
</ListItemIcon>
|
||||
|
|
@ -262,27 +211,19 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showExtractArchive && (
|
||||
<SquareMenuItem
|
||||
onClick={() => dispatch(extractArchive(fmIndex, targets[0]))}
|
||||
>
|
||||
<SquareMenuItem onClick={() => dispatch(extractArchive(fmIndex, targets[0]))}>
|
||||
<ListItemIcon>
|
||||
<ArchiveArrow fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
{t("application:fileManager.extractArchive")}
|
||||
</ListItemText>
|
||||
<ListItemText>{t("application:fileManager.extractArchive")}</ListItemText>
|
||||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showTorrentRemoteDownload && (
|
||||
<SquareMenuItem
|
||||
onClick={() => dispatch(newRemoteDownload(fmIndex, targets[0]))}
|
||||
>
|
||||
<SquareMenuItem onClick={() => dispatch(newRemoteDownload(fmIndex, targets[0]))}>
|
||||
<ListItemIcon>
|
||||
<CloudDownloadOutlined fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
{t("application:fileManager.createRemoteDownloadForTorrent")}
|
||||
</ListItemText>
|
||||
<ListItemText>{t("application:fileManager.createRemoteDownloadForTorrent")}</ListItemText>
|
||||
</SquareMenuItem>
|
||||
)}
|
||||
</>
|
||||
|
|
@ -291,11 +232,7 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
const part2Elements = part2 ? (
|
||||
<>
|
||||
{displayOpt.showCreateFolder && (
|
||||
<SquareMenuItem
|
||||
onClick={() =>
|
||||
dispatch(createNew(fmIndex, CreateNewDialogType.folder))
|
||||
}
|
||||
>
|
||||
<SquareMenuItem onClick={() => dispatch(createNew(fmIndex, CreateNewDialogType.folder))}>
|
||||
<ListItemIcon>
|
||||
<FolderAdd fontSize="small" />
|
||||
</ListItemIcon>
|
||||
|
|
@ -303,9 +240,7 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showCreateFile && (
|
||||
<SquareMenuItem
|
||||
onClick={() => dispatch(createNew(fmIndex, CreateNewDialogType.file))}
|
||||
>
|
||||
<SquareMenuItem onClick={() => dispatch(createNew(fmIndex, CreateNewDialogType.file))}>
|
||||
<ListItemIcon>
|
||||
<FileAdd fontSize="small" />
|
||||
</ListItemIcon>
|
||||
|
|
@ -313,9 +248,7 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showShare && (
|
||||
<SquareMenuItem
|
||||
onClick={() => dispatch(openShareDialog(fmIndex, targets[0]))}
|
||||
>
|
||||
<SquareMenuItem onClick={() => dispatch(openShareDialog(fmIndex, targets[0]))}>
|
||||
<ListItemIcon>
|
||||
<ShareOutlined fontSize="small" />
|
||||
</ListItemIcon>
|
||||
|
|
@ -323,9 +256,7 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showRename && (
|
||||
<SquareMenuItem
|
||||
onClick={() => dispatch(renameFile(fmIndex, targets[0]))}
|
||||
>
|
||||
<SquareMenuItem onClick={() => dispatch(renameFile(fmIndex, targets[0]))}>
|
||||
<ListItemIcon>
|
||||
<RenameOutlined fontSize="small" />
|
||||
</ListItemIcon>
|
||||
|
|
@ -333,9 +264,7 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showCopy && (
|
||||
<SquareMenuItem
|
||||
onClick={() => dispatch(dialogBasedMoveCopy(fmIndex, targets, true))}
|
||||
>
|
||||
<SquareMenuItem onClick={() => dispatch(dialogBasedMoveCopy(fmIndex, targets, true))}>
|
||||
<ListItemIcon>
|
||||
<CopyOutlined fontSize="small" />
|
||||
</ListItemIcon>
|
||||
|
|
@ -343,15 +272,11 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showDirectLink && (
|
||||
<SquareMenuItem
|
||||
onClick={() => dispatch(batchGetDirectLinks(fmIndex, targets))}
|
||||
>
|
||||
<SquareMenuItem onClick={() => dispatch(batchGetDirectLinks(fmIndex, targets))}>
|
||||
<ListItemIcon>
|
||||
<LinkOutlined fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
{t("application:fileManager.getSourceLink")}
|
||||
</ListItemText>
|
||||
<ListItemText>{t("application:fileManager.getSourceLink")}</ListItemText>
|
||||
</SquareMenuItem>
|
||||
)}
|
||||
</>
|
||||
|
|
@ -360,11 +285,7 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
const part3Elements = part3 ? (
|
||||
<>
|
||||
{displayOpt.showTags && (
|
||||
<CascadingSubmenu
|
||||
popupId={"tags"}
|
||||
title={t("application:fileManager.tags")}
|
||||
icon={<Tag fontSize="small" />}
|
||||
>
|
||||
<CascadingSubmenu popupId={"tags"} title={t("application:fileManager.tags")} icon={<Tag fontSize="small" />}>
|
||||
<TagMenuItems displayOpt={displayOpt} targets={targets} />
|
||||
</CascadingSubmenu>
|
||||
)}
|
||||
|
|
@ -386,24 +307,18 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
<MoreMenuItems displayOpt={displayOpt} targets={targets} />
|
||||
</CascadingSubmenu>
|
||||
)}
|
||||
{displayOpt.showNewFileFromTemplate && (
|
||||
<NewFileTemplateMenuItems displayOpt={displayOpt} targets={targets} />
|
||||
)}
|
||||
{displayOpt.showNewFileFromTemplate && <NewFileTemplateMenuItems displayOpt={displayOpt} targets={targets} />}
|
||||
</>
|
||||
) : undefined;
|
||||
|
||||
const part4Elements = part4 ? (
|
||||
<>
|
||||
{displayOpt.showGoToSharedLink && (
|
||||
<SquareMenuItem
|
||||
onClick={() => dispatch(goToSharedLink(fmIndex, targets[0]))}
|
||||
>
|
||||
<SquareMenuItem onClick={() => dispatch(goToSharedLink(fmIndex, targets[0]))}>
|
||||
<ListItemIcon>
|
||||
<FolderLink fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
{t("application:fileManager.goToSharedLink")}
|
||||
</ListItemText>
|
||||
<ListItemText>{t("application:fileManager.goToSharedLink")}</ListItemText>
|
||||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showGoToParent && (
|
||||
|
|
@ -411,21 +326,15 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
<ListItemIcon>
|
||||
<FolderOutlined fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
{t("application:fileManager.openParentFolder")}
|
||||
</ListItemText>
|
||||
<ListItemText>{t("application:fileManager.openParentFolder")}</ListItemText>
|
||||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showInfo && (
|
||||
<SquareMenuItem
|
||||
onClick={() => dispatch(openSidebar(fmIndex, targets[0]))}
|
||||
>
|
||||
<SquareMenuItem onClick={() => dispatch(openSidebar(fmIndex, targets[0]))}>
|
||||
<ListItemIcon>
|
||||
<Info fontSize="small" />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
{t("application:fileManager.viewDetails")}
|
||||
</ListItemText>
|
||||
<ListItemText>{t("application:fileManager.viewDetails")}</ListItemText>
|
||||
</SquareMenuItem>
|
||||
)}
|
||||
</>
|
||||
|
|
@ -442,10 +351,7 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
</SquareMenuItem>
|
||||
)}
|
||||
{displayOpt.showDelete && (
|
||||
<SquareMenuItem
|
||||
hoverColor={theme.palette.error.light}
|
||||
onClick={() => dispatch(deleteFile(fmIndex, targets))}
|
||||
>
|
||||
<SquareMenuItem hoverColor={theme.palette.error.light} onClick={() => dispatch(deleteFile(fmIndex, targets))}>
|
||||
<ListItemIcon>
|
||||
<DeleteOutlined fontSize="small" />
|
||||
</ListItemIcon>
|
||||
|
|
@ -463,13 +369,9 @@ const ContextMenu = ({ fmIndex = 0 }: ContextMenuProps) => {
|
|||
</>
|
||||
) : undefined;
|
||||
|
||||
const allParts = [
|
||||
part1Elements,
|
||||
part2Elements,
|
||||
part3Elements,
|
||||
part4Elements,
|
||||
part5Elements,
|
||||
].filter((p) => p != undefined);
|
||||
const allParts = [part1Elements, part2Elements, part3Elements, part4Elements, part5Elements].filter(
|
||||
(p) => p != undefined,
|
||||
);
|
||||
|
||||
return (
|
||||
<SquareMenu
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ export interface DisplayOption {
|
|||
|
||||
showEnter?: boolean;
|
||||
showOpen?: boolean;
|
||||
showOpenWithCascading?: () => boolean;
|
||||
showOpenWith?: () => boolean;
|
||||
showDownload?: boolean;
|
||||
showGoToSharedLink?: boolean;
|
||||
|
|
@ -228,7 +229,13 @@ export const getActionOpt = (
|
|||
display.orCapability &&
|
||||
(currentUserAnonymous?.group?.direct_link_batch_size ?? 0) >= targets.length &&
|
||||
display.orCapability.enabled(NavigatorCapability.download_file);
|
||||
display.showOpen = targets.length == 1 && display.hasFile && display.showDownload && !!viewerSetting;
|
||||
display.showOpen =
|
||||
targets.length == 1 &&
|
||||
display.hasFile &&
|
||||
display.showDownload &&
|
||||
!!viewerSetting &&
|
||||
!!firstFileSuffix &&
|
||||
!!viewerSetting?.[firstFileSuffix];
|
||||
display.showEnter =
|
||||
targets.length == 1 &&
|
||||
display.hasFolder &&
|
||||
|
|
@ -249,11 +256,13 @@ export const getActionOpt = (
|
|||
groupBs.enabled(GroupPermission.remote_download) &&
|
||||
firstFileSuffix == "torrent";
|
||||
|
||||
display.showOpenWith = () => false;
|
||||
display.showOpenWithCascading = () => false;
|
||||
display.showOpenWith = () => targets.length == 1 && !!display.hasFile && !!display.showDownload;
|
||||
if (display.showOpen) {
|
||||
display.showOpen = !!firstFileSuffix && !!viewerSetting?.[firstFileSuffix];
|
||||
display.showOpenWithCascading = () =>
|
||||
!!(display.showOpen && viewerSetting && viewerSetting[firstFileSuffix ?? ""]?.length >= 1);
|
||||
display.showOpenWith = () =>
|
||||
!!(display.showOpen && viewerSetting && viewerSetting[firstFileSuffix ?? ""]?.length > 1);
|
||||
!!(display.showOpen && viewerSetting && viewerSetting[firstFileSuffix ?? ""]?.length < 1);
|
||||
}
|
||||
display.showOrganize = display.showPin || display.showMove || display.showChangeFolderColor || display.showChangeIcon;
|
||||
display.showGoToSharedLink =
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
|
|
@ -12,25 +11,24 @@ import {
|
|||
ListItemText,
|
||||
Stack,
|
||||
} from "@mui/material";
|
||||
import { useAppDispatch, useAppSelector } from "../../../redux/hooks.ts";
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import DraggableDialog, {
|
||||
StyledDialogContentText,
|
||||
} from "../../Dialogs/DraggableDialog.tsx";
|
||||
import { closeViewerSelector } from "../../../redux/globalStateSlice.ts";
|
||||
import { fileExtension } from "../../../util";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Viewer, ViewerType } from "../../../api/explorer.ts";
|
||||
import { builtInViewers, openViewer } from "../../../redux/thunks/viewer.ts";
|
||||
import Image from "../../Icons/Image.tsx";
|
||||
import AutoHeight from "../../Common/AutoHeight.tsx";
|
||||
import Markdown from "../../Icons/Markdown.tsx";
|
||||
import DocumentPDF from "../../Icons/DocumentPDF.tsx";
|
||||
import Book from "../../Icons/Book.tsx";
|
||||
import MusicNote1 from "../../Icons/MusicNote1.tsx";
|
||||
import MoreHorizontal from "../../Icons/MoreHorizontal.tsx";
|
||||
import { closeViewerSelector } from "../../../redux/globalStateSlice.ts";
|
||||
import { useAppDispatch, useAppSelector } from "../../../redux/hooks.ts";
|
||||
import { ViewersByID } from "../../../redux/siteConfigSlice.ts";
|
||||
import { builtInViewers, openViewer } from "../../../redux/thunks/viewer.ts";
|
||||
import SessionManager, { UserSettings } from "../../../session";
|
||||
import { fileExtension } from "../../../util";
|
||||
import AutoHeight from "../../Common/AutoHeight.tsx";
|
||||
import { SecondaryButton } from "../../Common/StyledComponents.tsx";
|
||||
import DraggableDialog, { StyledDialogContentText } from "../../Dialogs/DraggableDialog.tsx";
|
||||
import Book from "../../Icons/Book.tsx";
|
||||
import DocumentPDF from "../../Icons/DocumentPDF.tsx";
|
||||
import Image from "../../Icons/Image.tsx";
|
||||
import Markdown from "../../Icons/Markdown.tsx";
|
||||
import MoreHorizontal from "../../Icons/MoreHorizontal.tsx";
|
||||
import MusicNote1 from "../../Icons/MusicNote1.tsx";
|
||||
|
||||
export interface ViewerIconProps {
|
||||
viewer: Viewer;
|
||||
|
|
@ -48,11 +46,7 @@ export const ViewerIDWithDefaultIcons = [
|
|||
builtInViewers.markdown,
|
||||
];
|
||||
|
||||
export const ViewerIcon = ({
|
||||
viewer,
|
||||
size = 32,
|
||||
py = 0.5,
|
||||
}: ViewerIconProps) => {
|
||||
export const ViewerIcon = ({ viewer, size = 32, py = 0.5 }: ViewerIconProps) => {
|
||||
const BuiltinIcons = useMemo(() => {
|
||||
if (viewer.icon) {
|
||||
return undefined;
|
||||
|
|
@ -63,23 +57,18 @@ export const ViewerIcon = ({
|
|||
case builtInViewers.image:
|
||||
return <Image sx={{ width: size, height: size, color: "#d32f2f" }} />;
|
||||
case builtInViewers.pdf:
|
||||
return (
|
||||
<DocumentPDF sx={{ width: size, height: size, color: "#f44336" }} />
|
||||
);
|
||||
return <DocumentPDF sx={{ width: size, height: size, color: "#f44336" }} />;
|
||||
case builtInViewers.epub:
|
||||
return <Book sx={{ width: size, height: size, color: "#81b315" }} />;
|
||||
case builtInViewers.music:
|
||||
return (
|
||||
<MusicNote1 sx={{ width: size, height: size, color: "#651fff" }} />
|
||||
);
|
||||
return <MusicNote1 sx={{ width: size, height: size, color: "#651fff" }} />;
|
||||
case builtInViewers.markdown:
|
||||
return (
|
||||
<Markdown
|
||||
sx={{
|
||||
width: size,
|
||||
height: size,
|
||||
color: (theme) =>
|
||||
theme.palette.mode == "dark" ? "#cbcbcb" : "#383838",
|
||||
color: (theme) => (theme.palette.mode == "dark" ? "#cbcbcb" : "#383838"),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
|
@ -106,18 +95,14 @@ export const ViewerIcon = ({
|
|||
const OpenWith = () => {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const [selectedViewer, setSelectedViewer] = React.useState<Viewer | null>(
|
||||
null,
|
||||
);
|
||||
const [selectedViewer, setSelectedViewer] = React.useState<Viewer | null>(null);
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
|
||||
const selectorState = useAppSelector(
|
||||
(state) => state.globalState.viewerSelector,
|
||||
);
|
||||
const selectorState = useAppSelector((state) => state.globalState.viewerSelector);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectorState?.open) {
|
||||
setExpanded(false);
|
||||
setExpanded(!selectorState.viewers);
|
||||
setSelectedViewer(null);
|
||||
}
|
||||
}, [selectorState]);
|
||||
|
|
@ -140,10 +125,7 @@ const OpenWith = () => {
|
|||
}
|
||||
|
||||
if (always) {
|
||||
SessionManager.set(
|
||||
UserSettings.OpenWithPrefix + ext,
|
||||
viewer?.id ?? selectedViewer?.id,
|
||||
);
|
||||
SessionManager.set(UserSettings.OpenWithPrefix + ext, viewer?.id ?? selectedViewer?.id);
|
||||
}
|
||||
|
||||
dispatch(
|
||||
|
|
@ -157,6 +139,15 @@ const OpenWith = () => {
|
|||
dispatch(closeViewerSelector());
|
||||
};
|
||||
|
||||
const onViewerClick = (viewer: Viewer) => {
|
||||
if (selectorState?.viewers) {
|
||||
setSelectedViewer(viewer);
|
||||
} else {
|
||||
// For files without matching viewers, open the selected viewer without asking for preference
|
||||
openWith(false, viewer);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<DraggableDialog
|
||||
title={t("application:fileManager.openWith")}
|
||||
|
|
@ -183,16 +174,12 @@ const OpenWith = () => {
|
|||
overflow: "auto",
|
||||
}}
|
||||
>
|
||||
{(
|
||||
(expanded
|
||||
? Object.values(ViewersByID)
|
||||
: selectorState?.viewers) ?? emptyViewer
|
||||
).map((viewer) => (
|
||||
{((expanded ? Object.values(ViewersByID) : selectorState?.viewers) ?? emptyViewer).map((viewer) => (
|
||||
<ListItem
|
||||
disablePadding
|
||||
key={viewer.id}
|
||||
onDoubleClick={() => openWith(false, viewer)}
|
||||
onClick={() => setSelectedViewer(viewer)}
|
||||
onClick={() => onViewerClick(viewer)}
|
||||
>
|
||||
<ListItemButton selected={viewer.id == selectedViewer?.id}>
|
||||
<ListItemAvatar sx={{ minWidth: "48px" }}>
|
||||
|
|
@ -221,20 +208,12 @@ const OpenWith = () => {
|
|||
<Divider />
|
||||
<Grid container spacing={2} sx={{ p: 2 }}>
|
||||
<Grid md={6} xs={12} item>
|
||||
<SecondaryButton
|
||||
fullWidth
|
||||
variant={"contained"}
|
||||
onClick={() => openWith(true)}
|
||||
>
|
||||
<SecondaryButton fullWidth variant={"contained"} onClick={() => openWith(true)}>
|
||||
{t("modals.always")}
|
||||
</SecondaryButton>
|
||||
</Grid>
|
||||
<Grid md={6} xs={12} item>
|
||||
<SecondaryButton
|
||||
fullWidth
|
||||
variant={"contained"}
|
||||
onClick={() => openWith(false)}
|
||||
>
|
||||
<SecondaryButton fullWidth variant={"contained"} onClick={() => openWith(false)}>
|
||||
{t("modals.justOnce")}
|
||||
</SecondaryButton>
|
||||
</Grid>
|
||||
|
|
|
|||
|
|
@ -78,25 +78,16 @@ export function openViewers(
|
|||
}
|
||||
|
||||
const viewerOptions = Viewers[ext];
|
||||
if (!viewerOptions) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (viewerOptions.length > 1) {
|
||||
// open viewer selection dialog
|
||||
dispatch(
|
||||
setViewerSelector({
|
||||
open: true,
|
||||
file,
|
||||
entitySize,
|
||||
viewers: viewerOptions,
|
||||
version: preferredVersion,
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(openViewer(file, viewerOptions[0], entitySize, preferredVersion));
|
||||
// open viewer selection dialog
|
||||
dispatch(
|
||||
setViewerSelector({
|
||||
open: true,
|
||||
file,
|
||||
entitySize,
|
||||
viewers: viewerOptions,
|
||||
version: preferredVersion,
|
||||
}),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue