Merge lp:~nik90/podbird/5.5-kevin-redesign into lp:podbird
- 5.5-kevin-redesign
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 44 |
Proposed branch: | lp:~nik90/podbird/5.5-kevin-redesign |
Merge into: | lp:podbird |
Prerequisite: | lp:~nik90/podbird/5-auto-download-option |
Diff against target: |
1344 lines (+528/-409) 11 files modified
app/podbird.qml (+12/-2) app/podcasts.js (+16/-3) app/themes/Dark.qml (+4/-4) app/themes/Light.qml (+4/-4) app/ui/ActionButton.qml (+1/-0) app/ui/BlurredBackground.qml (+4/-21) app/ui/EpisodesPage.qml (+269/-227) app/ui/PlayerControls.qml (+2/-2) app/ui/PodcastsTab.qml (+3/-8) app/ui/SearchPage.qml (+153/-102) po/com.mikeasoft.podbird.pot (+60/-36) |
To merge this branch: | bzr merge lp:~nik90/podbird/5.5-kevin-redesign |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Sheldon | Approve | ||
Review via email: mp+255155@code.launchpad.net |
Commit message
Description of the change
This MP is a huge one brings a lot of improvements which are listed below,
- Redesigned the episodes page and search page according to the designs provided by Kevin (community designer) which is a lot of list..best would be to run this branch and check ;)
- Starting a download or deleting a download file no longer refreshes the entire episodesModel as it is expensive and jarring to the user. Instead I have used episodeModel.
- In the episodes page, the episodes are now separated by "New" and "Listened". Again this is done intelligently using the setProperty() function. This enables us to no longer show the "tick" icon.
- The Podcasts page now shows alternating colors for listitems
- The blurred background component has been cleaned up and is now more customizable. It allow for setting the blur opacity which helps with using different values for the Light and Dark theme.
- Dark theme has received some minor color changes.
- Sqlite Schema Upgrade to v1.1. In this version I introduced a new column to every episode "Queued" which keeps track if the episode is in the download queue or not. By storing this in the database, the queue status is preserved if if the user closes the episode page and reopens another page. This is important to inform the user of what episodes are being auto-downloaded by Podbird on app startup.
- 67. By Nekhelesh Ramananthan
-
Fixed a rare case where the downloading status was not shown properly when the user closes and reopens the episodes page
Nekhelesh Ramananthan (nik90) wrote : | # |
- 68. By Nekhelesh Ramananthan
-
Used a cutom progress bar and tweaked theme colors
- 69. By Nekhelesh Ramananthan
-
Small UI Tweaks
- 70. By Nekhelesh Ramananthan
-
Dynamically load/unload the search tab
- 71. By Nekhelesh Ramananthan
-
Renamed search tab to search page
- 72. By Nekhelesh Ramananthan
-
merged prerequisite
- 73. By Nekhelesh Ramananthan
-
Added a new column queued to database via a schema upgrade
- 74. By Nekhelesh Ramananthan
-
Added comments and fixed alter table sqlite command
- 75. By Nekhelesh Ramananthan
-
merged prerequisite
- 76. By Nekhelesh Ramananthan
-
Tweaked bottom bar color
- 77. By Nekhelesh Ramananthan
-
Added a new application icon
- 78. By Nekhelesh Ramananthan
-
Changed New to Unheard
- 79. By Nekhelesh Ramananthan
-
Fixed issue where auto-download did not set the queue status correctly. Also fixed formatTime() function complaining about model.duration missing
- 80. By Nekhelesh Ramananthan
-
merged prerequisite fix
- 81. By Nekhelesh Ramananthan
-
Merged prerequisite
- 82. By Nekhelesh Ramananthan
-
Merged prerequisite
Nekhelesh Ramananthan (nik90) wrote : | # |
Note: If you notice any issues while testing this branch, please list them out. Most likely they have been fixed in one of the MPs which came after this. For instance, the database scheme upgrade done in this MP is usually to its full potential only in lp:~nik90/podbird/7-mark-episode-listened MP.
Michael Sheldon (michael-sheldon) wrote : | # |
Only found two small issues that don't appear to be covered by other branches; I've added fixes for them myself whilst merging, they were just that 1) the new download indicator doesn't show any activity when download manager gives bad progress information (I've made the progress indicator bounce back and forth under these circumstances) and 2) the redesigned episodes page shows "NaN:NaN" for podcasts that don't provide duration information.
Like I said, I've fixed these though, so have now merged this branch :).
Preview Diff
1 | === modified file 'app/podbird.qml' |
2 | --- app/podbird.qml 2015-04-15 23:06:20 +0000 |
3 | +++ app/podbird.qml 2015-04-18 14:12:52 +0000 |
4 | @@ -167,9 +167,18 @@ |
5 | objectName: "podcastsTab" |
6 | } |
7 | |
8 | - SearchTab { |
9 | + Tab { |
10 | id: searchTab |
11 | - objectName: "searchTab" |
12 | + |
13 | + title: i18n.tr("Find New Podcasts") |
14 | + |
15 | + page: Loader { |
16 | + parent: searchTab |
17 | + anchors.left: parent.left |
18 | + anchors.right: parent.right |
19 | + anchors.bottom: parent.bottom |
20 | + source: (tabs.selectedTab === searchTab) ? Qt.resolvedUrl("ui/SearchPage.qml") : "" |
21 | + } |
22 | } |
23 | |
24 | Tab { |
25 | @@ -248,6 +257,7 @@ |
26 | for (var j=0; j < loopCount; j++) { |
27 | if (!rs2.rows.item(j).downloadedfile && !rs2.rows.item(j).listened) { |
28 | downloader.addDownload(rs2.rows.item(j).guid, rs2.rows.item(j).audiourl) |
29 | + tx.executeSql("UPDATE Episode SET queued=1 WHERE guid = ?", [rs2.rows.item(j).guid]); |
30 | } |
31 | } |
32 | } |
33 | |
34 | === modified file 'app/podcasts.js' |
35 | --- app/podcasts.js 2015-02-28 09:46:48 +0000 |
36 | +++ app/podcasts.js 2015-04-18 14:12:52 +0000 |
37 | @@ -1,5 +1,5 @@ |
38 | /* |
39 | - * Copyright 2015 Michael Sheldon <mike@mikeasoft.com> |
40 | + * Copyright 2015 Podbird Team |
41 | * |
42 | * This file is part of Podbird. |
43 | * |
44 | @@ -17,11 +17,24 @@ |
45 | */ |
46 | |
47 | function init() { |
48 | - var db = LocalStorage.openDatabaseSync("Podbird", "1.0", "Database of subscribed podcasts and their episodes", 1000000); |
49 | + var db = LocalStorage.openDatabaseSync("Podbird", "", "Database of subscribed podcasts and their episodes", 1000000); |
50 | + |
51 | db.transaction(function(tx) { |
52 | tx.executeSql('CREATE TABLE IF NOT EXISTS Podcast(artist TEXT, name TEXT, description TEXT, feed TEXT, image TEXT, lastupdate TIMESTAMP)'); |
53 | - tx.executeSql('CREATE TABLE IF NOT EXISTS Episode(guid TEXT, podcast INTEGER, name TEXT, subtitle TEXT, description TEXT, duration INTEGER, audiourl TEXT, downloadedfile TEXT, published TIMESTAMP, listened BOOLEAN, position INTEGER, FOREIGN KEY(podcast) REFERENCES Podcast(rowid))'); |
54 | + tx.executeSql('CREATE TABLE IF NOT EXISTS Episode(guid TEXT, podcast INTEGER, name TEXT, subtitle TEXT, description TEXT, duration INTEGER, audiourl TEXT, downloadedfile TEXT, published TIMESTAMP, listened BOOLEAN, queued BOOLEAN, position INTEGER, FOREIGN KEY(podcast) REFERENCES Podcast(rowid))'); |
55 | }); |
56 | + |
57 | + /* |
58 | + Schema Upgrade to v1.1 which adds a new queued boolean variable which is needed to track the queued status |
59 | + of a episode properly. |
60 | + */ |
61 | + if (db.version == "1.0") { |
62 | + db.changeVersion("1.0", "1.1", function(tx) { |
63 | + tx.executeSql('ALTER TABLE Episode ADD queued BOOLEAN'); |
64 | + tx.executeSql('UPDATE Episode SET queued=0'); |
65 | + }); |
66 | + } |
67 | + |
68 | return db; |
69 | } |
70 | |
71 | |
72 | === modified file 'app/themes/Dark.qml' |
73 | --- app/themes/Dark.qml 2015-03-04 02:58:36 +0000 |
74 | +++ app/themes/Dark.qml 2015-04-18 14:12:52 +0000 |
75 | @@ -21,12 +21,12 @@ |
76 | |
77 | QtObject { |
78 | // MainView |
79 | - property color background: "#1E1E23" |
80 | + property color background: "#242423" |
81 | |
82 | // Main Text Colors |
83 | property color baseText: "White" |
84 | property color baseSubText: "#999999" |
85 | - property color focusText: "#FF9900" |
86 | + property color focusText: "#35AF44" |
87 | |
88 | // Icon Colors |
89 | property color baseIcon: "White" |
90 | @@ -37,8 +37,8 @@ |
91 | property color neutralActionButton: UbuntuColors.coolGrey |
92 | |
93 | // Bottom Player Bar Colors |
94 | - property color bottomBarBackground: "#0F0F0F" |
95 | + property color bottomBarBackground: "#15141A" |
96 | |
97 | // Highlight Color |
98 | - property color hightlightListView: "#2C2C34" |
99 | + property color hightlightListView: "#333533" |
100 | } |
101 | |
102 | === modified file 'app/themes/Light.qml' |
103 | --- app/themes/Light.qml 2015-03-04 02:58:36 +0000 |
104 | +++ app/themes/Light.qml 2015-04-18 14:12:52 +0000 |
105 | @@ -21,12 +21,12 @@ |
106 | |
107 | QtObject { |
108 | // MainView |
109 | - property color background: "#EEEEEE" |
110 | + property color background: "#ECECEC" |
111 | |
112 | // Main Text Colors |
113 | property color baseText: UbuntuColors.darkGrey |
114 | property color baseSubText: "#999999" |
115 | - property color focusText: UbuntuColors.orange |
116 | + property color focusText: "#35AF44" |
117 | |
118 | // Icon Colors |
119 | property color baseIcon: UbuntuColors.darkGrey |
120 | @@ -37,8 +37,8 @@ |
121 | property color neutralActionButton: UbuntuColors.coolGrey |
122 | |
123 | // Bottom Player Bar Colors |
124 | - property color bottomBarBackground: "#0F0F0F" |
125 | + property color bottomBarBackground: "#323435" |
126 | |
127 | // Highlight Color |
128 | - property color hightlightListView: "#D8D8D8" |
129 | + property color hightlightListView: "#F5F5F5" |
130 | } |
131 | |
132 | === modified file 'app/ui/ActionButton.qml' |
133 | --- app/ui/ActionButton.qml 2015-03-08 11:10:07 +0000 |
134 | +++ app/ui/ActionButton.qml 2015-04-18 14:12:52 +0000 |
135 | @@ -23,6 +23,7 @@ |
136 | id: abstractButton |
137 | |
138 | property string iconName |
139 | + property alias color: _icon.color |
140 | |
141 | Rectangle { |
142 | visible: abstractButton.pressed |
143 | |
144 | === modified file 'app/ui/BlurredBackground.qml' |
145 | --- app/ui/BlurredBackground.qml 2015-02-10 06:57:54 +0000 |
146 | +++ app/ui/BlurredBackground.qml 2015-04-18 14:12:52 +0000 |
147 | @@ -25,15 +25,8 @@ |
148 | Item { |
149 | width: parent.width |
150 | |
151 | - property string art // : player.currentMetaFile === "" ? Qt.resolvedUrl("../images/music-app-cover@30.png") : player.currentMetaArt |
152 | - |
153 | - // dark layer |
154 | - Rectangle { |
155 | - anchors { |
156 | - fill: parent |
157 | - } |
158 | - color: "black" |
159 | - } |
160 | + property string art |
161 | + property real backgroundStrength: 0.4 |
162 | |
163 | // the album art |
164 | Image { |
165 | @@ -44,16 +37,6 @@ |
166 | fillMode: Image.PreserveAspectCrop |
167 | height: parent.height |
168 | source: art // this has to be fixed for the default cover art to work - cant find in this dir |
169 | - |
170 | - // TODO: This should be investigated once http://pad.lv/1391368 |
171 | - // is resolved. Once it is, these can either be set to |
172 | - // "height" and "width" or a property exposed via the |
173 | - // SDK or Thumbnailer to avoid a regression caused by |
174 | - // these hardcoded values changing in the Thumbnailer. |
175 | - // 512 is size of the "xlarge" thumbnails in pixels. |
176 | - sourceSize.height: 512 |
177 | - sourceSize.width: 512 |
178 | - |
179 | visible: false |
180 | width: Math.max(parent.height, parent.width) |
181 | } |
182 | @@ -63,8 +46,8 @@ |
183 | id: backgroundBlur |
184 | anchors.fill: backgroundImage |
185 | source: backgroundImage |
186 | - radius: units.dp(42) |
187 | - opacity: 0.2 |
188 | + radius: units.dp(30) |
189 | + opacity: backgroundStrength |
190 | } |
191 | onArtChanged: { |
192 | // TODO: This is a work around for LP:1261078 and LP:1306845. Ideally, |
193 | |
194 | === modified file 'app/ui/EpisodesPage.qml' |
195 | --- app/ui/EpisodesPage.qml 2015-03-29 15:33:26 +0000 |
196 | +++ app/ui/EpisodesPage.qml 2015-04-18 14:12:52 +0000 |
197 | @@ -30,17 +30,21 @@ |
198 | id: episodesPage |
199 | |
200 | visible: false |
201 | - title: episodeName |
202 | + title: i18n.tr("Podcast") |
203 | + flickable: null |
204 | |
205 | property string episodeName |
206 | property string episodeId |
207 | property string episodeArtist |
208 | property string episodeImage |
209 | + property string tempGuid: "NULL" |
210 | |
211 | property bool episodesUpdating: false; |
212 | |
213 | Component.onCompleted: { |
214 | loadEpisodes(episodeId, episodeArtist, episodeImage) |
215 | + if (downloader.downloadingGuid != "") |
216 | + tempGuid = downloader.downloadingGuid |
217 | } |
218 | |
219 | /* |
220 | @@ -95,7 +99,7 @@ |
221 | onTriggered: { |
222 | var db = Podcasts.init(); |
223 | db.transaction(function (tx) { |
224 | - tx.executeSql("UPDATE Episode SET listened=1 WHERE podcast=?", [episodeModel.pid]); |
225 | + tx.executeSql("UPDATE Episode SET listened=1 WHERE podcast=?", [episodeId]); |
226 | refreshModel(); |
227 | }); |
228 | } |
229 | @@ -122,6 +126,7 @@ |
230 | episodeList.forceActiveFocus() |
231 | searchField.text = "" |
232 | episodesPage.state = "default" |
233 | + episodeList.positionViewAtBeginning() |
234 | } |
235 | } |
236 | |
237 | @@ -139,7 +144,36 @@ |
238 | Connections { |
239 | target: downloader |
240 | onDownloadingGuidChanged: { |
241 | - loadEpisodes(episodeId, episodeArtist, episodeImage); |
242 | + var db = Podcasts.init(); |
243 | + db.transaction(function (tx) { |
244 | + /* |
245 | + If tempGuid is NULL, then the episode currently being downloaded is not found within |
246 | + this podcast. On the other hand, if it is within this podcast, then update the episodeModel |
247 | + with the downloadedfile location we just received from the downloader. |
248 | + */ |
249 | + if (tempGuid != "NULL") { |
250 | + var rs2 = tx.executeSql("SELECT downloadedfile, podcast FROM Episode WHERE guid=?", [tempGuid]); |
251 | + for (var i=0; i<episodeModel.count; i++) { |
252 | + if (episodeModel.get(i).guid == tempGuid) { |
253 | + console.log("[LOG]: Setting episode download URL to " + rs2.rows.item(0).downloadedfile) |
254 | + episodeModel.setProperty(i, "downloadedfile", rs2.rows.item(0).downloadedfile) |
255 | + break |
256 | + } |
257 | + } |
258 | + tempGuid = "NULL" |
259 | + } |
260 | + |
261 | + /* |
262 | + Here it is checked if the currently downloaded episode belongs to the podcast |
263 | + page being currently displayed. If it is, then the downloaded episode guid is |
264 | + stored in the tempGuid variable to track it. |
265 | + */ |
266 | + var rs = tx.executeSql("SELECT podcast FROM Episode WHERE guid=?", [downloader.downloadingGuid]); |
267 | + |
268 | + if (downloader.downloadingGuid != "" && rs.rows.item(0).podcast == episodeId && tempGuid == "NULL") { |
269 | + tempGuid = downloader.downloadingGuid |
270 | + } |
271 | + }); |
272 | } |
273 | } |
274 | |
275 | @@ -155,12 +189,12 @@ |
276 | onClicked: { |
277 | var db = Podcasts.init(); |
278 | db.transaction(function (tx) { |
279 | - var rs = tx.executeSql("SELECT downloadedfile FROM Episode WHERE downloadedfile NOT NULL AND podcast=?", [episodeModel.pid]); |
280 | + var rs = tx.executeSql("SELECT downloadedfile FROM Episode WHERE downloadedfile NOT NULL AND podcast=?", [episodeId]); |
281 | for(var i = 0; i < rs.rows.length; i++) { |
282 | fileManager.deleteFile(rs.rows.item(i).downloadedfile); |
283 | } |
284 | - tx.executeSql("DELETE FROM Episode WHERE podcast=?", [episodeModel.pid]); |
285 | - tx.executeSql("DELETE FROM Podcast WHERE rowid=?", [episodeModel.pid]); |
286 | + tx.executeSql("DELETE FROM Episode WHERE podcast=?", [episodeId]); |
287 | + tx.executeSql("DELETE FROM Podcast WHERE rowid=?", [episodeId]); |
288 | mainStack.pop() |
289 | PopupUtils.close(dialogInternal) |
290 | }); |
291 | @@ -187,9 +221,6 @@ |
292 | |
293 | ListModel { |
294 | id: episodeModel |
295 | - property string pid; |
296 | - property string artist; |
297 | - property string image; |
298 | } |
299 | |
300 | SortFilterModel { |
301 | @@ -199,12 +230,118 @@ |
302 | filter.pattern: RegExp(searchField.text, "gi") |
303 | } |
304 | |
305 | - ListView { |
306 | + function formatTime(seconds) { |
307 | + var time = Podcasts.getTimeDiff(seconds) |
308 | + var hour = time[0] |
309 | + var minute = time[1] |
310 | + // TRANSLATORS: the first argument is the number of hours, |
311 | + // followed by minute (eg. 20h 3m) |
312 | + if(hour > 0 && minute > 0) { |
313 | + // xgettext: no-c-format |
314 | + return (i18n.tr("%1 hr %2 min")) |
315 | + .arg(hour) |
316 | + .arg(minute) |
317 | + } |
318 | + |
319 | + // TRANSLATORS: this string indicates the number of hours |
320 | + // eg. 20h (no plural state required) |
321 | + else if(hour > 0 && minute === 0) { |
322 | + // xgettext: no-c-format |
323 | + return (i18n.tr("%1 hr")) |
324 | + .arg(hour) |
325 | + } |
326 | + |
327 | + // TRANSLATORS: this string indicates the number of minutes |
328 | + // eg. 15m (no plural state required) |
329 | + else if(hour === 0 && minute > 0) { |
330 | + // xgettext: no-c-format |
331 | + return (i18n.tr("%1 min")) |
332 | + .arg(minute) |
333 | + } |
334 | + |
335 | + else { |
336 | + return Podcasts.formatTime(seconds) |
337 | + } |
338 | + } |
339 | + |
340 | + UbuntuListView { |
341 | id: episodeList |
342 | |
343 | + anchors.fill: parent |
344 | + model: sortedEpisodeModel |
345 | + |
346 | clip: true |
347 | - anchors.fill: parent |
348 | - model: sortedEpisodeModel |
349 | + section.property: "listened" |
350 | + section.labelPositioning: ViewSection.InlineLabels |
351 | + |
352 | + section.delegate: Rectangle { |
353 | + width: parent.width |
354 | + color: section === "0" ? podbird.theme.hightlightListView : "Transparent" |
355 | + height: header.implicitHeight + units.gu(2) |
356 | + Label { |
357 | + id: header |
358 | + anchors { |
359 | + left: parent.left |
360 | + right: parent.right |
361 | + margins: units.gu(2) |
362 | + verticalCenter: parent.verticalCenter |
363 | + } |
364 | + fontSize: "x-large" |
365 | + text: section === "0" ? i18n.tr("Unheard") : i18n.tr("Listened") |
366 | + } |
367 | + } |
368 | + |
369 | + header: BlurredBackground { |
370 | + id: blurredBackground |
371 | + |
372 | + art: episodeImage |
373 | + width: parent.width |
374 | + visible: episodesPage.state !== "search" |
375 | + height: episodesPage.state !== "search" ? cover.height + units.gu(4) : 0 |
376 | + backgroundStrength: podbird.settings.themeName === "Light.qml" ? 0.3 : 0.6 |
377 | + |
378 | + Image { |
379 | + id:cover |
380 | + width: units.gu(12) |
381 | + height: width |
382 | + sourceSize.height: width |
383 | + sourceSize.width: width |
384 | + source: episodeImage |
385 | + anchors { |
386 | + left: parent.left |
387 | + top: parent.top |
388 | + margins: units.gu(2) |
389 | + } |
390 | + } |
391 | + |
392 | + Column { |
393 | + id: podcastTitle |
394 | + |
395 | + anchors { |
396 | + left: cover.right |
397 | + right: parent.right |
398 | + bottom: parent.bottom |
399 | + margins: units.gu(2) |
400 | + } |
401 | + |
402 | + Label { |
403 | + text: episodeName |
404 | + width: parent.width |
405 | + wrapMode: Text.WordWrap |
406 | + maximumLineCount: 2 |
407 | + elide: Text.ElideRight |
408 | + color: podbird.theme.baseText |
409 | + } |
410 | + |
411 | + Label { |
412 | + text: i18n.tr("%1 episode", "%1 episodes", episodeList.count).arg(episodeList.count) |
413 | + width: parent.width |
414 | + elide: Text.ElideRight |
415 | + fontSize: "x-small" |
416 | + color: podbird.theme.baseText |
417 | + } |
418 | + } |
419 | + } |
420 | |
421 | footer: Item { |
422 | width: parent.width |
423 | @@ -214,51 +351,41 @@ |
424 | delegate: ListItem.Empty { |
425 | id: listItem |
426 | |
427 | - property bool expanded: false |
428 | + property bool expanded |
429 | |
430 | - width: parent.width |
431 | - height: mainColumn.height |
432 | + height: dataColumn.height + units.gu(2) |
433 | highlightWhenPressed: false |
434 | + showDivider: false |
435 | |
436 | - onClicked: listItem.expanded = !listItem.expanded |
437 | + onClicked: { |
438 | + expanded = !expanded; |
439 | + } |
440 | |
441 | Rectangle { |
442 | - anchors.fill: parent |
443 | - color: listItem.pressed ? podbird.theme.hightlightListView : "transparent" |
444 | + visible: !model.listened |
445 | + width: parent.width |
446 | + height: dataColumn.height + units.gu(2) |
447 | + color: podbird.theme.hightlightListView |
448 | } |
449 | |
450 | Column { |
451 | - id: mainColumn |
452 | - |
453 | - anchors { |
454 | - top: parent.top |
455 | - left: parent.left |
456 | - right: parent.right |
457 | - margins: units.gu(2) |
458 | - topMargin: units.gu(1) |
459 | - } |
460 | + id: dataColumn |
461 | |
462 | spacing: units.gu(1) |
463 | + anchors.left: parent.left |
464 | + anchors.right: parent.right |
465 | + anchors.margins: units.gu(2) |
466 | + anchors.top: parent.top |
467 | + anchors.topMargin: units.gu(0.5) |
468 | |
469 | RowLayout { |
470 | - id: titleRow |
471 | + id: rowlayout |
472 | |
473 | width: parent.width |
474 | - spacing: units.gu(2) |
475 | - |
476 | - Image { |
477 | - id: imgFrame |
478 | - width: units.gu(6) |
479 | - height: width |
480 | - sourceSize.height: width |
481 | - sourceSize.width: width |
482 | - source: model.image |
483 | - } |
484 | + height: titleColumn.height |
485 | |
486 | Column { |
487 | - id: detailColumn |
488 | - |
489 | - anchors.verticalCenter: imgFrame.verticalCenter |
490 | + id: titleColumn |
491 | Layout.fillWidth: true |
492 | |
493 | Label { |
494 | @@ -267,19 +394,97 @@ |
495 | maximumLineCount: 2 |
496 | wrapMode: Text.WordWrap |
497 | elide: Text.ElideRight |
498 | - color: currentGuid === model.guid ? podbird.theme.focusText |
499 | - : podbird.theme.baseText |
500 | + color: listItem.expanded || currentGuid === model.guid || downloader.downloadingGuid === model.guid ? podbird.theme.focusText |
501 | + : podbird.theme.baseText |
502 | } |
503 | |
504 | Label { |
505 | id: episodePublishDate |
506 | width: parent.width |
507 | - text: Qt.formatDate(new Date(model.published), "MMM d, yyyy") |
508 | + text: formatTime(model.duration) + " | " + Qt.formatDate(new Date(model.published), "MMM d, yyyy") |
509 | fontSize: "x-small" |
510 | - color: currentGuid === model.guid ? podbird.theme.focusText |
511 | - : podbird.theme.baseText |
512 | elide: Text.ElideRight |
513 | - } |
514 | + color: podbird.theme.baseSubText |
515 | + } |
516 | + } |
517 | + |
518 | + ActionButton { |
519 | + id: downloadButton |
520 | + |
521 | + width: units.gu(5) |
522 | + height: units.gu(4) |
523 | + |
524 | + property bool queued: false |
525 | + |
526 | + iconName: model.downloadedfile ? "delete" : (queued && downloader.downloadingGuid !== model.guid ? "history" : "save") |
527 | + enabled: downloader.downloadingGuid !== model.guid |
528 | + color: downloader.downloadingGuid === model.guid ? podbird.theme.focusText |
529 | + : podbird.theme.baseText |
530 | + |
531 | + onClicked: { |
532 | + if (model.downloadedfile) { |
533 | + fileManager.deleteFile(model.downloadedfile); |
534 | + var db = Podcasts.init(); |
535 | + db.transaction(function (tx) { |
536 | + tx.executeSql("UPDATE Episode SET downloadedfile = NULL WHERE guid = ?", [model.guid]); |
537 | + }); |
538 | + episodeModel.setProperty(index, "downloadedfile", "") |
539 | + downloadButton.queued = false |
540 | + } else { |
541 | + downloadButton.queued = true; |
542 | + downloader.addDownload(model.guid, model.audiourl); |
543 | + } |
544 | + } |
545 | + } |
546 | + |
547 | + ActionButton { |
548 | + width: units.gu(4) |
549 | + height: units.gu(4) |
550 | + |
551 | + iconName: player.playbackState === MediaPlayer.PlayingState && currentGuid === model.guid ? "media-playback-pause" |
552 | + : "media-playback-start" |
553 | + color: player.playbackState === MediaPlayer.PlayingState && currentGuid === model.guid ? podbird.theme.focusText |
554 | + : podbird.theme.baseIcon |
555 | + |
556 | + onClicked: { |
557 | + var db = Podcasts.init(); |
558 | + db.transaction(function (tx) { |
559 | + if (currentGuid === model.guid) { |
560 | + if (player.playbackState === MediaPlayer.PlayingState) { |
561 | + player.pause() |
562 | + } else { |
563 | + player.play() |
564 | + } |
565 | + } else { |
566 | + currentGuid = ""; |
567 | + player.source = model.downloadedfile ? model.downloadedfile : model.audiourl; |
568 | + var rs = tx.executeSql("SELECT position FROM Episode WHERE guid=?", [model.guid]); |
569 | + player.play(); |
570 | + player.seek(rs.rows.item(0).position); |
571 | + currentName = model.name; |
572 | + currentArtist = model.artist; |
573 | + currentImage = model.image; |
574 | + currentGuid = model.guid; |
575 | + } |
576 | + }); |
577 | + } |
578 | + } |
579 | + } |
580 | + |
581 | + Rectangle { |
582 | + id: progressBar |
583 | + radius: width/3 |
584 | + width: parent.width |
585 | + height: units.dp(5) |
586 | + color: Theme.palette.normal.base |
587 | + visible: downloader.downloadingGuid === model.guid |
588 | + Rectangle { |
589 | + height: parent.height |
590 | + radius: parent.radius |
591 | + anchors.left: parent.left |
592 | + anchors.top: parent.top |
593 | + color: podbird.theme.focusText |
594 | + width: downloader.progress > 0 ? Math.min((downloader.progress / 100) * parent.width, parent.width) : 0 |
595 | } |
596 | } |
597 | |
598 | @@ -288,184 +493,15 @@ |
599 | text: model.description |
600 | textFormat: Text.RichText |
601 | clip: true |
602 | - height: listItem.expanded ? contentHeight : units.gu(4) |
603 | + height: listItem.expanded ? contentHeight : 0 |
604 | wrapMode: Text.WordWrap |
605 | width: parent.width |
606 | - elide: Text.ElideRight |
607 | fontSize: "small" |
608 | color: podbird.theme.baseSubText |
609 | Behavior on height { |
610 | UbuntuNumberAnimation { |
611 | - duration: UbuntuAnimation.SlowDuration |
612 | - } |
613 | - } |
614 | - |
615 | - } |
616 | - |
617 | - Item { |
618 | - id: statusBox |
619 | - |
620 | - width: parent.width |
621 | - height: units.gu(6) |
622 | - |
623 | - function formatTime(seconds) { |
624 | - var time = Podcasts.getTimeDiff(seconds) |
625 | - var hour = time[0] |
626 | - var minute = time[1] |
627 | - // TRANSLATORS: the first argument is the number of hours, |
628 | - // followed by minute (eg. 20h 3m) |
629 | - if(hour > 0 && minute > 0) { |
630 | - // xgettext: no-c-format |
631 | - return (i18n.tr("%1h %2m")) |
632 | - .arg(hour) |
633 | - .arg(minute) |
634 | - } |
635 | - |
636 | - // TRANSLATORS: this string indicates the number of hours |
637 | - // eg. 20h (no plural state required) |
638 | - else if(hour > 0 && minute === 0) { |
639 | - // xgettext: no-c-format |
640 | - return (i18n.tr("%1h")) |
641 | - .arg(hour) |
642 | - } |
643 | - |
644 | - // TRANSLATORS: this string indicates the number of minutes |
645 | - // eg. 15m (no plural state required) |
646 | - else if(hour === 0 && minute > 0) { |
647 | - // xgettext: no-c-format |
648 | - return (i18n.tr("%1m")) |
649 | - .arg(minute) |
650 | - } |
651 | - |
652 | - else { |
653 | - return Podcasts.formatTime(model.duration) |
654 | - } |
655 | - } |
656 | - |
657 | - Rectangle { |
658 | - id: listened |
659 | - border.color: UbuntuColors.lightGrey |
660 | - height: units.gu(2.5) |
661 | - width: height |
662 | - radius: width / 2 |
663 | - anchors.right: durationIcon.left |
664 | - anchors.rightMargin: units.gu(2) |
665 | - anchors.verticalCenter: actionRow.verticalCenter |
666 | - visible: model.listened |
667 | - Icon { |
668 | - id: tick |
669 | - name: "tick" |
670 | - anchors.centerIn: parent |
671 | - anchors.verticalCenterOffset: units.gu(0.1) |
672 | - height: units.gu(1.4) |
673 | - width: height |
674 | - } |
675 | - } |
676 | - |
677 | - Icon { |
678 | - id: durationIcon |
679 | - width: units.gu(2.5) |
680 | - height: width |
681 | - name: "alarm-clock" |
682 | - visible: duration.text !== "" |
683 | - anchors.right: duration.left |
684 | - anchors.rightMargin: units.gu(0.5) |
685 | - anchors.verticalCenter: actionRow.verticalCenter |
686 | - color: podbird.theme.baseIcon |
687 | - } |
688 | - |
689 | - Label { |
690 | - id: duration |
691 | - color: podbird.theme.baseText |
692 | - anchors.right: parent.right |
693 | - anchors.verticalCenter: durationIcon.verticalCenter |
694 | - fontSize: "small" |
695 | - text: !isNaN(model.duration) && model.duration !== 0 ? statusBox.formatTime(model.duration) : "" |
696 | - } |
697 | - |
698 | - Row { |
699 | - id: actionRow |
700 | - |
701 | - anchors.left: parent.left |
702 | - anchors.leftMargin: units.gu(-1.5) |
703 | - |
704 | - ActionButton { |
705 | - width: units.gu(5) |
706 | - height: units.gu(4) |
707 | - |
708 | - iconName: player.playbackState === MediaPlayer.PlayingState && currentGuid === model.guid ? "media-playback-pause" |
709 | - : "media-playback-start" |
710 | - |
711 | - onClicked: { |
712 | - var db = Podcasts.init(); |
713 | - db.transaction(function (tx) { |
714 | - if (currentGuid === model.guid) { |
715 | - if (player.playbackState === MediaPlayer.PlayingState) { |
716 | - player.pause() |
717 | - } else { |
718 | - player.play() |
719 | - } |
720 | - } else { |
721 | - currentGuid = ""; |
722 | - player.source = model.downloadedfile ? model.downloadedfile : model.audiourl; |
723 | - var rs = tx.executeSql("SELECT position FROM Episode WHERE guid=?", [model.guid]); |
724 | - player.play(); |
725 | - player.seek(rs.rows.item(0).position); |
726 | - currentName = model.name; |
727 | - currentArtist = model.artist; |
728 | - currentImage = model.image; |
729 | - currentGuid = model.guid; |
730 | - } |
731 | - }); |
732 | - } |
733 | - } |
734 | - |
735 | - ActionButton { |
736 | - id: downloadButton |
737 | - |
738 | - width: units.gu(5) |
739 | - height: units.gu(4) |
740 | - |
741 | - property bool queued: false |
742 | - |
743 | - iconName: model.downloadedfile ? "delete" : (queued && downloader.downloadingGuid !== model.guid ? "history" : "save") |
744 | - opacity: downloader.downloadingGuid === model.guid ? 0.4 : 1.0 |
745 | - enabled: downloader.downloadingGuid !== model.guid |
746 | - |
747 | - ActivityIndicator { |
748 | - anchors.centerIn: parent |
749 | - visible: downloader.downloadingGuid === model.guid |
750 | - running: visible |
751 | - } |
752 | - |
753 | - onClicked: { |
754 | - if (model.downloadedfile) { |
755 | - fileManager.deleteFile(model.downloadedfile); |
756 | - var db = Podcasts.init(); |
757 | - db.transaction(function (tx) { |
758 | - tx.executeSql("UPDATE Episode SET downloadedfile = NULL WHERE guid = ?", [model.guid]); |
759 | - }); |
760 | - loadEpisodes(episodeModel.pid, episodeModel.artist, episodeModel.image); |
761 | - } else { |
762 | - downloadButton.queued = true; |
763 | - downloader.addDownload(model.guid, model.audiourl); |
764 | - } |
765 | - } |
766 | - } |
767 | - } |
768 | - |
769 | - |
770 | - ProgressBar { |
771 | - visible: downloader.downloadingGuid === model.guid |
772 | - minimumValue: 0 |
773 | - maximumValue: 100 |
774 | - anchors.left: actionRow.right |
775 | - anchors.right: model.listened ? listened.left : durationIcon.left |
776 | - anchors.leftMargin: units.gu(2) |
777 | - anchors.rightMargin: units.gu(2) |
778 | - anchors.verticalCenter: actionRow.verticalCenter |
779 | - height: units.gu(2.6) |
780 | - value: downloader.progress |
781 | + duration: UbuntuAnimation.BriskDuration |
782 | + } |
783 | } |
784 | } |
785 | } |
786 | @@ -483,21 +519,27 @@ |
787 | |
788 | function refreshModel() { |
789 | var db = Podcasts.init(); |
790 | - loadEpisodes(episodeModel.pid, episodeModel.artist, episodeModel.image); |
791 | + loadEpisodes(episodeId, episodeArtist, episodeImage); |
792 | episodesUpdating = false; |
793 | } |
794 | |
795 | function loadEpisodes(pid, artist, img) { |
796 | + var i, episode; |
797 | + var newCount = 0; |
798 | + |
799 | + episodeModel.clear(); |
800 | + |
801 | var db = Podcasts.init(); |
802 | db.transaction(function (tx) { |
803 | - episodeModel.clear(); |
804 | var rs = tx.executeSql("SELECT rowid, * FROM Episode WHERE podcast=? ORDER BY published DESC", [pid]); |
805 | - for(var i = 0; i < rs.rows.length; i++) { |
806 | - var episode = rs.rows.item(i); |
807 | - episodeModel.pid = pid; |
808 | - episodeModel.artist = artist; |
809 | - episodeModel.image = img; |
810 | - episodeModel.append({"guid" : episode.guid, "listened" : episode.listened, "published": episode.published, "name" : episode.name, "description" : episode.description, "duration" : episode.duration, "position" : episode.position, "downloadedfile" : episode.downloadedfile, "image" : img, "artist" : artist, "audiourl" : episode.audiourl}); |
811 | + for(i = 0; i < rs.rows.length; i++) { |
812 | + episode = rs.rows.item(i); |
813 | + if (!episode.listened) { |
814 | + episodeModel.insert(newCount, {"guid" : episode.guid, "listened" : episode.listened, "published": episode.published, "name" : episode.name, "description" : episode.description, "duration" : episode.duration, "position" : episode.position, "downloadedfile" : episode.downloadedfile, "image" : img, "artist" : artist, "audiourl" : episode.audiourl}); |
815 | + newCount++; |
816 | + } else { |
817 | + episodeModel.insert(i,{"guid" : episode.guid, "listened" : episode.listened, "published": episode.published, "name" : episode.name, "description" : episode.description, "duration" : episode.duration, "position" : episode.position, "downloadedfile" : episode.downloadedfile, "image" : img, "artist" : artist, "audiourl" : episode.audiourl}); |
818 | + } |
819 | } |
820 | }); |
821 | } |
822 | |
823 | === modified file 'app/ui/PlayerControls.qml' |
824 | --- app/ui/PlayerControls.qml 2015-03-08 11:10:07 +0000 |
825 | +++ app/ui/PlayerControls.qml 2015-04-18 14:12:52 +0000 |
826 | @@ -53,7 +53,7 @@ |
827 | id: progressBarHint |
828 | anchors.left: parent.left |
829 | anchors.top: cover.bottom |
830 | - color: UbuntuColors.orange |
831 | + color: podbird.theme.focusText |
832 | height: units.gu(0.25) |
833 | width: player.duration > 0 ? (player.position / player.duration) * parent.width : 0 |
834 | } |
835 | @@ -72,7 +72,7 @@ |
836 | color: "white" |
837 | elide: Text.ElideRight |
838 | maximumLineCount: 2 |
839 | - wrapMode: Text.WrapAnywhere |
840 | + wrapMode: Text.WordWrap |
841 | text: currentName |
842 | } |
843 | |
844 | |
845 | === modified file 'app/ui/PodcastsTab.qml' |
846 | --- app/ui/PodcastsTab.qml 2015-03-29 15:33:26 +0000 |
847 | +++ app/ui/PodcastsTab.qml 2015-04-18 14:12:52 +0000 |
848 | @@ -186,13 +186,6 @@ |
849 | filter.pattern: RegExp(searchField.text, "gi") |
850 | } |
851 | |
852 | - ListModel { |
853 | - id: episodeModel |
854 | - property string pid; |
855 | - property string artist; |
856 | - property string image; |
857 | - } |
858 | - |
859 | ListView { |
860 | id: view |
861 | |
862 | @@ -213,6 +206,7 @@ |
863 | height: units.gu(8) |
864 | removable: true |
865 | confirmRemoval: true |
866 | + showDivider: false |
867 | highlightWhenPressed: false |
868 | |
869 | onItemRemoved: { |
870 | @@ -230,7 +224,8 @@ |
871 | |
872 | Rectangle { |
873 | anchors.fill: parent |
874 | - color: listItem.pressed ? podbird.theme.hightlightListView : "transparent" |
875 | + opacity: 0.3 |
876 | + color: index % 2 === 0 ? podbird.theme.hightlightListView : "Transparent" |
877 | } |
878 | |
879 | onClicked: { |
880 | |
881 | === renamed file 'app/ui/SearchTab.qml' => 'app/ui/SearchPage.qml' |
882 | --- app/ui/SearchTab.qml 2015-03-29 15:33:26 +0000 |
883 | +++ app/ui/SearchPage.qml 2015-04-18 14:12:52 +0000 |
884 | @@ -23,24 +23,64 @@ |
885 | import Ubuntu.Components.ListItems 1.0 as ListItem |
886 | import "../podcasts.js" as Podcasts |
887 | |
888 | -Tab { |
889 | - title: i18n.tr("Find New Podcasts") |
890 | +Page { |
891 | + id: searchPage |
892 | |
893 | property var xhr: new XMLHttpRequest; |
894 | |
895 | - page: Page { |
896 | - Column { |
897 | - spacing: units.gu(2) |
898 | - anchors.fill: parent |
899 | - anchors.topMargin: units.gu(2) |
900 | - |
901 | - TextField { |
902 | + /* |
903 | + #FIXME: The following lines of code is necessary due to a upstream bug |
904 | + in the SDK http://pad.lv/1400297. This bug is still present in the rtm. |
905 | + Once it is fixed, this following property and connection can be remvoed. |
906 | + */ |
907 | + property Item __oldContents: null |
908 | + Connections { |
909 | + target: searchPage.head |
910 | + onContentsChanged: { |
911 | + if (searchPage.__oldContents) { |
912 | + searchPage.__oldContents.parent = null; |
913 | + } |
914 | + searchPage.__oldContents = searchPage.head.contents; |
915 | + } |
916 | + } |
917 | + |
918 | + state: "default" |
919 | + states: [ |
920 | + PageHeadState { |
921 | + name: "default" |
922 | + head: searchPage.head |
923 | + actions: [ |
924 | + Action { |
925 | + iconName: "search" |
926 | + text: i18n.tr("Search Episode") |
927 | + onTriggered: { |
928 | + searchPage.state = "search" |
929 | + searchField.forceActiveFocus() |
930 | + } |
931 | + } |
932 | + ] |
933 | + }, |
934 | + |
935 | + PageHeadState { |
936 | + name: "search" |
937 | + head: searchPage.head |
938 | + backAction: Action { |
939 | + iconName: "back" |
940 | + text: i18n.tr("Back") |
941 | + onTriggered: { |
942 | + resultsView.forceActiveFocus() |
943 | + searchField.text = "" |
944 | + searchPage.state = "default" |
945 | + } |
946 | + } |
947 | + |
948 | + contents: TextField { |
949 | id: searchField |
950 | - anchors.left: parent.left |
951 | - anchors.right: parent.right |
952 | - anchors.margins: units.gu(2) |
953 | + inputMethodHints: Qt.ImhNoPredictiveText |
954 | placeholderText: i18n.tr("Search...") |
955 | - inputMethodHints: Qt.ImhNoPredictiveText; |
956 | + anchors.left: parent ? parent.left : undefined |
957 | + anchors.right: parent ? parent.right : undefined |
958 | + anchors.rightMargin: units.gu(2) |
959 | onTextChanged: { |
960 | if (text.length > 2) { |
961 | search(text) |
962 | @@ -49,95 +89,106 @@ |
963 | } |
964 | } |
965 | } |
966 | - |
967 | - ListView { |
968 | - id: resultsView |
969 | - clip: true |
970 | - width: parent.width |
971 | - model: searchResults |
972 | - height: parent.height - searchField.height - units.gu(2) |
973 | - |
974 | - footer: Item { |
975 | - width: parent.width |
976 | - height: units.gu(7) |
977 | - } |
978 | - |
979 | - delegate: ListItem.Empty { |
980 | - id: listItem |
981 | - |
982 | - height: units.gu(8) |
983 | - highlightWhenPressed: false |
984 | - |
985 | - Rectangle { |
986 | - anchors.fill: parent |
987 | - color: listItem.pressed ? podbird.theme.hightlightListView : "transparent" |
988 | - } |
989 | - |
990 | - RowLayout { |
991 | - id: titleRow |
992 | - |
993 | - anchors.left: parent.left |
994 | - anchors.right: parent.right |
995 | - anchors.margins: units.gu(2) |
996 | - anchors.verticalCenter: parent.verticalCenter |
997 | - |
998 | - spacing: units.gu(2) |
999 | - |
1000 | - Image { |
1001 | - id: imgFrame |
1002 | - width: units.gu(6) |
1003 | - height: width |
1004 | - sourceSize.height: width |
1005 | - sourceSize.width: width |
1006 | - source: model.image |
1007 | - } |
1008 | - |
1009 | - Column { |
1010 | - id: detailColumn |
1011 | - |
1012 | - anchors.verticalCenter: imgFrame.verticalCenter |
1013 | - Layout.fillWidth: true |
1014 | - |
1015 | - Label { |
1016 | - id: podcastTitle |
1017 | - textFormat: Text.PlainText |
1018 | - text: model.name |
1019 | - width: parent.width |
1020 | - fontSize: "small" |
1021 | - elide: Text.ElideRight |
1022 | - } |
1023 | - |
1024 | - Label { |
1025 | - id: episodeCount |
1026 | - width: parent.width |
1027 | - color: "#999999" |
1028 | - text: model.artist |
1029 | - fontSize: "x-small" |
1030 | - elide: Text.ElideRight |
1031 | - } |
1032 | - } |
1033 | - |
1034 | - Button { |
1035 | - anchors.right: parent.right |
1036 | - text: i18n.tr("Subscribe") |
1037 | - color: UbuntuColors.green |
1038 | - onClicked: { |
1039 | - Podcasts.subscribe(model.artist, model.name, model.feed, model.image); |
1040 | - imageDownloader.feed = model.feed; |
1041 | - imageDownloader.download(model.image); |
1042 | - tabs.selectedTabIndex = 0; |
1043 | - searchField.text = "" |
1044 | - } |
1045 | - } |
1046 | - } |
1047 | - } |
1048 | - |
1049 | - Scrollbar { |
1050 | - flickableItem: resultsView |
1051 | - } |
1052 | - |
1053 | - } |
1054 | - } |
1055 | + } |
1056 | + ] |
1057 | + |
1058 | + EmptyState { |
1059 | + anchors.centerIn: parent |
1060 | + anchors.verticalCenterOffset: Qt.inputMethod.visible ? units.gu(4) : 0 |
1061 | + visible: searchResults.count === 0 |
1062 | + iconName: "search" |
1063 | + title: searchPage.state !== "search" ? i18n.tr("Looking for a new Podcast?") : i18n.tr("No Podcasts found") |
1064 | + subTitle: searchPage.state !== "search" ? i18n.tr("Click the 'magnifier' at the top to search.") : i18n.tr("No podcasts found matching the search term.") |
1065 | + } |
1066 | + |
1067 | + ListView { |
1068 | + id: resultsView |
1069 | + |
1070 | + clip: true |
1071 | + model: searchResults |
1072 | + anchors.fill: parent |
1073 | + |
1074 | + footer: Item { |
1075 | + width: parent.width |
1076 | + height: units.gu(7) |
1077 | + } |
1078 | + |
1079 | + delegate: ListItem.Empty { |
1080 | + id: listItem |
1081 | + |
1082 | + height: units.gu(8) |
1083 | + showDivider: false |
1084 | + highlightWhenPressed: false |
1085 | + |
1086 | + Rectangle { |
1087 | + anchors.fill: parent |
1088 | + opacity: 0.3 |
1089 | + color: index % 2 === 0 ? podbird.theme.hightlightListView : "Transparent" |
1090 | + } |
1091 | + |
1092 | + RowLayout { |
1093 | + id: titleRow |
1094 | + |
1095 | + anchors.left: parent.left |
1096 | + anchors.right: parent.right |
1097 | + anchors.margins: units.gu(2) |
1098 | + anchors.verticalCenter: parent.verticalCenter |
1099 | + |
1100 | + spacing: units.gu(2) |
1101 | + |
1102 | + Image { |
1103 | + id: imgFrame |
1104 | + width: units.gu(6) |
1105 | + height: width |
1106 | + sourceSize.height: width |
1107 | + sourceSize.width: width |
1108 | + source: model.image |
1109 | + } |
1110 | + |
1111 | + Column { |
1112 | + id: detailColumn |
1113 | + |
1114 | + anchors.verticalCenter: imgFrame.verticalCenter |
1115 | + Layout.fillWidth: true |
1116 | + |
1117 | + Label { |
1118 | + id: podcastTitle |
1119 | + textFormat: Text.PlainText |
1120 | + text: model.name |
1121 | + width: parent.width |
1122 | + fontSize: "medium" |
1123 | + elide: Text.ElideRight |
1124 | + } |
1125 | + |
1126 | + Label { |
1127 | + id: episodeCount |
1128 | + width: parent.width |
1129 | + color: "#999999" |
1130 | + text: model.artist |
1131 | + fontSize: "x-small" |
1132 | + elide: Text.ElideRight |
1133 | + } |
1134 | + } |
1135 | + |
1136 | + Button { |
1137 | + anchors.right: parent.right |
1138 | + text: i18n.tr("Subscribe") |
1139 | + color: UbuntuColors.green |
1140 | + onClicked: { |
1141 | + Podcasts.subscribe(model.artist, model.name, model.feed, model.image); |
1142 | + imageDownloader.feed = model.feed; |
1143 | + imageDownloader.download(model.image); |
1144 | + tabs.selectedTabIndex = 0; |
1145 | + searchField.text = "" |
1146 | + } |
1147 | + } |
1148 | + } |
1149 | + } |
1150 | + |
1151 | + Scrollbar { |
1152 | + flickableItem: resultsView |
1153 | + } |
1154 | + |
1155 | } |
1156 | |
1157 | ListModel { |
1158 | |
1159 | === modified file 'po/com.mikeasoft.podbird.pot' |
1160 | --- po/com.mikeasoft.podbird.pot 2015-04-16 10:18:41 +0000 |
1161 | +++ po/com.mikeasoft.podbird.pot 2015-04-18 14:12:52 +0000 |
1162 | @@ -8,7 +8,7 @@ |
1163 | msgstr "" |
1164 | "Project-Id-Version: \n" |
1165 | "Report-Msgid-Bugs-To: \n" |
1166 | -"POT-Creation-Date: 2015-04-16 12:16+0200\n" |
1167 | +"POT-Creation-Date: 2015-04-16 12:43+0200\n" |
1168 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
1169 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
1170 | "Language-Team: LANGUAGE <LL@li.org>\n" |
1171 | @@ -18,7 +18,11 @@ |
1172 | "Content-Transfer-Encoding: 8bit\n" |
1173 | "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" |
1174 | |
1175 | -#: ../app/podbird.qml:178 |
1176 | +#: ../app/podbird.qml:173 |
1177 | +msgid "Find New Podcasts" |
1178 | +msgstr "" |
1179 | + |
1180 | +#: ../app/podbird.qml:187 |
1181 | msgid "Settings" |
1182 | msgstr "" |
1183 | |
1184 | @@ -59,7 +63,7 @@ |
1185 | #: ../app/settings/DownloadSetting.qml:34 |
1186 | #: ../app/settings/DownloadSetting.qml:35 |
1187 | #: ../app/settings/DownloadSetting.qml:36 |
1188 | -#: ../app/settings/DownloadSetting.qml:37 |
1189 | +#: ../app/settings/DownloadSetting.qml:37 ../app/ui/EpisodesPage.qml:337 |
1190 | #, qt-format |
1191 | msgid "%1 episode" |
1192 | msgid_plural "%1 episodes" |
1193 | @@ -78,61 +82,73 @@ |
1194 | msgid "Dark" |
1195 | msgstr "" |
1196 | |
1197 | -#: ../app/ui/EpisodesPage.qml:85 |
1198 | +#: ../app/ui/EpisodesPage.qml:33 |
1199 | +msgid "Podcast" |
1200 | +msgstr "" |
1201 | + |
1202 | +#: ../app/ui/EpisodesPage.qml:89 ../app/ui/SearchPage.qml:55 |
1203 | msgid "Search Episode" |
1204 | msgstr "" |
1205 | |
1206 | -#: ../app/ui/EpisodesPage.qml:94 |
1207 | +#: ../app/ui/EpisodesPage.qml:98 |
1208 | msgid "Mark all listened" |
1209 | msgstr "" |
1210 | |
1211 | -#: ../app/ui/EpisodesPage.qml:105 ../app/ui/EpisodesPage.qml:153 |
1212 | +#: ../app/ui/EpisodesPage.qml:109 ../app/ui/EpisodesPage.qml:187 |
1213 | msgid "Unsubscribe" |
1214 | msgstr "" |
1215 | |
1216 | -#: ../app/ui/EpisodesPage.qml:120 ../app/ui/PodcastsTab.qml:86 |
1217 | -#: ../app/ui/PodcastsTab.qml:109 |
1218 | +#: ../app/ui/EpisodesPage.qml:124 ../app/ui/PodcastsTab.qml:86 |
1219 | +#: ../app/ui/PodcastsTab.qml:109 ../app/ui/SearchPage.qml:69 |
1220 | msgid "Back" |
1221 | msgstr "" |
1222 | |
1223 | -#: ../app/ui/EpisodesPage.qml:131 |
1224 | +#: ../app/ui/EpisodesPage.qml:136 |
1225 | msgid "Search episode" |
1226 | msgstr "" |
1227 | |
1228 | -#: ../app/ui/EpisodesPage.qml:150 |
1229 | +#: ../app/ui/EpisodesPage.qml:184 |
1230 | msgid "Unsubscribe Confirmation" |
1231 | msgstr "" |
1232 | |
1233 | -#: ../app/ui/EpisodesPage.qml:151 |
1234 | +#: ../app/ui/EpisodesPage.qml:185 |
1235 | #, qt-format |
1236 | msgid "Are you sure you want to unsubscribe from <b>%1</b>?" |
1237 | msgstr "" |
1238 | |
1239 | -#: ../app/ui/EpisodesPage.qml:170 |
1240 | +#: ../app/ui/EpisodesPage.qml:204 |
1241 | msgid "Cancel" |
1242 | msgstr "" |
1243 | |
1244 | -#: ../app/ui/EpisodesPage.qml:184 |
1245 | +#: ../app/ui/EpisodesPage.qml:218 |
1246 | msgid "No Episodes found" |
1247 | msgstr "" |
1248 | |
1249 | -#: ../app/ui/EpisodesPage.qml:185 |
1250 | +#: ../app/ui/EpisodesPage.qml:219 |
1251 | msgid "No episodes found matching the search term." |
1252 | msgstr "" |
1253 | |
1254 | -#: ../app/ui/EpisodesPage.qml:319 |
1255 | -#, no-c-format, qt-format |
1256 | -msgid "%1h %2m" |
1257 | -msgstr "" |
1258 | - |
1259 | -#: ../app/ui/EpisodesPage.qml:328 |
1260 | -#, no-c-format, qt-format |
1261 | -msgid "%1h" |
1262 | -msgstr "" |
1263 | - |
1264 | -#: ../app/ui/EpisodesPage.qml:336 |
1265 | -#, no-c-format, qt-format |
1266 | -msgid "%1m" |
1267 | +#: ../app/ui/EpisodesPage.qml:241 |
1268 | +#, no-c-format, qt-format |
1269 | +msgid "%1 hr %2 min" |
1270 | +msgstr "" |
1271 | + |
1272 | +#: ../app/ui/EpisodesPage.qml:250 |
1273 | +#, no-c-format, qt-format |
1274 | +msgid "%1 hr" |
1275 | +msgstr "" |
1276 | + |
1277 | +#: ../app/ui/EpisodesPage.qml:258 |
1278 | +#, no-c-format, qt-format |
1279 | +msgid "%1 min" |
1280 | +msgstr "" |
1281 | + |
1282 | +#: ../app/ui/EpisodesPage.qml:290 |
1283 | +msgid "Unheard" |
1284 | +msgstr "" |
1285 | + |
1286 | +#: ../app/ui/EpisodesPage.qml:290 |
1287 | +msgid "Listened" |
1288 | msgstr "" |
1289 | |
1290 | #: ../app/ui/NowPlayingPage.qml:28 |
1291 | @@ -197,26 +213,34 @@ |
1292 | "page to add some." |
1293 | msgstr "" |
1294 | |
1295 | -#: ../app/ui/PodcastsTab.qml:175 |
1296 | +#: ../app/ui/PodcastsTab.qml:175 ../app/ui/SearchPage.qml:101 |
1297 | msgid "No podcasts found matching the search term." |
1298 | msgstr "" |
1299 | |
1300 | -#: ../app/ui/PodcastsTab.qml:291 |
1301 | +#: ../app/ui/PodcastsTab.qml:286 |
1302 | #, qt-format |
1303 | msgid "%1 unheard episode" |
1304 | msgid_plural "%1 unheard episodes" |
1305 | msgstr[0] "" |
1306 | msgstr[1] "" |
1307 | |
1308 | -#: ../app/ui/SearchTab.qml:27 |
1309 | -msgid "Find New Podcasts" |
1310 | -msgstr "" |
1311 | - |
1312 | -#: ../app/ui/SearchTab.qml:42 |
1313 | +#: ../app/ui/SearchPage.qml:80 |
1314 | msgid "Search..." |
1315 | msgstr "" |
1316 | |
1317 | -#: ../app/ui/SearchTab.qml:122 |
1318 | +#: ../app/ui/SearchPage.qml:100 |
1319 | +msgid "Looking for a new Podcast?" |
1320 | +msgstr "" |
1321 | + |
1322 | +#: ../app/ui/SearchPage.qml:100 |
1323 | +msgid "No Podcasts found" |
1324 | +msgstr "" |
1325 | + |
1326 | +#: ../app/ui/SearchPage.qml:101 |
1327 | +msgid "Click the 'magnifier' at the top to search." |
1328 | +msgstr "" |
1329 | + |
1330 | +#: ../app/ui/SearchPage.qml:175 |
1331 | msgid "Subscribe" |
1332 | msgstr "" |
1333 | |
1334 | @@ -323,6 +347,6 @@ |
1335 | msgid "Finish" |
1336 | msgstr "" |
1337 | |
1338 | -#: /home/krnekhelesh/Documents/Ubuntu-Projects/MP-Reviews/builddir/build-5-auto-download-option-UbuntuSDK_for_armhf_GCC_ubuntu_sdk_14_10_utopic-Default/po/Podbird.desktop.in.h:1 |
1339 | +#: /home/krnekhelesh/Documents/Ubuntu-Projects/MP-Reviews/builddir/build-5.5-kevin-episodes-design-UbuntuSDK_for_armhf_GCC_ubuntu_sdk_14_10_utopic-Default/po/Podbird.desktop.in.h:1 |
1340 | msgid "Podbird" |
1341 | msgstr "" |
1342 | |
1343 | === modified file 'podbird.png' |
1344 | Binary files podbird.png 2015-03-30 00:28:42 +0000 and podbird.png 2015-04-18 14:12:52 +0000 differ |
Here's a screenshot of what it looks now https:/ /imgur. com/5gKB4QG