Cleanup episode events, mark episodes as old, fresh episodes fix
This commit is contained in:
parent
8eebb09707
commit
0ff355737c
11 changed files with 126 additions and 93 deletions
|
@ -28,16 +28,13 @@ Python {
|
|||
property string progname: 'gpodder'
|
||||
property bool ready: false
|
||||
property bool refreshing: false
|
||||
signal downloading(int episode_id)
|
||||
signal downloadProgress(int episode_id, real progress)
|
||||
signal playbackProgress(int episode_id, real progress)
|
||||
signal downloaded(int episode_id)
|
||||
signal deleted(int episode_id)
|
||||
signal isNewChanged(int episode_id, bool is_new)
|
||||
signal stateChanged(int episode_id, int state)
|
||||
signal podcastListChanged()
|
||||
signal updatingPodcast(int podcast_id)
|
||||
signal updatedPodcast(var podcast)
|
||||
signal episodeListChanged(int podcast_id)
|
||||
signal updatedEpisode(var episode)
|
||||
|
||||
Component.onCompleted: {
|
||||
setHandler('hello', function (coreversion, uiversion) {
|
||||
|
@ -47,17 +44,14 @@ Python {
|
|||
console.log('Python ' + py.pythonVersion());
|
||||
});
|
||||
|
||||
setHandler('downloading', py.downloading);
|
||||
setHandler('download-progress', py.downloadProgress);
|
||||
setHandler('playback-progress', py.playbackProgress);
|
||||
setHandler('downloaded', py.downloaded);
|
||||
setHandler('deleted', py.deleted);
|
||||
setHandler('is-new-changed', py.isNewChanged);
|
||||
setHandler('state-changed', py.stateChanged);
|
||||
setHandler('podcast-list-changed', py.podcastListChanged);
|
||||
setHandler('updating-podcast', py.updatingPodcast);
|
||||
setHandler('updated-podcast', py.updatedPodcast);
|
||||
setHandler('refreshing', function(v) { py.refreshing = v; });
|
||||
setHandler('episode-list-changed', py.episodeListChanged);
|
||||
setHandler('updated-episode', py.updatedEpisode);
|
||||
|
||||
addImportPath(Qt.resolvedUrl('../..'));
|
||||
|
||||
|
|
|
@ -26,7 +26,22 @@ import 'constants.js' as Constants
|
|||
ListModel {
|
||||
id: episodeListModel
|
||||
|
||||
property var podcast_id
|
||||
|
||||
function loadEpisodes(podcast_id) {
|
||||
episodeListModel.podcast_id = podcast_id;
|
||||
reload();
|
||||
}
|
||||
|
||||
function loadFreshEpisodes(callback) {
|
||||
episodeListModel.podcast_id = -1;
|
||||
py.call('main.get_fresh_episodes', [], function (episodes) {
|
||||
Util.updateModelFrom(episodeListModel, episodes);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function reload() {
|
||||
py.call('main.load_episodes', [podcast_id], function (episodes) {
|
||||
Util.updateModelFrom(episodeListModel, episodes);
|
||||
});
|
||||
|
@ -43,21 +58,18 @@ ListModel {
|
|||
Util.updateModelWith(episodeListModel, 'id', episode_id,
|
||||
{'playbackProgress': progress});
|
||||
}
|
||||
onDownloaded: {
|
||||
Util.updateModelWith(episodeListModel, 'id', episode_id,
|
||||
{'progress': 0, 'downloadState': Constants.state.downloaded});
|
||||
}
|
||||
onDeleted: {
|
||||
Util.updateModelWith(episodeListModel, 'id', episode_id,
|
||||
{'downloadState': Constants.state.deleted, 'isNew': false});
|
||||
}
|
||||
onIsNewChanged: {
|
||||
Util.updateModelWith(episodeListModel, 'id', episode_id,
|
||||
{'isNew': is_new});
|
||||
}
|
||||
onStateChanged: {
|
||||
Util.updateModelWith(episodeListModel, 'id', episode_id,
|
||||
{'downloadState': state});
|
||||
onUpdatedEpisode: {
|
||||
for (var i=0; i<episodeListModel.count; i++) {
|
||||
if (episodeListModel.get(i).id == episode.id) {
|
||||
episodeListModel.set(i, episode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
onEpisodeListChanged: {
|
||||
if (episodeListModel.podcast_id == podcast_id) {
|
||||
episodeListModel.reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
61
main.py
61
main.py
|
@ -79,6 +79,11 @@ class gPotherSide:
|
|||
if podcast.id == podcast_id:
|
||||
return podcast
|
||||
|
||||
def _episode_state_changed(self, episode):
|
||||
pyotherside.send('updated-episode', self.convert_episode(episode))
|
||||
pyotherside.send('updated-podcast', self.convert_podcast(episode.parent))
|
||||
pyotherside.send('update-stats')
|
||||
|
||||
def get_stats(self):
|
||||
podcasts = self.core.model.get_podcasts()
|
||||
|
||||
|
@ -139,6 +144,8 @@ class gPotherSide:
|
|||
'downloadState': episode.state,
|
||||
'isNew': episode.is_new,
|
||||
'playbackProgress': self._get_playback_progress(episode),
|
||||
'published': util.format_date(episode.published),
|
||||
'hasShownotes': episode.description != '',
|
||||
}
|
||||
|
||||
def load_episodes(self, id):
|
||||
|
@ -151,6 +158,7 @@ class gPotherSide:
|
|||
_, _, new, _, _ = podcast.get_statistics()
|
||||
if new:
|
||||
summary.append({
|
||||
'title': podcast.title,
|
||||
'coverart': self._get_cover(podcast),
|
||||
'newEpisodes': new,
|
||||
})
|
||||
|
@ -158,16 +166,6 @@ class gPotherSide:
|
|||
summary.sort(key=lambda e: e['newEpisodes'], reverse=True)
|
||||
return summary[:int(count)]
|
||||
|
||||
def convert_fresh_episode(self, episode):
|
||||
return {
|
||||
'id': episode.id,
|
||||
'title': episode.title,
|
||||
'podcast': episode.channel.title,
|
||||
'published': util.format_date(episode.published),
|
||||
'progress': episode.download_progress(),
|
||||
'downloadState': episode.state,
|
||||
}
|
||||
|
||||
def get_fresh_episodes(self):
|
||||
fresh_episodes = []
|
||||
for podcast in self.core.model.get_podcasts():
|
||||
|
@ -176,7 +174,7 @@ class gPotherSide:
|
|||
fresh_episodes.append(episode)
|
||||
|
||||
fresh_episodes.sort(key=lambda e: e.published, reverse=True)
|
||||
return [self.convert_fresh_episode(e) for e in fresh_episodes]
|
||||
return [self.convert_episode(e) for e in fresh_episodes]
|
||||
|
||||
@run_in_background_thread
|
||||
def subscribe(self, url):
|
||||
|
@ -210,26 +208,23 @@ class gPotherSide:
|
|||
|
||||
@run_in_background_thread
|
||||
def download_episode(self, episode_id):
|
||||
def progress_callback(progress):
|
||||
pyotherside.send('download-progress', episode_id, progress)
|
||||
episode = self._get_episode_by_id(episode_id)
|
||||
if episode.state == gpodder.STATE_DOWNLOADED:
|
||||
return
|
||||
|
||||
pyotherside.send('downloading', episode_id)
|
||||
if episode.download(progress_callback):
|
||||
pyotherside.send('downloaded', episode_id)
|
||||
else:
|
||||
pyotherside.send('download-failed', episode_id)
|
||||
def progress_callback(progress):
|
||||
self._episode_state_changed(episode)
|
||||
|
||||
# TODO: Handle the case where there is already a DownloadTask
|
||||
episode.download(progress_callback)
|
||||
self.core.save()
|
||||
pyotherside.send('update-stats')
|
||||
self._episode_state_changed(episode)
|
||||
|
||||
def delete_episode(self, episode_id):
|
||||
episode = self._get_episode_by_id(episode_id)
|
||||
episode.delete()
|
||||
self.core.save()
|
||||
pyotherside.send('deleted', episode_id)
|
||||
pyotherside.send('update-stats')
|
||||
self._episode_state_changed(episode)
|
||||
|
||||
def toggle_new(self, episode_id):
|
||||
episode = self._get_episode_by_id(episode_id)
|
||||
|
@ -238,8 +233,25 @@ class gPotherSide:
|
|||
episode.state = gpodder.STATE_NORMAL
|
||||
episode.save()
|
||||
self.core.save()
|
||||
pyotherside.send('is-new-changed', episode_id, episode.is_new)
|
||||
pyotherside.send('state-changed', episode_id, episode.state)
|
||||
self._episode_state_changed(episode)
|
||||
|
||||
def mark_episodes_as_old(self, podcast_id):
|
||||
podcast = self._get_podcast_by_id(podcast_id)
|
||||
|
||||
any_changed = False
|
||||
for episode in podcast.episodes:
|
||||
if episode.is_new and episode.state == gpodder.STATE_NORMAL:
|
||||
any_changed = True
|
||||
episode.is_new = False
|
||||
episode.save()
|
||||
|
||||
if any_changed:
|
||||
pyotherside.send('episode-list-changed', podcast_id)
|
||||
pyotherside.send('updated-podcast', self.convert_podcast(podcast))
|
||||
pyotherside.send('update-stats')
|
||||
|
||||
self.core.save()
|
||||
|
||||
|
||||
@run_in_background_thread
|
||||
def check_for_episodes(self):
|
||||
|
@ -268,7 +280,7 @@ class gPotherSide:
|
|||
episode = self._get_episode_by_id(episode_id)
|
||||
episode.playback_mark()
|
||||
self.core.save()
|
||||
pyotherside.send('is-new-changed', episode_id, episode.is_new)
|
||||
self._episode_state_changed(episode)
|
||||
return {
|
||||
'title': episode.title,
|
||||
'podcast_title': episode.parent.title,
|
||||
|
@ -319,3 +331,4 @@ toggle_new = gpotherside.toggle_new
|
|||
rename_podcast = gpotherside.rename_podcast
|
||||
change_section = gpotherside.change_section
|
||||
report_playback_event = gpotherside.report_playback_event
|
||||
mark_episodes_as_old = gpotherside.mark_episodes_as_old
|
||||
|
|
|
@ -63,7 +63,7 @@ Item {
|
|||
text: 'Download'
|
||||
color: (episodeItem.isPlaying || progress > 0) ? titleLabel.color : Constants.colors.download
|
||||
icon: Icons.cloud_download
|
||||
visible: downloadState != Constants.state.downloaded
|
||||
enabled: downloadState != Constants.state.downloaded
|
||||
onClicked: {
|
||||
episodeList.selectedIndex = -1;
|
||||
py.call('main.download_episode', [id]);
|
||||
|
@ -74,7 +74,7 @@ Item {
|
|||
text: 'Delete'
|
||||
color: (episodeItem.isPlaying || progress > 0) ? titleLabel.color : Constants.colors.destructive
|
||||
icon: Icons.trash
|
||||
visible: downloadState != Constants.state.deleted
|
||||
enabled: downloadState != Constants.state.deleted
|
||||
onClicked: {
|
||||
var ctx = { py: py, id: id };
|
||||
pgst.showConfirmation('Delete episode', Icons.trash, function () {
|
||||
|
@ -96,6 +96,7 @@ Item {
|
|||
color: titleLabel.color
|
||||
icon: Icons.article
|
||||
onClicked: pgst.loadPage('EpisodeDetail.qml', {episode_id: id, title: title});
|
||||
enabled: hasShownotes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,8 +176,10 @@ Item {
|
|||
return Constants.colors.download;
|
||||
} else if (episodeItem.opened) {
|
||||
return Constants.colors.highlight;
|
||||
} else if (isNew) {
|
||||
} else if (isNew && downloadState == Constants.state.downloaded) {
|
||||
return Constants.colors.highlight;
|
||||
} else if (isNew) {
|
||||
return Constants.colors.fresh;
|
||||
} else {
|
||||
return Constants.colors.text;
|
||||
}
|
||||
|
@ -202,7 +205,7 @@ Item {
|
|||
}
|
||||
|
||||
visible: downloadState == Constants.state.downloaded
|
||||
icon: Icons.cd
|
||||
icon: Icons.folder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,16 @@ SlidePage {
|
|||
}
|
||||
}
|
||||
|
||||
PullMenuItem {
|
||||
text: 'Mark all as old'
|
||||
icon: Icons.eye
|
||||
color: Constants.colors.text
|
||||
onClicked: {
|
||||
py.call('main.mark_episodes_as_old', [episodesPage.podcast_id]);
|
||||
episodesPage.unPull();
|
||||
}
|
||||
}
|
||||
|
||||
PullMenuItem {
|
||||
text: 'Unsubscribe'
|
||||
icon: Icons.trash
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
import QtQuick 2.0
|
||||
|
||||
import 'common'
|
||||
import 'common/util.js' as Util
|
||||
|
||||
SlidePage {
|
||||
|
@ -27,8 +28,7 @@ SlidePage {
|
|||
property bool ready: false
|
||||
|
||||
Component.onCompleted: {
|
||||
py.call('main.get_fresh_episodes', [], function (episodes) {
|
||||
Util.updateModelFrom(freshEpisodesListModel, episodes);
|
||||
freshEpisodesListModel.loadFreshEpisodes(function () {
|
||||
freshEpisodes.ready = true;
|
||||
});
|
||||
}
|
||||
|
@ -39,33 +39,16 @@ SlidePage {
|
|||
}
|
||||
|
||||
PListView {
|
||||
id: freshEpisodesList
|
||||
id: episodeList
|
||||
property int selectedIndex: -1
|
||||
title: 'Fresh episodes'
|
||||
|
||||
model: ListModel { id: freshEpisodesListModel }
|
||||
model: GPodderEpisodeListModel { id: freshEpisodesListModel }
|
||||
|
||||
section.property: 'published'
|
||||
section.delegate: SectionHeader { text: section }
|
||||
|
||||
delegate: EpisodeItem {
|
||||
onClicked: py.call('main.download_episode', [id]);
|
||||
|
||||
Connections {
|
||||
target: py
|
||||
onDownloadProgress: {
|
||||
if (episode_id == id) {
|
||||
freshEpisodesListModel.setProperty(index, 'progress', progress);
|
||||
}
|
||||
}
|
||||
onDownloaded: {
|
||||
if (id == episode_id) {
|
||||
freshEpisodesListModel.remove(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//pgst.loadPage('EpisodeDetail.qml', {episode_id: id, title: title});
|
||||
}
|
||||
delegate: EpisodeItem { }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ ButtonArea {
|
|||
|
||||
property alias text: label.text
|
||||
property color color: Constants.colors.secondaryHighlight
|
||||
property color _real_color: enabled ? color : Constants.colors.placeholder
|
||||
property alias icon: icon.icon
|
||||
property alias size: icon.size
|
||||
property bool alwaysShowText: false
|
||||
|
@ -48,7 +49,7 @@ ButtonArea {
|
|||
id: label
|
||||
font.pixelSize: 15 * pgst.scalef
|
||||
visible: parent.pressed || parent.alwaysShowText
|
||||
color: parent.pressed ? Qt.darker(iconMenuItem.color, 1.1) : iconMenuItem.color
|
||||
color: parent.pressed ? Qt.darker(iconMenuItem._real_color, 1.1) : iconMenuItem._real_color
|
||||
|
||||
anchors {
|
||||
bottom: icon.top
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
import QtQuick 2.0
|
||||
|
||||
import 'common/constants.js' as Constants
|
||||
|
||||
ButtonArea {
|
||||
id: podcastItem
|
||||
|
||||
|
@ -58,12 +60,24 @@ ButtonArea {
|
|||
left: cover.right
|
||||
leftMargin: 10 * pgst.scalef
|
||||
rightMargin: 10 * pgst.scalef
|
||||
right: parent.right
|
||||
right: downloadsLabel.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
elide: Text.ElideRight
|
||||
text: title
|
||||
}
|
||||
color: newEpisodes ? Constants.colors.fresh : Constants.colors.text
|
||||
}
|
||||
|
||||
PLabel {
|
||||
id: downloadsLabel
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: 10 * pgst.scalef
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
text: downloaded ? downloaded : ''
|
||||
color: Constants.colors.text
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ SlidePage {
|
|||
|
||||
PullMenuItem {
|
||||
text: 'Refresh feeds'
|
||||
icon: Icons.reload
|
||||
icon: Icons.loop_alt2
|
||||
onClicked: {
|
||||
podcastsPage.unPull();
|
||||
py.call('main.check_for_episodes');
|
||||
|
|
|
@ -116,35 +116,35 @@ SlidePage {
|
|||
|
||||
StartPageButton {
|
||||
id: freshEpisodesPage
|
||||
enabled: freshEpisodesRepeater.count > 0
|
||||
|
||||
title: py.refreshing ? 'Refreshing feeds' : 'Fresh episodes'
|
||||
onClicked: pgst.loadPage('FreshEpisodes.qml');
|
||||
|
||||
Row {
|
||||
id: freshEpisodesRow
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 50 * pgst.scalef
|
||||
anchors.bottomMargin: 20 * pgst.scalef
|
||||
anchors.leftMargin: 20 * pgst.scalef
|
||||
anchors.left: parent.left
|
||||
spacing: 10 * pgst.scalef
|
||||
|
||||
PLabel {
|
||||
color: Constants.colors.placeholder
|
||||
text: 'No fresh episodes'
|
||||
visible: freshEpisodesRepeater.count == 0
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: freshEpisodesRepeater
|
||||
|
||||
Image {
|
||||
CoverArt {
|
||||
source: modelData.coverart
|
||||
sourceSize { width: 80 * pgst.scalef; height: 80 * pgst.scalef }
|
||||
text: modelData.title
|
||||
|
||||
width: 80 * pgst.scalef
|
||||
height: 80 * pgst.scalef
|
||||
|
||||
PLabel {
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: parent.bottom
|
||||
margins: 5 * pgst.scalef
|
||||
}
|
||||
|
||||
text: modelData.newEpisodes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ SlidePage {
|
|||
|
||||
PIcon {
|
||||
id: refresher
|
||||
icon: Icons.reload
|
||||
icon: Icons.loop_alt2
|
||||
color: Constants.colors.highlight
|
||||
|
||||
anchors {
|
||||
|
|
|
@ -13,3 +13,6 @@ var arrow_left = '\u2190';
|
|||
var arrow_right = '\u2192';
|
||||
var last = '\ue04d';
|
||||
var aperture = '\ue026';
|
||||
var eye = '\ue025';
|
||||
var loop_alt2 = '\ue033';
|
||||
var folder = '\ue065';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue