audio: Refactor applet and extract singleton to MobileShellState

The eventual goal is to have as few singletons with state as possible in the mobileshell component when it is imported into components such as the lockscreen.

This doesn't fully accomplish it, but moves the audio provider singleton to MobileShellState, which will eventually need to be prevented from importing into non plasmashell processes.

This also disables the sound feedback when changing volume, since it can be a source of lag when showing the applet.
This commit is contained in:
Devin Lin 2023-03-16 07:21:01 +00:00
parent 076d1c4f0c
commit 158af43fd4
24 changed files with 283 additions and 301 deletions

View file

@ -76,10 +76,10 @@ void MobileShellPlugin::registerTypes(const char *uri)
qmlRegisterType(resolvePath("components/VelocityCalculator.qml"), uri, 1, 0, "VelocityCalculator");
// /dataproviders
qmlRegisterType(resolvePath("dataproviders/AudioInfo.qml"), uri, 1, 0, "AudioInfo");
qmlRegisterType(resolvePath("dataproviders/BatteryInfo.qml"), uri, 1, 0, "BatteryInfo");
qmlRegisterType(resolvePath("dataproviders/BluetoothInfo.qml"), uri, 1, 0, "BluetoothInfo");
qmlRegisterType(resolvePath("dataproviders/SignalStrengthInfo.qml"), uri, 1, 0, "SignalStrengthInfo");
qmlRegisterSingletonType(resolvePath("dataproviders/AudioProvider.qml"), uri, 1, 0, "AudioProvider");
// /homescreen
qmlRegisterType(resolvePath("homescreen/HomeScreen.qml"), uri, 1, 0, "HomeScreen");
@ -92,6 +92,9 @@ void MobileShellPlugin::registerTypes(const char *uri)
// /statusbar
qmlRegisterType(resolvePath("statusbar/StatusBar.qml"), uri, 1, 0, "StatusBar");
// /volumeosd
qmlRegisterType(resolvePath("volumeosd/VolumeOSD.qml"), uri, 1, 0, "VolumeOSD");
// /widgets
qmlRegisterType(resolvePath("widgets/krunner/KRunnerWidget.qml"), uri, 1, 0, "KRunnerWidget");
qmlRegisterType(resolvePath("widgets/mediacontrols/MediaControlsWidget.qml"), uri, 1, 0, "MediaControlsWidget");

View file

@ -0,0 +1,90 @@
// SPDX-FileCopyrightText: 2023 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
import QtQuick
import org.kde.plasma.private.volume
QtObject {
property SinkModel paSinkModel: SinkModel {}
// whether the audio icon should be visible in the status bar
readonly property bool isVisible: paSinkModel.preferredSink && paSinkModel.preferredSink.muted
// the icon that should be displayed in the status bar
readonly property string icon: paSinkModel.preferredSink && !isDummyOutput(paSinkModel.preferredSink)
? iconName(paSinkModel.preferredSink.volume, paSinkModel.preferredSink.muted)
: iconName(0, true)
// the name of the audio device when it isn't valid
readonly property string dummyOutputName: "auto_null"
// the maximum volume amount
readonly property int maxVolumeValue: Math.round(100 * PulseAudio.NormalVolume / 100.0)
// step that increments when adjusting the volume
readonly property int volumeStep: Math.round(5 * PulseAudio.NormalVolume / 100.0)
function isDummyOutput(output) {
return output && output.name === dummyOutputName;
}
function boundVolume(volume) {
return Math.max(PulseAudio.MinimalVolume, Math.min(volume, maxVolumeValue));
}
function volumePercent(volume, max){
if (!max) {
max = PulseAudio.NormalVolume;
}
return Math.round(volume / max * 100.0);
}
function increaseVolume() {
if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
return;
}
var volume = boundVolume(paSinkModel.preferredSink.volume + volumeStep);
var percent = volumePercent(volume, maxVolumeValue);
paSinkModel.preferredSink.muted = percent == 0;
paSinkModel.preferredSink.volume = volume;
}
function decreaseVolume() {
if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
return;
}
var volume = boundVolume(paSinkModel.preferredSink.volume - volumeStep);
var percent = volumePercent(volume, maxVolumeValue);
paSinkModel.preferredSink.muted = percent == 0;
paSinkModel.preferredSink.volume = volume;
}
function muteVolume() {
if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
return;
}
paSinkModel.preferredSink.muted = !paSinkModel.preferredSink.muted;
}
function iconName(volume, muted, prefix) {
if (!prefix) {
prefix = "audio-volume";
}
var icon = null;
var percent = volume / maxVolumeValue;
if (percent <= 0.0 || muted) {
icon = prefix + "-muted";
} else if (percent <= 0.25) {
icon = prefix + "-low";
} else if (percent <= 0.75) {
icon = prefix + "-medium";
} else {
icon = prefix + "-high";
}
return icon;
}
}

View file

@ -1,195 +0,0 @@
/*
SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
SPDX-FileCopyrightText: 2019 Aditya Mehra <Aix.m@outlook.com>
SPDX-FileCopyrightText: 2014-2015 Harald Sitter <sitter@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
import QtQuick 2.2
import QtQuick.Layouts 1.4
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.private.volume 0.1
import "../osd/volume"
pragma Singleton
QtObject {
/**
* Whether or not to bind the volume global key shortcuts.
* We should never bind the shortcut multiple times in the shell, or else they may not work at all.
*
* We only set this to true when loaded for the panel containment (and NOT in the lockscreen).
*/
property bool bindShortcuts: false
readonly property bool isVisible: paSinkModel.preferredSink && paSinkModel.preferredSink.muted
readonly property string icon: paSinkModel.preferredSink && !isDummyOutput(paSinkModel.preferredSink)
? iconName(paSinkModel.preferredSink.volume, paSinkModel.preferredSink.muted)
: iconName(0, true)
readonly property int maxVolumeValue: Math.round(100 * PulseAudio.NormalVolume / 100.0)
readonly property int volumeStep: Math.round(5 * PulseAudio.NormalVolume / 100.0)
property int volumeValue
readonly property string dummyOutputName: "auto_null"
function showVolumeOverlay() {
osd.showOverlay();
}
function iconName(volume, muted, prefix) {
if (!prefix) {
prefix = "audio-volume";
}
var icon = null;
var percent = volume / maxVolumeValue;
if (percent <= 0.0 || muted) {
icon = prefix + "-muted";
} else if (percent <= 0.25) {
icon = prefix + "-low";
} else if (percent <= 0.75) {
icon = prefix + "-medium";
} else {
icon = prefix + "-high";
}
return icon;
}
function isDummyOutput(output) {
return output && output.name === dummyOutputName;
}
function boundVolume(volume) {
return Math.max(PulseAudio.MinimalVolume, Math.min(volume, maxVolumeValue));
}
function volumePercent(volume, max){
if(!max) {
max = PulseAudio.NormalVolume;
}
return Math.round(volume / max * 100.0);
}
function playFeedback(sinkIndex) {
if (sinkIndex == undefined) {
sinkIndex = paSinkModel.preferredSink.index;
}
feedback.play(sinkIndex)
}
function increaseVolume() {
if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
return;
}
var volume = boundVolume(paSinkModel.preferredSink.volume + volumeStep);
var percent = volumePercent(volume, maxVolumeValue);
paSinkModel.preferredSink.muted = percent == 0;
paSinkModel.preferredSink.volume = volume;
volumeValue = percent;
osd.showOverlay();
playFeedback();
}
function decreaseVolume() {
if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
return;
}
var volume = boundVolume(paSinkModel.preferredSink.volume - volumeStep);
var percent = volumePercent(volume, maxVolumeValue);
paSinkModel.preferredSink.muted = percent == 0;
paSinkModel.preferredSink.volume = volume;
volumeValue = percent;
osd.showOverlay();
playFeedback();
}
function muteVolume() {
if (!paSinkModel.preferredSink || isDummyOutput(paSinkModel.preferredSink)) {
return;
}
var toMute = !paSinkModel.preferredSink.muted;
paSinkModel.preferredSink.muted = toMute;
volumeValue = toMute ? 0 : volumePercent(paSinkModel.preferredSink.volume, maxVolumeValue);
osd.showOverlay();
if (!toMute) {
playFeedback();
}
}
property var updateVolume: Connections {
target: paSinkModel.preferredSink
function onVolumeChanged() {
var percent = volumePercent(paSinkModel.preferredSink.volume, maxVolumeValue);
volumeValue = percent;
}
}
property var updateVolumeOnSinkChange: Connections {
target: paSinkModel
function onPreferredSinkChanged() {
if (paSinkModel.preferredSink) {
var percent = volumePercent(paSinkModel.preferredSink.volume, maxVolumeValue);
volumeValue = percent;
}
}
}
property SinkModel paSinkModel: SinkModel {}
property var osd: VolumeOSD {
volume: volumeValue
}
property VolumeFeedback feedback: VolumeFeedback {}
// only bind the global shortcuts when told to
property var actionCollection: Loader {
active: bindShortcuts
sourceComponent: GlobalActionCollection {
// KGlobalAccel cannot transition from kmix to something else, so if
// the user had a custom shortcut set for kmix those would get lost.
// To avoid this we hijack kmix name and actions. Entirely mental but
// best we can do to not cause annoyance for the user.
// The display name actually is updated to whatever registered last
// though, so as far as user visible strings go we should be fine.
// As of 2015-07-21:
// componentName: kmix
// actions: increase_volume, decrease_volume, mute
name: "kmix"
displayName: i18n("Audio")
GlobalAction {
objectName: "increase_volume"
text: i18n("Increase Volume")
shortcut: Qt.Key_VolumeUp
onTriggered: increaseVolume()
}
GlobalAction {
objectName: "decrease_volume"
text: i18n("Decrease Volume")
shortcut: Qt.Key_VolumeDown
onTriggered: decreaseVolume()
}
GlobalAction {
objectName: "mute"
text: i18n("Mute")
shortcut: Qt.Key_VolumeMute
onTriggered: muteVolume()
}
}
}
}

