diff --git a/applets/mediacontroller/contents/ui/ExpandedRepresentation.qml b/applets/mediacontroller/contents/ui/ExpandedRepresentation.qml --- a/applets/mediacontroller/contents/ui/ExpandedRepresentation.qml +++ b/applets/mediacontroller/contents/ui/ExpandedRepresentation.qml @@ -33,7 +33,7 @@ Layout.preferredWidth: Layout.minimumWidth * 1.5 Layout.preferredHeight: Layout.minimumHeight * 1.5 - readonly property int controlSize: Math.min(height, width) / 4 + readonly property int controlSize: units.iconSizes.large property int position: mpris2Source.currentData.Position || 0 readonly property real rate: mpris2Source.currentData.Rate || 1 @@ -118,149 +118,104 @@ } } - ColumnLayout { - id: titleColumn - width: parent.width - spacing: units.smallSpacing - - PlasmaComponents.ComboBox { - id: playerCombo - Layout.fillWidth: true - visible: model.length > 2 // more than one player, @multiplex is always there - model: { - var model = [{ - text: i18n("Choose player automatically"), - source: mpris2Source.multiplexSource - }] - - var sources = mpris2Source.sources - for (var i = 0, length = sources.length; i < length; ++i) { - var source = sources[i] - if (source === mpris2Source.multiplexSource) { - continue - } - - // we could show the pretty player name ("Identity") here but then we - // would have to connect all sources just for this - model.push({text: source, source: source}) + PlasmaComponents.ComboBox { + id: playerCombo + width: Math.round(0.6 * parent.width) + height: visible ? undefined : 0 + anchors.horizontalCenter: parent.horizontalCenter + visible: model.length > 2 // more than one player, @multiplex is always there + model: { + var model = [{ + text: i18n("Choose player automatically"), + source: mpris2Source.multiplexSource + }] + + var sources = mpris2Source.sources + for (var i = 0, length = sources.length; i < length; ++i) { + var source = sources[i] + if (source === mpris2Source.multiplexSource) { + continue } - return model + // we could show the pretty player name ("Identity") here but then we + // would have to connect all sources just for this + model.push({text: source, source: source}) } - onModelChanged: { - // if model changes, ComboBox resets, so we try to find the current player again... - for (var i = 0, length = model.length; i < length; ++i) { - if (model[i].source === mpris2Source.current) { - currentIndex = i - break - } + return model + } + + onModelChanged: { + // if model changes, ComboBox resets, so we try to find the current player again... + for (var i = 0, length = model.length; i < length; ++i) { + if (model[i].source === mpris2Source.current) { + currentIndex = i + break } } + } - onActivated: { - disablePositionUpdate = true - // ComboBox has currentIndex and currentText, why doesn't it have currentItem/currentModelValue? - mpris2Source.current = model[index].source - disablePositionUpdate = false - } + onActivated: { + disablePositionUpdate = true + // ComboBox has currentIndex and currentText, why doesn't it have currentItem/currentModelValue? + mpris2Source.current = model[index].source + disablePositionUpdate = false } + } - RowLayout { - id: titleRow - Layout.fillWidth: true - Layout.minimumHeight: albumArt.Layout.preferredHeight - spacing: units.largeSpacing - - Image { - id: albumArt - readonly property int size: Math.round(expandedRepresentation.height / 2 - (playerCombo.count > 2 ? playerCombo.height : 0)) - source: root.albumArt - asynchronous: true - fillMode: Image.PreserveAspectCrop - sourceSize: Qt.size(size, size) - Layout.preferredHeight: size - Layout.preferredWidth: size - visible: !!root.track && status === Image.Ready - } + Item { + anchors { + horizontalCenter: parent.horizontalCenter + top: playerCombo.bottom + bottom: controlCol.top + margins: units.smallSpacing + } - ColumnLayout { - Layout.fillWidth: true - spacing: units.smallSpacing / 2 - - PlasmaExtras.Heading { - id: song - Layout.fillWidth: true - level: 3 - opacity: 0.6 - - maximumLineCount: 3 - wrapMode: Text.WrapAtWordBoundaryOrAnywhere - elide: Text.ElideRight - text: root.track ? root.track : i18n("No media playing") - textFormat: Text.PlainText - } + PlasmaCore.IconItem { + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } - PlasmaExtras.Heading { - id: artist - Layout.fillWidth: true - level: 4 - opacity: 0.4 - maximumLineCount: 2 - wrapMode: Text.WrapAtWordBoundaryOrAnywhere - visible: text !== "" - - elide: Text.ElideRight - text: root.artist || "" - textFormat: Text.PlainText - } + height: Math.round(parent.height / 2) + width: height - PlasmaExtras.Heading { - Layout.fillWidth: true - level: 5 - opacity: 0.4 - wrapMode: Text.NoWrap - elide: Text.ElideRight - visible: text !== "" - text: { - var metadata = root.currentMetadata - if (!metadata) { - return "" - } - var xesamAlbum = metadata["xesam:album"] - if (xesamAlbum) { - return xesamAlbum - } + source: mpris2Source.currentData["Desktop Icon Name"] + visible: !albumArt.visible - // if we play a local file without title and artist, show its containing folder instead - if (metadata["xesam:title"] || root.artist) { - return "" - } + usesPlasmaTheme: false + } + } - var xesamUrl = (metadata["xesam:url"] || "").toString() - if (xesamUrl.indexOf("file:///") !== 0) { // "!startsWith()" - return "" - } + Image { + id: albumArt + anchors { + horizontalCenter: parent.horizontalCenter + top: playerCombo.bottom + bottom: controlCol.top + margins: units.smallSpacing + } + source: root.albumArt + asynchronous: true + fillMode: Image.PreserveAspectFit + sourceSize: Qt.size(height, height) + visible: !!root.track && status === Image.Ready + } - var urlParts = xesamUrl.split("/") - if (urlParts.length < 3) { - return "" - } + Column { + id: controlCol + width: parent.width + anchors.bottom: parent.bottom - var lastFolderPath = urlParts[urlParts.length - 2] // last would be filename - if (lastFolderPath) { - return lastFolderPath - } + spacing: units.smallSpacing - return "" - } - textFormat: Text.PlainText - } + RowLayout { + anchors { + left: parent.left + right: parent.right + margins: units.smallSpacing } - } - RowLayout { - Layout.fillWidth: true spacing: units.smallSpacing // if there's no "mpris:length" in the metadata, we cannot seek, so hide it in that case @@ -280,11 +235,10 @@ PlasmaComponents.Label { Layout.preferredWidth: timeMetrics.width - Layout.fillHeight: true verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignRight text: KCoreAddons.Format.formatDuration(seekSlider.value / 1000, expandedRepresentation.durationFormattingOptions) - opacity: 0.6 + opacity: 0.9 font: theme.smallestFont } @@ -324,14 +278,126 @@ PlasmaComponents.Label { Layout.preferredWidth: timeMetrics.width - Layout.fillHeight: true verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignLeft text: i18nc("Remaining time for song e.g -5:42", "-%1", KCoreAddons.Format.formatDuration((seekSlider.maximumValue - seekSlider.value) / 1000, expandedRepresentation.durationFormattingOptions)) - opacity: 0.6 + opacity: 0.9 font: theme.smallestFont } } + + Column { + width: parent.width + + PlasmaExtras.Heading { + id: song + width: parent.width + height: undefined + level: 4 + horizontalAlignment: Text.AlignHCenter + + maximumLineCount: 1 + elide: Text.ElideRight + text: { + if (!root.track) { + return i18n("No media playing") + } + return root.artist ? i18nc("artist – track", "%1 – %2", root.artist, root.track) : root.track + } + textFormat: Text.PlainText + } + + PlasmaExtras.Heading { + width: parent.width + height: undefined + level: 5 + opacity: 0.6 + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.NoWrap + elide: Text.ElideRight + visible: text !== "" + text: { + var metadata = root.currentMetadata + if (!metadata) { + return "" + } + var xesamAlbum = metadata["xesam:album"] + if (xesamAlbum) { + return xesamAlbum + } + + // if we play a local file without title and artist, show its containing folder instead + if (metadata["xesam:title"] || root.artist) { + return "" + } + + var xesamUrl = (metadata["xesam:url"] || "").toString() + if (xesamUrl.indexOf("file:///") !== 0) { // "!startsWith()" + return "" + } + + var urlParts = xesamUrl.split("/") + if (urlParts.length < 3) { + return "" + } + + var lastFolderPath = urlParts[urlParts.length - 2] // last would be filename + if (lastFolderPath) { + return lastFolderPath + } + + return "" + } + textFormat: Text.PlainText + } + } + + Item { + width: parent.width + height: playerControls.height + + Row { + id: playerControls + property bool enabled: root.canControl + property int controlsSize: theme.mSize(theme.defaultFont).height * 3 + + anchors.horizontalCenter: parent.horizontalCenter + spacing: units.largeSpacing + + PlasmaComponents.ToolButton { + anchors.verticalCenter: parent.verticalCenter + width: expandedRepresentation.controlSize + height: width + enabled: playerControls.enabled && root.canGoPrevious + iconSource: LayoutMirroring.enabled ? "media-skip-forward" : "media-skip-backward" + onClicked: { + seekSlider.value = 0 // Let the media start from beginning. Bug 362473 + root.action_previous() + } + } + + PlasmaComponents.ToolButton { + width: Math.round(expandedRepresentation.controlSize * 1.5) + height: width + enabled: root.state == "playing" ? root.canPause : root.canPlay + iconSource: root.state == "playing" ? "media-playback-pause" : "media-playback-start" + onClicked: root.togglePlaying() + } + + PlasmaComponents.ToolButton { + anchors.verticalCenter: parent.verticalCenter + width: expandedRepresentation.controlSize + height: width + enabled: playerControls.enabled && root.canGoNext + iconSource: LayoutMirroring.enabled ? "media-skip-backward" : "media-skip-forward" + onClicked: { + seekSlider.value = 0 // Let the media start from beginning. Bug 362473 + root.action_next() + } + } + } + } } Timer { @@ -347,51 +413,4 @@ service.startOperationCall(operation) } } - - Item { - anchors.bottom: parent.bottom - width: parent.width - height: playerControls.height - - Row { - id: playerControls - property bool enabled: root.canControl - property int controlsSize: theme.mSize(theme.defaultFont).height * 3 - - anchors.horizontalCenter: parent.horizontalCenter - spacing: units.largeSpacing - - PlasmaComponents.ToolButton { - anchors.verticalCenter: parent.verticalCenter - width: expandedRepresentation.controlSize - height: width - enabled: playerControls.enabled && root.canGoPrevious - iconSource: LayoutMirroring.enabled ? "media-skip-forward" : "media-skip-backward" - onClicked: { - seekSlider.value = 0 // Let the media start from beginning. Bug 362473 - root.action_previous() - } - } - - PlasmaComponents.ToolButton { - width: Math.round(expandedRepresentation.controlSize * 1.5) - height: width - enabled: root.state == "playing" ? root.canPause : root.canPlay - iconSource: root.state == "playing" ? "media-playback-pause" : "media-playback-start" - onClicked: root.togglePlaying(); - } - - PlasmaComponents.ToolButton { - anchors.verticalCenter: parent.verticalCenter - width: expandedRepresentation.controlSize - height: width - enabled: playerControls.enabled && root.canGoNext - iconSource: LayoutMirroring.enabled ? "media-skip-backward" : "media-skip-forward" - onClicked: { - seekSlider.value = 0 // Let the media start from beginning. Bug 362473 - root.action_next() - } - } - } - } }