1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-05 21:15:38 -05:00

filebrowser: re-add layer surface version

This commit is contained in:
bbedward
2025-11-26 23:51:59 -05:00
parent 1978e67401
commit bbe1c1f1e0
5 changed files with 1146 additions and 1113 deletions

View File

@@ -0,0 +1,891 @@
import Qt.labs.folderlistmodel
import QtCore
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Widgets
FocusScope {
id: root
property string homeDir: StandardPaths.writableLocation(StandardPaths.HomeLocation)
property string docsDir: StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
property string musicDir: StandardPaths.writableLocation(StandardPaths.MusicLocation)
property string videosDir: StandardPaths.writableLocation(StandardPaths.MoviesLocation)
property string picsDir: StandardPaths.writableLocation(StandardPaths.PicturesLocation)
property string downloadDir: StandardPaths.writableLocation(StandardPaths.DownloadLocation)
property string desktopDir: StandardPaths.writableLocation(StandardPaths.DesktopLocation)
property string currentPath: ""
property var fileExtensions: ["*.*"]
property alias filterExtensions: root.fileExtensions
property string browserTitle: "Select File"
property string browserIcon: "folder_open"
property string browserType: "generic"
property bool showHiddenFiles: false
property int selectedIndex: -1
property bool keyboardNavigationActive: false
property bool backButtonFocused: false
property bool saveMode: false
property string defaultFileName: ""
property int keyboardSelectionIndex: -1
property bool keyboardSelectionRequested: false
property bool showKeyboardHints: false
property bool showFileInfo: false
property string selectedFilePath: ""
property string selectedFileName: ""
property bool selectedFileIsDir: false
property bool showOverwriteConfirmation: false
property string pendingFilePath: ""
property bool showSidebar: true
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
property bool pathInputHasFocus: false
property int actualGridColumns: 5
property bool _initialized: false
signal fileSelected(string path)
signal closeRequested
function initialize() {
loadSettings();
currentPath = getLastPath();
_initialized = true;
}
function reset() {
currentPath = getLastPath();
selectedIndex = -1;
keyboardNavigationActive = false;
backButtonFocused = false;
}
function loadSettings() {
const type = browserType || "default";
const settings = CacheData.fileBrowserSettings[type];
const isImageBrowser = ["wallpaper", "profile"].includes(browserType);
if (settings) {
viewMode = settings.viewMode || (isImageBrowser ? "grid" : "list");
sortBy = settings.sortBy || "name";
sortAscending = settings.sortAscending !== undefined ? settings.sortAscending : true;
iconSizeIndex = settings.iconSizeIndex !== undefined ? settings.iconSizeIndex : 1;
showSidebar = settings.showSidebar !== undefined ? settings.showSidebar : true;
} else {
viewMode = isImageBrowser ? "grid" : "list";
}
}
function saveSettings() {
if (!_initialized)
return;
const type = browserType || "default";
let settings = CacheData.fileBrowserSettings;
if (!settings[type]) {
settings[type] = {};
}
settings[type].viewMode = viewMode;
settings[type].sortBy = sortBy;
settings[type].sortAscending = sortAscending;
settings[type].iconSizeIndex = iconSizeIndex;
settings[type].showSidebar = showSidebar;
settings[type].lastPath = currentPath;
CacheData.fileBrowserSettings = settings;
if (browserType === "wallpaper") {
CacheData.wallpaperLastPath = currentPath;
} else if (browserType === "profile") {
CacheData.profileLastPath = currentPath;
}
CacheData.saveCache();
}
onViewModeChanged: saveSettings()
onSortByChanged: saveSettings()
onSortAscendingChanged: saveSettings()
onIconSizeIndexChanged: saveSettings()
onShowSidebarChanged: saveSettings()
function isImageFile(fileName) {
if (!fileName)
return false;
const ext = fileName.toLowerCase().split('.').pop();
return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(ext);
}
function getLastPath() {
const type = browserType || "default";
const settings = CacheData.fileBrowserSettings[type];
const lastPath = settings?.lastPath || "";
return (lastPath && lastPath !== "") ? lastPath : homeDir;
}
function saveLastPath(path) {
const type = browserType || "default";
let settings = CacheData.fileBrowserSettings;
if (!settings[type]) {
settings[type] = {};
}
settings[type].lastPath = path;
CacheData.fileBrowserSettings = settings;
CacheData.saveCache();
if (browserType === "wallpaper") {
CacheData.wallpaperLastPath = path;
} else if (browserType === "profile") {
CacheData.profileLastPath = path;
}
}
function setSelectedFileData(path, name, isDir) {
selectedFilePath = path;
selectedFileName = name;
selectedFileIsDir = isDir;
}
function navigateUp() {
const path = currentPath;
if (path === homeDir)
return;
const lastSlash = path.lastIndexOf('/');
if (lastSlash <= 0)
return;
const newPath = path.substring(0, lastSlash);
if (newPath.length < homeDir.length) {
currentPath = homeDir;
saveLastPath(homeDir);
} else {
currentPath = newPath;
saveLastPath(newPath);
}
}
function navigateTo(path) {
currentPath = path;
saveLastPath(path);
selectedIndex = -1;
backButtonFocused = false;
}
function keyboardFileSelection(index) {
if (index < 0)
return;
keyboardSelectionTimer.targetIndex = index;
keyboardSelectionTimer.start();
}
function executeKeyboardSelection(index) {
keyboardSelectionIndex = index;
keyboardSelectionRequested = true;
}
function handleSaveFile(filePath) {
var normalizedPath = filePath;
if (!normalizedPath.startsWith("file://")) {
normalizedPath = "file://" + filePath;
}
var exists = false;
var fileName = filePath.split('/').pop();
for (var i = 0; i < folderModel.count; i++) {
if (folderModel.get(i, "fileName") === fileName && !folderModel.get(i, "fileIsDir")) {
exists = true;
break;
}
}
if (exists) {
pendingFilePath = normalizedPath;
showOverwriteConfirmation = true;
} else {
fileSelected(normalizedPath);
closeRequested();
}
}
onCurrentPathChanged: {
selectedFilePath = "";
selectedFileName = "";
selectedFileIsDir = false;
saveSettings();
}
onSelectedIndexChanged: {
if (selectedIndex >= 0 && folderModel && selectedIndex < folderModel.count) {
selectedFilePath = "";
selectedFileName = "";
selectedFileIsDir = false;
}
}
property var steamPaths: [StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.steam/steam/steamapps/workshop/content/431960", StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.local/share/Steam/steamapps/workshop/content/431960", StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.var/app/com.valvesoftware.Steam/.local/share/Steam/steamapps/workshop/content/431960", StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/snap/steam/common/.local/share/Steam/steamapps/workshop/content/431960"]
property var quickAccessLocations: [
{
"name": "Home",
"path": homeDir,
"icon": "home"
},
{
"name": "Documents",
"path": docsDir,
"icon": "description"
},
{
"name": "Downloads",
"path": downloadDir,
"icon": "download"
},
{
"name": "Pictures",
"path": picsDir,
"icon": "image"
},
{
"name": "Music",
"path": musicDir,
"icon": "music_note"
},
{
"name": "Videos",
"path": videosDir,
"icon": "movie"
},
{
"name": "Desktop",
"path": desktopDir,
"icon": "computer"
}
]
FolderListModel {
id: folderModel
showDirsFirst: true
showDotAndDotDot: false
showHidden: root.showHiddenFiles
nameFilters: fileExtensions
showFiles: true
showDirs: true
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
}
QtObject {
id: keyboardController
property int totalItems: folderModel.count
property int gridColumns: viewMode === "list" ? 1 : Math.max(1, actualGridColumns)
function handleKey(event) {
if (event.key === Qt.Key_Escape) {
closeRequested();
event.accepted = true;
return;
}
if (event.key === Qt.Key_F10) {
showKeyboardHints = !showKeyboardHints;
event.accepted = true;
return;
}
if (event.key === Qt.Key_F1 || event.key === Qt.Key_I) {
showFileInfo = !showFileInfo;
event.accepted = true;
return;
}
if ((event.modifiers & Qt.AltModifier && event.key === Qt.Key_Left) || event.key === Qt.Key_Backspace) {
if (currentPath !== homeDir) {
navigateUp();
event.accepted = true;
}
return;
}
if (!keyboardNavigationActive) {
const isInitKey = event.key === Qt.Key_Tab || event.key === Qt.Key_Down || event.key === 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);
if (isInitKey) {
keyboardNavigationActive = true;
if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
} else {
backButtonFocused = false;
selectedIndex = 0;
}
event.accepted = true;
}
return;
}
switch (event.key) {
case Qt.Key_Tab:
if (backButtonFocused) {
backButtonFocused = false;
selectedIndex = 0;
} else if (selectedIndex < totalItems - 1) {
selectedIndex++;
} else if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
} else {
selectedIndex = 0;
}
event.accepted = true;
break;
case Qt.Key_Backtab:
if (backButtonFocused) {
backButtonFocused = false;
selectedIndex = totalItems - 1;
} else if (selectedIndex > 0) {
selectedIndex--;
} else if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
} else {
selectedIndex = totalItems - 1;
}
event.accepted = true;
break;
case Qt.Key_N:
if (event.modifiers & Qt.ControlModifier) {
if (backButtonFocused) {
backButtonFocused = false;
selectedIndex = 0;
} else if (selectedIndex < totalItems - 1) {
selectedIndex++;
}
event.accepted = true;
}
break;
case Qt.Key_P:
if (event.modifiers & Qt.ControlModifier) {
if (selectedIndex > 0) {
selectedIndex--;
} else if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
}
event.accepted = true;
}
break;
case Qt.Key_J:
if (event.modifiers & Qt.ControlModifier) {
if (selectedIndex < totalItems - 1) {
selectedIndex++;
}
event.accepted = true;
}
break;
case Qt.Key_K:
if (event.modifiers & Qt.ControlModifier) {
if (selectedIndex > 0) {
selectedIndex--;
} else if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
}
event.accepted = true;
}
break;
case Qt.Key_H:
if (event.modifiers & Qt.ControlModifier) {
if (!backButtonFocused && selectedIndex > 0) {
selectedIndex--;
} else if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
}
event.accepted = true;
}
break;
case Qt.Key_L:
if (event.modifiers & Qt.ControlModifier) {
if (backButtonFocused) {
backButtonFocused = false;
selectedIndex = 0;
} else if (selectedIndex < totalItems - 1) {
selectedIndex++;
}
event.accepted = true;
}
break;
case Qt.Key_Left:
if (pathInputHasFocus)
return;
if (backButtonFocused)
return;
if (selectedIndex > 0) {
selectedIndex--;
} else if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
}
event.accepted = true;
break;
case Qt.Key_Right:
if (pathInputHasFocus)
return;
if (backButtonFocused) {
backButtonFocused = false;
selectedIndex = 0;
} else if (selectedIndex < totalItems - 1) {
selectedIndex++;
}
event.accepted = true;
break;
case Qt.Key_Up:
if (backButtonFocused) {
backButtonFocused = false;
if (gridColumns === 1) {
selectedIndex = 0;
} else {
var col = selectedIndex % gridColumns;
selectedIndex = Math.min(col, totalItems - 1);
}
} else if (selectedIndex >= gridColumns) {
selectedIndex -= gridColumns;
} else if (selectedIndex > 0 && gridColumns === 1) {
selectedIndex--;
} else if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
}
event.accepted = true;
break;
case Qt.Key_Down:
if (backButtonFocused) {
backButtonFocused = false;
selectedIndex = 0;
} else if (gridColumns === 1) {
if (selectedIndex < totalItems - 1) {
selectedIndex++;
}
} else {
var newIndex = selectedIndex + gridColumns;
if (newIndex < totalItems) {
selectedIndex = newIndex;
} else {
var lastRowStart = Math.floor((totalItems - 1) / gridColumns) * gridColumns;
var col = selectedIndex % gridColumns;
var targetIndex = lastRowStart + col;
if (targetIndex < totalItems && targetIndex > selectedIndex) {
selectedIndex = targetIndex;
}
}
}
event.accepted = true;
break;
case Qt.Key_Return:
case Qt.Key_Enter:
case Qt.Key_Space:
if (backButtonFocused) {
navigateUp();
} else if (selectedIndex >= 0 && selectedIndex < totalItems) {
root.keyboardFileSelection(selectedIndex);
}
event.accepted = true;
break;
}
}
}
Timer {
id: keyboardSelectionTimer
property int targetIndex: -1
interval: 1
onTriggered: {
executeKeyboardSelection(targetIndex);
}
}
focus: true
Keys.onPressed: event => {
keyboardController.handleKey(event);
}
Column {
anchors.fill: parent
spacing: 0
Item {
width: parent.width
height: 48
Row {
spacing: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: Theme.spacingL
DankIcon {
name: browserIcon
size: Theme.iconSizeLarge
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: browserTitle
font.pixelSize: Theme.fontSizeXLarge
color: Theme.surfaceText
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
Row {
anchors.right: parent.right
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankActionButton {
circular: false
iconName: showHiddenFiles ? "visibility_off" : "visibility"
iconSize: Theme.iconSize - 4
iconColor: showHiddenFiles ? Theme.primary : Theme.surfaceText
onClicked: showHiddenFiles = !showHiddenFiles
}
DankActionButton {
circular: false
iconName: viewMode === "grid" ? "view_list" : "grid_view"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
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: viewMode === "grid"
onClicked: iconSizeIndex = (iconSizeIndex + 1) % iconSizes.length
}
DankActionButton {
circular: false
iconName: "info"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
onClicked: root.showKeyboardHints = !root.showKeyboardHints
}
DankActionButton {
circular: false
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
onClicked: root.closeRequested()
}
}
}
StyledRect {
width: parent.width
height: 1
color: Theme.outline
}
Item {
width: parent.width
height: parent.height - 49
Row {
anchors.fill: parent
spacing: 0
Row {
width: showSidebar ? 201 : 0
height: parent.height
spacing: 0
visible: showSidebar
FileBrowserSidebar {
height: parent.height
quickAccessLocations: root.quickAccessLocations
currentPath: root.currentPath
onLocationSelected: path => navigateTo(path)
}
StyledRect {
width: 1
height: parent.height
color: Theme.outline
}
}
Column {
width: parent.width - (showSidebar ? 201 : 0)
height: parent.height
spacing: 0
FileBrowserNavigation {
width: parent.width
currentPath: root.currentPath
homeDir: root.homeDir
backButtonFocused: root.backButtonFocused
keyboardNavigationActive: root.keyboardNavigationActive
showSidebar: root.showSidebar
pathEditMode: root.pathEditMode
onNavigateUp: root.navigateUp()
onNavigateTo: path => root.navigateTo(path)
onPathInputFocusChanged: hasFocus => {
root.pathInputHasFocus = hasFocus;
if (hasFocus) {
root.pathEditMode = true;
}
}
}
StyledRect {
width: parent.width
height: 1
color: Theme.outline
}
Item {
id: gridContainer
width: parent.width
height: parent.height - 41
clip: true
property real gridCellWidth: iconSizes[iconSizeIndex] + 24
property real gridCellHeight: iconSizes[iconSizeIndex] + 56
property real availableGridWidth: width - Theme.spacingM * 2
property int gridColumns: Math.max(1, Math.floor(availableGridWidth / gridCellWidth))
property real gridLeftMargin: Theme.spacingM + Math.max(0, (availableGridWidth - (gridColumns * gridCellWidth)) / 2)
onGridColumnsChanged: {
root.actualGridColumns = gridColumns;
}
Component.onCompleted: {
root.actualGridColumns = gridColumns;
}
DankGridView {
id: fileGrid
anchors.fill: parent
anchors.leftMargin: gridContainer.gridLeftMargin
anchors.rightMargin: Theme.spacingM
anchors.topMargin: Theme.spacingS
anchors.bottomMargin: Theme.spacingS
visible: viewMode === "grid"
cellWidth: gridContainer.gridCellWidth
cellHeight: gridContainer.gridCellHeight
cacheBuffer: 260
model: folderModel
currentIndex: selectedIndex
onCurrentIndexChanged: {
if (keyboardNavigationActive && currentIndex >= 0)
positionViewAtIndex(currentIndex, GridView.Contain);
}
ScrollBar.vertical: DankScrollbar {
id: gridScrollbar
}
ScrollBar.horizontal: ScrollBar {
policy: ScrollBar.AlwaysOff
}
delegate: FileBrowserGridDelegate {
iconSizes: root.iconSizes
iconSizeIndex: root.iconSizeIndex
selectedIndex: root.selectedIndex
keyboardNavigationActive: root.keyboardNavigationActive
onItemClicked: (index, path, name, isDir) => {
selectedIndex = index;
setSelectedFileData(path, name, isDir);
if (isDir) {
navigateTo(path);
} else {
fileSelected(path);
root.closeRequested();
}
}
onItemSelected: (index, path, name, isDir) => {
setSelectedFileData(path, name, isDir);
}
Connections {
function onKeyboardSelectionRequestedChanged() {
if (root.keyboardSelectionRequested && root.keyboardSelectionIndex === index) {
root.keyboardSelectionRequested = false;
selectedIndex = index;
setSelectedFileData(filePath, fileName, fileIsDir);
if (fileIsDir) {
navigateTo(filePath);
} else {
fileSelected(filePath);
root.closeRequested();
}
}
}
target: root
}
}
}
DankListView {
id: fileList
anchors.fill: parent
anchors.leftMargin: Theme.spacingM
anchors.rightMargin: Theme.spacingM
anchors.topMargin: Theme.spacingS
anchors.bottomMargin: Theme.spacingS
visible: viewMode === "list"
spacing: 2
model: folderModel
currentIndex: selectedIndex
onCurrentIndexChanged: {
if (keyboardNavigationActive && currentIndex >= 0)
positionViewAtIndex(currentIndex, ListView.Contain);
}
ScrollBar.vertical: DankScrollbar {
id: listScrollbar
}
delegate: FileBrowserListDelegate {
width: fileList.width
selectedIndex: root.selectedIndex
keyboardNavigationActive: root.keyboardNavigationActive
onItemClicked: (index, path, name, isDir) => {
selectedIndex = index;
setSelectedFileData(path, name, isDir);
if (isDir) {
navigateTo(path);
} else {
fileSelected(path);
root.closeRequested();
}
}
onItemSelected: (index, path, name, isDir) => {
setSelectedFileData(path, name, isDir);
}
Connections {
function onKeyboardSelectionRequestedChanged() {
if (root.keyboardSelectionRequested && root.keyboardSelectionIndex === index) {
root.keyboardSelectionRequested = false;
selectedIndex = index;
setSelectedFileData(filePath, fileName, fileIsDir);
if (fileIsDir) {
navigateTo(filePath);
} else {
fileSelected(filePath);
root.closeRequested();
}
}
}
target: root
}
}
}
}
}
}
FileBrowserSaveRow {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: Theme.spacingL
saveMode: root.saveMode
defaultFileName: root.defaultFileName
currentPath: root.currentPath
onSaveRequested: filePath => handleSaveFile(filePath)
}
KeyboardHints {
id: keyboardHints
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: Theme.spacingL
showHints: root.showKeyboardHints
}
FileInfo {
id: fileInfo
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: Theme.spacingL
width: 300
showFileInfo: root.showFileInfo
selectedIndex: root.selectedIndex
sourceFolderModel: folderModel
currentPath: root.currentPath
currentFileName: root.selectedFileName
currentFileIsDir: root.selectedFileIsDir
currentFileExtension: {
if (root.selectedFileIsDir || !root.selectedFileName)
return "";
var lastDot = root.selectedFileName.lastIndexOf('.');
return lastDot > 0 ? root.selectedFileName.substring(lastDot + 1).toLowerCase() : "";
}
}
FileBrowserSortMenu {
id: sortMenu
anchors.top: parent.top
anchors.right: parent.right
anchors.topMargin: 120
anchors.rightMargin: Theme.spacingL
sortBy: root.sortBy
sortAscending: root.sortAscending
onSortBySelected: value => {
root.sortBy = value;
}
onSortOrderSelected: ascending => {
root.sortAscending = ascending;
}
}
}
FileBrowserOverwriteDialog {
anchors.fill: parent
showDialog: showOverwriteConfirmation
pendingFilePath: root.pendingFilePath
onConfirmed: filePath => {
showOverwriteConfirmation = false;
fileSelected(filePath);
pendingFilePath = "";
Qt.callLater(() => root.closeRequested());
}
onCancelled: {
showOverwriteConfirmation = false;
pendingFilePath = "";
}
}
}
}

View File

@@ -1,54 +1,19 @@
import Qt.labs.folderlistmodel
import QtCore
import QtQuick import QtQuick
import QtQuick.Controls
import Quickshell import Quickshell
import qs.Common import qs.Common
import qs.Modals.FileBrowser
import qs.Widgets
FloatingWindow { FloatingWindow {
id: fileBrowserModal id: fileBrowserModal
property string homeDir: StandardPaths.writableLocation(StandardPaths.HomeLocation)
property string docsDir: StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
property string musicDir: StandardPaths.writableLocation(StandardPaths.MusicLocation)
property string videosDir: StandardPaths.writableLocation(StandardPaths.MoviesLocation)
property string picsDir: StandardPaths.writableLocation(StandardPaths.PicturesLocation)
property string downloadDir: StandardPaths.writableLocation(StandardPaths.DownloadLocation)
property string desktopDir: StandardPaths.writableLocation(StandardPaths.DesktopLocation)
property string currentPath: ""
property var fileExtensions: ["*.*"]
property alias filterExtensions: fileBrowserModal.fileExtensions
property string browserTitle: "Select File" property string browserTitle: "Select File"
property string browserIcon: "folder_open" property string browserIcon: "folder_open"
property string browserType: "generic" property string browserType: "generic"
property var fileExtensions: ["*.*"]
property alias filterExtensions: fileBrowserModal.fileExtensions
property bool showHiddenFiles: false property bool showHiddenFiles: false
property int selectedIndex: -1
property bool keyboardNavigationActive: false
property bool backButtonFocused: false
property bool saveMode: false property bool saveMode: false
property string defaultFileName: "" property string defaultFileName: ""
property int keyboardSelectionIndex: -1
property bool keyboardSelectionRequested: false
property bool showKeyboardHints: false
property bool showFileInfo: false
property string selectedFilePath: ""
property string selectedFileName: ""
property bool selectedFileIsDir: false
property bool showOverwriteConfirmation: false
property string pendingFilePath: ""
property var parentModal: null property var parentModal: null
property bool showSidebar: true
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
property bool pathInputHasFocus: false
property int actualGridColumns: 5
property bool _initialized: false
property bool shouldHaveFocus: visible property bool shouldHaveFocus: visible
property bool allowFocusOverride: false property bool allowFocusOverride: false
property bool shouldBeVisible: visible property bool shouldBeVisible: visible
@@ -65,152 +30,6 @@ FloatingWindow {
visible = false; visible = false;
} }
function loadSettings() {
const type = browserType || "default";
const settings = CacheData.fileBrowserSettings[type];
const isImageBrowser = ["wallpaper", "profile"].includes(browserType);
if (settings) {
viewMode = settings.viewMode || (isImageBrowser ? "grid" : "list");
sortBy = settings.sortBy || "name";
sortAscending = settings.sortAscending !== undefined ? settings.sortAscending : true;
iconSizeIndex = settings.iconSizeIndex !== undefined ? settings.iconSizeIndex : 1;
showSidebar = settings.showSidebar !== undefined ? settings.showSidebar : true;
} else {
viewMode = isImageBrowser ? "grid" : "list";
}
}
function saveSettings() {
if (!_initialized)
return;
const type = browserType || "default";
let settings = CacheData.fileBrowserSettings;
if (!settings[type]) {
settings[type] = {};
}
settings[type].viewMode = viewMode;
settings[type].sortBy = sortBy;
settings[type].sortAscending = sortAscending;
settings[type].iconSizeIndex = iconSizeIndex;
settings[type].showSidebar = showSidebar;
settings[type].lastPath = currentPath;
CacheData.fileBrowserSettings = settings;
if (browserType === "wallpaper") {
CacheData.wallpaperLastPath = currentPath;
} else if (browserType === "profile") {
CacheData.profileLastPath = currentPath;
}
CacheData.saveCache();
}
onViewModeChanged: saveSettings()
onSortByChanged: saveSettings()
onSortAscendingChanged: saveSettings()
onIconSizeIndexChanged: saveSettings()
onShowSidebarChanged: saveSettings()
function isImageFile(fileName) {
if (!fileName) {
return false;
}
const ext = fileName.toLowerCase().split('.').pop();
return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(ext);
}
function getLastPath() {
const type = browserType || "default";
const settings = CacheData.fileBrowserSettings[type];
const lastPath = settings?.lastPath || "";
return (lastPath && lastPath !== "") ? lastPath : homeDir;
}
function saveLastPath(path) {
const type = browserType || "default";
let settings = CacheData.fileBrowserSettings;
if (!settings[type]) {
settings[type] = {};
}
settings[type].lastPath = path;
CacheData.fileBrowserSettings = settings;
CacheData.saveCache();
if (browserType === "wallpaper") {
CacheData.wallpaperLastPath = path;
} else if (browserType === "profile") {
CacheData.profileLastPath = path;
}
}
function setSelectedFileData(path, name, isDir) {
selectedFilePath = path;
selectedFileName = name;
selectedFileIsDir = isDir;
}
function navigateUp() {
const path = currentPath;
if (path === homeDir)
return;
const lastSlash = path.lastIndexOf('/');
if (lastSlash > 0) {
const newPath = path.substring(0, lastSlash);
if (newPath.length < homeDir.length) {
currentPath = homeDir;
saveLastPath(homeDir);
} else {
currentPath = newPath;
saveLastPath(newPath);
}
}
}
function navigateTo(path) {
currentPath = path;
saveLastPath(path);
selectedIndex = -1;
backButtonFocused = false;
}
function keyboardFileSelection(index) {
if (index >= 0) {
keyboardSelectionTimer.targetIndex = index;
keyboardSelectionTimer.start();
}
}
function executeKeyboardSelection(index) {
keyboardSelectionIndex = index;
keyboardSelectionRequested = true;
}
function handleSaveFile(filePath) {
var normalizedPath = filePath;
if (!normalizedPath.startsWith("file://")) {
normalizedPath = "file://" + filePath;
}
var exists = false;
var fileName = filePath.split('/').pop();
for (var i = 0; i < folderModel.count; i++) {
if (folderModel.get(i, "fileName") === fileName && !folderModel.get(i, "fileIsDir")) {
exists = true;
break;
}
}
if (exists) {
pendingFilePath = normalizedPath;
showOverwriteConfirmation = true;
} else {
fileSelected(normalizedPath);
fileBrowserModal.close();
}
}
objectName: "fileBrowserModal" objectName: "fileBrowserModal"
title: "Files - " + browserTitle title: "Files - " + browserTitle
minimumSize: Qt.size(500, 400) minimumSize: Qt.size(500, 400)
@@ -219,718 +38,39 @@ FloatingWindow {
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
visible: false visible: false
Component.onCompleted: {
loadSettings();
currentPath = getLastPath();
_initialized = true;
}
property var steamPaths: [StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.steam/steam/steamapps/workshop/content/431960", StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.local/share/Steam/steamapps/workshop/content/431960", StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.var/app/com.valvesoftware.Steam/.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
onVisibleChanged: { onVisibleChanged: {
if (visible) { if (visible) {
if (parentModal) { if (parentModal) {
parentModal.shouldHaveFocus = false; parentModal.shouldHaveFocus = false;
parentModal.allowFocusOverride = true; parentModal.allowFocusOverride = true;
} }
currentPath = getLastPath(); content.reset();
selectedIndex = -1; Qt.callLater(() => content.forceActiveFocus());
keyboardNavigationActive = false;
backButtonFocused = false;
Qt.callLater(() => {
if (contentFocusScope) {
contentFocusScope.forceActiveFocus();
}
});
} else { } else {
if (parentModal) { if (parentModal) {
parentModal.allowFocusOverride = false; parentModal.allowFocusOverride = false;
parentModal.shouldHaveFocus = Qt.binding(() => { parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible);
return parentModal.shouldBeVisible;
});
} }
dialogClosed(); dialogClosed();
} }
} }
onCurrentPathChanged: {
selectedFilePath = "";
selectedFileName = "";
selectedFileIsDir = false;
saveSettings();
}
onSelectedIndexChanged: {
if (selectedIndex >= 0 && folderModel && selectedIndex < folderModel.count) {
selectedFilePath = "";
selectedFileName = "";
selectedFileIsDir = false;
}
}
FolderListModel {
id: folderModel
showDirsFirst: true
showDotAndDotDot: false
showHidden: fileBrowserModal.showHiddenFiles
nameFilters: fileExtensions
showFiles: true
showDirs: true
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": docsDir,
"icon": "description"
},
{
"name": "Downloads",
"path": downloadDir,
"icon": "download"
},
{
"name": "Pictures",
"path": picsDir,
"icon": "image"
},
{
"name": "Music",
"path": musicDir,
"icon": "music_note"
},
{
"name": "Videos",
"path": videosDir,
"icon": "movie"
},
{
"name": "Desktop",
"path": desktopDir,
"icon": "computer"
}
]
QtObject {
id: keyboardController
property int totalItems: folderModel.count
property int gridColumns: viewMode === "list" ? 1 : Math.max(1, actualGridColumns)
function handleKey(event) {
if (event.key === Qt.Key_Escape) {
close();
event.accepted = true;
return;
}
if (event.key === Qt.Key_F10) {
showKeyboardHints = !showKeyboardHints;
event.accepted = true;
return;
}
if (event.key === Qt.Key_F1 || event.key === Qt.Key_I) {
showFileInfo = !showFileInfo;
event.accepted = true;
return;
}
if ((event.modifiers & Qt.AltModifier && event.key === Qt.Key_Left) || event.key === Qt.Key_Backspace) {
if (currentPath !== homeDir) {
navigateUp();
event.accepted = true;
}
return;
}
if (!keyboardNavigationActive) {
const isInitKey = event.key === Qt.Key_Tab || event.key === Qt.Key_Down || event.key === 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);
if (isInitKey) {
keyboardNavigationActive = true;
if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
} else {
backButtonFocused = false;
selectedIndex = 0;
}
event.accepted = true;
}
return;
}
switch (event.key) {
case Qt.Key_Tab:
if (backButtonFocused) {
backButtonFocused = false;
selectedIndex = 0;
} else if (selectedIndex < totalItems - 1) {
selectedIndex++;
} else if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
} else {
selectedIndex = 0;
}
event.accepted = true;
break;
case Qt.Key_Backtab:
if (backButtonFocused) {
backButtonFocused = false;
selectedIndex = totalItems - 1;
} else if (selectedIndex > 0) {
selectedIndex--;
} else if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
} else {
selectedIndex = totalItems - 1;
}
event.accepted = true;
break;
case Qt.Key_N:
if (event.modifiers & Qt.ControlModifier) {
if (backButtonFocused) {
backButtonFocused = false;
selectedIndex = 0;
} else if (selectedIndex < totalItems - 1) {
selectedIndex++;
}
event.accepted = true;
}
break;
case Qt.Key_P:
if (event.modifiers & Qt.ControlModifier) {
if (selectedIndex > 0) {
selectedIndex--;
} else if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
}
event.accepted = true;
}
break;
case Qt.Key_J:
if (event.modifiers & Qt.ControlModifier) {
if (selectedIndex < totalItems - 1) {
selectedIndex++;
}
event.accepted = true;
}
break;
case Qt.Key_K:
if (event.modifiers & Qt.ControlModifier) {
if (selectedIndex > 0) {
selectedIndex--;
} else if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
}
event.accepted = true;
}
break;
case Qt.Key_H:
if (event.modifiers & Qt.ControlModifier) {
if (!backButtonFocused && selectedIndex > 0) {
selectedIndex--;
} else if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
}
event.accepted = true;
}
break;
case Qt.Key_L:
if (event.modifiers & Qt.ControlModifier) {
if (backButtonFocused) {
backButtonFocused = false;
selectedIndex = 0;
} else if (selectedIndex < totalItems - 1) {
selectedIndex++;
}
event.accepted = true;
}
break;
case Qt.Key_Left:
if (pathInputHasFocus)
return;
if (backButtonFocused)
return;
if (selectedIndex > 0) {
selectedIndex--;
} else if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
}
event.accepted = true;
break;
case Qt.Key_Right:
if (pathInputHasFocus)
return;
if (backButtonFocused) {
backButtonFocused = false;
selectedIndex = 0;
} else if (selectedIndex < totalItems - 1) {
selectedIndex++;
}
event.accepted = true;
break;
case Qt.Key_Up:
if (backButtonFocused) {
backButtonFocused = false;
if (gridColumns === 1) {
selectedIndex = 0;
} else {
var col = selectedIndex % gridColumns;
selectedIndex = Math.min(col, totalItems - 1);
}
} else if (selectedIndex >= gridColumns) {
selectedIndex -= gridColumns;
} else if (selectedIndex > 0 && gridColumns === 1) {
selectedIndex--;
} else if (currentPath !== homeDir) {
backButtonFocused = true;
selectedIndex = -1;
}
event.accepted = true;
break;
case Qt.Key_Down:
if (backButtonFocused) {
backButtonFocused = false;
selectedIndex = 0;
} else if (gridColumns === 1) {
if (selectedIndex < totalItems - 1) {
selectedIndex++;
}
} else {
var newIndex = selectedIndex + gridColumns;
if (newIndex < totalItems) {
selectedIndex = newIndex;
} else {
var lastRowStart = Math.floor((totalItems - 1) / gridColumns) * gridColumns;
var col = selectedIndex % gridColumns;
var targetIndex = lastRowStart + col;
if (targetIndex < totalItems && targetIndex > selectedIndex) {
selectedIndex = targetIndex;
}
}
}
event.accepted = true;
break;
case Qt.Key_Return:
case Qt.Key_Enter:
case Qt.Key_Space:
if (backButtonFocused)
navigateUp();
else if (selectedIndex >= 0 && selectedIndex < totalItems)
fileBrowserModal.keyboardFileSelection(selectedIndex);
event.accepted = true;
break;
}
}
}
Timer {
id: keyboardSelectionTimer
property int targetIndex: -1
interval: 1
onTriggered: {
executeKeyboardSelection(targetIndex);
}
}
FocusScope {
id: contentFocusScope
FileBrowserContent {
id: content
anchors.fill: parent anchors.fill: parent
focus: true focus: true
Keys.onPressed: event => { browserTitle: fileBrowserModal.browserTitle
keyboardController.handleKey(event); browserIcon: fileBrowserModal.browserIcon
} browserType: fileBrowserModal.browserType
fileExtensions: fileBrowserModal.fileExtensions
showHiddenFiles: fileBrowserModal.showHiddenFiles
saveMode: fileBrowserModal.saveMode
defaultFileName: fileBrowserModal.defaultFileName
Column { Component.onCompleted: initialize()
anchors.fill: parent
spacing: 0
Item { onFileSelected: path => fileBrowserModal.fileSelected(path)
width: parent.width onCloseRequested: fileBrowserModal.close()
height: 48
Row {
spacing: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: Theme.spacingL
DankIcon {
name: browserIcon
size: Theme.iconSizeLarge
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: browserTitle
font.pixelSize: Theme.fontSizeXLarge
color: Theme.surfaceText
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
Row {
anchors.right: parent.right
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankActionButton {
circular: false
iconName: showHiddenFiles ? "visibility_off" : "visibility"
iconSize: Theme.iconSize - 4
iconColor: showHiddenFiles ? Theme.primary : Theme.surfaceText
onClicked: showHiddenFiles = !showHiddenFiles
}
DankActionButton {
circular: false
iconName: viewMode === "grid" ? "view_list" : "grid_view"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
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: viewMode === "grid"
onClicked: iconSizeIndex = (iconSizeIndex + 1) % iconSizes.length
}
DankActionButton {
circular: false
iconName: "info"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
onClicked: fileBrowserModal.showKeyboardHints = !fileBrowserModal.showKeyboardHints
}
DankActionButton {
circular: false
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
onClicked: fileBrowserModal.close()
}
}
}
StyledRect {
width: parent.width
height: 1
color: Theme.outline
}
Item {
width: parent.width
height: parent.height - 49
Row {
anchors.fill: parent
spacing: 0
Row {
width: showSidebar ? 201 : 0
height: parent.height
spacing: 0
visible: showSidebar
FileBrowserSidebar {
height: parent.height
quickAccessLocations: fileBrowserModal.quickAccessLocations
currentPath: fileBrowserModal.currentPath
onLocationSelected: path => navigateTo(path)
}
StyledRect {
width: 1
height: parent.height
color: Theme.outline
}
}
Column {
width: parent.width - (showSidebar ? 201 : 0)
height: parent.height
spacing: 0
FileBrowserNavigation {
width: parent.width
currentPath: fileBrowserModal.currentPath
homeDir: fileBrowserModal.homeDir
backButtonFocused: fileBrowserModal.backButtonFocused
keyboardNavigationActive: fileBrowserModal.keyboardNavigationActive
showSidebar: fileBrowserModal.showSidebar
pathEditMode: fileBrowserModal.pathEditMode
onNavigateUp: fileBrowserModal.navigateUp()
onNavigateTo: path => fileBrowserModal.navigateTo(path)
onPathInputFocusChanged: hasFocus => {
fileBrowserModal.pathInputHasFocus = hasFocus;
if (hasFocus) {
fileBrowserModal.pathEditMode = true;
}
}
}
StyledRect {
width: parent.width
height: 1
color: Theme.outline
}
Item {
id: gridContainer
width: parent.width
height: parent.height - 41
clip: true
property real gridCellWidth: iconSizes[iconSizeIndex] + 24
property real gridCellHeight: iconSizes[iconSizeIndex] + 56
property real availableGridWidth: width - Theme.spacingM * 2
property int gridColumns: Math.max(1, Math.floor(availableGridWidth / gridCellWidth))
property real gridLeftMargin: Theme.spacingM + Math.max(0, (availableGridWidth - (gridColumns * gridCellWidth)) / 2)
onGridColumnsChanged: {
fileBrowserModal.actualGridColumns = gridColumns;
}
Component.onCompleted: {
fileBrowserModal.actualGridColumns = gridColumns;
}
DankGridView {
id: fileGrid
anchors.fill: parent
anchors.leftMargin: gridContainer.gridLeftMargin
anchors.rightMargin: Theme.spacingM
anchors.topMargin: Theme.spacingS
anchors.bottomMargin: Theme.spacingS
visible: viewMode === "grid"
cellWidth: gridContainer.gridCellWidth
cellHeight: gridContainer.gridCellHeight
cacheBuffer: 260
model: folderModel
currentIndex: selectedIndex
onCurrentIndexChanged: {
if (keyboardNavigationActive && currentIndex >= 0)
positionViewAtIndex(currentIndex, GridView.Contain);
}
ScrollBar.vertical: DankScrollbar {
id: gridScrollbar
}
ScrollBar.horizontal: ScrollBar {
policy: ScrollBar.AlwaysOff
}
delegate: FileBrowserGridDelegate {
iconSizes: fileBrowserModal.iconSizes
iconSizeIndex: fileBrowserModal.iconSizeIndex
selectedIndex: fileBrowserModal.selectedIndex
keyboardNavigationActive: fileBrowserModal.keyboardNavigationActive
onItemClicked: (index, path, name, isDir) => {
selectedIndex = index;
setSelectedFileData(path, name, isDir);
if (isDir) {
navigateTo(path);
} else {
fileSelected(path);
fileBrowserModal.close();
}
}
onItemSelected: (index, path, name, isDir) => {
setSelectedFileData(path, name, isDir);
}
Connections {
function onKeyboardSelectionRequestedChanged() {
if (fileBrowserModal.keyboardSelectionRequested && fileBrowserModal.keyboardSelectionIndex === index) {
fileBrowserModal.keyboardSelectionRequested = false;
selectedIndex = index;
setSelectedFileData(filePath, fileName, fileIsDir);
if (fileIsDir) {
navigateTo(filePath);
} else {
fileSelected(filePath);
fileBrowserModal.close();
}
}
}
target: fileBrowserModal
}
}
}
DankListView {
id: fileList
anchors.fill: parent
anchors.leftMargin: Theme.spacingM
anchors.rightMargin: Theme.spacingM
anchors.topMargin: Theme.spacingS
anchors.bottomMargin: Theme.spacingS
visible: viewMode === "list"
spacing: 2
model: folderModel
currentIndex: selectedIndex
onCurrentIndexChanged: {
if (keyboardNavigationActive && currentIndex >= 0)
positionViewAtIndex(currentIndex, ListView.Contain);
}
ScrollBar.vertical: DankScrollbar {
id: listScrollbar
}
delegate: FileBrowserListDelegate {
width: fileList.width
selectedIndex: fileBrowserModal.selectedIndex
keyboardNavigationActive: fileBrowserModal.keyboardNavigationActive
onItemClicked: (index, path, name, isDir) => {
selectedIndex = index;
setSelectedFileData(path, name, isDir);
if (isDir) {
navigateTo(path);
} else {
fileSelected(path);
fileBrowserModal.close();
}
}
onItemSelected: (index, path, name, isDir) => {
setSelectedFileData(path, name, isDir);
}
Connections {
function onKeyboardSelectionRequestedChanged() {
if (fileBrowserModal.keyboardSelectionRequested && fileBrowserModal.keyboardSelectionIndex === index) {
fileBrowserModal.keyboardSelectionRequested = false;
selectedIndex = index;
setSelectedFileData(filePath, fileName, fileIsDir);
if (fileIsDir) {
navigateTo(filePath);
} else {
fileSelected(filePath);
fileBrowserModal.close();
}
}
}
target: fileBrowserModal
}
}
}
}
}
}
FileBrowserSaveRow {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: Theme.spacingL
saveMode: fileBrowserModal.saveMode
defaultFileName: fileBrowserModal.defaultFileName
currentPath: fileBrowserModal.currentPath
onSaveRequested: filePath => handleSaveFile(filePath)
}
KeyboardHints {
id: keyboardHints
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: Theme.spacingL
showHints: fileBrowserModal.showKeyboardHints
}
FileInfo {
id: fileInfo
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: Theme.spacingL
width: 300
showFileInfo: fileBrowserModal.showFileInfo
selectedIndex: fileBrowserModal.selectedIndex
sourceFolderModel: folderModel
currentPath: fileBrowserModal.currentPath
currentFileName: fileBrowserModal.selectedFileName
currentFileIsDir: fileBrowserModal.selectedFileIsDir
currentFileExtension: {
if (fileBrowserModal.selectedFileIsDir || !fileBrowserModal.selectedFileName)
return "";
var lastDot = fileBrowserModal.selectedFileName.lastIndexOf('.');
return lastDot > 0 ? fileBrowserModal.selectedFileName.substring(lastDot + 1).toLowerCase() : "";
}
}
FileBrowserSortMenu {
id: sortMenu
anchors.top: parent.top
anchors.right: parent.right
anchors.topMargin: 120
anchors.rightMargin: Theme.spacingL
sortBy: fileBrowserModal.sortBy
sortAscending: fileBrowserModal.sortAscending
onSortBySelected: value => {
fileBrowserModal.sortBy = value;
}
onSortOrderSelected: ascending => {
fileBrowserModal.sortAscending = ascending;
}
}
}
FileBrowserOverwriteDialog {
anchors.fill: parent
showDialog: showOverwriteConfirmation
pendingFilePath: fileBrowserModal.pendingFilePath
onConfirmed: filePath => {
showOverwriteConfirmation = false;
fileSelected(filePath);
pendingFilePath = "";
Qt.callLater(() => fileBrowserModal.close());
}
onCancelled: {
showOverwriteConfirmation = false;
pendingFilePath = "";
}
}
}
} }
} }

