quickshell restruct and work
This commit is contained in:
47
quickshell/bar/widgets/Audio.qml
Normal file
47
quickshell/bar/widgets/Audio.qml
Normal file
@@ -0,0 +1,47 @@
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell.Widgets
|
||||
import Quickshell.Services.Pipewire
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property PwNode speakerNode: Pipewire.defaultAudioSink
|
||||
property PwNode microphoneNode: Pipewire.defaultAudioSource
|
||||
PwObjectTracker { objects: [ root.microphoneNode, root.speakerNode ] }
|
||||
|
||||
width: row.width
|
||||
height: row.height
|
||||
|
||||
// console.log("a");
|
||||
|
||||
RowLayout {
|
||||
id: row
|
||||
|
||||
IconImage {
|
||||
// anchors.centerIn: parent
|
||||
implicitSize: 27
|
||||
source: "root:/assets/bar/Speaker.svg"
|
||||
}
|
||||
|
||||
|
||||
Text {
|
||||
id: text
|
||||
text: root.speakerNode.audio.muted ? "0%" : root.speakerNode.audio.volume * 100 + "%"
|
||||
font.pointSize: 10.75
|
||||
color: root.speakerNode.audio.muted ? "red" : "#FFFFFF"
|
||||
}
|
||||
|
||||
IconImage {
|
||||
implicitSize: 26
|
||||
source: "root:/assets/bar/Mic.svg"
|
||||
}
|
||||
|
||||
Text {
|
||||
text: parseInt(root.microphoneNode.audio.muted ? "0" : root.microphoneNode.audio.volume * 100) + "%"
|
||||
font.pointSize: 10.75
|
||||
color: root.microphoneNode.audio.muted ? "red" : "#FFFFFF"
|
||||
}
|
||||
}
|
||||
}
|
||||
63
quickshell/bar/widgets/SystemTray.qml
Normal file
63
quickshell/bar/widgets/SystemTray.qml
Normal 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"
|
||||
}
|
||||
}
|
||||
18
quickshell/bar/widgets/Time.qml
Normal file
18
quickshell/bar/widgets/Time.qml
Normal file
@@ -0,0 +1,18 @@
|
||||
pragma Singleton
|
||||
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property string time: {
|
||||
Qt.formatDateTime(clock.date, "ddd d MMM [hh:mm]")
|
||||
}
|
||||
|
||||
|
||||
SystemClock {
|
||||
id: clock
|
||||
precision: SystemClock.Minutes
|
||||
}
|
||||
}
|
||||
42
quickshell/bar/widgets/Workspaces.qml
Normal file
42
quickshell/bar/widgets/Workspaces.qml
Normal file
@@ -0,0 +1,42 @@
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell.Widgets
|
||||
import Quickshell.Hyprland
|
||||
|
||||
RowLayout {
|
||||
id: root
|
||||
spacing: 3
|
||||
|
||||
Repeater {
|
||||
model: Hyprland.workspaces
|
||||
delegate: Item {
|
||||
required property int index
|
||||
property HyprlandWorkspace index_workspace: Hyprland.workspaces.values[index]
|
||||
width: 25
|
||||
height: 30
|
||||
MouseArea {
|
||||
Rectangle {
|
||||
id: reg
|
||||
anchors.fill: parent
|
||||
color: index_workspace.focused ? "#3B3B3B" : "#808080"
|
||||
}
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: index_workspace.id
|
||||
color: "#FFFFFF"
|
||||
font.pointSize: 10.75
|
||||
}
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onPressed: event => {
|
||||
if (event.button === Qt.LeftButton) {
|
||||
Hyprland.dispatch('workspace ' + index_workspace.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
quickshell/bar/widgets/common/Dot.qml
Normal file
8
quickshell/bar/widgets/common/Dot.qml
Normal file
@@ -0,0 +1,8 @@
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Text {
|
||||
text: "•"
|
||||
color: "white"
|
||||
font.pointSize: 12.5
|
||||
}
|
||||
9
quickshell/bar/widgets/common/Meow.qml
Normal file
9
quickshell/bar/widgets/common/Meow.qml
Normal 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"
|
||||
}
|
||||
}
|
||||
13
quickshell/bar/widgets/common/VerticalSeprator.qml
Normal file
13
quickshell/bar/widgets/common/VerticalSeprator.qml
Normal file
@@ -0,0 +1,13 @@
|
||||
import Quickshell
|
||||
import QtQml
|
||||
import QtQuick
|
||||
|
||||
Rectangle {
|
||||
id: a
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
width: 2
|
||||
color: "#8d8d8d"
|
||||
}
|
||||
173
quickshell/bar/widgets/player/PlayerController.qml
Normal file
173
quickshell/bar/widgets/player/PlayerController.qml
Normal file
@@ -0,0 +1,173 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQml.Models
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Services.Mpris
|
||||
// import qs
|
||||
|
||||
Singleton {
|
||||
id: root;
|
||||
property MprisPlayer trackedPlayer: null;
|
||||
property MprisPlayer activePlayer: findSpotify();
|
||||
|
||||
|
||||
signal trackChanged(reverse: bool);
|
||||
|
||||
property bool __reverse: false;
|
||||
|
||||
property var activeTrack;
|
||||
|
||||
Instantiator {
|
||||
model: Mpris.players;
|
||||
|
||||
Connections {
|
||||
required property MprisPlayer modelData;
|
||||
target: modelData;
|
||||
|
||||
Component.onCompleted: {
|
||||
if (root.trackedPlayer == null || modelData.isPlaying) {
|
||||
root.trackedPlayer = modelData;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
if (root.trackedPlayer == null || !root.trackedPlayer.isPlaying) {
|
||||
for (const player of Mpris.players.values) {
|
||||
if (player.playbackState.isPlaying) {
|
||||
root.trackedPlayer = player;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (trackedPlayer == null && Mpris.players.values.length != 0) {
|
||||
trackedPlayer = Mpris.players.values[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onPlaybackStateChanged() {
|
||||
if (root.trackedPlayer !== modelData) root.trackedPlayer = modelData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: activePlayer
|
||||
|
||||
function onPostTrackChanged() {
|
||||
root.updateTrack();
|
||||
}
|
||||
|
||||
function onTrackArtUrlChanged() {
|
||||
console.log("arturl:", activePlayer.trackArtUrl)
|
||||
//root.updateTrack();
|
||||
if (root.activePlayer.uniqueId == root.activeTrack.uniqueId && root.activePlayer.trackArtUrl != root.activeTrack.artUrl) {
|
||||
// cantata likes to send cover updates *BEFORE* updating the track info.
|
||||
// as such, art url changes shouldn't be able to break the reverse animation
|
||||
const r = root.__reverse;
|
||||
root.updateTrack();
|
||||
root.__reverse = r;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onActivePlayerChanged: this.updateTrack();
|
||||
|
||||
function updateTrack() {
|
||||
//console.log(`update: ${this.activePlayer?.trackTitle ?? ""} : ${this.activePlayer?.trackArtists}`)
|
||||
this.activeTrack = {
|
||||
uniqueId: this.activePlayer?.uniqueId ?? 0,
|
||||
artUrl: this.activePlayer?.trackArtUrl ?? "",
|
||||
title: this.activePlayer?.trackTitle || "Unknown Title",
|
||||
artist: this.activePlayer?.trackArtist || "Unknown Artist",
|
||||
album: this.activePlayer?.trackAlbum || "Unknown Album",
|
||||
};
|
||||
|
||||
this.trackChanged(__reverse);
|
||||
this.__reverse = false;
|
||||
}
|
||||
|
||||
property bool isPlaying: this.activePlayer && this.activePlayer.isPlaying;
|
||||
property bool canTogglePlaying: this.activePlayer?.canTogglePlaying ?? false;
|
||||
function togglePlaying() {
|
||||
if (this.canTogglePlaying) this.activePlayer.togglePlaying();
|
||||
}
|
||||
|
||||
property bool canGoPrevious: this.activePlayer?.canGoPrevious ?? false;
|
||||
function previous() {
|
||||
if (this.canGoPrevious) {
|
||||
this.__reverse = true;
|
||||
this.activePlayer.previous();
|
||||
}
|
||||
}
|
||||
|
||||
property bool canGoNext: this.activePlayer?.canGoNext ?? false;
|
||||
function next() {
|
||||
if (this.canGoNext) {
|
||||
this.__reverse = false;
|
||||
this.activePlayer.next();
|
||||
}
|
||||
}
|
||||
|
||||
property bool canChangeVolume: this.activePlayer && this.activePlayer.volumeSupported && this.activePlayer.canControl;
|
||||
|
||||
property bool loopSupported: this.activePlayer && this.activePlayer.loopSupported && this.activePlayer.canControl;
|
||||
property var loopState: this.activePlayer?.loopState ?? MprisLoopState.None;
|
||||
function setLoopState(loopState: var) {
|
||||
if (this.loopSupported) {
|
||||
this.activePlayer.loopState = loopState;
|
||||
}
|
||||
}
|
||||
|
||||
property bool shuffleSupported: this.activePlayer && this.activePlayer.shuffleSupported && this.activePlayer.canControl;
|
||||
property bool hasShuffle: this.activePlayer?.shuffle ?? false;
|
||||
function setShuffle(shuffle: bool) {
|
||||
if (this.shuffleSupported) {
|
||||
this.activePlayer.shuffle = shuffle;
|
||||
}
|
||||
}
|
||||
|
||||
function setActivePlayer(player: MprisPlayer) {
|
||||
const targetPlayer = player ?? Mpris.players[0];
|
||||
console.log(`setactive: ${targetPlayer} from ${activePlayer}`)
|
||||
|
||||
if (targetPlayer && this.activePlayer) {
|
||||
this.__reverse = Mpris.players.indexOf(targetPlayer) < Mpris.players.indexOf(this.activePlayer);
|
||||
} else {
|
||||
// always animate forward if going to null
|
||||
this.__reverse = false;
|
||||
}
|
||||
|
||||
this.trackedPlayer = targetPlayer;
|
||||
}
|
||||
|
||||
function findSpotify(): MprisPlayer {
|
||||
const players = Mpris.players
|
||||
for (const player of players.values) {
|
||||
if (player.identity == "Spotify") {
|
||||
return player
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
console.log("");
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "mpris"
|
||||
|
||||
function pauseAll(): void {
|
||||
for (const player of Mpris.players.values) {
|
||||
if (player.canPause) player.pause();
|
||||
}
|
||||
}
|
||||
|
||||
function playPause(): void { root.togglePlaying(); }
|
||||
function previous(): void { root.previous(); }
|
||||
function next(): void { root.next(); }
|
||||
}
|
||||
}
|
||||
216
quickshell/bar/widgets/player/PlayerControllerV2.qml
Normal file
216
quickshell/bar/widgets/player/PlayerControllerV2.qml
Normal file
@@ -0,0 +1,216 @@
|
||||
// Reworked the PlayerController a bit
|
||||
|
||||
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQml.Models
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Services.Mpris
|
||||
// import qs
|
||||
|
||||
Singleton {
|
||||
id: root;
|
||||
property Mpris mpris: Mpris;
|
||||
property MprisPlayer activePlayer: findSpotify();
|
||||
|
||||
signal trackChanged(reverse: bool);
|
||||
|
||||
property bool __reverse: false;
|
||||
|
||||
property var activeTrack;
|
||||
|
||||
property string activeTrackPositionFormated: "0:00";
|
||||
property string activeTrackLengthFormated: "0:00";
|
||||
|
||||
PersistentProperties {
|
||||
id: persist
|
||||
reloadableId: "MusicWidget";
|
||||
property string lastActivePlayerIdentify: "";
|
||||
|
||||
onReloaded: {
|
||||
root.updateActiveTrackPosition()
|
||||
}
|
||||
onLoaded: {
|
||||
root.updateActiveTrackPosition()
|
||||
}
|
||||
}
|
||||
|
||||
Instantiator {
|
||||
model: Mpris.players;
|
||||
|
||||
Connections {
|
||||
required property MprisPlayer modelData;
|
||||
target: modelData;
|
||||
|
||||
Component.onCompleted: {
|
||||
if (root.trackedPlayer == null || modelData.isPlaying) {
|
||||
root.trackedPlayer = modelData;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
if (root.trackedPlayer == null || !root.trackedPlayer.isPlaying) {
|
||||
for (const player of Mpris.players.values) {
|
||||
if (player.playbackState.isPlaying) {
|
||||
root.trackedPlayer = player;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (trackedPlayer == null && Mpris.players.values.length != 0) {
|
||||
trackedPlayer = Mpris.players.values[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onPlaybackStateChanged() {
|
||||
console.log("Playback state has been changed")
|
||||
// if (root.trackedPlayer !== modelData) root.trackedPlayer = modelData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: activePlayer
|
||||
|
||||
function onPostTrackChanged() {
|
||||
root.updateTrack();
|
||||
}
|
||||
|
||||
function onTrackArtUrlChanged() {
|
||||
console.log("arturl:", activePlayer.trackArtUrl)
|
||||
//root.updateTrack();
|
||||
if (root.activePlayer.uniqueId == root.activeTrack.uniqueId && root.activePlayer.trackArtUrl != root.activeTrack.artUrl) {
|
||||
// cantata likes to send cover updates *BEFORE* updating the track info.
|
||||
// as such, art url changes shouldn't be able to break the reverse animation
|
||||
const r = root.__reverse;
|
||||
root.updateTrack();
|
||||
root.__reverse = r;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onActivePlayerChanged: this.updateTrack();
|
||||
|
||||
function setPlayerByIdentity(id: string) {
|
||||
for (var i = 0; i < 9; i++) {
|
||||
console.log(i)
|
||||
}
|
||||
mpris.players
|
||||
}
|
||||
|
||||
function updateTrack() {
|
||||
this.activeTrack = {
|
||||
uniqueId: this.activePlayer?.uniqueId ?? 0,
|
||||
artUrl: this.activePlayer?.trackArtUrl ?? "",
|
||||
title: this.activePlayer?.trackTitle || "Unknown Title",
|
||||
artist: this.activePlayer?.trackArtist || "Unknown Artist",
|
||||
album: this.activePlayer?.trackAlbum || "Unknown Album",
|
||||
};
|
||||
|
||||
this.trackChanged(__reverse);
|
||||
this.__reverse = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
property bool isPlaying: this.activePlayer && this.activePlayer.isPlaying;
|
||||
property bool canTogglePlaying: this.activePlayer?.canTogglePlaying ?? false;
|
||||
function togglePlaying() {
|
||||
if (this.canTogglePlaying) this.activePlayer.togglePlaying();
|
||||
}
|
||||
|
||||
property bool canGoPrevious: this.activePlayer?.canGoPrevious ?? false;
|
||||
function previous() {
|
||||
if (this.canGoPrevious) {
|
||||
this.__reverse = true;
|
||||
this.activePlayer.previous();
|
||||
}
|
||||
}
|
||||
|
||||
property bool canGoNext: this.activePlayer?.canGoNext ?? false;
|
||||
function next() {
|
||||
if (this.canGoNext) {
|
||||
this.__reverse = false;
|
||||
this.activePlayer.next();
|
||||
}
|
||||
}
|
||||
|
||||
property bool canChangeVolume: this.activePlayer && this.activePlayer.volumeSupported && this.activePlayer.canControl;
|
||||
|
||||
property bool loopSupported: this.activePlayer && this.activePlayer.loopSupported && this.activePlayer.canControl;
|
||||
property var loopState: this.activePlayer?.loopState ?? MprisLoopState.None;
|
||||
function setLoopState(loopState: var) {
|
||||
if (this.loopSupported) {
|
||||
this.activePlayer.loopState = loopState;
|
||||
}
|
||||
}
|
||||
|
||||
property bool shuffleSupported: this.activePlayer && this.activePlayer.shuffleSupported && this.activePlayer.canControl;
|
||||
property bool hasShuffle: this.activePlayer?.shuffle ?? false;
|
||||
function setShuffle(shuffle: bool) {
|
||||
if (this.shuffleSupported) {
|
||||
this.activePlayer.shuffle = shuffle;
|
||||
}
|
||||
}
|
||||
|
||||
function setActivePlayer(player: MprisPlayer) {
|
||||
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) {
|
||||
if (player.identity == "Spotify") {
|
||||
return player
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
console.log("");
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "mpris"
|
||||
|
||||
function pauseAll(): void {
|
||||
for (const player of Mpris.players.values) {
|
||||
if (player.canPause) player.pause();
|
||||
}
|
||||
}
|
||||
|
||||
function playPause(): void { root.togglePlaying(); }
|
||||
function previous(): void { root.previous(); }
|
||||
function next(): void { root.next(); }
|
||||
}
|
||||
}
|
||||
46
quickshell/bar/widgets/player/PlayerPopup.qml
Normal file
46
quickshell/bar/widgets/player/PlayerPopup.qml
Normal file
@@ -0,0 +1,46 @@
|
||||
import QtQml
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import QtQuick.Layouts
|
||||
|
||||
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: 350
|
||||
width: 300
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "#919191"
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
Item {
|
||||
width: coverImg.width
|
||||
height: coverImg.height
|
||||
Image {
|
||||
id: coverImg
|
||||
anchors.fill: parent
|
||||
source: player.activePlayer.trackArtUrl;
|
||||
width: 275
|
||||
height: 275
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: player.activePlayer.trackTitle
|
||||
color: "white"
|
||||
font.pointSize: 10.75
|
||||
}
|
||||
Text {
|
||||
text: player.activePlayer.trackArtist
|
||||
color: "white"
|
||||
font.pointSize: 10.75
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
205
quickshell/bar/widgets/player/PlayerPopupV2.qml
Normal file
205
quickshell/bar/widgets/player/PlayerPopupV2.qml
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
88
quickshell/bar/widgets/player/PlayerWidget.qml
Normal file
88
quickshell/bar/widgets/player/PlayerWidget.qml
Normal file
@@ -0,0 +1,88 @@
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell.Widgets
|
||||
import QtQuick.Effects
|
||||
// import playbutton.svg
|
||||
|
||||
Item {
|
||||
id: root
|
||||
Layout.fillHeight: true
|
||||
implicitWidth: hi.width
|
||||
property PlayerControllerV2 player: PlayerControllerV2;
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: event => {
|
||||
audioPopup.visible = true;
|
||||
}
|
||||
onExited: event => {
|
||||
audioPopup.visible = false;
|
||||
}
|
||||
}
|
||||
Image {
|
||||
source: player.activePlayer.trackArtUrl;
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: MultiEffect {
|
||||
blur: 0.3
|
||||
blurEnabled: true
|
||||
}
|
||||
}
|
||||
// parent.aaaaa: false
|
||||
RowLayout {
|
||||
id: hi
|
||||
Item {
|
||||
implicitHeight: 30;
|
||||
implicitWidth: 30;
|
||||
IconImage {
|
||||
implicitSize: 30;
|
||||
source: "root:assets/media_player/skip_next.svg";
|
||||
scale: -1
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: event => {
|
||||
player.activePlayer.previous();
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
implicitHeight: 30;
|
||||
implicitWidth: 30;
|
||||
IconImage {
|
||||
implicitSize: 30;
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
implicitHeight: 30;
|
||||
implicitWidth: 30;
|
||||
IconImage {
|
||||
implicitSize: 30;
|
||||
source: "root:assets/media_player/skip_next.svg";
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: event => {
|
||||
player.activePlayer.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PlayerPopup {
|
||||
id: audioPopup
|
||||
}
|
||||
}
|
||||
151
quickshell/bar/widgets/player/PlayerWidgetV2.qml
Normal file
151
quickshell/bar/widgets/player/PlayerWidgetV2.qml
Normal 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user