1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 21:42:51 -05:00

integrate light/dark mode and profile image with desktop portal

This commit is contained in:
bbedward
2025-08-05 15:40:34 -04:00
parent 13f37ed48d
commit 283673a314
6 changed files with 231 additions and 33 deletions

View File

@@ -22,7 +22,6 @@ Singleton {
property bool use24HourClock: true property bool use24HourClock: true
property bool useFahrenheit: false property bool useFahrenheit: false
property bool nightModeEnabled: false property bool nightModeEnabled: false
property string profileImage: ""
property string weatherLocation: "New York, NY" property string weatherLocation: "New York, NY"
property string weatherCoordinates: "40.7128,-74.0060" property string weatherCoordinates: "40.7128,-74.0060"
property bool useAutoLocation: false property bool useAutoLocation: false
@@ -147,7 +146,6 @@ Singleton {
use24HourClock = settings.use24HourClock !== undefined ? settings.use24HourClock : true; use24HourClock = settings.use24HourClock !== undefined ? settings.use24HourClock : true;
useFahrenheit = settings.useFahrenheit !== undefined ? settings.useFahrenheit : false; useFahrenheit = settings.useFahrenheit !== undefined ? settings.useFahrenheit : false;
nightModeEnabled = settings.nightModeEnabled !== undefined ? settings.nightModeEnabled : false; nightModeEnabled = settings.nightModeEnabled !== undefined ? settings.nightModeEnabled : false;
profileImage = settings.profileImage !== undefined ? settings.profileImage : "";
weatherLocation = settings.weatherLocation !== undefined ? settings.weatherLocation : "New York, NY"; weatherLocation = settings.weatherLocation !== undefined ? settings.weatherLocation : "New York, NY";
weatherCoordinates = settings.weatherCoordinates !== undefined ? settings.weatherCoordinates : "40.7128,-74.0060"; weatherCoordinates = settings.weatherCoordinates !== undefined ? settings.weatherCoordinates : "40.7128,-74.0060";
useAutoLocation = settings.useAutoLocation !== undefined ? settings.useAutoLocation : false; useAutoLocation = settings.useAutoLocation !== undefined ? settings.useAutoLocation : false;
@@ -229,7 +227,6 @@ Singleton {
"use24HourClock": use24HourClock, "use24HourClock": use24HourClock,
"useFahrenheit": useFahrenheit, "useFahrenheit": useFahrenheit,
"nightModeEnabled": nightModeEnabled, "nightModeEnabled": nightModeEnabled,
"profileImage": profileImage,
"weatherLocation": weatherLocation, "weatherLocation": weatherLocation,
"weatherCoordinates": weatherCoordinates, "weatherCoordinates": weatherCoordinates,
"useAutoLocation": useAutoLocation, "useAutoLocation": useAutoLocation,
@@ -421,10 +418,6 @@ Singleton {
saveSettings(); saveSettings();
} }
function setProfileImage(imageUrl) {
profileImage = imageUrl;
saveSettings();
}
// Widget visibility setters // Widget visibility setters
function setShowLauncherButton(enabled) { function setShowLauncherButton(enabled) {

View File

@@ -151,13 +151,13 @@ PanelWindow {
id: profileImageLoader id: profileImageLoader
source: { source: {
if (Prefs.profileImage === "") if (PortalService.profileImage === "")
return ""; return "";
if (Prefs.profileImage.startsWith("/")) if (PortalService.profileImage.startsWith("/"))
return "file://" + Prefs.profileImage; return "file://" + PortalService.profileImage;
return Prefs.profileImage; return PortalService.profileImage;
} }
smooth: true smooth: true
asynchronous: true asynchronous: true
@@ -215,7 +215,7 @@ PanelWindow {
name: "warning" name: "warning"
size: Theme.iconSize + 8 size: Theme.iconSize + 8
color: Theme.primaryText color: Theme.primaryText
visible: Prefs.profileImage !== "" && profileImageLoader.status === Image.Error visible: PortalService.profileImage !== "" && profileImageLoader.status === Image.Error
} }
} }
@@ -743,8 +743,7 @@ PanelWindow {
description: "Use light theme instead of dark theme" description: "Use light theme instead of dark theme"
checked: Prefs.isLightMode checked: Prefs.isLightMode
onToggled: (checked) => { onToggled: (checked) => {
Prefs.setLightMode(checked); PortalService.setLightMode(checked);
Theme.isLightMode = checked;
} }
} }

View File

@@ -167,11 +167,11 @@ Item {
Image { Image {
id: profileImageLoader id: profileImageLoader
source: { source: {
if (Prefs.profileImage === "") if (PortalService.profileImage === "")
return "" return ""
if (Prefs.profileImage.startsWith("/")) if (PortalService.profileImage.startsWith("/"))
return "file://" + Prefs.profileImage return "file://" + PortalService.profileImage
return Prefs.profileImage return PortalService.profileImage
} }
smooth: true smooth: true
asynchronous: true asynchronous: true
@@ -226,7 +226,7 @@ Item {
name: "warning" name: "warning"
size: Theme.iconSize + 4 size: Theme.iconSize + 4
color: Theme.primaryText color: Theme.primaryText
visible: Prefs.profileImage !== "" && profileImageLoader.status === Image.Error visible: PortalService.profileImage !== "" && profileImageLoader.status === Image.Error
} }
} }

View File

@@ -76,8 +76,7 @@ ScrollView {
description: "Use light theme instead of dark theme" description: "Use light theme instead of dark theme"
checked: Prefs.isLightMode checked: Prefs.isLightMode
onToggled: (checked) => { onToggled: (checked) => {
Prefs.setLightMode(checked); PortalService.setLightMode(checked);
Theme.isLightMode = checked;
} }
} }

