Merge lp:~stolowski/unity-lens-shopping/u1ms-preview into lp:unity-lens-shopping

Proposed by Paweł Stołowski
Status: Merged
Approved by: Paweł Stołowski
Approved revision: 27
Merged at revision: 21
Proposed branch: lp:~stolowski/unity-lens-shopping/u1ms-preview
Merge into: lp:unity-lens-shopping
Diff against target: 431 lines (+350/-24)
6 files modified
po/POTFILES.in (+2/-0)
po/POTFILES.skip (+2/-0)
src/Makefile.am (+2/-0)
src/preview-player-client.vala (+112/-0)
src/scope.vala (+38/-24)
src/u1ms-preview.vala (+194/-0)
To merge this branch: bzr merge lp:~stolowski/unity-lens-shopping/u1ms-preview
Reviewer Review Type Date Requested Status
Michal Hruby (community) Approve
Review via email: mp+126424@code.launchpad.net

This proposal supersedes a proposal from 2012-09-25.

Commit message

Reuse u1ms preview code from musicstore scope for u1ms results. The code has been refactored and copied over to have it isolated as much as possible in new classes/files. After Q we need to move it to a library and clean both shopping lens and musicstore scope.

Description of the change

Reuse u1ms preview code from musicstore scope for u1ms results. The code has been refactored and copied over to have it isolated as much as possible in new classes/files. After Q we need to move it to a library and clean both shopping lens and musicstore scope.

To post a comment you must log in.
Revision history for this message
Michal Hruby (mhr3) wrote : Posted in a previous version of this proposal

Can you please add huge WARNING / FIXME comment on the top saying that the file is a copy, and should be kept in sync with the original / moved in a common lib.

Otherwise looks and works fine.

Revision history for this message
Michal Hruby (mhr3) wrote : Posted in a previous version of this proposal

+1

review: Approve
Revision history for this message
Michal Hruby (mhr3) wrote : Posted in a previous version of this proposal

Oh actually POTFILES need update, make check fails.

review: Needs Fixing
Revision history for this message
Paweł Stołowski (stolowski) wrote : Posted in a previous version of this proposal

Fixed.

Revision history for this message
Unity Merger (unity-merger) wrote : Posted in a previous version of this proposal

There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.

Revision history for this message
Michal Hruby (mhr3) :
review: Approve
Revision history for this message
Unity Merger (unity-merger) wrote :

