configs are here
This commit is contained in:
47
quickshell_/Audio.qml
Normal file
47
quickshell_/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: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: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"
|
||||
}
|
||||
}
|
||||
}
|
||||
67
quickshell_/Bar.qml
Normal file
67
quickshell_/Bar.qml
Normal file
@@ -0,0 +1,67 @@
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell.Widgets
|
||||
|
||||
PanelWindow {
|
||||
property var modelData
|
||||
screen: modelData.values[0];
|
||||
|
||||
color: '#20ffffff'
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: true
|
||||
}
|
||||
|
||||
implicitHeight: 30
|
||||
RowLayout {
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: 10
|
||||
rightMargin: 10
|
||||
}
|
||||
RowLayout { // Left
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
}
|
||||
RowLayout { // Center
|
||||
// TODO: add icons of the active window per workspace in the workspace tab
|
||||
anchors.centerIn: parent
|
||||
Workspaces {}
|
||||
}
|
||||
RowLayout { // Right
|
||||
Layout.alignment: Qt.AlignRight
|
||||
VerticalSeprator {}
|
||||
Loader {
|
||||
sourceComponent: Audio {}
|
||||
}
|
||||
RowLayout {
|
||||
id: aaaaa
|
||||
// If player disapear the seprator disapears with it
|
||||
visible: Player.activePlayer.isPlaying()
|
||||
VerticalSeprator {}
|
||||
PlayerText {
|
||||
}
|
||||
}
|
||||
VerticalSeprator {}
|
||||
WrapperItem {
|
||||
Text { // Date & Time
|
||||
text: Time.time
|
||||
color: '#FFFFFF'
|
||||
font.pointSize: 10.75
|
||||
}
|
||||
}
|
||||
// VerticalSeprator {}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
height: 2
|
||||
color: "#8d8d8d"
|
||||
}
|
||||
}
|
||||
34
quickshell_/BarButton.qml
Normal file
34
quickshell_/BarButton.qml
Normal file
@@ -0,0 +1,34 @@
|
||||
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 }
|
||||
}
|
||||
}
|
||||
79
quickshell_/BarContain.qml
Normal file
79
quickshell_/BarContain.qml
Normal file
@@ -0,0 +1,79 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
53
quickshell_/FullwidthMouseArea.qml
Normal file
53
quickshell_/FullwidthMouseArea.qml
Normal file
@@ -0,0 +1,53 @@
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property bool fillWindowWidth: false;
|
||||
property real extraVerticalMargin: 0;
|
||||
|
||||
property alias mouseArea: mouseArea;
|
||||
property alias hoverEnabled: mouseArea.hoverEnabled;
|
||||
property alias acceptedButtons: mouseArea.acceptedButtons;
|
||||
property alias pressedButtons: mouseArea.pressedButtons;
|
||||
property alias containsMouse: mouseArea.containsMouse;
|
||||
property alias isPressed: mouseArea.pressed;
|
||||
|
||||
signal clicked(event: MouseEvent);
|
||||
signal entered();
|
||||
signal exited();
|
||||
signal pressed(event: MouseEvent);
|
||||
signal released(event: MouseEvent);
|
||||
signal wheel(event: WheelEvent);
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
anchors {
|
||||
fill: parent
|
||||
// not much point in finding exact values
|
||||
leftMargin: root.fillWindowWidth ? -50 : 0
|
||||
rightMargin: root.fillWindowWidth ? -50 : 0
|
||||
topMargin: -root.extraVerticalMargin
|
||||
bottomMargin: -root.extraVerticalMargin
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
this.clicked.connect(root.clicked);
|
||||
//this.entered.connect(root.entered);
|
||||
//this.exited.connect(root.exited);
|
||||
//this.pressed.connect(root.pressed);
|
||||
this.released.connect(root.released);
|
||||
//this.wheel.connect(root.wheel);
|
||||
}
|
||||
|
||||
// for some reason MouseArea.pressed is both a prop and signal so connect doesn't work
|
||||
onPressed: event => root.pressed(event);
|
||||
|
||||
// connecting to onwheel seems to implicitly accept it. undo that.
|
||||
onWheel: event => {
|
||||
event.accepted = false;
|
||||
root.wheel(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
1
quickshell_/Mic.svg
Normal file
1
quickshell_/Mic.svg
Normal 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="M480-420q-41.92 0-70.96-29.04Q380-478.08 380-520v-240q0-41.92 29.04-70.96Q438.08-860 480-860q41.92 0 70.96 29.04Q580-801.92 580-760v240q0 41.92-29.04 70.96Q521.92-420 480-420Zm-30 290v-131.85q-99-11.31-164.5-84.92Q220-420.39 220-520h60q0 83 58.5 141.5T480-320q83 0 141.5-58.5T680-520h60q0 99.61-65.5 173.23Q609-273.16 510-261.85V-130h-60Z"/></svg>
|
||||
|
After Width: | Height: | Size: 463 B |
45
quickshell_/Player.qml
Normal file
45
quickshell_/Player.qml
Normal file
@@ -0,0 +1,45 @@
|
||||
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()
|
||||
}
|
||||
}
|
||||
173
quickshell_/PlayerController.qml
Normal file
173
quickshell_/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(); }
|
||||
}
|
||||
}
|
||||
176
quickshell_/PlayerControllerV2.qml
Normal file
176
quickshell_/PlayerControllerV2.qml
Normal file
@@ -0,0 +1,176 @@
|
||||
// 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;
|
||||
|
||||
PersistentProperties {
|
||||
id: persist
|
||||
reloadableId: "MusicWidget";
|
||||
property string lastActivePlayerIdentify: "";
|
||||
|
||||
onReloaded: {
|
||||
// rightclickMenu.snapOpacity(widgetOpen ? 1.0 : 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
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}`)
|
||||
|
||||
this.activePlayer = player;
|
||||
}
|
||||
|
||||
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(); }
|
||||
}
|
||||
}
|
||||
48
quickshell_/PlayerPopup.qml
Normal file
48
quickshell_/PlayerPopup.qml
Normal file
@@ -0,0 +1,48 @@
|
||||
import QtQml
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import QtQuick.Layouts
|
||||
|
||||
PopupWindow {
|
||||
property PlayerControllerV2 playerController: null;
|
||||
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
129
quickshell_/PlayerText.qml
Normal file
129
quickshell_/PlayerText.qml
Normal file
@@ -0,0 +1,129 @@
|
||||
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
|
||||
|
||||
visible: Player.activePlayer.canPlay()
|
||||
|
||||
|
||||
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:skip_next";
|
||||
scale: -1
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: event => {
|
||||
Player.activePlayer.previous();
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
implicitHeight: 30;
|
||||
implicitWidth: 30;
|
||||
IconImage {
|
||||
implicitSize: 30;
|
||||
source: !Player.activePlayer.isPlaying ? "root:playbutton.svg" : "root:pausebutton.svg";
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: false
|
||||
onPressed: event => {
|
||||
Player.activePlayer.togglePlaying();
|
||||
// console.debug("" + Player.activePlayer.)
|
||||
}
|
||||
}
|
||||
// PopupAnchor {}
|
||||
}
|
||||
|
||||
Item {
|
||||
implicitHeight: 30;
|
||||
implicitWidth: 30;
|
||||
IconImage {
|
||||
implicitSize: 30;
|
||||
source: "root:skip_next";
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: event => {
|
||||
Player.activePlayer.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PopupWindow {
|
||||
id: audioPopup
|
||||
color: "transparent"
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
quickshell_/Speaker.svg
Normal file
1
quickshell_/Speaker.svg
Normal 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="M561.54-155.62v-62q86.54-27.53 139.42-100 52.89-72.46 52.89-163.38t-52.89-163.38q-52.88-72.47-139.42-100v-62q111.69 29.92 182 119.92 70.3 90 70.3 205.46 0 115.46-70.3 205.46-70.31 90-182 119.92ZM146.16-380v-200h148.46l171.53-171.53v543.06L294.62-380H146.16Zm415.38 46.15v-294.3q40.46 22 62.54 61.96 22.07 39.96 22.07 86.19 0 45.61-22.27 84.88-22.27 39.27-62.34 61.27Z"/></svg>
|
||||
|
After Width: | Height: | Size: 492 B |
18
quickshell_/Time.qml
Normal file
18
quickshell_/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
|
||||
}
|
||||
}
|
||||
13
quickshell_/VerticalSeprator.qml
Normal file
13
quickshell_/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"
|
||||
}
|
||||
12
quickshell_/WindowInfo.qml
Normal file
12
quickshell_/WindowInfo.qml
Normal file
@@ -0,0 +1,12 @@
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell.Widgets
|
||||
import Quickshell.Hyprland
|
||||
|
||||
Item {
|
||||
RowLayout {
|
||||
|
||||
}
|
||||
}
|
||||
42
quickshell_/Workspaces.qml
Normal file
42
quickshell_/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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
quickshell_/pausebutton.svg
Normal file
1
quickshell_/pausebutton.svg
Normal 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="M560-200v-560h160v560H560Zm-320 0v-560h160v560H240Z"/></svg>
|
||||
|
After Width: | Height: | Size: 176 B |
1
quickshell_/playbutton.svg
Normal file
1
quickshell_/playbutton.svg
Normal 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="M320-200v-560l440 280-440 280Z"/></svg>
|
||||
|
After Width: | Height: | Size: 155 B |
6
quickshell_/shell.qml
Normal file
6
quickshell_/shell.qml
Normal file
@@ -0,0 +1,6 @@
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Scope {
|
||||
Bar {}
|
||||
}
|
||||
1
quickshell_/skip_next.svg
Normal file
1
quickshell_/skip_next.svg
Normal 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="M660-240v-480h80v480h-80Zm-440 0v-480l360 240-360 240Z"/></svg>
|
||||
|
After Width: | Height: | Size: 179 B |
Reference in New Issue
Block a user