Merge lp:~nik90/podbird/8.6-aboutpage into lp:podbird

Proposed by Nekhelesh Ramananthan
Status: Superseded
Proposed branch: lp:~nik90/podbird/8.6-aboutpage
Merge into: lp:podbird
Diff against target: 4725 lines (+3268/-686)
38 files modified
CMakeLists.txt (+2/-2)
Podbird.apparmor (+4/-2)
app/CMakeLists.txt (+3/-1)
app/graphics/CMakeLists.txt (+7/-0)
app/graphics/notFound.svg (+131/-0)
app/graphics/owlSearch.svg (+140/-0)
app/podbird.qml (+102/-8)
app/podcasts.js (+16/-3)
app/settings/About.qml (+151/-0)
app/settings/CMakeLists.txt (+7/-0)
app/settings/CleanSetting.qml (+65/-0)
app/settings/DownloadSetting.qml (+64/-0)
app/settings/ThemeSetting.qml (+63/-0)
app/themes/Dark.qml (+4/-4)
app/themes/Light.qml (+4/-4)
app/ui/ActionButton.qml (+2/-2)
app/ui/BlurredBackground.qml (+4/-21)
app/ui/Card.qml (+139/-0)
app/ui/CardView.qml (+55/-0)
app/ui/ColumnFlow.qml (+494/-0)
app/ui/EmptyState.qml (+6/-2)
app/ui/EpisodesPage.qml (+393/-232)
app/ui/ExpandableListItem.qml (+1/-0)
app/ui/NowPlayingPage.qml (+5/-0)
app/ui/PlayerControls.qml (+2/-2)
app/ui/PodcastsTab.qml (+168/-120)
app/ui/SearchPage.qml (+160/-101)
app/ui/SettingsPage.qml (+119/-86)
app/ui/Walkthrough.qml (+169/-0)
app/welcomewizard/CMakeLists.txt (+8/-0)
app/welcomewizard/Slide1.qml (+76/-0)
app/welcomewizard/Slide2.qml (+66/-0)
app/welcomewizard/Slide3.qml (+67/-0)
app/welcomewizard/Slide4.qml (+70/-0)
app/welcomewizard/Slide5.qml (+66/-0)
app/welcomewizard/Slide6.qml (+80/-0)
app/welcomewizard/WelcomeWizard.qml (+41/-0)
po/com.mikeasoft.podbird.pot (+314/-96)
To merge this branch: bzr merge lp:~nik90/podbird/8.6-aboutpage
Reviewer Review Type Date Requested Status
Michael Sheldon Pending
Review via email: mp+255909@code.launchpad.net

Commit message

Added about page to provide information about the licensing, version and also the contributors of Podbird.

Description of the change

Added about page to provide information about the licensing, version and also the contributors of Podbird.

To post a comment you must log in.
lp:~nik90/podbird/8.6-aboutpage updated
79. By Nekhelesh Ramananthan

merged prerequisite

80. By Nekhelesh Ramananthan

Split the credits and about page as otherwise it exposes a SDK bug

81. By Nekhelesh Ramananthan

Merged prerequisite

82. By Nekhelesh Ramananthan

merged prerequisite fix

83. By Nekhelesh Ramananthan

merged prerequisite

84. By Nekhelesh Ramananthan

Fixed version

85. By Nekhelesh Ramananthan

changed version to beta1

86. By Nekhelesh Ramananthan

merged prerequsiite

87. By Nekhelesh Ramananthan

merged prerequisite

88. By Nekhelesh Ramananthan

updated to v0.6.b2

89. By Nekhelesh Ramananthan

merged prerequisite lp:~nik90/podbird/8.5-usermetrics

90. By Nekhelesh Ramananthan

