1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-08 06:25:37 -05:00
Files
DankMaterialShell/Modals/FileBrowser/FileBrowserGridDelegate.qml
2025-10-25 23:30:33 -04:00

215 lines
7.3 KiB
QML

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 isImageFile(fileName) {
if (!fileName) {
return false
}
const ext = fileName.toLowerCase().split('.').pop()
return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(ext)
}
function getFileIcon(fileName, isDir) {
if (isDir) {
return "folder"
}
if (!fileName) {
return "description"
}
const ext = fileName.toLowerCase().split('.').pop()
const iconMap = {
"mp3": 'music_note',
"wav": 'music_note',
"flac": 'music_note',
"ogg": 'music_note',
"aac": 'music_note',
"mp4": 'movie',
"mkv": 'movie',
"avi": 'movie',
"mov": 'movie',
"webm": 'movie',
"flv": 'movie',
"wmv": 'movie',
"jpg": 'image',
"jpeg": 'image',
"png": 'image',
"gif": 'image',
"bmp": 'image',
"webp": 'image',
"svg": 'image',
"pdf": 'picture_as_pdf',
"zip": 'folder_zip',
"rar": 'folder_zip',
"7z": 'folder_zip',
"tar": 'folder_zip',
"gz": 'folder_zip',
"bz2": 'folder_zip',
"xz": 'folder_zip',
"txt": 'description',
"md": 'description',
"doc": 'description',
"docx": 'description',
"odt": 'description',
"rtf": 'description',
"sh": 'terminal',
"py": 'code',
"js": 'code',
"ts": 'code',
"cpp": 'code',
"c": 'code',
"h": 'code',
"java": 'code',
"go": 'code',
"rs": 'code',
"php": 'code',
"rb": 'code',
"qml": 'code',
"html": 'code',
"css": 'code',
"json": 'data_object',
"xml": 'data_object',
"yaml": 'data_object',
"yml": 'data_object',
"toml": 'data_object'
}
return iconMap[ext] || 'description'
}
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.surfaceContainerHigh : "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
CachingImage {
id: gridPreviewImage
anchors.fill: parent
anchors.margins: 2
property var weExtensions: [".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp", ".tga"]
property int weExtIndex: 0
source: {
if (weMode && delegateRoot.fileIsDir) {
return "file://" + delegateRoot.filePath + "/preview" + weExtensions[weExtIndex]
}
return (!delegateRoot.fileIsDir && isImageFile(delegateRoot.fileName)) ? ("file://" + delegateRoot.filePath) : ""
}
onStatusChanged: {
if (weMode && delegateRoot.fileIsDir && status === Image.Error) {
if (weExtIndex < weExtensions.length - 1) {
weExtIndex++
source = "file://" + delegateRoot.filePath + "/preview" + weExtensions[weExtIndex]
} else {
source = ""
}
}
}
fillMode: Image.PreserveAspectCrop
maxCacheSize: weMode ? 225 : iconSizes[iconSizeIndex]
visible: false
}
MultiEffect {
anchors.fill: parent
anchors.margins: 2
source: gridPreviewImage
maskEnabled: true
maskSource: gridImageMask
visible: gridPreviewImage.status === Image.Ready && ((!delegateRoot.fileIsDir && isImageFile(delegateRoot.fileName)) || (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
}
}
DankIcon {
anchors.centerIn: parent
name: getFileIcon(delegateRoot.fileName, delegateRoot.fileIsDir)
size: iconSizes[iconSizeIndex] * 0.45
color: delegateRoot.fileIsDir ? Theme.primary : Theme.surfaceText
visible: (!delegateRoot.fileIsDir && !isImageFile(delegateRoot.fileName)) || (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)
}
}
}