ui: Added webkit view
[maevies] / ui / maeviesui / maeviesui / gui.py
index 175f1a0..c5787a0 100644 (file)
 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ###########################################################################
 
-from maeviesui.util import constants
-
-import hildon
 import pygtk
+import os
+pygtk.require('2.0')
+import gtk
+import hildon
 import pango
 import gobject
-import random
-pygtk.require("2.0")
-import gtk
+from webkit import WebView
+
+from maeviesui.util import constants
+from maeviesui.util.asyncworker import AsyncWorker, AsyncItem
+from maeviesui.util.util import image_downloader
+from maeviesui.util.moviemanager import MovieManager, TmdbMovie, TmdbMovieImage, \
+    WatcMovie
+
+moviemanager = MovieManager()
 
 class Maevies(hildon.StackableWindow):
 
@@ -37,7 +44,7 @@ class Maevies(hildon.StackableWindow):
 
     def __init__(self):
         super(Maevies, self).__init__()
-        self.set_title("Maevies - 0.1")
+        self.set_title('Maevies - 0.1')
         self.connect('delete-event',
                      lambda widget, event: gtk.main_quit())
 
@@ -51,11 +58,11 @@ class Maevies(hildon.StackableWindow):
         box.set_border_width(20)
 
         button = hildon.Button(gtk.HILDON_SIZE_THUMB_HEIGHT,
-                               hildon.BUTTON_ARRANGEMENT_VERTICAL, title, subtitle)
-        button.connect("clicked", self._button_clicked, action)
+                               hildon.BUTTON_ARRANGEMENT_VERTICAL,
+                               title, subtitle)
+        button.connect('clicked', self._button_clicked, action)
 
-        box.pack_start(button,
-                             expand = True, fill = False)
+        box.pack_start(button, expand=True, fill=False)
 
         return box
 
@@ -63,24 +70,31 @@ class Maevies(hildon.StackableWindow):
         contents = gtk.HBox()
         contents.set_border_width(60)
         contents.set_homogeneous(True)
-        contents.pack_start(self._create_button("On Theaters", "Movies playing",
-                                             self.ACTION_THEATERS),
-                            expand = True, fill = True)
-        contents.pack_start(self._create_button("Favorites", "Your saved searches",
-                                             self.ACTION_FAVORITES),
-                            expand = True, fill = True)
-        contents.pack_start(self._create_button("Search", "Enter a new search",
-                                             self.ACTION_SEARCH),
-                            expand = True, fill = True)
+        contents.pack_start(self._create_button('On Theaters',
+                                                'Movies playing',
+                                                self.ACTION_THEATERS),
+                            expand=True, fill=True)
+        contents.pack_start(self._create_button('Favorites',
+                                                'Your saved searches',
+                                                self.ACTION_FAVORITES),
+                            expand=True, fill=True)
+        contents.pack_start(self._create_button('Search',
+                                                'Enter a new search',
+                                                self.ACTION_SEARCH),
+                            expand=True, fill=True)
 
         return contents;
 
     def _button_clicked(self, button, action):
-        if action == self.ACTION_SEARCH:
+        if action == self.ACTION_THEATERS:
+            theaters_view = TheatersWindow()
+            theaters_view.display_shows()
+        elif action == self.ACTION_SEARCH:
             search_dialog = SearchDialog(self)
             if search_dialog.run() == gtk.RESPONSE_ACCEPT:
-                ResultsWindow(search_term = search_dialog.get_search_term(),
-                              search_category = search_dialog.get_search_category())
+                results_window = ResultsWindow()
+                results_window.start_search(search_dialog.get_search_term(),
+                                            search_dialog.get_search_category())
             search_dialog.destroy()
         elif action == self.ACTION_ABOUT:
             about_dialog = AboutDialog(self)
@@ -91,8 +105,8 @@ class Maevies(hildon.StackableWindow):
         menu = hildon.AppMenu()
 
         about = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
-        about.set_label("About")
-        about.connect("clicked", self._button_clicked, self.ACTION_ABOUT)
+        about.set_label('About')
+        about.connect('clicked', self._button_clicked, self.ACTION_ABOUT)
 
         menu.append(about)
 
@@ -105,15 +119,15 @@ class Maevies(hildon.StackableWindow):
 
 class SearchDialog(gtk.Dialog):
 
-    _search_fields = [
-           "Movies",
-           "People",
-           ]
+    TMDB_SEARCH = 0
+    WATC_SEARCH = 1
+    search_fields = {TMDB_SEARCH:'TMDb',
+                      WATC_SEARCH:'WATC'}
 
     def __init__(self, parent):
