Move page actions to bar, and consolidate podcast list and info pages
This commit is contained in:
parent
9860c8b9e5
commit
3a6446dea5
@ -1,122 +0,0 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2020 Tobias Fella <fella@posteo.de>
|
||||
* SPDX-FileCopyrightText: 2021 Bart De Vries <bart@mogwai.be>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.14 as Controls
|
||||
import QtQuick.Layouts 1.14
|
||||
import QtGraphicalEffects 1.15
|
||||
import org.kde.kirigami 2.14 as Kirigami
|
||||
|
||||
import org.kde.kasts 1.0
|
||||
|
||||
Kirigami.ScrollablePage {
|
||||
id: page
|
||||
|
||||
property var feed
|
||||
|
||||
title: i18n("Episode List")
|
||||
supportsRefreshing: true
|
||||
|
||||
onRefreshingChanged: {
|
||||
if(refreshing) {
|
||||
updateFeed.run()
|
||||
}
|
||||
}
|
||||
|
||||
// Overlay dialog box showing options what to do on metered connections
|
||||
ConnectionCheckAction {
|
||||
id: updateFeed
|
||||
|
||||
function action() {
|
||||
feed.refresh()
|
||||
}
|
||||
|
||||
function abortAction() {
|
||||
page.refreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that this feed is also showing as "refreshing" on FeedListPage
|
||||
Connections {
|
||||
target: feed
|
||||
function onRefreshingChanged(refreshing) {
|
||||
if(!refreshing)
|
||||
page.refreshing = refreshing
|
||||
}
|
||||
}
|
||||
|
||||
actions.main: Kirigami.Action {
|
||||
iconName: "view-refresh"
|
||||
text: i18n("Refresh Podcast")
|
||||
onTriggered: page.refreshing = true
|
||||
}
|
||||
|
||||
contextualActions: [
|
||||
Kirigami.Action {
|
||||
iconName: "help-about-symbolic"
|
||||
text: i18n("Podcast Details")
|
||||
onTriggered: {
|
||||
while(pageStack.depth > 2)
|
||||
pageStack.pop()
|
||||
pageStack.push("qrc:/FeedDetailsPage.qml", {"feed": feed})
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
// add the default actions through onCompleted to add them to the ones
|
||||
// defined above
|
||||
Component.onCompleted: {
|
||||
for (var i in entryList.defaultActionList) {
|
||||
contextualActions.push(entryList.defaultActionList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
visible: entryList.count === 0
|
||||
|
||||
width: Kirigami.Units.gridUnit * 20
|
||||
anchors.centerIn: parent
|
||||
|
||||
text: feed.errorId === 0 ? i18n("No Episodes Available") : i18n("Error (%1): %2", feed.errorId, feed.errorString)
|
||||
icon.name: feed.errorId === 0 ? "" : "data-error"
|
||||
}
|
||||
|
||||
Component {
|
||||
id: entryListDelegate
|
||||
GenericEntryDelegate {
|
||||
listView: entryList
|
||||
}
|
||||
}
|
||||
|
||||
GenericEntryListView {
|
||||
id: entryList
|
||||
visible: count !== 0
|
||||
reuseItems: true
|
||||
|
||||
model: page.feed.entries
|
||||
delegate: entryListDelegate
|
||||
|
||||
// OverlayHeader looks nicer, but seems completely broken when flicking the list
|
||||
// headerPositioning: ListView.OverlayHeader
|
||||
header: GenericHeader {
|
||||
id: headerImage
|
||||
|
||||
image: feed.cachedImage
|
||||
title: feed.name
|
||||
subtitle: page.feed.authors.length === 0 ? "" : i18nc("by <author(s)>", "by %1", page.feed.authors[0].name)
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
while(pageStack.depth > 2)
|
||||
pageStack.pop()
|
||||
pageStack.push("qrc:/FeedDetailsPage.qml", {"feed": feed})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -23,6 +23,13 @@ Kirigami.ScrollablePage {
|
||||
|
||||
padding: 0 // needed to get the inline header to fill the page
|
||||
|
||||
function openPodcast() {
|
||||
pushPage("FeedListPage")
|
||||
SettingsManager.lastOpenedPage = "FeedListPage" // for persistency
|
||||
lastFeed = entry.feed.url;
|
||||
pageStack.push("qrc:/FeedDetailsPage.qml", {"feed": entry.feed});
|
||||
}
|
||||
|
||||
// This function is needed to close the EntryPage if it is opened over the
|
||||
// QueuePage when the episode is removed from the queue (e.g. when the
|
||||
// episode finishes).
|
||||
@ -65,30 +72,149 @@ Kirigami.ScrollablePage {
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
GenericHeader {
|
||||
id: infoHeader
|
||||
Layout.fillWidth: true
|
||||
image: entry.cachedImage
|
||||
title: entry.title
|
||||
subtitle: entry.feed.name
|
||||
clickable: true
|
||||
|
||||
onClicked: page.openPodcast()
|
||||
}
|
||||
|
||||
// header actions
|
||||
Controls.Control {
|
||||
Layout.fillWidth: true
|
||||
|
||||
leftPadding: Kirigami.Units.largeSpacing
|
||||
rightPadding: Kirigami.Units.largeSpacing
|
||||
bottomPadding: Kirigami.Units.smallSpacing
|
||||
topPadding: Kirigami.Units.smallSpacing
|
||||
|
||||
background: Rectangle {
|
||||
color: Kirigami.Theme.alternateBackgroundColor
|
||||
|
||||
Kirigami.Separator {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Kirigami.ActionToolBar {
|
||||
alignment: Qt.AlignLeft
|
||||
background: Item {}
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
text: !entry.enclosure ? i18n("Open in Browser") :
|
||||
(entry.enclosure.status === Enclosure.Downloadable || entry.enclosure.status === Enclosure.PartiallyDownloaded) ? i18n("Download") :
|
||||
entry.enclosure.status === Enclosure.Downloading ? i18n("Cancel Download") :
|
||||
!entry.queueStatus ? i18n("Delete Download") :
|
||||
(AudioManager.entry === entry && AudioManager.playbackState === Audio.PlayingState) ? i18n("Pause") :
|
||||
i18n("Play")
|
||||
icon.name: !entry.enclosure ? "globe" :
|
||||
(entry.enclosure.status === Enclosure.Downloadable || entry.enclosure.status === Enclosure.PartiallyDownloaded) ? "download" :
|
||||
entry.enclosure.status === Enclosure.Downloading ? "edit-delete-remove" :
|
||||
!entry.queueStatus ? "delete" :
|
||||
(AudioManager.entry === entry && AudioManager.playbackState === Audio.PlayingState) ? "media-playback-pause" :
|
||||
"media-playback-start"
|
||||
onTriggered: {
|
||||
if (!entry.enclosure) {
|
||||
Qt.openUrlExternally(entry.link)
|
||||
} else if (entry.enclosure.status === Enclosure.Downloadable || entry.enclosure.status === Enclosure.PartiallyDownloaded) {
|
||||
downloadOverlay.entry = entry;
|
||||
downloadOverlay.run();
|
||||
} else if (entry.enclosure.status === Enclosure.Downloading) {
|
||||
entry.enclosure.cancelDownload()
|
||||
} else if (!entry.queueStatus) {
|
||||
entry.enclosure.deleteFile()
|
||||
} else {
|
||||
if(AudioManager.entry === entry && AudioManager.playbackState === Audio.PlayingState) {
|
||||
AudioManager.pause()
|
||||
} else {
|
||||
AudioManager.entry = entry
|
||||
AudioManager.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: !entry.queueStatus ? i18n("Add to Queue") : i18n("Remove from Queue")
|
||||
icon.name: !entry.queueStatus ? "media-playlist-append" : "list-remove"
|
||||
visible: entry.enclosure || entry.queueStatus
|
||||
onTriggered: {
|
||||
if(!entry.queueStatus) {
|
||||
entry.queueStatus = true
|
||||
} else {
|
||||
// first change to next track if this one is playing
|
||||
if (entry.hasEnclosure && entry === AudioManager.entry) {
|
||||
AudioManager.next()
|
||||
}
|
||||
entry.queueStatus = false
|
||||
}
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Delete Download")
|
||||
icon.name: "delete"
|
||||
onTriggered: entry.enclosure.deleteFile();
|
||||
visible: entry.enclosure && ((entry.enclosure.status === Enclosure.Downloaded && entry.queueStatus) || entry.enclosure.status === Enclosure.PartiallyDownloaded)
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Reset Play Position")
|
||||
visible: entry.enclosure && entry.enclosure.playPosition > 1000
|
||||
onTriggered: entry.enclosure.playPosition = 0
|
||||
displayHint: Kirigami.DisplayHint.AlwaysHide
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: entry.read ? i18n("Mark as Unplayed") : i18n("Mark as Played")
|
||||
displayHint: Kirigami.DisplayHint.AlwaysHide
|
||||
onTriggered: {
|
||||
entry.read = !entry.read
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: entry.new ? i18n("Remove \"New\" Label") : i18n("Label as \"New\"")
|
||||
displayHint: Kirigami.DisplayHint.AlwaysHide
|
||||
onTriggered: {
|
||||
entry.new = !entry.new
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Open Podcast")
|
||||
displayHint: Kirigami.DisplayHint.AlwaysHide
|
||||
onTriggered: page.openPodcast()
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
TextEdit {
|
||||
id: textLabel
|
||||
Layout.margins: Kirigami.Units.gridUnit
|
||||
Layout.topMargin: Kirigami.Units.gridUnit
|
||||
Layout.leftMargin: Kirigami.Units.gridUnit
|
||||
Layout.rightMargin: Kirigami.Units.gridUnit
|
||||
Layout.bottomMargin: Kirigami.Units.gridUnit
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
readOnly: true
|
||||
selectByMouse: !Kirigami.Settings.isMobile
|
||||
text: page.entry.content
|
||||
baseUrl: page.entry.baseUrl
|
||||
textFormat: Text.RichText
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
onWidthChanged: { text = entry.adjustedContent(width, font.pixelSize) }
|
||||
font.pointSize: SettingsManager && !(SettingsManager.articleFontUseSystem) ? SettingsManager.articleFontSize : Kirigami.Theme.defaultFont.pointSize
|
||||
color: Kirigami.Theme.textColor
|
||||
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
onWidthChanged: { text = entry.adjustedContent(width, font.pixelSize) }
|
||||
}
|
||||
|
||||
ListView {
|
||||
visible: count !== 0
|
||||
Layout.fillWidth: true
|
||||
@ -105,19 +231,26 @@ Kirigami.ScrollablePage {
|
||||
entry: page.entry
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
|
||||
Controls.Button {
|
||||
Layout.leftMargin: Kirigami.Units.gridUnit
|
||||
Layout.rightMargin: Kirigami.Units.gridUnit
|
||||
Layout.bottomMargin: Kirigami.Units.gridUnit
|
||||
visible: entry.hasEnclosure
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
TextEdit {
|
||||
readOnly: true
|
||||
textFormat:TextEdit.RichText
|
||||
text: i18n("Episode Download URL:")
|
||||
wrapMode: TextEdit.Wrap
|
||||
color: Kirigami.Theme.textColor
|
||||
|
||||
text: i18n("Copy Episode Download URL")
|
||||
height: enclosureUrl.height
|
||||
width: enclosureUrl.height
|
||||
icon.name: "edit-copy"
|
||||
|
||||
onClicked: {
|
||||
applicationWindow().showPassiveNotification(i18n("Link copied"));
|
||||
enclosureUrl.selectAll();
|
||||
enclosureUrl.copy();
|
||||
enclosureUrl.deselect();
|
||||
}
|
||||
|
||||
// copy url from this invisible textedit
|
||||
TextEdit {
|
||||
id: enclosureUrl
|
||||
visible: false
|
||||
@ -126,103 +259,6 @@ Kirigami.ScrollablePage {
|
||||
text: entry.hasEnclosure ? entry.enclosure.url : ""
|
||||
color: Kirigami.Theme.textColor
|
||||
}
|
||||
Controls.Button {
|
||||
height: enclosureUrl.height
|
||||
width: enclosureUrl.height
|
||||
icon.name: "edit-copy"
|
||||
onClicked: {
|
||||
enclosureUrl.selectAll();
|
||||
enclosureUrl.copy();
|
||||
enclosureUrl.deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actions.main: Kirigami.Action {
|
||||
text: !entry.enclosure ? i18n("Open in Browser") :
|
||||
(entry.enclosure.status === Enclosure.Downloadable || entry.enclosure.status === Enclosure.PartiallyDownloaded) ? i18n("Download") :
|
||||
entry.enclosure.status === Enclosure.Downloading ? i18n("Cancel Download") :
|
||||
!entry.queueStatus ? i18n("Delete Download") :
|
||||
(AudioManager.entry === entry && AudioManager.playbackState === Audio.PlayingState) ? i18n("Pause") :
|
||||
i18n("Play")
|
||||
icon.name: !entry.enclosure ? "globe" :
|
||||
(entry.enclosure.status === Enclosure.Downloadable || entry.enclosure.status === Enclosure.PartiallyDownloaded) ? "download" :
|
||||
entry.enclosure.status === Enclosure.Downloading ? "edit-delete-remove" :
|
||||
!entry.queueStatus ? "delete" :
|
||||
(AudioManager.entry === entry && AudioManager.playbackState === Audio.PlayingState) ? "media-playback-pause" :
|
||||
"media-playback-start"
|
||||
onTriggered: {
|
||||
if (!entry.enclosure) {
|
||||
Qt.openUrlExternally(entry.link)
|
||||
} else if (entry.enclosure.status === Enclosure.Downloadable || entry.enclosure.status === Enclosure.PartiallyDownloaded) {
|
||||
downloadOverlay.entry = entry;
|
||||
downloadOverlay.run();
|
||||
} else if (entry.enclosure.status === Enclosure.Downloading) {
|
||||
entry.enclosure.cancelDownload()
|
||||
} else if (!entry.queueStatus) {
|
||||
entry.enclosure.deleteFile()
|
||||
} else {
|
||||
if(AudioManager.entry === entry && AudioManager.playbackState === Audio.PlayingState) {
|
||||
AudioManager.pause()
|
||||
} else {
|
||||
AudioManager.entry = entry
|
||||
AudioManager.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actions.left: Kirigami.Action {
|
||||
text: !entry.queueStatus ? i18n("Add to Queue") : i18n("Remove from Queue")
|
||||
icon.name: !entry.queueStatus ? "media-playlist-append" : "list-remove"
|
||||
visible: entry.enclosure || entry.queueStatus
|
||||
onTriggered: {
|
||||
if(!entry.queueStatus) {
|
||||
entry.queueStatus = true
|
||||
} else {
|
||||
// first change to next track if this one is playing
|
||||
if (entry.hasEnclosure && entry === AudioManager.entry) {
|
||||
AudioManager.next()
|
||||
}
|
||||
entry.queueStatus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actions.right: Kirigami.Action {
|
||||
text: i18n("Delete Download")
|
||||
icon.name: "delete"
|
||||
onTriggered: entry.enclosure.deleteFile();
|
||||
visible: entry.enclosure && ((entry.enclosure.status === Enclosure.Downloaded && entry.queueStatus) || entry.enclosure.status === Enclosure.PartiallyDownloaded)
|
||||
}
|
||||
|
||||
contextualActions: [
|
||||
Kirigami.Action {
|
||||
text: i18n("Reset Play Position")
|
||||
visible: entry.enclosure && entry.enclosure.playPosition > 1000
|
||||
onTriggered: entry.enclosure.playPosition = 0
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: entry.read ? i18n("Mark as Unplayed") : i18n("Mark as Played")
|
||||
onTriggered: {
|
||||
entry.read = !entry.read
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: entry.new ? i18n("Remove \"New\" Label") : i18n("Label as \"New\"")
|
||||
onTriggered: {
|
||||
entry.new = !entry.new
|
||||
}
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Open Podcast")
|
||||
onTriggered: {
|
||||
pushPage("FeedListPage")
|
||||
SettingsManager.lastOpenedPage = "FeedListPage" // for persistency
|
||||
lastFeed = entry.feed.url;
|
||||
pageStack.push("qrc:/EntryListPage.qml", {"feed": entry.feed});
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -20,145 +20,304 @@ Kirigami.ScrollablePage {
|
||||
property bool isSubscribed: true
|
||||
|
||||
property string author: isSubscribed ? (page.feed.authors.length === 0 ? "" : page.feed.authors[0].name) : feed.author
|
||||
property bool showMoreInfo: false
|
||||
|
||||
title: i18n("Podcast Details")
|
||||
|
||||
header: GenericHeader {
|
||||
id: headerImage
|
||||
supportsRefreshing: true
|
||||
|
||||
image: isSubscribed ? feed.cachedImage : feed.image
|
||||
title: isSubscribed ? feed.name : feed.title
|
||||
subtitle: author !== "" ? i18nc("by <Author(s)>", "by %1", author) : ""
|
||||
Controls.Button {
|
||||
text: enabled ? i18n("Subscribe") : i18n("Subscribed")
|
||||
icon.name: "kt-add-feeds"
|
||||
visible: !isSubscribed
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: Kirigami.Units.largeSpacing
|
||||
anchors.topMargin: Kirigami.Units.largeSpacing
|
||||
onClicked: {
|
||||
DataManager.addFeed(feed.url)
|
||||
}
|
||||
enabled: !DataManager.feedExists(feed.url)
|
||||
onRefreshingChanged: {
|
||||
if (refreshing) {
|
||||
updateFeed.run()
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
TextEdit {
|
||||
readOnly: true
|
||||
selectByMouse: !Kirigami.Settings.isMobile
|
||||
textFormat:TextEdit.RichText
|
||||
text: feed.description
|
||||
font.pointSize: Math.round(Kirigami.Theme.defaultFont.pointSize * 1.2)
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
color: Kirigami.Theme.textColor
|
||||
// Overlay dialog box showing options what to do on metered connections
|
||||
ConnectionCheckAction {
|
||||
id: updateFeed
|
||||
|
||||
function action() {
|
||||
feed.refresh()
|
||||
}
|
||||
TextEdit {
|
||||
readOnly: true
|
||||
selectByMouse: !Kirigami.Settings.isMobile
|
||||
textFormat:TextEdit.RichText
|
||||
text: i18nc("by <Author(s)>", "by %1", author)
|
||||
visible: author !== ""
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
color: Kirigami.Theme.textColor
|
||||
|
||||
function abortAction() {
|
||||
page.refreshing = false
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Math.max(feedUrlLayout.height, feedUrlCopyButton.width)
|
||||
RowLayout {
|
||||
id: feedUrlLayout
|
||||
anchors.left: parent.left
|
||||
anchors.right: feedUrlCopyButton.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
TextEdit {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
readOnly: true
|
||||
textFormat:TextEdit.RichText
|
||||
text: i18n("Podcast URL:")
|
||||
wrapMode: TextEdit.Wrap
|
||||
color: Kirigami.Theme.textColor
|
||||
}
|
||||
TextEdit {
|
||||
id: feedUrl
|
||||
Layout.alignment: Qt.AlignTop
|
||||
readOnly: true
|
||||
selectByMouse: !Kirigami.Settings.isMobile
|
||||
textFormat:TextEdit.RichText
|
||||
text: "<a href='%1'>%1</a>".arg(feed.url)
|
||||
wrapMode: TextEdit.Wrap
|
||||
Layout.fillWidth: true
|
||||
color: Kirigami.Theme.textColor
|
||||
}
|
||||
}
|
||||
Controls.Button {
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.leftMargin: Kirigami.Units.smallSpacing
|
||||
id: feedUrlCopyButton
|
||||
icon.name: "edit-copy"
|
||||
onClicked: {
|
||||
feedUrl.selectAll();
|
||||
feedUrl.copy();
|
||||
feedUrl.deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure that this feed is also showing as "refreshing" on FeedListPage
|
||||
Connections {
|
||||
target: feed
|
||||
function onRefreshingChanged(refreshing) {
|
||||
if(!refreshing)
|
||||
page.refreshing = refreshing
|
||||
}
|
||||
RowLayout {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
TextEdit {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
readOnly: true
|
||||
textFormat:TextEdit.RichText
|
||||
text: i18n("Weblink:")
|
||||
wrapMode: TextEdit.Wrap
|
||||
color: Kirigami.Theme.textColor
|
||||
}
|
||||
|
||||
// add the default actions through onCompleted to add them to the ones
|
||||
// defined above
|
||||
Component.onCompleted: {
|
||||
for (var i in entryList.defaultActionList) {
|
||||
contextualActions.push(entryList.defaultActionList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: entryListDelegate
|
||||
GenericEntryDelegate {
|
||||
listView: entryList
|
||||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: emptyListModel
|
||||
}
|
||||
|
||||
GenericEntryListView {
|
||||
id: entryList
|
||||
visible: true
|
||||
reuseItems: true
|
||||
currentIndex: -1
|
||||
|
||||
model: page.feed.entries ? page.feed.entries : emptyListModel
|
||||
delegate: entryListDelegate
|
||||
|
||||
// OverlayHeader looks nicer, but seems completely broken when flicking the list
|
||||
//headerPositioning: ListView.OverlayHeader
|
||||
|
||||
header: ColumnLayout {
|
||||
id: headerColumn
|
||||
height: (isSubscribed && entryList.count > 0) ? implicitHeight : entryList.height
|
||||
width: entryList.width
|
||||
spacing: 0
|
||||
|
||||
property real headerOverlayProgress: Math.min(1, Math.abs(entryList.contentY) / headerColumn.height)
|
||||
|
||||
Kirigami.Theme.inherit: false
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||
|
||||
GenericHeader {
|
||||
id: headerImage
|
||||
Layout.fillWidth: true
|
||||
|
||||
image: isSubscribed ? feed.cachedImage : feed.image
|
||||
title: isSubscribed ? feed.name : feed.title
|
||||
subtitle: (!page.feed.authors || page.feed.authors.length === 0) ? "" : i18nc("by <author(s)>", "by %1", page.feed.authors[0].name)
|
||||
}
|
||||
|
||||
TextEdit {
|
||||
readOnly: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
selectByMouse: !Kirigami.Settings.isMobile
|
||||
textFormat:TextEdit.RichText
|
||||
text: "<a href='%1'>%1</a>".arg(feed.link)
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
wrapMode: Text.WordWrap
|
||||
// header actions
|
||||
Controls.Control {
|
||||
Layout.fillWidth: true
|
||||
color: Kirigami.Theme.textColor
|
||||
|
||||
leftPadding: Kirigami.Units.largeSpacing
|
||||
rightPadding: Kirigami.Units.largeSpacing
|
||||
bottomPadding: Kirigami.Units.smallSpacing
|
||||
topPadding: Kirigami.Units.smallSpacing
|
||||
|
||||
background: Rectangle {
|
||||
color: Kirigami.Theme.alternateBackgroundColor
|
||||
}
|
||||
|
||||
contentItem: Kirigami.ActionToolBar {
|
||||
alignment: Qt.AlignLeft
|
||||
background: Item {}
|
||||
|
||||
// HACK: ActionToolBar loads buttons dynamically, and so the height calculation
|
||||
// changes the position
|
||||
onHeightChanged: entryList.contentY = entryList.originY
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
visible: isSubscribed
|
||||
iconName: "view-refresh"
|
||||
text: i18n("Refresh Podcast")
|
||||
onTriggered: page.refreshing = true
|
||||
},
|
||||
Kirigami.Action {
|
||||
iconName: "kt-add-feeds"
|
||||
text: enabled ? i18n("Subscribe") : i18n("Subscribed")
|
||||
enabled: !DataManager.feedExists(feed.url)
|
||||
visible: !isSubscribed
|
||||
onTriggered: DataManager.addFeed(feed.url)
|
||||
},
|
||||
Kirigami.Action {
|
||||
iconName: "help-about-symbolic"
|
||||
text: i18n("Show Details")
|
||||
checkable: true
|
||||
onCheckedChanged: {
|
||||
showMoreInfo = checked;
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Separator { Layout.fillWidth: true }
|
||||
|
||||
// podcast description
|
||||
Controls.Control {
|
||||
Layout.fillHeight: !isSubscribed
|
||||
Layout.fillWidth: true
|
||||
leftPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
|
||||
rightPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing
|
||||
topPadding: Kirigami.Units.largeSpacing
|
||||
bottomPadding: Kirigami.Units.largeSpacing
|
||||
|
||||
// HACK: opening more info changes the position of the header
|
||||
onHeightChanged: entryList.contentY = entryList.originY
|
||||
|
||||
background: Rectangle {
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
Controls.Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
textFormat: TextEdit.RichText
|
||||
text: feed.description
|
||||
font.pointSize: Kirigami.Theme.defaultFont.pointSize
|
||||
wrapMode: Text.WordWrap
|
||||
color: Kirigami.Theme.textColor
|
||||
lineHeight: 1.2
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.preferredHeight: Math.max(feedUrlLayout.height, feedUrlCopyButton.width)
|
||||
visible: page.showMoreInfo
|
||||
height: visible ? implicitHeight : 0
|
||||
RowLayout {
|
||||
id: feedUrlLayout
|
||||
anchors.left: parent.left
|
||||
anchors.right: feedUrlCopyButton.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
TextEdit {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
readOnly: true
|
||||
textFormat:TextEdit.RichText
|
||||
text: i18n("Podcast URL:")
|
||||
wrapMode: TextEdit.Wrap
|
||||
color: Kirigami.Theme.textColor
|
||||
}
|
||||
TextEdit {
|
||||
id: feedUrl
|
||||
Layout.alignment: Qt.AlignTop
|
||||
readOnly: true
|
||||
selectByMouse: !Kirigami.Settings.isMobile
|
||||
textFormat:TextEdit.RichText
|
||||
text: "<a href='%1'>%1</a>".arg(feed.url)
|
||||
wrapMode: TextEdit.Wrap
|
||||
Layout.fillWidth: true
|
||||
color: Kirigami.Theme.textColor
|
||||
}
|
||||
}
|
||||
Controls.Button {
|
||||
id: feedUrlCopyButton
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.leftMargin: Kirigami.Units.smallSpacing
|
||||
icon.name: "edit-copy"
|
||||
|
||||
onClicked: {
|
||||
feedUrl.selectAll();
|
||||
feedUrl.copy();
|
||||
feedUrl.deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
visible: page.showMoreInfo
|
||||
height: visible ? implicitHeight : 0
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
TextEdit {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
readOnly: true
|
||||
textFormat: TextEdit.RichText
|
||||
text: i18n("Weblink:")
|
||||
wrapMode: TextEdit.Wrap
|
||||
color: Kirigami.Theme.textColor
|
||||
}
|
||||
|
||||
TextEdit {
|
||||
readOnly: true
|
||||
Layout.alignment: Qt.AlignTop
|
||||
selectByMouse: !Kirigami.Settings.isMobile
|
||||
textFormat:TextEdit.RichText
|
||||
text: "<a href='%1'>%1</a>".arg(feed.link)
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
color: Kirigami.Theme.textColor
|
||||
}
|
||||
}
|
||||
TextEdit {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
visible: isSubscribed && page.showMoreInfo
|
||||
height: visible ? implicitHeight : 0
|
||||
|
||||
readOnly: true
|
||||
selectByMouse: !Kirigami.Settings.isMobile
|
||||
textFormat:TextEdit.RichText
|
||||
text: isSubscribed ? i18n("Subscribed since: %1", feed.subscribed.toLocaleString(Qt.locale(), Locale.ShortFormat)) : ""
|
||||
wrapMode: Text.WordWrap
|
||||
color: Kirigami.Theme.textColor
|
||||
}
|
||||
TextEdit {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
visible: isSubscribed && page.showMoreInfo
|
||||
height: visible ? implicitHeight : 0
|
||||
|
||||
readOnly: true
|
||||
selectByMouse: !Kirigami.Settings.isMobile
|
||||
textFormat:TextEdit.RichText
|
||||
text: isSubscribed ? i18n("Last Updated: %1", feed.lastUpdated.toLocaleString(Qt.locale(), Locale.ShortFormat)) : ""
|
||||
wrapMode: Text.WordWrap
|
||||
color: Kirigami.Theme.textColor
|
||||
}
|
||||
TextEdit {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
visible: isSubscribed && page.showMoreInfo
|
||||
height: visible ? implicitHeight : 0
|
||||
|
||||
readOnly: true
|
||||
selectByMouse: !Kirigami.Settings.isMobile
|
||||
textFormat:TextEdit.RichText
|
||||
text: i18np("1 Episode", "%1 Episodes", feed.entryCount) + ", " + i18np("1 Unplayed", "%1 Unplayed", feed.unreadEntryCount)
|
||||
wrapMode: Text.WordWrap
|
||||
color: Kirigami.Theme.textColor
|
||||
}
|
||||
|
||||
Item { Layout.fillHeight: true }
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Separator { Layout.fillWidth: true }
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
height: visible ? implicitHeight : 0
|
||||
visible: entryList.count === 0 && isSubscribed
|
||||
|
||||
Kirigami.PlaceholderMessage {
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: Kirigami.Units.gridUnit * 20
|
||||
|
||||
text: feed.errorId === 0 ? i18n("No Episodes Available") : i18n("Error (%1): %2", feed.errorId, feed.errorString)
|
||||
icon.name: feed.errorId === 0 ? "" : "data-error"
|
||||
}
|
||||
}
|
||||
}
|
||||
TextEdit {
|
||||
readOnly: true
|
||||
selectByMouse: !Kirigami.Settings.isMobile
|
||||
textFormat:TextEdit.RichText
|
||||
text: isSubscribed ? i18n("Subscribed since: %1", feed.subscribed.toLocaleString(Qt.locale(), Locale.ShortFormat)) : ""
|
||||
visible: isSubscribed
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
color: Kirigami.Theme.textColor
|
||||
}
|
||||
TextEdit {
|
||||
readOnly: true
|
||||
selectByMouse: !Kirigami.Settings.isMobile
|
||||
textFormat:TextEdit.RichText
|
||||
text: isSubscribed ? i18n("Last Updated: %1", feed.lastUpdated.toLocaleString(Qt.locale(), Locale.ShortFormat)) : ""
|
||||
visible: isSubscribed
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
color: Kirigami.Theme.textColor
|
||||
}
|
||||
TextEdit {
|
||||
readOnly: true
|
||||
selectByMouse: !Kirigami.Settings.isMobile
|
||||
textFormat:TextEdit.RichText
|
||||
text: i18np("1 Episode", "%1 Episodes", feed.entryCount) + ", " + i18np("1 Unplayed", "%1 Unplayed", feed.unreadEntryCount)
|
||||
visible: isSubscribed
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
color: Kirigami.Theme.textColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -229,7 +229,7 @@ Controls.ItemDelegate {
|
||||
lastFeed = feed.url
|
||||
if (pageStack.depth > 1)
|
||||
pageStack.pop();
|
||||
pageStack.push("qrc:/EntryListPage.qml", {"feed": feed})
|
||||
pageStack.push("qrc:/FeedDetailsPage.qml", {"feed": feed})
|
||||
}
|
||||
|
||||
Controls.ToolTip {
|
||||
|
@ -11,7 +11,7 @@ import Qt.labs.platform 1.1
|
||||
import QtQuick.Layouts 1.14
|
||||
import QtQml.Models 2.15
|
||||
|
||||
import org.kde.kirigami 2.12 as Kirigami
|
||||
import org.kde.kirigami 2.19 as Kirigami
|
||||
|
||||
import org.kde.kasts 1.0
|
||||
|
||||
@ -57,11 +57,13 @@ Kirigami.ScrollablePage {
|
||||
Kirigami.Action {
|
||||
text: i18n("Import Podcasts...")
|
||||
iconName: "document-import"
|
||||
displayHint: Kirigami.DisplayHint.AlwaysHide
|
||||
onTriggered: importDialog.open()
|
||||
},
|
||||
Kirigami.Action {
|
||||
text: i18n("Export Podcasts...")
|
||||
iconName: "document-export"
|
||||
displayHint: Kirigami.DisplayHint.AlwaysHide
|
||||
onTriggered: exportDialog.open()
|
||||
}
|
||||
]
|
||||
@ -106,6 +108,7 @@ Kirigami.ScrollablePage {
|
||||
|
||||
GridView {
|
||||
id: feedList
|
||||
currentIndex: -1
|
||||
visible: count !== 0
|
||||
clip: true
|
||||
|
||||
|
@ -14,11 +14,16 @@ import org.kde.kirigami 2.14 as Kirigami
|
||||
import org.kde.kasts 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
required property string image
|
||||
required property string title
|
||||
|
||||
property string subtitle: ""
|
||||
property var headerHeight: Kirigami.Units.gridUnit * 8
|
||||
|
||||
property bool clickable: false
|
||||
signal clicked()
|
||||
|
||||
implicitHeight: headerHeight
|
||||
implicitWidth: parent.width
|
||||
|
||||
@ -41,6 +46,15 @@ Item {
|
||||
color:"#87000000" //RGBA, but first value is actually the alpha channel
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
if (root.clickable) {
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
property int size: Kirigami.Units.gridUnit * 6
|
||||
property int margin: Kirigami.Units.gridUnit * 1
|
||||
|
@ -3,7 +3,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file alias="main.qml">qml/main.qml</file>
|
||||
<file alias="EntryListPage.qml">qml/EntryListPage.qml</file>
|
||||
<file alias="FeedListPage.qml">qml/FeedListPage.qml</file>
|
||||
<file alias="EntryPage.qml">qml/EntryPage.qml</file>
|
||||
<file alias="AboutPage.qml">qml/Settings/AboutPage.qml</file>
|
||||
|
Loading…
x
Reference in New Issue
Block a user