Initial commit

This commit is contained in:
kossLAN 2025-06-07 04:01:14 -04:00
commit 05cd51b54e
Signed by: kossLAN
SSH key fingerprint: SHA256:bdV0x+wdQHGJ6LgmstH3KV8OpWY+OOFmJcPcB0wQPV8
148 changed files with 10112 additions and 0 deletions

33
bar/control/Button.qml Normal file
View file

@ -0,0 +1,33 @@
import Quickshell
import QtQuick
import "../../widgets/" as Widgets
Widgets.IconButton {
id: root
required property var bar
required property var screen
implicitSize: 20
source: "root:/resources/general/nixos.svg"
padding: 2
onClicked: {
if (controlPanel.visible) {
controlPanel.hide();
} else {
controlPanel.show();
}
}
ControlPanel {
id: controlPanel
anchor {
window: root.screen
onAnchoring: {
anchor.rect = mapToItem(root.screen.contentItem, 0, root.screen.height, width, 0);
}
}
}
}

View file

@ -0,0 +1,308 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
import Quickshell.Services.Mpris
import Qt5Compat.GraphicalEffects
import "volume" as Volume
import "../../widgets/" as Widgets
import "../.."
// Change to PopupWindow
PopupWindow {
id: root
implicitWidth: 400
implicitHeight: container.height + 10
color: "transparent"
visible: container.opacity > 0
anchor.rect.x: 0
anchor.rect.y: parentWindow.implicitHeight
// anchors {
// top: true
// left: true
// }
function show() {
container.opacity = 1;
grab.active = true;
}
function hide() {
container.opacity = 0;
grab.active = false;
}
HyprlandFocusGrab {
id: grab
windows: [root]
onCleared: {
root.hide();
}
}
// Add drop shadow effect
// Rectangle {
// id: shadowSource
// color: ShellSettings.settings.colors["surface"]
// radius: 8
// opacity: container.opacity
// width: container.width
// height: container.height
//
// anchors {
// top: parent.top
// left: parent.left
// margins: 5
// }
//
// layer.enabled: true
// layer.effect: DropShadow {
// horizontalOffset: 0
// verticalOffset: 2
// radius: 8.0
// samples: 17
// color: Qt.rgba(0, 0, 0, 0.5)
// transparentBorder: true
// }
// visible: false // Hide the source rectangle
// }
Item {
id: shadowItem
anchors.fill: container
z: container.z - 1
opacity: container.opacity
Rectangle {
id: shadowRect
anchors.fill: parent
color: "transparent"
layer.enabled: true
layer.effect: DropShadow {
horizontalOffset: 0
verticalOffset: 2
radius: 8.0
samples: 17
color: Qt.rgba(0, 0, 0, 0.5)
source: container
}
}
}
Rectangle {
id: container
color: ShellSettings.settings.colors["surface"]
radius: 18
opacity: 0
width: parent.width - 10
height: contentColumn.implicitHeight + 20
anchors {
top: parent.top
left: parent.left
margins: 5
}
Behavior on opacity {
NumberAnimation {
duration: 300
easing.type: Easing.OutCubic
}
}
ColumnLayout {
id: contentColumn
spacing: 10
anchors {
top: parent.top
left: parent.left
right: parent.right
margins: 10
}
// RowLayout {
// Layout.fillWidth: true
// Layout.preferredHeight: 40
//
// Rectangle {
// radius: 20
// color: ShellSettings.settings.colors["surface_container_high"]
// Layout.fillWidth: true
// Layout.fillHeight: true
//
// RowLayout {
// anchors {
// fill: parent
// leftMargin: 6
// }
//
// ProfileImage {
// id: profileImage
// Layout.preferredWidth: 25
// Layout.preferredHeight: 25
// // implicitWidth: 30
// // implicitHeight: 30
// }
//
// Text {
// text: "kossLAN"
// color: ShellSettings.settings.colors["inverse_surface"]
// font.pointSize: 12
// verticalAlignment: Text.AlignVCenter
// Layout.fillWidth: true
// Layout.fillHeight: true
// Layout.margins: 4
// }
// }
// }
//
// Rectangle {
// radius: 20
// color: ShellSettings.settings.colors["surface_container_high"]
// Layout.preferredWidth: powerButtons.implicitWidth + 10
// Layout.fillHeight: true
//
// RowLayout {
// id: powerButtons
// spacing: 10
//
// anchors {
// fill: parent
// leftMargin: 5
// rightMargin: 5
// }
//
// Widgets.IconButton {
// id: sleepButton
// implicitSize: 24
// radius: 20
// source: "root:resources/control/sleep.svg"
// onClicked: sleepProcess.running = true
// }
//
// Process {
// id: sleepProcess
// running: false
// command: ["hyprctl", "dispatch", "dpms", "off"]
// }
//
// Rectangle {
// radius: 20
// color: ShellSettings.settings.colors["surface_bright"]
// Layout.preferredWidth: 2
// Layout.fillHeight: true
// Layout.topMargin: 4
// Layout.bottomMargin: 4
// }
//
// Widgets.IconButton {
// id: powerButton
// implicitSize: 24
// radius: 20
// source: "root:resources/control/shutdown.svg"
// }
// }
// }
// }
RowLayout {
spacing: 15
Layout.fillWidth: true
Rectangle {
color: ShellSettings.settings.colors["surface_container_high"]
radius: 12
Layout.fillWidth: true
Layout.preferredHeight: 30
}
}
RowLayout {
spacing: 15
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
Repeater {
model: [1, 2, 3, 4, 5]
delegate: Rectangle {
color: ShellSettings.settings.colors["surface_container_high"]
radius: width / 2
Layout.preferredWidth: 45
Layout.preferredHeight: 45
}
}
}
ColumnLayout {
spacing: 10
Layout.fillWidth: true
RowLayout {
spacing: 10
Layout.fillWidth: true
Layout.preferredHeight: 55
Rectangle {
color: ShellSettings.settings.colors["primary"]
radius: width / 2
Layout.fillWidth: true
Layout.fillHeight: true
}
Rectangle {
color: ShellSettings.settings.colors["primary"]
radius: width / 2
Layout.fillWidth: true
Layout.fillHeight: true
}
}
RowLayout {
spacing: 10
Layout.fillWidth: true
Layout.preferredHeight: 55
Rectangle {
color: ShellSettings.settings.colors["surface_container_high"]
radius: width / 2
Layout.fillWidth: true
Layout.fillHeight: true
}
Rectangle {
color: ShellSettings.settings.colors["surface_container_high"]
radius: width / 2
Layout.fillWidth: true
Layout.fillHeight: true
}
}
}
Volume.Mixer {
id: sinkMixer
isSink: true
Layout.fillWidth: true
}
Volume.Mixer {
id: sourceMixer
isSink: false
Layout.fillWidth: true
}
MediaPlayer {
player: Mpris.players?.values[0]
visible: Mpris.players?.values.length != 0
Layout.fillWidth: true
Layout.preferredHeight: 150
}
}
}
}

248
bar/control/MediaPlayer.qml Normal file
View file

@ -0,0 +1,248 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell
import Quickshell.Services.Mpris
import "../.."
import "../../widgets" as Widgets
Item {
id: root
required property var player
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: root.width
height: root.height
radius: 14
color: "black"
}
}
ColorQuantizer {
id: gradientQuantizer
source: root.player?.trackArtUrl ?? ""
depth: 2
rescaleSize: 64
}
ColorQuantizer {
id: accentQuantizer
source: root.player?.trackArtUrl ?? ""
depth: 0
rescaleSize: 64
}
ShaderEffect {
property color topLeftColor: gradientQuantizer?.colors[0] ?? "white"
property color topRightColor: gradientQuantizer?.colors[1] ?? "black"
property color bottomLeftColor: gradientQuantizer?.colors[2] ?? "white"
property color bottomRightColor: gradientQuantizer?.colors[3] ?? "black"
anchors.fill: parent
fragmentShader: "root:/shaders/vertexgradient.frag.qsb"
vertexShader: "root:/shaders/vertexgradient.vert.qsb"
Behavior on topLeftColor {
ColorAnimation {
duration: 500
easing.type: Easing.InOutQuad
}
}
Behavior on topRightColor {
ColorAnimation {
duration: 500
easing.type: Easing.InOutQuad
}
}
Behavior on bottomLeftColor {
ColorAnimation {
duration: 500
easing.type: Easing.InOutQuad
}
}
Behavior on bottomRightColor {
ColorAnimation {
duration: 500
easing.type: Easing.InOutQuad
}
}
}
RowLayout {
id: cardLayout
spacing: 15
anchors {
fill: parent
margins: 10
}
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 5
RowLayout {
Rectangle {
id: mprisImage
color: "transparent"
radius: 10
width: 50
height: 50
Layout.alignment: Qt.AlignVCenter
visible: true
layer.enabled: true
layer.effect: DropShadow {
transparentBorder: true
spread: 0.02
samples: 25
color: "#80000000"
}
Image {
anchors.fill: parent
source: root.player?.trackArtUrl ?? ""
sourceSize.width: 1024
sourceSize.height: 1024
fillMode: Image.PreserveAspectFit
layer.enabled: true
layer.effect: OpacityMask {
source: Rectangle {
width: mprisImage.width
height: mprisImage.height
radius: 10
color: "white"
}
maskSource: Rectangle {
width: mprisImage.width
height: mprisImage.height
radius: 10
color: "black"
}
}
}
}
ColumnLayout {
Layout.leftMargin: 7.5
Layout.alignment: Qt.AlignBottom
Text {
text: root.player?.trackArtist ?? "NA"
color: "white"
font.pointSize: 13
font.bold: true
horizontalAlignment: Text.AlignLeft
Layout.fillWidth: true
elide: Text.ElideRight
}
Text {
text: root.player?.trackTitle ?? "NA"
color: "white"
font.pointSize: 13
horizontalAlignment: Text.AlignLeft
Layout.fillWidth: true
elide: Text.ElideRight
}
}
}
RowLayout {
spacing: 6
Text {
text: timeStr(root.player?.position)
color: "white"
font {
pointSize: 9
bold: true
}
}
FrameAnimation {
running: root.player?.playbackState == MprisPlaybackState.Playing
onTriggered: root.player?.positionChanged()
}
Widgets.RoundSlider {
id: positionSlider
implicitHeight: 7
from: 0
to: root.player?.length
accentColor: accentQuantizer.colors[0]?.darker(1.2) ?? "purple"
value: root.player?.position ?? 0
Layout.fillWidth: true
onMoved: {
if (root.player == null)
return;
root.player.position = value;
}
}
Text {
text: timeStr(root.player?.length)
color: "white"
font {
pointSize: 9
bold: true
}
}
}
// Music Controls
RowLayout {
spacing: 2
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Widgets.IconButton {
implicitSize: 40
activeRectangle: false
padding: 4
source: "root:resources/mpris/previous.svg"
onClicked: root.player?.previous()
}
Widgets.IconButton {
implicitSize: 40
activeRectangle: false
padding: 4
source: root.player?.isPlaying ? "root:resources/mpris/pause.svg" : "root:resources/mpris/play.svg"
onClicked: {
if (!root.player?.canPlay)
return;
player.isPlaying ? player.pause() : player.play();
}
}
Widgets.IconButton {
implicitSize: 40
activeRectangle: false
padding: 4
source: "root:resources/mpris/next.svg"
onClicked: root.player?.next()
}
}
}
}
function timeStr(time: int): string {
const seconds = time % 60;
const minutes = Math.floor(time / 60);
return `${minutes}:${seconds.toString().padStart(2, '0')}`;
}
}

View file

@ -0,0 +1,33 @@
pragma ComponentBehavior: Bound
import QtQuick
import Qt5Compat.GraphicalEffects
Rectangle {
id: profileImage
color: "transparent"
Image {
anchors.fill: parent
source: "root:resources/general/pfp.png"
sourceSize.width: 100
sourceSize.height: 100
layer.enabled: true
layer.effect: OpacityMask {
source: Rectangle {
width: profileImage.width
height: profileImage.height
radius: 10
color: "white"
}
maskSource: Rectangle {
width: profileImage.width
height: profileImage.height
radius: 10
color: "black"
}
}
}
}

View file

@ -0,0 +1,79 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.Pipewire
import "../../.."
import "../../../widgets" as Widgets
Rectangle {
id: root
required property PwNode node
required property var isSink
color: ShellSettings.settings.colors["surface_container_high"]
PwObjectTracker {
id: defaultSourceTracker
objects: [root.node]
}
RowLayout {
anchors.fill: parent
spacing: 8
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: 2
spacing: 10
Text {
color: ShellSettings.settings.colors["inverse_surface"]
text: {
// Taken from quickshell-examples
const app = root.node?.properties["application.name"] ?? (root.node?.description != "" ? root.node?.description : root.node?.name);
const media = root.node?.properties["media.name"];
const title = media != undefined ? `${app} - ${media}` : app;
return title != undefined ? title : "null";
}
font.bold: true
elide: Text.ElideRight
Layout.fillWidth: true
Layout.topMargin: 5
Layout.rightMargin: 5
}
Widgets.RoundSlider {
implicitHeight: 7
from: 0
to: 1
value: root.node?.audio.volume ?? 0
onValueChanged: root.node.audio.volume = value
Layout.fillWidth: true
Layout.bottomMargin: 7.5
}
}
Widgets.IconButton {
source: {
if (!root.isSink)
return root.node?.audio.muted ? "root:resources/volume/microphone-mute.svg" : "root:resources/volume/microphone-full.svg";
return root.node?.audio.muted ? "root:resources/volume/volume-mute.svg" : "root:resources/volume/volume-full.svg";
}
implicitSize: 36
padding: 4
radius: implicitSize / 2
Layout.rightMargin: 10
Layout.alignment: Qt.AlignLeft
onClicked: {
root.node.audio.muted = !root.node.audio.muted;
}
}
}
}