-        super(SearchDialog, self).__init__(parent = parent,
-                                            flags = gtk.DIALOG_DESTROY_WITH_PARENT)
-        self.set_title("Enter search terms")
+        super(SearchDialog, self).__init__(parent=parent,
+                                           flags=gtk.DIALOG_DESTROY_WITH_PARENT)
+        self.set_title('Enter search terms')
 
         self.vbox.pack_start(self._create_contents(), True, False, 0)
         self.add_button(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)
@@ -127,22 +141,22 @@ class SearchDialog(gtk.Dialog):
         search_contents = gtk.VBox()
 
         search_contents.pack_start(self._search_entry,
-                                   expand = True, fill = True)
+                                   expand=True, fill=True)
         search_contents.pack_start(search_button,
-                                   expand = True, fill = True)
+                                   expand=True, fill=True)
 
         return search_contents
 
     def _create_picker_button(self):
         self._picker_button = hildon.PickerButton(gtk.HILDON_SIZE_FINGER_HEIGHT,
-                                            hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
-        self._picker_button.set_title("Search for")
+                                                  hildon.BUTTON_ARRANGEMENT_HORIZONTAL)
+        self._picker_button.set_title('Search on')
 
-        selector = hildon.TouchSelector(text = True)
+        selector = hildon.TouchSelector(text=True)
         selector.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
 
-        for field in self._search_fields:
-            selector.append_text(field)
+        for search_method in [self.TMDB_SEARCH, self.WATC_SEARCH]:
+            selector.append_text(self.search_fields[search_method])
 
         self._picker_button.set_selector(selector)
         self._picker_button.set_active(0)
@@ -153,52 +167,51 @@ class SearchDialog(gtk.Dialog):
         return self._search_entry.get_text()
 
     def get_search_category(self):
-        return self._search_fields[self._picker_button.get_active()]
+        return self._picker_button.get_active()
 
 class ResultsWindow(hildon.StackableWindow):
 
-    def __init__(self, search_term, search_category):
+    def __init__(self):
         super(ResultsWindow, self).__init__()
-        self.set_title("Search results")
+        self.set_title('Search results')
 
-        self.search_term = search_term
-        self.search_category = search_category
+        self.add(self._create_contents())
 
-        self._simulate_search()
+        moviemanager.response_received_cb = self._response_received_cb
+        self.show_all()
+
+    def _create_contents(self):
         content_area = hildon.PannableArea()
         self._movies_view = MoviesView()
+        self._movies_view.connect('row-activated', self._row_activated_cb)
 
         content_area.add(self._movies_view)
-        self.add(content_area)
+        return content_area
 
-        self.show_all()
+    def _row_activated_cb(self, view, path, column):
+        movie = view.get_movie_from_path(path)
+        if isinstance(movie, TmdbMovie):
+            MovieWindow(movie)
+        elif isinstance(movie, WatcMovie):
+            WatcWindow(movie)
 
-    def _simulate_search(self):
-        self._show_banner()
+    def start_search(self, search_term, search_category):
+        self._show_banner(search_term, search_category)
         hildon.hildon_gtk_window_set_progress_indicator(self, True)
-        gobject.timeout_add(constants.TIMEOUT_TIME_MILLIS, self._populate_view)
-
-    def _populate_view(self):
-        self._movies_view.add_movies([MovieDecorator("The Lord of the Rings"),
-                                      MovieDecorator("The Lord of the flies"),
-                                      MovieDecorator("Gone by the wind"),
-                                      MovieDecorator("Madagascar"),
-                                      MovieDecorator("Madagascar 2"),
-                                      MovieDecorator("2 Fast 2 Furious"),
-                                      MovieDecorator("Fast &amp; Furious"),
-                                      MovieDecorator("Pitch Black"),
-                                      ])
+        moviemanager.query(search_term, search_category)
+
+    def _response_received_cb(self, movies):
+        self._movies_view.add_movies(movies)
         hildon.hildon_gtk_window_set_progress_indicator(self, False)
-        return False
 
-    def _show_banner(self):
-        message = "Searching <i>%(category)s</i> for <i>%(term)s</i>" % {'category': self.search_category,
-                                                                         'term' : self.search_term}
+    def _show_banner(self, search_term, search_category):
+        message = ('Searching on <i>%(category)s</i> for <i>%(term)s</i>' %
+                   {'category': SearchDialog.search_fields[search_category],
+                    'term' : search_term})
         banner = hildon.hildon_banner_show_information_with_markup(self,
-                                                                   "ignored",
+                                                                   'ignored',
                                                                    message)
         banner.set_timeout(constants.TIMEOUT_TIME_MILLIS)
