Consolidating the Presenter Window code for making changes easier
[watersofshiloah] / src / windows / _base.py
index 3f06913..721aeec 100644 (file)
@@ -14,6 +14,7 @@ import util.go_utils as go_utils
 import stream_index
 import banners
 import playcontrol
+import presenter
 
 
 _moduleLogger = logging.getLogger(__name__)
@@ -180,15 +181,20 @@ class ListWindow(BasicWindow):
 
                self._treeView = gtk.TreeView()
                self._treeView.connect("row-activated", self._on_row_activated)
+               self._treeView.set_property("fixed-height-mode", True)
                self._treeView.set_headers_visible(False)
                self._treeView.set_model(self._model)
                for column in columns:
                        if column is not None:
                                self._treeView.append_column(column)
 
+               viewport = gtk.Viewport()
+               viewport.add(self._treeView)
+
                self._treeScroller = gtk.ScrolledWindow()
-               self._treeScroller.add(self._treeView)
+               self._treeScroller.add(viewport)
                self._treeScroller.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+               self._treeScroller = hildonize.hildonize_scrollwindow(self._treeScroller)
 
                self._separator = gtk.HSeparator()
                self._playcontrol = playcontrol.NavControl(self._player, self._store)
@@ -245,7 +251,9 @@ class ListWindow(BasicWindow):
 
        @misc_utils.log_exception(_moduleLogger)
        def _on_row_activated(self, view, path, column):
-               raise NotImplementedError("")
+               itr = self._model.get_iter(path)
+               node = self._model.get_value(itr, 0)
+               self._window_from_node(node)
 
        @misc_utils.log_exception(_moduleLogger)
        def _on_player_title_change(self, player, node):
@@ -285,3 +293,202 @@ class ListWindow(BasicWindow):
                path = (rowIndex, )
                self._treeView.scroll_to_cell(path)
                self._treeView.get_selection().select_path(path)
