From e95ec1f76a0ef678bedf5a22fb4328c1f4284fc0 Mon Sep 17 00:00:00 2001 From: Thomas Perl Date: Sat, 7 Mar 2015 17:36:23 +0100 Subject: [PATCH] Experimental tablet UI --- common/GPodderEpisodeListModel.qml | 4 + touch/EpisodeListView.qml | 7 +- touch/EpisodesPage.qml | 7 +- touch/Main.qml | 2 +- touch/PodcastsPage.qml | 122 ++++++++++++++++------------- touch/SplitPage.qml | 34 ++++++++ touch/SplitPane.qml | 29 +++++++ touch/gpodder.qml | 2 +- 8 files changed, 142 insertions(+), 65 deletions(-) create mode 100644 touch/SplitPage.qml create mode 100644 touch/SplitPane.qml diff --git a/common/GPodderEpisodeListModel.qml b/common/GPodderEpisodeListModel.qml index 33535b6..f8e632f 100644 --- a/common/GPodderEpisodeListModel.qml +++ b/common/GPodderEpisodeListModel.qml @@ -62,6 +62,10 @@ ListModel { }); } + onPodcast_idChanged: { + reload(); + } + property var worker: ModelWorkerScript { id: modelWorker } 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/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/Main.qml b/touch/Main.qml index 28c89f7..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 diff --git a/touch/PodcastsPage.qml b/touch/PodcastsPage.qml index b07129f..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 @@ -91,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/SplitPage.qml b/touch/SplitPage.qml new file mode 100644 index 0000000..dd580e5 --- /dev/null +++ b/touch/SplitPage.qml @@ -0,0 +1,34 @@ + +/** + * + * 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: splitPage + property real position: 0.5 + + 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/SplitPane.qml b/touch/SplitPane.qml new file mode 100644 index 0000000..db89e25 --- /dev/null +++ b/touch/SplitPane.qml @@ -0,0 +1,29 @@ + + +/** + * + * 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 + +Item { + anchors { + top: parent.top + bottom: parent.bottom + } +} 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 {}