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

mecha refactoring

This commit is contained in:
bbedward
2025-07-23 15:15:51 -04:00
parent 19adcf3578
commit c01da89311
37 changed files with 431 additions and 396 deletions

View File

@@ -116,7 +116,7 @@ shell.qml # Main entry point (minimal orchestration)
4. **Modules/** - UI components
- **Full-screen components**: AppLauncher, ClipboardHistoryModal, ControlCenter
- **Panel components**: TopBar, SystemTrayWidget, NotificationPopup
- **Panel components**: TopBar, SystemTray, NotificationPopup
- **Layout components**: WorkspaceSwitcher
5. **Widgets/** - Reusable UI controls

49
Common/Anims.qml Normal file
View File

@@ -0,0 +1,49 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
Singleton {
id: root
readonly property int durShort: 160
readonly property int durMed: 220
readonly property int durLong: 320
readonly property int slidePx: 100
readonly property QtObject direction: QtObject {
readonly property int fromLeft: 0
readonly property int fromRight: 1
readonly property int fadeOnly: 2
}
readonly property Component slideInLeft: Transition {
NumberAnimation { properties: "x"; from: -Anims.slidePx; to: 0; duration: Anims.durMed; easing.type: Easing.OutCubic }
NumberAnimation { properties: "opacity"; from: 0.0; to: 1.0; duration: Anims.durShort }
}
readonly property Component slideOutLeft: Transition {
NumberAnimation { properties: "x"; to: -Anims.slidePx; duration: Anims.durShort; easing.type: Easing.InCubic }
NumberAnimation { properties: "opacity"; to: 0.0; duration: Anims.durShort }
}
readonly property Component slideInRight: Transition {
NumberAnimation { properties: "x"; from: Anims.slidePx; to: 0; duration: Anims.durMed; easing.type: Easing.OutCubic }
NumberAnimation { properties: "opacity"; from: 0.0; to: 1.0; duration: Anims.durShort }
}
readonly property Component slideOutRight: Transition {
NumberAnimation { properties: "x"; to: Anims.slidePx; duration: Anims.durShort; easing.type: Easing.InCubic }
NumberAnimation { properties: "opacity"; to: 0.0; duration: Anims.durShort }
}
readonly property Component fadeIn: Transition {
NumberAnimation { properties: "opacity"; from: 0.0; to: 1.0; duration: Anims.durShort; easing.type: Easing.OutCubic }
}
readonly property Component fadeOut: Transition {
NumberAnimation { properties: "opacity"; to: 0.0; duration: Anims.durShort; easing.type: Easing.InCubic }
}
}

View File

@@ -31,7 +31,7 @@ Singleton {
property bool showWorkspaceIndex: false
property bool showWorkspacePadding: false
property string appLauncherViewMode: "list"
property string spotlightLauncherViewMode: "list"
property string spotlightModalViewMode: "list"
property string networkPreference: "auto"
property string iconTheme: "System Default"
property var availableIconThemes: ["System Default"]
@@ -70,7 +70,7 @@ Singleton {
showWorkspaceIndex = settings.showWorkspaceIndex !== undefined ? settings.showWorkspaceIndex : false;
showWorkspacePadding = settings.showWorkspacePadding !== undefined ? settings.showWorkspacePadding : false;
appLauncherViewMode = settings.appLauncherViewMode !== undefined ? settings.appLauncherViewMode : "list";
spotlightLauncherViewMode = settings.spotlightLauncherViewMode !== undefined ? settings.spotlightLauncherViewMode : "list";
spotlightModalViewMode = settings.spotlightModalViewMode !== undefined ? settings.spotlightModalViewMode : "list";
networkPreference = settings.networkPreference !== undefined ? settings.networkPreference : "auto";
iconTheme = settings.iconTheme !== undefined ? settings.iconTheme : "System Default";
useOSLogo = settings.useOSLogo !== undefined ? settings.useOSLogo : false;
@@ -112,7 +112,7 @@ Singleton {
"showWorkspaceIndex": showWorkspaceIndex,
"showWorkspacePadding": showWorkspacePadding,
"appLauncherViewMode": appLauncherViewMode,
"spotlightLauncherViewMode": spotlightLauncherViewMode,
"spotlightModalViewMode": spotlightModalViewMode,
"networkPreference": networkPreference,
"iconTheme": iconTheme,
"useOSLogo": useOSLogo,
@@ -277,8 +277,8 @@ Singleton {
saveSettings();
}
function setSpotlightLauncherViewMode(mode) {
spotlightLauncherViewMode = mode;
function setSpotlightModalViewMode(mode) {
spotlightModalViewMode = mode;
saveSettings();
}

View File

@@ -0,0 +1,46 @@
import QtQuick
import qs.Common
Item {
id: root
// attach to target
required property Item target
property int direction: Anims.direction.fadeOnly
// call these
function show() { _apply(true) }
function hide() { _apply(false) }
function _apply(showing) {
const off = Anims.slidePx
let fromX = 0
let toX = 0
switch(direction) {
case Anims.direction.fromLeft: fromX = -off; toX = 0; break
case Anims.direction.fromRight: fromX = off; toX = 0; break
default: fromX = 0; toX = 0;
}
if (showing) {
target.x = fromX
target.opacity = 0
target.visible = true
animX.from = fromX; animX.to = toX
animO.from = 0; animO.to = 1
} else {
animX.from = target.x; animX.to = (direction === Anims.direction.fromLeft ? -off :
direction === Anims.direction.fromRight ? off : 0)
animO.from = target.opacity; animO.to = 0
}
seq.restart()
}
SequentialAnimation {
id: seq
ParallelAnimation {
NumberAnimation { id: animX; target: root.target; property: "x"; duration: Anims.durMed; easing.type: Easing.OutCubic }
NumberAnimation { id: animO; target: root.target; property: "opacity"; duration: Anims.durShort }
}
ScriptAction { script: if (root.target.opacity === 0) root.target.visible = false }
}
}

View File

@@ -3,7 +3,6 @@ import QtQuick.Effects
import Quickshell
import Quickshell.Wayland
import qs.Common
import qs.Widgets
PanelWindow {
id: root

View File

@@ -10,7 +10,7 @@ import qs.Widgets
DankModal {
id: root
property bool networkInfoDialogVisible: false
property bool networkInfoModalVisible: false
property string networkSSID: ""
property var networkData: null
property string networkDetails: ""
@@ -18,18 +18,18 @@ DankModal {
function showNetworkInfo(ssid, data) {
networkSSID = ssid;
networkData = data;
networkInfoDialogVisible = true;
networkInfoModalVisible = true;
WifiService.fetchNetworkInfo(ssid);
}
function hideDialog() {
networkInfoDialogVisible = false;
networkInfoModalVisible = false;
networkSSID = "";
networkData = null;
networkDetails = "";
}
visible: networkInfoDialogVisible
visible: networkInfoModalVisible
width: 600
height: 500
enableShadow: true

View File

@@ -9,6 +9,7 @@ import Quickshell.Widgets
import qs.Common
import qs.Services
import qs.Widgets
import qs.Modules.ProcessList
DankModal {
id: processListModal

View File

@@ -2,6 +2,7 @@ import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Widgets
import qs.Modules.Settings
DankModal {
id: settingsModal

View File

@@ -8,7 +8,7 @@ import qs.Services
import qs.Widgets
DankModal {
id: spotlightLauncher
id: spotlightModal
property bool spotlightOpen: false
property var filteredApps: []
@@ -25,13 +25,13 @@ DankModal {
}));
}
property string selectedCategory: "All"
property string viewMode: Prefs.spotlightLauncherViewMode // "list" or "grid"
property string viewMode: Prefs.spotlightModalViewMode // "list" or "grid"
property int gridColumns: 4
function show() {
console.log("SpotlightLauncher: show() called");
console.log("SpotlightModal: show() called");
spotlightOpen = true;
console.log("SpotlightLauncher: spotlightOpen set to", spotlightOpen);
console.log("SpotlightModal: spotlightOpen set to", spotlightOpen);
searchDebounceTimer.stop(); // Stop any pending search
updateFilteredApps(); // Immediate update when showing
}
@@ -208,7 +208,7 @@ DankModal {
enableShadow: true
onVisibleChanged: {
console.log("SpotlightLauncher visibility changed to:", visible);
console.log("SpotlightModal visibility changed to:", visible);
if (visible && !spotlightOpen) {
show();
}
@@ -219,7 +219,7 @@ DankModal {
}
Component.onCompleted: {
console.log("SpotlightLauncher: Component.onCompleted called - component loaded successfully!");
console.log("SpotlightModal: Component.onCompleted called - component loaded successfully!");
var allCategories = AppSearchService.getAllCategories().filter((cat) => {
return cat !== "Education" && cat !== "Science";
});
@@ -405,7 +405,7 @@ DankModal {
}
Connections {
target: spotlightLauncher
target: spotlightModal
function onOpened() {
searchField.forceActiveFocus();
}
@@ -464,7 +464,7 @@ DankModal {
cursorShape: Qt.PointingHandCursor
onClicked: {
viewMode = "list";
Prefs.setSpotlightLauncherViewMode("list");
Prefs.setSpotlightModalViewMode("list");
}
}
}
@@ -493,7 +493,7 @@ DankModal {
cursorShape: Qt.PointingHandCursor
onClicked: {
viewMode = "grid";
Prefs.setSpotlightLauncherViewMode("grid");
Prefs.setSpotlightModalViewMode("grid");
}
}
}
@@ -557,20 +557,20 @@ DankModal {
IpcHandler {
function open() {
console.log("SpotlightLauncher: IPC open() called");
spotlightLauncher.show();
console.log("SpotlightModal: IPC open() called");
spotlightModal.show();
return "SPOTLIGHT_OPEN_SUCCESS";
}
function close() {
console.log("SpotlightLauncher: IPC close() called");
spotlightLauncher.hide();
console.log("SpotlightModal: IPC close() called");
spotlightModal.hide();
return "SPOTLIGHT_CLOSE_SUCCESS";
}
function toggle() {
console.log("SpotlightLauncher: IPC toggle() called");
spotlightLauncher.toggle();
console.log("SpotlightModal: IPC toggle() called");
spotlightModal.toggle();
return "SPOTLIGHT_TOGGLE_SUCCESS";
}

View File

@@ -7,11 +7,11 @@ import qs.Widgets
DankModal {
id: root
property bool wifiPasswordDialogVisible: false
property bool wifiPasswordModalVisible: false
property string wifiPasswordSSID: ""
property string wifiPasswordInput: ""
visible: wifiPasswordDialogVisible
visible: wifiPasswordModalVisible
width: 420
height: 230
keyboardFocus: "ondemand"
@@ -21,7 +21,7 @@ DankModal {
}
onBackgroundClicked: {
wifiPasswordDialogVisible = false;
wifiPasswordModalVisible = false;
wifiPasswordInput = "";
}
@@ -31,7 +31,7 @@ DankModal {
if (WifiService.passwordDialogShouldReopen && WifiService.connectingSSID !== "") {
wifiPasswordSSID = WifiService.connectingSSID;
wifiPasswordInput = "";
wifiPasswordDialogVisible = true;
wifiPasswordModalVisible = true;
WifiService.passwordDialogShouldReopen = false;
}
}
@@ -79,7 +79,7 @@ DankModal {
iconColor: Theme.surfaceText
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12)
onClicked: {
wifiPasswordDialogVisible = false;
wifiPasswordModalVisible = false;
wifiPasswordInput = "";
}
}
@@ -112,7 +112,7 @@ DankModal {
}
onAccepted: {
WifiService.connectToWifiWithPassword(wifiPasswordSSID, passwordInput.text);
wifiPasswordDialogVisible = false;
wifiPasswordModalVisible = false;
wifiPasswordInput = "";
passwordInput.text = "";
}
@@ -212,7 +212,7 @@ DankModal {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
wifiPasswordDialogVisible = false;
wifiPasswordModalVisible = false;
wifiPasswordInput = "";
}
}
@@ -246,7 +246,7 @@ DankModal {
enabled: parent.enabled
onClicked: {
WifiService.connectToWifiWithPassword(wifiPasswordSSID, passwordInput.text);
wifiPasswordDialogVisible = false;
wifiPasswordModalVisible = false;
wifiPasswordInput = "";
passwordInput.text = "";
}

View File

@@ -6,7 +6,7 @@ import qs.Services
import qs.Widgets
Column {
id: calendarWidget
id: calendarGrid
property date displayDate: new Date()
property date selectedDate: new Date()

View File

@@ -7,7 +7,7 @@ import qs.Widgets
// Events widget for selected date - Material Design 3 style
Rectangle {
id: eventsWidget
id: events
property date selectedDate: new Date()
property var selectedDateEvents: []
@@ -17,7 +17,7 @@ Rectangle {
function updateSelectedDateEvents() {
if (CalendarService && CalendarService.khalAvailable) {
let events = CalendarService.getEventsForDate(selectedDate);
console.log("EventsWidget: Updating events for", Qt.formatDate(selectedDate, "yyyy-MM-dd"), "found", events.length, "events");
console.log("Events: Updating events for", Qt.formatDate(selectedDate, "yyyy-MM-dd"), "found", events.length, "events");
selectedDateEvents = events;
} else {
selectedDateEvents = [];
@@ -25,7 +25,7 @@ Rectangle {
}
onSelectedDateEventsChanged: {
console.log("EventsWidget: selectedDateEvents changed, count:", selectedDateEvents.length);
console.log("Events: selectedDateEvents changed, count:", selectedDateEvents.length);
eventsList.model = selectedDateEvents;
}
width: parent.width

View File

@@ -8,7 +8,7 @@ import qs.Services
import qs.Widgets
Rectangle {
id: mediaPlayerWidget
id: mediaPlayer
property MprisPlayer activePlayer: MprisController.activePlayer
property string lastValidTitle: ""

View File

@@ -6,7 +6,7 @@ import qs.Services
import qs.Widgets
Rectangle {
id: weatherWidget
id: weather
width: parent.width
height: parent.height

View File

@@ -13,8 +13,8 @@ Rectangle {
property var networkData: null
property bool menuVisible: false
property var parentItem
property var wifiPasswordDialogRef
property var networkInfoDialogRef
property var wifiPasswordModalRef
property var networkInfoModalRef
function show(x, y) {
const menuWidth = 160;
@@ -123,10 +123,10 @@ Rectangle {
if (wifiContextMenuWindow.networkData.saved) {
WifiService.connectToWifi(wifiContextMenuWindow.networkData.ssid);
} else if (wifiContextMenuWindow.networkData.secured) {
if (wifiPasswordDialogRef) {
wifiPasswordDialogRef.wifiPasswordSSID = wifiContextMenuWindow.networkData.ssid;
wifiPasswordDialogRef.wifiPasswordInput = "";
wifiPasswordDialogRef.wifiPasswordDialogVisible = true;
if (wifiPasswordModalRef) {
wifiPasswordModalRef.wifiPasswordSSID = wifiContextMenuWindow.networkData.ssid;
wifiPasswordModalRef.wifiPasswordInput = "";
wifiPasswordModalRef.wifiPasswordModalVisible = true;
}
} else {
WifiService.connectToWifi(wifiContextMenuWindow.networkData.ssid);
@@ -248,8 +248,8 @@ Rectangle {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (wifiContextMenuWindow.networkData && networkInfoDialogRef) {
networkInfoDialogRef.showNetworkInfo(wifiContextMenuWindow.networkData.ssid, wifiContextMenuWindow.networkData);
if (wifiContextMenuWindow.networkData && networkInfoModalRef) {
networkInfoModalRef.showNetworkInfo(wifiContextMenuWindow.networkData.ssid, wifiContextMenuWindow.networkData);
}
wifiContextMenuWindow.hide();
}

View File

@@ -12,7 +12,7 @@ Column {
property var wifiContextMenuWindow
property var sortedWifiNetworks
property var wifiPasswordDialogRef
property var wifiPasswordModalRef
function getWiFiSignalIcon(signalStrength) {
switch (signalStrength) {
@@ -255,10 +255,10 @@ Column {
if (modelData.saved) {
WifiService.connectToWifi(modelData.ssid);
} else if (modelData.secured) {
if (wifiPasswordDialogRef) {
wifiPasswordDialogRef.wifiPasswordSSID = modelData.ssid;
wifiPasswordDialogRef.wifiPasswordInput = "";
wifiPasswordDialogRef.wifiPasswordDialogVisible = true;
if (wifiPasswordModalRef) {
wifiPasswordModalRef.wifiPasswordSSID = modelData.ssid;
wifiPasswordModalRef.wifiPasswordInput = "";
wifiPasswordModalRef.wifiPasswordModalVisible = true;
}
} else {
WifiService.connectToWifi(modelData.ssid);

View File

@@ -11,8 +11,8 @@ import qs.Modules.ControlCenter.Network
Item {
id: networkTab
property var wifiPasswordDialogRef: wifiPasswordDialog
property var networkInfoDialogRef: networkInfoDialog
property var wifiPasswordModalRef: wifiPasswordModal
property var networkInfoModalRef: networkInfoModal
// Properly sorted WiFi networks with connected networks first
property var sortedWifiNetworks: {
@@ -188,7 +188,7 @@ Item {
WiFiNetworksList {
wifiContextMenuWindow: wifiContextMenuWindow
sortedWifiNetworks: networkTab.sortedWifiNetworks
wifiPasswordDialogRef: networkTab.wifiPasswordDialogRef
wifiPasswordModalRef: networkTab.wifiPasswordModalRef
}
// Timer for refreshing network status after WiFi toggle
@@ -312,8 +312,8 @@ Item {
WiFiContextMenu {
id: wifiContextMenuWindow
parentItem: networkTab
wifiPasswordDialogRef: networkTab.wifiPasswordDialogRef
networkInfoDialogRef: networkTab.networkInfoDialogRef
wifiPasswordModalRef: networkTab.wifiPasswordModalRef
networkInfoModalRef: networkTab.networkInfoModalRef
}
// Background MouseArea to close the context menu

View File

@@ -12,7 +12,7 @@ import qs.Widgets
PanelWindow {
// For recents, use the recent apps from Prefs and filter out non-existent ones
id: launcher
id: appDrawerPopout
property bool isVisible: false
// App management
@@ -125,9 +125,9 @@ PanelWindow {
Prefs.addRecentApp(selectedApp.desktopEntry);
selectedApp.desktopEntry.execute();
} else {
launcher.launchApp(selectedApp.exec);
appDrawerPopout.launchApp(selectedApp.exec);
}
launcher.hide();
appDrawerPopout.hide();
}
}
@@ -145,7 +145,7 @@ PanelWindow {
}
function show() {
launcher.isVisible = true;
appDrawerPopout.isVisible = true;
searchField.enabled = true;
searchDebounceTimer.stop(); // Stop any pending search
updateFilteredModel();
@@ -153,14 +153,14 @@ PanelWindow {
function hide() {
searchField.enabled = false; // Disable before hiding to prevent Wayland warnings
launcher.isVisible = false;
appDrawerPopout.isVisible = false;
searchDebounceTimer.stop(); // Stop any pending search
searchField.text = "";
showCategories = false;
}
function toggle() {
if (launcher.isVisible)
if (appDrawerPopout.isVisible)
hide();
else
show();
@@ -207,13 +207,13 @@ PanelWindow {
Rectangle {
anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.3)
opacity: launcher.isVisible ? 1 : 0
visible: launcher.isVisible
opacity: appDrawerPopout.isVisible ? 1 : 0
visible: appDrawerPopout.isVisible
MouseArea {
anchors.fill: parent
enabled: launcher.isVisible
onClicked: launcher.hide()
enabled: appDrawerPopout.isVisible
onClicked: appDrawerPopout.hide()
}
Behavior on opacity {
@@ -273,66 +273,15 @@ PanelWindow {
height: 600
color: Theme.popupBackground()
radius: Theme.cornerRadiusXLarge
opacity: launcher.isVisible ? 1 : 0
// Animated entrance with spring effect
transform: [
Scale {
id: scaleTransform
origin.x: 0
origin.y: 0
xScale: launcher.isVisible ? 1 : 0.92
yScale: launcher.isVisible ? 1 : 0.92
Behavior on xScale {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Easing.OutBack
easing.overshoot: 1.2
}
}
Behavior on yScale {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Easing.OutBack
easing.overshoot: 1.2
}
}
},
Translate {
id: translateTransform
x: launcher.isVisible ? 0 : -30
y: launcher.isVisible ? 0 : -15
opacity: appDrawerPopout.isVisible ? 1 : 0
x: appDrawerPopout.isVisible ? Theme.spacingL : Theme.spacingL - Anims.slidePx
y: Theme.barHeight + Theme.spacingXS
Behavior on x {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
duration: Anims.durMed
easing.type: Easing.OutCubic
}
}
Behavior on y {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
]
anchors {
top: parent.top
left: parent.left
topMargin: Theme.barHeight + Theme.spacingXS
leftMargin: Theme.spacingL
}
// Material 3 elevation with multiple layers
@@ -370,14 +319,14 @@ PanelWindow {
anchors.fill: parent
focus: true
Component.onCompleted: {
if (launcher.isVisible)
if (appDrawerPopout.isVisible)
forceActiveFocus();
}
// Handle keyboard shortcuts
Keys.onPressed: function(event) {
if (event.key === Qt.Key_Escape) {
launcher.hide();
appDrawerPopout.hide();
event.accepted = true;
} else if (event.key === Qt.Key_Down) {
selectNext();
@@ -452,7 +401,7 @@ PanelWindow {
leftIconFocusedColor: Theme.primary
showClearButton: true
font.pixelSize: Theme.fontSizeLarge
enabled: launcher.isVisible
enabled: appDrawerPopout.isVisible
placeholderText: "Search applications..."
onTextEdited: {
searchDebounceTimer.restart();
@@ -465,9 +414,9 @@ PanelWindow {
Prefs.addRecentApp(firstApp.desktopEntry);
firstApp.desktopEntry.execute();
} else {
launcher.launchApp(firstApp.exec);
appDrawerPopout.launchApp(firstApp.exec);
}
launcher.hide();
appDrawerPopout.hide();
event.accepted = true;
} else if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || (event.key === Qt.Key_Left && viewMode === "grid") || (event.key === Qt.Key_Right && viewMode === "grid") || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) {
// Pass navigation keys and enter (when not searching) to main handler
@@ -477,13 +426,13 @@ PanelWindow {
Connections {
function onVisibleChanged() {
if (launcher.visible)
if (appDrawerPopout.visible)
searchField.forceActiveFocus();
else
searchField.clearFocus();
}
target: launcher
target: appDrawerPopout
}
}
@@ -621,9 +570,9 @@ PanelWindow {
Prefs.addRecentApp(modelData.desktopEntry);
modelData.desktopEntry.execute();
} else {
launcher.launchApp(modelData.exec);
appDrawerPopout.launchApp(modelData.exec);
}
launcher.hide();
appDrawerPopout.hide();
}
onItemHovered: function(index) {
selectedIndex = index;
@@ -646,9 +595,9 @@ PanelWindow {
Prefs.addRecentApp(modelData.desktopEntry);
modelData.desktopEntry.execute();
} else {
launcher.launchApp(modelData.exec);
appDrawerPopout.launchApp(modelData.exec);
}
launcher.hide();
appDrawerPopout.hide();
}
onItemHovered: function(index) {
selectedIndex = index;
@@ -768,10 +717,9 @@ PanelWindow {
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
duration: Anims.durShort
easing.type: Easing.OutCubic
}
}
}

View File

@@ -54,16 +54,18 @@ PanelWindow {
}
Rectangle {
width: Math.min(380, parent.width - Theme.spacingL * 2)
height: Math.min(450, parent.height - Theme.barHeight - Theme.spacingS * 2)
x: Math.max(Theme.spacingL, parent.width - width - Theme.spacingL)
readonly property real targetWidth: Math.min(380, Screen.width - Theme.spacingL * 2)
readonly property real targetHeight: Math.min(450, Screen.height - Theme.barHeight - Theme.spacingS * 2)
width: targetWidth
height: targetHeight
property real normalX: Math.max(Theme.spacingL, Screen.width - targetWidth - Theme.spacingL)
x: batteryPopupVisible ? normalX : normalX + Anims.slidePx
y: Theme.barHeight + Theme.spacingS
color: Theme.popupBackground()
radius: Theme.cornerRadiusLarge
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
opacity: batteryPopupVisible ? 1 : 0
scale: batteryPopupVisible ? 1 : 0.85
// Prevent click-through to background
MouseArea {
@@ -352,8 +354,8 @@ PanelWindow {
width: parent.width
height: 50
radius: Theme.cornerRadius
color: profileArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : (batteryControlPopup.isActiveProfile(modelData) ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
border.color: batteryControlPopup.isActiveProfile(modelData) ? Theme.primary : "transparent"
color: profileArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : (batteryPopout.isActiveProfile(modelData) ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
border.color: batteryPopout.isActiveProfile(modelData) ? Theme.primary : "transparent"
border.width: 2
Row {
@@ -365,7 +367,7 @@ PanelWindow {
DankIcon {
name: Theme.getPowerProfileIcon(modelData)
size: Theme.iconSize
color: batteryControlPopup.isActiveProfile(modelData) ? Theme.primary : Theme.surfaceText
color: batteryPopout.isActiveProfile(modelData) ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
@@ -376,8 +378,8 @@ PanelWindow {
Text {
text: Theme.getPowerProfileLabel(modelData)
font.pixelSize: Theme.fontSizeMedium
color: batteryControlPopup.isActiveProfile(modelData) ? Theme.primary : Theme.surfaceText
font.weight: batteryControlPopup.isActiveProfile(modelData) ? Font.Medium : Font.Normal
color: batteryPopout.isActiveProfile(modelData) ? Theme.primary : Theme.surfaceText
font.weight: batteryPopout.isActiveProfile(modelData) ? Font.Medium : Font.Normal
}
Text {
@@ -397,7 +399,7 @@ PanelWindow {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
batteryControlPopup.setProfile(modelData);
batteryPopout.setProfile(modelData);
}
}
@@ -461,18 +463,16 @@ PanelWindow {
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
duration: Anims.durShort
easing.type: Easing.OutCubic
}
}
}
Behavior on scale {
Behavior on x {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
duration: Anims.durMed
easing.type: Easing.OutCubic
}
}
}

View File

@@ -7,19 +7,33 @@ import Quickshell.Wayland
import Quickshell.Widgets
import qs.Common
import qs.Services
import qs.Modules.CentcomCenter
PanelWindow {
id: root
readonly property bool hasActiveMedia: MprisController.activePlayer !== null
property bool calendarVisible: false
property bool internalVisible: false
visible: calendarVisible
visible: internalVisible
onCalendarVisibleChanged: {
if (calendarVisible) {
internalVisible = true
Qt.callLater(() => {
// This ensures opacity changes after window is visible
internalVisible = true // Force re-trigger if needed
})
} else {
internalVisible = false
}
}
onVisibleChanged: {
if (visible && CalendarService)
CalendarService.loadCurrentMonth();
}
implicitWidth: 480
implicitHeight: 600
WlrLayershell.layer: WlrLayershell.Overlay
@@ -57,24 +71,31 @@ PanelWindow {
contentHeight += mainRowHeight + Theme.spacingM;
// Add events widget height - use calculated height instead of actual
if (CalendarService && CalendarService.khalAvailable) {
let hasEvents = eventsWidget.selectedDateEvents && eventsWidget.selectedDateEvents.length > 0;
let eventsHeight = hasEvents ? Math.min(300, 80 + eventsWidget.selectedDateEvents.length * 60) : 120;
let hasEvents = events.selectedDateEvents && events.selectedDateEvents.length > 0;
let eventsHeight = hasEvents ? Math.min(300, 80 + events.selectedDateEvents.length * 60) : 120;
contentHeight += eventsHeight;
}
return Math.min(contentHeight, parent.height * 0.9);
}
width: calculateWidth()
readonly property real targetWidth: Math.min(Screen.width * 0.9, 600)
width: targetWidth
height: calculateHeight()
x: (parent.width - width) / 2
y: Theme.barHeight + 4
color: Theme.surfaceContainer
radius: Theme.cornerRadiusLarge
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
layer.enabled: true
opacity: calendarVisible ? 1 : 0
scale: calendarVisible ? 1 : 0.92
x: (Screen.width - targetWidth) / 2
y: Theme.barHeight + 4
Behavior on opacity {
NumberAnimation {
duration: Anims.durShort
easing.type: Easing.OutCubic
}
}
Rectangle {
anchors.fill: parent
@@ -101,7 +122,6 @@ PanelWindow {
}
// Update height when calendar service events change
Connections {
function onEventsByDateChanged() {
mainContainer.height = mainContainer.calculateHeight();
@@ -115,16 +135,16 @@ PanelWindow {
enabled: CalendarService !== null
}
// Update height when events widget's selectedDateEvents changes
Connections {
function onSelectedDateEventsChanged() {
mainContainer.height = mainContainer.calculateHeight();
}
target: eventsWidget
enabled: eventsWidget !== null
target: events
enabled: events !== null
}
Column {
anchors.fill: parent
anchors.margins: Theme.spacingM
@@ -153,13 +173,13 @@ PanelWindow {
visible: hasAnyWidgets
anchors.top: parent.top
MediaPlayerWidget {
MediaPlayer {
visible: true // Always visible - shows placeholder when no media
width: parent.width
height: 160
}
WeatherWidget {
Weather {
visible: true // Always visible - shows placeholder when no weather
width: parent.width
height: 140
@@ -168,8 +188,8 @@ PanelWindow {
}
// Right section for calendar
CalendarWidget {
id: calendarWidget
CalendarGrid {
id: calendarGrid
width: leftWidgets.hasAnyWidgets ? parent.width * 0.55 - Theme.spacingL : parent.width
height: parent.height
@@ -178,11 +198,11 @@ PanelWindow {
}
// Full-width events widget below
EventsWidget {
id: eventsWidget
Events {
id: events
width: parent.width
selectedDate: calendarWidget.selectedDate
selectedDate: calendarGrid.selectedDate
}
}
@@ -196,35 +216,14 @@ PanelWindow {
shadowOpacity: 0.15
}
Behavior on opacity {
NumberAnimation {
duration: Theme.longDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on scale {
NumberAnimation {
duration: Theme.longDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on height {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.standardEasing
}
}
}
MouseArea {
anchors.fill: parent
z: -1
enabled: calendarVisible
onClicked: {
calendarVisible = false;
}

View File

@@ -1,4 +1,3 @@
import "../../Widgets"
import QtQuick
import QtQuick.Controls
import QtQuick.Effects
@@ -10,6 +9,7 @@ import Quickshell.Widgets
import qs.Common
import qs.Services
import qs.Widgets
import qs.Modules.ControlCenter
PanelWindow {
id: root
@@ -48,87 +48,25 @@ PanelWindow {
}
Rectangle {
width: Math.min(600, Screen.width - Theme.spacingL * 2)
readonly property real targetWidth: Math.min(600, Screen.width - Theme.spacingL * 2)
width: targetWidth
height: root.powerOptionsExpanded ? 570 : 500
x: Math.max(Theme.spacingL, Screen.width - width - Theme.spacingL)
y: Theme.barHeight + Theme.spacingXS
color: Theme.popupBackground()
radius: Theme.cornerRadiusLarge
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
opacity: controlCenterVisible ? 1 : 0
// TopBar dropdown animation - optimized for performance
transform: [
Scale {
id: scaleTransform
property real normalX: Math.max(Theme.spacingL, Screen.width - targetWidth - Theme.spacingL)
x: controlCenterVisible ? normalX : normalX + Anims.slidePx
origin.x: 600 // Use fixed width since popup is max 600px wide
origin.y: 0
xScale: controlCenterVisible ? 1 : 0.95
yScale: controlCenterVisible ? 1 : 0.8
},
Translate {
id: translateTransform
x: controlCenterVisible ? 0 : 15 // Slide slightly left when hidden
y: controlCenterVisible ? 0 : -30
}
]
// Single coordinated animation for better performance
states: [
State {
name: "visible"
when: controlCenterVisible
PropertyChanges {
target: scaleTransform
xScale: 1
yScale: 1
}
PropertyChanges {
target: translateTransform
x: 0
y: 0
}
},
State {
name: "hidden"
when: !controlCenterVisible
PropertyChanges {
target: scaleTransform
xScale: 0.95
yScale: 0.8
}
PropertyChanges {
target: translateTransform
x: 15
y: -30
}
}
]
transitions: [
Transition {
from: "*"
to: "*"
ParallelAnimation {
Behavior on x {
NumberAnimation {
targets: [scaleTransform, translateTransform]
properties: "xScale,yScale,x,y"
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
duration: Anims.durMed
easing.type: Easing.OutCubic
}
}
}
]
ColumnLayout {
anchors.fill: parent
anchors.margins: Theme.spacingL
@@ -720,10 +658,9 @@ PanelWindow {
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
duration: Anims.durShort
easing.type: Easing.OutCubic
}
}
}

View File

@@ -9,9 +9,10 @@ import Quickshell.Widgets
import qs.Common
import qs.Services
import qs.Widgets
import qs.Modules.ProcessList
PanelWindow {
id: processListDropdown
id: processListPopout
property bool isVisible: false
property var parentWidget: null
@@ -53,74 +54,34 @@ PanelWindow {
MouseArea {
anchors.fill: parent
onClicked: processListDropdown.hide()
onClicked: processListPopout.hide()
}
Rectangle {
id: dropdownContent
width: Math.min(600, Screen.width - Theme.spacingL * 2)
height: Math.min(600, Screen.height - Theme.barHeight - Theme.spacingS * 2)
x: Math.max(Theme.spacingL, Screen.width - width - Theme.spacingL)
readonly property real targetWidth: Math.min(600, Screen.width - Theme.spacingL * 2)
readonly property real targetHeight: Math.min(600, Screen.height - Theme.barHeight - Theme.spacingS * 2)
width: targetWidth
height: targetHeight
y: Theme.barHeight + Theme.spacingXS
radius: Theme.cornerRadiusLarge
color: Theme.popupBackground()
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1
clip: true
opacity: processListDropdown.isVisible ? 1 : 0
opacity: processListPopout.isVisible ? 1 : 0
layer.enabled: true
transform: [
Scale {
id: scaleTransform
origin.x: dropdownContent.width * 0.85
origin.y: 0
xScale: processListDropdown.isVisible ? 1 : 0.95
yScale: processListDropdown.isVisible ? 1 : 0.8
Behavior on xScale {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on yScale {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
},
Translate {
id: translateTransform
x: processListDropdown.isVisible ? 0 : 20
y: processListDropdown.isVisible ? 0 : -30
property real normalX: Math.max(Theme.spacingL, Screen.width - targetWidth - Theme.spacingL)
x: processListPopout.isVisible ? normalX : normalX + Anims.slidePx
Behavior on x {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
duration: Anims.durMed
easing.type: Easing.OutCubic
}
}
Behavior on y {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
]
MouseArea {
anchors.fill: parent
@@ -157,15 +118,14 @@ PanelWindow {
shadowVerticalOffset: 8
shadowBlur: 1
shadowColor: Qt.rgba(0, 0, 0, 0.15)
shadowOpacity: processListDropdown.isVisible ? 0.15 : 0
shadowOpacity: processListPopout.isVisible ? 0.15 : 0
}
Behavior on opacity {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
duration: Anims.durShort
easing.type: Easing.OutCubic
}
}
}

View File

@@ -16,13 +16,16 @@ ScrollView {
Rectangle {
width: parent.width
height: 200
height: systemInfoColumn.implicitHeight + 2 * Theme.spacingL
radius: Theme.cornerRadiusLarge
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.6)
border.width: 0
Column {
anchors.fill: parent
id: systemInfoColumn
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Theme.spacingL
spacing: Theme.spacingL
@@ -95,7 +98,8 @@ ScrollView {
Text {
text: SystemMonitorService.motherboard
font.pixelSize: Theme.fontSizeSmall
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
font.weight: Font.Medium
color: Theme.surfaceText
width: parent.width
elide: Text.ElideRight
}
@@ -118,7 +122,8 @@ ScrollView {
Text {
text: "BIOS " + SystemMonitorService.biosVersion
font.pixelSize: Theme.fontSizeSmall
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
font.weight: Font.Medium
color: Theme.surfaceText
width: parent.width
elide: Text.ElideRight
}
@@ -134,13 +139,16 @@ ScrollView {
Rectangle {
width: parent.width
height: Math.max(180, diskMountRepeater.count * 28 + 100)
height: storageColumn.implicitHeight + 2 * Theme.spacingL
radius: Theme.cornerRadiusLarge
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.6)
border.width: 0
Column {
anchors.fill: parent
id: storageColumn
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Theme.spacingL
spacing: Theme.spacingS
@@ -173,13 +181,6 @@ ScrollView {
elide: Text.ElideRight
}
ScrollView {
width: parent.width
height: Math.max(120, diskMountRepeater.count * 28 + 50)
clip: true
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
Column {
width: parent.width
spacing: 2
@@ -345,5 +346,3 @@ ScrollView {
}
}
}

View File

@@ -5,7 +5,7 @@ import qs.Services
import qs.Widgets
Rectangle {
id: batteryWidget
id: battery
property bool batteryPopupVisible: false

View File

@@ -6,7 +6,7 @@ import qs.Services
import qs.Widgets
Rectangle {
id: cpuWidget
id: cpuMonitor
property bool showPercentage: true
property bool showIcon: true
@@ -24,7 +24,7 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onClicked: {
ProcessMonitorService.setSortBy("cpu");
processListDropdown.toggle();
processListPopout.toggle();
}
}

View File

@@ -6,7 +6,7 @@ import qs.Services
import qs.Widgets
Rectangle {
id: ramWidget
id: ramMonitor
property bool showPercentage: true
property bool showIcon: true
@@ -24,7 +24,7 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onClicked: {
ProcessMonitorService.setSortBy("memory");
processListDropdown.toggle();
processListPopout.toggle();
}
}

View File

@@ -133,9 +133,9 @@ PanelWindow {
LauncherButton {
anchors.verticalCenter: parent.verticalCenter
isActive: appLauncher.isVisible
isActive: appDrawerPopout.isVisible
onClicked: {
appLauncher.toggle();
appDrawerPopout.toggle();
}
}
@@ -144,41 +144,41 @@ PanelWindow {
screenName: root.screenName
}
FocusedAppWidget {
FocusedApp {
anchors.verticalCenter: parent.verticalCenter
visible: Prefs.showFocusedWindow
}
}
ClockWidget {
id: clockWidget
Clock {
id: clock
anchors.centerIn: parent
onClockClicked: {
centcomCenter.calendarVisible = !centcomCenter.calendarVisible;
centcomPopout.calendarVisible = !centcomPopout.calendarVisible;
}
}
MediaWidget {
Media {
anchors.verticalCenter: parent.verticalCenter
anchors.right: clockWidget.left
anchors.rightMargin: Theme.spacingS
visible: Prefs.showMusic && MprisController.activePlayer
onClicked: {
centcomCenter.calendarVisible = !centcomCenter.calendarVisible;
centcomPopout.calendarVisible = !centcomPopout.calendarVisible;
}
}
WeatherWidget {
id: weatherWidget
Weather {
id: weather
anchors.verticalCenter: parent.verticalCenter
anchors.left: clockWidget.right
anchors.left: clock.right
anchors.leftMargin: Theme.spacingS
visible: Prefs.showWeather && WeatherService.weather.available && WeatherService.weather.temp > 0 && WeatherService.weather.tempF > 0
onClicked: {
centcomCenter.calendarVisible = !centcomCenter.calendarVisible;
centcomPopout.calendarVisible = !centcomPopout.calendarVisible;
}
}
@@ -190,7 +190,7 @@ PanelWindow {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
SystemTrayWidget {
SystemTrayBar {
anchors.verticalCenter: parent.verticalCenter
visible: Prefs.showSystemTray
onMenuRequested: (menu, item, x, y) => {
@@ -240,12 +240,12 @@ PanelWindow {
}
// System Monitor Widgets
CpuMonitorWidget {
CpuMonitor {
anchors.verticalCenter: parent.verticalCenter
visible: Prefs.showSystemResources
}
RamMonitorWidget {
RamMonitor {
anchors.verticalCenter: parent.verticalCenter
visible: Prefs.showSystemResources
}
@@ -260,11 +260,11 @@ PanelWindow {
}
// Battery Widget
BatteryWidget {
Battery {
anchors.verticalCenter: parent.verticalCenter
batteryPopupVisible: batteryControlPopup.batteryPopupVisible
batteryPopupVisible: batteryPopout.batteryPopupVisible
onToggleBatteryPopup: {
batteryControlPopup.batteryPopupVisible = !batteryControlPopup.batteryPopupVisible;
batteryPopout.batteryPopupVisible = !batteryPopout.batteryPopupVisible;
}
}
@@ -272,10 +272,10 @@ PanelWindow {
// Bluetooth devices are automatically updated via signals
anchors.verticalCenter: parent.verticalCenter
isActive: controlCenter.controlCenterVisible
isActive: controlCenterPopout.controlCenterVisible
onClicked: {
controlCenter.controlCenterVisible = !controlCenter.controlCenterVisible;
if (controlCenter.controlCenterVisible) {
controlCenterPopout.controlCenterVisible = !controlCenterPopout.controlCenterVisible;
if (controlCenterPopout.controlCenterVisible) {
if (NetworkService.wifiEnabled)
WifiService.scanWifi();

View File

@@ -0,0 +1,38 @@
import QtQuick
import QtQuick.Effects
import Quickshell
import Quickshell.Io
import Quickshell.Widgets
import qs.Common
IconImage {
id: root
property string colorOverride: ""
property real brightnessOverride: 0.5
property real contrastOverride: 1
smooth: true
asynchronous: true
layer.enabled: colorOverride !== ""
Process {
running: true
command: ["sh", "-c", ". /etc/os-release && echo $LOGO"]
stdout: StdioCollector {
onStreamFinished: () => {
root.source = Quickshell.iconPath(this.text.trim());
}
}
}
layer.effect: MultiEffect {
colorization: 1
colorizationColor: colorOverride
brightness: brightnessOverride
contrast: contrastOverride
}
}

View File

@@ -0,0 +1,56 @@
import QtQuick
import qs.Common
Item {
id: root
required property Item target
property int direction: Anims.direction.fadeOnly
function show() { _apply(true) }
function hide() { _apply(false) }
function _apply(showing) {
const off = Anims.slidePx
let fromX = 0
let toX = 0
switch(direction) {
case Anims.direction.fromLeft: fromX = -off; toX = 0; break
case Anims.direction.fromRight: fromX = off; toX = 0; break
default: fromX = 0; toX = 0;
}
if (showing) {
target.x = fromX
target.opacity = 0
target.visible = true
animX.from = fromX; animX.to = toX
animO.from = 0; animO.to = 1
} else {
animX.from = target.x; animX.to = (direction === Anims.direction.fromLeft ? -off :
direction === Anims.direction.fromRight ? off : 0)
animO.from = target.opacity; animO.to = 0
}
seq.restart()
}
SequentialAnimation {
id: seq
ParallelAnimation {
NumberAnimation {
id: animX
target: root.target
property: "x"
duration: Anims.durMed
easing.type: Easing.OutCubic
}
NumberAnimation {
id: animO
target: root.target
property: "opacity"
duration: Anims.durShort
}
}
ScriptAction { script: if (root.target.opacity === 0) root.target.visible = false }
}
}

View File

@@ -8,6 +8,8 @@ import qs.Modules.Settings
import qs.Modules.TopBar
import qs.Modules.ProcessList
import qs.Modules.ControlCenter.Network
import qs.Modules.Popouts
import qs.Modals
ShellRoot {
id: root
@@ -23,8 +25,8 @@ ShellRoot {
}
// Global popup windows
CentcomCenter {
id: centcomCenter
CentcomPopout {
id: centcomPopout
}
TrayMenuPopup {
@@ -39,38 +41,38 @@ ShellRoot {
id: notificationPopup
}
ControlCenter {
id: controlCenter
ControlCenterPopout {
id: controlCenterPopout
onPowerActionRequested: (action, title, message) => {
powerConfirmDialog.powerConfirmAction = action;
powerConfirmDialog.powerConfirmTitle = title;
powerConfirmDialog.powerConfirmMessage = message;
powerConfirmDialog.powerConfirmVisible = true;
powerConfirmModal.powerConfirmAction = action;
powerConfirmModal.powerConfirmTitle = title;
powerConfirmModal.powerConfirmMessage = message;
powerConfirmModal.powerConfirmVisible = true;
}
}
WifiPasswordDialog {
id: wifiPasswordDialog
WifiPasswordModal {
id: wifiPasswordModal
}
NetworkInfoDialog {
id: networkInfoDialog
NetworkInfoModal {
id: networkInfoModal
}
BatteryControlPopup {
id: batteryControlPopup
BatteryPopout {
id: batteryPopout
}
PowerMenuPopup {
id: powerMenuPopup
}
PowerConfirmDialog {
id: powerConfirmDialog
PowerConfirmModal {
id: powerConfirmModal
}
ProcessListDropdown {
id: processListDropdown
ProcessListPopout {
id: processListPopout
}
SettingsModal {
@@ -79,12 +81,12 @@ ShellRoot {
// Application and clipboard components
AppLauncher {
id: appLauncher
AppDrawerPopout {
id: appDrawerPopout
}
SpotlightLauncher {
id: spotlightLauncher
SpotlightModal {
id: spotlightModal
}
ProcessListModal {