Download links
[jamaendo] / jamaui / ui.py
1 #!/usr/bin/env python
2 #
3 # This file is part of Jamaendo.
4 # Copyright (c) 2010 Kristoffer Gronlund
5 #
6 # Jamaendo is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # Jamaendo is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with Jamaendo.  If not, see <http://www.gnu.org/licenses/>.
18 #
19 # Player code heavily based on http://thpinfo.com/2008/panucci/:
20 #  A resuming media player for Podcasts and Audiobooks
21 #  Copyright (c) 2008-05-26 Thomas Perl <thpinfo.com>
22 #  (based on http://pygstdocs.berlios.de/pygst-tutorial/seeking.html)
23 #
24 # Jamaendo jamendo.com API wrapper licensed under the New BSD License;
25 # see module for details.
26 #
27
28 import os, sys
29 import gtk
30 import gobject
31 import util
32 import logging
33 from settings import settings
34
35 import ossohelper
36
37 gobject.threads_init()
38
39 log = logging.getLogger(__name__)
40
41 VERSION = '0.1'
42
43 try:
44     import hildon
45 except:
46     if util.platform == 'maemo':
47         log.critical('Using GTK widgets, install "python2.5-hildon" '
48             'for this to work properly.')
49     else:
50         log.critical('This ui only works in maemo')
51         sys.exit(1)
52
53 from dbus.mainloop.glib import DBusGMainLoop
54
55 DBusGMainLoop(set_as_default=True)
56
57 import jamaendo
58
59 from postoffice import postoffice
60 from playerwindow import open_playerwindow
61 from search import SearchWindow
62 from featured import FeaturedWindow
63 from radios import RadiosWindow
64 from favorites import FavoritesWindow
65
66 class PlaylistsWindow(hildon.StackableWindow):
67     def __init__(self):
68         hildon.StackableWindow.__init__(self)
69         self.set_title("Playlists")
70
71         label = gtk.Label("Playlists")
72         vbox = gtk.VBox(False, 0)
73         vbox.pack_start(label, True, True, 0)
74         self.add(vbox)
75
76 class Jamaui(object):
77     def __init__(self):
78         self.app = None
79         self.menu = None
80         self.window = None
81
82     def create_window(self):
83         self.app = hildon.Program()
84         self.window = hildon.StackableWindow()
85         self.app.add_window(self.window)
86
87         self.window.set_title("jamaendo")
88         self.window.connect("destroy", self.destroy)
89
90         self.CONFDIR = os.path.expanduser('~/MyDocs/.jamaendo')
91         jamaendo.set_cache_dir(self.CONFDIR)
92         settings.set_filename(os.path.join(self.CONFDIR, 'ui_settings'))
93         settings.load()
94
95         postoffice.connect('request-album-cover', self.on_request_cover)
96
97     def save_settings(self):
98         settings.save()
99
100     def create_menu(self):
101         self.menu = hildon.AppMenu()
102
103         #search = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
104         #search.set_label("Search")
105         #search.connect("clicked", self.on_search)
106         #self.menu.append(search)
107
108         #player = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
109         #player.set_label("Open player")
110         #player.connect("clicked", self.on_player)
111         #self.menu.append(player)
112
113         player = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
114         player.set_label("Favorites")
115         player.connect("clicked", self.on_favorites)
116         self.menu.append(player)
117
118         #player = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
119         #player.set_label("Playlists")
120         #player.connect("clicked", self.on_playlists)
121         #self.menu.append(player)
122
123         player = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
124         player.set_label("Settings")
125         player.connect("clicked", self.on_settings)
126         self.menu.append(player)
127
128
129         # Don't use localdb ATM
130         #refresh = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
131         #refresh.set_label("Refresh")
132         #refresh.connect("clicked", self.on_refresh)
133         #self.menu.append(refresh)
134
135         menu_about = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
136         menu_about.set_label("About")
137         menu_about.connect("clicked", self.show_about, self.window)
138         self.menu.append(menu_about)
139         gtk.about_dialog_set_url_hook(self.open_link, None)
140
141         self.menu.show_all()
142         self.window.set_app_menu(self.menu)
143
144
145     def setup_widgets(self):
146         bgimg = util.find_resource('bg.png')
147         if bgimg:
148             background, mask = gtk.gdk.pixbuf_new_from_file(bgimg).render_pixmap_and_mask()
149             self.window.realize()
150             self.window.window.set_back_pixmap(background, False)
151
152         bbox = gtk.HButtonBox()
153         alignment = gtk.Alignment(xalign=0.2, yalign=0.925, xscale=1.0)
154         alignment.add(bbox)
155         bbox.set_property('layout-style', gtk.BUTTONBOX_SPREAD)
156         self.bbox = bbox
157         self.window.add(alignment)
158
159         self.add_mainscreen_button("Featured", "Most listened to", self.on_featured)
160         self.add_mainscreen_button("Radios", "The best in free music", self.on_radios)
161         self.add_mainscreen_button("Search", "Search for artists/albums", self.on_search)
162
163         self.window.show_all()
164
165     def add_mainscreen_button(self, title, subtitle, callback):
166         btn = hildon.Button(gtk.HILDON_SIZE_THUMB_HEIGHT,
167                             hildon.BUTTON_ARRANGEMENT_VERTICAL)
168         btn.set_text(title, subtitle)
169         btn.set_property('width-request', 225)
170         btn.connect('clicked', callback)
171         self.bbox.add(btn)
172
173     def on_request_cover(self, albumid, size):
174         jamaendo.get_album_cover_async(self.got_album_cover, int(albumid), size)
175
176     def got_album_cover(self, albumid, size, cover):
177         postoffice.notify('album-cover', albumid, size, cover)
178
179     #def add_featured_button(self):
180     #    self.featured_sel = hildon.TouchSelector(text=True)
181     #    self.featured_sel.append_text("Albums of the week")
182     #    self.featured_sel.append_text("Tracks of the week")
183     #    self.featured_sel.append_text("New releases")
184     #    btn = hildon.PickerButton(gtk.HILDON_SIZE_THUMB_HEIGHT,
185     #                              hildon.BUTTON_ARRANGEMENT_VERTICAL)
186     #    btn.set_text("Featured", "Most listened to")
187     #    btn.set_property('width-request', 225)
188     #    btn.set_selector(self.featured_sel)
189     #    self.featured_btn = btn
190     #    self.bbox.add(btn)
191
192     def destroy(self, widget):
193         postoffice.disconnect('request-album-cover', self.on_request_cover)
194         gtk.main_quit()
195
196     def show_about(self, w, win):
197         dialog = gtk.AboutDialog()
198         dialog.set_program_name("jamaendo")
199         dialog.set_website("http://github.com/krig")
200         dialog.set_website_label("http://github.com/krig")
201         dialog.set_version(VERSION)
202         dialog.set_license("""Copyright (c) 2010, Kristoffer Gronlund
203 All rights reserved.
204
205 Redistribution and use in source and binary forms, with or without
206 modification, are permitted provided that the following conditions are met:
207      * Redistributions of source code must retain the above copyright
208        notice, this list of conditions and the following disclaimer.
209      * Redistributions in binary form must reproduce the above copyright
210        notice, this list of conditions and the following disclaimer in the
211        documentation and/or other materials provided with the distribution.
212      * Neither the name of Jamaendo nor the
213        names of its contributors may be used to endorse or promote products
214        derived from this software without specific prior written permission.
215
216 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
217 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
218 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
219 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
220 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
221 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
222 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
223 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
224 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
225 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
226 """)
227         dialog.set_authors(("Kristoffer Gronlund <kristoffer.gronlund@purplescout.se>",
228                             "Based on Panucci, written by Thomas Perl <thpinfo.com>"))
229         dialog.set_comments("""Jamaendo plays music from the music catalog of JAMENDO.
230
231 JAMENDO is an online platform that distributes musical works under Creative Commons licenses.""")
232         gtk.about_dialog_set_email_hook(self.open_link, dialog)
233         gtk.about_dialog_set_url_hook(self.open_link, dialog)
234         dialog.connect( 'response', lambda dlg, response: dlg.destroy())
235         for parent in dialog.vbox.get_children():
236             for child in parent.get_children():
237                 if isinstance(child, gtk.Label):
238                     child.set_selectable(False)
239                     child.set_alignment(0.0, 0.5)
240         dialog.run()
241         dialog.destroy()
242
243     def open_link(self, d, url, data):
244         print "url: %s" % (url)
245         import webbrowser
246         webbrowser.open_new(url)
247
248
249     #def on_refresh(self, button):
250     #    dialog = RefreshDialog()
251     #    dialog.show_all()
252     #    dialog.run()
253     #    dialog.hide()
254
255     def on_featured(self, button):
256         dialog = hildon.PickerDialog(self.window)
257         sel = hildon.TouchSelector(text=True)
258         for feature, _ in FeaturedWindow.features:
259             sel.append_text(feature)
260         dialog.set_selector(sel)
261         dialog.set_title("Featured")
262         if dialog.run() == gtk.RESPONSE_OK:
263             txt = sel.get_current_text()
264             self.featuredwnd = FeaturedWindow(txt)
265             self.featuredwnd.show_all()
266         dialog.destroy()
267
268     def on_radios(self, button):
269         self.radioswnd = RadiosWindow()
270         self.radioswnd.show_all()
271
272     def on_search(self, button):
273         self.searchwnd = SearchWindow()
274         self.searchwnd.show_all()
275
276     def on_playlists(self, button):
277         self.playlistswnd = PlaylistsWindow()
278         self.playlistswnd.show_all()
279
280     def on_settings(self, button):
281         dialog = gtk.Dialog()
282         dialog.set_title("Settings")
283         dialog.add_button( gtk.STOCK_OK, gtk.RESPONSE_OK )
284         vbox = dialog.vbox
285         tbl = gtk.Table(1, 2)
286         tbl.attach(gtk.Label("Username:"), 0, 1, 0, 1)
287         entry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
288         entry.set_placeholder("jamendo.com username")
289         if settings.user:
290             entry.set_text(settings.user)
291         tbl.attach(entry, 1, 2, 0, 1)
292         vbox.pack_start(tbl, True, True, 2)
293         dialog.show_all()
294         result = dialog.run()
295         val = entry.get_text()
296         dialog.destroy()
297         print val, result
298         if val and result == gtk.RESPONSE_OK:
299             print "new user name:", val
300             settings.user = val
301             self.save_settings()
302
303
304     def on_favorites(self, button):
305         self.favoriteswnd = FavoritesWindow()
306         self.favoriteswnd.show_all()
307
308     def on_player(self, button):
309         open_playerwindow([])
310
311     '''
312     def on_search(self, button):
313         if self.searchbar:
314             self.searchbar.show()
315         else:
316             self.searchstore = gtk.ListStore(gobject.TYPE_STRING)
317             iter = self.searchstore.append()
318             self.searchstore.set(iter, 0, "Test1")
319             iter = self.searchstore.append()
320             self.searchstore.set(iter, 0, "Test2")
321             self.searchbar = hildon.FindToolbar("Search", self.searchstore, 0)
322             self.searchbar.set_active(0)
323             self.window.add_toolbar(self.searchbar)
324             self.searchbar.show()
325     '''
326
327     def run(self):
328         ossohelper.application_init('org.jamaendo', '0.1')
329         self.create_window()
330         self.create_menu()
331         self.setup_widgets()
332         self.window.show_all()
333         gtk.main()
334         ossohelper.application_exit()
335
336 if __name__=="__main__":
337     ui = Jamaui()
338     ui.run()
339