last 7 months of qs changes
This commit is contained in:
parent
2c64563ade
commit
4b90113a54
103 changed files with 3467 additions and 1415 deletions
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue