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()
import helldon as hildon
import jamaendo
import util
-from settings import settings
+import draw
+import colors
from postoffice import postoffice
import logging
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:
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)
_, _, _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)
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))
--- /dev/null
+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)
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
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)
except:
import helldon as hildon
import util
+import datetime
import pango
import jamaendo
from settings import settings
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)
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)
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 = '<span font_desc="%s" foreground="%s">%s</span>' % \
+ (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:
import jamaendo
from settings import settings
import logging
+from albumlist import PlaylistList
log = logging.getLogger(__name__)
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()
# 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)
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):
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')
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')
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)
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)
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)
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)
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
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()
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):
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()
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()
return os.path.join('/usr/share/jamaendo', name)
else:
return None
-