last 7 months of qs changes

This commit is contained in:
outfoxxed 2025-01-06 00:13:19 -08:00
parent 2c64563ade
commit 4b90113a54
Signed by: outfoxxed
GPG key ID: 4C88A185FB89301E
103 changed files with 3467 additions and 1415 deletions

View file

@ -1,3 +1,5 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
@ -7,9 +9,10 @@ import Quickshell.Services.Mpris
import ".."
import "../.."
MouseArea {
FullwidthMouseArea {
id: root
hoverEnabled: true
fillWindowWidth: true
required property var bar;
implicitHeight: column.implicitHeight + 10
@ -27,12 +30,12 @@ MouseArea {
property alias widgetOpen: persist.widgetOpen;
acceptedButtons: Qt.RightButton
onClicked: widgetOpen = !widgetOpen
onPressed: widgetOpen = !widgetOpen
onWheel: event => {
event.accepted = true;
if (MprisController.canChangeVolume) {
this.activePlayer.volume = Math.max(0, Math.min(1, this.activePlayer.volume + (event.angleDelta.y / 120) * 0.05));
root.activePlayer.volume = Math.max(0, Math.min(1, root.activePlayer.volume + (event.angleDelta.y / 120) * 0.05));
}
}
@ -42,7 +45,7 @@ MouseArea {
id: widget
anchors.fill: parent
property real scaleMul: root.pressed || widgetOpen ? 100 : 1
property real scaleMul: widgetOpen ? 100 : 1
Behavior on scaleMul { SmoothedAnimation { velocity: 600 } }
scale: scaleCurve.interpolate(scaleMul / 100, 1, (width - 6) / width)
@ -56,8 +59,10 @@ MouseArea {
BackgroundArt {
id: bkg
anchors.fill: parent
overlay.color: "#30000000"
function updateArt(reverse: bool) {
console.log("update art", MprisController.activeTrack.artUrl)
this.setArt(MprisController.activeTrack.artUrl, reverse, false)
}
@ -86,6 +91,7 @@ MouseArea {
implicitHeight: width
scaleIcon: false
baseMargin: 3
hoverEnabled: false
enabled: MprisController.canGoPrevious;
onClicked: MprisController.previous();
}
@ -95,11 +101,9 @@ MouseArea {
image: `root:icons/${MprisController.isPlaying ? "pause" : "play"}.svg`;
implicitHeight: width
scaleIcon: false
enabled: MprisController.isPlaying ? MprisController.canPause : MprisController.canPlay;
onClicked: {
if (MprisController.isPlaying) MprisController.pause();
else MprisController.play();
}
hoverEnabled: false
enabled: MprisController.canTogglePlaying;
onClicked: MprisController.togglePlaying();
}
ClickableIcon {
@ -108,51 +112,162 @@ MouseArea {
implicitHeight: width
scaleIcon: false
baseMargin: 3
hoverEnabled: false
enabled: MprisController.canGoNext;
onClicked: MprisController.next();
}
}
property var tooltip: TooltipItem {
property Scope positionInfo: Scope {
id: positionInfo
property var player: root.activePlayer;
property int position: Math.floor(player.position);
property int length: Math.floor(player.length);
FrameAnimation {
id: posTracker;
running: positionInfo.player.isPlaying && (tooltip.visible || rightclickMenu.visible);
onTriggered: positionInfo.player.positionChanged();
}
function timeStr(time: int): string {
const seconds = time % 60;
const minutes = Math.floor(time / 60);
return `${minutes}:${seconds.toString().padStart(2, '0')}`
}
}
property TooltipItem tooltip: TooltipItem {
id: tooltip
tooltip: bar.tooltip
owner: root
show: root.containsMouse && (activePlayer?.metadata["mpris:trackid"] ?? false)
show: root.containsMouse
//implicitHeight: root.height - 10
//implicitWidth: childrenRect.width
/*ColumnLayout {
ColumnLayout {
visible: MprisController.activePlayer != null
Label { text: MprisController.activeTrack?.title ?? "" }
Label {
text: {
const artist = MprisController.activeTrack?.artist ?? "";
const album = MprisController.activeTrack?.album ?? "";
return artist + (album ? ` - ${album}` : "");
}
}
Label { text: MprisController.activePlayer?.identity ?? "" }
}
Label {
visible: MprisController.activePlayer == null
text: "No media playing"
}
Rectangle { implicitHeight: 10; color: "white"; Layout.fillWidth: true }
}*/
contentItem.anchors.margins: 0
Item {
implicitWidth: 200
implicitHeight: 100
}
id: ttcontent
width: parent.width
height: Math.max(parent.height, implicitHeight)
implicitWidth: cl.implicitWidth + 10
implicitHeight: cl.implicitHeight + 10 + (MprisController.activePlayer ? 8 : 0)
/*Loader {
active: tooltip.visible
ColumnLayout {
id: cl
anchors {
left: parent.left
right: parent.right
top: parent.top
margins: 5
}
sourceComponent: ColumnLayout {
height: root.height - 10
RowLayout {
Image {
Layout.fillHeight: true
source: mainPlayer.metadata["mpris:artUrl"] ?? ""
//visible: MprisController.activePlayer != null
FontMetrics { id: fontmetrics }
component FullheightLabel: Item {
implicitHeight: fontmetrics.height
implicitWidth: label.implicitWidth
property alias text: label.text
cache: false
fillMode: Image.PreserveAspectCrop
sourceSize.width: height
sourceSize.height: height
}
Label {
text: mainPlayer.identity
id: label
anchors.verticalCenter: parent.verticalCenter
}
}
Slider {
Layout.fillWidth: true
FullheightLabel {
visible: MprisController.activePlayer != null
text: MprisController.activeTrack?.title ?? ""
}
FullheightLabel {
visible: MprisController.activePlayer != null
text: MprisController.activeTrack?.artist ?? ""
/*text: {
const artist = MprisController.activeTrack?.artist ?? "";
const album = MprisController.activeTrack?.album ?? "";
return artist + (album ? ` - ${album}` : "");
}*/
}
Label {
text: {
if (!MprisController.activePlayer) return "No media playing";
return MprisController.activePlayer?.identity + " - "
+ positionInfo.timeStr(positionInfo.position) + " / "
+ positionInfo.timeStr(positionInfo.length);
}
}
}
}*/
Rectangle {
id: ttprect
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
color: "#30ceffff"
implicitHeight: 8
visible: MprisController.activePlayer != null
Rectangle {
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
}
color: "#80ceffff"
width: parent.width * (root.activePlayer.position / root.activePlayer.length)
}
}
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: ttcontent.width
height: ttcontent.height
bottomLeftRadius: 5
bottomRightRadius: 5
}
}
}
}
property var rightclickMenu: TooltipItem {
@ -182,6 +297,7 @@ MouseArea {
target: MprisController
function onTrackChanged(reverse: bool) {
console.log(`track changed: rev: ${reverse}`)
popupBkg.setArt(MprisController.activeTrack.artUrl, reverse, false);
}
}
@ -191,71 +307,41 @@ MouseArea {
}
}
contentItem {
implicitWidth: 500
implicitHeight: 650
}
Loader {
active: rightclickMenu.visible
width: 500
height: 650
active: rightclickMenu.visible
sourceComponent: ColumnLayout {
property var player: activePlayer;
anchors.fill: parent;
property int position: 0;
property int length: 0;
FrameAnimation {
id: posTracker;
running: player.playbackState == MprisPlaybackState.Playing && widgetOpen;
onTriggered: player.positionChanged();
}
Connections {
target: player
function onPositionChanged() {
const newPosition = Math.floor(player.position);
if (newPosition != position) position = newPosition;
}
function onLengthChanged() {
const newLength = Math.floor(player.length);
if (newLength != length) length = newLength;
}
}
property var player: root.activePlayer;
Connections {
target: MprisController
function onTrackChanged(reverse: bool) {
trackStack.updateTrack(reverse, false);
length = Math.floor(player.length);
}
}
Component.onCompleted: {
position = Math.floor(player.position);
length = Math.floor(player.length);
}
function timeStr(time: int): string {
const seconds = time % 60;
const minutes = Math.floor(time / 60);
return `${minutes}:${seconds.toString().padStart(2, '0')}`
}
Item {
id: playerSelectorContainment
Layout.fillWidth: true
implicitHeight: playerSelector.implicitHeight + 20
implicitWidth: playerSelector.implicitWidth
ScrollView {
RowLayout { //ScrollView {
id: playerSelector
anchors.centerIn: parent
width: Math.min(implicitWidth, playerSelectorContainment.width)
RowLayout {
//RowLayout {
Repeater {
model: Mpris.players
@ -281,8 +367,7 @@ MouseArea {
source: {
const entry = DesktopEntries.byId(modelData.desktopEntry);
console.log(`ent ${entry} id ${modelData.desktopEntry}`)
if (!entry) return "image://icon/";
return `image://icon/${entry.icon}`;
return Quickshell.iconPath(entry?.icon);
}
//asynchronous: true
@ -292,18 +377,18 @@ MouseArea {
}
}
}
}
//}
}
}
}
Item {
Layout.fillWidth: true
Layout.bottomMargin: 10
Layout.bottomMargin: 20
Label {
anchors.centerIn: parent
text: activePlayer.identity
text: root.activePlayer.identity
}
}
@ -311,7 +396,13 @@ MouseArea {
id: trackStack
Layout.fillWidth: true
implicitHeight: 400
clip: animating || (lastFlicked?.contentX ?? 0) != 0
// inverse of default tooltip margin - 1px for border
Layout.leftMargin: -4
Layout.rightMargin: -4
property Flickable lastFlicked;
property bool reverse: false;
Component.onCompleted: updateTrack(false, true);
@ -333,14 +424,16 @@ MouseArea {
// but may take longer if the image is huge.
readonly property bool svReady: img.status === Image.Ready;
contentWidth: width + 1
onDragStarted: trackStack.lastFlicked = this
onDragEnded: {
return;
//return;
console.log(`dragend ${contentX}`)
if (Math.abs(contentX) > 75) {
if (contentX < 0) MprisController.previous();
else if (contentX > 0) MprisController.next();
}
}
ColumnLayout {
id: trackContent
width: flickable.width
@ -348,7 +441,7 @@ MouseArea {
Item {
Layout.fillWidth: true
implicitHeight: 300//img.implicitHeight
implicitHeight: 302//img.implicitHeight
implicitWidth: img.implicitWidth
Image {
@ -362,27 +455,50 @@ MouseArea {
sourceSize.height: 300
sourceSize.width: 300
layer.enabled: true
layer.effect: OpacityMask {
cached: true
maskSource: Rectangle {
width: img.width
height: img.height
radius: 5
}
}
}
}
Item {
component CenteredText: Item {
Layout.fillWidth: true
Layout.topMargin: 20
property alias text: label.text
property alias font: label.font
Label {
id: label
visible: text != ""
anchors.centerIn: parent
text: track.title
elide: Text.ElideRight
width: Math.min(parent.width - 20, implicitWidth)
}
}
Item {
Layout.fillWidth: true
CenteredText {
Layout.topMargin: 20
text: track.title
font.pointSize: albumLabel.font.pointSize + 1
}
Label {
anchors.centerIn: parent
text: track.artist
}
CenteredText {
id: albumLabel
Layout.topMargin: 18
text: track.album
opacity: 0.8
}
CenteredText {
Layout.topMargin: 25
text: track.artist
}
Item { Layout.fillHeight: true }
@ -462,11 +578,8 @@ MouseArea {
implicitWidth: 80
implicitHeight: width
scaleIcon: false
enabled: MprisController.isPlaying ? MprisController.canPause : MprisController.canPlay
onClicked: {
if (MprisController.isPlaying) MprisController.pause();
else MprisController.play();
}
enabled: MprisController.canTogglePlaying;
onClicked: MprisController.togglePlaying();
}
ClickableIcon {
@ -491,33 +604,70 @@ MouseArea {
}
RowLayout {
Layout.margins: 5
Label {
Layout.preferredWidth: lengthLabel.implicitWidth
text: timeStr(position)
text: positionInfo.timeStr(positionInfo.position)
}
MediaSlider {
id: slider
property bool bindSlider: true;
property real boundAnimStart: 0;
property real boundAnimFactor: 1;
property real lastPosition: 0;
property real lastLength: 0;
property real boundPosition: {
const ppos = player.position / player.length;
const bpos = boundAnimStart;
return (ppos * boundAnimFactor) + (bpos * (1.0 - boundAnimFactor));
}
NumberAnimation {
id: boundAnim
target: slider
property: "boundAnimFactor"
from: 0
to: 1
duration: 600
easing.type: Easing.OutExpo
}
Connections {
target: player
function onPositionChanged() {
if (false && player.position == 0 && slider.lastPosition != 0 && !boundAnim.running) {
slider.boundAnimStart = slider.lastPosition / slider.lastLength;
boundAnim.start();
}
slider.lastPosition = player.position;
slider.lastLength = player.length;
}
}
Layout.fillWidth: true
property var bindSlider: true;
enabled: player.canSeek
from: 0
to: player.length
to: 1
onPressedChanged: {
if (!pressed) player.position = value;
if (!pressed) player.position = value * player.length;
bindSlider = !pressed;
}
Binding {
when: slider.bindSlider
slider.value: player.position
slider.value: slider.boundPosition
}
}
Label {
id: lengthLabel
text: timeStr(length)
text: positionInfo.timeStr(positionInfo.length)
}
}
}