mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
This merge request adjust animations in the VolumeOSD and NotificationPopup to bring consistency and to make it feel better when swiping up a notification.
262 lines
9.3 KiB
QML
262 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)
|
|
|
|
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()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|