Warning, /multimedia/kasts/src/qml/FeedDetailsPage.qml is written in an unsupported language. File is not indexed.
0001 /** 0002 * SPDX-FileCopyrightText: 2020 Tobias Fella <tobias.fella@kde.org> 0003 * SPDX-FileCopyrightText: 2021-2022 Bart De Vries <bart@mogwai.be> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 import QtQuick 0009 import QtQuick.Controls as Controls 0010 import QtQuick.Layouts 0011 0012 import org.kde.kirigami as Kirigami 0013 0014 import org.kde.kasts 0015 0016 Kirigami.ScrollablePage { 0017 id: page 0018 0019 LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft 0020 LayoutMirroring.childrenInherit: true 0021 0022 property QtObject feed; 0023 property bool isSubscribed: true 0024 property var subscribeAction: undefined // this is only used if instantiated from the discoverpage 0025 0026 property bool showMoreInfo: false 0027 0028 title: i18n("Podcast Details") 0029 0030 Keys.onPressed: (event) => { 0031 if (event.matches(StandardKey.Find)) { 0032 searchActionButton.checked = true; 0033 } 0034 } 0035 0036 supportsRefreshing: true 0037 0038 onRefreshingChanged: { 0039 if (refreshing) { 0040 updateFeed.run() 0041 } 0042 } 0043 0044 // Overlay dialog box showing options what to do on metered connections 0045 ConnectionCheckAction { 0046 id: updateFeed 0047 0048 function action() { 0049 feed.refresh() 0050 } 0051 0052 function abortAction() { 0053 page.refreshing = false 0054 } 0055 } 0056 0057 // Make sure that this feed is also showing as "refreshing" on FeedListPage 0058 Connections { 0059 target: feed 0060 function onRefreshingChanged(refreshing) { 0061 if(!refreshing) 0062 page.refreshing = refreshing 0063 } 0064 } 0065 0066 actions: Kirigami.Action { 0067 id: searchActionButton 0068 icon.name: "search" 0069 text: i18nc("@action:intoolbar", "Search") 0070 checkable: true 0071 enabled: page.feed.entries ? true : false 0072 visible: enabled 0073 } 0074 0075 header: Loader { 0076 anchors.right: parent.right 0077 anchors.left: parent.left 0078 0079 active: searchActionButton.checked 0080 visible: active 0081 0082 sourceComponent: SearchBar { 0083 proxyModel: page.feed.entries ? page.feed.entries : emptyListModel 0084 parentKey: searchActionButton 0085 } 0086 } 0087 0088 ListModel { 0089 id: emptyListModel 0090 readonly property var filterType: AbstractEpisodeProxyModel.NoFilter 0091 } 0092 0093 GenericEntryListView { 0094 id: entryList 0095 reuseItems: true 0096 currentIndex: -1 0097 0098 model: page.feed.entries ? page.feed.entries : emptyListModel 0099 delegate: GenericEntryDelegate { 0100 listViewObject: entryList 0101 } 0102 0103 header: ColumnLayout { 0104 id: headerColumn 0105 height: (isSubscribed && entryList.count > 0) ? implicitHeight : entryList.height 0106 width: entryList.width 0107 spacing: 0 0108 0109 Kirigami.Theme.inherit: false 0110 Kirigami.Theme.colorSet: Kirigami.Theme.Window 0111 0112 GenericHeader { 0113 id: headerImage 0114 Layout.fillWidth: true 0115 0116 property string authors: isSubscribed ? feed.authors : feed.author 0117 0118 image: isSubscribed ? feed.cachedImage : feed.image 0119 title: isSubscribed ? feed.name : feed.title 0120 subtitle: authors ? i18nc("by <author(s)>", "by %1", authors) : undefined 0121 } 0122 0123 // header actions 0124 Controls.Control { 0125 Layout.fillWidth: true 0126 0127 leftPadding: Kirigami.Units.largeSpacing 0128 rightPadding: Kirigami.Units.largeSpacing 0129 bottomPadding: Kirigami.Units.smallSpacing 0130 topPadding: Kirigami.Units.smallSpacing 0131 0132 background: Rectangle { 0133 Kirigami.Theme.inherit: false 0134 Kirigami.Theme.colorSet: Kirigami.Theme.Header 0135 color: Kirigami.Theme.backgroundColor 0136 } 0137 0138 contentItem: Kirigami.ActionToolBar { 0139 id: feedToolBar 0140 alignment: Qt.AlignLeft 0141 background: Item {} 0142 0143 // HACK: ActionToolBar loads buttons dynamically, and so the 0144 // height calculation changes the position 0145 onHeightChanged: entryList.contentY = entryList.originY 0146 0147 actions: [ 0148 Kirigami.Action { 0149 visible: isSubscribed 0150 icon.name: "view-refresh" 0151 text: i18n("Refresh Podcast") 0152 onTriggered: page.refreshing = true 0153 }, 0154 Kirigami.Action { 0155 icon.name: "kt-add-feeds" 0156 text: enabled ? i18n("Subscribe") : i18n("Subscribed") 0157 enabled: !DataManager.feedExists(feed.url) 0158 visible: !isSubscribed 0159 onTriggered: { 0160 DataManager.addFeed(feed.url); 0161 enabled = false; 0162 // Also disable button on discoverpage 0163 if (subscribeAction !== undefined) { 0164 subscribeAction.enabled = false; 0165 } 0166 } 0167 }, 0168 Kirigami.Action { 0169 icon.name: "documentinfo" 0170 text: i18n("Show Details") 0171 checkable: true 0172 checked: showMoreInfo 0173 onCheckedChanged: { 0174 showMoreInfo = checked; 0175 } 0176 } 0177 ] 0178 0179 // add the default actions through onCompleted to add them 0180 // to the ones defined above 0181 Component.onCompleted: { 0182 if (isSubscribed) { 0183 for (var i in entryList.defaultActionList) { 0184 feedToolBar.actions.push(entryList.defaultActionList[i]); 0185 } 0186 } 0187 } 0188 } 0189 } 0190 0191 Kirigami.Separator { Layout.fillWidth: true } 0192 0193 // podcast description 0194 Controls.Control { 0195 Layout.fillHeight: !isSubscribed 0196 Layout.fillWidth: true 0197 leftPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing 0198 rightPadding: Kirigami.Units.largeSpacing + Kirigami.Units.smallSpacing 0199 topPadding: Kirigami.Units.largeSpacing 0200 bottomPadding: Kirigami.Units.largeSpacing 0201 0202 // HACK: opening more info changes the position of the header 0203 onHeightChanged: entryList.contentY = entryList.originY 0204 0205 background: Rectangle { 0206 color: Kirigami.Theme.backgroundColor 0207 } 0208 0209 contentItem: ColumnLayout { 0210 spacing: Kirigami.Units.smallSpacing 0211 0212 Controls.Label { 0213 Layout.fillWidth: true 0214 Layout.alignment: Qt.AlignTop 0215 textFormat: page.showMoreInfo ? TextEdit.RichText : Text.StyledText 0216 maximumLineCount: page.showMoreInfo ? undefined : 2 0217 elide: Text.ElideRight 0218 text: feed.description 0219 font.pointSize: Kirigami.Theme.defaultFont.pointSize 0220 wrapMode: Text.WordWrap 0221 color: Kirigami.Theme.textColor 0222 lineHeight: 1.2 0223 } 0224 0225 Item { 0226 Layout.fillWidth: true 0227 Layout.alignment: Qt.AlignTop 0228 Layout.preferredHeight: Math.max(feedUrlLayout.height, feedUrlCopyButton.width) 0229 visible: page.showMoreInfo 0230 height: visible ? implicitHeight : 0 0231 RowLayout { 0232 id: feedUrlLayout 0233 anchors.left: parent.left 0234 anchors.right: feedUrlCopyButton.left 0235 anchors.verticalCenter: parent.verticalCenter 0236 spacing: Kirigami.Units.smallSpacing 0237 TextEdit { 0238 Layout.alignment: Qt.AlignTop 0239 readOnly: true 0240 textFormat:TextEdit.RichText 0241 text: i18n("Podcast URL:") 0242 wrapMode: TextEdit.Wrap 0243 color: Kirigami.Theme.textColor 0244 } 0245 TextEdit { 0246 id: feedUrl 0247 Layout.alignment: Qt.AlignTop 0248 readOnly: true 0249 selectByMouse: !Kirigami.Settings.isMobile 0250 textFormat:TextEdit.RichText 0251 text: "<a href='%1'>%1</a>".arg(feed.url) 0252 wrapMode: TextEdit.Wrap 0253 Layout.fillWidth: true 0254 color: Kirigami.Theme.textColor 0255 } 0256 } 0257 Controls.Button { 0258 id: feedUrlCopyButton 0259 anchors.right: parent.right 0260 anchors.top: parent.top 0261 anchors.leftMargin: Kirigami.Units.smallSpacing 0262 icon.name: "edit-copy" 0263 0264 onClicked: { 0265 feedUrl.selectAll(); 0266 feedUrl.copy(); 0267 feedUrl.deselect(); 0268 } 0269 } 0270 } 0271 RowLayout { 0272 Layout.fillWidth: true 0273 Layout.alignment: Qt.AlignTop 0274 visible: page.showMoreInfo 0275 height: visible ? implicitHeight : 0 0276 spacing: Kirigami.Units.smallSpacing 0277 TextEdit { 0278 Layout.alignment: Qt.AlignTop 0279 readOnly: true 0280 textFormat: TextEdit.RichText 0281 text: i18n("Weblink:") 0282 wrapMode: TextEdit.Wrap 0283 color: Kirigami.Theme.textColor 0284 } 0285 0286 TextEdit { 0287 readOnly: true 0288 Layout.alignment: Qt.AlignTop 0289 selectByMouse: !Kirigami.Settings.isMobile 0290 textFormat:TextEdit.RichText 0291 text: "<a href='%1'>%1</a>".arg(feed.link) 0292 onLinkActivated: (link) => { 0293 Qt.openUrlExternally(link); 0294 } 0295 wrapMode: Text.WordWrap 0296 Layout.fillWidth: true 0297 color: Kirigami.Theme.textColor 0298 } 0299 } 0300 TextEdit { 0301 Layout.alignment: Qt.AlignTop 0302 Layout.fillWidth: true 0303 visible: isSubscribed && page.showMoreInfo 0304 height: visible ? implicitHeight : 0 0305 0306 readOnly: true 0307 selectByMouse: !Kirigami.Settings.isMobile 0308 textFormat:TextEdit.RichText 0309 text: isSubscribed ? i18n("Subscribed since: %1", feed.subscribed.toLocaleString(Qt.locale(), Locale.ShortFormat)) : "" 0310 wrapMode: Text.WordWrap 0311 color: Kirigami.Theme.textColor 0312 } 0313 TextEdit { 0314 Layout.alignment: Qt.AlignTop 0315 Layout.fillWidth: true 0316 visible: isSubscribed && page.showMoreInfo 0317 height: visible ? implicitHeight : 0 0318 0319 readOnly: true 0320 selectByMouse: !Kirigami.Settings.isMobile 0321 textFormat:TextEdit.RichText 0322 text: isSubscribed ? i18n("Last updated: %1", feed.lastUpdated.toLocaleString(Qt.locale(), Locale.ShortFormat)) : "" 0323 wrapMode: Text.WordWrap 0324 color: Kirigami.Theme.textColor 0325 } 0326 TextEdit { 0327 Layout.alignment: Qt.AlignTop 0328 Layout.fillWidth: true 0329 visible: isSubscribed && page.showMoreInfo 0330 height: visible ? implicitHeight : 0 0331 0332 readOnly: true 0333 selectByMouse: !Kirigami.Settings.isMobile 0334 textFormat:TextEdit.RichText 0335 text: i18np("1 Episode", "%1 Episodes", feed.entryCount) + ", " + i18np("1 Unplayed", "%1 Unplayed", feed.unreadEntryCount) 0336 wrapMode: Text.WordWrap 0337 color: Kirigami.Theme.textColor 0338 } 0339 0340 Item { Layout.fillHeight: true } 0341 } 0342 } 0343 0344 Kirigami.Separator { Layout.fillWidth: true } 0345 0346 Item { 0347 Layout.fillHeight: true 0348 Layout.fillWidth: true 0349 height: visible ? implicitHeight : 0 0350 visible: entryList.count === 0 && isSubscribed 0351 0352 Kirigami.PlaceholderMessage { 0353 anchors.centerIn: parent 0354 0355 width: Kirigami.Units.gridUnit * 20 0356 0357 text: feed.errorId === 0 ? i18n("No episodes available") : i18n("Error (%1): %2", feed.errorId, feed.errorString) 0358 icon.name: feed.errorId === 0 ? "" : "data-error" 0359 } 0360 } 0361 } 0362 0363 FilterInlineMessage { 0364 proxyModel: page.feed.entries ? page.feed.entries : emptyListModel 0365 } 0366 } 0367 }