1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-12 16:52:10 -04:00

Initial qmlformat

This commit is contained in:
bbedward
2025-07-17 17:58:56 -04:00
parent cbb42df3a9
commit 023b6bc0d1
62 changed files with 7805 additions and 6606 deletions

View File

@@ -7,100 +7,111 @@ import qs.Services
Item {
id: root
property list<real> audioLevels: [0, 0, 0, 0]
readonly property MprisPlayer activePlayer: MprisController.activePlayer
readonly property bool hasActiveMedia: activePlayer !== null
property var audioLevels: [0, 0, 0, 0]
readonly property MprisPlayer activePlayer: MprisController.activePlayer
readonly property bool hasActiveMedia: activePlayer !== null
property bool cavaAvailable: false
width: 20
height: Theme.iconSize
Process {
id: cavaCheck
command: ["which", "cava"]
running: true
onExited: (exitCode) => {
root.cavaAvailable = exitCode === 0
root.cavaAvailable = exitCode === 0;
if (root.cavaAvailable) {
console.log("cava found - enabling real audio visualization")
cavaProcess.running = Qt.binding(() => root.hasActiveMedia && root.activePlayer?.playbackState === MprisPlaybackState.Playing)
console.log("cava found - enabling real audio visualization");
cavaProcess.running = Qt.binding(() => {
return root.hasActiveMedia && root.activePlayer && root.activePlayer.playbackState === MprisPlaybackState.Playing;
});
} else {
console.log("cava not found - using fallback animation")
fallbackTimer.running = Qt.binding(() => root.hasActiveMedia && root.activePlayer?.playbackState === MprisPlaybackState.Playing)
console.log("cava not found - using fallback animation");
fallbackTimer.running = Qt.binding(() => {
return root.hasActiveMedia && root.activePlayer && root.activePlayer.playbackState === MprisPlaybackState.Playing;
});
}
}
}
Process {
id: cavaProcess
running: false
command: ["sh", "-c", `printf '[general]\nmode=normal\nframerate=30\nautosens=0\nsensitivity=50\nbars=4\n[output]\nmethod=raw\nraw_target=/dev/stdout\ndata_format=ascii\nchannels=mono\nmono_option=average\n[smoothing]\nnoise_reduction=20' | cava -p /dev/stdin`]
onRunningChanged: {
if (!running)
root.audioLevels = [0, 0, 0, 0];
}
stdout: SplitParser {
splitMarker: "\n"
onRead: data => {
onRead: (data) => {
if (data.trim()) {
let points = data.split(";").map(p => parseFloat(p.trim())).filter(p => !isNaN(p))
if (points.length >= 4) {
root.audioLevels = [points[0], points[1], points[2], points[3]]
}
let points = data.split(";").map((p) => {
return parseFloat(p.trim());
}).filter((p) => {
return !isNaN(p);
});
if (points.length >= 4)
root.audioLevels = [points[0], points[1], points[2], points[3]];
}
}
}
onRunningChanged: {
if (!running) {
root.audioLevels = [0, 0, 0, 0]
}
}
}
Timer {
id: fallbackTimer
running: false
interval: 100
repeat: true
onTriggered: {
root.audioLevels = [
Math.random() * 40 + 10,
Math.random() * 60 + 20,
Math.random() * 50 + 15,
Math.random() * 35 + 20
]
root.audioLevels = [Math.random() * 40 + 10, Math.random() * 60 + 20, Math.random() * 50 + 15, Math.random() * 35 + 20];
}
}
Row {
anchors.centerIn: parent
spacing: 2
Repeater {
model: 4
Rectangle {
width: 3
height: {
if (root.activePlayer?.playbackState === MprisPlaybackState.Playing && root.audioLevels.length > index) {
const rawLevel = root.audioLevels[index] || 0
const scaledLevel = Math.sqrt(Math.min(Math.max(rawLevel, 0), 100) / 100) * 100
const maxHeight = Theme.iconSize - 2
const minHeight = 3
return minHeight + (scaledLevel / 100) * (maxHeight - minHeight)
if (root.activePlayer && root.activePlayer.playbackState === MprisPlaybackState.Playing && root.audioLevels.length > index) {
const rawLevel = root.audioLevels[index] || 0;
const scaledLevel = Math.sqrt(Math.min(Math.max(rawLevel, 0), 100) / 100) * 100;
const maxHeight = Theme.iconSize - 2;
const minHeight = 3;
return minHeight + (scaledLevel / 100) * (maxHeight - minHeight);
}
return 3
return 3;
}
radius: 1.5
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
Behavior on height {
NumberAnimation {
duration: 80
easing.type: Easing.OutQuad
}
}
}
}
}
}
}

View File

@@ -4,30 +4,25 @@ import qs.Common
Rectangle {
id: root
property date currentDate: new Date()
signal clockClicked()
width: clockRow.implicitWidth + Theme.spacingS * 2
height: 30
radius: Theme.cornerRadius
color: clockMouseArea.containsMouse ?
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) :
Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08)
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
color: clockMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08)
Component.onCompleted: {
root.currentDate = systemClock.date;
}
Row {
id: clockRow
anchors.centerIn: parent
spacing: Theme.spacingS
Text {
text: Prefs.use24HourClock ? Qt.formatTime(root.currentDate, "H:mm") : Qt.formatTime(root.currentDate, "h:mm AP")
font.pixelSize: Theme.fontSizeMedium
@@ -35,14 +30,14 @@ Rectangle {
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: "•"
font.pixelSize: Theme.fontSizeMedium
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: Qt.formatDate(root.currentDate, "ddd d")
font.pixelSize: Theme.fontSizeMedium
@@ -50,26 +45,33 @@ Rectangle {
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
SystemClock {
id: systemClock
precision: SystemClock.Seconds
onDateChanged: root.currentDate = systemClock.date
}
Component.onCompleted: {
root.currentDate = systemClock.date
}
MouseArea {
id: clockMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.clockClicked()
root.clockClicked();
}
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}

View File

@@ -4,37 +4,43 @@ import qs.Services
Rectangle {
id: root
property bool isActive: false
signal clicked()
width: Math.max(80, controlIndicators.implicitWidth + Theme.spacingS * 2)
height: 30
radius: Theme.cornerRadius
color: controlCenterArea.containsMouse || root.isActive ?
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) :
Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.08)
color: controlCenterArea.containsMouse || root.isActive ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) : Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.08)
Row {
id: controlIndicators
anchors.centerIn: parent
spacing: Theme.spacingXS
// Network Status Icon
Text {
text: {
if (NetworkService.networkStatus === "ethernet") return "lan"
else if (NetworkService.networkStatus === "wifi") {
if (NetworkService.networkStatus === "ethernet") {
return "lan";
} else if (NetworkService.networkStatus === "wifi") {
switch (WifiService.wifiSignalStrength) {
case "excellent": return "wifi"
case "good": return "wifi_2_bar"
case "fair": return "wifi_1_bar"
case "poor": return "wifi_calling_3"
default: return "wifi"
case "excellent":
return "wifi";
case "good":
return "wifi_2_bar";
case "fair":
return "wifi_1_bar";
case "poor":
return "wifi_calling_3";
default:
return "wifi";
}
} else {
return "wifi_off";
}
else return "wifi_off"
}
font.family: Theme.iconFont
font.pixelSize: Theme.iconSize - 8
@@ -43,7 +49,7 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
visible: true
}
// Bluetooth Icon (when available and enabled) - moved next to network
Text {
text: "bluetooth"
@@ -54,51 +60,49 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
visible: BluetoothService.available && BluetoothService.enabled
}
// Audio Icon with scroll wheel support
Rectangle {
width: audioIcon.implicitWidth + 4
height: audioIcon.implicitHeight + 4
color: "transparent"
anchors.verticalCenter: parent.verticalCenter
Text {
id: audioIcon
text: AudioService.sinkMuted ? "volume_off" :
AudioService.volumeLevel < 33 ? "volume_down" : "volume_up"
text: AudioService.sinkMuted ? "volume_off" : AudioService.volumeLevel < 33 ? "volume_down" : "volume_up"
font.family: Theme.iconFont
font.pixelSize: Theme.iconSize - 8
font.weight: Theme.iconFontWeight
color: audioWheelArea.containsMouse || controlCenterArea.containsMouse || root.isActive ?
Theme.primary : Theme.surfaceText
color: audioWheelArea.containsMouse || controlCenterArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText
anchors.centerIn: parent
}
MouseArea {
// Scroll up - increase volume
// Scroll down - decrease volume
id: audioWheelArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.NoButton
onWheel: function(wheelEvent) {
let delta = wheelEvent.angleDelta.y
let currentVolume = AudioService.volumeLevel
let newVolume
if (delta > 0) {
// Scroll up - increase volume
newVolume = Math.min(100, currentVolume + 5)
} else {
// Scroll down - decrease volume
newVolume = Math.max(0, currentVolume - 5)
}
AudioService.setVolume(newVolume)
wheelEvent.accepted = true
let delta = wheelEvent.angleDelta.y;
let currentVolume = AudioService.volumeLevel;
let newVolume;
if (delta > 0)
newVolume = Math.min(100, currentVolume + 5);
else
newVolume = Math.max(0, currentVolume - 5);
AudioService.setVolume(newVolume);
wheelEvent.accepted = true;
}
}
}
// Microphone Icon (when active)
Text {
text: "mic"
@@ -109,23 +113,26 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
visible: false // TODO: Add mic detection
}
}
MouseArea {
id: controlCenterArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.clicked()
root.clicked();
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}

View File

@@ -4,43 +4,34 @@ import qs.Services
Rectangle {
id: root
width: Math.max(contentRow.implicitWidth + Theme.spacingS * 2, 60)
height: 30
radius: Theme.cornerRadius
color: mouseArea.containsMouse ?
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) :
Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08)
color: mouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08)
clip: true
visible: FocusedWindowService.niriAvailable && (FocusedWindowService.focusedAppName || FocusedWindowService.focusedWindowTitle)
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Row {
id: contentRow
anchors.centerIn: parent
spacing: Theme.spacingS
Text {
id: appText
text: FocusedWindowService.focusedAppName || ""
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
// Limit app name width
elide: Text.ElideRight
maximumLineCount: 1
width: Math.min(implicitWidth, 120)
}
Text {
text: "•"
font.pixelSize: Theme.fontSizeMedium
@@ -48,35 +39,47 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
visible: appText.text && titleText.text
}
Text {
id: titleText
text: FocusedWindowService.focusedWindowTitle || ""
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
// Limit title width - increased for longer titles
elide: Text.ElideRight
maximumLineCount: 1
width: Math.min(implicitWidth, 350)
}
}
MouseArea {
// Non-interactive widget - just provides hover state for visual feedback
id: mouseArea
anchors.fill: parent
hoverEnabled: true
// Non-interactive widget - just provides hover state for visual feedback
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
// Smooth width animation when the text changes
Behavior on width {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}

View File

@@ -4,12 +4,12 @@ import qs.Services
Rectangle {
id: root
width: 40
height: 30
radius: Theme.cornerRadius
color: launcherArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.12) : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08)
Text {
anchors.centerIn: parent
text: OSDetectorService.osLogo || "apps"
@@ -18,22 +18,24 @@ Rectangle {
font.weight: Theme.iconFontWeight
color: Theme.surfaceText
}
MouseArea {
id: launcherArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
LauncherService.toggleAppLauncher()
LauncherService.toggleAppLauncher();
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}

View File

@@ -39,6 +39,37 @@ Rectangle {
}
]
transitions: [
Transition {
from: "shown"
to: "hidden"
SequentialAnimation {
PauseAnimation {
duration: 500
}
NumberAnimation {
properties: "opacity,width"
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
},
Transition {
from: "hidden"
to: "shown"
NumberAnimation {
properties: "opacity,width"
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
]
Row {
id: mediaRow
@@ -64,9 +95,8 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
width: 140
text: {
if (!activePlayer || !activePlayer.trackTitle) {
if (!activePlayer || !activePlayer.trackTitle)
return "";
}
let identity = activePlayer.identity || "";
let isWebMedia = identity.toLowerCase().includes("firefox") || identity.toLowerCase().includes("chrome") || identity.toLowerCase().includes("chromium") || identity.toLowerCase().includes("edge") || identity.toLowerCase().includes("safari");
@@ -209,38 +239,6 @@ Rectangle {
}
transitions: [
Transition {
from: "shown"
to: "hidden"
SequentialAnimation {
PauseAnimation {
duration: 500
}
NumberAnimation {
properties: "opacity,width"
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
},
Transition {
from: "hidden"
to: "shown"
NumberAnimation {
properties: "opacity,width"
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
]
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration

View File

@@ -3,28 +3,26 @@ import qs.Common
Rectangle {
id: root
property bool hasUnread: false
property bool isActive: false
signal clicked()
width: 40
height: 30
radius: Theme.cornerRadius
color: notificationArea.containsMouse || root.isActive ?
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) :
Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.08)
color: notificationArea.containsMouse || root.isActive ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) : Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.08)
Text {
anchors.centerIn: parent
text: "notifications"
font.family: Theme.iconFont
font.pixelSize: Theme.iconSize - 6
font.weight: Theme.iconFontWeight
color: notificationArea.containsMouse || root.isActive ?
Theme.primary : Theme.surfaceText
color: notificationArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText
}
// Notification dot indicator
Rectangle {
width: 8
@@ -37,22 +35,24 @@ Rectangle {
anchors.topMargin: 6
visible: root.hasUnread
}
MouseArea {
id: notificationArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.clicked()
root.clicked();
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}

View File

@@ -4,36 +4,38 @@ import qs.Common
Rectangle {
id: root
signal menuRequested(var menu, var item, real x, real y)
width: Math.max(40, systemTrayRow.implicitWidth + Theme.spacingS * 2)
height: 30
radius: Theme.cornerRadius
color: Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.08)
visible: systemTrayRow.children.length > 0
Row {
id: systemTrayRow
anchors.centerIn: parent
spacing: Theme.spacingXS
Repeater {
model: SystemTray.items
delegate: Rectangle {
property var trayItem: modelData
width: 24
height: 24
radius: Theme.cornerRadiusSmall
color: trayItemArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
property var trayItem: modelData
Image {
anchors.centerIn: parent
width: 18
height: 18
source: {
let icon = trayItem?.icon;
let icon = trayItem && trayItem.icon;
if (typeof icon === 'string' || icon instanceof String) {
if (icon.includes("?path=")) {
const [name, path] = icon.split("?path=");
@@ -48,51 +50,58 @@ Rectangle {
smooth: true
fillMode: Image.PreserveAspectFit
}
MouseArea {
id: trayItemArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: (mouse) => {
if (!trayItem) return;
if (!trayItem)
return ;
if (mouse.button === Qt.LeftButton) {
if (!trayItem.onlyMenu) {
trayItem.activate()
}
if (!trayItem.onlyMenu)
trayItem.activate();
} else if (mouse.button === Qt.RightButton) {
if (trayItem.hasMenu) {
customTrayMenu.showMenu(mouse.x, mouse.y)
}
if (trayItem.hasMenu)
customTrayMenu.showMenu(mouse.x, mouse.y);
}
}
}
QtObject {
id: customTrayMenu
property bool menuVisible: false
function showMenu(x, y) {
root.menuRequested(customTrayMenu, trayItem, x, y)
menuVisible = true
root.menuRequested(customTrayMenu, trayItem, x, y);
menuVisible = true;
}
function hideMenu() {
menuVisible = false
menuVisible = false;
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}
}

View File

@@ -1,61 +1,54 @@
import "../../Common/Utilities.js" as Utils
import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import Quickshell
import Quickshell.Widgets
import Quickshell.Wayland
import Quickshell.Io
import Quickshell.Services.SystemTray
import Quickshell.Services.Notifications
import Quickshell.Services.Mpris
import Quickshell.Services.Notifications
import Quickshell.Services.SystemTray
import Quickshell.Wayland
import Quickshell.Widgets
import qs.Common
import qs.Services
import qs.Widgets
import "../../Common/Utilities.js" as Utils
PanelWindow {
// Proxy objects for external connections
id: root
property var modelData
screen: modelData
property string screenName: modelData.name
// Transparency property for the top bar background
property real backgroundTransparency: Prefs.topBarTransparency
Connections {
target: Prefs
function onTopBarTransparencyChanged() {
root.backgroundTransparency = Prefs.topBarTransparency
}
}
// Notification properties
readonly property int notificationCount: NotificationService.notifications.length
// Proxy objects for external connections
screen: modelData
implicitHeight: Theme.barHeight - 4
color: "transparent"
Connections {
function onTopBarTransparencyChanged() {
root.backgroundTransparency = Prefs.topBarTransparency;
}
target: Prefs
}
QtObject {
id: notificationHistory
property int count: 0
}
anchors {
top: true
left: true
right: true
}
implicitHeight: Theme.barHeight - 4
color: "transparent"
// Floating panel container with margins
Item {
anchors.fill: parent
@@ -64,22 +57,13 @@ PanelWindow {
anchors.bottomMargin: 0
anchors.leftMargin: 8
anchors.rightMargin: 8
Rectangle {
anchors.fill: parent
radius: Theme.cornerRadiusXLarge
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, root.backgroundTransparency)
layer.enabled: true
layer.effect: MultiEffect {
shadowEnabled: true
shadowHorizontalOffset: 0
shadowVerticalOffset: 4
shadowBlur: 0.5 // radius/32, adjusted for visual match
shadowColor: Qt.rgba(0, 0, 0, 0.15)
shadowOpacity: 0.15
}
Rectangle {
anchors.fill: parent
color: "transparent"
@@ -87,29 +71,43 @@ PanelWindow {
border.width: 1
radius: parent.radius
}
Rectangle {
anchors.fill: parent
color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04)
radius: parent.radius
SequentialAnimation on opacity {
running: false
loops: Animation.Infinite
NumberAnimation {
to: 0.08
duration: Theme.extraLongDuration
easing.type: Theme.standardEasing
}
NumberAnimation {
to: 0.02
duration: Theme.extraLongDuration
easing.type: Theme.standardEasing
}
}
}
layer.effect: MultiEffect {
shadowEnabled: true
shadowHorizontalOffset: 0
shadowVerticalOffset: 4
shadowBlur: 0.5 // radius/32, adjusted for visual match
shadowColor: Qt.rgba(0, 0, 0, 0.15)
shadowOpacity: 0.15
}
}
Item {
anchors.fill: parent
anchors.leftMargin: Theme.spacingM
@@ -117,82 +115,83 @@ PanelWindow {
anchors.topMargin: Theme.spacingXS
anchors.bottomMargin: Theme.spacingXS
clip: true
Row {
id: leftSection
height: parent.height
spacing: Theme.spacingXS
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
LauncherButton {
anchors.verticalCenter: parent.verticalCenter
}
WorkspaceSwitcher {
anchors.verticalCenter: parent.verticalCenter
screenName: root.screenName
}
FocusedAppWidget {
anchors.verticalCenter: parent.verticalCenter
visible: Prefs.showFocusedWindow
}
}
ClockWidget {
id: clockWidget
anchors.centerIn: parent
onClockClicked: {
centerCommandCenter.calendarVisible = !centerCommandCenter.calendarVisible
centerCommandCenter.calendarVisible = !centerCommandCenter.calendarVisible;
}
}
MediaWidget {
anchors.verticalCenter: parent.verticalCenter
anchors.right: clockWidget.left
anchors.rightMargin: Theme.spacingS
visible: Prefs.showMusic && MprisController.activePlayer
onClicked: {
centerCommandCenter.calendarVisible = !centerCommandCenter.calendarVisible
centerCommandCenter.calendarVisible = !centerCommandCenter.calendarVisible;
}
}
WeatherWidget {
id: weatherWidget
anchors.verticalCenter: parent.verticalCenter
anchors.left: clockWidget.right
anchors.leftMargin: Theme.spacingS
visible: Prefs.showWeather && WeatherService.weather.available && WeatherService.weather.temp > 0 && WeatherService.weather.tempF > 0
onClicked: {
centerCommandCenter.calendarVisible = !centerCommandCenter.calendarVisible
centerCommandCenter.calendarVisible = !centerCommandCenter.calendarVisible;
}
}
Row {
id: rightSection
height: parent.height
spacing: Theme.spacingXS
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
SystemTrayWidget {
anchors.verticalCenter: parent.verticalCenter
visible: Prefs.showSystemTray
onMenuRequested: (menu, item, x, y) => {
trayMenuPopup.currentTrayMenu = menu
trayMenuPopup.currentTrayItem = item
trayMenuPopup.trayMenuX = rightSection.x + rightSection.width - 400 - Theme.spacingL
trayMenuPopup.trayMenuY = Theme.barHeight - Theme.spacingXS
trayMenuPopup.showTrayMenu = true
menu.menuVisible = true
trayMenuPopup.currentTrayMenu = menu;
trayMenuPopup.currentTrayItem = item;
trayMenuPopup.trayMenuX = rightSection.x + rightSection.width - 400 - Theme.spacingL;
trayMenuPopup.trayMenuY = Theme.barHeight - Theme.spacingXS;
trayMenuPopup.showTrayMenu = true;
menu.menuVisible = true;
}
}
Rectangle {
width: 40
height: 30
@@ -200,7 +199,7 @@ PanelWindow {
color: clipboardArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.08)
anchors.verticalCenter: parent.verticalCenter
visible: Prefs.showClipboard
Text {
anchors.centerIn: parent
text: "content_paste"
@@ -209,26 +208,28 @@ PanelWindow {
font.weight: Theme.iconFontWeight
color: Theme.surfaceText
}
MouseArea {
id: clipboardArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
clipboardHistoryPopup.toggle()
clipboardHistoryPopup.toggle();
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
// System Monitor Widgets
CpuMonitorWidget {
anchors.verticalCenter: parent.verticalCenter
@@ -239,40 +240,44 @@ PanelWindow {
anchors.verticalCenter: parent.verticalCenter
visible: Prefs.showSystemResources
}
NotificationCenterButton {
anchors.verticalCenter: parent.verticalCenter
hasUnread: root.notificationCount > 0
isActive: notificationCenter.notificationHistoryVisible
onClicked: {
notificationCenter.notificationHistoryVisible = !notificationCenter.notificationHistoryVisible
notificationCenter.notificationHistoryVisible = !notificationCenter.notificationHistoryVisible;
}
}
// Battery Widget
BatteryWidget {
anchors.verticalCenter: parent.verticalCenter
batteryPopupVisible: batteryControlPopup.batteryPopupVisible
onToggleBatteryPopup: {
batteryControlPopup.batteryPopupVisible = !batteryControlPopup.batteryPopupVisible
batteryControlPopup.batteryPopupVisible = !batteryControlPopup.batteryPopupVisible;
}
}
ControlCenterButton {
// Bluetooth devices are automatically updated via signals
anchors.verticalCenter: parent.verticalCenter
isActive: controlCenterPopup.controlCenterVisible
onClicked: {
controlCenterPopup.controlCenterVisible = !controlCenterPopup.controlCenterVisible
controlCenterPopup.controlCenterVisible = !controlCenterPopup.controlCenterVisible;
if (controlCenterPopup.controlCenterVisible) {
if (NetworkService.wifiEnabled) {
WifiService.scanWifi()
}
// Bluetooth devices are automatically updated via signals
if (NetworkService.wifiEnabled)
WifiService.scanWifi();
}
}
}
}
}
}
}
}

View File

@@ -4,37 +4,21 @@ import qs.Services
Rectangle {
id: root
signal clicked()
// Visibility is now controlled by TopBar.qml
width: visible ? Math.min(100, weatherRow.implicitWidth + Theme.spacingS * 2) : 0
height: 30
radius: Theme.cornerRadius
color: weatherArea.containsMouse ?
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) :
Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08)
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on width {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
color: weatherArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08)
Row {
id: weatherRow
anchors.centerIn: parent
spacing: Theme.spacingXS
Text {
text: WeatherService.getWeatherIcon(WeatherService.weather.wCode)
font.family: Theme.iconFont
@@ -42,7 +26,7 @@ Rectangle {
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: (Prefs.useFahrenheit ? WeatherService.weather.tempF : WeatherService.weather.temp) + "°" + (Prefs.useFahrenheit ? "F" : "C")
font.pixelSize: Theme.fontSizeSmall
@@ -50,14 +34,32 @@ Rectangle {
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: weatherArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.clicked()
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on width {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}

View File

@@ -5,119 +5,120 @@ import qs.Services
Rectangle {
id: root
property string screenName: ""
property int currentWorkspace: getDisplayActiveWorkspace()
property var workspaceList: getDisplayWorkspaces()
function getDisplayWorkspaces() {
if (!NiriWorkspaceService.niriAvailable || NiriWorkspaceService.allWorkspaces.length === 0)
return [1, 2];
if (!root.screenName)
return NiriWorkspaceService.getCurrentOutputWorkspaceNumbers();
var displayWorkspaces = [];
for (var i = 0; i < NiriWorkspaceService.allWorkspaces.length; i++) {
var ws = NiriWorkspaceService.allWorkspaces[i];
if (ws.output === root.screenName)
displayWorkspaces.push(ws.idx + 1);
}
return displayWorkspaces.length > 0 ? displayWorkspaces : [1, 2];
}
function getDisplayActiveWorkspace() {
if (!NiriWorkspaceService.niriAvailable || NiriWorkspaceService.allWorkspaces.length === 0)
return 1;
if (!root.screenName)
return NiriWorkspaceService.getCurrentWorkspaceNumber();
for (var i = 0; i < NiriWorkspaceService.allWorkspaces.length; i++) {
var ws = NiriWorkspaceService.allWorkspaces[i];
if (ws.output === root.screenName && ws.is_active)
return ws.idx + 1;
}
return 1;
}
width: Math.max(120, workspaceRow.implicitWidth + Theme.spacingL * 2)
height: 30
radius: Theme.cornerRadiusLarge
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08)
visible: NiriWorkspaceService.niriAvailable
property int currentWorkspace: getDisplayActiveWorkspace()
property var workspaceList: getDisplayWorkspaces()
function getDisplayWorkspaces() {
if (!NiriWorkspaceService.niriAvailable || NiriWorkspaceService.allWorkspaces.length === 0) {
return [1, 2]
}
if (!root.screenName) {
return NiriWorkspaceService.getCurrentOutputWorkspaceNumbers()
}
var displayWorkspaces = []
for (var i = 0; i < NiriWorkspaceService.allWorkspaces.length; i++) {
var ws = NiriWorkspaceService.allWorkspaces[i]
if (ws.output === root.screenName) {
displayWorkspaces.push(ws.idx + 1)
}
}
return displayWorkspaces.length > 0 ? displayWorkspaces : [1, 2]
}
function getDisplayActiveWorkspace() {
if (!NiriWorkspaceService.niriAvailable || NiriWorkspaceService.allWorkspaces.length === 0) {
return 1
}
if (!root.screenName) {
return NiriWorkspaceService.getCurrentWorkspaceNumber()
}
for (var i = 0; i < NiriWorkspaceService.allWorkspaces.length; i++) {
var ws = NiriWorkspaceService.allWorkspaces[i]
if (ws.output === root.screenName && ws.is_active) {
return ws.idx + 1
}
}
return 1
}
Connections {
target: NiriWorkspaceService
function onAllWorkspacesChanged() {
root.workspaceList = root.getDisplayWorkspaces()
root.currentWorkspace = root.getDisplayActiveWorkspace()
root.workspaceList = root.getDisplayWorkspaces();
root.currentWorkspace = root.getDisplayActiveWorkspace();
}
function onFocusedWorkspaceIndexChanged() {
root.currentWorkspace = root.getDisplayActiveWorkspace()
root.currentWorkspace = root.getDisplayActiveWorkspace();
}
function onNiriAvailableChanged() {
if (NiriWorkspaceService.niriAvailable) {
root.workspaceList = root.getDisplayWorkspaces()
root.currentWorkspace = root.getDisplayActiveWorkspace()
root.workspaceList = root.getDisplayWorkspaces();
root.currentWorkspace = root.getDisplayActiveWorkspace();
}
}
target: NiriWorkspaceService
}
Row {
id: workspaceRow
anchors.centerIn: parent
spacing: Theme.spacingS
Repeater {
model: root.workspaceList
Rectangle {
property bool isActive: modelData === root.currentWorkspace
property bool isHovered: mouseArea.containsMouse
property int sequentialNumber: index + 1
width: isActive ? Theme.spacingXL + Theme.spacingM : Theme.spacingL + Theme.spacingXS
height: Theme.spacingM
radius: height / 2
color: isActive ? Theme.primary :
isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.5) :
Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
color: isActive ? Theme.primary : isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.5) : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
Quickshell.execDetached(["niri", "msg", "action", "focus-workspace", sequentialNumber.toString()]);
}
}
Behavior on width {
NumberAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on color {
ColorAnimation {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
Quickshell.execDetached(["niri", "msg", "action", "focus-workspace", sequentialNumber.toString()])
}
}
}
}
}
}
}