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

General code cleanups

This commit is contained in:
bbedward
2025-08-02 16:18:12 -04:00
parent 2cf7497324
commit 599118c63e
68 changed files with 102 additions and 1241 deletions

View File

@@ -7,79 +7,22 @@ import Quickshell
Singleton { Singleton {
id: root id: root
// Durations match M3 token tiers: short4/medium4/long4
readonly property int durShort: 200 readonly property int durShort: 200
readonly property int durMed: 450 readonly property int durMed: 450
readonly property int durLong: 600 readonly property int durLong: 600
readonly property int slidePx: 80 readonly property int slidePx: 80
// Material Design 3 motion curves (for QML BezierSpline)
// Use groups of: [cx1, cy1, cx2, cy2, endX, endY, ...]
// Single-segment cubics end with 1,1.
// Emphasized (multi-segment) for on-screen-to-on-screen moves
readonly property var emphasized: [ readonly property var emphasized: [
0.05, 0.00, 0.133333, 0.06, 0.166667, 0.40, 0.05, 0.00, 0.133333, 0.06, 0.166667, 0.40,
0.208333, 0.82, 0.25, 1.00, 1.00, 1.00 0.208333, 0.82, 0.25, 1.00, 1.00, 1.00
] ]
// Emphasized decelerate entering
readonly property var emphasizedDecel: [ 0.05, 0.70, 0.10, 1.00, 1.00, 1.00 ] readonly property var emphasizedDecel: [ 0.05, 0.70, 0.10, 1.00, 1.00, 1.00 ]
// Emphasized accelerate exiting
readonly property var emphasizedAccel: [ 0.30, 0.00, 0.80, 0.15, 1.00, 1.00 ] readonly property var emphasizedAccel: [ 0.30, 0.00, 0.80, 0.15, 1.00, 1.00 ]
// Standard set for small/subtle transitions
readonly property var standard: [ 0.20, 0.00, 0.00, 1.00, 1.00, 1.00 ] readonly property var standard: [ 0.20, 0.00, 0.00, 1.00, 1.00, 1.00 ]
readonly property var standardDecel: [ 0.00, 0.00, 0.00, 1.00, 1.00, 1.00 ] readonly property var standardDecel: [ 0.00, 0.00, 0.00, 1.00, 1.00, 1.00 ]
readonly property var standardAccel: [ 0.30, 0.00, 1.00, 1.00, 1.00, 1.00 ] readonly property var standardAccel: [ 0.30, 0.00, 1.00, 1.00, 1.00, 1.00 ]
// readonly property QtObject direction: QtObject {
// readonly property int fromLeft: 0
// readonly property int fromRight: 1
// readonly property int fadeOnly: 2
// }
// // Slide transitions (surface/large moves)
// // Enter = emphasizedDecel, Exit = emphasizedAccel
// readonly property Component slideInLeft: Transition {
// NumberAnimation {
// properties: "x"; from: -root.slidePx; to: 0; duration: root.durMed
// easing.type: Easing.BezierSpline; easing.bezierCurve: root.emphasizedDecel
// }
// }
// readonly property Component slideOutLeft: Transition {
// NumberAnimation {
// properties: "x"; to: -root.slidePx; duration: root.durShort
// easing.type: Easing.BezierSpline; easing.bezierCurve: root.emphasizedAccel
// }
// }
// readonly property Component slideInRight: Transition {
// NumberAnimation {
// properties: "x"; from: root.slidePx; to: 0; duration: root.durMed
// easing.type: Easing.BezierSpline; easing.bezierCurve: root.emphasizedDecel
// }
// }
// readonly property Component slideOutRight: Transition {
// NumberAnimation {
// properties: "x"; to: root.slidePx; duration: root.durShort
// easing.type: Easing.BezierSpline; easing.bezierCurve: root.emphasizedAccel
// }
// }
// // Fade transitions (small/subtle moves)
// // Enter = standardDecel, Exit = standardAccel
// readonly property Component fadeIn: Transition {
// NumberAnimation {
// properties: "opacity"; from: 0.0; to: 1.0; duration: root.durMed
// easing.type: Easing.BezierSpline; easing.bezierCurve: root.standardDecel
// }
// }
// readonly property Component fadeOut: Transition {
// NumberAnimation {
// properties: "opacity"; to: 0.0; duration: root.durShort
// easing.type: Easing.BezierSpline; easing.bezierCurve: root.standardAccel
// }
// }
} }

View File

@@ -52,20 +52,16 @@ Singleton {
function onLightModeChanged() { function onLightModeChanged() {
if (matugenColors && Object.keys(matugenColors).length > 0) { if (matugenColors && Object.keys(matugenColors).length > 0) {
console.log("Light mode changed - updating dynamic colors");
colorUpdateTrigger++; colorUpdateTrigger++;
colorsUpdated(); colorsUpdated();
// If dynamic theme is active, regenerate system themes with new light/dark mode
if (typeof Theme !== "undefined" && Theme.isDynamicTheme) { if (typeof Theme !== "undefined" && Theme.isDynamicTheme) {
console.log("Regenerating system themes for new light/dark mode");
generateSystemThemes(); generateSystemThemes();
} }
} }
} }
function extractColors() { function extractColors() {
console.log("Colors.extractColors() called, matugenAvailable:", matugenAvailable);
extractionRequested = true; extractionRequested = true;
if (matugenAvailable) if (matugenAvailable)
fileChecker.running = true; fileChecker.running = true;
@@ -91,7 +87,6 @@ Singleton {
} }
Component.onCompleted: { Component.onCompleted: {
console.log("Colors.qml → home =", homeDir);
matugenCheck.running = true; matugenCheck.running = true;
checkGtkThemingAvailability(); checkGtkThemingAvailability();
checkQtThemingAvailability(); checkQtThemingAvailability();
@@ -105,15 +100,12 @@ Singleton {
command: ["which", "matugen"] command: ["which", "matugen"]
onExited: (code) => { onExited: (code) => {
matugenAvailable = (code === 0); matugenAvailable = (code === 0);
console.log("Matugen in PATH:", matugenAvailable);
if (!matugenAvailable) { if (!matugenAvailable) {
console.warn("Matugen missing → dynamic theme disabled");
ToastService.wallpaperErrorStatus = "matugen_missing"; ToastService.wallpaperErrorStatus = "matugen_missing";
ToastService.showWarning("matugen not found - dynamic theming disabled"); ToastService.showWarning("matugen not found - dynamic theming disabled");
return ; return ;
} }
if (extractionRequested) { if (extractionRequested) {
console.log("Continuing with color extraction");
fileChecker.running = true; fileChecker.running = true;
} }
} }
@@ -127,8 +119,6 @@ Singleton {
if (code === 0) { if (code === 0) {
matugenProcess.running = true; matugenProcess.running = true;
} else { } else {
console.error("code", code);
console.error("Wallpaper not found:", wallpaperPath);
ToastService.wallpaperErrorStatus = "error"; ToastService.wallpaperErrorStatus = "error";
ToastService.showError("Wallpaper processing failed"); ToastService.showError("Wallpaper processing failed");
} }
@@ -146,7 +136,6 @@ Singleton {
onStreamFinished: { onStreamFinished: {
const out = matugenCollector.text; const out = matugenCollector.text;
if (!out.length) { if (!out.length) {
console.error("matugen produced zero bytes\nstderr:", matugenProcess.stderr);
ToastService.wallpaperErrorStatus = "error"; ToastService.wallpaperErrorStatus = "error";
ToastService.showError("Wallpaper Processing Failed"); ToastService.showError("Wallpaper Processing Failed");
return ; return ;
@@ -158,7 +147,6 @@ Singleton {
generateAppConfigs(); generateAppConfigs();
ToastService.clearWallpaperError(); ToastService.clearWallpaperError();
} catch (e) { } catch (e) {
console.error("JSON parse failed:", e);
ToastService.wallpaperErrorStatus = "error"; ToastService.wallpaperErrorStatus = "error";
ToastService.showError("Wallpaper Processing Failed"); ToastService.showError("Wallpaper Processing Failed");
} }
@@ -173,7 +161,6 @@ Singleton {
function generateAppConfigs() { function generateAppConfigs() {
if (!matugenColors || !matugenColors.colors) { if (!matugenColors || !matugenColors.colors) {
console.warn("No matugen colors available for app config generation");
return; return;
} }
@@ -197,8 +184,7 @@ Singleton {
var secondary = dark.secondary || "#8ab4f8"; var secondary = dark.secondary || "#8ab4f8";
var inverse = dark.inverse_primary || "#6200ea"; var inverse = dark.inverse_primary || "#6200ea";
var content = `// AUTO-GENERATED on ${new Date().toISOString()} var content = `layout {
layout {
border { border {
active-color "${primary}" active-color "${primary}"
inactive-color "${secondary}" inactive-color "${secondary}"
@@ -209,8 +195,7 @@ layout {
background-color "${bg}" background-color "${bg}"
}`; }`;
niriConfigWriter.command = ["bash", "-c", `echo '${content}' > niri-colors.generated.kdl`]; Quickshell.execDetached(["bash", "-c", `echo '${content}' > niri-colors.generated.kdl`]);
niriConfigWriter.running = true;
} }
function generateGhosttyConfig() { function generateGhosttyConfig() {
@@ -236,8 +221,7 @@ layout {
var error_b = light.error || "#b00020"; var error_b = light.error || "#b00020";
var inverse_b = light.inverse_primary || "#bb86fc"; var inverse_b = light.inverse_primary || "#bb86fc";
var content = `# AUTO-GENERATED on ${new Date().toISOString()} var content = `background = ${bg}
background = ${bg}
foreground = ${fg} foreground = ${fg}
cursor-color = ${inverse} cursor-color = ${inverse}
selection-background = ${secondary} selection-background = ${secondary}
@@ -259,8 +243,10 @@ palette = 13=${tertiary_ctr_b}
palette = 14=${inverse_b} palette = 14=${inverse_b}
palette = 15=${fg_b}`; palette = 15=${fg_b}`;
ghosttyConfigWriter.command = ["bash", "-c", `echo '${content}' > ghostty-colors.generated.conf`]; var ghosttyConfigDir = configDir + "/ghostty";
ghosttyConfigWriter.running = true; var ghosttyConfigPath = ghosttyConfigDir + "/config-colors";
Quickshell.execDetached(["bash", "-c", `mkdir -p '${ghosttyConfigDir}' && echo '${content}' > '${ghosttyConfigPath}'`]);
} }
function checkGtkThemingAvailability() { function checkGtkThemingAvailability() {
@@ -273,97 +259,49 @@ palette = 15=${fg_b}`;
function generateSystemThemes() { function generateSystemThemes() {
if (systemThemeGenerationInProgress) { if (systemThemeGenerationInProgress) {
console.log("System theme generation already in progress, skipping");
return; return;
} }
if (!matugenAvailable) { if (!matugenAvailable) {
console.warn("Matugen not available, cannot generate system themes");
return; return;
} }
if (!wallpaperPath || wallpaperPath === "") { if (!wallpaperPath || wallpaperPath === "") {
console.warn("No wallpaper path set, cannot generate system themes");
return; return;
} }
console.log("Generating system themes using matugen templates");
console.log("Wallpaper:", wallpaperPath);
console.log("Shell directory:", shellDir);
// Get current theme preferences
const isLight = (typeof Theme !== "undefined" && Theme.isLightMode) ? "true" : "false"; const isLight = (typeof Theme !== "undefined" && Theme.isLightMode) ? "true" : "false";
const iconTheme = (typeof Prefs !== "undefined" && Prefs.iconTheme) ? Prefs.iconTheme : "System Default"; const iconTheme = (typeof Prefs !== "undefined" && Prefs.iconTheme) ? Prefs.iconTheme : "System Default";
const gtkTheming = (typeof Prefs !== "undefined" && Prefs.gtkThemingEnabled) ? "true" : "false"; const gtkTheming = (typeof Prefs !== "undefined" && Prefs.gtkThemingEnabled) ? "true" : "false";
const qtTheming = (typeof Prefs !== "undefined" && Prefs.qtThemingEnabled) ? "true" : "false"; const qtTheming = (typeof Prefs !== "undefined" && Prefs.qtThemingEnabled) ? "true" : "false";
console.log("Theme mode:", isLight === "true" ? "light" : "dark");
console.log("Icon theme:", iconTheme);
console.log("GTK theming enabled:", gtkTheming);
console.log("Qt theming enabled:", qtTheming);
systemThemeGenerationInProgress = true; systemThemeGenerationInProgress = true;
systemThemeGenerator.command = [shellDir + "/generate-themes.sh", wallpaperPath, shellDir, configDir, "generate", isLight, iconTheme, gtkTheming, qtTheming]; systemThemeGenerator.command = [shellDir + "/generate-themes.sh", wallpaperPath, shellDir, configDir, "generate", isLight, iconTheme, gtkTheming, qtTheming];
systemThemeGenerator.running = true; systemThemeGenerator.running = true;
} }
function generateGtkThemes() { function generateGtkThemes() {
console.log("Generating GTK themes using matugen templates");
generateSystemThemes(); generateSystemThemes();
} }
function generateQtThemes() { function generateQtThemes() {
console.log("Generating Qt themes using matugen templates");
generateSystemThemes(); generateSystemThemes();
} }
function restoreSystemThemes() { function restoreSystemThemes() {
console.log("Restoring original system themes");
const shellDir = root.shellDir; const shellDir = root.shellDir;
if (!shellDir) { if (!shellDir) {
console.warn("Shell directory not available, cannot restore system themes");
return; return;
} }
// Get current theme preferences
const isLight = (typeof Theme !== "undefined" && Theme.isLightMode) ? "true" : "false"; const isLight = (typeof Theme !== "undefined" && Theme.isLightMode) ? "true" : "false";
const iconTheme = (typeof Prefs !== "undefined" && Prefs.iconTheme) ? Prefs.iconTheme : "System Default"; const iconTheme = (typeof Prefs !== "undefined" && Prefs.iconTheme) ? Prefs.iconTheme : "System Default";
const gtkTheming = (typeof Prefs !== "undefined" && Prefs.gtkThemingEnabled) ? "true" : "false"; const gtkTheming = (typeof Prefs !== "undefined" && Prefs.gtkThemingEnabled) ? "true" : "false";
const qtTheming = (typeof Prefs !== "undefined" && Prefs.qtThemingEnabled) ? "true" : "false"; const qtTheming = (typeof Prefs !== "undefined" && Prefs.qtThemingEnabled) ? "true" : "false";
console.log("Restoring to theme mode:", isLight === "true" ? "light" : "dark");
console.log("Icon theme:", iconTheme);
console.log("GTK theming enabled:", gtkTheming);
console.log("Qt theming enabled:", qtTheming);
systemThemeRestoreProcess.command = [shellDir + "/generate-themes.sh", "", shellDir, configDir, "restore", isLight, iconTheme, gtkTheming, qtTheming]; systemThemeRestoreProcess.command = [shellDir + "/generate-themes.sh", "", shellDir, configDir, "restore", isLight, iconTheme, gtkTheming, qtTheming];
systemThemeRestoreProcess.running = true; systemThemeRestoreProcess.running = true;
} }
Process {
id: niriConfigWriter
running: false
onExited: (exitCode) => {
if (exitCode === 0) {
console.log("Generated niri-colors.generated.kdl");
} else {
console.warn("Failed to generate niri config, exit code:", exitCode);
}
}
}
Process {
id: ghosttyConfigWriter
running: false
onExited: (exitCode) => {
if (exitCode === 0) {
console.log("Generated ghostty-colors.generated.conf");
} else {
console.warn("Failed to generate ghostty config, exit code:", exitCode);
}
}
}
Process { Process {
id: gtkAvailabilityChecker id: gtkAvailabilityChecker
@@ -371,7 +309,6 @@ palette = 15=${fg_b}`;
running: false running: false
onExited: (exitCode) => { onExited: (exitCode) => {
gtkThemingEnabled = (exitCode === 0); gtkThemingEnabled = (exitCode === 0);
console.log("GTK theming available:", gtkThemingEnabled);
} }
} }
@@ -381,7 +318,6 @@ palette = 15=${fg_b}`;
running: false running: false
onExited: (exitCode) => { onExited: (exitCode) => {
qtThemingEnabled = (exitCode === 0); qtThemingEnabled = (exitCode === 0);
console.log("Qt theming available:", qtThemingEnabled);
} }
} }
@@ -397,21 +333,10 @@ palette = 15=${fg_b}`;
id: systemThemeStderr id: systemThemeStderr
} }
onStarted: {
console.log("System theme generation process started with command:", command);
}
onExited: (exitCode) => { onExited: (exitCode) => {
systemThemeGenerationInProgress = false; systemThemeGenerationInProgress = false;
console.log("System theme generation process exited with code:", exitCode);
if (exitCode === 0) { if (exitCode !== 0) {
console.log("System themes generated successfully");
console.log("stdout:", systemThemeStdout.text);
} else {
console.error("System theme generation failed, exit code:", exitCode);
console.error("stdout:", systemThemeStdout.text);
console.error("stderr:", systemThemeStderr.text);
ToastService.showError("Failed to generate system themes: " + systemThemeStderr.text); ToastService.showError("Failed to generate system themes: " + systemThemeStderr.text);
} }
} }
@@ -429,21 +354,10 @@ palette = 15=${fg_b}`;
id: restoreThemeStderr id: restoreThemeStderr
} }
onStarted: {
console.log("System theme restoration process started with command:", command);
}
onExited: (exitCode) => { onExited: (exitCode) => {
console.log("System theme restoration process exited with code:", exitCode);
if (exitCode === 0) { if (exitCode === 0) {
console.log("System themes restored successfully");
console.log("stdout:", restoreThemeStdout.text);
ToastService.showInfo("System themes restored to default"); ToastService.showInfo("System themes restored to default");
} else { } else {
console.error("System theme restoration failed, exit code:", exitCode);
console.error("stdout:", restoreThemeStdout.text);
console.error("stderr:", restoreThemeStderr.text);
ToastService.showWarning("Failed to restore system themes: " + restoreThemeStderr.text); ToastService.showWarning("Failed to restore system themes: " + restoreThemeStderr.text);
} }
} }

View File

@@ -42,12 +42,10 @@ Singleton {
property var topBarCenterWidgets: ["clock", "music", "weather"] property var topBarCenterWidgets: ["clock", "music", "weather"]
property var topBarRightWidgets: ["systemTray", "clipboard", "systemResources", "notificationButton", "battery", "controlCenterButton"] property var topBarRightWidgets: ["systemTray", "clipboard", "systemResources", "notificationButton", "battery", "controlCenterButton"]
// Reactive ListModel properties for TopBar
property alias topBarLeftWidgetsModel: leftWidgetsModel property alias topBarLeftWidgetsModel: leftWidgetsModel
property alias topBarCenterWidgetsModel: centerWidgetsModel property alias topBarCenterWidgetsModel: centerWidgetsModel
property alias topBarRightWidgetsModel: rightWidgetsModel property alias topBarRightWidgetsModel: rightWidgetsModel
// Signal to force immediate TopBar layout refresh
signal forceTopBarLayoutRefresh() signal forceTopBarLayoutRefresh()
ListModel { ListModel {
@@ -108,7 +106,6 @@ Singleton {
if (missingFonts.length > 0) { if (missingFonts.length > 0) {
var message = "Missing fonts: " + missingFonts.join(", ") + ". Using system defaults." var message = "Missing fonts: " + missingFonts.join(", ") + ". Using system defaults."
console.warn("Prefs: " + message)
ToastService.showWarning(message) ToastService.showWarning(message)
} }
} }
@@ -162,7 +159,6 @@ Singleton {
showWorkspaceIndex = settings.showWorkspaceIndex !== undefined ? settings.showWorkspaceIndex : false; showWorkspaceIndex = settings.showWorkspaceIndex !== undefined ? settings.showWorkspaceIndex : false;
showWorkspacePadding = settings.showWorkspacePadding !== undefined ? settings.showWorkspacePadding : false; showWorkspacePadding = settings.showWorkspacePadding !== undefined ? settings.showWorkspacePadding : false;
if (settings.topBarWidgetOrder) { if (settings.topBarWidgetOrder) {
// Migrate from old single list to new three-list system
topBarLeftWidgets = settings.topBarWidgetOrder.filter(w => ["launcherButton", "workspaceSwitcher", "focusedWindow"].includes(w)); topBarLeftWidgets = settings.topBarWidgetOrder.filter(w => ["launcherButton", "workspaceSwitcher", "focusedWindow"].includes(w));
topBarCenterWidgets = settings.topBarWidgetOrder.filter(w => ["clock", "music", "weather"].includes(w)); topBarCenterWidgets = settings.topBarWidgetOrder.filter(w => ["clock", "music", "weather"].includes(w));
topBarRightWidgets = settings.topBarWidgetOrder.filter(w => ["systemTray", "clipboard", "systemResources", "notificationButton", "battery", "controlCenterButton"].includes(w)); topBarRightWidgets = settings.topBarWidgetOrder.filter(w => ["systemTray", "clipboard", "systemResources", "notificationButton", "battery", "controlCenterButton"].includes(w));
@@ -497,7 +493,6 @@ Singleton {
function updateListModel(listModel, order) { function updateListModel(listModel, order) {
listModel.clear(); listModel.clear();
for (var i = 0; i < order.length; i++) { for (var i = 0; i < order.length; i++) {
// Handle both old string format and new object format
var widgetId = typeof order[i] === "string" ? order[i] : order[i].id; var widgetId = typeof order[i] === "string" ? order[i] : order[i].id;
var enabled = typeof order[i] === "string" ? true : order[i].enabled; var enabled = typeof order[i] === "string" ? true : order[i].enabled;
var size = typeof order[i] === "string" ? undefined : order[i].size; var size = typeof order[i] === "string" ? undefined : order[i].size;
@@ -577,21 +572,16 @@ Singleton {
updateQtIconTheme(themeName); updateQtIconTheme(themeName);
saveSettings(); saveSettings();
// If dynamic theme is active, regenerate system themes with new icon theme
if (typeof Theme !== "undefined" && Theme.isDynamicTheme && typeof Colors !== "undefined") { if (typeof Theme !== "undefined" && Theme.isDynamicTheme && typeof Colors !== "undefined") {
console.log("Icon theme changed during dynamic theming - regenerating system themes");
Colors.generateSystemThemes(); Colors.generateSystemThemes();
} }
} }
function updateGtkIconTheme(themeName) { function updateGtkIconTheme(themeName) {
console.log("Updating GTK icon theme to:", themeName);
var gtkThemeName = (themeName === "System Default") ? systemDefaultIconTheme : themeName; var gtkThemeName = (themeName === "System Default") ? systemDefaultIconTheme : themeName;
// Update icon theme via dconf/gsettings AND settings.ini files
if (gtkThemeName !== "System Default" && gtkThemeName !== "") { if (gtkThemeName !== "System Default" && gtkThemeName !== "") {
var script = var script =
"# Update dconf/gsettings with multiple fallbacks for Fedora\n" +
"if command -v gsettings >/dev/null 2>&1 && gsettings list-schemas | grep -q org.gnome.desktop.interface; then\n" + "if command -v gsettings >/dev/null 2>&1 && gsettings list-schemas | grep -q org.gnome.desktop.interface; then\n" +
" gsettings set org.gnome.desktop.interface icon-theme '" + gtkThemeName + "'\n" + " gsettings set org.gnome.desktop.interface icon-theme '" + gtkThemeName + "'\n" +
" echo 'Updated via gsettings'\n" + " echo 'Updated via gsettings'\n" +
@@ -635,7 +625,6 @@ Singleton {
} }
function updateQtIconTheme(themeName) { function updateQtIconTheme(themeName) {
console.log("Updating Qt icon theme to:", themeName);
var qtThemeName = (themeName === "System Default") ? "" : themeName; var qtThemeName = (themeName === "System Default") ? "" : themeName;
var home = _shq(root._homeUrl.replace("file://", "")); var home = _shq(root._homeUrl.replace("file://", ""));
@@ -743,7 +732,6 @@ Singleton {
wallpaperPath = path; wallpaperPath = path;
saveSettings(); saveSettings();
// Trigger dynamic theming if enabled
if (wallpaperDynamicTheming && path && typeof Theme !== "undefined") { if (wallpaperDynamicTheming && path && typeof Theme !== "undefined") {
Theme.switchTheme(themeIndex, true, true); Theme.switchTheme(themeIndex, true, true);
} }
@@ -753,7 +741,6 @@ Singleton {
wallpaperDynamicTheming = enabled; wallpaperDynamicTheming = enabled;
saveSettings(); saveSettings();
// If enabled and we have a wallpaper, trigger dynamic theming
if (enabled && wallpaperPath && typeof Theme !== "undefined") { if (enabled && wallpaperPath && typeof Theme !== "undefined") {
Theme.switchTheme(themeIndex, true, true); Theme.switchTheme(themeIndex, true, true);
} }
@@ -763,7 +750,6 @@ Singleton {
wallpaperPath = imagePath; wallpaperPath = imagePath;
saveSettings(); saveSettings();
// Trigger color extraction if dynamic theming is enabled
if (wallpaperDynamicTheming && typeof Colors !== "undefined") { if (wallpaperDynamicTheming && typeof Colors !== "undefined") {
Colors.extractColors(); Colors.extractColors();
} }
@@ -799,7 +785,6 @@ Singleton {
saveSettings(); saveSettings();
} }
// Helper to safely single-quote shell strings
function _shq(s) { function _shq(s) {
return "'" + String(s).replace(/'/g, "'\\''") + "'"; return "'" + String(s).replace(/'/g, "'\\''") + "'";
} }
@@ -819,64 +804,7 @@ Singleton {
} }
} }
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) => {
// Qt theme reload signal sent
}
}
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 { Process {
id: systemDefaultDetectionProcess id: systemDefaultDetectionProcess

View File

@@ -9,7 +9,6 @@ import Quickshell.Services.UPower
Singleton { Singleton {
id: root id: root
// Theme definitions with complete Material 3 expressive color palettes
property var themes: [{ property var themes: [{
"name": "Blue", "name": "Blue",
"primary": "#42a5f5", "primary": "#42a5f5",
@@ -171,7 +170,6 @@ Singleton {
"surfaceContainer": "#201a19", "surfaceContainer": "#201a19",
"surfaceContainerHigh": "#2b2221" "surfaceContainerHigh": "#2b2221"
}] }]
// Light theme variants
property var lightThemes: [{ property var lightThemes: [{
"name": "Blue Light", "name": "Blue Light",
"primary": "#1976d2", "primary": "#1976d2",
@@ -333,11 +331,9 @@ Singleton {
"surfaceContainer": "#f3f3f3", "surfaceContainer": "#f3f3f3",
"surfaceContainerHigh": "#ececec" "surfaceContainerHigh": "#ececec"
}] }]
// Current theme index (10 = Auto/Dynamic)
property int currentThemeIndex: 0 property int currentThemeIndex: 0
property bool isDynamicTheme: false property bool isDynamicTheme: false
property bool isLightMode: false property bool isLightMode: false
// Dynamic color properties that change based on current theme
property color primary: isDynamicTheme ? Colors.accentHi : getCurrentTheme().primary property color primary: isDynamicTheme ? Colors.accentHi : getCurrentTheme().primary
property color primaryText: isDynamicTheme ? Colors.primaryText : getCurrentTheme().primaryText property color primaryText: isDynamicTheme ? Colors.primaryText : getCurrentTheme().primaryText
property color primaryContainer: isDynamicTheme ? Colors.primaryContainer : getCurrentTheme().primaryContainer property color primaryContainer: isDynamicTheme ? Colors.primaryContainer : getCurrentTheme().primaryContainer
@@ -352,25 +348,20 @@ Singleton {
property color outline: isDynamicTheme ? Colors.outline : getCurrentTheme().outline property color outline: isDynamicTheme ? Colors.outline : getCurrentTheme().outline
property color surfaceContainer: isDynamicTheme ? Colors.surfaceContainer : getCurrentTheme().surfaceContainer property color surfaceContainer: isDynamicTheme ? Colors.surfaceContainer : getCurrentTheme().surfaceContainer
property color surfaceContainerHigh: isDynamicTheme ? Colors.surfaceContainerHigh : getCurrentTheme().surfaceContainerHigh property color surfaceContainerHigh: isDynamicTheme ? Colors.surfaceContainerHigh : getCurrentTheme().surfaceContainerHigh
// Static colors that don't change with themes
property color archBlue: "#1793D1" property color archBlue: "#1793D1"
property color success: "#4CAF50" property color success: "#4CAF50"
property color warning: "#FF9800" property color warning: "#FF9800"
property color info: "#2196F3" property color info: "#2196F3"
property color error: "#F2B8B5" property color error: "#F2B8B5"
// Common alpha color variants for consistency
// Primary colors with alpha
property color primaryHover: Qt.rgba(primary.r, primary.g, primary.b, 0.12) property color primaryHover: Qt.rgba(primary.r, primary.g, primary.b, 0.12)
property color primaryHoverLight: Qt.rgba(primary.r, primary.g, primary.b, 0.08) property color primaryHoverLight: Qt.rgba(primary.r, primary.g, primary.b, 0.08)
property color primaryPressed: Qt.rgba(primary.r, primary.g, primary.b, 0.16) property color primaryPressed: Qt.rgba(primary.r, primary.g, primary.b, 0.16)
property color primarySelected: Qt.rgba(primary.r, primary.g, primary.b, 0.3) property color primarySelected: Qt.rgba(primary.r, primary.g, primary.b, 0.3)
property color primaryBackground: Qt.rgba(primary.r, primary.g, primary.b, 0.04) property color primaryBackground: Qt.rgba(primary.r, primary.g, primary.b, 0.04)
// Secondary colors with alpha
property color secondaryHover: Qt.rgba(secondary.r, secondary.g, secondary.b, 0.08) property color secondaryHover: Qt.rgba(secondary.r, secondary.g, secondary.b, 0.08)
// Surface colors with alpha
property color surfaceHover: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, 0.08) property color surfaceHover: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, 0.08)
property color surfacePressed: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, 0.12) property color surfacePressed: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, 0.12)
property color surfaceSelected: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, 0.15) property color surfaceSelected: Qt.rgba(surfaceVariant.r, surfaceVariant.g, surfaceVariant.b, 0.15)
@@ -382,7 +373,6 @@ Singleton {
property color surfaceTextLight: Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.06) property color surfaceTextLight: Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.06)
property color surfaceTextMedium: Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.7) property color surfaceTextMedium: Qt.rgba(surfaceText.r, surfaceText.g, surfaceText.b, 0.7)
// Outline colors with alpha
property color outlineLight: Qt.rgba(outline.r, outline.g, outline.b, 0.05) property color outlineLight: Qt.rgba(outline.r, outline.g, outline.b, 0.05)
property color outlineMedium: Qt.rgba(outline.r, outline.g, outline.b, 0.08) property color outlineMedium: Qt.rgba(outline.r, outline.g, outline.b, 0.08)
property color outlineStrong: Qt.rgba(outline.r, outline.g, outline.b, 0.12) property color outlineStrong: Qt.rgba(outline.r, outline.g, outline.b, 0.12)
@@ -390,14 +380,11 @@ Singleton {
property color outlineHeavy: Qt.rgba(outline.r, outline.g, outline.b, 0.3) property color outlineHeavy: Qt.rgba(outline.r, outline.g, outline.b, 0.3)
property color outlineButton: Qt.rgba(outline.r, outline.g, outline.b, 0.5) property color outlineButton: Qt.rgba(outline.r, outline.g, outline.b, 0.5)
// Error colors with alpha
property color errorHover: Qt.rgba(error.r, error.g, error.b, 0.12) property color errorHover: Qt.rgba(error.r, error.g, error.b, 0.12)
property color errorPressed: Qt.rgba(error.r, error.g, error.b, 0.9) property color errorPressed: Qt.rgba(error.r, error.g, error.b, 0.9)
// Warning colors with alpha
property color warningHover: Qt.rgba(warning.r, warning.g, warning.b, 0.12) property color warningHover: Qt.rgba(warning.r, warning.g, warning.b, 0.12)
// Shadow colors
property color shadowLight: Qt.rgba(0, 0, 0, 0.05) property color shadowLight: Qt.rgba(0, 0, 0, 0.05)
property color shadowMedium: Qt.rgba(0, 0, 0, 0.08) property color shadowMedium: Qt.rgba(0, 0, 0, 0.08)
property color shadowDark: Qt.rgba(0, 0, 0, 0.1) property color shadowDark: Qt.rgba(0, 0, 0, 0.1)
@@ -429,80 +416,51 @@ Singleton {
property real opacityMedium: 0.6 property real opacityMedium: 0.6
property real opacityHigh: 0.87 property real opacityHigh: 0.87
property real opacityFull: 1 property real opacityFull: 1
// Transparency system - can be overridden by Prefs
property real panelTransparency: 0.85 property real panelTransparency: 0.85
property real widgetTransparency: 0.85 property real widgetTransparency: 0.85
property real popupTransparency: 0.92 property real popupTransparency: 0.92
// Handle successful color extraction
function onColorsUpdated() { function onColorsUpdated() {
console.log("Colors updated successfully - switching to dynamic theme");
// Only switch to dynamic theme if we're already in dynamic mode
if (isDynamicTheme) { if (isDynamicTheme) {
currentThemeIndex = 10; currentThemeIndex = 10;
isDynamicTheme = true; isDynamicTheme = true;
console.log("Dynamic theme activated. Theme.primary should now be:", primary);
// Save preference after successful switch
if (typeof Prefs !== "undefined") if (typeof Prefs !== "undefined")
Prefs.setTheme(currentThemeIndex, isDynamicTheme); Prefs.setTheme(currentThemeIndex, isDynamicTheme);
} else {
console.log("Color extraction completed, but staying with static theme");
} }
} }
// Function to switch themes
function switchTheme(themeIndex, isDynamic = false, savePrefs = true) { function switchTheme(themeIndex, isDynamic = false, savePrefs = true) {
console.log("Theme.switchTheme called:", themeIndex, isDynamic, "savePrefs:", savePrefs);
if (isDynamic && themeIndex === 10) { if (isDynamic && themeIndex === 10) {
console.log("Attempting to switch to dynamic theme - checking colors first");
// Set dynamic theme flag immediately so onColorsUpdated works
isDynamicTheme = true; isDynamicTheme = true;
// Don't change theme index yet - wait for color extraction to succeed
if (typeof Colors !== "undefined") { if (typeof Colors !== "undefined") {
console.log("Calling Colors.extractColors()");
Colors.extractColors(); Colors.extractColors();
} else {
console.error("Colors singleton not available");
} }
} else if (themeIndex >= 0 && themeIndex < themes.length) { } else if (themeIndex >= 0 && themeIndex < themes.length) {
// If switching away from dynamic theme, restore system themes
if (isDynamicTheme && typeof Colors !== "undefined") { if (isDynamicTheme && typeof Colors !== "undefined") {
console.log("Switching away from dynamic theme, restoring system themes");
Colors.restoreSystemThemes(); Colors.restoreSystemThemes();
} }
currentThemeIndex = themeIndex; currentThemeIndex = themeIndex;
isDynamicTheme = false; isDynamicTheme = false;
} }
// Save preference (unless this is a startup restoration)
if (savePrefs && typeof Prefs !== "undefined") if (savePrefs && typeof Prefs !== "undefined")
Prefs.setTheme(currentThemeIndex, isDynamicTheme); Prefs.setTheme(currentThemeIndex, isDynamicTheme);
} }
// Function to toggle light/dark mode
function toggleLightMode(savePrefs = true) { function toggleLightMode(savePrefs = true) {
console.log("Theme.toggleLightMode called, current isLightMode:", isLightMode);
isLightMode = !isLightMode; isLightMode = !isLightMode;
console.log("Light mode toggled to:", isLightMode);
// Save preference
if (savePrefs && typeof Prefs !== "undefined") if (savePrefs && typeof Prefs !== "undefined")
Prefs.setLightMode(isLightMode); Prefs.setLightMode(isLightMode);
} }
// Helper function to get current theme array
function getCurrentThemeArray() { function getCurrentThemeArray() {
return isLightMode ? lightThemes : themes; return isLightMode ? lightThemes : themes;
} }
// Helper function to get current theme
function getCurrentTheme() { function getCurrentTheme() {
var themeArray = getCurrentThemeArray(); var themeArray = getCurrentThemeArray();
return currentThemeIndex < themeArray.length ? themeArray[currentThemeIndex] : themeArray[0]; return currentThemeIndex < themeArray.length ? themeArray[currentThemeIndex] : themeArray[0];
} }
// Smart transparency functions for content-aware backgrounds
function getPopupBackgroundAlpha() { function getPopupBackgroundAlpha() {
return popupTransparency; return popupTransparency;
} }
@@ -511,7 +469,6 @@ Singleton {
return popupTransparency; return popupTransparency;
} }
// Convenience functions for themed backgrounds with transparency
function popupBackground() { function popupBackground() {
return Qt.rgba(surfaceContainer.r, surfaceContainer.g, surfaceContainer.b, popupTransparency); return Qt.rgba(surfaceContainer.r, surfaceContainer.g, surfaceContainer.b, popupTransparency);
} }
@@ -606,7 +563,6 @@ Singleton {
} }
function getPowerProfileLabel(profile) { function getPowerProfileLabel(profile) {
console.log("Theme.getPowerProfileLabel called with profile:", profile);
switch (profile) { switch (profile) {
case PowerProfile.PowerSaver: case PowerProfile.PowerSaver:
return "Power Saver"; return "Power Saver";
@@ -632,14 +588,10 @@ Singleton {
} }
} }
// Initialize theme system
Component.onCompleted: { Component.onCompleted: {
console.log("Theme Component.onCompleted");
// Connect to Colors signal
if (typeof Colors !== "undefined") if (typeof Colors !== "undefined")
Colors.colorsUpdated.connect(root.onColorsUpdated); Colors.colorsUpdated.connect(root.onColorsUpdated);
// Initialize transparency values from Prefs
if (typeof Prefs !== "undefined") { if (typeof Prefs !== "undefined") {
if (Prefs.popupTransparency !== undefined) if (Prefs.popupTransparency !== undefined)
root.popupTransparency = Prefs.popupTransparency; root.popupTransparency = Prefs.popupTransparency;
@@ -647,23 +599,18 @@ Singleton {
if (Prefs.topBarWidgetTransparency !== undefined) if (Prefs.topBarWidgetTransparency !== undefined)
root.widgetTransparency = Prefs.topBarWidgetTransparency; root.widgetTransparency = Prefs.topBarWidgetTransparency;
// 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;
}); });
if (Prefs.topBarWidgetTransparencyChanged) if (Prefs.topBarWidgetTransparencyChanged)
Prefs.topBarWidgetTransparencyChanged.connect(function() { Prefs.topBarWidgetTransparencyChanged.connect(function() {
if (typeof Prefs !== "undefined" && Prefs.topBarWidgetTransparency !== undefined) if (typeof Prefs !== "undefined" && Prefs.topBarWidgetTransparency !== undefined)
root.widgetTransparency = Prefs.topBarWidgetTransparency; root.widgetTransparency = Prefs.topBarWidgetTransparency;
}); });
} }
console.log("Theme initialized, waiting for Prefs to load settings and apply theme");
} }

View File

@@ -8,7 +8,6 @@ import qs.Services
import qs.Widgets import qs.Widgets
DankModal { DankModal {
// Don't hide the interface, just show toast
id: clipboardHistoryModal id: clipboardHistoryModal
@@ -18,8 +17,6 @@ DankModal {
property bool showClearConfirmation: false property bool showClearConfirmation: false
property var clipboardEntries: [] property var clipboardEntries: []
property string searchText: "" property string searchText: ""
property bool imagemagickAvailable: false
property string thumbnailCacheDir: ""
function updateFilteredModel() { function updateFilteredModel() {
filteredClipboardModel.clear(); filteredClipboardModel.clear();
@@ -52,7 +49,7 @@ DankModal {
clipboardHistoryModal.isVisible = true; clipboardHistoryModal.isVisible = true;
initializeThumbnailSystem(); initializeThumbnailSystem();
refreshClipboard(); refreshClipboard();
console.log("ClipboardHistoryModal: Opening and refreshing");
} }
function hide() { function hide() {
@@ -62,34 +59,17 @@ DankModal {
} }
function initializeThumbnailSystem() { function initializeThumbnailSystem() {
getCacheDirProcess.running = true; // No initialization needed - using direct image display
} }
function cleanupTempFiles() { function cleanupTempFiles() {
cleanupProcess.command = ["sh", "-c", "rm -f /tmp/clipboard_preview_*.png"]; Quickshell.execDetached(["sh", "-c", "rm -f /tmp/clipboard_*.png"]);
cleanupProcess.running = true;
} }
function generateThumbnails() { function generateThumbnails() {
if (!imagemagickAvailable) // No thumbnail generation needed - using direct image display
return ;
for (let i = 0; i < clipboardModel.count; i++) {
const entry = clipboardModel.get(i).entry;
const entryType = getEntryType(entry);
if (entryType === "image") {
const entryId = entry.split('\t')[0];
const thumbnailPath = `${thumbnailCacheDir}/${entryId}.png`;
thumbnailGenProcess.command = ["sh", "-c", `mkdir -p "${thumbnailCacheDir}" && cliphist decode ${entryId} | magick - -resize '128x128>' "${thumbnailPath}"`];
thumbnailGenProcess.running = true;
}
}
} }
function getThumbnailPath(entry) {
const entryId = entry.split('\t')[0];
return `${thumbnailCacheDir}/${entryId}.png`;
}
function refreshClipboard() { function refreshClipboard() {
clipboardProcess.running = true; clipboardProcess.running = true;
@@ -97,15 +77,14 @@ DankModal {
function copyEntry(entry) { function copyEntry(entry) {
const entryId = entry.split('\t')[0]; const entryId = entry.split('\t')[0];
copyProcess.command = ["sh", "-c", `cliphist decode ${entryId} | wl-copy`]; Quickshell.execDetached(["sh", "-c", `cliphist decode ${entryId} | wl-copy`]);
copyProcess.running = true;
console.log("ClipboardHistoryModal: Entry copied, showing toast");
ToastService.showInfo("Copied to clipboard"); ToastService.showInfo("Copied to clipboard");
clipboardHistoryModal.hide(); clipboardHistoryModal.hide();
} }
function deleteEntry(entry) { function deleteEntry(entry) {
console.log("Deleting entry:", entry);
deleteProcess.command = ["sh", "-c", `echo '${entry.replace(/'/g, "'\\''")}' | cliphist delete`]; deleteProcess.command = ["sh", "-c", `echo '${entry.replace(/'/g, "'\\''")}' | cliphist delete`];
deleteProcess.running = true; deleteProcess.running = true;
} }
@@ -143,7 +122,7 @@ DankModal {
return "text"; return "text";
} }
// DankModal configuration
visible: isVisible visible: isVisible
width: 650 width: 650
height: 550 height: 550
@@ -157,7 +136,6 @@ DankModal {
hide(); hide();
} }
// Clear confirmation dialog
DankModal { DankModal {
id: clearConfirmDialog id: clearConfirmDialog
@@ -264,7 +242,6 @@ DankModal {
} }
// Data models
ListModel { ListModel {
id: clipboardModel id: clipboardModel
} }
@@ -273,7 +250,6 @@ DankModal {
id: filteredClipboardModel id: filteredClipboardModel
} }
// Processes
Process { Process {
id: clipboardProcess id: clipboardProcess
@@ -292,23 +268,11 @@ DankModal {
} }
updateFilteredModel(); updateFilteredModel();
generateThumbnails();
} }
} }
} }
Process {
id: copyProcess
running: false
onExited: (exitCode) => {
if (exitCode !== 0)
console.error("Copy failed with exit code:", exitCode);
}
}
Process { Process {
id: deleteProcess id: deleteProcess
@@ -317,10 +281,11 @@ DankModal {
if (exitCode === 0) if (exitCode === 0)
refreshClipboard(); refreshClipboard();
else else
console.error("Delete failed with exit code:", exitCode); console.warn("Failed to delete clipboard entry");
} }
} }
Process { Process {
id: clearProcess id: clearProcess
@@ -332,71 +297,31 @@ DankModal {
filteredClipboardModel.clear(); filteredClipboardModel.clear();
totalCount = 0; totalCount = 0;
} else { } else {
console.error("Clear failed with exit code:", exitCode);
} }
} }
} }
Process {
id: cleanupProcess
running: false
}
Process {
id: getCacheDirProcess
command: ["sh", "-c", "echo ${XDG_CACHE_HOME:-$HOME/.cache}/cliphist/thumbs"]
running: false
stdout: StdioCollector {
onStreamFinished: {
thumbnailCacheDir = text.trim();
checkImageMagickProcess.running = true;
}
}
}
Process {
id: checkImageMagickProcess
command: ["which", "magick"]
running: false
onExited: (exitCode) => {
imagemagickAvailable = (exitCode === 0);
if (!imagemagickAvailable)
console.warn("ClipboardHistoryModal: ImageMagick not available, thumbnails disabled");
}
}
Process {
id: thumbnailGenProcess
running: false
onExited: (exitCode) => {
if (exitCode !== 0)
console.warn("ClipboardHistoryModal: Thumbnail generation failed with exit code:", exitCode);
}
}
IpcHandler { IpcHandler {
function open() { function open() {
console.log("ClipboardHistoryModal: IPC open() called");
clipboardHistoryModal.show(); clipboardHistoryModal.show();
return "CLIPBOARD_OPEN_SUCCESS"; return "CLIPBOARD_OPEN_SUCCESS";
} }
function close() { function close() {
console.log("ClipboardHistoryModal: IPC close() called");
clipboardHistoryModal.hide(); clipboardHistoryModal.hide();
return "CLIPBOARD_CLOSE_SUCCESS"; return "CLIPBOARD_CLOSE_SUCCESS";
} }
function toggle() { function toggle() {
console.log("ClipboardHistoryModal: IPC toggle() called");
clipboardHistoryModal.toggle(); clipboardHistoryModal.toggle();
return "CLIPBOARD_TOGGLE_SUCCESS"; return "CLIPBOARD_TOGGLE_SUCCESS";
} }
@@ -559,7 +484,6 @@ DankModal {
anchors.rightMargin: Theme.spacingS // Reduced right margin anchors.rightMargin: Theme.spacingS // Reduced right margin
spacing: Theme.spacingL spacing: Theme.spacingL
// Index number
Rectangle { Rectangle {
width: 24 width: 24
height: 24 height: 24
@@ -577,63 +501,49 @@ DankModal {
} }
// Content thumbnail/icon and text
Row { Row {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: parent.width - 68 // Account for index (24) + spacing (16) + delete button (32) - small margin width: parent.width - 68 // Account for index (24) + spacing (16) + delete button (32) - small margin
spacing: Theme.spacingM spacing: Theme.spacingM
// Thumbnail or icon container
Item { Item {
width: entryType === "image" ? 48 : Theme.iconSize width: entryType === "image" ? 48 : Theme.iconSize
height: entryType === "image" ? 48 : Theme.iconSize height: entryType === "image" ? 48 : Theme.iconSize
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
// Image thumbnail
CachingImage { CachingImage {
id: thumbnailImageSource id: thumbnailImageSource
anchors.fill: parent anchors.fill: parent
source: entryType === "image" && imagemagickAvailable ? "file://" + getThumbnailPath(model.entry) : "" property string entryId: model.entry.split('\t')[0]
source: entryType === "image" && imageLoader.imageData ? `data:image/png;base64,${imageLoader.imageData}` : ""
fillMode: Image.PreserveAspectCrop fillMode: Image.PreserveAspectCrop
smooth: true smooth: true
cache: true cache: true
visible: false visible: false // Hide the original image
asynchronous: true asynchronous: true
// Handle loading errors gracefully and retry once
onStatusChanged: { Process {
if (status === Image.Error && source !== "") { id: imageLoader
// Clear source to prevent repeated error attempts property string imageData: ""
const originalSource = source;
source = ""; command: ["sh", "-c", `cliphist decode ${thumbnailImageSource.entryId} | base64 -w 0`]
// Retry once after 2 seconds to allow thumbnail generation running: entryType === "image"
retryTimer.originalSource = originalSource;
retryTimer.start(); stdout: StdioCollector {
onStreamFinished: {
imageLoader.imageData = text.trim();
}
} }
} }
Timer {
id: retryTimer
property string originalSource: ""
interval: 2000
repeat: false
onTriggered: {
if (originalSource !== "" && thumbnailImageSource.source === "")
thumbnailImageSource.source = originalSource;
}
}
} }
MultiEffect { MultiEffect {
anchors.fill: parent anchors.fill: parent
anchors.margins: 2
source: thumbnailImageSource source: thumbnailImageSource
maskEnabled: true maskEnabled: true
maskSource: clipboardCircularMask maskSource: clipboardCircularMask
visible: entryType === "image" && imagemagickAvailable && thumbnailImageSource.status === Image.Ready visible: entryType === "image" && thumbnailImageSource.status === Image.Ready
maskThresholdMin: 0.5 maskThresholdMin: 0.5
maskSpreadAtMin: 1 maskSpreadAtMin: 1
} }
@@ -641,8 +551,8 @@ DankModal {
Item { Item {
id: clipboardCircularMask id: clipboardCircularMask
width: 48 width: 48 - 4
height: 48 height: 48 - 4
layer.enabled: true layer.enabled: true
layer.smooth: true layer.smooth: true
visible: false visible: false
@@ -656,9 +566,8 @@ DankModal {
} }
// Fallback icon
DankIcon { DankIcon {
visible: !(entryType === "image" && imagemagickAvailable && thumbnailImageSource.status === Image.Ready) visible: !(entryType === "image" && thumbnailImageSource.status === Image.Ready)
name: { name: {
if (entryType === "image") if (entryType === "image")
return "image"; return "image";
@@ -716,7 +625,6 @@ DankModal {
} }
// Delete button
DankActionButton { DankActionButton {
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: Theme.spacingM anchors.rightMargin: Theme.spacingM
@@ -726,12 +634,11 @@ DankModal {
iconColor: Theme.error iconColor: Theme.error
hoverColor: Theme.errorHover hoverColor: Theme.errorHover
onClicked: { onClicked: {
console.log("Delete clicked for entry:", model.entry);
deleteEntry(model.entry); deleteEntry(model.entry);
} }
} }
// Main click area - explicitly excludes delete button area
MouseArea { MouseArea {
id: mouseArea id: mouseArea

View File

@@ -7,44 +7,31 @@ import qs.Common
PanelWindow { PanelWindow {
id: root id: root
// Core properties
property alias content: contentLoader.sourceComponent property alias content: contentLoader.sourceComponent
// Sizing - can use fixed or relative to screen
property real width: 400 property real width: 400
property real height: 300 property real height: 300
// Screen-relative sizing helpers
readonly property real screenWidth: screen ? screen.width : 1920 readonly property real screenWidth: screen ? screen.width : 1920
readonly property real screenHeight: screen ? screen.height : 1080 readonly property real screenHeight: screen ? screen.height : 1080
// Background behavior
property bool showBackground: true property bool showBackground: true
property real backgroundOpacity: 0.5 property real backgroundOpacity: 0.5
// Positioning
property string positioning: "center" property string positioning: "center"
// "center", "top-right", "custom"
property point customPosition: Qt.point(0, 0) property point customPosition: Qt.point(0, 0)
// Focus management
property string keyboardFocus: "ondemand" property string keyboardFocus: "ondemand"
// "ondemand", "exclusive", "none"
property bool closeOnEscapeKey: true property bool closeOnEscapeKey: true
property bool closeOnBackgroundClick: true property bool closeOnBackgroundClick: true
// Animation
property string animationType: "scale" property string animationType: "scale"
// "scale", "slide", "fade"
property int animationDuration: Theme.mediumDuration property int animationDuration: Theme.mediumDuration
property var animationEasing: Theme.emphasizedEasing property var animationEasing: Theme.emphasizedEasing
// Styling
property color backgroundColor: Theme.surfaceContainer property color backgroundColor: Theme.surfaceContainer
property color borderColor: Theme.outlineMedium property color borderColor: Theme.outlineMedium
property real borderWidth: 1 property real borderWidth: 1
property real cornerRadius: Theme.cornerRadiusLarge property real cornerRadius: Theme.cornerRadiusLarge
property bool enableShadow: false property bool enableShadow: false
// Signals
signal opened() signal opened()
signal dialogClosed() signal dialogClosed()
signal backgroundClicked() signal backgroundClicked()
// Convenience functions
function open() { function open() {
visible = true; visible = true;
} }
@@ -57,8 +44,6 @@ PanelWindow {
visible = !visible; visible = !visible;
} }
// PanelWindow configuration
// visible property is inherited from PanelWindow
color: "transparent" color: "transparent"
WlrLayershell.layer: WlrLayershell.Overlay WlrLayershell.layer: WlrLayershell.Overlay
WlrLayershell.exclusiveZone: -1 WlrLayershell.exclusiveZone: -1
@@ -76,7 +61,6 @@ PanelWindow {
if (root.visible) { if (root.visible) {
opened(); opened();
} else { } else {
// Properly cleanup text input surfaces
if (Qt.inputMethod) { if (Qt.inputMethod) {
Qt.inputMethod.hide(); Qt.inputMethod.hide();
Qt.inputMethod.reset(); Qt.inputMethod.reset();
@@ -92,7 +76,6 @@ PanelWindow {
bottom: true bottom: true
} }
// Background overlay
Rectangle { Rectangle {
id: background id: background
@@ -122,13 +105,11 @@ PanelWindow {
} }
// Main content container
Rectangle { Rectangle {
id: contentContainer id: contentContainer
width: root.width width: root.width
height: root.height height: root.height
// Positioning
anchors.centerIn: positioning === "center" ? parent : undefined anchors.centerIn: positioning === "center" ? parent : undefined
x: { x: {
if (positioning === "top-right") if (positioning === "top-right")
@@ -149,7 +130,6 @@ PanelWindow {
border.color: root.borderColor border.color: root.borderColor
border.width: root.borderWidth border.width: root.borderWidth
layer.enabled: root.enableShadow layer.enabled: root.enableShadow
// Animation properties
opacity: root.visible ? 1 : 0 opacity: root.visible ? 1 : 0
scale: { scale: {
if (root.animationType === "scale") if (root.animationType === "scale")
@@ -157,7 +137,6 @@ PanelWindow {
return 1; return 1;
} }
// Transform for slide animation
transform: root.animationType === "slide" ? slideTransform : null transform: root.animationType === "slide" ? slideTransform : null
Translate { Translate {
@@ -167,7 +146,6 @@ PanelWindow {
y: root.visible ? 0 : -30 y: root.visible ? 0 : -30
} }
// Content area
Loader { Loader {
id: contentLoader id: contentLoader
@@ -176,7 +154,6 @@ PanelWindow {
asynchronous: false asynchronous: false
} }
// Animations
Behavior on opacity { Behavior on opacity {
NumberAnimation { NumberAnimation {
duration: root.animationDuration duration: root.animationDuration
@@ -195,7 +172,6 @@ PanelWindow {
} }
// Shadow effect
layer.effect: MultiEffect { layer.effect: MultiEffect {
shadowEnabled: true shadowEnabled: true
shadowHorizontalOffset: 0 shadowHorizontalOffset: 0
@@ -207,7 +183,6 @@ PanelWindow {
} }
// Keyboard handling
FocusScope { FocusScope {
id: focusScope id: focusScope

View File

@@ -44,9 +44,7 @@ DankModal {
lastPath = Prefs.profileLastPath; lastPath = Prefs.profileLastPath;
} }
// Check if last path exists, otherwise use home
if (lastPath && lastPath !== "") { if (lastPath && lastPath !== "") {
// TODO: Could add directory existence check here
return lastPath; return lastPath;
} }
return homeDir; return homeDir;
@@ -81,13 +79,11 @@ DankModal {
} }
onCurrentPathChanged: { onCurrentPathChanged: {
// Path changed, model will update automatically
} }
function navigateUp() { function navigateUp() {
var path = currentPath; var path = currentPath;
// Don't go above home directory
if (path === homeDir) { if (path === homeDir) {
return; return;
} }
@@ -95,7 +91,6 @@ DankModal {
var lastSlash = path.lastIndexOf('/'); var lastSlash = path.lastIndexOf('/');
if (lastSlash > 0) { if (lastSlash > 0) {
var newPath = path.substring(0, lastSlash); var newPath = path.substring(0, lastSlash);
// Don't go above home directory
if (newPath.length < homeDir.length) { if (newPath.length < homeDir.length) {
currentPath = homeDir; currentPath = homeDir;
saveLastPath(homeDir); saveLastPath(homeDir);
@@ -117,7 +112,6 @@ DankModal {
anchors.margins: Theme.spacingM anchors.margins: Theme.spacingM
spacing: Theme.spacingS spacing: Theme.spacingS
// Header
Item { Item {
width: parent.width width: parent.width
height: 40 height: 40
@@ -142,7 +136,6 @@ DankModal {
} }
} }
// Close button positioned at right
DankActionButton { DankActionButton {
circular: false circular: false
iconName: "close" iconName: "close"
@@ -155,7 +148,6 @@ DankModal {
} }
} }
// Current path display and navigation
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingS spacing: Theme.spacingS
@@ -197,7 +189,6 @@ DankModal {
} }
} }
// File grid
GridView { GridView {
id: fileGrid id: fileGrid
@@ -251,7 +242,6 @@ DankModal {
anchors.centerIn: parent anchors.centerIn: parent
spacing: Theme.spacingXS spacing: Theme.spacingXS
// Image preview or folder icon
Item { Item {
width: 80 width: 80
height: 60 height: 60
@@ -282,7 +272,6 @@ DankModal {
} }
} }
// File name
StyledText { StyledText {
text: delegateRoot.fileName || "" text: delegateRoot.fileName || ""
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall

View File

@@ -53,7 +53,6 @@ DankModal {
anchors.margins: Theme.spacingL anchors.margins: Theme.spacingL
spacing: Theme.spacingL spacing: Theme.spacingL
// Header
Row { Row {
width: parent.width width: parent.width
@@ -90,7 +89,6 @@ DankModal {
} }
// Network Details
Flickable { Flickable {
property real wheelMultiplier: 1.8 property real wheelMultiplier: 1.8
property int wheelBaseStep: 160 property int wheelBaseStep: 160
@@ -148,7 +146,6 @@ DankModal {
} }
// Close Button
Item { Item {
width: parent.width width: parent.width
height: 40 height: 40

View File

@@ -13,7 +13,7 @@ DankModal {
property string powerConfirmMessage: "" property string powerConfirmMessage: ""
function executePowerAction(action) { function executePowerAction(action) {
console.log("Executing power action:", action);
let command = []; let command = [];
switch (action) { switch (action) {
case "logout": case "logout":
@@ -30,12 +30,10 @@ DankModal {
break; break;
} }
if (command.length > 0) { if (command.length > 0) {
powerActionProcess.command = command; Quickshell.execDetached(command);
powerActionProcess.running = true;
} }
} }
// DankModal configuration
visible: powerConfirmVisible visible: powerConfirmVisible
width: 350 width: 350
height: 160 height: 160
@@ -45,17 +43,6 @@ DankModal {
powerConfirmVisible = false; powerConfirmVisible = false;
} }
Process {
id: powerActionProcess
running: false
onExited: (exitCode) => {
if (exitCode !== 0)
console.error("Power action failed with exit code:", exitCode);
}
}
content: Component { content: Component {
Item { Item {
anchors.fill: parent anchors.fill: parent
@@ -65,7 +52,6 @@ DankModal {
width: parent.width - Theme.spacingM * 2 width: parent.width - Theme.spacingM * 2
spacing: Theme.spacingM spacing: Theme.spacingM
// Title
StyledText { StyledText {
text: powerConfirmTitle text: powerConfirmTitle
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
@@ -84,7 +70,6 @@ DankModal {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
} }
// Message
StyledText { StyledText {
text: powerConfirmMessage text: powerConfirmMessage
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
@@ -98,12 +83,10 @@ DankModal {
height: Theme.spacingS height: Theme.spacingS
} }
// Buttons
Row { Row {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.spacingM spacing: Theme.spacingM
// Cancel button
Rectangle { Rectangle {
width: 120 width: 120
height: 40 height: 40
@@ -131,7 +114,6 @@ DankModal {
} }
// Confirm button
Rectangle { Rectangle {
width: 120 width: 120
height: 40 height: 40

View File

@@ -24,7 +24,6 @@ DankModal {
function hide() { function hide() {
processListModal.visible = false; processListModal.visible = false;
// Close any open context menus
if (processContextMenu.visible) if (processContextMenu.visible)
processContextMenu.close(); processContextMenu.close();

View File

@@ -19,7 +19,6 @@ DankModal {
closingModal(); closingModal();
} }
// DankModal configuration
visible: settingsVisible visible: settingsVisible
width: 750 width: 750
height: 750 height: 750
@@ -28,7 +27,6 @@ DankModal {
settingsVisible = false; settingsVisible = false;
} }
// Keyboard focus and shortcuts
FocusScope { FocusScope {
anchors.fill: parent anchors.fill: parent
focus: settingsModal.settingsVisible focus: settingsModal.settingsVisible
@@ -41,7 +39,6 @@ DankModal {
anchors.margins: Theme.spacingM anchors.margins: Theme.spacingM
spacing: Theme.spacingS spacing: Theme.spacingS
// Header
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
@@ -66,7 +63,6 @@ DankModal {
height: 1 height: 1
} }
// Close button
DankActionButton { DankActionButton {
circular: false circular: false
iconName: "close" iconName: "close"
@@ -78,7 +74,6 @@ DankModal {
} }
// Tabbed Settings
Column { Column {
width: parent.width width: parent.width
height: parent.height - 50 height: parent.height - 50
@@ -102,13 +97,11 @@ DankModal {
width: parent.width width: parent.width
height: parent.height - settingsTabBar.height height: parent.height - settingsTabBar.height
// Content container with proper padding
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingL anchors.margins: Theme.spacingL
color: "transparent" color: "transparent"
// Personalization Tab
Loader { Loader {
anchors.fill: parent anchors.fill: parent
active: settingsTabBar.currentIndex === 0 active: settingsTabBar.currentIndex === 0
@@ -119,7 +112,6 @@ DankModal {
} }
} }
// Time & Weather Tab
Loader { Loader {
anchors.fill: parent anchors.fill: parent
active: settingsTabBar.currentIndex === 1 active: settingsTabBar.currentIndex === 1
@@ -130,7 +122,6 @@ DankModal {
} }
} }
// Widgets Tab
Loader { Loader {
anchors.fill: parent anchors.fill: parent
active: settingsTabBar.currentIndex === 2 active: settingsTabBar.currentIndex === 2
@@ -141,7 +132,6 @@ DankModal {
} }
} }
// Launcher Tab
Loader { Loader {
anchors.fill: parent anchors.fill: parent
active: settingsTabBar.currentIndex === 3 active: settingsTabBar.currentIndex === 3
@@ -152,7 +142,6 @@ DankModal {
} }
} }
// Appearance Tab
Loader { Loader {
anchors.fill: parent anchors.fill: parent
active: settingsTabBar.currentIndex === 4 active: settingsTabBar.currentIndex === 4
@@ -172,19 +161,19 @@ DankModal {
IpcHandler { IpcHandler {
function open() { function open() {
console.log("SettingsModal: IPC open() called");
settingsModal.settingsVisible = true; settingsModal.settingsVisible = true;
return "SETTINGS_OPEN_SUCCESS"; return "SETTINGS_OPEN_SUCCESS";
} }
function close() { function close() {
console.log("SettingsModal: IPC close() called");
settingsModal.settingsVisible = false; settingsModal.settingsVisible = false;
return "SETTINGS_CLOSE_SUCCESS"; return "SETTINGS_CLOSE_SUCCESS";
} }
function toggle() { function toggle() {
console.log("SettingsModal: IPC toggle() called");
settingsModal.settingsVisible = !settingsModal.settingsVisible; settingsModal.settingsVisible = !settingsModal.settingsVisible;
return "SETTINGS_TOGGLE_SUCCESS"; return "SETTINGS_TOGGLE_SUCCESS";
} }

View File

@@ -14,9 +14,9 @@ DankModal {
property bool spotlightOpen: false property bool spotlightOpen: false
function show() { function show() {
console.log("SpotlightModal: show() called");
spotlightOpen = true; spotlightOpen = true;
console.log("SpotlightModal: spotlightOpen set to", spotlightOpen);
appLauncher.searchQuery = ""; appLauncher.searchQuery = "";
} }
@@ -34,7 +34,6 @@ DankModal {
show(); show();
} }
// DankModal configuration
visible: spotlightOpen visible: spotlightOpen
width: 550 width: 550
height: 600 height: 600
@@ -45,7 +44,7 @@ DankModal {
borderWidth: 1 borderWidth: 1
enableShadow: true enableShadow: true
onVisibleChanged: { onVisibleChanged: {
console.log("SpotlightModal visibility changed to:", visible);
if (visible && !spotlightOpen) if (visible && !spotlightOpen)
show(); show();
@@ -54,10 +53,9 @@ DankModal {
spotlightOpen = false; spotlightOpen = false;
} }
Component.onCompleted: { Component.onCompleted: {
console.log("SpotlightModal: Component.onCompleted called - component loaded successfully!");
} }
// App launcher logic
AppLauncher { AppLauncher {
id: appLauncher id: appLauncher
@@ -71,19 +69,19 @@ DankModal {
IpcHandler { IpcHandler {
function open() { function open() {
console.log("SpotlightModal: IPC open() called");
spotlightModal.show(); spotlightModal.show();
return "SPOTLIGHT_OPEN_SUCCESS"; return "SPOTLIGHT_OPEN_SUCCESS";
} }
function close() { function close() {
console.log("SpotlightModal: IPC close() called");
spotlightModal.hide(); spotlightModal.hide();
return "SPOTLIGHT_CLOSE_SUCCESS"; return "SPOTLIGHT_CLOSE_SUCCESS";
} }
function toggle() { function toggle() {
console.log("SpotlightModal: IPC toggle() called");
spotlightModal.toggle(); spotlightModal.toggle();
return "SPOTLIGHT_TOGGLE_SUCCESS"; return "SPOTLIGHT_TOGGLE_SUCCESS";
} }
@@ -97,7 +95,6 @@ DankModal {
anchors.fill: parent anchors.fill: parent
focus: true focus: true
// Handle keyboard shortcuts
Keys.onPressed: function(event) { Keys.onPressed: function(event) {
if (event.key === Qt.Key_Escape) { if (event.key === Qt.Key_Escape) {
hide(); hide();
@@ -153,7 +150,6 @@ DankModal {
} }
// Search field with view toggle buttons
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
@@ -211,13 +207,11 @@ DankModal {
} }
// View mode toggle buttons next to search bar
Row { Row {
spacing: Theme.spacingXS spacing: Theme.spacingXS
visible: appLauncher.model.count > 0 visible: appLauncher.model.count > 0
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
// List view button
Rectangle { Rectangle {
width: 36 width: 36
height: 36 height: 36
@@ -246,7 +240,6 @@ DankModal {
} }
// Grid view button
Rectangle { Rectangle {
width: 36 width: 36
height: 36 height: 36

View File

@@ -25,7 +25,6 @@ DankModal {
wifiPasswordInput = ""; wifiPasswordInput = "";
} }
// Auto-reopen dialog on invalid password
Connections { Connections {
function onPasswordDialogShouldReopenChanged() { function onPasswordDialogShouldReopenChanged() {
if (NetworkService.passwordDialogShouldReopen && NetworkService.connectingSSID !== "") { if (NetworkService.passwordDialogShouldReopen && NetworkService.connectingSSID !== "") {
@@ -48,7 +47,6 @@ DankModal {
width: parent.width - Theme.spacingM * 2 width: parent.width - Theme.spacingM * 2
spacing: Theme.spacingM spacing: Theme.spacingM
// Header
Row { Row {
width: parent.width width: parent.width
@@ -86,7 +84,6 @@ DankModal {
} }
// Password input
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 50 height: 50
@@ -133,7 +130,6 @@ DankModal {
} }
// Show password checkbox
Row { Row {
spacing: Theme.spacingS spacing: Theme.spacingS
@@ -177,7 +173,6 @@ DankModal {
} }
// Buttons
Item { Item {
width: parent.width width: parent.width
height: 40 height: 40

View File

@@ -31,7 +31,6 @@ PanelWindow {
show(); show();
} }
// Proper layer shell configuration
WlrLayershell.layer: WlrLayershell.Overlay WlrLayershell.layer: WlrLayershell.Overlay
WlrLayershell.exclusiveZone: -1 WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: isVisible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None WlrLayershell.keyboardFocus: isVisible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
@@ -39,7 +38,6 @@ PanelWindow {
visible: isVisible visible: isVisible
color: "transparent" color: "transparent"
// Full screen overlay setup for proper focus
anchors { anchors {
top: true top: true
left: true left: true
@@ -47,7 +45,6 @@ PanelWindow {
bottom: true bottom: true
} }
// App launcher logic
AppLauncher { AppLauncher {
id: appLauncher id: appLauncher
@@ -59,12 +56,10 @@ PanelWindow {
} }
} }
// Background click to close (no visual background)
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
enabled: appDrawerPopout.isVisible enabled: appDrawerPopout.isVisible
onClicked: function(mouse) { onClicked: function(mouse) {
// Only close if click is outside the launcher panel
var localPos = mapToItem(launcherLoader, mouse.x, mouse.y); var localPos = mapToItem(launcherLoader, mouse.x, mouse.y);
if (localPos.x < 0 || localPos.x > launcherLoader.width || localPos.y < 0 || localPos.y > launcherLoader.height) if (localPos.x < 0 || localPos.x > launcherLoader.width || localPos.y < 0 || localPos.y > launcherLoader.height)
appDrawerPopout.hide(); appDrawerPopout.hide();
@@ -72,7 +67,6 @@ PanelWindow {
} }
} }
// Main launcher panel with asynchronous loading
Loader { Loader {
id: launcherLoader id: launcherLoader
@@ -108,11 +102,9 @@ PanelWindow {
color: Theme.popupBackground() color: Theme.popupBackground()
radius: Theme.cornerRadiusXLarge radius: Theme.cornerRadiusXLarge
// Remove layer rendering for better performance
antialiasing: true antialiasing: true
smooth: true smooth: true
// Material 3 elevation with multiple layers
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
anchors.margins: -3 anchors.margins: -3
@@ -142,7 +134,6 @@ PanelWindow {
z: -1 z: -1
} }
// Content with focus management
Item { Item {
id: keyHandler id: keyHandler
@@ -153,7 +144,6 @@ PanelWindow {
forceActiveFocus(); forceActiveFocus();
} }
// Handle keyboard shortcuts
Keys.onPressed: function(event) { Keys.onPressed: function(event) {
if (event.key === Qt.Key_Escape) { if (event.key === Qt.Key_Escape) {
appDrawerPopout.hide(); appDrawerPopout.hide();
@@ -174,7 +164,6 @@ PanelWindow {
appLauncher.launchSelected(); appLauncher.launchSelected();
event.accepted = true; event.accepted = true;
} else if (!searchField.activeFocus && event.text && event.text.length > 0 && event.text.match(/[a-zA-Z0-9\\s]/)) { } else if (!searchField.activeFocus && event.text && event.text.length > 0 && event.text.match(/[a-zA-Z0-9\\s]/)) {
// User started typing, focus search field and pass the character
searchField.forceActiveFocus(); searchField.forceActiveFocus();
searchField.insertText(event.text); searchField.insertText(event.text);
event.accepted = true; event.accepted = true;
@@ -214,7 +203,6 @@ PanelWindow {
} }
// Enhanced search field
DankTextField { DankTextField {
id: searchField id: searchField
@@ -333,7 +321,6 @@ PanelWindow {
} }
// App grid/list container with enhanced styling
Rectangle { Rectangle {
width: parent.width width: parent.width
height: { height: {
@@ -347,7 +334,6 @@ PanelWindow {
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05)
border.width: 1 border.width: 1
// List view
DankListView { DankListView {
id: appList id: appList
@@ -372,7 +358,6 @@ PanelWindow {
} }
} }
// Grid view
DankGridView { DankGridView {
id: appGrid id: appGrid

View File

@@ -8,7 +8,6 @@ import qs.Widgets
Item { Item {
id: root id: root
// Public interface
property string searchQuery: "" property string searchQuery: ""
property string selectedCategory: "All" property string selectedCategory: "All"
property string viewMode: "list" // "list" or "grid" property string viewMode: "list" // "list" or "grid"
@@ -18,7 +17,6 @@ Item {
property bool debounceSearch: true property bool debounceSearch: true
property int debounceInterval: 50 property int debounceInterval: 50
property bool keyboardNavigationActive: false property bool keyboardNavigationActive: false
// Categories (computed from AppSearchService)
property var categories: { property var categories: {
var allCategories = AppSearchService.getAllCategories().filter((cat) => { var allCategories = AppSearchService.getAllCategories().filter((cat) => {
return cat !== "Education" && cat !== "Science"; return cat !== "Education" && cat !== "Science";
@@ -28,18 +26,13 @@ Item {
return cat !== "All"; return cat !== "All";
})); }));
} }
// Category icons (computed from AppSearchService)
property var categoryIcons: categories.map((category) => { property var categoryIcons: categories.map((category) => {
return AppSearchService.getCategoryIcon(category); return AppSearchService.getCategoryIcon(category);
}) })
// App usage ranking helper
property var appUsageRanking: Prefs.appUsageRanking property var appUsageRanking: Prefs.appUsageRanking
// Internal model
property alias model: filteredModel property alias model: filteredModel
// Watch AppSearchService.applications changes via property binding
property var _watchApplications: AppSearchService.applications property var _watchApplications: AppSearchService.applications
// Signals
signal appLaunched(var app) signal appLaunched(var app)
signal categorySelected(string category) signal categorySelected(string category)
signal viewModeSelected(string mode) signal viewModeSelected(string mode)
@@ -50,7 +43,6 @@ Item {
keyboardNavigationActive = false; keyboardNavigationActive = false;
var apps = []; var apps = [];
if (searchQuery.length === 0) { if (searchQuery.length === 0) {
// Show apps from category
if (selectedCategory === "All") { if (selectedCategory === "All") {
apps = AppSearchService.applications || []; apps = AppSearchService.applications || [];
} else { } else {
@@ -58,7 +50,6 @@ Item {
apps = categoryApps.slice(0, maxResults); apps = categoryApps.slice(0, maxResults);
} }
} else { } else {
// Search with category filter
if (selectedCategory === "All") { if (selectedCategory === "All") {
apps = AppSearchService.searchApplications(searchQuery); apps = AppSearchService.searchApplications(searchQuery);
} else { } else {
@@ -88,7 +79,6 @@ Item {
return (a.name || "").localeCompare(b.name || ""); return (a.name || "").localeCompare(b.name || "");
}); });
// Convert to model format and populate
apps.forEach((app) => { apps.forEach((app) => {
if (app) if (app)
filteredModel.append({ filteredModel.append({
@@ -103,7 +93,6 @@ Item {
}); });
} }
// Keyboard navigation functions
function selectNext() { function selectNext() {
if (filteredModel.count > 0) { if (filteredModel.count > 0) {
keyboardNavigationActive = true; keyboardNavigationActive = true;
@@ -142,7 +131,6 @@ Item {
} }
} }
// App launching
function launchSelected() { function launchSelected() {
if (filteredModel.count > 0 && selectedIndex >= 0 && selectedIndex < filteredModel.count) { if (filteredModel.count > 0 && selectedIndex >= 0 && selectedIndex < filteredModel.count) {
var selectedApp = filteredModel.get(selectedIndex); var selectedApp = filteredModel.get(selectedIndex);
@@ -151,28 +139,24 @@ Item {
} }
function launchApp(appData) { function launchApp(appData) {
if (!appData) { if (!appData)
console.warn("AppLauncher: No app data provided");
return ; return ;
}
appData.desktopEntry.execute(); appData.desktopEntry.execute();
appLaunched(appData); appLaunched(appData);
Prefs.addAppUsage(appData.desktopEntry); Prefs.addAppUsage(appData.desktopEntry);
} }
// Category management
function setCategory(category) { function setCategory(category) {
selectedCategory = category; selectedCategory = category;
categorySelected(category); categorySelected(category);
} }
// View mode management
function setViewMode(mode) { function setViewMode(mode) {
viewMode = mode; viewMode = mode;
viewModeSelected(mode); viewModeSelected(mode);
} }
// Watch for changes
onSearchQueryChanged: { onSearchQueryChanged: {
if (debounceSearch) if (debounceSearch)
searchDebounceTimer.restart(); searchDebounceTimer.restart();
@@ -182,7 +166,6 @@ Item {
onSelectedCategoryChanged: updateFilteredModel() onSelectedCategoryChanged: updateFilteredModel()
onAppUsageRankingChanged: updateFilteredModel() onAppUsageRankingChanged: updateFilteredModel()
on_WatchApplicationsChanged: updateFilteredModel() on_WatchApplicationsChanged: updateFilteredModel()
// Initialize
Component.onCompleted: { Component.onCompleted: {
updateFilteredModel(); updateFilteredModel();
} }
@@ -191,7 +174,6 @@ Item {
id: filteredModel id: filteredModel
} }
// Search debouncing
Timer { Timer {
id: searchDebounceTimer id: searchDebounceTimer

View File

@@ -14,7 +14,6 @@ Item {
height: compact ? 36 : (72 + Theme.spacingS) // Single row vs two rows height: compact ? 36 : (72 + Theme.spacingS) // Single row vs two rows
// Compact single-row layout (for SpotlightModal style)
Row { Row {
visible: compact visible: compact
width: parent.width width: parent.width
@@ -55,13 +54,11 @@ Item {
} }
// Two-row layout (for SpotlightModal organized style)
Column { Column {
visible: !compact visible: !compact
width: parent.width width: parent.width
spacing: Theme.spacingS spacing: Theme.spacingS
// Top row: All, Development, Graphics, Games (4 items)
Row { Row {
property var topRowCategories: ["All", "Development", "Graphics", "Games"] property var topRowCategories: ["All", "Development", "Graphics", "Games"]
@@ -105,7 +102,6 @@ Item {
} }
// Bottom row: Internet, Media, Office, Settings, System (5 items)
Row { Row {
property var bottomRowCategories: ["Internet", "Media", "Office", "Settings", "System"] property var bottomRowCategories: ["Internet", "Media", "Office", "Settings", "System"]

View File

@@ -15,7 +15,6 @@ Column {
if (!CalendarService || !CalendarService.khalAvailable) if (!CalendarService || !CalendarService.khalAvailable)
return ; return ;
// Calculate date range with padding
let firstDay = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1); let firstDay = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1);
let dayOfWeek = firstDay.getDay(); let dayOfWeek = firstDay.getDay();
let startDate = new Date(firstDay); let startDate = new Date(firstDay);
@@ -27,7 +26,6 @@ Column {
} }
spacing: Theme.spacingM spacing: Theme.spacingM
// Load events when display date changes
onDisplayDateChanged: { onDisplayDateChanged: {
loadEventsForMonth(); loadEventsForMonth();
} }
@@ -35,7 +33,6 @@ Column {
loadEventsForMonth(); loadEventsForMonth();
} }
// Load events when calendar service becomes available
Connections { Connections {
function onKhalAvailableChanged() { function onKhalAvailableChanged() {
if (CalendarService && CalendarService.khalAvailable) if (CalendarService && CalendarService.khalAvailable)
@@ -47,7 +44,6 @@ Column {
enabled: CalendarService !== null enabled: CalendarService !== null
} }
// Month navigation header
Row { Row {
width: parent.width width: parent.width
height: 40 height: 40
@@ -121,7 +117,6 @@ Column {
} }
// Days of week header
Row { Row {
width: parent.width width: parent.width
height: 32 height: 32
@@ -148,7 +143,6 @@ Column {
} }
// Calendar grid
Grid { Grid {
property date firstDay: { property date firstDay: {
let date = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1); let date = new Date(displayDate.getFullYear(), displayDate.getMonth(), 1);
@@ -196,7 +190,6 @@ Column {
font.weight: isToday || isSelected ? Font.Medium : Font.Normal font.weight: isToday || isSelected ? Font.Medium : Font.Normal
} }
// Event indicator - bottom fill effect
Rectangle { Rectangle {
id: eventIndicator id: eventIndicator

View File

@@ -21,10 +21,7 @@ PanelWindow {
if (calendarVisible) { if (calendarVisible) {
internalVisible = true; internalVisible = true;
Qt.callLater(() => { Qt.callLater(() => {
// This ensures opacity changes after window is visible
internalVisible = true; internalVisible = true;
// Force re-trigger if needed
// Ensure events are loaded for current display month
calendarGrid.loadEventsForMonth(); calendarGrid.loadEventsForMonth();
}); });
} else { } else {
@@ -51,8 +48,6 @@ PanelWindow {
} }
Rectangle { Rectangle {
// Animation finished, now we can safely resize
id: mainContainer id: mainContainer
readonly property real targetWidth: Math.min(Screen.width * 0.9, 600) readonly property real targetWidth: Math.min(Screen.width * 0.9, 600)
@@ -67,21 +62,16 @@ PanelWindow {
function calculateHeight() { function calculateHeight() {
let contentHeight = Theme.spacingM * 2; // margins let contentHeight = Theme.spacingM * 2; // margins
// Main row with widgets and calendar
let widgetHeight = 160; let widgetHeight = 160;
// Media widget always present
widgetHeight += 140 + Theme.spacingM; widgetHeight += 140 + Theme.spacingM;
// Weather widget always present
let calendarHeight = 300; let calendarHeight = 300;
let mainRowHeight = Math.max(widgetHeight, calendarHeight); let mainRowHeight = Math.max(widgetHeight, calendarHeight);
contentHeight += mainRowHeight + Theme.spacingM; contentHeight += mainRowHeight + Theme.spacingM;
// Add events widget height - use calculated height instead of actual
if (CalendarService && CalendarService.khalAvailable) { if (CalendarService && CalendarService.khalAvailable) {
let hasEvents = events.selectedDateEvents && events.selectedDateEvents.length > 0; let hasEvents = events.selectedDateEvents && events.selectedDateEvents.length > 0;
let eventsHeight = hasEvents ? Math.min(300, 80 + events.selectedDateEvents.length * 60) : 120; let eventsHeight = hasEvents ? Math.min(300, 80 + events.selectedDateEvents.length * 60) : 120;
contentHeight += eventsHeight; contentHeight += eventsHeight;
} else { } else {
// When no khal, reduce bottom margin to match top
contentHeight -= Theme.spacingM; contentHeight -= Theme.spacingM;
} }
return Math.min(contentHeight, parent.height * 0.9); return Math.min(contentHeight, parent.height * 0.9);
@@ -98,7 +88,6 @@ PanelWindow {
scale: calendarVisible ? 1 : 0.9 scale: calendarVisible ? 1 : 0.9
x: (Screen.width - targetWidth) / 2 x: (Screen.width - targetWidth) / 2
y: Theme.barHeight + 4 y: Theme.barHeight + 4
// Only resize after animation is complete
onOpacityChanged: { onOpacityChanged: {
if (opacity === 1) if (opacity === 1)
Qt.callLater(() => { Qt.callLater(() => {
@@ -165,7 +154,6 @@ PanelWindow {
anchors.margins: Theme.spacingM anchors.margins: Theme.spacingM
spacing: Theme.spacingM spacing: Theme.spacingM
// Main row with widgets and calendar - improved spacing and proportions
Row { Row {
width: parent.width width: parent.width
height: { height: {
@@ -176,7 +164,6 @@ PanelWindow {
} }
spacing: Theme.spacingM spacing: Theme.spacingM
// Left section for widgets - improved visual hierarchy
Column { Column {
id: leftWidgets id: leftWidgets
@@ -200,7 +187,6 @@ PanelWindow {
} }
// Right section for calendar - enhanced container
Rectangle { Rectangle {
width: leftWidgets.hasAnyWidgets ? parent.width * 0.55 - Theme.spacingM : parent.width width: leftWidgets.hasAnyWidgets ? parent.width * 0.55 - Theme.spacingM : parent.width
height: parent.height height: parent.height
@@ -263,7 +249,6 @@ PanelWindow {
z: -1 z: -1
enabled: calendarVisible enabled: calendarVisible
onClicked: function(mouse) { onClicked: function(mouse) {
// Only close if click is outside the main container
var localPos = mapToItem(mainContainer, mouse.x, mouse.y); var localPos = mapToItem(mainContainer, mouse.x, mouse.y);
if (localPos.x < 0 || localPos.x > mainContainer.width || localPos.y < 0 || localPos.y > mainContainer.height) if (localPos.x < 0 || localPos.x > mainContainer.width || localPos.y < 0 || localPos.y > mainContainer.height)
calendarVisible = false; calendarVisible = false;

View File

@@ -5,7 +5,6 @@ import qs.Common
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
// Events widget for selected date - Material Design 3 style
Rectangle { Rectangle {
id: events id: events
@@ -17,7 +16,6 @@ Rectangle {
function updateSelectedDateEvents() { function updateSelectedDateEvents() {
if (CalendarService && CalendarService.khalAvailable) { if (CalendarService && CalendarService.khalAvailable) {
let events = CalendarService.getEventsForDate(selectedDate); let events = CalendarService.getEventsForDate(selectedDate);
console.log("Events: Updating events for", Qt.formatDate(selectedDate, "yyyy-MM-dd"), "found", events.length, "events");
selectedDateEvents = events; selectedDateEvents = events;
} else { } else {
selectedDateEvents = []; selectedDateEvents = [];
@@ -25,7 +23,6 @@ Rectangle {
} }
onSelectedDateEventsChanged: { onSelectedDateEventsChanged: {
console.log("Events: selectedDateEvents changed, count:", selectedDateEvents.length);
eventsList.model = selectedDateEvents; eventsList.model = selectedDateEvents;
} }
width: parent.width width: parent.width
@@ -35,7 +32,6 @@ Rectangle {
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1 border.width: 1
visible: shouldShow visible: shouldShow
// Material elevation shadow
layer.enabled: true layer.enabled: true
Component.onCompleted: { Component.onCompleted: {
updateSelectedDateEvents(); updateSelectedDateEvents();
@@ -44,7 +40,6 @@ Rectangle {
updateSelectedDateEvents(); updateSelectedDateEvents();
} }
// Update events when selected date or events change
Connections { Connections {
function onEventsByDateChanged() { function onEventsByDateChanged() {
updateSelectedDateEvents(); updateSelectedDateEvents();
@@ -58,7 +53,6 @@ Rectangle {
enabled: CalendarService !== null enabled: CalendarService !== null
} }
// Header - always visible when widget is shown
Row { Row {
id: headerRow id: headerRow
@@ -85,7 +79,6 @@ Rectangle {
} }
// No events placeholder - centered in entire widget (not just content area)
Column { Column {
anchors.centerIn: parent anchors.centerIn: parent
spacing: Theme.spacingXS spacing: Theme.spacingXS
@@ -108,7 +101,6 @@ Rectangle {
} }
// Events list - positioned below header when there are events
ListView { ListView {
id: eventsList id: eventsList
@@ -157,7 +149,6 @@ Rectangle {
} }
border.width: 1 border.width: 1
// Event indicator strip
Rectangle { Rectangle {
width: 4 width: 4
height: parent.height - 8 height: parent.height - 8
@@ -270,7 +261,7 @@ Rectangle {
onClicked: { onClicked: {
if (modelData.url && modelData.url !== "") { if (modelData.url && modelData.url !== "") {
if (Qt.openUrlExternally(modelData.url) === false) if (Qt.openUrlExternally(modelData.url) === false)
console.warn("Couldn't open", modelData.url); console.warn("Failed to open URL: " + modelData.url);
} }
} }

View File

@@ -17,7 +17,6 @@ Rectangle {
property string lastValidArtUrl: "" property string lastValidArtUrl: ""
property real currentPosition: 0 property real currentPosition: 0
// Simple progress ratio calculation
function ratio() { function ratio() {
return activePlayer && activePlayer.length > 0 ? currentPosition / activePlayer.length : 0; return activePlayer && activePlayer.length > 0 ? currentPosition / activePlayer.length : 0;
} }
@@ -41,26 +40,22 @@ Rectangle {
interval: 2000 interval: 2000
running: { running: {
// Run when no active player (for cache clearing) OR when playing (for position updates)
return (!activePlayer) || (activePlayer && activePlayer.playbackState === MprisPlaybackState.Playing && activePlayer.length > 0 && !progressMouseArea.isSeeking); return (!activePlayer) || (activePlayer && activePlayer.playbackState === MprisPlaybackState.Playing && activePlayer.length > 0 && !progressMouseArea.isSeeking);
} }
repeat: true repeat: true
onTriggered: { onTriggered: {
if (!activePlayer) { if (!activePlayer) {
// Clear cache when no player
lastValidTitle = ""; lastValidTitle = "";
lastValidArtist = ""; lastValidArtist = "";
lastValidAlbum = ""; lastValidAlbum = "";
lastValidArtUrl = ""; lastValidArtUrl = "";
stop(); // Stop after clearing cache stop(); // Stop after clearing cache
} else if (activePlayer.playbackState === MprisPlaybackState.Playing && !progressMouseArea.isSeeking) { } else if (activePlayer.playbackState === MprisPlaybackState.Playing && !progressMouseArea.isSeeking) {
// Update position when playing
currentPosition = activePlayer.position; currentPosition = activePlayer.position;
} }
} }
} }
// Backend events
Connections { Connections {
function onPositionChanged() { function onPositionChanged() {
if (!progressMouseArea.isSeeking) if (!progressMouseArea.isSeeking)
@@ -83,7 +78,6 @@ Rectangle {
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingS anchors.margins: Theme.spacingS
// Placeholder when no media - centered in entire widget
Column { Column {
anchors.centerIn: parent anchors.centerIn: parent
spacing: Theme.spacingS spacing: Theme.spacingS
@@ -105,19 +99,16 @@ Rectangle {
} }
// Active content in a column
Column { Column {
anchors.fill: parent anchors.fill: parent
spacing: Theme.spacingS spacing: Theme.spacingS
visible: activePlayer && activePlayer.trackTitle !== "" || lastValidTitle !== "" visible: activePlayer && activePlayer.trackTitle !== "" || lastValidTitle !== ""
// Normal media info when playing
Row { Row {
width: parent.width width: parent.width
height: 60 height: 60
spacing: Theme.spacingM spacing: Theme.spacingM
// Album Art
Rectangle { Rectangle {
width: 60 width: 60
height: 60 height: 60
@@ -161,7 +152,6 @@ Rectangle {
} }
// Track Info
Column { Column {
width: parent.width - 60 - Theme.spacingM width: parent.width - 60 - Theme.spacingM
height: parent.height height: parent.height
@@ -218,7 +208,6 @@ Rectangle {
} }
// Progress bar
Item { Item {
id: progressBarContainer id: progressBarContainer
@@ -252,7 +241,6 @@ Rectangle {
} }
// Drag handle
Rectangle { Rectangle {
id: progressHandle id: progressHandle
@@ -318,7 +306,6 @@ Rectangle {
} }
} }
// Global mouse area for drag tracking
MouseArea { MouseArea {
id: progressGlobalMouseArea id: progressGlobalMouseArea
@@ -345,7 +332,6 @@ Rectangle {
} }
// Control buttons - always visible
Item { Item {
width: parent.width width: parent.width
height: 32 height: 32
@@ -356,7 +342,6 @@ Rectangle {
spacing: Theme.spacingM spacing: Theme.spacingM
height: parent.height height: parent.height
// Previous button
Rectangle { Rectangle {
width: 28 width: 28
height: 28 height: 28
@@ -380,7 +365,6 @@ Rectangle {
if (!activePlayer) if (!activePlayer)
return ; return ;
// >8 s → jump to start, otherwise previous track
if (currentPosition > 8 && activePlayer.canSeek) { if (currentPosition > 8 && activePlayer.canSeek) {
activePlayer.position = 0; activePlayer.position = 0;
currentPosition = 0; currentPosition = 0;
@@ -392,7 +376,6 @@ Rectangle {
} }
// Play/Pause button
Rectangle { Rectangle {
width: 32 width: 32
height: 32 height: 32
@@ -415,7 +398,6 @@ Rectangle {
} }
// Next button
Rectangle { Rectangle {
width: 28 width: 28
height: 28 height: 28

View File

@@ -20,7 +20,6 @@ Rectangle {
service: WeatherService service: WeatherService
} }
// Placeholder when no weather - centered in entire widget
Column { Column {
anchors.centerIn: parent anchors.centerIn: parent
spacing: Theme.spacingS spacing: Theme.spacingS
@@ -42,14 +41,12 @@ Rectangle {
} }
// Weather content when available - original Column structure
Column { Column {
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingL anchors.margins: Theme.spacingL
spacing: Theme.spacingS spacing: Theme.spacingS
visible: WeatherService.weather.available && WeatherService.weather.temp !== 0 visible: WeatherService.weather.available && WeatherService.weather.temp !== 0
// Weather header info
Item { Item {
width: parent.width width: parent.width
height: 60 height: 60
@@ -58,7 +55,6 @@ Rectangle {
anchors.centerIn: parent anchors.centerIn: parent
spacing: Theme.spacingL spacing: Theme.spacingL
// Weather icon
DankIcon { DankIcon {
name: WeatherService.getWeatherIcon(WeatherService.weather.wCode) name: WeatherService.getWeatherIcon(WeatherService.weather.wCode)
size: Theme.iconSize + 8 size: Theme.iconSize + 8
@@ -103,7 +99,6 @@ Rectangle {
} }
// Weather details grid
Grid { Grid {
columns: 2 columns: 2
spacing: Theme.spacingM spacing: Theme.spacingM

View File

@@ -23,13 +23,10 @@ PanelWindow {
visible: controlCenterVisible visible: controlCenterVisible
onVisibleChanged: { onVisibleChanged: {
// Enable/disable WiFi auto-refresh based on control center visibility
NetworkService.autoRefreshEnabled = visible && NetworkService.wifiEnabled; NetworkService.autoRefreshEnabled = visible && NetworkService.wifiEnabled;
// Stop bluetooth scanning when control center is closed
if (!visible && BluetoothService.adapter && BluetoothService.adapter.discovering) if (!visible && BluetoothService.adapter && BluetoothService.adapter.discovering)
BluetoothService.adapter.discovering = false; BluetoothService.adapter.discovering = false;
// Refresh uptime when opened
if (visible && UserInfoService) if (visible && UserInfoService)
UserInfoService.getUptime(); UserInfoService.getUptime();
@@ -59,7 +56,6 @@ PanelWindow {
height: root.powerOptionsExpanded ? 570 : 500 height: root.powerOptionsExpanded ? 570 : 500
y: Theme.barHeight + Theme.spacingXS y: Theme.barHeight + Theme.spacingXS
x: Math.max(Theme.spacingL, Screen.width - targetWidth - Theme.spacingL) x: Math.max(Theme.spacingL, Screen.width - targetWidth - Theme.spacingL)
// GPU-accelerated scale + opacity animation
opacity: controlCenterVisible ? 1 : 0 opacity: controlCenterVisible ? 1 : 0
scale: controlCenterVisible ? 1 : 0.9 scale: controlCenterVisible ? 1 : 0.9
@@ -86,7 +82,6 @@ PanelWindow {
radius: Theme.cornerRadiusLarge radius: Theme.cornerRadiusLarge
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1 border.width: 1
// Remove layer rendering for better performance
antialiasing: true antialiasing: true
smooth: true smooth: true
@@ -95,7 +90,6 @@ PanelWindow {
anchors.margins: Theme.spacingL anchors.margins: Theme.spacingL
spacing: Theme.spacingM spacing: Theme.spacingM
// Elegant User Header
Column { Column {
width: parent.width width: parent.width
spacing: Theme.spacingL spacing: Theme.spacingL
@@ -115,7 +109,6 @@ PanelWindow {
anchors.rightMargin: Theme.spacingL anchors.rightMargin: Theme.spacingL
spacing: Theme.spacingL spacing: Theme.spacingL
// Profile Picture Container
Item { Item {
id: avatarContainer id: avatarContainer
@@ -124,7 +117,6 @@ PanelWindow {
width: 64 width: 64
height: 64 height: 64
// This rectangle provides the themed ring via its border.
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
radius: width / 2 radius: width / 2
@@ -134,7 +126,6 @@ PanelWindow {
visible: parent.hasImage visible: parent.hasImage
} }
// Hidden Image loader. Its only purpose is to load the texture.
Image { Image {
id: profileImageLoader id: profileImageLoader
@@ -183,7 +174,6 @@ PanelWindow {
} }
// Fallback for when there is no image.
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
radius: width / 2 radius: width / 2
@@ -199,7 +189,6 @@ PanelWindow {
} }
// Error icon for when the image fails to load.
DankIcon { DankIcon {
anchors.centerIn: parent anchors.centerIn: parent
name: "warning" name: "warning"
@@ -210,7 +199,6 @@ PanelWindow {
} }
// User Info Text
Column { Column {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS spacing: Theme.spacingXS
@@ -233,14 +221,12 @@ PanelWindow {
} }
// Action Buttons - Lock, Power and Settings
Row { Row {
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: Theme.spacingL anchors.rightMargin: Theme.spacingL
spacing: Theme.spacingS spacing: Theme.spacingS
// Lock Button
DankActionButton { DankActionButton {
buttonSize: 40 buttonSize: 40
iconName: "lock" iconName: "lock"
@@ -254,7 +240,6 @@ PanelWindow {
} }
} }
// Power Button
Rectangle { Rectangle {
width: 40 width: 40
height: 40 height: 40
@@ -278,7 +263,6 @@ PanelWindow {
color: powerButton.containsMouse || root.powerOptionsExpanded ? Theme.error : Theme.surfaceText color: powerButton.containsMouse || root.powerOptionsExpanded ? Theme.error : Theme.surfaceText
Behavior on name { Behavior on name {
// Smooth icon transition
SequentialAnimation { SequentialAnimation {
NumberAnimation { NumberAnimation {
target: dankIcon target: dankIcon
@@ -330,7 +314,6 @@ PanelWindow {
} }
// Settings Button
DankActionButton { DankActionButton {
buttonSize: 40 buttonSize: 40
iconName: "settings" iconName: "settings"
@@ -348,7 +331,6 @@ PanelWindow {
} }
// Animated Collapsible Power Options (optimized)
Rectangle { Rectangle {
width: parent.width width: parent.width
height: root.powerOptionsExpanded ? 60 : 0 height: root.powerOptionsExpanded ? 60 : 0
@@ -364,7 +346,6 @@ PanelWindow {
spacing: Theme.spacingL spacing: Theme.spacingL
visible: root.powerOptionsExpanded visible: root.powerOptionsExpanded
// Logout
Rectangle { Rectangle {
width: 100 width: 100
height: 34 height: 34
@@ -414,7 +395,6 @@ PanelWindow {
} }
// Reboot
Rectangle { Rectangle {
width: 100 width: 100
height: 34 height: 34
@@ -464,7 +444,6 @@ PanelWindow {
} }
// Suspend
Rectangle { Rectangle {
width: 100 width: 100
height: 34 height: 34
@@ -514,7 +493,6 @@ PanelWindow {
} }
// Shutdown
Rectangle { Rectangle {
width: 100 width: 100
height: 34 height: 34
@@ -566,7 +544,6 @@ PanelWindow {
} }
// Single coordinated animation for power options
Behavior on height { Behavior on height {
NumberAnimation { NumberAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
@@ -689,7 +666,6 @@ PanelWindow {
anchors.margins: Theme.spacingS anchors.margins: Theme.spacingS
visible: root.currentTab === "display" visible: root.currentTab === "display"
spacing: Theme.spacingL spacing: Theme.spacingL
// Brightness Control
Column { Column {
width: parent.width width: parent.width
spacing: Theme.spacingS spacing: Theme.spacingS
@@ -765,7 +741,6 @@ PanelWindow {
} }
// Power menu height animation
Behavior on height { Behavior on height {
NumberAnimation { NumberAnimation {
duration: Theme.shortDuration // Faster for height changes duration: Theme.shortDuration // Faster for height changes
@@ -778,12 +753,10 @@ PanelWindow {
} }
// Click outside to close
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
z: -1 z: -1
onClicked: function(mouse) { onClicked: function(mouse) {
// Only close if click is outside the content loader
var localPos = mapToItem(contentLoader, mouse.x, mouse.y); var localPos = mapToItem(contentLoader, mouse.x, mouse.y);
if (localPos.x < 0 || localPos.x > contentLoader.width || localPos.y < 0 || localPos.y > contentLoader.height) if (localPos.x < 0 || localPos.x > contentLoader.width || localPos.y < 0 || localPos.y > contentLoader.height)
controlCenterVisible = false; controlCenterVisible = false;

View File

@@ -19,7 +19,7 @@ ScrollView {
interval: BrightnessService.ddcAvailable ? 500 : 50 // 500ms for slow DDC (i2c), 50ms for fast laptop backlight interval: BrightnessService.ddcAvailable ? 500 : 50 // 500ms for slow DDC (i2c), 50ms for fast laptop backlight
repeat: false repeat: false
onTriggered: { onTriggered: {
console.log("Debounce timer fired, setting brightness to:", pendingValue);
BrightnessService.setBrightness(pendingValue); BrightnessService.setBrightness(pendingValue);
} }
} }
@@ -29,7 +29,6 @@ ScrollView {
width: parent.width width: parent.width
spacing: Theme.spacingL spacing: Theme.spacingL
// Brightness Control
Column { Column {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
@@ -49,12 +48,12 @@ ScrollView {
rightIcon: "brightness_high" rightIcon: "brightness_high"
enabled: BrightnessService.brightnessAvailable enabled: BrightnessService.brightnessAvailable
onSliderValueChanged: function(newValue) { onSliderValueChanged: function(newValue) {
console.log("Slider changed to:", newValue);
brightnessDebounceTimer.pendingValue = newValue; brightnessDebounceTimer.pendingValue = newValue;
brightnessDebounceTimer.restart(); brightnessDebounceTimer.restart();
} }
onSliderDragFinished: function(finalValue) { onSliderDragFinished: function(finalValue) {
console.log("Drag finished, immediate set:", finalValue);
brightnessDebounceTimer.stop(); brightnessDebounceTimer.stop();
BrightnessService.setBrightness(finalValue); BrightnessService.setBrightness(finalValue);
} }
@@ -70,7 +69,6 @@ ScrollView {
} }
// Display settings
Column { Column {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
@@ -82,12 +80,10 @@ ScrollView {
font.weight: Font.Medium font.weight: Font.Medium
} }
// Mode toggles row (Night Mode + Light/Dark Mode)
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
// Night mode toggle
Rectangle { Rectangle {
width: (parent.width - Theme.spacingM) / 2 width: (parent.width - Theme.spacingM) / 2
height: 80 height: 80
@@ -125,11 +121,9 @@ ScrollView {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
if (Prefs.nightModeEnabled) { if (Prefs.nightModeEnabled) {
// Disable night mode - kill any running color temperature processes
nightModeDisableProcess.running = true; nightModeDisableProcess.running = true;
Prefs.setNightModeEnabled(false); Prefs.setNightModeEnabled(false);
} else { } else {
// Enable night mode using wlsunset or redshift
nightModeEnableProcess.running = true; nightModeEnableProcess.running = true;
Prefs.setNightModeEnabled(true); Prefs.setNightModeEnabled(true);
} }
@@ -138,7 +132,6 @@ ScrollView {
} }
// Light/Dark mode toggle
Rectangle { Rectangle {
width: (parent.width - Theme.spacingM) / 2 width: (parent.width - Theme.spacingM) / 2
height: 80 height: 80
@@ -195,7 +188,6 @@ ScrollView {
} }
// Night mode processes
Process { Process {
id: nightModeEnableProcess id: nightModeEnableProcess
@@ -203,7 +195,7 @@ ScrollView {
running: false running: false
onExited: (exitCode) => { onExited: (exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("Failed to enable night mode");
Prefs.setNightModeEnabled(false); Prefs.setNightModeEnabled(false);
} }
} }
@@ -216,7 +208,7 @@ ScrollView {
running: false running: false
onExited: (exitCode) => { onExited: (exitCode) => {
if (exitCode !== 0) if (exitCode !== 0)
console.warn("Failed to disable night mode");
} }
} }

View File

@@ -61,7 +61,6 @@ Rectangle {
} }
// Loading spinner for preference changes
DankIcon { DankIcon {
id: ethernetLoadingSpinner id: ethernetLoadingSpinner
@@ -86,7 +85,6 @@ Rectangle {
} }
// Ethernet toggle switch (matching WiFi style)
DankToggle { DankToggle {
id: ethernetToggle id: ethernetToggle
@@ -100,7 +98,6 @@ Rectangle {
} }
} }
// MouseArea for network preference (excluding toggle area)
MouseArea { MouseArea {
id: ethernetPreferenceArea id: ethernetPreferenceArea
@@ -111,7 +108,7 @@ Rectangle {
enabled: NetworkService.ethernetConnected && NetworkService.wifiEnabled && NetworkService.networkStatus !== "ethernet" && !NetworkService.changingNetworkPreference enabled: NetworkService.ethernetConnected && NetworkService.wifiEnabled && NetworkService.networkStatus !== "ethernet" && !NetworkService.changingNetworkPreference
onClicked: { onClicked: {
if (NetworkService.ethernetConnected && NetworkService.wifiEnabled) { if (NetworkService.ethernetConnected && NetworkService.wifiEnabled) {
console.log("Ethernet card clicked for preference");
if (NetworkService.networkStatus !== "ethernet") if (NetworkService.networkStatus !== "ethernet")
NetworkService.setNetworkPreference("ethernet"); NetworkService.setNetworkPreference("ethernet");
else else

View File

@@ -100,7 +100,6 @@ Rectangle {
} }
// Loading spinner for preference changes
DankIcon { DankIcon {
id: wifiLoadingSpinner id: wifiLoadingSpinner
@@ -125,7 +124,6 @@ Rectangle {
} }
// WiFi toggle switch
DankToggle { DankToggle {
id: wifiToggle id: wifiToggle
@@ -137,7 +135,6 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
onClicked: { onClicked: {
if (NetworkService.wifiEnabled) { if (NetworkService.wifiEnabled) {
// When turning WiFi off, clear all cached WiFi data
NetworkService.currentWifiSSID = ""; NetworkService.currentWifiSSID = "";
NetworkService.wifiSignalStrength = "excellent"; NetworkService.wifiSignalStrength = "excellent";
NetworkService.wifiNetworks = []; NetworkService.wifiNetworks = [];
@@ -154,7 +151,6 @@ Rectangle {
} }
} }
// MouseArea for network preference (excluding toggle area)
MouseArea { MouseArea {
id: wifiPreferenceArea id: wifiPreferenceArea
@@ -165,7 +161,7 @@ Rectangle {
enabled: NetworkService.ethernetConnected && NetworkService.wifiEnabled && NetworkService.networkStatus !== "wifi" && !NetworkService.changingNetworkPreference enabled: NetworkService.ethernetConnected && NetworkService.wifiEnabled && NetworkService.networkStatus !== "wifi" && !NetworkService.changingNetworkPreference
onClicked: { onClicked: {
if (NetworkService.ethernetConnected && NetworkService.wifiEnabled) { if (NetworkService.ethernetConnected && NetworkService.wifiEnabled) {
console.log("WiFi card clicked for preference");
if (NetworkService.networkStatus !== "wifi") if (NetworkService.networkStatus !== "wifi")
NetworkService.setNetworkPreference("wifi"); NetworkService.setNetworkPreference("wifi");
else else

View File

@@ -57,7 +57,6 @@ Rectangle {
visible = false; visible = false;
} }
// Drop shadow
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
anchors.topMargin: 4 anchors.topMargin: 4
@@ -76,7 +75,6 @@ Rectangle {
anchors.margins: Theme.spacingS anchors.margins: Theme.spacingS
spacing: 1 spacing: 1
// Connect/Disconnect option
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 32 height: 32
@@ -145,7 +143,6 @@ Rectangle {
} }
// Separator
Rectangle { Rectangle {
width: parent.width - Theme.spacingS * 2 width: parent.width - Theme.spacingS * 2
height: 5 height: 5
@@ -161,7 +158,6 @@ Rectangle {
} }
// Forget Network option (only for saved networks)
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 32 height: 32
@@ -217,7 +213,6 @@ Rectangle {
} }
// Network Info option
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 32 height: 32

View File

@@ -37,7 +37,6 @@ Column {
visible: NetworkService.wifiEnabled visible: NetworkService.wifiEnabled
spacing: Theme.spacingS spacing: Theme.spacingS
// Available Networks Section with refresh button (spanning version)
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingS spacing: Theme.spacingS
@@ -55,7 +54,6 @@ Column {
height: 1 height: 1
} }
// WiFi refresh button (spanning version)
Rectangle { Rectangle {
width: 28 width: 28
height: 28 height: 28
@@ -99,7 +97,6 @@ Column {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
if (!NetworkService.isScanning) { if (!NetworkService.isScanning) {
// Immediate visual feedback
refreshIconSpan.rotation += 30; refreshIconSpan.rotation += 30;
NetworkService.scanWifi(); NetworkService.scanWifi();
} }
@@ -110,7 +107,6 @@ Column {
} }
// Scrollable networks container
Flickable { Flickable {
width: parent.width width: parent.width
height: parent.height - 40 height: parent.height - 40
@@ -143,7 +139,6 @@ Column {
anchors.margins: Theme.spacingXS anchors.margins: Theme.spacingXS
anchors.rightMargin: Theme.spacingM // Extra right margin for scrollbar anchors.rightMargin: Theme.spacingM // Extra right margin for scrollbar
// Signal strength icon
DankIcon { DankIcon {
id: signalIcon2 id: signalIcon2
@@ -154,7 +149,6 @@ Column {
color: modelData.connected ? Theme.primary : Theme.surfaceText color: modelData.connected ? Theme.primary : Theme.surfaceText
} }
// Network info
Column { Column {
anchors.left: signalIcon2.right anchors.left: signalIcon2.right
anchors.leftMargin: Theme.spacingXS anchors.leftMargin: Theme.spacingXS
@@ -204,7 +198,6 @@ Column {
} }
// Right side icons
Row { Row {
id: rightIcons2 id: rightIcons2
@@ -212,7 +205,6 @@ Column {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS spacing: Theme.spacingXS
// Lock icon (if secured)
DankIcon { DankIcon {
name: "lock" name: "lock"
size: Theme.iconSize - 8 size: Theme.iconSize - 8
@@ -221,7 +213,6 @@ Column {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
// Context menu button
Rectangle { Rectangle {
id: wifiMenuButton id: wifiMenuButton

View File

@@ -14,13 +14,11 @@ Item {
property var wifiPasswordModalRef: wifiPasswordModal property var wifiPasswordModalRef: wifiPasswordModal
property var networkInfoModalRef: networkInfoModal property var networkInfoModalRef: networkInfoModal
// Properly sorted WiFi networks with connected networks first
property var sortedWifiNetworks: { property var sortedWifiNetworks: {
if (!NetworkService.wifiAvailable || !NetworkService.wifiEnabled) { if (!NetworkService.wifiAvailable || !NetworkService.wifiEnabled) {
return []; return [];
} }
// Explicitly reference both arrays to ensure reactivity
var allNetworks = NetworkService.wifiNetworks; var allNetworks = NetworkService.wifiNetworks;
var savedNetworks = NetworkService.savedWifiNetworks; var savedNetworks = NetworkService.savedWifiNetworks;
var currentSSID = NetworkService.currentWifiSSID; var currentSSID = NetworkService.currentWifiSSID;
@@ -29,32 +27,25 @@ Item {
var networks = [...allNetworks]; var networks = [...allNetworks];
// Update connected status, saved status and signal strength based on current state
networks.forEach(function(network) { networks.forEach(function(network) {
network.connected = (network.ssid === currentSSID); network.connected = (network.ssid === currentSSID);
// Update saved status based on savedWifiNetworks
network.saved = savedNetworks.some(function(saved) { network.saved = savedNetworks.some(function(saved) {
return saved.ssid === network.ssid; return saved.ssid === network.ssid;
}); });
// Use current connection's signal strength for connected network
if (network.connected && signalStrength) { if (network.connected && signalStrength) {
network.signalStrength = signalStrength; network.signalStrength = signalStrength;
} }
}); });
// Sort: connected networks first, then by signal strength
networks.sort(function(a, b) { networks.sort(function(a, b) {
// Connected networks always come first
if (a.connected && !b.connected) return -1; if (a.connected && !b.connected) return -1;
if (!a.connected && b.connected) return 1; if (!a.connected && b.connected) return 1;
// If both connected or both not connected, sort by signal strength
return b.signal - a.signal; return b.signal - a.signal;
}); });
return networks; return networks;
} }
// Force refresh of sortedWifiNetworks when networks are updated
property int forceRefresh: 0 property int forceRefresh: 0
Connections { Connections {
@@ -64,13 +55,11 @@ Item {
} }
} }
// Auto-enable WiFi auto-refresh when network tab is visible
Component.onCompleted: { Component.onCompleted: {
NetworkService.addRef(); NetworkService.addRef();
NetworkService.autoRefreshEnabled = true; NetworkService.autoRefreshEnabled = true;
if (NetworkService.wifiEnabled) if (NetworkService.wifiEnabled)
NetworkService.scanWifi(); NetworkService.scanWifi();
// Start smart monitoring
wifiMonitorTimer.start(); wifiMonitorTimer.start();
} }
@@ -79,18 +68,15 @@ Item {
NetworkService.autoRefreshEnabled = false; NetworkService.autoRefreshEnabled = false;
} }
// Two-column layout for WiFi and Ethernet (WiFi on left, Ethernet on right)
Row { Row {
anchors.fill: parent anchors.fill: parent
spacing: Theme.spacingM spacing: Theme.spacingM
// WiFi Column (left side)
Column { Column {
width: (parent.width - Theme.spacingM) / 2 width: (parent.width - Theme.spacingM) / 2
height: parent.height height: parent.height
spacing: Theme.spacingS spacing: Theme.spacingS
// WiFi Content in Flickable
Flickable { Flickable {
width: parent.width width: parent.width
height: parent.height - 30 height: parent.height - 30
@@ -106,7 +92,6 @@ Item {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
// Current WiFi connection status card
WiFiCard { WiFiCard {
refreshTimer: refreshTimer refreshTimer: refreshTimer
} }
@@ -118,13 +103,11 @@ Item {
} }
} }
// Ethernet Column (right side)
Column { Column {
width: (parent.width - Theme.spacingM) / 2 width: (parent.width - Theme.spacingM) / 2
height: parent.height height: parent.height
spacing: Theme.spacingS spacing: Theme.spacingS
// Ethernet Content in Flickable
Flickable { Flickable {
width: parent.width width: parent.width
height: parent.height - 30 height: parent.height - 30
@@ -140,7 +123,6 @@ Item {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
// Ethernet connection status card (matching WiFi height)
EthernetCard { EthernetCard {
} }
} }
@@ -152,7 +134,6 @@ Item {
} }
} }
// WiFi disabled message spanning across both columns
Rectangle { Rectangle {
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: 100 anchors.topMargin: 100
@@ -190,14 +171,12 @@ Item {
} }
} }
// WiFi networks spanning across both columns when WiFi is enabled
WiFiNetworksList { WiFiNetworksList {
wifiContextMenuWindow: wifiContextMenuWindow wifiContextMenuWindow: wifiContextMenuWindow
sortedWifiNetworks: networkTab.sortedWifiNetworks sortedWifiNetworks: networkTab.sortedWifiNetworks
wifiPasswordModalRef: networkTab.wifiPasswordModalRef wifiPasswordModalRef: networkTab.wifiPasswordModalRef
} }
// Timer for refreshing network status after WiFi toggle
Timer { Timer {
id: refreshTimer id: refreshTimer
interval: 2000 interval: 2000
@@ -212,18 +191,13 @@ Item {
} }
} }
// Auto-refresh when WiFi state changes
Connections { Connections {
target: NetworkService target: NetworkService
function onWifiEnabledChanged() { function onWifiEnabledChanged() {
if (NetworkService.wifiEnabled && visible) { if (NetworkService.wifiEnabled && visible) {
// When WiFi is enabled, scan and update info (only if tab is visible)
// Add a small delay to ensure WiFi service is ready
wifiScanDelayTimer.start(); wifiScanDelayTimer.start();
// Start monitoring when WiFi comes back on
wifiMonitorTimer.start(); wifiMonitorTimer.start();
} else { } else {
// When WiFi is disabled, clear all cached WiFi data
NetworkService.currentWifiSSID = ""; NetworkService.currentWifiSSID = "";
NetworkService.wifiSignalStrength = "excellent"; NetworkService.wifiSignalStrength = "excellent";
NetworkService.wifiNetworks = []; NetworkService.wifiNetworks = [];
@@ -232,13 +206,11 @@ Item {
NetworkService.connectingSSID = ""; NetworkService.connectingSSID = "";
NetworkService.isScanning = false; NetworkService.isScanning = false;
NetworkService.refreshNetworkStatus(); NetworkService.refreshNetworkStatus();
// Stop monitoring when WiFi is off
wifiMonitorTimer.stop(); wifiMonitorTimer.stop();
} }
} }
} }
// Delayed WiFi scan timer to ensure service is ready
Timer { Timer {
id: wifiScanDelayTimer id: wifiScanDelayTimer
interval: 1500 interval: 1500
@@ -249,14 +221,12 @@ Item {
if (!NetworkService.isScanning) { if (!NetworkService.isScanning) {
NetworkService.scanWifi(); NetworkService.scanWifi();
} else { } else {
// If still scanning, try again in a bit
wifiRetryTimer.start(); wifiRetryTimer.start();
} }
} }
} }
} }
// Retry timer for when WiFi is still scanning
Timer { Timer {
id: wifiRetryTimer id: wifiRetryTimer
interval: 2000 interval: 2000
@@ -271,7 +241,6 @@ Item {
} }
} }
// Smart WiFi monitoring - only runs when tab visible and conditions met
Timer { Timer {
id: wifiMonitorTimer id: wifiMonitorTimer
interval: 8000 // Check every 8 seconds interval: 8000 // Check every 8 seconds
@@ -279,21 +248,17 @@ Item {
repeat: true repeat: true
onTriggered: { onTriggered: {
if (!visible || !NetworkService.wifiEnabled) { if (!visible || !NetworkService.wifiEnabled) {
// Stop monitoring when not needed
running = false; running = false;
return; return;
} }
// Monitor connection changes and refresh networks when disconnected
var shouldScan = false; var shouldScan = false;
var reason = ""; var reason = "";
// Always scan if not connected to WiFi
if (NetworkService.networkStatus !== "wifi") { if (NetworkService.networkStatus !== "wifi") {
shouldScan = true; shouldScan = true;
reason = "not connected to WiFi"; reason = "not connected to WiFi";
} }
// Also scan occasionally even when connected to keep networks fresh
else if (NetworkService.wifiNetworks.length === 0) { else if (NetworkService.wifiNetworks.length === 0) {
shouldScan = true; shouldScan = true;
reason = "no networks cached"; reason = "no networks cached";
@@ -305,7 +270,6 @@ Item {
} }
} }
// Monitor tab visibility to start/stop smart monitoring
onVisibleChanged: { onVisibleChanged: {
if (visible && NetworkService.wifiEnabled) { if (visible && NetworkService.wifiEnabled) {
wifiMonitorTimer.start(); wifiMonitorTimer.start();
@@ -314,7 +278,6 @@ Item {
} }
} }
// WiFi Context Menu Window
WiFiContextMenu { WiFiContextMenu {
id: wifiContextMenuWindow id: wifiContextMenuWindow
parentItem: networkTab parentItem: networkTab
@@ -322,7 +285,6 @@ Item {
networkInfoModalRef: networkTab.networkInfoModalRef networkInfoModalRef: networkTab.networkInfoModalRef
} }
// Background MouseArea to close the context menu
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
visible: wifiContextMenuWindow.visible visible: wifiContextMenuWindow.visible
@@ -336,7 +298,6 @@ Item {
width: wifiContextMenuWindow.width width: wifiContextMenuWindow.width
height: wifiContextMenuWindow.height height: wifiContextMenuWindow.height
onClicked: { onClicked: {
// Prevent clicks on menu from closing it
} }
} }
} }

View File

@@ -31,7 +31,6 @@ PanelWindow {
bottom: true bottom: true
} }
// Click outside to dismiss overlay
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
@@ -51,9 +50,7 @@ PanelWindow {
opacity: powerMenuVisible ? 1 : 0 opacity: powerMenuVisible ? 1 : 0
scale: powerMenuVisible ? 1 : 0.85 scale: powerMenuVisible ? 1 : 0.85
// Prevent click-through to background
MouseArea { MouseArea {
// Consume the click to prevent it from reaching the background
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
@@ -65,7 +62,6 @@ PanelWindow {
anchors.margins: Theme.spacingL anchors.margins: Theme.spacingL
spacing: Theme.spacingM spacing: Theme.spacingM
// Header
Row { Row {
width: parent.width width: parent.width
@@ -94,12 +90,10 @@ PanelWindow {
} }
// Power options
Column { Column {
width: parent.width width: parent.width
spacing: Theme.spacingS spacing: Theme.spacingS
// Log Out
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 50 height: 50
@@ -146,7 +140,6 @@ PanelWindow {
} }
// Suspend
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 50 height: 50
@@ -193,7 +186,6 @@ PanelWindow {
} }
// Reboot
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 50 height: 50
@@ -240,7 +232,6 @@ PanelWindow {
} }
// Power Off
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 50 height: 50

View File

@@ -66,7 +66,7 @@ PanelWindow {
onScreenYChanged: margins.top = Theme.barHeight + 4 + screenY onScreenYChanged: margins.top = Theme.barHeight + 4 + screenY
onHasValidDataChanged: { onHasValidDataChanged: {
if (!hasValidData && !exiting && !_isDestroying) { if (!hasValidData && !exiting && !_isDestroying) {
console.warn("NotificationPopup: Data became invalid, forcing exit");
forceExit(); forceExit();
} }
} }
@@ -76,7 +76,7 @@ PanelWindow {
return enterX.restart(); return enterX.restart();
}); });
} else { } else {
console.warn("NotificationPopup created with invalid data");
forceExit(); forceExit();
} }
} }

View File

@@ -11,9 +11,7 @@ QtObject {
property int baseNotificationHeight: 120 property int baseNotificationHeight: 120
property int maxTargetNotifications: 3 property int maxTargetNotifications: 3
property var popupWindows: [] // strong refs to windows (live until exitFinished) property var popupWindows: [] // strong refs to windows (live until exitFinished)
// Track destroying windows to prevent duplicate cleanup
property var destroyingWindows: new Set() property var destroyingWindows: new Set()
// Factory
property Component popupComponent property Component popupComponent
popupComponent: Component { popupComponent: Component {
@@ -34,7 +32,6 @@ QtObject {
target: NotificationService target: NotificationService
} }
// Smart sweeper that only runs when needed
property Timer sweeper property Timer sweeper
sweeper: Timer { sweeper: Timer {
@@ -48,24 +45,21 @@ QtObject {
toRemove.push(p); toRemove.push(p);
continue; continue;
} }
// Check for various zombie conditions
const isZombie = p.status === Component.Null || (!p.visible && !p.exiting) || (!p.notificationData && !p._isDestroying) || (!p.hasValidData && !p._isDestroying); const isZombie = p.status === Component.Null || (!p.visible && !p.exiting) || (!p.notificationData && !p._isDestroying) || (!p.hasValidData && !p._isDestroying);
if (isZombie) { if (isZombie) {
console.warn("Sweeper found zombie window, cleaning up");
toRemove.push(p); toRemove.push(p);
// Try to force cleanup
if (p.forceExit) { if (p.forceExit) {
p.forceExit(); p.forceExit();
} else if (p.destroy) { } else if (p.destroy) {
try { try {
p.destroy(); p.destroy();
} catch (e) { } catch (e) {
console.warn("Error destroying zombie:", e);
} }
} }
} }
} }
// Remove all zombies from array
if (toRemove.length > 0) { if (toRemove.length > 0) {
for (let zombie of toRemove) { for (let zombie of toRemove) {
const i = popupWindows.indexOf(zombie); const i = popupWindows.indexOf(zombie);
@@ -74,7 +68,6 @@ QtObject {
} }
popupWindows = popupWindows.slice(); popupWindows = popupWindows.slice();
// Recompact after cleanup
const survivors = _active().sort((a, b) => { const survivors = _active().sort((a, b) => {
return a.screenY - b.screenY; return a.screenY - b.screenY;
}); });
@@ -82,7 +75,6 @@ QtObject {
survivors[k].screenY = topMargin + k * baseNotificationHeight; survivors[k].screenY = topMargin + k * baseNotificationHeight;
} }
} }
// Stop the timer if no windows remain
if (popupWindows.length === 0) if (popupWindows.length === 0)
sweeper.stop(); sweeper.stop();
@@ -91,7 +83,6 @@ QtObject {
function _hasWindowFor(w) { function _hasWindowFor(w) {
return popupWindows.some((p) => { return popupWindows.some((p) => {
// More robust check for valid windows
return p && p.notificationData === w && !p._isDestroying && p.status !== Component.Null; return p && p.notificationData === w && !p._isDestroying && p.status !== Component.Null;
}); });
} }
@@ -101,13 +92,11 @@ QtObject {
} }
function _sync(newWrappers) { function _sync(newWrappers) {
// Add new notifications
for (let w of newWrappers) { for (let w of newWrappers) {
if (w && !_hasWindowFor(w)) if (w && !_hasWindowFor(w))
insertNewestAtTop(w); insertNewestAtTop(w);
} }
// Remove old notifications
for (let p of popupWindows.slice()) { for (let p of popupWindows.slice()) {
if (!_isValidWindow(p)) if (!_isValidWindow(p))
continue; continue;
@@ -119,13 +108,11 @@ QtObject {
} }
} }
// Insert newest at top
function insertNewestAtTop(wrapper) { function insertNewestAtTop(wrapper) {
if (!wrapper) { if (!wrapper) {
console.warn("insertNewestAtTop: wrapper is null");
return ; return ;
} }
// Shift live, non-exiting windows down *now*
for (let p of popupWindows) { for (let p of popupWindows) {
if (!_isValidWindow(p)) if (!_isValidWindow(p))
continue; continue;
@@ -135,7 +122,6 @@ QtObject {
p.screenY = p.screenY + baseNotificationHeight; p.screenY = p.screenY + baseNotificationHeight;
} }
// Create the new top window at fixed Y
const notificationId = wrapper && wrapper.notification ? wrapper.notification.id : ""; const notificationId = wrapper && wrapper.notification ? wrapper.notification.id : "";
const win = popupComponent.createObject(null, { const win = popupComponent.createObject(null, {
"notificationData": wrapper, "notificationData": wrapper,
@@ -144,24 +130,21 @@ QtObject {
"screen": manager.modelData "screen": manager.modelData
}); });
if (!win) { if (!win) {
console.warn("Popup create failed");
return ; return ;
} }
// Validate the window was created properly
if (!win.hasValidData) { if (!win.hasValidData) {
console.warn("Popup created with invalid data, destroying");
win.destroy(); win.destroy();
return ; return ;
} }
popupWindows.push(win); popupWindows.push(win);
// Start sweeper if it's not running
if (!sweeper.running) if (!sweeper.running)
sweeper.start(); sweeper.start();
_maybeStartOverflow(); _maybeStartOverflow();
} }
// Overflow: keep one extra (slot #4), then ask bottom to exit gracefully
function _active() { function _active() {
return popupWindows.filter((p) => { return popupWindows.filter((p) => {
return _isValidWindow(p) && p.notificationData && p.notificationData.popup && !p.exiting; return _isValidWindow(p) && p.notificationData && p.notificationData.popup && !p.exiting;
@@ -186,55 +169,46 @@ QtObject {
const b = _bottom(); const b = _bottom();
if (b && !b.exiting) { if (b && !b.exiting) {
// Tell the popup to animate out (don't destroy here)
b.notificationData.removedByLimit = true; b.notificationData.removedByLimit = true;
b.notificationData.popup = false; b.notificationData.popup = false;
} }
} }
// After entrance, you may kick overflow (optional)
function _onPopupEntered(p) { function _onPopupEntered(p) {
if (_isValidWindow(p)) if (_isValidWindow(p))
_maybeStartOverflow(); _maybeStartOverflow();
} }
// Primary cleanup path (after the popup finishes its exit)
function _onPopupExitFinished(p) { function _onPopupExitFinished(p) {
if (!p) if (!p)
return ; return ;
// Prevent duplicate cleanup
const windowId = p.toString(); const windowId = p.toString();
if (destroyingWindows.has(windowId)) if (destroyingWindows.has(windowId))
return ; return ;
destroyingWindows.add(windowId); destroyingWindows.add(windowId);
// Remove from popupWindows
const i = popupWindows.indexOf(p); const i = popupWindows.indexOf(p);
if (i !== -1) { if (i !== -1) {
popupWindows.splice(i, 1); popupWindows.splice(i, 1);
popupWindows = popupWindows.slice(); popupWindows = popupWindows.slice();
} }
// Release the wrapper
if (NotificationService.releaseWrapper && p.notificationData) if (NotificationService.releaseWrapper && p.notificationData)
NotificationService.releaseWrapper(p.notificationData); NotificationService.releaseWrapper(p.notificationData);
// Schedule destruction
Qt.callLater(() => { Qt.callLater(() => {
if (p && p.destroy) { if (p && p.destroy) {
try { try {
p.destroy(); p.destroy();
} catch (e) { } catch (e) {
console.warn("Error destroying popup:", e);
} }
} }
// Clean up tracking after a delay
Qt.callLater(() => { Qt.callLater(() => {
destroyingWindows.delete(windowId); destroyingWindows.delete(windowId);
}); });
}); });
// Compact survivors (only live, non-exiting)
const survivors = _active().sort((a, b) => { const survivors = _active().sort((a, b) => {
return a.screenY - b.screenY; return a.screenY - b.screenY;
}); });
@@ -244,7 +218,6 @@ QtObject {
_maybeStartOverflow(); _maybeStartOverflow();
} }
// Emergency cleanup function
function cleanupAllWindows() { function cleanupAllWindows() {
sweeper.stop(); sweeper.stop();
for (let p of popupWindows.slice()) { for (let p of popupWindows.slice()) {
@@ -255,7 +228,7 @@ QtObject {
else if (p.destroy) else if (p.destroy)
p.destroy(); p.destroy();
} catch (e) { } catch (e) {
console.warn("Error during emergency cleanup:", e);
} }
} }
} }
@@ -263,7 +236,6 @@ QtObject {
destroyingWindows.clear(); destroyingWindows.clear();
} }
// Watch for changes to popup windows array
onPopupWindowsChanged: { onPopupWindowsChanged: {
if (popupWindows.length > 0 && !sweeper.running) if (popupWindows.length > 0 && !sweeper.running)
sweeper.start(); sweeper.start();

View File

@@ -19,7 +19,6 @@ PanelWindow {
function hide() { function hide() {
isVisible = false; isVisible = false;
// Close any open context menus
if (processContextMenu.visible) if (processContextMenu.visible)
processContextMenu.close(); processContextMenu.close();
@@ -58,7 +57,6 @@ PanelWindow {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: function(mouse) { onClicked: function(mouse) {
// Only close if click is outside the content loader
var localPos = mapToItem(contentLoader, mouse.x, mouse.y); var localPos = mapToItem(contentLoader, mouse.x, mouse.y);
if (localPos.x < 0 || localPos.x > contentLoader.width || localPos.y < 0 || localPos.y > contentLoader.height) if (localPos.x < 0 || localPos.x > contentLoader.width || localPos.y < 0 || localPos.y > contentLoader.height)
processListPopout.hide(); processListPopout.hide();
@@ -78,7 +76,6 @@ PanelWindow {
height: targetHeight height: targetHeight
y: Theme.barHeight + Theme.spacingXS y: Theme.barHeight + Theme.spacingXS
x: Math.max(Theme.spacingL, Screen.width - targetWidth - Theme.spacingL) x: Math.max(Theme.spacingL, Screen.width - targetWidth - Theme.spacingL)
// GPU-accelerated scale + opacity animation
opacity: processListPopout.isVisible ? 1 : 0 opacity: processListPopout.isVisible ? 1 : 0
scale: processListPopout.isVisible ? 1 : 0.9 scale: processListPopout.isVisible ? 1 : 0.9
@@ -108,7 +105,6 @@ PanelWindow {
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1 border.width: 1
clip: true clip: true
// Remove layer rendering for better performance
antialiasing: true antialiasing: true
smooth: true smooth: true

View File

@@ -294,7 +294,6 @@ Column {
} }
onModelChanged: { onModelChanged: {
if (model && model.length > 0 && !isUserScrolling && stableY > 40) if (model && model.length > 0 && !isUserScrolling && stableY > 40)
// Preserve scroll position when model updates
Qt.callLater(function() { Qt.callLater(function() {
contentY = stableY; contentY = stableY;
}); });

View File

@@ -20,7 +20,6 @@ ScrollView {
topPadding: Theme.spacingL topPadding: Theme.spacingL
bottomPadding: Theme.spacingXL bottomPadding: Theme.spacingXL
// Display Settings Section
StyledRect { StyledRect {
width: parent.width width: parent.width
height: displaySection.implicitHeight + Theme.spacingL * 2 height: displaySection.implicitHeight + Theme.spacingL * 2
@@ -91,7 +90,6 @@ ScrollView {
popupWidthOffset: 100 popupWidthOffset: 100
maxPopupHeight: 400 maxPopupHeight: 400
options: { options: {
// Force refresh of icon themes to prevent stale data
Prefs.detectAvailableIconThemes(); Prefs.detectAvailableIconThemes();
return Prefs.availableIconThemes; return Prefs.availableIconThemes;
} }
@@ -108,7 +106,6 @@ ScrollView {
text: "Font Family" text: "Font Family"
description: "Select system font family" description: "Select system font family"
currentValue: { currentValue: {
// Always show the font name in parentheses for clarity
if (Prefs.fontFamily === Prefs.defaultFontFamily) if (Prefs.fontFamily === Prefs.defaultFontFamily)
return "Default (" + Prefs.defaultFontFamily + ")"; return "Default (" + Prefs.defaultFontFamily + ")";
else else
@@ -122,19 +119,15 @@ ScrollView {
var availableFonts = Qt.fontFamilies(); var availableFonts = Qt.fontFamilies();
var rootFamilies = []; var rootFamilies = [];
var seenFamilies = new Set(); var seenFamilies = new Set();
// Filter to root family names by removing common weight/style suffixes
for (var i = 0; i < availableFonts.length; i++) { for (var i = 0; i < availableFonts.length; i++) {
var fontName = availableFonts[i]; var fontName = availableFonts[i];
// Skip fonts beginning with . (like .AppleSystem)
if (fontName.startsWith(".")) if (fontName.startsWith("."))
continue; continue;
// Skip the default font since we already added it as recommended
if (fontName === Prefs.defaultFontFamily) if (fontName === Prefs.defaultFontFamily)
continue; continue;
var rootName = fontName.replace(/ (Thin|Extra Light|Light|Regular|Medium|Semi Bold|Demi Bold|Bold|Extra Bold|Black|Heavy)$/i, "").replace(/ (Italic|Oblique|Condensed|Extended|Narrow|Wide)$/i, "").replace(/ (UI|Display|Text|Mono|Sans|Serif)$/i, function(match, suffix) { var rootName = fontName.replace(/ (Thin|Extra Light|Light|Regular|Medium|Semi Bold|Demi Bold|Bold|Extra Bold|Black|Heavy)$/i, "").replace(/ (Italic|Oblique|Condensed|Extended|Narrow|Wide)$/i, "").replace(/ (UI|Display|Text|Mono|Sans|Serif)$/i, function(match, suffix) {
// Keep these suffixes as they're part of the family name
return match; return match;
}).trim(); }).trim();
if (!seenFamilies.has(rootName) && rootName !== "") { if (!seenFamilies.has(rootName) && rootName !== "") {
@@ -237,18 +230,14 @@ ScrollView {
var availableFonts = Qt.fontFamilies(); var availableFonts = Qt.fontFamilies();
var monoFamilies = []; var monoFamilies = [];
var seenFamilies = new Set(); var seenFamilies = new Set();
// Filter to likely monospace fonts
for (var i = 0; i < availableFonts.length; i++) { for (var i = 0; i < availableFonts.length; i++) {
var fontName = availableFonts[i]; var fontName = availableFonts[i];
// Skip fonts beginning with .
if (fontName.startsWith(".")) if (fontName.startsWith("."))
continue; continue;
// Skip the default mono font since we already added it as recommended
if (fontName === Prefs.defaultMonoFontFamily) if (fontName === Prefs.defaultMonoFontFamily)
continue; continue;
// Look for common monospace indicators
var lowerName = fontName.toLowerCase(); var lowerName = fontName.toLowerCase();
if (lowerName.includes("mono") || lowerName.includes("code") || lowerName.includes("console") || lowerName.includes("terminal") || lowerName.includes("courier") || lowerName.includes("dejavu sans mono") || lowerName.includes("jetbrains") || lowerName.includes("fira") || lowerName.includes("hack") || lowerName.includes("source code") || lowerName.includes("ubuntu mono") || lowerName.includes("cascadia")) { if (lowerName.includes("mono") || lowerName.includes("code") || lowerName.includes("console") || lowerName.includes("terminal") || lowerName.includes("courier") || lowerName.includes("dejavu sans mono") || lowerName.includes("jetbrains") || lowerName.includes("fira") || lowerName.includes("hack") || lowerName.includes("source code") || lowerName.includes("ubuntu mono") || lowerName.includes("cascadia")) {
var rootName = fontName.replace(/ (Thin|Extra Light|Light|Regular|Medium|Semi Bold|Demi Bold|Bold|Extra Bold|Black|Heavy)$/i, "").replace(/ (Italic|Oblique|Condensed|Extended|Narrow|Wide)$/i, "").trim(); var rootName = fontName.replace(/ (Thin|Extra Light|Light|Regular|Medium|Semi Bold|Demi Bold|Bold|Extra Bold|Black|Heavy)$/i, "").replace(/ (Italic|Oblique|Condensed|Extended|Narrow|Wide)$/i, "").trim();
@@ -272,7 +261,6 @@ ScrollView {
} }
// Transparency Settings Section
StyledRect { StyledRect {
width: parent.width width: parent.width
height: transparencySection.implicitHeight + Theme.spacingL * 2 height: transparencySection.implicitHeight + Theme.spacingL * 2
@@ -391,7 +379,6 @@ ScrollView {
} }
// Theme Picker Section
StyledRect { StyledRect {
width: parent.width width: parent.width
height: themeSection.implicitHeight + Theme.spacingL * 2 height: themeSection.implicitHeight + Theme.spacingL * 2
@@ -458,12 +445,10 @@ ScrollView {
} }
// Theme Grid
Column { Column {
spacing: Theme.spacingS spacing: Theme.spacingS
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
// First row - Blue, Deep Blue, Purple, Green, Orange
Row { Row {
spacing: Theme.spacingM spacing: Theme.spacingM
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
@@ -480,7 +465,6 @@ ScrollView {
border.width: (Theme.currentThemeIndex === index && !Theme.isDynamicTheme) ? 2 : 1 border.width: (Theme.currentThemeIndex === index && !Theme.isDynamicTheme) ? 2 : 1
scale: (Theme.currentThemeIndex === index && !Theme.isDynamicTheme) ? 1.1 : 1 scale: (Theme.currentThemeIndex === index && !Theme.isDynamicTheme) ? 1.1 : 1
// Theme name tooltip
Rectangle { Rectangle {
width: nameText.contentWidth + Theme.spacingS * 2 width: nameText.contentWidth + Theme.spacingS * 2
height: nameText.contentHeight + Theme.spacingXS * 2 height: nameText.contentHeight + Theme.spacingXS * 2
@@ -537,7 +521,6 @@ ScrollView {
} }
// Second row - Red, Cyan, Pink, Amber, Coral
Row { Row {
spacing: Theme.spacingM spacing: Theme.spacingM
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
@@ -557,7 +540,6 @@ ScrollView {
visible: themeIndex < Theme.themes.length visible: themeIndex < Theme.themes.length
scale: Theme.currentThemeIndex === themeIndex ? 1.1 : 1 scale: Theme.currentThemeIndex === themeIndex ? 1.1 : 1
// Theme name tooltip
Rectangle { Rectangle {
width: nameText2.contentWidth + Theme.spacingS * 2 width: nameText2.contentWidth + Theme.spacingS * 2
height: nameText2.contentHeight + Theme.spacingXS * 2 height: nameText2.contentHeight + Theme.spacingXS * 2
@@ -616,13 +598,11 @@ ScrollView {
} }
// Spacer
Item { Item {
width: 1 width: 1
height: Theme.spacingM height: Theme.spacingM
} }
// Auto theme button
Rectangle { Rectangle {
width: 120 width: 120
height: 40 height: 40
@@ -704,7 +684,6 @@ ScrollView {
} }
} }
// Tooltip for Auto button
Rectangle { Rectangle {
width: autoTooltipText.contentWidth + Theme.spacingM * 2 width: autoTooltipText.contentWidth + Theme.spacingM * 2
height: autoTooltipText.contentHeight + Theme.spacingS * 2 height: autoTooltipText.contentHeight + Theme.spacingS * 2
@@ -768,7 +747,6 @@ ScrollView {
} }
// System App Theming Section
StyledRect { StyledRect {
width: parent.width width: parent.width
height: systemThemingSection.implicitHeight + Theme.spacingL * 2 height: systemThemingSection.implicitHeight + Theme.spacingL * 2
@@ -840,17 +818,15 @@ ScrollView {
} }
// Night mode processes
Process { Process {
id: nightModeEnableProcess id: nightModeEnableProcess
command: ["bash", "-c", "if command -v wlsunset > /dev/null; then pkill wlsunset; wlsunset -t 3000 & elif command -v redshift > /dev/null; then pkill redshift; redshift -P -O 3000 & else echo 'No night mode tool available'; fi"] command: ["bash", "-c", "if command -v wlsunset > /dev/null; then pkill wlsunset; wlsunset -t 3000 & elif command -v redshift > /dev/null; then pkill redshift; redshift -P -O 3000 & else echo 'No night mode tool available'; fi"]
running: false running: false
onExited: (exitCode) => { onExited: (exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0)
console.warn("Failed to enable night mode"); Prefs.setNightModeEnabled(true);
Prefs.setNightModeEnabled(false);
}
} }
} }
@@ -861,7 +837,7 @@ ScrollView {
running: false running: false
onExited: (exitCode) => { onExited: (exitCode) => {
if (exitCode !== 0) if (exitCode !== 0)
console.warn("Failed to disable night mode"); Prefs.setNightModeEnabled(false);
} }
} }

View File

@@ -22,7 +22,6 @@ ScrollView {
width: parent.width width: parent.width
spacing: Theme.spacingXL spacing: Theme.spacingXL
// Profile Section
StyledRect { StyledRect {
width: parent.width width: parent.width
height: profileSection.implicitHeight + Theme.spacingL * 2 height: profileSection.implicitHeight + Theme.spacingL * 2
@@ -63,7 +62,6 @@ ScrollView {
width: parent.width width: parent.width
spacing: Theme.spacingL spacing: Theme.spacingL
// Circular profile image preview
Item { Item {
id: avatarContainer id: avatarContainer
@@ -264,7 +262,6 @@ ScrollView {
} }
// Wallpaper Section
StyledRect { StyledRect {
width: parent.width width: parent.width
height: wallpaperSection.implicitHeight + Theme.spacingL * 2 height: wallpaperSection.implicitHeight + Theme.spacingL * 2
@@ -305,7 +302,6 @@ ScrollView {
width: parent.width width: parent.width
spacing: Theme.spacingL spacing: Theme.spacingL
// Wallpaper Preview
StyledRect { StyledRect {
width: 160 width: 160
height: 90 height: 90
@@ -463,7 +459,6 @@ ScrollView {
} }
// Dynamic Theming Section
StyledRect { StyledRect {
width: parent.width width: parent.width
height: dynamicThemeSection.implicitHeight + Theme.spacingL * 2 height: dynamicThemeSection.implicitHeight + Theme.spacingL * 2

View File

@@ -22,7 +22,6 @@ Column {
} }
// Section header
MouseArea { MouseArea {
width: parent.width width: parent.width
height: headerRow.height height: headerRow.height
@@ -85,7 +84,6 @@ Column {
} }
// Divider
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 1 height: 1
@@ -93,7 +91,6 @@ Column {
visible: expanded || !collapsible visible: expanded || !collapsible
} }
// Content
Loader { Loader {
id: contentLoader id: contentLoader

View File

@@ -15,7 +15,6 @@ ScrollView {
width: parent.width width: parent.width
spacing: Theme.spacingXL spacing: Theme.spacingXL
// Time Settings Section
StyledRect { StyledRect {
width: parent.width width: parent.width
height: timeSection.implicitHeight + Theme.spacingL * 2 height: timeSection.implicitHeight + Theme.spacingL * 2
@@ -66,7 +65,6 @@ ScrollView {
} }
// Weather Settings Section
StyledRect { StyledRect {
width: parent.width width: parent.width
height: weatherSection.implicitHeight + Theme.spacingL * 2 height: weatherSection.implicitHeight + Theme.spacingL * 2

View File

@@ -91,7 +91,6 @@ ScrollView {
"icon": "remove", "icon": "remove",
"enabled": true "enabled": true
}] }]
// Default widget configurations for each section (with enabled states)
property var defaultLeftWidgets: [{ property var defaultLeftWidgets: [{
"id": "launcherButton", "id": "launcherButton",
"enabled": true "enabled": true
@@ -295,7 +294,6 @@ ScrollView {
if (!Prefs.topBarRightWidgets || Prefs.topBarRightWidgets.length === 0) if (!Prefs.topBarRightWidgets || Prefs.topBarRightWidgets.length === 0)
Prefs.setTopBarRightWidgets(defaultRightWidgets); Prefs.setTopBarRightWidgets(defaultRightWidgets);
// Ensure existing spacers have default sizes
["left", "center", "right"].forEach((sectionId) => { ["left", "center", "right"].forEach((sectionId) => {
var widgets = []; var widgets = [];
if (sectionId === "left") if (sectionId === "left")
@@ -334,7 +332,6 @@ ScrollView {
topPadding: Theme.spacingL topPadding: Theme.spacingL
bottomPadding: Theme.spacingXL bottomPadding: Theme.spacingXL
// Header section
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
@@ -446,12 +443,10 @@ ScrollView {
} }
// Widget sections
Column { Column {
width: parent.width width: parent.width
spacing: Theme.spacingL spacing: Theme.spacingL
// Left Section
DankSections { DankSections {
width: parent.width width: parent.width
title: "Left Section" title: "Left Section"
@@ -478,7 +473,6 @@ ScrollView {
} }
} }
// Center Section
DankSections { DankSections {
width: parent.width width: parent.width
title: "Center Section" title: "Center Section"
@@ -505,7 +499,6 @@ ScrollView {
} }
} }
// Right Section
DankSections { DankSections {
width: parent.width width: parent.width
title: "Right Section" title: "Right Section"
@@ -534,7 +527,6 @@ ScrollView {
} }
// Workspace Section
StyledRect { StyledRect {
width: parent.width width: parent.width
height: workspaceSection.implicitHeight + Theme.spacingL * 2 height: workspaceSection.implicitHeight + Theme.spacingL * 2
@@ -597,7 +589,6 @@ ScrollView {
} }
// Tooltip for reset button (positioned above the button)
Rectangle { Rectangle {
width: tooltipText.contentWidth + Theme.spacingM * 2 width: tooltipText.contentWidth + Theme.spacingM * 2
height: tooltipText.contentHeight + Theme.spacingS * 2 height: tooltipText.contentHeight + Theme.spacingS * 2
@@ -630,7 +621,6 @@ ScrollView {
} }
// Widget selection popup
DankWidgetSelectionPopup { DankWidgetSelectionPopup {
id: widgetSelectionPopup id: widgetSelectionPopup

View File

@@ -130,7 +130,6 @@ PanelWindow {
} }
// Makes the background transparent to mouse events
mask: Region { mask: Region {
item: toast item: toast
} }

View File

@@ -24,7 +24,6 @@ Item {
interval: 256 interval: 256
repeat: true repeat: true
onTriggered: { onTriggered: {
// Generate fake audio levels when cava is unavailable
CavaService.values = [Math.random() * 40 + 10, Math.random() * 60 + 20, Math.random() * 50 + 15, Math.random() * 35 + 20, Math.random() * 45 + 15, Math.random() * 55 + 25]; CavaService.values = [Math.random() * 40 + 10, Math.random() * 60 + 20, Math.random() * 50 + 15, Math.random() * 35 + 20, Math.random() * 45 + 15, Math.random() * 55 + 25];
} }
} }

View File

@@ -96,7 +96,6 @@ Rectangle {
} }
} }
// Tooltip on hover
Rectangle { Rectangle {
id: batteryTooltip id: batteryTooltip

View File

@@ -46,11 +46,9 @@ PanelWindow {
bottom: true bottom: true
} }
// Click outside to dismiss overlay
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: function(mouse) { onClicked: function(mouse) {
// Only close if click is outside the content loader
var localPos = mapToItem(contentLoader, mouse.x, mouse.y); var localPos = mapToItem(contentLoader, mouse.x, mouse.y);
if (localPos.x < 0 || localPos.x > contentLoader.width || localPos.y < 0 || localPos.y > contentLoader.height) if (localPos.x < 0 || localPos.x > contentLoader.width || localPos.y < 0 || localPos.y > contentLoader.height)
batteryPopupVisible = false; batteryPopupVisible = false;
@@ -70,7 +68,6 @@ PanelWindow {
height: targetHeight height: targetHeight
x: Math.max(Theme.spacingL, Screen.width - targetWidth - Theme.spacingL) x: Math.max(Theme.spacingL, Screen.width - targetWidth - Theme.spacingL)
y: Theme.barHeight + Theme.spacingS y: Theme.barHeight + Theme.spacingS
// GPU-accelerated scale + opacity animation
opacity: batteryPopupVisible ? 1 : 0 opacity: batteryPopupVisible ? 1 : 0
scale: batteryPopupVisible ? 1 : 0.9 scale: batteryPopupVisible ? 1 : 0.9
@@ -97,11 +94,9 @@ PanelWindow {
radius: Theme.cornerRadiusLarge radius: Theme.cornerRadiusLarge
border.color: Theme.outlineMedium border.color: Theme.outlineMedium
border.width: 1 border.width: 1
// Remove layer rendering for better performance
antialiasing: true antialiasing: true
smooth: true smooth: true
// Material 3 elevation with multiple layers
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
anchors.margins: -3 anchors.margins: -3
@@ -273,7 +268,6 @@ PanelWindow {
} }
// No battery info card
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 80 height: 80
@@ -317,7 +311,6 @@ PanelWindow {
} }
// Battery details
Column { Column {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
@@ -334,7 +327,6 @@ PanelWindow {
width: parent.width width: parent.width
spacing: Theme.spacingXL spacing: Theme.spacingXL
// Health
Column { Column {
spacing: 2 spacing: 2
width: (parent.width - Theme.spacingXL) / 2 width: (parent.width - Theme.spacingXL) / 2
@@ -360,7 +352,6 @@ PanelWindow {
} }
// Capacity
Column { Column {
spacing: 2 spacing: 2
width: (parent.width - Theme.spacingXL) / 2 width: (parent.width - Theme.spacingXL) / 2
@@ -384,7 +375,6 @@ PanelWindow {
} }
// Power profiles
Column { Column {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
@@ -465,7 +455,6 @@ PanelWindow {
} }
// Degradation reason warning
Rectangle { Rectangle {
width: parent.width width: parent.width
height: 60 height: 60

View File

@@ -10,7 +10,6 @@ Rectangle {
signal clicked() signal clicked()
// Helper function for consistent WiFi signal icons
function getWiFiSignalIcon(signalStrength) { function getWiFiSignalIcon(signalStrength) {
switch (signalStrength) { switch (signalStrength) {
case "excellent": case "excellent":
@@ -40,7 +39,6 @@ Rectangle {
anchors.centerIn: parent anchors.centerIn: parent
spacing: Theme.spacingXS spacing: Theme.spacingXS
// Network Status Icon
DankIcon { DankIcon {
name: { name: {
if (NetworkService.networkStatus === "ethernet") if (NetworkService.networkStatus === "ethernet")
@@ -56,7 +54,6 @@ Rectangle {
visible: true visible: true
} }
// Bluetooth Icon (when available and enabled) - moved next to network
DankIcon { DankIcon {
name: "bluetooth" name: "bluetooth"
size: Theme.iconSize - 8 size: Theme.iconSize - 8
@@ -65,7 +62,6 @@ Rectangle {
visible: BluetoothService.available && BluetoothService.enabled visible: BluetoothService.available && BluetoothService.enabled
} }
// Audio Icon with scroll wheel support
Rectangle { Rectangle {
width: audioIcon.implicitWidth + 4 width: audioIcon.implicitWidth + 4
height: audioIcon.implicitHeight + 4 height: audioIcon.implicitHeight + 4
@@ -82,9 +78,6 @@ Rectangle {
} }
MouseArea { MouseArea {
// Scroll up - increase volume
// Scroll down - decrease volume
id: audioWheelArea id: audioWheelArea
anchors.fill: parent anchors.fill: parent
@@ -108,7 +101,6 @@ Rectangle {
} }
// Microphone Icon (when active)
DankIcon { DankIcon {
name: "mic" name: "mic"
size: Theme.iconSize - 8 size: Theme.iconSize - 8

View File

@@ -16,7 +16,6 @@ Rectangle {
height: 30 height: 30
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: { color: {
// Only show background when there's content to display
if (!FocusedWindowService.focusedAppName && !FocusedWindowService.focusedWindowTitle) if (!FocusedWindowService.focusedAppName && !FocusedWindowService.focusedWindowTitle)
return "transparent"; return "transparent";

View File

@@ -25,7 +25,6 @@ Rectangle {
color: Prefs.doNotDisturb ? Theme.error : (notificationArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText) color: Prefs.doNotDisturb ? Theme.error : (notificationArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText)
} }
// Notification dot indicator
Rectangle { Rectangle {
width: 8 width: 8
height: 8 height: 8

View File

@@ -13,7 +13,6 @@ Rectangle {
height: 30 height: 30
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: { color: {
// Only show background when there are system tray items to display
if (SystemTray.items.values.length === 0) if (SystemTray.items.values.length === 0)
return "transparent"; return "transparent";

View File

@@ -39,11 +39,9 @@ PanelWindow {
radius: Theme.cornerRadiusLarge radius: Theme.cornerRadiusLarge
border.color: Theme.outlineMedium border.color: Theme.outlineMedium
border.width: 1 border.width: 1
// Material 3 animations
opacity: showContextMenu ? 1 : 0 opacity: showContextMenu ? 1 : 0
scale: showContextMenu ? 1 : 0.85 scale: showContextMenu ? 1 : 0.85
// Material 3 drop shadow
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
anchors.topMargin: 4 anchors.topMargin: 4
@@ -65,11 +63,9 @@ PanelWindow {
menu: currentTrayItem && currentTrayItem.hasMenu ? currentTrayItem.menu : null menu: currentTrayItem && currentTrayItem.hasMenu ? currentTrayItem.menu : null
} }
// Custom menu styling using ListView
ListView { ListView {
id: menuList id: menuList
// Calculate maximum text width for dynamic menu sizing
property real maxTextWidth: { property real maxTextWidth: {
let maxWidth = 0; let maxWidth = 0;
if (model && model.values) { if (model && model.values) {
@@ -101,7 +97,6 @@ PanelWindow {
radius: modelData.isSeparator ? 0 : Theme.cornerRadiusSmall radius: modelData.isSeparator ? 0 : Theme.cornerRadiusSmall
color: modelData.isSeparator ? "transparent" : (menuItemArea.containsMouse ? Theme.primaryHover : "transparent") color: modelData.isSeparator ? "transparent" : (menuItemArea.containsMouse ? Theme.primaryHover : "transparent")
// Separator line
Rectangle { Rectangle {
visible: modelData.isSeparator visible: modelData.isSeparator
anchors.centerIn: parent anchors.centerIn: parent
@@ -110,7 +105,6 @@ PanelWindow {
color: Theme.surfaceVariantAlpha color: Theme.surfaceVariantAlpha
} }
// Menu item content
Row { Row {
visible: !modelData.isSeparator visible: !modelData.isSeparator
anchors.left: parent.left anchors.left: parent.left
@@ -176,7 +170,6 @@ PanelWindow {
} }
// Click outside to close
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
z: -1 z: -1

View File

@@ -125,7 +125,6 @@ PanelWindow {
id: topBarContent id: topBarContent
readonly property int availableWidth: width readonly property int availableWidth: width
// Use estimated fixed widths to break circular dependencies
readonly property int launcherButtonWidth: 40 readonly property int launcherButtonWidth: 40
readonly property int workspaceSwitcherWidth: 120 // Approximate readonly property int workspaceSwitcherWidth: 120 // Approximate
readonly property int focusedAppMaxWidth: 456 // Fixed width since we don't have focusedApp reference readonly property int focusedAppMaxWidth: 456 // Fixed width since we don't have focusedApp reference
@@ -228,7 +227,6 @@ PanelWindow {
anchors.bottomMargin: Theme.spacingXS anchors.bottomMargin: Theme.spacingXS
clip: true clip: true
// Dynamic left section
Row { Row {
id: leftSection id: leftSection
@@ -357,8 +355,8 @@ PanelWindow {
item.onWidthChanged.connect(centerSection.updateLayout); item.onWidthChanged.connect(centerSection.updateLayout);
if (model.widgetId === "spacer") if (model.widgetId === "spacer")
item.spacerSize = Qt.binding(() => { item.spacerSize = Qt.binding(() => {
return model.size || 20; return model.size || 20;
}); });
Qt.callLater(centerSection.updateLayout); Qt.callLater(centerSection.updateLayout);
} }

View File

@@ -8,7 +8,6 @@ Rectangle {
signal clicked() signal clicked()
// Visibility is now controlled by TopBar.qml
width: visible ? Math.min(100, weatherRow.implicitWidth + Theme.spacingS * 2) : 0 width: visible ? Math.min(100, weatherRow.implicitWidth + Theme.spacingS * 2) : 0
height: 30 height: 30
radius: Theme.cornerRadius radius: Theme.cornerRadius

View File

@@ -83,10 +83,8 @@ Rectangle {
target: NiriService target: NiriService
} }
// Force update when padding preference changes
Connections { Connections {
function onShowWorkspacePaddingChanged() { function onShowWorkspacePaddingChanged() {
// Force re-evaluation by updating the property
var baseList = root.getDisplayWorkspaces(); var baseList = root.getDisplayWorkspaces();
root.workspaceList = Prefs.showWorkspacePadding ? root.padWorkspaces(baseList) : baseList; root.workspaceList = Prefs.showWorkspacePadding ? root.padWorkspaces(baseList) : baseList;
} }
@@ -128,7 +126,6 @@ Rectangle {
} }
} }
// Show index for placeholders if Prefs.showWorkspaceIndex is true, otherwise show a subtle dot
StyledText { StyledText {
visible: Prefs.showWorkspaceIndex visible: Prefs.showWorkspaceIndex
anchors.centerIn: parent anchors.centerIn: parent

View File

@@ -12,28 +12,6 @@ Singleton {
property var applications: DesktopEntries.applications.values property var applications: DesktopEntries.applications.values
property var applicationsByName: {
var byName = {}
for (var i = 0; i < applications.length; i++) {
var app = applications[i]
byName[app.name.toLowerCase()] = app
}
return byName
}
property var applicationsByExec: {
var byExec = {}
for (var i = 0; i < applications.length; i++) {
var app = applications[i]
var execProp = app.execString || ""
var cleanExec = execProp ? execProp.replace(/%[fFuU]/g, "").trim() : ""
if (cleanExec) {
byExec[cleanExec] = app
}
}
return byExec
}
property var preppedApps: applications.map(app => ({ property var preppedApps: applications.map(app => ({
name: Fuzzy.prepare(app.name || ""), name: Fuzzy.prepare(app.name || ""),
comment: Fuzzy.prepare(app.comment || ""), comment: Fuzzy.prepare(app.comment || ""),
@@ -89,14 +67,7 @@ Singleton {
return results.map(r => r.obj.entry) return results.map(r => r.obj.entry)
} }
function getAppByName(name) {
return applicationsByName[name.toLowerCase()] || null
}
function getAppByExec(exec) {
var cleanExec = exec.replace(/%[fFuU]/g, "").trim()
return applicationsByExec[cleanExec] || null
}
function getCategoriesForApp(app) { function getCategoriesForApp(app) {
if (!app || !app.categories) return [] if (!app || !app.categories) return []

View File

@@ -77,35 +77,7 @@ Singleton {
return "bluetooth"; return "bluetooth";
} }
function getDeviceType(device) {
if (!device)
return "bluetooth";
var name = (device.name || device.deviceName || "").toLowerCase();
var icon = (device.icon || "").toLowerCase();
if (icon.includes("headset") || icon.includes("audio") || name.includes("headphone") || name.includes("airpod") || name.includes("headset") || name.includes("arctis"))
return "headset";
if (icon.includes("mouse") || name.includes("mouse"))
return "mouse";
if (icon.includes("keyboard") || name.includes("keyboard"))
return "keyboard";
if (icon.includes("phone") || name.includes("phone") || name.includes("iphone") || name.includes("android") || name.includes("samsung"))
return "phone";
if (icon.includes("watch") || name.includes("watch"))
return "watch";
if (icon.includes("speaker") || name.includes("speaker"))
return "speaker";
if (icon.includes("display") || name.includes("tv"))
return "tv";
return "bluetooth";
}
function canConnect(device) { function canConnect(device) {
if (!device) if (!device)

View File

@@ -22,7 +22,7 @@ Singleton {
laptopBrightnessProcess.command = ["brightnessctl", "set", brightnessLevel + "%"]; laptopBrightnessProcess.command = ["brightnessctl", "set", brightnessLevel + "%"];
laptopBrightnessProcess.running = true; laptopBrightnessProcess.running = true;
} else if (ddcAvailable) { } else if (ddcAvailable) {
console.log("Setting DDC brightness to:", brightnessLevel);
Quickshell.execDetached(["ddcutil", "setvcp", "10", brightnessLevel.toString()]); Quickshell.execDetached(["ddcutil", "setvcp", "10", brightnessLevel.toString()]);
} }
} }
@@ -66,7 +66,7 @@ Singleton {
onExited: function(exitCode) { onExited: function(exitCode) {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("Failed to set laptop brightness, exit code:", exitCode);
} }
} }
} }
@@ -87,7 +87,7 @@ Singleton {
onExited: function(exitCode) { onExited: function(exitCode) {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("Failed to get laptop brightness, exit code:", exitCode);
} }
} }
} }
@@ -108,7 +108,7 @@ Singleton {
onExited: function(exitCode) { onExited: function(exitCode) {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("Failed to get max laptop brightness, exit code:", exitCode);
} }
} }
} }
@@ -133,7 +133,7 @@ Singleton {
onExited: function(exitCode) { onExited: function(exitCode) {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("Failed to get DDC brightness, exit code:", exitCode);
brightnessLevel = 75; brightnessLevel = 75;
} }
} }

View File

@@ -45,27 +45,18 @@ Singleton {
function addRef() { function addRef() {
refCount++; refCount++;
console.log("NetworkService: addRef, refCount now:", refCount);
// Reference counting affects WiFi scanning operations only
// Basic network status monitoring always runs
} }
function removeRef() { function removeRef() {
refCount = Math.max(0, refCount - 1); refCount = Math.max(0, refCount - 1);
console.log("NetworkService: removeRef, refCount now:", refCount);
// Stop intensive WiFi operations when no consumers
if (refCount === 0) { if (refCount === 0) {
autoRefreshTimer.running = false; autoRefreshTimer.running = false;
} }
} }
// Load saved preference on startup
Component.onCompleted: { Component.onCompleted: {
// Load preference from Prefs system
root.userPreference = Prefs.networkPreference root.userPreference = Prefs.networkPreference
console.log("NetworkService: Loaded network preference from Prefs:", root.userPreference)
// Trigger immediate WiFi info update if WiFi is connected and enabled
if (root.networkStatus === "wifi" && root.wifiEnabled) { if (root.networkStatus === "wifi" && root.wifiEnabled) {
updateCurrentWifiInfo() updateCurrentWifiInfo()
} }
@@ -582,7 +573,7 @@ Singleton {
return b.signal - a.signal; return b.signal - a.signal;
}); });
root.wifiNetworks = networks; root.wifiNetworks = networks;
console.log("Found", networks.length, "WiFi networks");
// Stop scanning once we have results // Stop scanning once we have results
if (networks.length > 0) { if (networks.length > 0) {
root.isScanning = false; root.isScanning = false;
@@ -615,7 +606,7 @@ Singleton {
} }
root.savedWifiNetworks = saved; root.savedWifiNetworks = saved;
console.log("Found", saved.length, "saved WiFi networks");
} }
} }
} }
@@ -902,14 +893,14 @@ Singleton {
root.networkInfoDetails = details; root.networkInfoDetails = details;
root.networkInfoLoading = false; root.networkInfoLoading = false;
console.log("Network info fetched for:", root.networkInfoSSID);
} }
} }
onExited: (exitCode) => { onExited: (exitCode) => {
root.networkInfoLoading = false; root.networkInfoLoading = false;
if (exitCode !== 0) { if (exitCode !== 0) {
console.log("Failed to fetch network info, exit code:", exitCode);
root.networkInfoDetails = "Failed to fetch network information"; root.networkInfoDetails = "Failed to fetch network information";
} }
} }
@@ -917,7 +908,7 @@ Singleton {
stderr: SplitParser { stderr: SplitParser {
splitMarker: "\\n" splitMarker: "\\n"
onRead: (data) => { onRead: (data) => {
console.log("WiFi info stderr:", data);
} }
} }
} }

View File

@@ -180,7 +180,7 @@ Singleton {
try { try {
data = JSON.parse(text); data = JSON.parse(text);
} catch (error) { } catch (error) {
console.error("SysMonitorService: Failed to parse JSON:", error, "Raw text:", text.slice(0, 300));
isUpdating = false; isUpdating = false;
return; return;
} }
@@ -535,7 +535,7 @@ printf "}\\n"`
running: false running: false
onExited: (exitCode) => { onExited: (exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("Unified stats process failed with exit code:", exitCode);
isUpdating = false; isUpdating = false;
} }
} }
@@ -545,7 +545,7 @@ printf "}\\n"`
const fullText = text.trim(); const fullText = text.trim();
const lastBraceIndex = fullText.lastIndexOf('}'); const lastBraceIndex = fullText.lastIndexOf('}');
if (lastBraceIndex === -1) { if (lastBraceIndex === -1) {
console.error("SysMonitorService: No JSON object found in output.", fullText);
isUpdating = false; isUpdating = false;
return; return;
} }

View File

@@ -41,7 +41,7 @@ Singleton {
running: false running: false
onExited: (exitCode) => { onExited: (exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("UserInfoService: Failed to get user info");
root.username = "User"; root.username = "User";
root.fullName = "User"; root.fullName = "User";
root.hostname = "System"; root.hostname = "System";
@@ -55,7 +55,7 @@ Singleton {
root.username = parts[0] || ""; root.username = parts[0] || "";
root.fullName = parts[1] || parts[0] || ""; root.fullName = parts[1] || parts[0] || "";
root.hostname = parts[2] || ""; root.hostname = parts[2] || "";
console.log("UserInfoService: User info loaded -", root.username, root.fullName, root.hostname);
} }
} }
} }
@@ -70,7 +70,7 @@ Singleton {
running: false running: false
onExited: (exitCode) => { onExited: (exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("UserInfoService: Failed to get uptime");
root.uptime = "Unknown"; root.uptime = "Unknown";
} }
} }

View File

@@ -100,7 +100,7 @@ Singleton {
function addRef() { function addRef() {
refCount++; refCount++;
console.log("WeatherService: addRef, refCount now:", refCount);
if (refCount === 1 && !weather.available) { if (refCount === 1 && !weather.available) {
// Start fetching when first consumer appears // Start fetching when first consumer appears
fetchWeather(); fetchWeather();
@@ -109,13 +109,13 @@ Singleton {
function removeRef() { function removeRef() {
refCount = Math.max(0, refCount - 1); refCount = Math.max(0, refCount - 1);
console.log("WeatherService: removeRef, refCount now:", refCount);
} }
function fetchWeather() { function fetchWeather() {
// Only fetch if someone is consuming the data // Only fetch if someone is consuming the data
if (root.refCount === 0) { if (root.refCount === 0) {
console.log("WeatherService: Skipping fetch - no consumers");
return; return;
} }

View File

@@ -29,7 +29,6 @@ Image {
} }
onCachePathChanged: { onCachePathChanged: {
if (imageHash && cachePath) { if (imageHash && cachePath) {
// Ensure cache directory exists before trying to load from cache
Paths.mkdir(Paths.imagecache); Paths.mkdir(Paths.imagecache);
source = cachePath; source = cachePath;
} }

View File

@@ -5,8 +5,6 @@ import qs.Common
import qs.Widgets import qs.Widgets
Rectangle { Rectangle {
// Force recreate popup when component becomes visible
id: root id: root
property string text: "" property string text: ""
@@ -26,7 +24,6 @@ Rectangle {
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Theme.surfaceHover color: Theme.surfaceHover
Component.onCompleted: { Component.onCompleted: {
// Force a small delay to ensure proper initialization
forceRecreateTimer.start(); forceRecreateTimer.start();
} }
Component.onDestruction: { Component.onDestruction: {
@@ -104,7 +101,6 @@ Rectangle {
popup.close(); popup.close();
} else if (popup) { } else if (popup) {
var pos = dropdown.mapToItem(Overlay.overlay, 0, dropdown.height + 4); var pos = dropdown.mapToItem(Overlay.overlay, 0, dropdown.height + 4);
// Center the wider popup over the dropdown button
popup.x = pos.x - (root.popupWidthOffset / 2); popup.x = pos.x - (root.popupWidthOffset / 2);
popup.y = pos.y; popup.y = pos.y;
popup.open(); popup.open();
@@ -112,7 +108,6 @@ Rectangle {
} }
} }
// Use a Row for the left-aligned content (icon + text)
Row { Row {
id: contentRow id: contentRow
@@ -135,14 +130,12 @@ Rectangle {
text: root.currentValue text: root.currentValue
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText color: Theme.surfaceText
// Constrain width for proper eliding
width: dropdown.width - contentRow.x - expandIcon.width - Theme.spacingM - Theme.spacingS width: dropdown.width - contentRow.x - expandIcon.width - Theme.spacingM - Theme.spacingS
elide: Text.ElideRight elide: Text.ElideRight
} }
} }
// Anchor the expand icon to the right, outside of the Row
DankIcon { DankIcon {
id: expandIcon id: expandIcon
@@ -163,7 +156,6 @@ Rectangle {
active: true active: true
onRecreateFlagChanged: { onRecreateFlagChanged: {
// Force recreation by toggling active
active = false; active = false;
active = true; active = true;
} }
@@ -241,7 +233,6 @@ Rectangle {
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingS anchors.margins: Theme.spacingS
// Search field
Rectangle { Rectangle {
id: searchContainer id: searchContainer

View File

@@ -29,7 +29,6 @@ GridView {
signal itemClicked(int index, var modelData) signal itemClicked(int index, var modelData)
signal itemHovered(int index) signal itemHovered(int index)
// Ensure the current item is visible
function ensureVisible(index) { function ensureVisible(index) {
if (index < 0 || index >= gridView.count) if (index < 0 || index >= gridView.count)
return ; return ;
@@ -157,7 +156,6 @@ GridView {
itemHovered(index); itemHovered(index);
} }
onPositionChanged: { onPositionChanged: {
// Signal parent to reset keyboard navigation flag when mouse moves
keyboardNavigationReset(); keyboardNavigationReset();
} }
onClicked: { onClicked: {

View File

@@ -18,7 +18,6 @@ StyledText {
color: Theme.surfaceText color: Theme.surfaceText
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
// Material Icons variable font axes support
font.variableAxes: ({ font.variableAxes: ({
"FILL": fill.toFixed(1), "FILL": fill.toFixed(1),
"GRAD": grade, "GRAD": grade,
@@ -26,7 +25,6 @@ StyledText {
"wght": weight "wght": weight
}) })
// Smooth transitions for variable axes
Behavior on fill { Behavior on fill {
NumberAnimation { NumberAnimation {
duration: Appearance.anim.durations.quick duration: Appearance.anim.durations.quick

View File

@@ -20,7 +20,6 @@ ListView {
signal itemClicked(int index, var modelData) signal itemClicked(int index, var modelData)
signal itemHovered(int index) signal itemHovered(int index)
// Ensure the current item is visible
function ensureVisible(index) { function ensureVisible(index) {
if (index < 0 || index >= count) if (index < 0 || index >= count)
return ; return ;
@@ -156,7 +155,6 @@ ListView {
itemHovered(index); itemHovered(index);
} }
onPositionChanged: { onPositionChanged: {
// Signal parent to reset keyboard navigation flag when mouse moves
keyboardNavigationReset(); keyboardNavigationReset();
} }
onClicked: { onClicked: {

View File

@@ -21,7 +21,6 @@ Column {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
// Header
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
@@ -48,7 +47,6 @@ Column {
} }
// Widget Items
Column { Column {
id: itemsList id: itemsList
@@ -252,7 +250,6 @@ Column {
} }
// Add Widget Control
Rectangle { Rectangle {
width: 200 width: 200
height: 40 height: 40

View File

@@ -1,277 +0,0 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Widgets
Column {
id: root
property var items: []
property var allWidgets: []
property string title: ""
property string titleIcon: "widgets"
property string sectionId: ""
signal itemEnabledChanged(string itemId, bool enabled)
signal itemOrderChanged(var newOrder)
signal addWidget(string sectionId)
signal removeLastWidget(string sectionId)
width: parent.width
spacing: Theme.spacingM
// Header
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: root.titleIcon
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: root.title
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: parent.width - 60
height: 1
}
}
// Widget Items
Column {
id: itemsList
width: parent.width
spacing: Theme.spacingS
Repeater {
model: root.items
delegate: Item {
id: delegateItem
property int visualIndex: index
property bool held: dragArea.pressed
property string itemId: modelData.id
width: itemsList.width
height: 70
z: held ? 2 : 1
Rectangle {
id: itemBackground
anchors.fill: parent
anchors.margins: 2
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.8)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
Row {
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingM
// Drag handle
Rectangle {
width: 40
height: parent.height
color: "transparent"
anchors.verticalCenter: parent.verticalCenter
DankIcon {
name: "drag_indicator"
size: Theme.iconSize - 4
color: Theme.outline
anchors.centerIn: parent
opacity: 0.8
}
}
// Widget icon
DankIcon {
name: modelData.icon
size: Theme.iconSize
color: modelData.enabled ? Theme.primary : Theme.outline
anchors.verticalCenter: parent.verticalCenter
}
// Widget info
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 2
width: parent.width - 200 // Leave space for toggle
StyledText {
text: modelData.text
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: modelData.enabled ? Theme.surfaceText : Theme.outline
elide: Text.ElideRight
width: parent.width
}
StyledText {
text: modelData.description
font.pixelSize: Theme.fontSizeSmall
color: modelData.enabled ? Theme.outline : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.6)
elide: Text.ElideRight
width: parent.width
wrapMode: Text.WordWrap
}
}
// Spacer to push toggle to right
Item {
width: parent.width - 280 // Dynamic width
height: 1
}
// Toggle - positioned at right edge
DankToggle {
anchors.verticalCenter: parent.verticalCenter
width: 48
height: 24
hideText: true
checked: modelData.enabled
onToggled: (checked) => {
root.itemEnabledChanged(modelData.id, checked);
}
}
}
// Drag functionality
MouseArea {
id: dragArea
property bool validDragStart: false
anchors.fill: parent
hoverEnabled: true
drag.target: held && validDragStart ? delegateItem : undefined
drag.axis: Drag.YAxis
drag.minimumY: -delegateItem.height
drag.maximumY: itemsList.height
onPressed: (mouse) => {
// Only allow dragging from the drag handle area (first 60px)
if (mouse.x <= 60) {
validDragStart = true;
delegateItem.z = 2;
} else {
validDragStart = false;
mouse.accepted = false;
}
}
onReleased: {
delegateItem.z = 1;
if (drag.active && validDragStart) {
// Calculate new index based on position
var newIndex = Math.round(delegateItem.y / (delegateItem.height + itemsList.spacing));
newIndex = Math.max(0, Math.min(newIndex, root.items.length - 1));
if (newIndex !== index) {
var newItems = root.items.slice();
var draggedItem = newItems.splice(index, 1)[0];
newItems.splice(newIndex, 0, draggedItem);
root.itemOrderChanged(newItems.map((item) => {
return item.id;
}));
}
}
// Reset position
delegateItem.x = 0;
delegateItem.y = 0;
validDragStart = false;
}
}
// Animations for drag
Behavior on y {
enabled: !dragArea.held && !dragArea.drag.active
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}
// Add/Remove Controls
Rectangle {
width: parent.width * 0.5
height: 40
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1
anchors.horizontalCenter: parent.horizontalCenter
Row {
anchors.centerIn: parent
spacing: Theme.spacingL
StyledText {
text: "Add or remove widgets"
font.pixelSize: Theme.fontSizeSmall
color: Theme.outline
anchors.verticalCenter: parent.verticalCenter
}
Row {
spacing: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
// Add button
DankActionButton {
iconName: "add"
iconSize: Theme.iconSize - 4
iconColor: Theme.primary
hoverColor: Theme.primaryContainer
onClicked: {
root.addWidget(root.sectionId);
}
}
// Remove button
DankActionButton {
iconName: "remove"
iconSize: Theme.iconSize - 4
iconColor: Theme.error
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.1)
enabled: root.items.length > 0
opacity: root.items.length > 0 ? 1 : 0.5
onClicked: {
if (root.items.length > 0)
root.removeLastWidget(root.sectionId);
}
}
}
}
}
}

View File

@@ -19,13 +19,11 @@ StyledRect {
property alias validator: textInput.validator property alias validator: textInput.validator
property alias inputMethodHints: textInput.inputMethodHints property alias inputMethodHints: textInput.inputMethodHints
property alias maximumLength: textInput.maximumLength property alias maximumLength: textInput.maximumLength
// Icon properties
property string leftIconName: "" property string leftIconName: ""
property int leftIconSize: Theme.iconSize property int leftIconSize: Theme.iconSize
property color leftIconColor: Theme.surfaceVariantText property color leftIconColor: Theme.surfaceVariantText
property color leftIconFocusedColor: Theme.primary property color leftIconFocusedColor: Theme.primary
property bool showClearButton: false property bool showClearButton: false
// Custom properties
property color backgroundColor: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9) property color backgroundColor: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9)
property color focusedBorderColor: Theme.primary property color focusedBorderColor: Theme.primary
property color normalBorderColor: Theme.outlineStrong property color normalBorderColor: Theme.outlineStrong
@@ -33,22 +31,18 @@ StyledRect {
property int borderWidth: 1 property int borderWidth: 1
property int focusedBorderWidth: 2 property int focusedBorderWidth: 2
property real cornerRadius: Theme.cornerRadius property real cornerRadius: Theme.cornerRadius
// Internal padding calculations
readonly property real leftPadding: Theme.spacingM + (leftIconName ? leftIconSize + Theme.spacingM : 0) readonly property real leftPadding: Theme.spacingM + (leftIconName ? leftIconSize + Theme.spacingM : 0)
readonly property real rightPadding: Theme.spacingM + (showClearButton && text.length > 0 ? 24 + Theme.spacingM : 0) readonly property real rightPadding: Theme.spacingM + (showClearButton && text.length > 0 ? 24 + Theme.spacingM : 0)
property real topPadding: Theme.spacingM property real topPadding: Theme.spacingM
property real bottomPadding: Theme.spacingM property real bottomPadding: Theme.spacingM
// Behavior control
property bool ignoreLeftRightKeys: false property bool ignoreLeftRightKeys: false
property var keyForwardTargets: [] property var keyForwardTargets: []
// Signals
signal textEdited() signal textEdited()
signal editingFinished() signal editingFinished()
signal accepted() signal accepted()
signal focusStateChanged(bool hasFocus) signal focusStateChanged(bool hasFocus)
// Access to inner TextInput properties via functions
function getActiveFocus() { function getActiveFocus() {
return textInput.activeFocus; return textInput.activeFocus;
} }
@@ -61,7 +55,6 @@ StyledRect {
textInput.focus = value; textInput.focus = value;
} }
// Functions
function forceActiveFocus() { function forceActiveFocus() {
textInput.forceActiveFocus(); textInput.forceActiveFocus();
} }
@@ -94,7 +87,6 @@ StyledRect {
textInput.focus = false; textInput.focus = false;
} }
// Default styling
width: 200 width: 200
height: 48 height: 48
radius: cornerRadius radius: cornerRadius
@@ -102,7 +94,6 @@ StyledRect {
border.color: textInput.activeFocus ? focusedBorderColor : normalBorderColor border.color: textInput.activeFocus ? focusedBorderColor : normalBorderColor
border.width: textInput.activeFocus ? focusedBorderWidth : borderWidth border.width: textInput.activeFocus ? focusedBorderWidth : borderWidth
// Left icon
DankIcon { DankIcon {
id: leftIcon id: leftIcon
@@ -153,7 +144,6 @@ StyledRect {
} }
// Clear button
StyledRect { StyledRect {
id: clearButton id: clearButton

View File

@@ -12,7 +12,6 @@ Popup {
signal widgetSelected(string widgetId, string targetSection) signal widgetSelected(string widgetId, string targetSection)
// Prevent multiple openings
function safeOpen() { function safeOpen() {
if (!isOpening && !visible) { if (!isOpening && !visible) {
isOpening = true; isOpening = true;
@@ -29,7 +28,6 @@ Popup {
} }
onClosed: { onClosed: {
isOpening = false; isOpening = false;
// Clear references to prevent memory leaks
allWidgets = []; allWidgets = [];
targetSection = ""; targetSection = "";
} }
@@ -44,7 +42,6 @@ Popup {
contentItem: Item { contentItem: Item {
anchors.fill: parent anchors.fill: parent
// Close button in top-right
DankActionButton { DankActionButton {
iconName: "close" iconName: "close"
iconSize: Theme.iconSize - 2 iconSize: Theme.iconSize - 2
@@ -65,7 +62,6 @@ Popup {
anchors.margins: Theme.spacingL anchors.margins: Theme.spacingL
anchors.topMargin: Theme.spacingL + 30 // Space for close button anchors.topMargin: Theme.spacingL + 30 // Space for close button
// Header
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
@@ -95,7 +91,6 @@ Popup {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
} }
// Widget List
ScrollView { ScrollView {
width: parent.width width: parent.width
height: parent.height - 120 // Leave space for header and description height: parent.height - 120 // Leave space for header and description
@@ -120,7 +115,6 @@ Popup {
anchors.margins: Theme.spacingM anchors.margins: Theme.spacingM
spacing: Theme.spacingM spacing: Theme.spacingM
// Widget icon
DankIcon { DankIcon {
name: modelData.icon name: modelData.icon
size: Theme.iconSize size: Theme.iconSize
@@ -128,7 +122,6 @@ Popup {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
// Widget info
Column { Column {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: 2 spacing: 2
@@ -154,7 +147,6 @@ Popup {
} }
// Add icon
DankIcon { DankIcon {
name: "add" name: "add"
size: Theme.iconSize - 4 size: Theme.iconSize - 4

View File

@@ -10,18 +10,14 @@ Text {
color: Theme.surfaceText color: Theme.surfaceText
font.pixelSize: Appearance.fontSize.normal font.pixelSize: Appearance.fontSize.normal
font.family: { font.family: {
// Use system default
var requestedFont = isMonospace ? Prefs.monoFontFamily : Prefs.fontFamily; var requestedFont = isMonospace ? Prefs.monoFontFamily : Prefs.fontFamily;
var defaultFont = isMonospace ? Prefs.defaultMonoFontFamily : Prefs.defaultFontFamily; var defaultFont = isMonospace ? Prefs.defaultMonoFontFamily : Prefs.defaultFontFamily;
// If user hasn't overridden the font and we're using the default
if (requestedFont === defaultFont) { if (requestedFont === defaultFont) {
var availableFonts = Qt.fontFamilies(); var availableFonts = Qt.fontFamilies();
if (!availableFonts.includes(requestedFont)) if (!availableFonts.includes(requestedFont))
return isMonospace ? "Monospace" : "DejaVu Sans"; return isMonospace ? "Monospace" : "DejaVu Sans";
} }
// Either user overrode it, or default font is available
return requestedFont; return requestedFont;
} }
font.weight: Prefs.fontWeight font.weight: Prefs.fontWeight

View File

@@ -1,4 +1,3 @@
//@ pragma UseQApplication
import QtQuick import QtQuick
import Quickshell import Quickshell
@@ -30,7 +29,6 @@ ShellRoot {
anchors.fill: parent anchors.fill: parent
} }
// Multi-monitor support using Variants
Variants { Variants {
model: Quickshell.screens model: Quickshell.screens
@@ -103,7 +101,6 @@ ShellRoot {
id: settingsModal id: settingsModal
} }
// Application and clipboard components
AppDrawerPopout { AppDrawerPopout {
id: appDrawerPopout id: appDrawerPopout
} }