diff --git a/common/GPodderCore.qml b/common/GPodderCore.qml index 7920d32..a5983f3 100644 --- a/common/GPodderCore.qml +++ b/common/GPodderCore.qml @@ -77,16 +77,6 @@ Python { }); } - function setConfig(key, value) { - py.call('main.set_config_value', [key, value]); - } - - function getConfig(key, callback) { - py.call('main.get_config_value', [key], function (result) { - callback(result); - }); - } - onReceived: { console.log('unhandled message: ' + data); } diff --git a/common/GPodderEpisodeListModel.qml b/common/GPodderEpisodeListModel.qml index a51b540..f8e632f 100644 --- a/common/GPodderEpisodeListModel.qml +++ b/common/GPodderEpisodeListModel.qml @@ -62,6 +62,14 @@ ListModel { }); } + onPodcast_idChanged: { + reload(); + } + + property var worker: ModelWorkerScript { + id: modelWorker + } + function forEachEpisode(callback) { // Go from bottom up (= chronological order) for (var i=count-1; i>=0; i--) { @@ -122,11 +130,12 @@ ListModel { ready = false; py.call('main.load_episodes', [podcast_id, query], function (episodes) { - Util.updateModelFrom(episodeListModel, episodes); - episodeListModel.ready = true; - if (callback !== undefined) { - callback(); - } + modelWorker.updateModelFrom(episodeListModel, episodes, function () { + episodeListModel.ready = true; + if (callback !== undefined) { + callback(); + } + }); }); } } diff --git a/common/GPodderEpisodeListModelConnections.qml b/common/GPodderEpisodeListModelConnections.qml index 9744dab..22806ad 100644 --- a/common/GPodderEpisodeListModelConnections.qml +++ b/common/GPodderEpisodeListModelConnections.qml @@ -26,11 +26,11 @@ Connections { target: py onDownloadProgress: { - Util.updateModelWith(episodeListModel, 'id', episode_id, + episodeListModel.worker.updateModelWith(episodeListModel, 'id', episode_id, {'progress': progress}); } onPlaybackProgress: { - Util.updateModelWith(episodeListModel, 'id', episode_id, + episodeListModel.worker.updateModelWith(episodeListModel, 'id', episode_id, {'playbackProgress': progress}); } onUpdatedEpisode: { diff --git a/common/GPodderPlatform.qml b/common/GPodderPlatform.qml index 57fb97d..3fe70b1 100644 --- a/common/GPodderPlatform.qml +++ b/common/GPodderPlatform.qml @@ -26,11 +26,9 @@ Item { property bool android: (typeof(gpodderAndroid) !== 'undefined') || emulatingAndroid property bool needsBackButton: !android - - property bool toolbarOnTop: true + property bool toolbarOnTop: android property bool invertedToolbar: toolbarOnTop property bool titleInToolbar: toolbarOnTop - - property bool floatingPlayButton: true - property bool hideDisabledMenu: true + property bool floatingPlayButton: android + property bool hideDisabledMenu: android } diff --git a/common/GPodderPodcastListModel.qml b/common/GPodderPodcastListModel.qml index 285bf16..aa17c2f 100644 --- a/common/GPodderPodcastListModel.qml +++ b/common/GPodderPodcastListModel.qml @@ -25,9 +25,13 @@ import 'util.js' as Util ListModel { id: podcastListModel + property var worker: ModelWorkerScript { + id: modelWorker + } + function reload() { py.call('main.load_podcasts', [], function (podcasts) { - Util.updateModelFrom(podcastListModel, podcasts); + modelWorker.updateModelFrom(podcastListModel, podcasts); }); } } diff --git a/common/ModelWorkerScript.qml b/common/ModelWorkerScript.qml new file mode 100644 index 0000000..19c0057 --- /dev/null +++ b/common/ModelWorkerScript.qml @@ -0,0 +1,67 @@ + +/** + * + * gPodder QML UI Reference Implementation + * Copyright (c) 2015, Thomas Perl + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + */ + +import QtQuick 2.0 + + +WorkerScript { + source: 'modelworker.js' + + property int callbacks_seq: 1 + property var callbacks: ({}) + + function refCallback(callback) { + var id = callbacks_seq++; + callbacks[id] = callback; + return id; + } + + function unrefCallback(callback) { + var result = callbacks[callback]; + delete callbacks[callback]; + return result; + } + + function updateModelFrom(model, data, callback) { + sendMessage({ + action: 'updateModelFrom', + model: model, + data: data, + callback: refCallback(callback), + }); + } + + function updateModelWith(model, key, value, update, callback) { + sendMessage({ + action: 'updateModelWith', + model: model, + key: key, + value: value, + update: update, + callback: refCallback(callback), + }); + } + + onMessage: { + if (messageObject.callback !== undefined) { + unrefCallback(messageObject.callback)(); + } + } +} diff --git a/common/modelworker.js b/common/modelworker.js new file mode 100644 index 0000000..44561bd --- /dev/null +++ b/common/modelworker.js @@ -0,0 +1,42 @@ +function updateModelFrom(model, data) { + // TODO: This is very naive at the moment, we should do proper remove(), + // move(), set() and insert() calls, so that the UI can animate changes. + for (var i=0; i data.length) { + model.remove(model.count-1); + } + + model.sync(); +} + +function updateModelWith(model, key, value, update) { + for (var row=0; row data.length) { - model.remove(model.count-1); - } -} - -function updateModelWith(model, key, value, update) { - for (var row=0; row 0: - yield '%02d:%02d:%02d' % (episode.total_time / (60 * 60), - (episode.total_time / 60) % 60, - episode.total_time % 60) + yield '%02d:%02d:%02d' % (episode.total_time / (60 * 60), (episode.total_time / 60) % 60, episode.total_time % 60) def show_podcast(self, podcast_id): podcast = self._get_podcast_by_id(podcast_id) @@ -423,7 +404,8 @@ class gPotherSide: return [{ 'label': provider.name, 'can_search': provider.kind == provider.PROVIDER_SEARCH - } for provider in sorted(registry.directory.select(select_provider), key=provider_sort_key, reverse=True)] + } for provider in sorted(registry.directory.select(select_provider), + key=provider_sort_key, reverse=True)] def get_directory_entries(self, provider, query): def match_provider(p): @@ -440,116 +422,6 @@ class gPotherSide: return [] - -PILL_TEMPLATE = """ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {left_text} - {left_text} - - - - - - - {right_text} - {right_text} - - - -""" - - -class PillExpression(object): - def __init__(self, **kwargs): - self.kwargs = kwargs - - def __call__(self, matchobj): - return str(eval(matchobj.group(1), self.kwargs)) - - -def pill_image_provider(image_id, requested_size): - left_text, right_text = (int(x) for x in image_id.split('/')) - - width = 44 - height = 24 - radius = 6 - font_size = 13 - - text_lx = width / 4 - text_rx = width * 3 / 4 - - charheight = font_size - charwidth = font_size / 1.3 - - if left_text: - text_lx -= charwidth * len(str(left_text)) / 2 - if right_text: - text_rx -= charwidth * len(str(right_text)) / 2 - - outer_style = 'stroke: #333333; stroke-width: 1; fill-opacity: 0; stroke-opacity: 0.6;' - inner_style = 'stroke: #ffffff; stroke-width: 1; fill-opacity: 0; stroke-opacity: 0.3;' - - expression = PillExpression(height=height, width=width, left_text=left_text, - right_text=right_text, radius=radius, - lx=text_lx, rx=text_rx, font_size=font_size, - outer_style=outer_style, inner_style=inner_style) - svg = re.sub(r'[{]([^}]+)[}]', expression, PILL_TEMPLATE) - return bytearray(svg.encode('utf-8')), (width, height), pyotherside.format_data - - -@pyotherside.set_image_provider -def gpotherside_image_provider(image_id, requested_size): - provider, args = image_id.split('/', 1) - if provider == 'pill': - return pill_image_provider(args, requested_size) - - raise ValueError('Unknown provider: %s' % (provider,)) - - gpotherside = gPotherSide() pyotherside.atexit(gpotherside.atexit) @@ -561,7 +433,6 @@ load_podcasts = gpotherside.load_podcasts load_episodes = gpotherside.load_episodes show_episode = gpotherside.show_episode play_episode = gpotherside.play_episode -import_opml = gpotherside.import_opml subscribe = gpotherside.subscribe unsubscribe = gpotherside.unsubscribe check_for_episodes = gpotherside.check_for_episodes diff --git a/makefile b/makefile index 0d05e9a..27a4fd0 100644 --- a/makefile +++ b/makefile @@ -1,5 +1,5 @@ PROJECT := gpodder-ui-qml -VERSION := 4.6.0 +VERSION := 4.4.0 all: @echo "" diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 68859ad..0000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[pep8] -max-line-length = 120 diff --git a/touch/AboutPage.qml b/touch/AboutPage.qml index 36944a4..fa62f11 100644 --- a/touch/AboutPage.qml +++ b/touch/AboutPage.qml @@ -73,7 +73,7 @@ SlidePage { anchors.horizontalCenter: parent.horizontalCenter wrapMode: Text.WordWrap text: [ - '© 2005-2015 Thomas Perl and the gPodder Team', + '© 2005-2014 Thomas Perl and the gPodder Team', 'License: ISC / GPLv3 or later', 'Website: http://gpodder.org/', '', diff --git a/touch/EpisodeItem.qml b/touch/EpisodeItem.qml index 8a8a55e..8e28d15 100644 --- a/touch/EpisodeItem.qml +++ b/touch/EpisodeItem.qml @@ -135,22 +135,22 @@ Item { Rectangle { anchors { top: parent.top - left: parent.left + left: downloadIndicator.right } height: Constants.layout.padding * pgst.scalef - width: parent.width * progress + width: (parent.width - downloadIndicator.width) * progress color: Constants.colors.download } Rectangle { anchors { bottom: parent.bottom - left: parent.left + left: downloadIndicator.right } height: Constants.layout.padding * pgst.scalef - width: parent.width * playbackProgress + width: (parent.width - downloadIndicator.width) * playbackProgress color: titleLabel.color opacity: episodeItem.isPlaying ? 1 : .2 } @@ -163,17 +163,27 @@ Item { right: parent.right } - RectangleIndicator { + Rectangle { id: downloadIndicator - enabled: downloadState == Constants.state.downloaded + + width: Constants.layout.padding * pgst.scalef * (downloadState == Constants.state.downloaded) + + Behavior on width { PropertyAnimation { } } + + anchors { + top: parent.top + bottom: parent.bottom + left: parent.left + } + color: titleLabel.color } Column { anchors { left: parent.left - leftMargin: Constants.layout.padding * pgst.scalef - right: downloadIndicator.left + leftMargin: 2 * Constants.layout.padding * pgst.scalef + right: parent.right rightMargin: Constants.layout.padding * pgst.scalef verticalCenter: parent.verticalCenter } diff --git a/touch/EpisodeListView.qml b/touch/EpisodeListView.qml index 4fd0088..3b96397 100644 --- a/touch/EpisodeListView.qml +++ b/touch/EpisodeListView.qml @@ -29,6 +29,7 @@ PListView { id: episodeList property int selectedIndex: -1 + property alias podcast_id: episodeListModel.podcast_id PScrollIntoView { id: scrollIntoView } @@ -42,14 +43,14 @@ PListView { GPodderEpisodeListModelConnections {} PBusyIndicator { - visible: !episodeListModel.ready + visible: !episodeListModel.ready && episodeListModel.podcast_id anchors.centerIn: parent } PPlaceholder { // TODO: If filter is "all", say "No episodes" - text: 'No episodes found' - visible: episodeList.count === 0 && episodeListModel.ready + text: episodeListModel.podcast_id ? 'No episodes found' : 'No podcast selected' + visible: (episodeList.count === 0 && episodeListModel.ready) || !episodeListModel.podcast_id } delegate: EpisodeItem { } diff --git a/touch/EpisodeQueryPage.qml b/touch/EpisodeQueryPage.qml index bf8f423..ebd8d01 100644 --- a/touch/EpisodeQueryPage.qml +++ b/touch/EpisodeQueryPage.qml @@ -44,10 +44,6 @@ SlidePage { title: 'Episodes' section.property: 'section' - section.delegate: SectionHeader { - text: section - color: episodeList.selectedIndex === -1 ? Constants.colors.secondaryHighlight : Constants.colors.text - opacity: episodeList.selectedIndex === -1 ? 1 : 0.2 - } + section.delegate: SectionHeader { text: section } } } diff --git a/touch/EpisodesPage.qml b/touch/EpisodesPage.qml index dc046c2..6604593 100644 --- a/touch/EpisodesPage.qml +++ b/touch/EpisodesPage.qml @@ -80,12 +80,6 @@ SlidePage { ], undefined, undefined, true); } - - Component.onCompleted: { - episodeList.model.podcast_id = podcast_id; - // List model will be loaded automatically on load - } - EpisodeQueryControl { id: queryControl model: episodeList.model @@ -95,5 +89,6 @@ SlidePage { EpisodeListView { id: episodeList title: page.title + podcast_id: page.podcast_id } } diff --git a/touch/IconContextMenu.qml b/touch/IconContextMenu.qml index 7703956..68711ea 100644 --- a/touch/IconContextMenu.qml +++ b/touch/IconContextMenu.qml @@ -20,8 +20,6 @@ import QtQuick 2.0 -import 'common/constants.js' as Constants - Item { id: contextMenu default property alias children: contextMenuRow.children @@ -29,10 +27,6 @@ Item { Row { id: contextMenuRow - anchors { - verticalCenter: parent.verticalCenter - right: parent.right - margins: Constants.layout.padding * pgst.scalef - } + anchors.centerIn: parent } } diff --git a/touch/Main.qml b/touch/Main.qml index 9d4f850..177c367 100644 --- a/touch/Main.qml +++ b/touch/Main.qml @@ -68,7 +68,7 @@ Item { // Initial focus focus: true - property real scalef: (width < height) ? (width / 480) : (height / 480) + property real scalef: 1.0 //(width < height) ? (width / 480) : (height / 480) property int shorterSide: (width < height) ? width : height property int dialogsVisible: 0 @@ -125,7 +125,7 @@ Item { pgst.hasBackButton = Qt.binding(function () { return page.isDialog || page.canClose; }); pgst.hasMenuButton = Qt.binding(function () { return !page.isDialog && page.hasMenuButton; }); pgst.menuButtonLabel = Qt.binding(function () { return (!page.isDialog && pgst.hasMenuButton) ? page.menuButtonLabel : 'Menu'; }); - pgst.menuButtonIcon = Qt.binding(function () { return (!page.isDialog && pgst.hasMenuButton) ? page.menuButtonIcon : Icons.stack; }); + pgst.menuButtonIcon = Qt.binding(function () { return (!page.isDialog && pgst.hasMenuButton) ? page.menuButtonIcon : Icons.vellipsis; }); if (!page.isDialog) { pgst.windowTitle = page.title || 'gPodder'; diff --git a/touch/PListView.qml b/touch/PListView.qml index e607207..7f077d6 100644 --- a/touch/PListView.qml +++ b/touch/PListView.qml @@ -30,19 +30,6 @@ ListView { boundsBehavior: Flickable.StopAtBounds - function relayout() { - var _contentY = contentY; - var _model = model; - model = null; - model = _model; - contentY = _contentY; - } - - Connections { - target: pgst - onScalefChanged: relayout(); - } - header: SlidePageHeader { id: header title: pListView.title diff --git a/touch/PSlider.qml b/touch/PSlider.qml index 2f6855f..eb32ad3 100644 --- a/touch/PSlider.qml +++ b/touch/PSlider.qml @@ -28,7 +28,6 @@ Item { property real value property real min: 0.0 property real max: 1.0 - property real step: 0.0 property color color: Constants.colors.highlight property real displayedValue: mouseArea.pressed ? temporaryValue : value @@ -43,22 +42,13 @@ Item { MouseArea { id: mouseArea anchors.fill: parent - function updateValue(x) { - if (x > width) { - x = width; - } else if (x < 0) { - x = 0; - } - var v = (max - min) * (x / width); - if (slider.step > 0.0) { - v = slider.step * parseInt(0.5 + v / slider.step); - } - slider.temporaryValue = min + v; - return slider.temporaryValue; + onClicked: slider.valueChangeRequested(min + (max - min) * (mouse.x / width)) + onPressed: { + slider.temporaryValue = (min + (max - min) * (mouse.x / width)); + } + onPositionChanged: { + slider.temporaryValue = (min + (max - min) * (mouse.x / width)); } - onClicked: slider.valueChangeRequested(updateValue(mouse.x)); - onPressed: updateValue(mouse.x); - onPositionChanged: updateValue(mouse.x); preventStealing: true } @@ -78,14 +68,4 @@ Item { verticalCenter: parent.verticalCenter } } - - Repeater { - model: slider.step ? ((slider.max - slider.min) / slider.step - 1) : 0 - delegate: Rectangle { - width: Math.max(1, 1 * pgst.scalef) - height: parent.height - color: Constants.colors.area - x: parent.width * ((slider.step * (1 + index)) / (slider.max - slider.min)); - } - } } diff --git a/touch/PTextField.qml b/touch/PTextField.qml index 6c33d2e..660d630 100644 --- a/touch/PTextField.qml +++ b/touch/PTextField.qml @@ -50,7 +50,6 @@ Item { right: clipboardIcon.left margins: 5 * pgst.scalef } - clip: true inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText diff --git a/touch/PodcastItem.qml b/touch/PodcastItem.qml index 3eb80fd..91c15d5 100644 --- a/touch/PodcastItem.qml +++ b/touch/PodcastItem.qml @@ -33,6 +33,19 @@ ButtonArea { right: parent.right } + Rectangle { + width: Constants.layout.padding * pgst.scalef * (newEpisodes > 0) + Behavior on width { PropertyAnimation { } } + + anchors { + top: cover.top + bottom: cover.bottom + left: parent.left + } + + color: Constants.colors.fresh + } + CoverArt { id: cover visible: !updating @@ -72,7 +85,7 @@ ButtonArea { PLabel { id: downloadsLabel anchors { - right: newEpisodesIndicator.enabled ? newEpisodesIndicator.left : parent.right + right: parent.right rightMargin: Constants.layout.padding * pgst.scalef verticalCenter: parent.verticalCenter } @@ -80,10 +93,4 @@ ButtonArea { text: downloaded ? downloaded : '' color: Constants.colors.text } - - RectangleIndicator { - id: newEpisodesIndicator - enabled: newEpisodes > 0 - color: Constants.colors.fresh - } } diff --git a/touch/PodcastsPage.qml b/touch/PodcastsPage.qml index 6cdab93..f4a6d58 100644 --- a/touch/PodcastsPage.qml +++ b/touch/PodcastsPage.qml @@ -25,8 +25,9 @@ import 'common/util.js' as Util import 'icons/icons.js' as Icons import 'common/constants.js' as Constants -SlidePage { +SplitPage { id: page + position: 0.4 canClose: false @@ -47,9 +48,9 @@ SlidePage { } }, { - label: 'Settings', + label: 'About', callback: function () { - pgst.loadPage('SettingsPage.qml'); + pgst.loadPage('AboutPage.qml'); }, }, { @@ -66,20 +67,6 @@ SlidePage { }); }, }, - { - label: 'Add from OPML', - callback: function () { - var ctx = { py: py }; - pgst.loadPage('TextInputDialog.qml', { - buttonText: 'Subscribe', - placeholderText: 'OPML URL', - pasteOnLoad: true, - callback: function (url) { - ctx.py.call('main.import_opml', [url]); - } - }); - }, - }, { label: 'Discover new podcasts', callback: function () { @@ -105,67 +92,80 @@ SlidePage { ], undefined, undefined, true); } - PListView { - id: podcastList - title: 'Subscriptions' + SplitPane { + PListView { + id: podcastList + title: 'Subscriptions' - section.property: 'section' - section.delegate: SectionHeader { text: section } + section.property: 'section' + section.delegate: SectionHeader { text: section } - PPlaceholder { - text: 'No podcasts' - visible: podcastList.count === 0 - } + PPlaceholder { + text: 'No podcasts' + visible: podcastList.count === 0 + } - model: podcastListModel + model: podcastListModel - delegate: PodcastItem { - onClicked: pgst.loadPage('EpisodesPage.qml', {'podcast_id': id, 'title': title}); - onPressAndHold: { - pgst.showSelection([ - { - label: 'Refresh', - callback: function () { - py.call('main.check_for_episodes', [url]); + delegate: PodcastItem { + onClicked: { + episodesPage.podcast_id = id; + episodesPage.title = title; + }//pgst.loadPage('EpisodesPage.qml', {'podcast_id': id, 'title': title}); + onPressAndHold: { + pgst.showSelection([ + { + label: 'Refresh', + callback: function () { + py.call('main.check_for_episodes', [url]); + }, }, - }, - { - 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: '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: 'Mark episodes as old', - callback: function () { - py.call('main.mark_episodes_as_old', [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: 'Podcast details', - callback: function () { - pgst.loadPage('PodcastDetail.qml', {podcast_id: id, title: title}); - } - }, - ], title); + { + label: 'Mark episodes as old', + callback: function () { + py.call('main.mark_episodes_as_old', [id]); + }, + }, + { + label: 'Podcast details', + callback: function () { + pgst.loadPage('PodcastDetail.qml', {podcast_id: id, title: title}); + } + }, + ], title); + } } } } + + SplitPane { + EpisodesPage { + id: episodesPage + + anchors.fill: parent + } + } } diff --git a/touch/SectionHeader.qml b/touch/SectionHeader.qml index 7ce75e0..55234f6 100644 --- a/touch/SectionHeader.qml +++ b/touch/SectionHeader.qml @@ -24,29 +24,15 @@ import 'common/constants.js' as Constants Item { property alias text: pLabel.text - property alias color: pLabel.color height: 70 * pgst.scalef - width: parent.width - - Rectangle { - anchors { - verticalCenter: parent.verticalCenter - left: parent.left - right: pLabel.left - margins: Constants.layout.padding * pgst.scalef - } - - color: pLabel.color - height: 1 * pgst.scalef - } PLabel { id: pLabel anchors { - right: parent.right - verticalCenter: parent.verticalCenter - margins: Constants.layout.padding * pgst.scalef + left: parent.left + bottom: parent.bottom + margins: 10 * pgst.scalef } color: Constants.colors.secondaryHighlight diff --git a/touch/SettingsPage.qml b/touch/SettingsPage.qml deleted file mode 100644 index 8d47886..0000000 --- a/touch/SettingsPage.qml +++ /dev/null @@ -1,113 +0,0 @@ - -/** - * - * gPodder QML UI Reference Implementation - * Copyright (c) 2015, Thomas Perl - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - * - */ - -import QtQuick 2.0 - -import 'common/constants.js' as Constants - -SlidePage { - id: page - - Component.onCompleted: { - py.getConfig('plugins.youtube.api_key_v3', function (value) { - youtube_api_key_v3.text = value; - }); - py.getConfig('limit.episodes', function (value) { - limit_episodes.value = value; - }); - } - - Component.onDestruction: { - py.setConfig('plugins.youtube.api_key_v3', youtube_api_key_v3.text); - py.setConfig('limit.episodes', parseInt(limit_episodes.value)); - } - - Flickable { - id: flickable - anchors.fill: parent - boundsBehavior: Flickable.StopAtBounds - - contentWidth: detailColumn.width - contentHeight: detailColumn.height + detailColumn.spacing - - Column { - id: detailColumn - - width: page.width - spacing: 15 * pgst.scalef - - SlidePageHeader { title: 'Settings' } - - SectionHeader { text: 'YouTube' } - - SettingsLabel { text: 'API Key (v3)' } - - PTextField { - id: youtube_api_key_v3 - anchors { - left: parent.left - right: parent.right - margins: Constants.layout.padding * pgst.scalef - } - } - - SectionHeader { text: 'Limits' } - - SettingsLabel { text: 'Maximum episodes per feed' } - - PSlider { - id: limit_episodes - min: 100 - step: 100 - max: 1000 - anchors { - left: parent.left - right: parent.right - margins: Constants.layout.padding * pgst.scalef - } - onValueChangeRequested: { value = newValue; } - } - - PLabel { - text: parseInt(limit_episodes.displayedValue) - anchors { - left: parent.left - right: parent.right - margins: Constants.layout.padding * pgst.scalef - } - } - - SectionHeader { text: 'About' } - - ButtonArea { - width: parent.width - height: Constants.layout.item.height * pgst.scalef - PLabel { - anchors.centerIn: parent - text: 'About gPodder ' + py.uiversion - } - onClicked: pgst.loadPage('AboutPage.qml') - } - } - } - - PScrollDecorator { flickable: flickable } -} - diff --git a/touch/SlidePage.qml b/touch/SlidePage.qml index cdad75f..182fdf6 100644 --- a/touch/SlidePage.qml +++ b/touch/SlidePage.qml @@ -36,7 +36,7 @@ Rectangle { property string title: '' property bool hasMenuButton: false property string menuButtonLabel: 'Menu' - property string menuButtonIcon: Icons.stack + property string menuButtonIcon: Icons.vellipsis signal menuButtonClicked() function closePage() { diff --git a/touch/RectangleIndicator.qml b/touch/SplitPage.qml similarity index 70% rename from touch/RectangleIndicator.qml rename to touch/SplitPage.qml index 08adccd..dd580e5 100644 --- a/touch/RectangleIndicator.qml +++ b/touch/SplitPage.qml @@ -22,15 +22,13 @@ import QtQuick 2.0 import 'common/constants.js' as Constants -Rectangle { - width: Constants.layout.padding * 2 * pgst.scalef * enabled - height: width +SlidePage { + id: splitPage + property real position: 0.5 - Behavior on width { PropertyAnimation { } } - - anchors { - verticalCenter: parent.verticalCenter - right: parent.right - margins: Constants.layout.padding * 2 * pgst.scalef - width / 2 + Component.onCompleted: { + children[0].width = Qt.binding(function () { return splitPage.width * splitPage.position; }); + children[1].width = Qt.binding(function () { return splitPage.width * (1.0 - splitPage.position); }); + children[1].x = Qt.binding(function () { return children[0].width; }); } } diff --git a/touch/SettingsLabel.qml b/touch/SplitPane.qml similarity index 80% rename from touch/SettingsLabel.qml rename to touch/SplitPane.qml index 643189e..db89e25 100644 --- a/touch/SettingsLabel.qml +++ b/touch/SplitPane.qml @@ -1,4 +1,5 @@ + /** * * gPodder QML UI Reference Implementation @@ -20,13 +21,9 @@ import QtQuick 2.0 -import 'common/constants.js' as Constants - -PLabel { +Item { anchors { - left: parent.left - right: parent.right - margins: Constants.layout.padding * pgst.scalef + top: parent.top + bottom: parent.bottom } - color: Constants.colors.secondaryHighlight } diff --git a/touch/gpodder.qml b/touch/gpodder.qml index 122ff47..5df7a5d 100644 --- a/touch/gpodder.qml +++ b/touch/gpodder.qml @@ -24,7 +24,7 @@ import 'common/constants.js' as Constants Rectangle { color: Constants.colors.page - width: 480 + width: 1280 height: 800 Main {} diff --git a/touch/icons/icons.js b/touch/icons/icons.js index 344a50b..4372966 100644 --- a/touch/icons/icons.js +++ b/touch/icons/icons.js @@ -19,8 +19,8 @@ var folder = '\ue065'; var magnifying_glass = '\ue074'; var cog = '\u2699'; var link = '\ue077'; +var vellipsis = '\u22ee'; var paperclip = '\ue08a'; var tag_fill = '\ue02b'; var headphones = '\ue061'; var sleep = '\u263e'; -var stack = '\ue020';