View File

@@ -0,0 +1,63 @@
import QtQuick
import Quickshell.Wayland
import qs.Common
import qs.Modals.Common
DankModal {
id: fileBrowserSurfaceModal
property string browserTitle: "Select File"
property string browserIcon: "folder_open"
property string browserType: "generic"
property var fileExtensions: ["*.*"]
property alias filterExtensions: fileBrowserSurfaceModal.fileExtensions
property bool showHiddenFiles: false
property bool saveMode: false
property string defaultFileName: ""
property var parentPopout: null
signal fileSelected(string path)
layerNamespace: "dms:filebrowser"
modalWidth: 800
modalHeight: 600
backgroundColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
closeOnEscapeKey: true
closeOnBackgroundClick: true
allowStacking: true
keepPopoutsOpen: true
onBackgroundClicked: close()
onOpened: {
if (parentPopout) {
parentPopout.customKeyboardFocus = WlrKeyboardFocus.None;
}
content.reset();
Qt.callLater(() => content.forceActiveFocus());
}
onDialogClosed: {
if (parentPopout) {
parentPopout.customKeyboardFocus = null;
}
}
directContent: FileBrowserContent {
id: content
focus: true
browserTitle: fileBrowserSurfaceModal.browserTitle
browserIcon: fileBrowserSurfaceModal.browserIcon
browserType: fileBrowserSurfaceModal.browserType
fileExtensions: fileBrowserSurfaceModal.fileExtensions
showHiddenFiles: fileBrowserSurfaceModal.showHiddenFiles
saveMode: fileBrowserSurfaceModal.saveMode
defaultFileName: fileBrowserSurfaceModal.defaultFileName
Component.onCompleted: initialize()
onFileSelected: path => fileBrowserSurfaceModal.fileSelected(path)
onCloseRequested: fileBrowserSurfaceModal.close()
}
}

