1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-29 16:02: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 4. **Modules/** - UI components
- **Full-screen components**: AppLauncher, ClipboardHistoryModal, ControlCenter - **Full-screen components**: AppLauncher, ClipboardHistoryModal, ControlCenter
- **Panel components**: TopBar, SystemTrayWidget, NotificationPopup - **Panel components**: TopBar, SystemTray, NotificationPopup
- **Layout components**: WorkspaceSwitcher - **Layout components**: WorkspaceSwitcher
5. **Widgets/** - Reusable UI controls 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 showWorkspaceIndex: false
property bool showWorkspacePadding: false property bool showWorkspacePadding: false
property string appLauncherViewMode: "list" property string appLauncherViewMode: "list"
property string spotlightLauncherViewMode: "list" property string spotlightModalViewMode: "list"
property string networkPreference: "auto" property string networkPreference: "auto"
property string iconTheme: "System Default" property string iconTheme: "System Default"
property var availableIconThemes: ["System Default"] property var availableIconThemes: ["System Default"]
@@ -70,7 +70,7 @@ 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;
appLauncherViewMode = settings.appLauncherViewMode !== undefined ? settings.appLauncherViewMode : "list"; 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"; networkPreference = settings.networkPreference !== undefined ? settings.networkPreference : "auto";
iconTheme = settings.iconTheme !== undefined ? settings.iconTheme : "System Default"; iconTheme = settings.iconTheme !== undefined ? settings.iconTheme : "System Default";
useOSLogo = settings.useOSLogo !== undefined ? settings.useOSLogo : false; useOSLogo = settings.useOSLogo !== undefined ? settings.useOSLogo : false;
@@ -112,7 +112,7 @@ Singleton {
"showWorkspaceIndex": showWorkspaceIndex, "showWorkspaceIndex": showWorkspaceIndex,
"showWorkspacePadding": showWorkspacePadding, "showWorkspacePadding": showWorkspacePadding,
"appLauncherViewMode": appLauncherViewMode, "appLauncherViewMode": appLauncherViewMode,
"spotlightLauncherViewMode": spotlightLauncherViewMode, "spotlightModalViewMode": spotlightModalViewMode,
"networkPreference": networkPreference, "networkPreference": networkPreference,
"iconTheme": iconTheme, "iconTheme": iconTheme,
"useOSLogo": useOSLogo, "useOSLogo": useOSLogo,
@@ -277,8 +277,8 @@ Singleton {
saveSettings(); saveSettings();
} }
function setSpotlightLauncherViewMode(mode) { function setSpotlightModalViewMode(mode) {
spotlightLauncherViewMode = mode; spotlightModalViewMode = mode;
saveSettings(); 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
import Quickshell.Wayland import Quickshell.Wayland
import qs.Common import qs.Common
import qs.Widgets
PanelWindow { PanelWindow {
id: root id: root

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,7 @@ import qs.Services
import qs.Widgets import qs.Widgets
Column { Column {
id: calendarWidget id: calendarGrid
property date displayDate: new Date() property date displayDate: new Date()
property date selectedDate: 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 // Events widget for selected date - Material Design 3 style
Rectangle { Rectangle {
id: eventsWidget id: events
property date selectedDate: new Date() property date selectedDate: new Date()
property var selectedDateEvents: [] property var selectedDateEvents: []
@@ -17,7 +17,7 @@ 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("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; selectedDateEvents = events;
} else { } else {
selectedDateEvents = []; selectedDateEvents = [];
@@ -25,7 +25,7 @@ Rectangle {
} }
onSelectedDateEventsChanged: { onSelectedDateEventsChanged: {
console.log("EventsWidget: selectedDateEvents changed, count:", selectedDateEvents.length); console.log("Events: selectedDateEvents changed, count:", selectedDateEvents.length);
eventsList.model = selectedDateEvents; eventsList.model = selectedDateEvents;
} }
width: parent.width width: parent.width

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,19 +7,33 @@ import Quickshell.Wayland
import Quickshell.Widgets import Quickshell.Widgets
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Modules.CentcomCenter
PanelWindow { PanelWindow {
id: root id: root
readonly property bool hasActiveMedia: MprisController.activePlayer !== null readonly property bool hasActiveMedia: MprisController.activePlayer !== null
property bool calendarVisible: false 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: { onVisibleChanged: {
if (visible && CalendarService) if (visible && CalendarService)
CalendarService.loadCurrentMonth(); CalendarService.loadCurrentMonth();
} }
implicitWidth: 480 implicitWidth: 480
implicitHeight: 600 implicitHeight: 600
WlrLayershell.layer: WlrLayershell.Overlay WlrLayershell.layer: WlrLayershell.Overlay
@@ -57,24 +71,31 @@ PanelWindow {
contentHeight += mainRowHeight + Theme.spacingM; contentHeight += mainRowHeight + Theme.spacingM;
// Add events widget height - use calculated height instead of actual // Add events widget height - use calculated height instead of actual
if (CalendarService && CalendarService.khalAvailable) { if (CalendarService && CalendarService.khalAvailable) {
let hasEvents = eventsWidget.selectedDateEvents && eventsWidget.selectedDateEvents.length > 0; let hasEvents = events.selectedDateEvents && events.selectedDateEvents.length > 0;
let eventsHeight = hasEvents ? Math.min(300, 80 + eventsWidget.selectedDateEvents.length * 60) : 120; let eventsHeight = hasEvents ? Math.min(300, 80 + events.selectedDateEvents.length * 60) : 120;
contentHeight += eventsHeight; contentHeight += eventsHeight;
} }
return Math.min(contentHeight, parent.height * 0.9); 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() height: calculateHeight()
x: (parent.width - width) / 2
y: Theme.barHeight + 4
color: Theme.surfaceContainer color: Theme.surfaceContainer
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
layer.enabled: true layer.enabled: true
opacity: calendarVisible ? 1 : 0 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 { Rectangle {
anchors.fill: parent anchors.fill: parent
@@ -101,7 +122,6 @@ PanelWindow {
} }
// Update height when calendar service events change
Connections { Connections {
function onEventsByDateChanged() { function onEventsByDateChanged() {
mainContainer.height = mainContainer.calculateHeight(); mainContainer.height = mainContainer.calculateHeight();
@@ -115,16 +135,16 @@ PanelWindow {
enabled: CalendarService !== null enabled: CalendarService !== null
} }
// Update height when events widget's selectedDateEvents changes
Connections { Connections {
function onSelectedDateEventsChanged() { function onSelectedDateEventsChanged() {
mainContainer.height = mainContainer.calculateHeight(); mainContainer.height = mainContainer.calculateHeight();
} }
target: eventsWidget target: events
enabled: eventsWidget !== null enabled: events !== null
} }
Column { Column {
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingM anchors.margins: Theme.spacingM
@@ -153,13 +173,13 @@ PanelWindow {
visible: hasAnyWidgets visible: hasAnyWidgets
anchors.top: parent.top anchors.top: parent.top
MediaPlayerWidget { MediaPlayer {
visible: true // Always visible - shows placeholder when no media visible: true // Always visible - shows placeholder when no media
width: parent.width width: parent.width
height: 160 height: 160
} }
WeatherWidget { Weather {
visible: true // Always visible - shows placeholder when no weather visible: true // Always visible - shows placeholder when no weather
width: parent.width width: parent.width
height: 140 height: 140
@@ -168,8 +188,8 @@ PanelWindow {
} }
// Right section for calendar // Right section for calendar
CalendarWidget { CalendarGrid {
id: calendarWidget id: calendarGrid
width: leftWidgets.hasAnyWidgets ? parent.width * 0.55 - Theme.spacingL : parent.width width: leftWidgets.hasAnyWidgets ? parent.width * 0.55 - Theme.spacingL : parent.width
height: parent.height height: parent.height
@@ -178,11 +198,11 @@ PanelWindow {
} }
// Full-width events widget below // Full-width events widget below
EventsWidget { Events {
id: eventsWidget id: events
width: parent.width width: parent.width
selectedDate: calendarWidget.selectedDate selectedDate: calendarGrid.selectedDate
} }
} }
@@ -196,35 +216,14 @@ PanelWindow {
shadowOpacity: 0.15 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 { MouseArea {
anchors.fill: parent anchors.fill: parent
z: -1 z: -1
enabled: calendarVisible
onClicked: { onClicked: {
calendarVisible = false; calendarVisible = false;
} }

View File

@@ -1,4 +1,3 @@
import "../../Widgets"
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Effects import QtQuick.Effects
@@ -10,6 +9,7 @@ import Quickshell.Widgets
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
import qs.Modules.ControlCenter
PanelWindow { PanelWindow {
id: root id: root
@@ -48,86 +48,24 @@ PanelWindow {
} }
Rectangle { 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 height: root.powerOptionsExpanded ? 570 : 500
x: Math.max(Theme.spacingL, Screen.width - width - Theme.spacingL)
y: Theme.barHeight + Theme.spacingXS y: Theme.barHeight + Theme.spacingXS
color: Theme.popupBackground() color: Theme.popupBackground()
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
opacity: controlCenterVisible ? 1 : 0 opacity: controlCenterVisible ? 1 : 0
// TopBar dropdown animation - optimized for performance property real normalX: Math.max(Theme.spacingL, Screen.width - targetWidth - Theme.spacingL)
transform: [ x: controlCenterVisible ? normalX : normalX + Anims.slidePx
Scale {
id: scaleTransform
origin.x: 600 // Use fixed width since popup is max 600px wide Behavior on x {
origin.y: 0 NumberAnimation {
xScale: controlCenterVisible ? 1 : 0.95 duration: Anims.durMed
yScale: controlCenterVisible ? 1 : 0.8 easing.type: Easing.OutCubic
},
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 {
NumberAnimation {
targets: [scaleTransform, translateTransform]
properties: "xScale,yScale,x,y"
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
]
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
@@ -720,10 +658,9 @@ PanelWindow {
Behavior on opacity { Behavior on opacity {
NumberAnimation { NumberAnimation {
duration: Theme.mediumDuration duration: Anims.durShort
easing.type: Theme.emphasizedEasing easing.type: Easing.OutCubic
} }
} }
} }

View File

@@ -9,9 +9,10 @@ import Quickshell.Widgets
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
import qs.Modules.ProcessList
PanelWindow { PanelWindow {
id: processListDropdown id: processListPopout
property bool isVisible: false property bool isVisible: false
property var parentWidget: null property var parentWidget: null
@@ -53,73 +54,33 @@ PanelWindow {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: processListDropdown.hide() onClicked: processListPopout.hide()
} }
Rectangle { Rectangle {
id: dropdownContent id: dropdownContent
width: Math.min(600, Screen.width - Theme.spacingL * 2) readonly property real targetWidth: Math.min(600, Screen.width - Theme.spacingL * 2)
height: Math.min(600, Screen.height - Theme.barHeight - Theme.spacingS * 2) readonly property real targetHeight: Math.min(600, Screen.height - Theme.barHeight - Theme.spacingS * 2)
x: Math.max(Theme.spacingL, Screen.width - width - Theme.spacingL) width: targetWidth
height: targetHeight
y: Theme.barHeight + Theme.spacingXS y: Theme.barHeight + Theme.spacingXS
radius: Theme.cornerRadiusLarge radius: Theme.cornerRadiusLarge
color: Theme.popupBackground() color: Theme.popupBackground()
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
opacity: processListDropdown.isVisible ? 1 : 0 opacity: processListPopout.isVisible ? 1 : 0
layer.enabled: true layer.enabled: true
transform: [ property real normalX: Math.max(Theme.spacingL, Screen.width - targetWidth - Theme.spacingL)
Scale { x: processListPopout.isVisible ? normalX : normalX + Anims.slidePx
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
Behavior on x {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on y {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on x {
NumberAnimation {
duration: Anims.durMed
easing.type: Easing.OutCubic
} }
] }
MouseArea { MouseArea {
@@ -157,15 +118,14 @@ PanelWindow {
shadowVerticalOffset: 8 shadowVerticalOffset: 8
shadowBlur: 1 shadowBlur: 1
shadowColor: Qt.rgba(0, 0, 0, 0.15) shadowColor: Qt.rgba(0, 0, 0, 0.15)
shadowOpacity: processListDropdown.isVisible ? 0.15 : 0 shadowOpacity: processListPopout.isVisible ? 0.15 : 0
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { NumberAnimation {
duration: Theme.mediumDuration duration: Anims.durShort
easing.type: Theme.emphasizedEasing easing.type: Easing.OutCubic
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -133,9 +133,9 @@ PanelWindow {
LauncherButton { LauncherButton {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
isActive: appLauncher.isVisible isActive: appDrawerPopout.isVisible
onClicked: { onClicked: {
appLauncher.toggle(); appDrawerPopout.toggle();
} }
} }
@@ -144,41 +144,41 @@ PanelWindow {
screenName: root.screenName screenName: root.screenName
} }
FocusedAppWidget { FocusedApp {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: Prefs.showFocusedWindow visible: Prefs.showFocusedWindow
} }
} }
ClockWidget { Clock {
id: clockWidget id: clock
anchors.centerIn: parent anchors.centerIn: parent
onClockClicked: { onClockClicked: {
centcomCenter.calendarVisible = !centcomCenter.calendarVisible; centcomPopout.calendarVisible = !centcomPopout.calendarVisible;
} }
} }
MediaWidget { Media {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.right: clockWidget.left anchors.right: clockWidget.left
anchors.rightMargin: Theme.spacingS anchors.rightMargin: Theme.spacingS
visible: Prefs.showMusic && MprisController.activePlayer visible: Prefs.showMusic && MprisController.activePlayer
onClicked: { onClicked: {
centcomCenter.calendarVisible = !centcomCenter.calendarVisible; centcomPopout.calendarVisible = !centcomPopout.calendarVisible;
} }
} }
WeatherWidget { Weather {
id: weatherWidget id: weather
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.left: clockWidget.right anchors.left: clock.right
anchors.leftMargin: Theme.spacingS anchors.leftMargin: Theme.spacingS
visible: Prefs.showWeather && WeatherService.weather.available && WeatherService.weather.temp > 0 && WeatherService.weather.tempF > 0 visible: Prefs.showWeather && WeatherService.weather.available && WeatherService.weather.temp > 0 && WeatherService.weather.tempF > 0
onClicked: { onClicked: {
centcomCenter.calendarVisible = !centcomCenter.calendarVisible; centcomPopout.calendarVisible = !centcomPopout.calendarVisible;
} }
} }
@@ -190,7 +190,7 @@ PanelWindow {
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
SystemTrayWidget { SystemTrayBar {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: Prefs.showSystemTray visible: Prefs.showSystemTray
onMenuRequested: (menu, item, x, y) => { onMenuRequested: (menu, item, x, y) => {
@@ -240,12 +240,12 @@ PanelWindow {
} }
// System Monitor Widgets // System Monitor Widgets
CpuMonitorWidget { CpuMonitor {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: Prefs.showSystemResources visible: Prefs.showSystemResources
} }
RamMonitorWidget { RamMonitor {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: Prefs.showSystemResources visible: Prefs.showSystemResources
} }
@@ -260,11 +260,11 @@ PanelWindow {
} }
// Battery Widget // Battery Widget
BatteryWidget { Battery {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
batteryPopupVisible: batteryControlPopup.batteryPopupVisible batteryPopupVisible: batteryPopout.batteryPopupVisible
onToggleBatteryPopup: { onToggleBatteryPopup: {
batteryControlPopup.batteryPopupVisible = !batteryControlPopup.batteryPopupVisible; batteryPopout.batteryPopupVisible = !batteryPopout.batteryPopupVisible;
} }
} }
@@ -272,10 +272,10 @@ PanelWindow {
// Bluetooth devices are automatically updated via signals // Bluetooth devices are automatically updated via signals
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
isActive: controlCenter.controlCenterVisible isActive: controlCenterPopout.controlCenterVisible
onClicked: { onClicked: {
controlCenter.controlCenterVisible = !controlCenter.controlCenterVisible; controlCenterPopout.controlCenterVisible = !controlCenterPopout.controlCenterVisible;
if (controlCenter.controlCenterVisible) { if (controlCenterPopout.controlCenterVisible) {
if (NetworkService.wifiEnabled) if (NetworkService.wifiEnabled)
WifiService.scanWifi(); 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.TopBar
import qs.Modules.ProcessList import qs.Modules.ProcessList
import qs.Modules.ControlCenter.Network import qs.Modules.ControlCenter.Network
import qs.Modules.Popouts
import qs.Modals
ShellRoot { ShellRoot {
id: root id: root
@@ -23,8 +25,8 @@ ShellRoot {
} }
// Global popup windows // Global popup windows
CentcomCenter { CentcomPopout {
id: centcomCenter id: centcomPopout
} }
TrayMenuPopup { TrayMenuPopup {
@@ -39,38 +41,38 @@ ShellRoot {
id: notificationPopup id: notificationPopup
} }
ControlCenter { ControlCenterPopout {
id: controlCenter id: controlCenterPopout
onPowerActionRequested: (action, title, message) => { onPowerActionRequested: (action, title, message) => {
powerConfirmDialog.powerConfirmAction = action; powerConfirmModal.powerConfirmAction = action;
powerConfirmDialog.powerConfirmTitle = title; powerConfirmModal.powerConfirmTitle = title;
powerConfirmDialog.powerConfirmMessage = message; powerConfirmModal.powerConfirmMessage = message;
powerConfirmDialog.powerConfirmVisible = true; powerConfirmModal.powerConfirmVisible = true;
} }
} }
WifiPasswordDialog { WifiPasswordModal {
id: wifiPasswordDialog id: wifiPasswordModal
} }
NetworkInfoDialog { NetworkInfoModal {
id: networkInfoDialog id: networkInfoModal
} }
BatteryControlPopup { BatteryPopout {
id: batteryControlPopup id: batteryPopout
} }
PowerMenuPopup { PowerMenuPopup {
id: powerMenuPopup id: powerMenuPopup
} }
PowerConfirmDialog { PowerConfirmModal {
id: powerConfirmDialog id: powerConfirmModal
} }
ProcessListDropdown { ProcessListPopout {
id: processListDropdown id: processListPopout
} }
SettingsModal { SettingsModal {
@@ -79,12 +81,12 @@ ShellRoot {
// Application and clipboard components // Application and clipboard components
AppLauncher { AppDrawerPopout {
id: appLauncher id: appDrawerPopout
} }
SpotlightLauncher { SpotlightModal {
id: spotlightLauncher id: spotlightModal
} }
ProcessListModal { ProcessListModal {