View file

@ -5,15 +5,14 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.6
import QtQuick.Layouts 1.4
import QtQuick
import QtQuick.Layouts
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.plasma5support 2.0 as P5Support
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.workspace.components 2.0 as PW
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.plasma5support as P5Support
import org.kde.plasma.workspace.components as PW
Item {
QtObject {
property bool isVisible: pmSource.data["Battery"]["Has Cumulative"]
property int percent: pmSource.data["Battery"]["Percent"]
property bool pluggedIn: pmSource.data["AC Adapter"] ? pmSource.data["AC Adapter"]["Plugged in"] : false

View file

@ -8,13 +8,14 @@
import QtQuick 2.2
import QtQuick.Layouts 1.4
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.private.volume 0.1
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
PlasmaCore.IconItem {
id: paIcon
readonly property var provider: MobileShell.AudioProvider
readonly property var provider: MobileShell.AudioInfo {}
Layout.fillHeight: true
Layout.preferredWidth: height

View file

@ -5,42 +5,32 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.15 as Controls
import QtQuick.Layouts 1.1
import QtQuick.Window 2.2
import QtQuick
import QtQuick.Controls as Controls
import QtQuick.Layouts
import QtQuick.Window
import Qt5Compat.GraphicalEffects
import org.kde.plasma.core 2.1 as PlasmaCore
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtra
import org.kde.kquickcontrolsaddons 2.0 as KQCAddons
import org.kde.plasma.extras as PlasmaExtra
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.kquickcontrolsaddons as KQCAddons
import org.kde.plasma.private.volume 0.1
import org.kde.plasma.private.volume
// adapted version of https://invent.kde.org/plasma/plasma-pa/-/blob/master/applet/contents/ui/main.qml
// most audio functions are in VolumeProvider.qml (which will be a parent)
// capture presses on the audio applet so it doesn't close the overlay
ColumnLayout {
spacing: 0
// pulseaudio models
function isDummyOutput(output) {
return output && output.name === dummyOutputName;
}
SinkModel {
id: paSinkModel
}
required property MobileShell.AudioInfo audioInfo
PulseObjectFilterModel {
id: paSinkFilterModel
sortRole: "SortByDefault"
sortOrder: Qt.DescendingOrder
filterOutInactiveDevices: true
sourceModel: paSinkModel
sourceModel: audioInfo.paSinkModel
}
SourceModel {

View file

@ -29,9 +29,6 @@ Controls.ItemDelegate {
property alias iconUsesPlasmaTheme: clientIcon.usesPlasmaTheme
property string type // sink, source, source-output
// backgroundColor: "transparent" // we use panel background, no need for the same colour to be on top
// activeBackgroundColor: selectButton.visible ? PlasmaCore.Theme.highlightColor : "transparent"
onClicked: {
if (selectButton.visible) {
model.PulseObject.default = true;
@ -215,10 +212,6 @@ Controls.ItemDelegate {
// whereas PA rejected the volume change and is
// still at v15 (e.g.).
updateTimer.restart();
if (baseItem.type == "sink") {
playFeedback(Index); // goes to providers/VolumeProvider.qml
}
}
}

View file

@ -6,10 +6,10 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.15 as Controls
import QtQuick.Layouts 1.1
import QtQuick.Window 2.2
import QtQuick
import QtQuick.Controls as Controls
import QtQuick.Layouts
import QtQuick.Window
import Qt5Compat.GraphicalEffects
import org.kde.plasma.core 2.0 as PlasmaCore
@ -20,27 +20,30 @@ import org.kde.plasma.private.nanoshell 2.0 as NanoShell
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
import org.kde.plasma.private.mobileshell.state 1.0 as MobileShellState
import org.kde.kirigami 2.12 as Kirigami
import org.kde.kirigami as Kirigami
// this is loaded and managed by indicators/providers/VolumeProvider.qml
NanoShell.FullScreenOverlay {
Window {
id: window
required property int volume
// 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
visible: false
color: showFullApplet ? Qt.rgba(0, 0, 0, 0.6) : "transparent"
property bool suppressActiveClose: false // used by context menus opened in the applet to not autoclose the osd
Behavior on color {
ColorAnimation {}
}
property int volume: 0
property bool showFullApplet: false
function showOverlay() {
if (!window.visible) {
window.showFullApplet = false;
window.showMaximized();
window.showFullScreen();
hideTimer.restart();
} else if (!window.showFullApplet) { // don't autohide applet when the full applet is showing
hideTimer.restart();
@ -63,15 +66,19 @@ NanoShell.FullScreenOverlay {
window.showFullApplet = false;
}
}
MobileShell.AudioInfo {
id: audioInfo
}
Flickable {
id: flickable
anchors.fill: parent
contentHeight: cards.implicitHeight
boundsBehavior: window.showFullApplet ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
pressDelay: 50
MouseArea {
// capture taps behind cards to close
anchors.left: parent.left
@ -82,30 +89,30 @@ NanoShell.FullScreenOverlay {
hideTimer.stop();
hideTimer.triggered();
}
ColumnLayout {
id: cards
width: parent.width
anchors.left: parent.left
anchors.right: parent.right
spacing: 0
// osd card
PopupCard {
id: osd
Layout.topMargin: PlasmaCore.Units.largeSpacing
Layout.alignment: Qt.AlignHCenter
contentItem: RowLayout {
id: containerLayout
spacing: PlasmaCore.Units.smallSpacing
anchors.leftMargin: PlasmaCore.Units.smallSpacing * 2
anchors.rightMargin: PlasmaCore.Units.smallSpacing
PlasmaComponents.ToolButton {
icon.name: !paSinkModel.preferredSink || paSinkModel.preferredSink.muted ? "audio-volume-muted" : "audio-volume-high"
text: !paSinkModel.preferredSink || paSinkModel.preferredSink.muted ? i18n("Unmute") : i18n("Mute")
icon.name: !audioInfo.paSinkModel.preferredSink || audioInfo.paSinkModel.preferredSink.muted ? "audio-volume-muted" : "audio-volume-high"
text: !audioInfo.paSinkModel.preferredSink || audioInfo.paSinkModel.preferredSink.muted ? i18n("Unmute") : i18n("Mute")
display: Controls.AbstractButton.IconOnly
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: PlasmaCore.Units.iconSizes.medium
@ -113,7 +120,7 @@ NanoShell.FullScreenOverlay {
Layout.rightMargin: PlasmaCore.Units.smallSpacing
onClicked: muteVolume()
}
PlasmaComponents.ProgressBar {
id: volumeSlider
Layout.fillWidth: true
@ -124,7 +131,7 @@ NanoShell.FullScreenOverlay {
to: 100
Behavior on value { NumberAnimation { duration: PlasmaCore.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 {
@ -140,7 +147,7 @@ NanoShell.FullScreenOverlay {
Layout.rightMargin: PlasmaCore.Units.smallSpacing
level: 3
text: i18nc("Percentage value", "%1%", window.volume)
// Display a subtle visual indication that the volume might be
// dangerously high
// ------------------------------------------------
@ -156,7 +163,7 @@ NanoShell.FullScreenOverlay {
}
}
}
PlasmaComponents.ToolButton {
icon.name: "configure"
text: i18n("Open audio settings")
@ -167,16 +174,16 @@ NanoShell.FullScreenOverlay {
Layout.preferredWidth: PlasmaCore.Units.iconSizes.medium
Layout.preferredHeight: PlasmaCore.Units.iconSizes.medium
Layout.rightMargin: PlasmaCore.Units.smallSpacing
Behavior on opacity { NumberAnimation { duration: PlasmaCore.Units.shortDuration } }
onClicked: {
let coords = mapToItem(flickable, 0, 0);
MobileShellState.Shell.openAppLaunchAnimation("audio-volume-high", i18n("Audio Settings"), coords.x, coords.y, PlasmaCore.Units.iconSizes.medium);
MobileShell.ShellUtil.executeCommand("plasma-open-settings kcm_pulseaudio");
}
}
PlasmaComponents.ToolButton {
icon.name: window.showFullApplet ? "arrow-up" : "arrow-down"
text: i18n("Toggle showing audio streams")
@ -203,14 +210,16 @@ NanoShell.FullScreenOverlay {
Layout.topMargin: PlasmaCore.Units.largeSpacing
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: cards.width
audioInfo: audioInfo
opacity: window.showFullApplet ? 1 : 0
visible: opacity !== 0
transform: Translate {
transform: Translate {
y: window.showFullApplet ? 0 : -PlasmaCore.Units.gridUnit
Behavior on y { NumberAnimation {} }
}
Behavior on opacity { NumberAnimation {} }
}
}

View file

@ -37,7 +37,7 @@
<file>qml/dataproviders/BatteryInfo.qml</file>
<file>qml/dataproviders/BluetoothInfo.qml</file>
<file>qml/dataproviders/SignalStrengthInfo.qml</file>
<file>qml/dataproviders/AudioProvider.qml</file>
<file>qml/dataproviders/AudioInfo.qml</file>
<file>qml/homescreen/HomeScreen.qml</file>
@ -46,13 +46,13 @@
<file>qml/navigationpanel/NavigationPanelAction.qml</file>
<file>qml/navigationpanel/NavigationPanelButton.qml</file>
<file>qml/osd/volume/AudioApplet.qml</file>
<file>qml/osd/volume/DeviceListItem.qml</file>
<file>qml/osd/volume/icon.js</file>
<file>qml/osd/volume/ListItemBase.qml</file>
<file>qml/osd/volume/PopupCard.qml</file>
<file>qml/osd/volume/StreamListItem.qml</file>
<file>qml/osd/volume/VolumeOSD.qml</file>
<file>qml/volumeosd/AudioApplet.qml</file>
<file>qml/volumeosd/DeviceListItem.qml</file>
<file>qml/volumeosd/icon.js</file>
<file>qml/volumeosd/ListItemBase.qml</file>
<file>qml/volumeosd/PopupCard.qml</file>
<file>qml/volumeosd/StreamListItem.qml</file>
<file>qml/volumeosd/VolumeOSD.qml</file>
<file>qml/statusbar/indicators/BatteryIndicator.qml</file>
<file>qml/statusbar/indicators/BluetoothIndicator.qml</file>

View file

@ -0,0 +1,10 @@
<!--
- SPDX-FileCopyrightText: None
- SPDX-License-Identifier: CC0-1.0
-->
# MobileShell State Plugin
This plugin stores the state of the mobile shell.
It should ONLY be imported by components in the plasmashell process (otherwise it won't be able to get the state).

View file

@ -16,6 +16,7 @@ void MobileShellStatePlugin::registerTypes(const char *uri)
Q_ASSERT(QLatin1String(uri) == QLatin1String("org.kde.plasma.private.mobileshell.state"));
// /
qmlRegisterSingletonType(resolvePath("AudioProvider.qml"), uri, 1, 0, "AudioProvider");
qmlRegisterSingletonType(resolvePath("HomeScreenControls.qml"), uri, 1, 0, "HomeScreenControls");
qmlRegisterSingletonType(resolvePath("Shell.qml"), uri, 1, 0, "Shell");
qmlRegisterSingletonType(resolvePath("TopPanelControls.qml"), uri, 1, 0, "TopPanelControls");

View file

@ -0,0 +1,98 @@
/*
SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
SPDX-FileCopyrightText: 2019 Aditya Mehra <Aix.m@outlook.com>
SPDX-FileCopyrightText: 2014-2015 Harald Sitter <sitter@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
import QtQuick
import QtQuick.Layouts
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.private.volume 0.1
import org.kde.plasma.private.mobileshell as MobileShell
pragma Singleton
QtObject {
id: root
/**
* Whether or not to bind the volume global key shortcuts.
* We should never bind the shortcut multiple times in the shell, or else they may not work at all.
*
* We only set this to true when loaded for the panel containment (and NOT in the lockscreen).
*/
property bool bindShortcuts: false
property int volumeValue
function showVolumeOverlay() {
osd.showOverlay();
}
property var audioInfo: MobileShell.AudioInfo {}
property var updateVolume: Connections {
target: audioInfo.paSinkModel.preferredSink
function onVolumeChanged() {
var percent = audioInfo.volumePercent(audioInfo.paSinkModel.preferredSink.volume, audioInfo.maxVolumeValue);
volumeValue = percent;
osd.showOverlay();
}
function onMutedChanged() {
volumeValue = audioInfo.paSinkModel.preferredSink.muted ? 0 : audioInfo.volumePercent(audioInfo.paSinkModel.preferredSink.volume, audioInfo.maxVolumeValue);
osd.showOverlay();
}
}
property var updateVolumeOnSinkChange: Connections {
target: audioInfo.paSinkModel
function onPreferredSinkChanged() {
if (audioInfo.paSinkModel.preferredSink) {
var percent = audioInfo.volumePercent(audioInfo.paSinkModel.preferredSink.volume, audioInfo.maxVolumeValue);
volumeValue = percent;
}
}
}
property var osd: MobileShell.VolumeOSD {
volume: volumeValue
}
// only bind the global shortcuts when told to
property var actionCollection: Loader {
active: bindShortcuts
sourceComponent: GlobalActionCollection {
name: "kmix"
displayName: i18n("Audio")
GlobalAction {
objectName: "increase_volume"
text: i18n("Increase Volume")
shortcut: Qt.Key_VolumeUp
onTriggered: root.audioInfo.increaseVolume()
}
GlobalAction {
objectName: "decrease_volume"
text: i18n("Decrease Volume")
shortcut: Qt.Key_VolumeDown
onTriggered: root.audioInfo.decreaseVolume()
}
GlobalAction {
objectName: "mute"
text: i18n("Mute")
shortcut: Qt.Key_VolumeMute
onTriggered: root.audioInfo.muteVolume()
}
}
}
}

View file

@ -5,9 +5,6 @@
import QtQuick 2.12
import QtQuick.Window 2.2
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.windowplugin as WindowPlugin
pragma Singleton
/**
@ -26,15 +23,4 @@ QtObject {
property var taskSwitcher
property QtObject homeScreenWindow
property bool taskSwitcherVisible: false
// this state is updated from WindowUtil
property bool homeScreenVisible: true
property var windowListener: Connections {
target: WindowPlugin.WindowUtil
function onAllWindowsMinimizedChanged() {
root.homeScreenVisible = WindowPlugin.WindowUtil.allWindowsMinimized
}
}
}

View file

@ -12,11 +12,6 @@ pragma Singleton
QtObject {
id: delegate
/**
* Whether the homescreen is currently visible.
*/
readonly property bool homeScreenVisible: HomeScreenControls.homeScreenVisible
/**
* Whether the action drawer is currently open.
*/

View file

@ -7,6 +7,7 @@
<file>qml/HomeScreenControls.qml</file>
<file>qml/Shell.qml</file>
<file>qml/TopPanelControls.qml</file>
<file>qml/AudioProvider.qml</file>
</qresource>
</RCC>

View file

@ -16,6 +16,7 @@ import org.kde.plasma.components 3.0 as PlasmaComponents
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
import org.kde.plasma.private.mobileshell.state 1.0 as MobileShellState
import org.kde.private.mobile.homescreen.folio 1.0 as Folio
import org.kde.plasma.private.mobileshell.windowplugin as WindowPlugin
MobileShell.HomeScreen {
id: root
@ -43,7 +44,7 @@ MobileShell.HomeScreen {
// - minimize windows (only if we are in an app)
// - open app drawer
// - close app drawer and, if necessary, restore windows
if (!plasmoid.nativeInterface.showingDesktop && !MobileShellState.Shell.homeScreenVisible
if (!plasmoid.nativeInterface.showingDesktop && !WindowPlugin.WindowUtil.allWindowsMinimized
|| MobileShellState.Shell.actionDrawerVisible
|| searchWidget.isOpen
) {

View file

@ -14,6 +14,7 @@ import org.kde.draganddrop as DragDrop
import org.kde.kirigami as Kirigami
import org.kde.plasma.private.mobileshell.state as MobileShellState
import org.kde.plasma.private.mobileshell.windowplugin as WindowPlugin
Item {
id: root
@ -45,7 +46,7 @@ Item {
target: MobileShellState.HomeScreenControls
function onHomeScreenVisibleChanged(){
if (MobileShellState.HomeScreenControls.homeScreenVisible) {
if (WindowPlugin.WindowUtil.allWindowsMinimized) {
swipeView.focusChild();
}
}

View file

@ -46,9 +46,7 @@ MobileShell.HomeScreen {
// - minimize windows (only if we are in an app)
// - open app drawer
// - close app drawer and, if necessary, restore windows
if (!WindowPlugin.WindowUtil.showDesktop && !MobileShellState.Shell.homeScreenVisible
|| search.isOpen
) {
if (!WindowPlugin.WindowUtil.showDesktop && !WindowPlugin.WindowUtil.allWindowsMinimized || search.isOpen) {
// Always close action drawer
if (MobileShellState.Shell.actionDrawerVisible) {
MobileShellState.Shell.closeActionDrawer();

View file

@ -90,7 +90,7 @@ Item {
Component.onCompleted: {
// we want to bind global volume shortcuts here
MobileShell.AudioProvider.bindShortcuts = true;
MobileShellState.AudioProvider.bindShortcuts = true;
}
TaskManager.VirtualDesktopInfo {

View file

@ -1,17 +1,18 @@
// SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
import QtQuick 2.15
import QtQuick
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
import org.kde.plasma.private.mobileshell as MobileShell
import org.kde.plasma.private.mobileshell.state as MobileShellState
MobileShell.QuickSetting {
text: i18n("Sound")
icon: "audio-speakers-symbolic"
status: i18n("%1%", MobileShell.AudioProvider.volumeValue)
status: i18n("%1%", MobileShellState.AudioProvider.volumeValue)
enabled: false
settingsCommand: "plasma-open-settings kcm_pulseaudio"
function toggle() {
MobileShell.AudioProvider.showVolumeOverlay()
MobileShellState.AudioProvider.showVolumeOverlay()
}
}