From 4486e79afe3eeb95a00fe4b4d29f3bb5d8576997 Mon Sep 17 00:00:00 2001 From: bbedward Date: Mon, 14 Jul 2025 12:46:36 -0400 Subject: [PATCH] Enhancements to launcher and other warning fixes - Persist grid/list setting - Alignment improvement --- Common/Prefs.qml | 23 +- Common/Theme.qml | 4 +- Services/FocusedWindowService.qml | 2 +- Widgets/AppLauncher.qml | 22 +- .../CenterCommandCenter.qml | 12 +- Widgets/CenterCommandCenter/EventsWidget.qml | 281 ++++++++---------- Widgets/CenterCommandCenter/WeatherWidget.qml | 53 ++-- Widgets/ClipboardHistory.qml | 16 +- Widgets/ControlCenter/ControlCenterPopup.qml | 8 +- Widgets/PowerConfirmDialog.qml | 2 +- Widgets/ProcessListDropdown.qml | 7 +- Widgets/SettingsPopup.qml | 2 +- Widgets/SettingsToggle.qml | 2 +- Widgets/SpotlightLauncher.qml | 163 ++++++---- shell.qml | 7 - 15 files changed, 322 insertions(+), 282 deletions(-) diff --git a/Common/Prefs.qml b/Common/Prefs.qml index 44662ef4..8589bb5d 100644 --- a/Common/Prefs.qml +++ b/Common/Prefs.qml @@ -27,6 +27,10 @@ Singleton { property bool showSystemResources: true property bool showSystemTray: true + // View mode preferences for launchers + property string appLauncherViewMode: "list" + property string spotlightLauncherViewMode: "list" + Component.onCompleted: loadSettings() @@ -73,6 +77,8 @@ Singleton { showClipboard = settings.showClipboard !== undefined ? settings.showClipboard : true showSystemResources = settings.showSystemResources !== undefined ? settings.showSystemResources : true showSystemTray = settings.showSystemTray !== undefined ? settings.showSystemTray : true + appLauncherViewMode = settings.appLauncherViewMode !== undefined ? settings.appLauncherViewMode : "list" + spotlightLauncherViewMode = settings.spotlightLauncherViewMode !== undefined ? settings.spotlightLauncherViewMode : "list" console.log("Loaded settings - themeIndex:", themeIndex, "isDynamic:", themeIsDynamic, "lightMode:", isLightMode, "transparency:", topBarTransparency, "recentApps:", recentlyUsedApps.length) applyStoredTheme() @@ -102,7 +108,9 @@ Singleton { showMusic, showClipboard, showSystemResources, - showSystemTray + showSystemTray, + appLauncherViewMode, + spotlightLauncherViewMode }, null, 2)) console.log("Saving settings - themeIndex:", themeIndex, "isDynamic:", themeIsDynamic, "lightMode:", isLightMode, "transparency:", topBarTransparency, "recentApps:", recentlyUsedApps.length) } @@ -257,4 +265,17 @@ Singleton { showSystemTray = enabled saveSettings() } + + // View mode setters + function setAppLauncherViewMode(mode) { + console.log("Prefs setAppLauncherViewMode called - appLauncherViewMode:", mode) + appLauncherViewMode = mode + saveSettings() + } + + function setSpotlightLauncherViewMode(mode) { + console.log("Prefs setSpotlightLauncherViewMode called - spotlightLauncherViewMode:", mode) + spotlightLauncherViewMode = mode + saveSettings() + } } \ No newline at end of file diff --git a/Common/Theme.qml b/Common/Theme.qml index 31bd4ce8..9b8fa253 100644 --- a/Common/Theme.qml +++ b/Common/Theme.qml @@ -455,8 +455,8 @@ QtObject { property color surfaceVariant: isDynamicTheme ? Colors.surfaceVariant : getCurrentTheme().surfaceVariant property color surfaceVariantText: isDynamicTheme ? Colors.surfaceVariantText : getCurrentTheme().surfaceVariantText property color surfaceTint: isDynamicTheme ? Colors.surfaceTint : getCurrentTheme().surfaceTint - property color background: isDynamicTheme ? Colors.background : getCurrentTheme().background - property color backgroundText: isDynamicTheme ? Colors.backgroundText : getCurrentTheme().backgroundText + property color background: isDynamicTheme ? Colors.bg : getCurrentTheme().background + property color backgroundText: isDynamicTheme ? Colors.surfaceText : getCurrentTheme().backgroundText property color outline: isDynamicTheme ? Colors.outline : getCurrentTheme().outline property color surfaceContainer: isDynamicTheme ? Colors.surfaceContainer : getCurrentTheme().surfaceContainer property color surfaceContainerHigh: isDynamicTheme ? Colors.surfaceContainerHigh : getCurrentTheme().surfaceContainerHigh diff --git a/Services/FocusedWindowService.qml b/Services/FocusedWindowService.qml index 1cb3771c..dfb7f167 100644 --- a/Services/FocusedWindowService.qml +++ b/Services/FocusedWindowService.qml @@ -56,7 +56,7 @@ Singleton { root.focusedAppId = windowData.app_id || "" root.focusedWindowTitle = windowData.title || "" root.focusedAppName = getDisplayName(windowData.app_id || "") - root.focusedWindowId = windowData.id || -1 + root.focusedWindowId = parseInt(windowData.id) || -1 } catch (e) { console.warn("FocusedWindowService: Failed to parse focused window data:", e) clearFocusedWindow() diff --git a/Widgets/AppLauncher.qml b/Widgets/AppLauncher.qml index cc4acb6d..61d2f5b2 100644 --- a/Widgets/AppLauncher.qml +++ b/Widgets/AppLauncher.qml @@ -36,7 +36,7 @@ PanelWindow { property var recentApps: Prefs.getRecentApps() property var pinnedApps: ["firefox", "code", "terminal", "file-manager"] property bool showCategories: false - property string viewMode: "list" // "list" or "grid" + property string viewMode: Prefs.appLauncherViewMode // "list" or "grid" property int selectedIndex: 0 // Search debouncing @@ -625,7 +625,10 @@ PanelWindow { anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor - onClicked: viewMode = "list" + onClicked: { + viewMode = "list" + Prefs.setAppLauncherViewMode("list") + } } } @@ -650,7 +653,10 @@ PanelWindow { anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor - onClicked: viewMode = "grid" + onClicked: { + viewMode = "grid" + Prefs.setAppLauncherViewMode("grid") + } } } } @@ -721,18 +727,18 @@ PanelWindow { GridView { id: appGrid - width: parent.width + anchors.fill: parent anchors.margins: Theme.spacingS - // Responsive cell sizes based on screen width - property int baseCellWidth: Math.max(100, Math.min(140, width / 8)) + // Responsive cell sizes based on screen width - 4 columns + property int columnsCount: 4 + property int baseCellWidth: (width - Theme.spacingS * 2) / columnsCount property int baseCellHeight: baseCellWidth + 20 cellWidth: baseCellWidth cellHeight: baseCellHeight // Center the grid content - property int columnsCount: Math.floor(width / cellWidth) property int remainingSpace: width - (columnsCount * cellWidth) leftMargin: Math.max(Theme.spacingS, remainingSpace / 2) rightMargin: leftMargin @@ -983,7 +989,7 @@ PanelWindow { Text { anchors.horizontalCenter: parent.horizontalCenter - width: 88 + width: appGrid.cellWidth - 12 text: model.name font.pixelSize: Theme.fontSizeSmall color: Theme.surfaceText diff --git a/Widgets/CenterCommandCenter/CenterCommandCenter.qml b/Widgets/CenterCommandCenter/CenterCommandCenter.qml index 9b7f0b01..4a445f30 100644 --- a/Widgets/CenterCommandCenter/CenterCommandCenter.qml +++ b/Widgets/CenterCommandCenter/CenterCommandCenter.qml @@ -70,9 +70,7 @@ PanelWindow { // Main row with widgets and calendar let widgetHeight = 160 // Media widget always present - if (weather?.available) { - widgetHeight += (weather ? 140 : 80) + theme.spacingM - } + widgetHeight += (weather ? 140 : 80) + theme.spacingM // Weather widget always present let calendarHeight = 300 let mainRowHeight = Math.max(widgetHeight, calendarHeight) @@ -169,9 +167,7 @@ PanelWindow { width: parent.width height: { let widgetHeight = 160 // Media widget always present - if (weather?.available) { - widgetHeight += (weather ? 140 : 80) + theme.spacingM - } + widgetHeight += (weather ? 140 : 80) + theme.spacingM // Weather widget always present let calendarHeight = 300 return Math.max(widgetHeight, calendarHeight) } @@ -186,7 +182,7 @@ PanelWindow { visible: hasAnyWidgets anchors.top: parent.top - property bool hasAnyWidgets: true || weather?.available // Always show media widget + property bool hasAnyWidgets: true // Always show media widget and weather widget MediaPlayerWidget { visible: true // Always visible - shows placeholder when no media @@ -196,7 +192,7 @@ PanelWindow { } WeatherWidget { - visible: weather?.available + visible: true // Always visible - shows placeholder when no weather width: parent.width height: weather ? 140 : 80 theme: centerCommandCenter.theme diff --git a/Widgets/CenterCommandCenter/EventsWidget.qml b/Widgets/CenterCommandCenter/EventsWidget.qml index 8c6426a8..9f48e9d9 100644 --- a/Widgets/CenterCommandCenter/EventsWidget.qml +++ b/Widgets/CenterCommandCenter/EventsWidget.qml @@ -75,133 +75,119 @@ Rectangle { } } - Item { - anchors.fill: parent + // Header - always visible when widget is shown + Row { + id: headerRow + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right anchors.margins: theme.spacingL + spacing: theme.spacingS - Column { - anchors.fill: parent - spacing: theme.spacingM - - // Header - always visible when widget is shown - Item { - width: parent.width - height: headerRow.height - - Row { - id: headerRow - width: parent.width - spacing: theme.spacingS - - Text { - text: "event" - font.family: theme.iconFont - font.pixelSize: theme.iconSize - 2 - color: theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - Text { - text: hasEvents ? - (Qt.formatDate(selectedDate, "MMM d") + " • " + - (selectedDateEvents.length === 1 ? "1 event" : selectedDateEvents.length + " events")) : - Qt.formatDate(selectedDate, "MMM d") - font.pixelSize: theme.fontSizeMedium - color: theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - } + Text { + text: "event" + font.family: theme.iconFont + font.pixelSize: theme.iconSize - 2 + color: theme.primary + anchors.verticalCenter: parent.verticalCenter } - // Content area - Rectangle { - anchors.fill: parent - anchors.margins: theme.spacingL - color: "transparent" - - // No events placeholder - absolutely centered in this gray container - Column { - anchors.centerIn: parent - spacing: theme.spacingXS - visible: !hasEvents + Text { + text: hasEvents ? + (Qt.formatDate(selectedDate, "MMM d") + " • " + + (selectedDateEvents.length === 1 ? "1 event" : selectedDateEvents.length + " events")) : + Qt.formatDate(selectedDate, "MMM d") + font.pixelSize: theme.fontSizeMedium + color: theme.surfaceText + font.weight: Font.Medium + anchors.verticalCenter: parent.verticalCenter + } + } + + // No events placeholder - centered in entire widget (not just content area) + Column { + anchors.centerIn: parent + spacing: theme.spacingXS + visible: !hasEvents - Text { - text: "event_busy" - font.family: theme.iconFont - font.pixelSize: theme.iconSize + 8 - color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.3) - anchors.horizontalCenter: parent.horizontalCenter - } - - Text { - text: "No events" - font.pixelSize: theme.fontSizeMedium - color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.5) - font.weight: Font.Normal - anchors.horizontalCenter: parent.horizontalCenter - } + Text { + text: "event_busy" + font.family: theme.iconFont + font.pixelSize: theme.iconSize + 8 + color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.3) + anchors.horizontalCenter: parent.horizontalCenter + } + + Text { + text: "No events" + font.pixelSize: theme.fontSizeMedium + color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.5) + font.weight: Font.Normal + anchors.horizontalCenter: parent.horizontalCenter + } + } + + // Events list - positioned below header when there are events + ListView { + id: eventsList + anchors.top: headerRow.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: theme.spacingL + anchors.topMargin: theme.spacingM + visible: hasEvents + clip: true + spacing: theme.spacingS + boundsMovement: Flickable.StopAtBounds + boundsBehavior: Flickable.StopAtBounds + ScrollBar.vertical: ScrollBar { + policy: eventsList.contentHeight > eventsList.height ? ScrollBar.AsNeeded : ScrollBar.AlwaysOff + } + + delegate: Rectangle { + width: eventsList.width + height: eventContent.implicitHeight + theme.spacingM + radius: theme.cornerRadius + color: { + if (modelData.url && eventMouseArea.containsMouse) { + return Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.12) + } else if (eventMouseArea.containsMouse) { + return Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.06) } - - // Events list - ListView { - id: eventsList - anchors.fill: parent - anchors.margins: theme.spacingM - anchors.topMargin: theme.spacingM + 2 - visible: hasEvents - clip: true - spacing: theme.spacingS - boundsMovement: Flickable.StopAtBounds - boundsBehavior: Flickable.StopAtBounds - - ScrollBar.vertical: ScrollBar { - policy: eventsList.contentHeight > eventsList.height ? ScrollBar.AsNeeded : ScrollBar.AlwaysOff - } - - delegate: Rectangle { - width: eventsList.width - height: eventContent.implicitHeight + theme.spacingM - radius: theme.cornerRadius - color: { - if (modelData.url && eventMouseArea.containsMouse) { - return Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.12) - } else if (eventMouseArea.containsMouse) { - return Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.06) - } - return Qt.rgba(theme.surfaceVariant.r, theme.surfaceVariant.g, theme.surfaceVariant.b, 0.06) - } - border.color: { - if (modelData.url && eventMouseArea.containsMouse) { - return Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.3) - } else if (eventMouseArea.containsMouse) { - return Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.15) - } - return "transparent" - } - border.width: 1 - - // Event indicator strip - Rectangle { - width: 4 - height: parent.height - 8 - anchors.left: parent.left - anchors.leftMargin: 4 - anchors.verticalCenter: parent.verticalCenter - radius: 2 - color: theme.primary - opacity: 0.8 - } - - Column { - id: eventContent - anchors.left: parent.left - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: theme.spacingL + 4 - anchors.rightMargin: theme.spacingM - spacing: 6 + return Qt.rgba(theme.surfaceVariant.r, theme.surfaceVariant.g, theme.surfaceVariant.b, 0.06) + } + border.color: { + if (modelData.url && eventMouseArea.containsMouse) { + return Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.3) + } else if (eventMouseArea.containsMouse) { + return Qt.rgba(theme.primary.r, theme.primary.g, theme.primary.b, 0.15) + } + return "transparent" + } + border.width: 1 + + // Event indicator strip + Rectangle { + width: 4 + height: parent.height - 8 + anchors.left: parent.left + anchors.leftMargin: 4 + anchors.verticalCenter: parent.verticalCenter + radius: 2 + color: theme.primary + opacity: 0.8 + } + + Column { + id: eventContent + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: theme.spacingL + 4 + anchors.rightMargin: theme.spacingM + spacing: 6 Text { width: parent.width @@ -280,39 +266,36 @@ Rectangle { } } } - - MouseArea { - id: eventMouseArea - anchors.fill: parent - hoverEnabled: true - cursorShape: modelData.url ? Qt.PointingHandCursor : Qt.ArrowCursor - enabled: modelData.url !== "" - - onClicked: { - if (modelData.url && modelData.url !== "") { - if (Qt.openUrlExternally(modelData.url) === false) { - console.warn("Couldn't open", modelData.url) - } - } - } - } - - Behavior on color { - ColorAnimation { - duration: theme.shortDuration - easing.type: theme.standardEasing - } - } - - Behavior on border.color { - ColorAnimation { - duration: theme.shortDuration - easing.type: theme.standardEasing - } + + MouseArea { + id: eventMouseArea + anchors.fill: parent + hoverEnabled: true + cursorShape: modelData.url ? Qt.PointingHandCursor : Qt.ArrowCursor + enabled: modelData.url !== "" + + onClicked: { + if (modelData.url && modelData.url !== "") { + if (Qt.openUrlExternally(modelData.url) === false) { + console.warn("Couldn't open", modelData.url) } } } } + + Behavior on color { + ColorAnimation { + duration: theme.shortDuration + easing.type: theme.standardEasing + } + } + + Behavior on border.color { + ColorAnimation { + duration: theme.shortDuration + easing.type: theme.standardEasing + } + } } } } \ No newline at end of file diff --git a/Widgets/CenterCommandCenter/WeatherWidget.qml b/Widgets/CenterCommandCenter/WeatherWidget.qml index 912a59ae..f04875c4 100644 --- a/Widgets/CenterCommandCenter/WeatherWidget.qml +++ b/Widgets/CenterCommandCenter/WeatherWidget.qml @@ -27,43 +27,43 @@ Rectangle { shadowOpacity: 0.1 } + // Placeholder when no weather - centered in entire widget + Column { + anchors.centerIn: parent + spacing: theme.spacingS + visible: !weather || !weather.available || weather.temp === 0 + + Text { + text: "cloud_off" + font.family: theme.iconFont + font.pixelSize: theme.iconSize + 8 + color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.5) + anchors.horizontalCenter: parent.horizontalCenter + } + + Text { + text: "No Weather Data" + font.pixelSize: theme.fontSizeMedium + color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.7) + anchors.horizontalCenter: parent.horizontalCenter + } + } + + // Weather content when available - original Column structure Column { anchors.fill: parent anchors.margins: theme.spacingL - spacing: theme.spacingM + spacing: theme.spacingS + visible: weather && weather.available && weather.temp !== 0 - // Show different content based on whether we have weather data + // Weather header info Item { width: parent.width height: 60 - // Placeholder when no weather - Column { - anchors.centerIn: parent - spacing: theme.spacingS - visible: !weather || !weather.available || weather.temp === 0 - - Text { - text: "cloud_off" - font.family: theme.iconFont - font.pixelSize: theme.iconSize + 8 - color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.5) - anchors.horizontalCenter: parent.horizontalCenter - } - - Text { - text: "No Weather Data" - font.pixelSize: theme.fontSizeMedium - color: Qt.rgba(theme.surfaceText.r, theme.surfaceText.g, theme.surfaceText.b, 0.7) - anchors.horizontalCenter: parent.horizontalCenter - } - } - - // Normal weather info when available Row { anchors.fill: parent spacing: theme.spacingL - visible: weather && weather.available && weather.temp !== 0 // Weather icon Text { @@ -108,7 +108,6 @@ Rectangle { columns: 2 spacing: theme.spacingM anchors.horizontalCenter: parent.horizontalCenter - visible: weather && weather.available && weather.temp !== 0 Row { spacing: theme.spacingXS diff --git a/Widgets/ClipboardHistory.qml b/Widgets/ClipboardHistory.qml index 320c353e..8cfc160e 100644 --- a/Widgets/ClipboardHistory.qml +++ b/Widgets/ClipboardHistory.qml @@ -836,6 +836,17 @@ PanelWindow { console.warn("ClipboardHistory: Failed to load clipboard history") } } + + // Handle keyboard shortcuts + Keys.onPressed: (event) => { + if (event.key === Qt.Key_Escape) { + clipboardHistory.hide() + } + } + + Component.onCompleted: { + focus = true + } } Process { @@ -874,11 +885,6 @@ PanelWindow { } } - Keys.onPressed: (event) => { - if (event.key === Qt.Key_Escape) { - hide() - } - } IpcHandler { target: "clipboard" diff --git a/Widgets/ControlCenter/ControlCenterPopup.qml b/Widgets/ControlCenter/ControlCenterPopup.qml index 7be8bd6b..6d2388b1 100644 --- a/Widgets/ControlCenter/ControlCenterPopup.qml +++ b/Widgets/ControlCenter/ControlCenterPopup.qml @@ -153,7 +153,7 @@ PanelWindow { color: "transparent" border.color: Qt.rgba(0, 0, 0, 0.15) // Subtle dark outline border.width: 1 - visible: hasImage + visible: parent.hasImage } // Highlight ring to make it pop @@ -164,7 +164,7 @@ PanelWindow { color: "transparent" border.color: Qt.rgba(255, 255, 255, 0.1) // Subtle light ring border.width: 1 - visible: hasImage + visible: parent.hasImage } // Fallback icon for no profile picture (generic person) @@ -173,7 +173,7 @@ PanelWindow { text: "person" font.family: Theme.iconFont font.pixelSize: Theme.iconSize + 8 - color: Theme.onPrimary + color: Theme.primaryText visible: Prefs.profileImage === "" } @@ -183,7 +183,7 @@ PanelWindow { text: "warning" font.family: Theme.iconFont font.pixelSize: Theme.iconSize + 8 - color: Theme.onPrimary + color: Theme.primaryText visible: Prefs.profileImage !== "" && profileImage.status === Image.Error } } diff --git a/Widgets/PowerConfirmDialog.qml b/Widgets/PowerConfirmDialog.qml index aa4e8b58..50eb5c96 100644 --- a/Widgets/PowerConfirmDialog.qml +++ b/Widgets/PowerConfirmDialog.qml @@ -144,7 +144,7 @@ PanelWindow { Text { text: "Confirm" font.pixelSize: Theme.fontSizeMedium - color: Theme.onPrimary + color: Theme.primaryText font.weight: Font.Medium anchors.centerIn: parent } diff --git a/Widgets/ProcessListDropdown.qml b/Widgets/ProcessListDropdown.qml index 3acc1d9b..90419f95 100644 --- a/Widgets/ProcessListDropdown.qml +++ b/Widgets/ProcessListDropdown.qml @@ -245,8 +245,7 @@ PanelWindow { Row { id: columnHeaders Layout.fillWidth: true - anchors.left: parent.left - anchors.leftMargin: 8 + Layout.leftMargin: 8 spacing: 8 // Icon placeholder + Process name @@ -466,8 +465,8 @@ PanelWindow { } // Material 3 animations - opacity: menuVisible ? 1.0 : 0.0 - scale: menuVisible ? 1.0 : 0.85 + opacity: processContextMenuWindow.menuVisible ? 1.0 : 0.0 + scale: processContextMenuWindow.menuVisible ? 1.0 : 0.85 Behavior on opacity { NumberAnimation { diff --git a/Widgets/SettingsPopup.qml b/Widgets/SettingsPopup.qml index f83e5eea..0101479b 100644 --- a/Widgets/SettingsPopup.qml +++ b/Widgets/SettingsPopup.qml @@ -217,7 +217,7 @@ PanelWindow { text: profileImageInput.text === "" ? "person" : "warning" font.family: Theme.iconFont font.pixelSize: Theme.iconSize + 8 - color: Theme.onPrimary + color: Theme.primaryText visible: !avatarBox.hasImage } diff --git a/Widgets/SettingsToggle.qml b/Widgets/SettingsToggle.qml index 683fac63..e3955d66 100644 --- a/Widgets/SettingsToggle.qml +++ b/Widgets/SettingsToggle.qml @@ -80,7 +80,7 @@ Rectangle { radius: 10 anchors.verticalCenter: parent.verticalCenter x: root.checked ? parent.width - width - 2 : 2 - color: root.checked ? Theme.onPrimary : Theme.surfaceText + color: root.checked ? Theme.primaryText : Theme.surfaceText Behavior on x { NumberAnimation { diff --git a/Widgets/SpotlightLauncher.qml b/Widgets/SpotlightLauncher.qml index 80974f30..f3b8b4a0 100644 --- a/Widgets/SpotlightLauncher.qml +++ b/Widgets/SpotlightLauncher.qml @@ -22,7 +22,7 @@ PanelWindow { return result.concat(allCategories.filter(cat => cat !== "All")) } property string selectedCategory: "All" - property string viewMode: "list" // "list" or "grid" + property string viewMode: Prefs.spotlightLauncherViewMode // "list" or "grid" // Search debouncing Timer { @@ -510,7 +510,10 @@ PanelWindow { anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor - onClicked: viewMode = "list" + onClicked: { + viewMode = "list" + Prefs.setSpotlightLauncherViewMode("list") + } } } @@ -537,7 +540,10 @@ PanelWindow { anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor - onClicked: viewMode = "grid" + onClicked: { + viewMode = "grid" + Prefs.setSpotlightLauncherViewMode("grid") + } } } } @@ -598,19 +604,35 @@ PanelWindow { anchors.margins: Theme.spacingM spacing: Theme.spacingL - Rectangle { + Item { width: 40 height: 40 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) - border.width: 1 anchors.verticalCenter: parent.verticalCenter IconImage { + id: listIconImg anchors.fill: parent - anchors.margins: 4 source: model.icon ? Quickshell.iconPath(model.icon, "") : "" + smooth: true + asynchronous: true + visible: status === Image.Ready + } + + Rectangle { + anchors.fill: parent + visible: !listIconImg.visible + color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.10) + radius: Theme.cornerRadiusLarge + border.width: 1 + border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.20) + + Text { + anchors.centerIn: parent + text: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A" + font.pixelSize: 20 + color: Theme.primary + font.weight: Font.Bold + } } } @@ -650,56 +672,60 @@ PanelWindow { ScrollBar.vertical: ScrollBar { policy: ScrollBar.AlwaysOn } } - // Grid view - GridView { - id: resultsGrid - // Center the grid within the parent space - anchors.centerIn: parent - width: Math.min(parent.width, baseCellWidth * 6 + 16) // Optimal width for 6 columns plus spacing - height: parent.height - visible: viewMode === "grid" - model: filteredModel + // Grid view scroll container + ScrollView { + anchors.fill: parent clip: true - focus: spotlightOpen - interactive: true - flickDeceleration: 8000 - maximumFlickVelocity: 15000 + visible: viewMode === "grid" + ScrollBar.vertical.policy: ScrollBar.AsNeeded + ScrollBar.horizontal.policy: ScrollBar.AlwaysOff - // Optimized cell sizes for maximum space efficiency - 6 columns - property int baseCellWidth: Math.max(85, Math.min(100, width / 6)) - property int baseCellHeight: baseCellWidth + 30 - - cellWidth: baseCellWidth - cellHeight: baseCellHeight - - // Use full width with minimal 2px right margin for scrollbar - leftMargin: 0 - rightMargin: 2 - topMargin: Theme.spacingXS - bottomMargin: Theme.spacingXS - - // Make mouse wheel scrolling more responsive - property real wheelStepSize: 60 - - MouseArea { + GridView { + id: resultsGrid anchors.fill: parent - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - z: -1 + anchors.margins: Theme.spacingS - onWheel: (wheel) => { - var delta = wheel.angleDelta.y - var steps = delta / 120 // Standard wheel step - resultsGrid.contentY -= steps * resultsGrid.wheelStepSize + model: filteredModel + focus: spotlightOpen + interactive: true + flickDeceleration: 8000 + maximumFlickVelocity: 15000 + + // Responsive cell sizes based on screen width - wider cells for better fill + property int baseCellWidth: Math.max(120, Math.min(160, width / 6)) + property int baseCellHeight: baseCellWidth + 20 + + cellWidth: baseCellWidth + cellHeight: baseCellHeight + + // Center the grid content with better fill + property int columnsCount: Math.floor(width / cellWidth) + property int remainingSpace: width - (columnsCount * cellWidth) + leftMargin: Math.max(Theme.spacingXS, remainingSpace / 2) + rightMargin: leftMargin + + // Make mouse wheel scrolling more responsive + property real wheelStepSize: 60 + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + propagateComposedEvents: true + z: -1 - // Ensure we stay within bounds - if (resultsGrid.contentY < 0) { - resultsGrid.contentY = 0 - } else if (resultsGrid.contentY > resultsGrid.contentHeight - resultsGrid.height) { - resultsGrid.contentY = Math.max(0, resultsGrid.contentHeight - resultsGrid.height) + onWheel: (wheel) => { + var delta = wheel.angleDelta.y + var steps = delta / 120 // Standard wheel step + resultsGrid.contentY -= steps * resultsGrid.wheelStepSize + + // Ensure we stay within bounds + if (resultsGrid.contentY < 0) { + resultsGrid.contentY = 0 + } else if (resultsGrid.contentY > resultsGrid.contentHeight - resultsGrid.height) { + resultsGrid.contentY = Math.max(0, resultsGrid.contentHeight - resultsGrid.height) + } } } - } delegate: Rectangle { width: resultsGrid.cellWidth - 8 @@ -720,24 +746,36 @@ PanelWindow { height: iconSize anchors.horizontalCenter: parent.horizontalCenter + IconImage { + id: iconImg + anchors.fill: parent + source: model.icon ? Quickshell.iconPath(model.icon, "") : "" + smooth: true + asynchronous: true + visible: status === Image.Ready + } + Rectangle { anchors.fill: parent - radius: Theme.cornerRadius - color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) - border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) + visible: !iconImg.visible + color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.10) + radius: Theme.cornerRadiusLarge border.width: 1 - - IconImage { - anchors.fill: parent - anchors.margins: 4 - source: model.icon ? Quickshell.iconPath(model.icon, "") : "" + border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.20) + + Text { + anchors.centerIn: parent + text: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A" + font.pixelSize: Math.min(24, parent.width * 0.5) + color: Theme.primary + font.weight: Font.Bold } } } Text { anchors.horizontalCenter: parent.horizontalCenter - width: resultsGrid.cellWidth - 16 + width: resultsGrid.cellWidth - 12 text: model.name font.pixelSize: Theme.fontSizeSmall color: Theme.surfaceText @@ -759,10 +797,9 @@ PanelWindow { onClicked: launchApp(model) } } - - ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded } } } + } } } diff --git a/shell.qml b/shell.qml index f7f33724..0ab3381c 100644 --- a/shell.qml +++ b/shell.qml @@ -320,13 +320,6 @@ ShellRoot { onClipboardRequested: { clipboardHistoryPopup.toggle() } - - - onShowTrayMenuChanged: root.showTrayMenu = showTrayMenu - onCurrentTrayMenuChanged: root.currentTrayMenu = currentTrayMenu - onCurrentTrayItemChanged: root.currentTrayItem = currentTrayItem - onTrayMenuXChanged: root.trayMenuX = trayMenuX - onTrayMenuYChanged: root.trayMenuY = trayMenuY } }