-        pass
 
 class MoviesView(gtk.TreeView):
 
@@ -208,19 +221,26 @@ class MoviesView(gtk.TreeView):
         self.set_model(model)
 
         movie_image_renderer = gtk.CellRendererPixbuf()
-        column = gtk.TreeViewColumn('Image', movie_image_renderer, pixbuf = model.IMAGE_COLUMN)
+        column = gtk.TreeViewColumn('Image', movie_image_renderer,
+                                    pixbuf=model.IMAGE_COLUMN)
         self.append_column(column)
 
         movie_text_renderer = gtk.CellRendererText()
         movie_text_renderer.set_property('ellipsize', pango.ELLIPSIZE_END)
-        column = gtk.TreeViewColumn('Name', movie_text_renderer, markup = model.INFO_COLUMN)
+        column = gtk.TreeViewColumn('Name', movie_text_renderer,
+                                    markup=model.INFO_COLUMN)
         self.append_column(column)
 
         self.show_all()
 
     def add_movies(self, movie_list):
         model = self.get_model()
-        model.add(movie_list)
+        if model:
+            model.add(movie_list)
+
+    def get_movie_from_path(self, path):
+        model = self.get_model()
+        return model[path][model.MOVIE_COLUMN]
 
 class MoviesListStore(gtk.ListStore):
 
@@ -236,7 +256,7 @@ class MoviesListStore(gtk.ListStore):
     def add(self, movies_found):
         self.clear()
         for movie in movies_found:
