git.iko.soy/maciek134/podphoenix
on main help sign in
Merged devel branch 134 (added multiselect mode)
commitb2ae9ad26c9ed22b464c373053eeb8efc4ed9baf authorNekhelesh Ramananthan <krnekhelesh@gmail.com> dateSat 19 Mar 2016, 14:38 (11 years ago) parenta7311c4
6 files changed+257−96
app/components/CustomSectionHeader.qml+47 app/podbird.qml+2−2 app/podcasts.js+1 app/ui/EpisodesPage.qml+2−2 app/ui/EpisodesTab.qml+205−86 app/ui/Queue.qml−6
app/components/CustomSectionHeader.qmlnew file+47
@@ -0,0 +1,47 @@
1+/*
2+ * Copyright 2016 Podbird Team
3+ *
4+ * This file is part of Podbird.
5+ *
6+ * Podbird is free software; you can redistribute it and/or modify
7+ * it under the terms of the GNU General Public License as published by
8+ * the Free Software Foundation; version 3.
9+ *
10+ * Podbird is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License
16+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+import QtQuick 2.4
20+import Ubuntu.Components 1.3
21+
22+Item {
23+ id: customSectionHeader
24+
25+ property alias title: headerText.text
26+
27+ height: headerText.text !== "" ? headerText.implicitHeight + divider.height + headerText.anchors.topMargin + headerText.anchors.bottomMargin
28+ : units.gu(0)
29+
30+ anchors { left: parent.left; right: parent.right; margins: units.gu(2) }
31+
32+ Label {
33+ id: headerText
34+ color: podbird.appTheme.baseText
35+ font.weight: Font.DemiBold
36+ anchors { top: parent.top; topMargin: units.gu(2); bottom: parent.bottom; bottomMargin: units.gu(2) }
37+ width: parent.width
38+ }
39+
40+ Rectangle {
41+ id: divider
42+ color: settings.themeName === "Dark.qml" ? "#888888" : "#cdcdcd"
43+ width: parent.width
44+ height: units.dp(1)
45+ anchors.bottom: parent.bottom
46+ }
47+}
app/podbird.qml+2−2
@@ -221,16 +221,16 @@ MainView {
221221 Podcasts.clearQueue()
222222
223223 // Add episode to queue
224− player.playlist.addItem(Qt.resolvedUrl(url))
225224 Podcasts.addItemToQueue(guid, image, name, artist, url)
225+ player.playlist.addItem(url)
226226
227227 // Play episode
228228 player.play()
229229 }
230230
231231 function addEpisodeToQueue(guid, image, name, artist, url) {
232− player.playlist.addItem(Qt.resolvedUrl(url))
233232 Podcasts.addItemToQueue(guid, image, name, artist, url)
233+ player.playlist.addItem(url)
234234
235235 // If added episode is the first one in the queue, then set the current metadata
236236 // so that the bottom player controls will be shown, allowing the user to play
app/podcasts.js+1
@@ -49,6 +49,7 @@ function addItemToQueue(guid, image, name, artist, url) {
4949 var rs = tx.executeSql("INSERT OR REPLACE INTO Queue (ind, guid, image, name, artist, url) VALUES (?, ?, ?, ?, ?, ?)", [ind, guid, image, name, artist, url]);
5050 if (rs.rowsAffected > 0) {
5151 console.log("[LOG]: QUEUE add OK")
52+ console.log("[LOG]: URL Added to queue: " + url)
5253 } else {
5354 console.log("[LOG]: QUEUE add FAIL")
5455 }
app/ui/EpisodesPage.qml+2−2
@@ -517,7 +517,7 @@ Page {
517517 Action {
518518 iconName: "add-to-playlist"
519519 onTriggered: {
520− var url = model.downloadedfile ? model.downloadedfile : model.audiourl
520+ var url = model.downloadedfile ? "file://" + model.downloadedfile : model.audiourl
521521 player.addEpisodeToQueue(model.guid, model.image, model.name, model.artist, url)
522522 }
523523 },
@@ -549,7 +549,7 @@ Page {
549549 onClicked: {
550550 Haptics.play()
551551 if (currentGuid !== model.guid) {
552− currentUrl = model.downloadedfile ? model.downloadedfile : model.audiourl;
552+ currentUrl = model.downloadedfile ? "file://" + model.downloadedfile : model.audiourl;
553553 player.playEpisode(model.guid, model.image, model.name, model.artist, currentUrl)
554554 }
555555 }
app/ui/EpisodesTab.qml+205−86
@@ -64,62 +64,6 @@ Tab {
6464 episodesPage.header = searchHeader
6565 searchField.item.forceActiveFocus()
6666 }
67− },
68−
69− Action {
70− iconName: "select"
71− visible: episodesPageHeaderSections.selectedIndex === 0
72− text: i18n.tr("Mark all listened")
73− onTriggered: {
74− var db = Podcasts.init();
75− db.transaction(function (tx) {
76− for (var i=0; i<episodesModel.count; i++) {
77− tx.executeSql("UPDATE Episode SET listened=1 WHERE guid=?", [episodesModel.get(i).guid]);
78− }
79− episodesModel.clear()
80− });
81− }
82− },
83−
84− Action {
85− iconName: "save"
86− visible: episodesPageHeaderSections.selectedIndex !== 1
87− text: i18n.tr("Download all")
88− onTriggered: {
89− var db = Podcasts.init();
90− db.transaction(function (tx) {
91− for (var i=0; i<episodesModel.count; i++) {
92− if (!episodesModel.get(i).downloadedfile) {
93− episodesModel.setProperty(i, "queued", 1)
94− tx.executeSql("UPDATE Episode SET queued=1 WHERE guid = ?", [episodesModel.get(i).guid]);
95− if (episodesModel.get(i).audiourl) {
96− podbird.downloadEpisode(episodesModel.get(i).image, episodesModel.get(i).name, episodesModel.get(i).guid, episodesModel.get(i).audiourl)
97− } else {
98− console.log("[ERROR]: Invalid download url: " + episodesModel.get(i).audiourl)
99− }
100− }
101− }
102− });
103− }
104− },
105−
106− Action {
107− iconName: "delete"
108− text: i18n.tr("Delete all")
109− visible: episodesPageHeaderSections.selectedIndex === 1
110− onTriggered: {
111− var db = Podcasts.init();
112− db.transaction(function (tx) {
113− for (var i=0; i<episodesModel.count; i++) {
114− if (episodesModel.get(i).downloadedfile) {
115− fileManager.deleteFile(episodesModel.get(i).downloadedfile);
116− tx.executeSql("UPDATE Episode SET downloadedfile = NULL WHERE guid = ?", [episodesModel.get(i).guid]);
117− episodesModel.setProperty(i, "downloadedfile", "")
118− }
119− }
120− });
121− refreshModel();
122− }
12367 }
12468 ]
12569
@@ -177,6 +121,169 @@ Tab {
177121 }
178122 }
179123
124+ PageHeader {
125+ id: selectionHeader
126+ visible: episodeList.ViewItems.selectMode
127+
128+ onVisibleChanged: {
129+ if (visible) {
130+ episodesPage.header = selectionHeader
131+ }
132+ }
133+
134+ StyleHints {
135+ backgroundColor: podbird.appTheme.background
136+ }
137+
138+ leadingActionBar.actions: [
139+ Action {
140+ iconName: "back"
141+ text: i18n.tr("Back")
142+ onTriggered: {
143+ episodeList.closeSelection()
144+ }
145+ }
146+ ]
147+
148+ trailingActionBar {
149+ numberOfSlots: 6
150+ actions: [
151+ Action {
152+ iconName: "select"
153+ text: i18n.tr("Mark Listened")
154+ enabled: episodeList.ViewItems.selectedIndices.length !== 0
155+ onTriggered: {
156+ var db = Podcasts.init();
157+ db.transaction(function (tx) {
158+ for (var i=0; i<episodeList.ViewItems.selectedIndices.length; i++) {
159+ var index = episodeList.ViewItems.selectedIndices[i]
160+ tx.executeSql("UPDATE Episode SET listened=1 WHERE guid=?", [episodesModel.get(index).guid]);
161+ }
162+ });
163+
164+ refreshModel();
165+ episodeList.closeSelection()
166+ }
167+ },
168+
169+ Action {
170+ iconName: "save"
171+ text: i18n.tr("Download episode(s)")
172+ enabled: episodeList.ViewItems.selectedIndices.length !== 0
173+ visible: episodesPageHeaderSections.selectedIndex !== 1
174+
175+ onTriggered: {
176+ var db = Podcasts.init();
177+ db.transaction(function (tx) {
178+ for (var i=0; i<episodeList.ViewItems.selectedIndices.length; i++) {
179+ var index = episodeList.ViewItems.selectedIndices[i]
180+ if (!episodesModel.get(index).downloadedfile) {
181+ episodesModel.setProperty(index, "queued", 1)
182+ tx.executeSql("UPDATE Episode SET queued=1 WHERE guid = ?", [episodesModel.get(index).guid]);
183+ if (episodesModel.get(index).audiourl) {
184+ podbird.downloadEpisode(episodesModel.get(index).image, episodesModel.get(index).name, episodesModel.get(index).guid, episodesModel.get(index).audiourl)
185+ } else {
186+ console.log("[ERROR]: Invalid download url: " + episodesModel.get(index).audiourl)
187+ }
188+ }
189+ }
190+ });
191+
192+ refreshModel();
193+ episodeList.closeSelection()
194+ }
195+ },
196+
197+ Action {
198+ iconName: "delete"
199+ text: i18n.tr("Delete episode(s)")
200+ enabled: episodeList.ViewItems.selectedIndices.length !== 0
201+
202+ onTriggered: {
203+ var db = Podcasts.init();
204+ db.transaction(function (tx) {
205+ for (var i=0; i<episodeList.ViewItems.selectedIndices.length; i++) {
206+ var index = episodeList.ViewItems.selectedIndices[i]
207+ if (episodesModel.get(index).downloadedfile) {
208+ fileManager.deleteFile(episodesModel.get(index).downloadedfile);
209+ tx.executeSql("UPDATE Episode SET downloadedfile = NULL WHERE guid = ?", [episodesModel.get(index).guid]);
210+ episodesModel.setProperty(index, "downloadedfile", "")
211+ }
212+ }
213+ });
214+
215+ refreshModel();
216+ episodeList.closeSelection()
217+ }
218+ },
219+
220+ Action {
221+ iconName: "like"
222+ text: i18n.tr("Favourite episode(s)")
223+ visible: episodesPageHeaderSections.selectedIndex !== 2
224+ enabled: episodeList.ViewItems.selectedIndices.length !== 0
225+
226+ onTriggered: {
227+ var db = Podcasts.init();
228+ db.transaction(function (tx) {
229+ for (var i=0; i<episodeList.ViewItems.selectedIndices.length; i++) {
230+ var index = episodeList.ViewItems.selectedIndices[i]
231+ if (!episodesModel.get(index).favourited) {
232+ tx.executeSql("UPDATE Episode SET favourited=1 WHERE guid=?", [episodesModel.get(index).guid])
233+ episodesModel.setProperty(index, "favourited", 1)
234+ }
235+ }
236+ });
237+
238+ refreshModel();
239+ episodeList.closeSelection()
240+ }
241+ },
242+
243+ Action {
244+ iconName: "unlike"
245+ text: i18n.tr("Unfavourite episode(s)")
246+ visible: episodesPageHeaderSections.selectedIndex === 2
247+ enabled: episodeList.ViewItems.selectedIndices.length !== 0
248+
249+ onTriggered: {
250+ var db = Podcasts.init();
251+ db.transaction(function (tx) {
252+ for (var i=0; i<episodeList.ViewItems.selectedIndices.length; i++) {
253+ var index = episodeList.ViewItems.selectedIndices[i]
254+ if (episodesModel.get(index).favourited) {
255+ tx.executeSql("UPDATE Episode SET favourited=0 WHERE guid=?", [episodesModel.get(index).guid])
256+ episodesModel.setProperty(index, "favourited", 0)
257+ }
258+ }
259+ });
260+
261+ refreshModel();
262+ episodeList.closeSelection()
263+ }
264+ },
265+
266+ Action {
267+ iconName: "add-to-playlist"
268+ text: i18n.tr("Add to queue")
269+ enabled: episodeList.ViewItems.selectedIndices.length !== 0
270+
271+ onTriggered: {
272+ for (var i=0; i<episodeList.ViewItems.selectedIndices.length; i++) {
273+ var index = episodeList.ViewItems.selectedIndices[i]
274+ if (episodesModel.get(index).audiourl) {
275+ var url = episodesModel.get(index).downloadedfile ? "file://" + episodesModel.get(index).downloadedfile : episodesModel.get(index).audiourl
276+ player.addEpisodeToQueue(episodesModel.get(index).guid, episodesModel.get(index).image, episodesModel.get(index).name, episodesModel.get(index).artist, url)
277+ }
278+ }
279+
280+ episodeList.closeSelection()
281+ }
282+ }
283+ ]
284+ }
285+ }
286+
180287 Loader {
181288 id: emptyState
182289
@@ -318,6 +425,9 @@ Tab {
318425 ListView {
319426 id: episodeList
320427
428+ signal clearSelection()
429+ signal closeSelection()
430+
321431 Component.onCompleted: {
322432 // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition
323433 // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration
@@ -341,8 +451,8 @@ Tab {
341451 visible: height !== 0
342452 height: downloader.downloads.length > 0 && episodesPageHeaderSections.selectedIndex === 1 ? childrenRect.height : 0
343453
344− HeaderListItem {
345− title.text: i18n.tr("Downloads in progress")
454+ CustomSectionHeader {
455+ title: i18n.tr("Downloads in progress")
346456 }
347457
348458 Repeater {
@@ -381,40 +491,31 @@ Tab {
381491 }
382492 }
383493
384− HeaderListItem {
385− title.text: i18n.tr("Downloaded episodes")
494+ CustomSectionHeader {
495+ title: i18n.tr("Downloaded episodes")
386496 visible: sortedEpisodeModel.count !== 0 || episodesModel.count !== 0
387497 }
388498 }
389499
390500 section.property: "diff"
391501 section.labelPositioning: ViewSection.InlineLabels
392− section.delegate: ListItem {
393− height: headerText.title.text !== "" ? headerText.height + divider.height : units.gu(0)
394− divider.anchors.leftMargin: units.gu(2)
395− divider.anchors.rightMargin: units.gu(2)
396−
397− ListItemLayout {
398− id: headerText
399− title.text: {
400− if (section === "Today") {
401− return i18n.tr("Today")
402− }
502+ section.delegate: CustomSectionHeader {
503+ title: {
504+ if (section === "Today") {
505+ return i18n.tr("Today")
506+ }
403507
404− else if (section === "Yesterday") {
405− return i18n.tr("Yesterday")
406− }
508+ else if (section === "Yesterday") {
509+ return i18n.tr("Yesterday")
510+ }
407511
408− else if (section === "Older") {
409− return i18n.tr("Older")
410− }
512+ else if (section === "Older") {
513+ return i18n.tr("Older")
514+ }
411515
412− else {
413− return ""
414− }
516+ else {
517+ return ""
415518 }
416− title.color: podbird.appTheme.baseText
417− title.font.weight: Font.DemiBold
418519 }
419520 }
420521
@@ -525,7 +626,7 @@ Tab {
525626 Action {
526627 iconName: "add-to-playlist"
527628 onTriggered: {
528− var url = model.downloadedfile ? model.downloadedfile : model.audiourl
629+ var url = model.downloadedfile ? "file://" + model.downloadedfile : model.audiourl
529630 player.addEpisodeToQueue(model.guid, model.image, model.name, model.artist, url)
530631 }
531632 },
@@ -562,11 +663,29 @@ Tab {
562663
563664 onClicked: {
564665 Haptics.play()
565− if (currentGuid !== model.guid) {
566− currentUrl = model.downloadedfile ? model.downloadedfile : model.audiourl;
567− player.playEpisode(model.guid, model.image, model.name, model.artist, currentUrl)
666+ if (selectMode) {
667+ selected = !selected
668+ } else {
669+ if (currentGuid !== model.guid) {
670+ currentUrl = model.downloadedfile ? "file://" + model.downloadedfile : model.audiourl;
671+ player.playEpisode(model.guid, model.image, model.name, model.artist, currentUrl)
672+ }
568673 }
569674 }
675+
676+ onPressAndHold: {
677+ ListView.view.ViewItems.selectMode = !ListView.view.ViewItems.selectMode
678+ }
679+ }
680+
681+ onClearSelection: {
682+ ViewItems.selectedIndices = []
683+ }
684+
685+ onCloseSelection: {
686+ clearSelection()
687+ ViewItems.selectMode = false
688+ episodesPage.header = standardHeader
570689 }
571690
572691 Scrollbar {
app/ui/Queue.qml−6
@@ -69,13 +69,7 @@ Item {
6969 onTriggered: {
7070 player.playlist.removeItem(index)
7171 var source = model.source
72−
7372 source = source.toString()
74−
75− if (source.indexOf("file://") === 0) {
76− source = source.substring(7);
77− }
78−
7973 Podcasts.removeItemFromQueue(source)
8074 }
8175 }