quickshell restruct and work

This commit is contained in:
2025-07-27 17:05:34 +01:00
parent aa612919ec
commit 57689e5f8b
21 changed files with 505 additions and 219 deletions

View File

@@ -1,34 +0,0 @@
import QtQuick
import QtQuick.Effects
FullwidthMouseArea {
id: root
property bool showPressed: mouseArea.pressed;
property real baseMargin: 0;
property bool directScale: false;
readonly property Item contentItem: mContentItem;
default property alias contentItemData: mContentItem.data;
property real targetBrightness: root.showPressed ? -25 : root.mouseArea.containsMouse && root.enabled ? 75 : 0
Behavior on targetBrightness { SmoothedAnimation { velocity: 600 } }
property real targetMargins: root.showPressed ? 3 : 0;
Behavior on targetMargins { SmoothedAnimation { velocity: 25 } }
hoverEnabled: true
Item {
id: mContentItem
anchors.fill: parent;
anchors.margins: root.baseMargin + (root.directScale ? 0 : root.targetMargins);
scale: root.directScale ? (width - root.targetMargins * 2) / width : 1.0;
opacity: root.enabled ? 1.0 : 0.5;
Behavior on opacity { SmoothedAnimation { velocity: 5 } }
layer.enabled: root.targetBrightness != 0
layer.effect: MultiEffect { brightness: root.targetBrightness / 1000 }
}
}

View File

@@ -1,79 +0,0 @@
import QtQuick
import Quickshell
import Quickshell.Hyprland
import Quickshell.Wayland
PanelWindow {
id: root
default property alias barItems: containment.data;
anchors {
left: true
top: true
bottom: true
}
property real baseWidth: 55
property real leftMargin: root.compactState * 10
width: baseWidth + 15
exclusiveZone: baseWidth + (isFullscreenWorkspace ? 0 : 15) - margins.left
mask: Region {
height: root.height
width: root.exclusiveZone
}
color: "transparent"
WlrLayershell.namespace: "shell:bar"
readonly property Tooltip tooltip: tooltip;
Tooltip {
id: tooltip
bar: root
}
readonly property real tooltipXOffset: root.baseWidth + root.leftMargin + 5;
function boundedY(targetY: real, height: real): real {
return Math.max(barRect.anchors.topMargin + height, Math.min(barRect.height + barRect.anchors.topMargin - height, targetY))
}
readonly property bool isFullscreenWorkspace: Hyprland.monitorFor(screen).activeWorkspace.hasFullscreen
property real compactState: isFullscreenWorkspace ? 0 : 1
Behavior on compactState {
NumberAnimation {
duration: 600
easing.type: Easing.BezierSpline
easing.bezierCurve: [0.0, 0.75, 0.15, 1.0, 1.0, 1.0]
}
}
Rectangle {
id: barRect
x: root.leftMargin - Lock.Controller.lockSlide * (barRect.width + root.leftMargin)
width: parent.width - 15
anchors {
top: parent.top
bottom: parent.bottom
margins: root.compactState * 10
}
color: ShellGlobals.colors.bar
radius: root.compactState * 5
border.color: ShellGlobals.colors.barOutline
border.width: root.compactState
Item {
id: containment
anchors {
fill: parent
margins: 5
}
}
}
}

View File

@@ -1,45 +0,0 @@
pragma Singleton
import Quickshell
import Quickshell.Io
import QtQuick
import Quickshell.Services.Mpris
Singleton {
id: root
// property MprisPlayer trackedPlayer: null;
readonly property MprisPlayer activePlayer: PlayerController.activePlayer.identity === "Spotify"
? PlayerController.activePlayer
: null
readonly property string time: {
root.activePlayer.trackTitle
}
readonly property string artist: {
root.activePlayer.trackArtist
}
readonly property string timetime: {
Math.floor(root.activePlayer.position / 60) + ":" +
formatTwoDigits(Math.floor(root.activePlayer.position % 60))
}
readonly property string fulltime: {
Math.floor(root.activePlayer.length / 60) + ":" +
formatTwoDigits(Math.floor(root.activePlayer.length % 60))
}
function formatTwoDigits(num) {
return (num < 10 ? "0" : "") + num;
}
Timer {
// only emit the signal when the position is actually changing.
running: root.activePlayer.playbackState == MprisPlaybackState.Playing
// Make sure the position updates at least once per second.
interval: 1000
repeat: true
// emit the positionChanged signal every second.
onTriggered: root.activePlayer.positionChanged()
}
}