+
+
+class PresenterWindow(BasicWindow):
+
+       def __init__(self, app, player, store, node):
+               BasicWindow.__init__(self, app, player, store)
+               self._node = node
+               self._playerNode = self._player.node
+               self._nextSearch = None
+               self._updateSeek = None
+
+               self.connect_auto(self._player, "state-change", self._on_player_state_change)
+               self.connect_auto(self._player, "title-change", self._on_player_title_change)
+               self.connect_auto(self._player, "error", self._on_player_error)
+
+               self._loadingBanner = banners.GenericBanner()
+
+               self._presenter = presenter.StreamPresenter(self._store)
+               self._presenter.set_context(
+                       self._get_background(),
+                       self._node.title,
+                       self._node.subtitle,
+               )
+               self._presenterNavigation = presenter.NavigationBox()
+               self._presenterNavigation.toplevel.add(self._presenter.toplevel)
+               self._presenterNavigation.connect("action", self._on_nav_action)
+               self._presenterNavigation.connect("navigating", self._on_navigating)
+
+               self._seekbar = hildonize.create_seekbar()
+               self._seekbar.connect("change-value", self._on_user_seek)
+
+               self._layout.pack_start(self._loadingBanner.toplevel, False, False)
+               self._layout.pack_start(self._presenterNavigation.toplevel, True, True)
+               self._layout.pack_start(self._seekbar, False, False)
+
+               self._window.set_title(self._node.title)
+
+       def _get_background(self):
+               raise NotImplementedError()
+
+       def show(self):
+               BasicWindow.show(self)
+               self._window.show_all()
+               self._errorBanner.toplevel.hide()
+               self._loadingBanner.toplevel.hide()
+               self._set_context(self._player.state)
+               self._seekbar.hide()
+
+       def jump_to(self, node):
+               assert self._node is node
+
+       @property
+       def _active(self):
+               return self._playerNode is self._node
+
+       def _show_loading(self):
+               animationPath = self._store.STORE_LOOKUP["loading"]
+               animation = self._store.get_pixbuf_animation_from_store(animationPath)
+               self._loadingBanner.show(animation, "Loading...")
+
+       def _hide_loading(self):
+               self._loadingBanner.hide()
+
+       def _set_context(self, state):
+               if state == self._player.STATE_PLAY:
+                       if self._active:
+                               self._presenter.set_state(self._store.STORE_LOOKUP["pause"])
+                       else:
+                               self._presenter.set_state(self._store.STORE_LOOKUP["play"])
+               elif state == self._player.STATE_PAUSE:
+                       self._presenter.set_state(self._store.STORE_LOOKUP["play"])
+               elif state == self._player.STATE_STOP:
+                       self._presenter.set_state(self._store.STORE_LOOKUP["play"])
+               else:
+                       _moduleLogger.info("Unhandled player state %s" % state)
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_user_seek(self, widget, scroll, value):
+               self._player.seek(value / 100.0)
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_player_update_seek(self):
+               if self._isDestroyed:
+                       return False
+               self._seekbar.set_value(self._player.percent_elapsed * 100)
+               return True
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_player_state_change(self, player, newState):
+               if self._active and self._player.state == self._player.STATE_PLAY:
+                       self._seekbar.show()
+                       assert self._updateSeek is None
+                       self._updateSeek = go_utils.Timeout(self._on_player_update_seek, once=False)
+                       self._updateSeek.start(seconds=1)
+               else:
+                       self._seekbar.hide()
+                       if self._updateSeek is not None:
+                               self._updateSeek.cancel()
+                               self._updateSeek = None
+
+               if not self._presenterNavigation.is_active():
+                       self._set_context(newState)
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_player_title_change(self, player, node):
+               if not self._active or node in [None, self._node]:
+                       self._playerNode = player.node
+                       return
+               self._playerNode = player.node
+               self.emit("jump-to", node)
+               self._window.destroy()
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_player_error(self, player, err, debug):
+               _moduleLogger.error("%r - %r" % (err, debug))
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_navigating(self, widget, navState):
+               if navState == "clicking":
+                       if self._player.state == self._player.STATE_PLAY:
+                               if self._active:
+                                       imageName = "pause_pressed"
+                               else:
+                                       imageName = "play_pressed"
+                       elif self._player.state == self._player.STATE_PAUSE:
+                               imageName = "play_pressed"
+                       elif self._player.state == self._player.STATE_STOP:
+                               imageName = "play_pressed"
+                       else:
+                               _moduleLogger.info("Unhandled player state %s" % self._player.state)
+               elif navState == "down":
+                       imageName = "home"
+               elif navState == "up":
+                       if self._player.state == self._player.STATE_PLAY:
+                               if self._active:
+                                       imageName = "pause"
+                               else:
+                                       imageName = "play"
+                       elif self._player.state == self._player.STATE_PAUSE:
+                               imageName = "play"
+                       elif self._player.state == self._player.STATE_STOP:
+                               imageName = "play"
+                       else:
+                               _moduleLogger.info("Unhandled player state %s" % self._player.state)
+               elif navState == "left":
+                       imageName = "next"
+               elif navState == "right":
+                       imageName = "prev"
+
+               self._presenter.set_state(self._store.STORE_LOOKUP[imageName])
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_nav_action(self, widget, navState):
+               self._set_context(self._player.state)
+
+               if navState == "clicking":
+                       if self._player.state == self._player.STATE_PLAY:
+                               if self._active:
+                                       self._player.pause()
+                               else:
+                                       self._player.set_piece_by_node(self._node)
+                                       self._player.play()
+                       elif self._player.state == self._player.STATE_PAUSE:
+                               self._player.play()
+                       elif self._player.state == self._player.STATE_STOP:
+                               self._player.set_piece_by_node(self._node)
+                               self._player.play()
+                       else:
+                               _moduleLogger.info("Unhandled player state %s" % self._player.state)
+               elif navState == "down":
+                       self.emit("home")
+                       self._window.destroy()
+               elif navState == "up":
+                       pass
+               elif navState == "left":
+                       if self._active:
+                               self._player.next()
+                       else:
+                               assert self._nextSearch is None
+                               self._nextSearch = stream_index.AsyncWalker(stream_index.get_next)
+                               self._nextSearch.start(self._node, self._on_next_node, self._on_node_search_error)
+               elif navState == "right":
+                       if self._active:
+                               self._player.back()
+                       else:
+                               assert self._nextSearch is None
+                               self._nextSearch = stream_index.AsyncWalker(stream_index.get_previous)
+                               self._nextSearch.start(self._node, self._on_next_node, self._on_node_search_error)
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_next_node(self, node):
+               self._nextSearch = None
+               self.emit("jump-to", node)
+               self._window.destroy()
+
+       @misc_utils.log_exception(_moduleLogger)
+       def _on_node_search_error(self, e):
+               self._nextSearch = None
+               self._errorBanner.push_message(str(e))