View file

@ -0,0 +1,176 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import Quickshell.Widgets
import Quickshell.Services.Pipewire
import "../../../widgets/" as Widgets
import "../../.."
// TODO: refactor this trash
Rectangle {
id: root
required property var isSink
color: "transparent"
radius: 10
property bool expanded: false
property int baseHeight: 60
property int contentHeight: expanded ? (applicationVolumes.count * baseHeight) : 0
implicitHeight: baseHeight + contentHeight
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: root.width
height: root.height
radius: root.baseHeight / 2
color: "black"
}
}
Item {
id: headerSection
width: parent.width
height: root.baseHeight
anchors.top: parent.top
RowLayout {
spacing: 0
anchors.fill: parent
Rectangle {
color: ShellSettings.settings.colors["surface_container_high"]
Widgets.IconButton {
id: arrowButton
implicitSize: 44
activeRectangle: false
source: "root:resources/general/right-arrow.svg"
padding: 4
rotation: root.expanded ? 90 : 0
anchors.centerIn: parent
Behavior on rotation {
NumberAnimation {
duration: 150
easing.type: Easing.OutCubic
}
}
onClicked: {
root.expanded = !root.expanded;
}
}
Layout.preferredWidth: 40
Layout.preferredHeight: root.baseHeight
}
Card {
node: root.isSink ? Pipewire.defaultAudioSink : Pipewire.defaultAudioSource
isSink: root.isSink
Layout.fillWidth: true
Layout.preferredHeight: root.baseHeight
}
}
}
Rectangle {
id: divider
color: ShellSettings.settings.colors["surface_bright"]
height: 2
width: parent.width
anchors.top: headerSection.bottom
opacity: root.expanded ? 1.0 : 0.0
// Behavior on opacity {
// NumberAnimation {
// duration: 150
// easing.type: Easing.OutCubic
// }
// }
}
Item {
id: contentSection
width: parent.width
anchors.top: divider.bottom
height: root.contentHeight
clip: true
// Behavior on height {
// SmoothedAnimation {
// duration: 150
// velocity: 200
// easing.type: Easing.OutCubic
// }
// }
Column {
id: applicationsColumn
width: parent.width
anchors.top: parent.top
opacity: root.expanded ? 1.0 : 0.0
// Behavior on opacity {
// NumberAnimation {
// duration: 100
// easing.type: Easing.OutCubic
// }
// }
PwNodeLinkTracker {
id: linkTracker
node: root.isSink ? Pipewire.defaultAudioSink : Pipewire.defaultAudioSource
}
Repeater {
id: applicationVolumes
model: linkTracker.linkGroups
delegate: RowLayout {
id: cardRow
required property PwLinkGroup modelData
spacing: 0
width: applicationsColumn.width
height: root.baseHeight
Rectangle {
color: ShellSettings.settings.colors["surface_container_high"]
IconImage {
implicitSize: 32
source: {
if (cardRow.modelData.source?.properties["application.icon-name"] == null) {
return "root:resources/general/placeholder.svg";
}
return `image://icon/${cardRow.modelData.source?.properties["application.icon-name"]}`;
}
anchors {
fill: parent
leftMargin: 8
rightMargin: 8
}
}
Layout.preferredWidth: 40
Layout.preferredHeight: root.baseHeight
}
Card {
node: cardRow.modelData.source
isSink: root.isSink
Layout.fillWidth: true
Layout.preferredHeight: root.baseHeight
}
}
}
}
}
}