From 5d94c0a7d44a2255b81815a52a7056a94a39842d Mon Sep 17 00:00:00 2001 From: nippy Date: Sat, 18 Apr 2026 13:49:56 +0200 Subject: update Raveos themes --- .../Modals/FileBrowser/FileBrowserGridDelegate.qml | 253 +++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserGridDelegate.qml (limited to 'raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserGridDelegate.qml') diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserGridDelegate.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserGridDelegate.qml new file mode 100644 index 0000000..effa9bd --- /dev/null +++ b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modals/FileBrowser/FileBrowserGridDelegate.qml @@ -0,0 +1,253 @@ +import QtQuick +import QtQuick.Effects +import qs.Common +import qs.Widgets + +StyledRect { + id: delegateRoot + + required property bool fileIsDir + required property string filePath + required property string fileName + required property int index + + property bool weMode: false + property var iconSizes: [80, 120, 160, 200] + property int iconSizeIndex: 1 + property int selectedIndex: -1 + property bool keyboardNavigationActive: false + + signal itemClicked(int index, string path, string name, bool isDir) + signal itemSelected(int index, string path, string name, bool isDir) + + function getFileExtension(fileName) { + const parts = fileName.split('.'); + if (parts.length > 1) { + return parts[parts.length - 1].toLowerCase(); + } + return ""; + } + + function determineFileType(fileName) { + const ext = getFileExtension(fileName); + + const imageExts = ["png", "jpg", "jpeg", "gif", "bmp", "webp", "svg", "ico", "jxl", "avif", "heif", "exr"]; + if (imageExts.includes(ext)) { + return "image"; + } + + const videoExts = ["mp4", "mkv", "avi", "mov", "webm", "flv", "wmv", "m4v"]; + if (videoExts.includes(ext)) { + return "video"; + } + + const audioExts = ["mp3", "wav", "flac", "ogg", "m4a", "aac", "wma"]; + if (audioExts.includes(ext)) { + return "audio"; + } + + const codeExts = ["js", "ts", "jsx", "tsx", "py", "go", "rs", "c", "cpp", "h", "java", "kt", "swift", "rb", "php", "html", "css", "scss", "json", "xml", "yaml", "yml", "toml", "sh", "bash", "zsh", "fish", "qml", "vue", "svelte"]; + if (codeExts.includes(ext)) { + return "code"; + } + + const docExts = ["txt", "md", "pdf", "doc", "docx", "odt", "rtf"]; + if (docExts.includes(ext)) { + return "document"; + } + + const archiveExts = ["zip", "tar", "gz", "bz2", "xz", "7z", "rar"]; + if (archiveExts.includes(ext)) { + return "archive"; + } + + if (!ext || fileName.indexOf('.') === -1) { + return "binary"; + } + + return "file"; + } + + function isImageFile(fileName) { + if (!fileName) { + return false; + } + return determineFileType(fileName) === "image"; + } + + function isVideoFile(fileName) { + if (!fileName) { + return false; + } + return determineFileType(fileName) === "video"; + } + + property bool isImage: isImageFile(delegateRoot.fileName) + property bool isVideo: isVideoFile(delegateRoot.fileName) + + property string _xdgCacheHome: Paths.strip(Paths.xdgCache) + property string _thumbnailSize: iconSizeIndex >= 2 ? "x-large" : "large" + property int _thumbnailPx: iconSizeIndex >= 2 ? 512 : 256 + property string videoThumbnailPath: { + if (!delegateRoot.fileIsDir && isVideo) { + const hash = Qt.md5("file://" + delegateRoot.filePath); + return _xdgCacheHome + "/thumbnails/" + _thumbnailSize + "/" + hash + ".png"; + } + return ""; + } + + property string _videoThumb: "" + + onVideoThumbnailPathChanged: { + _videoThumb = ""; + if (!videoThumbnailPath) + return; + const thumbPath = videoThumbnailPath; + const thumbDir = _xdgCacheHome + "/thumbnails/" + _thumbnailSize; + const size = _thumbnailPx; + const fp = delegateRoot.filePath; + Paths.mkdir(thumbDir); + Proc.runCommand(null, ["test", "-f", thumbPath], function(output, exitCode) { + if (exitCode === 0) { + _videoThumb = thumbPath; + } else { + Proc.runCommand(null, ["ffmpegthumbnailer", "-i", fp, "-o", thumbPath, "-s", String(size), "-f"], function(output, exitCode) { + if (exitCode === 0) + _videoThumb = thumbPath; + }); + } + }); + } + + function getIconForFile(fileName) { + const lowerName = fileName.toLowerCase(); + if (lowerName.startsWith("dockerfile")) { + return "docker"; + } + const ext = fileName.split('.').pop(); + return ext || ""; + } + + width: weMode ? 245 : iconSizes[iconSizeIndex] + 16 + height: weMode ? 205 : iconSizes[iconSizeIndex] + 48 + radius: Theme.cornerRadius + color: { + if (keyboardNavigationActive && delegateRoot.index === selectedIndex) + return Theme.surfacePressed; + + return mouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent"; + } + border.color: keyboardNavigationActive && delegateRoot.index === selectedIndex ? Theme.primary : "transparent" + border.width: (keyboardNavigationActive && delegateRoot.index === selectedIndex) ? 2 : 0 + + Component.onCompleted: { + if (keyboardNavigationActive && delegateRoot.index === selectedIndex) + itemSelected(delegateRoot.index, delegateRoot.filePath, delegateRoot.fileName, delegateRoot.fileIsDir); + } + + onSelectedIndexChanged: { + if (keyboardNavigationActive && selectedIndex === delegateRoot.index) + itemSelected(delegateRoot.index, delegateRoot.filePath, delegateRoot.fileName, delegateRoot.fileIsDir); + } + + Column { + anchors.centerIn: parent + spacing: Theme.spacingS + + Item { + width: weMode ? 225 : (iconSizes[iconSizeIndex] - 8) + height: weMode ? 165 : (iconSizes[iconSizeIndex] - 8) + anchors.horizontalCenter: parent.horizontalCenter + + Image { + id: gridPreviewImage + anchors.fill: parent + anchors.margins: 2 + property var weExtensions: [".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp", ".tga", ".jxl", ".avif", ".heif", ".exr"] + property int weExtIndex: 0 + property string imagePath: { + if (weMode && delegateRoot.fileIsDir) + return delegateRoot.filePath + "/preview" + weExtensions[weExtIndex]; + if (!delegateRoot.fileIsDir && isImage) + return delegateRoot.filePath; + if (_videoThumb) + return _videoThumb; + return ""; + } + source: imagePath ? "file://" + imagePath.split('/').map(s => encodeURIComponent(s)).join('/') : "" + onStatusChanged: { + if (weMode && delegateRoot.fileIsDir && status === Image.Error) { + if (weExtIndex < weExtensions.length - 1) { + weExtIndex++; + } else { + imagePath = ""; + } + } + } + fillMode: Image.PreserveAspectCrop + sourceSize.width: weMode ? 225 : iconSizes[iconSizeIndex] + sourceSize.height: weMode ? 225 : iconSizes[iconSizeIndex] + asynchronous: true + visible: false + } + + MultiEffect { + anchors.fill: parent + anchors.margins: 2 + source: gridPreviewImage + maskEnabled: true + maskSource: gridImageMask + visible: gridPreviewImage.status === Image.Ready && ((!delegateRoot.fileIsDir && (isImage || isVideo)) || (weMode && delegateRoot.fileIsDir)) + maskThresholdMin: 0.5 + maskSpreadAtMin: 1 + } + + Item { + id: gridImageMask + anchors.fill: parent + anchors.margins: 2 + layer.enabled: true + layer.smooth: true + visible: false + + Rectangle { + anchors.fill: parent + radius: Theme.cornerRadius + color: "black" + antialiasing: true + } + } + + DankNFIcon { + anchors.centerIn: parent + name: delegateRoot.fileIsDir ? "folder" : getIconForFile(delegateRoot.fileName) + size: iconSizes[iconSizeIndex] * 0.45 + color: delegateRoot.fileIsDir ? Theme.primary : Theme.surfaceText + visible: (!delegateRoot.fileIsDir && !isImage && !(isVideo && gridPreviewImage.status === Image.Ready)) || (delegateRoot.fileIsDir && !weMode) + } + } + + StyledText { + text: delegateRoot.fileName || "" + font.pixelSize: Theme.fontSizeSmall + color: Theme.surfaceText + width: delegateRoot.width - Theme.spacingM + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + anchors.horizontalCenter: parent.horizontalCenter + maximumLineCount: 2 + wrapMode: Text.Wrap + } + } + + MouseArea { + id: mouseArea + + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { + itemClicked(delegateRoot.index, delegateRoot.filePath, delegateRoot.fileName, delegateRoot.fileIsDir); + } + } +} -- cgit v1.3