No commit message specified.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'po/POTFILES.in'
2--- po/POTFILES.in 2012-07-25 13:07:48 +0000
3+++ po/POTFILES.in 2012-09-26 10:14:27 +0000
4@@ -1,5 +1,7 @@
5 [encoding: UTF-8]
6 src/daemon.vala
7 src/main.vala
8+src/u1ms-preview.vala
9+src/scope.vala
10 [type: gettext/ini]shopping.lens.in.in
11
12
13=== modified file 'po/POTFILES.skip'
14--- po/POTFILES.skip 2012-09-17 21:39:10 +0000
15+++ po/POTFILES.skip 2012-09-26 10:14:27 +0000
16@@ -5,3 +5,5 @@
17 src/banshee-scope.c
18 src/rhythmbox-scope.c
19 src/scope.c
20+src/preview-player-client.c
21+src/u1ms-preview.c
22
23=== modified file 'src/Makefile.am'
24--- src/Makefile.am 2012-09-17 18:04:15 +0000
25+++ src/Makefile.am 2012-09-26 10:14:27 +0000
26@@ -44,6 +44,8 @@
27 main.vala \
28 scope.vala \
29 markup-cleaner.vala \
30+ preview-player-client.vala \
31+ u1ms-preview.vala \
32 $(NULL)
33
34 unity_shopping_daemon_SOURCES = \
35
36=== added file 'src/preview-player-client.vala'
37--- src/preview-player-client.vala 1970-01-01 00:00:00 +0000
38+++ src/preview-player-client.vala 2012-09-26 10:14:27 +0000
39@@ -0,0 +1,112 @@
40+/*
41+ * Copyright (C) 2012 Canonical Ltd
42+ *
43+ * This program is free software: you can redistribute it and/or modify
44+ * it under the terms of the GNU General Public License version 3 as
45+ * published by the Free Software Foundation.
46+ *
47+ * This program is distributed in the hope that it will be useful,
48+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
49+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50+ * GNU General Public License for more details.
51+ *
52+ * You should have received a copy of the GNU General Public License
53+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
54+ *
55+ * Authored by Pawel Stolowski <pawel.stolowski@canonical.com>
56+ */
57+
58+
59+/*
60+ * FIXME: this code was copied from music-lens; it needs to be kept in sync and eventually moved to a library !!!
61+ */
62+namespace Unity.ShoppingLens {
63+
64+ static const string PREVIEW_PLAYER_DBUS_NAME = "com.canonical.Unity.Lens.Music.PreviewPlayer";
65+ static const string PREVIEW_PLAYER_DBUS_PATH = "/com/canonical/Unity/Lens/Music/PreviewPlayer";
66+
67+ [DBus (name = "com.canonical.Unity.Lens.Music.PreviewPlayer")]
68+ public interface PreviewPlayerService: GLib.Object
69+ {
70+ public signal void progress(string uri, uint32 state, double progress);
71+
72+ public abstract async void play (string uri) throws Error;
73+ public abstract async void pause () throws Error;
74+ public abstract async void pause_resume () throws Error;
75+ public abstract async void resume () throws Error;
76+ public abstract async void stop () throws Error;
77+ public abstract async void close () throws Error;
78+ }
79+
80+ public class PreviewPlayer: GLib.Object
81+ {
82+ public signal void progress(string uri, Unity.MusicPreview.TrackState state, double progress);
83+
84+ public async void connect_to () throws Error
85+ {
86+ _preview_player_service = Bus.get_proxy_sync (BusType.SESSION, PREVIEW_PLAYER_DBUS_NAME, PREVIEW_PLAYER_DBUS_PATH);
87+ _preview_player_service.progress.connect (on_progress_signal);
88+ }
89+
90+ public async void play (string uri) throws Error
91+ {
92+ if (_preview_player_service == null)
93+ {
94+ yield connect_to ();
95+ }
96+ yield _preview_player_service.play (uri);
97+ }
98+
99+ public async void pause () throws Error
100+ {
101+ if (_preview_player_service == null)
102+ {
103+ yield connect_to ();
104+ }
105+ yield _preview_player_service.pause ();
106+ }
107+
108+ public async void pause_resume () throws Error
109+ {
110+ if (_preview_player_service == null)
111+ {
112+ yield connect_to ();
113+ }
114+ yield _preview_player_service.pause_resume ();
115+ }
116+
117+ public async void resume () throws Error
118+ {
119+ if (_preview_player_service == null)
120+ {
121+ yield connect_to ();
122+ }
123+ yield _preview_player_service.resume ();
124+ }
125+
126+ public async void stop () throws Error
127+ {
128+ if (_preview_player_service == null)
129+ {
130+ yield connect_to ();
131+ }
132+ yield _preview_player_service.stop ();
133+ }
134+
135+ public async void close () throws Error
136+ {
137+ if (_preview_player_service == null)
138+ {
139+ yield connect_to ();
140+ }
141+ yield _preview_player_service.close ();
142+ }
143+
144+ internal void on_progress_signal (string uri, uint32 state, double progress_value)
145+ {
146+ progress(uri, (Unity.MusicPreview.TrackState)state, progress_value);
147+ }
148+
149+ private PreviewPlayerService _preview_player_service;
150+ }
151+}
152\ No newline at end of file
153
154=== modified file 'src/scope.vala'
155--- src/scope.vala 2012-09-20 11:00:09 +0000
156+++ src/scope.vala 2012-09-26 10:14:27 +0000
157@@ -27,6 +27,7 @@
158
159 private HashTable<string, string> results_details_map;
160 private HashTable<string, string> global_results_details_map;
161+ private PreviewPlayerHandler player;
162
163 public ShoppingScope ()
164 {
165@@ -136,30 +137,43 @@
166 {
167 var parser = get_json_reply (details_uri, null);
168
169- var root = parser.get_root ().get_object ();
170- unowned string title = root.get_string_member ("title");
171- unowned string description = root.get_string_member ("description_html");
172- unowned string price = root.get_string_member ("formatted_price");
173- if (price == null) price = root.get_string_member ("price");
174-
175- var img_obj = root.get_object_member ("images");
176- string image_uri = extract_image_uri (img_obj, int.MAX);
177-
178- Icon? image = null;
179- if (image_uri != "")
180- {
181- image = new FileIcon (File.new_for_uri (image_uri));
182- }
183-
184- var preview = new GenericPreview (title, MarkupCleaner.html_to_pango_markup (description), image);
185- var icon_dir = File.new_for_path (ICON_PATH);
186- var icon = new FileIcon (icon_dir.get_child ("service-amazon.svg"));
187- var buy_action = new PreviewAction ("buy", _("Buy"), icon);
188- if (price != null) buy_action.extra_text = price;
189- /* Leaving the activation on unity for now */
190- // buy_action.activated.connect ((uri) => { });
191- preview.add_action (buy_action);
192- return preview;
193+ if (U1MSPreviewFactory.is_u1ms_details (parser))
194+ {
195+ var u1mspf = new U1MSPreviewFactory ();
196+ var preview = u1mspf.create_preview (parser);
197+ u1mspf.add_download_action (preview); // download will be handled by normal activation
198+ if (player == null)
199+ player = new PreviewPlayerHandler ();
200+ player.music_preview = preview;
201+ return preview;
202+ }
203+ else
204+ {
205+ var root = parser.get_root ().get_object ();
206+ unowned string title = root.get_string_member ("title");
207+ unowned string description = root.get_string_member ("description_html");
208+ unowned string price = root.get_string_member ("formatted_price");
209+ if (price == null) price = root.get_string_member ("price");
210+
211+ var img_obj = root.get_object_member ("images");
212+ string image_uri = extract_image_uri (img_obj, int.MAX);
213+
214+ Icon? image = null;
215+ if (image_uri != "")
216+ {
217+ image = new FileIcon (File.new_for_uri (image_uri));
218+ }
219+
220+ var preview = new GenericPreview (title, MarkupCleaner.html_to_pango_markup (description), image);
221+ var icon_dir = File.new_for_path (ICON_PATH);
222+ var icon = new FileIcon (icon_dir.get_child ("service-amazon.svg"));
223+ var buy_action = new PreviewAction ("buy", _("Buy"), icon);
224+ if (price != null) buy_action.extra_text = price;
225+ /* Leaving the activation on unity for now */
226+ // buy_action.activated.connect ((uri) => { });
227+ preview.add_action (buy_action);
228+ return preview;
229+ }
230 }
231 catch (Error err)
232 {
233
234=== added file 'src/u1ms-preview.vala'
235--- src/u1ms-preview.vala 1970-01-01 00:00:00 +0000
236+++ src/u1ms-preview.vala 2012-09-26 10:14:27 +0000
237@@ -0,0 +1,194 @@
238+/*
239+ * Copyright (C) 2011 Canonical, Ltd.
240+ *
241+ * This library is free software; you can redistribute it and/or modify
242+ * it under the terms of the GNU Lesser General Public License
243+ * version 3.0 as published by the Free Software Foundation.
244+ *
245+ * This library is distributed in the hope that it will be useful,
246+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
247+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
248+ * GNU Lesser General Public License version 3.0 for more details.
249+ *
250+ * You should have received a copy of the GNU Lesser General Public
251+ * License along with this library. If not, see
252+ * <http://www.gnu.org/licenses/>.
253+ *
254+ * Authored by Pawel Stolowski <pawel.stolowski@canonical.com>
255+ *
256+ */
257+
258+/*
259+ * FIXME: this code is based on musicstore-scope preview handling code; it needs to be kept in sync and eventually moved to a library !!!
260+ */
261+namespace Unity.ShoppingLens
262+{
263+
264+ public class PreviewPlayerHandler
265+ {
266+ private PreviewPlayer preview_player;
267+ private Unity.MusicPreview music_preview_;
268+
269+ public Unity.MusicPreview music_preview
270+ {
271+ get
272+ {
273+ return music_preview_;
274+ }
275+ set
276+ {
277+ music_preview_ = value;
278+ if (value != null)
279+ {
280+ music_preview.play.connect (play);
281+ music_preview.pause.connect (pause);
282+ music_preview.closed.connect (closed);
283+ }
284+ }
285+ }
286+
287+ public PreviewPlayerHandler (Unity.MusicPreview? preview = null)
288+ {
289+ music_preview = preview;
290+ }
291+
292+ private void on_progress_changed (string uri, Unity.MusicPreview.TrackState state, double progress)
293+ {
294+ if (music_preview != null)
295+ {
296+ music_preview.current_track_uri = uri;
297+ music_preview.current_track_state = state;
298+ music_preview.current_progress = (float)progress;
299+ }
300+ }
301+
302+ private void closed (Unity.Preview preview)
303+ {
304+ if (preview_player != null)
305+ {
306+ try
307+ {
308+ preview_player.close ();
309+ }
310+ catch (Error e)
311+ {
312+ warning ("Failed to close preview player: %s", e.message);
313+ }
314+ }
315+ }
316+
317+ private void play (Unity.Preview preview, string uri)
318+ {
319+ debug ("play request: '%s'", uri);
320+
321+ try
322+ {
323+ if (preview_player == null)
324+ {
325+ preview_player = new PreviewPlayer ();
326+ preview_player.progress.connect (on_progress_changed);
327+ preview_player.connect_to ();
328+ }
329+
330+ // we will receive state back in on_progress_changed, but set it now so that it's immediately reflected in the dash
331+ music_preview.current_track_uri = uri;
332+ music_preview.current_progress = 0.0f;
333+ music_preview.current_track_state = Unity.MusicPreview.TrackState.PLAYING;
334+
335+ preview_player.play (uri);
336+ }
337+ catch (Error e)
338+ {
339+ warning ("Failed to play '%s': %s", uri, e.message);
340+ }
341+ }
342+
343+ public void pause (Unity.Preview preview, string uri)
344+ {
345+ debug ("pause request: '%s'", uri);
346+
347+ try
348+ {
349+ if (preview_player != null)
350+ {
351+ // we will receive state back in on_progress_changed, but set it now so that it's immediately reflected in the dash
352+ music_preview.current_track_uri = uri;
353+ music_preview.current_track_state = Unity.MusicPreview.TrackState.PAUSED;
354+
355+ preview_player.pause ();
356+ }
357+ }
358+ catch (Error e)
359+ {
360+ warning ("Failed to pause '%s': %s", uri, e.message);
361+ }
362+ }
363+ }
364+
365+
366+ public class U1MSPreviewFactory
367+ {
368+ public string formatted_price { get; internal set; }
369+
370+ public static bool is_u1ms_details (Json.Parser parser)
371+ {
372+ var root_obj = parser.get_root ().get_object ();
373+ return root_obj.has_member ("source") && root_obj.get_string_member ("source") == "Ubuntu One Music Store" && root_obj.has_member ("tracks");
374+ }
375+
376+ public Unity.MusicPreview? create_preview (Json.Parser parser)
377+ {
378+ var root_obj = parser.get_root ().get_object ();
379+
380+ var title = root_obj.get_string_member ("title");
381+ var artwork_path = root_obj.get_string_member ("image");
382+ File cover_file = File.new_for_uri (artwork_path); //artwork path is a remote uri
383+ var cover = new FileIcon (cover_file);
384+
385+ var artist = root_obj.get_string_member ("artist");
386+
387+ var preview = new Unity.MusicPreview (title, artist, cover);
388+
389+ if (root_obj.has_member ("formatted_price"))
390+ formatted_price = root_obj.get_string_member ("formatted_price");
391+ else
392+ formatted_price = "";
393+
394+ if (root_obj.has_member ("tracks"))
395+ {
396+ var tracks_node = root_obj.get_array_member ("tracks");
397+ int i = 1;
398+ foreach (var track_node in tracks_node.get_elements ())
399+ {
400+ var track_obj = track_node.get_object ();
401+ TrackMetadata tm = new TrackMetadata ();
402+ tm.uri = track_obj.get_string_member ("preview");
403+ tm.track_no = i++; //FIXME: u1ms search doesn't provide track numbers *yet*
404+ tm.title = track_obj.get_string_member ("title");
405+ tm.length = (int)track_obj.get_member ("duration").get_int ();
406+ preview.add_track (tm);
407+ }
408+ }
409+ else // details for single track
410+ {
411+ TrackMetadata tm = new TrackMetadata ();
412+ tm.uri = root_obj.get_string_member ("preview");
413+ tm.title = root_obj.get_string_member ("title");
414+ tm.length = (int)root_obj.get_member ("duration").get_int ();
415+ preview.add_track (tm);
416+ }
417+ return preview;
418+ }
419+
420+ public Unity.PreviewAction? add_download_action (Unity.MusicPreview preview)
421+ {
422+ GLib.Icon? icon = new GLib.FileIcon (File.new_for_path (Config.DATADIR + "/icons/unity-icon-theme/places/svg/service-u1.svg"));
423+ var download_action = new Unity.PreviewAction ("download_album", _("Download"), icon);
424+ if (formatted_price != null)
425+ download_action.extra_text = formatted_price;
426+ preview.add_action (download_action);
427+ return download_action;
428+ }
429+ }
430+
431+}

Subscribers

People subscribed via source and target branches