Compare commits

..

No commits in common. "b06e3582ff7a499e98e735b43144ce713fcc23ba" and "7e359fb7308c08dec9365871a7029b1eee620e33" have entirely different histories.

23 changed files with 197 additions and 598 deletions

View file

@ -16,8 +16,7 @@ M.BarSection {
property bool _osdActive: false property bool _osdActive: false
readonly property bool _showPanel: root._hovered || _panelHovered || _osdActive readonly property bool _showPanel: root._hovered || _panelHovered || _osdActive
onPercentChanged: if (percent > 0) onPercentChanged: if (percent > 0) _flashPanel()
_flashPanel()
function _flashPanel() { function _flashPanel() {
_osdActive = true; _osdActive = true;
@ -57,8 +56,7 @@ M.BarSection {
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
const dev = text.trim(); const dev = text.trim();
if (dev) if (dev) root._blDev = "/sys/class/backlight/" + dev;
root._blDev = "/sys/class/backlight/" + dev;
} }
} }
} }
@ -116,7 +114,10 @@ M.BarSection {
anchors.left: true anchors.left: true
margins.top: 0 margins.top: 0
margins.left: Math.max(0, Math.min(Math.round(root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0) - implicitWidth / 2), (panel.screen?.width ?? 1920) - implicitWidth)) margins.left: Math.max(0, Math.min(
Math.round(root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0) - implicitWidth / 2),
(panel.screen?.width ?? 1920) - implicitWidth
))
implicitWidth: panelContent.width implicitWidth: panelContent.width
implicitHeight: panelContent.height implicitHeight: panelContent.height
@ -137,38 +138,14 @@ M.BarSection {
ParallelAnimation { ParallelAnimation {
id: showAnim id: showAnim
NumberAnimation { NumberAnimation { target: panelContent; property: "opacity"; to: 1; duration: 120; easing.type: Easing.OutCubic }
target: panelContent NumberAnimation { target: panelContent; property: "y"; to: 0; duration: 150; easing.type: Easing.OutCubic }
property: "opacity"
to: 1
duration: 120
easing.type: Easing.OutCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: 0
duration: 150
easing.type: Easing.OutCubic
}
} }
ParallelAnimation { ParallelAnimation {
id: hideAnim id: hideAnim
NumberAnimation { NumberAnimation { target: panelContent; property: "opacity"; to: 0; duration: 150; easing.type: Easing.InCubic }
target: panelContent NumberAnimation { target: panelContent; property: "y"; to: -panelContent.height; duration: 150; easing.type: Easing.InCubic }
property: "opacity"
to: 0
duration: 150
easing.type: Easing.InCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: -panelContent.height
duration: 150
easing.type: Easing.InCubic
}
onFinished: panel._winVisible = false onFinished: panel._winVisible = false
} }
@ -233,11 +210,7 @@ M.BarSection {
color: M.Theme.base0A color: M.Theme.base0A
radius: 3 radius: 3
Behavior on width { Behavior on width { NumberAnimation { duration: 80 } }
NumberAnimation {
duration: 80
}
}
} }
MouseArea { MouseArea {
@ -245,10 +218,7 @@ M.BarSection {
anchors.margins: -6 anchors.margins: -6
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: mouse => _set(mouse) onPressed: mouse => _set(mouse)
onPositionChanged: mouse => { onPositionChanged: mouse => { if (pressed) _set(mouse); }
if (pressed)
_set(mouse);
}
function _set(mouse) { function _set(mouse) {
root.setPercent(mouse.x / slider.width * 100); root.setPercent(mouse.x / slider.width * 100);
} }

View file

@ -34,14 +34,8 @@ PanelWindow {
height: 3 height: 3
gradient: Gradient { gradient: Gradient {
orientation: Gradient.Horizontal orientation: Gradient.Horizontal
GradientStop { GradientStop { position: 0; color: M.Theme.base0C }
position: 0 GradientStop { position: 1; color: M.Theme.base09 }
color: M.Theme.base0C
}
GradientStop {
position: 1
color: M.Theme.base09
}
} }
} }
@ -59,12 +53,8 @@ PanelWindow {
M.BarGroup { M.BarGroup {
borderColor: M.Theme.base0D borderColor: M.Theme.base0D
M.Clock { M.Clock { visible: M.Modules.clock.enable }
visible: M.Modules.clock.enable M.Notifications { visible: M.Modules.notifications.enable }
}
M.Notifications {
visible: M.Modules.notifications.enable
}
} }
} }
@ -77,17 +67,11 @@ PanelWindow {
M.BarGroup { M.BarGroup {
borderColor: M.Theme.base0D borderColor: M.Theme.base0D
M.Workspaces { M.Workspaces { bar: bar; visible: M.Modules.workspaces.enable }
bar: bar
visible: M.Modules.workspaces.enable
}
} }
M.BarGroup { M.BarGroup {
borderColor: M.Theme.base0D borderColor: M.Theme.base0D
M.Tray { M.Tray { bar: bar; visible: M.Modules.tray.enable }
bar: bar
visible: M.Modules.tray.enable
}
} }
M.BarGroup { M.BarGroup {
borderColor: M.Theme.base0D borderColor: M.Theme.base0D
@ -96,9 +80,7 @@ PanelWindow {
visible: M.Modules.windowTitle.enable visible: M.Modules.windowTitle.enable
} }
} }
Item { Item { Layout.fillWidth: true }
Layout.fillWidth: true
}
} }
// ---- right ---- // ---- right ----
@ -108,73 +90,45 @@ PanelWindow {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: M.Theme.barSpacing spacing: M.Theme.barSpacing
Item { Item { Layout.fillWidth: true }
Layout.fillWidth: true
}
// Media // Media
M.BarGroup { M.BarGroup {
borderColor: M.Theme.base0E borderColor: M.Theme.base0E
M.Mpris { M.Mpris { bar: bar }
bar: bar M.Volume { visible: M.Modules.volume.enable }
}
M.Volume {
visible: M.Modules.volume.enable
}
} }
// Connectivity // Connectivity
M.BarGroup { M.BarGroup {
borderColor: M.Theme.base0D borderColor: M.Theme.base0D
M.Network { M.Network { bar: bar; visible: M.Modules.network.enable }
bar: bar M.Bluetooth { bar: bar }
visible: M.Modules.network.enable
}
M.Bluetooth {
bar: bar
}
} }
// Controls // Controls
M.BarGroup { M.BarGroup {
borderColor: M.Theme.base0A borderColor: M.Theme.base0A
M.Backlight {} M.Backlight {}
M.PowerProfile { M.PowerProfile { visible: M.Modules.powerProfile.enable }
visible: M.Modules.powerProfile.enable M.IdleInhibitor { visible: M.Modules.idleInhibitor.enable }
}
M.IdleInhibitor {
visible: M.Modules.idleInhibitor.enable
}
} }
// Stats // Stats
M.BarGroup { M.BarGroup {
borderColor: M.Theme.base08 borderColor: M.Theme.base08
M.Cpu { M.Cpu { visible: M.Modules.cpu.enable }
visible: M.Modules.cpu.enable M.Memory { visible: M.Modules.memory.enable }
} M.Temperature { visible: M.Modules.temperature.enable }
M.Memory { M.Weather { visible: M.Modules.weather.enable }
visible: M.Modules.memory.enable M.Disk { visible: M.Modules.disk.enable }
}
M.Temperature {
visible: M.Modules.temperature.enable
}
M.Weather {
visible: M.Modules.weather.enable
}
M.Disk {
visible: M.Modules.disk.enable
}
} }
// Power // Power
M.BarGroup { M.BarGroup {
borderColor: M.Theme.base08 borderColor: M.Theme.base08
M.Battery {} M.Battery {}
M.Power { M.Power { bar: bar; visible: M.Modules.power.enable }
bar: bar
visible: M.Modules.power.enable
}
} }
} }
} }

View file

@ -41,14 +41,8 @@ Item {
anchors.fill: parent anchors.fill: parent
radius: M.Theme.radius radius: M.Theme.radius
gradient: Gradient { gradient: Gradient {
GradientStop { GradientStop { position: 0; color: Qt.rgba(root.borderColor.r, root.borderColor.g, root.borderColor.b, 0.15) }
position: 0 GradientStop { position: 1; color: "transparent" }
color: Qt.rgba(root.borderColor.r, root.borderColor.g, root.borderColor.b, 0.15)
}
GradientStop {
position: 1
color: "transparent"
}
} }
} }

View file

@ -21,23 +21,9 @@ Text {
SequentialAnimation { SequentialAnimation {
id: _crossfade id: _crossfade
NumberAnimation { NumberAnimation { target: root; property: "opacity"; to: 0; duration: 60; easing.type: Easing.InQuad }
target: root ScriptAction { script: root._displayIcon = root._pendingIcon }
property: "opacity" NumberAnimation { target: root; property: "opacity"; to: 1; duration: 100; easing.type: Easing.OutQuad }
to: 0
duration: 60
easing.type: Easing.InQuad
}
ScriptAction {
script: root._displayIcon = root._pendingIcon
}
NumberAnimation {
target: root
property: "opacity"
to: 1
duration: 100
easing.type: Easing.OutQuad
}
} }
color: M.Theme.base05 color: M.Theme.base05
font.pixelSize: M.Theme.fontSize + 1 font.pixelSize: M.Theme.fontSize + 1

View file

@ -8,11 +8,7 @@ Row {
property string tooltip: "" property string tooltip: ""
property bool _hovered: false property bool _hovered: false
Behavior on opacity { Behavior on opacity { NumberAnimation { duration: 150 } }
NumberAnimation {
duration: 150
}
}
layer.enabled: _hovered layer.enabled: _hovered
layer.effect: MultiEffect { layer.effect: MultiEffect {

View file

@ -28,37 +28,19 @@ M.BarSection {
SequentialAnimation { SequentialAnimation {
running: root._critical running: root._critical
loops: Animation.Infinite loops: Animation.Infinite
NumberAnimation { NumberAnimation { target: root; property: "_blinkOpacity"; to: 0.2; duration: 400; easing.type: Easing.InOutQuad }
target: root NumberAnimation { target: root; property: "_blinkOpacity"; to: 1; duration: 400; easing.type: Easing.InOutQuad }
property: "_blinkOpacity" onRunningChanged: if (!running) root._blinkOpacity = 1
to: 0.2
duration: 400
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: root
property: "_blinkOpacity"
to: 1
duration: 400
easing.type: Easing.InOutQuad
}
onRunningChanged: if (!running)
root._blinkOpacity = 1
} }
property bool _warnSent: false property bool _warnSent: false
property bool _critSent: false property bool _critSent: false
onChargingChanged: { onChargingChanged: { _warnSent = false; _critSent = false; }
_warnSent = false;
_critSent = false;
}
onPctChanged: { onPctChanged: {
if (charging) if (charging) return;
return;
if (pct < _critThresh && !_critSent) { if (pct < _critThresh && !_critSent) {
_critSent = true; _critSent = true; _warnSent = true;
_warnSent = true;
_notif.command = ["notify-send", "--urgency=critical", "--icon=battery-low", "--category=device", "Very Low Battery", "Connect to power now!"]; _notif.command = ["notify-send", "--urgency=critical", "--icon=battery-low", "--category=device", "Very Low Battery", "Connect to power now!"];
_notif.running = true; _notif.running = true;
} else if (pct < _warnThresh && !_warnSent) { } else if (pct < _warnThresh && !_warnSent) {
@ -68,9 +50,7 @@ M.BarSection {
} }
} }
Process { Process { id: _notif }
id: _notif
}
M.BarIcon { M.BarIcon {
icon: { icon: {

View file

@ -72,10 +72,7 @@ M.BarSection {
TapHandler { TapHandler {
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onTapped: { onTapped: menuLoader.active = !menuLoader.active
menuLoader.active = !menuLoader.active;
M.FlyoutState.visible = false;
}
} }
TapHandler { TapHandler {

View file

@ -13,18 +13,23 @@ M.PopupPanel {
property Process _scanner: Process { property Process _scanner: Process {
id: scanner id: scanner
running: true running: true
command: ["sh", "-c", "bluetoothctl devices Paired 2>/dev/null | while read -r _ mac name; do " + "info=$(bluetoothctl info \"$mac\" 2>/dev/null); " + "conn=$(echo \"$info\" | grep -c 'Connected: yes'); " + "bat=$(echo \"$info\" | awk -F'[(): ]' '/Battery Percentage/{for(i=1;i<=NF;i++) if($i+0==$i && $i!=\"\") print $i}'); " + "echo \"$mac:$conn:${bat:-}:$name\"; " + "done"] command: ["sh", "-c",
"bluetoothctl devices Paired 2>/dev/null | while read -r _ mac name; do " +
"info=$(bluetoothctl info \"$mac\" 2>/dev/null); " +
"conn=$(echo \"$info\" | grep -c 'Connected: yes'); " +
"bat=$(echo \"$info\" | awk -F'[(): ]' '/Battery Percentage/{for(i=1;i<=NF;i++) if($i+0==$i && $i!=\"\") print $i}'); " +
"echo \"$mac:$conn:${bat:-}:$name\"; " +
"done"
]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
const devs = []; const devs = [];
for (const line of text.trim().split("\n")) { for (const line of text.trim().split("\n")) {
if (!line) if (!line) continue;
continue;
const i1 = line.indexOf(":"); const i1 = line.indexOf(":");
const i2 = line.indexOf(":", i1 + 1); const i2 = line.indexOf(":", i1 + 1);
const i3 = line.indexOf(":", i2 + 1); const i3 = line.indexOf(":", i2 + 1);
if (i3 < 0) if (i3 < 0) continue;
continue;
devs.push({ devs.push({
mac: line.slice(0, i1), mac: line.slice(0, i1),
connected: line.slice(i1 + 1, i2) === "1", connected: line.slice(i1 + 1, i2) === "1",
@ -33,8 +38,7 @@ M.PopupPanel {
}); });
} }
devs.sort((a, b) => { devs.sort((a, b) => {
if (a.connected !== b.connected) if (a.connected !== b.connected) return a.connected ? -1 : 1;
return a.connected ? -1 : 1;
return a.name.localeCompare(b.name); return a.name.localeCompare(b.name);
}); });
menuWindow._devices = devs; menuWindow._devices = devs;
@ -47,8 +51,7 @@ M.PopupPanel {
property string action: "" property string action: ""
property string mac: "" property string mac: ""
command: ["bluetoothctl", action, mac] command: ["bluetoothctl", action, mac]
onRunningChanged: if (!running) onRunningChanged: if (!running) scanner.running = true
scanner.running = true
} }
Repeater { Repeater {

View file

@ -33,45 +33,24 @@ PanelWindow {
anchors.left: true anchors.left: true
margins.top: 0 margins.top: 0
margins.left: Math.max(0, Math.min(Math.round(M.FlyoutState.itemX - implicitWidth / 2), screen.width - implicitWidth)) margins.left: Math.max(0, Math.min(
Math.round(M.FlyoutState.itemX - implicitWidth / 2),
screen.width - implicitWidth
))
implicitWidth: label.implicitWidth + M.Theme.barPadding * 2 implicitWidth: label.implicitWidth + M.Theme.barPadding * 2
implicitHeight: label.implicitHeight + M.Theme.barPadding * 2 implicitHeight: label.implicitHeight + M.Theme.barPadding * 2
ParallelAnimation { ParallelAnimation {
id: showAnim id: showAnim
NumberAnimation { NumberAnimation { target: content; property: "opacity"; to: 1; duration: 120; easing.type: Easing.OutCubic }
target: content NumberAnimation { target: content; property: "y"; to: 0; duration: 150; easing.type: Easing.OutCubic }
property: "opacity"
to: 1
duration: 120
easing.type: Easing.OutCubic
}
NumberAnimation {
target: content
property: "y"
to: 0
duration: 150
easing.type: Easing.OutCubic
}
} }
ParallelAnimation { ParallelAnimation {
id: hideAnim id: hideAnim
NumberAnimation { NumberAnimation { target: content; property: "opacity"; to: 0; duration: 150; easing.type: Easing.InCubic }
target: content NumberAnimation { target: content; property: "y"; to: -content.height; duration: 150; easing.type: Easing.InCubic }
property: "opacity"
to: 0
duration: 150
easing.type: Easing.InCubic
}
NumberAnimation {
target: content
property: "y"
to: -content.height
duration: 150
easing.type: Easing.InCubic
}
onFinished: root._winVisible = false onFinished: root._winVisible = false
} }

View file

@ -7,77 +7,25 @@ import Quickshell.Io
QtObject { QtObject {
id: root id: root
property var workspaces: ({ property var workspaces: ({ enable: true })
enable: true property var tray: ({ enable: true })
}) property var windowTitle: ({ enable: true })
property var tray: ({ property var clock: ({ enable: true })
enable: true property var notifications: ({ enable: true })
}) property var mpris: ({ enable: true })
property var windowTitle: ({ property var volume: ({ enable: true })
enable: true property var bluetooth: ({ enable: true, interval: 5000 })
}) property var backlight: ({ enable: true, step: 5 })
property var clock: ({ property var network: ({ enable: true, interval: 5000 })
enable: true property var powerProfile: ({ enable: true, interval: 5000 })
}) property var idleInhibitor: ({ enable: true })
property var notifications: ({ property var weather: ({ enable: true, args: ["--nerd"], interval: 3600000 })
enable: true property var temperature: ({ enable: true, interval: 2000, warm: 60, hot: 80 })
}) property var cpu: ({ enable: true, interval: 1000 })
property var mpris: ({ property var memory: ({ enable: true, interval: 2000 })
enable: true property var disk: ({ enable: true, interval: 30000 })
}) property var battery: ({ enable: true, warning: 25, critical: 15 })
property var volume: ({ property var power: ({ enable: true })
enable: true
})
property var bluetooth: ({
enable: true,
interval: 5000
})
property var backlight: ({
enable: true,
step: 5
})
property var network: ({
enable: true,
interval: 5000
})
property var powerProfile: ({
enable: true,
interval: 5000
})
property var idleInhibitor: ({
enable: true
})
property var weather: ({
enable: true,
args: ["--nerd"],
interval: 3600000
})
property var temperature: ({
enable: true,
interval: 2000,
warm: 60,
hot: 80
})
property var cpu: ({
enable: true,
interval: 1000
})
property var memory: ({
enable: true,
interval: 2000
})
property var disk: ({
enable: true,
interval: 30000
})
property var battery: ({
enable: true,
warning: 25,
critical: 15
})
property var power: ({
enable: true
})
property FileView _file: FileView { property FileView _file: FileView {
path: (Quickshell.env("XDG_CONFIG_HOME") || (Quickshell.env("HOME") + "/.config")) + "/nova-shell/modules.json" path: (Quickshell.env("XDG_CONFIG_HOME") || (Quickshell.env("HOME") + "/.config")) + "/nova-shell/modules.json"
@ -94,15 +42,12 @@ QtObject {
return; return;
} }
for (const k of Object.keys(data)) { for (const k of Object.keys(data)) {
if (!(k in root)) if (!(k in root)) continue;
continue;
const v = data[k]; const v = data[k];
if (typeof v === "object" && v !== null) if (typeof v === "object" && v !== null)
root[k] = Object.assign({}, root[k], v); root[k] = Object.assign({}, root[k], v);
else if (typeof v === "boolean") else if (typeof v === "boolean")
root[k] = Object.assign({}, root[k], { root[k] = Object.assign({}, root[k], { enable: v });
enable: v
});
} }
} }
} }

View file

@ -19,12 +19,8 @@ M.BarSection {
// Cache art URL at root level so it's captured even when panel is hidden // Cache art URL at root level so it's captured even when panel is hidden
readonly property string _artUrl: player?.trackArtUrl ?? "" readonly property string _artUrl: player?.trackArtUrl ?? ""
readonly property string _currentTrack: player?.trackTitle ?? "" readonly property string _currentTrack: player?.trackTitle ?? ""
on_ArtUrlChanged: if (_artUrl) on_ArtUrlChanged: if (_artUrl) _cachedArt = _artUrl
_cachedArt = _artUrl on_CurrentTrackChanged: if (_currentTrack !== _artTrack) { _artTrack = _currentTrack; _cachedArt = _artUrl || "" }
on_CurrentTrackChanged: if (_currentTrack !== _artTrack) {
_artTrack = _currentTrack;
_cachedArt = _artUrl || "";
}
// Preload art while panel is hidden ensures QML image cache has the pixels // Preload art while panel is hidden ensures QML image cache has the pixels
Image { Image {
@ -93,7 +89,10 @@ M.BarSection {
anchors.left: true anchors.left: true
margins.top: 0 margins.top: 0
margins.left: Math.max(0, Math.min(Math.round(root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0) - implicitWidth / 2), (panel.screen?.width ?? 1920) - implicitWidth)) margins.left: Math.max(0, Math.min(
Math.round(root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0) - implicitWidth / 2),
(panel.screen?.width ?? 1920) - implicitWidth
))
implicitWidth: panelContent.width implicitWidth: panelContent.width
implicitHeight: panelContent.height implicitHeight: panelContent.height
@ -114,38 +113,14 @@ M.BarSection {
ParallelAnimation { ParallelAnimation {
id: showAnim id: showAnim
NumberAnimation { NumberAnimation { target: panelContent; property: "opacity"; to: 1; duration: 120; easing.type: Easing.OutCubic }
target: panelContent NumberAnimation { target: panelContent; property: "y"; to: 0; duration: 150; easing.type: Easing.OutCubic }
property: "opacity"
to: 1
duration: 120
easing.type: Easing.OutCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: 0
duration: 150
easing.type: Easing.OutCubic
}
} }
ParallelAnimation { ParallelAnimation {
id: hideAnim id: hideAnim
NumberAnimation { NumberAnimation { target: panelContent; property: "opacity"; to: 0; duration: 150; easing.type: Easing.InCubic }
target: panelContent NumberAnimation { target: panelContent; property: "y"; to: -panelContent.height; duration: 150; easing.type: Easing.InCubic }
property: "opacity"
to: 0
duration: 150
easing.type: Easing.InCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: -panelContent.height
duration: 150
easing.type: Easing.InCubic
}
onFinished: panel._winVisible = false onFinished: panel._winVisible = false
} }
@ -197,14 +172,10 @@ M.BarSection {
source: root._cachedArt source: root._cachedArt
property bool _hasArt: false property bool _hasArt: false
onStatusChanged: if (status === Image.Ready) onStatusChanged: if (status === Image.Ready) _hasArt = true
_hasArt = true
Connections { Connections {
target: root target: root
function on_CachedArtChanged() { function on_CachedArtChanged() { if (!root._cachedArt) _artImg._hasArt = false }
if (!root._cachedArt)
_artImg._hasArt = false;
}
} }
} }
@ -215,14 +186,8 @@ M.BarSection {
height: 40 height: 40
visible: _artImg.visible visible: _artImg.visible
gradient: Gradient { gradient: Gradient {
GradientStop { GradientStop { position: 0; color: "transparent" }
position: 0 GradientStop { position: 1; color: M.Theme.base01 }
color: "transparent"
}
GradientStop {
position: 1
color: M.Theme.base01
}
} }
} }
@ -264,8 +229,7 @@ M.BarSection {
width: parent.width width: parent.width
text: { text: {
const p = root.player; const p = root.player;
if (!p) if (!p) return "";
return "";
const artist = Array.isArray(p.trackArtists) ? p.trackArtists.join(", ") : (p.trackArtists || ""); const artist = Array.isArray(p.trackArtists) ? p.trackArtists.join(", ") : (p.trackArtists || "");
return [artist, p.trackAlbum].filter(s => s).join(" \u2014 "); return [artist, p.trackAlbum].filter(s => s).join(" \u2014 ");
} }

View file

@ -10,8 +10,7 @@ M.BarSection {
const parts = []; const parts = [];
if (root.state === "wifi") { if (root.state === "wifi") {
parts.push("WiFi: " + root.essid); parts.push("WiFi: " + root.essid);
if (root.signal) if (root.signal) parts.push("Signal: " + root.signal + "%");
parts.push("Signal: " + root.signal + "%");
} else if (root.state === "eth") { } else if (root.state === "eth") {
parts.push("Ethernet"); parts.push("Ethernet");
} else if (root.state === "linked") { } else if (root.state === "linked") {
@ -19,10 +18,8 @@ M.BarSection {
} else { } else {
return "Disconnected"; return "Disconnected";
} }
if (root.ipAddr) if (root.ipAddr) parts.push("IP: " + root.ipAddr);
parts.push("IP: " + root.ipAddr); if (root.ifname) parts.push("Interface: " + root.ifname);
if (root.ifname)
parts.push("Interface: " + root.ifname);
return parts.join("\n"); return parts.join("\n");
} }
@ -99,10 +96,7 @@ M.BarSection {
TapHandler { TapHandler {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onTapped: { onTapped: menuLoader.active = !menuLoader.active
menuLoader.active = !menuLoader.active;
M.FlyoutState.visible = false;
}
} }
Loader { Loader {

View file

@ -13,7 +13,12 @@ M.PopupPanel {
property Process _scanner: Process { property Process _scanner: Process {
id: scanner id: scanner
running: true running: true
command: ["sh", "-c", "echo '---CONNS---';" + "nmcli -t -f NAME,UUID,TYPE,ACTIVE connection show 2>/dev/null;" + "echo '---WIFI---';" + "nmcli -t -f SSID,SIGNAL device wifi list --rescan no 2>/dev/null"] command: ["sh", "-c",
"echo '---CONNS---';" +
"nmcli -t -f NAME,UUID,TYPE,ACTIVE connection show 2>/dev/null;" +
"echo '---WIFI---';" +
"nmcli -t -f SSID,SIGNAL device wifi list --rescan no 2>/dev/null"
]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
const sections = text.split("---WIFI---"); const sections = text.split("---WIFI---");
@ -23,19 +28,16 @@ M.PopupPanel {
// Visible SSIDs with signal // Visible SSIDs with signal
const visible = {}; const visible = {};
for (const l of wifiLines.trim().split("\n")) { for (const l of wifiLines.trim().split("\n")) {
if (!l) if (!l) continue;
continue;
const parts = l.split(":"); const parts = l.split(":");
const ssid = parts[0]; const ssid = parts[0];
if (ssid) if (ssid) visible[ssid] = parseInt(parts[1]) || 0;
visible[ssid] = parseInt(parts[1]) || 0;
} }
// Saved connections filter: show wired always, wifi only if visible // Saved connections filter: show wired always, wifi only if visible
const nets = []; const nets = [];
for (const l of connLines.trim().split("\n")) { for (const l of connLines.trim().split("\n")) {
if (!l) if (!l) continue;
continue;
const parts = l.split(":"); const parts = l.split(":");
const name = parts[0]; const name = parts[0];
const uuid = parts[1]; const uuid = parts[1];
@ -43,8 +45,7 @@ M.PopupPanel {
const active = parts[3] === "yes"; const active = parts[3] === "yes";
const isWifi = type.includes("wireless"); const isWifi = type.includes("wireless");
if (isWifi && !(name in visible)) if (isWifi && !(name in visible)) continue;
continue;
nets.push({ nets.push({
name: name, name: name,
@ -57,10 +58,8 @@ M.PopupPanel {
// Active first, then by signal (wifi) or name // Active first, then by signal (wifi) or name
nets.sort((a, b) => { nets.sort((a, b) => {
if (a.active !== b.active) if (a.active !== b.active) return a.active ? -1 : 1;
return a.active ? -1 : 1; if (a.signal >= 0 && b.signal >= 0) return b.signal - a.signal;
if (a.signal >= 0 && b.signal >= 0)
return b.signal - a.signal;
return a.name.localeCompare(b.name); return a.name.localeCompare(b.name);
}); });
@ -73,16 +72,14 @@ M.PopupPanel {
id: connectProc id: connectProc
property string uuid: "" property string uuid: ""
command: ["nmcli", "connection", "up", uuid] command: ["nmcli", "connection", "up", uuid]
onRunningChanged: if (!running) onRunningChanged: if (!running) scanner.running = true
scanner.running = true
} }
property Process _disconnectProc: Process { property Process _disconnectProc: Process {
id: disconnectProc id: disconnectProc
property string uuid: "" property string uuid: ""
command: ["nmcli", "connection", "down", uuid] command: ["nmcli", "connection", "down", uuid]
onRunningChanged: if (!running) onRunningChanged: if (!running) scanner.running = true
scanner.running = true
} }
Repeater { Repeater {

View file

@ -57,31 +57,17 @@ M.BarSection {
id: countScale id: countScale
origin.x: countLabel.width / 2 origin.x: countLabel.width / 2
origin.y: countLabel.height / 2 origin.y: countLabel.height / 2
xScale: 1 xScale: 1; yScale: 1
yScale: 1
} }
SequentialAnimation { SequentialAnimation {
id: popAnim id: popAnim
NumberAnimation { NumberAnimation { target: countScale; properties: "xScale,yScale"; to: 1.4; duration: 100; easing.type: Easing.OutQuad }
target: countScale NumberAnimation { target: countScale; properties: "xScale,yScale"; to: 1.0; duration: 200; easing.type: Easing.OutElastic }
properties: "xScale,yScale"
to: 1.4
duration: 100
easing.type: Easing.OutQuad
}
NumberAnimation {
target: countScale
properties: "xScale,yScale"
to: 1.0
duration: 200
easing.type: Easing.OutElastic
}
} }
} }
onCountChanged: if (count > 0) onCountChanged: if (count > 0) popAnim.start()
popAnim.start()
TapHandler { TapHandler {
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton

View file

@ -35,45 +35,24 @@ PanelWindow {
anchors.left: true anchors.left: true
margins.top: 0 margins.top: 0
margins.left: Math.max(0, Math.min(Math.round(M.OsdState.itemX - implicitWidth / 2), screen.width - implicitWidth)) margins.left: Math.max(0, Math.min(
Math.round(M.OsdState.itemX - implicitWidth / 2),
screen.width - implicitWidth
))
implicitWidth: 200 implicitWidth: 200
implicitHeight: 48 implicitHeight: 48
ParallelAnimation { ParallelAnimation {
id: showAnim id: showAnim
NumberAnimation { NumberAnimation { target: content; property: "opacity"; to: 1; duration: 150; easing.type: Easing.OutCubic }
target: content NumberAnimation { target: content; property: "y"; to: 0; duration: 200; easing.type: Easing.OutCubic }
property: "opacity"
to: 1
duration: 150
easing.type: Easing.OutCubic
}
NumberAnimation {
target: content
property: "y"
to: 0
duration: 200
easing.type: Easing.OutCubic
}
} }
ParallelAnimation { ParallelAnimation {
id: hideAnim id: hideAnim
NumberAnimation { NumberAnimation { target: content; property: "opacity"; to: 0; duration: 250; easing.type: Easing.InCubic }
target: content NumberAnimation { target: content; property: "y"; to: -content.height; duration: 250; easing.type: Easing.InCubic }
property: "opacity"
to: 0
duration: 250
easing.type: Easing.InCubic
}
NumberAnimation {
target: content
property: "y"
to: -content.height
duration: 250
easing.type: Easing.InCubic
}
onFinished: root._winVisible = false onFinished: root._winVisible = false
} }
@ -125,10 +104,7 @@ PanelWindow {
radius: 3 radius: 3
Behavior on width { Behavior on width {
NumberAnimation { NumberAnimation { duration: 120; easing.type: Easing.OutCubic }
duration: 120
easing.type: Easing.OutCubic
}
} }
} }
} }

View file

@ -14,7 +14,7 @@ PanelWindow {
required property real anchorX required property real anchorX
property real panelWidth: 220 property real panelWidth: 220
signal dismissed signal dismissed()
visible: true visible: true
color: "transparent" color: "transparent"
@ -44,7 +44,10 @@ PanelWindow {
Item { Item {
id: panel id: panel
x: Math.max(0, Math.min(Math.round(root.anchorX - contentCol.width / 2), root.width - contentCol.width)) x: Math.max(0, Math.min(
Math.round(root.anchorX - contentCol.width / 2),
root.width - contentCol.width
))
y: 0 y: 0
width: contentCol.width width: contentCol.width
height: contentCol.height height: contentCol.height
@ -76,40 +79,14 @@ PanelWindow {
ParallelAnimation { ParallelAnimation {
id: showAnim id: showAnim
NumberAnimation { NumberAnimation { target: panel; property: "opacity"; from: 0; to: 1; duration: 150; easing.type: Easing.OutCubic }
target: panel NumberAnimation { target: panel; property: "y"; from: -panel.height; to: 0; duration: 200; easing.type: Easing.OutCubic }
property: "opacity"
from: 0
to: 1
duration: 150
easing.type: Easing.OutCubic
}
NumberAnimation {
target: panel
property: "y"
from: -panel.height
to: 0
duration: 200
easing.type: Easing.OutCubic
}
} }
ParallelAnimation { ParallelAnimation {
id: hideAnim id: hideAnim
NumberAnimation { NumberAnimation { target: panel; property: "opacity"; to: 0; duration: 150; easing.type: Easing.InCubic }
target: panel NumberAnimation { target: panel; property: "y"; to: -panel.height; duration: 150; easing.type: Easing.InCubic }
property: "opacity"
to: 0
duration: 150
easing.type: Easing.InCubic
}
NumberAnimation {
target: panel
property: "y"
to: -panel.height
duration: 150
easing.type: Easing.InCubic
}
onFinished: root.dismissed() onFinished: root.dismissed()
} }
} }

View file

@ -18,10 +18,7 @@ M.BarIcon {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: menuLoader.active = !menuLoader.active
menuLoader.active = !menuLoader.active;
M.FlyoutState.visible = false;
}
} }
Loader { Loader {

View file

@ -18,36 +18,11 @@ M.PopupPanel {
Repeater { Repeater {
model: [ model: [
{ { label: "Lock", icon: "\uF023", cmd: ["loginctl", "lock-session"], color: M.Theme.base0D },
label: "Lock", { label: "Suspend", icon: "\uF186", cmd: ["systemctl", "suspend"], color: M.Theme.base0E },
icon: "\uF023", { label: "Logout", icon: "\uF2F5", cmd: menuWindow._isNiri ? ["niri", "msg", "action", "quit"] : ["loginctl", "terminate-user", ""], color: M.Theme.base0A },
cmd: ["loginctl", "lock-session"], { label: "Reboot", icon: "\uF021", cmd: ["systemctl", "reboot"], color: M.Theme.base09 },
color: M.Theme.base0D { label: "Shutdown", icon: "\uF011", cmd: ["systemctl", "poweroff"], color: M.Theme.base08 }
},
{
label: "Suspend",
icon: "\uF186",
cmd: ["systemctl", "suspend"],
color: M.Theme.base0E
},
{
label: "Logout",
icon: "\uF2F5",
cmd: menuWindow._isNiri ? ["niri", "msg", "action", "quit"] : ["loginctl", "terminate-user", ""],
color: M.Theme.base0A
},
{
label: "Reboot",
icon: "\uF021",
cmd: ["systemctl", "reboot"],
color: M.Theme.base09
},
{
label: "Shutdown",
icon: "\uF011",
cmd: ["systemctl", "poweroff"],
color: M.Theme.base08
}
] ]
delegate: Item { delegate: Item {

View file

@ -8,12 +8,9 @@ M.BarSection {
tooltip: "Temperature: " + root.celsius + "\u00B0C" tooltip: "Temperature: " + root.celsius + "\u00B0C"
property int celsius: 0 property int celsius: 0
property color _stateColor: celsius > (M.Modules.temperature.hot || 80) ? M.Theme.base09 : celsius > (M.Modules.temperature.warm || 60) ? M.Theme.base0A : M.Theme.base08 property color _stateColor: celsius > (M.Modules.temperature.hot || 80) ? M.Theme.base09
Behavior on _stateColor { : celsius > (M.Modules.temperature.warm || 60) ? M.Theme.base0A : M.Theme.base08
ColorAnimation { Behavior on _stateColor { ColorAnimation { duration: 300 } }
duration: 300
}
}
FileView { FileView {
id: thermal id: thermal

View file

@ -30,22 +30,9 @@ RowLayout {
SequentialAnimation { SequentialAnimation {
running: iconItem._needsAttention running: iconItem._needsAttention
loops: Animation.Infinite loops: Animation.Infinite
NumberAnimation { NumberAnimation { target: iconItem; property: "_pulseOpacity"; to: 0.3; duration: 400; easing.type: Easing.InOutQuad }
target: iconItem NumberAnimation { target: iconItem; property: "_pulseOpacity"; to: 1; duration: 400; easing.type: Easing.InOutQuad }
property: "_pulseOpacity" onRunningChanged: if (!running) iconItem._pulseOpacity = 1
to: 0.3
duration: 400
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: iconItem
property: "_pulseOpacity"
to: 1
duration: 400
easing.type: Easing.InOutQuad
}
onRunningChanged: if (!running)
iconItem._pulseOpacity = 1
} }
Item { Item {
@ -94,7 +81,6 @@ RowLayout {
if (root._activeMenu && root._activeMenu !== menuLoader) if (root._activeMenu && root._activeMenu !== menuLoader)
root._activeMenu.active = false; root._activeMenu.active = false;
menuLoader.active = true; menuLoader.active = true;
M.FlyoutState.visible = false;
root._activeMenu = menuLoader; root._activeMenu = menuLoader;
} else { } else {
iconItem.modelData.secondaryActivate(); iconItem.modelData.secondaryActivate();

View file

@ -120,7 +120,10 @@ M.BarSection {
anchors.left: true anchors.left: true
margins.top: 0 margins.top: 0
margins.left: Math.max(0, Math.min(Math.round(root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0) - implicitWidth / 2), (panel.screen?.width ?? 1920) - implicitWidth)) margins.left: Math.max(0, Math.min(
Math.round(root.mapToGlobal(root.width / 2, 0).x - (QsWindow.window?.screen?.x ?? 0) - implicitWidth / 2),
(panel.screen?.width ?? 1920) - implicitWidth
))
implicitWidth: panelContent.width implicitWidth: panelContent.width
implicitHeight: panelContent.height implicitHeight: panelContent.height
@ -143,38 +146,14 @@ M.BarSection {
ParallelAnimation { ParallelAnimation {
id: showAnim id: showAnim
NumberAnimation { NumberAnimation { target: panelContent; property: "opacity"; to: 1; duration: 120; easing.type: Easing.OutCubic }
target: panelContent NumberAnimation { target: panelContent; property: "y"; to: 0; duration: 150; easing.type: Easing.OutCubic }
property: "opacity"
to: 1
duration: 120
easing.type: Easing.OutCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: 0
duration: 150
easing.type: Easing.OutCubic
}
} }
ParallelAnimation { ParallelAnimation {
id: hideAnim id: hideAnim
NumberAnimation { NumberAnimation { target: panelContent; property: "opacity"; to: 0; duration: 150; easing.type: Easing.InCubic }
target: panelContent NumberAnimation { target: panelContent; property: "y"; to: -panelContent.height; duration: 150; easing.type: Easing.InCubic }
property: "opacity"
to: 0
duration: 150
easing.type: Easing.InCubic
}
NumberAnimation {
target: panelContent
property: "y"
to: -panelContent.height
duration: 150
easing.type: Easing.InCubic
}
onFinished: panel._winVisible = false onFinished: panel._winVisible = false
} }
@ -224,8 +203,7 @@ M.BarSection {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: if (root.sink?.audio) onClicked: if (root.sink?.audio) root.sink.audio.muted = !root.sink.audio.muted
root.sink.audio.muted = !root.sink.audio.muted
} }
} }
@ -251,11 +229,7 @@ M.BarSection {
color: root._volumeColor color: root._volumeColor
radius: 3 radius: 3
Behavior on width { Behavior on width { NumberAnimation { duration: 80 } }
NumberAnimation {
duration: 80
}
}
} }
MouseArea { MouseArea {
@ -263,13 +237,9 @@ M.BarSection {
anchors.margins: -6 anchors.margins: -6
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: mouse => _setVol(mouse) onPressed: mouse => _setVol(mouse)
onPositionChanged: mouse => { onPositionChanged: mouse => { if (pressed) _setVol(mouse); }
if (pressed)
_setVol(mouse);
}
function _setVol(mouse) { function _setVol(mouse) {
if (!root.sink?.audio) if (!root.sink?.audio) return;
return;
root.sink.audio.volume = Math.max(0, Math.min(1, mouse.x / slider.width)); root.sink.audio.volume = Math.max(0, Math.min(1, mouse.x / slider.width));
} }
} }
@ -311,12 +281,7 @@ M.BarSection {
property real _targetHeight: root._expanded ? implicitHeight : 0 property real _targetHeight: root._expanded ? implicitHeight : 0
height: _targetHeight height: _targetHeight
Behavior on height { Behavior on height { NumberAnimation { duration: 200; easing.type: Easing.OutCubic } }
NumberAnimation {
duration: 200
easing.type: Easing.OutCubic
}
}
// Separator // Separator
Rectangle { Rectangle {
@ -480,13 +445,9 @@ M.BarSection {
anchors.margins: -6 anchors.margins: -6
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onPressed: mouse => _set(mouse) onPressed: mouse => _set(mouse)
onPositionChanged: mouse => { onPositionChanged: mouse => { if (pressed) _set(mouse); }
if (pressed)
_set(mouse);
}
function _set(mouse) { function _set(mouse) {
if (!streamEntry.modelData.audio) if (!streamEntry.modelData.audio) return;
return;
streamEntry.modelData.audio.volume = Math.max(0, Math.min(1, mouse.x / streamSlider.width)); streamEntry.modelData.audio.volume = Math.max(0, Math.min(1, mouse.x / streamSlider.width));
} }
} }
@ -507,10 +468,7 @@ M.BarSection {
} }
// Bottom padding // Bottom padding
Item { Item { width: 1; height: 4 }
width: 1
height: 4
}
} }
} }
} }

View file

@ -90,11 +90,7 @@ Row {
height: 20 height: 20
radius: M.Theme.radius radius: M.Theme.radius
color: pill.active ? M.Theme.base0D : (pill._hovered ? M.Theme.base03 : M.Theme.base02) color: pill.active ? M.Theme.base0D : (pill._hovered ? M.Theme.base03 : M.Theme.base02)
Behavior on color { Behavior on color { ColorAnimation { duration: 150 } }
ColorAnimation {
duration: 150
}
}
Text { Text {
anchors.centerIn: parent anchors.centerIn: parent

View file

@ -66,8 +66,7 @@ in
default = true; default = true;
description = "Enable the ${name} module."; description = "Enable the ${name} module.";
}; };
} } // extra;
// extra;
}; };
}; };
intervalOpt = default: { intervalOpt = default: {
@ -104,21 +103,18 @@ in
description = "Brightness adjustment step (%)."; description = "Brightness adjustment step (%).";
}; };
}; };
temperature = moduleOpt "temperature" ( temperature = moduleOpt "temperature" ((intervalOpt 2000) // {
(intervalOpt 2000) warm = lib.mkOption {
// { type = lib.types.int;
warm = lib.mkOption { default = 60;
type = lib.types.int; description = "Temperature threshold for warm state (°C).";
default = 60; };
description = "Temperature threshold for warm state (°C)."; hot = lib.mkOption {
}; type = lib.types.int;
hot = lib.mkOption { default = 80;
type = lib.types.int; description = "Temperature threshold for hot state (°C).";
default = 80; };
description = "Temperature threshold for hot state (°C)."; });
};
}
);
battery = moduleOpt "battery" { battery = moduleOpt "battery" {
warning = lib.mkOption { warning = lib.mkOption {
type = lib.types.int; type = lib.types.int;
@ -131,21 +127,18 @@ in
description = "Battery percentage for critical notification and blink."; description = "Battery percentage for critical notification and blink.";
}; };
}; };
weather = moduleOpt "weather" ( weather = moduleOpt "weather" ((intervalOpt 3600000) // {
(intervalOpt 3600000) args = lib.mkOption {
// { type = lib.types.listOf lib.types.str;
args = lib.mkOption { default = [ "--nerd" ];
type = lib.types.listOf lib.types.str; description = "Arguments passed to wttrbar.";
default = [ "--nerd" ]; example = [
description = "Arguments passed to wttrbar."; "--nerd"
example = [ "--location"
"--nerd" "Berlin"
"--location" ];
"Berlin" };
]; });
};
}
);
}; };
theme = lib.mkOption { theme = lib.mkOption {
@ -181,8 +174,7 @@ in
++ lib.optional cfg.modules.weather.enable pkgs.wttrbar; ++ lib.optional cfg.modules.weather.enable pkgs.wttrbar;
xdg.configFile."nova-shell/modules.json".source = xdg.configFile."nova-shell/modules.json".source =
(pkgs.formats.json { }).generate "nova-shell-modules.json" (pkgs.formats.json { }).generate "nova-shell-modules.json" cfg.modules;
cfg.modules;
xdg.configFile."nova-shell/theme.json".source = xdg.configFile."nova-shell/theme.json".source =
let let