View File

@@ -83,13 +83,13 @@ ScrollView {
id: avatarImageSource id: avatarImageSource
source: { source: {
if (Prefs.profileImage === "") if (PortalService.profileImage === "")
return ""; return "";
if (Prefs.profileImage.startsWith("/")) if (PortalService.profileImage.startsWith("/"))
return "file://" + Prefs.profileImage; return "file://" + PortalService.profileImage;
return Prefs.profileImage; return PortalService.profileImage;
} }
smooth: true smooth: true
asynchronous: true asynchronous: true
@@ -147,7 +147,7 @@ ScrollView {
name: "warning" name: "warning"
size: Theme.iconSizeLarge size: Theme.iconSizeLarge
color: Theme.error color: Theme.error
visible: Prefs.profileImage !== "" && avatarImageSource.status === Image.Error visible: PortalService.profileImage !== "" && avatarImageSource.status === Image.Error
} }
} }
@@ -158,7 +158,7 @@ ScrollView {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
StyledText { StyledText {
text: Prefs.profileImage ? Prefs.profileImage.split('/').pop() : "No profile image selected" text: PortalService.profileImage ? PortalService.profileImage.split('/').pop() : "No profile image selected"
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText color: Theme.surfaceText
elide: Text.ElideMiddle elide: Text.ElideMiddle
@@ -166,12 +166,32 @@ ScrollView {
} }
StyledText { StyledText {
text: Prefs.profileImage ? Prefs.profileImage : "" text: PortalService.profileImage ? PortalService.profileImage : ""
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
elide: Text.ElideMiddle elide: Text.ElideMiddle
width: parent.width width: parent.width
visible: Prefs.profileImage !== "" visible: PortalService.profileImage !== ""
}
Row {
spacing: Theme.spacingXS
visible: !PortalService.accountsServiceAvailable
DankIcon {
name: "error"
size: Theme.iconSizeSmall
color: Theme.error
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "xdg-desktop-portal-gtk missing"
font.pixelSize: Theme.fontSizeSmall
color: Theme.error
anchors.verticalCenter: parent.verticalCenter
}
} }
Row { Row {
@@ -214,12 +234,13 @@ ScrollView {
} }
StyledRect { StyledRect {
width: 80 width: 80
height: 32 height: 32
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Theme.surfaceVariant color: Theme.surfaceVariant
opacity: Prefs.profileImage !== "" ? 1 : 0.5 opacity: PortalService.profileImage !== "" ? 1 : 0.5
Row { Row {
anchors.centerIn: parent anchors.centerIn: parent
@@ -243,10 +264,10 @@ ScrollView {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
enabled: Prefs.profileImage !== "" enabled: PortalService.profileImage !== ""
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: { onClicked: {
Prefs.setProfileImage(""); PortalService.setProfileImage("");
} }
} }
@@ -551,7 +572,7 @@ ScrollView {
browserType: "profile" browserType: "profile"
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"] fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
onFileSelected: (path) => { onFileSelected: (path) => {
Prefs.setProfileImage(path); PortalService.setProfileImage(path);
visible = false; visible = false;
} }
onDialogClosed: {} onDialogClosed: {}

186
Services/PortalService.qml Normal file
View File

@@ -0,0 +1,186 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
property bool accountsServiceAvailable: false
property string systemProfileImage: ""
property string profileImage: ""
property bool settingsPortalAvailable: false
property int systemColorScheme: 0 // 0=default, 1=prefer-dark, 2=prefer-light
function getSystemProfileImage() {
systemProfileCheckProcess.running = true
}
function setProfileImage(imagePath) {
profileImage = imagePath
if (accountsServiceAvailable && imagePath) {
setSystemProfileImage(imagePath)
}
}
function getSystemColorScheme() {
systemColorSchemeCheckProcess.running = true
}
function setLightMode(isLightMode) {
if (typeof Theme !== "undefined") {
Theme.isLightMode = isLightMode
}
if (typeof Prefs !== "undefined") {
Prefs.setLightMode(isLightMode)
}
if (settingsPortalAvailable) {
setSystemColorScheme(isLightMode)
}
}
function setSystemColorScheme(isLightMode) {
if (!settingsPortalAvailable) return
var colorScheme = isLightMode ? "prefer-light" : "prefer-dark"
var script = "gsettings set org.gnome.desktop.interface color-scheme '" + colorScheme + "'"
systemColorSchemeSetProcess.command = ["bash", "-c", script]
systemColorSchemeSetProcess.running = true
}
function setSystemProfileImage(imagePath) {
if (!accountsServiceAvailable || !imagePath) return
var script = [
"dbus-send --system --print-reply --dest=org.freedesktop.Accounts",
"/org/freedesktop/Accounts/User$(id -u)",
"org.freedesktop.Accounts.User.SetIconFile",
"string:'" + imagePath + "'"
].join(" ")
systemProfileSetProcess.command = ["bash", "-c", script]
systemProfileSetProcess.running = true
}
Component.onCompleted: {
checkAccountsService()
checkSettingsPortal()
}
function checkAccountsService() {
accountsServiceCheckProcess.running = true
}
function checkSettingsPortal() {
settingsPortalCheckProcess.running = true
}
Process {
id: accountsServiceCheckProcess
command: ["bash", "-c", "dbus-send --system --print-reply --dest=org.freedesktop.Accounts /org/freedesktop/Accounts org.freedesktop.Accounts.FindUserByName string:\"$USER\""]
running: false
onExited: (exitCode) => {
root.accountsServiceAvailable = (exitCode === 0)
if (root.accountsServiceAvailable) {
root.getSystemProfileImage()
}
}
}
Process {
id: systemProfileCheckProcess
command: ["bash", "-c", "dbus-send --system --print-reply --dest=org.freedesktop.Accounts /org/freedesktop/Accounts/User$(id -u) org.freedesktop.DBus.Properties.Get string:org.freedesktop.Accounts.User string:IconFile"]
running: false
stdout: StdioCollector {
onStreamFinished: {
var match = text.match(/string\s+"([^"]+)"/)
if (match && match[1] && match[1] !== "" && match[1] !== "/var/lib/AccountsService/icons/") {
root.systemProfileImage = match[1]
if (!root.profileImage || root.profileImage === "") {
root.profileImage = root.systemProfileImage
}
}
}
}
onExited: (exitCode) => {
if (exitCode !== 0) {
root.systemProfileImage = ""
}
}
}
Process {
id: systemProfileSetProcess
running: false
onExited: (exitCode) => {
if (exitCode === 0) {
root.getSystemProfileImage()
}
}
}
Process {
id: settingsPortalCheckProcess
command: ["gdbus", "call", "--session", "--dest", "org.freedesktop.portal.Desktop", "--object-path", "/org/freedesktop/portal/desktop", "--method", "org.freedesktop.portal.Settings.ReadOne", "org.freedesktop.appearance", "color-scheme"]
running: false
onExited: (exitCode) => {
root.settingsPortalAvailable = (exitCode === 0)
if (root.settingsPortalAvailable) {
root.getSystemColorScheme()
}
}
}
Process {
id: systemColorSchemeCheckProcess
command: ["gdbus", "call", "--session", "--dest", "org.freedesktop.portal.Desktop", "--object-path", "/org/freedesktop/portal/desktop", "--method", "org.freedesktop.portal.Settings.ReadOne", "org.freedesktop.appearance", "color-scheme"]
running: false
stdout: StdioCollector {
onStreamFinished: {
var match = text.match(/uint32 (\d+)/)
if (match && match[1]) {
root.systemColorScheme = parseInt(match[1])
if (typeof Theme !== "undefined") {
var shouldBeLightMode = (root.systemColorScheme === 2)
if (Theme.isLightMode !== shouldBeLightMode) {
Theme.isLightMode = shouldBeLightMode
if (typeof Prefs !== "undefined") {
Prefs.setLightMode(shouldBeLightMode)
}
}
}
}
}
}
onExited: (exitCode) => {
if (exitCode !== 0) {
root.systemColorScheme = 0
}
}
}
Process {
id: systemColorSchemeSetProcess
running: false
onExited: (exitCode) => {
if (exitCode === 0) {
Qt.callLater(() => {
root.getSystemColorScheme()
})
}
}
}
}