1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 13:32:50 -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 useFahrenheit: false
property bool nightModeEnabled: false
property string profileImage: ""
property string weatherLocation: "New York, NY"
property string weatherCoordinates: "40.7128,-74.0060"
property bool useAutoLocation: false
@@ -147,7 +146,6 @@ Singleton {
use24HourClock = settings.use24HourClock !== undefined ? settings.use24HourClock : true;
useFahrenheit = settings.useFahrenheit !== undefined ? settings.useFahrenheit : false;
nightModeEnabled = settings.nightModeEnabled !== undefined ? settings.nightModeEnabled : false;
profileImage = settings.profileImage !== undefined ? settings.profileImage : "";
weatherLocation = settings.weatherLocation !== undefined ? settings.weatherLocation : "New York, NY";
weatherCoordinates = settings.weatherCoordinates !== undefined ? settings.weatherCoordinates : "40.7128,-74.0060";
useAutoLocation = settings.useAutoLocation !== undefined ? settings.useAutoLocation : false;
@@ -229,7 +227,6 @@ Singleton {
"use24HourClock": use24HourClock,
"useFahrenheit": useFahrenheit,
"nightModeEnabled": nightModeEnabled,
"profileImage": profileImage,
"weatherLocation": weatherLocation,
"weatherCoordinates": weatherCoordinates,
"useAutoLocation": useAutoLocation,
@@ -421,10 +418,6 @@ Singleton {
saveSettings();
}
function setProfileImage(imageUrl) {
profileImage = imageUrl;
saveSettings();
}
// Widget visibility setters
function setShowLauncherButton(enabled) {

View File

@@ -151,13 +151,13 @@ PanelWindow {
id: profileImageLoader
source: {
if (Prefs.profileImage === "")
if (PortalService.profileImage === "")
return "";
if (Prefs.profileImage.startsWith("/"))
return "file://" + Prefs.profileImage;
if (PortalService.profileImage.startsWith("/"))
return "file://" + PortalService.profileImage;
return Prefs.profileImage;
return PortalService.profileImage;
}
smooth: true
asynchronous: true
@@ -215,7 +215,7 @@ PanelWindow {
name: "warning"
size: Theme.iconSize + 8
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"
checked: Prefs.isLightMode
onToggled: (checked) => {
Prefs.setLightMode(checked);
Theme.isLightMode = checked;
PortalService.setLightMode(checked);
}
}

View File

@@ -167,11 +167,11 @@ Item {
Image {
id: profileImageLoader
source: {
if (Prefs.profileImage === "")
if (PortalService.profileImage === "")
return ""
if (Prefs.profileImage.startsWith("/"))
return "file://" + Prefs.profileImage
return Prefs.profileImage
if (PortalService.profileImage.startsWith("/"))
return "file://" + PortalService.profileImage
return PortalService.profileImage
}
smooth: true
asynchronous: true
@@ -226,7 +226,7 @@ Item {
name: "warning"
size: Theme.iconSize + 4
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"
checked: Prefs.isLightMode
onToggled: (checked) => {
Prefs.setLightMode(checked);
Theme.isLightMode = checked;
PortalService.setLightMode(checked);
}
}

View File

@@ -83,13 +83,13 @@ ScrollView {
id: avatarImageSource
source: {
if (Prefs.profileImage === "")
if (PortalService.profileImage === "")
return "";
if (Prefs.profileImage.startsWith("/"))
return "file://" + Prefs.profileImage;
if (PortalService.profileImage.startsWith("/"))
return "file://" + PortalService.profileImage;
return Prefs.profileImage;
return PortalService.profileImage;
}
smooth: true
asynchronous: true
@@ -147,7 +147,7 @@ ScrollView {
name: "warning"
size: Theme.iconSizeLarge
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
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
color: Theme.surfaceText
elide: Text.ElideMiddle
@@ -166,12 +166,32 @@ ScrollView {
}
StyledText {
text: Prefs.profileImage ? Prefs.profileImage : ""
text: PortalService.profileImage ? PortalService.profileImage : ""
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
elide: Text.ElideMiddle
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 {
@@ -214,12 +234,13 @@ ScrollView {
}
StyledRect {
width: 80
height: 32
radius: Theme.cornerRadius
color: Theme.surfaceVariant
opacity: Prefs.profileImage !== "" ? 1 : 0.5
opacity: PortalService.profileImage !== "" ? 1 : 0.5
Row {
anchors.centerIn: parent
@@ -243,10 +264,10 @@ ScrollView {
MouseArea {
anchors.fill: parent
enabled: Prefs.profileImage !== ""
enabled: PortalService.profileImage !== ""
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
Prefs.setProfileImage("");
PortalService.setProfileImage("");
}
}
@@ -551,7 +572,7 @@ ScrollView {
browserType: "profile"
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
onFileSelected: (path) => {
Prefs.setProfileImage(path);
PortalService.setProfileImage(path);
visible = false;
}
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()
})
}
}
}
}