[gnome-music] Switch to js



commit b0e455b8ec73600c399cf74ed67a59eb7055af93
Author: Seif Lotfy <seif lotfy com>
Date:   Sun Mar 31 22:43:19 2013 +0200

    Switch to js

 .gitignore                                         |   97 -
 AUTHORS                                            |    1 -
 COPYING                                            |  339 -
 INSTALL                                            |  370 -
 Makefile.am                                        |   46 +-
 NEWS                                               |    3 +
 README                                             |    4 -
 autogen.sh                                         |   30 +-
 configure.ac                                       |   79 +-
 data/Makefile.am                                   |   25 -
 data/album-art-default.svg                         |  673 --
 data/gnome-music.desktop.in.in                     |    9 -
 git.mk                                             |  227 +
 gnome-music.doap                                   |   19 -
 libgd                                              |    1 -
 po/LINGUAS                                         |   13 -
 po/POTFILES.in                                     |    7 -
 po/POTFILES.skip                                   |    4 -
 po/cs.po                                           |  147 -
 po/de.po                                           |  150 -
 po/es.po                                           |  149 -
 po/fi.po                                           |  147 -
 po/gl.po                                           |  147 -
 po/hu.po                                           |  148 -
 po/nb.po                                           |  143 -
 po/pa.po                                           |  149 -
 po/pl.po                                           |  156 -
 po/pt_BR.po                                        |  146 -
 po/ru.po                                           |  153 -
 po/sl.po                                           |  150 -
 po/sr.po                                           |  150 -
 po/sr latin po                                     |  150 -
 src/Makefile.am                                    |   98 +-
 src/album-art-cache.vala                           |  157 -
 src/album_art_cache.js                             |  191 +
 src/app-menu.ui                                    |   21 -
 src/application.js                                 |  161 +
 src/clickable_label.js                             |   34 +
 src/gnome-music.in                                 |    7 +
 src/grilo.js                                       |  115 +
 src/main.js                                        |   26 +
 src/main.vala                                      |   49 -
 src/models.js                                      |   96 +
 src/music-album-info-box.vala                      |   97 -
 src/music-app.vala                                 |  336 -
 src/music-browse-history.vala                      |   75 -
 src/music-clickable-label.vala                     |   69 -
 src/music-collection-view.vala                     |  225 -
 src/music-list-store.vala                          |  341 -
 src/music-player.vala                              |  303 -
 src/music-playlist-songs.vala                      |   95 -
 src/music-playlist-view.vala                       |   64 -
 src/music-playlist.vala                            |  165 -
 src/music-searchbar.vala                           |   84 -
 src/music-topbar.vala                              |  346 -
 src/music-utils.vala                               |   19 -
 src/package.js                                     |  282 +
 src/player.js                                      |  289 +
 src/query.js                                       |   34 +
 src/resources/app-menu.ui                          |   27 +
 {data => src/resources}/gtk-style.css              |    1 +
 src/resources/lp.jpg                               |  Bin 0 -> 20663 bytes
 src/{ => resources}/music.gresource.xml            |    0
 src/{ => resources}/org.gnome.Music.gschema.xml.in |    0
 src/searchbar.js                                   |  132 +
 src/toolbar.js                                     |   84 +
 src/view.js                                        |  383 +
 src/widgets.js                                     |  186 +
 vapi/Makefile.am                                   |    5 -
 vapi/config.vapi                                   |   18 -
 vapi/custom.vapi                                   |   12 -
 vapi/upstream/Makefile.am                          |   19 -
 vapi/upstream/cairo.vapi                           |  724 --
 vapi/upstream/clutter-1.0.deps                     |    5 -
 vapi/upstream/clutter-1.0.vapi                     | 7680 ------------------
 vapi/upstream/clutter-gtk-1.0.deps                 |    8 -
 vapi/upstream/clutter-gtk-1.0.vapi                 |   58 -
 vapi/upstream/cogl-1.0.deps                        |    1 -
 vapi/upstream/cogl-1.0.vapi                        |  802 --
 vapi/upstream/gdk-3.0.deps                         |    5 -
 vapi/upstream/gdk-3.0.vapi                         | 5957 --------------
 vapi/upstream/gdk-pixbuf-2.0.deps                  |    1 -
 vapi/upstream/gdk-pixbuf-2.0.vapi                  |  242 -
 vapi/upstream/gtk+-3.0.deps                        |    7 -
 vapi/upstream/gtk+-3.0.vapi                        | 8543 --------------------
 85 files changed, 2362 insertions(+), 30349 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 6dbff12..25c551b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,41 +1,9 @@
-ACLOCAL_AMFLAGS= -I libgd ${ACLOCAL_FLAGS}
-NULL=
+ACLOCAL_AMFLAGS = -I m4 -I libgd
 
-SUBDIRS = data libgd src po vapi
-
-EXTRA_DIST = \
-       autogen.sh \
-       intltool-extract.in \
-       intltool-merge.in \
-       intltool-update.in \
-       $(NULL)
-
-ChangeLog:
-       $(AM_V_GEN) if test -d "$(srcdir)/.git"; then \
-         (GIT_DIR=$(top_srcdir)/.git ./missing --run git log --stat) | fmt --split-only > $  tmp \
-         && mv -f $  tmp $@ \
-         || ($(RM) $  tmp; \
-             echo Failed to generate ChangeLog, your ChangeLog may be outdated >&2; \
-             (test -f $@ || echo git-log is required to generate this file >> $@)); \
-       else \
-         test -f $@ || \
-         (echo A git checkout and git-log is required to generate ChangeLog >&2 && \
-         echo A git checkout and git-log is required to generate this file >> $@); \
-       fi
-
-
-distclean-local:
-       if test "$(srcdir)" = "."; then :; else \
-               rm -f ChangeLog; \
-       fi
-
-
-DISTCLEANFILES = \
-intltool-extract \
-intltool-merge \
-intltool-update
+SUBDIRS = libgd src
 
 MAINTAINERCLEANFILES = \
+       $(srcdir)/INSTALL \
        $(srcdir)/aclocal.m4 \
        $(srcdir)/autoscan.log \
        $(srcdir)/compile \
@@ -45,6 +13,10 @@ MAINTAINERCLEANFILES = \
        $(srcdir)/configure.scan \
        $(srcdir)/depcomp \
        $(srcdir)/install-sh \
+       $(srcdir)/ltmain.sh \
        $(srcdir)/missing \
-       $(srcdir)/ChangeLog \
-       `find "$(srcdir)" -type f -name Makefile.in -print`
+       $(srcdir)/mkinstalldirs
+
+GITIGNOREFILES = m4/
+
+-include $(top_srcdir)/git.mk
diff --git a/NEWS b/NEWS
index e69de29..4507184 100644
--- a/NEWS
+++ b/NEWS
@@ -0,0 +1,3 @@
+0.2
+===
+* Initial release, first one to be published at GNOME archives
diff --git a/autogen.sh b/autogen.sh
index 3fe3f24..5f239c0 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,14 +1,26 @@
-#!/bin/sh
-
-set -e # exit on errors
+#!/bin/bash
+# Run this to generate all the initial makefiles, etc.
 
 srcdir=`dirname $0`
 test -z "$srcdir" && srcdir=.
 
-git submodule update --init --recursive
-autoreconf -v --force --install
-intltoolize -f
+ACLOCAL_FLAGS="-I libgd ${ACLOCAL_FLAGS}"
+PKG_NAME="gnome-music"
+
+test -f $srcdir/configure.ac || {
+    echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
+    echo " top-level gnome-music directory"
+    exit 1
+}
+
+which gnome-autogen.sh || {
+    echo "You need to install gnome-common from GNOME Git (or from"
+    echo "your OS vendor's package manager)."
+    exit 1
+}
 
