@@ -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 {