View File

@@ -3,12 +3,8 @@ import QtCore
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Effects import QtQuick.Effects
import QtQuick.Layouts
import Quickshell
import Quickshell.Wayland
import qs.Common import qs.Common
import qs.Modals.FileBrowser import qs.Modals.FileBrowser
import qs.Services
import qs.Widgets import qs.Widgets
Item { Item {
@@ -38,222 +34,222 @@ Item {
function getCurrentWallpaper() { function getCurrentWallpaper() {
if (SessionData.perMonitorWallpaper && targetScreenName) { if (SessionData.perMonitorWallpaper && targetScreenName) {
return SessionData.getMonitorWallpaper(targetScreenName) return SessionData.getMonitorWallpaper(targetScreenName);
} }
return SessionData.wallpaperPath return SessionData.wallpaperPath;
} }
function setCurrentWallpaper(path) { function setCurrentWallpaper(path) {
if (SessionData.perMonitorWallpaper && targetScreenName) { if (SessionData.perMonitorWallpaper && targetScreenName) {
SessionData.setMonitorWallpaper(targetScreenName, path) SessionData.setMonitorWallpaper(targetScreenName, path);
} else { } else {
SessionData.setWallpaper(path) SessionData.setWallpaper(path);
} }
} }
onCurrentPageChanged: { onCurrentPageChanged: {
if (currentPage !== lastPage) { if (currentPage !== lastPage) {
enableAnimation = false enableAnimation = false;
lastPage = currentPage lastPage = currentPage;
} }
updateSelectedFileName() updateSelectedFileName();
} }
onGridIndexChanged: { onGridIndexChanged: {
updateSelectedFileName() updateSelectedFileName();
} }
onVisibleChanged: { onVisibleChanged: {
if (visible && active) { if (visible && active) {
setInitialSelection() setInitialSelection();
} }
} }
Component.onCompleted: { Component.onCompleted: {
loadWallpaperDirectory() loadWallpaperDirectory();
} }
onActiveChanged: { onActiveChanged: {
if (active && visible) { if (active && visible) {
setInitialSelection() setInitialSelection();
} }
} }
function handleKeyEvent(event) { function handleKeyEvent(event) {
const columns = 4 const columns = 4;
const currentCol = gridIndex % columns const currentCol = gridIndex % columns;
const visibleCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage) const visibleCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage);
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
if (gridIndex >= 0 && gridIndex < visibleCount) { if (gridIndex >= 0 && gridIndex < visibleCount) {
const absoluteIndex = currentPage * itemsPerPage + gridIndex const absoluteIndex = currentPage * itemsPerPage + gridIndex;
if (absoluteIndex < wallpaperFolderModel.count) { if (absoluteIndex < wallpaperFolderModel.count) {
const filePath = wallpaperFolderModel.get(absoluteIndex, "filePath") const filePath = wallpaperFolderModel.get(absoluteIndex, "filePath");
if (filePath) { if (filePath) {
setCurrentWallpaper(filePath.toString().replace(/^file:\/\//, '')) setCurrentWallpaper(filePath.toString().replace(/^file:\/\//, ''));
} }
} }
} }
return true return true;
} }
if (event.key === Qt.Key_Right) { if (event.key === Qt.Key_Right) {
if (gridIndex + 1 < visibleCount) { if (gridIndex + 1 < visibleCount) {
gridIndex++ gridIndex++;
} else if (currentPage < totalPages - 1) { } else if (currentPage < totalPages - 1) {
gridIndex = 0 gridIndex = 0;
currentPage++ currentPage++;
} }
return true return true;
} }
if (event.key === Qt.Key_Left) { if (event.key === Qt.Key_Left) {
if (gridIndex > 0) { if (gridIndex > 0) {
gridIndex-- gridIndex--;
} else if (currentPage > 0) { } else if (currentPage > 0) {
currentPage-- currentPage--;
const prevPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage) const prevPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage);
gridIndex = prevPageCount - 1 gridIndex = prevPageCount - 1;
} }
return true return true;
} }
if (event.key === Qt.Key_Down) { if (event.key === Qt.Key_Down) {
if (gridIndex + columns < visibleCount) { if (gridIndex + columns < visibleCount) {
gridIndex += columns gridIndex += columns;
} else if (currentPage < totalPages - 1) { } else if (currentPage < totalPages - 1) {
gridIndex = currentCol gridIndex = currentCol;
currentPage++ currentPage++;
} }
return true return true;
} }
if (event.key === Qt.Key_Up) { if (event.key === Qt.Key_Up) {
if (gridIndex >= columns) { if (gridIndex >= columns) {
gridIndex -= columns gridIndex -= columns;
} else if (currentPage > 0) { } else if (currentPage > 0) {
currentPage-- currentPage--;
const prevPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage) const prevPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage);
const prevPageRows = Math.ceil(prevPageCount / columns) const prevPageRows = Math.ceil(prevPageCount / columns);
gridIndex = (prevPageRows - 1) * columns + currentCol gridIndex = (prevPageRows - 1) * columns + currentCol;
gridIndex = Math.min(gridIndex, prevPageCount - 1) gridIndex = Math.min(gridIndex, prevPageCount - 1);
} }
return true return true;
} }
if (event.key === Qt.Key_PageUp && currentPage > 0) { if (event.key === Qt.Key_PageUp && currentPage > 0) {
gridIndex = 0 gridIndex = 0;
currentPage-- currentPage--;
return true return true;
} }
if (event.key === Qt.Key_PageDown && currentPage < totalPages - 1) { if (event.key === Qt.Key_PageDown && currentPage < totalPages - 1) {
gridIndex = 0 gridIndex = 0;
currentPage++ currentPage++;
return true return true;
} }
if (event.key === Qt.Key_Home && event.modifiers & Qt.ControlModifier) { if (event.key === Qt.Key_Home && event.modifiers & Qt.ControlModifier) {
gridIndex = 0 gridIndex = 0;
currentPage = 0 currentPage = 0;
return true return true;
} }
if (event.key === Qt.Key_End && event.modifiers & Qt.ControlModifier) { if (event.key === Qt.Key_End && event.modifiers & Qt.ControlModifier) {
currentPage = totalPages - 1 currentPage = totalPages - 1;
const lastPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage) const lastPageCount = Math.min(itemsPerPage, wallpaperFolderModel.count - currentPage * itemsPerPage);
gridIndex = Math.max(0, lastPageCount - 1) gridIndex = Math.max(0, lastPageCount - 1);
return true return true;
} }
return false return false;
} }
function setInitialSelection() { function setInitialSelection() {
const currentWallpaper = getCurrentWallpaper() const currentWallpaper = getCurrentWallpaper();
if (!currentWallpaper || wallpaperFolderModel.count === 0) { if (!currentWallpaper || wallpaperFolderModel.count === 0) {
gridIndex = 0 gridIndex = 0;
updateSelectedFileName() updateSelectedFileName();
Qt.callLater(() => { Qt.callLater(() => {
enableAnimation = true enableAnimation = true;
}) });
return return;
} }
for (var i = 0; i < wallpaperFolderModel.count; i++) { for (var i = 0; i < wallpaperFolderModel.count; i++) {
const filePath = wallpaperFolderModel.get(i, "filePath") const filePath = wallpaperFolderModel.get(i, "filePath");
if (filePath && filePath.toString().replace(/^file:\/\//, '') === currentWallpaper) { if (filePath && filePath.toString().replace(/^file:\/\//, '') === currentWallpaper) {
const targetPage = Math.floor(i / itemsPerPage) const targetPage = Math.floor(i / itemsPerPage);
const targetIndex = i % itemsPerPage const targetIndex = i % itemsPerPage;
currentPage = targetPage currentPage = targetPage;
gridIndex = targetIndex gridIndex = targetIndex;
updateSelectedFileName() updateSelectedFileName();
Qt.callLater(() => { Qt.callLater(() => {
enableAnimation = true enableAnimation = true;
}) });
return return;
} }
} }
gridIndex = 0 gridIndex = 0;
updateSelectedFileName() updateSelectedFileName();
Qt.callLater(() => { Qt.callLater(() => {
enableAnimation = true enableAnimation = true;
}) });
} }
function loadWallpaperDirectory() { function loadWallpaperDirectory() {
const currentWallpaper = getCurrentWallpaper() const currentWallpaper = getCurrentWallpaper();
if (!currentWallpaper || currentWallpaper.startsWith("#")) { if (!currentWallpaper || currentWallpaper.startsWith("#")) {
if (CacheData.wallpaperLastPath && CacheData.wallpaperLastPath !== "") { if (CacheData.wallpaperLastPath && CacheData.wallpaperLastPath !== "") {
wallpaperDir = CacheData.wallpaperLastPath wallpaperDir = CacheData.wallpaperLastPath;
} else { } else {
wallpaperDir = "" wallpaperDir = "";
} }
return return;
} }
wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/')) wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/'));
} }
function updateSelectedFileName() { function updateSelectedFileName() {
if (wallpaperFolderModel.count === 0) { if (wallpaperFolderModel.count === 0) {
selectedFileName = "" selectedFileName = "";
return return;
} }
const absoluteIndex = currentPage * itemsPerPage + gridIndex const absoluteIndex = currentPage * itemsPerPage + gridIndex;
if (absoluteIndex < wallpaperFolderModel.count) { if (absoluteIndex < wallpaperFolderModel.count) {
const filePath = wallpaperFolderModel.get(absoluteIndex, "filePath") const filePath = wallpaperFolderModel.get(absoluteIndex, "filePath");
if (filePath) { if (filePath) {
const pathStr = filePath.toString().replace(/^file:\/\//, '') const pathStr = filePath.toString().replace(/^file:\/\//, '');
selectedFileName = pathStr.substring(pathStr.lastIndexOf('/') + 1) selectedFileName = pathStr.substring(pathStr.lastIndexOf('/') + 1);
return return;
} }
} }
selectedFileName = "" selectedFileName = "";
} }
Connections { Connections {
target: SessionData target: SessionData
function onWallpaperPathChanged() { function onWallpaperPathChanged() {
loadWallpaperDirectory() loadWallpaperDirectory();
if (visible && active) { if (visible && active) {
setInitialSelection() setInitialSelection();
} }
} }
function onMonitorWallpapersChanged() { function onMonitorWallpapersChanged() {
loadWallpaperDirectory() loadWallpaperDirectory();
if (visible && active) { if (visible && active) {
setInitialSelection() setInitialSelection();
} }
} }
} }
onTargetScreenNameChanged: { onTargetScreenNameChanged: {
loadWallpaperDirectory() loadWallpaperDirectory();
if (visible && active) { if (visible && active) {
setInitialSelection() setInitialSelection();
} }
} }
@@ -262,17 +258,17 @@ Item {
function onCountChanged() { function onCountChanged() {
if (wallpaperFolderModel.status === FolderListModel.Ready) { if (wallpaperFolderModel.status === FolderListModel.Ready) {
if (visible && active) { if (visible && active) {
setInitialSelection() setInitialSelection();
} }
updateSelectedFileName() updateSelectedFileName();
} }
} }
function onStatusChanged() { function onStatusChanged() {
if (wallpaperFolderModel.status === FolderListModel.Ready && wallpaperFolderModel.count > 0) { if (wallpaperFolderModel.status === FolderListModel.Ready && wallpaperFolderModel.count > 0) {
if (visible && active) { if (visible && active) {
setInitialSelection() setInitialSelection();
} }
updateSelectedFileName() updateSelectedFileName();
} }
} }
} }
@@ -290,51 +286,27 @@ Item {
folder: wallpaperDir ? "file://" + wallpaperDir : "" folder: wallpaperDir ? "file://" + wallpaperDir : ""
} }
Loader { FileBrowserSurfaceModal {
id: wallpaperBrowserLoader id: wallpaperBrowser
active: false
asynchronous: true
onActiveChanged: { browserTitle: I18n.tr("Select Wallpaper Directory", "wallpaper directory file browser title")
if (active && parentPopout) { browserIcon: "folder_open"
parentPopout.WlrLayershell.keyboardFocus = WlrKeyboardFocus.None browserType: "wallpaper"
} showHiddenFiles: false
} fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
parentPopout: root.parentPopout
sourceComponent: FileBrowserModal {
Component.onCompleted: { onFileSelected: path => {
open() const cleanPath = path.replace(/^file:\/\//, '');
} setCurrentWallpaper(cleanPath);
browserTitle: I18n.tr("Select Wallpaper Directory", "wallpaper directory file browser title")
browserIcon: "folder_open" const dirPath = cleanPath.substring(0, cleanPath.lastIndexOf('/'));
browserType: "wallpaper" if (dirPath) {
showHiddenFiles: false wallpaperDir = dirPath;
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"] CacheData.wallpaperLastPath = dirPath;
allowStacking: true CacheData.saveCache();
onFileSelected: path => {
const cleanPath = path.replace(/^file:\/\//, '')
setCurrentWallpaper(cleanPath)
const dirPath = cleanPath.substring(0, cleanPath.lastIndexOf('/'))
if (dirPath) {
wallpaperDir = dirPath
CacheData.wallpaperLastPath = dirPath
CacheData.saveCache()
}
close()
}
onDialogClosed: {
if (parentPopout) {
if (CompositorService.isHyprland) {
parentPopout.WlrLayershell.keyboardFocus = WlrKeyboardFocus.OnDemand
} else {
parentPopout.WlrLayershell.keyboardFocus = WlrKeyboardFocus.Exclusive
}
}
Qt.callLater(() => wallpaperBrowserLoader.active = false)
} }
close();
} }
} }
@@ -376,41 +348,41 @@ Item {
} }
model: { model: {
const startIndex = currentPage * itemsPerPage const startIndex = currentPage * itemsPerPage;
const endIndex = Math.min(startIndex + itemsPerPage, wallpaperFolderModel.count) const endIndex = Math.min(startIndex + itemsPerPage, wallpaperFolderModel.count);
const items = [] const items = [];
for (var i = startIndex; i < endIndex; i++) { for (var i = startIndex; i < endIndex; i++) {
const filePath = wallpaperFolderModel.get(i, "filePath") const filePath = wallpaperFolderModel.get(i, "filePath");
if (filePath) { if (filePath) {
items.push(filePath.toString().replace(/^file:\/\//, '')) items.push(filePath.toString().replace(/^file:\/\//, ''));
} }
} }
return items return items;
} }
onModelChanged: { onModelChanged: {
const clampedIndex = model.length > 0 ? Math.min(Math.max(0, gridIndex), model.length - 1) : 0 const clampedIndex = model.length > 0 ? Math.min(Math.max(0, gridIndex), model.length - 1) : 0;
if (gridIndex !== clampedIndex) { if (gridIndex !== clampedIndex) {
gridIndex = clampedIndex gridIndex = clampedIndex;
} }
} }
onCountChanged: { onCountChanged: {
if (count > 0) { if (count > 0) {
const clampedIndex = Math.min(gridIndex, count - 1) const clampedIndex = Math.min(gridIndex, count - 1);
currentIndex = clampedIndex currentIndex = clampedIndex;
positionViewAtIndex(clampedIndex, GridView.Contain) positionViewAtIndex(clampedIndex, GridView.Contain);
} }
enableAnimation = true enableAnimation = true;
} }
Connections { Connections {
target: root target: root
function onGridIndexChanged() { function onGridIndexChanged() {
if (wallpaperGrid.count > 0) { if (wallpaperGrid.count > 0) {
wallpaperGrid.currentIndex = gridIndex wallpaperGrid.currentIndex = gridIndex;
if (!enableAnimation) { if (!enableAnimation) {
wallpaperGrid.positionViewAtIndex(gridIndex, GridView.Contain) wallpaperGrid.positionViewAtIndex(gridIndex, GridView.Contain);
} }
} }
} }
@@ -487,9 +459,9 @@ Item {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
gridIndex = index gridIndex = index;
if (modelData) { if (modelData) {
setCurrentWallpaper(modelData) setCurrentWallpaper(modelData);
} }
} }
} }
@@ -535,7 +507,7 @@ Item {
opacity: enabled ? 1.0 : 0.3 opacity: enabled ? 1.0 : 0.3
onClicked: { onClicked: {
if (currentPage > 0) { if (currentPage > 0) {
currentPage-- currentPage--;
} }
} }
} }
@@ -557,7 +529,7 @@ Item {
opacity: enabled ? 1.0 : 0.3 opacity: enabled ? 1.0 : 0.3
onClicked: { onClicked: {
if (currentPage < totalPages - 1) { if (currentPage < totalPages - 1) {
currentPage++ currentPage++;
} }
} }
} }
@@ -570,7 +542,7 @@ Item {
iconSize: 20 iconSize: 20
buttonSize: 32 buttonSize: 32
opacity: 0.7 opacity: 0.7
onClicked: wallpaperBrowserLoader.active = true onClicked: wallpaperBrowser.open()
} }
} }

