# coding: utf-8 from loguru import logger from PyQt6.QtCore import Qt, pyqtSignal from PyQt6.QtGui import QPixmap from PyQt6.QtWidgets import QHBoxLayout from qfluentwidgets import Action, BodyLabel, CardWidget, ImageLabel, InfoBar, InfoBarPosition, MenuAnimationType, \ MessageBox, PushButton, RoundMenu, StrongBodyLabel from qfluentwidgets import FluentIcon as FIF from app.core import (DeleteFileThread, formatDate, formatSize, getFileIcon, lang, signalBus) from app.view.widgets.share_file_messageBox import ShareFileMessageBox class FileCard(CardWidget): def __init__(self, _id, fileName, fileType, path, date, size, parent=None): super().__init__(parent) self._id = _id self.fileName = fileName self.fileSize = size self.changeTime = date self.fileType = fileType self.filePath = path self.setFixedHeight(50) self.iconLabel = ImageLabel(self) self.fileNameLabel = StrongBodyLabel(self.fileName, self) self.fileSizeLabel = BodyLabel(formatSize(self.fileSize), self) self.changeTimeLabel = BodyLabel(formatDate(self.changeTime), self) self.hBoxLayout = QHBoxLayout(self) self.hBoxLayout.addWidget(self.iconLabel) self.hBoxLayout.addWidget(self.fileNameLabel) self.hBoxLayout.addWidget(self.fileSizeLabel) self.hBoxLayout.addWidget(self.changeTimeLabel) self.hBoxLayout.setStretch(0, 1) self.hBoxLayout.setStretch(1, 2) self.hBoxLayout.setStretch(2, 1) self.hBoxLayout.setContentsMargins(10, 10, 10, 10) self.hBoxLayout.setSpacing(10) self.loadIcon() if self.fileType == "dir": self.clicked.connect(self.dirClicked) self.suffix = fileName.split(".")[-1].lower() def mousePressEvent(self, event): """重写鼠标点击事件,区分左右键""" if event.button() == Qt.MouseButton.RightButton: # 使用globalPosition()获取全局位置并转换为适合菜单显示的坐标 global_pos = event.globalPosition().toPoint() if self.fileType == "file": self.showFileContextMenu(global_pos) else: self.showFolderContextMenu(global_pos) else: super().mousePressEvent(event) def loadIcon(self): icon_name = getFileIcon(self.fileType, self.fileName) self.iconLabel.setImage(QPixmap(f":app/icons/{icon_name}")) self.iconLabel.scaledToHeight(25) self.iconLabel.scaledToWidth(25) def dirClicked(self): if self.filePath == "/": paths = "/" + self.fileName else: paths = f"{self.filePath}/{self.fileName}" signalBus.dirOpenSignal.emit(paths) def selfPreview(self): if self.fileType == "file" and self.suffix in [ "jpg", "png", "jpeg", "bmp", "gif", ]: signalBus.imagePreviewSignal.emit(self._id) if self.fileType == "file" and self.suffix in ["txt", "py", "md"]: signalBus.txtPreviewSignal.emit(self._id) def downloadFile(self): if self.fileType == "file": # 构建Cloudreve V4 API所需的正确路径格式 # 确保不会出现重复的前缀和文件名 if self.filePath == "/": # 根目录情况 full_path = f"cloudreve://my/{self.fileName}" else: # 子目录情况,确保正确拼接路径 # 清理路径,避免重复的斜杠 clean_path = self.filePath.lstrip("/") full_path = f"cloudreve://my/{clean_path}/{self.fileName}" # 确保路径格式正确,没有重复的部分 full_path = full_path.replace("cloudreve://my/cloudreve://my", "cloudreve://my") # 确保没有重复的文件名 if f"/{self.fileName}/{self.fileName}" in full_path: full_path = full_path.replace(f"/{self.fileName}/{self.fileName}", f"/{self.fileName}") signalBus.addDownloadFileTask.emit( f"own.{self.suffix}", self.fileName, full_path ) def showFileContextMenu(self, pos): """显示上下文菜单""" menu = RoundMenu(parent=self) menu.addActions( [ Action( FIF.DOWNLOAD, lang("下载"), triggered=lambda: self.downloadFile() ), Action( FIF.PROJECTOR, lang("预览"), triggered=lambda: self.selfPreview() ), ] ) menu.addSeparator() menu.addActions( [ Action(FIF.DELETE, lang("删除"), triggered=lambda: self.deleteSelf()), ] ) menu.exec(pos, aniType=MenuAnimationType.DROP_DOWN) def showFolderContextMenu(self, pos): """显示上下文菜单""" menu = RoundMenu(parent=self) menu.addActions( [ Action(FIF.DOWNLOAD, lang("进入"), triggered=lambda: self.dirClicked()), ] ) menu.addSeparator() menu.addActions( [ Action(FIF.DELETE, lang("删除"), triggered=lambda: self.deleteSelf()), ] ) menu.exec(pos, aniType=MenuAnimationType.DROP_DOWN) def deleteSelf(self): w = MessageBox( "确认删除", f"你确定要删除{self.fileName}吗?\n删除后不可恢复噢!", parent=self.window(), ) if w.exec(): self.deleteThread = DeleteFileThread(self._id, self.fileType) self.deleteThread.successDelete.connect(self.deleteSuccess) self.deleteThread.errorDelete.connect(self.deleteError) self.deleteThread.start() else: InfoBar.info( "提示", "删除已取消", Qt.Orientation.Horizontal, True, 1000, InfoBarPosition.TOP_RIGHT, self.window(), ) def deleteSuccess(self): InfoBar.success( "成功", "成功删除", Qt.Orientation.Horizontal, True, 1000, InfoBarPosition.TOP_RIGHT, self.window(), ) signalBus.refreshFolderListSignal.emit() def deleteError(self, error_msg): InfoBar.error( "失败", "删除失败", Qt.Orientation.Horizontal, True, 1000, InfoBarPosition.TOP_RIGHT, self.window(), ) logger.error(f"删除文件失败:{error_msg}") def contextMenuEvent(self, e): """重写上下文菜单事件,确保只有右键点击才会触发""" pass class ShareFileCard(CardWidget): def __init__(self, data, parent=None): super().__init__(parent) self._id = data["key"] self.fileName = data["source"]["name"] self.fileSize = data["source"]["size"] self.changeTime = data["create_date"] self.fileType = "dir" if data["is_dir"] else "file" self.preview = data["preview"] self.passWord = data["password"] self.remainDownloads = data["remain_downloads"] self.downloads = data["downloads"] self.score = data["score"] self.views = data["views"] self.expireTime = data["expire"] self.setFixedHeight(50) self.iconLabel = ImageLabel(self) self.fileNameLabel = StrongBodyLabel(self.fileName, self) self.changeTimeLabel = BodyLabel(formatDate(self.changeTime), self) self.viewButton = PushButton("查看", self) self.viewButton.clicked.connect(self.viewFile) self.hBoxLayout = QHBoxLayout(self) self.hBoxLayout.addWidget(self.iconLabel) self.hBoxLayout.addWidget(self.fileNameLabel) self.hBoxLayout.addWidget(self.changeTimeLabel) self.hBoxLayout.addWidget(self.viewButton) self.hBoxLayout.setStretch(0, 1) self.hBoxLayout.setStretch(1, 2) self.hBoxLayout.setStretch(2, 1) self.hBoxLayout.setContentsMargins(10, 10, 10, 10) self.hBoxLayout.setSpacing(10) self.loadIcon() self.suffix = self.fileName.split(".")[-1].lower() def loadIcon(self): icon_name = getFileIcon(self.fileType, self.fileName) self.iconLabel.setImage(QPixmap(f":app/icons/{icon_name}")) self.iconLabel.scaledToHeight(25) self.iconLabel.scaledToWidth(25) def viewFile(self): if self.fileType == "file": w = ShareFileMessageBox( self._id, self.iconLabel.pixmap(), self.suffix, self.window() ) if w.exec(): ... else: signalBus.shareFolderViewSignal.emit(self._id) class SharedFolderFileCard(CardWidget): shareFileDownloadSignal = pyqtSignal() # 共享文件下载信号 def __init__(self, key, _id, fileName, fileType, path, date, size, parent=None): super().__init__(parent) self._id = _id self.key = key self.fileName = fileName self.fileSize = size self.changeTime = date self.fileType = fileType self.filePath = path self.setFixedHeight(50) self.iconLabel = ImageLabel(self) self.fileNameLabel = StrongBodyLabel(self.fileName, self) self.fileSizeLabel = BodyLabel(formatSize(self.fileSize), self) self.changeTimeLabel = BodyLabel(formatDate(self.changeTime), self) self.hBoxLayout = QHBoxLayout(self) self.hBoxLayout.addWidget(self.iconLabel) self.hBoxLayout.addWidget(self.fileNameLabel) self.hBoxLayout.addWidget(self.fileSizeLabel) self.hBoxLayout.addWidget(self.changeTimeLabel) self.hBoxLayout.setStretch(0, 1) self.hBoxLayout.setStretch(1, 2) self.hBoxLayout.setStretch(2, 1) self.hBoxLayout.setContentsMargins(10, 10, 10, 10) self.hBoxLayout.setSpacing(10) self.loadIcon() self.suffix = self.fileName.split(".")[-1].lower() if self.fileType == "dir": # 连接左键点击信号 self.clicked.connect(self.dirClicked) def mousePressEvent(self, event): """重写鼠标点击事件,区分左右键""" if event.button() == Qt.MouseButton.RightButton: # 右键点击,显示上下文菜单 if self.fileType == "file": self.showFileContextMenu(event.globalPos()) else: self.showFolderContextMenu(event.globalPos()) else: # 左键或其他按钮点击,调用父类处理 super().mousePressEvent(event) def loadIcon(self): icon_name = getFileIcon(self.fileType, self.fileName) self.iconLabel.setImage(QPixmap(f":app/icons/{icon_name}")) self.iconLabel.scaledToHeight(25) self.iconLabel.scaledToWidth(25) def dirClicked(self): if self.filePath == "/": paths = "/" + self.fileName else: paths = f"{self.filePath}/{self.fileName}" signalBus.shareDirOpenSignal.emit(paths) def downloadFile(self): if self.fileType == "file": signalBus.addDownloadFileTask.emit( f"share.{self.suffix}", self.fileName, f"{self.filePath}/{self.fileName}.{self.key}", ) signalBus.shareFileDownloadSignal.emit() def showFileContextMenu(self, pos): """显示上下文菜单""" menu = RoundMenu(parent=self) menu.addActions( [ Action( FIF.DOWNLOAD, lang("下载"), triggered=lambda: self.downloadFile() ), ] ) menu.exec(pos, aniType=MenuAnimationType.DROP_DOWN) def showFolderContextMenu(self, pos): """显示上下文菜单""" menu = RoundMenu(parent=self) menu.addActions( [ Action(FIF.DOWNLOAD, lang("进入"), triggered=lambda: self.dirClicked()), ] ) menu.exec(pos, aniType=MenuAnimationType.DROP_DOWN)