Merge lp:~nik90/podbird/add-queue-support into lp:podbird/devel
- add-queue-support
- Merge into devel
Proposed by
Nekhelesh Ramananthan
Status: | Merged |
---|---|
Merged at revision: | 128 |
Proposed branch: | lp:~nik90/podbird/add-queue-support |
Merge into: | lp:podbird/devel |
Diff against target: |
1283 lines (+696/-336) 9 files modified
app/podbird.qml (+119/-52) app/podcasts.js (+99/-0) app/ui/EpisodesPage.qml (+15/-17) app/ui/EpisodesTab.qml (+15/-17) app/ui/NowPlayingPage.qml (+330/-224) app/ui/PlayerControls.qml (+6/-6) app/ui/PodcastsTab.qml (+1/-1) app/ui/Queue.qml (+94/-0) po/podbird.nik90.pot (+17/-19) |
To merge this branch: | bzr merge lp:~nik90/podbird/add-queue-support |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Podbird Developers | Pending | ||
Review via email: mp+288875@code.launchpad.net |
Commit message
Description of the change
Added Queue Support
This however removes,
- usermetrics since it won't be updated due to the app being in the background
- playing from the previously saved position...again this won't work when the app is in the background.
To post a comment you must log in.
- 138. By Nekhelesh Ramananthan
-
Removed unnecessary comments and getNextIndex() function
- 139. By Nekhelesh Ramananthan
-
Removed unnecessary js queue functions
- 140. By Nekhelesh Ramananthan
-
Fixed empty bottom player controls
- 141. By Nekhelesh Ramananthan
-
Another small fix
- 142. By Nekhelesh Ramananthan
-
Revert manifest framework change
- 143. By Nekhelesh Ramananthan
-
Small code style change
- 144. By Nekhelesh Ramananthan
-
Changed string fullview
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'app/podbird.qml' |
2 | --- app/podbird.qml 2016-03-05 16:54:12 +0000 |
3 | +++ app/podbird.qml 2016-03-14 00:33:23 +0000 |
4 | @@ -19,7 +19,7 @@ |
5 | import QtQuick 2.4 |
6 | import Podbird 1.0 |
7 | import UserMetrics 0.1 |
8 | -import QtMultimedia 5.4 |
9 | +import QtMultimedia 5.6 |
10 | import Ubuntu.Connectivity 1.0 |
11 | import Qt.labs.settings 1.0 |
12 | import Ubuntu.Components 1.3 |
13 | @@ -50,6 +50,7 @@ |
14 | db.transaction(function (tx) { |
15 | tx.executeSql('UPDATE Episode SET queued=0 WHERE queued=1'); |
16 | }) |
17 | + Podcasts.clearQueue() |
18 | } |
19 | |
20 | // RefreshModel function to call refreshModel() function of the tab currently |
21 | @@ -167,55 +168,121 @@ |
22 | } |
23 | } |
24 | |
25 | - // UserMetrics to show Podbird stats on welcome screen |
26 | - Metric { |
27 | - id: podcastsMetric |
28 | - name: "podcast-metrics" |
29 | - // TRANSLATORS: this refers to a number of songs greater than one. The actual number will be prepended to the string automatically (plural forms are not yet fully supported in usermetrics, the library that displays that string) |
30 | - format: i18n.tr("Podcasts listened to today: <b>%1</b>") |
31 | - emptyFormat: i18n.tr("No podcasts listened to today") |
32 | - domain: "com.mikeasoft.podbird" |
33 | - } |
34 | - |
35 | - // Load the media player only when the user starts to play some media. This |
36 | - // should improve app-startup slightly. |
37 | - Loader { |
38 | - id: playerLoader |
39 | - sourceComponent: currentUrl != "" ? playerComponent : undefined |
40 | - } |
41 | - |
42 | - Component { |
43 | - id: playerComponent |
44 | - MediaPlayer { |
45 | - id: player |
46 | - |
47 | - property bool podcastCounted: false |
48 | - |
49 | - source: currentUrl |
50 | - |
51 | - onSourceChanged: { |
52 | - podcastCounted = false |
53 | - } |
54 | - |
55 | - onPositionChanged: { |
56 | - if (currentGuid == "" || duration <= 0) { |
57 | - return; |
58 | - } |
59 | - |
60 | - if (position > 10000 && !podcastCounted) { |
61 | - podcastCounted = true |
62 | - podcastsMetric.increment() |
63 | - console.log("[LOG]: Podcast User metric incremented") |
64 | - } |
65 | - |
66 | - var db = Podcasts.init(); |
67 | - db.transaction(function (tx) { |
68 | - tx.executeSql("UPDATE Episode SET position=? WHERE guid=?", [position >= duration ? 120 : position, currentGuid]); |
69 | - if (position >= duration - 120) { |
70 | - tx.executeSql("UPDATE Episode SET listened = 1 WHERE guid=?", [currentGuid]); |
71 | - } |
72 | - }); |
73 | - } |
74 | + MediaPlayer { |
75 | + id: player |
76 | + |
77 | + // Wrapper function around decodeURIComponent() to prevent exceptions |
78 | + // from bubbling up to the app. |
79 | + function decodeFileURI(filename) |
80 | + { |
81 | + var newFilename = ""; |
82 | + try { |
83 | + newFilename = decodeURIComponent(filename); |
84 | + } catch (e) { |
85 | + newFilename = filename; |
86 | + console.log("Unicode decoding error:", filename, e.message) |
87 | + } |
88 | + |
89 | + return newFilename; |
90 | + } |
91 | + |
92 | + function metaForSource(source) { |
93 | + var blankMeta = { |
94 | + name: "", |
95 | + artist: "", |
96 | + image: "", |
97 | + guid: "", |
98 | + } |
99 | + |
100 | + source = source.toString() |
101 | + |
102 | + if (source.indexOf("file://") === 0) { |
103 | + source = source.substring(7); |
104 | + } |
105 | + |
106 | + return Podcasts.lookup(decodeFileURI(source)) || blankMeta; |
107 | + } |
108 | + |
109 | + function toggle() { |
110 | + if (playbackState === MediaPlayer.PlayingState) { |
111 | + pause() |
112 | + } else { |
113 | + play() |
114 | + } |
115 | + } |
116 | + |
117 | + function playEpisode(guid, image, name, artist, url) { |
118 | + // Clear current queue |
119 | + player.playlist.clear() |
120 | + Podcasts.clearQueue() |
121 | + |
122 | + // Add episode to queue |
123 | + player.playlist.addItem(Qt.resolvedUrl(url)) |
124 | + Podcasts.addItemToQueue(guid, image, name, artist, url) |
125 | + |
126 | + // Play episode |
127 | + player.play() |
128 | + } |
129 | + |
130 | + function addEpisodeToQueue(guid, image, name, artist, url) { |
131 | + player.playlist.addItem(Qt.resolvedUrl(url)) |
132 | + Podcasts.addItemToQueue(guid, image, name, artist, url) |
133 | + |
134 | + // If added episode is the first one in the queue, then set the current metadata |
135 | + // so that the bottom player controls will be shown, allowing the user to play |
136 | + // the episode if he chooses to. |
137 | + if (player.playlist.itemCount === 0) { |
138 | + currentGuid = guid |
139 | + currentName = name |
140 | + currentArtist = artist |
141 | + currentImage = image |
142 | + currentUrl = url |
143 | + } |
144 | + } |
145 | + |
146 | + property bool endOfMedia: false |
147 | + property double progress: 0 |
148 | + |
149 | + playlist: Playlist { |
150 | + playbackMode: Playlist.Sequential |
151 | + |
152 | + readonly property bool canGoPrevious: currentIndex !== 0 |
153 | + readonly property bool canGoNext: currentIndex !== itemCount - 1 |
154 | + |
155 | + onCurrentItemSourceChanged: { |
156 | + var meta = player.metaForSource(currentItemSource) |
157 | + currentGuid = ""; |
158 | + currentName = meta.name |
159 | + currentArtist = meta.artist |
160 | + currentImage = meta.image |
161 | + currentGuid = meta.guid |
162 | + } |
163 | + } |
164 | + |
165 | + onStatusChanged: { |
166 | + if (status === MediaPlayer.EndOfMedia) { |
167 | + console.log("[LOG]: End of Media. Stopping.") |
168 | + endOfMedia = true |
169 | + stop() |
170 | + } |
171 | + } |
172 | + |
173 | + onStopped: { |
174 | + if (playlist.itemCount > 0) { |
175 | + if (endOfMedia) { |
176 | + // We just ended media, so jump to start of playlist |
177 | + playlist.currentIndex = 0; |
178 | + |
179 | + // Play then pause otherwise when we come from EndOfMedia |
180 | + // it calls next() until EndOfMedia again. |
181 | + play() |
182 | + } |
183 | + |
184 | + pause() |
185 | + } |
186 | + |
187 | + // Always reset endOfMedia |
188 | + endOfMedia = false |
189 | } |
190 | } |
191 | |
192 | @@ -290,13 +357,13 @@ |
193 | states: [ |
194 | State { |
195 | name: "shown" |
196 | - when: currentUrl != "" && !mainStack.currentPage.isNowPlayingPage |
197 | + when: player.playlist.itemCount !== 0 && !mainStack.currentPage.isNowPlayingPage |
198 | PropertyChanges { target: playerControlLoader; anchors.bottomMargin: 0 } |
199 | }, |
200 | |
201 | State { |
202 | name: "hidden" |
203 | - when: currentUrl == "" || mainStack.currentPage.isNowPlayingPage || !playerControl.visible |
204 | + when: player.playlist.itemCount === 0 || mainStack.currentPage.isNowPlayingPage || !playerControl.visible |
205 | PropertyChanges { target: playerControlLoader; anchors.bottomMargin: -units.gu(7) } |
206 | } |
207 | ] |
208 | |
209 | === modified file 'app/podcasts.js' |
210 | --- app/podcasts.js 2016-03-05 20:10:55 +0000 |
211 | +++ app/podcasts.js 2016-03-14 00:33:23 +0000 |
212 | @@ -22,6 +22,7 @@ |
213 | db.transaction(function(tx) { |
214 | tx.executeSql('CREATE TABLE IF NOT EXISTS Podcast(artist TEXT, name TEXT, description TEXT, feed TEXT, image TEXT, lastupdate TIMESTAMP)'); |
215 | 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, queued BOOLEAN, listened BOOLEAN, favourited BOOLEAN, position INTEGER, FOREIGN KEY(podcast) REFERENCES Podcast(rowid))'); |
216 | + tx.executeSql('CREATE TABLE IF NOT EXISTS Queue(ind INTEGER NOT NULL, guid TEXT, image TEXT, name TEXT, artist TEXT, url TEXT)'); |
217 | }); |
218 | |
219 | /* |
220 | @@ -39,6 +40,104 @@ |
221 | return db; |
222 | } |
223 | |
224 | +// Function to add item to queue |
225 | +function addItemToQueue(guid, image, name, artist, url) { |
226 | + var db = init() |
227 | + |
228 | + db.transaction(function(tx) { |
229 | + var ind = getNextIndex(tx); |
230 | + var rs = tx.executeSql("INSERT OR REPLACE INTO Queue (ind, guid, image, name, artist, url) VALUES (?, ?, ?, ?, ?, ?)", [ind, guid, image, name, artist, url]); |
231 | + if (rs.rowsAffected > 0) { |
232 | + console.log("[LOG]: QUEUE add OK") |
233 | + } else { |
234 | + console.log("[LOG]: QUEUE add FAIL") |
235 | + } |
236 | + }); |
237 | +} |
238 | + |
239 | +function removeItemFromQueue(source) { |
240 | + var db = init() |
241 | + |
242 | + db.transaction(function(tx) { |
243 | + // Remove selected source from the queue |
244 | + tx.executeSql("DELETE FROM Queue WHERE url = ?", source) |
245 | + |
246 | + // Rebuild queue in order |
247 | + var rs = tx.executeSql("SELECT ind FROM Queue ORDER BY ind ASC") |
248 | + |
249 | + for (var i=0; i<rs.rows.length; i++) { |
250 | + tx.executeSql("UPDATE Queue SET ind = ? WHERE ind = ?", [i, rs.rows.item(i).ind]) |
251 | + } |
252 | + }) |
253 | +} |
254 | + |
255 | +// Function to clear the queue |
256 | +function clearQueue() { |
257 | + var db = init(); |
258 | + db.transaction(function(tx) { |
259 | + tx.executeSql("DELETE FROM Queue"); |
260 | + }); |
261 | +} |
262 | + |
263 | +function lookup(source) { |
264 | + var db = init(); |
265 | + var meta = { |
266 | + name: "", |
267 | + artist: "", |
268 | + image: "", |
269 | + guid: "", |
270 | + } |
271 | + |
272 | + db.transaction(function(tx) { |
273 | + var rs = tx.executeSql("SELECT * FROM Queue ORDER BY ind ASC"); |
274 | + for(var i = 0; i < rs.rows.length; i++) { |
275 | + var episode = rs.rows.item(i); |
276 | + if (source === episode.url) { |
277 | + meta.name = episode.name |
278 | + meta.artist = episode.artist |
279 | + meta.image = episode.image |
280 | + meta.guid = episode.guid |
281 | + break |
282 | + } |
283 | + } |
284 | + }); |
285 | + |
286 | + return meta |
287 | +} |
288 | + |
289 | +// Function to get the next index for the queue |
290 | +function getNextIndex(tx) { |
291 | + var ind; |
292 | + |
293 | + if (tx === undefined) { |
294 | + var db = init(); |
295 | + db.transaction(function(tx) { |
296 | + ind = getNextIndex(tx); |
297 | + }); |
298 | + } else { |
299 | + var rs = tx.executeSql('SELECT MAX(ind) FROM Queue') |
300 | + ind = isQueueEmpty(tx) ? 0 : rs.rows.item(0)["MAX(ind)"] + 1 |
301 | + } |
302 | + |
303 | + return ind; |
304 | +} |
305 | + |
306 | +function isQueueEmpty(tx) { |
307 | + var empty = false; |
308 | + |
309 | + if (tx === undefined) { |
310 | + var db = init(); |
311 | + db.transaction( function(tx) { |
312 | + empty = isQueueEmpty(tx) |
313 | + }); |
314 | + } else { |
315 | + var rs = tx.executeSql("SELECT count(*) as value FROM Queue") |
316 | + empty = rs.rows.item(0).value === 0 |
317 | + } |
318 | + |
319 | + return empty |
320 | +} |
321 | + |
322 | function subscribe(artist, name, feed, img) { |
323 | var db = init(); |
324 | db.transaction(function(tx) { |
325 | |
326 | === modified file 'app/ui/EpisodesPage.qml' |
327 | --- app/ui/EpisodesPage.qml 2016-03-06 23:00:20 +0000 |
328 | +++ app/ui/EpisodesPage.qml 2016-03-14 00:33:23 +0000 |
329 | @@ -17,7 +17,7 @@ |
330 | */ |
331 | |
332 | import QtQuick 2.4 |
333 | -import QtMultimedia 5.4 |
334 | +import QtMultimedia 5.6 |
335 | import Ubuntu.Components 1.3 |
336 | import QtQuick.LocalStorage 2.0 |
337 | import Ubuntu.DownloadManager 0.1 |
338 | @@ -443,8 +443,8 @@ |
339 | id: listItemLayout |
340 | |
341 | title.text: model.name !== undefined ? model.name.trim() : "Undefined" |
342 | - title.color: currentGuid === model.guid || downloader.downloadingGuid === model.guid ? podbird.appTheme.focusText |
343 | - : podbird.appTheme.baseText |
344 | + title.color: downloader.downloadingGuid === model.guid ? podbird.appTheme.focusText |
345 | + : podbird.appTheme.baseText |
346 | // #FIXME: Change this 2 to prevent title eliding when UITK is updated to rev > 1800 |
347 | title.maximumLineCount: 1 |
348 | |
349 | @@ -512,6 +512,14 @@ |
350 | }, |
351 | |
352 | Action { |
353 | + iconName: "add-to-playlist" |
354 | + onTriggered: { |
355 | + var url = model.downloadedfile ? model.downloadedfile : model.audiourl |
356 | + player.addEpisodeToQueue(model.guid, model.image, model.name, model.artist, url) |
357 | + } |
358 | + }, |
359 | + |
360 | + Action { |
361 | iconName: model.favourited ? "unlike" : "like" |
362 | onTriggered: { |
363 | var db = Podcasts.init(); |
364 | @@ -537,20 +545,10 @@ |
365 | |
366 | onClicked: { |
367 | Haptics.play() |
368 | - var db = Podcasts.init(); |
369 | - db.transaction(function (tx) { |
370 | - if (currentGuid !== model.guid) { |
371 | - currentGuid = ""; |
372 | - currentUrl = model.downloadedfile ? model.downloadedfile : model.audiourl; |
373 | - var rs = tx.executeSql("SELECT position FROM Episode WHERE guid=?", [model.guid]); |
374 | - playerLoader.item.play(); |
375 | - playerLoader.item.seek(rs.rows.item(0).position); |
376 | - currentName = model.name; |
377 | - currentArtist = model.artist; |
378 | - currentImage = model.image; |
379 | - currentGuid = model.guid; |
380 | - } |
381 | - }); |
382 | + if (currentGuid !== model.guid) { |
383 | + currentUrl = model.downloadedfile ? model.downloadedfile : model.audiourl; |
384 | + player.playEpisode(model.guid, model.image, model.name, model.artist, currentUrl) |
385 | + } |
386 | } |
387 | } |
388 | |
389 | |
390 | === modified file 'app/ui/EpisodesTab.qml' |
391 | --- app/ui/EpisodesTab.qml 2016-03-06 23:00:20 +0000 |
392 | +++ app/ui/EpisodesTab.qml 2016-03-14 00:33:23 +0000 |
393 | @@ -17,7 +17,7 @@ |
394 | */ |
395 | |
396 | import QtQuick 2.4 |
397 | -import QtMultimedia 5.4 |
398 | +import QtMultimedia 5.6 |
399 | import Ubuntu.Components 1.3 |
400 | import QtQuick.LocalStorage 2.0 |
401 | import Ubuntu.DownloadManager 0.1 |
402 | @@ -381,8 +381,8 @@ |
403 | id: listItemLayout |
404 | |
405 | title.text: model.name !== undefined ? model.name.trim() : "Undefined" |
406 | - title.color: currentGuid === model.guid || downloader.downloadingGuid === model.guid ? podbird.appTheme.focusText |
407 | - : podbird.appTheme.baseText |
408 | + title.color: downloader.downloadingGuid === model.guid ? podbird.appTheme.focusText |
409 | + : podbird.appTheme.baseText |
410 | // #FIXME: Change this 2 to prevent title eliding when UITK is updated to rev > 1800 |
411 | title.maximumLineCount: 1 |
412 | |
413 | @@ -466,6 +466,14 @@ |
414 | }, |
415 | |
416 | Action { |
417 | + iconName: "add-to-playlist" |
418 | + onTriggered: { |
419 | + var url = model.downloadedfile ? model.downloadedfile : model.audiourl |
420 | + player.addEpisodeToQueue(model.guid, model.image, model.name, model.artist, url) |
421 | + } |
422 | + }, |
423 | + |
424 | + Action { |
425 | iconName: model.favourited ? "unlike" : "like" |
426 | onTriggered: { |
427 | var db = Podcasts.init(); |
428 | @@ -497,20 +505,10 @@ |
429 | |
430 | onClicked: { |
431 | Haptics.play() |
432 | - var db = Podcasts.init(); |
433 | - db.transaction(function (tx) { |
434 | - if (currentGuid !== model.guid) { |
435 | - currentGuid = ""; |
436 | - currentUrl = model.downloadedfile ? model.downloadedfile : model.audiourl; |
437 | - var rs = tx.executeSql("SELECT position FROM Episode WHERE guid=?", [model.guid]); |
438 | - playerLoader.item.play(); |
439 | - playerLoader.item.seek(rs.rows.item(0).position); |
440 | - currentName = model.name; |
441 | - currentArtist = model.artist; |
442 | - currentImage = model.image; |
443 | - currentGuid = model.guid; |
444 | - } |
445 | - }); |
446 | + if (currentGuid !== model.guid) { |
447 | + currentUrl = model.downloadedfile ? model.downloadedfile : model.audiourl; |
448 | + player.playEpisode(model.guid, model.image, model.name, model.artist, currentUrl) |
449 | + } |
450 | } |
451 | } |
452 | |
453 | |
454 | === modified file 'app/ui/NowPlayingPage.qml' |
455 | --- app/ui/NowPlayingPage.qml 2016-03-04 10:40:54 +0000 |
456 | +++ app/ui/NowPlayingPage.qml 2016-03-14 00:33:23 +0000 |
457 | @@ -17,8 +17,9 @@ |
458 | */ |
459 | |
460 | import QtQuick 2.4 |
461 | -import QtMultimedia 5.4 |
462 | +import QtMultimedia 5.6 |
463 | import Ubuntu.Components 1.3 |
464 | +import QtQuick.LocalStorage 2.0 |
465 | import "../podcasts.js" as Podcasts |
466 | import "../components" |
467 | |
468 | @@ -26,245 +27,350 @@ |
469 | id: nowPlayingPage |
470 | |
471 | visible: false |
472 | - title: i18n.tr("Now Playing") |
473 | |
474 | property bool isNowPlayingPage: true |
475 | - property bool isLandscapeMode: width > height |
476 | - |
477 | - // Landscape rule |
478 | - states: [ |
479 | - State { |
480 | - name: "landscape" |
481 | - when: isLandscapeMode |
482 | - |
483 | - PropertyChanges { |
484 | - target: blurredBackground |
485 | - width: parent.width/2.2 |
486 | - height: parent.height |
487 | - } |
488 | - |
489 | - AnchorChanges { |
490 | - target: blurredBackground |
491 | + |
492 | + header: PageHeader { |
493 | + title: i18n.tr("Now Playing") |
494 | + |
495 | + StyleHints { |
496 | + backgroundColor: podbird.appTheme.background |
497 | + } |
498 | + |
499 | + trailingActionBar.actions: Action { |
500 | + iconName: "delete" |
501 | + visible: nowPlayingPageSections.selectedIndex === 1 |
502 | + onTriggered: { |
503 | + Podcasts.clearQueue() |
504 | + player.playlist.clear() |
505 | + mainStack.pop() |
506 | + } |
507 | + } |
508 | + |
509 | + extension: Sections { |
510 | + id: nowPlayingPageSections |
511 | + |
512 | + anchors { |
513 | + left: parent.left |
514 | + leftMargin: units.gu(2) |
515 | + bottom: parent.bottom |
516 | + } |
517 | + |
518 | + StyleHints { |
519 | + selectedSectionColor: podbird.appTheme.focusText |
520 | + } |
521 | + model: [i18n.tr("Full view"), i18n.tr("Queue")] |
522 | + } |
523 | + } |
524 | + |
525 | + VisualItemModel { |
526 | + id: tabs |
527 | + |
528 | + Item { |
529 | + id: nowPlayingItem |
530 | + |
531 | + width: tabView.width |
532 | + height: tabView.height |
533 | + |
534 | + property bool isLandscapeMode: nowPlayingPage.width > nowPlayingPage.height |
535 | + |
536 | + // Landscape rule |
537 | + states: [ |
538 | + State { |
539 | + name: "landscape" |
540 | + when: nowPlayingItem.isLandscapeMode |
541 | + |
542 | + PropertyChanges { |
543 | + target: blurredBackground |
544 | + width: nowPlayingPage.width/2.2 |
545 | + height: nowPlayingPage.height |
546 | + } |
547 | + |
548 | + AnchorChanges { |
549 | + target: blurredBackground |
550 | + anchors { |
551 | + top: nowPlayingItem.top |
552 | + left: parent.left |
553 | + right: undefined |
554 | + } |
555 | + } |
556 | + |
557 | + AnchorChanges { |
558 | + target: dataContainer |
559 | + anchors { |
560 | + top: nowPlayingItem.top |
561 | + left: blurredBackground.right |
562 | + right: parent.right |
563 | + bottom: parent.bottom |
564 | + } |
565 | + } |
566 | + } |
567 | + ] |
568 | + |
569 | + BlurredBackground { |
570 | + id: blurredBackground |
571 | + |
572 | + anchors.left: parent.left |
573 | + anchors.top: nowPlayingItem.top |
574 | + anchors.right: parent.right |
575 | + height: title.lineCount === 1 ? nowPlayingPage.height/2.3 + units.gu(3) |
576 | + : nowPlayingPage.height/2.3 |
577 | + art: currentImage |
578 | + |
579 | + Image { |
580 | + width: Math.min(nowPlayingPage.width/2, nowPlayingPage.height/2) |
581 | + height: width |
582 | + sourceSize.height: width |
583 | + sourceSize.width: width |
584 | + source: currentImage |
585 | + asynchronous: true |
586 | + anchors.centerIn: parent |
587 | + } |
588 | + } |
589 | + |
590 | + Item { |
591 | + id: dataContainer |
592 | + |
593 | anchors { |
594 | - top: parent.top |
595 | + top: blurredBackground.bottom |
596 | left: parent.left |
597 | - right: undefined |
598 | - } |
599 | - } |
600 | - |
601 | - AnchorChanges { |
602 | - target: dataContainer |
603 | - anchors { |
604 | - top: parent.top |
605 | - left: blurredBackground.right |
606 | right: parent.right |
607 | bottom: parent.bottom |
608 | + margins: units.gu(2) |
609 | + bottomMargin: nowPlayingItem.isLandscapeMode ? units.gu(4) : units.gu(2) |
610 | + } |
611 | + |
612 | + Label { |
613 | + id: title |
614 | + anchors.left: parent.left |
615 | + anchors.right: parent.right |
616 | + anchors.top: parent.top |
617 | + text: currentName |
618 | + elide: Text.ElideRight |
619 | + textSize: Label.Large |
620 | + maximumLineCount: 2 |
621 | + wrapMode: Text.WordWrap |
622 | + color: podbird.appTheme.baseText |
623 | + } |
624 | + |
625 | + Label { |
626 | + id: artist |
627 | + anchors.left: title.left |
628 | + anchors.right: title.right |
629 | + anchors.top: title.bottom |
630 | + anchors.topMargin: units.gu(1) |
631 | + text: currentArtist |
632 | + elide: Text.ElideRight |
633 | + textSize: Label.Small |
634 | + color: podbird.appTheme.baseSubText |
635 | + } |
636 | + |
637 | + Slider { |
638 | + id: scrubber |
639 | + |
640 | + anchors { |
641 | + left: parent.left |
642 | + right: parent.right |
643 | + bottom: controls.top |
644 | + bottomMargin: nowPlayingItem.isLandscapeMode && title.lineCount < 2 ? units.gu(4) : units.gu(2) |
645 | + } |
646 | + |
647 | + live: true |
648 | + minimumValue: 0 |
649 | + maximumValue: player.duration |
650 | + value: player.position |
651 | + height: units.gu(2) |
652 | + |
653 | + onValueChanged: { |
654 | + if (pressed) { |
655 | + player.seek(value); |
656 | + } |
657 | + } |
658 | + |
659 | + function formatValue(v) { return Podcasts.formatTime(v/1000); } |
660 | + StyleHints { foregroundColor: podbird.appTheme.focusText } |
661 | + } |
662 | + |
663 | + Connections { |
664 | + target: player |
665 | + onPositionChanged: scrubber.value = player.position |
666 | + } |
667 | + |
668 | + Label { |
669 | + id: startTime |
670 | + textSize: Label.Small |
671 | + anchors.left: scrubber.left |
672 | + anchors.top: scrubber.bottom |
673 | + color: podbird.appTheme.baseText |
674 | + text: Podcasts.formatTime(player.position / 1000) |
675 | + } |
676 | + |
677 | + Label { |
678 | + id: endTime |
679 | + textSize: Label.Small |
680 | + anchors.right: scrubber.right |
681 | + anchors.top: scrubber.bottom |
682 | + color: podbird.appTheme.baseText |
683 | + text: Podcasts.formatTime(player.duration / 1000) |
684 | + } |
685 | + |
686 | + Row { |
687 | + id: controls |
688 | + |
689 | + anchors.bottom: parent.bottom |
690 | + anchors.horizontalCenter: parent.horizontalCenter |
691 | + spacing: units.gu(1) |
692 | + |
693 | + AbstractButton { |
694 | + id: mediaBackwardButton |
695 | + width: units.gu(6) |
696 | + height: width |
697 | + anchors.verticalCenter: parent.verticalCenter |
698 | + enabled: player.playlist.canGoPrevious |
699 | + opacity: enabled ? 1.0 : 0.4 |
700 | + onClicked: player.playlist.previous() |
701 | + |
702 | + Icon { |
703 | + id: mediaBackwardIcon |
704 | + width: units.gu(3) |
705 | + height: width |
706 | + anchors.centerIn: parent |
707 | + color: podbird.appTheme.baseIcon |
708 | + name: "media-skip-backward" |
709 | + } |
710 | + } |
711 | + |
712 | + AbstractButton { |
713 | + id: skipBackwardButton |
714 | + width: units.gu(6) |
715 | + height: width |
716 | + anchors.verticalCenter: parent.verticalCenter |
717 | + opacity: player.position === 0 ? 0.4 : 1.0 |
718 | + onClicked: { |
719 | + if (player.position > 0) { |
720 | + player.seek(player.position - podbird.settings.skipBack * 1000); |
721 | + } |
722 | + } |
723 | + |
724 | + Row { |
725 | + spacing: units.gu(1) |
726 | + anchors.centerIn: parent |
727 | + |
728 | + Label { |
729 | + // TRANSLATORS: The string shown in the UI is -15s to denote the number of seconds that the podcast playback will skip backward. |
730 | + // xgettext: no-c-format |
731 | + text: i18n.tr("-%1s").arg(podbird.settings.skipBack) |
732 | + textSize: Label.XxSmall |
733 | + color: podbird.appTheme.baseText |
734 | + anchors.verticalCenter: skipBackwardIcon.verticalCenter |
735 | + } |
736 | + |
737 | + Icon { |
738 | + id: skipBackwardIcon |
739 | + width: units.gu(3) |
740 | + height: width |
741 | + name: "media-seek-backward" |
742 | + color: podbird.appTheme.baseIcon |
743 | + } |
744 | + } |
745 | + } |
746 | + |
747 | + AbstractButton { |
748 | + id: playButton |
749 | + width: units.gu(10) |
750 | + height: width |
751 | + opacity: playButton.pressed ? 0.4 : 1.0 |
752 | + onClicked: player.playbackState === MediaPlayer.PlayingState ? player.pause() : player.play() |
753 | + |
754 | + Icon { |
755 | + id: playIcon |
756 | + width: units.gu(6) |
757 | + height: width |
758 | + anchors.centerIn: parent |
759 | + color: podbird.appTheme.baseIcon |
760 | + name: player.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" |
761 | + : "media-playback-start" |
762 | + } |
763 | + } |
764 | + |
765 | + AbstractButton { |
766 | + id: skipForwardButton |
767 | + width: units.gu(6) |
768 | + height: width |
769 | + anchors.verticalCenter: parent.verticalCenter |
770 | + opacity: player.position === 0 ? 0.4 : 1.0 |
771 | + onClicked: { |
772 | + if (player.position > 0) { |
773 | + player.seek(player.position + podbird.settings.skipForward * 1000); |
774 | + } |
775 | + } |
776 | + |
777 | + Row { |
778 | + spacing: units.gu(1) |
779 | + anchors.centerIn: parent |
780 | + |
781 | + Icon { |
782 | + id: skipForwardIcon |
783 | + width: units.gu(3) |
784 | + height: width |
785 | + name: "media-seek-forward" |
786 | + color: podbird.appTheme.baseIcon |
787 | + } |
788 | + |
789 | + Label { |
790 | + // TRANSLATORS: The string shown in the UI is +15s to denote the number of seconds that the podcast playback will skip forward. |
791 | + // xgettext: no-c-format |
792 | + text: i18n.tr("+%1s").arg(podbird.settings.skipForward) |
793 | + textSize: Label.XxSmall |
794 | + color: podbird.appTheme.baseText |
795 | + anchors.verticalCenter: skipForwardIcon.verticalCenter |
796 | + } |
797 | + } |
798 | + } |
799 | + |
800 | + AbstractButton { |
801 | + id: mediaForwardButton |
802 | + width: units.gu(6) |
803 | + height: width |
804 | + anchors.verticalCenter: parent.verticalCenter |
805 | + enabled: player.playlist.canGoNext |
806 | + opacity: enabled ? 1.0 : 0.4 |
807 | + onClicked: player.playlist.next() |
808 | + |
809 | + Icon { |
810 | + id: mediaForwardIcon |
811 | + width: units.gu(3) |
812 | + height: width |
813 | + anchors.centerIn: parent |
814 | + color: podbird.appTheme.baseIcon |
815 | + name: "media-skip-forward" |
816 | + } |
817 | + } |
818 | } |
819 | } |
820 | } |
821 | - ] |
822 | - |
823 | - BlurredBackground { |
824 | - id: blurredBackground |
825 | - |
826 | - anchors.left: parent.left |
827 | - anchors.top: parent.top |
828 | - anchors.right: parent.right |
829 | - height: title.lineCount === 1 ? parent.height/2 + units.gu(3) |
830 | - : parent.height/2 |
831 | - art: currentImage |
832 | - |
833 | - Image { |
834 | - width: Math.min(parent.width/2, parent.height) |
835 | - height: width |
836 | - sourceSize.height: width |
837 | - sourceSize.width: width |
838 | - source: currentImage |
839 | - asynchronous: true |
840 | - anchors.centerIn: parent |
841 | + |
842 | + Queue { |
843 | + width: tabView.width |
844 | + height: tabView.height |
845 | } |
846 | } |
847 | |
848 | - Item { |
849 | - id: dataContainer |
850 | + ListView { |
851 | + id: tabView |
852 | + model: tabs |
853 | + interactive: false |
854 | |
855 | anchors { |
856 | - top: blurredBackground.bottom |
857 | + top: nowPlayingPage.header.bottom |
858 | left: parent.left |
859 | right: parent.right |
860 | bottom: parent.bottom |
861 | - margins: units.gu(2) |
862 | - bottomMargin: isLandscapeMode ? units.gu(4) : units.gu(2) |
863 | - } |
864 | - |
865 | - Label { |
866 | - id: title |
867 | - anchors.left: parent.left |
868 | - anchors.right: parent.right |
869 | - anchors.top: parent.top |
870 | - text: currentName |
871 | - elide: Text.ElideRight |
872 | - textSize: Label.Large |
873 | - maximumLineCount: 2 |
874 | - wrapMode: Text.WordWrap |
875 | - color: podbird.appTheme.baseText |
876 | - } |
877 | - |
878 | - Label { |
879 | - id: artist |
880 | - anchors.left: title.left |
881 | - anchors.right: title.right |
882 | - anchors.top: title.bottom |
883 | - anchors.topMargin: units.gu(1) |
884 | - text: currentArtist |
885 | - elide: Text.ElideRight |
886 | - textSize: Label.Small |
887 | - color: podbird.appTheme.baseSubText |
888 | - } |
889 | - |
890 | - Slider { |
891 | - id: scrubber |
892 | - |
893 | - anchors { |
894 | - left: parent.left |
895 | - right: parent.right |
896 | - bottom: controls.top |
897 | - bottomMargin: isLandscapeMode && title.lineCount < 2 ? units.gu(4) : units.gu(2) |
898 | - } |
899 | - |
900 | - live: true |
901 | - minimumValue: 0 |
902 | - maximumValue: playerLoader.item.duration |
903 | - value: playerLoader.item.position |
904 | - height: units.gu(2) |
905 | - |
906 | - onValueChanged: { |
907 | - if (pressed) { |
908 | - playerLoader.item.seek(value); |
909 | - } |
910 | - } |
911 | - |
912 | - function formatValue(v) { return Podcasts.formatTime(v/1000); } |
913 | - StyleHints { foregroundColor: podbird.appTheme.focusText } |
914 | - } |
915 | - |
916 | - Connections { |
917 | - target: playerLoader.item |
918 | - onPositionChanged: scrubber.value = playerLoader.item.position |
919 | - } |
920 | - |
921 | - Label { |
922 | - id: startTime |
923 | - textSize: Label.Small |
924 | - anchors.left: scrubber.left |
925 | - anchors.top: scrubber.bottom |
926 | - color: podbird.appTheme.baseText |
927 | - text: Podcasts.formatTime(playerLoader.item.position / 1000) |
928 | - } |
929 | - |
930 | - Label { |
931 | - id: endTime |
932 | - textSize: Label.Small |
933 | - anchors.right: scrubber.right |
934 | - anchors.top: scrubber.bottom |
935 | - color: podbird.appTheme.baseText |
936 | - text: Podcasts.formatTime(playerLoader.item.duration / 1000) |
937 | - } |
938 | - |
939 | - Row { |
940 | - id: controls |
941 | - |
942 | - anchors.bottom: parent.bottom |
943 | - anchors.horizontalCenter: parent.horizontalCenter |
944 | - spacing: units.gu(2) |
945 | - |
946 | - AbstractButton { |
947 | - id: skipBackwardButton |
948 | - width: units.gu(6) |
949 | - height: width |
950 | - anchors.verticalCenter: parent.verticalCenter |
951 | - opacity: playerLoader.item.position === 0 ? 0.4 : 1.0 |
952 | - onClicked: { |
953 | - if (playerLoader.item.position > 0) { |
954 | - playerLoader.item.seek(playerLoader.item.position - podbird.settings.skipBack * 1000); |
955 | - } |
956 | - } |
957 | - |
958 | - Row { |
959 | - spacing: units.gu(1) |
960 | - anchors.centerIn: parent |
961 | - |
962 | - Label { |
963 | - // TRANSLATORS: The string shown in the UI is -15s to denote the number of seconds that the podcast playback will skip backward. |
964 | - // xgettext: no-c-format |
965 | - text: i18n.tr("-%1s").arg(podbird.settings.skipBack) |
966 | - textSize: Label.XxSmall |
967 | - color: podbird.appTheme.baseText |
968 | - anchors.verticalCenter: skipBackwardIcon.verticalCenter |
969 | - } |
970 | - |
971 | - Icon { |
972 | - id: skipBackwardIcon |
973 | - width: units.gu(3) |
974 | - height: width |
975 | - name: "media-seek-backward" |
976 | - color: podbird.appTheme.baseIcon |
977 | - } |
978 | - } |
979 | - } |
980 | - |
981 | - AbstractButton { |
982 | - id: playButton |
983 | - width: units.gu(10) |
984 | - height: width |
985 | - opacity: playButton.pressed ? 0.4 : 1.0 |
986 | - onClicked: playerLoader.item.playbackState === MediaPlayer.PlayingState ? playerLoader.item.pause() : playerLoader.item.play() |
987 | - |
988 | - Icon { |
989 | - id: playIcon |
990 | - width: units.gu(6) |
991 | - height: width |
992 | - anchors.centerIn: parent |
993 | - color: podbird.appTheme.baseIcon |
994 | - name: playerLoader.item.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" |
995 | - : "media-playback-start" |
996 | - } |
997 | - } |
998 | - |
999 | - AbstractButton { |
1000 | - id: skipForwardButton |
1001 | - width: units.gu(6) |
1002 | - height: width |
1003 | - anchors.verticalCenter: parent.verticalCenter |
1004 | - opacity: playerLoader.item.position === 0 ? 0.4 : 1.0 |
1005 | - onClicked: { |
1006 | - if (playerLoader.item.position > 0) { |
1007 | - playerLoader.item.seek(playerLoader.item.position + podbird.settings.skipForward * 1000); |
1008 | - } |
1009 | - } |
1010 | - |
1011 | - Row { |
1012 | - spacing: units.gu(1) |
1013 | - anchors.centerIn: parent |
1014 | - |
1015 | - Icon { |
1016 | - id: skipForwardIcon |
1017 | - width: units.gu(3) |
1018 | - height: width |
1019 | - name: "media-seek-forward" |
1020 | - color: podbird.appTheme.baseIcon |
1021 | - } |
1022 | - |
1023 | - Label { |
1024 | - // TRANSLATORS: The string shown in the UI is +15s to denote the number of seconds that the podcast playback will skip forward. |
1025 | - // xgettext: no-c-format |
1026 | - text: i18n.tr("+%1s").arg(podbird.settings.skipForward) |
1027 | - textSize: Label.XxSmall |
1028 | - color: podbird.appTheme.baseText |
1029 | - anchors.verticalCenter: skipForwardIcon.verticalCenter |
1030 | - } |
1031 | - } |
1032 | - } |
1033 | - } |
1034 | + } |
1035 | + |
1036 | + orientation: Qt.Horizontal |
1037 | + snapMode: ListView.SnapOneItem |
1038 | + currentIndex: nowPlayingPageSections.selectedIndex |
1039 | + highlightMoveDuration: UbuntuAnimation.SlowDuration |
1040 | } |
1041 | } |
1042 | |
1043 | === modified file 'app/ui/PlayerControls.qml' |
1044 | --- app/ui/PlayerControls.qml 2016-03-04 10:40:54 +0000 |
1045 | +++ app/ui/PlayerControls.qml 2016-03-14 00:33:23 +0000 |
1046 | @@ -17,7 +17,7 @@ |
1047 | */ |
1048 | |
1049 | import QtQuick 2.4 |
1050 | -import QtMultimedia 5.4 |
1051 | +import QtMultimedia 5.6 |
1052 | import Ubuntu.Components 1.3 |
1053 | |
1054 | Rectangle { |
1055 | @@ -49,7 +49,7 @@ |
1056 | anchors.top: cover.bottom |
1057 | color: podbird.appTheme.focusText |
1058 | height: units.gu(0.25) |
1059 | - width: playerLoader.item.duration > 0 ? (playerLoader.item.position / playerLoader.item.duration) * parent.width : 0 |
1060 | + width: player.duration > 0 ? (player.position / player.duration) * parent.width : 0 |
1061 | } |
1062 | |
1063 | Column { |
1064 | @@ -97,16 +97,16 @@ |
1065 | visible: playButton.pressed |
1066 | } |
1067 | |
1068 | - onClicked: playerLoader.item.playbackState === MediaPlayer.PlayingState ? playerLoader.item.pause() |
1069 | - : playerLoader.item.play() |
1070 | + onClicked: player.playbackState === MediaPlayer.PlayingState ? player.pause() |
1071 | + : player.play() |
1072 | |
1073 | Icon { |
1074 | color: "white" |
1075 | width: units.gu(3) |
1076 | height: width |
1077 | anchors.centerIn: playButtonBackground |
1078 | - name: playerLoader.item.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" |
1079 | - : "media-playback-start" |
1080 | + name: player.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" |
1081 | + : "media-playback-start" |
1082 | opacity: playButton.pressed ? 0.4 : 1.0 |
1083 | } |
1084 | } |
1085 | |
1086 | === modified file 'app/ui/PodcastsTab.qml' |
1087 | --- app/ui/PodcastsTab.qml 2016-03-06 23:00:20 +0000 |
1088 | +++ app/ui/PodcastsTab.qml 2016-03-14 00:33:23 +0000 |
1089 | @@ -17,7 +17,7 @@ |
1090 | */ |
1091 | |
1092 | import QtQuick 2.4 |
1093 | -import QtMultimedia 5.4 |
1094 | +import QtMultimedia 5.6 |
1095 | import QtQuick.LocalStorage 2.0 |
1096 | import Ubuntu.Components 1.3 |
1097 | import Ubuntu.DownloadManager 0.1 |
1098 | |
1099 | === added file 'app/ui/Queue.qml' |
1100 | --- app/ui/Queue.qml 1970-01-01 00:00:00 +0000 |
1101 | +++ app/ui/Queue.qml 2016-03-14 00:33:23 +0000 |
1102 | @@ -0,0 +1,94 @@ |
1103 | +/* |
1104 | + * Copyright 2016 Podbird Team |
1105 | + * |
1106 | + * This file is part of Podbird. |
1107 | + * |
1108 | + * Podbird is free software; you can redistribute it and/or modify |
1109 | + * it under the terms of the GNU General Public License as published by |
1110 | + * the Free Software Foundation; version 3. |
1111 | + * |
1112 | + * Podbird is distributed in the hope that it will be useful, |
1113 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1114 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1115 | + * GNU General Public License for more details. |
1116 | + * |
1117 | + * You should have received a copy of the GNU General Public License |
1118 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1119 | + */ |
1120 | + |
1121 | +import QtQuick 2.4 |
1122 | +import Ubuntu.Components 1.3 |
1123 | +import "../podcasts.js" as Podcasts |
1124 | +import "../components" |
1125 | + |
1126 | +Item { |
1127 | + id: queuePage |
1128 | + |
1129 | + ListView { |
1130 | + id: queueList |
1131 | + |
1132 | + anchors.fill: parent |
1133 | + model: player.playlist |
1134 | + |
1135 | + delegate: ListItem { |
1136 | + id: listItem |
1137 | + |
1138 | + height: layout.height |
1139 | + divider.visible: false |
1140 | + |
1141 | + ListItemLayout { |
1142 | + id: layout |
1143 | + |
1144 | + // Grab the metaData for the current index using its unique source url |
1145 | + property var metaModel: player.metaForSource(model.source) |
1146 | + |
1147 | + Image { |
1148 | + id: imgFrame |
1149 | + width: units.gu(6) |
1150 | + height: width |
1151 | + source: Qt.resolvedUrl(layout.metaModel.image) |
1152 | + sourceSize.height: width |
1153 | + sourceSize.width: width |
1154 | + SlotsLayout.position: SlotsLayout.First |
1155 | + } |
1156 | + |
1157 | + title.text: layout.metaModel.name |
1158 | + // #FIXME: Change this 2 to prevent title eliding when UITK is updated to rev > 1800 |
1159 | + title.maximumLineCount: 1 |
1160 | + title.color: player.playlist.currentIndex === index ? podbird.appTheme.focusText |
1161 | + : podbird.appTheme.baseText |
1162 | + |
1163 | + subtitle.text: layout.metaModel.artist |
1164 | + subtitle.color: podbird.appTheme.baseSubText |
1165 | + } |
1166 | + |
1167 | + leadingActions: ListItemActions { |
1168 | + actions: [ |
1169 | + Action { |
1170 | + iconName: "delete" |
1171 | + onTriggered: { |
1172 | + player.playlist.removeItem(index) |
1173 | + var source = model.source |
1174 | + |
1175 | + source = source.toString() |
1176 | + |
1177 | + if (source.indexOf("file://") === 0) { |
1178 | + source = source.substring(7); |
1179 | + } |
1180 | + |
1181 | + Podcasts.removeItemFromQueue(source) |
1182 | + } |
1183 | + } |
1184 | + ] |
1185 | + } |
1186 | + |
1187 | + onClicked: { |
1188 | + if (player.playlist.currentIndex === index) { |
1189 | + player.toggle() |
1190 | + } else { |
1191 | + player.playlist.currentIndex = index |
1192 | + } |
1193 | + } |
1194 | + } |
1195 | + } |
1196 | +} |
1197 | |
1198 | === modified file 'po/podbird.nik90.pot' |
1199 | --- po/podbird.nik90.pot 2016-03-06 23:40:40 +0000 |
1200 | +++ po/podbird.nik90.pot 2016-03-14 00:33:23 +0000 |
1201 | @@ -8,7 +8,7 @@ |
1202 | msgstr "" |
1203 | "Project-Id-Version: \n" |
1204 | "Report-Msgid-Bugs-To: \n" |
1205 | -"POT-Creation-Date: 2016-03-07 05:06+0530\n" |
1206 | +"POT-Creation-Date: 2016-03-14 06:03+0530\n" |
1207 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
1208 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
1209 | "Language-Team: LANGUAGE <LL@li.org>\n" |
1210 | @@ -34,27 +34,17 @@ |
1211 | msgid "Skip" |
1212 | msgstr "" |
1213 | |
1214 | -#. TRANSLATORS: this refers to a number of songs greater than one. The actual number will be prepended to the string automatically (plural forms are not yet fully supported in usermetrics, the library that displays that string) |
1215 | -#: ../app/podbird.qml:175 |
1216 | -#, qt-format |
1217 | -msgid "Podcasts listened to today: <b>%1</b>" |
1218 | -msgstr "" |
1219 | - |
1220 | -#: ../app/podbird.qml:176 |
1221 | -msgid "No podcasts listened to today" |
1222 | -msgstr "" |
1223 | - |
1224 | -#: ../app/podcasts.js:182 |
1225 | +#: ../app/podcasts.js:281 |
1226 | #, no-c-format, qt-format |
1227 | msgid "%1 hr %2 min" |
1228 | msgstr "" |
1229 | |
1230 | -#: ../app/podcasts.js:191 |
1231 | +#: ../app/podcasts.js:290 |
1232 | #, no-c-format, qt-format |
1233 | msgid "%1 hr" |
1234 | msgstr "" |
1235 | |
1236 | -#: ../app/podcasts.js:199 |
1237 | +#: ../app/podcasts.js:298 |
1238 | #, no-c-format, qt-format |
1239 | msgid "%1 min" |
1240 | msgstr "" |
1241 | @@ -284,18 +274,26 @@ |
1242 | msgid "Older" |
1243 | msgstr "" |
1244 | |
1245 | -#: ../app/ui/NowPlayingPage.qml:29 |
1246 | +#: ../app/ui/NowPlayingPage.qml:34 |
1247 | msgid "Now Playing" |
1248 | msgstr "" |
1249 | |
1250 | +#: ../app/ui/NowPlayingPage.qml:62 |
1251 | +msgid "Full view" |
1252 | +msgstr "" |
1253 | + |
1254 | +#: ../app/ui/NowPlayingPage.qml:62 |
1255 | +msgid "Queue" |
1256 | +msgstr "" |
1257 | + |
1258 | #. TRANSLATORS: The string shown in the UI is -15s to denote the number of seconds that the podcast playback will skip backward. |
1259 | -#: ../app/ui/NowPlayingPage.qml:200 |
1260 | +#: ../app/ui/NowPlayingPage.qml:262 |
1261 | #, no-c-format, qt-format |
1262 | msgid "-%1s" |
1263 | msgstr "" |
1264 | |
1265 | #. TRANSLATORS: The string shown in the UI is +15s to denote the number of seconds that the podcast playback will skip forward. |
1266 | -#: ../app/ui/NowPlayingPage.qml:261 |
1267 | +#: ../app/ui/NowPlayingPage.qml:323 |
1268 | #, no-c-format, qt-format |
1269 | msgid "+%1s" |
1270 | msgstr "" |
1271 | @@ -529,10 +527,10 @@ |
1272 | msgid "Finish" |
1273 | msgstr "" |
1274 | |
1275 | -#: /home/krnekhelesh/Development/devel-trunk-untouched-build/po/Podbird.desktop.in.h:1 |
1276 | +#: /home/krnekhelesh/Development/add-playlist-support-build/po/Podbird.desktop.in.h:1 |
1277 | msgid "The chirpiest podcast manager for Ubuntu" |
1278 | msgstr "" |
1279 | |
1280 | -#: /home/krnekhelesh/Development/devel-trunk-untouched-build/po/Podbird.desktop.in.h:2 |
1281 | +#: /home/krnekhelesh/Development/add-playlist-support-build/po/Podbird.desktop.in.h:2 |
1282 | msgid "podcast;audio;itunes;broadcast;digital;stream;podcatcher;video;vodcast;" |
1283 | msgstr "" |