-            row = {self.IMAGE_COLUMN: movie.get_image(),
+            row = {self.IMAGE_COLUMN: movie.get_placeholder_image(),
                    self.INFO_COLUMN: movie.get_info(),
                    self.MOVIE_COLUMN: movie,
                   }
@@ -245,39 +265,156 @@ class MoviesListStore(gtk.ListStore):
 class AboutDialog(gtk.Dialog):
 
     def __init__(self, parent):
-        super(AboutDialog, self).__init__(parent = parent,
-                                          flags = gtk.DIALOG_DESTROY_WITH_PARENT)
-        self.set_title("About Maevies")
+        super(AboutDialog, self).__init__(parent=parent,
+                                          flags=gtk.DIALOG_DESTROY_WITH_PARENT)
+        self.set_title('About Maevies')
+
+        self.show_all()
+
+class MovieWindow(hildon.StackableWindow):
+
+    def _fetch_movie_image(self, movie):
+        image = gtk.Image()
+        image.set_from_pixbuf(gtk.IconTheme().load_icon('general_video',
+                                                        256, 0))
+        movie_image = movie.get_image('poster', 'mid')
+        if isinstance(movie_image, TmdbMovieImage):
+            image_file = os.path.abspath('/tmp/' + movie_image.get_id() + '.jpg')
+            if os.path.isfile(image_file):
+                image.set_from_pixbuf(gtk.gdk.pixbuf_new_from_file_at_size(image_file,
+                                                                       256,
+                                                                       256))
+            else:
+                banner = hildon.hildon_banner_show_information_with_markup(self,
+                                                                           'ignored',
+                                                                           'Fetching movie poster')
+                banner.set_timeout(constants.TIMEOUT_TIME_MILLIS)
+                hildon.hildon_gtk_window_set_progress_indicator(self, True)
+
+                async_item = AsyncItem(image_downloader, (movie_image.get_url(),
+                                                          '/tmp/' + movie_image.get_id()),
+                                       self._set_fetched_image, (image,))
+                self.async_worker.queue.put(async_item)
+                self.async_worker.start()
+
+        return image
+
+    def _set_fetched_image(self, image, target, error):
+        if not error:
+            image_file = os.path.abspath(target)
+            image.set_from_pixbuf(gtk.gdk.pixbuf_new_from_file_at_size(image_file,
+                                                                       256,
+                                                                       256))
+        hildon.hildon_gtk_window_set_progress_indicator(self, False)
+
+    def _create_contents(self, movie):
+        main_area = hildon.PannableArea()
+
+        main_box = gtk.VBox(False, 20)
+        main_box.set_border_width(20)
+        upper_content = gtk.HBox(False, 40)
+        upper_content.set_border_width(20)
+
+        image = self._fetch_movie_image(movie)
+
+        side_content = gtk.VBox(False, 30)
+
+        for key in movie.fields:
+            label = gtk.Label()
+            label.set_markup('<b>%(field)s:</b> <small>%(value)s</small>' %
+                             {'field' : key,
+                              'value' : movie.get_value(key)})
+            label.set_alignment(constants.LEFT_ALIGNMENT,
+                                constants.CENTER_ALIGNMENT)
+            side_content.pack_start(label, False, False)
+
+        upper_content.pack_start(image, False, False)
+        upper_content.pack_start(side_content, False, False)
+
+        movie_overview = hildon.TextView()
+        movie_overview.set_placeholder('Overview')
+        movie_overview.set_wrap_mode(gtk.WRAP_WORD)
+        movie_overview.get_buffer().set_text(movie.get_overview())
+
+        label = gtk.Label()
+        label.set_markup('<b>Overview:</b>')
+        label.set_alignment(constants.LEFT_ALIGNMENT,
+                            constants.CENTER_ALIGNMENT)
+
+        main_box.pack_start(upper_content, False, False)
+        main_box.pack_start(label, False, False)
+        main_box.pack_start(movie_overview, False, False)
+
+        main_area.add_with_viewport(main_box)
+        main_area.set_size_request_policy(hildon.SIZE_REQUEST_CHILDREN)
+
+        return main_area
+
+    def __init__(self, movie):
+        super(MovieWindow, self).__init__()
+        self.async_worker = AsyncWorker()
+        self.set_title('Movie info')
+        self.add(self._create_contents(movie))
         self.show_all()
 
-class MovieDecorator:
+class WebkitWindow(hildon.StackableWindow):
 
-    def __init__(self, name):
-        self._name = name
-        pass
+    def __init__(self):
+        super(WebkitWindow, self).__init__()
 
-    def get_name(self):
-        return self._name
+        self.view = WebView()
+        self.view.connect('load-started', self._load_start)
+        self.view.connect('load-finished', self._load_finished)
+        self.view.set_full_content_zoom(True)
 
-    def get_length(self):
-        return "%sh:%sm" % (random.randrange(1, 2), random.randrange(0, 59))
+        wbk_settings = self.view.get_settings()
+        wbk_settings.set_property('auto-shrink-images', True)
 
-    def get_score(self):
-        return "%s" % (random.randrange(6, 9))
+        self.pannable = hildon.PannableArea()
+        self.pannable.add(self.view)
+        self.pannable.set_size_request_policy(hildon.SIZE_REQUEST_CHILDREN)
+        self.pannable.set_property("mov-mode", hildon.MOVEMENT_MODE_BOTH)
 
-    def get_info(self):
-        return "<b>%s</b>\n<small><i>Length: </i>%s || <i>Score: </i>%s</small>" % (
-                                                                                     self.get_name(),
-                                                                                     self.get_length(),
-                                                                                     self.get_score())
+        self.add(self.pannable)
+        self.show_all()
+
+    def _load_start(self, view, data):
+        hildon.hildon_gtk_window_set_progress_indicator(self, True)
 
-    def get_image(self):
-        return self._get_placeholder_pixbuf()
+    def _load_finished(self, view, data):
+        hildon.hildon_gtk_window_set_progress_indicator(self, False)
+
+    def load_url(self, url):
+        self.view.open(url)
 
-    def _get_placeholder_pixbuf(self):
-        pixbuf = gtk.IconTheme().load_icon('general_video_file', 48, 0)
-        return pixbuf
+class TheatersWindow(WebkitWindow):
 
-if __name__ == "__main__":
+    def __init__(self):
+        super(TheatersWindow, self).__init__()
+        self.show_all()
+
+    def display_shows(self):
+        self.load_url('http://www.google.com/movies')
+
+class WatcWindow(WebkitWindow):
+
+    def __init__(self, movie):
+        super(WatcWindow, self).__init__()
+        self.show_all()
+        has_stingers = movie.get_stingers()
+        if has_stingers == 0:
+            stingers = '?'
+        elif has_stingers == 1:
+            stingers = '*'
+        else:
+            stingers = ''
+        url = ('http://whatsafterthecredits.com/index.php?title=%(title)s_(%(year)s)%(stingers)s' %
+                      {'title':movie.get_title().strip(),
+                       'year':movie.get_year().strip(),
+                       'stingers':stingers})
+        print url
+        self.load_url(url)
+
+if __name__ == '__main__':
     maevies = Maevies()
     maevies.run()