-if [ -z "$NOCONFIGURE" ]; then
-    "$srcdir"/configure --enable-maintainer-mode "$@"
-fi
+(cd "$srcdir" ;
+test -d m4 || mkdir m4/ ;
+git submodule update --init --recursive ;
+)
+. gnome-autogen.sh
diff --git a/configure.ac b/configure.ac
index ed87f1d..7f0fdfc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,68 +1,35 @@
-AC_PREREQ([2.67])
-AC_INIT([gnome-music],[0.0.0],[https://github.com/tapia/gnome-music])
-AC_CONFIG_SRCDIR([src/main.vala])
+AC_PREREQ(2.63)
+AC_INIT([gnome-music],[0.2],
+       [https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-music],
+       [gnome-music],
+       [https://live.gnome.org/Design/Apps/Music])
+
 AC_CONFIG_HEADERS([config.h])
-AM_INIT_AUTOMAKE
-# Enable silent rules is available
-AM_SILENT_RULES([yes])
-AM_MAINTAINER_MODE([enable])
+AC_CONFIG_MACRO_DIR([m4])
 
-LT_INIT
-AC_PROG_CC
-AM_PROG_VALAC([0.17])
-AC_PROG_INSTALL
+AM_INIT_AUTOMAKE([1.11 dist-xz foreign tar-ustar -Wno-portability])
 
-GOBJECT_INTROSPECTION_REQUIRE([0.9.6])
+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
 
-GLIB_GSETTINGS
-
-# i18n stuff
-IT_PROG_INTLTOOL([0.40])
+AC_PROG_CC
+AM_PROG_CC_C_O
+LT_INIT([disable-static])
 
-AM_GNU_GETTEXT([external])
-AM_GNU_GETTEXT_VERSION([0.17])
+LIBGD_INIT([header-bar main-toolbar main-view stack revealer gir])
 
-GETTEXT_PACKAGE=gnome-music
-AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"], [Gettext Package])
-AC_SUBST(GETTEXT_PACKAGE)
+PKG_PROG_PKG_CONFIG([0.22])
 
-SQLITE_MIN_VERSION=3.7.14
-GLIB_MIN_VERSION=2.31.0
-GTK_MIN_VERSION=3.5.6
-GRILO_MIN_VERSION=0.2
-GEE_MIN_VERSION=0.6.4
-GSTREAMER_MIN_VERSION=0.10
+GLIB_GSETTINGS
+GOBJECT_INTROSPECTION_REQUIRE([1.30.0])
 
-PKG_CHECK_MODULES(MUSIC, [
-  sqlite3 >= $SQLITE_MIN_VERSION
-  glib-2.0 >= $GLIB_MIN_VERSION
-  gtk+-3.0 >= $GTK_MIN_VERSION
-  grilo-0.2 >= $GRILO_MIN_VERSION
-  gee-1.0 >= $GEE_MIN_VERSION
-  gstreamer-0.10 >= $GSTREAMER_MIN_VERSION
-])
+AC_PATH_PROG([GJS],[gjs])
 
-MUSIC_PACKAGES="--pkg glib-2.0 --pkg gtk+-3.0 --pkg grilo-0.2 --pkg gee-1.0 --pkg gstreamer-0.10"
-AC_SUBST(MUSIC_PACKAGES)
+GLIB_COMPILE_RESOURCES=`$PKG_CONFIG --variable glib_compile_resources gio-2.0`
+AC_SUBST(GLIB_COMPILE_RESOURCES)
 
-LIBGD_INIT([
-  gtk-hacks
-  main-toolbar
-  main-icon-view
-  margin-container
-  static
-  tagged-entry
-  vapi
+AC_CONFIG_FILES([
+  Makefile
+  libgd/Makefile
+  src/Makefile
 ])
-
-AC_CONFIG_FILES([Makefile
-                 vapi/Makefile
-                 vapi/upstream/Makefile
-                 src/Makefile
-                 libgd/Makefile
-                 data/Makefile
-                 po/Makefile.in
-                 data/gnome-music.desktop.in
-                 ])
-
 AC_OUTPUT
diff --git a/git.mk b/git.mk
new file mode 100644
index 0000000..d5bf7b8
--- /dev/null
+++ b/git.mk
@@ -0,0 +1,227 @@
+# git.mk
+#
+# Copyright 2009, Red Hat, Inc.
+# Copyright 2010,2011 Behdad Esfahbod
+# Written by Behdad Esfahbod
+#
+# Copying and distribution of this file, with or without modification,
+# is permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved.
+#
+# The latest version of this file can be downloaded from:
+#   https://raw.github.com/behdad/git.mk/master/git.mk
+# Bugs, etc, should be reported upstream at:
+#   https://github.com/behdad/git.mk
+#
+# To use in your project, import this file in your git repo's toplevel,
+# then do "make -f git.mk".  This modifies all Makefile.am files in
+# your project to -include git.mk.  Remember to add that line to new
+# Makefile.am files you create in your project, or just rerun the
+# "make -f git.mk".
+#
+# This enables automatic .gitignore generation.  If you need to ignore
+# more files, add them to the GITIGNOREFILES variable in your Makefile.am.
+# But think twice before doing that.  If a file has to be in .gitignore,
+# chances are very high that it's a generated file and should be in one
+# of MOSTLYCLEANFILES, CLEANFILES, DISTCLEANFILES, or MAINTAINERCLEANFILES.
+#
+# The only case that you need to manually add a file to GITIGNOREFILES is
+# when remove files in one of mostlyclean-local, clean-local, distclean-local,
+# or maintainer-clean-local make targets.
+#
+# Note that for files like editor backup, etc, there are better places to
+# ignore them.  See "man gitignore".
+#
+# If "make maintainer-clean" removes the files but they are not recognized
+# by this script (that is, if "git status" shows untracked files still), send
+# me the output of "git status" as well as your Makefile.am and Makefile for
+# the directories involved and I'll diagnose.
+#
+# For a list of toplevel files that should be in MAINTAINERCLEANFILES, see
+# Makefile.am.sample in the git.mk git repo.
+#
+# Don't EXTRA_DIST this file.  It is supposed to only live in git clones,
+# not tarballs.  It serves no useful purpose in tarballs and clutters the
+# build dir.
+#
+# This file knows how to handle autoconf, automake, libtool, gtk-doc,
+# gnome-doc-utils, yelp.m4, mallard, intltool, gsettings, dejagnu.
+#
+# This makefile provides the following targets:
+#
+# - all: "make all" will build all gitignore files.
+# - gitignore: makes all gitignore files in the current dir and subdirs.
+# - .gitignore: make gitignore file for the current dir.
+# - gitignore-recurse: makes all gitignore files in the subdirs.
+#
+# KNOWN ISSUES:
+#
+# - Recursive configure doesn't work as $(top_srcdir)/git.mk inside the
+#   submodule doesn't find us.  If you have configure.{in,ac} files in
+#   subdirs, add a proxy git.mk file in those dirs that simply does:
+#   "include $(top_srcdir)/../git.mk".  Add more ..'s to your taste.
+#   And add those files to git.  See vte/gnome-pty-helper/git.mk for
+#   example.
+#
+
+git-all: git-mk-install
+
+git-mk-install:
+       @echo Installing git makefile
+       @any_failed=; \
+               find "`test -z "$(top_srcdir)" && echo . || echo "$(top_srcdir)"`" -name Makefile.am | while 
read x; do \
+               if grep 'include .*/git.mk' $$x >/dev/null; then \
+                       echo $$x already includes git.mk; \
+               else \
+                       failed=; \
+                       echo "Updating $$x"; \
+                       { cat $$x; \
+                         echo ''; \
+                         echo '-include $$(top_srcdir)/git.mk'; \
+                       } > $$x.tmp || failed=1; \
+                       if test x$$failed = x; then \
+                               mv $$x.tmp $$x || failed=1; \
+                       fi; \
+                       if test x$$failed = x; then : else \
+                               echo Failed updating $$x; >&2 \
+                               any_failed=1; \
+                       fi; \
+       fi; done; test -z "$$any_failed"
+
+.PHONY: git-all git-mk-install
+
+
+### .gitignore generation
+
+$(srcdir)/.gitignore: Makefile.am $(top_srcdir)/git.mk
+       $(AM_V_GEN) \
+       { \
+               if test "x$(DOC_MODULE)" = x -o "x$(DOC_MAIN_SGML_FILE)" = x; then :; else \
+                       for x in \
+                               $(DOC_MODULE)-decl-list.txt \
+                               $(DOC_MODULE)-decl.txt \
+                               tmpl/$(DOC_MODULE)-unused.sgml \
+                               "tmpl/*.bak" \
+                               xml html \
+                       ; do echo /$$x; done; \
+               fi; \
+               if test "x$(DOC_MODULE)$(DOC_ID)" = x -o "x$(DOC_LINGUAS)" = x; then :; else \
+                       for lc in $(DOC_LINGUAS); do \
+                               for x in \
+                                       $(if $(DOC_MODULE),$(DOC_MODULE).xml) \
+                                       $(DOC_PAGES) \
+                                       $(DOC_INCLUDES) \
+                               ; do echo /$$lc/$$x; done; \
+                       done; \
+                       for x in \
+                               $(_DOC_OMF_ALL) \
+                               $(_DOC_DSK_ALL) \
+                               $(_DOC_HTML_ALL) \
+                               $(_DOC_MOFILES) \
+                               $(DOC_H_FILE) \
+                               "*/.xml2po.mo" \
+                               "*/*.omf.out" \
+                       ; do echo /$$x; done; \
+               fi; \
+               if test "x$(HELP_ID)" = x -o "x$(HELP_LINGUAS)" = x; then :; else \
+                       for lc in $(HELP_LINGUAS); do \
+                               for x in \
+                                       $(HELP_FILES) \
+                                       "$$lc.stamp" \
+                                       "$$lc.mo" \
+                               ; do echo /$$lc/$$x; done; \
+                       done; \
+               fi; \
+               if test "x$(gsettings_SCHEMAS)" = x; then :; else \
+                       for x in \
+                               $(gsettings_SCHEMAS:.xml=.valid) \
+                               $(gsettings__enum_file) \
+                       ; do echo /$$x; done; \
+               fi; \
+               if test -f $(srcdir)/po/Makefile.in.in; then \
+                       for x in \
+                               po/Makefile.in.in \
+                               po/Makefile.in \
+                               po/Makefile \
+                               po/POTFILES \
+                               po/stamp-it \
+                               po/.intltool-merge-cache \
+                               "po/*.gmo" \
+                               "po/*.mo" \
+                               po/$(GETTEXT_PACKAGE).pot \
+                               intltool-extract.in \
+                               intltool-merge.in \
+                               intltool-update.in \
+                       ; do echo /$$x; done; \
+               fi; \
+               if test -f $(srcdir)/configure; then \
+                       for x in \
+                               autom4te.cache \
+                               configure \
+                               config.h \
+                               stamp-h1 \
+                               libtool \
+                               config.lt \
+                       ; do echo /$$x; done; \
+               fi; \
+               if test "x$(DEJATOOL)" = x; then :; else \
+                       for x in \
+                               $(DEJATOOL) \
+                       ; do echo /$$x.sum; echo /$$x.log; done; \
+                       echo /site.exp; \
+               fi; \
+               for x in \
+                       .gitignore \
+                       $(GITIGNOREFILES) \
+                       $(CLEANFILES) \
+                       $(PROGRAMS) $(check_PROGRAMS) $(EXTRA_PROGRAMS) \
+                       $(LIBRARIES) $(check_LIBRARIES) $(EXTRA_LIBRARIES) \
+                       $(LTLIBRARIES) $(check_LTLIBRARIES) $(EXTRA_LTLIBRARIES) \
+                       so_locations \
+                       .libs _libs \
+                       $(MOSTLYCLEANFILES) \
+                       "*.$(OBJEXT)" \
+                       "*.lo" \
+                       $(DISTCLEANFILES) \
+                       $(am__CONFIG_DISTCLEAN_FILES) \
+                       $(CONFIG_CLEAN_FILES) \
+                       TAGS ID GTAGS GRTAGS GSYMS GPATH tags \
+                       "*.tab.c" \
+                       $(MAINTAINERCLEANFILES) \
+                       $(BUILT_SOURCES) \
+                       $(DEPDIR) \
+                       Makefile \
+                       Makefile.in \
+                       "*.orig" \
+                       "*.rej" \
+                       "*.bak" \
+                       "*~" \
+                       ".*.sw[nop]" \
+                       ".dirstamp" \
+               ; do echo /$$x; done; \
+       } | \
+       sed "s ^/`echo "$(srcdir)" | sed 's/\(.\)/[\1]/g'`/@/@" | \
+       sed 's@/[.]/@/@g' | \
+       LC_ALL=C sort | uniq > $  tmp && \
+       mv $  tmp $@;
+
+all: $(srcdir)/.gitignore gitignore-recurse-maybe
+gitignore: $(srcdir)/.gitignore gitignore-recurse
+
+gitignore-recurse-maybe:
+       @for subdir in $(DIST_SUBDIRS); do \
+         case " $(SUBDIRS) " in \
+           *" $$subdir "*) :;; \
+           *) test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) .gitignore 
gitignore-recurse-maybe || echo "Skipping $$subdir");; \
+         esac; \
+       done
+gitignore-recurse:
+       @for subdir in $(DIST_SUBDIRS); do \
+           test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) .gitignore gitignore-recurse || 
echo "Skipping $$subdir"); \
+       done
+
+maintainer-clean: gitignore-clean
+gitignore-clean:
+       -rm -f $(srcdir)/.gitignore
+
+.PHONY: gitignore-clean gitignore gitignore-recurse gitignore-recurse-maybe
diff --git a/src/Makefile.am b/src/Makefile.am
index d285385..695ef5c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,71 +1,35 @@
 NULL =
 
-AM_CPPFLAGS = \
-       -include config.h                                       \
-       $(MUSIC_CFLAGS)                                         \
-       -DLOCALEDIR=\""$(localedir)"\"          \
-       -DPKGDATADIR=\""$(pkgdatadir)"\"        \
-       -DPKGLIBDIR=\""$(pkglibdir)"\"          \
-       -DGNOME_DESKTOP_USE_UNSTABLE_API        \
-       -I$(top_srcdir)/libgd               \
+nodist_bin_SCRIPTS = gnome-music
+
+jsdir = $(pkgdatadir)
+dist_js_DATA = \
+       album_art_cache.js \
+       player.js \
+       toolbar.js \
+       application.js \
+       gnome-music.in \
+       grilo.js \
+       query.js \
+       widgets.js \
+       main.js \
+       package.js \
+       searchbar.js \
+       view.js \
        $(NULL)
 
