Initial commit
Based on private pyotherside devel branch (gPodder Cuatro, May 2013).
15
README
Normal file
|
@ -0,0 +1,15 @@
|
|||
gPodder 4 QML UI Reference Implementation
|
||||
-----------------------------------------
|
||||
|
||||
Nothing (much) to see here (yet), move along.
|
||||
|
||||
Usage: qmlscene index.qml
|
||||
|
||||
Dependencies:
|
||||
|
||||
Package Min.Version URL
|
||||
------------------------------------------------------------
|
||||
Qt 5.0.2 http://qt-project.org/
|
||||
Python 3.3.0 http://python.org/
|
||||
PyOtherSide 1.0.0 http://thp.io/2011/pyotherside/
|
||||
gPodder 4.0.0 http://gpodder.org/
|
29
index.qml
Normal file
|
@ -0,0 +1,29 @@
|
|||
/**
|
||||
*
|
||||
* 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 'qml'
|
||||
|
||||
Rectangle {
|
||||
color: 'black'
|
||||
width: 480
|
||||
height: 800
|
||||
|
||||
Main {}
|
||||
}
|
227
main.py
Normal file
|
@ -0,0 +1,227 @@
|
|||
#
|
||||
# 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 sys
|
||||
import os
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'gpodder', 'src'))
|
||||
|
||||
import pyotherside
|
||||
import gpodder
|
||||
|
||||
from gpodder.api import core
|
||||
from gpodder.api import util
|
||||
|
||||
import logging
|
||||
import functools
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def run_in_background_thread(f):
|
||||
"""Decorator for functions that take longer to finish
|
||||
|
||||
The function will be run in its own thread, and control
|
||||
will be returned to the caller right away, which allows
|
||||
other Python code to run while this function finishes.
|
||||
|
||||
The function cannot return a value (control is usually
|
||||
returned to the caller before execution is finished).
|
||||
"""
|
||||
@functools.wraps(f)
|
||||
def wrapper(*args):
|
||||
util.run_in_background(lambda: f(*args))
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class gPotherSide:
|
||||
def __init__(self):
|
||||
self.core = core.Core()
|
||||
self._checking_for_new_episodes = False
|
||||
|
||||
def atexit(self):
|
||||
self.core.shutdown()
|
||||
|
||||
def _get_episode_by_id(self, episode_id):
|
||||
for podcast in self.core.model.get_podcasts():
|
||||
for episode in podcast.episodes:
|
||||
if episode.id == episode_id:
|
||||
return episode
|
||||
|
||||
def _get_podcast_by_id(self, podcast_id):
|
||||
for podcast in self.core.model.get_podcasts():
|
||||
if podcast.id == podcast_id:
|
||||
return podcast
|
||||
|
||||
def get_stats(self):
|
||||
podcasts = self.core.model.get_podcasts()
|
||||
|
||||
total, deleted, new, downloaded, unplayed = 0, 0, 0, 0, 0
|
||||
for podcast in podcasts:
|
||||
to, de, ne, do, un = podcast.get_statistics()
|
||||
total += to
|
||||
deleted += de
|
||||
new += ne
|
||||
downloaded += do
|
||||
unplayed += un
|
||||
|
||||
return '\n'.join([
|
||||
'%d podcasts' % len(podcasts),
|
||||
'%d episodes' % total,
|
||||
'%d new episodes' % new,
|
||||
'%d downloads' % downloaded,
|
||||
])
|
||||
|
||||
def _get_cover(self, podcast):
|
||||
filename = self.core.cover_downloader.get_cover(podcast)
|
||||
if not filename:
|
||||
return 'artwork/default.png'
|
||||
return 'file://' + filename
|
||||
|
||||
def convert_podcast(self, podcast):
|
||||
total, deleted, new, downloaded, unplayed = podcast.get_statistics()
|
||||
|
||||
return {
|
||||
'id': podcast.id,
|
||||
'title': podcast.title,
|
||||
'newEpisodes': new,
|
||||
'downloaded': downloaded,
|
||||
'coverart': self._get_cover(podcast),
|
||||
'updating': podcast._updating,
|
||||
'section': podcast.section,
|
||||
}
|
||||
|
||||
def load_podcasts(self):
|
||||
podcasts = self.core.model.get_podcasts()
|
||||
return [self.convert_podcast(podcast) for podcast in sorted(podcasts,
|
||||
key=lambda podcast: (podcast.section, podcast.title))]
|
||||
|
||||
def convert_episode(self, episode):
|
||||
return {
|
||||
'id': episode.id,
|
||||
'title': episode.title,
|
||||
'progress': episode.download_progress(),
|
||||
}
|
||||
|
||||
def load_episodes(self, id):
|
||||
podcast = self._get_podcast_by_id(id)
|
||||
return [self.convert_episode(episode) for episode in podcast.episodes]
|
||||
|
||||
def get_fresh_episodes_summary(self, count):
|
||||
summary = []
|
||||
for podcast in self.core.model.get_podcasts():
|
||||
_, _, new, _, _ = podcast.get_statistics()
|
||||
if new:
|
||||
summary.append({
|
||||
'coverart': self._get_cover(podcast),
|
||||
'newEpisodes': new,
|
||||
})
|
||||
|
||||
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(),
|
||||
}
|
||||
|
||||
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_fresh_episode(e) for e in fresh_episodes]
|
||||
|
||||
@run_in_background_thread
|
||||
def subscribe(self, url):
|
||||
url = util.normalize_feed_url(url)
|
||||
self.core.model.load_podcast(url, create=True)
|
||||
pyotherside.send('podcast-list-changed')
|
||||
pyotherside.send('update-stats')
|
||||
|
||||
@run_in_background_thread
|
||||
def unsubscribe(self, podcast_id):
|
||||
podcast = self._get_podcast_by_id(podcast_id)
|
||||
podcast.unsubscribe()
|
||||
pyotherside.send('podcast-list-changed')
|
||||
pyotherside.send('update-stats')
|
||||
|
||||
@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)
|
||||
pyotherside.send('downloading', episode_id)
|
||||
if episode.download(progress_callback):
|
||||
pyotherside.send('downloaded', episode_id)
|
||||
else:
|
||||
pyotherside.send('download-failed', episode_id)
|
||||
pyotherside.send('update-stats')
|
||||
|
||||
@run_in_background_thread
|
||||
def check_for_episodes(self):
|
||||
if self._checking_for_new_episodes:
|
||||
return
|
||||
|
||||
self._checking_for_new_episodes = True
|
||||
pyotherside.send('refreshing', True)
|
||||
podcasts = self.core.model.get_podcasts()
|
||||
for index, podcast in enumerate(podcasts):
|
||||
pyotherside.send('refresh-progress', index, len(podcasts))
|
||||
pyotherside.send('updating-podcast', podcast.id)
|
||||
try:
|
||||
podcast.update()
|
||||
except Exception as e:
|
||||
logger.warn('Could not update %s: %s', podcast.url,
|
||||
e, exc_info=True)
|
||||
pyotherside.send('updated-podcast', self.convert_podcast(podcast))
|
||||
pyotherside.send('update-stats')
|
||||
|
||||
self._checking_for_new_episodes = False
|
||||
pyotherside.send('refreshing', False)
|
||||
|
||||
def show_episode(self, episode_id):
|
||||
episode = self._get_episode_by_id(episode_id)
|
||||
return {
|
||||
'title': episode.trimmed_title,
|
||||
'description': util.remove_html_tags(episode.description),
|
||||
}
|
||||
|
||||
gpotherside = gPotherSide()
|
||||
pyotherside.atexit(gpotherside.atexit)
|
||||
|
||||
pyotherside.send('hello', gpodder.__version__, gpodder.__copyright__)
|
||||
|
||||
# Exposed API Endpoints for calls from QML
|
||||
load_podcasts = gpotherside.load_podcasts
|
||||
load_episodes = gpotherside.load_episodes
|
||||
show_episode = gpotherside.show_episode
|
||||
subscribe = gpotherside.subscribe
|
||||
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
|
37
qml/ButtonArea.qml
Normal file
|
@ -0,0 +1,37 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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
|
||||
|
||||
Rectangle {
|
||||
id: buttonArea
|
||||
|
||||
signal clicked
|
||||
|
||||
property bool transparent: false
|
||||
color: mouseArea.pressed?'#33ffffff':(transparent?'#00000000':'#88000000')
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
onClicked: buttonArea.clicked();
|
||||
}
|
||||
}
|
||||
|
57
qml/Dragging.qml
Normal file
|
@ -0,0 +1,57 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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
|
||||
|
||||
MouseArea {
|
||||
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
|
||||
maximumX: canClose ? parent.width : 0
|
||||
filterChildren: true
|
||||
}
|
||||
|
||||
onPressedChanged: {
|
||||
if (pressed) {
|
||||
dragging.stacking.stopAllAnimations();
|
||||
} else {
|
||||
if (hasPull && parent.x < -parent.width / 4 + 10) {
|
||||
pulled();
|
||||
parent.x = -parent.width / 4;
|
||||
//dragging.stacking.fadeInAgain();
|
||||
} else if (parent.x > parent.width / 3) {
|
||||
dragging.stacking.startFadeOut();
|
||||
} else {
|
||||
dragging.stacking.fadeInAgain();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
65
qml/EpisodeDetail.qml
Normal file
|
@ -0,0 +1,65 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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 'constants.js' as Constants
|
||||
|
||||
SlidePage {
|
||||
id: detailPage
|
||||
|
||||
property int episode_id
|
||||
property string title
|
||||
|
||||
Component.onCompleted: {
|
||||
label.text = 'Loading...';
|
||||
py.call('main.show_episode', [episode_id], function (episode) {
|
||||
label.text = episode.description;
|
||||
});
|
||||
}
|
||||
|
||||
Flickable {
|
||||
id: flickable
|
||||
anchors.fill: parent
|
||||
|
||||
contentWidth: detailColumn.width
|
||||
contentHeight: detailColumn.height + detailColumn.spacing
|
||||
|
||||
Column {
|
||||
id: detailColumn
|
||||
|
||||
width: detailPage.width
|
||||
spacing: 10 * pgst.scalef
|
||||
|
||||
SlidePageHeader {
|
||||
title: detailPage.title
|
||||
}
|
||||
|
||||
PLabel {
|
||||
id: label
|
||||
width: parent.width * .8
|
||||
font.pixelSize: 30 * pgst.scalef
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
59
qml/EpisodeItem.qml
Normal file
|
@ -0,0 +1,59 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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 'constants.js' as Constants
|
||||
|
||||
ButtonArea {
|
||||
id: podcastItem
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
}
|
||||
width: parent.width * progress
|
||||
color: Constants.colors.download
|
||||
opacity: .4
|
||||
}
|
||||
|
||||
transparent: true
|
||||
height: 80 * pgst.scalef
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
PLabel {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
margins: 30 * pgst.scalef
|
||||
}
|
||||
|
||||
elide: Text.ElideRight
|
||||
text: title
|
||||
}
|
||||
}
|
||||
|
70
qml/EpisodesPage.qml
Normal file
|
@ -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
|
||||
import io.thp.pyotherside 1.0
|
||||
|
||||
import 'util.js' as Util
|
||||
|
||||
SlidePage {
|
||||
id: episodesPage
|
||||
|
||||
hasPull: true
|
||||
|
||||
property int podcast_id
|
||||
property string title
|
||||
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
Component.onCompleted: {
|
||||
py.call('main.load_episodes', [podcast_id], function (episodes) {
|
||||
Util.updateModelFrom(episodeListModel, episodes);
|
||||
});
|
||||
}
|
||||
|
||||
PullMenu {
|
||||
PullMenuItem {
|
||||
source: 'images/play.png'
|
||||
onClicked: {
|
||||
episodesPage.unPull();
|
||||
}
|
||||
}
|
||||
|
||||
PullMenuItem {
|
||||
source: 'images/delete.png'
|
||||
onClicked: {
|
||||
py.call('main.unsubscribe', [episodesPage.podcast_id]);
|
||||
episodesPage.closePage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PListView {
|
||||
id: episodeList
|
||||
title: episodesPage.title
|
||||
model: ListModel { id: episodeListModel }
|
||||
|
||||
delegate: EpisodeItem {
|
||||
onClicked: pgst.loadPage('EpisodeDetail.qml', {episode_id: id, title: title});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
71
qml/FreshEpisodes.qml
Normal file
|
@ -0,0 +1,71 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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 'util.js' as Util
|
||||
|
||||
SlidePage {
|
||||
id: freshEpisodes
|
||||
property bool ready: false
|
||||
|
||||
Component.onCompleted: {
|
||||
py.call('main.get_fresh_episodes', [], function (episodes) {
|
||||
Util.updateModelFrom(freshEpisodesListModel, episodes);
|
||||
freshEpisodes.ready = true;
|
||||
});
|
||||
}
|
||||
|
||||
PBusyIndicator {
|
||||
visible: !freshEpisodes.ready
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
PListView {
|
||||
id: freshEpisodesList
|
||||
title: 'Fresh episodes'
|
||||
|
||||
model: ListModel { id: freshEpisodesListModel }
|
||||
|
||||
section.property: 'published'
|
||||
section.delegate: SectionHeader { text: section }
|
||||
|
||||
delegate: EpisodeItem {
|
||||
onClicked: py.call('main.download_episode', [id]);
|
||||
|
||||
Connections {
|
||||
target: pgst
|
||||
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});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
109
qml/Main.qml
Normal file
|
@ -0,0 +1,109 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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 io.thp.pyotherside 1.0
|
||||
|
||||
Rectangle {
|
||||
id: pgst
|
||||
property bool ready: false
|
||||
|
||||
property real scalef: width / 480
|
||||
|
||||
anchors.fill: parent
|
||||
color: '#336688'
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: 'images/mask.png'
|
||||
}
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: 'images/noise.png'
|
||||
fillMode: Image.Tile
|
||||
}
|
||||
|
||||
function update(page, x) {
|
||||
var index = -1;
|
||||
for (var i=0; i<children.length; i++) {
|
||||
if (children[i] === page) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
children[index-1].opacity = x / width;
|
||||
}
|
||||
|
||||
signal downloading(int episode_id)
|
||||
signal downloadProgress(int episode_id, real progress)
|
||||
signal downloaded(int episode_id)
|
||||
|
||||
function loadPage(filename, properties) {
|
||||
var component = Qt.createComponent(filename);
|
||||
console.log('error: ' + component.errorString());
|
||||
if (properties === undefined) {
|
||||
component.createObject(pgst);
|
||||
} else {
|
||||
component.createObject(pgst, properties);
|
||||
}
|
||||
}
|
||||
|
||||
Python {
|
||||
id: py
|
||||
|
||||
Component.onCompleted: {
|
||||
addImportPath('.');
|
||||
|
||||
setHandler('hello', function (version, copyright) {
|
||||
console.log('gPodder version ' + version + ' starting up');
|
||||
console.log('Copyright: ' + copyright);
|
||||
});
|
||||
|
||||
setHandler('downloading', pgst.downloading);
|
||||
setHandler('download-progress', pgst.downloadProgress);
|
||||
setHandler('downloaded', pgst.downloaded);
|
||||
|
||||
// Load the Python side of things
|
||||
importModule('main', function() {
|
||||
pgst.ready = true;
|
||||
});
|
||||
}
|
||||
|
||||
onReceived: {
|
||||
console.log('unhandled message: ' + data);
|
||||
}
|
||||
|
||||
onError: {
|
||||
console.log('Python failure: ' + traceback);
|
||||
}
|
||||
}
|
||||
|
||||
PBusyIndicator {
|
||||
anchors.centerIn: parent
|
||||
visible: !pgst.ready
|
||||
}
|
||||
|
||||
StartPage {
|
||||
id: startPage
|
||||
visible: pgst.ready
|
||||
}
|
||||
}
|
53
qml/PBusyIndicator.qml
Normal file
|
@ -0,0 +1,53 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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 {
|
||||
height: 64 * pgst.scalef
|
||||
width: 64 * pgst.scalef
|
||||
|
||||
Image {
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 30*Math.abs(Math.sin(phase)) * pgst.scalef
|
||||
}
|
||||
|
||||
transform: Scale {
|
||||
origin.x: 32 * pgst.scalef
|
||||
origin.y: 32 * pgst.scalef
|
||||
xScale: 1.0 - 0.3 * (1.0 - Math.abs(Math.sin(phase)))
|
||||
}
|
||||
|
||||
source: 'images/gpodder.png'
|
||||
}
|
||||
|
||||
property real phase: 0
|
||||
|
||||
PropertyAnimation on phase {
|
||||
loops: Animation.Infinite
|
||||
duration: 2000
|
||||
running: parent.visible
|
||||
from: 0
|
||||
to: 2*Math.PI
|
||||
}
|
||||
}
|
||||
|
27
qml/PLabel.qml
Normal file
|
@ -0,0 +1,27 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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
|
||||
|
||||
Text {
|
||||
font.pixelSize: 30 * pgst.scalef
|
||||
color: 'white'
|
||||
}
|
||||
|
34
qml/PListView.qml
Normal file
|
@ -0,0 +1,34 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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 'constants.js' as Constants
|
||||
|
||||
ListView {
|
||||
id: pListView
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
property string title
|
||||
|
||||
header: SlidePageHeader { title: pListView.title }
|
||||
}
|
||||
|
51
qml/PTextField.qml
Normal file
|
@ -0,0 +1,51 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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
|
||||
|
||||
Rectangle {
|
||||
id: textField
|
||||
|
||||
property alias text: textInput.text
|
||||
property string placeholderText: ''
|
||||
|
||||
radius: 10 * pgst.scalef
|
||||
height: 50 * pgst.scalef
|
||||
color: 'white'
|
||||
|
||||
TextInput {
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: 5 * pgst.scalef
|
||||
}
|
||||
color: 'black'
|
||||
id: textInput
|
||||
font.pixelSize: height
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.fill: textInput
|
||||
visible: !textInput.focus && (textInput.text == '')
|
||||
text: textField.placeholderText
|
||||
color: '#aaa'
|
||||
font.pixelSize: textInput.font.pixelSize
|
||||
}
|
||||
}
|
||||
|
71
qml/PodcastItem.qml
Normal file
|
@ -0,0 +1,71 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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: podcastItem
|
||||
|
||||
transparent: true
|
||||
|
||||
height: 100 * pgst.scalef
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
Image {
|
||||
id: cover
|
||||
visible: !updating
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: 10 * pgst.scalef
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
|
||||
width: 80 * pgst.scalef
|
||||
height: 80 * pgst.scalef
|
||||
|
||||
source: coverart
|
||||
}
|
||||
|
||||
PBusyIndicator {
|
||||
anchors.centerIn: cover
|
||||
visible: updating
|
||||
}
|
||||
|
||||
PLabel {
|
||||
anchors {
|
||||
left: cover.right
|
||||
leftMargin: 10 * pgst.scalef
|
||||
rightMargin: 10 * pgst.scalef
|
||||
right: parent.right
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
elide: Text.ElideRight
|
||||
text: title
|
||||
}
|
||||
}
|
||||
|
110
qml/PodcastsPage.qml
Normal file
|
@ -0,0 +1,110 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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 'util.js' as Util
|
||||
|
||||
SlidePage {
|
||||
id: podcastsPage
|
||||
hasPull: true
|
||||
|
||||
function reload() {
|
||||
loading.visible = true;
|
||||
py.call('main.load_podcasts', [], function (podcasts) {
|
||||
Util.updateModelFrom(podcastListModel, podcasts);
|
||||
loading.visible = false;
|
||||
});
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
reload();
|
||||
|
||||
py.setHandler('podcast-list-changed', podcastsPage.reload);
|
||||
|
||||
py.setHandler('updating-podcast', function (podcast_id) {
|
||||
for (var i=0; i<podcastListModel.count; i++) {
|
||||
var podcast = podcastListModel.get(i);
|
||||
if (podcast.id == podcast_id) {
|
||||
podcastListModel.setProperty(i, 'updating', true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
py.setHandler('updated-podcast', function (podcast) {
|
||||
for (var i=0; i<podcastListModel.count; i++) {
|
||||
if (podcastListModel.get(i).id == podcast.id) {
|
||||
podcastListModel.set(i, podcast);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
py.setHandler('podcast-list-changed', undefined);
|
||||
py.setHandler('updating-podcast', undefined);
|
||||
py.setHandler('updated-podcast', undefined);
|
||||
}
|
||||
|
||||
PullMenu {
|
||||
PullMenuItem {
|
||||
source: 'images/play.png'
|
||||
}
|
||||
|
||||
PullMenuItem {
|
||||
source: 'images/search.png'
|
||||
onClicked: {
|
||||
podcastsPage.unPull();
|
||||
py.call('main.check_for_episodes');
|
||||
}
|
||||
}
|
||||
|
||||
PullMenuItem {
|
||||
source: 'images/subscriptions.png'
|
||||
onClicked: {
|
||||
pgst.loadPage('Subscribe.qml');
|
||||
podcastsPage.unPull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PLabel {
|
||||
id: loading
|
||||
anchors.centerIn: parent
|
||||
text: 'Loading'
|
||||
}
|
||||
|
||||
PListView {
|
||||
id: podcastList
|
||||
title: 'Subscriptions'
|
||||
|
||||
section.property: 'section'
|
||||
section.delegate: SectionHeader { text: section }
|
||||
|
||||
model: ListModel { id: podcastListModel }
|
||||
|
||||
delegate: PodcastItem {
|
||||
onClicked: pgst.loadPage('EpisodesPage.qml', {'podcast_id': id, 'title': title});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
35
qml/PullMenu.qml
Normal file
|
@ -0,0 +1,35 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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
|
||||
|
||||
Column {
|
||||
id: pullMenu
|
||||
|
||||
width: parent.width / 4
|
||||
height: parent.height
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.right
|
||||
|
||||
Item { width: 1; height: 1 }
|
||||
|
||||
spacing: (width - 72 * pgst.scalef) / 2
|
||||
}
|
||||
|
38
qml/PullMenuItem.qml
Normal file
|
@ -0,0 +1,38 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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
|
||||
|
||||
Image {
|
||||
id: pullMenuItem
|
||||
|
||||
signal clicked
|
||||
|
||||
width: 72 * pgst.scalef
|
||||
height: 72 * pgst.scalef
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: pullMenuItem.clicked();
|
||||
}
|
||||
}
|
||||
|
39
qml/SectionHeader.qml
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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 {
|
||||
property alias text: pLabel.text
|
||||
|
||||
height: 70 * pgst.scalef
|
||||
|
||||
PLabel {
|
||||
id: pLabel
|
||||
anchors {
|
||||
left: parent.left
|
||||
bottom: parent.bottom
|
||||
margins: 10 * pgst.scalef
|
||||
}
|
||||
|
||||
color: '#aaa'
|
||||
}
|
||||
}
|
||||
|
33
qml/Settings.qml
Normal file
|
@ -0,0 +1,33 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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
|
||||
|
||||
SlidePage {
|
||||
SlidePageHeader { title: 'Settings' }
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
color: 'white'
|
||||
font.pixelSize: 50 * pgst.scalef
|
||||
text: 'TODO'
|
||||
}
|
||||
}
|
||||
|
92
qml/SlidePage.qml
Normal file
|
@ -0,0 +1,92 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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 'constants.js' as Constants
|
||||
|
||||
Rectangle {
|
||||
id: page
|
||||
color: '#88000000'
|
||||
|
||||
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))
|
||||
|
||||
function unPull() {
|
||||
stacking.fadeInAgain();
|
||||
}
|
||||
|
||||
function closePage() {
|
||||
stacking.startFadeOut();
|
||||
}
|
||||
|
||||
onXChanged: pgst.update(page, x)
|
||||
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
Stacking { id: stacking }
|
||||
|
||||
Dragging {
|
||||
id: dragging
|
||||
stacking: stacking
|
||||
|
||||
onPulled: console.log('have pulled it!')
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: 'black'
|
||||
anchors.fill: parent
|
||||
|
||||
opacity: page.pullPhase * 0.8
|
||||
|
||||
MouseArea {
|
||||
enabled: parent.opacity > 0
|
||||
anchors.fill: parent
|
||||
onClicked: page.unPull();
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
anchors {
|
||||
right: parent.left
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
width: 10 * pgst.scalef
|
||||
source: 'images/pageshadow.png'
|
||||
opacity: .2
|
||||
}
|
||||
|
||||
Image {
|
||||
anchors {
|
||||
left: parent.right
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
mirror: true
|
||||
width: 10 * pgst.scalef
|
||||
source: 'images/pageshadow.png'
|
||||
opacity: .2
|
||||
}
|
||||
}
|
||||
|
60
qml/SlidePageHeader.qml
Normal file
|
@ -0,0 +1,60 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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 'constants.js' as Constants
|
||||
|
||||
Item {
|
||||
id: slidePageHeader
|
||||
property string title
|
||||
|
||||
width: parent.width
|
||||
height: Constants.layout.header.height * pgst.scalef
|
||||
|
||||
Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
topMargin: slidePageHeader.height * 0.15
|
||||
}
|
||||
|
||||
height: slidePageHeader.height * 0.7
|
||||
color: '#33000000'
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
rightMargin: 20 * pgst.scalef
|
||||
leftMargin: 70 * pgst.scalef
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
color: 'white'
|
||||
horizontalAlignment: Text.AlignRight
|
||||
font.pixelSize: parent.height * .4 * pgst.scalef
|
||||
elide: Text.ElideRight
|
||||
text: parent.title
|
||||
}
|
||||
}
|
||||
|
63
qml/Stacking.qml
Normal file
|
@ -0,0 +1,63 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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: 'x'
|
||||
to: 0
|
||||
duration: 500
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
PropertyAnimation {
|
||||
id: fadeOut
|
||||
target: stacking.page
|
||||
property: 'x'
|
||||
to: stacking.page.width
|
||||
duration: 500
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
function startFadeOut() {
|
||||
fadeOut.start();
|
||||
page.destroy(500);
|
||||
}
|
||||
|
||||
function fadeInAgain() {
|
||||
fadeIn.start();
|
||||
}
|
||||
|
||||
function stopAllAnimations() {
|
||||
fadeIn.stop();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
page.x = page.width;
|
||||
fadeIn.start();
|
||||
}
|
||||
}
|
||||
|
235
qml/StartPage.qml
Normal file
|
@ -0,0 +1,235 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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
|
||||
|
||||
SlidePage {
|
||||
id: startPage
|
||||
canClose: false
|
||||
|
||||
function update_stats() {
|
||||
py.call('main.get_stats', [], function (result) {
|
||||
stats.text = result;
|
||||
});
|
||||
|
||||
py.call('main.get_fresh_episodes_summary', [3], function (episodes) {
|
||||
freshEpisodesRepeater.model = episodes;
|
||||
});
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
py.setHandler('update-stats', startPage.update_stats);
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
py.setHandler('update-stats', undefined);
|
||||
}
|
||||
|
||||
Flickable {
|
||||
Connections {
|
||||
target: pgst
|
||||
onReadyChanged: {
|
||||
if (pgst.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
|
||||
|
||||
Image {
|
||||
id: subscriptions
|
||||
source: 'images/subscriptions.png'
|
||||
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
margins: 20 * pgst.scalef
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StartPageButton {
|
||||
id: freshEpisodesPage
|
||||
|
||||
title: 'Fresh episodes'
|
||||
onClicked: pgst.loadPage('FreshEpisodes.qml');
|
||||
|
||||
Component.onCompleted: {
|
||||
py.setHandler('refreshing', function (is_refreshing) {
|
||||
refresherButtonArea.visible = !is_refreshing;
|
||||
if (!is_refreshing) {
|
||||
freshEpisodesPage.title = 'Fresh episodes';
|
||||
}
|
||||
});
|
||||
|
||||
py.setHandler('refresh-progress', function (pos, total) {
|
||||
freshEpisodesPage.title = 'Refreshing feeds (' + pos + '/' + total + ')';
|
||||
});
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 50 * pgst.scalef
|
||||
anchors.leftMargin: 20 * pgst.scalef
|
||||
anchors.left: parent.left
|
||||
spacing: 10 * pgst.scalef
|
||||
|
||||
Repeater {
|
||||
id: freshEpisodesRepeater
|
||||
|
||||
Image {
|
||||
source: modelData.coverart
|
||||
sourceSize { width: 80 * pgst.scalef; height: 80 * pgst.scalef }
|
||||
width: 80 * pgst.scalef
|
||||
height: 80 * pgst.scalef
|
||||
|
||||
PLabel {
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: parent.bottom
|
||||
margins: 5 * pgst.scalef
|
||||
}
|
||||
|
||||
text: modelData.newEpisodes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ButtonArea {
|
||||
id: refresherButtonArea
|
||||
|
||||
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
|
||||
|
||||
Image {
|
||||
id: refresher
|
||||
source: 'images/search.png'
|
||||
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
margins: 20 * pgst.scalef
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ButtonArea {
|
||||
onClicked: pgst.loadPage('Settings.qml');
|
||||
|
||||
anchors {
|
||||
left: recommendationsPane.left
|
||||
right: recommendationsPane.right
|
||||
}
|
||||
|
||||
height: 100 * pgst.scalef
|
||||
|
||||
PLabel {
|
||||
anchors.centerIn: parent
|
||||
text: 'Settings'
|
||||
}
|
||||
}
|
||||
|
||||
StartPageButton {
|
||||
id: recommendationsPane
|
||||
|
||||
title: 'Recommendations'
|
||||
onClicked: pgst.loadPage('Settings.qml');
|
||||
|
||||
Row {
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
bottom: parent.bottom
|
||||
margins: 40 * pgst.scalef
|
||||
}
|
||||
|
||||
spacing: 20 * pgst.scalef
|
||||
|
||||
Connections {
|
||||
target: pgst
|
||||
onReadyChanged: {
|
||||
if (pgst.ready) {
|
||||
py.call('main.load_podcasts', [], function (podcasts) {
|
||||
recommendationsRepeater.model = podcasts.splice(0, 4);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: recommendationsRepeater
|
||||
Image { source: modelData.coverart; sourceSize { width: 80 * pgst.scalef; height: 80 * pgst.scalef } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
42
qml/StartPageButton.qml
Normal file
|
@ -0,0 +1,42 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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
|
||||
}
|
||||
}
|
||||
|
64
qml/Subscribe.qml
Normal file
|
@ -0,0 +1,64 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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
|
||||
|
||||
SlidePage {
|
||||
id: subscribe
|
||||
|
||||
SlidePageHeader { title: 'Add subscription' }
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
33
qml/constants.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
var layout = {
|
||||
header: {
|
||||
height: 100, /* page header height */
|
||||
},
|
||||
};
|
||||
|
||||
var colors = {
|
||||
download: '#8ae234', /* download green */
|
||||
select: '#7f5785', /* gpodder dark purple */
|
||||
fresh: '#cf65de', /* gpodder purple */
|
||||
playback: '#729fcf', /* playback blue */
|
||||
};
|
||||
|
BIN
qml/images/delete.png
Normal file
After Width: | Height: | Size: 394 B |
BIN
qml/images/gpodder.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
qml/images/mask.png
Normal file
After Width: | Height: | Size: 151 KiB |
BIN
qml/images/noise.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
qml/images/pageshadow.png
Normal file
After Width: | Height: | Size: 162 B |
BIN
qml/images/play.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
qml/images/search.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
qml/images/subscriptions.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
33
qml/util.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
|
||||
/**
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
function updateModelFrom(model, data) {
|
||||
for (var i=0; i<data.length; i++) {
|
||||
if (model.count < i) {
|
||||
model.append(data[i]);
|
||||
} else {
|
||||
model.set(i, data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
while (model.count > data.length) {
|
||||
model.remove(model.count-1);
|
||||
}
|
||||
}
|