mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
We so far have been recreating the background elements for all the item throughout the shell. This merge request simplifies this by unifying these elements into a single component, making is easier to keep things at a consistent design while also being able to adjust things when needed in the future. Per request, I tried to keep thing looking mostly the same as before. The first picture is what the action drawer looks like now, the one after is with these changes.  
263 lines
9.3 KiB
QML
263 lines
9.3 KiB
QML
/*
|
|
* SPDX-FileCopyrightText: 2024 Micah Stanley <stanleymicah@proton.me>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
import QtQuick
|
|
import QtQuick.Controls as Controls
|
|
import QtQuick.Layouts
|
|
import QtQuick.Window
|
|
|
|
import org.kde.kirigami 2.20 as Kirigami
|
|
import org.kde.plasma.components 3.0 as PlasmaComponents
|
|
import org.kde.plasma.private.mobileshell as MobileShell
|
|
import org.kde.plasma.private.mobileshell.state as MobileShellState
|
|
|
|
import org.kde.plasma.private.volume
|
|
|
|
import org.kde.layershell 1.0 as LayerShell
|
|
|
|
|
|
Window {
|
|
id: window
|
|
|
|
width: osd.width + 6
|
|
height: cards.implicitHeight + 6 + cards.openOffset
|
|
|
|
onWidthChanged: if (visible) window.updateTouchRegion()
|
|
|
|
visible: false
|
|
|
|
LayerShell.Window.scope: "overlay"
|
|
LayerShell.Window.anchors: LayerShell.Window.AnchorTop
|
|
LayerShell.Window.layer: LayerShell.Window.LayerOverlay
|
|
LayerShell.Window.exclusionZone: -1
|
|
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
|
|
|
|
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
|
Kirigami.Theme.inherit: false
|
|
|
|
color: "transparent"
|
|
|
|
function showOverlay() {
|
|
if (cards.state == "closed") {
|
|
hideTimer.stop();
|
|
window.open();
|
|
} else if (!volumeSlider.isPressed) {
|
|
hideTimer.restart();
|
|
}
|
|
}
|
|
|
|
function open() {
|
|
// set window input transparency to allow touches to pass through while the opening animation is playing
|
|
ShellUtil.setInputTransparent(window, true);
|
|
|
|
window.visible = true;
|
|
cards.state = "open";
|
|
}
|
|
|
|
function close() {
|
|
cards.state = "closed";
|
|
// set window input transparency to allow touches to pass through while the closing animation is playing
|
|
ShellUtil.setInputTransparent(window, true);
|
|
}
|
|
|
|
function updateTouchRegion() {
|
|
ShellUtil.setInputRegion(window, Qt.rect(0, cards.openOffset, window.width, cards.implicitHeight + 6));
|
|
}
|
|
|
|
Timer {
|
|
id: hideTimer
|
|
interval: 2000
|
|
running: false
|
|
onTriggered: {
|
|
window.close();
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
window.close();
|
|
visible = false;
|
|
}
|
|
|
|
ColumnLayout {
|
|
id: cards
|
|
width: parent.width
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
spacing: 0
|
|
|
|
readonly property real closedOffset: -(cards.implicitHeight + Kirigami.Units.smallSpacing)
|
|
readonly property real openOffset: Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing * 3
|
|
property real offset: closedOffset
|
|
|
|
state: "closed"
|
|
|
|
states: [
|
|
State {
|
|
name: "open"
|
|
PropertyChanges {
|
|
target: cards; offset: openOffset
|
|
}
|
|
},
|
|
State {
|
|
name: "closed"
|
|
PropertyChanges {
|
|
target: cards; offset: closedOffset
|
|
}
|
|
}
|
|
]
|
|
|
|
transitions: Transition {
|
|
SequentialAnimation {
|
|
ParallelAnimation {
|
|
PropertyAnimation {
|
|
properties: "offset"; easing.type: cards.state == "open" ? Easing.OutQuint : Easing.InQuint; duration: Kirigami.Units.veryLongDuration * 1.25
|
|
}
|
|
}
|
|
ScriptAction {
|
|
script: {
|
|
if (cards.state == "open") {
|
|
hideTimer.restart();
|
|
// set window input transparency to accept touches
|
|
ShellUtil.setInputTransparent(window, false);
|
|
window.updateTouchRegion();
|
|
} else {
|
|
hideTimer.stop();
|
|
window.visible = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PopupCard {
|
|
id: osd
|
|
Layout.alignment: Qt.AlignHCenter
|
|
implicitWidth: Math.min(Kirigami.Units.gridUnit * 15, Screen.width - Kirigami.Units.gridUnit * 2)
|
|
popupBackground: true
|
|
|
|
transform: [
|
|
Translate {
|
|
y: cards.offset + 1
|
|
}
|
|
]
|
|
|
|
contentItem: RowLayout {
|
|
id: containerLayout
|
|
spacing: Kirigami.Units.smallSpacing
|
|
|
|
anchors.leftMargin: Kirigami.Units.smallSpacing * 2
|
|
anchors.rightMargin: Kirigami.Units.smallSpacing
|
|
|
|
property int volumePercent: PreferredDevice.sink.volume / PulseAudio.NormalVolume * 100.0
|
|
|
|
PlasmaComponents.ToolButton {
|
|
icon.name: !PreferredDevice.sink || PreferredDevice.sink.muted ? "audio-volume-muted" : MobileShell.AudioInfo.icon
|
|
text: !PreferredDevice.sink || PreferredDevice.sink.muted ? i18n("Unmute") : i18n("Mute")
|
|
display: Controls.AbstractButton.IconOnly
|
|
Layout.alignment: Qt.AlignVCenter
|
|
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
|
|
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
|
|
Layout.rightMargin: Kirigami.Units.smallSpacing
|
|
onClicked: {
|
|
hideTimer.restart();
|
|
PreferredDevice.sink.muted = !PreferredDevice.sink.muted;
|
|
}
|
|
}
|
|
|
|
PlasmaComponents.Slider {
|
|
id: volumeSlider
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
Layout.alignment: Qt.AlignVCenter
|
|
Layout.rightMargin: Kirigami.Units.smallSpacing * 2
|
|
|
|
property real volume: PreferredDevice.sink.volume
|
|
property bool muted: PreferredDevice.sink.muted
|
|
property bool ignoreValueChange: false
|
|
property bool isPressed: false
|
|
|
|
from: PulseAudio.MinimalVolume
|
|
to: PulseAudio.NormalVolume
|
|
stepSize: to / (to / PulseAudio.NormalVolume * 100.0)
|
|
opacity: muted ? 0.5 : 1.0
|
|
|
|
Component.onCompleted: {
|
|
ignoreValueChange = false;
|
|
}
|
|
|
|
onVolumeChanged: {
|
|
if (!window.visible) {
|
|
return;
|
|
}
|
|
var oldIgnoreValueChange = ignoreValueChange;
|
|
ignoreValueChange = true;
|
|
value = muted ? 0 : PreferredDevice.sink.volume;
|
|
ignoreValueChange = oldIgnoreValueChange;
|
|
if (volumeSlider.isPressed) {
|
|
return;
|
|
}
|
|
window.open();
|
|
hideTimer.restart();
|
|
}
|
|
|
|
onMutedChanged: {
|
|
var oldIgnoreValueChange = ignoreValueChange;
|
|
ignoreValueChange = true;
|
|
value = muted ? 0 : PreferredDevice.sink.volume;
|
|
ignoreValueChange = oldIgnoreValueChange;
|
|
if (!window.visible || volumeSlider.isPressed) {
|
|
return;
|
|
}
|
|
window.open();
|
|
hideTimer.restart();
|
|
}
|
|
|
|
onValueChanged: {
|
|
if (!ignoreValueChange) {
|
|
PreferredDevice.sink.muted = false;
|
|
PreferredDevice.sink.volume = value;
|
|
if (!volumeSlider.isPressed) {
|
|
updateTimer.restart();
|
|
}
|
|
}
|
|
}
|
|
|
|
onPressedChanged: {
|
|
volumeSlider.isPressed = pressed;
|
|
if (pressed) {
|
|
window.open();
|
|
hideTimer.stop();
|
|
} else {
|
|
// Make sure to sync the volume once the button was
|
|
// released.
|
|
// Otherwise it might be that the slider is at v10
|
|
// whereas PA rejected the volume change and is
|
|
// still at v15 (e.g.).
|
|
hideTimer.restart();
|
|
updateTimer.restart();
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: updateTimer
|
|
interval: 200
|
|
onTriggered: volumeSlider.value = PreferredDevice.sink.volume
|
|
}
|
|
}
|
|
|
|
PlasmaComponents.ToolButton {
|
|
icon.name: window.showFullApplet ? "arrow-up" : "arrow-down"
|
|
text: i18n("configure audio streams")
|
|
display: Controls.AbstractButton.IconOnly
|
|
Layout.alignment: Qt.AlignVCenter
|
|
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
|
|
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
|
|
onClicked: MobileShellState.ShellDBusClient.showVolumeOSD()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|