8fc19977c552045729955f73fcc5c2b0442847c1
[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.set_icon('jamaendo')
89         self.window.connect("destroy", self.destroy)
90
91         self.CONFDIR = os.path.expanduser('~/MyDocs/.jamaendo')
92         jamaendo.set_cache_dir(self.CONFDIR)
93         settings.set_filename(os.path.join(self.CONFDIR, 'ui_settings'))
94         settings.load()
95
96         postoffice.connect('request-album-cover', self.on_request_cover)
97
98     def save_settings(self):
99         settings.save()
100
101     def create_menu(self):
102         self.menu = hildon.AppMenu()
103
104         #search = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
105         #search.set_label("Search")
106         #search.connect("clicked", self.on_search)
107         #self.menu.append(search)
108
109         #player = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
110         #player.set_label("Open player")
111         #player.connect("clicked", self.on_player)
112         #self.menu.append(player)
113
114         player = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
115         player.set_label("Favorites")
116         player.connect("clicked", self.on_favorites)
117         self.menu.append(player)
118
119         #player = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
120         #player.set_label("Playlists")
121         #player.connect("clicked", self.on_playlists)
122         #self.menu.append(player)
123
124         player = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
125         player.set_label("Settings")
126         player.connect("clicked", self.on_settings)
127         self.menu.append(player)
128
129
130         # Don't use localdb ATM
131         #refresh = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
132         #refresh.set_label("Refresh")
133         #refresh.connect("clicked", self.on_refresh)
134         #self.menu.append(refresh)
135
136         menu_about = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
137         menu_about.set_label("About")
138         menu_about.connect("clicked", self.show_about, self.window)
139         self.menu.append(menu_about)
140         gtk.about_dialog_set_url_hook(self.open_link, None)
141
142         self.menu.show_all()
143         self.window.set_app_menu(self.menu)
144
145
146     def setup_widgets(self):
147         bgimg = util.find_resource('bg.png')
148         if bgimg:
149             background, mask = gtk.gdk.pixbuf_new_from_file(bgimg).render_pixmap_and_mask()
150             self.window.realize()
151             self.window.window.set_back_pixmap(background, False)
152
153         bbox = gtk.HButtonBox()
154         alignment = gtk.Alignment(xalign=0.2, yalign=0.925, xscale=1.0)
155         alignment.add(bbox)
156         bbox.set_property('layout-style', gtk.BUTTONBOX_SPREAD)
157         self.bbox = bbox
158         self.window.add(alignment)
159
160         self.add_mainscreen_button("Featured", "Most listened to", self.on_featured)
161         self.add_mainscreen_button("Radios", "The best in free music", self.on_radios)
162         self.add_mainscreen_button("Search", "Search for artists/albums", self.on_search)
163
164         self.window.show_all()
165
166     def add_mainscreen_button(self, title, subtitle, callback):
167         btn = hildon.Button(gtk.HILDON_SIZE_THUMB_HEIGHT,
168                             hildon.BUTTON_ARRANGEMENT_VERTICAL)
169         btn.set_text(title, subtitle)
170         btn.set_property('width-request', 225)
171         btn.connect('clicked', callback)
172         self.bbox.add(btn)
173
174     def on_request_cover(self, albumid, size):
175         jamaendo.get_album_cover_async(self.got_album_cover, int(albumid), size)
176
177     def got_album_cover(self, albumid, size, cover):
178         postoffice.notify('album-cover', albumid, size, cover)
179
180     #def add_featured_button(self):
181     #    self.featured_sel = hildon.TouchSelector(text=True)
182     #    self.featured_sel.append_text("Albums of the week")
183     #    self.featured_sel.append_text("Tracks of the week")
184     #    self.featured_sel.append_text("New releases")
185     #    btn = hildon.PickerButton(gtk.HILDON_SIZE_THUMB_HEIGHT,
186     #                              hildon.BUTTON_ARRANGEMENT_VERTICAL)
187     #    btn.set_text("Featured", "Most listened to")
188     #    btn.set_property('width-request', 225)
189     #    btn.set_selector(self.featured_sel)
190     #    self.featured_btn = btn
191     #    self.bbox.add(btn)
192
193     def destroy(self, widget):
194         postoffice.disconnect('request-album-cover', self.on_request_cover)
195         gtk.main_quit()
196
197     def show_about(self, w, win):
198         dialog = gtk.AboutDialog()
199         dialog.set_program_name("jamaendo")
200         dialog.set_website("http://github.com/krig")
201         dialog.set_website_label("http://github.com/krig")
202         dialog.set_version(VERSION)
203         dialog.set_license("""Copyright (c) 2010, Kristoffer Gronlund
204 All rights reserved.
205
206 Redistribution and use in source and binary forms, with or without
207 modification, are permitted provided that the following conditions are met:
208      * Redistributions of source code must retain the above copyright
209        notice, this list of conditions and the following disclaimer.
210      * Redistributions in binary form must reproduce the above copyright
211        notice, this list of conditions and the following disclaimer in the
212        documentation and/or other materials provided with the distribution.
213      * Neither the name of Jamaendo nor the
214        names of its contributors may be used to endorse or promote products
215        derived from this software without specific prior written permission.
216
217 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
218 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
219 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
220 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
221 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
222 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
223 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
224 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
225 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
226 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
227 """)
228         dialog.set_authors(("Kristoffer Gronlund <kristoffer.gronlund@purplescout.se>",
229                             "Based on Panucci, written by Thomas Perl <thpinfo.com>"))
230         dialog.set_comments("""Jamaendo plays music from the music catalog of JAMENDO.
231
232 JAMENDO is an online platform that distributes musical works under Creative Commons licenses.""")
233         gtk.about_dialog_set_email_hook(self.open_link, dialog)
234         gtk.about_dialog_set_url_hook(self.open_link, dialog)
235         dialog.connect( 'response', lambda dlg, response: dlg.destroy())
236         for parent in dialog.vbox.get_children():
237             for child in parent.get_children():
238                 if isinstance(child, gtk.Label):
239                     child.set_selectable(False)
240                     child.set_alignment(0.0, 0.5)
241         dialog.run()
242         dialog.destroy()
243
244     def open_link(self, d, url, data):
245         #print "url: %s" % (url)
246         import webbrowser
247         webbrowser.open_new(url)
248
249
250     #def on_refresh(self, button):
251     #    dialog = RefreshDialog()
252     #    dialog.show_all()
253     #    dialog.run()
254     #    dialog.hide()
255
256     def on_featured(self, button):
257         dialog = hildon.PickerDialog(self.window)
258         sel = hildon.TouchSelector(text=True)
259         for feature, _ in FeaturedWindow.features:
260             sel.append_text(feature)
261         dialog.set_selector(sel)
262         dialog.set_title("Featured")
263         if dialog.run() == gtk.RESPONSE_OK:
264             txt = sel.get_current_text()
265             self.featuredwnd = FeaturedWindow(txt)
266             self.featuredwnd.show_all()
267         dialog.destroy()
268
269     def on_radios(self, button):
270         self.radioswnd = RadiosWindow()
271         self.radioswnd.show_all()
272
273     def on_search(self, button):
274         self.searchwnd = SearchWindow()
275         self.searchwnd.show_all()
276
277     def on_playlists(self, button):
278         self.playlistswnd = PlaylistsWindow()
279         self.playlistswnd.show_all()
280
281     def on_settings(self, button):
282         dialog = gtk.Dialog()
283         dialog.set_title("Settings")
284         dialog.add_button( gtk.STOCK_OK, gtk.RESPONSE_OK )
285         vbox = dialog.vbox
286         tbl = gtk.Table(1, 2)
287         tbl.attach(gtk.Label("Username:"), 0, 1, 0, 1)
288         entry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
289         entry.set_placeholder("jamendo.com username")
290         if settings.user:
291             entry.set_text(settings.user)
292         tbl.attach(entry, 1, 2, 0, 1)
293         vbox.pack_start(tbl, True, True, 2)
294         dialog.show_all()
295         result = dialog.run()
296         val = entry.get_text()
297         dialog.destroy()
298         #print val, result
299         if val and result == gtk.RESPONSE_OK:
300             #print "new user name:", val
301             settings.user = val
302             self.save_settings()
303
304
305     def on_favorites(self, button):
306         self.favoriteswnd = FavoritesWindow()
307         self.favoriteswnd.show_all()
308
309     def on_player(self, button):
310         open_playerwindow([])
311
312     '''
313     def on_search(self, button):
314         if self.searchbar:
315             self.searchbar.show()
316         else:
317             self.searchstore = gtk.ListStore(gobject.TYPE_STRING)
318             iter = self.searchstore.append()
319             self.searchstore.set(iter, 0, "Test1")
320             iter = self.searchstore.append()
321             self.searchstore.set(iter, 0, "Test2")
322             self.searchbar = hildon.FindToolbar("Search", self.searchstore, 0)
323             self.searchbar.set_active(0)
324             self.window.add_toolbar(self.searchbar)
325             self.searchbar.show()
326     '''
327
328     def run(self):
329         ossohelper.application_init('org.jamaendo', '0.1')
330         self.create_window()
331         self.create_menu()
332         self.setup_widgets()
333         self.window.show_all()
334         gtk.main()
335         ossohelper.application_exit()
336
337 if __name__=="__main__":
338     ui = Jamaui()
339     ui.run()
340