mirror of https://github.com/KDE/kasts.git
Add mobile bottom navbar, use Titles toolbar on mobile, and add blurred image background to mobile player
This commit is contained in:
parent
f861f4e802
commit
e16c40d57c
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2021 Devin Lin <espidev@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Layouts 1.2
|
||||
import org.kde.kirigami 2.19 as Kirigami
|
||||
|
||||
import org.kde.kasts 1.0
|
||||
|
||||
Kirigami.NavigationTabBar {
|
||||
id: root
|
||||
|
||||
property alias toolbarHeight: root.implicitHeight
|
||||
property bool transparentBackground: false
|
||||
|
||||
shadow: false
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
iconName: "view-media-playlist"
|
||||
text: i18n("Queue")
|
||||
checked: "QueuePage" === SettingsManager.lastOpenedPage
|
||||
onTriggered: {
|
||||
pushPage("QueuePage");
|
||||
SettingsManager.lastOpenedPage = "QueuePage"; // for persistency
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
iconName: "bookmarks"
|
||||
text: i18n("Subscriptions")
|
||||
checked: "FeedListPage" === SettingsManager.lastOpenedPage
|
||||
onTriggered: {
|
||||
pushPage("FeedListPage");
|
||||
SettingsManager.lastOpenedPage = "FeedListPage"; // for persistency
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
iconName: "rss"
|
||||
text: i18n("Episodes")
|
||||
checked: "EpisodeListPage" === SettingsManager.lastOpenedPage
|
||||
onTriggered: {
|
||||
pushPage("EpisodeListPage")
|
||||
SettingsManager.lastOpenedPage = "EpisodeListPage" // for persistency
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
iconName: "settings-configure"
|
||||
text: i18n("Settings")
|
||||
checked: "SettingsPage" === SettingsManager.lastOpenedPage
|
||||
onTriggered: {
|
||||
applicationWindow().pageStack.clear()
|
||||
applicationWindow().pageStack.push("qrc:/SettingsPage.qml", {}, {
|
||||
title: i18n("Settings")
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -26,12 +26,21 @@ Kirigami.ScrollablePage {
|
|||
}
|
||||
|
||||
actions.main: Kirigami.Action {
|
||||
iconName: "download"
|
||||
text: i18n("Downloads")
|
||||
onTriggered: {
|
||||
pushPage("DownloadListPage")
|
||||
SettingsManager.lastOpenedPage = "DownloadListPage" // for persistency
|
||||
}
|
||||
}
|
||||
|
||||
actions.left: Kirigami.Action {
|
||||
iconName: "view-filter"
|
||||
text: i18n("Filter")
|
||||
onTriggered: filterTypeOverlay.open();
|
||||
}
|
||||
|
||||
actions.left: Kirigami.Action {
|
||||
actions.right: Kirigami.Action {
|
||||
iconName: "view-refresh"
|
||||
text: i18n("Refresh All Podcasts")
|
||||
onTriggered: refreshing = true
|
||||
|
|
|
@ -33,14 +33,22 @@ Kirigami.ScrollablePage {
|
|||
}
|
||||
|
||||
actions.main: Kirigami.Action {
|
||||
text: i18n("Add Podcast")
|
||||
iconName: "list-add"
|
||||
visible: Kirigami.Settings.isMobile
|
||||
text: i18n("Discover")
|
||||
iconName: "search"
|
||||
onTriggered: {
|
||||
addSheet.open()
|
||||
applicationWindow().pageStack.push("qrc:/DiscoverPage.qml");
|
||||
}
|
||||
}
|
||||
|
||||
contextualActions: [
|
||||
Kirigami.Action {
|
||||
text: i18n("Add Podcast")
|
||||
iconName: "list-add"
|
||||
onTriggered: {
|
||||
addSheet.open()
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Refresh All Podcasts")
|
||||
iconName: "view-refresh"
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import QtQuick 2.14
|
||||
import QtQuick.Controls 2.14 as Controls
|
||||
import QtQuick.Layouts 1.14
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import org.kde.kirigami 2.14 as Kirigami
|
||||
|
||||
|
@ -20,6 +21,8 @@ Flickable {
|
|||
|
||||
property bool isMaximized: contentY === contentHeight / 2
|
||||
|
||||
property int contentToPlayerSpacing: 0
|
||||
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
NumberAnimation on contentY {
|
||||
|
@ -51,6 +54,10 @@ Flickable {
|
|||
onReleased: footerBar.resetToBoundsOnFlick()
|
||||
}
|
||||
|
||||
function close() {
|
||||
toClose.restart();
|
||||
}
|
||||
|
||||
function resetToBoundsOnFlick() {
|
||||
if (!atYBeginning || !atYEnd) {
|
||||
if (footerBar.verticalVelocity > 0) {
|
||||
|
@ -90,8 +97,11 @@ Flickable {
|
|||
// a cover for content underneath the panel
|
||||
Rectangle {
|
||||
id: coverUnderneath
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
anchors.fill: parent
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.View
|
||||
Kirigami.Theme.inherit: false
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,23 +111,52 @@ Flickable {
|
|||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: root.height + root.miniplayerSize
|
||||
height: root.height + root.miniplayerSize + contentToPlayerSpacing
|
||||
spacing: 0
|
||||
|
||||
MinimizedPlayerControls {
|
||||
id: playControlItem
|
||||
|
||||
Controls.Control {
|
||||
implicitHeight: root.miniplayerSize + contentToPlayerSpacing
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumHeight: root.miniplayerSize
|
||||
Layout.alignment: Qt.AlignTop
|
||||
focus: true
|
||||
padding: 0
|
||||
|
||||
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: 64
|
||||
transparentBorder: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MinimizedPlayerControls {
|
||||
id: playControlItem
|
||||
height: root.miniplayerSize
|
||||
focus: true
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
}
|
||||
}
|
||||
|
||||
PlayerControls {
|
||||
id: mobileTrackPlayer
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.margins: Kirigami.Units.largeSpacing * 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/**
|
||||
* 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
|
||||
*/
|
||||
|
@ -8,25 +9,20 @@ import QtQuick 2.14
|
|||
import QtQuick.Controls 2.14 as Controls
|
||||
import QtQuick.Layouts 1.14
|
||||
import QtMultimedia 5.15
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
import org.kde.kirigami 2.12 as Kirigami
|
||||
|
||||
import org.kde.kasts 1.0
|
||||
|
||||
Item {
|
||||
property int miniplayerheight: Kirigami.Units.gridUnit * 3
|
||||
property int miniplayerheight: Math.round(Kirigami.Units.gridUnit * 3)
|
||||
property int progressbarheight: Kirigami.Units.gridUnit / 6
|
||||
property int buttonsize: Kirigami.Units.gridUnit * 2
|
||||
height: miniplayerheight + progressbarheight
|
||||
property int buttonsize: Kirigami.Units.gridUnit * 1.5
|
||||
height: miniplayerheight
|
||||
|
||||
visible: AudioManager.entry
|
||||
|
||||
// Set background
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
}
|
||||
|
||||
// progress bar for limited width (phones)
|
||||
Rectangle {
|
||||
id: miniprogressbar
|
||||
|
@ -41,44 +37,50 @@ Item {
|
|||
|
||||
RowLayout {
|
||||
id: footerrowlayout
|
||||
anchors.topMargin: miniprogressbar.height
|
||||
anchors.fill: parent
|
||||
Item {
|
||||
spacing: 0
|
||||
|
||||
Rectangle {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
// press feedback
|
||||
color: (trackClick.pressed || trackClick.containsMouse) ? Qt.rgba(0, 0, 0, 0.05) : "transparent"
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
||||
ImageWithFallback {
|
||||
imageSource: AudioManager.entry.cachedImage
|
||||
Layout.preferredHeight: miniplayerheight
|
||||
Layout.preferredWidth: miniplayerheight
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: height
|
||||
}
|
||||
|
||||
// track information
|
||||
ColumnLayout {
|
||||
Layout.fillHeight: true
|
||||
Layout.maximumHeight: parent.height
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Kirigami.Units.smallSpacing
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Controls.Label {
|
||||
id: mainLabel
|
||||
text: AudioManager.entry.title
|
||||
wrapMode: Text.Wrap
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignBottom
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
//font.weight: Font.Bold
|
||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 1
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
Controls.Label {
|
||||
id: feedLabel
|
||||
text: AudioManager.entry.feed.name
|
||||
wrapMode: Text.Wrap
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
elide: Text.ElideRight
|
||||
|
@ -101,9 +103,10 @@ Item {
|
|||
icon.height: parent.parent.buttonsize
|
||||
icon.width: parent.parent.buttonsize
|
||||
flat: true
|
||||
Layout.fillHeight: true
|
||||
Layout.maximumHeight: parent.parent.miniplayerheight
|
||||
Layout.maximumWidth: height
|
||||
Layout.preferredHeight: parent.parent.miniplayerheight - Kirigami.Units.smallSpacing * 2
|
||||
Layout.preferredWidth: height
|
||||
Layout.leftMargin: Kirigami.Units.smallSpacing
|
||||
Layout.rightMargin: Kirigami.Units.smallSpacing
|
||||
onClicked: AudioManager.playbackState === Audio.PlayingState ? AudioManager.pause() : AudioManager.play()
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/**
|
||||
* 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
|
||||
*/
|
||||
|
@ -21,16 +22,47 @@ Kirigami.Page {
|
|||
clip: true
|
||||
Layout.margins: 0
|
||||
|
||||
padding: 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:0
|
||||
anchors.topMargin: Kirigami.Units.largeSpacing * 2
|
||||
anchors.bottomMargin: Kirigami.Units.largeSpacing * 2
|
||||
|
||||
Controls.Button {
|
||||
id: swipeUpButton
|
||||
property int swipeUpButtonSize: Kirigami.Units.gridUnit * 2
|
||||
property int swipeUpButtonSize: Kirigami.Units.iconSizes.smallMedium
|
||||
icon.name: "arrow-down"
|
||||
icon.height: swipeUpButtonSize
|
||||
icon.width: swipeUpButtonSize
|
||||
|
@ -39,97 +71,118 @@ Kirigami.Page {
|
|||
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 - swipeUpButton.height
|
||||
Layout.preferredHeight: parent.height - media.height - indicator.height - indicator.Layout.bottomMargin - swipeUpButton.height
|
||||
Layout.margins: 0
|
||||
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
|
||||
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
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
|
||||
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 {
|
||||
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
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Kirigami.PlaceholderMessage {
|
||||
visible: chapterList.count === 0
|
||||
|
||||
width: parent.width
|
||||
anchors.centerIn: parent
|
||||
Controls.Control {
|
||||
leftPadding: Kirigami.Units.largeSpacing * 2
|
||||
rightPadding: Kirigami.Units.largeSpacing * 2
|
||||
|
||||
text: i18n("No chapter marks found.")
|
||||
}
|
||||
ListView {
|
||||
id: chapterList
|
||||
model: ChapterModel {
|
||||
enclosureId: AudioManager.entry.id
|
||||
enclosurePath: AudioManager.entry.enclosure.path
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
clip: true
|
||||
visible: chapterList.count !== 0
|
||||
anchors.fill: parent
|
||||
delegate: ChapterListDelegate {
|
||||
entry: AudioManager.entry
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -141,19 +194,20 @@ Kirigami.Page {
|
|||
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
|
||||
Layout.margins: 0
|
||||
|
||||
ColumnLayout {
|
||||
id: mediaControls
|
||||
|
||||
//implicitHeight: controls.height
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: 0
|
||||
|
@ -161,7 +215,8 @@ Kirigami.Page {
|
|||
Controls.Slider {
|
||||
enabled: AudioManager.entry
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: 0
|
||||
Layout.leftMargin: Kirigami.Units.largeSpacing
|
||||
Layout.rightMargin: Kirigami.Units.largeSpacing
|
||||
padding: 0
|
||||
from: 0
|
||||
to: AudioManager.duration
|
||||
|
@ -170,16 +225,20 @@ Kirigami.Page {
|
|||
}
|
||||
RowLayout {
|
||||
id: controls
|
||||
Layout.margins: 0
|
||||
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 {
|
||||
|
@ -190,6 +249,7 @@ Kirigami.Page {
|
|||
text: (SettingsManager.toggleRemainingTime) ?
|
||||
"-" + AudioManager.formattedLeftDuration
|
||||
: AudioManager.formattedDuration
|
||||
font: Kirigami.Theme.smallFont
|
||||
|
||||
}
|
||||
MouseArea {
|
||||
|
@ -199,7 +259,11 @@ Kirigami.Page {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -207,8 +271,9 @@ Kirigami.Page {
|
|||
|
||||
// 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 * 2
|
||||
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
|
||||
|
@ -221,49 +286,56 @@ Kirigami.Page {
|
|||
playbackRateDialog.open()
|
||||
}
|
||||
flat: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
padding: 0
|
||||
implicitWidth: playButton.width
|
||||
implicitHeight: playButton.height
|
||||
}
|
||||
Controls.Button {
|
||||
icon.name: "media-seek-backward"
|
||||
icon.height: parent.iconSize
|
||||
icon.width: parent.iconSize
|
||||
flat: true
|
||||
|
||||
// middle section
|
||||
RowLayout {
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.preferredWidth: parent.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: parent.iconSize
|
||||
icon.width: parent.iconSize
|
||||
flat: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.preferredWidth: parent.buttonSize
|
||||
onClicked: AudioManager.playbackState === Audio.PlayingState ? AudioManager.pause() : AudioManager.play()
|
||||
enabled: AudioManager.canPlay
|
||||
}
|
||||
Controls.Button {
|
||||
icon.name: "media-seek-forward"
|
||||
icon.height: parent.iconSize
|
||||
icon.width: parent.iconSize
|
||||
flat: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.preferredWidth: parent.buttonSize
|
||||
onClicked: AudioManager.skipForward()
|
||||
enabled: AudioManager.canSkipForward
|
||||
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: parent.iconSize
|
||||
icon.width: parent.iconSize
|
||||
icon.height: bottomRow.iconSize
|
||||
icon.width: bottomRow.iconSize
|
||||
flat: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.preferredWidth: parent.buttonSize
|
||||
Layout.alignment: Qt.AlignRight
|
||||
Layout.preferredWidth: bottomRow.buttonSize
|
||||
onClicked: AudioManager.next()
|
||||
enabled: AudioManager.canGoNext
|
||||
}
|
||||
|
|
211
src/qml/main.qml
211
src/qml/main.qml
|
@ -8,6 +8,7 @@
|
|||
import QtQuick 2.14
|
||||
import QtQuick.Controls 2.14 as Controls
|
||||
import QtQuick.Layouts 1.14
|
||||
import QtGraphicalEffects 1.12
|
||||
|
||||
import org.kde.kirigami 2.14 as Kirigami
|
||||
import org.kde.kasts.solidextras 1.0
|
||||
|
@ -21,18 +22,33 @@ Kirigami.ApplicationWindow {
|
|||
minimumWidth: Kirigami.Units.gridUnit * 17
|
||||
minimumHeight: Kirigami.Units.gridUnit * 20
|
||||
|
||||
property var miniplayerSize: Kirigami.Units.gridUnit * 3 + Kirigami.Units.gridUnit / 6
|
||||
property int bottomMessageSpacing: Kirigami.Settings.isMobile ? Kirigami.Units.largeSpacing * 9 + ( AudioManager.entry ? ( footerLoader.item.contentY == 0 ? miniplayerSize : 0 ) : 0 ) : Kirigami.Units.largeSpacing * 2
|
||||
property var miniplayerSize: Math.round(Kirigami.Units.gridUnit * 3) + Kirigami.Units.gridUnit / 6
|
||||
property int bottomMessageSpacing: {
|
||||
if (Kirigami.Settings.isMobile) {
|
||||
return Kirigami.Units.largeSpacing + ( AudioManager.entry ? ( footerLoader.item.contentY == 0 ? miniplayerSize : 0 ) : 0 ) + (root.footer.height);
|
||||
} else {
|
||||
return Kirigami.Units.largeSpacing * 2;
|
||||
}
|
||||
}
|
||||
property int originalWidth: Kirigami.Units.gridUnit * 10
|
||||
property var lastFeed: ""
|
||||
property string currentPage: ""
|
||||
|
||||
property bool isWidescreen: root.width >= root.height
|
||||
onIsWidescreenChanged: {
|
||||
if (!Kirigami.Settings.isMobile) {
|
||||
changeNavigation(!isWidescreen);
|
||||
changeNavigation(!isWidescreen);
|
||||
}
|
||||
|
||||
function changeNavigation(isNarrow) {
|
||||
if (isNarrow) {
|
||||
globalDrawer.collapsed = true
|
||||
globalDrawer.width = Layout.implicitWidth
|
||||
} else {
|
||||
globalDrawer.collapsed = false
|
||||
globalDrawer.width = originalWidth
|
||||
}
|
||||
}
|
||||
|
||||
function getPage(page) {
|
||||
switch (page) {
|
||||
case "QueuePage": return "qrc:/QueuePage.qml";
|
||||
|
@ -55,8 +71,10 @@ Kirigami.ApplicationWindow {
|
|||
currentPage = SettingsManager.lastOpenedPage
|
||||
pageStack.initialPage = getPage(SettingsManager.lastOpenedPage)
|
||||
|
||||
// move mobile handles to toolbar
|
||||
pageStack.globalToolBar.canContainHandles = true;
|
||||
if (Kirigami.Settings.isMobile) {
|
||||
pageStack.globalToolBar.style = Kirigami.ApplicationHeaderStyle.ToolBar;
|
||||
pageStack.globalToolBar.showNavigationButtons = Kirigami.ApplicationHeaderStyle.ShowBackButton;
|
||||
}
|
||||
|
||||
// Delete played enclosures if set in settings
|
||||
if (SettingsManager.autoDeleteOnPlayed == 2) {
|
||||
|
@ -73,93 +91,78 @@ Kirigami.ApplicationWindow {
|
|||
}
|
||||
}
|
||||
|
||||
globalDrawer: Kirigami.GlobalDrawer {
|
||||
isMenu: false
|
||||
modal: Kirigami.Settings.isMobile
|
||||
collapsible: !Kirigami.Settings.isMobile
|
||||
header: Kirigami.AbstractApplicationHeader {
|
||||
visible: !Kirigami.Settings.isMobile
|
||||
}
|
||||
globalDrawer: sidebar.item
|
||||
Loader {
|
||||
id: sidebar
|
||||
active: !Kirigami.Settings.isMobile || root.isWidescreen
|
||||
sourceComponent: Kirigami.GlobalDrawer {
|
||||
width: 200
|
||||
modal: false
|
||||
isMenu: false
|
||||
collapsible: !Kirigami.Settings.isMobile
|
||||
header: Kirigami.AbstractApplicationHeader {}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!Kirigami.Settings.isMobile) {
|
||||
Kirigami.Theme.colorSet = Kirigami.Theme.Window;
|
||||
Kirigami.Theme.inherit = false;
|
||||
}
|
||||
}
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||
Kirigami.Theme.inherit: false
|
||||
|
||||
// make room at the bottom for miniplayer
|
||||
handle.anchors.bottomMargin: (( AudioManager.entry && Kirigami.Settings.isMobile ) ? (footerLoader.item.contentY == 0 ? miniplayerSize : 0) : 0) + Kirigami.Units.smallSpacing
|
||||
handleVisible: Kirigami.Settings.isMobile ? !AudioManager.entry || footerLoader.item.contentY === 0 : false
|
||||
showHeaderWhenCollapsed: true
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
text: i18n("Queue")
|
||||
iconName: "source-playlist"
|
||||
checked: currentPage == "QueuePage"
|
||||
onTriggered: {
|
||||
pushPage("QueuePage")
|
||||
SettingsManager.lastOpenedPage = "QueuePage" // for persistency
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
text: i18n("Queue")
|
||||
iconName: "source-playlist"
|
||||
checked: currentPage == "QueuePage"
|
||||
onTriggered: {
|
||||
pushPage("QueuePage")
|
||||
SettingsManager.lastOpenedPage = "QueuePage" // for persistency
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Discover")
|
||||
iconName: "search"
|
||||
checked: currentPage == "DiscoverPage"
|
||||
onTriggered: {
|
||||
pushPage("DiscoverPage")
|
||||
SettingsManager.lastOpenedPage = "DiscoverPage" // for persistency
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Episodes")
|
||||
iconName: "rss"
|
||||
checked: currentPage == "EpisodeListPage"
|
||||
onTriggered: {
|
||||
pushPage("EpisodeListPage")
|
||||
SettingsManager.lastOpenedPage = "EpisodeListPage" // for persistency
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Subscriptions")
|
||||
iconName: "bookmarks"
|
||||
checked: currentPage == "FeedListPage"
|
||||
onTriggered: {
|
||||
pushPage("FeedListPage")
|
||||
SettingsManager.lastOpenedPage = "FeedListPage" // for persistency
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Downloads")
|
||||
iconName: "download"
|
||||
checked: currentPage == "DownloadListPage"
|
||||
onTriggered: {
|
||||
pushPage("DownloadListPage")
|
||||
SettingsManager.lastOpenedPage = "DownloadListPage" // for persistency
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Settings")
|
||||
iconName: "settings-configure"
|
||||
checked: currentPage == "SettingsPage"
|
||||
onTriggered: {
|
||||
root.pageStack.layers.clear()
|
||||
root.pageStack.pushDialogLayer("qrc:/SettingsPage.qml", {}, {
|
||||
title: i18n("Settings")
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Discover")
|
||||
iconName: "search"
|
||||
checked: currentPage == "DiscoverPage"
|
||||
onTriggered: {
|
||||
pushPage("DiscoverPage")
|
||||
SettingsManager.lastOpenedPage = "DiscoverPage" // for persistency
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Episodes")
|
||||
iconName: "rss"
|
||||
checked: currentPage == "EpisodeListPage"
|
||||
onTriggered: {
|
||||
pushPage("EpisodeListPage")
|
||||
SettingsManager.lastOpenedPage = "EpisodeListPage" // for persistency
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Subscriptions")
|
||||
iconName: "bookmarks"
|
||||
checked: currentPage == "FeedListPage"
|
||||
onTriggered: {
|
||||
pushPage("FeedListPage")
|
||||
SettingsManager.lastOpenedPage = "FeedListPage" // for persistency
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Downloads")
|
||||
iconName: "download"
|
||||
checked: currentPage == "DownloadListPage"
|
||||
onTriggered: {
|
||||
pushPage("DownloadListPage")
|
||||
SettingsManager.lastOpenedPage = "DownloadListPage" // for persistency
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Settings")
|
||||
iconName: "settings-configure"
|
||||
checked: currentPage == "SettingsPage"
|
||||
onTriggered: {
|
||||
root.pageStack.layers.clear()
|
||||
root.pageStack.pushDialogLayer("qrc:/SettingsPage.qml", {}, {
|
||||
title: i18n("Settings")
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
function changeNavigation(isNarrow) {
|
||||
if(isNarrow) {
|
||||
globalDrawer.collapsed = true
|
||||
globalDrawer.width = Layout.implicitWidth
|
||||
}
|
||||
else {
|
||||
globalDrawer.collapsed = false
|
||||
globalDrawer.width = originalWidth
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,9 +193,7 @@ Kirigami.ApplicationWindow {
|
|||
active: !Kirigami.Settings.isMobile
|
||||
visible: active
|
||||
|
||||
sourceComponent: HeaderBar {
|
||||
focus: true
|
||||
}
|
||||
sourceComponent: HeaderBar { focus: true }
|
||||
}
|
||||
|
||||
// create space at the bottom to show miniplayer without it hiding stuff
|
||||
|
@ -209,8 +210,32 @@ Kirigami.ApplicationWindow {
|
|||
sourceComponent: FooterBar {
|
||||
contentHeight: root.height * 2
|
||||
focus: true
|
||||
contentToPlayerSpacing: footer.active ? footer.item.height + 1 : 0
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: footerShadowLoader
|
||||
active: footer.active && !footerLoader.active
|
||||
anchors.fill: footer
|
||||
|
||||
sourceComponent: RectangularGlow {
|
||||
glowRadius: 5
|
||||
spread: 0.3
|
||||
color: Qt.rgba(0.0, 0.0, 0.0, 0.1)
|
||||
}
|
||||
}
|
||||
|
||||
footer: Loader {
|
||||
visible: active
|
||||
active: Kirigami.Settings.isMobile && !root.isWidescreen
|
||||
sourceComponent: BottomToolbar {
|
||||
transparentBackground: footerLoader.active
|
||||
opacity: (!footerLoader.item || footerLoader.item.contentY === 0) ? 1 : 0
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: Kirigami.Units.shortDuration }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notification that shows the progress of feed updates
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
<file alias="NetworkSettingsPage.qml">qml/Settings/NetworkSettingsPage.qml</file>
|
||||
<file alias="StorageSettingsPage.qml">qml/Settings/StorageSettingsPage.qml</file>
|
||||
<file alias="SynchronizationSettingsPage.qml">qml/Settings/SynchronizationSettingsPage.qml</file>
|
||||
<file alias="BottomToolbar.qml">qml/BottomToolbar.qml</file>
|
||||
<file>qtquickcontrols2.conf</file>
|
||||
<file alias="logo.svg">../kasts.svg</file>
|
||||
</qresource>
|
||||
|
|
Loading…
Reference in New Issue