Move page actions to bar, and consolidate podcast list and info pages

This commit is contained in:
Devin Lin 2022-09-07 19:03:07 +00:00 committed by Bart De Vries
parent 9860c8b9e5
commit 3a6446dea5
7 changed files with 450 additions and 361 deletions

View File

@ -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})
}
}
}
}
}

View File

@ -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});
}
}
]
}

View File

@ -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
}
}
}

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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>