[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish.spec
|
|
[-]
[+]
|
Deleted |
_service:tar_git:harbour-org.gpodder.sailfish-4.0.0.tar.gz/gpodder-ui-qml/touch/FreshEpisodes.qml
^
|
@@ -1,54 +0,0 @@
-
-/**
- *
- * gPodder QML UI Reference Implementation
- * Copyright (c) 2013, Thomas Perl <m@thp.io>
- *
- * 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'
-import 'common/util.js' as Util
-
-SlidePage {
- id: freshEpisodes
- property bool ready: false
-
- Component.onCompleted: {
- freshEpisodesListModel.loadFreshEpisodes(function () {
- freshEpisodes.ready = true;
- });
- }
-
- PBusyIndicator {
- visible: !freshEpisodes.ready
- anchors.centerIn: parent
- }
-
- PListView {
- id: episodeList
- property int selectedIndex: -1
- title: 'Fresh episodes'
-
- model: GPodderEpisodeListModel { id: freshEpisodesListModel }
-
- section.property: 'published'
- section.delegate: SectionHeader { text: section }
-
- delegate: EpisodeItem { }
- }
-}
-
|
[-]
[+]
|
Deleted |
_service:tar_git:harbour-org.gpodder.sailfish-4.0.0.tar.gz/gpodder-ui-qml/touch/StartPage.qml
^
|
@@ -1,225 +0,0 @@
-
-/**
- *
- * gPodder QML UI Reference Implementation
- * Copyright (c) 2013, Thomas Perl <m@thp.io>
- *
- * 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 'icons/icons.js' as Icons
-import 'common/constants.js' as Constants
-import 'common/util.js' as Util
-
-SlidePage {
- id: startPage
- canClose: false
- hasPull: true
-
- PullMenu {
- PullMenuItem {
- text: 'Now Playing'
- color: Constants.colors.playback
- icon: Icons.play
- onClicked: {
- pgst.loadPage('PlayerPage.qml');
- startPage.unPull();
- }
- }
- }
-
- function update_stats() {
- py.call('main.get_stats', [], function (result) {
- stats.text = Util.format(
- '{podcasts} podcasts\n' +
- '{episodes} episodes\n' +
- '{newEpisodes} new episodes\n' +
- '{downloaded} downloaded',
- result);
- });
-
- py.call('main.get_fresh_episodes_summary', [3], function (episodes) {
- freshEpisodesRepeater.model = episodes;
- });
- }
-
- Item {
- Connections {
- target: py
- onUpdateStats: startPage.update_stats();
- }
- }
-
- Flickable {
- id: flickable
- boundsBehavior: Flickable.StopAtBounds
-
- Connections {
- target: py
- onReadyChanged: {
- if (py.ready) {
- startPage.update_stats();
- }
- }
- }
-
- anchors.fill: parent
-
- contentWidth: startPageColumn.width
- contentHeight: startPageColumn.height + startPageColumn.spacing
-
- Column {
- id: startPageColumn
-
- width: startPage.width
- spacing: 20 * pgst.scalef
-
- SlidePageHeader {
- title: 'gPodder'
- }
-
- StartPageButton {
- id: subscriptionsPane
-
- title: 'Subscriptions'
- onClicked: pgst.loadPage('PodcastsPage.qml');
-
- PLabel {
- id: stats
-
- anchors {
- verticalCenter: parent.verticalCenter
- left: parent.left
- margins: 20 * pgst.scalef
- }
- }
-
- ButtonArea {
- anchors {
- bottom: parent.bottom
- right: parent.right
- }
-
- transparent: true
- onClicked: pgst.loadPage('Subscribe.qml');
- width: subscriptions.width + 2*subscriptions.anchors.margins
- height: subscriptions.height + 2*subscriptions.anchors.margins
-
- PIcon {
- id: subscriptions
- icon: Icons.plus
- color: Constants.colors.download
-
- anchors {
- bottom: parent.bottom
- right: parent.right
- margins: 20 * pgst.scalef
- }
- }
- }
- }
-
- StartPageButton {
- id: freshEpisodes
- 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: 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
-
- CoverArt {
- source: modelData.coverart
- text: modelData.title
-
- width: 80 * pgst.scalef
- height: 80 * pgst.scalef
- }
- }
- }
-
- ButtonArea {
- id: refresherButtonArea
- visible: !py.refreshing
-
- anchors {
- bottom: parent.bottom
- right: parent.right
- }
-
- transparent: true
- onClicked: py.call('main.check_for_episodes');
- width: refresher.width + 2*refresher.anchors.margins
- height: refresher.height + 2*refresher.anchors.margins
-
- PIcon {
- id: refresher
- icon: Icons.loop_alt2
- color: Constants.colors.highlight
-
- anchors {
- bottom: parent.bottom
- right: parent.right
- margins: 20 * pgst.scalef
- }
- }
- }
- }
-
- Repeater {
- model: ListModel {
|
[-]
[+]
|
Deleted |
_service:tar_git:harbour-org.gpodder.sailfish-4.0.0.tar.gz/gpodder-ui-qml/touch/StartPageButton.qml
^
|
@@ -1,42 +0,0 @@
-
-/**
- *
- * gPodder QML UI Reference Implementation
- * Copyright (c) 2013, Thomas Perl <m@thp.io>
- *
- * 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
-
-ButtonArea {
- id: startPageButton
-
- property string title
-
- anchors.horizontalCenter: parent.horizontalCenter
- width: parent.width * .9
- height: 200 * pgst.scalef
-
- PLabel {
- anchors {
- right: parent.right
- top: parent.top
- margins: 20 * pgst.scalef
- }
-
- text: startPageButton.title
- }
-}
-
|
[-]
[+]
|
Deleted |
_service:tar_git:harbour-org.gpodder.sailfish-4.0.0.tar.gz/gpodder-ui-qml/touch/Subscribe.qml
^
|
@@ -1,69 +0,0 @@
-
-/**
- *
- * gPodder QML UI Reference Implementation
- * Copyright (c) 2013, Thomas Perl <m@thp.io>
- *
- * 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
-
-SlidePage {
- id: subscribe
-
- SlidePageHeader {
- title: 'Add subscription'
- color: Constants.colors.download
- }
-
- Column {
- anchors.centerIn: parent
- spacing: 30 * pgst.scalef
-
- PTextField {
- id: input
- width: subscribe.width *.8
- placeholderText: 'Feed URL'
- }
-
- ButtonArea {
- id: button
- width: input.width
- height: input.height
-
- PLabel {
- anchors.centerIn: parent
- text: 'Subscribe'
- }
-
- onClicked: {
- loading.visible = true;
- button.visible = false;
- input.visible = false;
- py.call('main.subscribe', [input.text], function () {
- subscribe.closePage();
- });
- }
- }
-
- PBusyIndicator {
- id: loading
- visible: false
- anchors.horizontalCenter: parent.horizontalCenter
- }
- }
-}
|
[-]
[+]
|
Deleted |
_service:tar_git:harbour-org.gpodder.sailfish-4.0.0.tar.gz/qml/FreshEpisodes.qml
^
|
@@ -1,67 +0,0 @@
-
-/**
- *
- * gPodder QML UI Reference Implementation
- * Copyright (c) 2013, Thomas Perl <m@thp.io>
- *
- * 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 Sailfish.Silica 1.0
-
-import 'common'
-import 'common/util.js' as Util
-
-Page {
- id: freshEpisodes
- property bool ready: false
-
- onStatusChanged: pgst.handlePageStatusChange(status)
-
- Component.onCompleted: {
- episodesListModel.loadFreshEpisodes(function () {
- freshEpisodes.ready = true;
- });
- }
-
- BusyIndicator {
- visible: !freshEpisodes.ready
- running: visible
- anchors.centerIn: parent
- }
-
- SilicaListView {
- id: freshEpisodesList
- anchors.fill: parent
-
- VerticalScrollDecorator { flickable: freshEpisodesList }
-
- header: PageHeader {
- title: 'Fresh episodes'
- }
-
- model: GPodderEpisodeListModel { id: episodesListModel }
-
- section.property: 'published'
- section.delegate: SectionHeader { text: section }
-
- delegate: EpisodeItem {}
-
- ViewPlaceholder {
- enabled: freshEpisodesList.count == 0 && freshEpisodes.ready
- text: 'No fresh episodes'
- }
- }
-}
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-core/share/man/man1/gpo.1
^
|
@@ -1,4 +1,4 @@
-.TH GPO "1" "March 2014" "gpodder 4.0.0" "User Commands"
+.TH GPO "1" "March 2014" "gpodder 4.1.0" "User Commands"
.SH NAME
gpo \- gPodder command-line interface
.SH SYNOPSIS
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-core/src/gpodder/__init__.py
^
|
@@ -50,9 +50,9 @@
# This metadata block gets parsed by setup.py - use single quotes only
__tagline__ = 'Media and podcast aggregator'
__author__ = 'Thomas Perl <thp@gpodder.org>'
-__version__ = '4.0.0'
-__date__ = '2014-02-14'
-__relname__ = 'Iffy Kiffy Izzy Oh'
+__version__ = '4.1.0'
+__date__ = '2014-03-29'
+__relname__ = 'Moombahcore'
__copyright__ = '© 2005-2014 Thomas Perl and the gPodder Team'
__license__ = 'ISC / GPLv3 or later'
__url__ = 'http://gpodder.org/'
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-core/src/gpodder/api.py
^
|
@@ -21,6 +21,7 @@
import gpodder.core
import gpodder.util
+import gpodder.query
class core:
@@ -32,3 +33,7 @@
normalize_feed_url = gpodder.util.normalize_feed_url
remove_html_tags = gpodder.util.remove_html_tags
format_date = gpodder.util.format_date
+
+
+class query:
+ EQL = gpodder.query.EQL
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-core/src/gpodder/storage.py
^
|
@@ -28,6 +28,7 @@
def __init__(self, filename):
self.filename = filename + '.jsondb'
self.sequence_lock = threading.Lock()
+ self.save_lock = threading.Lock()
self._data = {
'podcast': {},
@@ -88,7 +89,8 @@
def close(self):
"""Close and store outstanding changes"""
- with util.update_file_safely(self.filename) as filename:
- with gzip.open(filename, 'wb') as fp:
- data = bytes(json.dumps(self._data, separators=(',', ':')), 'utf-8')
- fp.write(data)
+ with self.save_lock:
+ with util.update_file_safely(self.filename) as filename:
+ with gzip.open(filename, 'wb') as fp:
+ data = bytes(json.dumps(self._data, separators=(',', ':')), 'utf-8')
+ fp.write(data)
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/common/GPodderEpisodeListModel.qml
^
|
@@ -26,24 +26,72 @@
ListModel {
id: episodeListModel
- property var podcast_id
+ property var podcast_id: -1
- function loadEpisodes(podcast_id) {
- episodeListModel.podcast_id = podcast_id;
- reload();
+ property var queries: ({
+ All: '',
+ Fresh: 'new or downloading',
+ Downloaded: 'downloaded or downloading',
+ UnplayedDownloads: 'downloaded and not played',
+ FinishedDownloads: 'downloaded and finished',
+ HideDeleted: 'not deleted',
+ Deleted: 'deleted',
+ ShortDownloads: 'downloaded and min > 0 and min < 10',
+ })
+
+ property var filters: ([
+ { label: 'All', query: episodeListModel.queries.All },
+ { label: 'Fresh', query: episodeListModel.queries.Fresh },
+ { label: 'Downloaded', query: episodeListModel.queries.Downloaded },
+ { label: 'Unplayed downloads', query: episodeListModel.queries.UnplayedDownloads },
+ { label: 'Finished downloads', query: episodeListModel.queries.FinishedDownloads },
+ { label: 'Hide deleted', query: episodeListModel.queries.HideDeleted },
+ { label: 'Deleted episodes', query: episodeListModel.queries.Deleted },
+ { label: 'Short downloads (< 10 min)', query: episodeListModel.queries.ShortDownloads },
+ ])
+
+ property bool ready: false
+ property int currentFilterIndex: -1
+ property string currentCustomQuery: queries.All
+
+ function setQuery(query) {
+ for (var i=0; i<filters.length; i++) {
+ if (filters[i].query === query) {
+ currentFilterIndex = i;
+ return;
+ }
+ }
+
+ currentFilterIndex = -1;
+ currentCustomQuery = query;
}
- function loadFreshEpisodes(callback) {
+ function loadAllEpisodes(callback) {
episodeListModel.podcast_id = -1;
- py.call('main.get_fresh_episodes', [], function (episodes) {
- Util.updateModelFrom(episodeListModel, episodes);
- callback();
- });
+ reload(callback);
+ }
+
+ function loadEpisodes(podcast_id, callback) {
+ episodeListModel.podcast_id = podcast_id;
+ reload(callback);
}
- function reload() {
- py.call('main.load_episodes', [podcast_id], function (episodes) {
+ function reload(callback) {
+ var query;
+
+ if (currentFilterIndex !== -1) {
+ query = filters[currentFilterIndex].query;
+ } else {
+ query = currentCustomQuery;
+ }
+
+ ready = false;
+ py.call('main.load_episodes', [podcast_id, query], function (episodes) {
Util.updateModelFrom(episodeListModel, episodes);
+ episodeListModel.ready = true;
+ if (callback !== undefined) {
+ callback();
+ }
});
}
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/common/constants.js
^
|
@@ -32,10 +32,17 @@
destructive: '#cf424f', /* destructive actions */
page: '#dddddd',
+ toolbar: '#d0d0d0',
+ dialog: '#dddddd',
+ dialogBackground: '#aa000000',
text: '#333333', /* text color */
+ dialogText: '#333333',
highlight: '#433b67',
+ dialogHighlight: '#433b67',
secondaryHighlight: '#605885',
area: '#cccccc',
+ dialogArea: '#d0d0d0',
+ toolbarArea: '#bbbbbb',
placeholder: '#666666',
//page: '#000000',
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/main.py
^
|
@@ -19,7 +19,7 @@
# of gpodder-core, but we might have a different release schedule later on. If
# we decide to have parallel releases, we can at least start using this version
# to check if the core version is compatible with the QML UI version.
-__version__ = '4.0.0'
+__version__ = '4.1.0'
import sys
import os
@@ -31,9 +31,12 @@
from gpodder.api import core
from gpodder.api import util
+from gpodder.api import query
import logging
import functools
+import time
+import datetime
logger = logging.getLogger(__name__)
@@ -55,6 +58,8 @@
class gPotherSide:
+ ALL_PODCASTS = -1
+
def __init__(self):
self.core = None
self._checking_for_new_episodes = False
@@ -138,6 +143,8 @@
return [self.convert_podcast(podcast) for podcast in podcasts]
def convert_episode(self, episode):
+ now = datetime.datetime.now()
+ tnow = time.time()
return {
'id': episode.id,
'title': episode.trimmed_title,
@@ -146,12 +153,42 @@
'isNew': episode.is_new,
'playbackProgress': self._get_playback_progress(episode),
'published': util.format_date(episode.published),
+ 'section': self._format_published_section(now, tnow, episode.published),
'hasShownotes': episode.description != '',
}
- def load_episodes(self, id):
- podcast = self._get_podcast_by_id(id)
- return [self.convert_episode(episode) for episode in podcast.episodes]
+ def _format_published_section(self, now, tnow, published):
+ diff = (tnow - published)
+
+ if diff < 60 * 60 * 24 * 7:
+ return util.format_date(published)
+
+ dt = datetime.datetime.fromtimestamp(published)
+ if dt.year == now.year:
+ return dt.strftime('%B %Y')
+
+ return dt.strftime('%Y')
+
+ def load_episodes(self, id=ALL_PODCASTS, eql=None):
+ if id is not None and id != self.ALL_PODCASTS:
+ podcasts = [self._get_podcast_by_id(id)]
+ else:
+ podcasts = self.core.model.get_podcasts()
+
+ if eql:
+ filter_func = query.EQL(eql).filter
+ else:
+ filter_func = lambda episodes: episodes
+
+ result = []
+
+ for podcast in podcasts:
+ result.extend(filter_func(podcast.episodes))
+
+ if id == self.ALL_PODCASTS:
+ result.sort(key=lambda e: e.published, reverse=True)
+
+ return [self.convert_episode(episode) for episode in result]
def get_fresh_episodes_summary(self, count):
summary = []
@@ -167,20 +204,19 @@
summary.sort(key=lambda e: e['newEpisodes'], reverse=True)
return summary[:int(count)]
- def get_fresh_episodes(self):
- fresh_episodes = []
- for podcast in self.core.model.get_podcasts():
- for episode in podcast.episodes:
- if episode.is_fresh():
- fresh_episodes.append(episode)
-
- fresh_episodes.sort(key=lambda e: e.published, reverse=True)
- return [self.convert_episode(e) for e in fresh_episodes]
-
@run_in_background_thread
def subscribe(self, url):
- url = util.normalize_feed_url(url)
+ url = self.core.model.normalize_feed_url(url)
# TODO: Check if subscription already exists
+
+ # Kludge: After one second, update the podcast list,
+ # so that we see the podcast that is being updated
+ @run_in_background_thread
+ def show_loading():
+ time.sleep(1)
+ pyotherside.send('podcast-list-changed')
+ show_loading()
+
self.core.model.load_podcast(url, create=True)
self.core.save()
pyotherside.send('podcast-list-changed')
@@ -307,8 +343,20 @@
return {
'title': episode.trimmed_title,
'description': util.remove_html_tags(episode.description),
+ 'metadata': ' | '.join(self._format_metadata(episode)),
+ 'link': episode.link if episode.link != episode.url else '',
}
+ def _format_metadata(self, episode):
+ if episode.published:
+ yield datetime.datetime.fromtimestamp(episode.published).strftime('%Y-%m-%d')
+
+ if episode.file_size > 0:
+ yield '%.2f MiB' % (episode.file_size / (1024 * 1024))
+
+ if episode.total_time > 0:
+ yield '%02d:%02d:%02d' % (episode.total_time / (60 * 60), (episode.total_time / 60) % 60, episode.total_time % 60)
+
gpotherside = gPotherSide()
pyotherside.atexit(gpotherside.atexit)
@@ -324,7 +372,6 @@
unsubscribe = gpotherside.unsubscribe
check_for_episodes = gpotherside.check_for_episodes
get_stats = gpotherside.get_stats
-get_fresh_episodes = gpotherside.get_fresh_episodes
get_fresh_episodes_summary = gpotherside.get_fresh_episodes_summary
download_episode = gpotherside.download_episode
delete_episode = gpotherside.delete_episode
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/makefile
^
|
@@ -1,5 +1,5 @@
PROJECT := gpodder-ui-qml
-VERSION := 4.0.0
+VERSION := 4.1.0
all:
@echo ""
@@ -13,7 +13,7 @@
git archive --format=tar --prefix=$(PROJECT)-$(VERSION)/ $(VERSION) | gzip >$@
clean:
- find . -name '__pycache__' -exec rm {} +
+ find . -name '__pycache__' -exec rm -rf {} +
distclean: clean
rm -rf dist
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/AboutPage.qml
^
|
@@ -20,6 +20,8 @@
import QtQuick 2.0
+import 'common/constants.js' as Constants
+
SlidePage {
id: aboutPage
@@ -35,33 +37,37 @@
id: detailColumn
width: aboutPage.width
- spacing: 5 * pgst.scalef
+ spacing: 15 * pgst.scalef
SlidePageHeader {
title: 'About gPodder'
}
- SectionHeader {
- text: 'How to use'
+ Column {
width: parent.width
- }
-
- PLabel {
- width: parent.width * .9
- font.pixelSize: 30 * pgst.scalef
- anchors.horizontalCenter: parent.horizontalCenter
- wrapMode: Text.WordWrap
- text: 'Swipe left on a page to reveal the menu for that page. Go back by swiping pages to the right.\n\nAdd subscriptions via their feed URL or use gpodder.net to search for podcasts.'
- }
- SectionHeader {
- text: 'More information'
- width: parent.width
+ PLabel {
+ width: parent.width * .95
+ font.pixelSize: 30 * pgst.scalef
+ anchors.horizontalCenter: parent.horizontalCenter
+ wrapMode: Text.WordWrap
+ text: 'gPodder ' + py.uiversion
+ color: Constants.colors.highlight
+ }
+
+ PLabel {
+ width: parent.width * .95
+ font.pixelSize: 20 * pgst.scalef
+ anchors.horizontalCenter: parent.horizontalCenter
+ wrapMode: Text.WordWrap
+ text: 'http://gpodder.org/'
+ color: Constants.colors.placeholder
+ }
}
PLabel {
- width: parent.width * .9
- font.pixelSize: 20 * pgst.scalef
+ width: parent.width * .95
+ font.pixelSize: 30 * pgst.scalef
anchors.horizontalCenter: parent.horizontalCenter
wrapMode: Text.WordWrap
text: [
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/ButtonArea.qml
^
|
@@ -26,6 +26,7 @@
id: mouseArea
property bool transparent: false
property bool canHighlight: true
+ property alias color: background.color
Rectangle {
id: background
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/Confirmation.qml
^
|
@@ -23,65 +23,81 @@
import 'common/constants.js' as Constants
import 'icons/icons.js' as Icons
-SlidePage {
+Dialog {
id: confirmation
property alias title: header.title
- property alias icon: icon.icon
+ property alias description: description.text
+ property alias affirmativeAction: affirmativeButton.text
+ property alias negativeAction: negativeButton.text
+
+ property string icon
property alias color: header.color
property var callback: undefined
- SlidePageHeader {
- id: header
- color: Constants.colors.destructive
- title: 'Confirmation'
- }
+ contentHeight: contentColumn.height
- PIcon {
- id: icon
- size: 300
- anchors.centerIn: parent
- color: header.color
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- if (confirmation.callback !== undefined) {
- confirmation.callback();
- confirmation.closePage();
- }
- }
+ Column {
+ id: contentColumn
+ width: parent.width
+
+ SlidePageHeader {
+ id: header
+ color: Constants.colors.destructive
+ title: 'Confirmation'
}
- }
- PLabel {
- anchors {
- horizontalCenter: parent.horizontalCenter
- top: icon.bottom
- margins: 30 * pgst.scalef
- }
+ PLabel {
+ id: description
- text: 'Tap to confirm'
- color: header.color
- }
+ width: parent.width - 30 * pgst.scalef
+ anchors.horizontalCenter: parent.horizontalCenter
+ wrapMode: Text.WordWrap
- Row {
- anchors {
- horizontalCenter: parent.horizontalCenter
- bottom: parent.bottom
- margins: 60 * pgst.scalef
+ visible: text
}
- spacing: 30 * pgst.scalef
+ Item { width: parent.width; height: 10 * pgst.scalef }
- PLabel {
- text: 'Swipe right to cancel'
- color: Constants.colors.text
- }
+ Row {
+ width: parent.width - 30 * pgst.scalef
+ height: 80 * pgst.scalef
+ spacing: 30 * pgst.scalef
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ ConfirmationButton {
+ id: affirmativeButton
+
+ width: (parent.width - parent.spacing) * 2 / 3
+ height: parent.height
+
+ text: 'Yes'
+ icon: confirmation.icon
+ contentColor: header.color
+
+ onClicked: {
+ if (confirmation.callback !== undefined) {
+ confirmation.callback();
+ confirmation.closePage();
+ }
+ }
+ }
+
+ ConfirmationButton {
+ id: negativeButton
+
+ width: (parent.width - parent.spacing) * 1 / 3
+ height: parent.height
- PIcon {
- color: Constants.colors.text
- icon: Icons.arrow_right
+ text: 'Cancel'
+ contentColor: Constants.colors.placeholder
+
+ onClicked: {
+ confirmation.closePage();
+ }
+ }
}
+
+ Item { width: parent.width; height: 30 * pgst.scalef }
}
}
|
[-]
[+]
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/ConfirmationButton.qml
^
|
@@ -0,0 +1,48 @@
+
+/**
+ *
+ * gPodder QML UI Reference Implementation
+ * Copyright (c) 2014, Thomas Perl <m@thp.io>
+ *
+ * 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
+
+ButtonArea {
+ id: confirmationButton
+
+ property alias text: label.text
+ property alias icon: icon.icon
+ property color contentColor: Constants.colors.highlight
+
+ Row {
+ anchors.centerIn: parent
+ spacing: 5 * pgst.scalef
+
+ PIcon {
+ id: icon
+ anchors.verticalCenter: parent.verticalCenter
+ color: confirmationButton.contentColor
+ }
+
+ PLabel {
+ id: label
+ anchors.verticalCenter: parent.verticalCenter
+ color: confirmationButton.contentColor
+ }
+ }
+}
|
[-]
[+]
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/Dialog.qml
^
|
@@ -0,0 +1,73 @@
+
+/**
+ *
+ * gPodder QML UI Reference Implementation
+ * Copyright (c) 2014, Thomas Perl <m@thp.io>
+ *
+ * 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
+
+Rectangle {
+ id: page
+ z: 200
+
+ color: Constants.colors.dialogBackground
+
+ Component.onCompleted: pgst.dialogsVisible = pgst.dialogsVisible + 1;
+ Component.onDestruction: pgst.dialogsVisible = pgst.dialogsVisible - 1;
+
+ default property alias children: contents.children
+ property bool isDialog: true
+ property int contentHeight: -1
+ property bool fullWidth: false
+
+ function closePage() {
+ stacking.startFadeOut();
+ }
+
+ onXChanged: pgst.update(page, x)
+
+ width: parent.width
+ height: parent.height
+
+ DialogStacking { id: stacking }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: page.closePage();
+ }
+
+ MouseArea {
+ // Tapping on the dialog contents should do nothing
+ anchors.fill: contents
+ }
+
+ Rectangle {
+ id: contents
+ property int border: parent.width * 0.1
+ width: parent.fullWidth ? parent.width : (parent.width - 2 * border)
+ property int maxHeight: parent.height - toolbar.height
+ height: ((page.contentHeight > 0 && page.contentHeight < maxHeight) ? page.contentHeight : maxHeight) * parent.opacity
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: parent.top
+ }
+ color: Constants.colors.dialog
+ clip: true
+ }
+}
|
[-]
[+]
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/DialogStacking.qml
^
|
@@ -0,0 +1,70 @@
+
+/**
+ *
+ * gPodder QML UI Reference Implementation
+ * Copyright (c) 2013, Thomas Perl <m@thp.io>
+ *
+ * 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
+
+Item {
+ id: stacking
+ property variant page: parent
+
+ PropertyAnimation {
+ id: fadeIn
+ target: stacking.page
+ property: 'opacity'
+ to: 1
+ duration: 500
+ easing.type: Easing.OutCubic
+
+ onStopped: {
+ pgst.loadPageInProgress = false;
+ }
+ }
+
+ PropertyAnimation {
+ id: fadeOut
+ target: stacking.page
+ property: 'opacity'
+ to: 0
+ duration: 500
+ easing.type: Easing.OutCubic
+ }
+
+ function startFadeOut() {
+ fadeOut.start();
+ page.destroy(500);
+ }
+
+ function fadeInAgain() {
+ fadeIn.start();
+ }
+
+ function stopAllAnimations() {
+ fadeIn.stop();
+ }
+
+ Component.onCompleted: {
+ if (pgst.loadPageInProgress) {
+ page.x = 0;
+ page.opacity = 0;
+ fadeIn.start();
+ }
+ }
+}
+
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/Directory.qml
^
|
@@ -25,10 +25,20 @@
SlidePage {
id: directory
+ function search(text) {
+ loading.visible = true;
+ directorySearchModel.search(text, function() {
+ loading.visible = false;
+ });
+ }
+
ListView {
+ id: listView
+
anchors.fill: parent
boundsBehavior: Flickable.StopAtBounds
- PScrollDecorator {}
+
+ PScrollDecorator { flickable: listView }
model: GPodderDirectorySearchModel { id: directorySearchModel }
@@ -53,6 +63,7 @@
id: input
width: parent.width
placeholderText: 'Search term'
+ onAccepted: directory.search(input.text);
}
ButtonArea {
@@ -65,12 +76,7 @@
text: 'Search'
}
- onClicked: {
- loading.visible = true;
- directorySearchModel.search(input.text, function() {
- loading.visible = false;
- });
- }
+ onClicked: directory.search(input.text);
}
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/Dragging.qml
^
|
@@ -24,16 +24,14 @@
id: dragging
property Item stacking
- property bool hasPull: false
property bool canClose: true
- signal pulled
anchors.fill: parent
drag {
target: parent
axis: Drag.XAxis
- minimumX: dragging.hasPull ? (-parent.width/4) : 0
+ minimumX: 0
maximumX: canClose ? parent.width : 0
filterChildren: true
}
@@ -46,10 +44,7 @@
if (pressed) {
dragging.stacking.stopAllAnimations();
} else {
- if (hasPull && parent.x < -parent.width / 4 + 10) {
- pulled();
- parent.x = -parent.width / 4;
- } else if (parent.x > parent.width / 3) {
+ if (parent.x > parent.width / 3) {
dragging.stacking.startFadeOut();
} else {
dragging.stacking.fadeInAgain();
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/EpisodeDetail.qml
^
|
@@ -20,16 +20,33 @@
import QtQuick 2.0
+import 'common/constants.js' as Constants
+import 'icons/icons.js' as Icons
+
SlidePage {
id: detailPage
property int episode_id
property string title
+ property string link
+ property bool ready: false
+
+ hasMenuButton: detailPage.link != ''
+ menuButtonIcon: Icons.link
+ menuButtonLabel: 'Website'
+ onMenuButtonClicked: Qt.openUrlExternally(detailPage.link)
+
+ PBusyIndicator {
+ anchors.centerIn: parent
+ visible: !detailPage.ready
+ }
Component.onCompleted: {
- label.text = 'Loading...';
py.call('main.show_episode', [episode_id], function (episode) {
- label.text = episode.description;
+ descriptionLabel.text = episode.description;
+ metadataLabel.text = episode.metadata;
+ detailPage.link = episode.link;
+ detailPage.ready = true;
});
}
@@ -47,17 +64,36 @@
width: detailPage.width
spacing: 10 * pgst.scalef
- SlidePageHeader {
- title: detailPage.title
- }
-
- PLabel {
- id: label
- width: parent.width * .8
- font.pixelSize: 30 * pgst.scalef
+ Item { height: 20 * pgst.scalef; width: parent.width }
+
+ Column {
+ width: parent.width - 2 * 30 * pgst.scalef
anchors.horizontalCenter: parent.horizontalCenter
- wrapMode: Text.WordWrap
- }
+ spacing: 10 * pgst.scalef
+
+ PLabel {
+ text: detailPage.title
+ width: parent.width
+ wrapMode: Text.WordWrap
+ font.pixelSize: 35 * pgst.scalef
+ color: Constants.colors.highlight
+ }
+
+ PLabel {
+ id: metadataLabel
+ width: parent.width
+ wrapMode: Text.WordWrap
+ font.pixelSize: 20 * pgst.scalef
+ color: Constants.colors.placeholder
+ }
+
+ PLabel {
+ id: descriptionLabel
+ width: parent.width
+ font.pixelSize: 30 * pgst.scalef
+ wrapMode: Text.WordWrap
+ }
+ }
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/EpisodeItem.qml
^
|
@@ -77,7 +77,7 @@
enabled: downloadState != Constants.state.deleted
onClicked: {
var ctx = { py: py, id: id };
- pgst.showConfirmation('Delete episode', Icons.trash, function () {
+ pgst.showConfirmation(title, 'Delete', 'Cancel', 'Delete this episode?', Icons.trash, function () {
ctx.py.call('main.delete_episode', [ctx.id]);
});
}
|
[-]
[+]
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/EpisodeListView.qml
^
|
@@ -0,0 +1,53 @@
+
+/**
+ *
+ * gPodder QML UI Reference Implementation
+ * Copyright (c) 2013, 2014, Thomas Perl <m@thp.io>
+ *
+ * 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'
+
+
+PListView {
+ id: episodeList
+
+ property int selectedIndex: -1
+
+ PScrollIntoView { id: scrollIntoView }
+
+ onSelectedIndexChanged: {
+ if (selectedIndex === count - 1) {
+ scrollIntoView.begin(episodeList);
+ }
+ }
+
+ model: GPodderEpisodeListModel { id: episodeListModel }
+
+ PBusyIndicator {
+ visible: !episodeListModel.ready
+ anchors.centerIn: parent
+ }
+
+ PPlaceholder {
+ // TODO: If filter is "all", say "No episodes"
+ text: 'No episodes found'
+ visible: episodeList.count === 0 && episodeListModel.ready
+ }
+
+ delegate: EpisodeItem { }
+}
|
[-]
[+]
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/EpisodeQueryControl.qml
^
|
@@ -0,0 +1,47 @@
+
+/**
+ *
+ * gPodder QML UI Reference Implementation
+ * Copyright (c) 2014, Thomas Perl <m@thp.io>
+ *
+ * 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
+
+Item {
+ id: episodeQueryControl
+
+ property var model
+ property string title
+ property string currentFilter: model.filters[model.currentFilterIndex].label
+
+ function showSelectionDialog() {
+ pgst.loadPage('SelectionDialog.qml', {
+ title: episodeQueryControl.title,
+ callback: function (index, result) {
+ episodeQueryControl.model.currentFilterIndex = index;
+ episodeQueryControl.model.reload();
+ },
+ items: function () {
+ var labels = [];
+ for (var i in episodeQueryControl.model.filters) {
+ labels.push(episodeQueryControl.model.filters[i].label);
+ }
+ return labels;
+ }(),
+ selectedIndex: episodeQueryControl.model.currentFilterIndex,
+ });
+ }
+}
|
[-]
[+]
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/EpisodeQueryPage.qml
^
|
@@ -0,0 +1,54 @@
+
+/**
+ *
+ * gPodder QML UI Reference Implementation
+ * Copyright (c) 2013, Thomas Perl <m@thp.io>
+ *
+ * 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'
+import 'common/util.js' as Util
+import 'common/constants.js' as Constants
+import 'icons/icons.js' as Icons
+
+SlidePage {
+ id: allEpisodesPage
+
+ hasMenuButton: true
+ menuButtonIcon: Icons.magnifying_glass
+ menuButtonLabel: 'Filter'
+ onMenuButtonClicked: queryControl.showSelectionDialog()
+
+ EpisodeQueryControl {
+ id: queryControl
+ model: episodeList.model
+ title: 'Select filter'
+ }
+
+ Component.onCompleted: {
+ episodeList.model.setQuery(episodeList.model.queries.Fresh);
+ episodeList.model.reload();
+ }
+
+ EpisodeListView {
+ id: episodeList
+ title: 'Episodes'
+
+ section.property: 'section'
+ section.delegate: SectionHeader { text: section }
+ }
+}
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/EpisodesPage.qml
^
|
@@ -28,65 +28,53 @@
SlidePage {
id: episodesPage
- hasPull: true
-
property int podcast_id
property string title
- width: parent.width
- height: parent.height
+ hasMenuButton: true
+ menuButtonLabel: 'Settings'
+ onMenuButtonClicked: {
+ pgst.showSelection([
+ {
+ label: 'Filter list (' + queryControl.currentFilter + ')',
+ callback: function () {
+ queryControl.showSelectionDialog();
+ }
+ },
+ {
+ label: 'Mark episodes as old',
+ callback: function () {
+ py.call('main.mark_episodes_as_old', [episodesPage.podcast_id]);
+ },
+ },
+ {
+ label: 'Unsubscribe',
+ callback: function () {
+ var ctx = { py: py, id: episodesPage.podcast_id, page: episodesPage };
+ pgst.showConfirmation(title, 'Unsubscribe', 'Cancel', 'Remove this podcast and all downloaded episodes?', Icons.trash, function () {
+ ctx.py.call('main.unsubscribe', [ctx.id]);
+ ctx.page.closePage();
+ });
+ },
+ },
+ ]);
+ }
+
- Component.onCompleted: episodeListModel.loadEpisodes(podcast_id);
+ Component.onCompleted: {
+ episodeList.model.podcast_id = podcast_id;
+ episodeList.model.setQuery(episodeList.model.queries.All);
+ episodeList.model.reload();
+ }
- PullMenu {
- PullMenuItem {
- text: 'Now Playing'
- icon: Icons.play
- color: Constants.colors.playback
- onClicked: {
- pgst.loadPage('PlayerPage.qml');
- episodesPage.unPull();
- }
- }
-
- 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
- color: Constants.colors.destructive
- onClicked: {
- episodesPage.unPull();
-
- var ctx = { py: py, id: episodesPage.podcast_id, page: episodesPage };
- pgst.showConfirmation('Unsubscribe', Icons.trash, function () {
- ctx.py.call('main.unsubscribe', [ctx.id]);
- ctx.page.closePage();
- });
- }
- }
+ EpisodeQueryControl {
+ id: queryControl
+ model: episodeList.model
+ title: 'Select filter'
}
- PListView {
+ EpisodeListView {
id: episodeList
- property int selectedIndex: -1
title: episodesPage.title
- model: GPodderEpisodeListModel { id: episodeListModel }
-
- PPlaceholder {
- text: 'No episodes'
- visible: episodeList.count === 0
- }
-
- delegate: EpisodeItem { }
}
}
-
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/Main.qml
^
|
@@ -21,6 +21,9 @@
import QtQuick 2.0
import 'common'
+import 'common/constants.js' as Constants
+import 'icons/icons.js' as Icons
+
Item {
id: pgst
@@ -29,7 +32,9 @@
GPodderPodcastListModel { id: podcastListModel }
- property real scalef: width / 480
+ property real scalef: (width < height) ? (width / 480) : (height / 480)
+ property int shorterSide: (width < height) ? width : height
+ property int dialogsVisible: 0
anchors.fill: parent
@@ -42,20 +47,70 @@
}
}
- children[index-1].opacity = x / width;
+ if (page.isDialog) {
+ children[index-1].opacity = 1;
+ } else {
+ children[index-1].opacity = x / width;
+ }
+
//children[index-1].pushPhase = x / width;
}
property bool loadPageInProgress: false
+ property bool hasBackButton: false
+ property int bottomSpacing: toolbar.showing ? toolbar.height+toolbar.anchors.bottomMargin : 0
+
+ property bool hasMenuButton: false
+ property string menuButtonLabel: ''
+ property string menuButtonIcon: ''
+
+ function topOfStackChanged(offset) {
+ if (offset === undefined) {
+ offset = 0;
+ }
+
+ var page = children[children.length+offset-1];
+
+ // TODO: Maybe make these property bindings instead
+ pgst.hasBackButton = (!page.isDialog && page.canClose);
+ pgst.hasMenuButton = page.hasMenuButton;
+ if (pgst.hasMenuButton) {
+ pgst.menuButtonLabel = page.menuButtonLabel;
+ pgst.menuButtonIcon = page.menuButtonIcon;
+ } else {
+ pgst.menuButtonLabel = 'Menu';
+ pgst.menuButtonIcon = Icons.vellipsis;
+ }
+ }
- function showConfirmation(title, icon, callback) {
+ function showConfirmation(title, affirmative, negative, description, icon, callback) {
loadPage('Confirmation.qml', {
title: title,
+ affirmativeAction: affirmative,
+ negativeAction: negative,
+ description: description,
icon: icon,
callback: callback,
});
}
+ function showSelection(items, title, selectedIndex) {
+ loadPage('SelectionDialog.qml', {
+ title: title,
+ callback: function (index, item) {
+ items[index].callback();
+ },
+ items: function() {
+ var result = [];
+ for (var i in items) {
+ result.push(items[i].label);
+ }
+ return result;
+ }(),
+ selectedIndex: selectedIndex,
+ });
+ }
+
function loadPage(filename, properties) {
if (pgst.loadPageInProgress) {
console.log('ignoring loadPage request while load in progress');
@@ -81,8 +136,70 @@
visible: !py.ready
}
- StartPage {
- id: startPage
+ Image {
+ z: 101
+ anchors {
+ left: parent.left
+ right: parent.right
+ bottom: toolbar.top
+ }
+
+ source: 'images/toolbarshadow.png'
+ opacity: .1
+ height: 10 * pgst.scalef
+ visible: toolbar.showing
+ }
+
+ PToolbar {
+ id: toolbar
+ z: 102
+
+ Row {
+ anchors {
+ verticalCenter: parent.verticalCenter
+ left: parent.left
+ }
+
+ PToolbarButton {
+ id: backButton
+
+ text: 'Back'
+ icon: Icons.arrow_left
+
+ enabled: pgst.hasBackButton
+ onClicked: pgst.children[pgst.children.length-1].closePage();
+ }
+ }
+
+ Row {
+ anchors {
+ verticalCenter: parent.verticalCenter
+ right: parent.right
+ }
+
+ PToolbarButton {
+ id: throbber
+
+ text: 'Now Playing'
+ icon: Icons.play
+
+ enabled: player.episode != 0
+ onClicked: loadPage('PlayerPage.qml');
+ }
+
+ PToolbarButton {
+ id: menuButton
+
+ text: pgst.menuButtonLabel
+ icon: pgst.menuButtonIcon
+
+ enabled: pgst.hasMenuButton
+ onClicked: pgst.children[pgst.children.length-1].menuButtonClicked()
+ }
+ }
+ }
+
+ PodcastsPage {
visible: py.ready
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/PListView.qml
^
|
@@ -29,7 +29,11 @@
property real pushPhase: 0
boundsBehavior: Flickable.StopAtBounds
- header: SlidePageHeader { title: pListView.title }
+
+ header: SlidePageHeader {
+ id: header
+ title: pListView.title
+ }
PScrollDecorator { flickable: pListView }
}
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/PPlaceholder.qml
^
|
@@ -26,5 +26,5 @@
PLabel {
anchors.centerIn: parent
font.pixelSize: 40 * pgst.scalef
- color: Constants.colors.text
+ color: Constants.colors.placeholder
}
|
[-]
[+]
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/PScrollIntoView.qml
^
|
@@ -0,0 +1,54 @@
+
+/**
+ *
+ * gPodder QML UI Reference Implementation
+ * Copyright (c) 2014, Thomas Perl <m@thp.io>
+ *
+ * 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
+
+
+Timer {
+ id: scrollTimer
+ interval: 10
+ repeat: true
+
+ function begin(flickable_) {
+ flickable = flickable_;
+ lastHeight = flickable.contentHeight;
+ repeatLimit = defaultRepeatLimit;
+ scrollTimer.start();
+ }
+
+ property var flickable
+ property int defaultRepeatLimit: 10
+ property int repeatLimit: defaultRepeatLimit
+ property real lastHeight: 0
+
+ onTriggered: {
+ flickable.contentY = flickable.contentHeight - flickable.height;
+ flickable.returnToBounds();
+
+ repeatLimit = repeatLimit - 1;
+ lastHeight = flickable.contentHeight;
+
+ if (repeatLimit <= 0 && lastHeight === flickable.contentHeight) {
+ stop();
+ }
+ }
+}
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/PTextField.qml
^
|
@@ -21,33 +21,89 @@
import QtQuick 2.0
import 'common/constants.js' as Constants
+import 'icons/icons.js' as Icons
Item {
id: textField
property alias text: textInput.text
property string placeholderText: ''
+ signal accepted
+
+ function paste() {
+ textInput.paste();
+ }
height: 50 * pgst.scalef
TextInput {
+ id: textInput
anchors {
- fill: parent
+ verticalCenter: parent.verticalCenter
+ left: parent.left
+ right: clipboardIcon.left
margins: 5 * pgst.scalef
}
color: Constants.colors.text
selectionColor: Constants.colors.background
- id: textInput
- font.pixelSize: height
+ font.pixelSize: parent.height * 0.7
font.family: placeholder.font.family
+ focus: true
+ onAccepted: textField.accepted()
}
PLabel {
id: placeholder
anchors.fill: textInput
- visible: !textInput.focus && (textInput.text == '')
+ visible: (textInput.text == '')
text: textField.placeholderText
color: Constants.colors.placeholder
font.pixelSize: textInput.font.pixelSize
}
+
+ IconMenuItem {
+ id: clipboardIcon
+
+ anchors {
+ right: parent.right
+ margins: 5 * pgst.scalef
+ verticalCenter: parent.verticalCenter
+ }
+
+ icon: Icons.paperclip
+ onClicked: {
+ pgst.showSelection([
+ {
+ label: 'Copy',
+ callback: function () {
+ textInput.copy();
+ }
+ },
+ {
+ label: 'Paste',
+ callback: function() {
+ textInput.paste();
+ }
+ },
+ {
+ label: 'Cut',
+ callback: function() {
+ textInput.cut();
+ }
+ },
+ {
+ label: 'Clear',
+ callback: function() {
+ textInput.text = '';
+ }
+ },
+ {
+ label: 'Select all',
+ callback: function() {
+ textInput.selectAll();
+ }
+ }
+ ]);
+ }
+ }
}
|
[-]
[+]
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/PToolbar.qml
^
|
@@ -0,0 +1,48 @@
+
+/**
+ *
+ * gPodder QML UI Reference Implementation
+ * Copyright (c) 2014, Thomas Perl <m@thp.io>
+ *
+ * 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'
+
+import 'common/constants.js' as Constants
+import 'icons/icons.js' as Icons
+
+Rectangle {
+ id: toolbar
+ property bool showing: true
+
+ color: Constants.colors.toolbar
+
+ height: 80 * pgst.scalef
+
+ MouseArea {
+ // Capture all touch events
+ anchors.fill: parent
+ }
+
+ anchors {
+ left: parent.left
+ right: parent.right
+ bottom: parent.bottom
+ bottomMargin: toolbar.showing ? 0 : -height
+ }
+
+ Behavior on anchors.bottomMargin { PropertyAnimation { duration: 100 } }
+}
|
[-]
[+]
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/PToolbarButton.qml
^
|
@@ -0,0 +1,59 @@
+
+/**
+ *
+ * gPodder QML UI Reference Implementation
+ * Copyright (c) 2014, Thomas Perl <m@thp.io>
+ *
+ * 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'
+
+import 'common/constants.js' as Constants
+import 'icons/icons.js' as Icons
+
+Rectangle {
+ id: toolbarButton
+
+ //property alias color: iconMenuItem.color
+ //property alias text: iconMenuItem.text
+ property string text: ''
+ property alias icon: iconMenuItem.icon
+
+ signal clicked()
+
+ width: iconMenuItem.width
+ height: iconMenuItem.height
+ color: iconMenuItem.pressed ? Constants.colors.toolbarArea : 'transparent'
+
+ Rectangle {
+ height: 5 * pgst.scalef
+ color: iconMenuItem.pressed ? Constants.colors.secondaryHighlight : 'transparent'
+
+ anchors {
+ left: parent.left
+ right: parent.right
+ top: parent.top
+ }
+ }
+
+ IconMenuItem {
+ id: iconMenuItem
+ color: Constants.colors.text
+ transparent: true
+ enabled: parent.enabled
+ onClicked: toolbarButton.clicked()
+ }
+}
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/PlayerPage.qml
^
|
@@ -24,9 +24,12 @@
import 'common/constants.js' as Constants
import 'icons/icons.js' as Icons
-SlidePage {
+Dialog {
id: playerPage
+ contentHeight: flickable.contentHeight
+ fullWidth: true
+
Flickable {
id: flickable
anchors.fill: parent
@@ -38,14 +41,9 @@
Column {
id: column
- width: playerPage.width
+ width: flickable.width
spacing: 10 * pgst.scalef
- SlidePageHeader {
- title: 'Now playing'
- color: Constants.colors.playback
- }
-
Column {
anchors {
left: parent.left
@@ -53,6 +51,8 @@
margins: 30 * pgst.scalef
}
+ Item { width: parent.width; height: 20 * pgst.scalef }
+
PLabel {
anchors {
left: parent.left
@@ -60,6 +60,7 @@
}
text: player.episode_title
elide: Text.ElideRight
+ color: Constants.colors.dialogText
}
PLabel {
@@ -69,17 +70,19 @@
}
text: player.podcast_title
elide: Text.ElideRight
+ color: Constants.colors.dialogText
}
}
PLabel {
anchors.horizontalCenter: parent.horizontalCenter
text: Util.formatPosition(slider.displayedValue/1000, player.duration/1000)
+ color: Constants.colors.dialogText
}
PSlider {
id: slider
- width: playerPage.width
+ width: flickable.width
value: player.position
min: 0
max: player.duration
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/PodcastsPage.qml
^
|
@@ -27,37 +27,51 @@
SlidePage {
id: podcastsPage
- hasPull: true
+ canClose: false
- PullMenu {
- PullMenuItem {
- text: 'Now Playing'
- color: Constants.colors.playback
- icon: Icons.play
- onClicked: {
- pgst.loadPage('PlayerPage.qml');
- podcastsPage.unPull();
- }
- }
-
- PullMenuItem {
- text: 'Refresh feeds'
- icon: Icons.loop_alt2
- onClicked: {
- podcastsPage.unPull();
- py.call('main.check_for_episodes');
- }
- }
-
- PullMenuItem {
- text: 'Subscribe'
- icon: Icons.plus
- color: Constants.colors.download
- onClicked: {
- pgst.loadPage('Subscribe.qml');
- podcastsPage.unPull();
- }
- }
+ hasMenuButton: true
+ menuButtonLabel: 'Settings'
+ onMenuButtonClicked: {
+ pgst.showSelection([
+ {
+ label: 'Check for new episodes',
+ callback: function () {
+ py.call('main.check_for_episodes');
+ }
+ },
+ {
+ label: 'Filter episodes',
+ callback: function () {
+ pgst.loadPage('EpisodeQueryPage.qml');
+ }
+ },
+ {
+ label: 'About',
+ callback: function () {
+ pgst.loadPage('AboutPage.qml');
+ },
+ },
+ {
+ label: 'Add new podcast',
+ callback: function () {
+ var ctx = { py: py };
+ pgst.loadPage('TextInputDialog.qml', {
+ buttonText: 'Subscribe',
+ placeholderText: 'Feed URL',
+ pasteOnLoad: true,
+ callback: function (url) {
+ ctx.py.call('main.subscribe', [url]);
+ }
+ });
+ },
+ },
+ {
+ label: 'Search gpodder.net',
+ callback: function () {
+ pgst.loadPage('Directory.qml');
+ },
+ },
+ ]);
}
PListView {
@@ -76,6 +90,46 @@
delegate: PodcastItem {
onClicked: pgst.loadPage('EpisodesPage.qml', {'podcast_id': id, 'title': title});
+ onPressAndHold: {
+ pgst.showSelection([
+ {
+ label: 'Unsubscribe',
+ callback: function () {
+ var ctx = { py: py, id: id };
+ pgst.showConfirmation(title, 'Unsubscribe', 'Cancel', 'Remove this podcast and all downloaded episodes?', Icons.trash, function () {
+ ctx.py.call('main.unsubscribe', [ctx.id]);
+ });
+ } },
+ {
+ label: 'Rename',
+ callback: function () {
+ var ctx = { py: py, id: id };
+ pgst.loadPage('TextInputDialog.qml', {
+ buttonText: 'Rename',
+ placeholderText: 'New name',
+ text: title,
+ callback: function (new_title) {
+ ctx.py.call('main.rename_podcast', [ctx.id, new_title]);
+ }
+ });
+ }
+ },
+ {
+ label: 'Change section',
+ 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]);
+ }
+ });
+ }
+ },
+ ], title);
+ }
}
}
}
|
[-]
[+]
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/SelectionDialog.qml
^
|
@@ -0,0 +1,91 @@
+
+/**
+ *
+ * gPodder QML UI Reference Implementation
+ * Copyright (c) 2014, Thomas Perl <m@thp.io>
+ *
+ * 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 'icons/icons.js' as Icons
+
+Dialog {
+ id: selectionDialog
+
+ property string title: ''
+ property var callback: undefined
+ property var items: ([])
+ property var selectedIndex: -1
+
+ contentHeight: selectionDialogFlickable.contentHeight
+
+ Flickable {
+ id: selectionDialogFlickable
+
+ boundsBehavior: Flickable.StopAtBounds
+
+ anchors.fill: parent
+ contentHeight: contentColumn.height
+
+ Column {
+ id: contentColumn
+ width: parent.width
+
+ SlidePageHeader {
+ id: header
+ visible: title != ''
+ color: Constants.colors.dialogHighlight
+ title: selectionDialog.title
+ }
+
+ Repeater {
+ model: selectionDialog.items
+
+ delegate: ButtonArea {
+ id: buttonArea
+
+ color: Constants.colors.dialogArea
+ width: parent.width
+ height: 70 * pgst.scalef
+
+ transparent: (index != selectionDialog.selectedIndex)
+
+ PLabel {
+ anchors {
+ left: parent.left
+ verticalCenter: parent.verticalCenter
+ margins: 20 * pgst.scalef
+ }
+
+ text: modelData
+ color: (index == selectionDialog.selectedIndex || buttonArea.pressed) ? Constants.colors.dialogHighlight : Constants.colors.dialogText
+ font.pixelSize: 30 * pgst.scalef
+ }
+
+ onClicked: {
+ if (selectionDialog.callback !== undefined) {
+ selectionDialog.callback(index, modelData);
+ }
+ selectionDialog.closePage();
+ }
+ }
+ }
+ }
+ }
+
+ PScrollDecorator { flickable: selectionDialogFlickable }
+}
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/SlidePage.qml
^
|
@@ -21,19 +21,22 @@
import QtQuick 2.0
import 'common/constants.js' as Constants
+import 'icons/icons.js' as Icons
Rectangle {
id: page
color: Constants.colors.page
+ Component.onCompleted: pgst.topOfStackChanged();
+
default property alias children: dragging.children
- property alias hasPull: dragging.hasPull
property alias canClose: dragging.canClose
- property real pullPhase: (x >= 0) ? 0 : (-x / (width / 4))
+ property bool isDialog: false
- function unPull() {
- stacking.fadeInAgain();
- }
+ property bool hasMenuButton: false
+ property string menuButtonLabel: 'Menu'
+ property string menuButtonIcon: Icons.vellipsis
+ signal menuButtonClicked()
function closePage() {
stacking.startFadeOut();
@@ -42,7 +45,7 @@
onXChanged: pgst.update(page, x)
width: parent.width
- height: parent.height
+ height: parent.height - parent.bottomSpacing
Stacking { id: stacking }
@@ -51,19 +54,6 @@
stacking: stacking
}
- Rectangle {
- color: Constants.colors.page
- anchors.fill: parent
-
- opacity: page.pullPhase * 0.9
-
- MouseArea {
- enabled: parent.opacity > 0
- anchors.fill: parent
- onClicked: page.unPull();
- }
- }
-
Image {
anchors {
right: parent.left
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/Stacking.qml
^
|
@@ -48,6 +48,7 @@
function startFadeOut() {
fadeOut.start();
+ pgst.topOfStackChanged(-1);
page.destroy(500);
}
|
[-]
[+]
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/TextInputDialog.qml
^
|
@@ -0,0 +1,74 @@
+
+/**
+ *
+ * gPodder QML UI Reference Implementation
+ * Copyright (c) 2014, Thomas Perl <m@thp.io>
+ *
+ * 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
+
+Dialog {
+ id: textInputDialog
+
+ property string buttonText
+ property string placeholderText
+ property string text
+ property bool pasteOnLoad: false
+ property var callback
+
+ contentHeight: contentColumn.height
+
+ Component.onCompleted: {
+ if (pasteOnLoad) {
+ input.paste();
+ }
+ }
+
+ function accept() {
+ textInputDialog.callback(input.text);
+ textInputDialog.closePage();
+ }
+
+ Column {
+ id: contentColumn
+
+ anchors.centerIn: parent
+ spacing: 20 * pgst.scalef
+
+ PTextField {
+ id: input
+ width: textInputDialog.width *.8
+ placeholderText: textInputDialog.placeholderText
+ text: textInputDialog.text
+ onAccepted: textInputDialog.accept();
+ }
+
+ ButtonArea {
+ id: button
+ width: input.width
+ height: input.height
+
+ PLabel {
+ anchors.centerIn: parent
+ text: textInputDialog.buttonText
+ }
+
+ onClicked: textInputDialog.accept();
+ }
+ }
+}
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/icons/icons.js
^
|
@@ -16,3 +16,8 @@
var eye = '\ue025';
var loop_alt2 = '\ue033';
var folder = '\ue065';
+var magnifying_glass = '\ue074';
+var cog = '\u2699';
+var link = '\ue077';
+var vellipsis = '\u22ee';
+var paperclip = '\ue08a';
|
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/gpodder-ui-qml/touch/images/toolbarshadow.png
^
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/podcastparser/podcastparser.py
^
|
@@ -280,7 +280,7 @@
prefix = self.NAMESPACES.get(namespace_uri)
if prefix is None and namespace:
# Proper use of namespaces, but unknown namespace
- logger.warn('Unknown namespace: %s', namespace_uri)
+ #logger.warn('Unknown namespace: %s', namespace_uri)
# We prefix the tag name here to make sure that it does not
# match any other tag below if we can't recognize the namespace
name = '!%s:%s' % (namespace, name)
@@ -462,8 +462,9 @@
'rss/channel/item/link': EpisodeAttr('link'),
'rss/channel/item/description': EpisodeAttr('description',
squash_whitespace),
- # Alternatives for description: itunes:summary, itunes:subtitle,
- # content:encoded
+ 'rss/channel/item/itunes:summary': EpisodeAttr('description',
+ squash_whitespace),
+ # Alternatives for description: itunes:subtitle, content:encoded
'rss/channel/item/itunes:duration': EpisodeAttr('total_time', parse_time),
'rss/channel/item/pubDate': EpisodeAttr('published', parse_pubdate),
'rss/channel/item/atom:link': AtomLink(),
|
[-]
[+]
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/qml/AllEpisodesPage.qml
^
|
@@ -0,0 +1,72 @@
+
+/**
+ *
+ * gPodder QML UI Reference Implementation
+ * Copyright (c) 2013, Thomas Perl <m@thp.io>
+ *
+ * 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 Sailfish.Silica 1.0
+
+import 'common'
+import 'common/util.js' as Util
+
+Page {
+ id: freshEpisodes
+
+ onStatusChanged: pgst.handlePageStatusChange(status)
+
+ Component.onCompleted: {
+ episodesListModel.setQuery(episodesListModel.queries.Fresh);
+ episodesListModel.reload();
+ }
+
+ BusyIndicator {
+ visible: !episodesListModel.ready
+ running: visible
+ anchors.centerIn: parent
+ }
+
+ SilicaListView {
+ id: freshEpisodesList
+ anchors.fill: parent
+
+ PullDownMenu {
+ EpisodeListFilterItem { id: filterItem; model: episodesListModel }
+ }
+
+ VerticalScrollDecorator { flickable: freshEpisodesList }
+
+ header: PageHeader {
+ title: 'Episodes: ' + filterItem.currentFilter
+ }
+
+ model: GPodderEpisodeListModel { id: episodesListModel }
+
+ section.property: 'section'
+ section.delegate: SectionHeader {
+ text: section
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ delegate: EpisodeItem {}
+
+ ViewPlaceholder {
+ enabled: freshEpisodesList.count == 0 && episodesListModel.ready
+ text: 'No episodes found'
+ }
+ }
+}
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/qml/EpisodeDetail.qml
^
|
@@ -26,20 +26,38 @@
property int episode_id
property string title
+ property string link
+ property bool ready: false
onStatusChanged: pgst.handlePageStatusChange(status)
Component.onCompleted: {
- label.text = 'Loading...';
py.call('main.show_episode', [episode_id], function (episode) {
- label.text = episode.description;
+ descriptionLabel.text = episode.description;
+ metadataLabel.text = episode.metadata;
+ detailPage.link = episode.link;
+ detailPage.ready = true;
});
}
+ BusyIndicator {
+ visible: !detailPage.ready
+ running: visible
+ anchors.centerIn: parent
+ }
+
SilicaFlickable {
id: flickable
anchors.fill: parent
+ PullDownMenu {
+ MenuItem {
+ text: 'Visit website'
+ onClicked: Qt.openUrlExternally(detailPage.link);
+ enabled: detailPage.link != ''
+ }
+ }
+
VerticalScrollDecorator { flickable: flickable }
contentWidth: detailColumn.width
@@ -52,11 +70,39 @@
spacing: Theme.paddingMedium
PageHeader {
- title: detailPage.title
+ title: 'Shownotes'
+ }
+
+ Label {
+ text: detailPage.title
+ wrapMode: Text.WordWrap
+ font.pixelSize: Theme.fontSizeLarge
+ color: Theme.highlightColor
+
+ anchors {
+ left: parent.left
+ right: parent.right
+ margins: Theme.paddingMedium
+ }
+ }
+
+ Label {
+ id: metadataLabel
+
+ font.pixelSize: Theme.fontSizeSmall
+ color: Theme.secondaryColor
+
+ anchors {
+ left: parent.left
+ right: parent.right
+ margins: Theme.paddingMedium
+ }
+
+ wrapMode: Text.WordWrap
}
Label {
- id: label
+ id: descriptionLabel
anchors {
left: parent.left
right: parent.right
|
[-]
[+]
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/qml/EpisodeFilterDialog.qml
^
|
@@ -0,0 +1,68 @@
+
+/**
+ *
+ * gPodder QML UI Reference Implementation
+ * Copyright (c) 2014, Thomas Perl <m@thp.io>
+ *
+ * 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 Sailfish.Silica 1.0
+
+Page {
+ id: filterSelector
+
+ property var model
+ property int selectedIndex: model.currentFilterIndex
+
+ SilicaListView {
+ anchors.fill: parent
+
+ header: PageHeader {
+ title: 'Filter episode list'
+ }
+
+ model: {
+ var result = [];
+ for (var i in filterSelector.model.filters) {
+ result.push(filterSelector.model.filters[i].label);
+ }
+ return result;
+ }
+
+ delegate: ListItem {
+ id: listItem
+
+ highlighted: down || (index == filterSelector.selectedIndex)
+
+ onClicked: {
+ filterSelector.model.currentFilterIndex = index;
+ filterSelector.model.reload();
+ pageStack.pop();
+ }
+
+ Label {
+ anchors {
+ left: parent.left
+ verticalCenter: parent.verticalCenter
+ margins: Theme.paddingMedium
+ }
+
+ color: listItem.highlighted ? Theme.highlightColor: Theme.primaryColor
+ text: modelData
+ }
+ }
+ }
+}
|
[-]
[+]
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/qml/EpisodeListFilterItem.qml
^
|
@@ -0,0 +1,35 @@
+
+/**
+ *
+ * gPodder QML UI Reference Implementation
+ * Copyright (c) 2014, Thomas Perl <m@thp.io>
+ *
+ * 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 Sailfish.Silica 1.0
+
+import 'common'
+import 'common/util.js' as Util
+
+MenuItem {
+ id: episodeListFilterItem
+
+ property var model
+ property string currentFilter: model.filters[model.currentFilterIndex].label
+
+ text: 'Filter: ' + currentFilter
+ onClicked: pageStack.push('EpisodeFilterDialog.qml', { model: model });
+}
|
[-]
[+]
|
Added |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/qml/EpisodeQueryControl.qml
^
|
@@ -0,0 +1,46 @@
+
+/**
+ *
+ * gPodder QML UI Reference Implementation
+ * Copyright (c) 2014, Thomas Perl <m@thp.io>
+ *
+ * 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
+
+Item {
+ id: episodeQueryControl
+
+ property var model
+ property string title
+
+ function showSelectionDialog() {
+ pgst.loadPage('SelectionDialog.qml', {
+ title: episodeQueryControl.title,
+ callback: function (index, result) {
+ episodeQueryControl.model.currentFilterIndex = index;
+ episodeQueryControl.model.reload();
+ },
+ items: function () {
+ var labels = [];
+ for (var i in episodeQueryControl.model.filters) {
+ labels.push(episodeQueryControl.model.filters[i].label);
+ }
+ return labels;
+ }(),
+ selectedIndex: episodeQueryControl.model.currentFilterIndex,
+ });
+ }
+}
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/qml/EpisodesPage.qml
^
|
@@ -38,7 +38,15 @@
RemorsePopup { id: remorse }
Component.onCompleted: {
- episodeListModel.loadEpisodes(podcast_id);
+ episodeListModel.podcast_id = podcast_id;
+ episodeListModel.setQuery(episodeListModel.queries.All);
+ episodeListModel.reload();
+ }
+
+ BusyIndicator {
+ visible: !episodeListModel.ready
+ running: visible
+ anchors.centerIn: parent
}
SilicaListView {
@@ -72,13 +80,15 @@
})
}
}
+
+ EpisodeListFilterItem { model: episodeListModel }
}
delegate: EpisodeItem {}
ViewPlaceholder {
- enabled: episodeList.count == 0
- text: 'No episodes'
+ enabled: episodeList.count == 0 && episodeListModel.ready
+ text: 'No episodes found'
}
}
}
|
[-]
[+]
|
Changed |
_service:tar_git:harbour-org.gpodder.sailfish-4.1.0.tar.gz/qml/PodcastsPage.qml
^
|
@@ -42,8 +42,8 @@
}
MenuItem {
- text: 'Fresh episodes'
- onClicked: pgst.loadPage('FreshEpisodes.qml');
+ text: 'Filter episodes'
+ onClicked: pgst.loadPage('AllEpisodesPage.qml');
}
MenuItem {
@@ -70,7 +70,10 @@
}
section.property: 'section'
- section.delegate: SectionHeader { text: section }
+ section.delegate: SectionHeader {
+ text: section
+ horizontalAlignment: Text.AlignHCenter
+ }
model: podcastListModel
|