diff --git a/main.py b/main.py index 7bd6ec1..59f1fe2 100644 --- a/main.py +++ b/main.py @@ -368,6 +368,20 @@ class gPotherSide: if episode.total_time > 0: yield '%02d:%02d:%02d' % (episode.total_time / (60 * 60), (episode.total_time / 60) % 60, episode.total_time % 60) + def show_podcast(self, podcast_id): + podcast = self._get_podcast_by_id(podcast_id) + if podcast is None: + return {} + + return { + 'title': podcast.title, + 'description': util.remove_html_tags(podcast.description), + 'link': podcast.link, + 'url': podcast.url, + 'section': podcast.section, + 'coverart': self._get_cover(podcast), + } + def set_config_value(self, option, value): self.core.config.update_field(option, value) @@ -430,3 +444,4 @@ set_config_value = gpotherside.set_config_value get_config_value = gpotherside.get_config_value get_directory_providers = gpotherside.get_directory_providers get_directory_entries = gpotherside.get_directory_entries +show_podcast = gpotherside.show_podcast diff --git a/touch/EpisodeDetail.qml b/touch/EpisodeDetail.qml index 24a709e..4439d41 100644 --- a/touch/EpisodeDetail.qml +++ b/touch/EpisodeDetail.qml @@ -45,6 +45,7 @@ SlidePage { Component.onCompleted: { py.call('main.show_episode', [episode_id], function (episode) { + detailPage.title = episode.title; descriptionLabel.text = episode.description; metadataLabel.text = episode.metadata; detailPage.link = episode.link; diff --git a/touch/EpisodesPage.qml b/touch/EpisodesPage.qml index 72aaf13..c96b666 100644 --- a/touch/EpisodesPage.qml +++ b/touch/EpisodesPage.qml @@ -47,6 +47,12 @@ SlidePage { py.call('main.mark_episodes_as_old', [episodesPage.podcast_id]); }, }, + { + label: 'Podcast details', + callback: function () { + pgst.loadPage('PodcastDetail.qml', {podcast_id: podcast_id, title: title}); + } + }, { label: 'Unsubscribe', callback: function () { diff --git a/touch/PExpander.qml b/touch/PExpander.qml index da1d102..c849a1c 100644 --- a/touch/PExpander.qml +++ b/touch/PExpander.qml @@ -27,7 +27,7 @@ import 'common/util.js' as Util Item { id: expander - property bool expanded: false + property bool expanded: !canExpand property bool canExpand: expandedHeight > contractedHeight property real contractedHeight: 100 * pgst.scalef diff --git a/touch/PodcastDetail.qml b/touch/PodcastDetail.qml new file mode 100644 index 0000000..e1396b1 --- /dev/null +++ b/touch/PodcastDetail.qml @@ -0,0 +1,161 @@ + +/** + * + * gPodder QML UI Reference Implementation + * Copyright (c) 2014, Thomas Perl + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + */ + +import QtQuick 2.0 + +import 'common/constants.js' as Constants +import 'common/util.js' as Util +import 'icons/icons.js' as Icons + +SlidePage { + id: podcastDetail + + property int podcast_id + property string title + property string description + property string link + property string section + property string coverart + property string url + + property bool ready: false + + hasMenuButton: true + onMenuButtonClicked: { + pgst.showSelection([ + { + label: 'Visit website', + callback: function () { + Qt.openUrlExternally(podcastDetail.link); + } + }, + { + label: 'Copy feed URL', + callback: function () { + pgst.loadPage('TextInputDialog.qml', { + placeholderText: 'Feed URL', + text: podcastDetail.url, + }); + } + }, + { + label: 'Change section', + callback: function () { + var ctx = { py: py, id: podcastDetail.podcast_id }; + pgst.loadPage('TextInputDialog.qml', { + buttonText: 'Change section', + placeholderText: 'New section', + text: section, + callback: function (new_section) { + ctx.py.call('main.change_section', [ctx.id, new_section]); + } + }); + } + }, + ]); + } + + PBusyIndicator { + anchors.centerIn: parent + visible: !podcastDetail.ready + } + + Component.onCompleted: { + py.call('main.show_podcast', [podcast_id], function (podcast) { + podcastDetail.title = podcast.title; + podcastDetail.description = podcast.description; + podcastDetail.link = podcast.link; + podcastDetail.section = podcast.section; + podcastDetail.coverart = podcast.coverart; + podcastDetail.url = podcast.url; + podcastDetail.ready = true; + }); + } + + Flickable { + id: flickable + anchors.fill: parent + boundsBehavior: Flickable.StopAtBounds + + contentWidth: detailColumn.width + contentHeight: detailColumn.height + detailColumn.spacing + + Column { + id: detailColumn + + width: podcastDetail.width + spacing: Constants.layout.padding * pgst.scalef + + Item { height: Constants.layout.padding * pgst.scalef; width: parent.width } + + Column { + width: parent.width - 2 * Constants.layout.padding * pgst.scalef + anchors.horizontalCenter: parent.horizontalCenter + spacing: Constants.layout.padding * pgst.scalef + + PExpander { + width: parent.width + expandedHeight: coverImage.height + + Image { + id: coverImage + source: podcastDetail.coverart + fillMode: Image.PreserveAspectFit + width: parent.width + } + } + + PLabel { + text: podcastDetail.title + width: parent.width + wrapMode: Text.WordWrap + font.pixelSize: 35 * pgst.scalef + color: Constants.colors.highlight + } + + PLabel { + visible: text !== '' + text: podcastDetail.link + width: parent.width + wrapMode: Text.WordWrap + font.pixelSize: 20 * pgst.scalef + color: Constants.colors.placeholder + } + + PLabel { + text: 'Section: ' + podcastDetail.section + width: parent.width + wrapMode: Text.WordWrap + font.pixelSize: 20 * pgst.scalef + color: Constants.colors.placeholder + } + + PLabel { + text: podcastDetail.description + width: parent.width + font.pixelSize: 30 * pgst.scalef + wrapMode: Text.WordWrap + } + } + } + } + + PScrollDecorator { flickable: flickable } +} diff --git a/touch/PodcastsPage.qml b/touch/PodcastsPage.qml index e3cb824..aa97778 100644 --- a/touch/PodcastsPage.qml +++ b/touch/PodcastsPage.qml @@ -137,17 +137,9 @@ SlidePage { }, }, { - label: 'Change section', + label: 'Podcast details', callback: function () { - var ctx = { py: py, id: id }; - pgst.loadPage('TextInputDialog.qml', { - buttonText: 'Change section', - placeholderText: 'New section', - text: section, - callback: function (new_section) { - ctx.py.call('main.change_section', [ctx.id, new_section]); - } - }); + pgst.loadPage('PodcastDetail.qml', {podcast_id: id, title: title}); } }, ], title); diff --git a/touch/TextInputDialog.qml b/touch/TextInputDialog.qml index f4bb7a8..b5eb2b6 100644 --- a/touch/TextInputDialog.qml +++ b/touch/TextInputDialog.qml @@ -62,6 +62,7 @@ Dialog { id: button width: input.width height: input.height + visible: textInputDialog.buttonText !== '' PLabel { anchors.centerIn: parent