mirror of
https://github.com/KDE/kasts.git
synced 2025-01-21 21:05:58 +01:00
347 lines
14 KiB
QML
347 lines
14 KiB
QML
/**
|
|
* SPDX-FileCopyrightText: 2021 Bart De Vries <bart@mogwai.be>
|
|
* SPDX-FileCopyrightText: 2021 Devin Lin <devin@kde.org>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
*/
|
|
|
|
import QtQuick 2.14
|
|
import QtQuick.Controls 2.14 as Controls
|
|
import QtQuick.Layouts 1.14
|
|
import QtMultimedia 5.15
|
|
import QtGraphicalEffects 1.15
|
|
|
|
import org.kde.kirigami 2.14 as Kirigami
|
|
|
|
import org.kde.kasts 1.0
|
|
|
|
Kirigami.Page {
|
|
id: playerControls
|
|
|
|
title: AudioManager.entry ? AudioManager.entry.title : i18n("No Track Loaded")
|
|
clip: true
|
|
Layout.margins: 0
|
|
|
|
leftPadding: 0
|
|
rightPadding: 0
|
|
topPadding: 0
|
|
bottomPadding: Kirigami.Units.gridUnit
|
|
|
|
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
|
Kirigami.Theme.inherit: false
|
|
|
|
background: Image {
|
|
opacity: 0.2
|
|
source: AudioManager.entry.cachedImage
|
|
asynchronous: true
|
|
|
|
anchors.fill: parent
|
|
fillMode: Image.PreserveAspectCrop
|
|
|
|
layer.enabled: true
|
|
layer.effect: HueSaturation {
|
|
cached: true
|
|
|
|
lightness: 0.7
|
|
saturation: 0.9
|
|
|
|
layer.enabled: true
|
|
layer.effect: FastBlur {
|
|
cached: true
|
|
radius: 100
|
|
transparentBorder: false
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
id: playerControlsColumn
|
|
anchors.fill: parent
|
|
anchors.topMargin: Kirigami.Units.largeSpacing * 2
|
|
anchors.bottomMargin: Kirigami.Units.largeSpacing * 2
|
|
|
|
Controls.Button {
|
|
id: swipeUpButton
|
|
property int swipeUpButtonSize: Kirigami.Units.iconSizes.smallMedium
|
|
icon.name: "arrow-down"
|
|
icon.height: swipeUpButtonSize
|
|
icon.width: swipeUpButtonSize
|
|
flat: true
|
|
Layout.alignment: Qt.AlignHCenter
|
|
Layout.topMargin: 0
|
|
onClicked: toClose.restart()
|
|
}
|
|
|
|
Controls.SwipeView {
|
|
id: swipeView
|
|
|
|
currentIndex: 0
|
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
|
Layout.preferredWidth: parent.width
|
|
Layout.preferredHeight: parent.height - media.height - indicator.height - indicator.Layout.bottomMargin - swipeUpButton.height
|
|
Layout.margins: 0
|
|
|
|
Controls.Control {
|
|
leftPadding: Kirigami.Units.largeSpacing * 2
|
|
rightPadding: Kirigami.Units.largeSpacing * 2
|
|
|
|
contentItem: Item {
|
|
property int textMargin: Kirigami.Units.gridUnit // margin above and below the text below the image
|
|
ImageWithFallback {
|
|
id: coverImage
|
|
imageSource: AudioManager.entry ? AudioManager.entry.cachedImage : "no-image"
|
|
imageFillMode: Image.PreserveAspectCrop
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.top: parent.top
|
|
anchors.topMargin: Math.max(0, parent.height - (height + imageLabels.height + 2*parent.textMargin))/2
|
|
height: Math.min(Math.min(parent.height, Kirigami.Units.iconSizes.enormous * 3) - (imageLabels.height + 2 * parent.textMargin),
|
|
Math.min(parent.width, Kirigami.Units.iconSizes.enormous * 3))
|
|
width: height
|
|
fractionalRadius: 1 / 20
|
|
}
|
|
ColumnLayout {
|
|
id: imageLabels
|
|
anchors.top: coverImage.bottom
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.topMargin: parent.textMargin
|
|
Controls.Label {
|
|
text: AudioManager.entry ? AudioManager.entry.title : i18n("No Title")
|
|
elide: Text.ElideRight
|
|
Layout.alignment: Qt.AlignHCenter
|
|
Layout.maximumWidth: parent.width
|
|
font.weight: Font.Medium
|
|
}
|
|
Controls.Label {
|
|
text: AudioManager.entry ? AudioManager.entry.feed.name : i18n("No Podcast Title")
|
|
elide: Text.ElideRight
|
|
Layout.alignment: Qt.AlignHCenter
|
|
Layout.maximumWidth: parent.width
|
|
opacity: 0.6
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Controls.Control {
|
|
leftPadding: Kirigami.Units.largeSpacing * 2
|
|
rightPadding: Kirigami.Units.largeSpacing * 2
|
|
|
|
contentItem: Item {
|
|
Flickable {
|
|
anchors.fill: parent
|
|
anchors.leftMargin: playerControlsColumn.anchors.margins
|
|
clip: true
|
|
contentHeight: description.height
|
|
ColumnLayout {
|
|
id: description
|
|
width: parent.width
|
|
Kirigami.Heading {
|
|
text: AudioManager.entry ? AudioManager.entry.title : i18n("No Track Title")
|
|
level: 3
|
|
wrapMode: Text.WordWrap
|
|
Layout.fillWidth: true
|
|
Layout.bottomMargin: Kirigami.Units.largeSpacing
|
|
}
|
|
Controls.Label {
|
|
id: text
|
|
text: AudioManager.entry ? AudioManager.entry.content : i18n("No Track Loaded")
|
|
verticalAlignment: Text.AlignTop
|
|
baseUrl: AudioManager.entry ? AudioManager.entry.baseUrl : ""
|
|
textFormat: Text.RichText
|
|
wrapMode: Text.WordWrap
|
|
onLinkActivated: Qt.openUrlExternally(link)
|
|
Layout.fillWidth: true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Controls.Control {
|
|
leftPadding: Kirigami.Units.largeSpacing * 2
|
|
rightPadding: Kirigami.Units.largeSpacing * 2
|
|
|
|
contentItem: Item {
|
|
Kirigami.PlaceholderMessage {
|
|
visible: chapterList.count === 0
|
|
|
|
width: parent.width
|
|
anchors.centerIn: parent
|
|
|
|
text: i18n("No chapters found.")
|
|
}
|
|
ListView {
|
|
id: chapterList
|
|
model: ChapterModel {
|
|
enclosureId: AudioManager.entry.id
|
|
enclosurePath: AudioManager.entry.enclosure.path
|
|
}
|
|
clip: true
|
|
visible: chapterList.count !== 0
|
|
anchors.fill: parent
|
|
delegate: ChapterListDelegate {
|
|
entry: AudioManager.entry
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Controls.PageIndicator {
|
|
id: indicator
|
|
|
|
count: swipeView.count
|
|
currentIndex: swipeView.currentIndex
|
|
Layout.alignment: Qt.AlignHCenter
|
|
Layout.bottomMargin: Kirigami.Units.gridUnit
|
|
}
|
|
|
|
Item {
|
|
id: media
|
|
|
|
implicitHeight: mediaControls.height
|
|
Layout.leftMargin: Kirigami.Units.largeSpacing * 2
|
|
Layout.rightMargin: Kirigami.Units.largeSpacing * 2
|
|
Layout.fillWidth: true
|
|
|
|
ColumnLayout {
|
|
id: mediaControls
|
|
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.margins: 0
|
|
|
|
Controls.Slider {
|
|
enabled: AudioManager.entry
|
|
Layout.fillWidth: true
|
|
Layout.leftMargin: Kirigami.Units.largeSpacing
|
|
Layout.rightMargin: Kirigami.Units.largeSpacing
|
|
padding: 0
|
|
from: 0
|
|
to: AudioManager.duration
|
|
value: AudioManager.position
|
|
onMoved: AudioManager.seek(value)
|
|
}
|
|
RowLayout {
|
|
id: controls
|
|
Layout.leftMargin: Kirigami.Units.largeSpacing
|
|
Layout.rightMargin: Kirigami.Units.largeSpacing
|
|
Layout.fillWidth: true
|
|
Controls.Label {
|
|
Layout.alignment: Qt.AlignLeft
|
|
padding: Kirigami.Units.largeSpacing
|
|
text: AudioManager.formattedPosition
|
|
font: Kirigami.Theme.smallFont
|
|
}
|
|
Item {
|
|
Layout.fillWidth: true
|
|
}
|
|
Item {
|
|
Layout.alignment: Qt.AlignRight
|
|
Layout.preferredHeight: endLabel.implicitHeight
|
|
Layout.preferredWidth: endLabel.implicitWidth
|
|
Controls.Label {
|
|
id: endLabel
|
|
padding: Kirigami.Units.largeSpacing
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: (SettingsManager.toggleRemainingTime) ?
|
|
"-" + AudioManager.formattedLeftDuration
|
|
: AudioManager.formattedDuration
|
|
font: Kirigami.Theme.smallFont
|
|
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
onClicked: SettingsManager.toggleRemainingTime = !SettingsManager.toggleRemainingTime
|
|
}
|
|
}
|
|
}
|
|
|
|
RowLayout {
|
|
id: bottomRow
|
|
Layout.leftMargin: Kirigami.Units.largeSpacing
|
|
Layout.rightMargin: Kirigami.Units.largeSpacing
|
|
Layout.maximumWidth: Number.POSITIVE_INFINITY //TODO ?
|
|
Layout.fillWidth: true
|
|
Layout.margins: 0
|
|
Layout.topMargin: Kirigami.Units.largeSpacing
|
|
|
|
// Make button width scale properly on narrow windows instead of overflowing
|
|
property int buttonSize: Math.min(playButton.implicitWidth, ((playerControlsColumn.width - 4 * spacing) / 5 - playButton.leftPadding - playButton.rightPadding))
|
|
property int iconSize: Kirigami.Units.gridUnit * 1.5
|
|
|
|
// left section
|
|
Controls.Button {
|
|
// Use contentItem and a Label because using plain "text"
|
|
// does not rescale automatically if the text changes
|
|
contentItem: Controls.Label {
|
|
text: AudioManager.playbackRate + "x"
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
}
|
|
onClicked: {
|
|
playbackRateDialog.open()
|
|
}
|
|
flat: true
|
|
padding: 0
|
|
implicitWidth: playButton.width
|
|
implicitHeight: playButton.height
|
|
}
|
|
|
|
// middle section
|
|
RowLayout {
|
|
spacing: Kirigami.Units.largeSpacing
|
|
Layout.alignment: Qt.AlignHCenter
|
|
Controls.Button {
|
|
icon.name: "media-seek-backward"
|
|
icon.height: bottomRow.iconSize
|
|
icon.width: bottomRow.iconSize
|
|
flat: true
|
|
Layout.alignment: Qt.AlignRight
|
|
Layout.preferredWidth: bottomRow.buttonSize
|
|
onClicked: AudioManager.skipBackward()
|
|
enabled: AudioManager.canSkipBackward
|
|
}
|
|
Controls.Button {
|
|
id: playButton
|
|
icon.name: AudioManager.playbackState === Audio.PlayingState ? "media-playback-pause" : "media-playback-start"
|
|
icon.height: bottomRow.iconSize
|
|
icon.width: bottomRow.iconSize
|
|
flat: true
|
|
Layout.alignment: Qt.AlignHCenter
|
|
Layout.preferredWidth: bottomRow.buttonSize
|
|
onClicked: AudioManager.playbackState === Audio.PlayingState ? AudioManager.pause() : AudioManager.play()
|
|
enabled: AudioManager.canPlay
|
|
}
|
|
Controls.Button {
|
|
icon.name: "media-seek-forward"
|
|
icon.height: bottomRow.iconSize
|
|
icon.width: bottomRow.iconSize
|
|
flat: true
|
|
Layout.alignment: Qt.AlignLeft
|
|
Layout.preferredWidth: bottomRow.buttonSize
|
|
onClicked: AudioManager.skipForward()
|
|
enabled: AudioManager.canSkipForward
|
|
}
|
|
}
|
|
|
|
// right section
|
|
Controls.Button {
|
|
icon.name: "media-skip-forward"
|
|
icon.height: bottomRow.iconSize
|
|
icon.width: bottomRow.iconSize
|
|
flat: true
|
|
Layout.alignment: Qt.AlignRight
|
|
Layout.preferredWidth: bottomRow.buttonSize
|
|
onClicked: AudioManager.next()
|
|
enabled: AudioManager.canGoNext
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|