better structure
This commit is contained in:
23
config/quickshell/Modules/Bar/Components/Battery.qml
Normal file
23
config/quickshell/Modules/Bar/Components/Battery.qml
Normal file
@@ -0,0 +1,23 @@
|
||||
import QtQuick
|
||||
import Quickshell.Services.UPower
|
||||
import qs.Constants
|
||||
import qs.Modules.Bar.Misc
|
||||
import qs.Services
|
||||
|
||||
MonitorItem {
|
||||
readonly property var battery: UPower.displayDevice
|
||||
readonly property bool isReady: (battery && battery.ready && battery.isLaptopBattery && battery.isPresent)
|
||||
readonly property real percent: (isReady ? (battery.percentage * 100) : 0)
|
||||
readonly property bool charging: (isReady ? battery.state === UPowerDeviceState.Charging : false)
|
||||
property int lowBatteryThreshold: 20
|
||||
|
||||
symbol: {
|
||||
return charging ? Icons.charging : percent >= 80 ? Icons.battery100 : percent >= 60 ? Icons.battery75 : percent >= 40 ? Icons.battery50 : percent >= 20 ? Icons.battery25 : Icons.battery00;
|
||||
}
|
||||
fillColor: Colors.sapphire
|
||||
value: percent
|
||||
critical: isReady && !charging && percent <= lowBatteryThreshold
|
||||
maxValue: 100
|
||||
textSuffix: "%"
|
||||
pointerCursor: false
|
||||
}
|
||||
35
config/quickshell/Modules/Bar/Components/Brightness.qml
Normal file
35
config/quickshell/Modules/Bar/Components/Brightness.qml
Normal file
@@ -0,0 +1,35 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Constants
|
||||
import qs.Modules.Bar.Misc
|
||||
import qs.Services
|
||||
|
||||
MonitorItem {
|
||||
property ShellScreen screen: null
|
||||
|
||||
function getMonitor() {
|
||||
return BrightnessService.getMonitorForScreen(screen) || null;
|
||||
}
|
||||
|
||||
symbol: Icons.brightness
|
||||
fillColor: Colors.blue
|
||||
value: {
|
||||
const monitor = getMonitor();
|
||||
return monitor ? Math.round(monitor.brightness * 100) : "N/A";
|
||||
}
|
||||
maxValue: 100
|
||||
textSuffix: "%"
|
||||
expandOnValueChange: true
|
||||
onWheelUp: {
|
||||
const monitor = getMonitor();
|
||||
if (monitor)
|
||||
monitor.increaseBrightness();
|
||||
|
||||
}
|
||||
onWheelDown: {
|
||||
const monitor = getMonitor();
|
||||
if (monitor)
|
||||
monitor.decreaseBrightness();
|
||||
|
||||
}
|
||||
}
|
||||
73
config/quickshell/Modules/Bar/Components/CavaBar.qml
Normal file
73
config/quickshell/Modules/Bar/Components/CavaBar.qml
Normal file
@@ -0,0 +1,73 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.Constants
|
||||
import qs.Services
|
||||
import qs.Utils
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property int count: 6
|
||||
property int barWidth: 5
|
||||
property int barSpacing: 3
|
||||
|
||||
implicitWidth: root.barWidth * root.count + root.barSpacing * (root.count - 1)
|
||||
implicitHeight: parent.height - 10
|
||||
|
||||
Cava {
|
||||
id: cavaProcess
|
||||
|
||||
count: root.count
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: root.barSpacing
|
||||
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: cavaProcess.values
|
||||
|
||||
Rectangle {
|
||||
width: root.barWidth
|
||||
implicitHeight: Math.max(1, modelData * (parent.height - 10))
|
||||
color: Colors.cavaList[Math.min(Math.floor(modelData * (Colors.cavaList.length - 1)), Colors.cavaList.length - 1)]
|
||||
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: 100
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onClicked: (mouse) => {
|
||||
if (mouse.button === Qt.LeftButton)
|
||||
MusicManager.playPause();
|
||||
else if (mouse.button === Qt.RightButton)
|
||||
SettingsService.showLyricsBar = !SettingsService.showLyricsBar;
|
||||
}
|
||||
onWheel: function(wheel) {
|
||||
if (wheel.angleDelta.y > 0)
|
||||
MusicManager.previous();
|
||||
else if (wheel.angleDelta.y < 0)
|
||||
MusicManager.next();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
28
config/quickshell/Modules/Bar/Components/CpuTemp.qml
Normal file
28
config/quickshell/Modules/Bar/Components/CpuTemp.qml
Normal file
@@ -0,0 +1,28 @@
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
import qs.Constants
|
||||
import qs.Modules.Bar.Misc
|
||||
import qs.Services
|
||||
|
||||
MonitorItem {
|
||||
symbol: SystemStatService.cpuTemp > 80 ? Icons.tempHigh : SystemStatService.cpuTemp > 50 ? Icons.tempMedium : Icons.tempLow
|
||||
fillColor: Colors.yellow
|
||||
critical: SystemStatService.cpuTemp > 80
|
||||
value: Math.round(SystemStatService.cpuTemp)
|
||||
maxValue: 100
|
||||
textSuffix: "°C"
|
||||
onClicked: {
|
||||
if (action.running) {
|
||||
action.signal(15);
|
||||
return ;
|
||||
}
|
||||
action.exec(["ghostty", "-e", "btop"]);
|
||||
}
|
||||
|
||||
Process {
|
||||
id: action
|
||||
|
||||
running: false
|
||||
}
|
||||
|
||||
}
|
||||
28
config/quickshell/Modules/Bar/Components/CpuUsage.qml
Normal file
28
config/quickshell/Modules/Bar/Components/CpuUsage.qml
Normal file
@@ -0,0 +1,28 @@
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
import qs.Constants
|
||||
import qs.Modules.Bar.Misc
|
||||
import qs.Services
|
||||
|
||||
MonitorItem {
|
||||
symbol: Icons.cpu
|
||||
fillColor: Colors.teal
|
||||
critical: SystemStatService.cpuUsage > 90
|
||||
value: Math.round(SystemStatService.cpuUsage)
|
||||
maxValue: 100
|
||||
textSuffix: "%"
|
||||
onClicked: {
|
||||
if (action.running) {
|
||||
action.signal(15);
|
||||
return ;
|
||||
}
|
||||
action.exec(["ghostty", "-e", "btop"]);
|
||||
}
|
||||
|
||||
Process {
|
||||
id: action
|
||||
|
||||
running: false
|
||||
}
|
||||
|
||||
}
|
||||
129
config/quickshell/Modules/Bar/Components/FocusedWindow.qml
Normal file
129
config/quickshell/Modules/Bar/Components/FocusedWindow.qml
Normal file
@@ -0,0 +1,129 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import qs.Constants
|
||||
import qs.Services
|
||||
import qs.Utils
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property real maxWidth: 250
|
||||
property string fallbackIcon: "application-x-executable"
|
||||
|
||||
function getAppIcon(appId) {
|
||||
try {
|
||||
if (appId) {
|
||||
try {
|
||||
const normalizedId = (typeof appId === 'string') ? appId : String(appId);
|
||||
const iconResult = ThemeIcons.iconForAppId(normalizedId.toLowerCase());
|
||||
if (iconResult && iconResult !== "")
|
||||
return iconResult;
|
||||
|
||||
} catch (iconError) {
|
||||
Logger.warn("FocusedWindow", "Error getting icon from CompositorService: " + iconError);
|
||||
}
|
||||
}
|
||||
return ThemeIcons.iconFromName(root.fallbackIcon);
|
||||
} catch (e) {
|
||||
Logger.warn("FocusedWindow", "Error in getAppIcon:", e);
|
||||
return ThemeIcons.iconFromName(root.fallbackIcon);
|
||||
}
|
||||
}
|
||||
|
||||
implicitHeight: parent.height
|
||||
|
||||
RowLayout {
|
||||
id: layout
|
||||
|
||||
anchors.fill: parent
|
||||
spacing: 10
|
||||
visible: Niri.focusedWindowId !== -1
|
||||
|
||||
Item {
|
||||
// Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
id: iconContainer
|
||||
|
||||
implicitWidth: 18
|
||||
implicitHeight: 18
|
||||
|
||||
IconImage {
|
||||
id: windowIcon
|
||||
|
||||
anchors.fill: parent
|
||||
source: getAppIcon(Niri.focusedWindowAppId)
|
||||
asynchronous: true
|
||||
smooth: true
|
||||
visible: source !== ""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Item {
|
||||
id: titleContainer
|
||||
|
||||
implicitWidth: root.maxWidth
|
||||
implicitHeight: parent.height
|
||||
// Layout.alignment: Qt.AlignVCenter
|
||||
clip: true
|
||||
|
||||
Text {
|
||||
id: windowTitle
|
||||
|
||||
text: Niri.focusedWindowTitle
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pointSize: Fonts.medium
|
||||
font.family: Fonts.primary
|
||||
color: Colors.primary
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton
|
||||
onEntered: {
|
||||
if (windowTitle.implicitWidth > titleContainer.width)
|
||||
windowTitle.x = titleContainer.width - windowTitle.implicitWidth;
|
||||
|
||||
}
|
||||
onExited: {
|
||||
windowTitle.x = 0;
|
||||
}
|
||||
onClicked: function(mouse) {
|
||||
if (mouse.button === Qt.MiddleButton)
|
||||
Quickshell.execDetached(["niri", "msg", "action", "close-window"]);
|
||||
else if (mouse.button === Qt.LeftButton)
|
||||
Quickshell.execDetached(["niri", "msg", "action", "center-window"]);
|
||||
}
|
||||
onWheel: function(wheel) {
|
||||
if (wheel.angleDelta.y > 0)
|
||||
Quickshell.execDetached(["niri", "msg", "action", "set-column-width", "+10%"]);
|
||||
else if (wheel.angleDelta.y < 0)
|
||||
Quickshell.execDetached(["niri", "msg", "action", "set-column-width", "-10%"]);
|
||||
else if (wheel.angleDelta.x > 0)
|
||||
Quickshell.execDetached(["niri", "msg", "action", "focus-column-left"]);
|
||||
else if (wheel.angleDelta.x < 0)
|
||||
Quickshell.execDetached(["niri", "msg", "action", "focus-column-right"]);
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
duration: 1000
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
85
config/quickshell/Modules/Bar/Components/Ip.qml
Normal file
85
config/quickshell/Modules/Bar/Components/Ip.qml
Normal file
@@ -0,0 +1,85 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Constants
|
||||
import qs.Services
|
||||
|
||||
Item {
|
||||
// Text {
|
||||
// id: ipText
|
||||
// anchors.verticalCenter: parent.verticalCenter
|
||||
// text: Icons.global + " " + (showCountryCode ? IpService.countryCode : IpService.ip)
|
||||
// font.pixelSize: Fonts.medium
|
||||
// color: Colors.peach
|
||||
// }
|
||||
|
||||
id: root
|
||||
|
||||
property bool showCountryCode: true
|
||||
|
||||
implicitHeight: parent.height
|
||||
implicitWidth: layout.width + 10
|
||||
|
||||
RowLayout {
|
||||
id: layout
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
spacing: 0
|
||||
|
||||
Text {
|
||||
text: Icons.global
|
||||
font.pointSize: Fonts.icon + 6
|
||||
color: Colors.peach
|
||||
}
|
||||
|
||||
Item {
|
||||
id: expander
|
||||
|
||||
implicitWidth: mouseArea.containsMouse ? ipText.implicitWidth + 10 : 0
|
||||
implicitHeight: parent.height
|
||||
clip: true
|
||||
|
||||
Text {
|
||||
id: ipText
|
||||
|
||||
text: showCountryCode ? IpService.countryCode : IpService.ip
|
||||
font.pointSize: showCountryCode ? Fonts.medium : Fonts.small
|
||||
font.family: Fonts.primary
|
||||
color: Colors.peach
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 5
|
||||
}
|
||||
|
||||
Behavior on implicitWidth {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
onClicked: (mouse) => {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
WriteClipboard.write(showCountryCode ? IpService.countryCode : IpService.ip);
|
||||
SendNotification.show("Copied to clipboard", showCountryCode ? IpService.countryCode : IpService.ip);
|
||||
} else if (mouse.button === Qt.RightButton)
|
||||
showCountryCode = !showCountryCode;
|
||||
else if (mouse.button === Qt.MiddleButton)
|
||||
IpService.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
89
config/quickshell/Modules/Bar/Components/LyricsBar.qml
Normal file
89
config/quickshell/Modules/Bar/Components/LyricsBar.qml
Normal file
@@ -0,0 +1,89 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Constants
|
||||
import qs.Noctalia
|
||||
import qs.Services
|
||||
|
||||
Rectangle {
|
||||
implicitHeight: parent.height
|
||||
radius: Style.radiusS
|
||||
color: Colors.base
|
||||
border.color: Colors.primary
|
||||
border.width: Style.borderS
|
||||
|
||||
Connections {
|
||||
function onShowLyricsBarChanged() {
|
||||
visible = SettingsService.showLyricsBar;
|
||||
if (visible)
|
||||
LyricsService.startSyncing();
|
||||
else
|
||||
LyricsService.stopSyncing();
|
||||
}
|
||||
|
||||
target: SettingsService
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Style.marginM
|
||||
anchors.rightMargin: Style.marginM
|
||||
spacing: Style.marginS
|
||||
|
||||
Item {
|
||||
implicitWidth: parent.width - slowerButton.implicitWidth * 3 - parent.spacing * 3 - parent.anchors.leftMargin - parent.anchors.rightMargin
|
||||
Layout.fillHeight: true
|
||||
clip: true
|
||||
|
||||
NText {
|
||||
text: LyricsService.lyrics[LyricsService.currentIndex] || ""
|
||||
family: Fonts.sans
|
||||
pointSize: Style.fontSizeS
|
||||
maximumLineCount: 1
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
id: slowerButton
|
||||
|
||||
baseSize: 24
|
||||
colorBg: Color.transparent
|
||||
colorBgHover: Colors.blue
|
||||
colorFg: Colors.blue
|
||||
icon: "rotate-2"
|
||||
onClicked: {
|
||||
LyricsService.increaseOffset();
|
||||
}
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
id: playPauseButton
|
||||
|
||||
baseSize: 24
|
||||
colorBg: Color.transparent
|
||||
colorBgHover: Colors.yellow
|
||||
colorFg: Colors.yellow
|
||||
icon: "rotate-clockwise-2"
|
||||
onClicked: {
|
||||
LyricsService.decreaseOffset();
|
||||
}
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
id: nextButton
|
||||
|
||||
baseSize: 24
|
||||
colorBg: Color.transparent
|
||||
colorBgHover: Colors.green
|
||||
colorFg: Colors.green
|
||||
icon: "rotate-clockwise"
|
||||
onClicked: {
|
||||
LyricsService.resetOffset();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
34
config/quickshell/Modules/Bar/Components/MemUsage.qml
Normal file
34
config/quickshell/Modules/Bar/Components/MemUsage.qml
Normal file
@@ -0,0 +1,34 @@
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
import qs.Constants
|
||||
import qs.Modules.Bar.Misc
|
||||
import qs.Services
|
||||
|
||||
MonitorItem {
|
||||
property bool showPercent: false
|
||||
|
||||
symbol: Icons.memory
|
||||
fillColor: Colors.green
|
||||
critical: SystemStatService.memPercent > 90
|
||||
value: Math.round(SystemStatService.memPercent)
|
||||
maxValue: 100
|
||||
textValue: showPercent ? SystemStatService.memPercent : SystemStatService.memGb
|
||||
textSuffix: showPercent ? "%" : "GB"
|
||||
onClicked: {
|
||||
if (action.running) {
|
||||
action.signal(15);
|
||||
return ;
|
||||
}
|
||||
action.exec(["ghostty", "-e", "btop"]);
|
||||
}
|
||||
onRightClicked: {
|
||||
showPercent = !showPercent;
|
||||
}
|
||||
|
||||
Process {
|
||||
id: action
|
||||
|
||||
running: false
|
||||
}
|
||||
|
||||
}
|
||||
52
config/quickshell/Modules/Bar/Components/NetworkSpeed.qml
Normal file
52
config/quickshell/Modules/Bar/Components/NetworkSpeed.qml
Normal file
@@ -0,0 +1,52 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Constants
|
||||
import qs.Services
|
||||
|
||||
Item {
|
||||
implicitHeight: parent.height
|
||||
implicitWidth: layout.width + 10
|
||||
|
||||
RowLayout {
|
||||
id: layout
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
spacing: 5
|
||||
|
||||
Text {
|
||||
text: Icons.download
|
||||
font.pointSize: Fonts.icon - 3
|
||||
color: Colors.primary
|
||||
Layout.leftMargin: 10
|
||||
}
|
||||
|
||||
Text {
|
||||
text: SystemStatService.formatSpeed(SystemStatService.rxSpeed)
|
||||
font.pointSize: Fonts.medium
|
||||
font.family: Fonts.primary
|
||||
color: Colors.primary
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 5
|
||||
}
|
||||
|
||||
Text {
|
||||
text: Icons.upload
|
||||
font.pointSize: Fonts.icon - 3
|
||||
color: Colors.primary
|
||||
}
|
||||
|
||||
Text {
|
||||
text: SystemStatService.formatSpeed(SystemStatService.txSpeed)
|
||||
font.pointSize: Fonts.medium
|
||||
font.family: Fonts.primary
|
||||
color: Colors.primary
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
107
config/quickshell/Modules/Bar/Components/RecordIndicator.qml
Normal file
107
config/quickshell/Modules/Bar/Components/RecordIndicator.qml
Normal file
@@ -0,0 +1,107 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Constants
|
||||
import qs.Services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property color fillColor: Colors.red
|
||||
property color _actualColor: Colors.red
|
||||
|
||||
visible: RecordService.isRecording
|
||||
implicitHeight: parent.height
|
||||
implicitWidth: layout.width + 10
|
||||
|
||||
SequentialAnimation {
|
||||
id: blinkAnimation
|
||||
|
||||
running: RecordService.isRecording
|
||||
loops: Animation.Infinite
|
||||
|
||||
ColorAnimation {
|
||||
target: root
|
||||
property: "_actualColor"
|
||||
to: Qt.rgba(fillColor.r, fillColor.g, fillColor.b, 0)
|
||||
duration: Style.animationSlowest
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
|
||||
ColorAnimation {
|
||||
target: root
|
||||
property: "_actualColor"
|
||||
to: fillColor
|
||||
duration: Style.animationSlowest
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: layout
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
spacing: 0
|
||||
|
||||
Text {
|
||||
text: Icons.record
|
||||
font.pointSize: Fonts.icon + 6
|
||||
color: _actualColor
|
||||
}
|
||||
|
||||
Item {
|
||||
id: expander
|
||||
|
||||
implicitWidth: mouseArea.containsMouse ? ipText.implicitWidth + 10 : 0
|
||||
implicitHeight: parent.height
|
||||
clip: true
|
||||
|
||||
Text {
|
||||
id: ipText
|
||||
|
||||
text: RecordService.recordingDisplay
|
||||
font.pointSize: Fonts.medium
|
||||
font.family: Fonts.primary
|
||||
color: fillColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 5
|
||||
}
|
||||
|
||||
Behavior on implicitWidth {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
onClicked: (mouse) => {
|
||||
if (mouse.button === Qt.LeftButton)
|
||||
RecordService.startOrStop();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on _actualColor {
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
18
config/quickshell/Modules/Bar/Components/Separator.qml
Normal file
18
config/quickshell/Modules/Bar/Components/Separator.qml
Normal file
@@ -0,0 +1,18 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.Constants
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
implicitHeight: parent.height
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: 1.5
|
||||
height: parent.height * 0.32
|
||||
color: Colors.text
|
||||
}
|
||||
|
||||
}
|
||||
22
config/quickshell/Modules/Bar/Components/Time.qml
Normal file
22
config/quickshell/Modules/Bar/Components/Time.qml
Normal file
@@ -0,0 +1,22 @@
|
||||
import QtQuick
|
||||
import qs.Constants
|
||||
import qs.Services
|
||||
|
||||
Text {
|
||||
text: TimeService.time + " | " + TimeService.dateString
|
||||
font.pointSize: Fonts.medium
|
||||
font.family: Fonts.primary
|
||||
color: Colors.primary
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onClicked: (mouse) => {
|
||||
if (mouse.button === Qt.LeftButton)
|
||||
PanelService.getPanel("calendarPanel")?.toggle(this)
|
||||
else if (mouse.button === Qt.RightButton)
|
||||
PanelService.getPanel("notificationHistoryPanel")?.toggle(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
61
config/quickshell/Modules/Bar/Components/TrayExpander.qml
Normal file
61
config/quickshell/Modules/Bar/Components/TrayExpander.qml
Normal file
@@ -0,0 +1,61 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Constants
|
||||
import qs.Modules.Bar.Misc
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
|
||||
implicitHeight: parent.height
|
||||
implicitWidth: layout.implicitWidth
|
||||
|
||||
RowLayout {
|
||||
id: layout
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
SymbolButton {
|
||||
symbol: Icons.tray
|
||||
buttonColor: Colors.green
|
||||
disabledHover: true
|
||||
}
|
||||
|
||||
Item {
|
||||
id: trayContainer
|
||||
|
||||
implicitHeight: parent.height
|
||||
implicitWidth: mouseArea.containsMouse ? expandedTray.implicitWidth : 0
|
||||
clip: true
|
||||
|
||||
SystemTray {
|
||||
id: expandedTray
|
||||
|
||||
screen: root.screen
|
||||
}
|
||||
|
||||
Behavior on implicitWidth {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
|
||||
}
|
||||
26
config/quickshell/Modules/Bar/Components/Volume.qml
Normal file
26
config/quickshell/Modules/Bar/Components/Volume.qml
Normal file
@@ -0,0 +1,26 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Constants
|
||||
import qs.Modules.Bar.Misc
|
||||
import qs.Services
|
||||
|
||||
MonitorItem {
|
||||
symbol: AudioService.muted ? Icons.volumeMuted : (AudioService.volume >= 0.5 ? Icons.volumeHigh : (AudioService.volume >= 0.2 ? Icons.volumeMedium : Icons.volumeLow))
|
||||
fillColor: Colors.lavender
|
||||
value: Math.round(AudioService.volume * 100)
|
||||
maxValue: 100
|
||||
textSuffix: "%"
|
||||
expandOnValueChange: true
|
||||
onWheelUp: {
|
||||
AudioService.increaseVolume();
|
||||
}
|
||||
onWheelDown: {
|
||||
AudioService.decreaseVolume();
|
||||
}
|
||||
onClicked: {
|
||||
AudioService.toggleMute();
|
||||
}
|
||||
onRightClicked: {
|
||||
Quickshell.execDetached(["sh", "-c", "pkill -x -n pavucontrol || pavucontrol"]);
|
||||
}
|
||||
}
|
||||
299
config/quickshell/Modules/Bar/Components/Workspace.qml
Normal file
299
config/quickshell/Modules/Bar/Components/Workspace.qml
Normal file
@@ -0,0 +1,299 @@
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Window
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Constants
|
||||
import qs.Services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property ShellScreen screen
|
||||
property bool hovered: false
|
||||
property ListModel localWorkspaces
|
||||
property real masterProgress: 0
|
||||
property bool effectsActive: false
|
||||
property color effectColor: Colors.primary
|
||||
property int horizontalPadding: 16
|
||||
property int spacingBetweenPills: 8
|
||||
property bool isDestroying: false
|
||||
|
||||
signal workspaceChanged(int workspaceId, color primaryColor)
|
||||
|
||||
function triggerUnifiedWave() {
|
||||
effectColor = Colors.primary;
|
||||
masterAnimation.restart();
|
||||
}
|
||||
|
||||
function updateWorkspaceFocus() {
|
||||
for (let i = 0; i < localWorkspaces.count; i++) {
|
||||
const ws = localWorkspaces.get(i);
|
||||
if (ws.isFocused === true) {
|
||||
root.triggerUnifiedWave();
|
||||
root.workspaceChanged(ws.id, Colors.primary);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
implicitWidth: {
|
||||
let total = 0;
|
||||
for (let i = 0; i < localWorkspaces.count; i++) {
|
||||
const ws = localWorkspaces.get(i);
|
||||
if (ws.isFocused)
|
||||
total += 44;
|
||||
else if (ws.isActive)
|
||||
total += 28;
|
||||
else
|
||||
total += 16;
|
||||
}
|
||||
total += Math.max(localWorkspaces.count - 1, 0) * spacingBetweenPills;
|
||||
total += horizontalPadding * 2;
|
||||
return total;
|
||||
}
|
||||
height: parent.height
|
||||
Component.onCompleted: {
|
||||
localWorkspaces.clear();
|
||||
for (let i = 0; i < WorkspaceManager.workspaces.count; i++) {
|
||||
const ws = WorkspaceManager.workspaces.get(i);
|
||||
if (ws.output.toLowerCase() === screen.name.toLowerCase())
|
||||
localWorkspaces.append(ws);
|
||||
|
||||
}
|
||||
workspaceRepeater.model = localWorkspaces;
|
||||
updateWorkspaceFocus();
|
||||
}
|
||||
Component.onDestruction: {
|
||||
root.isDestroying = true;
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onWorkspacesChanged() {
|
||||
localWorkspaces.clear();
|
||||
for (let i = 0; i < WorkspaceManager.workspaces.count; i++) {
|
||||
const ws = WorkspaceManager.workspaces.get(i);
|
||||
if (ws.output.toLowerCase() === screen.name.toLowerCase())
|
||||
localWorkspaces.append(ws);
|
||||
|
||||
}
|
||||
workspaceRepeater.model = localWorkspaces;
|
||||
updateWorkspaceFocus();
|
||||
}
|
||||
|
||||
target: WorkspaceManager
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: masterAnimation
|
||||
|
||||
PropertyAction {
|
||||
target: root
|
||||
property: "effectsActive"
|
||||
value: true
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
target: root
|
||||
property: "masterProgress"
|
||||
from: 0
|
||||
to: 1
|
||||
duration: 1000
|
||||
easing.type: Easing.OutQuint
|
||||
}
|
||||
|
||||
PropertyAction {
|
||||
target: root
|
||||
property: "effectsActive"
|
||||
value: false
|
||||
}
|
||||
|
||||
PropertyAction {
|
||||
target: root
|
||||
property: "masterProgress"
|
||||
value: 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: workspaceBackground
|
||||
|
||||
width: parent.width - 15
|
||||
height: 26
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
radius: 12
|
||||
color: Colors.transparent
|
||||
layer.enabled: true
|
||||
|
||||
layer.effect: DropShadow {
|
||||
color: "black"
|
||||
radius: 12
|
||||
samples: 24
|
||||
verticalOffset: 0
|
||||
horizontalOffset: 0
|
||||
opacity: 0.1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Row {
|
||||
id: pillRow
|
||||
|
||||
spacing: spacingBetweenPills
|
||||
anchors.verticalCenter: workspaceBackground.verticalCenter
|
||||
width: root.width - horizontalPadding * 2
|
||||
x: horizontalPadding
|
||||
|
||||
Repeater {
|
||||
id: workspaceRepeater
|
||||
|
||||
model: localWorkspaces
|
||||
|
||||
Item {
|
||||
id: workspacePillContainer
|
||||
|
||||
height: 12
|
||||
width: {
|
||||
if (model.isFocused)
|
||||
return 44;
|
||||
else if (model.isActive)
|
||||
return 28;
|
||||
else
|
||||
return 16;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
// half of focused height (if you want to animate this too)
|
||||
|
||||
id: workspacePill
|
||||
|
||||
anchors.fill: parent
|
||||
radius: {
|
||||
if (model.isFocused)
|
||||
return 12;
|
||||
else
|
||||
return 6;
|
||||
}
|
||||
color: {
|
||||
if (model.isFocused)
|
||||
return Colors.primary;
|
||||
|
||||
if (model.isActive)
|
||||
return Colors.primary.lighter(130);
|
||||
|
||||
if (model.isUrgent)
|
||||
return Theme.error;
|
||||
|
||||
return Colors.surface2;
|
||||
}
|
||||
scale: model.isFocused ? 1 : 0.9
|
||||
z: 0
|
||||
|
||||
MouseArea {
|
||||
id: pillMouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
WorkspaceManager.switchToWorkspace(model.idx);
|
||||
}
|
||||
z: 20
|
||||
hoverEnabled: true
|
||||
}
|
||||
// Material 3-inspired smooth animation for width, height, scale, color, opacity, and radius
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: 350
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: 350
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: 300
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on radius {
|
||||
NumberAnimation {
|
||||
duration: 350
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: pillBurst
|
||||
|
||||
anchors.centerIn: workspacePillContainer
|
||||
width: workspacePillContainer.width + 18 * root.masterProgress
|
||||
height: workspacePillContainer.height + 18 * root.masterProgress
|
||||
radius: width / 2
|
||||
color: "transparent"
|
||||
border.color: root.effectColor
|
||||
border.width: 2 + 6 * (1 - root.masterProgress)
|
||||
opacity: root.effectsActive && model.isFocused ? (1 - root.masterProgress) * 0.7 : 0
|
||||
visible: root.effectsActive && model.isFocused
|
||||
z: 1
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: 350
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: 350
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
localWorkspaces: ListModel {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user