1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-06 05:25:41 -05:00

File browser improvements

This commit is contained in:
bbedward
2025-10-07 14:46:12 -04:00
committed by purian23
parent 205c43181b
commit 7a5d612599

View File

@@ -36,6 +36,13 @@ DankModal {
property string wePath: "" property string wePath: ""
property bool weMode: false property bool weMode: false
property var parentModal: null property var parentModal: null
property bool showSidebar: browserType !== "wallpaper"
property string viewMode: "grid"
property string sortBy: "name"
property bool sortAscending: true
property int iconSizeIndex: 1
property var iconSizes: [80, 120, 160, 200]
property bool pathEditMode: false
signal fileSelected(string path) signal fileSelected(string path)
@@ -105,14 +112,22 @@ DankModal {
keyboardSelectionRequested = true keyboardSelectionRequested = true
} }
function formatFileSize(size) {
if (size < 1024)
return size + " B"
if (size < 1024 * 1024)
return (size / 1024).toFixed(1) + " KB"
if (size < 1024 * 1024 * 1024)
return (size / (1024 * 1024)).toFixed(1) + " MB"
return (size / (1024 * 1024 * 1024)).toFixed(1) + " GB"
}
function handleSaveFile(filePath) { function handleSaveFile(filePath) {
// Ensure the filePath has the correct file:// protocol format
var normalizedPath = filePath var normalizedPath = filePath
if (!normalizedPath.startsWith("file://")) { if (!normalizedPath.startsWith("file://")) {
normalizedPath = "file://" + filePath normalizedPath = "file://" + filePath
} }
// Check if file exists by looking through the folder model
var exists = false var exists = false
var fileName = filePath.split('/').pop() var fileName = filePath.split('/').pop()
@@ -140,12 +155,10 @@ DankModal {
currentPath = getLastPath() currentPath = getLastPath()
} }
property var steamPaths: [ property var steamPaths: [StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.steam/steam/steamapps/workshop/content/431960", StandardPaths.writableLocation(
StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.steam/steam/steamapps/workshop/content/431960", StandardPaths.HomeLocation) + "/.local/share/Steam/steamapps/workshop/content/431960", StandardPaths.writableLocation(
StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.local/share/Steam/steamapps/workshop/content/431960", StandardPaths.HomeLocation) + "/.var/app/com.valvesoftware.Steam/.local/share/Steam/steamapps/workshop/content/431960", StandardPaths.writableLocation(
StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.var/app/com.valvesoftware.Steam/.local/share/Steam/steamapps/workshop/content/431960", StandardPaths.HomeLocation) + "/snap/steam/common/.local/share/Steam/steamapps/workshop/content/431960"]
StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/snap/steam/common/.local/share/Steam/steamapps/workshop/content/431960"
]
property int currentPathIndex: 0 property int currentPathIndex: 0
function discoverWallpaperEngine() { function discoverWallpaperEngine() {
@@ -222,7 +235,52 @@ DankModal {
showFiles: true showFiles: true
showDirs: true showDirs: true
folder: currentPath ? "file://" + currentPath : "file://" + homeDir folder: currentPath ? "file://" + currentPath : "file://" + homeDir
sortField: {
switch (sortBy) {
case "name":
return FolderListModel.Name
case "size":
return FolderListModel.Size
case "modified":
return FolderListModel.Time
case "type":
return FolderListModel.Type
default:
return FolderListModel.Name
} }
}
sortReversed: !sortAscending
}
property var quickAccessLocations: [{
"name": "Home",
"path": homeDir,
"icon": "home"
}, {
"name": "Documents",
"path": homeDir + "/Documents",
"icon": "description"
}, {
"name": "Downloads",
"path": homeDir + "/Downloads",
"icon": "download"
}, {
"name": "Pictures",
"path": homeDir + "/Pictures",
"icon": "image"
}, {
"name": "Music",
"path": homeDir + "/Music",
"icon": "music_note"
}, {
"name": "Videos",
"path": homeDir + "/Videos",
"icon": "movie"
}, {
"name": "Desktop",
"path": homeDir + "/Desktop",
"icon": "computer"
}]
QtObject { QtObject {
id: keyboardController id: keyboardController
@@ -257,10 +315,8 @@ DankModal {
return return
} }
if (!keyboardNavigationActive) { if (!keyboardNavigationActive) {
const isInitKey = event.key === Qt.Key_Tab || event.key === Qt.Key_Down || event.key === Qt.Key_Right || const isInitKey = event.key === Qt.Key_Tab || event.key === Qt.Key_Down || event.key
(event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) || === Qt.Key_Right || (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) || (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) || (event.key === Qt.Key_L && event.modifiers & Qt.ControlModifier)
(event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) ||
(event.key === Qt.Key_L && event.modifiers & Qt.ControlModifier)
if (isInitKey) { if (isInitKey) {
keyboardNavigationActive = true keyboardNavigationActive = true
@@ -483,11 +539,77 @@ DankModal {
} }
} }
Row {
anchors.fill: parent
spacing: 0
StyledRect {
id: sidebar
width: showSidebar ? 200 : 0
height: parent.height
color: Theme.surfaceContainer
visible: showSidebar
clip: true
Column { Column {
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingM anchors.margins: Theme.spacingS
spacing: Theme.spacingXS
StyledText {
text: "Quick Access"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium
font.weight: Font.Medium
leftPadding: Theme.spacingS
}
Repeater {
model: quickAccessLocations
StyledRect {
width: parent.width
height: 36
radius: Theme.cornerRadiusSmall
color: quickAccessMouseArea.containsMouse ? Theme.surfaceVariant : (currentPath === modelData.path ? Theme.surfacePressed : "transparent")
Row {
anchors.fill: parent
anchors.leftMargin: Theme.spacingS
spacing: Theme.spacingS spacing: Theme.spacingS
DankIcon {
name: modelData.icon
size: Theme.iconSize
color: currentPath === modelData.path ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: modelData.name
font.pixelSize: Theme.fontSizeMedium
color: currentPath === modelData.path ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: quickAccessMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: navigateTo(modelData.path)
}
}
}
}
}
Column {
width: parent.width - (showSidebar ? sidebar.width : 0)
height: parent.height
spacing: 0
Item { Item {
width: parent.width width: parent.width
height: 40 height: 40
@@ -495,6 +617,8 @@ DankModal {
Row { Row {
spacing: Theme.spacingM spacing: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
DankIcon { DankIcon {
name: browserIcon name: browserIcon
@@ -514,9 +638,37 @@ DankModal {
Row { Row {
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS spacing: Theme.spacingS
DankActionButton {
circular: false
iconName: showHiddenFiles ? "visibility_off" : "visibility"
iconSize: Theme.iconSize - 4
iconColor: showHiddenFiles ? Theme.primary : Theme.surfaceText
visible: !weMode
onClicked: showHiddenFiles = !showHiddenFiles
}
DankActionButton {
circular: false
iconName: viewMode === "grid" ? "view_list" : "grid_view"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
visible: !weMode
onClicked: viewMode = viewMode === "grid" ? "list" : "grid"
}
DankActionButton {
circular: false
iconName: iconSizeIndex === 0 ? "photo_size_select_small" : iconSizeIndex === 1 ? "photo_size_select_large" : iconSizeIndex === 2 ? "photo_size_select_actual" : "zoom_in"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
visible: !weMode && viewMode === "grid"
onClicked: iconSizeIndex = (iconSizeIndex + 1) % iconSizes.length
}
DankActionButton { DankActionButton {
circular: false circular: false
iconName: "movie" iconName: "movie"
@@ -551,8 +703,17 @@ DankModal {
} }
} }
StyledRect {
width: parent.width
height: 1
color: Theme.outline
}
Row { Row {
width: parent.width width: parent.width
height: 40
leftPadding: Theme.spacingM
rightPadding: Theme.spacingM
spacing: Theme.spacingS spacing: Theme.spacingS
StyledRect { StyledRect {
@@ -561,6 +722,7 @@ DankModal {
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: (backButtonMouseArea.containsMouse || (backButtonFocused && keyboardNavigationActive)) && currentPath !== homeDir ? Theme.surfaceVariant : "transparent" color: (backButtonMouseArea.containsMouse || (backButtonFocused && keyboardNavigationActive)) && currentPath !== homeDir ? Theme.surfaceVariant : "transparent"
opacity: currentPath !== homeDir ? 1 : 0 opacity: currentPath !== homeDir ? 1 : 0
anchors.verticalCenter: parent.verticalCenter
DankIcon { DankIcon {
anchors.centerIn: parent anchors.centerIn: parent
@@ -580,27 +742,101 @@ DankModal {
} }
} }
Item {
width: parent.width - 40 - Theme.spacingS - (showSidebar ? 0 : 80)
height: 32
anchors.verticalCenter: parent.verticalCenter
StyledRect {
anchors.fill: parent
radius: Theme.cornerRadiusSmall
color: pathEditMode ? Theme.surfaceContainer : "transparent"
border.color: pathEditMode ? Theme.primary : "transparent"
border.width: pathEditMode ? 1 : 0
visible: !pathEditMode
StyledText { StyledText {
id: pathDisplay
text: fileBrowserModal.currentPath.replace("file://", "") text: fileBrowserModal.currentPath.replace("file://", "")
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText color: Theme.surfaceText
font.weight: Font.Medium font.weight: Font.Medium
width: parent.width - 40 - Theme.spacingS anchors.fill: parent
anchors.leftMargin: Theme.spacingS
anchors.rightMargin: Theme.spacingS
elide: Text.ElideMiddle elide: Text.ElideMiddle
anchors.verticalCenter: parent.verticalCenter verticalAlignment: Text.AlignVCenter
maximumLineCount: 1 maximumLineCount: 1
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
} }
MouseArea {
anchors.fill: parent
cursorShape: Qt.IBeamCursor
onClicked: {
pathEditMode = true
pathInput.text = fileBrowserModal.currentPath.replace("file://", "")
Qt.callLater(() => pathInput.forceActiveFocus())
} }
}
}
DankTextField {
id: pathInput
anchors.fill: parent
visible: pathEditMode
topPadding: Theme.spacingXS
bottomPadding: Theme.spacingXS
onAccepted: {
const newPath = text.trim()
if (newPath !== "") {
navigateTo(newPath)
}
pathEditMode = false
}
Keys.onEscapePressed: {
pathEditMode = false
}
onActiveFocusChanged: {
if (!activeFocus && pathEditMode) {
pathEditMode = false
}
}
}
}
Row {
spacing: Theme.spacingXS
visible: !showSidebar
anchors.verticalCenter: parent.verticalCenter
DankActionButton {
circular: false
iconName: "sort"
iconSize: Theme.iconSize - 6
iconColor: Theme.surfaceText
onClicked: sortMenu.visible = !sortMenu.visible
}
}
}
StyledRect {
width: parent.width
height: 1
color: Theme.outline
}
Item {
width: parent.width
height: parent.height - 122
clip: true
DankGridView { DankGridView {
id: fileGrid id: fileGrid
anchors.fill: parent
width: parent.width visible: viewMode === "grid"
height: parent.height - 80 cellWidth: weMode ? 255 : iconSizes[iconSizeIndex] + 20
clip: true cellHeight: weMode ? 215 : iconSizes[iconSizeIndex] + 50
cellWidth: weMode ? 255 : 150
cellHeight: weMode ? 215 : 130
cacheBuffer: 260 cacheBuffer: 260
model: folderModel model: folderModel
currentIndex: selectedIndex currentIndex: selectedIndex
@@ -625,8 +861,8 @@ DankModal {
required property string fileName required property string fileName
required property int index required property int index
width: weMode ? 245 : 140 width: weMode ? 245 : iconSizes[iconSizeIndex] + 10
height: weMode ? 205 : 120 height: weMode ? 205 : iconSizes[iconSizeIndex] + 40
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: { color: {
if (keyboardNavigationActive && delegateRoot.index === selectedIndex) if (keyboardNavigationActive && delegateRoot.index === selectedIndex)
@@ -657,8 +893,8 @@ DankModal {
spacing: Theme.spacingXS spacing: Theme.spacingXS
Item { Item {
width: weMode ? 225 : 80 width: weMode ? 225 : iconSizes[iconSizeIndex]
height: weMode ? 165 : 60 height: weMode ? 165 : iconSizes[iconSizeIndex]
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
CachingImage { CachingImage {
@@ -683,7 +919,7 @@ DankModal {
} }
fillMode: Image.PreserveAspectCrop fillMode: Image.PreserveAspectCrop
visible: (!delegateRoot.fileIsDir && isImageFile(delegateRoot.fileName)) || (weMode && delegateRoot.fileIsDir) visible: (!delegateRoot.fileIsDir && isImageFile(delegateRoot.fileName)) || (weMode && delegateRoot.fileIsDir)
maxCacheSize: weMode ? 225 : 80 maxCacheSize: weMode ? 225 : iconSizes[iconSizeIndex]
} }
DankIcon { DankIcon {
@@ -763,6 +999,151 @@ DankModal {
} }
} }
} }
DankListView {
id: fileList
anchors.fill: parent
visible: viewMode === "list"
model: folderModel
currentIndex: selectedIndex
onCurrentIndexChanged: {
if (keyboardNavigationActive && currentIndex >= 0)
positionViewAtIndex(currentIndex, ListView.Contain)
}
ScrollBar.vertical: ScrollBar {
policy: ScrollBar.AsNeeded
}
delegate: StyledRect {
id: listDelegateRoot
required property bool fileIsDir
required property string filePath
required property string fileName
required property url fileURL
required property int index
required property var fileModified
required property int fileSize
width: fileList.width
height: 48
radius: Theme.cornerRadiusSmall
color: {
if (keyboardNavigationActive && listDelegateRoot.index === selectedIndex)
return Theme.surfacePressed
return listMouseArea.containsMouse ? Theme.surfaceVariant : "transparent"
}
border.color: keyboardNavigationActive && listDelegateRoot.index === selectedIndex ? Theme.primary : "transparent"
border.width: (listMouseArea.containsMouse || (keyboardNavigationActive && listDelegateRoot.index === selectedIndex)) ? 1 : 0
Component.onCompleted: {
if (keyboardNavigationActive && listDelegateRoot.index === selectedIndex)
setSelectedFileData(listDelegateRoot.filePath, listDelegateRoot.fileName, listDelegateRoot.fileIsDir)
}
Connections {
function onSelectedIndexChanged() {
if (keyboardNavigationActive && selectedIndex === listDelegateRoot.index)
setSelectedFileData(listDelegateRoot.filePath, listDelegateRoot.fileName, listDelegateRoot.fileIsDir)
}
target: fileBrowserModal
}
Row {
anchors.fill: parent
anchors.leftMargin: Theme.spacingM
anchors.rightMargin: Theme.spacingM
spacing: Theme.spacingM
Item {
width: 32
height: 32
anchors.verticalCenter: parent.verticalCenter
CachingImage {
anchors.fill: parent
source: (!listDelegateRoot.fileIsDir && isImageFile(listDelegateRoot.fileName)) ? ("file://" + listDelegateRoot.filePath) : ""
fillMode: Image.PreserveAspectCrop
visible: !listDelegateRoot.fileIsDir && isImageFile(listDelegateRoot.fileName)
maxCacheSize: 32
}
DankIcon {
anchors.centerIn: parent
name: listDelegateRoot.fileIsDir ? "folder" : "description"
size: Theme.iconSize
color: Theme.primary
visible: listDelegateRoot.fileIsDir || !isImageFile(listDelegateRoot.fileName)
}
}
StyledText {
text: listDelegateRoot.fileName || ""
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
width: parent.width - 300
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: listDelegateRoot.fileIsDir ? "" : formatFileSize(listDelegateRoot.fileSize)
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium
width: 80
horizontalAlignment: Text.AlignRight
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: Qt.formatDateTime(listDelegateRoot.fileModified, "MMM d, yyyy h:mm AP")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium
width: 150
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: listMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
selectedIndex = listDelegateRoot.index
setSelectedFileData(listDelegateRoot.filePath, listDelegateRoot.fileName, listDelegateRoot.fileIsDir)
if (listDelegateRoot.fileIsDir) {
navigateTo(listDelegateRoot.filePath)
} else {
fileSelected(listDelegateRoot.filePath)
fileBrowserModal.close()
}
}
}
Connections {
function onKeyboardSelectionRequestedChanged() {
if (fileBrowserModal.keyboardSelectionRequested && fileBrowserModal.keyboardSelectionIndex === listDelegateRoot.index) {
fileBrowserModal.keyboardSelectionRequested = false
selectedIndex = listDelegateRoot.index
setSelectedFileData(listDelegateRoot.filePath, listDelegateRoot.fileName, listDelegateRoot.fileIsDir)
if (listDelegateRoot.fileIsDir) {
navigateTo(listDelegateRoot.filePath)
} else {
fileSelected(listDelegateRoot.filePath)
fileBrowserModal.close()
}
}
}
target: fileBrowserModal
}
}
}
}
}
} }
Row { Row {
@@ -870,6 +1251,183 @@ DankModal {
} }
} }
StyledRect {
id: sortMenu
anchors.top: parent.top
anchors.right: parent.right
anchors.topMargin: 120
anchors.rightMargin: Theme.spacingL
width: 200
height: sortColumn.height + Theme.spacingM * 2
color: Theme.surfaceContainer
radius: Theme.cornerRadius
border.color: Theme.outlineMedium
border.width: 1
visible: false
z: 100
Column {
id: sortColumn
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Theme.spacingM
spacing: Theme.spacingXS
StyledText {
text: "Sort By"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium
font.weight: Font.Medium
}
Repeater {
model: [{
"name": "Name",
"value": "name"
}, {
"name": "Size",
"value": "size"
}, {
"name": "Modified",
"value": "modified"
}, {
"name": "Type",
"value": "type"
}]
StyledRect {
width: sortColumn.width
height: 32
radius: Theme.cornerRadiusSmall
color: sortMouseArea.containsMouse ? Theme.surfaceVariant : (sortBy === modelData.value ? Theme.surfacePressed : "transparent")
Row {
anchors.fill: parent
anchors.leftMargin: Theme.spacingS
spacing: Theme.spacingS
DankIcon {
name: sortBy === modelData.value ? "check" : ""
size: Theme.iconSizeSmall
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
visible: sortBy === modelData.value
}
StyledText {
text: modelData.name
font.pixelSize: Theme.fontSizeMedium
color: sortBy === modelData.value ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: sortMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
sortBy = modelData.value
sortMenu.visible = false
}
}
}
}
StyledRect {
width: sortColumn.width
height: 1
color: Theme.outline
}
StyledText {
text: "Order"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium
font.weight: Font.Medium
topPadding: Theme.spacingXS
}
StyledRect {
width: sortColumn.width
height: 32
radius: Theme.cornerRadiusSmall
color: ascMouseArea.containsMouse ? Theme.surfaceVariant : (sortAscending ? Theme.surfacePressed : "transparent")
Row {
anchors.fill: parent
anchors.leftMargin: Theme.spacingS
spacing: Theme.spacingS
DankIcon {
name: "arrow_upward"
size: Theme.iconSizeSmall
color: sortAscending ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Ascending"
font.pixelSize: Theme.fontSizeMedium
color: sortAscending ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: ascMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
sortAscending = true
sortMenu.visible = false
}
}
}
StyledRect {
width: sortColumn.width
height: 32
radius: Theme.cornerRadiusSmall
color: descMouseArea.containsMouse ? Theme.surfaceVariant : (!sortAscending ? Theme.surfacePressed : "transparent")
Row {
anchors.fill: parent
anchors.leftMargin: Theme.spacingS
spacing: Theme.spacingS
DankIcon {
name: "arrow_downward"
size: Theme.iconSizeSmall
color: !sortAscending ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Descending"
font.pixelSize: Theme.fontSizeMedium
color: !sortAscending ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: descMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
sortAscending = false
sortMenu.visible = false
}
}
}
}
}
// Overwrite confirmation dialog // Overwrite confirmation dialog
Item { Item {
id: overwriteDialog id: overwriteDialog