VolumeOSD: Improve design, and prevent touch events from being taken from outside the osd

Fixes: https://invent.kde.org/plasma/plasma-mobile/-/issues/274

Any feedback on these changes would be much appreciated.

![Screenshot_20241024_093458-1](/uploads/7b4f89ace1a53c559737d1c05d591329/Screenshot_20241024_093458-1.png)
![Screenshot_20241023_070919](/uploads/c7b9a8de7c9bba2de01d734408e02b2b/Screenshot_20241023_070919.png)

Change Log:
- NanoShell FullScreenOverlay was changed to a LayerShellQt Window to keep it on the top layer and to prevent the popup from obsorbing all touch inputs.
- New animations were added to the volume popup.
- User can now change the volume by touching and dragging on the popup
- The mute button on the popup was fixed
- Mute buttons were added next to the volume sliders in the AudioApplet page
- Volume icons now dynamically update to the volume level
- Visual design adjustments
This commit is contained in:
Micah Stanley 2024-10-25 15:52:49 +00:00 committed by Devin Lin
parent 8d1bb7642d
commit 681d1683f5
10 changed files with 534 additions and 150 deletions

View file

@ -94,6 +94,8 @@ find_package(KWin ${PROJECT_DEP_VERSION} REQUIRED COMPONENTS
kwin
)
find_package(LayerShellQt REQUIRED)
find_package(LibKWorkspace CONFIG REQUIRED)
find_package(Libudev REQUIRED)

View file

@ -52,6 +52,7 @@ target_link_libraries(mobileshellplugin
Plasma::KWaylandClient
KF6::Service
KF6::Package
LayerShellQt::Interface
)
ecm_finalize_qml_module(mobileshellplugin)

View file

