Merge branch 'main' into feat/improved-gestures
Python / lint-format (pull_request) Successful in 22s
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 27s
Python / test (pull_request) Successful in 50s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m2s

This commit is contained in:
2026-06-01 12:13:33 +02:00
4 changed files with 178 additions and 150 deletions
+11 -7
View File
@@ -10,31 +10,35 @@ Slider {
background: Item { background: Item {
CustomRect { CustomRect {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.bottomMargin: root.implicitHeight / 6
anchors.left: parent.left anchors.left: parent.left
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: root.implicitHeight / 6
bottomRightRadius: root.implicitHeight / 6 bottomRightRadius: root.implicitHeight / 6
color: root.color color: root.color
implicitWidth: root.handle.x - root.implicitHeight / 2 implicitWidth: root.handle.x - root.implicitHeight / 6
radius: Appearance.rounding.full radius: root.implicitHeight / 6
topRightRadius: root.implicitHeight / 6 topRightRadius: root.implicitHeight / 6
} }
CustomRect { CustomRect {
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
anchors.bottomMargin: root.implicitHeight / 6
anchors.right: parent.right anchors.right: parent.right
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: root.implicitHeight / 6
bottomLeftRadius: root.implicitHeight / 6 bottomLeftRadius: root.implicitHeight / 6
color: DynamicColors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainerHighest
implicitWidth: parent.width - root.handle.x - root.handle.implicitWidth - root.implicitHeight / 2 implicitWidth: parent.width - root.handle.x - root.handle.implicitWidth - root.implicitHeight / 6
radius: Appearance.rounding.full radius: root.implicitHeight / 6
topLeftRadius: root.implicitHeight / 6 topLeftRadius: root.implicitHeight / 6
} }
} }
handle: CustomRect { handle: CustomRect {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
color: root.color color: root.color
implicitHeight: 15 implicitHeight: root.implicitHeight
implicitWidth: 5 implicitWidth: root.implicitHeight / 4.5
radius: Appearance.rounding.full radius: Appearance.rounding.full
x: root.visualPosition * root.availableWidth - implicitWidth / 2 x: root.visualPosition * root.availableWidth - implicitWidth / 2
-1
View File
@@ -14,7 +14,6 @@ Scope {
function nearestThresholdAbove(p: real): var { function nearestThresholdAbove(p: real): var {
const thresholds = [...root.popupThresholds]; const thresholds = [...root.popupThresholds];
for (const perc of thresholds) { for (const perc of thresholds) {
console.log(perc.message);
if (p < perc.perc) if (p < perc.perc)
return perc; return perc;
} }
@@ -80,7 +80,8 @@ Item {
required property ShellScreen modelData required property ShellScreen modelData
function applyCrop(): void { function applyCrop(): void {
if (!cropRectLoader.item) return; if (!cropRectLoader.item)
return;
const cropRect = cropRectLoader.item; const cropRect = cropRectLoader.item;
// We need to calculate the exact percentage coordinates that map perfectly // We need to calculate the exact percentage coordinates that map perfectly
@@ -97,7 +98,8 @@ Item {
} }
function zoomClipRect(zoom: real): void { function zoomClipRect(zoom: real): void {
if (!cropRectLoader.item) return; if (!cropRectLoader.item)
return;
const cropRect = cropRectLoader.item; const cropRect = cropRectLoader.item;
let oldCenterX = cropRect.x + cropRect.width * 0.5; let oldCenterX = cropRect.x + cropRect.width * 0.5;
@@ -139,8 +141,9 @@ Item {
id: zoomSlider id: zoomSlider
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 10 Layout.preferredHeight: 30
from: 1.0 from: 1.0
implicitHeight: 30
to: 5.0 to: 5.0
value: cropRectLoader.item ? cropRectLoader.item.zoom : 1.0 value: cropRectLoader.item ? cropRectLoader.item.zoom : 1.0
@@ -198,6 +201,7 @@ Item {
Loader { Loader {
id: cropRectLoader id: cropRectLoader
active: scaledImg.paintedWidth > 0 && scaledImg.status == Image.Ready active: scaledImg.paintedWidth > 0 && scaledImg.status == Image.Ready
sourceComponent: Component { sourceComponent: Component {
@@ -272,7 +276,8 @@ Item {
id: mouse id: mouse
function updateCrop(mouseX, mouseY) { function updateCrop(mouseX, mouseY) {
if (!cropRectLoader.item) return; if (!cropRectLoader.item)
return;
const cropRect = cropRectLoader.item; const cropRect = cropRectLoader.item;
let nx = mouseX - cropRect.width * 0.5; let nx = mouseX - cropRect.width * 0.5;
+150 -130
View File
@@ -52,25 +52,25 @@ Item {
CustomRect { CustomRect {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2 Layout.preferredHeight: 50 + Appearance.spacing.smaller * 2
Layout.topMargin: root.topMargin Layout.topMargin: root.topMargin
color: DynamicColors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
radius: root.rounding radius: root.rounding
RowLayout { Item {
id: outputVolume id: sinkIcon
anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.margins: Appearance.spacing.smaller anchors.leftMargin: Appearance.padding.normal
anchors.right: parent.right anchors.top: parent.top
anchors.verticalCenter: parent.verticalCenter implicitWidth: childrenRect.width
spacing: 15
CustomRect { CustomRect {
Layout.alignment: Qt.AlignVCenter anchors.centerIn: parent
Layout.preferredHeight: 40
Layout.preferredWidth: 40
color: Audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary color: Audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: 40
implicitWidth: 40
radius: Appearance.rounding.full radius: Appearance.rounding.full
MaterialIcon { MaterialIcon {
@@ -92,45 +92,53 @@ Item {
} }
} }
} }
}
ColumnLayout { ColumnLayout {
anchors.bottom: parent.bottom
anchors.bottomMargin: Appearance.padding.smallest
anchors.left: sinkIcon.right
anchors.leftMargin: Appearance.spacing.normal
anchors.right: parent.right
anchors.rightMargin: Appearance.padding.large
anchors.top: parent.top
anchors.topMargin: Appearance.padding.smaller
RowLayout {
Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
RowLayout { CustomText {
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.fillWidth: true Layout.fillWidth: true
text: "Output Volume"
CustomText {
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.fillWidth: true
text: "Output Volume"
}
CustomText {
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
font.bold: true
text: qsTr("%1").arg(Audio.muted ? qsTr("Muted") : `${Math.round(Audio.volume * 100)}%`)
}
} }
CustomMouseArea { CustomText {
Layout.bottomMargin: 5 Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
Layout.fillWidth: true font.bold: true
Layout.preferredHeight: 10 text: qsTr("%1").arg(Audio.muted ? qsTr("Muted") : `${Math.round(Audio.volume * 100)}%`)
}
}
CustomSlider { CustomMouseArea {
anchors.left: parent.left Layout.bottomMargin: 5
anchors.right: parent.right Layout.fillHeight: true
color: Audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary Layout.fillWidth: true
implicitHeight: 10
value: Audio.volume
Behavior on value { CustomSlider {
Anim { anchors.left: parent.left
} anchors.right: parent.right
color: Audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: parent.height
value: Audio.volume
Behavior on value {
Anim {
} }
onMoved: Audio.setVolume(value)
} }
onMoved: Audio.setVolume(value)
} }
} }
} }
@@ -138,7 +146,7 @@ Item {
CustomClippingRect { CustomClippingRect {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2 Layout.preferredHeight: 50 + Appearance.spacing.smaller * 2
Layout.topMargin: root.topMargin Layout.topMargin: root.topMargin
color: DynamicColors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
radius: root.rounding radius: root.rounding
@@ -165,20 +173,20 @@ Item {
} }
} }
RowLayout { Item {
id: inputVolume id: sourceIcon
anchors.bottom: parent.bottom
anchors.left: parent.left anchors.left: parent.left
anchors.margins: Appearance.spacing.smaller anchors.leftMargin: Appearance.padding.normal
anchors.right: parent.right anchors.top: parent.top
anchors.verticalCenter: parent.verticalCenter implicitWidth: childrenRect.width
spacing: 15
CustomRect { CustomRect {
Layout.alignment: Qt.AlignVCenter anchors.centerIn: parent
Layout.preferredHeight: 40
Layout.preferredWidth: 40
color: Audio.sourceMuted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary color: Audio.sourceMuted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: 40
implicitWidth: 40
radius: Appearance.rounding.full radius: Appearance.rounding.full
MaterialIcon { MaterialIcon {
@@ -200,46 +208,53 @@ Item {
} }
} }
} }
}
ColumnLayout { ColumnLayout {
anchors.bottom: parent.bottom
anchors.bottomMargin: Appearance.padding.smallest
anchors.left: sourceIcon.right
anchors.leftMargin: Appearance.spacing.normal
anchors.right: parent.right
anchors.rightMargin: Appearance.padding.large
anchors.top: parent.top
anchors.topMargin: Appearance.padding.smaller
RowLayout {
Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
RowLayout { CustomText {
Layout.fillHeight: true Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.fillWidth: true Layout.fillWidth: true
text: "Input Volume"
CustomText {
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.fillWidth: true
text: "Input Volume"
}
CustomText {
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
font.bold: true
text: qsTr("%1").arg(Audio.sourceMuted ? qsTr("Muted") : `${Math.round(Audio.sourceVolume * 100)}%`)
}
} }
CustomMouseArea { CustomText {
Layout.bottomMargin: 5 Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
Layout.fillWidth: true font.bold: true
implicitHeight: 10 text: qsTr("%1").arg(Audio.sourceMuted ? qsTr("Muted") : `${Math.round(Audio.sourceVolume * 100)}%`)
}
}
CustomSlider { CustomMouseArea {
anchors.left: parent.left Layout.bottomMargin: 5
anchors.right: parent.right Layout.fillHeight: true
color: Audio.sourceMuted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary Layout.fillWidth: true
implicitHeight: 10
value: Audio.sourceVolume
Behavior on value { CustomSlider {
Anim { anchors.left: parent.left
} anchors.right: parent.right
color: Audio.sourceMuted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: parent.height
value: Audio.sourceVolume
Behavior on value {
Anim {
} }
onMoved: Audio.setSourceVolume(value)
} }
onMoved: Audio.setSourceVolume(value)
} }
} }
} }
@@ -265,7 +280,7 @@ Item {
required property var modelData required property var modelData
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 42 + Appearance.spacing.smaller * 2 Layout.preferredHeight: 50 + Appearance.spacing.smaller * 2
Layout.topMargin: root.topMargin Layout.topMargin: root.topMargin
color: DynamicColors.tPalette.m3surfaceContainer color: DynamicColors.tPalette.m3surfaceContainer
radius: root.rounding radius: root.rounding
@@ -292,18 +307,20 @@ Item {
} }
} }
RowLayout { Item {
id: layoutVolume id: appBoxIcon
anchors.fill: parent anchors.bottom: parent.bottom
anchors.margins: Appearance.spacing.smaller anchors.left: parent.left
spacing: 15 anchors.leftMargin: Appearance.padding.normal
anchors.top: parent.top
implicitWidth: childrenRect.width
CustomRect { CustomRect {
Layout.alignment: Qt.AlignVCenter anchors.centerIn: parent
Layout.preferredHeight: 40
Layout.preferredWidth: 40
color: appBox.modelData.audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary color: appBox.modelData.audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: 40
implicitWidth: 40
radius: Appearance.rounding.full radius: Appearance.rounding.full
MaterialIcon { MaterialIcon {
@@ -325,55 +342,58 @@ Item {
} }
} }
} }
}
ColumnLayout { TextMetrics {
Layout.alignment: Qt.AlignLeft | Qt.AlignTop id: metrics
elide: Text.ElideRight
elideWidth: root.width - 50
text: Audio.getStreamName(appBox.modelData)
}
ColumnLayout {
anchors.bottom: parent.bottom
anchors.bottomMargin: Appearance.padding.smallest
anchors.left: appBoxIcon.right
anchors.leftMargin: Appearance.spacing.normal
anchors.right: parent.right
anchors.rightMargin: Appearance.padding.large
anchors.top: parent.top
anchors.topMargin: Appearance.padding.smaller
RowLayout {
Layout.fillHeight: true Layout.fillHeight: true
Layout.fillWidth: true
TextMetrics { CustomText {
id: metrics
elide: Text.ElideRight
elideWidth: root.width - 50
text: Audio.getStreamName(appBox.modelData)
}
RowLayout {
Layout.fillHeight: true
Layout.fillWidth: true
CustomText {
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.fillHeight: true
Layout.fillWidth: true
elide: Text.ElideRight
text: metrics.elidedText
}
CustomText {
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
Layout.fillHeight: true
font.bold: true
text: qsTr("%1").arg(appBox.modelData.audio.muted ? qsTr("Muted") : `${Math.round(appBox.modelData.audio.volume * 100)}%`)
}
}
CustomMouseArea {
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.fillHeight: true
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: 10 elide: Text.ElideRight
text: metrics.elidedText
}
CustomSlider { CustomText {
anchors.left: parent.left Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
anchors.right: parent.right font.bold: true
color: appBox.modelData.audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary text: qsTr("%1").arg(appBox.modelData.audio.muted ? qsTr("Muted") : `${Math.round(appBox.modelData.audio.volume * 100)}%`)
implicitHeight: 10 }
value: appBox.modelData.audio.volume }
onMoved: { CustomMouseArea {
Audio.setStreamVolume(appBox.modelData, value); Layout.bottomMargin: 5
} Layout.fillHeight: true
Layout.fillWidth: true
CustomSlider {
anchors.left: parent.left
anchors.right: parent.right
color: appBox.modelData.audio.muted ? DynamicColors.palette.m3error : DynamicColors.palette.m3primary
implicitHeight: parent.height
value: appBox.modelData.audio.volume
onMoved: {
Audio.setStreamVolume(appBox.modelData, value);
} }
} }
} }