Commit 8ada15ad authored by George Vogiatzis's avatar George Vogiatzis Committed by Nate Graham

[Applet]Update layout based on T10470

Summary:
Change layout according to T10470 mockups.
Remove port combobox and put port selection back the hamburger menu.
Compact representation tooltip shows only port description, if available.
Display only port description, if there is no other device with same
description sub-string.

Visual Issues:
Unable to extent the bottom line to touch the edges of the window,
that are part of the system tray.
Line svg has spacing on the sides.

1st part of patches D26271, D26256, D26418, D26574.
Not included in these patches: 100% volume mark, Color style.

Reviewers: #vdg, #plasma, manueljlin, drosca, ngraham

Reviewed By: #vdg, manueljlin, ngraham

Subscribers: cfeck, ndavis, filipf, ngraham, plasma-devel

Tags: #plasma

Maniphest Tasks: T10470

Differential Revision: https://phabricator.kde.org/D26271
parent 9a1c33e7
......@@ -24,20 +24,27 @@ import "../code/icon.js" as Icon
ListItemBase {
readonly property var currentPort: Ports[ActivePortIndex]
property bool onlyOne: false
draggable: false
label: {
if (!currentPort) {
return Description
} else {
if (onlyOne) {
return currentPort.description
} else {
return i18nc("label of device items", "%1 (%2)", currentPort.description, Description)
if (currentPort) {
var model = type === "sink" ? paSinkModel : paSourceModel;
var itemLength = currentPort.description.length;
for (var i = 0; i < model.rowCount(); i++) {
if (i !== index) {
var port = model.data(model.index(i, 0), model.role("Ports"))
[model.data(model.index(i, 0), model.role("ActivePortIndex"))];
if (port.description) {
var length = Math.min(itemLength, port.description.length)
if (currentPort.description.substring(0, length) === port.description.substring(0, length)) {
return i18nc("label of device items", "%1 (%2)", currentPort.description, Description);
}
}
}
}
return currentPort.description;
} else {
return Description;
}
}
labelOpacity: onlyOne ? 1 : 0.6
icon: Icon.formFactorIcon(FormFactor) || IconName
}
......@@ -36,8 +36,7 @@ import "../code/icon.js" as Icon
PlasmaComponents.ListItem {
id: item
property alias label: textLabel.text
property alias labelOpacity: textLabel.opacity
property alias label: defaultButton.text
property alias draggable: dragArea.enabled
property alias icon: clientIcon.source
property alias iconUsesPlasmaTheme: clientIcon.usesPlasmaTheme
......@@ -45,20 +44,18 @@ PlasmaComponents.ListItem {
checked: dropArea.containsDrag
opacity: (draggedStream && draggedStream.deviceIndex == Index) ? 0.3 : 1.0
separatorVisible: false
ListView.delayRemove: dragArea.dragActive
Item {
width: parent.width
height: rowLayout.height
height: column.height
RowLayout {
id: rowLayout
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: LayoutMirroring.enabled ? 0 : units.smallSpacing
anchors.leftMargin: LayoutMirroring.enabled ? units.smallSpacing : 0
spacing: units.smallSpacing
PlasmaCore.IconItem {
id: clientIcon
......@@ -66,6 +63,7 @@ PlasmaComponents.ListItem {
Layout.preferredHeight: column.height * 0.75
Layout.preferredWidth: Layout.preferredHeight
source: "unknown"
visible: type === "sink-input" || type === "source-input"
onSourceChanged: {
if (!valid && source != "unknown") {
......@@ -107,72 +105,49 @@ PlasmaComponents.ListItem {
ColumnLayout {
id: column
spacing: 1
spacing: 0
RowLayout {
Layout.fillWidth: true
Layout.minimumHeight: contextMenuButton.height
PlasmaExtras.Heading {
id: textLabel
Layout.fillWidth: true
height: undefined
level: 5
opacity: 0.6
wrapMode: Text.NoWrap
elide: Text.ElideRight
visible: !portbox.visible
PlasmaComponents3.RadioButton {
id: defaultButton
Layout.leftMargin: LayoutMirroring.enabled ? 0 : Math.round((muteButton.width - defaultButton.indicator.width) / 2)
Layout.rightMargin: LayoutMirroring.enabled ? Math.round((muteButton.width - defaultButton.indicator.width) / 2) : 0
spacing: units.smallSpacing + Math.round((muteButton.width - defaultButton.indicator.width) / 2)
checked: PulseObject.default ? PulseObject.default : false
visible: (type == "sink" && sinkView.model.count > 1) || (type == "source" && sourceView.model.count > 1)
onClicked: PulseObject.default = true;
}
PlasmaComponents3.ComboBox {
id: portbox
visible: portbox.count > 1
Layout.minimumWidth: units.gridUnit * 10
model: {
var items = [];
for (var i = 0; i < PulseObject.ports.length; ++i) {
var port = PulseObject.ports[i];
if (port.availability != Port.Unavailable) {
items.push(port.description);
}
}
return items
}
currentIndex: ActivePortIndex
onActivated: ActivePortIndex = index
Label {
id: soloLabel
text: defaultButton.text
visible: !defaultButton.visible
elide: Text.ElideRight
}
Item {
visible: portbox.visible
Layout.fillWidth: true
}
PlasmaComponents3.ToolButton {
id: defaultButton
text: i18n("Default Device")
icon.name: PulseObject.default ? "starred-symbolic" : "non-starred-symbolic"
checkable: true
checked: PulseObject.default
visible: (type == "sink" && sinkView.model.count > 1) || (type == "source" && sourceView.model.count > 1)
onClicked: PulseObject.default = true;
}
SmallToolButton {
id: contextMenuButton
icon: "application-menu"
checkable: true
onClicked: contextMenu.show()
tooltip: i18n("Show additional options for %1", textLabel.text)
tooltip: i18n("Show additional options for %1", defaultButton.text)
}
}
RowLayout {
SmallToolButton {
id: muteButton
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)
tooltip: i18n("Mute %1", defaultButton.text)
}
PlasmaComponents.Slider {
......@@ -195,7 +170,7 @@ PlasmaComponents.ListItem {
enabled: VolumeWritable
opacity: Muted ? 0.5 : 1
Accessible.name: i18nc("Accessibility data on volume slider", "Adjust volume for %1", textLabel.text)
Accessible.name: i18nc("Accessibility data on volume slider", "Adjust volume for %1", defaultButton.text)
Component.onCompleted: {
ignoreValueChange = false;
......@@ -320,7 +295,7 @@ PlasmaComponents.ListItem {
contextMenu.addMenuItem(menuItem);
// Switch all streams of the relevant kind to this device
if (type == "source") {
if (type == "source" && sourceView.model.count > 1) {
menuItem = newMenuItem();
menuItem.text = i18n("Record all audio via this device");
menuItem.icon = "mic-on" // or "mic-ready" // or "audio-input-microphone-symbolic"
......@@ -328,7 +303,7 @@ PlasmaComponents.ListItem {
PulseObject.switchStreams();
});
contextMenu.addMenuItem(menuItem);
} else if (type == "sink") {
} else if (type == "sink" && sinkView.model.count > 1) {
menuItem = newMenuItem();
menuItem.text = i18n("Play all audio via this device");
menuItem.icon = "audio-on" // or "audio-ready" // or "audio-speakers-symbolic"
......@@ -338,8 +313,48 @@ PlasmaComponents.ListItem {
contextMenu.addMenuItem(menuItem);
}
// Ports
// Intentionally only shown when there are at least two available ports.
if (PulseObject.ports && PulseObject.ports.length > 1) {
contextMenu.addMenuItem(newSeperator());
var menuItem = newMenuItem();
menuItem.text = i18nc("Heading for a list of ports of a device (for example built-in laptop speakers or a plug for headphones)", "Ports");
menuItem.section = true;
contextMenu.addMenuItem(menuItem);
menuItem.visible = false;
var menuItemsPorts = [];
var availablePorts = 0;
for (var i = 0; i < PulseObject.ports.length; i++) {
var port = PulseObject.ports[i];
if (port.availability != Port.Unavailable) {
menuItemsPorts[availablePorts] = newMenuItem();
menuItemsPorts[availablePorts].text = port.description;
menuItemsPorts[availablePorts].checkable = true;
menuItemsPorts[availablePorts].checked = i === PulseObject.activePortIndex;
var setActivePort = function(portIndex) {
return function() {
PulseObject.activePortIndex = portIndex;
};
};
menuItemsPorts[availablePorts].clicked.connect(setActivePort(i));
contextMenu.addMenuItem(menuItemsPorts[availablePorts]);
menuItemsPorts[availablePorts].visible = false;
availablePorts++;
}
}
if (1 < availablePorts){
menuItem.visible = true;
for (var i = 0; i < availablePorts; i++) {
menuItemsPorts[i].visible = true;
}
}
}
// Choose output / input device
// By choice only shown when there are at least two options
// Intentionally only shown when there are at least two options
if ((type == "sink-input" && sinkView.model.count > 1) || (type == "source-input" && sourceView.model.count > 1)) {
contextMenu.addMenuItem(newSeperator());
var menuItem = newMenuItem();
......
......@@ -25,20 +25,7 @@ import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.private.volume 0.1
ListItemBase {
property bool onlyOne: false
label: {
if (! Client) {
return Name
} else {
if (onlyOne) {
return Client.name
} else {
return i18nc("label of stream items", "%1 (%2)", Client.name, Name)
}
}
}
labelOpacity: onlyOne ? 1 : 0.6
label: Client ? Client.name : Name
icon: IconName
iconUsesPlasmaTheme: false
}
......@@ -23,6 +23,7 @@ import QtQuick.Layouts 1.0
import org.kde.plasma.core 2.1 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.plasma.plasmoid 2.0
......@@ -63,7 +64,16 @@ Item {
return i18n("Volume at %1%", volumePercent(sink.volume));
}
}
Plasmoid.toolTipSubText: paSinkModel.preferredSink && !isDummyOutput(paSinkModel.preferredSink) ? paSinkModel.preferredSink.description : ""
Plasmoid.toolTipSubText: {
if (paSinkModel.preferredSink && !isDummyOutput(paSinkModel.preferredSink)) {
var port = paSinkModel.preferredSink.ports[paSinkModel.preferredSink.activePortIndex];
if (port) {
return port.description
}
return paSinkModel.preferredSink.name
}
return ""
}
function isDummyOutput(output) {
return output && output.name === dummyOutputName;
......@@ -298,6 +308,11 @@ Item {
id: feedback
}
PlasmaCore.Svg {
id: lineSvg
imagePath: "widgets/line"
}
Plasmoid.fullRepresentation: ColumnLayout {
spacing: units.smallSpacing
Layout.preferredHeight: main.Layout.preferredHeight
......@@ -306,12 +321,11 @@ Item {
function beginMoveStream(type, stream) {
if (type == "sink") {
sourceView.visible = false;
sourceViewHeader.visible = false;
} else if (type == "source") {
sinkView.visible = false;
sinkViewHeader.visible = false;
}
devicesLine.visible = false;
tabBar.currentTab = devicesTab;
}
......@@ -319,9 +333,8 @@ Item {
tabBar.currentTab = streamsTab;
sourceView.visible = true;
sourceViewHeader.visible = true;
devicesLine.visible = true;
sinkView.visible = true;
sinkViewHeader.visible = true;
}
RowLayout {
......@@ -343,16 +356,6 @@ Item {
text: i18n("Applications")
}
}
PlasmaComponents.ToolButton {
Layout.alignment: Qt.AlignBottom
tooltip: plasmoid.action("configure").text
iconName: "configure"
Accessible.name: tooltip
onClicked: {
plasmoid.action("configure").trigger();
}
}
}
PlasmaExtras.ScrollArea {
......@@ -373,17 +376,13 @@ Item {
ColumnLayout {
id: streamsView
spacing: 0
visible: tabBar.currentTab == streamsTab
readonly property bool simpleMode: (sinkInputView.count >= 1 && sourceOutputView.count == 0) || (sinkInputView.count == 0 && sourceOutputView.count >= 1)
property int maximumWidth: scrollView.viewport.width
width: maximumWidth
Layout.maximumWidth: maximumWidth
Header {
Layout.fillWidth: true
visible: sinkInputView.count > 0 && !streamsView.simpleMode
text: i18n("Playback Streams")
}
ListView {
id: sinkInputView
......@@ -399,15 +398,20 @@ Item {
delegate: StreamListItem {
type: "sink-input"
draggable: sinkView.count > 1
onlyOne: streamsView.simpleMode
}
}
Header {
Layout.fillWidth: true
visible: sourceOutputView.count > 0 && !streamsView.simpleMode
text: i18n("Recording Streams")
PlasmaCore.SvgItem {
elementId: "horizontal-line"
Layout.preferredWidth: scrollView.viewport.width - units.smallSpacing * 4
Layout.preferredHeight: naturalSize.height
Layout.leftMargin: units.smallSpacing * 2
Layout.rightMargin: units.smallSpacing * 2
Layout.topMargin: units.smallSpacing
svg: lineSvg
visible: sinkInputView.model.count > 0 && sourceOutputView.model.count > 0
}
ListView {
id: sourceOutputView
......@@ -423,7 +427,6 @@ Item {
delegate: StreamListItem {
type: "source-input"
draggable: sourceView.count > 1
onlyOne: streamsView.simpleMode
}
}
}
......@@ -435,19 +438,15 @@ Item {
property int maximumWidth: scrollView.viewport.width
width: maximumWidth
Layout.maximumWidth: maximumWidth
spacing: 0
Header {
id: sinkViewHeader
Layout.fillWidth: true
visible: sinkView.count > 0 && !devicesView.simpleMode
text: i18n("Playback Devices")
}
ListView {
id: sinkView
Layout.fillWidth: true
Layout.minimumHeight: contentHeight
Layout.maximumHeight: contentHeight
spacing: 0
model: PlasmaCore.SortFilterModel {
sortRole: "SortByDefault"
......@@ -467,16 +466,20 @@ Item {
boundsBehavior: Flickable.StopAtBounds;
delegate: DeviceListItem {
type: "sink"
onlyOne: devicesView.simpleMode
}
}
Header {
id: sourceViewHeader
Layout.fillWidth: true
visible: sourceView.count > 0 && !devicesView.simpleMode
text: i18n("Recording Devices")
PlasmaCore.SvgItem {
id: devicesLine
elementId: "horizontal-line"
Layout.preferredWidth: scrollView.viewport.width - units.smallSpacing * 4
Layout.leftMargin: units.smallSpacing * 2
Layout.rightMargin: Layout.leftMargin
Layout.topMargin: units.smallSpacing
svg: lineSvg
visible: sinkView.model.count > 0 && sourceView.model.count > 0 && (sinkView.model.count > 1 || sourceView.model.count > 1)
}
ListView {
id: sourceView
......@@ -492,7 +495,6 @@ Item {
boundsBehavior: Flickable.StopAtBounds;
delegate: DeviceListItem {
type: "source"
onlyOne: devicesView.simpleMode
}
}
}
......@@ -522,6 +524,29 @@ Item {
}
}
}
PlasmaCore.SvgItem {
elementId: "horizontal-line"
Layout.fillWidth: true
Layout.topMargin: 0 - units.smallSpacing / 2
Layout.leftMargin: 0 - units.smallSpacing * 1.5
Layout.rightMargin: Layout.leftMargin
svg: lineSvg
}
RowLayout {
Item {
Layout.fillWidth: true
}
PlasmaComponents.ToolButton {
tooltip: plasmoid.action("configure").text
iconName: "configure"
Accessible.name: tooltip
onClicked: plasmoid.action("configure").trigger()
}
}
}
Component.onCompleted: {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment