brightess and volume control
This commit is contained in:
1
Lock.qml
1
Lock.qml
@@ -15,7 +15,6 @@ WlSessionLock {
|
||||
id: surface
|
||||
color: "transparent"
|
||||
|
||||
Component.onCompleted: console.log("done")
|
||||
Rectangle {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -10,14 +10,13 @@ Column {
|
||||
width: Math.max(childrenRect.width, 300)
|
||||
height: childrenRect.height
|
||||
anchors.topMargin: 6
|
||||
TapHandler {onTapped: console.log(width)}
|
||||
Rectangle {
|
||||
radius: 12
|
||||
height: 40
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 6
|
||||
color: "#181818"
|
||||
color: "#111"
|
||||
Rectangle {
|
||||
color: "white"
|
||||
width: (parent.width - anchors.margins * 2)/3
|
||||
@@ -116,7 +115,7 @@ Column {
|
||||
id: card
|
||||
required property var data
|
||||
required property var label
|
||||
color: "#181818"
|
||||
color: "#111"
|
||||
height: 60
|
||||
width: 100
|
||||
radius: 12
|
||||
|
||||
154
Panes/Brightness.qml
Normal file
154
Panes/Brightness.qml
Normal file
@@ -0,0 +1,154 @@
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Hyprland
|
||||
import QtQuick
|
||||
import qs.Services
|
||||
import qs.Widgets as Widgets
|
||||
|
||||
Column {
|
||||
anchors {
|
||||
top: parent.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 6
|
||||
}
|
||||
width: 300
|
||||
height: childrenRect.height + anchors.margins * 2
|
||||
spacing: 6
|
||||
Item {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
margins: 12
|
||||
}
|
||||
width: childrenRect.width
|
||||
height: children[1].height
|
||||
Image {
|
||||
anchors {
|
||||
left: parent.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
verticalCenterOffset: 1
|
||||
}
|
||||
width: 24
|
||||
height: width
|
||||
sourceSize {width: width; height: height}
|
||||
source: Quickshell.iconPath("brightnesssettings")
|
||||
}
|
||||
Text {
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.children[0].right
|
||||
leftMargin: 6
|
||||
}
|
||||
font.pixelSize: 16
|
||||
color: "white"
|
||||
text: "Laptop display"
|
||||
}
|
||||
}
|
||||
Widgets.Slider {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
margins: 12
|
||||
}
|
||||
height: 24
|
||||
value: Brightness.monitors[0].value / Brightness.monitors[0].max
|
||||
onMoved: {
|
||||
Brightness.monitors[0].set(Math.round(Brightness.monitors[0].max * position))
|
||||
}
|
||||
}
|
||||
component ToggleButton: Item {
|
||||
id: toggleButton
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
margins: 12
|
||||
}
|
||||
height: children[0].height
|
||||
property bool active: false
|
||||
property var text
|
||||
Text {
|
||||
anchors {
|
||||
left: parent.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
height: 24
|
||||
font.pixelSize: 14
|
||||
color: "white"
|
||||
text: toggleButton.text
|
||||
}
|
||||
Rectangle {
|
||||
anchors {
|
||||
right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
rightMargin: (24 - width)/2 + (36-24)/2
|
||||
}
|
||||
radius: height/2
|
||||
color: parent.active ? "white" : "#00ffffff"
|
||||
height: 10
|
||||
width: parent.active ? 36 : 24
|
||||
border.width: parent.active ? height/2 : 2
|
||||
border.color: "white"
|
||||
Behavior on width {NumberAnimation { duration: 150; easing.type: Easing.OutCubic }}
|
||||
Behavior on border.width {NumberAnimation { duration: 150; easing.type: Easing.OutCubic }}
|
||||
}
|
||||
}
|
||||
ToggleButton {
|
||||
id: sunsetToggle
|
||||
text: "Night Light"
|
||||
Process {
|
||||
running: true
|
||||
command: [ "pgrep", "-x", "sunset" ]
|
||||
onExited: (exitCode) => {if (!exitCode) sunsetToggle.active = true}
|
||||
}
|
||||
TapHandler {
|
||||
property var idleProc: Process {command: ["hyprsunset"]}
|
||||
property var idleKill: Process {command: ["pkill", "-x", "hyprsunset"]}
|
||||
onTapped: {
|
||||
parent.active = !parent.active
|
||||
if (parent.active)
|
||||
idleProc.startDetached()
|
||||
else
|
||||
idleKill.startDetached()
|
||||
}
|
||||
}
|
||||
}
|
||||
ToggleButton {
|
||||
id: idleToggle
|
||||
text: "Idle Timer"
|
||||
Process {
|
||||
running: true
|
||||
command: [ "pgrep", "-x", "hypridle" ]
|
||||
onExited: (exitCode) => {if (!exitCode) idleToggle.active = true}
|
||||
}
|
||||
TapHandler {
|
||||
property var idleProc: Process {command: ["hypridle"]}
|
||||
property var idleKill: Process {command: ["pkill", "-x", "hypridle"]}
|
||||
onTapped: {
|
||||
parent.active = !parent.active
|
||||
if (parent.active)
|
||||
idleProc.startDetached()
|
||||
else
|
||||
idleKill.startDetached()
|
||||
}
|
||||
}
|
||||
}
|
||||
ToggleButton {
|
||||
id: dpmsToggle
|
||||
text: "Screen on"
|
||||
active: true
|
||||
TapHandler {
|
||||
property var resetTimer: Timer {
|
||||
interval: 500
|
||||
running: false
|
||||
repeat: false
|
||||
onTriggered: dpmsToggle.active = true
|
||||
}
|
||||
onTapped: {
|
||||
dpmsToggle.active = false;
|
||||
Hyprland.dispatch("dpms off");
|
||||
resetTimer.start();
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ Item {
|
||||
margins: 6
|
||||
}
|
||||
height: 48
|
||||
color: "#181818"
|
||||
color: "#111"
|
||||
radius: 10
|
||||
TextInput {
|
||||
id: input
|
||||
@@ -95,7 +95,6 @@ Item {
|
||||
property: "x"
|
||||
duration: 300
|
||||
easing.type: Easing.OutQuint
|
||||
onStarted: console.log("displaced")
|
||||
}
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
@@ -146,7 +145,7 @@ Item {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 64
|
||||
height: width
|
||||
source: Quickshell.iconPath(modelData.icon)
|
||||
source: Quickshell.iconPath(modelData.icon, "application-default")
|
||||
}
|
||||
Text {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -20,7 +20,7 @@ Item {
|
||||
Rectangle {
|
||||
width: 400
|
||||
height: 300
|
||||
color: "#181818"
|
||||
color: "#111"
|
||||
radius: 10
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
@@ -47,7 +47,6 @@ Item {
|
||||
anchors.rightMargin: anchors.leftMargin
|
||||
clip: true
|
||||
spacing: 4
|
||||
interactive: background.index === 3
|
||||
|
||||
add: Transition {NumberAnimation {
|
||||
property: "opacity"
|
||||
@@ -69,7 +68,7 @@ Item {
|
||||
header: Item {height: 4; width: 1}
|
||||
model: Array.from(notifServer.trackedNotifications.values)
|
||||
delegate: Widgets.Notification {
|
||||
color: "#222"
|
||||
color: "#181818"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,25 +97,32 @@ Item {
|
||||
}
|
||||
}
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
margins: 6
|
||||
}
|
||||
opacity: Mpris.players.values.length
|
||||
Behavior on opacity {NumberAnimation {duration: 150}}
|
||||
Shape {
|
||||
id: progressShape
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 180
|
||||
height: 180
|
||||
width: 160
|
||||
height: width
|
||||
property var strokeWidth: 6
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
ShapePath {
|
||||
capStyle: ShapePath.RoundCap
|
||||
strokeColor: "#444"
|
||||
fillColor: "transparent"
|
||||
strokeWidth: 4
|
||||
strokeWidth: progressShape.strokeWidth
|
||||
PathAngleArc {
|
||||
moveToStart: true
|
||||
radiusX: 90 - 6
|
||||
radiusY: 90 - 6
|
||||
centerX: 90
|
||||
centerY: 90
|
||||
radiusX: (progressShape.width-progressShape.strokeWidth)/2
|
||||
radiusY: (progressShape.height-progressShape.strokeWidth)/2
|
||||
centerX: progressShape.width/2
|
||||
centerY: progressShape.height/2
|
||||
startAngle: 90 + 20
|
||||
sweepAngle: 360 - 40
|
||||
}
|
||||
@@ -125,13 +131,13 @@ Item {
|
||||
capStyle: ShapePath.RoundCap
|
||||
strokeColor: "white"
|
||||
fillColor: "transparent"
|
||||
strokeWidth: 4
|
||||
strokeWidth: 6
|
||||
PathAngleArc {
|
||||
moveToStart: true
|
||||
radiusX: 90 - 6
|
||||
radiusY: 90 - 6
|
||||
centerX: 90
|
||||
centerY: 90
|
||||
radiusX: (progressShape.width-progressShape.strokeWidth)/2
|
||||
radiusY: (progressShape.height-progressShape.strokeWidth)/2
|
||||
centerX: progressShape.width/2
|
||||
centerY: progressShape.height/2
|
||||
startAngle: 90 + 20
|
||||
sweepAngle: (player.modelData?.position/player.modelData.length) * (360 - 40)
|
||||
}
|
||||
@@ -140,9 +146,12 @@ Item {
|
||||
color: "transparent"
|
||||
radius: height/2
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
anchors.margins: progressShape.strokeWidth*2
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
mipmap: true
|
||||
smooth: true
|
||||
source: player.modelData?.trackArtUrl ?? source
|
||||
}
|
||||
NumberAnimation on rotation {
|
||||
@@ -159,15 +168,25 @@ Item {
|
||||
}
|
||||
Item {width: 1; height: 10}
|
||||
Text {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
elide: Text.ElideRight
|
||||
color: "white"
|
||||
text: player.modelData?.trackTitle ?? ""
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.pixelSize: 16
|
||||
}
|
||||
Text {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
elide: Text.ElideRight
|
||||
color: "white"
|
||||
text: player.modelData?.trackArtist ?? ""
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.pixelSize: 12
|
||||
}
|
||||
Item {width: 1; height: 8}
|
||||
|
||||
@@ -9,7 +9,7 @@ Item {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
width: 350
|
||||
height: childrenRect.height
|
||||
height: childrenRect.height + 12
|
||||
Connections {
|
||||
target: notifServer
|
||||
function onNotification(notif) {
|
||||
@@ -22,6 +22,7 @@ Item {
|
||||
}
|
||||
Widgets.Notification {
|
||||
id: notifPopup
|
||||
y: 6
|
||||
anchors.margins: 6
|
||||
modelData: notifServer.trackedNotifications.values[0] ?? undefined
|
||||
color: "transparent"
|
||||
@@ -32,4 +33,8 @@ Item {
|
||||
interval: 3000
|
||||
onTriggered: root.close()
|
||||
}
|
||||
Connections {
|
||||
target: background
|
||||
function onIndexChanged() { timeout.stop() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ Item {
|
||||
bottom: parent.bottom
|
||||
}
|
||||
Widgets.Battery {}
|
||||
Widgets.Volume {}
|
||||
Widgets.Brightness {}
|
||||
}
|
||||
Widgets.Workspaces {
|
||||
height: parent.height
|
||||
@@ -31,6 +33,7 @@ Item {
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
Widgets.Uptime {}
|
||||
Widgets.Time {}
|
||||
}
|
||||
}
|
||||
|
||||
104
Panes/Volume.qml
Normal file
104
Panes/Volume.qml
Normal file
@@ -0,0 +1,104 @@
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import Quickshell.Services.Pipewire
|
||||
import qs.Widgets as Widgets
|
||||
|
||||
Row {
|
||||
anchors {
|
||||
top: parent.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
padding: 6
|
||||
height: 316
|
||||
spacing: 6
|
||||
|
||||
PwObjectTracker {
|
||||
objects: Pipewire.nodes.values.filter(node => [17, 21].includes(node.type))
|
||||
}
|
||||
|
||||
component NodeList: ClippingRectangle {
|
||||
id: nodeListRect
|
||||
width: 350
|
||||
color: "transparent"
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 6
|
||||
}
|
||||
radius: 10
|
||||
property var model
|
||||
clip: true
|
||||
ListView {
|
||||
anchors.fill: parent
|
||||
spacing: 6
|
||||
header: Item {width: 1; height: 6}
|
||||
footer: header
|
||||
model: nodeListRect.model
|
||||
delegate: Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
radius: 12
|
||||
color: "#111"
|
||||
height: children[1].height
|
||||
Image {
|
||||
anchors {
|
||||
left: parent.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
leftMargin: 6
|
||||
}
|
||||
sourceSize {width: width; height: height}
|
||||
source: Quickshell.iconPath((() => {
|
||||
const description = modelData.description.toLowerCase();
|
||||
if (description.search("hdmi") !== -1)
|
||||
return "display"
|
||||
if (description.search("speaker") !== -1)
|
||||
return "audio-speakers"
|
||||
if (description.search("earphone") !== -1 || description.search("headphone") !== -1)
|
||||
return "audio-headset"
|
||||
if (modelData.properties["device.icon-name"])
|
||||
return modelData.properties["device.icon-name"]
|
||||
return modelData.properties["application.name"]
|
||||
})()?.toLowerCase(), "audio-on")
|
||||
width: 32
|
||||
height: width
|
||||
}
|
||||
Column {
|
||||
anchors {
|
||||
left: parent.children[0].right
|
||||
right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
margins: 6
|
||||
rightMargin: 12
|
||||
}
|
||||
topPadding: 6
|
||||
bottomPadding: 6
|
||||
spacing: 2
|
||||
Text {
|
||||
text: {
|
||||
if (modelData.nickname !== "") return modelData.nickname
|
||||
if (modelData.description !== "") return description
|
||||
return modelData.name
|
||||
}
|
||||
color: "white"
|
||||
font.pixelSize: 16
|
||||
}
|
||||
Widgets.Slider {
|
||||
value: modelData.audio.volume
|
||||
onMoved: modelData.audio.volume = position
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NodeList {
|
||||
model: Pipewire.nodes.values.filter(node => node.type === 17)
|
||||
}
|
||||
NodeList {
|
||||
model: Pipewire.nodes.values.filter(node => node.type === 21)
|
||||
}
|
||||
}
|
||||
68
Services/Brightness.qml
Normal file
68
Services/Brightness.qml
Normal file
@@ -0,0 +1,68 @@
|
||||
pragma Singleton
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Hyprland
|
||||
|
||||
Singleton {
|
||||
id: brightness
|
||||
property var monitors: []
|
||||
Process {
|
||||
id: lsbacklight
|
||||
running: true
|
||||
command: ["find", "/sys/class/backlight", "-maxdepth", "1", "-mindepth", "1"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: brightness.monitors = this.text.split('\n')
|
||||
.filter(mon => mon)
|
||||
.map(mon => brightnessMonitorGen.createObject(brightness, {path: mon}))
|
||||
}
|
||||
}
|
||||
Component {
|
||||
id: brightnessMonitorGen
|
||||
BrightnessMonitor {}
|
||||
}
|
||||
component BrightnessMonitor: QtObject {
|
||||
id: monitor
|
||||
property var path
|
||||
property var value
|
||||
property var max
|
||||
property var get: Process {
|
||||
running: true
|
||||
command: ["brightnessctl", "i", "-m"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: [,,value,,max] = this.text.split(",")
|
||||
}
|
||||
}
|
||||
property var setInterp: Process {
|
||||
running: false
|
||||
command: ["brillo", "-r", "-u", "300000", "-S", value]
|
||||
}
|
||||
property var setInstant: Process {
|
||||
running: false
|
||||
command: ["brightnessctl", "s", value]
|
||||
}
|
||||
function increase() {
|
||||
value += value * 0.1 + max * 0.01
|
||||
value = Math.min(max, value)
|
||||
setInterp.startDetached()
|
||||
}
|
||||
function decrease() {
|
||||
value -= value * 0.1 + max * 0.01
|
||||
value = Math.max(0, value)
|
||||
setInterp.startDetached()
|
||||
}
|
||||
function set(value) {
|
||||
this.value = Math.max(Math.min(value, max), 0)
|
||||
setInstant.startDetached()
|
||||
}
|
||||
}
|
||||
GlobalShortcut {
|
||||
name: "increase_brightness"
|
||||
onPressed: monitors[0]?.increase()
|
||||
}
|
||||
GlobalShortcut {
|
||||
name: "decrease_brightness"
|
||||
onPressed: monitors[0]?.decrease()
|
||||
}
|
||||
}
|
||||
12
TopBar.qml
12
TopBar.qml
@@ -36,7 +36,7 @@ PanelWindow {
|
||||
|
||||
GlobalShortcut {
|
||||
id: shortcut
|
||||
name: "topbar"
|
||||
name: "peek_bar"
|
||||
description: "Hold to peek, tap to toggle topbar"
|
||||
onPressed: {
|
||||
background.index = 0
|
||||
@@ -70,7 +70,7 @@ PanelWindow {
|
||||
id: background
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
color: "#222222"
|
||||
color: "#181818"
|
||||
radius: 16
|
||||
width: children[0].width + radius*2
|
||||
height: children[0].height
|
||||
@@ -107,6 +107,7 @@ PanelWindow {
|
||||
}
|
||||
width: children[0].width
|
||||
height: children[0].height
|
||||
visible: opacity
|
||||
opacity: 0
|
||||
property var fadeIn: SequentialAnimation {
|
||||
PauseAnimation {duration: 200}
|
||||
@@ -156,6 +157,8 @@ PanelWindow {
|
||||
Pane { Panes.Battery {} }
|
||||
Pane { Panes.NotificationCenter {} }
|
||||
Pane { Panes.Notifications {} }
|
||||
Pane { Panes.Volume {} }
|
||||
Pane { Panes.Brightness {} }
|
||||
|
||||
property var entry: SequentialAnimation {
|
||||
PauseAnimation {duration: 2}
|
||||
@@ -180,6 +183,9 @@ PanelWindow {
|
||||
launcher.clear()
|
||||
}
|
||||
}
|
||||
HoverHandler {id: hover}
|
||||
HoverHandler {
|
||||
id: hover
|
||||
onHoveredChanged: { if (!hovered && background.index === 0) root.close() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
7
Wall.qml
7
Wall.qml
@@ -15,6 +15,11 @@ Variants {
|
||||
aboveWindows: false
|
||||
property var modelData
|
||||
screen: modelData
|
||||
color: "#141414"
|
||||
color: "#111"
|
||||
Image {
|
||||
source: Quickshell.shellPath("wallpaper")
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,13 @@ Item {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
width: children[1].width + 20
|
||||
width: children[1].width + 16
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 4
|
||||
anchors.rightMargin: 2
|
||||
color: hover.hovered ? "#11ffffff" : "#00ffffff"
|
||||
Behavior on color {ColorAnimation {duration: 150}}
|
||||
radius: 8
|
||||
bottomLeftRadius: 12
|
||||
}
|
||||
|
||||
40
Widgets/Brightness.qml
Normal file
40
Widgets/Brightness.qml
Normal file
@@ -0,0 +1,40 @@
|
||||
import Quickshell
|
||||
import QtQuick.Shapes
|
||||
import qs.Services
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
width: children[1].width + 16
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 4
|
||||
anchors.leftMargin: 2
|
||||
anchors.rightMargin: 2
|
||||
color: hover.hovered ? "#11ffffff" : "#00ffffff"
|
||||
Behavior on color {ColorAnimation {duration: 150}}
|
||||
radius: 8
|
||||
}
|
||||
PercentIndicator {
|
||||
x: 8
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 26
|
||||
height: width
|
||||
percent: Brightness.monitors[0].value / Brightness.monitors[0].max
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
width: 20
|
||||
height: width
|
||||
sourceSize {width: width; height: height}
|
||||
source: Quickshell.iconPath("brightnesssettings")
|
||||
}
|
||||
}
|
||||
HoverHandler {id: hover}
|
||||
TapHandler {onTapped: {
|
||||
background.index = 6
|
||||
}}
|
||||
}
|
||||
40
Widgets/PercentIndicator.qml
Normal file
40
Widgets/PercentIndicator.qml
Normal file
@@ -0,0 +1,40 @@
|
||||
import Quickshell
|
||||
import QtQuick.Shapes
|
||||
import Quickshell.Services.Pipewire
|
||||
import QtQuick
|
||||
|
||||
Shape {
|
||||
id: root
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
property var percent
|
||||
ShapePath {
|
||||
capStyle: ShapePath.RoundCap
|
||||
fillColor: "transparent"
|
||||
strokeColor: "#333"
|
||||
strokeWidth: 2
|
||||
PathAngleArc {
|
||||
moveToStart: true
|
||||
centerX: root.width/2
|
||||
centerY: root.height/2
|
||||
radiusX: root.width/2
|
||||
radiusY: root.height/2
|
||||
startAngle: 90 + 40
|
||||
sweepAngle: 360 - 80
|
||||
}
|
||||
}
|
||||
ShapePath {
|
||||
capStyle: ShapePath.RoundCap
|
||||
fillColor: "transparent"
|
||||
strokeColor: "white"
|
||||
strokeWidth: 2
|
||||
PathAngleArc {
|
||||
moveToStart: true
|
||||
centerX: root.width/2
|
||||
centerY: root.height/2
|
||||
radiusX: root.width/2 - 1
|
||||
radiusY: root.height/2 - 1
|
||||
startAngle: 90 + 40
|
||||
sweepAngle: root.percent * (360 - 80)
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Widgets/Slider.qml
Normal file
42
Widgets/Slider.qml
Normal file
@@ -0,0 +1,42 @@
|
||||
import QtQuick.Controls as QQC
|
||||
import QtQuick
|
||||
|
||||
QQC.Slider {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
height: 24
|
||||
orientation: Qt.Horizontal
|
||||
handle: Rectangle {
|
||||
x: parent.visualPosition * (parent.availableWidth - width)
|
||||
y: parent.availableHeight / 2 - height / 2
|
||||
height: 16
|
||||
width: 4
|
||||
radius: width/2
|
||||
}
|
||||
background: Rectangle {
|
||||
height: 6
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.handle.right
|
||||
right: parent.right
|
||||
leftMargin: 4
|
||||
}
|
||||
color: "#333"
|
||||
topRightRadius: height/2
|
||||
bottomRightRadius: topRightRadius
|
||||
}
|
||||
Rectangle {
|
||||
height: 6
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
right: parent.handle.left
|
||||
rightMargin: 4
|
||||
}
|
||||
color: "white"
|
||||
topLeftRadius: height/2
|
||||
bottomLeftRadius: topLeftRadius
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ Item {
|
||||
radius: 8
|
||||
bottomRightRadius: 12
|
||||
color: hover.hovered ? "#11ffffff" : "#00ffffff"
|
||||
Behavior on color {ColorAnimation {duration: 100}}
|
||||
Behavior on color {ColorAnimation {duration: 150}}
|
||||
}
|
||||
Row {
|
||||
spacing: 12
|
||||
|
||||
7
Widgets/Uptime.qml
Normal file
7
Widgets/Uptime.qml
Normal file
@@ -0,0 +1,7 @@
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
anchors {
|
||||
}
|
||||
}
|
||||
44
Widgets/Volume.qml
Normal file
44
Widgets/Volume.qml
Normal file
@@ -0,0 +1,44 @@
|
||||
import Quickshell
|
||||
import QtQuick.Shapes
|
||||
import Quickshell.Services.Pipewire
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
width: children[1].width + 16
|
||||
|
||||
PwObjectTracker {
|
||||
objects: [Pipewire.defaultAudioSink]
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 4
|
||||
anchors.leftMargin: 2
|
||||
anchors.rightMargin: 2
|
||||
color: hover.hovered ? "#11ffffff" : "#00ffffff"
|
||||
Behavior on color {ColorAnimation {duration: 150}}
|
||||
radius: 8
|
||||
}
|
||||
PercentIndicator {
|
||||
x: 8
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 26
|
||||
height: width
|
||||
percent: Pipewire.defaultAudioSink.audio.volume
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
width: 20
|
||||
height: width
|
||||
sourceSize {width: width; height: height}
|
||||
source: Quickshell.iconPath("volume-level-high")
|
||||
}
|
||||
}
|
||||
HoverHandler {id: hover}
|
||||
TapHandler {onTapped: {
|
||||
background.index = 5
|
||||
}}
|
||||
}
|
||||
@@ -18,9 +18,11 @@ Item {
|
||||
width: 24
|
||||
property var workspace: Hyprland.workspaces.values.find(ws => ws.id === modelData+1)
|
||||
property var icon: {
|
||||
const appId = workspace ? Array.from(workspace.toplevels.values).sort(
|
||||
(a, b) => b.lastIpcObject.focusHistoryId - a.lastIpcObject.focusHistoryId
|
||||
)[0]?.wayland?.appId : undefined
|
||||
let appId
|
||||
if (workspace) {
|
||||
let toplevel = Array.from(workspace.toplevels.values).reduce((prev, curr) => (prev.lastIpcObject.focusHistoryID < curr.lastIpcObject.focusHistoryID) ? prev : curr)
|
||||
appId = toplevel.wayland?.appId
|
||||
}
|
||||
return DesktopEntries.applications.values.find(
|
||||
app => app.startupClass === appId || app.id === appId
|
||||
)?.icon;
|
||||
@@ -59,4 +61,8 @@ Item {
|
||||
height: 4
|
||||
radius: height/2
|
||||
}
|
||||
Connections {
|
||||
target: Hyprland
|
||||
function onActiveToplevelChanged() {Hyprland.refreshToplevels()}
|
||||
}
|
||||
}
|
||||
|
||||
11
shell.qml
11
shell.qml
@@ -1,3 +1,4 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Services.Notifications
|
||||
@@ -9,12 +10,20 @@ ShellRoot {
|
||||
onNotification: (notif) => notif.tracked = true
|
||||
}
|
||||
Shell.Wall {}
|
||||
Shell.TopBar {}
|
||||
Shell.TopBar {id: bar}
|
||||
Shell.Boateye {}
|
||||
Shell.Lock {
|
||||
id: lock
|
||||
animate: true
|
||||
}
|
||||
PanelWindow {
|
||||
anchors {
|
||||
top: true
|
||||
}
|
||||
implicitHeight: 1
|
||||
implicitWidth: 800
|
||||
HoverHandler {onHoveredChanged: {if (hovered) bar.open() }}
|
||||
}
|
||||
IpcHandler {
|
||||
target: "lock"
|
||||
function instalock() {lock.animate = false; lock.locked = true}
|
||||
|
||||
Reference in New Issue
Block a user