1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 13:32:50 -05:00

wallpaper: encode image URIs

fixes #1306
This commit is contained in:
bbedward
2026-01-08 14:31:48 -05:00
parent f5f21e738a
commit a21a846bf5
11 changed files with 131 additions and 117 deletions

View File

@@ -52,6 +52,12 @@ FocusScope {
signal fileSelected(string path)
signal closeRequested
function encodeFileUrl(path) {
if (!path)
return "";
return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/');
}
function initialize() {
loadSettings();
currentPath = getLastPath();
@@ -188,7 +194,7 @@ FocusScope {
function handleSaveFile(filePath) {
var normalizedPath = filePath;
if (!normalizedPath.startsWith("file://")) {
normalizedPath = "file://" + filePath;
normalizedPath = encodeFileUrl(filePath);
}
var exists = false;
@@ -274,7 +280,7 @@ FocusScope {
nameFilters: fileExtensions
showFiles: true
showDirs: true
folder: currentPath ? "file://" + currentPath : "file://" + homeDir
folder: encodeFileUrl(currentPath || homeDir)
sortField: {
switch (sortBy) {
case "name":

View File

@@ -21,67 +21,67 @@ StyledRect {
signal itemSelected(int index, string path, string name, bool isDir)
function getFileExtension(fileName) {
const parts = fileName.split('.')
const parts = fileName.split('.');
if (parts.length > 1) {
return parts[parts.length - 1].toLowerCase()
return parts[parts.length - 1].toLowerCase();
}
return ""
return "";
}
function determineFileType(fileName) {
const ext = getFileExtension(fileName)
const ext = getFileExtension(fileName);
const imageExts = ["png", "jpg", "jpeg", "gif", "bmp", "webp", "svg", "ico"]
const imageExts = ["png", "jpg", "jpeg", "gif", "bmp", "webp", "svg", "ico"];
if (imageExts.includes(ext)) {
return "image"
return "image";
}
const videoExts = ["mp4", "mkv", "avi", "mov", "webm", "flv", "wmv", "m4v"]
const videoExts = ["mp4", "mkv", "avi", "mov", "webm", "flv", "wmv", "m4v"];
if (videoExts.includes(ext)) {
return "video"
return "video";
}
const audioExts = ["mp3", "wav", "flac", "ogg", "m4a", "aac", "wma"]
const audioExts = ["mp3", "wav", "flac", "ogg", "m4a", "aac", "wma"];
if (audioExts.includes(ext)) {
return "audio"
return "audio";
}
const codeExts = ["js", "ts", "jsx", "tsx", "py", "go", "rs", "c", "cpp", "h", "java", "kt", "swift", "rb", "php", "html", "css", "scss", "json", "xml", "yaml", "yml", "toml", "sh", "bash", "zsh", "fish", "qml", "vue", "svelte"]
const codeExts = ["js", "ts", "jsx", "tsx", "py", "go", "rs", "c", "cpp", "h", "java", "kt", "swift", "rb", "php", "html", "css", "scss", "json", "xml", "yaml", "yml", "toml", "sh", "bash", "zsh", "fish", "qml", "vue", "svelte"];
if (codeExts.includes(ext)) {
return "code"
return "code";
}
const docExts = ["txt", "md", "pdf", "doc", "docx", "odt", "rtf"]
const docExts = ["txt", "md", "pdf", "doc", "docx", "odt", "rtf"];
if (docExts.includes(ext)) {
return "document"
return "document";
}
const archiveExts = ["zip", "tar", "gz", "bz2", "xz", "7z", "rar"]
const archiveExts = ["zip", "tar", "gz", "bz2", "xz", "7z", "rar"];
if (archiveExts.includes(ext)) {
return "archive"
return "archive";
}
if (!ext || fileName.indexOf('.') === -1) {
return "binary"
return "binary";
}
return "file"
return "file";
}
function isImageFile(fileName) {
if (!fileName) {
return false
return false;
}
return determineFileType(fileName) === "image"
return determineFileType(fileName) === "image";
}
function getIconForFile(fileName) {
const lowerName = fileName.toLowerCase()
const lowerName = fileName.toLowerCase();
if (lowerName.startsWith("dockerfile")) {
return "docker"
return "docker";
}
const ext = fileName.split('.').pop()
return ext || ""
const ext = fileName.split('.').pop();
return ext || "";
}
width: weMode ? 245 : iconSizes[iconSizeIndex] + 16
@@ -89,21 +89,21 @@ StyledRect {
radius: Theme.cornerRadius
color: {
if (keyboardNavigationActive && delegateRoot.index === selectedIndex)
return Theme.surfacePressed
return Theme.surfacePressed;
return mouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent"
return mouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent";
}
border.color: keyboardNavigationActive && delegateRoot.index === selectedIndex ? Theme.primary : "transparent"
border.width: (keyboardNavigationActive && delegateRoot.index === selectedIndex) ? 2 : 0
Component.onCompleted: {
if (keyboardNavigationActive && delegateRoot.index === selectedIndex)
itemSelected(delegateRoot.index, delegateRoot.filePath, delegateRoot.fileName, delegateRoot.fileIsDir)
itemSelected(delegateRoot.index, delegateRoot.filePath, delegateRoot.fileName, delegateRoot.fileIsDir);
}
onSelectedIndexChanged: {
if (keyboardNavigationActive && selectedIndex === delegateRoot.index)
itemSelected(delegateRoot.index, delegateRoot.filePath, delegateRoot.fileName, delegateRoot.fileIsDir)
itemSelected(delegateRoot.index, delegateRoot.filePath, delegateRoot.fileName, delegateRoot.fileIsDir);
}
Column {
@@ -121,19 +121,17 @@ StyledRect {
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) : ""
imagePath: {
if (weMode && delegateRoot.fileIsDir)
return delegateRoot.filePath + "/preview" + weExtensions[weExtIndex];
return (!delegateRoot.fileIsDir && isImageFile(delegateRoot.fileName)) ? delegateRoot.filePath : "";
}
onStatusChanged: {
if (weMode && delegateRoot.fileIsDir && status === Image.Error) {
if (weExtIndex < weExtensions.length - 1) {
weExtIndex++
source = "file://" + delegateRoot.filePath + "/preview" + weExtensions[weExtIndex]
weExtIndex++;
} else {
source = ""
imagePath = "";
}
}
}
@@ -198,7 +196,7 @@ StyledRect {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
itemClicked(delegateRoot.index, delegateRoot.filePath, delegateRoot.fileName, delegateRoot.fileIsDir)
itemClicked(delegateRoot.index, delegateRoot.filePath, delegateRoot.fileName, delegateRoot.fileIsDir);
}
}
}

View File

@@ -20,97 +20,97 @@ StyledRect {
signal itemSelected(int index, string path, string name, bool isDir)
function getFileExtension(fileName) {
const parts = fileName.split('.')
const parts = fileName.split('.');
if (parts.length > 1) {
return parts[parts.length - 1].toLowerCase()
return parts[parts.length - 1].toLowerCase();
}
return ""
return "";
}
function determineFileType(fileName) {
const ext = getFileExtension(fileName)
const ext = getFileExtension(fileName);
const imageExts = ["png", "jpg", "jpeg", "gif", "bmp", "webp", "svg", "ico"]
const imageExts = ["png", "jpg", "jpeg", "gif", "bmp", "webp", "svg", "ico"];
if (imageExts.includes(ext)) {
return "image"
return "image";
}
const videoExts = ["mp4", "mkv", "avi", "mov", "webm", "flv", "wmv", "m4v"]
const videoExts = ["mp4", "mkv", "avi", "mov", "webm", "flv", "wmv", "m4v"];
if (videoExts.includes(ext)) {
return "video"
return "video";
}
const audioExts = ["mp3", "wav", "flac", "ogg", "m4a", "aac", "wma"]
const audioExts = ["mp3", "wav", "flac", "ogg", "m4a", "aac", "wma"];
if (audioExts.includes(ext)) {
return "audio"
return "audio";
}
const codeExts = ["js", "ts", "jsx", "tsx", "py", "go", "rs", "c", "cpp", "h", "java", "kt", "swift", "rb", "php", "html", "css", "scss", "json", "xml", "yaml", "yml", "toml", "sh", "bash", "zsh", "fish", "qml", "vue", "svelte"]
const codeExts = ["js", "ts", "jsx", "tsx", "py", "go", "rs", "c", "cpp", "h", "java", "kt", "swift", "rb", "php", "html", "css", "scss", "json", "xml", "yaml", "yml", "toml", "sh", "bash", "zsh", "fish", "qml", "vue", "svelte"];
if (codeExts.includes(ext)) {
return "code"
return "code";
}
const docExts = ["txt", "md", "pdf", "doc", "docx", "odt", "rtf"]
const docExts = ["txt", "md", "pdf", "doc", "docx", "odt", "rtf"];
if (docExts.includes(ext)) {
return "document"
return "document";
}
const archiveExts = ["zip", "tar", "gz", "bz2", "xz", "7z", "rar"]
const archiveExts = ["zip", "tar", "gz", "bz2", "xz", "7z", "rar"];
if (archiveExts.includes(ext)) {
return "archive"
return "archive";
}
if (!ext || fileName.indexOf('.') === -1) {
return "binary"
return "binary";
}
return "file"
return "file";
}
function isImageFile(fileName) {
if (!fileName) {
return false
return false;
}
return determineFileType(fileName) === "image"
return determineFileType(fileName) === "image";
}
function getIconForFile(fileName) {
const lowerName = fileName.toLowerCase()
const lowerName = fileName.toLowerCase();
if (lowerName.startsWith("dockerfile")) {
return "docker"
return "docker";
}
const ext = fileName.split('.').pop()
return ext || ""
const ext = fileName.split('.').pop();
return ext || "";
}
function formatFileSize(size) {
if (size < 1024)
return size + " B"
return size + " B";
if (size < 1024 * 1024)
return (size / 1024).toFixed(1) + " KB"
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"
return (size / (1024 * 1024)).toFixed(1) + " MB";
return (size / (1024 * 1024 * 1024)).toFixed(1) + " GB";
}
height: 44
radius: Theme.cornerRadius
color: {
if (keyboardNavigationActive && listDelegateRoot.index === selectedIndex)
return Theme.surfacePressed
return listMouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent"
return Theme.surfacePressed;
return listMouseArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) : "transparent";
}
border.color: keyboardNavigationActive && listDelegateRoot.index === selectedIndex ? Theme.primary : "transparent"
border.width: (keyboardNavigationActive && listDelegateRoot.index === selectedIndex) ? 2 : 0
Component.onCompleted: {
if (keyboardNavigationActive && listDelegateRoot.index === selectedIndex)
itemSelected(listDelegateRoot.index, listDelegateRoot.filePath, listDelegateRoot.fileName, listDelegateRoot.fileIsDir)
itemSelected(listDelegateRoot.index, listDelegateRoot.filePath, listDelegateRoot.fileName, listDelegateRoot.fileIsDir);
}
onSelectedIndexChanged: {
if (keyboardNavigationActive && selectedIndex === listDelegateRoot.index)
itemSelected(listDelegateRoot.index, listDelegateRoot.filePath, listDelegateRoot.fileName, listDelegateRoot.fileIsDir)
itemSelected(listDelegateRoot.index, listDelegateRoot.filePath, listDelegateRoot.fileName, listDelegateRoot.fileIsDir);
}
Row {
@@ -127,7 +127,7 @@ StyledRect {
CachingImage {
id: listPreviewImage
anchors.fill: parent
source: (!listDelegateRoot.fileIsDir && isImageFile(listDelegateRoot.fileName)) ? ("file://" + listDelegateRoot.filePath) : ""
imagePath: (!listDelegateRoot.fileIsDir && isImageFile(listDelegateRoot.fileName)) ? listDelegateRoot.filePath : ""
fillMode: Image.PreserveAspectCrop
maxCacheSize: 32
visible: false
@@ -203,7 +203,7 @@ StyledRect {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
itemClicked(listDelegateRoot.index, listDelegateRoot.filePath, listDelegateRoot.fileName, listDelegateRoot.fileIsDir)
itemClicked(listDelegateRoot.index, listDelegateRoot.filePath, listDelegateRoot.fileName, listDelegateRoot.fileIsDir);
}
}
}

View File

@@ -40,6 +40,12 @@ Variants {
id: root
anchors.fill: parent
function encodeFileUrl(path) {
if (!path)
return "";
return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/');
}
property string source: SessionData.getMonitorWallpaper(modelData.name) || ""
property bool isColorSource: source.startsWith("#")
@@ -83,7 +89,7 @@ Variants {
isInitialized = true;
return;
}
const formattedSource = source.startsWith("file://") ? source : "file://" + source;
const formattedSource = source.startsWith("file://") ? source : encodeFileUrl(source);
setWallpaperImmediate(formattedSource);
isInitialized = true;
}
@@ -100,7 +106,7 @@ Variants {
return;
}
const formattedSource = source.startsWith("file://") ? source : "file://" + source;
const formattedSource = source.startsWith("file://") ? source : encodeFileUrl(source);
if (!isInitialized || !currentWallpaper.source) {
setWallpaperImmediate(formattedSource);

View File

@@ -1,7 +1,6 @@
import Qt.labs.folderlistmodel
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import qs.Common
import qs.Modals.FileBrowser
@@ -311,7 +310,7 @@ Item {
showFiles: true
showDirs: false
sortField: FolderListModel.Name
folder: wallpaperDir ? "file://" + wallpaperDir : ""
folder: wallpaperDir ? "file://" + wallpaperDir.split('/').map(s => encodeURIComponent(s)).join('/') : ""
}
FileBrowserSurfaceModal {
@@ -401,7 +400,9 @@ Item {
currentIndex = clampedIndex;
positionViewAtIndex(clampedIndex, GridView.Contain);
}
Qt.callLater(() => { enableAnimation = true; });
Qt.callLater(() => {
enableAnimation = true;
});
}
Connections {

View File

@@ -15,6 +15,12 @@ import qs.Modules.Lock
Item {
id: root
function encodeFileUrl(path) {
if (!path)
return "";
return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/');
}
readonly property string xdgDataDirs: Quickshell.env("XDG_DATA_DIRS")
property string screenName: ""
property string randomFact: ""
@@ -162,7 +168,7 @@ Item {
var _ = SessionData.perMonitorWallpaper;
var __ = SessionData.monitorWallpapers;
var currentWallpaper = SessionData.getMonitorWallpaper(screenName);
return (currentWallpaper && !currentWallpaper.startsWith("#")) ? currentWallpaper : "";
return (currentWallpaper && !currentWallpaper.startsWith("#")) ? encodeFileUrl(currentWallpaper) : "";
}
fillMode: Theme.getFillMode(GreetdSettings.wallpaperFillMode)
smooth: true
@@ -356,14 +362,10 @@ Item {
Layout.preferredWidth: 60
Layout.preferredHeight: 60
imageSource: {
if (PortalService.profileImage === "") {
if (PortalService.profileImage === "")
return "";
}
if (PortalService.profileImage.startsWith("/")) {
return "file://" + PortalService.profileImage;
}
if (PortalService.profileImage.startsWith("/"))
return encodeFileUrl(PortalService.profileImage);
return PortalService.profileImage;
}
fallbackIcon: "person"
@@ -1154,7 +1156,7 @@ Item {
required property string modelData
FolderListModel {
folder: "file://" + modelData
folder: encodeFileUrl(modelData)
nameFilters: ["*.desktop"]
showDirs: false
showDotAndDotDot: false

View File

@@ -14,6 +14,12 @@ import qs.Widgets
Item {
id: root
function encodeFileUrl(path) {
if (!path)
return "";
return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/');
}
property string passwordBuffer: ""
property bool demoMode: false
property string screenName: ""
@@ -170,7 +176,7 @@ Item {
anchors.fill: parent
source: {
var currentWallpaper = SessionData.getMonitorWallpaper(screenName);
return (currentWallpaper && !currentWallpaper.startsWith("#")) ? currentWallpaper : "";
return (currentWallpaper && !currentWallpaper.startsWith("#")) ? encodeFileUrl(currentWallpaper) : "";
}
fillMode: Theme.getFillMode(SettingsData.wallpaperFillMode)
smooth: true
@@ -659,14 +665,10 @@ Item {
Layout.preferredWidth: 60
Layout.preferredHeight: 60
imageSource: {
if (PortalService.profileImage === "") {
if (PortalService.profileImage === "")
return "";
}
if (PortalService.profileImage.startsWith("/")) {
return "file://" + PortalService.profileImage;
}
if (PortalService.profileImage.startsWith("/"))
return encodeFileUrl(PortalService.profileImage);
return PortalService.profileImage;
}
fallbackIcon: "person"

View File

@@ -389,7 +389,7 @@ Item {
CachingImage {
anchors.fill: parent
anchors.margins: 1
source: Theme.wallpaperPath ? "file://" + Theme.wallpaperPath : ""
imagePath: (Theme.wallpaperPath && !Theme.wallpaperPath.startsWith("#")) ? Theme.wallpaperPath : ""
fillMode: Image.PreserveAspectCrop
visible: Theme.wallpaperPath && !Theme.wallpaperPath.startsWith("#")
layer.enabled: true

View File

@@ -55,9 +55,9 @@ Item {
CachingImage {
anchors.fill: parent
anchors.margins: 1
source: {
imagePath: {
var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath;
return (currentWallpaper !== "" && !currentWallpaper.startsWith("#")) ? "file://" + currentWallpaper : "";
return (currentWallpaper !== "" && !currentWallpaper.startsWith("#")) ? currentWallpaper : "";
}
fillMode: Image.PreserveAspectCrop
visible: {
@@ -391,9 +391,9 @@ Item {
CachingImage {
anchors.fill: parent
anchors.margins: 1
source: {
imagePath: {
var lightWallpaper = SessionData.wallpaperPathLight;
return (lightWallpaper !== "" && !lightWallpaper.startsWith("#")) ? "file://" + lightWallpaper : "";
return (lightWallpaper !== "" && !lightWallpaper.startsWith("#")) ? lightWallpaper : "";
}
fillMode: Image.PreserveAspectCrop
visible: {
@@ -575,9 +575,9 @@ Item {
CachingImage {
anchors.fill: parent
anchors.margins: 1
source: {
imagePath: {
var darkWallpaper = SessionData.wallpaperPathDark;
return (darkWallpaper !== "" && !darkWallpaper.startsWith("#")) ? "file://" + darkWallpaper : "";
return (darkWallpaper !== "" && !darkWallpaper.startsWith("#")) ? darkWallpaper : "";
}
fillMode: Image.PreserveAspectCrop
visible: {
@@ -968,17 +968,9 @@ Item {
SettingsDropdownRow {
id: intervalDropdown
property var intervalOptions: [
"5 seconds", "10 seconds", "15 seconds", "20 seconds", "25 seconds", "30 seconds",
"35 seconds", "40 seconds", "45 seconds", "50 seconds", "55 seconds",
"1 minute", "5 minutes", "15 minutes", "30 minutes", "1 hour", "1.5 hours", "2 hours",
"3 hours", "4 hours", "6 hours", "8 hours", "12 hours"
]
property var intervalOptions: ["5 seconds", "10 seconds", "15 seconds", "20 seconds", "25 seconds", "30 seconds", "35 seconds", "40 seconds", "45 seconds", "50 seconds", "55 seconds", "1 minute", "5 minutes", "15 minutes", "30 minutes", "1 hour", "1.5 hours", "2 hours", "3 hours", "4 hours", "6 hours", "8 hours", "12 hours"]
property var intervalValues: [
5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60,
300, 900, 1800, 3600, 5400, 7200, 10800, 14400, 21600, 28800, 43200
]
property var intervalValues: [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 300, 900, 1800, 3600, 5400, 7200, 10800, 14400, 21600, 28800, 43200]
tab: "wallpaper"
tags: ["interval", "cycling", "time", "frequency"]
settingKey: "wallpaperCyclingInterval"

View File

@@ -39,6 +39,12 @@ Variants {
id: root
anchors.fill: parent
function encodeFileUrl(path) {
if (!path)
return "";
return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/');
}
property string source: SessionData.getMonitorWallpaper(modelData.name) || ""
property bool isColorSource: source.startsWith("#")
property string transitionType: SessionData.wallpaperTransition
@@ -108,7 +114,7 @@ Variants {
isInitialized = true;
return;
}
const formattedSource = source.startsWith("file://") ? source : "file://" + source;
const formattedSource = source.startsWith("file://") ? source : encodeFileUrl(source);
setWallpaperImmediate(formattedSource);
isInitialized = true;
}
@@ -119,7 +125,7 @@ Variants {
return;
}
const formattedSource = source.startsWith("file://") ? source : "file://" + source;
const formattedSource = source.startsWith("file://") ? source : encodeFileUrl(source);
if (!isInitialized || !currentWallpaper.source) {
setWallpaperImmediate(formattedSource);

View File

@@ -20,6 +20,7 @@ Image {
readonly property string imageHash: imagePath ? djb2Hash(imagePath) : ""
readonly property string cachePath: imageHash ? `${Paths.stringify(Paths.imagecache)}/${imageHash}@${maxCacheSize}x${maxCacheSize}.png` : ""
readonly property string encodedImagePath: imagePath ? "file://" + imagePath.split('/').map(s => encodeURIComponent(s)).join('/') : ""
asynchronous: true
fillMode: Image.PreserveAspectCrop
@@ -33,15 +34,15 @@ Image {
return;
}
Paths.mkdir(Paths.imagecache);
source = cachePath || imagePath;
source = cachePath || encodedImagePath;
}
onStatusChanged: {
if (source == cachePath && status === Image.Error) {
source = imagePath;
source = encodedImagePath;
return;
}
if (source != imagePath || status !== Image.Ready || !cachePath)
if (source != encodedImagePath || status !== Image.Ready || !cachePath)
return;
Paths.mkdir(Paths.imagecache);
const grabPath = cachePath;