From: Kristoffer Grönlund Date: Wed, 6 Jan 2010 02:26:12 +0000 (+0100) Subject: Most of the work I had indented for 0.2 done, only missing playlist management X-Git-Url: http://git.maemo.org/git/?p=jamaendo;a=commitdiff_plain;h=9c1d9eef21a957d26a71c20f90c8fd5aee7b0f15 Most of the work I had indented for 0.2 done, only missing playlist management --- diff --git a/data/bg.png b/data/bg.png index ce8b7d6..76fa7f1 100644 Binary files a/data/bg.png and b/data/bg.png differ diff --git a/data/bg.xcf b/data/bg.xcf index a017eca..5f520bb 100644 Binary files a/data/bg.xcf and b/data/bg.xcf differ diff --git a/jamaui/__init__.py b/jamaui/__init__.py index 819b0d7..5bf0b3e 100644 --- a/jamaui/__init__.py +++ b/jamaui/__init__.py @@ -26,7 +26,7 @@ import logging import sys LOG_FILENAME = '/tmp/jamaendo.log' -LOG_LEVEL = logging.DEBUG +LOG_LEVEL = logging.INFO LOG_FORMAT = "%(asctime)s %(name)-10s: [%(lineno)4d] %(levelname)-5s %(message)s" _rootlogger = logging.getLogger() diff --git a/jamaui/albumlist.py b/jamaui/albumlist.py index dbaa8ff..c1dc2ab 100644 --- a/jamaui/albumlist.py +++ b/jamaui/albumlist.py @@ -7,7 +7,8 @@ except: import helldon as hildon import jamaendo import util -from settings import settings +import draw +import colors from postoffice import postoffice import logging @@ -24,6 +25,10 @@ class _BaseList(gtk.TreeView): self.__store = None self.default_pixbuf = util.find_resource('album.png') self.connect('destroy', self.on_destroy) + self.connect('expose-event', self.on_treeview_expose_event) + self.loading_message = "Loading..." + self.empty_message = "Empty." + self._is_loading = True def get_pixbuf(self, img): try: @@ -48,6 +53,32 @@ class _BaseList(gtk.TreeView): def on_destroy(self, wnd): pass + def set_loading(self, loading): + self._is_loading = loading + self.queue_draw() + + def on_treeview_expose_event(self, treeview, event): + if event.window == treeview.get_bin_window(): + model = treeview.get_model() + if (model is not None and model.get_iter_first() is not None): + return False + + ctx = event.window.cairo_create() + ctx.rectangle(event.area.x, event.area.y, + event.area.width, event.area.height) + ctx.clip() + x, y, width, height, depth = event.window.get_geometry() + + if self._is_loading: + text = self.loading_message + else: + text = self.empty_message + + desc = colors.get_font_desc('LargeSystemFont') + draw.text_box_centered(ctx, treeview, width, height, text, desc) + + return False + class MusicList(_BaseList): def __init__(self): _BaseList.__init__(self) @@ -192,6 +223,66 @@ class TrackList(_BaseList): _, _, _id = self.__store.get(treeiter, 0, 1, 2) return _id + +class PlaylistList(_BaseList): + def __init__(self): + _BaseList.__init__(self) + (self.COL_ICON, self.COL_NAME, self.COL_INFO, self.COL_ID) = range(4) + self.__store = gtk.ListStore(gtk.gdk.Pixbuf, str, str, int) + + self.set_model(self.__store) + + icon = gtk.TreeViewColumn('Icon') + self.append_column(icon) + cell = gtk.CellRendererPixbuf() + icon.pack_start(cell, True) + icon.add_attribute(cell, 'pixbuf', self.COL_ICON) + + col = gtk.TreeViewColumn('Name') + self.append_column(col) + cell = gtk.CellRendererText() + col.pack_start(cell, True) + col.add_attribute(cell, 'text', self.COL_NAME) + + col = gtk.TreeViewColumn('Info') + self.append_column(col) + cell = gtk.CellRendererText() + cell.set_property('xalign', 1.0) + col.pack_start(cell, True) + col.add_attribute(cell, 'text', self.COL_INFO) + + self.set_search_column(self.COL_NAME) + col.set_sort_column_id(self.COL_NAME) + + postoffice.connect('album-cover', self, self.on_album_cover) + + def on_destroy(self, wnd): + _BaseList.on_destroy(self, wnd) + postoffice.disconnect('album-cover', self) + + def on_album_cover(self, albumid, size, cover): + if size == self.ICON_SIZE: + for row in self.__store: + if row[self.COL_ID] == albumid: + row[self.COL_ICON] = self.get_pixbuf(cover) + + def add_playlist(self, name, tracks): + def trackcount(lst): + ln = len(lst) + if ln > 1: + return "(%d tracks)"%(ln) + elif ln == 1: + return "(1 track)" + return "(empty)" + track = tracks[0] if len(tracks) else None + track_album_id = int(track['data']['album_id']) if track else 0 + self.__store.append([self.get_default_pixbuf(), name, trackcount(tracks), track_album_id]) + if track_album_id: + postoffice.notify('request-album-cover', track_album_id, self.ICON_SIZE) + + def get_playlist_name(self, path): + return self.__store.get(self.__store.get_iter(path), self.COL_NAME)[0] + class RadioList(_BaseList): def __init__(self): _BaseList.__init__(self) diff --git a/jamaui/colors.py b/jamaui/colors.py index 391d18a..62ab8c9 100644 --- a/jamaui/colors.py +++ b/jamaui/colors.py @@ -64,13 +64,18 @@ if _using_helldon: return "#333333" else: def color(name): - return get_color('SecondaryTextColor').to_string() + return get_color(name).to_string() import sys current_module = sys.modules[__name__] +def mk_font_fun(name): + def inner(): + return font(name) + return inner + for fnt in logical_font_names: - setattr(current_module, fnt, lambda: font(fnt)) + setattr(current_module, fnt.replace('-', ''), mk_font_fun(fnt)) for clr in logical_color_names: setattr(current_module, clr, lambda: color(clr)) diff --git a/jamaui/draw.py b/jamaui/draw.py new file mode 100644 index 0000000..400111d --- /dev/null +++ b/jamaui/draw.py @@ -0,0 +1,23 @@ +import gtk +import pango + +def text_box_centered(ctx, widget, w_width, w_height, text, font_desc=None): + style = widget.rc_get_style() + text_color = style.text[gtk.STATE_PRELIGHT] + red, green, blue = text_color.red, text_color.green, text_color.blue + text_color = [float(x)/65535. for x in (red, green, blue)] + text_color.append(.5) + + if font_desc is None: + font_desc = style.font_desc + font_desc.set_size(14*pango.SCALE) + + pango_context = widget.create_pango_context() + layout = pango.Layout(pango_context) + layout.set_font_description(font_desc) + layout.set_text(text) + width, height = layout.get_pixel_size() + + ctx.move_to(w_width/2-width/2, w_height/2-height/2) + ctx.set_source_rgba(*text_color) + ctx.show_layout(layout) diff --git a/jamaui/listbox.py b/jamaui/listbox.py index c74f1d8..dad31ef 100644 --- a/jamaui/listbox.py +++ b/jamaui/listbox.py @@ -48,7 +48,7 @@ class ListDialog(gtk.Dialog): self.listbox = ListBox() panarea = hildon.PannableArea() panarea.add(self.listbox) - panarea.set_size_request(800, 300) + panarea.set_size_request_policy(hildon.SIZE_REQUEST_CHILDREN) self.vbox.pack_start(panarea, True, True, 0) self.selected = None @@ -69,8 +69,9 @@ class ButtonListDialog(gtk.Dialog): self.vbox.pack_start(self.panarea, True, True, 0) def add_button(self, label, clickcb, *args): - btn = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH|gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL) + btn = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH|gtk.HILDON_SIZE_FINGER_HEIGHT, + hildon.BUTTON_ARRANGEMENT_VERTICAL) btn.set_label(label) btn.connect('clicked', clickcb, *args) - self.buttons.pack_end(btn, False, False, 0) + self.buttons.pack_start(btn, False, False, 0) diff --git a/jamaui/playerwindow.py b/jamaui/playerwindow.py index 1ff65f8..72472d5 100644 --- a/jamaui/playerwindow.py +++ b/jamaui/playerwindow.py @@ -28,6 +28,7 @@ try: except: import helldon as hildon import util +import datetime import pango import jamaendo from settings import settings @@ -75,6 +76,9 @@ class PlayerWindow(hildon.StackableWindow): self.album = gtk.Label() self.album.set_alignment(0,0) self.album.set_ellipsize(pango.ELLIPSIZE_END) + self.playtime = gtk.Label() + self.playtime.set_alignment(1,0) + self.playtime.set_ellipsize(pango.ELLIPSIZE_END) self.progress = SongPosition() self.set_labels('', '', '', 0, 0) @@ -85,6 +89,7 @@ class PlayerWindow(hildon.StackableWindow): vbox2.pack_start(self.track, True) vbox2.pack_start(self.artist, True) vbox2.pack_start(self.album, True) + vbox2.pack_start(self.playtime, False, True) vbox2.pack_start(self.progress, False, True) hbox.set_border_width(8) @@ -252,10 +257,31 @@ class PlayerWindow(hildon.StackableWindow): def clear_position(self): self.progress.set_position(0) + def nanosecs_to_str(self, ns): + time_secs = int(float(ns)/1000000000.0) + if time_secs <= 59: + return "00:%02d"%(time_secs) + time_mins = int(time_secs/60.0) + time_secs -= time_mins*60 + if time_mins <= 59: + return "%02d:%02d"%(time_mins, time_secs) + + time_hrs = int(time_mins/60.0) + time_mins -= time_hrs*60 + return "%d:%02d:%02d"%(time_hrs, time_secs, time_mins) + def set_song_position(self, time_elapsed, total_time): value = (float(time_elapsed) / float(total_time)) if total_time else 0 self.progress.set_position(value) + + txt = '%s' % \ + (colors.XLargeSystemFont(), + colors.SecondaryTextColor(), + self.nanosecs_to_str(time_elapsed) + ) + self.playtime.set_markup(txt) + def set_default_cover(self): tmp = util.find_resource('album.png') if tmp: diff --git a/jamaui/playlists.py b/jamaui/playlists.py index 3012e29..9f70de4 100644 --- a/jamaui/playlists.py +++ b/jamaui/playlists.py @@ -29,6 +29,7 @@ except: import jamaendo from settings import settings import logging +from albumlist import PlaylistList log = logging.getLogger(__name__) @@ -99,47 +100,40 @@ class PlaylistsWindow(hildon.StackableWindow): self.set_title("Playlists") self.panarea = hildon.PannableArea() - - (self.COL_NAME, self.COL_INFO) = range(2) - self.store = gtk.ListStore(str, str) - self.treeview = gtk.TreeView() - self.treeview.set_model(self.store) - - col = gtk.TreeViewColumn('Name') - self.treeview.append_column(col) - cell = gtk.CellRendererText() - col.pack_start(cell, True) - col.add_attribute(cell, 'text', self.COL_NAME) - self.treeview.set_search_column(self.COL_NAME) - col.set_sort_column_id(self.COL_NAME) - - col = gtk.TreeViewColumn('Info') - self.treeview.append_column(col) - cell = gtk.CellRendererText() - cell.set_property('xalign', 1.0) - col.pack_start(cell, True) - col.add_attribute(cell, 'text', self.COL_INFO) - - self.treeview.connect('row-activated', self.row_activated) - - self.panarea.add(self.treeview) - + self.playlistlist = PlaylistList() + self.playlistlist.empty_message = "No playlists" + self.playlistlist.connect('row-activated', self.row_activated) + self.panarea.add(self.playlistlist) self.add(self.panarea) - def trackcount(lst): - ln = len(lst) - if ln > 1: - return "(%d tracks)"%(ln) - elif ln == 1: - return "(1 track)" - return "(empty)" - for key, lst in sorted(list(settings.playlists.iteritems())): - self.store.append([key, trackcount(lst)]) + self.playlistlist.add_playlist(key, lst) + self.playlistlist.set_loading(False) + + self.create_menu() + + def create_menu(self): + def on_player(*args): + from playerwindow import open_playerwindow + open_playerwindow() + self.menu = hildon.AppMenu() + player = hildon.GtkButton(gtk.HILDON_SIZE_AUTO) + player.set_label("Open player") + player.connect("clicked", on_player) + self.menu.append(player) + player = hildon.GtkButton(gtk.HILDON_SIZE_AUTO) + player.set_label("Delete playlists") + player.connect("clicked", self.on_delete_playlists) + self.menu.append(player) + self.menu.show_all() + self.set_app_menu(self.menu) + + def on_delete_playlists(self, *args): + _show_banner(self, "TODOO") def row_activated(self, treeview, path, view_column): - name = self.store.get(self.store.get_iter(path), self.COL_NAME)[0] - pl = settings.get_playlist(name) + sel = self.playlistlist.get_playlist_name(path) + pl = settings.get_playlist(sel) if pl: from playerwindow import open_playerwindow wnd = open_playerwindow() diff --git a/jamaui/search.py b/jamaui/search.py index 4ea8dd3..52d74f7 100644 --- a/jamaui/search.py +++ b/jamaui/search.py @@ -44,19 +44,10 @@ class SearchWindow(hildon.StackableWindow): # Results list self.panarea = hildon.PannableArea() self.musiclist = MusicList() - self.result_store = gtk.ListStore(str, int) - #self.result_store.append(['red']) - self.result_view = gtk.TreeView(self.result_store) - col = gtk.TreeViewColumn('Name') - self.result_view.append_column(col) - cell = gtk.CellRendererText() - col.pack_start(cell, True) - col.add_attribute(cell, 'text', 0) - self.result_view.set_search_column(0) - col.set_sort_column_id(0) - self.result_view.connect('row-activated', self.row_activated) - - self.panarea.add(self.result_view) + self.musiclist.loading_message = "Nothing found yet" + self.musiclist.empty_message = "No matching results" + self.musiclist.connect('row-activated', self.row_activated) + self.panarea.add(self.musiclist) vbox.pack_start(self.panarea, True, True, 0) @@ -110,28 +101,28 @@ class SearchWindow(hildon.StackableWindow): def on_search(self, w): mode = self.mode.get_active() txt = self.entry.get_text() - self.result_store.clear() - if mode == 0: - for artist in jamaendo.search_artists(query=txt): - title = artist.name - self.idmap[artist.ID] = artist - self.result_store.append([title, artist.ID]) - elif mode == 1: - for album in jamaendo.search_albums(query=txt): - title = "%s - %s" % (album.artist_name, album.name) - self.idmap[album.ID] = album - self.result_store.append([title, album.ID]) - elif mode == 2: - for track in jamaendo.search_tracks(query=txt): - title = "%s - %s" % (track.artist_name, track.name) - self.idmap[track.ID] = track - self.result_store.append([title, track.ID]) + self.musiclist.set_loading(False) + self.musiclist.get_model().clear() + + try: + if mode == 0: + items = jamaendo.search_artists(query=txt) + elif mode == 1: + items = jamaendo.search_albums(query=txt) + elif mode == 2: + items = jamaendo.search_tracks(query=txt) + + for item in items: + self.idmap[item.ID] = item + + self.musiclist.add_items(items) + except jamaendo.JamaendoAPIException: + # nothing found, force redraw + self.musiclist.queue_draw() def row_activated(self, treeview, path, view_column): - treeiter = self.result_store.get_iter(path) - title, _id = self.result_store.get(treeiter, 0, 1) + _id = self.musiclist.get_item_id(path) item = self.idmap[_id] - #print _id, item self.open_item(item) def open_item(self, item): diff --git a/jamaui/settings.py b/jamaui/settings.py index a9c86ed..94e10a6 100644 --- a/jamaui/settings.py +++ b/jamaui/settings.py @@ -91,10 +91,11 @@ class Settings(object): for k in self.defaults.keys(): if k in settings: - if k == 'playlists' and not isinstance(k, dict): + val = settings[k] + if k == 'playlists' and not isinstance(val, dict): continue - setattr(self, k, settings[k]) - print settings + setattr(self, k, val) + log.debug("Loaded settings: %s", settings) except Exception, e: log.exception('failed to load settings') @@ -108,7 +109,7 @@ class Settings(object): f = open(self.__savename, 'w') cPickle.dump(settings, f) f.close() - print settings + log.debug("Saved settings: %s", settings) except Exception, e: log.exception('failed to save settings') diff --git a/jamaui/songposition.py b/jamaui/songposition.py index 8aea80e..67e7a12 100644 --- a/jamaui/songposition.py +++ b/jamaui/songposition.py @@ -12,7 +12,7 @@ class SongPosition(gtk.DrawingArea): def __init__(self): gtk.DrawingArea.__init__(self) self.connect('expose-event', self.on_expose) - self.set_size_request(self.WIDTH, self.HEIGHT) + self.set_size_request(int(self.WIDTH), int(self.HEIGHT)) self.pos = 0.0 orange0 = self.hex_to_flt(0xec, 0xac, 0x1f) @@ -85,7 +85,7 @@ class SongPosition(gtk.DrawingArea): context.fill() context.rectangle(0, 0, rect.width, rect.height) - context.set_source_rgb(0.6, 0.6, 0.6) + context.set_source_rgb(0.3, 0.3, 0.3) context.stroke() #context.rectangle(lowx, 0, self.WIDTH, rect.height) diff --git a/jamaui/ui.py b/jamaui/ui.py index 5732ee7..777bfd0 100644 --- a/jamaui/ui.py +++ b/jamaui/ui.py @@ -93,11 +93,6 @@ class Jamaui(object): def create_menu(self): self.menu = hildon.AppMenu() - #search = hildon.GtkButton(gtk.HILDON_SIZE_AUTO) - #search.set_label("Search") - #search.connect("clicked", self.on_search) - #self.menu.append(search) - player = hildon.GtkButton(gtk.HILDON_SIZE_AUTO) player.set_label("Open player") player.connect("clicked", self.on_player) @@ -118,13 +113,6 @@ class Jamaui(object): player.connect("clicked", self.on_settings) self.menu.append(player) - - # Don't use localdb ATM - #refresh = hildon.GtkButton(gtk.HILDON_SIZE_AUTO) - #refresh.set_label("Refresh") - #refresh.connect("clicked", self.on_refresh) - #self.menu.append(refresh) - menu_about = hildon.GtkButton(gtk.HILDON_SIZE_AUTO) menu_about.set_label("About") menu_about.connect("clicked", self.show_about, self.window) @@ -143,7 +131,7 @@ class Jamaui(object): self.window.window.set_back_pixmap(background, False) bbox = gtk.HButtonBox() - alignment = gtk.Alignment(xalign=0.2, yalign=0.925, xscale=1.0) + alignment = gtk.Alignment(xalign=0.2, yalign=0.28, xscale=1.0) alignment.add(bbox) bbox.set_property('layout-style', gtk.BUTTONBOX_SPREAD) self.bbox = bbox @@ -179,19 +167,6 @@ class Jamaui(object): postoffice.notify('images', images) gtk.gdk.threads_leave() - #def add_featured_button(self): - # self.featured_sel = hildon.TouchSelector(text=True) - # self.featured_sel.append_text("Albums of the week") - # self.featured_sel.append_text("Tracks of the week") - # self.featured_sel.append_text("New releases") - # btn = hildon.PickerButton(gtk.HILDON_SIZE_THUMB_HEIGHT, - # hildon.BUTTON_ARRANGEMENT_VERTICAL) - # btn.set_text("Featured", "Most listened to") - # btn.set_property('width-request', 225) - # btn.set_selector(self.featured_sel) - # self.featured_btn = btn - # self.bbox.add(btn) - def destroy(self, widget): postoffice.disconnect(['request-album-cover', 'request-images'], self) settings.save() @@ -248,17 +223,9 @@ JAMENDO is an online platform that distributes musical works under Creative Comm dialog.destroy() def open_link(self, d, url, data): - #print "url: %s" % (url) import webbrowser webbrowser.open_new(url) - - #def on_refresh(self, button): - # dialog = RefreshDialog() - # dialog.show_all() - # dialog.run() - # dialog.hide() - def on_featured(self, button): dialog = ButtonListDialog('Featured', self.window) def fn(btn, feature): @@ -288,21 +255,19 @@ JAMENDO is an online platform that distributes musical works under Creative Comm dialog.set_title("Settings") dialog.add_button( gtk.STOCK_OK, gtk.RESPONSE_OK ) vbox = dialog.vbox - tbl = gtk.Table(1, 2) - tbl.attach(gtk.Label("Username:"), 0, 1, 0, 1) + hboxinner = gtk.HBox() + hboxinner.pack_start(gtk.Label("Username:"), False, False, 0) entry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT) entry.set_placeholder("jamendo.com username") if settings.user: entry.set_text(settings.user) - tbl.attach(entry, 1, 2, 0, 1) - vbox.pack_start(tbl, True, True, 2) + hboxinner.pack_start(entry, True, True, 0) + vbox.pack_start(hboxinner, True, True, 0) dialog.show_all() result = dialog.run() val = entry.get_text() dialog.destroy() - #print val, result if val and result == gtk.RESPONSE_OK: - #print "new user name:", val settings.user = val settings.save() @@ -314,22 +279,6 @@ JAMENDO is an online platform that distributes musical works under Creative Comm def on_player(self, button): open_playerwindow() - ''' - def on_search(self, button): - if self.searchbar: - self.searchbar.show() - else: - self.searchstore = gtk.ListStore(gobject.TYPE_STRING) - iter = self.searchstore.append() - self.searchstore.set(iter, 0, "Test1") - iter = self.searchstore.append() - self.searchstore.set(iter, 0, "Test2") - self.searchbar = hildon.FindToolbar("Search", self.searchstore, 0) - self.searchbar.set_active(0) - self.window.add_toolbar(self.searchbar) - self.searchbar.show() - ''' - def run(self): ossohelper.application_init('org.jamaendo', '0.1') self.create_window() diff --git a/jamaui/util.py b/jamaui/util.py index bd0c758..3c82f17 100644 --- a/jamaui/util.py +++ b/jamaui/util.py @@ -56,4 +56,3 @@ def find_resource(name): return os.path.join('/usr/share/jamaendo', name) else: return None -