-AM_VALAFLAGS = \
-       --vapidir=$(srcdir)/                    \
-       --vapidir=$(top_srcdir)/libgd   \
-    --vapidir=$(top_srcdir)/vapi       \
-       --pkg config                                    \
-       --pkg gd-1.0                                    \
-       @MUSIC_PACKAGES@                                \
-       $(NULL)
-
-bin_PROGRAMS = gnome-music
-
-vala_sources = \
-        music-app.vala                 \
-        music-topbar.vala              \
-        music-searchbar.vala           \
-        music-player.vala              \
-               music-collection-view.vala      \
-               music-list-store.vala           \
-               music-playlist.vala             \
-               music-playlist-view.vala        \
-               music-playlist-songs.vala       \
-               music-album-info-box.vala       \
-               music-browse-history.vala       \
-               music-clickable-label.vala      \
-               music-utils.vala                        \
-               album-art-cache.vala            \
-               main.vala                       \
-               $(NULL)
-
-gsettingsschema_in_files = org.gnome.Music.gschema.xml.in
-gsettings_SCHEMAS = $(gsettingsschema_in_files:.xml.in=.xml)
-.PRECIOUS: $(gsettings_SCHEMAS)
-
- INTLTOOL_XML_NOMERGE_RULE@
-
- GSETTINGS_RULES@
-
-music-resources.c: music.gresource.xml app-menu.ui
-       $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $(srcdir)/music.gresource.xml \
-               --target=$@ --sourcedir=$(srcdir) --c-name music --generate-source
-
-gnome_music_SOURCES =  \
-       $(vala_sources)         \
-       $(NULL)
-
-gnome_music_LDADD =    $(MUSIC_LIBS)                                   \
-                                       $(top_builddir)/libgd/libgd.la  \
-                                       $(NULL)
-
-CLEANFILES = \
-       $(vala_sources:.vala=.c)        \
-       $(gsettings_SCHEMAS)            \
-       *.vapi *.stamp
-
-EXTRA_DIST = \
-       music.gresource.xml                     \
-       app-menu.ui                                     \
-       $(gsettingsschema_in_files)     \
-       $(NULL)
+gnome-music: gnome-music.in
+       $(AM_V_GEN) sed \
+               -e "s|[ ]GJS@|$(GJS)|g" \
+               -e "s|[ ]PACKAGE_NAME@|$(PACKAGE_NAME)|g" \
+               -e "s|[ ]PACKAGE_VERSION@|$(PACKAGE_VERSION)|g" \
+               -e "s|[ ]prefix@|$(prefix)|g" \
+               -e "s|[ ]libdir@|$(libdir)|g" \
+               -e "s|[ ]pkgdatadir@|$(pkgdatadir)|g" \
+               $< > $@
+       @chmod +x $@
+
+EXTRA_DIST = gnome-music.in
+DISTCLEANFILES = gnome-music
+
+-include $(top_srcdir)/git.mk
diff --git a/src/album_art_cache.js b/src/album_art_cache.js
new file mode 100644
index 0000000..c28a825
--- /dev/null
+++ b/src/album_art_cache.js
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2013 Seif Lotfy <seif lotfy com>.
+ *
+ * Gnome Music is free software; you can Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Gnome Music is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with Gnome Music; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+const Lang = imports.lang;
+const GdkPixbuf = imports.gi.GdkPixbuf;
+const GLib = imports.gi.GLib;
+const Gio = imports.gi.Gio;
+const Regex = GLib.Regex;
+const Path = GLib.Path;
+const Grl = imports.gi.Grl;
+
+const invalid_chars = /[()<>\[\]{}_! #$^&*+=|\\\/\"'?~]/g;
+const convert_chars = /[\t]/g;
+const blocks = ["()", "{}", "[]", "<>"];
+
+
+function escapeRegExp(str) {
+    return str.replace(/[\(\)\[\]\<\>\{\}\_\!\ \#\$\^\&\*\+\=\|\\\/\"\'\?\~]/g, "\\$&");
+}
+
+String.prototype.printf = function() {
+   var content = this;
+
+   for (let i = 0; i < arguments.length; i++) {
+        let replacement = '{' + i + '}';
+
+        content = content.replace(replacement, arguments[i]);
+   }
+
+   return content;
+};
+
+const AlbumArtCache = new Lang.Class({
+    Name: "AlbumArtCache",
+    Extends: GLib.Object,
+
+    _init: function() {
+        this.parent();
+        this.block_regexes = [];
+        this.space_compress_regex = new RegExp("\\s+");
+
+        for (let i in blocks) {
+            let block = blocks[i],
+                block_re = escapeRegExp(block[0]) + "[^" + escapeRegExp(block[1]) + "]*" + 
escapeRegExp(block[1]);
+
+            this.block_regexes.push(new RegExp(block_re));
+        }
+
+        this.cache_dir = GLib.build_filenamev([GLib.get_user_cache_dir (), "media-art"]);
+    },
+
+    lookup: function(size, artist_, album_) {
+        var artist = artist_,
+            album = album_;
+
+        if (artist == null) {
+            artist = " " ;
+        }
+
+        if (album == null) {
+            album = " ";
+        }
+
+        try {
+            let key = "album-" + this.normalizeAndHash(artist) + "-" + this.normalizeAndHash(album);
+            let path = GLib.build_filenamev([this.cache_dir, key + ".jpeg"]);
+
+            return GdkPixbuf.Pixbuf.new_from_file_at_scale(path, size, -1, true);
+        }
+
+        catch (error) {
+            //print (error)
+        }
+
+        try {
+            let key = "album-" + this.normalizeAndHash(artist, false, true) + "-" + 
this.normalizeAndHash(album, false, true);
+            let path = GLib.build_filenamev([this.cache_dir, key + ".jpeg"]);
+
+            return GdkPixbuf.Pixbuf.new_from_file_at_scale(path, size, -1, true);
+        }
+
+        catch (error) {
+            //print (error)
+        }
+
+        try {
+            let key = "album-" + this.normalizeAndHash(" ", false, true) + "-" + 
this.normalizeAndHash(album, false, true);
+            let path = GLib.build_filenamev([this.cache_dir, key + ".jpeg"]);
+
+            return GdkPixbuf.Pixbuf.new_from_file_at_scale(path, size, -1, true);
+        }
+
+        catch (error) {
+            //print (error)
+        }
+
+        try {
+            let key = "album-" + this.normalizeAndHash(artist + "\t" + album, true, true);
+            let path = GLib.build_filenamev ([this.cache_dir, key + ".jpeg"]);
+
+            return GdkPixbuf.Pixbuf.new_from_file_at_scale(path, size, -1, true);
+        }
+
+        catch (error) {
+            //print (error)
+        }
+
+        return null;
+    },
+
+    normalizeAndHash: function(input, utf8_only, utf8) {
+        var normalized = " ";
+
+        if (input != null && input != "") {
+            if (utf8_only) {
+                normalized = input;
+            }
+
+            else {
+                normalized = this.stripInvalidEntities(input);
+                normalized = normalized.toLowerCase();
+            }
+
+            if (utf8) {
+                normalized = GLib.utf8_normalize(normalized, -1, 2)
+            }
+        }
+
+        return GLib.compute_checksum_for_string(GLib.ChecksumType.MD5, normalized, -1);
+    },
+
+    stripInvalidEntities: function(original) {
+        var result = original;
+
+        for (let i in this.block_regexes) {
+            let re = this.block_regexes[i];
+
+            result = result.replace(re, '');
+        }
+
+        result = result
+            .replace(invalid_chars, '')
+            .replace(convert_chars, ' ')
+            .replace(this.space_compress_regex, ' ');
+
+        return result;
+    },
+
+    getFromUri: function(uri, artist, album, width, height, callback) {
+        if (uri != null) {
+            print ("missing", album, artist)
+            let key = "album-" + this.normalizeAndHash(artist) + "-" + this.normalizeAndHash(album);
+            let path = GLib.build_filenamev([this.cache_dir, key + ".jpeg"]);
+            var file = Gio.File.new_for_uri(uri);
+            file.read_async(300, null, Lang.bind(this,
+                function(source, res, user_data) {
+                    var stream = file.read_finish(res);
+                    var icon = GdkPixbuf.Pixbuf.new_from_stream_at_scale(stream, height, width, true, null);
+                    var new_file = Gio.File.new_for_path(path);
+                    file.copy(new_file, Gio.FileCopyFlags.NONE, null, null)
+                    callback(icon);
+            }));
+        }
+    }
+
+});
+
+AlbumArtCache.instance = null;
+
+AlbumArtCache.getDefault = function() {
+    if (AlbumArtCache.instance == null) {
+        AlbumArtCache.instance = new AlbumArtCache();
+    }
+
+    return AlbumArtCache.instance;
+};
diff --git a/src/application.js b/src/application.js
new file mode 100644
index 0000000..908aad7
--- /dev/null
+++ b/src/application.js
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2013 Eslam Mostafa.
+ *
+ * Gnome Music is free software; you can Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Gnome Music is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with Gnome Music; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Eslam Mostafa <cseslam gmail com>
+ *
+ */
+
+
+const Lang = imports.lang;
+const Gtk = imports.gi.Gtk;
+const Gdk = imports.gi.Gdk;
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const Gd = imports.gi.Gd;
+
+const Toolbar = imports.toolbar;
+const Views = imports.view;
+const Player = imports.player;
+
+const Gettext = imports.gettext;
+const _ = imports.gettext.gettext;
+
+var AppState = {
+    ARTISTS: 0,
+    ALBUMS: 1,
+    SONGS: 2,
+    PLAYLISTS: 3,
+    PLAYLIST: 4,
+    PLAYLIST_NEW: 5
+};
+
+const Application = new Lang.Class({
+    Name: 'Music',
+    Extends: Gtk.Application,
+
+    _init: function() {
+        this.parent({
+            application_id:     'org.gnome.Music',
+            flags:              Gio.ApplicationFlags.FLAGS_NONE,
+            inactivity_timeout: 12000
+        });
+
+        GLib.set_prgname('gnome-music');
+        GLib.set_application_name(_("Music"));
+
+        this.connect('activate', Lang.bind(this, this._onActivate));
+        this.connect('startup', Lang.bind(this, this._onStartup));
+   },
+
+    _buildApp: function() {
+        this._window = new Gtk.ApplicationWindow({
+            application:        this,
+            title:              _("Music"),
+            window_position:    Gtk.WindowPosition.CENTER,
+            hide_titlebar_when_maximized: true
+        });
+
+
+        this._window.set_size_request (800, 600)
+        this.vbox = new Gtk.Box({
+            orientation:        Gtk.Orientation.VERTICAL,
+            spacing:            0
+        });
+
+        this.player = new Player.Player();
+
+        this.views = new Array();
+
+        this.toolbar = new Toolbar.Toolbar();
+        this._stack = new Gd.Stack({
+            visible:            true
+        });
+
+        this._window.set_default_size(640, 400);
+        this.vbox.pack_start(this.toolbar, false, false, 0);
+        this.vbox.pack_start(this._stack, true, true, 0);
+        this.vbox.pack_start(this.player.eventbox, false, false, 0);
+        this._window.add(this.vbox);
+
+        this.views[0] = new Views.Albums(this.toolbar);
+        this.views[1] = new Views.Artists(this.toolbar);
+        this.views[2] = new Views.Songs(this.toolbar);
+        this.views[3] = new Views.Playlists(this.toolbar);
+
+        for (let i in this.views) {
+            this._stack.add_titled(
+                this.views[i],
+                this.views[i].title,
+                this.views[i].title
+            );
+        }
+
+        //this._stack.connect("notify::visible-child", this._onNotifyMode);
+
+        this.views[0].populate();
+        this.toolbar.set_stack(this._stack);
+        this.toolbar.show();
+        this.player.eventbox.show_all();
+        this.vbox.show();
+    },
+
+    _onNotifyMode: function(stack, param) {
+        stack.get_visible_child().populate();
+    },
+
+    _buildAppMenu: function() {
+        var builder,
+            menu;
+
+        builder = new Gtk.Builder();
+        builder.add_from_file('resources/app-menu.ui'); //fix this
+
+        menu = builder.get_object('app-menu');
+        this.set_app_menu(menu);
+    },
+
+    _toggleView: function(btn, i) {
+        this._stack.set_visible_child(this.views[i])
+    },
+
+    switchToView: function(view) {
+        if (view == 'artists') {
+            this.notebook.set_current_page(0);
+        }
+
+        else if (view == 'albums') {
+            this.notebook.set_current_page(1);
+        }
+
+        else if (view == 'songs') {
+            this.notebook.set_current_page(2);
+        }
+
+        else if (view == 'playlists') {
+            this.notebook.set_current_page(3);
+        }
+
+        this.notebook.show_all();
+    },
+
+    _onActivate: function() {
+        this._window.show();
+    },
+
+    _onStartup: function() {
+        this._buildApp();
+    }
+});
diff --git a/src/clickable_label.js b/src/clickable_label.js
new file mode 100644
index 0000000..f4ec997
--- /dev/null
+++ b/src/clickable_label.js
@@ -0,0 +1,34 @@
+const Gtk = imports.gi.Gtk;
+const Gdk = imports.gi.Gdk;
+const Lang = imports.lang;
+
+const ClickableLabel = new Lang.Class({
+    Name: "ClickableLabel",
+    Extends: Gtk.EventBox,
+    
+    _init: function (text) {
+        let hbox = new Gtk.HBox ();
+        let label = new Gtk.Label ({label : text});
+        label.set_alignment(0, 0.5);
+        
+        this.parent ();
+        hbox.add (label);
+        this.add(hbox);
+        /*
+        this.connect ("enter_notify_event", function () {
+                       let cursor = new Gdk.Cursor ({Gdk.CursorType.HAND2});
+                       
+                       this.get_window ().set_cursor (cursor);
+                       return false;
+        });
+        
+        this.connect("leave_notify_event", function () {
+                       let cursor = new Gdk.Cursor (Gdk.CursorType.Arrow);
+                       
+                       this.get_window ().set_cursor (cursor);
+                       return false;
+               });
+        */ 
+    },
+    
+});
diff --git a/src/gnome-music.in b/src/gnome-music.in
new file mode 100644
index 0000000..599e93d
--- /dev/null
+++ b/src/gnome-music.in
@@ -0,0 +1,7 @@
+#! GJS@
+imports.searchPath.push("@pkgdatadir@");
+imports.package.start({ name: "@PACKAGE_NAME@",
+                        version: "@PACKAGE_VERSION@",
+                        prefix: "@prefix@",
+                        libdir: "@libdir@" });
+
diff --git a/src/grilo.js b/src/grilo.js
new file mode 100644
index 0000000..2372f1b
--- /dev/null
+++ b/src/grilo.js
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2013 Eslam Mostafa <cseslam gmail com>.
+ * Copyright (c) 2013 Seif Lotfy <seif lotfy com>.
+ *
+ * Gnome Music is free software; you can Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Gnome Music is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with Gnome Music; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *
+ */
+
+const Grl = imports.gi.Grl;
+const Lang = imports.lang;
+const Signals = imports.signals;
+const Tracker = imports.gi.Tracker;
+const Query = imports.query;
+const tracker = Tracker.SparqlConnection.get (null);
+
+Grl.init (null, 0);
+const Grilo = new Lang.Class({
+    Name: 'Grilo',
+
+    _init: function() {
+        this.registry = Grl.Registry.get_default ();
+        this.registry.load_all_plugins();
+
+        let sources = {};
+        this.sources = sources;
+        this.tracker = null;
+
+        this.registry.connect ("source_added",
+            Lang.bind(this, this._onSourceAdded));
+
+        this.registry.connect ("source_removed",
+            function (pluginRegistry, mediaSource) {
+                log ("source removed");
+            });
+
+        if (this.registry.load_all == false) {
+            log ("Failed to load plugins.");
+        }
+    },
+
+    _onSourceAdded: function(pluginRegistry, mediaSource) {
+        if (mediaSource.sourceId == "grl-tracker-source") {
+            let ops = mediaSource.supported_operations ();
+            if (ops & Grl.SupportedOps.SEARCH) {
+        print ("Detected new source availabe: '" +
+                     mediaSource.get_name () +
+                     "' and it supports search");
+                this.sources[mediaSource.sourceId] = mediaSource;
+                this.tracker = mediaSource;
+                if (this.tracker != null)
+                    this.emit('ready');
+            }
+        }
+    },
+
+    populateAlbums: function (offset, callback) {
+        this.populateItems (Query.album, offset, callback)
+    },
+
+    populateSongs: function (offset, callback) {
+        this.populateItems (Query.songs, offset, callback)
+    },
+
+    populateItems: function (query, offset, callback) {
+        var options = Grl.OperationOptions.new(null);
+        options.set_flags (Grl.ResolutionFlags.FULL | Grl.ResolutionFlags.IDLE_RELAY);
+        options.set_count(50);
+        query = query + " OFFSET " + offset;
+        grilo.tracker.query(
+            query,
+                [Grl.METADATA_KEY_ID, Grl.METADATA_KEY_TITLE, Grl.METADATA_KEY_ARTIST],
+                options,
+                Lang.bind(this, callback, null));
+    },
+
+    getAlbumSongs: function (artist, album, callback) {
+        var query =  Query.album_songs(artist, album);
+        var options = Grl.OperationOptions.new(null);
+        options.set_flags (Grl.ResolutionFlags.FULL | Grl.ResolutionFlags.IDLE_RELAY);
+        grilo.tracker.query(
+            query,
+                [Grl.METADATA_KEY_ID, Grl.METADATA_KEY_TITLE, Grl.METADATA_KEY_ARTIST],
+                options,
+                Lang.bind(this, callback, null));
+    },
+
+    _searchCallback: function search_cb () {
+        log ("yeah");
+    },
+
+    search: function (q) {
+        for each (let source in this.sources) {
+            log (source.get_name () + " - " + q);
+            source.search (q, [Grl.METADATA_KEY_ID], 0, 10,
+                           Grl.MetadataResolutionFlags.FULL |
+                               Grl.MetadataResolutionFlags.IDLE_RELAY,
+                           this._searchCallback, source);
+        }
+    },
+});
+Signals.addSignalMethods(Grilo.prototype);
+
+let grilo = new Grilo();
diff --git a/src/main.js b/src/main.js
new file mode 100644
index 0000000..6196be2
--- /dev/null
+++ b/src/main.js
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2013 Eslam Mostafa <cseslam gmail com>.
+ * Copyright (c) 2013 Seif Lotfy <seif lotfy com>.
+ *
+ * Gnome Music is free software; you can Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Gnome Music is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with Gnome Music; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+pkg.initSubmodule('libgd')
+
+const GIRepository = imports.gi.GIRepository;
+const App = imports.application;
+
+let app = new App.Application();
+app.run(ARGV);
diff --git a/src/models.js b/src/models.js
new file mode 100644
index 0000000..3b7a570
--- /dev/null
+++ b/src/models.js
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013 Eslam Mostafa.
+ *
+ * Gnome Music is free software; you can Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Gnome Music is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with Gnome Music; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Eslam Mostafa <cseslam gmail com>
+ *
+ */
+
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+
+const Columns = {
+    ID:             Gd.MainColumns.ID,
+    URI:            Gd.MainColumns.URI,
+    PRIMARY_TEXT:   Gd.MainColumns.PRIMARY_TEXT,
+    SECONDARY_TEXT: Gd.MainColumns.SECONDARY_TEXT,
+    ICON:           Gd.MainColumns.ICON,
+    MTIME:          Gd.MainColumns.MTIME,
+    SELECTED:       Gd.MainColumns.SELECTED,
+    LOCATION:       7,
+    INFO:           8
+};
+
+const BaseModel = new Lang.Class({
+    Name: "BaseModel",
+    Extends: Gtk.ListStore,
+
+    _init: function() {
+        this.parent();
+    },
+
+    push_item: function(tracker_id, uri, title, artists, icon, duration, data) {
+        var iter = this.append();
+
+        this.set(iter, [Columns.PRIMARY_TEXT, Columns.ICON], title, icon);
+    }
+});
+
+const AlbumModel = new Lang.Class({
+    Name: "AlbumModel",
+    Extends: BaseModel,
+
+    _init: function() {
+        this.parent();
+
+        this.set_columns([
+            GObject.TYPE_STRING,        // Album id
+            GObject.TYPE_STRING,        // Album uri
+            GObject.TYPE_STRING,        // Album title
+            GObject.TYPE_STRING,        // Album artists
+            GObject.TYPE_STRING,        // Album data
+            GdkPixbuf.Pixbuf,           // Album icon
+            GObject.TYPE_INT,           // Album duration
+            GObject.TYPE_BOOLEAN        // Album ??
+        ]);
+    }
+});
+
+const ArtistsModel = new Lang.Class({
+    Name: "ArtistModel",
+    Extends: BaseModel,
+
+    _init: function() {
+        this.parent();
+    }
+});
+
+const SongModel = new Lang.Class({
+    Name: "SongModel",
+    Extends: BaseModel,
+
+    _init: function() {
+        this.parent();
+    }
+});
+
+const PlaylistModel = new Lang.Class({
+    Name: "PlaylistModel",
+    Extends: BaseModel,
+
+    _init: function() {
+        this.parent();
+    }
+});
\ No newline at end of file
diff --git a/src/package.js b/src/package.js
new file mode 100644
index 0000000..67d98d1
--- /dev/null
+++ b/src/package.js
@@ -0,0 +1,282 @@
+// Copyright 2012 Giovanni Campagna
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+
+/**
+ * This module provides a set of convenience APIs for building packaged
+ * applications.
+ */
+
+const GLib = imports.gi.GLib;
+const GIRepository = imports.gi.GIRepository;
+const System = imports.system;
+
+const Gettext = imports.gettext;
+
+/*< public >*/
+var name;
+var version;
+var prefix;
+var datadir;
+var libdir;
+var pkgdatadir;
+var pkglibdir;
+var moduledir;
+var localedir;
+
+/*< private >*/
+let _base;
+let _requires;
+
+/**
+ * init:
+ * @params: package parameters
+ *
+ * Initialize directories and global variables. Must be called
+ * before any of other API in Package is used.
+ * @params must be an object with at least the following keys:
+ *  - name: the package name ($(PACKAGE_NAME) in autotools)
+ *  - version: the package version
+ *  - prefix: the installation prefix
+ *
+ * init() will take care to check if the program is running from
+ * the source directory or not, by looking for a 'src' directory.
+ *
+ * At the end, the global variable 'pkg' will contain the
+ * Package module (imports.package). Additionally, the following
+ * module variables will be available:
+ *  - name, version: same as in @params
+ *  - prefix: the installation prefix (as passed in @params)
+ *  - datadir, libdir: the final datadir and libdir when installed;
+ *                     usually, these would be prefix + '/share' and
+ *                     and prefix + '/lib' (or '/lib64')
+ *  - pkgdatadir: the directory to look for private data files, such as
+ *                images, stylesheets and UI definitions;
+ *                this will be datadir + name when installed and
+ *                './data' when running from the source tree
+ *  - pkglibdir: the directory to look for private typelibs and C
+ *               libraries;
+ *               this will be libdir + name when installed and
+ *               './lib' when running from the source tree
+ *  - moduledir: the directory to look for JS modules;
+ *               this will be pkglibdir when installed and
+ *               './src' when running from the source tree
+ *  - localedir: the directory containing gettext translation files;
+ *               this will be datadir + '/locale' when installed
+ *               and './po' in the source tree
+ *
+ * All paths are absolute and will not end with '/'.
+ *
+ * As a side effect, init() calls GLib.set_prgname().
+ */
+function init(params) {
+    window.pkg = imports.package;
+    name = params.name;
+    version = params.version;
+
+    // Must call it first, because it can only be called
+    // once, and other library calls might have it as a
+    // side effect
+    GLib.set_prgname(name);
+
+    prefix = params.prefix;
+    libdir = params.libdir;
+    datadir = GLib.build_filenamev([prefix, 'share']);
+    let libpath, girpath;
+
+    if (GLib.file_test('./src',
+                       GLib.FileTest.IS_DIR)) {
+        log('Running from source tree, using local files');
+        // Running from source directory
+        _base = GLib.get_current_dir();
+        pkglibdir = GLib.build_filenamev([_base, 'lib']);
+        libpath = GLib.build_filenamev([pkglibdir, '.libs']);
+        girpath = pkglibdir;
+        pkgdatadir = GLib.build_filenamev([_base, 'data']);
+        localedir = GLib.build_filenamev([_base, 'po']);
+        moduledir = GLib.build_filenamev([_base, 'src']);
+    } else {
+        _base = prefix;
+        pkglibdir = GLib.build_filenamev([libdir, name]);
+        libpath = pkglibdir;
+        girpath = GLib.build_filenamev([pkglibdir, 'girepository-1.0']);
+        pkgdatadir = GLib.build_filenamev([datadir, name]);
+        localedir = GLib.build_filenamev([datadir, 'locale']);
+        moduledir = pkgdatadir;
+    }
+
+    imports.searchPath.push(moduledir);
+    GIRepository.Repository.prepend_search_path(girpath);
+    GIRepository.Repository.prepend_library_path(libpath);
+}
+
+/**
+ * start:
+ * @params: see init()
+ *
+ * This is a convenience function if your package has a
+ * single entry point.
+ * You must define a main(ARGV) function inside a main.js
+ * module in moduledir.
+ */
+function start(params) {
+    init(params);
+
+    return imports.main.main(ARGV);
+}
+
+function _checkVersion(required, current) {
+    if (required == '') {
+        // No requirement
+        return true;
+    }
+
+    // Major version must match, it's used for API
+    // incompatible changes.
+    // The rest just needs to be less or equal to
+    // current. The code is generic, but gjs modules
+    // should use only [major, minor]
+    if (required[0] != current[0])
+        return false;
+
+    for (let i = 1; i < Math.min(current.length, required.length); i++) {
+        if (required[i] > current[i])
+            return false;
+        if (required[i] < current[i])
+            return true;
+
+        // else they're equal, go on
+    }
+
+    return true;
+}
+
+function _isGjsModule(name, version) {
+    // This is a subset of the JS modules we offer,
+    // it includes only those that makes sense to use
+    // standalone and in a general app.
+    //
+    // You will not find Gettext or Format here, use
+    // the package functions instead. And Package, obviously,
+    // because it's available as window.package.
+    //
+    // cairo is also a JS module, but the version checking
+    // differs, see _isForeignModule()
+    //
+    // FIXME: Mainloop might be better as a GLib override?
+    // FIXME: Signals should be an extension to Lang
+    const RECOGNIZED_MODULE_NAMES = ['Lang',
+                                     'Mainloop',
+                                     'Signals',
+                                     'System',
+                                     'Params'];
+    for (let i = 0; i < RECOGNIZED_MODULE_NAMES.length; i++) {
+        let module = RECOGNIZED_MODULE_NAMES[i];
+
+        if (module == name) {
+            let actualModule = imports[module.toLowerCase()];
+            let required = version.split('.');
+
+            if (!_checkVersion(required, actualModule.$API_VERSION)) {
+                printerr('Unsatisfied dependency: requested GJS module at version '
+                         + version + ', but only ' + (actualModule.$API_VERSION.join('.'))
+                         + ' is available');
+                System.exit(1);
+            } else {
+                window[module] = actualModule;
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+/**
+ * require:
+ * @libs: the external dependencies to import
+ *
+ * Mark a dependency on a specific version of one or more
+ * external GI typelibs.
+ * @libs must be an object whose keys are a typelib name,
+ * and values are the respective version. The empty string
+ * indicates any version.
+ *
+ * If dependencies are statisfied, require() will make
+ * the module objects available as global names.
+ */
+function require(libs) {
+    _requires = libs;
+
+    for (let l in libs) {
+        let version = libs[l];
+
+        if (_isGjsModule(l, version))
+            continue;
+
+        if (version != '')
+            imports.gi.versions[l] = version;
+
+        try {
+            if (name == 'cairo') {
+                // Import the GI package to check the version,
+                // but then load the JS one
+                imports.gi.cairo;
+                window.cairo = imports.cairo;
+            } else {
+                window[l] = imports.gi[l];
+            }
+        } catch(e) {
+            printerr('Unsatisfied dependency: ' + e.message);
+            System.exit(1);
+        }
+    }
+}
+
+function dumpRequires() {
+    print(JSON.stringify(_requires));
+}
+
+function initGettext() {
+    Gettext.bindtextdomain(name, localedir);
+    Gettext.textdomain(name);
+
+    let gettext = imports.gettext;
+    window._ = gettext.gettext;
+    window.C_ = gettext.pgettext;
+    window.N_ = function(x) { return x; }
+}
+
+function initFormat() {
+    let format = imports.format;
+    String.prototype.format = format.format;
+}
+
+function initSubmodule(name) {
+    if (moduledir != pkgdatadir) {
+        // Running from source tree, add './name' to search paths
+
+        let submoduledir = GLib.build_filenamev([_base, name]);
+        let libpath = GLib.build_filenamev([submoduledir, '.libs']);
+        GIRepository.Repository.prepend_search_path(submoduledir);
+        GIRepository.Repository.prepend_library_path(libpath);
+    } else {
+        // Running installed, submodule is in $(pkglibdir), nothing to do
+    }
+}
diff --git a/src/player.js b/src/player.js
new file mode 100644
index 0000000..e6372db
--- /dev/null
+++ b/src/player.js
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2013 Eslam Mostafa.
+ *
+ * Gnome Music is free software; you can Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Gnome Music is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with Gnome Music; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Eslam Mostafa <cseslam gmail com>
+ *
+ */
+
+const Lang = imports.lang;
+const Gtk = imports.gi.Gtk;
+const Gd = imports.gi.Gd;
+const Gst = imports.gi.Gst;
+const GLib = imports.gi.GLib;
+
+//pkg.initSubmodule('libgd');
+
+const Mainloop = imports.mainloop;
+const AlbumArtCache = imports.album_art_cache;
+
+const ART_SIZE = 240;
+
+const PlayPauseButton = new Lang.Class({
+    Name: "PlayPauseButton",
+    Extends: Gtk.ToggleButton,
+
+    _init: function() {
+        this.play_image = Gtk.Image.new_from_icon_name("media-playback-start-symbolic", Gtk.IconSize.BUTTON);
+        this.pause_image = Gtk.Image.new_from_icon_name("media-playback-pause-symbolic", 
Gtk.IconSize.BUTTON);
+
+        this.parent();
+        this.set_image(this.play_image);
+    },
+});
+
+const Player = new Lang.Class({
+    Name: "Player",
+    //Extends: GLib.Object,
+
+    _init: function(playlist) {
+        this.playlist = playlist;
+        this.cache = AlbumArtCache.AlbumArtCache.getDefault();
+
+        //Gst.init(null, 0);
+        //this.source = new Gst.ElementFactory.make("audiotestrc", "source");
+        //this.sink = new Gst.ElementFactory.make("autoaudiosink", "output");
+        //this.playbin = new Gst.ElementFactory.make("playbin", "playbin");
+        //this.bus = this.playbin.get_bus();
+
+        this._setup_view();
+    },
+
+    _setup_view: function() {
+        var alignment,
+            artist_lbl,
+            box,
+            databox,
+            label,
+            next_btn,
+            play_btn,
+            prev_btn,
+            rate_btn,
+            toolbar_center,
+            toolbar_end,
+            toolbar_start,
+            toolbar_song_info;
+
+        this.eventbox = new Gtk.Box();
+        this.eventbox.set_spacing(9)
+        this.eventbox.set_border_width(9)
+        toolbar_start = new Gtk.Box({
+            orientation:        Gtk.Orientation.HORIZONTAL,
+            spacing:            0
+        });
+        toolbar_start.get_style_context().add_class(Gtk.STYLE_CLASS_LINKED);
+
+        prev_btn = new Gtk.Button();
+        prev_btn.set_image(Gtk.Image.new_from_icon_name("media-skip-backward-symbolic", 
Gtk.IconSize.BUTTON));
+        prev_btn.connect("clicked", Lang.bind(this, this._onPrevBtnClicked));
+        toolbar_start.pack_start(prev_btn, false, false, 0);
+
+        play_btn = new PlayPauseButton();
+        play_btn.connect("toggled", Lang.bind(this, this._onPlayBtnToggled));
+        toolbar_start.pack_start(play_btn, false, false, 0);
+
+        next_btn = new Gtk.Button();
+        next_btn.set_image(Gtk.Image.new_from_icon_name("media-skip-forward-symbolic", Gtk.IconSize.BUTTON));
+        next_btn.connect("clicked", Lang.bind(this, this._onNextBtnClicked));
+        toolbar_start.pack_start(next_btn, false, false, 0);
+        
+        this.eventbox.pack_start(toolbar_start, false, false, 3)
+
+        toolbar_song_info = new Gtk.Box({
+            orientation:        Gtk.Orientation.HORIZONTAL,
+            spacing:            0
+        });
+
+        this.cover_img = new Gtk.Image();
+        toolbar_song_info.pack_start(this.cover_img, false, false, 0);
+
+        databox = new Gtk.Box({
+            orientation:        Gtk.Orientation.VERTICAL,
+            spacing:            0
+        });
+        toolbar_song_info.pack_start(databox, false, false, 0);
+        toolbar_start.pack_start(toolbar_song_info, false, false, 9)
+
+
+        this.title_lbl = new Gtk.Label({
+            label:              ""
+        });
+        databox.pack_start(this.title_lbl, false, false, 0);
+
+        artist_lbl = new Gtk.Label({
+            label:              ""
+        });
+        artist_lbl.get_style_context().add_class("dim-label");
+        databox.pack_start(artist_lbl, false, false, 0);
+
+        toolbar_center = new Gtk.Box({
+            orientation:        Gtk.Orientation.HORIZONTAL,
+            spacing:            0
+        });
+
+        this.progress_scale = new Gtk.Scale({
+            orientation:        Gtk.Orientation.HORIZONTAL,
+            sensitive:          false
+        });
+        this.progress_scale.set_draw_value(false);
+        this._setDuration(1);
+        this.progress_scale.connect("change_value", Lang.bind(this, this.onProgressScaleChangeValue));
+        toolbar_center.pack_start(this.progress_scale, true, true, 0);
+
+        /*this.song_playback_time_lbl = new Gtk.Label({
+            label:              "00:00"
+        });
+        toolbar_center.pack_start(this.song_playback_time_lbl, false, false, 0);
+        label = new Gtk.Label({
+            label:              "/"
+        });
+        toolbar_center.pack_start(label, false, false, 0);
+        this.song_total_time_lbl = new Gtk.Label({
+            label:              "00:00"
+        });
+        toolbar_center.pack_start(this.song_total_time_lbl, false, false, 0);
+        */
+        this.eventbox.pack_start(toolbar_center, true, true, 0)
+
+        toolbar_end = new Gtk.Box({
+            orientation:        Gtk.Orientation.HORIZONTAL,
+            spacing:            5
+        });
+        alignment = new Gtk.Alignment({
+            xalign:             1,
+            yalign:             0.5,
+            xscale:             0,
+            yscale:             0
+        });
+        this.eventbox.pack_end(toolbar_end, false, false, 3);
+
+        rate_btn = new Gtk.Button ();
+        rate_btn.set_image(Gtk.Image.new_from_icon_name("bookmark-new-symbolic", Gtk.IconSize.BUTTON));
+        toolbar_end.pack_end(rate_btn, false, false, 0);
+
+        this.shuffle_btn = new Gtk.ToggleButton ();
+        this.shuffle_btn.set_image (Gtk.Image.new_from_icon_name("media-playlist-shuffle-symbolic", 
Gtk.IconSize.BUTTON));
+        this.shuffle_btn.connect("clicked", Lang.bind(this, this._onShuffleBtnClicked));
+        toolbar_end.pack_end(this.shuffle_btn, false, false, 0);
+
+        this.eventbox.show_all();
+
+    },
+
+    load: function(media) {
+        var pixbuf,
+            uri;
+
+        this._setDuration(media.get_duration());
+        this.song_total_time_lbl.set_label(this.seconds_to_string (media.get_duration()));
+        this.progress_scale.sensitive = true;
+
+        // FIXME: site contains the album's name. It's obviously a hack to remove
+        pixbuf = this.cache.lookup (ART_SIZE, media.get_author (), media.get_site ());
+        this.cover_img.set_from_pixbuf (pixbuf);
+
+        if (media.get_title() != null) {
+            this.title_lbl.set_label(media.get_title());
+        }
+
+        else {
+            let url = media.get_url(),
+                file = GLib.File.new_for_path(url),
+                basename = file.get_basename(),
+                to_show = GLib.Uri.unescape_string(basename, null);
+
+            this.title_lbl.set_label(to_show);
+        }
+
+        artist_lbl.set_label(media.get_author());
+
+        uri = media.get_url();
+    },
+
+    uri: function() {
+    },
+
+    _onPlayBtnToggled: function(btn) {
+        if (btn.get_active()) {
+            //this.beginPlayback();
+        }
+
+        else {
+            //this.pausePlayback();
+        }
+    },
+
+    _onNextBtnClicked: function(btn) {
+        this._needNext();
+    },
+
+    _onPrevBtnClicked: function(btn) {
+        this._needPrevious();
+    },
+
+    _needNext: function() {
+    },
+
+    _needPrevious: function() {
+    },
+
+    _onShuffleBtnClicked: function(order) {
+    },
+
+    _onPlaylistShuffleModeChanged: function(mode) {
+        this.shuffle_btn.set_active(mode);
+    },
+
+    _setDuration: function(duration) {
+        this.progress_scale.set_range(0.0, duration*60);
+        this.progress_scale.set_value(0.0);
+    },
+
+    _updatePosition: function(update) {
+        if (update) {
+            if (this.position_update_timeout == 0) {
+                Timeout.add_seconds(1, Lang.bind(this, this.update_position_cb));
+            }
+        }
+
+        else {
+            if (this.position_update_timeout != 0) {
+                this.source.remove(position_update_timeout);
+                this.position_update_timeout = 0;
+            }
+        }
+    },
+
+    _updatePositionCallback: function() {
+        var format = Gst.Format.TIME,
+            duration = 0,
+            seconds;
+
+        this.playbin.query_position(format, duration);
+        this.progress_scale.set_value(duration);
+
+        seconds = duration / Gst.SECOND;
+
+        this.song_playback_time_lbl.set_label(this.seconds_to_string(seconds));
+
+        return true;
+    },
+
+    onProgressScaleChangeValue: function(scroll, newValue) {
+        this.playbin.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, newValue);
+
+        return false;
+     }
+});
diff --git a/src/query.js b/src/query.js
new file mode 100644
index 0000000..8a647dc
--- /dev/null
+++ b/src/query.js
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2013 Igalia S.L.
+ *                    Authored by: Juan A. Suarez Romero <jasuarez igalia com>
+ *
+ * Gnome Music is free software; you can Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Gnome Music is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with Gnome Music; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *
+ */
+
+const album = 'SELECT rdf:type(?album) tracker:id(?album) as id (SELECT nmm:artistName(?artist) WHERE { 
?album nmm:albumArtist ?artist }  LIMIT 1) AS artist nie:title(?album) as title nie:title(?album) as album 
tracker:coalesce( (SELECT GROUP_CONCAT(nmm:artistName(?artist), ",") WHERE { ?album nmm:albumArtist ?artist 
}), (SELECT GROUP_CONCAT((SELECT nmm:artistName(nmm:performer(?_12)) as perf WHERE { ?_12 nmm:musicAlbum 
?album } GROUP BY ?perf), ",") as album_performer WHERE { }) ) as author 
xsd:integer(tracker:coalesce(nmm:albumTrackCount(?album), (SELECT COUNT(?_1) WHERE { ?_1 nmm:musicAlbum 
?album; tracker:available "true" }))) as childcount (SELECT fn:year-from-dateTime(?c) WHERE { ?_2 
nmm:musicAlbum ?album; nie:contentCreated ?c; tracker:available "true" } LIMIT 1) as publishing-date { ?album 
a nmm:MusicAlbum FILTER (EXISTS { ?_3 nmm:musicAlbum ?album; tracker:available "true" }) } ORDER BY 
?album_artist ?albumyear nie:title(?album)';
+
+const album_count = 'SELECT COUNT(?album) AS childcount WHERE { ?album a nmm:MusicAlbum }';
+
+const songs = 'SELECT rdf:type(?song) tracker:id(?song) as id nie:url(?song) as url  nie:title(?song) as 
title nmm:artistName(nmm:performer(?song)) as artist  nie:title(nmm:musicAlbum(?song)) as album 
nfo:duration(?song) as duration { ?song a nmm:MusicPiece } ORDER BY tracker:added(?song)';
+
+const songs_count = 'SELECT COUNT(?song) AS childcount WHERE { ?song a nmm:MusicPiece }';
+
+function album_songs (artistName, albumTitle) {
+    var query = "SELECT rdf:type(?song) tracker:id(?song) as id nie:url(?song) as url  nie:title(?song) as 
title nmm:artistName(nmm:performer(?song)) as artist  nie:title(nmm:musicAlbum(?song)) as album 
nfo:duration(?song) as duration { ?song a nmm:MusicPiece ; nmm:performer [ nmm:artistName '%an' ]  ; 
nmm:musicAlbum  [ nmm:albumTitle '%at' ] } ORDER BY tracker:added(?song)";
+    query = query.replace("%an", artistName);
+    query = query.replace("%at", albumTitle);
+    return query;
+}
diff --git a/src/resources/app-menu.ui b/src/resources/app-menu.ui
new file mode 100644
index 0000000..a45acc9
--- /dev/null
+++ b/src/resources/app-menu.ui
@@ -0,0 +1,27 @@
+<interface>
+  <menu id="app-menu">
+    <section>
+      <item>
+        <attribute name="action">app.newPlaylist</attribute>
+        <attribute name="label" translatable="yes">_New Playlist</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="action">app.nowPlaying</attribute>
+        <attribute name="label" translatable="yes">_Now Playing</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="action">app.about</attribute>
+        <attribute name="label" translatable="yes">_About Contacts</attribute>
+      </item>
+      <item>
+        <attribute name="action">app.quit</attribute>
+        <attribute name="label" translatable="yes">_Quit</attribute>
+        <attribute name="accel">&lt;Primary&gt;q</attribute>
+    </item>
+    </section>
+  </menu>
+</interface>
diff --git a/data/gtk-style.css b/src/resources/gtk-style.css
similarity index 99%
rename from data/gtk-style.css
rename to src/resources/gtk-style.css
index 06aef5d..fdf22fb 100644
--- a/data/gtk-style.css
+++ b/src/resources/gtk-style.css
@@ -92,3 +92,4 @@
     font-weight: bold;
     color: mix (@theme_fg_color, @theme_bg_color, 0.50);    
 }
+
diff --git a/src/resources/lp.jpg b/src/resources/lp.jpg
new file mode 100644
index 0000000..e1be0ba
Binary files /dev/null and b/src/resources/lp.jpg differ
diff --git a/src/music.gresource.xml b/src/resources/music.gresource.xml
similarity index 100%
rename from src/music.gresource.xml
rename to src/resources/music.gresource.xml
diff --git a/src/org.gnome.Music.gschema.xml.in b/src/resources/org.gnome.Music.gschema.xml.in
similarity index 100%
rename from src/org.gnome.Music.gschema.xml.in
rename to src/resources/org.gnome.Music.gschema.xml.in
diff --git a/src/searchbar.js b/src/searchbar.js
new file mode 100644
index 0000000..29344c4
--- /dev/null
+++ b/src/searchbar.js
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2013 Eslam Mostafa.
+ *
+ * Gnome Music is free software; you can Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Gnome Music is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with Gnome Music; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Author: Eslam Mostafa <cseslam gmail com>
+ *
+ */
+
+const Lang = imports.lang;
+const Gtk = imports.gi.Gtk;
+const Gdk = imports.gi.Gdk;
+const Gd = imports.gi.Gd;
+
+const Searchbar = new Lang.Class({
+    Name: "Searchbar",
+    
+    actor: function() { return this._eventbox; },
+    
+    _eventbox: null,
+    
+    _search_entry: null,
+    
+    _init: function() {
+        this._setup_ui();
+    },
+    
+    _setup_ui: function() {
+        this._eventbox = new Gtk.EventBox();
+        //this._eventbox.margin_top = 5;
+        //this._eventbox.margin_bottom = 5;
+        
+        let container = new Gd.MarginContainer();
+        //container.min_margin = 64;
+        //container.max_margin = 128;
+        this._eventbox.add (container);
+        
+        let box = new Gtk.Box({orientation: Gtk.Orientation.HORIZONTAL, spacing : 0});
+        container.add(box);
+        
+        this._search_entry = new Gd.TaggedEntry();
+        this._search_entry.hexpand = true;
+        this._search_entry.key_press_event.connect (on_search_entry_key_pressed);
+        this._search_entry.changed.connect (on_search_entry_changed);
+        this._search_entry.tag_clicked.connect (on_search_entry_tag_clicked);
+        box.add (this._search_entry);
+        
+        this._eventbox.show_all();
+    },
+    
+    _on_search_entry_key_pressed: function(e) {
+        let keyval = e.keyval;
+        
+        if(keyval == Gdk.Key.Escape) {
+            //App.app.search_mode = false;
+            return true;
+        }
+        
+        return false;
+    },
+    
+    _on_search_entry_changed: function() {
+        debug("2");
+    },
+    
+    _on_search_entry_tag_clicked: function() {
+        debug("3");
+    },
+    
+    show: function() {
+        this.actor.show();
+    },
+    
+    hide: function() {
+        this.actor.hide();
+    },
+    
+    grab_focus: function() {
+        this._search_entry.grab_focus();
+    },
+    
+});
+
+const Dropdown = new Lang.Class({
+    Name: 'Dropdown',
+
+    _init: function() {
+        this._sourceView = new Manager.BaseView(Application.sourceManager);
+        this._typeView = new Manager.BaseView(Application.searchTypeManager);
+        this._matchView = new Manager.BaseView(Application.searchMatchManager);
+        // TODO: this is out for now, but should we move it somewhere
+        // else?
+        // this._categoryView = new Manager.BaseView(Application.searchCategoryManager);
+
+        this._sourceView.connect('item-activated',
+                                 Lang.bind(this, this._onItemActivated));
+        this._typeView.connect('item-activated',
+                               Lang.bind(this, this._onItemActivated));
+        this._matchView.connect('item-activated',
+                                Lang.bind(this, this._onItemActivated));
+
+        let frame = new Gtk.Frame({ shadow_type: Gtk.ShadowType.IN,
+                                    opacity: 0.9 });
+        frame.get_style_context().add_class('documents-dropdown');
+
+        this.widget = new Gd.Revealer({ halign: Gtk.Align.CENTER,
+                                        valign: Gtk.Align.START });
+        this.widget.add(frame);
+
+        this._grid = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL });
+        frame.add(this._grid);
+
+        this._grid.add(this._sourceView.widget);
+        this._grid.add(this._typeView.widget);
+        this._grid.add(this._matchView.widget);
+        //this._grid.add(this._categoryView.widget);
+
+        this.hide();
+        this.widget.show_all();
+    },
+});
diff --git a/src/toolbar.js b/src/toolbar.js
new file mode 100644
index 0000000..8d3e57d
--- /dev/null
+++ b/src/toolbar.js
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013 Next Tuesday GmbH.
+ *               Authored by: Seif Lotfy <sfl nexttuesday de>
+ * Copyright (c) 2013 Seif Lotfy <seif lotfy com>.
+ *
+ * Gnome Music is free software; you can Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Gnome Music is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with Gnome Music; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+const Lang = imports.lang;
+
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const Gtk = imports.gi.Gtk;
+const Gd = imports.gi.Gd;
+const Pango = imports.gi.Pango;
+const Signals = imports.signals;
+
+const Gettext = imports.gettext;
+const _ = imports.gettext.gettext;
+
+const Searchbar = imports.searchbar;
+
+const ToolbarState = {
+    SINGLE: 0,
+    ALBUMS: 1,
+    ARTISTS: 2,
+    PLAYLISTS: 3,
+    SONGS: 4};
+
+const Toolbar = new Lang.Class({
+    Name: 'MainToolbar',
+    Extends: Gd.HeaderBar,
+
+    _init: function() {
+        this.parent();
+        this._stack_switcher = new Gd.StackSwitcher ();
+        this.set_custom_title (null);
+        this._addBackButton();
+    },
+
+    set_stack: function(stack) {
+        this._stack_switcher.set_stack (stack);
+    },
+
+    get_stack: function() {
+        return this._stack_switcher.get_stack();
+    },
+
+    setState: function (state) {
+        if (state == ToolbarState.SINGLE) {
+            this.custom_title = null
+            this._backButton.show()
+        }
+        else {
+            this.title = ""
+            this.custom_title = this._stack_switcher;
+            this._backButton.hide()
+        }
+        this.emit ("state-changed")
+    },
+
+    _addBackButton: function() {
+        let iconName =
+            (this.get_direction() == Gtk.TextDirection.RTL) ?
+            'go-next-symbolic' : 'go-previous-symbolic';
+        this._backButton = new Gd.HeaderSimpleButton({ symbolic_icon_name: iconName,
+                                                     label: _("Back") });
+        this._backButton.connect('clicked', Lang.bind(this, this.setState))
+        this.pack_start(this._backButton);
+    }
+});
+Signals.addSignalMethods(Toolbar.prototype);
diff --git a/src/view.js b/src/view.js
new file mode 100644
index 0000000..0092b43
--- /dev/null
+++ b/src/view.js
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2013 Next Tuesday GmbH.
+ *               Authored by: Seif Lotfy
+ * Copyright (c) 2013 Eslam Mostafa.
+ * Copyright (c) 2013 Seif Lotfy.
+ *
+ * Gnome Music is free software; you can Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Gnome Music is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with Gnome Music; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+const Lang = imports.lang;
+const Gtk = imports.gi.Gtk;
+const Gdk = imports.gi.Gdk;
+const GdkPixbuf = imports.gi.GdkPixbuf;
+const GObject = imports.gi.GObject;
+const Gd = imports.gi.Gd;
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const Grl = imports.gi.Grl;
+const Tracker = imports.gi.Tracker;
+const Signals = imports.signals;
+const Application = imports.application;
+const Query = imports.query;
+const Widgets = imports.widgets;
+const Toolbar = imports.toolbar;
+
+const tracker = Tracker.SparqlConnection.get (null);
+const AlbumArtCache = imports.album_art_cache;
+const Grilo = imports.grilo;
+const albumArtCache = AlbumArtCache.AlbumArtCache.getDefault();
+
+function extractFileName(uri) {
+    var exp = /^.*[\\\/]|[.][^.]*$/g;
+    return unescape(uri.replace(exp, ''));
+}
+
+const grilo = Grilo.grilo;
+
+
+const LoadMoreButton = new Lang.Class({
+    Name: 'LoadMoreButton',
+    _init: function(counter) {
+        this._block = false;
+        this._counter = counter;
+        let child = new Gtk.Grid({ column_spacing: 10,
+                                   hexpand: true,
+                                   halign: Gtk.Align.CENTER,
+                                   visible: true });
+
+        this._spinner = new Gtk.Spinner({ halign: Gtk.Align.CENTER,
+                                          no_show_all: true });
+        this._spinner.set_size_request(16, 16);
+        child.add(this._spinner);
+
+        this._label = new Gtk.Label({ label: "Load More",
+                                      visible: true });
+        child.add(this._label);
+
+        this.widget = new Gtk.Button({ no_show_all: true,
+                                       child: child });
+        this.widget.get_style_context().add_class('documents-load-more');
+        this.widget.connect('clicked', Lang.bind(this,
+            function() {
+                this._label.label = "Loading...";
+                this._spinner.show();
+                this._spinner.start();
+            }));
+
+        this._onItemCountChanged();
+    },
+
+    _onItemCountChanged: function() {
+        let remainingDocs = this._counter();
+        let visible = !(remainingDocs <= 0 || this._block);
+        this.widget.set_visible(visible);
+
+        if (!visible) {
+            this._label.label = "Load More";
+            this._spinner.stop();
+            this._spinner.hide();
+        }
+    },
+
+    setBlock: function(block) {
+        if (this._block == block)
+            return;
+
+        this._block = block;
+        this._onItemCountChanged();
+    }
+});
+
+const ViewContainer = new Lang.Class({
+    Name: "ViewContainer",
+    Extends: Gd.Stack,
+
+    _init: function(title, header_bar) {
+        this.parent({transition_type: Gd.StackTransitionType.CROSSFADE});
+        this._grid = new Gtk.Grid({orientation: Gtk.Orientation.VERTICAL})
+        this._iconWidth = -1
+        this._iconHeight = 128
+        this._offset = 0;
+        this._adjustmentValueId = 0;
+        this._adjustmentChangedId = 0;
+        this._scrollbarVisibleId = 0;
+        this._model = Gtk.ListStore.new([
+            GObject.TYPE_STRING,
+            GObject.TYPE_STRING,
+            GObject.TYPE_STRING,
+            GObject.TYPE_STRING,
+            GdkPixbuf.Pixbuf,
+            GObject.TYPE_OBJECT,
+            GObject.TYPE_BOOLEAN
+        ]);
+        this.view = new Gd.MainView({
+            shadow_type:    Gtk.ShadowType.NONE
+        });
+        this.view.set_view_type(Gd.MainViewType.ICON);
+        this.view.set_model(this._model);
+        this._grid.add(this.view);
+
+        this._loadMore = new LoadMoreButton(this._getRemainingItemCount);
+        this._grid.add(this._loadMore.widget);
+        this._loadMore.widget.connect("clicked", Lang.bind(this, this.populate))
+        this.view.connect('item-activated',
+                            Lang.bind(this, this._onItemActivated));
+        this._cursor = null;
+        this.header_bar = header_bar;
+        this.title = title;
+
+        this.add(this._grid)
+
+        this.show_all();
+        this._items = [];
+        this._loadMore.widget.hide();
+        this._connectView();
+        grilo.connect('ready', Lang.bind(this, this.populate));
+        this.header_bar.connect('state-changed', Lang.bind(this, this._onStateChanged))
+    },
+
+    _onStateChanged: function() {
+    },
+
+    _connectView: function() {
+        this._adjustmentValueId = this.view.vadjustment.connect(
+            'value-changed',
+            Lang.bind(this, this._onScrolledWinChange)
+        );
+        this._adjustmentChangedId = this.view.vadjustment.connect(
+            'changed',
+            Lang.bind(this, this._onScrolledWinChange)
+        );
+        this._scrollbarVisibleId = this.view.get_vscrollbar().connect(
+            'notify::visible',
+            Lang.bind(this, this._onScrolledWinChange)
+        );
+        this._onScrolledWinChange();
+    },
+
+    _onScrolledWinChange: function() {
+        let vScrollbar = this.view.get_vscrollbar();
+        let adjustment = this.view.vadjustment;
+        let revealAreaHeight = 32;
+
+        // if there's no vscrollbar, or if it's not visible, hide the button
+        if (!vScrollbar ||
+            !vScrollbar.get_visible()) {
+            this._loadMore.setBlock(true);
+            return;
+        }
+
+        let value = adjustment.value;
+        let upper = adjustment.upper;
+        let page_size = adjustment.page_size;
+
+        let end = false;
+        // special case this values which happen at construction
+        if ((value == 0) && (upper == 1) && (page_size == 1))
+            end = false;
+        else
+            end = !(value < (upper - page_size - revealAreaHeight));
+        if (this._getRemainingItemCount() <= 0)
+            end = false;
+        this._loadMore.setBlock(!end);
+    },
+
+    populate: function() {
+    },
+
+    _addItem: function(source, param, item) {
+        if (item != null) {
+            this._offset += 1;
+            let path = "/usr/share/icons/gnome/scalable/places/folder-music-symbolic.svg";
+            let icon = GdkPixbuf.Pixbuf.new_from_file_at_scale(path, this._iconHeight, this._iconWidth, 
true);
+            var iter = this._model.append();
+            var artist = "Unkown"
+            if (item.get_author() != null)
+                artist = item.get_author();
+            if (item.get_string(Grl.METADATA_KEY_ARTIST) != null)
+                artist = item.get_string(Grl.METADATA_KEY_ARTIST)
+            if (item.get_title() == null) {
+                item.set_title (extractFileName(item.get_url()));
+            }
+            this._model.set(
+                    iter,
+                    [0, 1, 2, 3, 4, 5],
+                    [toString(item.get_id()), "", item.get_title(), artist, icon, item]
+                );
+            GLib.idle_add(300, Lang.bind(this, this._updateAlbumArt, item, iter));
+        }
+    },
+
+    _getRemainingItemCount: function () {
+        let count = -1;
+        if (this.countQuery != null) {
+            let cursor = tracker.query(this.countQuery, null)
+            if (cursor != null && cursor.next(null))
+                count = cursor.get_integer(0);
+        }
+        return ( count - this._offset);
+    },
+
+    _updateAlbumArt: function(item, iter) {
+        var artist = null;
+        if (item.get_author() != null)
+            artist = item.get_author();
+        if (item.get_string(Grl.METADATA_KEY_ARTIST) != null)
+            artist = item.get_string(Grl.METADATA_KEY_ARTIST)
+        var icon = albumArtCache.lookup(this._iconHeight, artist, item.get_string(Grl.METADATA_KEY_ALBUM));
+        if (icon != null) {
+            this._model.set_value(iter, 4, icon);
+            return false;
+        }
+        var options = Grl.OperationOptions.new(null);
+        options.set_flags (Grl.ResolutionFlags.FULL | Grl.ResolutionFlags.IDLE_RELAY);
+        grilo.tracker.resolve(
+            item,
+            [Grl.METADATA_KEY_THUMBNAIL],
+            options,
+            Lang.bind(this,
+            function(source, param, item) {
+                var uri = item.get_thumbnail();
+                albumArtCache.getFromUri(uri, 
+                    artist, 
+                    item.get_string(Grl.METADATA_KEY_ALBUM),
+                    this._iconWidth,
+                    this._iconHeight,
+                    Lang.bind(this,
+                        function (icon) {
+                            this._model.set_value(iter, 4, icon);
+                        }))
+            }));
+        return false;
+    },
+
+    _addListRenderers: function () {
+    },
+
+    _onItemActivated: function (widget, id, path) {
+    }
+
+});
+
+const Albums = new Lang.Class({
+    Name: "AlbumsView",
+    Extends: ViewContainer,
+
+    _init: function(header_bar){
+        this.parent("Albums", header_bar);
+        this.view.set_view_type(Gd.MainViewType.ICON);
+        this.countQuery = Query.album_count;
+        this._albumWidget = new Widgets.AlbumWidget ();
+        this.add(this._albumWidget)
+        this.header_bar.setState (1);
+    },
+
+    _onStateChanged: function (widget) {
+        if (this.header_bar.get_stack() != null && 
+            this == this.header_bar.get_stack().get_visible_child())
+            this.visible_child = this._grid;
+    },
+
+    _onItemActivated: function (widget, id, path) {
+        var iter = this._model.get_iter (path)[1]
+        var title = this._model.get_value (iter, 2)
+        var artist = this._model.get_value (iter, 3)
+        var item = this._model.get_value (iter, 5)
+        var window = new Gtk.Window ()
+        this._albumWidget.update (artist, title, item)
+        this.header_bar.setState (0);
+        this.header_bar.title = title
+        this.header_bar.sub_title = artist
+        this.visible_child = this._albumWidget
+    },
+
+    populate: function() {
+        if (grilo.tracker != null)
+            grilo.populateAlbums (this._offset, Lang.bind(this, this._addItem, null));
+    },
+
+});
+
+const Songs = new Lang.Class({
+    Name: "SongsView",
+    Extends: ViewContainer,
+
+    _init: function(header_bar) {
+        this.parent("Songs", header_bar);
+        this.countQuery = Query.songs_count;
+        this._items = {};
+        this.view.set_view_type(Gd.MainViewType.LIST);
+        this._iconHeight = 32
+        this._iconWidth = 32
+        this._addListRenderers();
+    },
+
+    _addListRenderers: function() {
+        let listWidget = this.view.get_generic_view();
+
+        let typeRenderer =
+            new Gd.StyledTextRenderer({ xpad: 0 });
+        typeRenderer.add_class('dim-label');
+        typeRenderer.set_property("ellipsize", 3);
+        listWidget.add_renderer(typeRenderer, Lang.bind(this,
+            function(col, cell, model, iter) {
+                let item = model.get_value(iter, 5);
+                typeRenderer.set_property("ellipsize", 3);
+                typeRenderer.text = item.get_string(Grl.METADATA_KEY_ALBUM);
+            }));
+
+        let durationRenderer =
+            new Gd.StyledTextRenderer({ xpad: 16 });
+        durationRenderer.add_class('dim-label');
+        listWidget.add_renderer(durationRenderer, Lang.bind(this,
+            function(col, cell, model, iter) {
+                let item = model.get_value(iter, 5);
+                let duration = item.get_duration ();
+                var minutes = parseInt(duration / 60);
+                var seconds = duration % 60;
+                var time = null
+                if (seconds < 10)
+                    time =  minutes + ":0" + seconds;
+                else
+                    time = minutes + ":" + seconds;
+                durationRenderer.text = time;
+            }));
+    },
+
+    populate: function() {
+        if (grilo.tracker != null)
+            grilo.populateSongs (this._offset, Lang.bind(this, this._addItem, null));
+    },
+
+});
+
+const Playlists = new Lang.Class({
+    Name: "PlaylistsView",
+    Extends: ViewContainer,
+
+    _init: function(header_bar) {
+        this.parent("Playlists", header_bar);
+    },
+});
+
+const Artists = new Lang.Class({
+    Name: "ArtistsView",
+    Extends: ViewContainer,
+
+    _init: function(header_bar) {
+        this.parent("Artists", header_bar);
+    },
+});
diff --git a/src/widgets.js b/src/widgets.js
new file mode 100644
index 0000000..5a1498d
--- /dev/null
+++ b/src/widgets.js
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2013 Eslam Mostafa <cseslam gmail com>.
+ * Copyright (c) 2013 Seif Lotfy <seif lotfy com>.
+ *
+ * Gnome Music is free software; you can Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Gnome Music is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with Gnome Music; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+const Gtk = imports.gi.Gtk;
+const Gdk = imports.gi.Gdk;
+const GdkPixbuf = imports.gi.GdkPixbuf;
+const Gio = imports.gi.Gio;
+const Lang = imports.lang;
+const Grl = imports.gi.Grl;
+const Query = imports.query;
+const Grilo = imports.grilo;
+
+const grilo = Grilo.grilo;
+const AlbumArtCache = imports.album_art_cache;
+const albumArtCache = AlbumArtCache.AlbumArtCache.getDefault();
+
+const ClickableLabel = new Lang.Class({
+    Name: "ClickableLabel",
+    Extends: Gtk.Button,    
+    
+    _init: function (track) {        
+        this.track = track
+        var text = track.get_title()
+        var duration = track.get_duration()
+        let box = new Gtk.HBox();
+        let label = new Gtk.Label({ label : text });
+        label.set_alignment(0.0, 0.5)
+
+        var minutes = parseInt(duration / 60);
+        var seconds = duration % 60;
+        var time = null
+        if (seconds < 10)
+            time =  minutes + ":0" + seconds;
+        else
+            time = minutes + ":" + seconds;
+        let length_label = new Gtk.Label({ label : time });
+        length_label.set_alignment(0.0, 0.5)
+        
+        this.parent();
+        this.set_relief(Gtk.ReliefStyle.NONE);
+        this.set_can_focus(false);
+        box.homogeneous = true;
+        box.pack_start(label, true, true, 0);
+        box.pack_end(length_label, true, true, 0);
+        this.add(box);
+        this.show_all();
+            
+        this.connect("clicked", Lang.bind(this, this._on_btn_clicked));
+    },
+    
+    _on_btn_clicked: function(btn) {
+    },
+    
+});
+
+
+const AlbumWidget = new Lang.Class({
+    Name: "AlbumWidget",
+    Extends: Gtk.EventBox,
+    
+    _init: function (album) {
+        this.hbox = new Gtk.HBox ();
+        this.box = new Gtk.VBox();
+        this.scrolledWindow = new Gtk.ScrolledWindow();
+        this.songsList = new Gtk.VBox();
+        this.cover = new Gtk.Image();
+        this.vbox = new Gtk.VBox();
+        this.title_label = new Gtk.Label({label : ""});
+        this.artist_label = new Gtk.Label({label : ""});
+        this.tracks_labels = {};
+        this.running_length = 0;
+        this.released_label = new Gtk.Label()
+        this.released_label.set_markup ("<span color='grey'>Released</span>");
+        this.running_length_label = new Gtk.Label({});
+        this.running_length_label.set_markup ("<span color='grey'>Running Length</span>");
+        this.released_label_info = new Gtk.Label({label: "----"});
+        this.running_length_label_info = new Gtk.Label({label: "--:--"});
+        this.released_label.set_alignment(1.0, 0.5)
+        this.running_length_label.set_alignment(1.0, 0.5)
+        this.released_label_info.set_alignment(0.0, 0.5)
+        this.running_length_label_info.set_alignment(0.0, 0.5)
+
+        this.parent();
+        this.hbox.set_homogeneous(true);
+        this.box.set_homogeneous (false);
+        this.songsList.pack_start(new Gtk.Label(), false, false, 24)
+        this.songsList.pack_end(new Gtk.Label(), true, true, 24)
+        this.vbox.set_homogeneous(false);
+        this.scrolledWindow.set_policy(
+            Gtk.PolicyType.NEVER,
+            Gtk.PolicyType.AUTOMATIC);
+        this.scrolledWindow.add(this.songsList);
+
+
+        this.infobox = new Gtk.Box()
+        this.infobox.homogeneous = true;
+        this.infobox.spacing = 36
+        var box = new Gtk.VBox();
+        box.pack_start (this.released_label, false, false, 0)
+        box.pack_start (this.running_length_label, false, false, 0)
+        this.infobox.pack_start(box, true, true, 0)
+        box = new Gtk.VBox();
+        box.pack_start (this.released_label_info, false, false, 0)
+        box.pack_start (this.running_length_label_info, false, false, 0)
+        this.infobox.pack_start(box, true, true, 0)
+
+        this.vbox.pack_start (new Gtk.Label({label:""}), false, false, 24);
+        this.vbox.pack_start (this.cover, false, false, 0);
+        this.vbox.pack_start (this.title_label, false, false, 9);
+        this.vbox.pack_start (this.artist_label, false, false, 0);
+        this.vbox.pack_start (new Gtk.Label({label:""}), false, false, 6);
+        this.vbox.pack_start(this.infobox, false, false, 0)
+        this.box.pack_end (this.scrolledWindow, true, true, 0);
+
+        let hbox = new Gtk.Box()
+        hbox.pack_start (new Gtk.Label({label: ""}), true, true, 0)
+        hbox.pack_start (this.vbox, false, false, 0)
+        this.hbox.pack_start (hbox, true, true, 64);
+        this.hbox.pack_start (this.box, true, true, 6);
+
+        this.get_style_context ().add_class ("view");
+        this.get_style_context ().add_class ("content-view");
+        this.add(this.hbox)
+        this.show_all ()
+    },
+
+    update: function (artist, album, item) {
+        var pixbuf = albumArtCache.lookup (256, artist, item.get_string(Grl.METADATA_KEY_ALBUM));
+        let duration = 0;
+        for (let t in this.tracks_labels) {            
+            this.songsList.remove(this.tracks_labels[t]);
+        }
+        this.tracks_labels = {};
+        grilo.getAlbumSongs(artist, album, Lang.bind(this, function (source, prefs, track) {
+            if (track != null) {
+                duration = duration + track.get_duration()
+                this.tracks_labels[track.get_title()] = new ClickableLabel (track);
+                this.songsList.pack_start(this.tracks_labels[track.get_title()], false, false, 0);
+                this.running_length_label_info.set_text(parseInt(duration/60) + " min")
+            }
+        }));
+
+        //update labels view
+        var i = 0 ;                                        
+        for (let t in this.tracks_labels) {                                
+            let length = new Gtk.Label ({label : tracks[t]}); //use this._toTimeLength()    
+            this.songsList.pack_start(this.tracks_labels[t], false, false, 0);
+            this.running_length = this.running_length+ parseInt(tracks[t], 10);
+            i++;
+        }
+                
+        if (pixbuf == null) {
+            let path = "/usr/share/icons/gnome/scalable/places/folder-music-symbolic.svg";
+            pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(path, -1, 256, true);
+        }
+        this.cover.set_from_pixbuf (pixbuf);
+        
+        this.setArtistLabel(artist);
+        this.setTitleLabel(album);        
+    },
+    
+    setArtistLabel: function(artist) {
+        this.artist_label.set_markup("<b><span size='large' color='grey'>" + artist + "</span></b>");
+    },
+    
+    setTitleLabel: function(title) {
+        this.title_label.set_markup("<b><span size='large'>" + title + "</span></b>");
+    },
+
+});



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]