@ -19,8 +19,14 @@ import org.kde.plasma.private.volume
// capture presses on the audio applet so it doesn't close the overlay
ColumnLayout {
id: audioApplet
spacing: 0
Kirigami.Theme.colorSet: Kirigami.Theme.View
Kirigami.Theme.inherit: false
property real scale: 1.0
PulseObjectFilterModel {
id: paSinkFilterModel
sortRoleName: "SortByDefault"
@ -50,6 +56,14 @@ ColumnLayout {
PopupCard {
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: Kirigami.Units.gridUnit
transform: Scale {
origin.x: Math.round(implicitWidth / 2)
origin.y: Math.round(height / 2)
xScale: audioApplet.scale
yScale: audioApplet.scale
}
contentItem: ColumnLayout {
anchors.rightMargin: Kirigami.Units.smallSpacing
anchors.leftMargin: Kirigami.Units.smallSpacing
@ -80,6 +94,14 @@ ColumnLayout {
PopupCard {
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: Kirigami.Units.gridUnit
transform: Scale {
origin.x: Math.round(implicitWidth / 2)
origin.y: Math.round(height / 2)
xScale: audioApplet.scale
yScale: audioApplet.scale
}
contentItem: ColumnLayout {
anchors.rightMargin: Kirigami.Units.smallSpacing
anchors.leftMargin: Kirigami.Units.smallSpacing
@ -111,6 +133,14 @@ ColumnLayout {
visible: sourceInputView.model.count + sourceMediaInputView.model.count !== 0
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: Kirigami.Units.gridUnit
transform: Scale {
origin.x: Math.round(implicitWidth / 2)
origin.y: Math.round(height / 2)
xScale: audioApplet.scale
yScale: audioApplet.scale
}
contentItem: ColumnLayout {
anchors.rightMargin: Kirigami.Units.smallSpacing
anchors.leftMargin: Kirigami.Units.smallSpacing
@ -164,6 +194,14 @@ ColumnLayout {
visible: sourceOutputView.model.count !== 0
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: Kirigami.Units.gridUnit
transform: Scale {
origin.x: Math.round(implicitWidth / 2)
origin.y: Math.round(height / 2)
xScale: audioApplet.scale
yScale: audioApplet.scale
}
contentItem: ColumnLayout {
anchors.rightMargin: Kirigami.Units.smallSpacing
anchors.leftMargin: Kirigami.Units.smallSpacing

View file

@ -128,6 +128,18 @@ Controls.ItemDelegate {
Layout.fillWidth: true
spacing: Kirigami.Units.smallSpacing
PlasmaComponents.ToolButton {
icon.name: Icon.name(Volume / PulseAudio.NormalVolume * 100.0, Muted)
text: Muted ? i18n("Unmute") : i18n("Mute")
display: Controls.AbstractButton.IconOnly
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium
Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium
onClicked: {
Muted = !Muted
}
}
// this slider was effectively copied from the source (linked at the top of the file)
PlasmaComponents.Slider {
id: slider

View file

@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2021 Devin Lin <espidev@gmail.com>
* SPDX-FileCopyrightText: 2024 Micah Stanley <stanleymicah@proton.me>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
@ -9,6 +10,9 @@ import QtQuick.Controls as Controls
import QtQuick.Layouts
import QtQuick.Window
import QtQuick.Effects
import Qt5Compat.GraphicalEffects
import org.kde.kirigami 2.20 as Kirigami
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.components 3.0 as PlasmaComponents
@ -16,11 +20,40 @@ import org.kde.plasma.components 3.0 as PlasmaComponents
// capture presses on the audio applet so it doesn't close the overlay
Controls.Control {
id: content
implicitWidth: Math.min(Kirigami.Units.gridUnit * 20, parent.width - Kirigami.Units.gridUnit * 2)
implicitWidth: Math.min(Kirigami.Units.gridUnit * 20, Screen.width - Kirigami.Units.gridUnit * 2)
padding: Kirigami.Units.smallSpacing * 2
background: KSvg.FrameSvgItem {
imagePath: "widgets/background"
anchors.margins: -Kirigami.Units.smallSpacing * 2
Kirigami.Theme.colorSet: Kirigami.Theme.View
Kirigami.Theme.inherit: false
MultiEffect {
anchors.fill: parent
source: simpleShadow
blurMax: 16
shadowEnabled: true
shadowVerticalOffset: 1
shadowOpacity: 0.85
shadowColor: Qt.lighter(Kirigami.Theme.backgroundColor, 0.2)
}
Rectangle {
id: simpleShadow
anchors.fill: parent
anchors.leftMargin: -1
anchors.rightMargin: -1
anchors.bottomMargin: -1
color: {
let darkerBackgroundColor = Qt.darker(Kirigami.Theme.backgroundColor, 1.3);
return Qt.rgba(darkerBackgroundColor.r, darkerBackgroundColor.g, darkerBackgroundColor.b, 0.5)
}
radius: Kirigami.Units.cornerRadius
}
Rectangle {
anchors.fill: parent
color: Qt.lighter(Kirigami.Theme.backgroundColor, 1.5)
opacity: 0.85
radius: Kirigami.Units.cornerRadius
}
}

View file

@ -0,0 +1,270 @@
/*
* 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
visible: false
readonly property real offsetMargins: Math.max(cards.offset, 0)
LayerShell.Window.scope: "overlay"
LayerShell.Window.anchors: LayerShell.Window.AnchorTop
LayerShell.Window.layer: LayerShell.Window.LayerOverlay
LayerShell.Window.exclusionZone: -1
LayerShell.Window.margins.top: offsetMargins
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() {
cards.state = "open";
// set window input transparency to accept touches
ShellUtil.setInputTransparent(window, false);
window.visible = true;
}
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);
}
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
property real scale: 0.95
state: "closed"
states: [
State {
name: "open"
PropertyChanges {
target: cards; offset: openOffset
}
PropertyChanges {
target: cards; scale: 1.0
}
},
State {
name: "closed"
PropertyChanges {
target: cards; offset: closedOffset
}
PropertyChanges {
target: cards; scale: 0.95
}
}
]
transitions: Transition {
SequentialAnimation {
ParallelAnimation {
PropertyAnimation {
properties: "offset"; easing.type: Easing.OutExpo; duration: Kirigami.Units.veryLongDuration
}
PropertyAnimation {
properties: "scale"; easing.type: Easing.OutExpo; duration: Kirigami.Units.veryLongDuration
}
}
ScriptAction {
script: {
if (cards.state == "open") {
hideTimer.restart();
} 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 - window.offsetMargins + 1
},
Scale {
origin.x: Math.round(width / 2)
origin.y: Math.round(height / 2)
xScale: cards.scale
yScale: cards.scale
}
]
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()
}
}
}
}
}

View file

@ -13,63 +13,130 @@ 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.nanoshell 2.0 as NanoShell
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.state as MobileShellState
import org.kde.plasma.private.volume
NanoShell.FullScreenOverlay {
import org.kde.layershell 1.0 as LayerShell
Window {
id: window
// used by context menus opened in the applet to not autoclose the osd
property bool suppressActiveClose: false
// whether the applet is showing all devices
property bool showFullApplet: false
width: Screen.width
height: Screen.height
visible: false
color: showFullApplet ? Qt.rgba(0, 0, 0, 0.6) : "transparent"
Behavior on color {
ColorAnimation {}
}
LayerShell.Window.scope: "overlay"
LayerShell.Window.anchors: LayerShell.Window.AnchorTop
LayerShell.Window.layer: LayerShell.Window.LayerTop
LayerShell.Window.exclusionZone: -1
readonly property color backgroundColor: Qt.darker(Qt.rgba(Kirigami.Theme.backgroundColor.r, Kirigami.Theme.backgroundColor.g, Kirigami.Theme.backgroundColor.b, 0.95), 1.05)
Kirigami.Theme.colorSet: Kirigami.Theme.View
Kirigami.Theme.inherit: false
color: backgroundColor
function showOverlay() {
if (!window.visible) {
window.showFullApplet = false;
window.showFullScreen();
hideTimer.restart();
} else if (!window.showFullApplet) { // don't autohide applet when the full applet is showing
hideTimer.restart();
window.open();
}
}
onActiveChanged: {
if (!active && !suppressActiveClose) {
hideTimer.stop();
hideTimer.triggered();
}
function open() {
flickable.state = "open";
// set window input transparency to accept touches
ShellUtil.setInputTransparent(window, false);
window.visible = true;
}
Timer {
id: hideTimer
interval: 3000
running: false
onTriggered: {
window.close();
window.showFullApplet = false;
}
function close() {
flickable.state = "closed";
// set window input transparency to allow touches to pass through while the closing animation is playing
ShellUtil.setInputTransparent(window, true);
}
Component.onCompleted: {
window.close();
visible = false;
}
Flickable {
id: flickable
anchors.fill: parent
contentHeight: cards.implicitHeight
boundsBehavior: window.showFullApplet ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
boundsBehavior: Flickable.DragAndOvershootBounds
pressDelay: 50
property real offset: -Kirigami.Units.gridUnit
property real scale: 0.95
state: "closed"
states: [
State {
name: "open"
PropertyChanges {
target: flickable; offset: 0
}
PropertyChanges {
target: flickable; scale: 1.0
}
PropertyChanges {
target: flickable; opacity: 1.0
}
PropertyChanges {
target: window; color: backgroundColor
}
},
State {
name: "closed"
PropertyChanges {
target: flickable; offset: -Kirigami.Units.gridUnit * 3
}
PropertyChanges {
target: flickable; scale: 0.95
}
PropertyChanges {
target: flickable; opacity: 0.0
}
PropertyChanges {
target: window; color: "transparent"
}
}
]
transitions: Transition {
SequentialAnimation {
ParallelAnimation {
PropertyAnimation {
properties: "offset"; easing.type: Easing.OutExpo; duration: Kirigami.Units.veryLongDuration
}
PropertyAnimation {
properties: "scale"; easing.type: Easing.OutExpo; duration: Kirigami.Units.veryLongDuration
}
PropertyAnimation {
properties: "opacity"; easing.type: Easing.OutExpo; duration: Kirigami.Units.veryLongDuration
}
PropertyAnimation {
properties: "color"; easing.type: Easing.OutExpo; duration: Kirigami.Units.veryLongDuration
}
}
ScriptAction {
script: {
if (flickable.state == "closed") {
window.visible = false;
}
}
}
}
}
MouseArea {
// capture taps behind cards to close
anchors.left: parent.left
@ -77,8 +144,7 @@ NanoShell.FullScreenOverlay {
width: parent.width
height: Math.max(cards.implicitHeight, window.height)
onReleased: {
hideTimer.stop();
hideTimer.triggered();
window.close();
}
ColumnLayout {
@ -88,126 +154,63 @@ NanoShell.FullScreenOverlay {
anchors.right: parent.right
spacing: 0
// osd card
PopupCard {
id: osd
Layout.topMargin: Kirigami.Units.gridUnit
Layout.alignment: Qt.AlignHCenter
contentItem: RowLayout {
id: containerLayout
spacing: Kirigami.Units.smallSpacing
anchors.leftMargin: Kirigami.Units.smallSpacing * 2
anchors.rightMargin: Kirigami.Units.smallSpacing
PlasmaComponents.ToolButton {
icon.name: !PreferredDevice.sink || PreferredDevice.sink.muted ? "audio-volume-muted" : "audio-volume-high"
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: muteVolume()
}
PlasmaComponents.ProgressBar {
id: volumeSlider
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: Kirigami.Units.smallSpacing * 2
value: MobileShell.AudioInfo.volumeValue
from: 0
to: MobileShell.AudioInfo.maxVolumePercent
Behavior on value { NumberAnimation { duration: Kirigami.Units.shortDuration } }
}
// Get the width of a three-digit number so we can size the label
// to the maximum width to avoid the progress bar resizing itself
TextMetrics {
id: widestLabelSize
text: i18n("100%")
font: percentageLabel.font
}
Kirigami.Heading {
id: percentageLabel
Layout.preferredWidth: widestLabelSize.width
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: Kirigami.Units.smallSpacing
level: 3
text: i18nc("Percentage value", "%1%", MobileShell.AudioInfo.volumeValue)
// Display a subtle visual indication that the volume might be
// dangerously high
// ------------------------------------------------
// Keep this in sync with the copies in plasma-pa:ListItemBase.qml
// and plasma-pa:VolumeSlider.qml
color: {
if (MobileShell.AudioInfo.volumeValue <= 100) {
return Kirigami.Theme.textColor
} else if (MobileShell.AudioInfo.volumeValue > 100 && MobileShell.AudioInfo.volumeValue <= 125) {
return Kirigami.Theme.neutralTextColor
} else {
return Kirigami.Theme.negativeTextColor
}
}
}
PlasmaComponents.ToolButton {
icon.name: "configure"
text: i18n("Open audio settings")
visible: opacity !== 0
opacity: showFullApplet ? 1 : 0
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
Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration } }
onClicked: {
let coords = mapToItem(flickable, 0, 0);
MobileShell.ShellUtil.executeCommand("plasma-open-settings kcm_pulseaudio");
}
}
PlasmaComponents.ToolButton {
icon.name: window.showFullApplet ? "arrow-up" : "arrow-down"
text: i18n("Toggle showing audio streams")
display: Controls.AbstractButton.IconOnly
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: Kirigami.Units.iconSizes.medium
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
onClicked: {
window.showFullApplet = !window.showFullApplet
// don't autohide applet when full applet is shown
if (window.showFullApplet) {
hideTimer.stop();
} else {
hideTimer.restart();
}
}
}
}
transform: Translate {
y: flickable.offset
}
// other applet cards
AudioApplet {
id: applet
Layout.topMargin: Kirigami.Units.gridUnit
Layout.topMargin: Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing * 3
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: cards.width
opacity: window.showFullApplet ? 1 : 0
visible: opacity !== 0
transform: Translate {
y: window.showFullApplet ? 0 : -Kirigami.Units.gridUnit
Behavior on y { NumberAnimation {} }
scale: flickable.scale
}
PopupCard {
id: settings
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: Kirigami.Units.gridUnit
transform: Scale {
origin.x: Math.round(implicitWidth / 2)
origin.y: Math.round(height / 2)
xScale: flickable.scale
yScale: flickable.scale
}
Behavior on opacity { NumberAnimation {} }
contentItem: RowLayout {
PlasmaComponents.ToolButton {
property int addedPadding: Kirigami.Units.smallSpacing * 2
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.preferredWidth: parent.width - addedPadding * 2
Layout.preferredHeight: Kirigami.Units.iconSizes.medium
Layout.margins: addedPadding
contentItem: Item {
anchors.fill: parent
RowLayout {
spacing: Kirigami.Units.largeSpacing
anchors.centerIn: parent
Kirigami.Icon {
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium
Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium
source: "settings-configure"
}
PlasmaComponents.Label {
text: i18n("Open audio settings")
anchors.verticalCenter: parent.verticalCenter
}
}
}
onClicked: {
MobileShell.ShellUtil.executeCommand("plasma-open-settings kcm_pulseaudio");
window.close();
}
}
}
}
}
}

View file

@ -20,7 +20,9 @@ QtObject {
id: component
function showVolumeOverlay() {
osd.showOverlay();
if (!osd.visible) {
vcp.showOverlay();
}
}
Component.onCompleted: {
@ -31,9 +33,11 @@ QtObject {
target: MobileShellState.ShellDBusClient
function onShowVolumeOSDRequested() {
component.showVolumeOverlay();
osd.showOverlay();
vcp.close();
}
}
property var osd: VolumeOSD {}
property var vcp: VolumeChangedPopup {}
}

View file

@ -14,6 +14,8 @@
#include <KNotification>
#include <KNotificationJobUiDelegate>
#include <QQuickWindow>
#include <QDBusPendingReply>
#include <QDateTime>
#include <QDebug>
@ -87,3 +89,16 @@ void ShellUtil::launchApp(const QString &storageId)
job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled));
job->start();
}
void ShellUtil::setInputTransparent(QQuickWindow *window, bool transparent) {
if (window) {
Qt::WindowFlags flags = window->flags();
if (transparent) {
flags |= Qt::WindowTransparentForInput;
} else {
flags &= ~Qt::WindowTransparentForInput;
}
window->setFlags(flags);
}
}

View file

@ -9,6 +9,7 @@
#include <QObject>
#include <QQuickItem>
#include <QQuickWindow>
#include <qqmlregistration.h>
#include <KConfigWatcher>
@ -65,6 +66,11 @@ public:
*/
Q_INVOKABLE bool isSystem24HourFormat();
/**
* Set window input to be transparent.
*/
Q_INVOKABLE void setInputTransparent(QQuickWindow *window, bool transparent);
Q_SIGNALS:
void isSystem24HourFormatChanged();