View File

@@ -1,25 +0,0 @@
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
import QtQuick.Effects
import Quickshell.Services.SystemTray
Item {
width: layout.width
height: layout.height
RowLayout {
id: layout
Repeater {
// id: repeater
model: SystemTray.items
required property int index
Text {
text: SystemTray.items.values[parent.index]
font.pointSize: 10
}
}
}
}

View File

@@ -1,12 +0,0 @@
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
import Quickshell.Hyprland
Item {
RowLayout {
}
}

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M220-240v-480h80v480h-80Zm520 0L380-480l360-240v480Z"/></svg>

After

Width:  |  Height:  |  Size: 177 B

View File

@@ -1,9 +1,14 @@
//@ pragma UseQApplication
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
import "widgets" as Widgets
import "widgets/player" as Player
import "widgets/common" as Common
// Tako kindly threatened you to sort the naming schema and to put all the svg's in an asset folder, so please do that
PanelWindow {
@@ -30,30 +35,31 @@ import Quickshell.Widgets
RowLayout { // Center
// TODO: add icons of the active window per workspace in the workspace tab
anchors.centerIn: parent
Workspaces {}
Widgets.Workspaces {}
}
RowLayout { // Right
Layout.alignment: Qt.AlignRight
VerticalSeprator {}
Common.VerticalSeprator {}
Loader {
sourceComponent: Audio {}
sourceComponent: Widgets.Audio {}
}
RowLayout {
visible: Player.activePlayer.isPlaying()
VerticalSeprator {}
PlayerText {
Common.VerticalSeprator {}
Player.PlayerWidgetV2 {
}
}
VerticalSeprator {}
Common.VerticalSeprator {}
WrapperItem {
Text { // Date & Time
text: Time.time
text: Widgets.Time.time
color: '#FFFFFF'
font.pointSize: 10.75
}
}
SystemTray {}
// VerticalSeprator {}
Widgets.SystemTray {
id: systemTray
}
}
}
Rectangle {

View File

@@ -0,0 +1,63 @@
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
import QtQuick.Effects
import Quickshell.Services.SystemTray
Item {
id: root
Layout.preferredHeight: 30
Layout.preferredWidth: layout.implicitWidth
RowLayout {
spacing: 0
anchors {
top: parent.top
bottom: parent.bottom
}
id: layout
Repeater {
model: SystemTray.items
delegate: Item {
required property SystemTrayItem modelData
id: item
Layout.preferredHeight: 30
Layout.preferredWidth: 30
MouseArea {
anchors.fill: parent
anchors.centerIn: parent
onPressed: event => {
item.modelData.display(trayItemPopupWindow, mouseX, mouseY)
}
}
IconImage {
anchors.centerIn: parent
implicitSize: 20
source: modelData.icon
}
PopupWindow {
// hacky ass way to get a tray item popup window
implicitHeight: 1
implicitWidth: 1
color: "transparent"
id: trayItemPopupWindow
anchor.item: item
visible: true
}
}
}
}
Rectangle {
z: -1
anchors {
left: root.left
right: root.right
verticalCenter: root.verticalCenter
}
height: root.height - 5
radius: 6
color: "black"
}
}

View File

@@ -0,0 +1,8 @@
import Quickshell
import QtQuick
Text {
text: "•"
color: "white"
font.pointSize: 12.5
}

View File

@@ -0,0 +1,9 @@
import Quickshell
import QtQuick
Item {
function iconFromDesktopfile(location): String { // testing // serves no purpose atm
return "/usr/share/pixmaps/spotify-client.png"
return "/usr/share/pixmaps/" + DesktopEntries.byId(location).icon + ".png"
}
}

View File

@@ -22,13 +22,19 @@ Singleton {
property var activeTrack;
property string activeTrackPositionFormated: "0:00";
property string activeTrackLengthFormated: "0:00";
PersistentProperties {
id: persist
reloadableId: "MusicWidget";
property string lastActivePlayerIdentify: "";
onReloaded: {
// rightclickMenu.snapOpacity(widgetOpen ? 1.0 : 0.0)
root.updateActiveTrackPosition()
}
onLoaded: {
root.updateActiveTrackPosition()
}
}
@@ -61,7 +67,8 @@ Singleton {
}
function onPlaybackStateChanged() {
if (root.trackedPlayer !== modelData) root.trackedPlayer = modelData;
console.log("Playback state has been changed")
// if (root.trackedPlayer !== modelData) root.trackedPlayer = modelData;
}
}
}
@@ -89,8 +96,14 @@ Singleton {
onActivePlayerChanged: this.updateTrack();
function setPlayerByIdentity(id: string) {
for (var i = 0; i < 9; i++) {
console.log(i)
}
mpris.players
}
function updateTrack() {
//console.log(`update: ${this.activePlayer?.trackTitle ?? ""} : ${this.activePlayer?.trackArtists}`)
this.activeTrack = {
uniqueId: this.activePlayer?.uniqueId ?? 0,
artUrl: this.activePlayer?.trackArtUrl ?? "",
@@ -103,6 +116,8 @@ Singleton {
this.__reverse = false;
}
property bool isPlaying: this.activePlayer && this.activePlayer.isPlaying;
property bool canTogglePlaying: this.activePlayer?.canTogglePlaying ?? false;
function togglePlaying() {
@@ -144,12 +159,36 @@ Singleton {
}
function setActivePlayer(player: MprisPlayer) {
const targetPlayer = player ?? Mpris.players[0];
const targetPlayer = player;
console.log(`setactive: ${targetPlayer} from ${activePlayer}`)
persist.lastActivePlayerIdentify = targetPlayer.identity
this.activePlayer = player;
}
Timer {
// only emit the signal when the position is actually changing.
running: root.activePlayer.playbackState == MprisPlaybackState.Playing
// Make sure the position updates at least once per second.
interval: 1000
repeat: true
// emit the positionChanged signal every second.
onTriggered: root.updateActiveTrackPosition()
}
function updateActiveTrackPosition() {
activeTrackPositionFormated = Math.floor(root.activePlayer.position / 60) + ":" + ("0" + Math.floor(root.activePlayer.position % 60)).slice(-2)
activeTrackLengthFormated = Math.floor(root.activePlayer.length / 60) + ":" + ("0" + Math.floor(root.activePlayer.length % 60)).slice(-2)
}
function update() {
updateActiveTrackPosition()
}
function trackPositionFormatter(position: double): string {
return Math.floor(position / 60) + ":" + ("0" + Math.floor(position % 60)).slice(-2)
}
function findSpotify(): MprisPlayer {
const players = Mpris.players
for (const player of players.values) {
@@ -157,6 +196,7 @@ Singleton {
return player
}
}
return undefined
console.log("");
}

View File

@@ -0,0 +1,205 @@
import QtQml
import QtQuick
import Quickshell
import QtQuick.Layouts
import QtQuick.Controls
import Quickshell.Services.Mpris
PopupWindow {
property PlayerControllerV2 player: PlayerControllerV2;
id: audioPopup
anchor {
item: root
}
anchor.rect.x: root.width / 2 - width / 2
anchor.rect.y: root.height * 1.2
height: columnContainer.height + 5
width: 425
Rectangle {
anchors.fill: parent
color: "#919191"
ColumnLayout {
id: columnContainer
anchors.centerIn: parent
Repeater {
model: player.mpris.players
Item {
id: root
width: 400
height: 80
required property MprisPlayer modelData
property string trackPosition: PlayerControllerV2.trackPositionFormatter(root.modelData.position)
property string trackLength: "0:00"
Rectangle {
id: background
anchors.fill: parent
color: "black"
radius: 7
}
MouseArea {
anchors.fill: parent
onClicked: event => {
audioPopup.player.setActivePlayer(root.modelData);
audioPopup.player.update();
}
}
ColumnLayout {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
Layout.alignment: Qt.AlignHCenter
width:380
RowLayout {
implicitWidth: 380
Item {
implicitWidth: 50
implicitHeight: 50
Image {
anchors.fill: parent
source: root.modelData.trackArtUrl
}
}
ColumnLayout {
spacing: 2
ScrollView {
implicitWidth: 230
height: parent.height
Text {
text: root.modelData.trackTitle
color: "white"
font.pointSize: 11
antialiasing: true
}
}
Text {
text: root.modelData.trackArtist
color: "white"
font.pointSize: 6
antialiasing: true
}
}
Rectangle { // Spacer
color: "transparent"
Layout.fillWidth: true
}
RowLayout {
Layout.alignment: Qt.AlignRight
spacing: 0
// buttons
Item {
width: 30
height: 25
Rectangle {
id: gobackButton
width: 30
height: 25
topLeftRadius: 7
bottomLeftRadius: 7
color: "white"
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: event => {
gobackButton.color = "grey"
}
onExited: event => {
gobackButton.color = "white"
}
}
}
Item {
width: 30
height: 25
Item {
width: 30
height: 25
Rectangle {
id: pauseButton
width: 30
height: 25
// topLeftRadius: 7
// bottomLeftRadius: 7
color: "white"
}
}
MouseArea {
// id: pauseButton
anchors.fill: parent
hoverEnabled: true
onEntered: event => {
pauseButton.color = "grey"
}
onExited: event => {
pauseButton.color = "white"
}
onClicked: event => {
root.modelData.togglePlaying();
}
}
}
Item {
width: 30
height: 25
Rectangle {
id: gonextButton
width: 30
height: 25
topRightRadius: 7
bottomRightRadius: 7
color: "white"
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: event => {
gonextButton.color = "grey"
}
onExited: event => {
gonextButton.color = "white"
}
}
}
}
}
RowLayout {
Slider {
id: slider
Layout.fillWidth: true
from: 0
value: root.modelData.position
to: root.modelData.length
onMoved: event => {
root.modelData.position = slider.value
audioPopup.player.update(); // force values to update // causing ui to update with it
}
Timer {
running: root.modelData.playbackState == MprisPlaybackState.Playing
interval: 500
repeat: true
onTriggered: slider.value = root.modelData.position
}
}
Text {
id: positionText
text: trackPosition + "/" + trackLength // returns float of seconds of length
color: "white"
font.pointSize: 10
}
}
}
Timer {
running: root.modelData.isPlaying
interval: 1000
repeat: true
onTriggered: {
trackPosition = PlayerControllerV2.trackPositionFormatter(root.modelData.position)
trackLength = PlayerControllerV2.trackPositionFormatter(root.modelData.length)
}
}
}
}
}
}
}

View File

@@ -10,9 +10,7 @@ Item {
id: root
Layout.fillHeight: true
implicitWidth: hi.width
visible: Player.activePlayer.canPlay()
property PlayerControllerV2 player: PlayerControllerV2;
MouseArea {
anchors.fill: parent
@@ -25,7 +23,7 @@ Item {
}
}
Image {
source: Player.activePlayer.trackArtUrl;
source: player.activePlayer.trackArtUrl;
anchors.fill: parent
fillMode: Image.PreserveAspectCrop
@@ -49,7 +47,7 @@ Item {
MouseArea {
anchors.fill: parent
onPressed: event => {
Player.activePlayer.previous();
player.activePlayer.previous();
}
}
}
@@ -58,17 +56,15 @@ Item {
implicitWidth: 30;
IconImage {
implicitSize: 30;
source: !Player.activePlayer.isPlaying ? "root:/assets/media_player/playbutton.svg" : "root:/assets/media_player/pausebutton.svg";
source: !player.activePlayer.isPlaying ? "root:/assets/media_player/playbutton.svg" : "root:/assets/media_player/pausebutton.svg";
}
MouseArea {
anchors.fill: parent
hoverEnabled: false
onPressed: event => {
Player.activePlayer.togglePlaying();
// console.debug("" + Player.activePlayer.)
player.activePlayer.togglePlaying();
}
}
// PopupAnchor {}
}
Item {
@@ -81,7 +77,7 @@ Item {
MouseArea {
anchors.fill: parent
onPressed: event => {
Player.activePlayer.next();
player.activePlayer.next();
}
}
}

View File

@@ -0,0 +1,151 @@
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
import Quickshell.Widgets
import QtQuick.Effects
import "../common" as Common
// import playbutton.svg
Item {
property PlayerControllerV2 player: PlayerControllerV2;
id: root
Layout.fillHeight: true
Layout.preferredWidth: mainLayout.width + 10
Loader {
id: audioPopupLoader
active: true
sourceComponent: PlayerPopupV2 {
id: audioPopup
}
}
RowLayout {
id: mainLayout
Layout.fillHeight: true
anchors {
verticalCenter: parent.verticalCenter
horizontalCenter: parent.horizontalCenter
}
Common.Meow {
id: commons
}
Item {
implicitWidth: text.width
implicitHeight: text.height
Rectangle {
id: hoverColor
anchors.centerIn: parent
visible: false
radius: 7
width: parent.width + 5
height: parent.height + 2.5
color: "grey"
}
Text {
id: text
text: (root.player.activePlayer == undefined) ? "Nothing" : player.activePlayer.trackTitle
color: "white"
font.pointSize: 10
font.italic: (root.player.activePlayer == undefined) ? true : false
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: event => {
hoverColor.visible = true
}
onExited: event => {
hoverColor.visible = false
}
onClicked: event => {
audioPopupLoader.item.visible = !audioPopupLoader.item.visible;
}
}
}
Common.Dot {}
Item {
id: mediaPositionControls
implicitWidth: positionText.width
implicitHeight: positionText.height
Text {
id: positionText
text: root.player.activeTrackPositionFormated + "/" + player.activeTrackLengthFormated // returns float of seconds of length
color: "white"
font.pointSize: 10
}
RowLayout {
visible: !positionText.visible
// enable: !positionText.visible
anchors {
left: parent.left
right: parent.right
}
anchors.verticalCenter: parent.verticalCenter
Item {
width: 20
height: 20
IconImage {
anchors.fill: parent
implicitSize: 20
source: "root:/assets/media_player/skip_previous.svg"
}
}
Item {
width: 20
height: 20
MouseArea {
anchors.fill: parent
width: 20
height: 20
hoverEnabled: true
onClicked: event => {
root.player.activePlayer.togglePlaying()
}
}
IconImage {
anchors.fill: parent
implicitSize: 20
source: (root.player.activePlayer.isPlaying) ? "root:/assets/media_player/pausebutton.svg" : "root:/assets/media_player/playbutton.svg"
}
}
Item {
width: 20
height: 20
IconImage {
anchors.fill: parent
implicitSize: 20
source: "root:/assets/media_player/skip_next.svg"
}
}
}
MouseArea {
z: 1
id: mouseAreaMediaButtons
height: parent.height + 15
anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: true // allows events to transparently go through to an overlapping mouseArea
onEntered: event => {
positionText.visible = false;
}
onExited: event => {
positionText.visible = true;
}
}
}
}
Rectangle {
z: -1
color: "black"
anchors {
verticalCenter: parent.verticalCenter
}
height: 25
width: parent.width
radius: 7
}
}

View File

@@ -1,6 +1,8 @@
//@ pragma UseQApplication
import Quickshell
import QtQuick
import "bar" as Bar
Scope {
Bar {}
Bar.Bar {}
}