diff --git a/applet/contents/ui/ListItemBase.qml b/applet/contents/ui/ListItemBase.qml --- a/applet/contents/ui/ListItemBase.qml +++ b/applet/contents/ui/ListItemBase.qml @@ -1,5 +1,6 @@ /* Copyright 2014-2015 Harald Sitter + Copyright 2019 Sefa Eyeoglu This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -135,6 +136,7 @@ readonly property bool isPlayback: type.substring(0, 4) == "sink" icon: Icon.name(Volume, Muted, isPlayback ? "audio-volume" : "microphone-sensitivity") onClicked: Muted = !Muted + checked: Muted tooltip: i18n("Mute %1", textLabel.text) } diff --git a/src/kcm/package/contents/code/icon.js b/src/kcm/package/contents/code/icon.js new file mode 100644 --- /dev/null +++ b/src/kcm/package/contents/code/icon.js @@ -0,0 +1,38 @@ +/* + Copyright 2014-2015 Harald Sitter + Copyright 2019 Sefa Eyeoglu + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) version 3, or any + later version accepted by the membership of KDE e.V. (or its + successor approved by the membership of KDE e.V.), which shall + act as a proxy defined in Section 6 of version 3 of the license. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . +*/ + +function name(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; +} diff --git a/src/kcm/package/contents/ui/Applications.qml b/src/kcm/package/contents/ui/Applications.qml --- a/src/kcm/package/contents/ui/Applications.qml +++ b/src/kcm/package/contents/ui/Applications.qml @@ -1,6 +1,7 @@ /* Copyright 2014-2015 Harald Sitter Copyright 2016 David Rosca + Copyright 2019 Sefa Eyeoglu This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -45,7 +46,7 @@ Header { Layout.fillWidth: true enabled: eventStreamView.count || sinkInputView.count - text: i18nd("kcm_pulseaudio", "Playback") + text: i18nd("kcm_pulseaudio", "Playback Streams") disabledText: i18ndc("kcm_pulseaudio", "@label", "No Applications Playing Audio") } @@ -62,6 +63,7 @@ } delegate: StreamListItem { deviceModel: sinkModel + isPlayback: true } } @@ -78,13 +80,14 @@ } delegate: StreamListItem { deviceModel: sinkModel + isPlayback: true } } Header { Layout.fillWidth: true enabled: sourceOutputView.count > 0 - text: i18nd("kcm_pulseaudio", "Recording") + text: i18nd("kcm_pulseaudio", "Recording Streams") disabledText: i18ndc("kcm_pulseaudio", "@label", "No Applications Recording Audio") } @@ -102,6 +105,7 @@ delegate: StreamListItem { deviceModel: sourceModel + isPlayback: false } } } diff --git a/src/kcm/package/contents/ui/DeviceListItem.qml b/src/kcm/package/contents/ui/DeviceListItem.qml --- a/src/kcm/package/contents/ui/DeviceListItem.qml +++ b/src/kcm/package/contents/ui/DeviceListItem.qml @@ -1,5 +1,6 @@ /* Copyright 2014-2015 Harald Sitter + Copyright 2019 Sefa Eyeoglu This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -29,6 +30,10 @@ id: delegate width: parent.width + property bool isPlayback: type.substring(0, 4) == "sink" + + readonly property var currentPort: Ports[ActivePortIndex] + RowLayout { Kirigami.Icon { Layout.alignment: Qt.AlignHCenter @@ -41,7 +46,38 @@ id: inputText Layout.fillWidth: true elide: Text.ElideRight - text: Description + text: !currentPort ? Description : i18ndc("kcm_pulseaudio", "label of device items", "%1 (%2)", currentPort.description, Description) + } + + Label { + visible: portbox.count > 1 + text: i18nd("kcm_pulseaudio", "Port:") + } + + ComboBox { + id: portbox + visible: portbox.count > 1 + readonly property var ports: Ports + onModelChanged: currentIndex = ActivePortIndex + currentIndex: ActivePortIndex + onActivated: ActivePortIndex = index + + onPortsChanged: { + var items = []; + for (var i = 0; i < ports.length; ++i) { + var port = ports[i]; + var text = port.description; + if (port.availability == Port.Unavailable) { + if (port.name == "analog-output-speaker" || port.name == "analog-input-microphone-internal") { + text += i18ndc("kcm_pulseaudio", "Port is unavailable", " (unavailable)"); + } else { + text += i18ndc("kcm_pulseaudio", "Port is unplugged", " (unplugged)"); + } + } + items.push(text); + } + model = items; + } } Button { @@ -52,51 +88,19 @@ checked: Default onClicked: Default = true; } - - MuteButton { - muted: Muted - onCheckedChanged: Muted = checked - } } ColumnLayout { width: parent.width RowLayout { - visible: portbox.count > 1 - - Label { - text: i18nd("kcm_pulseaudio", "Port") + MuteButton { + muted: Muted + onCheckedChanged: Muted = checked } - ComboBox { - id: portbox - readonly property var ports: Ports - Layout.fillWidth: true - onModelChanged: currentIndex = ActivePortIndex - currentIndex: ActivePortIndex - onActivated: ActivePortIndex = index - - onPortsChanged: { - var items = []; - for (var i = 0; i < ports.length; ++i) { - var port = ports[i]; - var text = port.description; - if (port.availability == Port.Unavailable) { - if (port.name == "analog-output-speaker" || port.name == "analog-input-microphone-internal") { - text += i18ndc("kcm_pulseaudio", "Port is unavailable", " (unavailable)"); - } else { - text += i18ndc("kcm_pulseaudio", "Port is unplugged", " (unplugged)"); - } - } - items.push(text); - } - model = items; - } - } + VolumeSlider {} } - - VolumeSlider {} } ListItemSeperator { view: delegate.ListView.view } diff --git a/src/kcm/package/contents/ui/Devices.qml b/src/kcm/package/contents/ui/Devices.qml --- a/src/kcm/package/contents/ui/Devices.qml +++ b/src/kcm/package/contents/ui/Devices.qml @@ -1,5 +1,6 @@ /* Copyright 2014-2015 Harald Sitter + Copyright 2019 Sefa Eyeoglu This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -42,8 +43,8 @@ Header { Layout.fillWidth: true enabled: sinks.count > 0 - text: i18nd("kcm_pulseaudio", "Outputs") - disabledText: i18ndc("kcm_pulseaudio", "@label", "No Output Devices Available") + text: i18nd("kcm_pulseaudio", "Playback Devices") + disabledText: i18ndc("kcm_pulseaudio", "@label", "No Playback Devices Available") } ListView { @@ -54,14 +55,16 @@ interactive: false spacing: units.smallSpacing * 2 model: sinkModel - delegate: DeviceListItem {} + delegate: DeviceListItem { + isPlayback: true + } } Header { Layout.fillWidth: true enabled: sources.count > 0 - text: i18nd("kcm_pulseaudio", "Inputs") - disabledText: i18ndc("kcm_pulseaudio", "@label", "No Input Devices Available") + text: i18nd("kcm_pulseaudio", "Recording Devices") + disabledText: i18ndc("kcm_pulseaudio", "@label", "No Recording Devices Available") } ListView { @@ -71,7 +74,9 @@ Layout.margins: units.gridUnit / 2 interactive: false model: sourceModel - delegate: DeviceListItem {} + delegate: DeviceListItem { + isPlayback: false + } } } } diff --git a/src/kcm/package/contents/ui/MuteButton.qml b/src/kcm/package/contents/ui/MuteButton.qml --- a/src/kcm/package/contents/ui/MuteButton.qml +++ b/src/kcm/package/contents/ui/MuteButton.qml @@ -1,5 +1,6 @@ /* Copyright 2014-2015 Harald Sitter + Copyright 2019 Sefa Eyeoglu This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -19,14 +20,18 @@ */ import QtQuick 2.0 -import QtQuick.Controls 1.0 +import QtQuick.Controls 2.5 as QQC2 +import "../code/icon.js" as Icon -Button { +QQC2.ToolButton { property bool muted: true - iconName: 'audio-volume-muted' - tooltip: i18nd("kcm_pulseaudio", "Mute audio") + icon.name: Icon.name(Volume, Muted, isPlayback ? "audio-volume" : "microphone-sensitivity") checkable: true checked: muted onMutedChanged: checked = muted + + QQC2.ToolTip { + text: i18ndc("kcm_pulseaudio", "Mute audio stream", "Mute %1", inputText.text) // a little hacky + } } diff --git a/src/kcm/package/contents/ui/StreamListItem.qml b/src/kcm/package/contents/ui/StreamListItem.qml --- a/src/kcm/package/contents/ui/StreamListItem.qml +++ b/src/kcm/package/contents/ui/StreamListItem.qml @@ -1,5 +1,6 @@ /* Copyright 2014-2015 Harald Sitter + Copyright 2019 Sefa Eyeoglu This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -30,6 +31,7 @@ property alias deviceModel: deviceComboBox.model readonly property bool isEventStream: Name == "sink-input-by-media-role:event" + property bool isPlayback: type.substring(0, 4) == "sink" width: parent.width @@ -71,14 +73,16 @@ Layout.preferredWidth: delegate.width / 3 visible: !isEventStream && count > 1 } + } + RowLayout { MuteButton { muted: Muted onCheckedChanged: Muted = checked } - } - VolumeSlider {} + VolumeSlider {} + } } } diff --git a/src/kcm/package/contents/ui/VolumeSlider.qml b/src/kcm/package/contents/ui/VolumeSlider.qml --- a/src/kcm/package/contents/ui/VolumeSlider.qml +++ b/src/kcm/package/contents/ui/VolumeSlider.qml @@ -1,5 +1,6 @@ /* Copyright 2014-2015 Harald Sitter + Copyright 2019 Sefa Eyeoglu This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -20,14 +21,14 @@ import QtQuick 2.4 import QtQuick.Layouts 1.0 -import QtQuick.Controls 2.0 +import QtQuick.Controls 2.5 as QQC2 import org.kde.plasma.private.volume 0.1 RowLayout { Layout.bottomMargin: hundredPercentLabel.height - Slider { + QQC2.Slider { id: slider // Helper properties to allow async slider updates. @@ -40,6 +41,8 @@ Layout.fillWidth: true from: PulseAudio.MinimalVolume to: PulseAudio.MaximalVolume + // TODO: implement a way to hide tickmarks + // stepSize: to / (PulseAudio.MaximalVolume / PulseAudio.NormalVolume * 100.0) visible: HasVolume enabled: VolumeWritable opacity: Muted ? 0.5 : 1 @@ -77,12 +80,12 @@ } } - Label { + QQC2.Label { id: hundredPercentLabel - readonly property real hundredPos: (slider.width / slider.maximumValue) * PulseAudio.NormalVolume + readonly property real hundredPos: (slider.width / slider.to) * PulseAudio.NormalVolume z: slider.z - 1 x: (Qt.application.layoutDirection == Qt.RightToLeft ? slider.width - hundredPos : hundredPos) - width / 2 - y: slider.height / 1.2 + y: slider.height opacity: 0.5 font.pixelSize: slider.height / 2.2 text: i18nd("kcm_pulseaudio", "100%") @@ -95,7 +98,7 @@ } } - Label { + QQC2.Label { id: percentText readonly property real value: PulseObject.volume > slider.maximumValue ? PulseObject.volume : slider.value Layout.alignment: Qt.AlignHCenter diff --git a/src/kcm/package/contents/ui/main.qml b/src/kcm/package/contents/ui/main.qml --- a/src/kcm/package/contents/ui/main.qml +++ b/src/kcm/package/contents/ui/main.qml @@ -1,5 +1,6 @@ /* Copyright 2014-2015 Harald Sitter + Copyright 2019 Sefa Eyeoglu This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -31,6 +32,7 @@ title: kcm.name property QtObject sinkModel: SinkModel { } property QtObject sourceModel: SourceModel { } + property int maxVolumeValue: PulseAudio.NormalVolume // the applet supports changing this value. We will just assume 65536 (100%) ConfigModule.quickHelp: i18nd("kcm_pulseaudio", "This module allows configuring the Pulseaudio sound subsystem.") implicitHeight: Kirigami.Units.gridUnit * 28