mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-15 02:02:08 -04:00
Implement user icon theme selection in settings
This commit is contained in:
246
Common/Prefs.qml
246
Common/Prefs.qml
@@ -7,8 +7,6 @@ import Quickshell
|
|||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
// "auto", "wifi", "ethernet"
|
|
||||||
// Alphabetical tiebreaker
|
|
||||||
|
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@@ -18,26 +16,24 @@ Singleton {
|
|||||||
property real topBarTransparency: 0.75
|
property real topBarTransparency: 0.75
|
||||||
property real popupTransparency: 0.92
|
property real popupTransparency: 0.92
|
||||||
property var recentlyUsedApps: []
|
property var recentlyUsedApps: []
|
||||||
// New global preferences
|
|
||||||
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 profileImage: ""
|
||||||
property string weatherLocationOverride: "New York, NY"
|
property string weatherLocationOverride: "New York, NY"
|
||||||
// Widget visibility preferences for TopBar
|
|
||||||
property bool showFocusedWindow: true
|
property bool showFocusedWindow: true
|
||||||
property bool showWeather: true
|
property bool showWeather: true
|
||||||
property bool showMusic: true
|
property bool showMusic: true
|
||||||
property bool showClipboard: true
|
property bool showClipboard: true
|
||||||
property bool showSystemResources: true
|
property bool showSystemResources: true
|
||||||
property bool showSystemTray: true
|
property bool showSystemTray: true
|
||||||
// WorkspaceSwitcher index toggle
|
|
||||||
property bool showWorkspaceIndex: true
|
property bool showWorkspaceIndex: true
|
||||||
// View mode preferences for launchers
|
|
||||||
property string appLauncherViewMode: "list"
|
property string appLauncherViewMode: "list"
|
||||||
property string spotlightLauncherViewMode: "list"
|
property string spotlightLauncherViewMode: "list"
|
||||||
// Network preference
|
|
||||||
property string networkPreference: "auto"
|
property string networkPreference: "auto"
|
||||||
|
property string iconTheme: "System Default"
|
||||||
|
property var availableIconThemes: ["System Default"]
|
||||||
|
property string systemDefaultIconTheme: "Adwaita"
|
||||||
|
|
||||||
function loadSettings() {
|
function loadSettings() {
|
||||||
parseSettings(settingsFile.text());
|
parseSettings(settingsFile.text());
|
||||||
@@ -68,15 +64,16 @@ Singleton {
|
|||||||
appLauncherViewMode = settings.appLauncherViewMode !== undefined ? settings.appLauncherViewMode : "list";
|
appLauncherViewMode = settings.appLauncherViewMode !== undefined ? settings.appLauncherViewMode : "list";
|
||||||
spotlightLauncherViewMode = settings.spotlightLauncherViewMode !== undefined ? settings.spotlightLauncherViewMode : "list";
|
spotlightLauncherViewMode = settings.spotlightLauncherViewMode !== undefined ? settings.spotlightLauncherViewMode : "list";
|
||||||
networkPreference = settings.networkPreference !== undefined ? settings.networkPreference : "auto";
|
networkPreference = settings.networkPreference !== undefined ? settings.networkPreference : "auto";
|
||||||
console.log("Loaded settings - themeIndex:", themeIndex, "isDynamic:", themeIsDynamic, "lightMode:", isLightMode, "transparency:", topBarTransparency, "recentApps:", recentlyUsedApps.length);
|
iconTheme = settings.iconTheme !== undefined ? settings.iconTheme : "System Default";
|
||||||
applyStoredTheme();
|
applyStoredTheme();
|
||||||
|
detectAvailableIconThemes();
|
||||||
|
updateGtkIconTheme(iconTheme);
|
||||||
|
applyStoredIconTheme();
|
||||||
} else {
|
} else {
|
||||||
console.log("Settings file is empty - applying default theme");
|
applyStoredTheme();
|
||||||
applyStoredTheme();
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Could not parse settings, using defaults:", e);
|
applyStoredTheme();
|
||||||
applyStoredTheme();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,19 +99,17 @@ Singleton {
|
|||||||
"showWorkspaceIndex": showWorkspaceIndex,
|
"showWorkspaceIndex": showWorkspaceIndex,
|
||||||
"appLauncherViewMode": appLauncherViewMode,
|
"appLauncherViewMode": appLauncherViewMode,
|
||||||
"spotlightLauncherViewMode": spotlightLauncherViewMode,
|
"spotlightLauncherViewMode": spotlightLauncherViewMode,
|
||||||
"networkPreference": networkPreference
|
"networkPreference": networkPreference,
|
||||||
|
"iconTheme": iconTheme
|
||||||
}, null, 2));
|
}, null, 2));
|
||||||
console.log("Saving settings - themeIndex:", themeIndex, "isDynamic:", themeIsDynamic, "lightMode:", isLightMode, "transparency:", topBarTransparency, "recentApps:", recentlyUsedApps.length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setShowWorkspaceIndex(enabled) {
|
function setShowWorkspaceIndex(enabled) {
|
||||||
console.log("Prefs setShowWorkspaceIndex called - showWorkspaceIndex:", enabled);
|
|
||||||
showWorkspaceIndex = enabled;
|
showWorkspaceIndex = enabled;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyStoredTheme() {
|
function applyStoredTheme() {
|
||||||
console.log("Applying stored theme:", themeIndex, themeIsDynamic, "lightMode:", isLightMode);
|
|
||||||
if (typeof Theme !== "undefined") {
|
if (typeof Theme !== "undefined") {
|
||||||
Theme.isLightMode = isLightMode;
|
Theme.isLightMode = isLightMode;
|
||||||
Theme.switchTheme(themeIndex, themeIsDynamic, false);
|
Theme.switchTheme(themeIndex, themeIsDynamic, false);
|
||||||
@@ -129,26 +124,22 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setTheme(index, isDynamic) {
|
function setTheme(index, isDynamic) {
|
||||||
console.log("Prefs setTheme called - themeIndex:", index, "isDynamic:", isDynamic);
|
|
||||||
themeIndex = index;
|
themeIndex = index;
|
||||||
themeIsDynamic = isDynamic;
|
themeIsDynamic = isDynamic;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setLightMode(lightMode) {
|
function setLightMode(lightMode) {
|
||||||
console.log("Prefs setLightMode called - isLightMode:", lightMode);
|
|
||||||
isLightMode = lightMode;
|
isLightMode = lightMode;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setTopBarTransparency(transparency) {
|
function setTopBarTransparency(transparency) {
|
||||||
console.log("Prefs setTopBarTransparency called - topBarTransparency:", transparency);
|
|
||||||
topBarTransparency = transparency;
|
topBarTransparency = transparency;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setPopupTransparency(transparency) {
|
function setPopupTransparency(transparency) {
|
||||||
console.log("Prefs setPopupTransparency called - popupTransparency:", transparency);
|
|
||||||
popupTransparency = transparency;
|
popupTransparency = transparency;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
@@ -207,98 +198,180 @@ Singleton {
|
|||||||
|
|
||||||
// New preference setters
|
// New preference setters
|
||||||
function setClockFormat(use24Hour) {
|
function setClockFormat(use24Hour) {
|
||||||
console.log("Prefs setClockFormat called - use24HourClock:", use24Hour);
|
|
||||||
use24HourClock = use24Hour;
|
use24HourClock = use24Hour;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setTemperatureUnit(fahrenheit) {
|
function setTemperatureUnit(fahrenheit) {
|
||||||
console.log("Prefs setTemperatureUnit called - useFahrenheit:", fahrenheit);
|
|
||||||
useFahrenheit = fahrenheit;
|
useFahrenheit = fahrenheit;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setNightModeEnabled(enabled) {
|
function setNightModeEnabled(enabled) {
|
||||||
console.log("Prefs setNightModeEnabled called - nightModeEnabled:", enabled);
|
|
||||||
nightModeEnabled = enabled;
|
nightModeEnabled = enabled;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setProfileImage(imageUrl) {
|
function setProfileImage(imageUrl) {
|
||||||
console.log("Prefs setProfileImage called - profileImage:", imageUrl);
|
|
||||||
profileImage = imageUrl;
|
profileImage = imageUrl;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Widget visibility setters
|
// Widget visibility setters
|
||||||
function setShowFocusedWindow(enabled) {
|
function setShowFocusedWindow(enabled) {
|
||||||
console.log("Prefs setShowFocusedWindow called - showFocusedWindow:", enabled);
|
|
||||||
showFocusedWindow = enabled;
|
showFocusedWindow = enabled;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setShowWeather(enabled) {
|
function setShowWeather(enabled) {
|
||||||
console.log("Prefs setShowWeather called - showWeather:", enabled);
|
|
||||||
showWeather = enabled;
|
showWeather = enabled;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setShowMusic(enabled) {
|
function setShowMusic(enabled) {
|
||||||
console.log("Prefs setShowMusic called - showMusic:", enabled);
|
|
||||||
showMusic = enabled;
|
showMusic = enabled;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setShowClipboard(enabled) {
|
function setShowClipboard(enabled) {
|
||||||
console.log("Prefs setShowClipboard called - showClipboard:", enabled);
|
|
||||||
showClipboard = enabled;
|
showClipboard = enabled;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setShowSystemResources(enabled) {
|
function setShowSystemResources(enabled) {
|
||||||
console.log("Prefs setShowSystemResources called - showSystemResources:", enabled);
|
|
||||||
showSystemResources = enabled;
|
showSystemResources = enabled;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setShowSystemTray(enabled) {
|
function setShowSystemTray(enabled) {
|
||||||
console.log("Prefs setShowSystemTray called - showSystemTray:", enabled);
|
|
||||||
showSystemTray = enabled;
|
showSystemTray = enabled;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
// View mode setters
|
// View mode setters
|
||||||
function setAppLauncherViewMode(mode) {
|
function setAppLauncherViewMode(mode) {
|
||||||
console.log("Prefs setAppLauncherViewMode called - appLauncherViewMode:", mode);
|
|
||||||
appLauncherViewMode = mode;
|
appLauncherViewMode = mode;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSpotlightLauncherViewMode(mode) {
|
function setSpotlightLauncherViewMode(mode) {
|
||||||
console.log("Prefs setSpotlightLauncherViewMode called - spotlightLauncherViewMode:", mode);
|
|
||||||
spotlightLauncherViewMode = mode;
|
spotlightLauncherViewMode = mode;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Weather location override setter
|
// Weather location override setter
|
||||||
function setWeatherLocationOverride(location) {
|
function setWeatherLocationOverride(location) {
|
||||||
console.log("Prefs setWeatherLocationOverride called - weatherLocationOverride:", location);
|
|
||||||
weatherLocationOverride = location;
|
weatherLocationOverride = location;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Network preference setter
|
// Network preference setter
|
||||||
function setNetworkPreference(preference) {
|
function setNetworkPreference(preference) {
|
||||||
console.log("Prefs setNetworkPreference called - networkPreference:", preference);
|
|
||||||
networkPreference = preference;
|
networkPreference = preference;
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function detectAvailableIconThemes() {
|
||||||
|
// First detect system default, then available themes
|
||||||
|
systemDefaultDetectionProcess.running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setIconTheme(themeName) {
|
||||||
|
iconTheme = themeName;
|
||||||
|
|
||||||
|
updateGtkIconTheme(themeName);
|
||||||
|
|
||||||
|
updateQuickshellIconTheme(themeName);
|
||||||
|
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateGtkIconTheme(themeName) {
|
||||||
|
var gtkThemeName;
|
||||||
|
|
||||||
|
switch(themeName) {
|
||||||
|
case "System Default":
|
||||||
|
gtkThemeName = systemDefaultIconTheme;
|
||||||
|
break;
|
||||||
|
case "Papirus":
|
||||||
|
gtkThemeName = "Papirus";
|
||||||
|
break;
|
||||||
|
case "Papirus-Dark":
|
||||||
|
gtkThemeName = "Papirus-Dark";
|
||||||
|
break;
|
||||||
|
case "Papirus-Light":
|
||||||
|
gtkThemeName = "Papirus-Light";
|
||||||
|
break;
|
||||||
|
case "Adwaita":
|
||||||
|
gtkThemeName = "Adwaita";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
gtkThemeName = themeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
envCheckProcess.command = ["sh", "-c", "echo 'QT_QPA_PLATFORMTHEME=' $QT_QPA_PLATFORMTHEME"];
|
||||||
|
envCheckProcess.running = true;
|
||||||
|
|
||||||
|
var gtk3Settings = `[Settings]
|
||||||
|
gtk-icon-theme-name=${gtkThemeName}
|
||||||
|
gtk-theme-name=Adwaita-dark
|
||||||
|
gtk-application-prefer-dark-theme=true`;
|
||||||
|
|
||||||
|
gtk3Process.command = ["sh", "-c", `mkdir -p ~/.config/gtk-3.0 && echo '${gtk3Settings}' > ~/.config/gtk-3.0/settings.ini`];
|
||||||
|
gtk3Process.running = true;
|
||||||
|
|
||||||
|
gtk4Process.command = ["sh", "-c", `mkdir -p ~/.config/gtk-4.0 && echo '${gtk3Settings}' > ~/.config/gtk-4.0/settings.ini`];
|
||||||
|
gtk4Process.running = true;
|
||||||
|
|
||||||
|
reloadThemeProcess.command = ["sh", "-c", "gsettings set org.gnome.desktop.interface icon-theme '" + gtkThemeName + "' 2>/dev/null || true"];
|
||||||
|
reloadThemeProcess.running = true;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateQuickshellIconTheme(themeName) {
|
||||||
|
var quickshellThemeName;
|
||||||
|
|
||||||
|
switch(themeName) {
|
||||||
|
case "System Default":
|
||||||
|
quickshellThemeName = "";
|
||||||
|
break;
|
||||||
|
case "Papirus":
|
||||||
|
quickshellThemeName = "Papirus";
|
||||||
|
break;
|
||||||
|
case "Papirus-Dark":
|
||||||
|
quickshellThemeName = "Papirus-Dark";
|
||||||
|
break;
|
||||||
|
case "Papirus-Light":
|
||||||
|
quickshellThemeName = "Papirus-Light";
|
||||||
|
break;
|
||||||
|
case "Adwaita":
|
||||||
|
quickshellThemeName = "Adwaita";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
quickshellThemeName = themeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (quickshellThemeName) {
|
||||||
|
envSetProcess.command = ["sh", "-c", `export QS_ICON_THEME="${quickshellThemeName}" && rm -rf ~/.cache/icon-cache ~/.cache/thumbnails 2>/dev/null || true`];
|
||||||
|
} else {
|
||||||
|
envSetProcess.command = ["sh", "-c", `unset QS_ICON_THEME && rm -rf ~/.cache/icon-cache ~/.cache/thumbnails 2>/dev/null || true`];
|
||||||
|
}
|
||||||
|
envSetProcess.running = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyStoredIconTheme() {
|
||||||
|
if (iconTheme && iconTheme !== "System Default") {
|
||||||
|
updateGtkIconTheme(iconTheme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: loadSettings()
|
Component.onCompleted: loadSettings()
|
||||||
// Monitor system resources preference changes to control service monitoring
|
|
||||||
onShowSystemResourcesChanged: {
|
onShowSystemResourcesChanged: {
|
||||||
console.log("Prefs: System resources monitoring", showSystemResources ? "enabled" : "disabled");
|
|
||||||
// Control SystemMonitorService based on whether system monitor widgets are visible
|
|
||||||
if (typeof SystemMonitorService !== 'undefined')
|
if (typeof SystemMonitorService !== 'undefined')
|
||||||
SystemMonitorService.enableTopBarMonitoring(showSystemResources);
|
SystemMonitorService.enableTopBarMonitoring(showSystemResources);
|
||||||
|
|
||||||
@@ -312,13 +385,106 @@ Singleton {
|
|||||||
blockWrites: true
|
blockWrites: true
|
||||||
watchChanges: true
|
watchChanges: true
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
console.log("Settings file loaded successfully");
|
|
||||||
parseSettings(settingsFile.text());
|
parseSettings(settingsFile.text());
|
||||||
}
|
}
|
||||||
onLoadFailed: (error) => {
|
onLoadFailed: (error) => {
|
||||||
console.log("Settings file not found, using defaults. Error:", error);
|
|
||||||
applyStoredTheme();
|
applyStoredTheme();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: gtk3Process
|
||||||
|
running: false
|
||||||
|
onExited: (exitCode) => {
|
||||||
|
if (exitCode === 0) {
|
||||||
|
} else {
|
||||||
|
console.warn("Failed to update GTK 3 settings, exit code:", exitCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: gtk4Process
|
||||||
|
running: false
|
||||||
|
onExited: (exitCode) => {
|
||||||
|
if (exitCode === 0) {
|
||||||
|
} else {
|
||||||
|
console.warn("Failed to update GTK 4 settings, exit code:", exitCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: reloadThemeProcess
|
||||||
|
running: false
|
||||||
|
onExited: (exitCode) => {
|
||||||
|
if (exitCode === 0) {
|
||||||
|
} else {
|
||||||
|
console.log("GTK theme reload failed (this is normal if gsettings is not available), exit code:", exitCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: qtThemeProcess
|
||||||
|
running: false
|
||||||
|
onExited: (exitCode) => {
|
||||||
|
console.log("Qt theme reload signal sent, exit code:", exitCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: envCheckProcess
|
||||||
|
running: false
|
||||||
|
onExited: (exitCode) => {
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
console.warn("Environment check failed, exit code:", exitCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: envSetProcess
|
||||||
|
running: false
|
||||||
|
onExited: (exitCode) => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: systemDefaultDetectionProcess
|
||||||
|
command: ["sh", "-c", "gsettings get org.gnome.desktop.interface icon-theme 2>/dev/null | sed \"s/'//g\" || echo 'Adwaita'"]
|
||||||
|
running: false
|
||||||
|
onExited: (exitCode) => {
|
||||||
|
if (exitCode === 0 && stdout && stdout.length > 0) {
|
||||||
|
systemDefaultIconTheme = stdout.trim();
|
||||||
|
} else {
|
||||||
|
systemDefaultIconTheme = "Adwaita";
|
||||||
|
}
|
||||||
|
iconThemeDetectionProcess.running = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: iconThemeDetectionProcess
|
||||||
|
command: ["sh", "-c", "find /usr/share/icons ~/.local/share/icons ~/.icons -maxdepth 1 -type d 2>/dev/null | sed 's|.*/||' | grep -v '^icons$' | sort -u"]
|
||||||
|
running: false
|
||||||
|
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: {
|
||||||
|
var detectedThemes = ["System Default"];
|
||||||
|
if (text && text.trim()) {
|
||||||
|
var themes = text.trim().split('\n');
|
||||||
|
for (var i = 0; i < themes.length; i++) {
|
||||||
|
var theme = themes[i].trim();
|
||||||
|
if (theme && theme !== "" && theme !== "default" && theme !== "hicolor" && theme !== "locolor") {
|
||||||
|
detectedThemes.push(theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
availableIconThemes = detectedThemes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -593,10 +593,10 @@ Singleton {
|
|||||||
// Connect to transparency changes
|
// Connect to transparency changes
|
||||||
if (Prefs.popupTransparencyChanged)
|
if (Prefs.popupTransparencyChanged)
|
||||||
Prefs.popupTransparencyChanged.connect(function() {
|
Prefs.popupTransparencyChanged.connect(function() {
|
||||||
if (typeof Prefs !== "undefined" && Prefs.popupTransparency !== undefined)
|
if (typeof Prefs !== "undefined" && Prefs.popupTransparency !== undefined)
|
||||||
root.popupTransparency = Prefs.popupTransparency;
|
root.popupTransparency = Prefs.popupTransparency;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
console.log("Theme initialized, waiting for Prefs to load settings and apply theme");
|
console.log("Theme initialized, waiting for Prefs to load settings and apply theme");
|
||||||
|
|||||||
104
Modules/GlobalDropdown.qml
Normal file
104
Modules/GlobalDropdown.qml
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import qs.Common
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: globalDropdownWindow
|
||||||
|
|
||||||
|
property var sourceComponent: null
|
||||||
|
property var options: []
|
||||||
|
property string currentValue: ""
|
||||||
|
property int targetX: 0
|
||||||
|
property int targetY: 0
|
||||||
|
signal valueSelected(string value)
|
||||||
|
|
||||||
|
visible: sourceComponent !== null
|
||||||
|
implicitWidth: 180
|
||||||
|
implicitHeight: Math.min(200, options.length * 36 + 16)
|
||||||
|
WlrLayershell.layer: WlrLayershell.Overlay
|
||||||
|
WlrLayershell.exclusiveZone: -1
|
||||||
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||||
|
WlrLayershell.margins {
|
||||||
|
top: targetY
|
||||||
|
left: targetX
|
||||||
|
}
|
||||||
|
anchors {
|
||||||
|
top: true
|
||||||
|
left: true
|
||||||
|
}
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
function showAt(component, globalX, globalY, opts, current) {
|
||||||
|
sourceComponent = component;
|
||||||
|
options = opts;
|
||||||
|
currentValue = current;
|
||||||
|
|
||||||
|
// Set the target position using margins
|
||||||
|
targetX = globalX;
|
||||||
|
targetY = globalY;
|
||||||
|
|
||||||
|
visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide() {
|
||||||
|
sourceComponent = null;
|
||||||
|
visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: Theme.cornerRadiusSmall
|
||||||
|
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 1.0)
|
||||||
|
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingS
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
model: globalDropdownWindow.options
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
width: ListView.view.width
|
||||||
|
height: 32
|
||||||
|
radius: Theme.cornerRadiusSmall
|
||||||
|
color: optionArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Theme.spacingS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: modelData
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: globalDropdownWindow.currentValue === modelData ? Theme.primary : Theme.surfaceText
|
||||||
|
font.weight: globalDropdownWindow.currentValue === modelData ? Font.Medium : Font.Normal
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: optionArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
globalDropdownWindow.valueSelected(modelData);
|
||||||
|
globalDropdownWindow.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close on click outside
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
z: -1
|
||||||
|
onClicked: globalDropdownWindow.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,9 +16,13 @@ PanelWindow {
|
|||||||
signal closingPopup()
|
signal closingPopup()
|
||||||
|
|
||||||
onSettingsVisibleChanged: {
|
onSettingsVisibleChanged: {
|
||||||
if (!settingsVisible)
|
if (!settingsVisible) {
|
||||||
closingPopup();
|
closingPopup();
|
||||||
|
// Hide any open dropdown when settings close
|
||||||
|
if (typeof globalDropdownWindow !== 'undefined') {
|
||||||
|
globalDropdownWindow.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
visible: settingsVisible
|
visible: settingsVisible
|
||||||
implicitWidth: 600
|
implicitWidth: 600
|
||||||
@@ -28,6 +32,110 @@ PanelWindow {
|
|||||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
|
// SettingsDropdown component - only used within this popup
|
||||||
|
Component {
|
||||||
|
id: settingsDropdownComponent
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: dropdownRoot
|
||||||
|
|
||||||
|
property string text: ""
|
||||||
|
property string description: ""
|
||||||
|
property string currentValue: ""
|
||||||
|
property var options: []
|
||||||
|
|
||||||
|
signal valueChanged(string value)
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
height: 60
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08)
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: dropdown.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.leftMargin: Theme.spacingM
|
||||||
|
anchors.rightMargin: Theme.spacingM
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: dropdownRoot.text
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: dropdownRoot.description
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
visible: description.length > 0
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: dropdown
|
||||||
|
|
||||||
|
width: 180
|
||||||
|
height: 36
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Theme.spacingM
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
radius: Theme.cornerRadiusSmall
|
||||||
|
color: dropdownArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.contentBackground()
|
||||||
|
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.leftMargin: Theme.spacingM
|
||||||
|
anchors.rightMargin: Theme.spacingS
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: dropdownRoot.currentValue
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: parent.width - 24
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "expand_more"
|
||||||
|
size: 20
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: dropdownArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
if (typeof globalDropdownWindow !== 'undefined') {
|
||||||
|
// Get global position of the dropdown button
|
||||||
|
var globalPos = dropdown.mapToGlobal(0, 0);
|
||||||
|
globalDropdownWindow.showAt(dropdownRoot, globalPos.x, globalPos.y + dropdown.height + 4, dropdownRoot.options, dropdownRoot.currentValue);
|
||||||
|
|
||||||
|
// Connect to value selection (with cleanup)
|
||||||
|
globalDropdownWindow.valueSelected.connect(function(value) {
|
||||||
|
dropdownRoot.currentValue = value;
|
||||||
|
dropdownRoot.valueChanged(value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: true
|
top: true
|
||||||
left: true
|
left: true
|
||||||
@@ -123,12 +231,38 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Settings sections
|
// Settings sections
|
||||||
ScrollView {
|
Flickable {
|
||||||
|
id: settingsScrollView
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height - 80
|
height: parent.height - 80
|
||||||
clip: true
|
clip: true
|
||||||
|
contentHeight: settingsColumn.height
|
||||||
|
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||||
|
flickDeceleration: 8000
|
||||||
|
maximumFlickVelocity: 15000
|
||||||
|
|
||||||
|
property real wheelStepSize: 60
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
propagateComposedEvents: true
|
||||||
|
z: -1
|
||||||
|
onWheel: (wheel) => {
|
||||||
|
var delta = wheel.angleDelta.y
|
||||||
|
var steps = delta / 120
|
||||||
|
settingsScrollView.contentY -= steps * settingsScrollView.wheelStepSize
|
||||||
|
|
||||||
|
// Keep within bounds
|
||||||
|
if (settingsScrollView.contentY < 0)
|
||||||
|
settingsScrollView.contentY = 0
|
||||||
|
else if (settingsScrollView.contentY > settingsScrollView.contentHeight - settingsScrollView.height)
|
||||||
|
settingsScrollView.contentY = Math.max(0, settingsScrollView.contentHeight - settingsScrollView.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
|
id: settingsColumn
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingL
|
spacing: Theme.spacingL
|
||||||
|
|
||||||
@@ -340,6 +474,7 @@ PanelWindow {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Weather Settings
|
// Weather Settings
|
||||||
SettingsSection {
|
SettingsSection {
|
||||||
title: "Weather"
|
title: "Weather"
|
||||||
@@ -534,6 +669,31 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
width: parent.width
|
||||||
|
sourceComponent: settingsDropdownComponent
|
||||||
|
onLoaded: {
|
||||||
|
item.text = "Icon Theme"
|
||||||
|
item.description = "Select icon theme (requires restart)"
|
||||||
|
item.currentValue = Prefs.iconTheme
|
||||||
|
// Set initial options, will be updated when detection completes
|
||||||
|
item.options = Qt.binding(function() { return Prefs.availableIconThemes; })
|
||||||
|
item.valueChanged.connect(function(value) {
|
||||||
|
Prefs.setIconTheme(value);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update options when available themes change
|
||||||
|
Connections {
|
||||||
|
target: Prefs
|
||||||
|
function onAvailableIconThemesChanged() {
|
||||||
|
if (parent.item && parent.item.hasOwnProperty('options')) {
|
||||||
|
parent.item.options = Prefs.availableIconThemes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Top Bar Transparency
|
// Top Bar Transparency
|
||||||
Column {
|
Column {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import qs.Modules
|
|||||||
import qs.Modules.CenterCommandCenter
|
import qs.Modules.CenterCommandCenter
|
||||||
import qs.Modules.ControlCenter
|
import qs.Modules.ControlCenter
|
||||||
import qs.Modules.TopBar
|
import qs.Modules.TopBar
|
||||||
import qs.Services
|
|
||||||
|
|
||||||
ShellRoot {
|
ShellRoot {
|
||||||
id: root
|
id: root
|
||||||
@@ -17,7 +16,6 @@ ShellRoot {
|
|||||||
delegate: TopBar {
|
delegate: TopBar {
|
||||||
modelData: item
|
modelData: item
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global popup windows
|
// Global popup windows
|
||||||
@@ -69,6 +67,10 @@ ShellRoot {
|
|||||||
id: settingsPopup
|
id: settingsPopup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GlobalDropdown {
|
||||||
|
id: globalDropdownWindow
|
||||||
|
}
|
||||||
|
|
||||||
// Application and clipboard components
|
// Application and clipboard components
|
||||||
AppLauncher {
|
AppLauncher {
|
||||||
id: appLauncher
|
id: appLauncher
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Test script for the new 2nd tier notification system
|
|
||||||
|
|
||||||
echo "Testing 2nd tier notification system..."
|
|
||||||
|
|
||||||
# Send a few test notifications to create a group
|
|
||||||
notify-send "Test App" "Short message 1"
|
|
||||||
sleep 1
|
|
||||||
notify-send "Test App" "This is a much longer message that should trigger the expand/collapse functionality for individual messages within the notification group system"
|
|
||||||
sleep 1
|
|
||||||
notify-send "Test App" "Message 3 with some content"
|
|
||||||
|
|
||||||
echo "Test notifications sent. Check the notification popup and center for:"
|
|
||||||
echo "1. 1st tier controls moved above group header"
|
|
||||||
echo "2. Message count badge next to app name when expanded"
|
|
||||||
echo "3. 'title • timestamp' format for individual messages"
|
|
||||||
echo "4. Expand/collapse buttons for long individual messages"
|
|
||||||
Reference in New Issue
Block a user