View File

@@ -9,7 +9,6 @@ import qs.Widgets
Item { Item {
id: personalizationTab id: personalizationTab
property var wallpaperBrowser: wallpaperBrowserLoader.item
property var parentModal: null property var parentModal: null
property var cachedFontFamilies: [] property var cachedFontFamilies: []
property bool fontsEnumerated: false property bool fontsEnumerated: false
@@ -207,9 +206,7 @@ Item {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: mainWallpaperBrowser.open()
wallpaperBrowserLoader.active = true;
}
} }
} }
@@ -598,7 +595,7 @@ Item {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
lightWallpaperBrowserLoader.active = true; lightWallpaperBrowser.open();
} }
} }
} }
@@ -787,7 +784,7 @@ Item {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
darkWallpaperBrowserLoader.active = true; darkWallpaperBrowser.open();
} }
} }
} }
@@ -2140,86 +2137,56 @@ Item {
} }
} }
Loader { FileBrowserModal {
id: wallpaperBrowserLoader id: mainWallpaperBrowser
active: false
asynchronous: true
sourceComponent: FileBrowserModal { parentModal: personalizationTab.parentModal
parentModal: personalizationTab.parentModal browserTitle: I18n.tr("Select Wallpaper", "wallpaper file browser title")
Component.onCompleted: { browserIcon: "wallpaper"
open(); browserType: "wallpaper"
} showHiddenFiles: true
browserTitle: I18n.tr("Select Wallpaper", "wallpaper file browser title") fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
browserIcon: "wallpaper" onFileSelected: path => {
browserType: "wallpaper" if (SessionData.perMonitorWallpaper) {
showHiddenFiles: true SessionData.setMonitorWallpaper(selectedMonitorName, path);
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"] } else {
onFileSelected: path => { SessionData.setWallpaper(path);
if (SessionData.perMonitorWallpaper) {
SessionData.setMonitorWallpaper(selectedMonitorName, path);
} else {
SessionData.setWallpaper(path);
}
close();
}
onDialogClosed: {
Qt.callLater(() => wallpaperBrowserLoader.active = false);
} }
close();
} }
} }
Loader { FileBrowserModal {
id: lightWallpaperBrowserLoader id: lightWallpaperBrowser
active: false
asynchronous: true
sourceComponent: FileBrowserModal { parentModal: personalizationTab.parentModal
parentModal: personalizationTab.parentModal browserTitle: I18n.tr("Select Wallpaper", "light mode wallpaper file browser title")
Component.onCompleted: { browserIcon: "light_mode"
open(); browserType: "wallpaper"
} showHiddenFiles: true
browserTitle: I18n.tr("Select Wallpaper", "light mode wallpaper file browser title") fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
browserIcon: "light_mode" onFileSelected: path => {
browserType: "wallpaper" SessionData.wallpaperPathLight = path;
showHiddenFiles: true SessionData.syncWallpaperForCurrentMode();
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"] SessionData.saveSettings();
onFileSelected: path => { close();
SessionData.wallpaperPathLight = path;
SessionData.syncWallpaperForCurrentMode();
SessionData.saveSettings();
close();
}
onDialogClosed: {
Qt.callLater(() => lightWallpaperBrowserLoader.active = false);
}
} }
} }
Loader { FileBrowserModal {
id: darkWallpaperBrowserLoader id: darkWallpaperBrowser
active: false
asynchronous: true
sourceComponent: FileBrowserModal { parentModal: personalizationTab.parentModal
parentModal: personalizationTab.parentModal browserTitle: I18n.tr("Select Wallpaper", "dark mode wallpaper file browser title")
Component.onCompleted: { browserIcon: "dark_mode"
open(); browserType: "wallpaper"
} showHiddenFiles: true
browserTitle: I18n.tr("Select Wallpaper", "dark mode wallpaper file browser title") fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
browserIcon: "dark_mode" onFileSelected: path => {
browserType: "wallpaper" SessionData.wallpaperPathDark = path;
showHiddenFiles: true SessionData.syncWallpaperForCurrentMode();
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"] SessionData.saveSettings();
onFileSelected: path => { close();
SessionData.wallpaperPathDark = path;
SessionData.syncWallpaperForCurrentMode();
SessionData.saveSettings();
close();
}
onDialogClosed: {
Qt.callLater(() => darkWallpaperBrowserLoader.active = false);
}
} }
} }
} }