Adjusted link color to be more visible in the dark theme throughout the app

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-01-04 10:20:41 +0000
3+++ CMakeLists.txt 2015-04-11 21:39:04 +0000
4@@ -28,7 +28,7 @@
5 set(APP_ID "com.mikeasoft.podbird")
6 set(PODBIRD_DIR "share/qml/podbird")
7 set(MAIN_QML "podbird.qml")
8-set(ICON "graphics/podbird.png")
9+set(ICON "podbird.png")
10
11 # Set install paths
12 set(CMAKE_INSTALL_PREFIX /)
13@@ -49,7 +49,7 @@
14 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json
15 DESTINATION ${CMAKE_INSTALL_PREFIX})
16
17-install(DIRECTORY "app/graphics" DESTINATION ${DATA_DIR})
18+install(FILES "podbird.png" DESTINATION ${DATA_DIR})
19 install(FILES "Podbird.apparmor" DESTINATION ${DATA_DIR})
20
21 add_subdirectory(app)
22
23=== modified file 'Podbird.apparmor'
24--- Podbird.apparmor 2015-01-30 00:16:10 +0000
25+++ Podbird.apparmor 2015-04-11 21:39:04 +0000
26@@ -1,7 +1,9 @@
27 {
28 "policy_groups": [
29 "networking",
30- "audio"
31+ "audio",
32+ "connectivity",
33+ "usermetrics"
34 ],
35 "policy_version": 1.2
36-}
37\ No newline at end of file
38+}
39
40=== modified file 'app/CMakeLists.txt'
41--- app/CMakeLists.txt 2015-03-03 22:44:29 +0000
42+++ app/CMakeLists.txt 2015-04-11 21:39:04 +0000
43@@ -11,4 +11,6 @@
44
45 add_subdirectory(ui)
46 add_subdirectory(themes)
47-
48+add_subdirectory(welcomewizard)
49+add_subdirectory(graphics)
50+add_subdirectory(settings)
51
52=== added file 'app/graphics/CMakeLists.txt'
53--- app/graphics/CMakeLists.txt 1970-01-01 00:00:00 +0000
54+++ app/graphics/CMakeLists.txt 2015-04-11 21:39:04 +0000
55@@ -0,0 +1,7 @@
56+file(GLOB GRAPHIC_FILES *.png *.jpg *.svg)
57+
58+# Make the files visible in the qtcreator tree
59+add_custom_target(podbird_GRAPHICFiles ALL SOURCES ${GRAPHIC_FILES})
60+
61+install(FILES ${GRAPHIC_FILES} DESTINATION ${PODBIRD_DIR}/graphics)
62+
63
64=== added file 'app/graphics/discover.png'
65Binary files app/graphics/discover.png 1970-01-01 00:00:00 +0000 and app/graphics/discover.png 2015-04-11 21:39:04 +0000 differ
66=== added file 'app/graphics/gift.png'
67Binary files app/graphics/gift.png 1970-01-01 00:00:00 +0000 and app/graphics/gift.png 2015-04-11 21:39:04 +0000 differ
68=== added file 'app/graphics/language.png'
69Binary files app/graphics/language.png 1970-01-01 00:00:00 +0000 and app/graphics/language.png 2015-04-11 21:39:04 +0000 differ
70=== added file 'app/graphics/notFound.svg'
71--- app/graphics/notFound.svg 1970-01-01 00:00:00 +0000
72+++ app/graphics/notFound.svg 2015-04-11 21:39:04 +0000
73@@ -0,0 +1,131 @@
74+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
75+<!-- Created with Inkscape (http://www.inkscape.org/) -->
76+
77+<svg
78+ xmlns:dc="http://purl.org/dc/elements/1.1/"
79+ xmlns:cc="http://creativecommons.org/ns#"
80+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
81+ xmlns:svg="http://www.w3.org/2000/svg"
82+ xmlns="http://www.w3.org/2000/svg"
83+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
84+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
85+ width="383.80545"
86+ height="214.75534"
87+ id="svg12819"
88+ version="1.1"
89+ inkscape:version="0.48.4 r9939"
90+ sodipodi:docname="notFound.svg"
91+ inkscape:export-filename="/home/kevin/Documents/Development/app screenshots/owlSearch.png"
92+ inkscape:export-xdpi="90"
93+ inkscape:export-ydpi="90">
94+ <defs
95+ id="defs12821" />
96+ <sodipodi:namedview
97+ id="base"
98+ pagecolor="#ffffff"
99+ bordercolor="#666666"
100+ borderopacity="1.0"
101+ inkscape:pageopacity="0.0"
102+ inkscape:pageshadow="2"
103+ inkscape:zoom="1.41521"
104+ inkscape:cx="388.73869"
105+ inkscape:cy="44.241833"
106+ inkscape:document-units="px"
107+ inkscape:current-layer="g15020"
108+ showgrid="false"
109+ fit-margin-top="10"
110+ fit-margin-left="0"
111+ fit-margin-right="0"
112+ fit-margin-bottom="10"
113+ inkscape:window-width="1920"
114+ inkscape:window-height="1056"
115+ inkscape:window-x="0"
116+ inkscape:window-y="24"
117+ inkscape:window-maximized="1" />
118+ <metadata
119+ id="metadata12824">
120+ <rdf:RDF>
121+ <cc:Work
122+ rdf:about="">
123+ <dc:format>image/svg+xml</dc:format>
124+ <dc:type
125+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
126+ <dc:title />
127+ </cc:Work>
128+ </rdf:RDF>
129+ </metadata>
130+ <g
131+ inkscape:label="Layer 1"
132+ inkscape:groupmode="layer"
133+ id="layer1"
134+ transform="translate(-174.89943,-164.11232)">
135+ <g
136+ style="display:inline"
137+ id="g14777"
138+ transform="matrix(0.69639553,0,0,0.69639553,-479.44734,119.33528)">
139+ <g
140+ id="g15020"
141+ transform="matrix(0.63322219,0,0,0.63322219,-295.2311,987.63072)">
142+ <g
143+ id="g15082"
144+ transform="translate(0,82.828838)">
145+ <path
146+ sodipodi:type="arc"
147+ style="fill:none;stroke:#808080;stroke-width:46.75191879;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
148+ id="path14966-8"
149+ sodipodi:cx="1962.8733"
150+ sodipodi:cy="-378.12149"
151+ sodipodi:rx="136.36804"
152+ sodipodi:ry="136.36804"
153+ d="m 2099.2413,-378.12149 c 0,75.31399 -61.054,136.36804 -136.368,136.36804 -75.314,0 -136.3681,-61.05405 -136.3681,-136.36804 0,-75.31399 61.0541,-136.36804 136.3681,-136.36804 75.314,0 136.368,61.05405 136.368,136.36804 z"
154+ transform="matrix(1.2126303,0,0,1.2126303,246.51638,-866.06892)" />
155+ <path
156+ sodipodi:type="arc"
157+ style="fill:#808080;fill-opacity:1;fill-rule:evenodd;stroke:none"
158+ id="path14988"
159+ sodipodi:cx="2108.5391"
160+ sodipodi:cy="-525.33698"
161+ sodipodi:rx="41.840195"
162+ sodipodi:ry="41.840195"
163+ d="m 2150.3793,-525.33698 c 0,23.10771 -18.7325,41.8402 -41.8402,41.8402 -23.1077,0 -41.8402,-18.73249 -41.8402,-41.8402 0,-23.1077 18.7325,-41.84019 41.8402,-41.84019 23.1077,0 41.8402,18.73249 41.8402,41.84019 z"
164+ transform="matrix(1.4359656,0,0,1.4359656,-645.94974,-626.80514)" />
165+ <path
166+ inkscape:connector-curvature="0"
167+ style="fill:#808080;fill-opacity:1;stroke:none"
168+ d="m 2089.4375,-438.03125 0,103.3125 17.9063,0 c 7.3889,-17.02228 24.323,-28.9375 44.0624,-28.9375 19.7395,0 36.7049,11.91522 44.0938,28.9375 l 17.9062,0 0,-103.3125 -123.9687,0 z"
169+ transform="matrix(1.4359656,0,0,1.4359656,-707.51452,-787.38294)"
170+ id="rect14986" />
171+ <path
172+ sodipodi:type="arc"
173+ style="fill:none;stroke:#808080;stroke-width:46.75191879;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
174+ id="path14966-8-2"
175+ sodipodi:cx="1962.8733"
176+ sodipodi:cy="-378.12149"
177+ sodipodi:rx="136.36804"
178+ sodipodi:ry="136.36804"
179+ d="m 2099.2413,-378.12149 c 0,75.31399 -61.054,136.36804 -136.368,136.36804 -75.314,0 -136.3681,-61.05405 -136.3681,-136.36804 0,-75.31399 61.0541,-136.36804 136.3681,-136.36804 75.314,0 136.368,61.05405 136.368,136.36804 z"
180+ transform="matrix(1.2126303,0,0,1.2126303,-236.42299,-866.06892)" />
181+ </g>
182+ <rect
183+ style="fill:#808080;fill-opacity:1;stroke:none"
184+ id="rect15091"
185+ width="129.21298"
186+ height="129.21298"
187+ x="856.36871"
188+ y="-2520.2727"
189+ transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)" />
190+ <path
191+ style="fill:#808080;fill-opacity:1;fill-rule:evenodd;stroke:none"
192+ d="m 103.71875,171.6875 -33.5625,16.21875 c 2.149792,8.13106 9.568126,14.125 18.375,14.125 10.489627,0 18.96875,-8.51037 18.96875,-19 0,-4.26924 -1.40349,-8.17188 -3.78125,-11.34375 z"
193+ transform="matrix(2.267712,0,0,2.267712,1943.0825,-1656.8514)"
194+ id="path15093"
195+ inkscape:connector-curvature="0" />
196+ <path
197+ inkscape:connector-curvature="0"
198+ style="fill:#808080;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline"
199+ d="m 2592.9883,-1268.3362 76.1101,36.7795 c -4.8751,18.4389 -21.6977,32.0314 -41.6692,32.0314 -23.7874,0 -43.0156,-19.2991 -43.0156,-43.0865 0,-9.6814 3.1827,-18.5315 8.5747,-25.7244 z"
200+ id="path15093-2" />
201+ </g>
202+ </g>
203+ </g>
204+</svg>
205
206=== added file 'app/graphics/owlSearch.svg'
207--- app/graphics/owlSearch.svg 1970-01-01 00:00:00 +0000
208+++ app/graphics/owlSearch.svg 2015-04-11 21:39:04 +0000
209@@ -0,0 +1,140 @@
210+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
211+<!-- Created with Inkscape (http://www.inkscape.org/) -->
212+
213+<svg
214+ xmlns:dc="http://purl.org/dc/elements/1.1/"
215+ xmlns:cc="http://creativecommons.org/ns#"
216+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
217+ xmlns:svg="http://www.w3.org/2000/svg"
218+ xmlns="http://www.w3.org/2000/svg"
219+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
220+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
221+ width="383.80545"
222+ height="214.75534"
223+ id="svg12819"
224+ version="1.1"
225+ inkscape:version="0.48.4 r9939"
226+ sodipodi:docname="owlSearch.svg"
227+ inkscape:export-filename="/home/kevin/Documents/Development/app screenshots/owlSearch.png"
228+ inkscape:export-xdpi="90"
229+ inkscape:export-ydpi="90">
230+ <defs
231+ id="defs12821" />
232+ <sodipodi:namedview
233+ id="base"
234+ pagecolor="#ffffff"
235+ bordercolor="#666666"
236+ borderopacity="1.0"
237+ inkscape:pageopacity="0.0"
238+ inkscape:pageshadow="2"
239+ inkscape:zoom="1.990625"
240+ inkscape:cx="153.4653"
241+ inkscape:cy="131.99307"
242+ inkscape:document-units="px"
243+ inkscape:current-layer="layer1"
244+ showgrid="false"
245+ fit-margin-top="10"
246+ fit-margin-left="0"
247+ fit-margin-right="0"
248+ fit-margin-bottom="10"
249+ inkscape:window-width="1920"
250+ inkscape:window-height="1056"
251+ inkscape:window-x="0"
252+ inkscape:window-y="24"
253+ inkscape:window-maximized="1" />
254+ <metadata
255+ id="metadata12824">
256+ <rdf:RDF>
257+ <cc:Work
258+ rdf:about="">
259+ <dc:format>image/svg+xml</dc:format>
260+ <dc:type
261+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
262+ <dc:title />
263+ </cc:Work>
264+ </rdf:RDF>
265+ </metadata>
266+ <g
267+ inkscape:label="Layer 1"
268+ inkscape:groupmode="layer"
269+ id="layer1"
270+ transform="translate(-174.89943,-164.11232)">
271+ <g
272+ style="display:inline"
273+ id="g14777"
274+ transform="matrix(0.69639553,0,0,0.69639553,-479.44734,119.33528)">
275+ <g
276+ id="g15020"
277+ transform="matrix(0.63322219,0,0,0.63322219,-295.2311,987.63072)">
278+ <g
279+ id="g15082"
280+ transform="translate(0,82.828838)">
281+ <path
282+ sodipodi:type="arc"
283+ style="fill:none;stroke:#808080;stroke-width:46.75191879;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
284+ id="path14966-8"
285+ sodipodi:cx="1962.8733"
286+ sodipodi:cy="-378.12149"
287+ sodipodi:rx="136.36804"
288+ sodipodi:ry="136.36804"
289+ d="m 2099.2413,-378.12149 c 0,75.31399 -61.054,136.36804 -136.368,136.36804 -75.314,0 -136.3681,-61.05405 -136.3681,-136.36804 0,-75.31399 61.0541,-136.36804 136.3681,-136.36804 75.314,0 136.368,61.05405 136.368,136.36804 z"
290+ transform="matrix(1.2126303,0,0,1.2126303,246.51638,-866.06892)" />
291+ <path
292+ sodipodi:type="arc"
293+ style="fill:#808080;fill-opacity:1;fill-rule:evenodd;stroke:none"
294+ id="path14988"
295+ sodipodi:cx="2108.5391"
296+ sodipodi:cy="-525.33698"
297+ sodipodi:rx="41.840195"
298+ sodipodi:ry="41.840195"
299+ d="m 2150.3793,-525.33698 c 0,23.10771 -18.7325,41.8402 -41.8402,41.8402 -23.1077,0 -41.8402,-18.73249 -41.8402,-41.8402 0,-23.1077 18.7325,-41.84019 41.8402,-41.84019 23.1077,0 41.8402,18.73249 41.8402,41.84019 z"
300+ transform="matrix(1.4359656,0,0,1.4359656,-645.94974,-626.80514)" />
301+ <path
302+ inkscape:connector-curvature="0"
303+ style="fill:#808080;fill-opacity:1;stroke:none"
304+ d="m 2089.4375,-438.03125 0,103.3125 17.9063,0 c 7.3889,-17.02228 24.323,-28.9375 44.0624,-28.9375 19.7395,0 36.7049,11.91522 44.0938,28.9375 l 17.9062,0 0,-103.3125 -123.9687,0 z"
305+ transform="matrix(1.4359656,0,0,1.4359656,-707.51452,-787.38294)"
306+ id="rect14986" />
307+ <path
308+ sodipodi:type="arc"
309+ style="fill:none;stroke:#808080;stroke-width:46.75191879;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
310+ id="path14966-8-2"
311+ sodipodi:cx="1962.8733"
312+ sodipodi:cy="-378.12149"
313+ sodipodi:rx="136.36804"
314+ sodipodi:ry="136.36804"
315+ d="m 2099.2413,-378.12149 c 0,75.31399 -61.054,136.36804 -136.368,136.36804 -75.314,0 -136.3681,-61.05405 -136.3681,-136.36804 0,-75.31399 61.0541,-136.36804 136.3681,-136.36804 75.314,0 136.368,61.05405 136.368,136.36804 z"
316+ transform="matrix(1.2126303,0,0,1.2126303,-236.42299,-866.06892)" />
317+ </g>
318+ <rect
319+ style="fill:#808080;fill-opacity:1;stroke:none"
320+ id="rect15091"
321+ width="129.21298"
322+ height="129.21298"
323+ x="856.36871"
324+ y="-2520.2727"
325+ transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)" />
326+ <path
327+ sodipodi:type="arc"
328+ style="fill:#808080;fill-opacity:1;fill-rule:evenodd;stroke:none"
329+ id="path15093"
330+ sodipodi:cx="1206.7955"
331+ sodipodi:cy="673.53888"
332+ sodipodi:rx="18.993151"
333+ sodipodi:ry="18.993151"
334+ d="m 1225.7887,673.53888 c 0,10.48963 -8.5035,18.99315 -18.9932,18.99315 -10.4896,0 -18.9931,-8.50352 -18.9931,-18.99315 0,-10.48963 8.5035,-18.99315 18.9931,-18.99315 10.4897,0 18.9932,8.50352 18.9932,18.99315 z"
335+ transform="matrix(2.267712,0,0,2.267712,-592.84807,-2769.1539)" />
336+ <path
337+ sodipodi:type="arc"
338+ style="fill:#808080;fill-opacity:1;fill-rule:evenodd;stroke:none;display:inline"
339+ id="path15093-0"
340+ sodipodi:cx="1206.7955"
341+ sodipodi:cy="673.53888"
342+ sodipodi:rx="18.993151"
343+ sodipodi:ry="18.993151"
344+ d="m 1225.7887,673.53888 c 0,10.48963 -8.5035,18.99315 -18.9932,18.99315 -10.4896,0 -18.9931,-8.50352 -18.9931,-18.99315 0,-10.48963 8.5035,-18.99315 18.9931,-18.99315 10.4897,0 18.9932,8.50352 18.9932,18.99315 z"
345+ transform="matrix(2.267712,0,0,2.267712,-109.9087,-2769.1539)" />
346+ </g>
347+ </g>
348+ </g>
349+</svg>
350
351=== modified file 'app/graphics/podbird.png'
352Binary files app/graphics/podbird.png 2015-01-04 10:20:41 +0000 and app/graphics/podbird.png 2015-04-11 21:39:04 +0000 differ
353=== added file 'app/graphics/smart.png'
354Binary files app/graphics/smart.png 1970-01-01 00:00:00 +0000 and app/graphics/smart.png 2015-04-11 21:39:04 +0000 differ
355=== added file 'app/graphics/support.png'
356Binary files app/graphics/support.png 1970-01-01 00:00:00 +0000 and app/graphics/support.png 2015-04-11 21:39:04 +0000 differ
357=== modified file 'app/podbird.qml'
358--- app/podbird.qml 2015-03-27 15:38:43 +0000
359+++ app/podbird.qml 2015-04-11 21:39:04 +0000
360@@ -18,7 +18,9 @@
361
362 import QtQuick 2.3
363 import Podbird 1.0
364+import UserMetrics 0.1
365 import QtMultimedia 5.0
366+import Ubuntu.Connectivity 1.0
367 import Qt.labs.settings 1.0
368 import Ubuntu.Components 1.1
369 import QtQuick.LocalStorage 2.0
370@@ -41,18 +43,35 @@
371 backgroundColor: theme.background
372
373 Component.onDestruction: {
374- console.log("Download cancelled");
375+ console.log("[LOG]: Download cancelled");
376 downloader.cancel();
377+ var db = Podcasts.init()
378+ db.transaction(function (tx) {
379+ tx.executeSql('UPDATE Episode SET queued=0 WHERE queued=1');
380+ })
381 }
382
383 Component.onCompleted: {
384+ var db = Podcasts.init()
385+ db.transaction(function (tx) {
386+ tx.executeSql('UPDATE Episode SET queued=0 WHERE queued=1');
387+ })
388+
389 var today = new Date()
390 // Only perform cleanup of old episodes once a day
391 if (Math.floor((today - settings.lastCheck)/86400000) >= 1 && settings.retentionDays !== -1) {
392- console.log("[LOG]: Starting cleanup of old episodes..")
393 cleanUp(today, settings.retentionDays)
394 settings.lastCheck = today
395 }
396+
397+ if (NetworkingStatus.limitedBandwith && settings.onlyWifiDownload || !NetworkingStatus.online || settings.maxEpisodeDownload === -1) {
398+ console.log("[LOG]: Skipped autodownloading due to missing wifi connectivity and only download on wifi preference.")
399+ console.log("[LOG]: Detecting limited bandwidth: " + NetworkingStatus.limitedBandwith)
400+ console.log("[LOG]: Detecting online connectivity: " + NetworkingStatus.online)
401+ console.log("[LOG]: User settings (onlywifidownload & maxEpisodeDownload): " + settings.onlyWifiDownload + ", " + settings.maxEpisodeDownload)
402+ } else {
403+ autoDownloadEpisodes(settings.maxEpisodeDownload)
404+ }
405 }
406
407 property string currentName
408@@ -73,6 +92,11 @@
409 property string themeName: "Light.qml"
410 property int retentionDays: -1
411 property var lastCheck: new Date()
412+ property bool firstRun: true
413+ property bool onlyWifiDownload: true
414+ property int maxEpisodeDownload: -1
415+ property bool hideListened: false
416+ property bool showListView: true
417 }
418
419 FileManager {
420@@ -100,7 +124,7 @@
421 var db = Podcasts.init();
422 var finalLocation = fileManager.saveDownload(path);
423 db.transaction(function (tx) {
424- tx.executeSql("UPDATE Episode SET downloadedfile=? WHERE guid=?", [finalLocation, downloadingGuid]);
425+ tx.executeSql("UPDATE Episode SET downloadedfile=?, queued=0 WHERE guid=?", [finalLocation, downloadingGuid]);
426 queue.shift();
427 if (queue.length > 0) {
428 downloadingGuid = queue[0][0];
429@@ -120,13 +144,36 @@
430 }
431 }
432
433+ // UserMetrics to show Podbird stats on welcome screen
434+ Metric {
435+ id: podcastsMetric
436+ name: "podcast-metrics"
437+ // 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)
438+ format: "<b>%1</b> " + i18n.tr("podcasts listened today")
439+ emptyFormat: i18n.tr("No podcasts listened today")
440+ domain: "com.mikeasoft.podbird"
441+ }
442+
443 MediaPlayer {
444 id: player
445+
446+ property bool podcastCounted: false
447+
448+ onSourceChanged: {
449+ podcastCounted = false
450+ }
451+
452 onPositionChanged: {
453 if (currentGuid == "" || duration <= 0) {
454 return;
455 }
456
457+ if (position > 10000 && !podcastCounted) {
458+ podcastCounted = true
459+ podcastsMetric.increment()
460+ console.log("[LOG]: Podcast User metric incremented")
461+ }
462+
463 var db = Podcasts.init();
464 db.transaction(function (tx) {
465 tx.executeSql("UPDATE Episode SET position=? WHERE guid=?", [position >= duration ? 120 : position, currentGuid]);
466@@ -139,7 +186,16 @@
467
468 PageStack {
469 id: mainStack
470- Component.onCompleted: push(tabs)
471+ Component.onCompleted: {
472+ // Show the welcome wizard only when running the app for the first time
473+ if (settings.firstRun) {
474+ console.log("[LOG]: Detecting first time run by user. Starting welcome wizard.")
475+ push(Qt.resolvedUrl("welcomewizard/WelcomeWizard.qml"))
476+ } else {
477+ push(tabs)
478+ }
479+ }
480+
481 Tabs {
482 id: tabs
483
484@@ -148,14 +204,32 @@
485 objectName: "podcastsTab"
486 }
487
488- SearchTab {
489+ Tab {
490 id: searchTab
491- objectName: "searchTab"
492+
493+ title: i18n.tr("Find New Podcasts")
494+
495+ page: Loader {
496+ parent: searchTab
497+ anchors.left: parent.left
498+ anchors.right: parent.right
499+ anchors.bottom: parent.bottom
500+ source: (tabs.selectedTab === searchTab) ? Qt.resolvedUrl("ui/SearchPage.qml") : ""
501+ }
502 }
503
504- SettingsTab {
505+ Tab {
506 id: settingsTab
507- objectName: "settingsTab"
508+
509+ title: i18n.tr("Settings")
510+
511+ page: Loader {
512+ parent: settingsTab
513+ anchors.left: parent.left
514+ anchors.right: parent.right
515+ anchors.bottom: parent.bottom
516+ source: (tabs.selectedTab === settingsTab) ? Qt.resolvedUrl("ui/SettingsPage.qml") : ""
517+ }
518 }
519 }
520 }
521@@ -189,6 +263,7 @@
522 }
523
524 function cleanUp(today, retentionDays) {
525+ console.log("[LOG]: Cleaning up old episodes")
526 var dayToMs = 86400000; //1 * 24 * 60 * 60 * 1000
527 var db = Podcasts.init()
528 db.transaction(function (tx) {
529@@ -206,4 +281,23 @@
530 }
531 });
532 }
533+
534+ function autoDownloadEpisodes(maxEpisodeDownload) {
535+ console.log("[LOG]: Auto-downloading new episodes")
536+ var db = Podcasts.init()
537+ db.transaction(function (tx) {
538+ var rs = tx.executeSql("SELECT rowid, * FROM Podcast ORDER BY name ASC");
539+ for (var i=0; i < rs.rows.length; i++) {
540+ var podcast = rs.rows.item(i);
541+ var rs2 = tx.executeSql("SELECT rowid, * FROM Episode WHERE podcast=? ORDER BY published DESC", [rs.rows.item(i).rowid]);
542+ var loopCount = maxEpisodeDownload > rs2.rows.length ? rs2.rows.length : maxEpisodeDownload
543+ for (var j=0; j < loopCount; j++) {
544+ if (!rs2.rows.item(j).downloadedfile && !rs2.rows.item(j).listened) {
545+ downloader.addDownload(rs2.rows.item(j).guid, rs2.rows.item(j).audiourl)
546+ tx.executeSql("UPDATE Episode SET queued=1 WHERE guid = ?", [rs2.rows.item(j).guid]);
547+ }
548+ }
549+ }
550+ });
551+ }
552 }
553
554=== modified file 'app/podcasts.js'
555--- app/podcasts.js 2015-02-28 09:46:48 +0000
556+++ app/podcasts.js 2015-04-11 21:39:04 +0000
557@@ -1,5 +1,5 @@
558 /*
559- * Copyright 2015 Michael Sheldon <mike@mikeasoft.com>
560+ * Copyright 2015 Podbird Team
561 *
562 * This file is part of Podbird.
563 *
564@@ -17,11 +17,24 @@
565 */
566
567 function init() {
568- var db = LocalStorage.openDatabaseSync("Podbird", "1.0", "Database of subscribed podcasts and their episodes", 1000000);
569+ var db = LocalStorage.openDatabaseSync("Podbird", "", "Database of subscribed podcasts and their episodes", 1000000);
570+
571 db.transaction(function(tx) {
572 tx.executeSql('CREATE TABLE IF NOT EXISTS Podcast(artist TEXT, name TEXT, description TEXT, feed TEXT, image TEXT, lastupdate TIMESTAMP)');
573- 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))');
574+ 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, position INTEGER, FOREIGN KEY(podcast) REFERENCES Podcast(rowid))');
575 });
576+
577+ /*
578+ Schema Upgrade to v1.1 which adds a new queued boolean variable which is needed to track the queued status
579+ of a episode properly.
580+ */
581+ if (db.version == "1.0") {
582+ db.changeVersion("1.0", "1.1", function(tx) {
583+ tx.executeSql('ALTER TABLE Episode ADD queued BOOLEAN');
584+ tx.executeSql('UPDATE Episode SET queued=0');
585+ });
586+ }
587+
588 return db;
589 }
590
591
592=== added directory 'app/settings'
593=== added file 'app/settings/About.qml'
594--- app/settings/About.qml 1970-01-01 00:00:00 +0000
595+++ app/settings/About.qml 2015-04-11 21:39:04 +0000
596@@ -0,0 +1,151 @@
597+/*
598+ * Copyright 2015 Podbird Team
599+ *
600+ * This file is part of Podbird.
601+ *
602+ * Podbird is free software; you can redistribute it and/or modify
603+ * it under the terms of the GNU General Public License as published by
604+ * the Free Software Foundation; version 3.
605+ *
606+ * Podbird is distributed in the hope that it will be useful,
607+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
608+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
609+ * GNU General Public License for more details.
610+ *
611+ * You should have received a copy of the GNU General Public License
612+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
613+ */
614+
615+import QtQuick 2.3
616+import Ubuntu.Components 1.1
617+import Ubuntu.Components.ListItems 1.0 as ListItem
618+
619+Page {
620+ id: aboutPage
621+
622+ title: i18n.tr("About")
623+ visible: false
624+
625+ head.sections.model: [i18n.tr("About"), i18n.tr("Credits")]
626+
627+ VisualItemModel {
628+ id: tabs
629+
630+ Item {
631+ width: tabView.width
632+ height: tabView.height
633+
634+ Column {
635+ spacing: units.gu(4)
636+ anchors.centerIn: parent
637+ width: parent.width > units.gu(50) ? units.gu(50) : parent.width
638+
639+ Image {
640+ height: width
641+ width: parent.width/2
642+ source: "../graphics/podbird.png"
643+ anchors.horizontalCenter: parent.horizontalCenter
644+ }
645+
646+ Column {
647+ width: parent.width
648+ Label {
649+ width: parent.width
650+ fontSize: "x-large"
651+ font.weight: Font.DemiBold
652+ horizontalAlignment: Text.AlignHCenter
653+ text: "Podbird"
654+ }
655+ Label {
656+ width: parent.width
657+ horizontalAlignment: Text.AlignHCenter
658+ text: qsTr("Version %1").arg(0.6)
659+ }
660+ }
661+
662+ Column {
663+ anchors {
664+ left: parent.left
665+ right: parent.right
666+ margins: units.gu(2)
667+ }
668+ Label {
669+ width: parent.width
670+ wrapMode: Text.WordWrap
671+ horizontalAlignment: Text.AlignHCenter
672+ text: "(C) 2015 Podbird Team"
673+ }
674+ Label {
675+ fontSize: "small"
676+ width: parent.width
677+ wrapMode: Text.WordWrap
678+ horizontalAlignment: Text.AlignHCenter
679+ text: i18n.tr("Released under the terms of the GNU GPL v3")
680+ }
681+ }
682+
683+ Label {
684+ width: parent.width
685+ wrapMode: Text.WordWrap
686+ fontSize: "small"
687+ horizontalAlignment: Text.AlignHCenter
688+ text: i18n.tr("Source code available on %1").arg("<a href=\"https://launchpad.net/podbird\">launchpad.net</a>")
689+ onLinkActivated: Qt.openUrlExternally(link)
690+ }
691+ }
692+ }
693+
694+ Item {
695+ width: tabView.width
696+ height: tabView.height
697+
698+ Column {
699+ anchors.topMargin: units.gu(1)
700+ anchors.fill: parent
701+
702+ ListItem.Header {
703+ text: i18n.tr("Developers")
704+ }
705+
706+ ListItem.Standard {
707+ showDivider: false
708+ text: "Michael Sheldon (Creator)"
709+ }
710+
711+ ListItem.Standard {
712+ showDivider: false
713+ text: "Nekhelesh Ramananthan"
714+ }
715+
716+ ListItem.Header {
717+ text: i18n.tr("Designer")
718+ }
719+
720+ ListItem.Standard {
721+ showDivider: false
722+ text: "Kevin Feyder"
723+ }
724+
725+ ListItem.Header {
726+ text: i18n.tr("Translators")
727+ }
728+
729+ ListItem.Standard {
730+ showDivider: false
731+ text: "Ubuntu Translators Team"
732+ }
733+ }
734+ }
735+ }
736+
737+ ListView {
738+ id: tabView
739+ model: tabs
740+ interactive: false
741+ anchors.fill: parent
742+ orientation: Qt.Horizontal
743+ snapMode: ListView.SnapOneItem
744+ currentIndex: aboutPage.head.sections.selectedIndex
745+ highlightMoveDuration: UbuntuAnimation.SlowDuration
746+ }
747+}
748
749=== added file 'app/settings/CMakeLists.txt'
750--- app/settings/CMakeLists.txt 1970-01-01 00:00:00 +0000
751+++ app/settings/CMakeLists.txt 2015-04-11 21:39:04 +0000
752@@ -0,0 +1,7 @@
753+file(GLOB SETTING_FILES *.qml)
754+
755+# Make the files visible in the qtcreator tree
756+add_custom_target(podbird_SETTINGFiles ALL SOURCES ${SETTING_FILES})
757+
758+install(FILES ${SETTING_FILES} DESTINATION ${PODBIRD_DIR}/settings)
759+
760
761=== added file 'app/settings/CleanSetting.qml'
762--- app/settings/CleanSetting.qml 1970-01-01 00:00:00 +0000
763+++ app/settings/CleanSetting.qml 2015-04-11 21:39:04 +0000
764@@ -0,0 +1,65 @@
765+/*
766+ * Copyright 2015 Podbird Team
767+ *
768+ * This file is part of Podbird.
769+ *
770+ * Podbird is free software; you can redistribute it and/or modify
771+ * it under the terms of the GNU General Public License as published by
772+ * the Free Software Foundation; version 3.
773+ *
774+ * Podbird is distributed in the hope that it will be useful,
775+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
776+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
777+ * GNU General Public License for more details.
778+ *
779+ * You should have received a copy of the GNU General Public License
780+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
781+ */
782+
783+import QtQuick 2.3
784+import Ubuntu.Components 1.1
785+import Ubuntu.Components.ListItems 1.0 as ListItem
786+
787+Page {
788+ id: cleanSettingPage
789+
790+ visible: false
791+ title: i18n.tr("Delete older than")
792+
793+ ListModel {
794+ id: cleanupModel
795+ Component.onCompleted: initialize()
796+ function initialize() {
797+ cleanupModel.append({ name: i18n.tr("Never"), value: -1 })
798+ cleanupModel.append({ name: i18n.tr("%1 day", "%1 days", 7).arg(7), value: 7 })
799+ cleanupModel.append({ name: i18n.tr("%1 month", "%1 months", 1).arg(1), value: 31 })
800+ cleanupModel.append({ name: i18n.tr("%1 month", "%1 months", 3).arg(3), value: 90 })
801+ cleanupModel.append({ name: i18n.tr("%1 month", "%1 months", 6).arg(6), value: 180 })
802+ cleanupModel.append({ name: i18n.tr("%1 year", "%1 years", 1).arg(1), value: 360 })
803+ }
804+ }
805+
806+ UbuntuListView {
807+ id: cleanup
808+
809+ model: cleanupModel
810+ anchors.fill: parent
811+
812+ delegate: ListItem.Standard {
813+ text: model.name
814+ onClicked: {
815+ podbird.settings.retentionDays = model.value
816+ }
817+
818+ Icon {
819+ width: units.gu(2)
820+ height: width
821+ name: "ok"
822+ visible: podbird.settings.retentionDays === model.value
823+ anchors.right: parent.right
824+ anchors.rightMargin: units.gu(3)
825+ anchors.verticalCenter: parent.verticalCenter
826+ }
827+ }
828+ }
829+}
830
831=== added file 'app/settings/DownloadSetting.qml'
832--- app/settings/DownloadSetting.qml 1970-01-01 00:00:00 +0000
833+++ app/settings/DownloadSetting.qml 2015-04-11 21:39:04 +0000
834@@ -0,0 +1,64 @@
835+/*
836+ * Copyright 2015 Podbird Team
837+ *
838+ * This file is part of Podbird.
839+ *
840+ * Podbird is free software; you can redistribute it and/or modify
841+ * it under the terms of the GNU General Public License as published by
842+ * the Free Software Foundation; version 3.
843+ *
844+ * Podbird is distributed in the hope that it will be useful,
845+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
846+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
847+ * GNU General Public License for more details.
848+ *
849+ * You should have received a copy of the GNU General Public License
850+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
851+ */
852+
853+import QtQuick 2.3
854+import Ubuntu.Components 1.1
855+import Ubuntu.Components.ListItems 1.0 as ListItem
856+
857+Page {
858+ id: downloadSetting
859+
860+ visible: false
861+ title: i18n.tr("Download at most")
862+
863+ ListModel {
864+ id: episodeDownloadNumber
865+ Component.onCompleted: initialize()
866+ function initialize() {
867+ episodeDownloadNumber.append({ name: i18n.tr("Never"), value: -1 })
868+ episodeDownloadNumber.append({ name: i18n.tr("%1 episode", "%1 episodes", 1).arg(1), value: 1 })
869+ episodeDownloadNumber.append({ name: i18n.tr("%1 episode", "%1 episodes", 3).arg(3), value: 3 })
870+ episodeDownloadNumber.append({ name: i18n.tr("%1 episode", "%1 episodes", 5).arg(5), value: 5 })
871+ episodeDownloadNumber.append({ name: i18n.tr("%1 episode", "%1 episodes", 10).arg(10), value: 10 })
872+ }
873+ }
874+
875+ UbuntuListView {
876+ id: download
877+
878+ model: episodeDownloadNumber
879+ anchors.fill: parent
880+
881+ delegate: ListItem.Standard {
882+ text: model.name
883+ onClicked: {
884+ podbird.settings.maxEpisodeDownload = model.value
885+ }
886+
887+ Icon {
888+ width: units.gu(2)
889+ height: width
890+ name: "ok"
891+ visible: podbird.settings.maxEpisodeDownload === model.value
892+ anchors.right: parent.right
893+ anchors.rightMargin: units.gu(3)
894+ anchors.verticalCenter: parent.verticalCenter
895+ }
896+ }
897+ }
898+}
899
900=== added file 'app/settings/ThemeSetting.qml'
901--- app/settings/ThemeSetting.qml 1970-01-01 00:00:00 +0000
902+++ app/settings/ThemeSetting.qml 2015-04-11 21:39:04 +0000
903@@ -0,0 +1,63 @@
904+/*
905+ * Copyright 2015 Podbird Team
906+ *
907+ * This file is part of Podbird.
908+ *
909+ * Podbird is free software; you can redistribute it and/or modify
910+ * it under the terms of the GNU General Public License as published by
911+ * the Free Software Foundation; version 3.
912+ *
913+ * Podbird is distributed in the hope that it will be useful,
914+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
915+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
916+ * GNU General Public License for more details.
917+ *
918+ * You should have received a copy of the GNU General Public License
919+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
920+ */
921+
922+import QtQuick 2.3
923+import Ubuntu.Components 1.1
924+import Ubuntu.Components.ListItems 1.0 as ListItem
925+
926+Page {
927+ id: themeSettingPage
928+
929+ visible: false
930+ title: i18n.tr("Theme")
931+
932+ ListModel {
933+ id: themeModel
934+ Component.onCompleted: initialize()
935+ function initialize() {
936+ themeModel.append({ name: i18n.tr("Light"), file: "Light.qml" })
937+ themeModel.append({ name: i18n.tr("Dark"), file: "Dark.qml" })
938+ }
939+ }
940+
941+ UbuntuListView {
942+ id: themes
943+
944+ model: themeModel
945+ anchors.fill: parent
946+
947+ delegate: ListItem.Standard {
948+ text: model.name
949+ onClicked: {
950+ var themeElement = model.file
951+ podbird.settings.themeName = themeElement
952+ podbird.themeManager.source = themeElement
953+ }
954+
955+ Icon {
956+ width: units.gu(2)
957+ height: width
958+ name: "ok"
959+ visible: podbird.settings.themeName === model.file
960+ anchors.right: parent.right
961+ anchors.rightMargin: units.gu(3)
962+ anchors.verticalCenter: parent.verticalCenter
963+ }
964+ }
965+ }
966+}
967
968=== modified file 'app/themes/Dark.qml'
969--- app/themes/Dark.qml 2015-03-04 02:58:36 +0000
970+++ app/themes/Dark.qml 2015-04-11 21:39:04 +0000
971@@ -21,12 +21,12 @@
972
973 QtObject {
974 // MainView
975- property color background: "#1E1E23"
976+ property color background: "#242423"
977
978 // Main Text Colors
979 property color baseText: "White"
980 property color baseSubText: "#999999"
981- property color focusText: "#FF9900"
982+ property color focusText: "#35AF44"
983
984 // Icon Colors
985 property color baseIcon: "White"
986@@ -37,8 +37,8 @@
987 property color neutralActionButton: UbuntuColors.coolGrey
988
989 // Bottom Player Bar Colors
990- property color bottomBarBackground: "#0F0F0F"
991+ property color bottomBarBackground: "#15141A"
992
993 // Highlight Color
994- property color hightlightListView: "#2C2C34"
995+ property color hightlightListView: "#333533"
996 }
997
998=== modified file 'app/themes/Light.qml'
999--- app/themes/Light.qml 2015-03-04 02:58:36 +0000
1000+++ app/themes/Light.qml 2015-04-11 21:39:04 +0000
1001@@ -21,12 +21,12 @@
1002
1003 QtObject {
1004 // MainView
1005- property color background: "#EEEEEE"
1006+ property color background: "#ECECEC"
1007
1008 // Main Text Colors
1009 property color baseText: UbuntuColors.darkGrey
1010 property color baseSubText: "#999999"
1011- property color focusText: UbuntuColors.orange
1012+ property color focusText: "#35AF44"
1013
1014 // Icon Colors
1015 property color baseIcon: UbuntuColors.darkGrey
1016@@ -37,8 +37,8 @@
1017 property color neutralActionButton: UbuntuColors.coolGrey
1018
1019 // Bottom Player Bar Colors
1020- property color bottomBarBackground: "#0F0F0F"
1021+ property color bottomBarBackground: "#323435"
1022
1023 // Highlight Color
1024- property color hightlightListView: "#D8D8D8"
1025+ property color hightlightListView: "#F5F5F5"
1026 }
1027
1028=== modified file 'app/ui/ActionButton.qml'
1029--- app/ui/ActionButton.qml 2015-03-08 11:10:07 +0000
1030+++ app/ui/ActionButton.qml 2015-04-11 21:39:04 +0000
1031@@ -22,7 +22,8 @@
1032 AbstractButton {
1033 id: abstractButton
1034
1035- property string iconName
1036+ property alias iconName: _icon.name
1037+ property alias color: _icon.color
1038
1039 Rectangle {
1040 visible: abstractButton.pressed
1041@@ -35,7 +36,6 @@
1042 width: units.gu(2.5)
1043 height: width
1044 anchors.centerIn: parent
1045- name: abstractButton.iconName
1046 color: podbird.theme.baseIcon
1047 }
1048 }
1049
1050=== modified file 'app/ui/BlurredBackground.qml'
1051--- app/ui/BlurredBackground.qml 2015-02-10 06:57:54 +0000
1052+++ app/ui/BlurredBackground.qml 2015-04-11 21:39:04 +0000
1053@@ -25,15 +25,8 @@
1054 Item {
1055 width: parent.width
1056
1057- property string art // : player.currentMetaFile === "" ? Qt.resolvedUrl("../images/music-app-cover@30.png") : player.currentMetaArt
1058-
1059- // dark layer
1060- Rectangle {
1061- anchors {
1062- fill: parent
1063- }
1064- color: "black"
1065- }
1066+ property string art
1067+ property real backgroundStrength: 0.4
1068
1069 // the album art
1070 Image {
1071@@ -44,16 +37,6 @@
1072 fillMode: Image.PreserveAspectCrop
1073 height: parent.height
1074 source: art // this has to be fixed for the default cover art to work - cant find in this dir
1075-
1076- // TODO: This should be investigated once http://pad.lv/1391368
1077- // is resolved. Once it is, these can either be set to
1078- // "height" and "width" or a property exposed via the
1079- // SDK or Thumbnailer to avoid a regression caused by
1080- // these hardcoded values changing in the Thumbnailer.
1081- // 512 is size of the "xlarge" thumbnails in pixels.
1082- sourceSize.height: 512
1083- sourceSize.width: 512
1084-
1085 visible: false
1086 width: Math.max(parent.height, parent.width)
1087 }
1088@@ -63,8 +46,8 @@
1089 id: backgroundBlur
1090 anchors.fill: backgroundImage
1091 source: backgroundImage
1092- radius: units.dp(42)
1093- opacity: 0.2
1094+ radius: units.dp(30)
1095+ opacity: backgroundStrength
1096 }
1097 onArtChanged: {
1098 // TODO: This is a work around for LP:1261078 and LP:1306845. Ideally,
1099
1100=== added file 'app/ui/Card.qml'
1101--- app/ui/Card.qml 1970-01-01 00:00:00 +0000
1102+++ app/ui/Card.qml 2015-04-11 21:39:04 +0000
1103@@ -0,0 +1,139 @@
1104+/*
1105+ * Copyright (C) 2014
1106+ * Andrew Hayzen <ahayzen@gmail.com>
1107+ *
1108+ * This program 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+ * This program 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.3
1122+import Ubuntu.Components 1.1
1123+
1124+Item {
1125+ id: card
1126+
1127+ /* Required by ColumnFlow */
1128+ property int index
1129+ property var model
1130+
1131+ property alias coverArt: imgFrame.source
1132+ property alias primaryText: primaryLabel.text
1133+ property alias secondaryText: secondaryLabel.text
1134+ property alias secondaryTextVisible: secondaryLabel.visible
1135+
1136+ signal clicked(var mouse)
1137+ signal pressAndHold(var mouse)
1138+
1139+ height: cardColumn.childrenRect.height + 2 * bg.anchors.margins
1140+
1141+ /* Background for card */
1142+ Rectangle {
1143+ id: bg
1144+ anchors.fill: parent
1145+ anchors.margins: units.gu(1)
1146+ color: podbird.theme.hightlightListView
1147+ }
1148+
1149+ /* Column containing image and labels */
1150+ Column {
1151+ id: cardColumn
1152+
1153+ anchors.fill: bg
1154+ spacing: units.gu(0.5)
1155+
1156+ Image {
1157+ id: imgFrame
1158+ width: parent.width
1159+ height: width
1160+ sourceSize.height: width
1161+ sourceSize.width: width
1162+ }
1163+
1164+ Item {
1165+ height: units.gu(1)
1166+ width: units.gu(1)
1167+ }
1168+
1169+ Label {
1170+ id: primaryLabel
1171+ anchors {
1172+ left: parent.left
1173+ right: parent.right
1174+ margins: units.gu(1)
1175+ }
1176+ color: podbird.theme.baseText
1177+ elide: Text.ElideRight
1178+ fontSize: "small"
1179+ opacity: 1.0
1180+ wrapMode: Text.WordWrap
1181+ horizontalAlignment: Text.AlignHCenter
1182+ }
1183+
1184+ Label {
1185+ id: secondaryLabel
1186+ anchors {
1187+ left: parent.left
1188+ leftMargin: units.gu(1)
1189+ right: parent.right
1190+ rightMargin: units.gu(1)
1191+ }
1192+ color: podbird.theme.baseSubText
1193+ elide: Text.ElideRight
1194+ fontSize: "small"
1195+ opacity: 1.0
1196+ wrapMode: Text.WordWrap
1197+ horizontalAlignment: Text.AlignHCenter
1198+ }
1199+
1200+ Item {
1201+ height: units.gu(1.5)
1202+ width: units.gu(1)
1203+ }
1204+ }
1205+
1206+ /* Overlay for when card is pressed */
1207+ Rectangle {
1208+ id: overlay
1209+ anchors.fill: bg
1210+ color: "#000"
1211+ opacity: 0
1212+
1213+ Behavior on opacity {
1214+ UbuntuNumberAnimation {}
1215+ }
1216+ }
1217+
1218+ /* Capture mouse events */
1219+ MouseArea {
1220+ anchors.fill: parent
1221+ onClicked: card.clicked(mouse)
1222+ onPressAndHold: card.pressAndHold(mouse)
1223+ onPressedChanged: overlay.opacity = pressed ? 0.3 : 0
1224+ }
1225+
1226+ /* Animations */
1227+ Behavior on height {
1228+ UbuntuNumberAnimation {}
1229+ }
1230+
1231+ Behavior on width {
1232+ UbuntuNumberAnimation {}
1233+ }
1234+
1235+ Behavior on x {
1236+ UbuntuNumberAnimation {}
1237+ }
1238+
1239+ Behavior on y {
1240+ UbuntuNumberAnimation {}
1241+ }
1242+}
1243
1244=== added file 'app/ui/CardView.qml'
1245--- app/ui/CardView.qml 1970-01-01 00:00:00 +0000
1246+++ app/ui/CardView.qml 2015-04-11 21:39:04 +0000
1247@@ -0,0 +1,55 @@
1248+/*
1249+ * Copyright (C) 2014
1250+ * Andrew Hayzen <ahayzen@gmail.com>
1251+ *
1252+ * This program is free software; you can redistribute it and/or modify
1253+ * it under the terms of the GNU General Public License as published by
1254+ * the Free Software Foundation; version 3.
1255+ *
1256+ * This program is distributed in the hope that it will be useful,
1257+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1258+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1259+ * GNU General Public License for more details.
1260+ *
1261+ * You should have received a copy of the GNU General Public License
1262+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1263+ */
1264+
1265+import QtQuick 2.3
1266+import Ubuntu.Components 1.1
1267+
1268+Flickable {
1269+ id: cardViewFlickable
1270+ anchors {
1271+ fill: parent
1272+ margins: units.gu(1)
1273+ }
1274+
1275+ // dont use flow.contentHeight as it is inaccurate due to height of labels
1276+ // changing as they load
1277+ contentHeight: flow.contentHeight + flow.anchors.margins * 2 + units.gu(8)
1278+ contentWidth: width
1279+
1280+ property alias count: flow.count
1281+ property alias delegate: flow.delegate
1282+ property var getter
1283+ property alias model: flow.model
1284+ property real itemWidth: units.gu(15)
1285+
1286+ onGetterChanged: flow.getter = getter // cannot use alias to set a function (must be var)
1287+
1288+ ColumnFlow {
1289+ id: flow
1290+ anchors.fill: parent
1291+ columns: parseInt(cardViewFlickable.width / itemWidth) || 1 // never drop to 0
1292+ flickable: cardViewFlickable
1293+ }
1294+
1295+ Component.onCompleted: {
1296+ // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition
1297+ // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration
1298+ var scaleFactor = units.gridUnit / 8;
1299+ maximumFlickVelocity = maximumFlickVelocity * scaleFactor;
1300+ flickDeceleration = flickDeceleration * scaleFactor;
1301+ }
1302+}
1303
1304=== added file 'app/ui/ColumnFlow.qml'
1305--- app/ui/ColumnFlow.qml 1970-01-01 00:00:00 +0000
1306+++ app/ui/ColumnFlow.qml 2015-04-11 21:39:04 +0000
1307@@ -0,0 +1,494 @@
1308+/*
1309+ * Copyright (C) 2014, 2015
1310+ * Andrew Hayzen <ahayzen@gmail.com>
1311+ *
1312+ * This program is free software; you can redistribute it and/or modify
1313+ * it under the terms of the GNU General Public License as published by
1314+ * the Free Software Foundation; version 3.
1315+ *
1316+ * This program is distributed in the hope that it will be useful,
1317+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1318+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1319+ * GNU General Public License for more details.
1320+ *
1321+ * You should have received a copy of the GNU General Public License
1322+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1323+ */
1324+
1325+import QtQuick 2.3
1326+
1327+Item {
1328+ id: columnFlow
1329+ property int columns: 1
1330+ property Flickable flickable
1331+ property var model
1332+ property Component delegate
1333+
1334+ property var getter: function (i) { return model.get(i); } // optional getter override (useful for music-app ms2 models)
1335+
1336+ property int buffer: units.gu(20)
1337+ property var columnHeights: []
1338+ property var columnHeightsMax: []
1339+ property int columnWidth: parent.width / columns
1340+ property int contentHeight: 0
1341+ property int count: model === undefined ? 0 : model.count
1342+ property int delayRebuildIndex: -1
1343+ property var incubating: ({}) // incubating objects
1344+ property var items: ({})
1345+ property var itemToColumn: ({}) // cache of the columns of indexes
1346+ property int lastIndex: 0 // the furtherest index loaded
1347+ property bool removing: false
1348+ property bool restoring: false // is the view restoring?
1349+ property var restoreItems: ({}) // when rebuilding items are stored here temporarily
1350+
1351+ onColumnWidthChanged: {
1352+ if (restoring) {
1353+ return;
1354+ } else if (columns != columnHeights.length && visible) {
1355+ // number of columns has changed so rebuild the columns
1356+ rebuildColumns()
1357+ } else { // column width has changed update visible items properties linked to columnWidth
1358+ for (var column=0; column < columnHeights.length; column++) {
1359+ for (var i in columnHeights[column]) {
1360+ if (columnHeights[column].hasOwnProperty(i) && items.hasOwnProperty(i)) {
1361+ items[i].width = columnWidth;
1362+ items[i].x = column * columnWidth;
1363+ }
1364+ }
1365+ }
1366+
1367+ ensureItemsVisible()
1368+ }
1369+ }
1370+
1371+ onVisibleChanged: {
1372+ if (visible && delayRebuildIndex !== -1) { // restore from count change
1373+ if (delayRebuildIndex === 0) {
1374+ reset()
1375+ } else {
1376+ removeIndex(delayRebuildIndex)
1377+ }
1378+
1379+ delayRebuildIndex = -1
1380+ append(true)
1381+ }
1382+
1383+ // number of columns has changed while invisible so reset if not already restoring
1384+ if (visible && !restoring && columns != columnHeights.length) {
1385+ rebuildColumns()
1386+ }
1387+ }
1388+
1389+ ListModel { // fakemodel for connections to link to when there is no model
1390+ id: fakeModel
1391+ }
1392+
1393+ Connections {
1394+ target: model === undefined ? fakeModel : model
1395+ onModelReset: {
1396+ if (!visible && lastIndex > 0) {
1397+ delayRebuildIndex = 0
1398+ } else {
1399+ reset()
1400+ append()
1401+ }
1402+ }
1403+ onRowsInserted: {
1404+ if (!visible && lastIndex > 0) {
1405+ setDelayRebuildIndex(first)
1406+ } else {
1407+ if (first <= lastIndex) {
1408+ if (first === 0) {
1409+ reset()
1410+ } else {
1411+ removeIndex(first) // remove earliest index and all items after
1412+ }
1413+ }
1414+
1415+ // Supply last index if larger as count is not updated until after insertion
1416+ append(true, last > count ? last : count)
1417+ }
1418+ }
1419+ onRowsRemoved: {
1420+ if (!visible) {
1421+ setDelayRebuildIndex(first)
1422+ } else {
1423+ if (first <= lastIndex) {
1424+ if (first === 0) {
1425+ reset()
1426+ } else {
1427+ removeIndex(first) // remove earliest index and all items after
1428+ }
1429+
1430+ // count is not updated until after removal, so send insertMax
1431+ // insertMax is count - removal region inclusive - 1 (lastIndex is 1 infront)
1432+
1433+ append(true, count - (1 + last - first) - 1) // rebuild any items on screen or before
1434+ }
1435+ }
1436+ }
1437+ }
1438+
1439+
1440+ Connections {
1441+ target: flickable
1442+ onContentYChanged: {
1443+ append() // Append any new items (scrolling down)
1444+
1445+ ensureItemsVisible()
1446+ }
1447+ }
1448+
1449+ // Append a new row of items if possible
1450+ function append(loadBefore, insertMax)
1451+ {
1452+ // Do not allow append to run if incubating
1453+ if (isIncubating() || restoring || removing) {
1454+ return;
1455+ }
1456+
1457+ // get the columns in order
1458+ var columnsByHeight = getColumnsByHeight();
1459+ var workDone = false;
1460+
1461+ // check if a new item in each column is possible
1462+ for (var i=0; i < columnsByHeight.length; i++) {
1463+ var y = columnHeightsMax[columnsByHeight[i]];
1464+
1465+ // build new object in column if possible
1466+ // if insertMax is undefined then allow if there is work todo (from the count in the model)
1467+ // otherwise use the insertMax as the count to compare with the lastIndex added to the columnFlow
1468+ // and
1469+ // allow if the y position is within the viewport
1470+ // or if loadBefore is true then allow if the y position is before the viewport
1471+ if (((count > 0 && lastIndex < count && insertMax === undefined) || (insertMax !== undefined && lastIndex <= insertMax)) && (inViewport(y, 0) || (loadBefore === true && beforeViewport(y)))) {
1472+ incubateObject(lastIndex++, columnsByHeight[i], getMaxInColumn(columnsByHeight[i]), append);
1473+ workDone = true
1474+ } else {
1475+ break;
1476+ }
1477+ }
1478+
1479+ if (!workDone) { // last iteration over append so visible ensure items are correct
1480+ ensureItemsVisible();
1481+ }
1482+ }
1483+
1484+ // Detect if a loaded object is before the viewport with a buffer
1485+ function beforeViewport(y)
1486+ {
1487+ return y <= flickable.contentY - buffer;
1488+ }
1489+
1490+ // Cache the size of the columns for use later
1491+ function cacheColumnHeights()
1492+ {
1493+ columnHeightsMax = [];
1494+
1495+ for (var i=0; i < columnHeights.length; i++) {
1496+ var sum = 0;
1497+
1498+ for (var j in columnHeights[i]) {
1499+ sum += columnHeights[i][j];
1500+ }
1501+
1502+ columnHeightsMax.push(sum);
1503+ }
1504+
1505+ if (!restoring) { // when not restoring otherwise user will be pushed to the top of the view
1506+ // set the height of columnFlow to max column (for flickable contentHeight)
1507+ contentHeight = Math.max.apply(null, columnHeightsMax);
1508+ }
1509+ }
1510+
1511+ // Recache the visible items heights (due to a change in their height)
1512+ function cacheVisibleItemsHeights()
1513+ {
1514+ for (var i in items) {
1515+ if (items.hasOwnProperty(i)) {
1516+ columnHeights[itemToColumn[i]][i] = items[i].height;
1517+ }
1518+ }
1519+
1520+ cacheColumnHeights();
1521+ }
1522+
1523+ // Ensures that the correct items are visible
1524+ function ensureItemsVisible()
1525+ {
1526+ for (var i in items) {
1527+ if (items.hasOwnProperty(i)) {
1528+ items[i].visible = inViewport(items[i].y, items[i].height)
1529+ }
1530+ }
1531+ }
1532+
1533+ // Return if there are incubating objects
1534+ function isIncubating()
1535+ {
1536+ for (var i in incubating) {
1537+ if (incubating.hasOwnProperty(i)) {
1538+ return true;
1539+ }
1540+ }
1541+
1542+ return false;
1543+ }
1544+
1545+ // Run after incubation to store new column height and call any further append/restores
1546+ function finishIncubation(index, callback)
1547+ {
1548+ var obj = incubating[index].object;
1549+ delete incubating[index];
1550+
1551+ obj.heightChanged.connect(cacheVisibleItemsHeights) // if the height changes recache
1552+
1553+ // Ensure properties linked to columnWidth are correct (as width may still be changing)
1554+ obj.x = itemToColumn[index] * columnWidth;
1555+ obj.width = columnWidth;
1556+
1557+ items[index] = obj;
1558+
1559+ columnHeights[itemToColumn[index]][index] = obj.height; // ensure height is the latest
1560+
1561+ if (!isIncubating()) {
1562+ cacheColumnHeights();
1563+
1564+ // Check if there is any more work to be done (append or restore)
1565+ callback();
1566+ }
1567+ }
1568+
1569+ // Force any incubation to finish
1570+ function forceIncubationCompletion()
1571+ {
1572+ for (var i in incubating) {
1573+ if (incubating.hasOwnProperty(i)) {
1574+ incubating[i].forceCompletion()
1575+ }
1576+ }
1577+ }
1578+
1579+ // Get the column index in order of height
1580+ function getColumnsByHeight()
1581+ {
1582+ var columnsByHeight = [];
1583+
1584+ for (var i=0; i < columnHeightsMax.length; i++) {
1585+ var min = undefined;
1586+ var index = -1;
1587+
1588+ // Find the smallest column that has not been found yet
1589+ for (var j=0; j < columnHeightsMax.length; j++) {
1590+ if (columnsByHeight.indexOf(j) === -1 && (min === undefined || columnHeightsMax[j] < min)) {
1591+ min = columnHeightsMax[j];
1592+ index = j;
1593+ }
1594+ }
1595+
1596+ columnsByHeight.push(index);
1597+ }
1598+
1599+ return columnsByHeight;
1600+ }
1601+
1602+ // Get the highest index for a column
1603+ function getMaxInColumn(column)
1604+ {
1605+ var max;
1606+
1607+ for (var i in columnHeights[column]) {
1608+ if (columnHeights[column].hasOwnProperty(i)) {
1609+ i = parseInt(i);
1610+
1611+ if (items.hasOwnProperty(i)) {
1612+ if (i > max || max === undefined) {
1613+ max = i;
1614+ }
1615+ }
1616+ }
1617+ }
1618+
1619+ return max;
1620+ }
1621+
1622+ // Incubate an object for creation
1623+ function incubateObject(index, column, anchorIndex, callback)
1624+ {
1625+ // Load parameters to send to the object on creation
1626+ var params = {
1627+ "anchors.top": anchorIndex === undefined ? parent.top : items[anchorIndex].bottom,
1628+ index: index,
1629+ model: getter(index),
1630+ width: columnWidth,
1631+ x: column * columnWidth
1632+ };
1633+
1634+ // Start incubating and cache the column
1635+ incubating[index] = delegate.incubateObject(parent, params);
1636+ itemToColumn[index] = column;
1637+
1638+ if (incubating[index].status != Component.Ready) {
1639+ incubating[index].onStatusChanged = function(status) {
1640+ if (status == Component.Ready) {
1641+ finishIncubation(index, callback)
1642+ }
1643+ }
1644+ } else {
1645+ finishIncubation(index, callback)
1646+ }
1647+ }
1648+
1649+ // Detect if a loaded object is in the viewport with a buffer
1650+ function inViewport(y, height)
1651+ {
1652+ return flickable.contentY - buffer < y + height && y < flickable.contentY + flickable.height + buffer;
1653+ }
1654+
1655+ // Number of columns has changed rebuild with live items
1656+ function rebuildColumns()
1657+ {
1658+ restoring = true;
1659+ var i;
1660+
1661+ forceIncubationCompletion()
1662+
1663+ columnHeights = []
1664+ columnHeightsMax = []
1665+
1666+ for (i=0; i < columns; i++) {
1667+ columnHeights.push({});
1668+ columnHeightsMax.push(0);
1669+ }
1670+
1671+ lastIndex = 0;
1672+
1673+ restoreItems = items;
1674+ items = {};
1675+
1676+ restoreExisting()
1677+
1678+ restoring = false;
1679+
1680+ cacheColumnHeights(); // rebuilds contentHeight
1681+
1682+ // If the columns have changed while the view was locked rerun
1683+ if (columns != columnHeights.length && visible) {
1684+ rebuildColumns()
1685+ } else {
1686+ append() // check if any new items can be added
1687+ }
1688+ }
1689+
1690+ // Remove an index from the model (invalidating anything after)
1691+ function removeIndex(index)
1692+ {
1693+ removing = true
1694+
1695+ forceIncubationCompletion()
1696+
1697+ for (var i in items) {
1698+ if (i >= index && items.hasOwnProperty(i)) {
1699+ delete columnHeights[itemToColumn[i]][i]
1700+ delete itemToColumn[i]
1701+
1702+ items[i].destroy()
1703+ delete items[i]
1704+ }
1705+ }
1706+
1707+ lastIndex = index
1708+ removing = false
1709+
1710+ cacheColumnHeights()
1711+ }
1712+
1713+ // Restores existing items into potentially new positions
1714+ function restoreExisting()
1715+ {
1716+ var i;
1717+
1718+ // get the columns in order
1719+ var columnsByHeight = getColumnsByHeight();
1720+ var workDone = false;
1721+
1722+ // check if a new item in each column is possible
1723+ for (i=0; i < columnsByHeight.length; i++) {
1724+ var column = columnsByHeight[i];
1725+
1726+ // build new object in column if possible
1727+ if (count > 0 && lastIndex < count) {
1728+ if (restoreItems.hasOwnProperty(lastIndex)) {
1729+ var item = restoreItems[lastIndex];
1730+ var maxInColumn = getMaxInColumn(column); // get lowest item in column
1731+
1732+ itemToColumn[lastIndex] = column;
1733+ columnHeights[column][lastIndex] = item.height; // ensure height is the latest
1734+
1735+ // Rebuild item properties
1736+ item.anchors.bottom = undefined
1737+ item.anchors.top = maxInColumn === undefined ? parent.top : items[maxInColumn].bottom;
1738+ item.x = column * columnWidth;
1739+ item.visible = inViewport(item.y, item.height);
1740+
1741+ // Migrate item from restoreItems to items
1742+ items[lastIndex] = item;
1743+ delete restoreItems[lastIndex];
1744+
1745+ // set after restore as height will likely change causing cacheVisibleItemsHeights to be run
1746+ item.width = columnWidth;
1747+
1748+ cacheColumnHeights(); // ensure column heights are up to date
1749+
1750+ lastIndex++;
1751+ workDone = true;
1752+ }
1753+ } else {
1754+ break;
1755+ }
1756+ }
1757+
1758+ if (workDone) {
1759+ restoreExisting() // if work done then check if any more is needed
1760+ } else {
1761+ restoreItems = {}; // ensure restoreItems is empty
1762+ }
1763+ }
1764+
1765+ // Reset the column flow
1766+ function reset()
1767+ {
1768+ forceIncubationCompletion()
1769+
1770+ // Destroy any old items
1771+ for (var j in items) {
1772+ if (items.hasOwnProperty(j)) {
1773+ items[j].destroy()
1774+ }
1775+ }
1776+
1777+ // Reset and rebuild the variables
1778+ items = ({})
1779+ itemToColumn = ({})
1780+ lastIndex = 0
1781+
1782+ columnHeights = []
1783+
1784+ for (var k=0; k < columns; k++) {
1785+ columnHeights.push({})
1786+ }
1787+
1788+ cacheColumnHeights()
1789+
1790+ contentHeight = 0
1791+ }
1792+
1793+ function setDelayRebuildIndex(index)
1794+ {
1795+ if (delayRebuildIndex === -1 || index < lastIndex) {
1796+ delayRebuildIndex = index
1797+ }
1798+ }
1799+
1800+ Component.onCompleted: append(true)
1801+}
1802
1803=== modified file 'app/ui/EmptyState.qml'
1804--- app/ui/EmptyState.qml 2015-03-04 03:27:26 +0000
1805+++ app/ui/EmptyState.qml 2015-04-11 21:39:04 +0000
1806@@ -31,14 +31,18 @@
1807 property alias iconName: emptyIcon.name
1808 property alias title: emptyLabel.text
1809 property alias subTitle: emptySublabel.text
1810+ property alias iconSource: emptyIcon.source
1811+
1812+ property real iconHeight: units.gu(10)
1813+ property real iconWidth: units.gu(10)
1814
1815 height: childrenRect.height
1816 width: parent.width
1817
1818 Icon {
1819 id: emptyIcon
1820- width: height
1821- height: units.gu(10)
1822+ width: parent.iconWidth
1823+ height: parent.iconHeight
1824 color: podbird.theme.baseIcon
1825 anchors.horizontalCenter: parent.horizontalCenter
1826 }
1827
1828=== modified file 'app/ui/EpisodesPage.qml'
1829--- app/ui/EpisodesPage.qml 2015-03-29 15:33:26 +0000
1830+++ app/ui/EpisodesPage.qml 2015-04-11 21:39:04 +0000
1831@@ -30,17 +30,21 @@
1832 id: episodesPage
1833
1834 visible: false
1835- title: episodeName
1836+ title: i18n.tr("Podcast")
1837+ flickable: null
1838
1839 property string episodeName
1840 property string episodeId
1841 property string episodeArtist
1842 property string episodeImage
1843+ property string tempGuid: "NULL"
1844
1845 property bool episodesUpdating: false;
1846
1847 Component.onCompleted: {
1848 loadEpisodes(episodeId, episodeArtist, episodeImage)
1849+ if (downloader.downloadingGuid != "")
1850+ tempGuid = downloader.downloadingGuid
1851 }
1852
1853 /*
1854@@ -95,7 +99,7 @@
1855 onTriggered: {
1856 var db = Podcasts.init();
1857 db.transaction(function (tx) {
1858- tx.executeSql("UPDATE Episode SET listened=1 WHERE podcast=?", [episodeModel.pid]);
1859+ tx.executeSql("UPDATE Episode SET listened=1 WHERE podcast=?", [episodeId]);
1860 refreshModel();
1861 });
1862 }
1863@@ -122,6 +126,7 @@
1864 episodeList.forceActiveFocus()
1865 searchField.text = ""
1866 episodesPage.state = "default"
1867+ episodeList.positionViewAtBeginning()
1868 }
1869 }
1870
1871@@ -139,7 +144,36 @@
1872 Connections {
1873 target: downloader
1874 onDownloadingGuidChanged: {
1875- loadEpisodes(episodeId, episodeArtist, episodeImage);
1876+ var db = Podcasts.init();
1877+ db.transaction(function (tx) {
1878+ /*
1879+ If tempGuid is NULL, then the episode currently being downloaded is not found within
1880+ this podcast. On the other hand, if it is within this podcast, then update the episodeModel
1881+ with the downloadedfile location we just received from the downloader.
1882+ */
1883+ if (tempGuid != "NULL") {
1884+ var rs2 = tx.executeSql("SELECT downloadedfile, podcast FROM Episode WHERE guid=?", [tempGuid]);
1885+ for (var i=0; i<episodeModel.count; i++) {
1886+ if (episodeModel.get(i).guid == tempGuid) {
1887+ console.log("[LOG]: Setting episode download URL to " + rs2.rows.item(0).downloadedfile)
1888+ episodeModel.setProperty(i, "downloadedfile", rs2.rows.item(0).downloadedfile)
1889+ break
1890+ }
1891+ }
1892+ tempGuid = "NULL"
1893+ }
1894+
1895+ /*
1896+ Here it is checked if the currently downloaded episode belongs to the podcast
1897+ page being currently displayed. If it is, then the downloaded episode guid is
1898+ stored in the tempGuid variable to track it.
1899+ */
1900+ var rs = tx.executeSql("SELECT podcast FROM Episode WHERE guid=?", [downloader.downloadingGuid]);
1901+
1902+ if (downloader.downloadingGuid != "" && rs.rows.item(0).podcast == episodeId && tempGuid == "NULL") {
1903+ tempGuid = downloader.downloadingGuid
1904+ }
1905+ });
1906 }
1907 }
1908
1909@@ -155,12 +189,12 @@
1910 onClicked: {
1911 var db = Podcasts.init();
1912 db.transaction(function (tx) {
1913- var rs = tx.executeSql("SELECT downloadedfile FROM Episode WHERE downloadedfile NOT NULL AND podcast=?", [episodeModel.pid]);
1914+ var rs = tx.executeSql("SELECT downloadedfile FROM Episode WHERE downloadedfile NOT NULL AND podcast=?", [episodeId]);
1915 for(var i = 0; i < rs.rows.length; i++) {
1916 fileManager.deleteFile(rs.rows.item(i).downloadedfile);
1917 }
1918- tx.executeSql("DELETE FROM Episode WHERE podcast=?", [episodeModel.pid]);
1919- tx.executeSql("DELETE FROM Podcast WHERE rowid=?", [episodeModel.pid]);
1920+ tx.executeSql("DELETE FROM Episode WHERE podcast=?", [episodeId]);
1921+ tx.executeSql("DELETE FROM Podcast WHERE rowid=?", [episodeId]);
1922 mainStack.pop()
1923 PopupUtils.close(dialogInternal)
1924 });
1925@@ -176,20 +210,135 @@
1926 }
1927 }
1928
1929+ Component {
1930+ id: popoverComponent
1931+
1932+ Popover {
1933+ id: popover
1934+
1935+ property bool queued: false
1936+ property bool listened: false
1937+ property string downloadedfile: ""
1938+ property string guid: ""
1939+ property string audiourl: ""
1940+ property int index: -1
1941+
1942+ contentWidth: mainColumn.width
1943+
1944+ Column {
1945+ id: mainColumn
1946+
1947+ width: Math.max(download.width, listen.width)
1948+ anchors.top: parent.top
1949+
1950+ ListItem.Empty {
1951+ id: download
1952+
1953+ width: Math.max(row.width, row2.width)
1954+
1955+ Row {
1956+ id: row
1957+
1958+ spacing: units.gu(3)
1959+ anchors.left: parent.left
1960+ anchors.leftMargin: units.gu(2)
1961+ anchors.verticalCenter: parent.verticalCenter
1962+ width: downloadIcon.width + downloadText.implicitWidth + row.spacing + units.gu(4)
1963+
1964+ Icon {
1965+ id: downloadIcon
1966+ width: height
1967+ height: downloadText.height
1968+ name: popover.downloadedfile ? "delete" : (popover.queued && downloader.downloadingGuid !== popover.guid ? "history" : "save")
1969+ }
1970+
1971+ Label {
1972+ id: downloadText
1973+ color: UbuntuColors.darkGrey
1974+ text: popover.downloadedfile ? i18n.tr("Delete local file")
1975+ : (popover.queued && downloader.downloadingGuid !== popover.guid ? i18n.tr("Episode queued for download")
1976+ : i18n.tr("Download episode"))
1977+ }
1978+ }
1979+
1980+ enabled: downloader.downloadingGuid !== popover.guid
1981+ onClicked: {
1982+ var db = Podcasts.init();
1983+ if (popover.downloadedfile) {
1984+ fileManager.deleteFile(popover.downloadedfile);
1985+ db.transaction(function (tx) {
1986+ tx.executeSql("UPDATE Episode SET downloadedfile = NULL WHERE guid = ?", [popover.guid]);
1987+ });
1988+ episodeModel.setProperty(popover.index, "downloadedfile", "")
1989+ } else {
1990+ db.transaction(function (tx) {
1991+ tx.executeSql("UPDATE Episode SET queued=1 WHERE guid = ?", [popover.guid]);
1992+ });
1993+ episodeModel.setProperty(popover.index, "queued", 1)
1994+ downloader.addDownload(popover.guid, popover.audiourl);
1995+ }
1996+ PopupUtils.close(popover)
1997+ }
1998+ }
1999+
2000+ ListItem.Empty {
2001+ id: listen
2002+
2003+ showDivider: false
2004+ width: Math.max(row.width, row2.width)
2005+
2006+ Row {
2007+ id: row2
2008+
2009+ spacing: units.gu(3)
2010+ anchors.left: parent.left
2011+ anchors.leftMargin: units.gu(2)
2012+ anchors.verticalCenter: parent.verticalCenter
2013+ width: listenIcon.width + listenText.implicitWidth + row2.spacing + units.gu(4)
2014+
2015+ Icon {
2016+ id: listenIcon
2017+ width: height
2018+ height: listenText.height
2019+ name: popover.listened ? "view-collapse" : "select"
2020+ }
2021+
2022+ Label {
2023+ id: listenText
2024+ color: UbuntuColors.darkGrey
2025+ text: popover.listened ? "Mark episode unlistened" : "Mark episode listened"
2026+ }
2027+ }
2028+
2029+ onClicked: {
2030+ var db = Podcasts.init();
2031+ db.transaction(function (tx) {
2032+ if (popover.listened)
2033+ tx.executeSql("UPDATE Episode SET listened=0 WHERE guid=?", [popover.guid])
2034+ else
2035+ tx.executeSql("UPDATE Episode SET listened=1 WHERE guid=?", [popover.guid])
2036+ refreshModel();
2037+ });
2038+ PopupUtils.close(popover)
2039+ }
2040+ }
2041+ }
2042+ }
2043+ }
2044+
2045 EmptyState {
2046 anchors.centerIn: parent
2047 anchors.verticalCenterOffset: Qt.inputMethod.visible ? units.gu(4) : 0
2048- visible: episodesPage.state === "search" && sortedEpisodeModel.count === 0
2049- iconName: "music-app-symbolic"
2050- title: i18n.tr("No Episodes found")
2051- subTitle: i18n.tr("No episodes found matching the search term.")
2052+ visible: (episodesPage.state === "search" && sortedEpisodeModel.count === 0) || (episodeModel.count === 0 && podbird.settings.hideListened)
2053+ iconHeight: units.gu(12)
2054+ iconWidth: iconHeight + units.gu(10)
2055+ iconSource: Qt.resolvedUrl("../graphics/notFound.svg")
2056+ title: podbird.settings.hideListened ? i18n.tr("No more episodes") : i18n.tr("No Episodes found")
2057+ subTitle: podbird.settings.hideListened ? i18n.tr("All episodes have been listened to.") : i18n.tr("No episodes found matching the search term.")
2058 }
2059
2060 ListModel {
2061 id: episodeModel
2062- property string pid;
2063- property string artist;
2064- property string image;
2065 }
2066
2067 SortFilterModel {
2068@@ -199,12 +348,126 @@
2069 filter.pattern: RegExp(searchField.text, "gi")
2070 }
2071
2072- ListView {
2073+ function formatTime(seconds) {
2074+ var time = Podcasts.getTimeDiff(seconds)
2075+ var hour = time[0]
2076+ var minute = time[1]
2077+ // TRANSLATORS: the first argument is the number of hours,
2078+ // followed by minute (eg. 20h 3m)
2079+ if(hour > 0 && minute > 0) {
2080+ // xgettext: no-c-format
2081+ return (i18n.tr("%1 hr %2 min"))
2082+ .arg(hour)
2083+ .arg(minute)
2084+ }
2085+
2086+ // TRANSLATORS: this string indicates the number of hours
2087+ // eg. 20h (no plural state required)
2088+ else if(hour > 0 && minute === 0) {
2089+ // xgettext: no-c-format
2090+ return (i18n.tr("%1 hr"))
2091+ .arg(hour)
2092+ }
2093+
2094+ // TRANSLATORS: this string indicates the number of minutes
2095+ // eg. 15m (no plural state required)
2096+ else if(hour === 0 && minute > 0) {
2097+ // xgettext: no-c-format
2098+ return (i18n.tr("%1 min"))
2099+ .arg(minute)
2100+ }
2101+
2102+ else {
2103+ return Podcasts.formatTime(seconds)
2104+ }
2105+ }
2106+
2107+ UbuntuListView {
2108 id: episodeList
2109
2110+ Component.onCompleted: {
2111+ // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition
2112+ // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration
2113+ var scaleFactor = units.gridUnit / 8;
2114+ maximumFlickVelocity = maximumFlickVelocity * scaleFactor;
2115+ flickDeceleration = flickDeceleration * scaleFactor;
2116+ }
2117+
2118+ anchors.fill: parent
2119+ model: sortedEpisodeModel
2120+
2121 clip: true
2122- anchors.fill: parent
2123- model: sortedEpisodeModel
2124+ section.property: "listened"
2125+ section.labelPositioning: ViewSection.InlineLabels
2126+
2127+ section.delegate: Rectangle {
2128+ width: parent.width
2129+ color: section === "0" ? podbird.theme.hightlightListView : "Transparent"
2130+ height: header.implicitHeight + units.gu(2)
2131+ Label {
2132+ id: header
2133+ anchors {
2134+ left: parent.left
2135+ right: parent.right
2136+ margins: units.gu(2)
2137+ verticalCenter: parent.verticalCenter
2138+ }
2139+ fontSize: "x-large"
2140+ text: section === "0" ? i18n.tr("Unheard") : i18n.tr("Listened")
2141+ }
2142+ }
2143+
2144+ header: BlurredBackground {
2145+ id: blurredBackground
2146+
2147+ art: episodeImage
2148+ width: parent.width
2149+ visible: episodesPage.state !== "search" && sortedEpisodeModel.count !== 0
2150+ height: episodesPage.state !== "search" && sortedEpisodeModel.count !== 0 ? cover.height + units.gu(4) : 0
2151+ backgroundStrength: podbird.settings.themeName === "Light.qml" ? 0.3 : 0.6
2152+
2153+ Image {
2154+ id:cover
2155+ width: units.gu(12)
2156+ height: width
2157+ sourceSize.height: width
2158+ sourceSize.width: width
2159+ source: episodeImage
2160+ anchors {
2161+ left: parent.left
2162+ top: parent.top
2163+ margins: units.gu(2)
2164+ }
2165+ }
2166+
2167+ Column {
2168+ id: podcastTitle
2169+
2170+ anchors {
2171+ left: cover.right
2172+ right: parent.right
2173+ bottom: parent.bottom
2174+ margins: units.gu(2)
2175+ }
2176+
2177+ Label {
2178+ text: episodeName
2179+ width: parent.width
2180+ wrapMode: Text.WordWrap
2181+ maximumLineCount: 2
2182+ elide: Text.ElideRight
2183+ color: podbird.theme.baseText
2184+ }
2185+
2186+ Label {
2187+ text: i18n.tr("%1 episode", "%1 episodes", episodeList.count).arg(episodeList.count)
2188+ width: parent.width
2189+ elide: Text.ElideRight
2190+ fontSize: "x-small"
2191+ color: podbird.theme.baseText
2192+ }
2193+ }
2194+ }
2195
2196 footer: Item {
2197 width: parent.width
2198@@ -214,51 +477,41 @@
2199 delegate: ListItem.Empty {
2200 id: listItem
2201
2202- property bool expanded: false
2203+ property bool expanded
2204
2205- width: parent.width
2206- height: mainColumn.height
2207+ height: dataColumn.height + units.gu(2)
2208 highlightWhenPressed: false
2209+ showDivider: false
2210
2211- onClicked: listItem.expanded = !listItem.expanded
2212+ onClicked: {
2213+ expanded = !expanded;
2214+ }
2215
2216 Rectangle {
2217- anchors.fill: parent
2218- color: listItem.pressed ? podbird.theme.hightlightListView : "transparent"
2219+ visible: !model.listened
2220+ width: parent.width
2221+ height: dataColumn.height + units.gu(2)
2222+ color: podbird.theme.hightlightListView
2223 }
2224
2225 Column {
2226- id: mainColumn
2227-
2228- anchors {
2229- top: parent.top
2230- left: parent.left
2231- right: parent.right
2232- margins: units.gu(2)
2233- topMargin: units.gu(1)
2234- }
2235+ id: dataColumn
2236
2237 spacing: units.gu(1)
2238+ anchors.left: parent.left
2239+ anchors.right: parent.right
2240+ anchors.margins: units.gu(2)
2241+ anchors.top: parent.top
2242+ anchors.topMargin: units.gu(0.5)
2243
2244 RowLayout {
2245- id: titleRow
2246+ id: rowlayout
2247
2248 width: parent.width
2249- spacing: units.gu(2)
2250-
2251- Image {
2252- id: imgFrame
2253- width: units.gu(6)
2254- height: width
2255- sourceSize.height: width
2256- sourceSize.width: width
2257- source: model.image
2258- }
2259+ height: titleColumn.height
2260
2261 Column {
2262- id: detailColumn
2263-
2264- anchors.verticalCenter: imgFrame.verticalCenter
2265+ id: titleColumn
2266 Layout.fillWidth: true
2267
2268 Label {
2269@@ -267,19 +520,88 @@
2270 maximumLineCount: 2
2271 wrapMode: Text.WordWrap
2272 elide: Text.ElideRight
2273- color: currentGuid === model.guid ? podbird.theme.focusText
2274- : podbird.theme.baseText
2275+ color: listItem.expanded || currentGuid === model.guid || downloader.downloadingGuid === model.guid ? podbird.theme.focusText
2276+ : podbird.theme.baseText
2277 }
2278
2279 Label {
2280 id: episodePublishDate
2281 width: parent.width
2282- text: Qt.formatDate(new Date(model.published), "MMM d, yyyy")
2283+ text: formatTime(model.duration) + " | " + Qt.formatDate(new Date(model.published), "MMM d, yyyy")
2284 fontSize: "x-small"
2285- color: currentGuid === model.guid ? podbird.theme.focusText
2286- : podbird.theme.baseText
2287 elide: Text.ElideRight
2288- }
2289+ color: podbird.theme.baseSubText
2290+ }
2291+ }
2292+
2293+ ActionButton {
2294+ id: contextualMenu
2295+
2296+ width: units.gu(5)
2297+ height: units.gu(4)
2298+
2299+ iconName: "contextual-menu"
2300+ color: progressBar.visible || listItem.expanded ? podbird.theme.focusText
2301+ : podbird.theme.baseIcon
2302+ onClicked: {
2303+ var popover = PopupUtils.open(popoverComponent, contextualMenu)
2304+ popover.queued = Qt.binding(function() { return model.queued })
2305+ popover.listened = Qt.binding(function() { return model.listened })
2306+ popover.guid = Qt.binding(function() { return model.guid })
2307+ popover.audiourl = Qt.binding(function() { return model.audiourl })
2308+ popover.downloadedfile = Qt.binding(function() { return episodeModel.get(index).downloadedfile })
2309+ popover.index = Qt.binding(function() { return index })
2310+ }
2311+ }
2312+
2313+ ActionButton {
2314+ width: units.gu(4)
2315+ height: units.gu(4)
2316+
2317+ iconName: player.playbackState === MediaPlayer.PlayingState && currentGuid === model.guid ? "media-playback-pause"
2318+ : "media-playback-start"
2319+ color: player.playbackState === MediaPlayer.PlayingState && currentGuid === model.guid ? podbird.theme.focusText
2320+ : podbird.theme.baseIcon
2321+
2322+ onClicked: {
2323+ var db = Podcasts.init();
2324+ db.transaction(function (tx) {
2325+ if (currentGuid === model.guid) {
2326+ if (player.playbackState === MediaPlayer.PlayingState) {
2327+ player.pause()
2328+ } else {
2329+ player.play()
2330+ }
2331+ } else {
2332+ currentGuid = "";
2333+ player.source = model.downloadedfile ? model.downloadedfile : model.audiourl;
2334+ var rs = tx.executeSql("SELECT position FROM Episode WHERE guid=?", [model.guid]);
2335+ player.play();
2336+ player.seek(rs.rows.item(0).position);
2337+ currentName = model.name;
2338+ currentArtist = model.artist;
2339+ currentImage = model.image;
2340+ currentGuid = model.guid;
2341+ }
2342+ });
2343+ }
2344+ }
2345+ }
2346+
2347+ Rectangle {
2348+ id: progressBar
2349+ radius: width/3
2350+ width: parent.width
2351+ height: units.dp(5)
2352+ color: Theme.palette.normal.base
2353+ visible: downloader.downloadingGuid === model.guid
2354+ Rectangle {
2355+ height: parent.height
2356+ radius: parent.radius
2357+ anchors.left: parent.left
2358+ anchors.top: parent.top
2359+ color: podbird.theme.focusText
2360+ width: downloader.progress > 0 ? Math.min((downloader.progress / 100) * parent.width, parent.width) : 0
2361 }
2362 }
2363
2364@@ -288,184 +610,15 @@
2365 text: model.description
2366 textFormat: Text.RichText
2367 clip: true
2368- height: listItem.expanded ? contentHeight : units.gu(4)
2369+ height: listItem.expanded ? contentHeight : 0
2370 wrapMode: Text.WordWrap
2371 width: parent.width
2372- elide: Text.ElideRight
2373 fontSize: "small"
2374 color: podbird.theme.baseSubText
2375 Behavior on height {
2376 UbuntuNumberAnimation {
2377- duration: UbuntuAnimation.SlowDuration
2378- }
2379- }
2380-
2381- }
2382-
2383- Item {
2384- id: statusBox
2385-
2386- width: parent.width
2387- height: units.gu(6)
2388-
2389- function formatTime(seconds) {
2390- var time = Podcasts.getTimeDiff(seconds)
2391- var hour = time[0]
2392- var minute = time[1]
2393- // TRANSLATORS: the first argument is the number of hours,
2394- // followed by minute (eg. 20h 3m)
2395- if(hour > 0 && minute > 0) {
2396- // xgettext: no-c-format
2397- return (i18n.tr("%1h %2m"))
2398- .arg(hour)
2399- .arg(minute)
2400- }
2401-
2402- // TRANSLATORS: this string indicates the number of hours
2403- // eg. 20h (no plural state required)
2404- else if(hour > 0 && minute === 0) {
2405- // xgettext: no-c-format
2406- return (i18n.tr("%1h"))
2407- .arg(hour)
2408- }
2409-
2410- // TRANSLATORS: this string indicates the number of minutes
2411- // eg. 15m (no plural state required)
2412- else if(hour === 0 && minute > 0) {
2413- // xgettext: no-c-format
2414- return (i18n.tr("%1m"))
2415- .arg(minute)
2416- }
2417-
2418- else {
2419- return Podcasts.formatTime(model.duration)
2420- }
2421- }
2422-
2423- Rectangle {
2424- id: listened
2425- border.color: UbuntuColors.lightGrey
2426- height: units.gu(2.5)
2427- width: height
2428- radius: width / 2
2429- anchors.right: durationIcon.left
2430- anchors.rightMargin: units.gu(2)
2431- anchors.verticalCenter: actionRow.verticalCenter
2432- visible: model.listened
2433- Icon {
2434- id: tick
2435- name: "tick"
2436- anchors.centerIn: parent
2437- anchors.verticalCenterOffset: units.gu(0.1)
2438- height: units.gu(1.4)
2439- width: height
2440- }
2441- }
2442-
2443- Icon {
2444- id: durationIcon
2445- width: units.gu(2.5)
2446- height: width
2447- name: "alarm-clock"
2448- visible: duration.text !== ""
2449- anchors.right: duration.left
2450- anchors.rightMargin: units.gu(0.5)
2451- anchors.verticalCenter: actionRow.verticalCenter
2452- color: podbird.theme.baseIcon
2453- }
2454-
2455- Label {
2456- id: duration
2457- color: podbird.theme.baseText
2458- anchors.right: parent.right
2459- anchors.verticalCenter: durationIcon.verticalCenter
2460- fontSize: "small"
2461- text: !isNaN(model.duration) && model.duration !== 0 ? statusBox.formatTime(model.duration) : ""
2462- }
2463-
2464- Row {
2465- id: actionRow
2466-
2467- anchors.left: parent.left
2468- anchors.leftMargin: units.gu(-1.5)
2469-
2470- ActionButton {
2471- width: units.gu(5)
2472- height: units.gu(4)
2473-
2474- iconName: player.playbackState === MediaPlayer.PlayingState && currentGuid === model.guid ? "media-playback-pause"
2475- : "media-playback-start"
2476-
2477- onClicked: {
2478- var db = Podcasts.init();
2479- db.transaction(function (tx) {
2480- if (currentGuid === model.guid) {
2481- if (player.playbackState === MediaPlayer.PlayingState) {
2482- player.pause()
2483- } else {
2484- player.play()
2485- }
2486- } else {
2487- currentGuid = "";
2488- player.source = model.downloadedfile ? model.downloadedfile : model.audiourl;
2489- var rs = tx.executeSql("SELECT position FROM Episode WHERE guid=?", [model.guid]);
2490- player.play();
2491- player.seek(rs.rows.item(0).position);
2492- currentName = model.name;
2493- currentArtist = model.artist;
2494- currentImage = model.image;
2495- currentGuid = model.guid;
2496- }
2497- });
2498- }
2499- }
2500-
2501- ActionButton {
2502- id: downloadButton
2503-
2504- width: units.gu(5)
2505- height: units.gu(4)
2506-
2507- property bool queued: false
2508-
2509- iconName: model.downloadedfile ? "delete" : (queued && downloader.downloadingGuid !== model.guid ? "history" : "save")
2510- opacity: downloader.downloadingGuid === model.guid ? 0.4 : 1.0
2511- enabled: downloader.downloadingGuid !== model.guid
2512-
2513- ActivityIndicator {
2514- anchors.centerIn: parent
2515- visible: downloader.downloadingGuid === model.guid
2516- running: visible
2517- }
2518-
2519- onClicked: {
2520- if (model.downloadedfile) {
2521- fileManager.deleteFile(model.downloadedfile);
2522- var db = Podcasts.init();
2523- db.transaction(function (tx) {
2524- tx.executeSql("UPDATE Episode SET downloadedfile = NULL WHERE guid = ?", [model.guid]);
2525- });
2526- loadEpisodes(episodeModel.pid, episodeModel.artist, episodeModel.image);
2527- } else {
2528- downloadButton.queued = true;
2529- downloader.addDownload(model.guid, model.audiourl);
2530- }
2531- }
2532- }
2533- }
2534-
2535-
2536- ProgressBar {
2537- visible: downloader.downloadingGuid === model.guid
2538- minimumValue: 0
2539- maximumValue: 100
2540- anchors.left: actionRow.right
2541- anchors.right: model.listened ? listened.left : durationIcon.left
2542- anchors.leftMargin: units.gu(2)
2543- anchors.rightMargin: units.gu(2)
2544- anchors.verticalCenter: actionRow.verticalCenter
2545- height: units.gu(2.6)
2546- value: downloader.progress
2547+ duration: UbuntuAnimation.BriskDuration
2548+ }
2549 }
2550 }
2551 }
2552@@ -483,21 +636,28 @@
2553
2554 function refreshModel() {
2555 var db = Podcasts.init();
2556- loadEpisodes(episodeModel.pid, episodeModel.artist, episodeModel.image);
2557+ loadEpisodes(episodeId, episodeArtist, episodeImage);
2558 episodesUpdating = false;
2559 }
2560
2561 function loadEpisodes(pid, artist, img) {
2562+ var i, episode;
2563+ var newCount = 0;
2564+
2565+ episodeModel.clear();
2566+
2567 var db = Podcasts.init();
2568 db.transaction(function (tx) {
2569- episodeModel.clear();
2570 var rs = tx.executeSql("SELECT rowid, * FROM Episode WHERE podcast=? ORDER BY published DESC", [pid]);
2571- for(var i = 0; i < rs.rows.length; i++) {
2572- var episode = rs.rows.item(i);
2573- episodeModel.pid = pid;
2574- episodeModel.artist = artist;
2575- episodeModel.image = img;
2576- 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});
2577+ for(i = 0; i < rs.rows.length; i++) {
2578+ episode = rs.rows.item(i);
2579+ //console.log(episode.queued)
2580+ if (!episode.listened) {
2581+ 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, "queued": episode.queued});
2582+ newCount++;
2583+ } else if (!podbird.settings.hideListened) {
2584+ 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, "queued": episode.queued});
2585+ }
2586 }
2587 });
2588 }
2589@@ -558,12 +718,13 @@
2590 db.transaction(function(tx2) {
2591 var ers = tx2.executeSql("SELECT rowid FROM Episode WHERE guid=?", [track.guid]);
2592 if (ers.rows.length === 0) {
2593- tx2.executeSql("INSERT INTO Episode(podcast, name, description, audiourl, guid, listened, duration, published) VALUES(?, ?, ? , ?, ?, ?, ?, ?)", [pid,
2594+ tx2.executeSql("INSERT INTO Episode(podcast, name, description, audiourl, guid, listened, queued, duration, published) VALUES(?, ?, ? , ?, ?, ?, ?, ?)", [pid,
2595 track.name,
2596 track.description,
2597 track.audiourl,
2598 track.guid,
2599 false,
2600+ false,
2601 track.duration,
2602 track.published]);
2603 }
2604
2605=== modified file 'app/ui/ExpandableListItem.qml'
2606--- app/ui/ExpandableListItem.qml 2015-03-27 15:04:39 +0000
2607+++ app/ui/ExpandableListItem.qml 2015-04-11 21:39:04 +0000
2608@@ -61,6 +61,7 @@
2609 width: units.gu(2)
2610 height: width
2611 anchors.right: parent.right
2612+ anchors.rightMargin: units.gu(1)
2613 anchors.verticalCenter: parent.verticalCenter
2614
2615 name: "go-down"
2616
2617=== modified file 'app/ui/NowPlayingPage.qml'
2618--- app/ui/NowPlayingPage.qml 2015-03-08 11:10:07 +0000
2619+++ app/ui/NowPlayingPage.qml 2015-04-11 21:39:04 +0000
2620@@ -101,6 +101,11 @@
2621 function formatValue(v) { return Podcasts.formatTime(v/1000); }
2622 }
2623
2624+ Connections {
2625+ target: player
2626+ onPositionChanged: scrubber.value = player.position
2627+ }
2628+
2629 Label {
2630 id: startTime
2631 fontSize: "small"
2632
2633=== modified file 'app/ui/PlayerControls.qml'
2634--- app/ui/PlayerControls.qml 2015-03-08 11:10:07 +0000
2635+++ app/ui/PlayerControls.qml 2015-04-11 21:39:04 +0000
2636@@ -53,7 +53,7 @@
2637 id: progressBarHint
2638 anchors.left: parent.left
2639 anchors.top: cover.bottom
2640- color: UbuntuColors.orange
2641+ color: podbird.theme.focusText
2642 height: units.gu(0.25)
2643 width: player.duration > 0 ? (player.position / player.duration) * parent.width : 0
2644 }
2645@@ -72,7 +72,7 @@
2646 color: "white"
2647 elide: Text.ElideRight
2648 maximumLineCount: 2
2649- wrapMode: Text.WrapAnywhere
2650+ wrapMode: Text.WordWrap
2651 text: currentName
2652 }
2653
2654
2655=== modified file 'app/ui/PodcastsTab.qml'
2656--- app/ui/PodcastsTab.qml 2015-03-29 15:33:26 +0000
2657+++ app/ui/PodcastsTab.qml 2015-04-11 21:39:04 +0000
2658@@ -36,6 +36,8 @@
2659 page: Page {
2660 id: podcastPage
2661
2662+ flickable: viewLoader.item
2663+
2664 /*
2665 #FIXME: The following lines of code is necessary due to a upstream bug
2666 in the SDK http://pad.lv/1400297. This bug is still present in the rtm.
2667@@ -74,6 +76,14 @@
2668 podcastPage.state = "search"
2669 searchField.forceActiveFocus()
2670 }
2671+ },
2672+
2673+ Action {
2674+ iconName: podbird.settings.showListView ? "view-grid-symbolic" : "view-list-symbolic"
2675+ text: podbird.settings.showListView ? i18n.tr("Grid View") : i18n.tr("List View")
2676+ onTriggered: {
2677+ podbird.settings.showListView = !podbird.settings.showListView
2678+ }
2679 }
2680 ]
2681 },
2682@@ -85,7 +95,7 @@
2683 iconName: "back"
2684 text: i18n.tr("Back")
2685 onTriggered: {
2686- view.forceActiveFocus()
2687+ viewLoader.item.forceActiveFocus()
2688 searchField.text = ""
2689 podcastPage.state = "default"
2690 }
2691@@ -108,7 +118,7 @@
2692 iconName: "back"
2693 text: i18n.tr("Back")
2694 onTriggered: {
2695- view.forceActiveFocus()
2696+ viewLoader.item.forceActiveFocus()
2697 feedUrlField.text = ""
2698 podcastPage.state = "default"
2699 }
2700@@ -119,7 +129,7 @@
2701 iconName: "ok"
2702 text: i18n.tr("Save Podcast")
2703 onTriggered: {
2704- view.forceActiveFocus()
2705+ viewLoader.item.forceActiveFocus()
2706 subscribeFromFeed(feedUrlField.text);
2707 feedUrlField.text = ""
2708 podcastPage.state = "default"
2709@@ -134,7 +144,7 @@
2710 anchors.left: parent ? parent.left : undefined
2711 anchors.right: parent ? parent.right : undefined
2712 onAccepted: {
2713- view.forceActiveFocus()
2714+ viewLoader.item.forceActiveFocus()
2715 subscribeFromFeed(feedUrlField.text);
2716 feedUrlField.text = ""
2717 podcastPage.state = "default"
2718@@ -167,8 +177,10 @@
2719 EmptyState {
2720 anchors.centerIn: parent
2721 anchors.verticalCenterOffset: Qt.inputMethod.visible ? units.gu(4) : 0
2722+ iconHeight: units.gu(12)
2723+ iconWidth: iconHeight + units.gu(10)
2724+ iconSource: Qt.resolvedUrl("../graphics/notFound.svg")
2725 visible: podcastModel.count === 0 || sortedPodcastModel.count === 0
2726- iconName: "music-app-symbolic"
2727 title: podcastModel.count === 0 ? i18n.tr("No Podcast Subscriptions")
2728 : i18n.tr("No Podcasts Found")
2729 subTitle: podcastModel.count === 0 ? i18n.tr("You haven't subscribed to any podcasts yet, visit the 'Find New Podcasts' page to add some.")
2730@@ -186,122 +198,158 @@
2731 filter.pattern: RegExp(searchField.text, "gi")
2732 }
2733
2734- ListModel {
2735- id: episodeModel
2736- property string pid;
2737- property string artist;
2738- property string image;
2739- }
2740-
2741- ListView {
2742- id: view
2743-
2744- clip: true
2745- model: sortedPodcastModel
2746+ Loader {
2747+ id: viewLoader
2748 anchors.fill: parent
2749-
2750- footer: Item {
2751- width: parent.width
2752- height: units.gu(8)
2753- }
2754-
2755- delegate: ListItem.Empty {
2756- id: listItem
2757-
2758- property bool expanded: false
2759-
2760- height: units.gu(8)
2761- removable: true
2762- confirmRemoval: true
2763- highlightWhenPressed: false
2764-
2765- onItemRemoved: {
2766- var db = Podcasts.init();
2767- db.transaction(function (tx) {
2768- var rs = tx.executeSql("SELECT downloadedfile FROM Episode WHERE downloadedfile NOT NULL AND podcast=?", [model.id]);
2769- for(var i = 0; i < rs.rows.length; i++) {
2770- fileManager.deleteFile(rs.rows.item(i).downloadedfile);
2771- }
2772- tx.executeSql("DELETE FROM Episode WHERE podcast=?", [model.id]);
2773- tx.executeSql("DELETE FROM Podcast WHERE rowid=?", [model.id]);
2774- refreshModel()
2775- });
2776- }
2777-
2778- Rectangle {
2779- anchors.fill: parent
2780- color: listItem.pressed ? podbird.theme.hightlightListView : "transparent"
2781- }
2782-
2783- onClicked: {
2784- if(podcastPage.state === "search") {
2785- view.forceActiveFocus()
2786- searchField.text = ""
2787- podcastPage.state = "default"
2788- }
2789- mainStack.push(Qt.resolvedUrl("EpisodesPage.qml"), {"episodeName": model.name, "episodeId": model.id, "episodeArtist": model.artist, "episodeImage": model.image})
2790- }
2791-
2792- Column {
2793- id: mainColumn
2794-
2795- anchors.left: parent.left
2796- anchors.right: parent.right
2797- anchors.margins: units.gu(2)
2798- anchors.verticalCenter: parent.verticalCenter
2799- spacing: units.gu(1)
2800-
2801- RowLayout {
2802- id: titleRow
2803-
2804- width: parent.width
2805- spacing: units.gu(2)
2806-
2807- Image {
2808- id: imgFrame
2809- width: units.gu(6)
2810- height: width
2811- sourceSize.height: width
2812- sourceSize.width: width
2813- source: model.image
2814- }
2815-
2816- Column {
2817- id: detailColumn
2818-
2819- anchors.verticalCenter: imgFrame.verticalCenter
2820- Layout.fillWidth: true
2821-
2822- Label {
2823- id: podcastTitle
2824- textFormat: Text.PlainText
2825- text: model.name.trim()
2826- width: parent.width
2827- fontSize: "small"
2828- elide: Text.ElideRight
2829- color: podbird.theme.baseText
2830- }
2831-
2832- Label {
2833- id: episodeCount
2834- width: parent.width
2835- fontSize: "x-small"
2836- color: podbird.theme.baseSubText
2837- visible: model.episodeCount > 0
2838- text: i18n.tr("%1 unheard episode", "%1 unheard episodes", model.episodeCount).arg(model.episodeCount)
2839- }
2840- }
2841- }
2842- }
2843- }
2844-
2845- PullToRefresh {
2846- refreshing: episodesUpdating
2847- onRefresh: updateEpisodes();
2848- }
2849- }
2850- Scrollbar {
2851- flickableItem: view
2852+ sourceComponent: podbird.settings.showListView ? listviewComponent : cardviewComponent
2853+ }
2854+
2855+ Component {
2856+ id: cardviewComponent
2857+
2858+ CardView {
2859+ id: cardView
2860+ model: sortedPodcastModel
2861+ delegate: Card {
2862+ id: albumCard
2863+ coverArt: model.image
2864+ primaryText: model.name.trim()
2865+ secondaryText: i18n.tr("%1 unheard episode", "%1 unheard episodes", model.episodeCount).arg(model.episodeCount)
2866+ onClicked: {
2867+ if(podcastPage.state === "search") {
2868+ cardView.forceActiveFocus()
2869+ searchField.text = ""
2870+ podcastPage.state = "default"
2871+ }
2872+ mainStack.push(Qt.resolvedUrl("EpisodesPage.qml"), {"episodeName": model.name, "episodeId": model.id, "episodeArtist": model.artist, "episodeImage": model.image})
2873+ }
2874+ }
2875+ }
2876+ }
2877+
2878+ Component {
2879+ id: listviewComponent
2880+
2881+ ListView {
2882+ id: listView
2883+
2884+ Component.onCompleted: {
2885+ // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition
2886+ // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration
2887+ var scaleFactor = units.gridUnit / 8;
2888+ maximumFlickVelocity = maximumFlickVelocity * scaleFactor;
2889+ flickDeceleration = flickDeceleration * scaleFactor;
2890+ }
2891+
2892+ model: sortedPodcastModel
2893+ anchors.fill: parent
2894+
2895+ footer: Item {
2896+ width: parent.width
2897+ height: units.gu(8)
2898+ }
2899+
2900+ delegate: ListItem.Empty {
2901+ id: listItem
2902+
2903+ property bool expanded: false
2904+
2905+ height: units.gu(8)
2906+ removable: true
2907+ confirmRemoval: true
2908+ showDivider: false
2909+ highlightWhenPressed: false
2910+
2911+ onItemRemoved: {
2912+ var db = Podcasts.init();
2913+ db.transaction(function (tx) {
2914+ var rs = tx.executeSql("SELECT downloadedfile FROM Episode WHERE downloadedfile NOT NULL AND podcast=?", [model.id]);
2915+ for(var i = 0; i < rs.rows.length; i++) {
2916+ fileManager.deleteFile(rs.rows.item(i).downloadedfile);
2917+ }
2918+ tx.executeSql("DELETE FROM Episode WHERE podcast=?", [model.id]);
2919+ tx.executeSql("DELETE FROM Podcast WHERE rowid=?", [model.id]);
2920+ podcastModel.remove(index, 1)
2921+ });
2922+ }
2923+
2924+ Rectangle {
2925+ anchors.fill: parent
2926+ opacity: 0.3
2927+ color: index % 2 === 0 ? podbird.theme.hightlightListView : "Transparent"
2928+ }
2929+
2930+ onClicked: {
2931+ if(podcastPage.state === "search") {
2932+ listView.forceActiveFocus()
2933+ searchField.text = ""
2934+ podcastPage.state = "default"
2935+ }
2936+ mainStack.push(Qt.resolvedUrl("EpisodesPage.qml"), {"episodeName": model.name, "episodeId": model.id, "episodeArtist": model.artist, "episodeImage": model.image})
2937+ }
2938+
2939+ Column {
2940+ id: mainColumn
2941+
2942+ anchors.left: parent.left
2943+ anchors.right: parent.right
2944+ anchors.margins: units.gu(2)
2945+ anchors.verticalCenter: parent.verticalCenter
2946+ spacing: units.gu(1)
2947+
2948+ RowLayout {
2949+ id: titleRow
2950+
2951+ width: parent.width
2952+ spacing: units.gu(2)
2953+
2954+ Image {
2955+ id: imgFrame
2956+ width: units.gu(6)
2957+ height: width
2958+ sourceSize.height: width
2959+ sourceSize.width: width
2960+ source: model.image
2961+ }
2962+
2963+ Column {
2964+ id: detailColumn
2965+
2966+ anchors.verticalCenter: imgFrame.verticalCenter
2967+ Layout.fillWidth: true
2968+
2969+ Label {
2970+ id: podcastTitle
2971+ textFormat: Text.PlainText
2972+ text: model.name.trim()
2973+ width: parent.width
2974+ fontSize: "small"
2975+ elide: Text.ElideRight
2976+ color: podbird.theme.baseText
2977+ }
2978+
2979+ Label {
2980+ id: episodeCount
2981+ width: parent.width
2982+ fontSize: "x-small"
2983+ color: podbird.theme.baseSubText
2984+ visible: model.episodeCount > 0
2985+ text: i18n.tr("%1 unheard episode", "%1 unheard episodes", model.episodeCount).arg(model.episodeCount)
2986+ }
2987+ }
2988+ }
2989+ }
2990+ }
2991+
2992+ Scrollbar {
2993+ flickableItem: listView
2994+ }
2995+
2996+ PullToRefresh {
2997+ refreshing: episodesUpdating
2998+ onRefresh: updateEpisodes();
2999+ }
3000+ }
3001 }
3002 }
3003
3004
3005=== renamed file 'app/ui/SearchTab.qml' => 'app/ui/SearchPage.qml'
3006--- app/ui/SearchTab.qml 2015-03-29 15:33:26 +0000
3007+++ app/ui/SearchPage.qml 2015-04-11 21:39:04 +0000
3008@@ -23,24 +23,64 @@
3009 import Ubuntu.Components.ListItems 1.0 as ListItem
3010 import "../podcasts.js" as Podcasts
3011
3012-Tab {
3013- title: i18n.tr("Find New Podcasts")
3014+Page {
3015+ id: searchPage
3016
3017 property var xhr: new XMLHttpRequest;
3018
3019- page: Page {
3020- Column {
3021- spacing: units.gu(2)
3022- anchors.fill: parent
3023- anchors.topMargin: units.gu(2)
3024-
3025- TextField {
3026+ /*
3027+ #FIXME: The following lines of code is necessary due to a upstream bug
3028+ in the SDK http://pad.lv/1400297. This bug is still present in the rtm.
3029+ Once it is fixed, this following property and connection can be remvoed.
3030+ */
3031+ property Item __oldContents: null
3032+ Connections {
3033+ target: searchPage.head
3034+ onContentsChanged: {
3035+ if (searchPage.__oldContents) {
3036+ searchPage.__oldContents.parent = null;
3037+ }
3038+ searchPage.__oldContents = searchPage.head.contents;
3039+ }
3040+ }
3041+
3042+ state: "default"
3043+ states: [
3044+ PageHeadState {
3045+ name: "default"
3046+ head: searchPage.head
3047+ actions: [
3048+ Action {
3049+ iconName: "search"
3050+ text: i18n.tr("Search Episode")
3051+ onTriggered: {
3052+ searchPage.state = "search"
3053+ searchField.forceActiveFocus()
3054+ }
3055+ }
3056+ ]
3057+ },
3058+
3059+ PageHeadState {
3060+ name: "search"
3061+ head: searchPage.head
3062+ backAction: Action {
3063+ iconName: "back"
3064+ text: i18n.tr("Back")
3065+ onTriggered: {
3066+ resultsView.forceActiveFocus()
3067+ searchField.text = ""
3068+ searchPage.state = "default"
3069+ }
3070+ }
3071+
3072+ contents: TextField {
3073 id: searchField
3074- anchors.left: parent.left
3075- anchors.right: parent.right
3076- anchors.margins: units.gu(2)
3077+ inputMethodHints: Qt.ImhNoPredictiveText
3078 placeholderText: i18n.tr("Search...")
3079- inputMethodHints: Qt.ImhNoPredictiveText;
3080+ anchors.left: parent ? parent.left : undefined
3081+ anchors.right: parent ? parent.right : undefined
3082+ anchors.rightMargin: units.gu(2)
3083 onTextChanged: {
3084 if (text.length > 2) {
3085 search(text)
3086@@ -49,94 +89,113 @@
3087 }
3088 }
3089 }
3090-
3091- ListView {
3092- id: resultsView
3093- clip: true
3094- width: parent.width
3095- model: searchResults
3096- height: parent.height - searchField.height - units.gu(2)
3097-
3098- footer: Item {
3099- width: parent.width
3100- height: units.gu(7)
3101- }
3102-
3103- delegate: ListItem.Empty {
3104- id: listItem
3105-
3106- height: units.gu(8)
3107- highlightWhenPressed: false
3108-
3109- Rectangle {
3110- anchors.fill: parent
3111- color: listItem.pressed ? podbird.theme.hightlightListView : "transparent"
3112- }
3113-
3114- RowLayout {
3115- id: titleRow
3116-
3117- anchors.left: parent.left
3118- anchors.right: parent.right
3119- anchors.margins: units.gu(2)
3120- anchors.verticalCenter: parent.verticalCenter
3121-
3122- spacing: units.gu(2)
3123-
3124- Image {
3125- id: imgFrame
3126- width: units.gu(6)
3127- height: width
3128- sourceSize.height: width
3129- sourceSize.width: width
3130- source: model.image
3131- }
3132-
3133- Column {
3134- id: detailColumn
3135-
3136- anchors.verticalCenter: imgFrame.verticalCenter
3137- Layout.fillWidth: true
3138-
3139- Label {
3140- id: podcastTitle
3141- textFormat: Text.PlainText
3142- text: model.name
3143- width: parent.width
3144- fontSize: "small"
3145- elide: Text.ElideRight
3146- }
3147-
3148- Label {
3149- id: episodeCount
3150- width: parent.width
3151- color: "#999999"
3152- text: model.artist
3153- fontSize: "x-small"
3154- elide: Text.ElideRight
3155- }
3156- }
3157-
3158- Button {
3159- anchors.right: parent.right
3160- text: i18n.tr("Subscribe")
3161- color: UbuntuColors.green
3162- onClicked: {
3163- Podcasts.subscribe(model.artist, model.name, model.feed, model.image);
3164- imageDownloader.feed = model.feed;
3165- imageDownloader.download(model.image);
3166- tabs.selectedTabIndex = 0;
3167- searchField.text = ""
3168- }
3169- }
3170- }
3171- }
3172-
3173- Scrollbar {
3174- flickableItem: resultsView
3175- }
3176-
3177- }
3178+ }
3179+ ]
3180+
3181+ EmptyState {
3182+ anchors.centerIn: parent
3183+ anchors.verticalCenterOffset: Qt.inputMethod.visible ? units.gu(4) : 0
3184+ iconHeight: units.gu(12)
3185+ iconWidth: iconHeight + units.gu(10)
3186+ visible: searchPage.state !== "search" ? true : searchResults.count === 0 && searchField.text.length > 2
3187+ iconSource: searchPage.state !== "search" ? Qt.resolvedUrl("../graphics/owlSearch.svg") : Qt.resolvedUrl("../graphics/notFound.svg")
3188+ title: searchPage.state !== "search" ? i18n.tr("Looking for a new Podcast?") : i18n.tr("No Podcasts found")
3189+ subTitle: searchPage.state !== "search" ? i18n.tr("Click the 'magnifier' at the top to search.") : i18n.tr("No podcasts found matching the search term.")
3190+ }
3191+
3192+ ListView {
3193+ id: resultsView
3194+
3195+ Component.onCompleted: {
3196+ // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition
3197+ // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration
3198+ var scaleFactor = units.gridUnit / 8;
3199+ maximumFlickVelocity = maximumFlickVelocity * scaleFactor;
3200+ flickDeceleration = flickDeceleration * scaleFactor;
3201+ }
3202+
3203+ model: searchResults
3204+ anchors.fill: parent
3205+
3206+ footer: Item {
3207+ width: parent.width
3208+ height: units.gu(7)
3209+ }
3210+
3211+ delegate: ListItem.Empty {
3212+ id: listItem
3213+
3214+ height: units.gu(8)
3215+ showDivider: false
3216+ highlightWhenPressed: false
3217+
3218+ Rectangle {
3219+ anchors.fill: parent
3220+ opacity: 0.3
3221+ color: index % 2 === 0 ? podbird.theme.hightlightListView : "Transparent"
3222+ }
3223+
3224+ RowLayout {
3225+ id: titleRow
3226+
3227+ anchors.left: parent.left
3228+ anchors.right: parent.right
3229+ anchors.margins: units.gu(2)
3230+ anchors.verticalCenter: parent.verticalCenter
3231+
3232+ spacing: units.gu(2)
3233+
3234+ Image {
3235+ id: imgFrame
3236+ width: units.gu(6)
3237+ height: width
3238+ sourceSize.height: width
3239+ sourceSize.width: width
3240+ source: model.image
3241+ }
3242+
3243+ Column {
3244+ id: detailColumn
3245+
3246+ anchors.verticalCenter: imgFrame.verticalCenter
3247+ Layout.fillWidth: true
3248+
3249+ Label {
3250+ id: podcastTitle
3251+ textFormat: Text.PlainText
3252+ text: model.name
3253+ width: parent.width
3254+ fontSize: "medium"
3255+ elide: Text.ElideRight
3256+ }
3257+
3258+ Label {
3259+ id: episodeCount
3260+ width: parent.width
3261+ color: "#999999"
3262+ text: model.artist
3263+ fontSize: "x-small"
3264+ elide: Text.ElideRight
3265+ }
3266+ }
3267+
3268+ Button {
3269+ anchors.right: parent.right
3270+ text: i18n.tr("Subscribe")
3271+ color: UbuntuColors.green
3272+ onClicked: {
3273+ Podcasts.subscribe(model.artist, model.name, model.feed, model.image);
3274+ imageDownloader.feed = model.feed;
3275+ imageDownloader.download(model.image);
3276+ tabs.selectedTabIndex = 0;
3277+ searchField.text = ""
3278+ }
3279+ }
3280+ }
3281+ }
3282+
3283+ Scrollbar {
3284+ flickableItem: resultsView
3285 }
3286 }
3287
3288
3289=== renamed file 'app/ui/SettingsTab.qml' => 'app/ui/SettingsPage.qml'
3290--- app/ui/SettingsTab.qml 2015-03-27 15:38:43 +0000
3291+++ app/ui/SettingsPage.qml 2015-04-11 21:39:04 +0000
3292@@ -20,98 +20,131 @@
3293 import Ubuntu.Components 1.1
3294 import Ubuntu.Components.ListItems 1.0 as ListItem
3295
3296-Tab {
3297- id: tab
3298-
3299- title: i18n.tr("Settings")
3300-
3301- page: Page {
3302- id: settingsPage
3303-
3304- ListModel {
3305- id: themeModel
3306- Component.onCompleted: initialize()
3307- function initialize() {
3308- themeModel.append({ name: i18n.tr("Light"), file: "Light.qml" })
3309- themeModel.append({ name: i18n.tr("Dark"), file: "Dark.qml" })
3310- }
3311- }
3312-
3313- ListModel {
3314- id: cleanupModel
3315- Component.onCompleted: initialize()
3316- function initialize() {
3317- cleanupModel.append({ name: i18n.tr("Never"), value: -1 })
3318- cleanupModel.append({ name: i18n.tr("7 days"), value: 7 })
3319- cleanupModel.append({ name: i18n.tr("31 days"), value: 31 })
3320- cleanupModel.append({ name: i18n.tr("90 days"), value: 90 })
3321- cleanupModel.append({ name: i18n.tr("180 days"), value: 180 })
3322- cleanupModel.append({ name: i18n.tr("360 days"), value: 360 })
3323- }
3324- }
3325+Page {
3326+ id: settingsPage
3327+
3328+ Flickable {
3329+ id: flickable
3330+
3331+ anchors.fill: parent
3332+ contentHeight: settingsColumn.height + units.gu(8)
3333+ contentWidth: parent.width
3334
3335 Column {
3336 id: settingsColumn
3337
3338- anchors.fill: parent
3339-
3340- ExpandableListItem {
3341- id: themeSetting
3342-
3343- model: themeModel
3344+ anchors {
3345+ top: parent.top
3346+ left: parent.left
3347+ right: parent.right
3348+ }
3349+
3350+ ListItem.Header {
3351+ text: i18n.tr("General Settings")
3352+ }
3353+
3354+ ListItem.SingleValue {
3355+ progression: true
3356+ showDivider: false
3357 text: i18n.tr("Theme")
3358- subText: podbird.settings.themeName.split(".qml")[0]
3359-
3360- delegate: ListItem.Standard {
3361- text: model.name
3362-
3363- onClicked: {
3364- var themeElement = model.file
3365- podbird.settings.themeName = themeElement
3366- podbird.themeManager.source = themeElement
3367- themeSetting.expanded = false
3368- }
3369-
3370- Icon {
3371- width: units.gu(2)
3372- height: width
3373- name: "ok"
3374- visible: podbird.settings.themeName === model.file
3375- anchors.right: parent.right
3376- anchors.rightMargin: units.gu(2)
3377- anchors.verticalCenter: parent.verticalCenter
3378- }
3379- }
3380- }
3381-
3382- ExpandableListItem {
3383- id: cleanupSetting
3384-
3385- listViewHeight: units.gu(36)
3386- model: cleanupModel
3387- text: i18n.tr("Remove episodes older than")
3388- subText: podbird.settings.retentionDays === -1 ? i18n.tr("Never")
3389- : i18n.tr("%1 days").arg(podbird.settings.retentionDays)
3390-
3391- delegate: ListItem.Standard {
3392- text: model.name
3393-
3394- onClicked: {
3395- podbird.settings.retentionDays = model.value
3396- cleanupSetting.expanded = false
3397- }
3398-
3399- Icon {
3400- width: units.gu(2)
3401- height: width
3402- name: "ok"
3403- visible: podbird.settings.retentionDays === model.value
3404- anchors.right: parent.right
3405- anchors.rightMargin: units.gu(2)
3406- anchors.verticalCenter: parent.verticalCenter
3407- }
3408- }
3409+ value: podbird.settings.themeName.split(".qml")[0]
3410+ onClicked: mainStack.push(Qt.resolvedUrl("../settings/ThemeSetting.qml"))
3411+ }
3412+
3413+ ListItem.Header {
3414+ text: i18n.tr("Podcast Episode Settings")
3415+ }
3416+
3417+ ListItem.Standard {
3418+ showDivider: false
3419+ text: i18n.tr("Hide listened episodes")
3420+ control: Switch {
3421+ checked: podbird.settings.hideListened
3422+ onClicked: podbird.settings.hideListened = checked
3423+ }
3424+ }
3425+
3426+ ListItem.Base {
3427+ height: units.gu(10)
3428+ progression: true
3429+ showDivider: false
3430+ onClicked: mainStack.push(Qt.resolvedUrl("../settings/CleanSetting.qml"))
3431+ Column {
3432+ anchors.verticalCenter: parent.verticalCenter
3433+ anchors.right: parent.right
3434+ anchors.left: parent.left
3435+ Label {
3436+ width: parent.width
3437+ wrapMode: Text.WordWrap
3438+ text: i18n.tr("Automatically delete old episodes")
3439+ }
3440+
3441+ Label {
3442+ fontSize: "small"
3443+ color: podbird.theme.baseSubText
3444+ width: parent.width
3445+ wrapMode: Text.WordWrap
3446+ text: i18n.tr("Delete episodes that are older than a given number of days for each podcast")
3447+ }
3448+ }
3449+ }
3450+
3451+ ListItem.Base {
3452+ height: units.gu(10)
3453+ progression: true
3454+ showDivider: false
3455+ onClicked: mainStack.push(Qt.resolvedUrl("../settings/DownloadSetting.qml"))
3456+ Column {
3457+ anchors.verticalCenter: parent.verticalCenter
3458+ anchors.right: parent.right
3459+ anchors.left: parent.left
3460+ Label {
3461+ width: parent.width
3462+ wrapMode: Text.WordWrap
3463+ text: i18n.tr("Automatically download new episodes")
3464+ }
3465+
3466+ Label {
3467+ fontSize: "small"
3468+ color: podbird.theme.baseSubText
3469+ width: parent.width
3470+ wrapMode: Text.WordWrap
3471+ text: i18n.tr("Default number of new episodes to download for each podcast")
3472+ }
3473+ }
3474+ }
3475+
3476+ ListItem.Standard {
3477+ showDivider: false
3478+ text: i18n.tr("Auto download on WiFi only")
3479+ enabled: podbird.settings.maxEpisodeDownload !== -1
3480+ control: Switch {
3481+ checked: podbird.settings.onlyWifiDownload
3482+ onClicked: {
3483+ podbird.settings.onlyWifiDownload = checked
3484+ }
3485+ }
3486+ }
3487+
3488+ ListItem.Header {
3489+ text: i18n.tr("Misc.")
3490+ }
3491+
3492+ ListItem.Standard {
3493+ progression: true
3494+ showDivider: false
3495+ text: i18n.tr("About")
3496+ onClicked: mainStack.push(Qt.resolvedUrl("../settings/About.qml"))
3497+ }
3498+
3499+ ListItem.Standard {
3500+ progression: true
3501+ showDivider: false
3502+ text: i18n.tr("Report Bug")
3503+ onClicked: Qt.openUrlExternally("https://bugs.launchpad.net/podbird/+filebug")
3504 }
3505 }
3506 }
3507 }
3508+
3509+
3510
3511=== added file 'app/ui/Walkthrough.qml'
3512--- app/ui/Walkthrough.qml 1970-01-01 00:00:00 +0000
3513+++ app/ui/Walkthrough.qml 2015-04-11 21:39:04 +0000
3514@@ -0,0 +1,169 @@
3515+/*
3516+ * Copyright 2015 Nekhelesh Ramananthan (UCS)
3517+ *
3518+ * This file is part of Podbird.
3519+ *
3520+ * Podbird is free software; you can redistribute it and/or modify
3521+ * it under the terms of the GNU General Public License as published by
3522+ * the Free Software Foundation; version 3.
3523+ *
3524+ * Podbird is distributed in the hope that it will be useful,
3525+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3526+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3527+ * GNU General Public License for more details.
3528+ *
3529+ * You should have received a copy of the GNU General Public License
3530+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3531+ */
3532+
3533+import QtQuick 2.3
3534+import Ubuntu.Components 1.1
3535+import Ubuntu.Components.ListItems 1.0 as ListItem
3536+
3537+Page {
3538+ id: walkthrough
3539+
3540+ // Property to set the app name used in the walkthrough
3541+ property string appName
3542+
3543+ // Property to check if this is the first run or not
3544+ property bool isFirstRun: true
3545+
3546+ // Property to store the slides shown in the walkthrough (Each slide is a component defined in a separate file for simplicity)
3547+ property list<Component> model
3548+
3549+ // Property to set the color of bottom cirle to indicate the user's progress
3550+ property color completeColor: "green"
3551+
3552+ // Property to set the color of the bottom circle to indicate the slide still left to cover
3553+ property color inCompleteColor: "lightgrey"
3554+
3555+ // Property to set the color of the skip welcome wizard text
3556+ property color skipTextColor: "grey"
3557+
3558+ // Property to signal walkthrough completion
3559+ signal finished
3560+
3561+ // ListView to show the slides
3562+ ListView {
3563+ id: listView
3564+ anchors {
3565+ left: parent.left
3566+ right: parent.right
3567+ top: skipLabel.bottom
3568+ bottom: slideIndicator.top
3569+ }
3570+
3571+ model: walkthrough.model
3572+ snapMode: ListView.SnapOneItem
3573+ orientation: Qt.Horizontal
3574+ highlightMoveDuration: UbuntuAnimation.FastDuration
3575+ highlightRangeMode: ListView.StrictlyEnforceRange
3576+ highlightFollowsCurrentItem: true
3577+
3578+ delegate: Item {
3579+ width: listView.width
3580+ height: listView.height
3581+ clip: true
3582+
3583+ Loader {
3584+ anchors {
3585+ fill: parent
3586+ margins: units.gu(2)
3587+ }
3588+
3589+ sourceComponent: modelData
3590+ }
3591+ }
3592+ }
3593+
3594+ // Label to skip the walkthrough. Only visible on the first slide
3595+ Label {
3596+ id: skipLabel
3597+
3598+ color: skipTextColor
3599+ fontSize: "small"
3600+ wrapMode: Text.WordWrap
3601+ text: i18n.tr("Skip")
3602+ horizontalAlignment: Text.AlignRight
3603+
3604+ anchors {
3605+ top: parent.top
3606+ left: parent.left
3607+ right: parent.right
3608+ margins: units.gu(2)
3609+ }
3610+
3611+ MouseArea {
3612+ anchors.fill: parent
3613+ onClicked: walkthrough.finished()
3614+ }
3615+ }
3616+
3617+ // Indicator element to represent the current slide of the walkthrough
3618+ Row {
3619+ id: slideIndicator
3620+ height: units.gu(6)
3621+ spacing: units.gu(2)
3622+ anchors {
3623+ bottom: parent.bottom
3624+ horizontalCenter: parent.horizontalCenter
3625+ }
3626+
3627+ Repeater {
3628+ model: walkthrough.model.length
3629+ delegate: Rectangle {
3630+ height: width
3631+ radius: width/2
3632+ width: units.gu(2)
3633+ antialiasing: true
3634+ border.width: listView.currentIndex == index ? units.gu(0.2) : units.gu(0)
3635+ border.color: completeColor
3636+ anchors.verticalCenter: parent.verticalCenter
3637+ color: listView.currentIndex == index ? "White"
3638+ : listView.currentIndex >= index ? completeColor
3639+ : inCompleteColor
3640+ Behavior on color {
3641+ ColorAnimation {
3642+ duration: UbuntuAnimation.FastDuration
3643+ }
3644+ }
3645+ }
3646+ }
3647+ }
3648+
3649+ ActionButton {
3650+ id: rightchevron
3651+
3652+ width: units.gu(6)
3653+ height: units.gu(6)
3654+
3655+ anchors {
3656+ bottom: parent.bottom
3657+ right: parent.right
3658+ }
3659+
3660+ iconName: "chevron"
3661+ visible: enabled
3662+ enabled: listView.currentIndex !== listView.count-1
3663+ onClicked: listView.currentIndex++
3664+ }
3665+
3666+ ActionButton {
3667+ id: leftchevron
3668+
3669+ width: units.gu(6)
3670+ height: units.gu(6)
3671+
3672+ anchors {
3673+ bottom: parent.bottom
3674+ left: parent.left
3675+ }
3676+
3677+ iconName: "chevron"
3678+ rotation: 180
3679+ visible: enabled
3680+ enabled: listView.currentIndex !== 0
3681+ onClicked: listView.currentIndex--
3682+ }
3683+}
3684
3685=== added directory 'app/welcomewizard'
3686=== added file 'app/welcomewizard/CMakeLists.txt'
3687--- app/welcomewizard/CMakeLists.txt 1970-01-01 00:00:00 +0000
3688+++ app/welcomewizard/CMakeLists.txt 2015-04-11 21:39:04 +0000
3689@@ -0,0 +1,8 @@
3690+file(GLOB WELCOMEWIZARD_QML_JS_FILES *.qml *.js)
3691+
3692+# Make the files visible in the qtcreator tree
3693+add_custom_target(podbird_welcomewizard_QMlFiles ALL SOURCES ${WELCOMEWIZARD_QML_JS_FILES})
3694+
3695+install(FILES ${WELCOMEWIZARD_QML_JS_FILES} DESTINATION ${PODBIRD_DIR}/welcomewizard)
3696+
3697+
3698
3699=== added file 'app/welcomewizard/Slide1.qml'
3700--- app/welcomewizard/Slide1.qml 1970-01-01 00:00:00 +0000
3701+++ app/welcomewizard/Slide1.qml 2015-04-11 21:39:04 +0000
3702@@ -0,0 +1,76 @@
3703+/*
3704+ * Copyright 2015 Podbird Team
3705+ *
3706+ * This file is part of Podbird.
3707+ *
3708+ * Podbird is free software; you can redistribute it and/or modify
3709+ * it under the terms of the GNU General Public License as published by
3710+ * the Free Software Foundation; version 3.
3711+ *
3712+ * Podbird is distributed in the hope that it will be useful,
3713+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3714+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3715+ * GNU General Public License for more details.
3716+ *
3717+ * You should have received a copy of the GNU General Public License
3718+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3719+ */
3720+
3721+import QtQuick 2.3
3722+import Ubuntu.Components 1.1
3723+
3724+// Slide 1
3725+Component {
3726+ id: slide1
3727+ Item {
3728+ id: slide1Container
3729+
3730+ Image {
3731+ anchors {
3732+ top: parent.top
3733+ bottom: introductionText.top
3734+ bottomMargin: units.gu(6)
3735+ horizontalCenter: parent.horizontalCenter
3736+ }
3737+ source: Qt.resolvedUrl("../graphics/podbird.png")
3738+ fillMode: Image.PreserveAspectFit
3739+ antialiasing: true
3740+ }
3741+
3742+ Label {
3743+ id: introductionText
3744+ text: i18n.tr("Welcome to Podbird")
3745+ fontSize: "x-large"
3746+ height: contentHeight
3747+ anchors.centerIn: parent
3748+ }
3749+
3750+ Label {
3751+ id: bodyText
3752+ text: i18n.tr("Enjoy your favourite podcasts with Podbird, the one and only podcast \
3753+manager for Ubuntu Touch.\n\nChirp Chirp..")
3754+ anchors.left: parent.left
3755+ anchors.right: parent.right
3756+ anchors.margins: units.gu(1)
3757+ anchors.top: introductionText.bottom
3758+ anchors.topMargin: units.gu(4)
3759+ anchors.bottom: swipeText.top
3760+ wrapMode: Text.WordWrap
3761+ horizontalAlignment: Text.AlignHCenter
3762+ }
3763+
3764+ Label {
3765+ id: swipeText
3766+ anchors.left: parent.left
3767+ anchors.right: parent.right
3768+ anchors.margins: units.gu(1)
3769+ anchors.bottom: parent.bottom
3770+ color: "grey"
3771+ fontSize: "small"
3772+ wrapMode: Text.WordWrap
3773+ horizontalAlignment: Text.AlignHCenter
3774+ text: i18n.tr("Swipe to move between Pages")
3775+
3776+ }
3777+ }
3778+}
3779
3780=== added file 'app/welcomewizard/Slide2.qml'
3781--- app/welcomewizard/Slide2.qml 1970-01-01 00:00:00 +0000
3782+++ app/welcomewizard/Slide2.qml 2015-04-11 21:39:04 +0000
3783@@ -0,0 +1,66 @@
3784+/*
3785+ * Copyright 2015 Podbird Team
3786+ *
3787+ * This file is part of Podbird.
3788+ *
3789+ * Podbird is free software; you can redistribute it and/or modify
3790+ * it under the terms of the GNU General Public License as published by
3791+ * the Free Software Foundation; version 3.
3792+ *
3793+ * Podbird is distributed in the hope that it will be useful,
3794+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3795+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3796+ * GNU General Public License for more details.
3797+ *
3798+ * You should have received a copy of the GNU General Public License
3799+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3800+ */
3801+
3802+import QtQuick 2.3
3803+import Ubuntu.Components 1.1
3804+
3805+// Slide 2
3806+Component {
3807+ id: slide2
3808+ Item {
3809+ id: slide1Container
3810+
3811+ Image {
3812+ anchors {
3813+ top: parent.top
3814+ bottom: introductionText.top
3815+ bottomMargin: units.gu(6)
3816+ horizontalCenter: parent.horizontalCenter
3817+ }
3818+ fillMode: Image.PreserveAspectFit
3819+ source: Qt.resolvedUrl("../graphics/discover.png")
3820+ }
3821+
3822+ Label {
3823+ id: introductionText
3824+ anchors.centerIn: parent
3825+ elide: Text.ElideRight
3826+ fontSize: "x-large"
3827+ maximumLineCount: 2
3828+ text: i18n.tr("Discover New Podcasts")
3829+ horizontalAlignment: Text.AlignHCenter
3830+ width: parent.width
3831+ wrapMode: Text.WordWrap
3832+ }
3833+
3834+ Label {
3835+ id: finalMessage
3836+ anchors {
3837+ top: introductionText.bottom
3838+ bottom: parent.bottom
3839+ left: parent.left
3840+ right: parent.right
3841+ margins: units.gu(1)
3842+ topMargin: units.gu(4)
3843+ }
3844+ horizontalAlignment: Text.AlignHCenter
3845+ text: i18n.tr("Podbird uses the Itunes database to provide access to a huge collections of podcasts. You can also add podcasts by URL.")
3846+ wrapMode: Text.WordWrap
3847+ }
3848+ }
3849+}
3850
3851=== added file 'app/welcomewizard/Slide3.qml'
3852--- app/welcomewizard/Slide3.qml 1970-01-01 00:00:00 +0000
3853+++ app/welcomewizard/Slide3.qml 2015-04-11 21:39:04 +0000
3854@@ -0,0 +1,67 @@
3855+/*
3856+ * Copyright 2015 Podbird Team
3857+ *
3858+ * This file is part of Podbird.
3859+ *
3860+ * Podbird is free software; you can redistribute it and/or modify
3861+ * it under the terms of the GNU General Public License as published by
3862+ * the Free Software Foundation; version 3.
3863+ *
3864+ * Podbird is distributed in the hope that it will be useful,
3865+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3866+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3867+ * GNU General Public License for more details.
3868+ *
3869+ * You should have received a copy of the GNU General Public License
3870+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3871+ */
3872+
3873+import QtQuick 2.3
3874+import Ubuntu.Components 1.1
3875+
3876+// Slide 3
3877+Component {
3878+ id: slide3
3879+ Item {
3880+ id: slide1Container
3881+
3882+ Image {
3883+ anchors {
3884+ top: parent.top
3885+ bottom: introductionText.top
3886+ bottomMargin: units.gu(6)
3887+ horizontalCenter: parent.horizontalCenter
3888+ }
3889+ fillMode: Image.PreserveAspectFit
3890+ source: Qt.resolvedUrl("../graphics/smart.png")
3891+ }
3892+
3893+ Label {
3894+ id: introductionText
3895+ anchors.centerIn: parent
3896+ elide: Text.ElideRight
3897+ fontSize: "x-large"
3898+ maximumLineCount: 2
3899+ text: i18n.tr("Smart Settings")
3900+ horizontalAlignment: Text.AlignHCenter
3901+ width: parent.width
3902+ wrapMode: Text.WordWrap
3903+ }
3904+
3905+ Label {
3906+ id: finalMessage
3907+ anchors {
3908+ top: introductionText.bottom
3909+ bottom: parent.bottom
3910+ left: parent.left
3911+ right: parent.right
3912+ margins: units.gu(1)
3913+ topMargin: units.gu(4)
3914+ }
3915+ horizontalAlignment: Text.AlignHCenter
3916+ text: i18n.tr("Podbird automatically downloads new episodes and cleans up old episodes. \
3917+As a power user you can also tweak these settings to suit your needs.")
3918+ wrapMode: Text.WordWrap
3919+ }
3920+ }
3921+}
3922
3923=== added file 'app/welcomewizard/Slide4.qml'
3924--- app/welcomewizard/Slide4.qml 1970-01-01 00:00:00 +0000
3925+++ app/welcomewizard/Slide4.qml 2015-04-11 21:39:04 +0000
3926@@ -0,0 +1,70 @@
3927+/*
3928+ * Copyright 2015 Podbird Team
3929+ *
3930+ * This file is part of Podbird.
3931+ *
3932+ * Podbird is free software; you can redistribute it and/or modify
3933+ * it under the terms of the GNU General Public License as published by
3934+ * the Free Software Foundation; version 3.
3935+ *
3936+ * Podbird is distributed in the hope that it will be useful,
3937+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3938+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3939+ * GNU General Public License for more details.
3940+ *
3941+ * You should have received a copy of the GNU General Public License
3942+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3943+ */
3944+
3945+import QtQuick 2.3
3946+import Ubuntu.Components 1.1
3947+
3948+// Slide 4
3949+Component {
3950+ id: slide4
3951+ Item {
3952+ id: slide1Container
3953+
3954+ Image {
3955+ anchors {
3956+ top: parent.top
3957+ bottom: introductionText.top
3958+ bottomMargin: units.gu(6)
3959+ horizontalCenter: parent.horizontalCenter
3960+ }
3961+ fillMode: Image.PreserveAspectFit
3962+ source: Qt.resolvedUrl("../graphics/language.png")
3963+ }
3964+
3965+ Label {
3966+ id: introductionText
3967+ anchors.centerIn: parent
3968+ elide: Text.ElideRight
3969+ fontSize: "x-large"
3970+ maximumLineCount: 2
3971+ // TRANSLATORS: This text should be in a language different from the language set by the user.
3972+ // For instance, if the app was in english, then it is appropriate to set this string as
3973+ // Hallo or Bonjour etc to symbolize the internationalization feature in podbird.
3974+ text: i18n.tr("Hallo! Bonjour!")
3975+ horizontalAlignment: Text.AlignHCenter
3976+ width: parent.width
3977+ wrapMode: Text.WordWrap
3978+ }
3979+
3980+ Label {
3981+ id: finalMessage
3982+ anchors {
3983+ top: introductionText.bottom
3984+ bottom: parent.bottom
3985+ left: parent.left
3986+ right: parent.right
3987+ margins: units.gu(1)
3988+ topMargin: units.gu(4)
3989+ }
3990+ horizontalAlignment: Text.AlignHCenter
3991+ text: i18n.tr("Podbird is available in over 15 languages and is translated by the \
3992+Ubuntu Translators community.")
3993+ wrapMode: Text.WordWrap
3994+ }
3995+ }
3996+}
3997
3998=== added file 'app/welcomewizard/Slide5.qml'
3999--- app/welcomewizard/Slide5.qml 1970-01-01 00:00:00 +0000
4000+++ app/welcomewizard/Slide5.qml 2015-04-11 21:39:04 +0000
4001@@ -0,0 +1,66 @@
4002+/*
4003+ * Copyright 2015 Podbird Team
4004+ *
4005+ * This file is part of Podbird.
4006+ *
4007+ * Podbird is free software; you can redistribute it and/or modify
4008+ * it under the terms of the GNU General Public License as published by
4009+ * the Free Software Foundation; version 3.
4010+ *
4011+ * Podbird is distributed in the hope that it will be useful,
4012+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4013+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4014+ * GNU General Public License for more details.
4015+ *
4016+ * You should have received a copy of the GNU General Public License
4017+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4018+ */
4019+
4020+import QtQuick 2.3
4021+import Ubuntu.Components 1.1
4022+
4023+// Slide 5
4024+Component {
4025+ id: slide5
4026+ Item {
4027+ id: slide1Container
4028+
4029+ Image {
4030+ anchors {
4031+ top: parent.top
4032+ bottom: introductionText.top
4033+ bottomMargin: units.gu(6)
4034+ horizontalCenter: parent.horizontalCenter
4035+ }
4036+ fillMode: Image.PreserveAspectFit
4037+ source: Qt.resolvedUrl("../graphics/support.png")
4038+ }
4039+
4040+ Label {
4041+ id: introductionText
4042+ anchors.centerIn: parent
4043+ elide: Text.ElideRight
4044+ fontSize: "x-large"
4045+ maximumLineCount: 2
4046+ text: i18n.tr("Support")
4047+ horizontalAlignment: Text.AlignHCenter
4048+ width: parent.width
4049+ wrapMode: Text.WordWrap
4050+ }
4051+
4052+ Label {
4053+ id: finalMessage
4054+ anchors {
4055+ top: introductionText.bottom
4056+ bottom: parent.bottom
4057+ left: parent.left
4058+ right: parent.right
4059+ margins: units.gu(1)
4060+ topMargin: units.gu(4)
4061+ }
4062+ horizontalAlignment: Text.AlignHCenter
4063+ text: i18n.tr("If you find any bugs or have any feature requests, let us know at our project page https://launchpad.net/podbird.")
4064+ wrapMode: Text.WordWrap
4065+ }
4066+ }
4067+}
4068
4069=== added file 'app/welcomewizard/Slide6.qml'
4070--- app/welcomewizard/Slide6.qml 1970-01-01 00:00:00 +0000
4071+++ app/welcomewizard/Slide6.qml 2015-04-11 21:39:04 +0000
4072@@ -0,0 +1,80 @@
4073+/*
4074+ * Copyright 2015 Podbird Team
4075+ *
4076+ * This file is part of Podbird.
4077+ *
4078+ * Podbird is free software; you can redistribute it and/or modify
4079+ * it under the terms of the GNU General Public License as published by
4080+ * the Free Software Foundation; version 3.
4081+ *
4082+ * Podbird is distributed in the hope that it will be useful,
4083+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4084+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4085+ * GNU General Public License for more details.
4086+ *
4087+ * You should have received a copy of the GNU General Public License
4088+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4089+ */
4090+
4091+import QtQuick 2.3
4092+import Ubuntu.Components 1.1
4093+
4094+// Slide 6
4095+Component {
4096+ id: slide6
4097+ Item {
4098+ id: slide1Container
4099+
4100+ Image {
4101+ anchors {
4102+ top: parent.top
4103+ bottom: introductionText.top
4104+ bottomMargin: units.gu(6)
4105+ horizontalCenter: parent.horizontalCenter
4106+ }
4107+ fillMode: Image.PreserveAspectFit
4108+ source: Qt.resolvedUrl("../graphics/gift.png")
4109+ }
4110+
4111+ Label {
4112+ id: introductionText
4113+ anchors.centerIn: parent
4114+ elide: Text.ElideRight
4115+ fontSize: "x-large"
4116+ maximumLineCount: 2
4117+ text: i18n.tr("Enjoy")
4118+ horizontalAlignment: Text.AlignHCenter
4119+ width: parent.width
4120+ wrapMode: Text.WordWrap
4121+ }
4122+
4123+ Label {
4124+ id: finalMessage
4125+ anchors {
4126+ top: introductionText.bottom
4127+ bottom: continueButton.top
4128+ left: parent.left
4129+ right: parent.right
4130+ margins: units.gu(1)
4131+ topMargin: units.gu(4)
4132+ }
4133+ horizontalAlignment: Text.AlignHCenter
4134+ text: i18n.tr("We hope you will enjoy using Podbird!")
4135+ wrapMode: Text.WordWrap
4136+ }
4137+
4138+ Button {
4139+ id: continueButton
4140+ anchors {
4141+ bottom: parent.bottom
4142+ bottomMargin: units.gu(3)
4143+ horizontalCenter: parent.horizontalCenter
4144+ }
4145+ height: units.gu(6)
4146+ width: parent.width/1.3
4147+ color: UbuntuColors.green
4148+ text: i18n.tr("Finish")
4149+ onClicked: finished()
4150+ }
4151+ }
4152+}
4153
4154=== added file 'app/welcomewizard/WelcomeWizard.qml'
4155--- app/welcomewizard/WelcomeWizard.qml 1970-01-01 00:00:00 +0000
4156+++ app/welcomewizard/WelcomeWizard.qml 2015-04-11 21:39:04 +0000
4157@@ -0,0 +1,41 @@
4158+/*
4159+ * Copyright 2015 Podbird Team
4160+ *
4161+ * This file is part of Podbird.
4162+ *
4163+ * Podbird is free software; you can redistribute it and/or modify
4164+ * it under the terms of the GNU General Public License as published by
4165+ * the Free Software Foundation; version 3.
4166+ *
4167+ * Podbird is distributed in the hope that it will be useful,
4168+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4169+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4170+ * GNU General Public License for more details.
4171+ *
4172+ * You should have received a copy of the GNU General Public License
4173+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4174+ */
4175+
4176+import QtQuick 2.3
4177+import Ubuntu.Components 1.1
4178+import "../ui"
4179+
4180+// Initial Walkthrough tutorial
4181+Walkthrough {
4182+ id: walkthrough
4183+ appName: "Podbird"
4184+ onFinished: {
4185+ console.log("[LOG]: Welcome tour complete")
4186+ settings.firstRun = false
4187+ mainStack.pop()
4188+ mainStack.push(tabs)
4189+ }
4190+ model: [
4191+ Slide1{},
4192+ Slide2{},
4193+ Slide3{},
4194+ Slide4{},
4195+ Slide5{},
4196+ Slide6{}
4197+ ]
4198+}
4199
4200=== modified file 'po/com.mikeasoft.podbird.pot'
4201--- po/com.mikeasoft.podbird.pot 2015-03-29 16:40:52 +0000
4202+++ po/com.mikeasoft.podbird.pot 2015-04-11 21:39:04 +0000
4203@@ -8,7 +8,7 @@
4204 msgstr ""
4205 "Project-Id-Version: \n"
4206 "Report-Msgid-Bugs-To: \n"
4207-"POT-Creation-Date: 2015-03-29 16:48+0100\n"
4208+"POT-Creation-Date: 2015-04-11 23:32+0200\n"
4209 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
4210 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
4211 "Language-Team: LANGUAGE <LL@li.org>\n"
4212@@ -18,72 +18,207 @@
4213 "Content-Transfer-Encoding: 8bit\n"
4214 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
4215
4216-#: ../app/ui/EpisodesPage.qml:85
4217+#. 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)
4218+#: ../app/podbird.qml:152
4219+msgid "podcasts listened today"
4220+msgstr ""
4221+
4222+#: ../app/podbird.qml:153
4223+msgid "No podcasts listened today"
4224+msgstr ""
4225+
4226+#: ../app/podbird.qml:210
4227+msgid "Find New Podcasts"
4228+msgstr ""
4229+
4230+#: ../app/podbird.qml:224
4231+msgid "Settings"
4232+msgstr ""
4233+
4234+#: ../app/settings/About.qml:8 ../app/settings/About.qml:11
4235+#: ../app/ui/SettingsPage.qml:136
4236+msgid "About"
4237+msgstr ""
4238+
4239+#: ../app/settings/About.qml:11
4240+msgid "Credits"
4241+msgstr ""
4242+
4243+#: ../app/settings/About.qml:65
4244+msgid "Released under the terms of the GNU GPL v3"
4245+msgstr ""
4246+
4247+#: ../app/settings/About.qml:74
4248+#, qt-format
4249+msgid "Source code available on %1"
4250+msgstr ""
4251+
4252+#: ../app/settings/About.qml:89
4253+msgid "Developers"
4254+msgstr ""
4255+
4256+#: ../app/settings/About.qml:103
4257+msgid "Designer"
4258+msgstr ""
4259+
4260+#: ../app/settings/About.qml:112
4261+msgid "Translators"
4262+msgstr ""
4263+
4264+#: ../app/settings/CleanSetting.qml:27
4265+msgid "Delete older than"
4266+msgstr ""
4267+
4268+#: ../app/settings/CleanSetting.qml:33 ../app/settings/DownloadSetting.qml:33
4269+msgid "Never"
4270+msgstr ""
4271+
4272+#: ../app/settings/CleanSetting.qml:34
4273+#, qt-format
4274+msgid "%1 day"
4275+msgid_plural "%1 days"
4276+msgstr[0] ""
4277+msgstr[1] ""
4278+
4279+#: ../app/settings/CleanSetting.qml:35 ../app/settings/CleanSetting.qml:36
4280+#: ../app/settings/CleanSetting.qml:37
4281+#, qt-format
4282+msgid "%1 month"
4283+msgid_plural "%1 months"
4284+msgstr[0] ""
4285+msgstr[1] ""
4286+
4287+#: ../app/settings/CleanSetting.qml:38
4288+#, qt-format
4289+msgid "%1 year"
4290+msgid_plural "%1 years"
4291+msgstr[0] ""
4292+msgstr[1] ""
4293+
4294+#: ../app/settings/DownloadSetting.qml:27
4295+msgid "Download at most"
4296+msgstr ""
4297+
4298+#: ../app/settings/DownloadSetting.qml:34
4299+#: ../app/settings/DownloadSetting.qml:35
4300+#: ../app/settings/DownloadSetting.qml:36
4301+#: ../app/settings/DownloadSetting.qml:37 ../app/ui/EpisodesPage.qml:463
4302+#, qt-format
4303+msgid "%1 episode"
4304+msgid_plural "%1 episodes"
4305+msgstr[0] ""
4306+msgstr[1] ""
4307+
4308+#: ../app/settings/ThemeSetting.qml:27 ../app/ui/SettingsPage.qml:49
4309+msgid "Theme"
4310+msgstr ""
4311+
4312+#: ../app/settings/ThemeSetting.qml:33
4313+msgid "Light"
4314+msgstr ""
4315+
4316+#: ../app/settings/ThemeSetting.qml:34
4317+msgid "Dark"
4318+msgstr ""
4319+
4320+#: ../app/ui/EpisodesPage.qml:33
4321+msgid "Podcast"
4322+msgstr ""
4323+
4324+#: ../app/ui/EpisodesPage.qml:89 ../app/ui/SearchPage.qml:55
4325 msgid "Search Episode"
4326 msgstr ""
4327
4328-#: ../app/ui/EpisodesPage.qml:94
4329+#: ../app/ui/EpisodesPage.qml:98
4330 msgid "Mark all listened"
4331 msgstr ""
4332
4333-#: ../app/ui/EpisodesPage.qml:105 ../app/ui/EpisodesPage.qml:153
4334+#: ../app/ui/EpisodesPage.qml:109 ../app/ui/EpisodesPage.qml:187
4335 msgid "Unsubscribe"
4336 msgstr ""
4337
4338-#: ../app/ui/EpisodesPage.qml:120 ../app/ui/PodcastsTab.qml:86
4339-#: ../app/ui/PodcastsTab.qml:109
4340+#: ../app/ui/EpisodesPage.qml:124 ../app/ui/PodcastsTab.qml:96
4341+#: ../app/ui/PodcastsTab.qml:119 ../app/ui/SearchPage.qml:69
4342 msgid "Back"
4343 msgstr ""
4344
4345-#: ../app/ui/EpisodesPage.qml:131
4346+#: ../app/ui/EpisodesPage.qml:136
4347 msgid "Search episode"
4348 msgstr ""
4349
4350-#: ../app/ui/EpisodesPage.qml:150
4351+#: ../app/ui/EpisodesPage.qml:184
4352 msgid "Unsubscribe Confirmation"
4353 msgstr ""
4354
4355-#: ../app/ui/EpisodesPage.qml:151
4356+#: ../app/ui/EpisodesPage.qml:185
4357 #, qt-format
4358 msgid "Are you sure you want to unsubscribe from <b>%1</b>?"
4359 msgstr ""
4360
4361-#: ../app/ui/EpisodesPage.qml:170
4362+#: ../app/ui/EpisodesPage.qml:204
4363 msgid "Cancel"
4364 msgstr ""
4365
4366-#: ../app/ui/EpisodesPage.qml:184
4367+#: ../app/ui/EpisodesPage.qml:258
4368+msgid "Delete local file"
4369+msgstr ""
4370+
4371+#: ../app/ui/EpisodesPage.qml:259
4372+msgid "Episode queued for download"
4373+msgstr ""
4374+
4375+#: ../app/ui/EpisodesPage.qml:260
4376+msgid "Download episode"
4377+msgstr ""
4378+
4379+#: ../app/ui/EpisodesPage.qml:336
4380+msgid "No more episodes"
4381+msgstr ""
4382+
4383+#: ../app/ui/EpisodesPage.qml:336
4384 msgid "No Episodes found"
4385 msgstr ""
4386
4387-#: ../app/ui/EpisodesPage.qml:185
4388+#: ../app/ui/EpisodesPage.qml:337
4389+msgid "All episodes have been listened to."
4390+msgstr ""
4391+
4392+#: ../app/ui/EpisodesPage.qml:337
4393 msgid "No episodes found matching the search term."
4394 msgstr ""
4395
4396-#: ../app/ui/EpisodesPage.qml:319
4397-#, no-c-format, qt-format
4398-msgid "%1h %2m"
4399-msgstr ""
4400-
4401-#: ../app/ui/EpisodesPage.qml:328
4402-#, no-c-format, qt-format
4403-msgid "%1h"
4404-msgstr ""
4405-
4406-#: ../app/ui/EpisodesPage.qml:336
4407-#, no-c-format, qt-format
4408-msgid "%1m"
4409+#: ../app/ui/EpisodesPage.qml:359
4410+#, no-c-format, qt-format
4411+msgid "%1 hr %2 min"
4412+msgstr ""
4413+
4414+#: ../app/ui/EpisodesPage.qml:368
4415+#, no-c-format, qt-format
4416+msgid "%1 hr"
4417+msgstr ""
4418+
4419+#: ../app/ui/EpisodesPage.qml:376
4420+#, no-c-format, qt-format
4421+msgid "%1 min"
4422+msgstr ""
4423+
4424+#: ../app/ui/EpisodesPage.qml:416
4425+msgid "Unheard"
4426+msgstr ""
4427+
4428+#: ../app/ui/EpisodesPage.qml:416
4429+msgid "Listened"
4430 msgstr ""
4431
4432 #: ../app/ui/NowPlayingPage.qml:28
4433 msgid "Now Playing"
4434 msgstr ""
4435
4436-#: ../app/ui/NowPlayingPage.qml:145
4437+#: ../app/ui/NowPlayingPage.qml:150
4438 msgid "-15s"
4439 msgstr ""
4440
4441-#: ../app/ui/NowPlayingPage.qml:204
4442+#: ../app/ui/NowPlayingPage.qml:209
4443 msgid "+15s"
4444 msgstr ""
4445
4446@@ -91,124 +226,207 @@
4447 msgid "Podcasts"
4448 msgstr ""
4449
4450-#: ../app/ui/PodcastsTab.qml:62
4451+#: ../app/ui/PodcastsTab.qml:64
4452 msgid "Add Podcast"
4453 msgstr ""
4454
4455-#: ../app/ui/PodcastsTab.qml:72
4456+#: ../app/ui/PodcastsTab.qml:74
4457 msgid "Search Podcast"
4458 msgstr ""
4459
4460-#: ../app/ui/PodcastsTab.qml:97
4461+#: ../app/ui/PodcastsTab.qml:83
4462+msgid "Grid View"
4463+msgstr ""
4464+
4465+#: ../app/ui/PodcastsTab.qml:83
4466+msgid "List View"
4467+msgstr ""
4468+
4469+#: ../app/ui/PodcastsTab.qml:107
4470 msgid "Search podcast"
4471 msgstr ""
4472
4473-#: ../app/ui/PodcastsTab.qml:120
4474+#: ../app/ui/PodcastsTab.qml:130
4475 msgid "Save Podcast"
4476 msgstr ""
4477
4478-#: ../app/ui/PodcastsTab.qml:133
4479+#: ../app/ui/PodcastsTab.qml:143
4480 msgid "Feed URL"
4481 msgstr ""
4482
4483-#: ../app/ui/PodcastsTab.qml:157
4484+#: ../app/ui/PodcastsTab.qml:167
4485 msgid "Unable to subscribe"
4486 msgstr ""
4487
4488-#: ../app/ui/PodcastsTab.qml:158
4489+#: ../app/ui/PodcastsTab.qml:168
4490 msgid "Please check the URL and try again"
4491 msgstr ""
4492
4493-#: ../app/ui/PodcastsTab.qml:160
4494+#: ../app/ui/PodcastsTab.qml:170
4495 msgid "Close"
4496 msgstr ""
4497
4498-#: ../app/ui/PodcastsTab.qml:172
4499+#: ../app/ui/PodcastsTab.qml:184
4500 msgid "No Podcast Subscriptions"
4501 msgstr ""
4502
4503-#: ../app/ui/PodcastsTab.qml:173
4504+#: ../app/ui/PodcastsTab.qml:185
4505 msgid "No Podcasts Found"
4506 msgstr ""
4507
4508-#: ../app/ui/PodcastsTab.qml:174
4509+#: ../app/ui/PodcastsTab.qml:186
4510 msgid ""
4511 "You haven't subscribed to any podcasts yet, visit the 'Find New Podcasts' "
4512 "page to add some."
4513 msgstr ""
4514
4515-#: ../app/ui/PodcastsTab.qml:175
4516+#: ../app/ui/PodcastsTab.qml:187 ../app/ui/SearchPage.qml:103
4517 msgid "No podcasts found matching the search term."
4518 msgstr ""
4519
4520-#: ../app/ui/PodcastsTab.qml:291
4521+#: ../app/ui/PodcastsTab.qml:217 ../app/ui/PodcastsTab.qml:337
4522 #, qt-format
4523 msgid "%1 unheard episode"
4524 msgid_plural "%1 unheard episodes"
4525 msgstr[0] ""
4526 msgstr[1] ""
4527
4528-#: ../app/ui/SearchTab.qml:27
4529-msgid "Find New Podcasts"
4530-msgstr ""
4531-
4532-#: ../app/ui/SearchTab.qml:42
4533+#: ../app/ui/SearchPage.qml:80
4534 msgid "Search..."
4535 msgstr ""
4536
4537-#: ../app/ui/SearchTab.qml:122
4538+#: ../app/ui/SearchPage.qml:102
4539+msgid "Looking for a new Podcast?"
4540+msgstr ""
4541+
4542+#: ../app/ui/SearchPage.qml:102
4543+msgid "No Podcasts found"
4544+msgstr ""
4545+
4546+#: ../app/ui/SearchPage.qml:103
4547+msgid "Click the 'magnifier' at the top to search."
4548+msgstr ""
4549+
4550+#: ../app/ui/SearchPage.qml:184
4551 msgid "Subscribe"
4552 msgstr ""
4553
4554-#: ../app/ui/SettingsTab.qml:26
4555-msgid "Settings"
4556-msgstr ""
4557-
4558-#: ../app/ui/SettingsTab.qml:35
4559-msgid "Light"
4560-msgstr ""
4561-
4562-#: ../app/ui/SettingsTab.qml:36
4563-msgid "Dark"
4564-msgstr ""
4565-
4566-#: ../app/ui/SettingsTab.qml:44 ../app/ui/SettingsTab.qml:93
4567-msgid "Never"
4568-msgstr ""
4569-
4570-#: ../app/ui/SettingsTab.qml:45
4571-msgid "7 days"
4572-msgstr ""
4573-
4574-#: ../app/ui/SettingsTab.qml:46
4575-msgid "31 days"
4576-msgstr ""
4577-
4578-#: ../app/ui/SettingsTab.qml:47
4579-msgid "90 days"
4580-msgstr ""
4581-
4582-#: ../app/ui/SettingsTab.qml:48
4583-msgid "180 days"
4584-msgstr ""
4585-
4586-#: ../app/ui/SettingsTab.qml:49
4587-msgid "360 days"
4588-msgstr ""
4589-
4590-#: ../app/ui/SettingsTab.qml:62
4591-msgid "Theme"
4592-msgstr ""
4593-
4594-#: ../app/ui/SettingsTab.qml:92
4595-msgid "Remove episodes older than"
4596-msgstr ""
4597-
4598-#: ../app/ui/SettingsTab.qml:94
4599-#, qt-format
4600-msgid "%1 days"
4601-msgstr ""
4602-
4603-#: /home/mike/src/build-podbird-Ubuntu_Device_GCC_armhf_ubuntu_sdk_14_10_utopic-Default/po/Podbird.desktop.in.h:1
4604+#: ../app/ui/SettingsPage.qml:43
4605+msgid "General Settings"
4606+msgstr ""
4607+
4608+#: ../app/ui/SettingsPage.qml:55
4609+msgid "Podcast Episode Settings"
4610+msgstr ""
4611+
4612+#: ../app/ui/SettingsPage.qml:60
4613+msgid "Hide listened episodes"
4614+msgstr ""
4615+
4616+#: ../app/ui/SettingsPage.qml:79
4617+msgid "Automatically delete old episodes"
4618+msgstr ""
4619+
4620+#: ../app/ui/SettingsPage.qml:87
4621+msgid ""
4622+"Delete episodes that are older than a given number of days for each podcast"
4623+msgstr ""
4624+
4625+#: ../app/ui/SettingsPage.qml:104
4626+msgid "Automatically download new episodes"
4627+msgstr ""
4628+
4629+#: ../app/ui/SettingsPage.qml:112
4630+msgid "Default number of new episodes to download for each podcast"
4631+msgstr ""
4632+
4633+#: ../app/ui/SettingsPage.qml:119
4634+msgid "Auto download on WiFi only"
4635+msgstr ""
4636+
4637+#: ../app/ui/SettingsPage.qml:130
4638+msgid "Misc."
4639+msgstr ""
4640+
4641+#: ../app/ui/SettingsPage.qml:143
4642+msgid "Report Bug"
4643+msgstr ""
4644+
4645+#: ../app/ui/Walkthrough.qml:87
4646+msgid "Skip"
4647+msgstr ""
4648+
4649+#: ../app/welcomewizard/Slide1.qml:42
4650+msgid "Welcome to Podbird"
4651+msgstr ""
4652+
4653+#: ../app/welcomewizard/Slide1.qml:50
4654+msgid ""
4655+"Enjoy your favourite podcasts with Podbird, the one and only podcast manager "
4656+"for Ubuntu Touch.\n"
4657+"\n"
4658+"Chirp Chirp.."
4659+msgstr ""
4660+
4661+#: ../app/welcomewizard/Slide1.qml:72
4662+msgid "Swipe to move between Pages"
4663+msgstr ""
4664+
4665+#: ../app/welcomewizard/Slide2.qml:45
4666+msgid "Discover New Podcasts"
4667+msgstr ""
4668+
4669+#: ../app/welcomewizard/Slide2.qml:62
4670+msgid ""
4671+"Podbird uses the Itunes database to provide access to a huge collections of "
4672+"podcasts. You can also add podcasts by URL."
4673+msgstr ""
4674+
4675+#: ../app/welcomewizard/Slide3.qml:45
4676+msgid "Smart Settings"
4677+msgstr ""
4678+
4679+#: ../app/welcomewizard/Slide3.qml:62
4680+msgid ""
4681+"Podbird automatically downloads new episodes and cleans up old episodes. As "
4682+"a power user you can also tweak these settings to suit your needs."
4683+msgstr ""
4684+
4685+#. TRANSLATORS: This text should be in a language different from the language set by the user.
4686+#. For instance, if the app was in english, then it is appropriate to set this string as
4687+#. Hallo or Bonjour etc to symbolize the internationalization feature in podbird.
4688+#: ../app/welcomewizard/Slide4.qml:48
4689+msgid "Hallo! Bonjour!"
4690+msgstr ""
4691+
4692+#: ../app/welcomewizard/Slide4.qml:65
4693+msgid ""
4694+"Podbird is available in over 15 languages and is translated by the Ubuntu "
4695+"Translators community."
4696+msgstr ""
4697+
4698+#: ../app/welcomewizard/Slide5.qml:45
4699+msgid "Support"
4700+msgstr ""
4701+
4702+#: ../app/welcomewizard/Slide5.qml:62
4703+msgid ""
4704+"If you find any bugs or have any feature requests, let us know at our "
4705+"project page https://launchpad.net/podbird."
4706+msgstr ""
4707+
4708+#: ../app/welcomewizard/Slide6.qml:45
4709+msgid "Enjoy"
4710+msgstr ""
4711+
4712+#: ../app/welcomewizard/Slide6.qml:62
4713+msgid "We hope you will enjoy using Podbird!"
4714+msgstr ""
4715+
4716+#: ../app/welcomewizard/Slide6.qml:76
4717+msgid "Finish"
4718+msgstr ""
4719+
4720+#: /home/krnekhelesh/Documents/Ubuntu-Projects/MP-Reviews/builddir/build-8.6-aboutpage-UbuntuSDK_for_armhf_GCC_ubuntu_sdk_14_10_utopic-Default/po/Podbird.desktop.in.h:1
4721 msgid "Podbird"
4722 msgstr ""
4723
4724=== added file 'podbird.png'
4725Binary files podbird.png 1970-01-01 00:00:00 +0000 and podbird.png 2015-04-11 21:39:04 +0000 differ

Subscribers

People subscribed via source and target branches