Merge lp:~nik90/podbird/revamp-podcast-grid-view into lp:podbird/devel

Proposed by Nekhelesh Ramananthan
Status: Merged
Merged at revision: 130
Proposed branch: lp:~nik90/podbird/revamp-podcast-grid-view
Merge into: lp:podbird/devel
Diff against target: 807 lines (+83/-636)
5 files modified
app/components/Card.qml (+62/-117)
app/components/CardView.qml (+15/-20)
app/components/ColumnFlow.qml (+0/-494)
app/ui/PodcastsTab.qml (+2/-1)
po/podbird.nik90.pot (+4/-4)
To merge this branch: bzr merge lp:~nik90/podbird/revamp-podcast-grid-view
Reviewer Review Type Date Requested Status
Podbird Developers Pending
Review via email: mp+288930@code.launchpad.net

Description of the change

- Transitioned from custom Column Flow component to QML Grid View.
- Updated grid view to match new visuals [1]

[1] https://drive.google.com/file/d/0B8NjAHEq9cvEY2VZb1lGczRKMVE/view

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'app/components/Card.qml'
2--- app/components/Card.qml 2016-03-04 10:40:54 +0000
3+++ app/components/Card.qml 2016-03-14 14:06:31 +0000
4@@ -1,12 +1,13 @@
5 /*
6- * Copyright (C) 2014-2016
7- * Andrew Hayzen <ahayzen@gmail.com>
8- *
9- * This program is free software; you can redistribute it and/or modify
10+ * Copyright 2016 Podbird Team
11+ *
12+ * This file is part of Podbird.
13+ *
14+ * Podbird is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; version 3.
17 *
18- * This program is distributed in the hope that it will be useful,
19+ * Podbird is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23@@ -18,122 +19,66 @@
24 import QtQuick 2.4
25 import Ubuntu.Components 1.3
26
27-Item {
28+AbstractButton {
29 id: card
30
31- /* Required by ColumnFlow */
32- property int index
33- property var model
34+ height: parent.parent.cellHeight
35+ width: parent.parent.cellWidth
36
37 property alias coverArt: imgFrame.source
38 property alias primaryText: primaryLabel.text
39- property alias secondaryText: secondaryLabel.text
40- property alias secondaryTextVisible: secondaryLabel.visible
41-
42- signal clicked(var mouse)
43- signal pressAndHold(var mouse)
44-
45- height: cardColumn.childrenRect.height + 2 * bg.anchors.margins
46-
47- /* Background for card */
48- Rectangle {
49- id: bg
50- anchors.fill: parent
51- anchors.margins: units.gu(1)
52- color: podbird.appTheme.hightlightListView
53- }
54-
55- /* Column containing image and labels */
56- Column {
57- id: cardColumn
58-
59- anchors.fill: bg
60- spacing: units.gu(0.5)
61-
62- Image {
63- id: imgFrame
64- width: parent.width
65- height: width
66- sourceSize.height: width
67- sourceSize.width: width
68- }
69-
70- Item {
71- height: units.gu(1)
72- width: units.gu(1)
73- }
74-
75- Label {
76- id: primaryLabel
77- anchors {
78- left: parent.left
79- right: parent.right
80- margins: units.gu(1)
81- }
82- color: podbird.appTheme.baseText
83- elide: Text.ElideRight
84- textSize: Label.Small
85- opacity: 1.0
86- wrapMode: Text.WordWrap
87- horizontalAlignment: Text.AlignHCenter
88- }
89-
90- Label {
91- id: secondaryLabel
92- anchors {
93- left: parent.left
94- leftMargin: units.gu(1)
95- right: parent.right
96- rightMargin: units.gu(1)
97- }
98- color: podbird.appTheme.baseSubText
99- elide: Text.ElideRight
100- textSize: Label.Small
101- opacity: 1.0
102- wrapMode: Text.WordWrap
103- horizontalAlignment: Text.AlignHCenter
104- }
105-
106- Item {
107- height: units.gu(1.5)
108- width: units.gu(1)
109- }
110- }
111-
112- /* Overlay for when card is pressed */
113- Rectangle {
114- id: overlay
115- anchors.fill: bg
116- color: "#000"
117- opacity: 0
118-
119- Behavior on opacity {
120- UbuntuNumberAnimation {}
121- }
122- }
123-
124- /* Capture mouse events */
125- MouseArea {
126- anchors.fill: parent
127- onClicked: card.clicked(mouse)
128- onPressAndHold: card.pressAndHold(mouse)
129- onPressedChanged: overlay.opacity = pressed ? 0.3 : 0
130- }
131-
132- /* Animations */
133- Behavior on height {
134- UbuntuNumberAnimation {}
135- }
136-
137- Behavior on width {
138- UbuntuNumberAnimation {}
139- }
140-
141- Behavior on x {
142- UbuntuNumberAnimation {}
143- }
144-
145- Behavior on y {
146- UbuntuNumberAnimation {}
147+ property string secondaryText: ""
148+
149+ Image {
150+ id: imgFrame
151+ width: parent.width/1.2
152+ height: width
153+ anchors.top: parent.top
154+ anchors.horizontalCenter: parent.horizontalCenter
155+ sourceSize.height: width
156+ sourceSize.width: width
157+
158+ Loader {
159+ id: hintLoader
160+ anchors.verticalCenter: parent.top
161+ anchors.right: parent.right
162+ anchors.rightMargin: units.gu(-0.5)
163+ sourceComponent: secondaryText !== "" ? hintComponent : undefined
164+ }
165+
166+ Component {
167+ id: hintComponent
168+ Rectangle {
169+ color: podbird.appTheme.focusText
170+ width: secondaryLabel.implicitWidth + units.gu(1)
171+ height: secondaryLabel.implicitHeight + units.gu(1)
172+ radius: units.gu(0.5)
173+ visible: secondaryLabel.text !== ""
174+ Label {
175+ id: secondaryLabel
176+ anchors.centerIn: parent
177+ text: secondaryText
178+ visible: text !== ""
179+ textSize: Label.Small
180+ color: "White"
181+ }
182+ }
183+ }
184+ }
185+
186+ Label {
187+ id: primaryLabel
188+ anchors {
189+ top: imgFrame.bottom
190+ left: imgFrame.left
191+ right: imgFrame.right
192+ margins: units.gu(1)
193+ }
194+ color: podbird.appTheme.baseText
195+ elide: Text.ElideRight
196+ textSize: Label.Small
197+ wrapMode: Text.WordWrap
198+ maximumLineCount: 2
199+ horizontalAlignment: Text.AlignHCenter
200 }
201 }
202
203=== modified file 'app/components/CardView.qml'
204--- app/components/CardView.qml 2016-03-04 10:40:54 +0000
205+++ app/components/CardView.qml 2016-03-14 14:06:31 +0000
206@@ -18,33 +18,28 @@
207 import QtQuick 2.4
208 import Ubuntu.Components 1.3
209
210-Flickable {
211- id: cardViewFlickable
212+GridView {
213+ id: gridView
214+
215 anchors {
216 fill: parent
217 margins: units.gu(1)
218 }
219
220- // dont use flow.contentHeight as it is inaccurate due to height of labels
221- // changing as they load
222- contentHeight: flow.contentHeight + flow.anchors.margins * 2 + units.gu(8)
223- contentWidth: width
224-
225- property alias count: flow.count
226- property alias delegate: flow.delegate
227- property var getter
228- property alias model: flow.model
229- property real itemWidth: units.gu(15)
230-
231- onGetterChanged: flow.getter = getter // cannot use alias to set a function (must be var)
232-
233- ColumnFlow {
234- id: flow
235- anchors.fill: parent
236- columns: parseInt(cardViewFlickable.width / itemWidth) || 1 // never drop to 0
237- flickable: cardViewFlickable
238+ cellHeight: cellSize + heightOffset
239+ cellWidth: cellSize + widthOffset
240+
241+ header: Item {
242+ width: parent.width
243+ height: units.gu(2)
244 }
245
246+ readonly property int columns: parseInt(width / itemWidth) || 1 // never drop to 0
247+ readonly property int cellSize: width / columns
248+ property int itemWidth: units.gu(15)
249+ property int heightOffset: 0
250+ property int widthOffset: 0
251+
252 Component.onCompleted: {
253 // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition
254 // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration
255
256=== removed file 'app/components/ColumnFlow.qml'
257--- app/components/ColumnFlow.qml 2016-03-04 10:40:54 +0000
258+++ app/components/ColumnFlow.qml 1970-01-01 00:00:00 +0000
259@@ -1,494 +0,0 @@
260-/*
261- * Copyright (C) 2014-2016
262- * Andrew Hayzen <ahayzen@gmail.com>
263- *
264- * This program is free software; you can redistribute it and/or modify
265- * it under the terms of the GNU General Public License as published by
266- * the Free Software Foundation; version 3.
267- *
268- * This program is distributed in the hope that it will be useful,
269- * but WITHOUT ANY WARRANTY; without even the implied warranty of
270- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
271- * GNU General Public License for more details.
272- *
273- * You should have received a copy of the GNU General Public License
274- * along with this program. If not, see <http://www.gnu.org/licenses/>.
275- */
276-
277-import QtQuick 2.4
278-
279-Item {
280- id: columnFlow
281- property int columns: 1
282- property Flickable flickable
283- property var model
284- property Component delegate
285-
286- property var getter: function (i) { return model.get(i); } // optional getter override (useful for music-app ms2 models)
287-
288- property int buffer: units.gu(20)
289- property var columnHeights: []
290- property var columnHeightsMax: []
291- property int columnWidth: parent.width / columns
292- property int contentHeight: 0
293- property int count: model === undefined ? 0 : model.count
294- property int delayRebuildIndex: -1
295- property var incubating: ({}) // incubating objects
296- property var items: ({})
297- property var itemToColumn: ({}) // cache of the columns of indexes
298- property int lastIndex: 0 // the furtherest index loaded
299- property bool removing: false
300- property bool restoring: false // is the view restoring?
301- property var restoreItems: ({}) // when rebuilding items are stored here temporarily
302-
303- onColumnWidthChanged: {
304- if (restoring) {
305- return;
306- } else if (columns != columnHeights.length && visible) {
307- // number of columns has changed so rebuild the columns
308- rebuildColumns()
309- } else { // column width has changed update visible items properties linked to columnWidth
310- for (var column=0; column < columnHeights.length; column++) {
311- for (var i in columnHeights[column]) {
312- if (columnHeights[column].hasOwnProperty(i) && items.hasOwnProperty(i)) {
313- items[i].width = columnWidth;
314- items[i].x = column * columnWidth;
315- }
316- }
317- }
318-
319- ensureItemsVisible()
320- }
321- }
322-
323- onVisibleChanged: {
324- if (visible && delayRebuildIndex !== -1) { // restore from count change
325- if (delayRebuildIndex === 0) {
326- reset()
327- } else {
328- removeIndex(delayRebuildIndex)
329- }
330-
331- delayRebuildIndex = -1
332- append(true)
333- }
334-
335- // number of columns has changed while invisible so reset if not already restoring
336- if (visible && !restoring && columns != columnHeights.length) {
337- rebuildColumns()
338- }
339- }
340-
341- ListModel { // fakemodel for connections to link to when there is no model
342- id: fakeModel
343- }
344-
345- Connections {
346- target: model === undefined ? fakeModel : model
347- onModelReset: {
348- if (!visible && lastIndex > 0) {
349- delayRebuildIndex = 0
350- } else {
351- reset()
352- append()
353- }
354- }
355- onRowsInserted: {
356- if (!visible && lastIndex > 0) {
357- setDelayRebuildIndex(first)
358- } else {
359- if (first <= lastIndex) {
360- if (first === 0) {
361- reset()
362- } else {
363- removeIndex(first) // remove earliest index and all items after
364- }
365- }
366-
367- // Supply last index if larger as count is not updated until after insertion
368- append(true, last > count ? last : count)
369- }
370- }
371- onRowsRemoved: {
372- if (!visible) {
373- setDelayRebuildIndex(first)
374- } else {
375- if (first <= lastIndex) {
376- if (first === 0) {
377- reset()
378- } else {
379- removeIndex(first) // remove earliest index and all items after
380- }
381-
382- // count is not updated until after removal, so send insertMax
383- // insertMax is count - removal region inclusive - 1 (lastIndex is 1 infront)
384-
385- append(true, count - (1 + last - first) - 1) // rebuild any items on screen or before
386- }
387- }
388- }
389- }
390-
391-
392- Connections {
393- target: flickable
394- onContentYChanged: {
395- append() // Append any new items (scrolling down)
396-
397- ensureItemsVisible()
398- }
399- }
400-
401- // Append a new row of items if possible
402- function append(loadBefore, insertMax)
403- {
404- // Do not allow append to run if incubating
405- if (isIncubating() || restoring || removing) {
406- return;
407- }
408-
409- // get the columns in order
410- var columnsByHeight = getColumnsByHeight();
411- var workDone = false;
412-
413- // check if a new item in each column is possible
414- for (var i=0; i < columnsByHeight.length; i++) {
415- var y = columnHeightsMax[columnsByHeight[i]];
416-
417- // build new object in column if possible
418- // if insertMax is undefined then allow if there is work todo (from the count in the model)
419- // otherwise use the insertMax as the count to compare with the lastIndex added to the columnFlow
420- // and
421- // allow if the y position is within the viewport
422- // or if loadBefore is true then allow if the y position is before the viewport
423- if (((count > 0 && lastIndex < count && insertMax === undefined) || (insertMax !== undefined && lastIndex <= insertMax)) && (inViewport(y, 0) || (loadBefore === true && beforeViewport(y)))) {
424- incubateObject(lastIndex++, columnsByHeight[i], getMaxInColumn(columnsByHeight[i]), append);
425- workDone = true
426- } else {
427- break;
428- }
429- }
430-
431- if (!workDone) { // last iteration over append so visible ensure items are correct
432- ensureItemsVisible();
433- }
434- }
435-
436- // Detect if a loaded object is before the viewport with a buffer
437- function beforeViewport(y)
438- {
439- return y <= flickable.contentY - buffer;
440- }
441-
442- // Cache the size of the columns for use later
443- function cacheColumnHeights()
444- {
445- columnHeightsMax = [];
446-
447- for (var i=0; i < columnHeights.length; i++) {
448- var sum = 0;
449-
450- for (var j in columnHeights[i]) {
451- sum += columnHeights[i][j];
452- }
453-
454- columnHeightsMax.push(sum);
455- }
456-
457- if (!restoring) { // when not restoring otherwise user will be pushed to the top of the view
458- // set the height of columnFlow to max column (for flickable contentHeight)
459- contentHeight = Math.max.apply(null, columnHeightsMax);
460- }
461- }
462-
463- // Recache the visible items heights (due to a change in their height)
464- function cacheVisibleItemsHeights()
465- {
466- for (var i in items) {
467- if (items.hasOwnProperty(i)) {
468- columnHeights[itemToColumn[i]][i] = items[i].height;
469- }
470- }
471-
472- cacheColumnHeights();
473- }
474-
475- // Ensures that the correct items are visible
476- function ensureItemsVisible()
477- {
478- for (var i in items) {
479- if (items.hasOwnProperty(i)) {
480- items[i].visible = inViewport(items[i].y, items[i].height)
481- }
482- }
483- }
484-
485- // Return if there are incubating objects
486- function isIncubating()
487- {
488- for (var i in incubating) {
489- if (incubating.hasOwnProperty(i)) {
490- return true;
491- }
492- }
493-
494- return false;
495- }
496-
497- // Run after incubation to store new column height and call any further append/restores
498- function finishIncubation(index, callback)
499- {
500- var obj = incubating[index].object;
501- delete incubating[index];
502-
503- obj.heightChanged.connect(cacheVisibleItemsHeights) // if the height changes recache
504-
505- // Ensure properties linked to columnWidth are correct (as width may still be changing)
506- obj.x = itemToColumn[index] * columnWidth;
507- obj.width = columnWidth;
508-
509- items[index] = obj;
510-
511- columnHeights[itemToColumn[index]][index] = obj.height; // ensure height is the latest
512-
513- if (!isIncubating()) {
514- cacheColumnHeights();
515-
516- // Check if there is any more work to be done (append or restore)
517- callback();
518- }
519- }
520-
521- // Force any incubation to finish
522- function forceIncubationCompletion()
523- {
524- for (var i in incubating) {
525- if (incubating.hasOwnProperty(i)) {
526- incubating[i].forceCompletion()
527- }
528- }
529- }
530-
531- // Get the column index in order of height
532- function getColumnsByHeight()
533- {
534- var columnsByHeight = [];
535-
536- for (var i=0; i < columnHeightsMax.length; i++) {
537- var min = undefined;
538- var index = -1;
539-
540- // Find the smallest column that has not been found yet
541- for (var j=0; j < columnHeightsMax.length; j++) {
542- if (columnsByHeight.indexOf(j) === -1 && (min === undefined || columnHeightsMax[j] < min)) {
543- min = columnHeightsMax[j];
544- index = j;
545- }
546- }
547-
548- columnsByHeight.push(index);
549- }
550-
551- return columnsByHeight;
552- }
553-
554- // Get the highest index for a column
555- function getMaxInColumn(column)
556- {
557- var max;
558-
559- for (var i in columnHeights[column]) {
560- if (columnHeights[column].hasOwnProperty(i)) {
561- i = parseInt(i);
562-
563- if (items.hasOwnProperty(i)) {
564- if (i > max || max === undefined) {
565- max = i;
566- }
567- }
568- }
569- }
570-
571- return max;
572- }
573-
574- // Incubate an object for creation
575- function incubateObject(index, column, anchorIndex, callback)
576- {
577- // Load parameters to send to the object on creation
578- var params = {
579- "anchors.top": anchorIndex === undefined ? parent.top : items[anchorIndex].bottom,
580- index: index,
581- model: getter(index),
582- width: columnWidth,
583- x: column * columnWidth
584- };
585-
586- // Start incubating and cache the column
587- incubating[index] = delegate.incubateObject(parent, params);
588- itemToColumn[index] = column;
589-
590- if (incubating[index].status != Component.Ready) {
591- incubating[index].onStatusChanged = function(status) {
592- if (status == Component.Ready) {
593- finishIncubation(index, callback)
594- }
595- }
596- } else {
597- finishIncubation(index, callback)
598- }
599- }
600-
601- // Detect if a loaded object is in the viewport with a buffer
602- function inViewport(y, height)
603- {
604- return flickable.contentY - buffer < y + height && y < flickable.contentY + flickable.height + buffer;
605- }
606-
607- // Number of columns has changed rebuild with live items
608- function rebuildColumns()
609- {
610- restoring = true;
611- var i;
612-
613- forceIncubationCompletion()
614-
615- columnHeights = []
616- columnHeightsMax = []
617-
618- for (i=0; i < columns; i++) {
619- columnHeights.push({});
620- columnHeightsMax.push(0);
621- }
622-
623- lastIndex = 0;
624-
625- restoreItems = items;
626- items = {};
627-
628- restoreExisting()
629-
630- restoring = false;
631-
632- cacheColumnHeights(); // rebuilds contentHeight
633-
634- // If the columns have changed while the view was locked rerun
635- if (columns != columnHeights.length && visible) {
636- rebuildColumns()
637- } else {
638- append() // check if any new items can be added
639- }
640- }
641-
642- // Remove an index from the model (invalidating anything after)
643- function removeIndex(index)
644- {
645- removing = true
646-
647- forceIncubationCompletion()
648-
649- for (var i in items) {
650- if (i >= index && items.hasOwnProperty(i)) {
651- delete columnHeights[itemToColumn[i]][i]
652- delete itemToColumn[i]
653-
654- items[i].destroy()
655- delete items[i]
656- }
657- }
658-
659- lastIndex = index
660- removing = false
661-
662- cacheColumnHeights()
663- }
664-
665- // Restores existing items into potentially new positions
666- function restoreExisting()
667- {
668- var i;
669-
670- // get the columns in order
671- var columnsByHeight = getColumnsByHeight();
672- var workDone = false;
673-
674- // check if a new item in each column is possible
675- for (i=0; i < columnsByHeight.length; i++) {
676- var column = columnsByHeight[i];
677-
678- // build new object in column if possible
679- if (count > 0 && lastIndex < count) {
680- if (restoreItems.hasOwnProperty(lastIndex)) {
681- var item = restoreItems[lastIndex];
682- var maxInColumn = getMaxInColumn(column); // get lowest item in column
683-
684- itemToColumn[lastIndex] = column;
685- columnHeights[column][lastIndex] = item.height; // ensure height is the latest
686-
687- // Rebuild item properties
688- item.anchors.bottom = undefined
689- item.anchors.top = maxInColumn === undefined ? parent.top : items[maxInColumn].bottom;
690- item.x = column * columnWidth;
691- item.visible = inViewport(item.y, item.height);
692-
693- // Migrate item from restoreItems to items
694- items[lastIndex] = item;
695- delete restoreItems[lastIndex];
696-
697- // set after restore as height will likely change causing cacheVisibleItemsHeights to be run
698- item.width = columnWidth;
699-
700- cacheColumnHeights(); // ensure column heights are up to date
701-
702- lastIndex++;
703- workDone = true;
704- }
705- } else {
706- break;
707- }
708- }
709-
710- if (workDone) {
711- restoreExisting() // if work done then check if any more is needed
712- } else {
713- restoreItems = {}; // ensure restoreItems is empty
714- }
715- }
716-
717- // Reset the column flow
718- function reset()
719- {
720- forceIncubationCompletion()
721-
722- // Destroy any old items
723- for (var j in items) {
724- if (items.hasOwnProperty(j)) {
725- items[j].destroy()
726- }
727- }
728-
729- // Reset and rebuild the variables
730- items = ({})
731- itemToColumn = ({})
732- lastIndex = 0
733-
734- columnHeights = []
735-
736- for (var k=0; k < columns; k++) {
737- columnHeights.push({})
738- }
739-
740- cacheColumnHeights()
741-
742- contentHeight = 0
743- }
744-
745- function setDelayRebuildIndex(index)
746- {
747- if (delayRebuildIndex === -1 || index < lastIndex) {
748- delayRebuildIndex = index
749- }
750- }
751-
752- Component.onCompleted: append(true)
753-}
754
755=== modified file 'app/ui/PodcastsTab.qml'
756--- app/ui/PodcastsTab.qml 2016-03-13 21:21:03 +0000
757+++ app/ui/PodcastsTab.qml 2016-03-14 14:06:31 +0000
758@@ -166,12 +166,13 @@
759 CardView {
760 id: cardView
761 clip: true
762+ heightOffset: units.gu(4)
763 model: sortedPodcastModel
764 delegate: Card {
765 id: albumCard
766 coverArt: model.image !== undefined ? model.image : Qt.resolvedUrl("../graphics/podbird.png")
767 primaryText: model.name !== undefined ? model.name.trim() : "Undefined"
768- secondaryText: model.episodeCount > 0 ? i18n.tr("%1 unheard episode", "%1 unheard episodes", model.episodeCount).arg(model.episodeCount)
769+ secondaryText: model.episodeCount > 0 ? model.episodeCount
770 : ""
771 onClicked: {
772 if(podcastPage.header === searchHeader) {
773
774=== modified file 'po/podbird.nik90.pot'
775--- po/podbird.nik90.pot 2016-03-14 00:41:21 +0000
776+++ po/podbird.nik90.pot 2016-03-14 14:06:31 +0000
777@@ -8,7 +8,7 @@
778 msgstr ""
779 "Project-Id-Version: \n"
780 "Report-Msgid-Bugs-To: \n"
781-"POT-Creation-Date: 2016-03-14 06:09+0530\n"
782+"POT-Creation-Date: 2016-03-14 19:27+0530\n"
783 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
784 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
785 "Language-Team: LANGUAGE <LL@li.org>\n"
786@@ -329,7 +329,7 @@
787 msgid "No podcasts found matching the search term."
788 msgstr ""
789
790-#: ../app/ui/PodcastsTab.qml:174 ../app/ui/PodcastsTab.qml:221
791+#: ../app/ui/PodcastsTab.qml:222
792 #, qt-format
793 msgid "%1 unheard episode"
794 msgid_plural "%1 unheard episodes"
795@@ -527,10 +527,10 @@
796 msgid "Finish"
797 msgstr ""
798
799-#: /home/krnekhelesh/Development/devel-trunk-untouched-build/po/Podbird.desktop.in.h:1
800+#: /home/krnekhelesh/Development/revamp-podcast-grid-view-build/po/Podbird.desktop.in.h:1
801 msgid "The chirpiest podcast manager for Ubuntu"
802 msgstr ""
803
804-#: /home/krnekhelesh/Development/devel-trunk-untouched-build/po/Podbird.desktop.in.h:2
805+#: /home/krnekhelesh/Development/revamp-podcast-grid-view-build/po/Podbird.desktop.in.h:2
806 msgid "podcast;audio;itunes;broadcast;digital;stream;podcatcher;video;vodcast;"
807 msgstr ""

Subscribers

People subscribed via source and target branches