Exemplo n.º 1
0
class MenuScreen(Screen):
    """ Site Menu Screen. Base class for all book menu screens """
    def __init__(self,
                 util,
                 listeners,
                 rows,
                 columns,
                 voice_assistant,
                 d=None,
                 turn_page=None,
                 page_in_title=True,
                 show_loading=False):
        """ Initializer
        
        :param util: utility object
        :param listeners: file browser listeners
        :param rows: menu rows
        :param d: dictionary with menu button flags
        :param turn_page: turn page callback
        :param util: utility object
        """
        self.util = util
        self.config = util.config
        self.factory = Factory(util)
        self.bounding_box = util.screen_rect
        self.player = None
        self.turn_page = turn_page
        self.page_in_title = page_in_title
        self.show_loading = show_loading

        self.cache = Cache(self.util)
        self.layout = BorderLayout(self.bounding_box)
        self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT,
                                            PERCENT_BOTTOM_HEIGHT, 0, 0)
        Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant,
                        "menu_screen_screen_title", True, self.layout.TOP)
        self.menu_layout = self.layout.CENTER

        if d:
            self.menu_button_layout = self.get_menu_button_layout(d)
            self.img_rect = self.menu_button_layout.image_rectangle

        listeners[GO_LEFT_PAGE] = self.previous_page
        listeners[GO_RIGHT_PAGE] = self.next_page

        self.total_pages = 0
        self.current_page = 1
        self.menu = None

    def get_menu_button_layout(self, d):
        """ Return menu button layout
        
        :param d: dictionary with menu button flags
        
        :return: menu button layout
        """
        s = State()
        s.show_img = True
        s.show_label = True
        button_w = int(self.menu_layout.w / d[1])
        button_h = int(self.menu_layout.h / d[0])
        label_padding = 2
        image_padding = 4
        try:
            self.show_author = d[2]
        except:
            self.show_author = False

        try:
            self.show_genre = d[3]
        except:
            self.show_genre = False

        s.bounding_box = Rect(0, 0, button_w, button_h)
        return MultiLineButtonLayout(s, label_padding, image_padding)

    def previous_page(self, state):
        """ Handle click on left button 
        
        :param state: button state object
        """
        if self.current_page == 1:
            return

        self.current_page -= 1
        if getattr(state, "select_last", False):
            self.components[1].selected_index = 0

        self.menu.current_page = self.current_page
        self.menu.selected_index = 0

        if self.show_loading:
            self.set_loading(self.screen_title.text)

        self.turn_page()

        if self.show_loading:
            self.reset_loading()

    def next_page(self, state):
        """ Handle click on right button 
        
        :param state: button state object
        """
        if self.total_pages <= 1 or self.total_pages == self.current_page:
            return

        self.current_page += 1

        if self.current_page > self.total_pages:
            self.current_page = self.total_pages

        self.menu.current_page = self.current_page
        self.menu.selected_index = 0

        if self.show_loading:
            self.set_loading(self.screen_title.text)

        self.turn_page()

        if self.show_loading:
            self.reset_loading()

    def set_menu(self, menu):
        """ Set menu 
        
        :param menu: menu object
        """
        self.menu = menu
        self.add_component(self.menu)

    def set_title(self, page_num):
        """ Set screen title 
        
        :param page_num: menu page number
        """
        if self.total_pages == 1 or not self.page_in_title:
            self.screen_title.set_text(self.title)
            return

        if len(str(page_num)) <= len(str(self.total_pages)):
            self.screen_title.set_text(self.title + " (" + str(page_num) + ")")

    def reset_title(self):
        """ Reset screen title """

        self.screen_title.set_text(self.title + " (" + str(self.current_page) +
                                   ")")

    def go_to_page(self, page_num):
        """ Handle go to page event 
        
        :param page_num: menu page number
        """
        n = int(page_num)
        if n > self.total_pages:
            n = self.total_pages
        if n == 0:
            n = 1
        self.current_page = n
        self.menu.current_page = self.current_page
        self.turn_page()

    def get_image_from_cache(self, url):
        """ Return image from cache
        
        :param url: image url
        
        :return: image
        """
        return self.cache.get_image(url)

    def put_image_to_cache(self, url, img):
        """ Put image into cache
        
        :param url: image url
        :param img: image
        """
        self.cache.cache_image(img, url)

    def set_button_image(self, b, icon, img_y=None):
        """ Set button image
        
        :param b: button
        :param icon: image
        :param img_y: image Y coordinate
        """
        bb = b.bounding_box
        comps = b.components
        im = comps[1]
        im.content = icon
        w = im.content.get_size()[0]
        h = im.content.get_size()[1]
        im.content_x = bb.x + (bb.width - w) / 2

        if img_y == None:
            img_area_height = bb.height - ((bb.height / LINES) * 2)
            img_y = bb.y + (img_area_height - h) / 2

        im.content_y = img_y
        self.components[1].clean_draw_update()

    def set_loading(self, name, text=None):
        """ Show Loading... sign
        
        :param name: screen title
        :param text: screen text
        """
        Screen.set_loading(self, name, self.menu_layout, text)
Exemplo n.º 2
0
class BookPlayer(FilePlayerScreen):
    """ Book Player Screen """
    def __init__(self, listeners, util, site_parser, voice_assistant):
        """ Initializer
        
        :param listeners: screen listeners
        :param util: utility object 
        :param site_parser: site parser        
        """
        FilePlayerScreen.__init__(self, listeners, util, self.get_playlist,
                                  voice_assistant)
        self.config = util.config
        self.image_util = util.image_util

        self.current_playlist = None
        self.parser = site_parser
        self.cache = Cache(self.util)
        self.current_book_state = None
        self.current_track_index = 0
        self.playlist = self.get_playlist()
        self.audio_files = self.get_audio_files_from_playlist()
        self.loading_listeners = []
        self.reset_loading_listeners = []
        self.LOADING = util.config[LABELS][KEY_LOADING]

    def get_playlist(self):
        """ Return current playlist
        
        :return: playlist
        """
        return self.current_playlist

    def set_book(self, new_track, state=None):
        """ Set book
        
        :param new_track: flag defining if track is new
        :param state: button state object 
        """
        self.set_loading()

        self.current_book_state = state
        img_url = None
        if hasattr(state, "event_origin"):
            img_url = state.event_origin.state.icon_base[0]
        elif hasattr(state, "img_url"):
            img_url = state.img_url
        self.current_playlist = self.parser.get_book_audio_files_by_url(
            state.book_url, img_url)
        state.url = self.parser.book_parser.img_url

        img = self.cache.get_image(state.url)
        if img == None:
            i = self.image_util.load_image_from_url(state.url)
            if i:
                self.cache.cache_image(i[1], state.url)
                img = i[1]

        bb = self.file_button.bounding_box
        w = bb.w
        h = bb.h
        self.cover_image = self.image_util.scale_image_with_padding(w,
                                                                    h,
                                                                    img,
                                                                    padding=1)

        self.screen_title.set_text(state.name)

        if self.current_playlist == None:
            return

        self.playlist = self.current_playlist

        if new_track and self.playlist:
            self.config[AUDIOBOOKS][BROWSER_BOOK_TITLE] = state.name
            self.config[AUDIOBOOKS][BROWSER_BOOK_URL] = state.book_url
            self.config[AUDIOBOOKS][BROWSER_IMAGE_URL] = img_url
            self.config[AUDIOBOOKS][BROWSER_TRACK_FILENAME] = self.playlist[0][
                "title"]
            state.track_time = self.config[AUDIOBOOKS][BROWSER_BOOK_TIME] = "0"
        elif not new_track:
            state.track_time = self.config[AUDIOBOOKS][BROWSER_BOOK_TIME]

        self.audio_files = self.playlist

    def set_current(self, new_track=False, state=None):
        """ Set current file 
        
        :param new_track: True - new audio file
        :param state: button state object 
        """
        if state.source == BOOK_MENU or state.source == INIT:
            if self.current_book_state and self.current_book_state.book_url == state.book_url and self.time_control.timer_started:
                return

            self.current_track_index = 0
            if state.source == INIT:
                new_track = False
            else:
                new_track = True
            self.set_book(new_track, state)
        elif state.source == TRACK_MENU:
            if getattr(state, "index",
                       None) and state.index == self.current_track_index:
                return
            new_track = True
            st = {"file_name": state.file_name}
            self.set_current_track_index(st)
        elif state.source == ARROW_BUTTON:
            new_track = True
            st = {"file_name": state.file_name}
            self.set_current_track_index(st)
        elif state.source == RESUME:
            new_track = False
            st = {"file_name": state.file_name}
            self.set_current_track_index(st)
        elif state.source == HOME_NAVIGATOR or state.source == BOOK_NAVIGATOR_BACK or state.source == BOOK_NAVIGATOR or state.source == GO_PLAYER:
            return

        if getattr(state, "url", None):
            self.file_button.components[
                1].image_filename = self.img_filename = state.url
        else:
            if hasattr(self, "img_filename"):
                self.file_button.components[
                    1].image_filename = self.img_filename
            else:
                self.file_button.components[
                    1].image_filename = self.img_filename = None
        img = self.cover_image
        if img:
            self.file_button.components[1].content = img
            self.file_button.state.icon_base = img
            self.file_button.state.show_bgr = True
            self.file_button.state.bgr = self.config[COLORS][COLOR_MEDIUM]
            self.file_button.add_background(self.file_button.state)
            self.file_button.components[
                1].content_x = self.layout.CENTER.x + int(
                    (self.layout.CENTER.w - img.get_size()[0]) / 2)
            if self.layout.CENTER.h > img.get_size()[1]:
                self.file_button.components[
                    1].content_y = self.layout.CENTER.y + int(
                        (self.layout.CENTER.h - img.get_size()[1]) / 2)
            else:
                self.file_button.components[1].content_y = self.layout.CENTER.y

        if self.current_playlist == None:
            return

        self.set_audio_file(new_track, state)

    def set_audio_file(self, new_track, s=None):
        """ Set new audio file
        
        :param new_track: True - new audio file
        :param s: button state object 
        """
        state = State()
        state.playback_mode = FILE_AUDIO
        state.playlist_track_number = 0
        name = url = None

        if s == None:
            if self.config[AUDIOBOOKS][BROWSER_TRACK_FILENAME]:
                name = self.config[AUDIOBOOKS][BROWSER_TRACK_FILENAME]
                for t in self.playlist:
                    if t["title"].endswith(name):
                        url = t["mp3"]
            else:
                i = 0
                if s != None:
                    i = s.index
                t = self.playlist[i]
                url = t["mp3"]
                name = t["title"]
        else:
            if getattr(s, "track_filename", None):
                i = self.get_current_track_index(
                    {"file_name": s.track_filename})
            elif getattr(s, "playlist_track_number", None):
                i = s.playlist_track_number
            else:
                i = self.current_track_index

            t = self.playlist[i]
            url = t["mp3"]
            name = t["title"]

        self.config[PLAYER_SETTINGS][PAUSE] = False
        state.file_name = name
        self.config[AUDIOBOOKS][BROWSER_TRACK_FILENAME] = t["file_name"]
        state.mute = self.config[PLAYER_SETTINGS][MUTE]
        state.pause = self.config[PLAYER_SETTINGS][PAUSE]
        self.play_button.draw_default_state(None)

        if self.config[VOLUME_CONTROL][
                VOLUME_CONTROL_TYPE] == VOLUME_CONTROL_TYPE_PLAYER:
            state.volume = self.config[PLAYER_SETTINGS][VOLUME]
        else:
            state.volume = None

        state.file_type = FILE_AUDIO
        state.dont_notify = True
        state.source = FILE_AUDIO
        state.url = url
        state.mode = AUDIOBOOKS

        state.playback_mode = FILE_AUDIO
        state.music_folder = self.config[AUDIO][MUSIC_FOLDER]
        self.audio_files = self.get_audio_files_from_playlist()

        if self.config[AUDIOBOOKS][BROWSER_BOOK_TIME]:
            if new_track:
                state.track_time = "0"
            else:
                state.track_time = self.config[AUDIOBOOKS][BROWSER_BOOK_TIME]

        self.reset_loading()

        logging.debug(state.url)

        self.notify_play_listeners(state)

    def get_audio_files(self):
        """ Return audio files from playlist
        
        :return: files
        """
        return self.get_audio_files_from_playlist()

    def get_audio_files_from_playlist(self):
        """ Call player for files in the playlist 
        
        :return: list of files from playlist
        """
        files = []
        if getattr(self, "playlist", None):
            for n in range(len(self.playlist)):
                st = State()
                st.index = st.comparator_item = n
                t = self.playlist[n]
                st.file_type = FILE_AUDIO
                st.file_name = t["file_name"]
                files.append(st)
        return files

    def set_loading(self):
        """ Show Loading... sign """

        b = self.config[COLORS][COLOR_DARK]
        f = self.config[COLORS][COLOR_BRIGHT]
        fs = 20
        bx = self.file_button.bounding_box
        x = bx.x - 1
        y = bx.y
        w = bx.w + 2
        h = bx.h
        bb = pygame.Rect(x, y, w, h)
        t = self.factory.create_output_text(self.LOADING, bb, b, f, fs)
        t.set_text(self.LOADING)
        t.layer_name = self.LOADING
        self.left_button.change_label("")
        self.right_button.change_label("")
        self.add_component(t)
        self.clean_draw_update()
        self.notify_loading_listeners()

    def reset_loading(self):
        """ Remove Loading... sign """

        n = getattr(self.components[-1], "layer_name", None)
        if n and n == self.LOADING:
            del self.components[-1]
            pygame.event.clear()
        self.notify_reset_loading_listeners()

    def add_loading_listener(self, listener):
        """ Add loading listener
        
        :param listener: event listener
        """
        if listener not in self.loading_listeners:
            self.loading_listeners.append(listener)

    def notify_loading_listeners(self):
        """ Notify all loading listeners """

        for listener in self.loading_listeners:
            listener(None)

    def add_reset_loading_listener(self, listener):
        """ Add reset loading listener
        
        :param listener: event listener
        """
        if listener not in self.reset_loading_listeners:
            self.reset_loading_listeners.append(listener)

    def notify_reset_loading_listeners(self):
        """ Notify all reset loading listeners """

        for listener in self.reset_loading_listeners:
            listener(None)

    def add_screen_observers(self, update_observer, redraw_observer,
                             start_time_control, stop_time_control,
                             title_to_json):
        """ Add screen observers
        
        :param update_observer: observer for updating the screen
        :param redraw_observer: observer to redraw the whole screen
        :param start_time_control:
        :param stop_time_control:
        :param title_to_json:
        """
        FilePlayerScreen.add_screen_observers(self, update_observer,
                                              redraw_observer,
                                              start_time_control,
                                              stop_time_control, title_to_json)
        self.add_loading_listener(redraw_observer)
        self.add_reset_loading_listener(redraw_observer)
Exemplo n.º 3
0
class MenuScreen(Screen):
    """ Site Menu Screen. Base class for all book menu screens """
    def __init__(self,
                 util,
                 listeners,
                 rows,
                 columns,
                 voice_assistant,
                 d=None,
                 turn_page=None,
                 page_in_title=True):
        """ Initializer
        
        :param util: utility object
        :param listeners: file browser listeners
        :param rows: menu rows
        :param d: dictionary with menu button flags
        :param turn_page: turn page callback
        :param util: utility object
        """
        self.util = util
        self.config = util.config
        self.factory = Factory(util)
        self.bounding_box = self.config[SCREEN_RECT]
        self.player = None
        self.turn_page = turn_page
        self.page_in_title = page_in_title

        self.cache = Cache(self.util)
        self.layout = BorderLayout(self.bounding_box)
        self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT,
                                            PERCENT_BOTTOM_HEIGHT, 0, 0)
        Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant,
                        "menu_screen_screen_title", True, self.layout.TOP)

        color_dark_light = self.config[COLORS][COLOR_DARK_LIGHT]
        self.menu_layout = self.layout.CENTER

        self.menu_button_layout = self.get_menu_button_layout(d)
        self.img_rect = self.menu_button_layout.image_rectangle

        listeners[GO_LEFT_PAGE] = self.previous_page
        listeners[GO_RIGHT_PAGE] = self.next_page

        try:
            self.navigator = BookNavigator(util, self.layout.BOTTOM, listeners,
                                           color_dark_light, d[4])
            Container.add_component(self, None)
            Container.add_component(self, self.navigator)
        except:
            Container.add_component(self, None)

        self.total_pages = 0
        self.current_page = 1
        self.menu = None

        self.loading_listeners = []
        self.LOADING = util.config[LABELS][KEY_LOADING]

    def get_menu_button_layout(self, d):
        """ Return menu button layout
        
        :param d: dictionary with menu button flags
        
        :return: menu button layout
        """
        s = State()
        s.show_img = True
        s.show_label = True
        button_w = int(self.menu_layout.w / d[1])
        button_h = int(self.menu_layout.h / d[0])
        label_padding = 2
        image_padding = 4
        try:
            self.show_author = d[2]
        except:
            self.show_author = False

        try:
            self.show_genre = d[3]
        except:
            self.show_genre = False

        s.bounding_box = Rect(0, 0, button_w, button_h)
        return MultiLineButtonLayout(s, label_padding, image_padding)

    def previous_page(self, state):
        """ Handle click on left button 
        
        :param state: button state object
        """
        if self.current_page == 1:
            return

        self.current_page -= 1
        if getattr(state, "select_last", False):
            self.components[1].selected_index = 0

        self.menu.current_page = self.current_page
        self.menu.selected_index = 0
        self.turn_page()

    def next_page(self, state):
        """ Handle click on right button 
        
        :param state: button state object
        """
        if self.total_pages <= 1 or self.total_pages == self.current_page:
            return

        self.current_page += 1

        if self.current_page > self.total_pages:
            self.current_page = self.total_pages

        self.menu.current_page = self.current_page
        self.menu.selected_index = 0
        self.turn_page()

    def set_menu(self, menu):
        """ Set menu 
        
        :param menu: menu object
        """
        self.menu = self.components[1] = menu

    def set_title(self, page_num):
        """ Set screen title 
        
        :param page_num: menu page number
        """
        if self.total_pages == 1 or not self.page_in_title:
            self.screen_title.set_text(self.title)
            return

        if len(str(page_num)) <= len(str(self.total_pages)):
            self.screen_title.set_text(self.title + " (" + str(page_num) + ")")

    def reset_title(self):
        """ Reset screen title """

        self.screen_title.set_text(self.title + " (" + str(self.current_page) +
                                   ")")

    def go_to_page(self, page_num):
        """ Handle go to page event 
        
        :param page_num: menu page number
        """
        n = int(page_num)
        if n > self.total_pages:
            n = self.total_pages
        if n == 0:
            n = 1
        self.current_page = n
        self.menu.current_page = self.current_page
        self.turn_page()

    def get_image_from_cache(self, url):
        """ Return image from cache
        
        :param url: image url
        
        :return: image
        """
        return self.cache.get_image(url)

    def put_image_to_cache(self, url, img):
        """ Put image into cache
        
        :param url: image url
        :param img: image
        """
        self.cache.cache_image(img, url)

    def set_button_image(self, b, icon, img_y=None):
        """ Set button image
        
        :param b: button
        :param icon: image
        :param img_y: image Y coordinate
        """
        bb = b.bounding_box
        comps = b.components
        im = comps[1]
        im.content = icon
        w = im.content.get_size()[0]
        h = im.content.get_size()[1]
        im.content_x = bb.x + (bb.width - w) / 2

        if img_y == None:
            img_area_height = bb.height - ((bb.height / LINES) * 2)
            img_y = bb.y + (img_area_height - h) / 2

        im.content_y = img_y
        self.components[1].clean_draw_update()

    def set_loading(self, name):
        """ Show Loading... sign
        
        :name: screen title
        """
        b = self.config[COLORS][COLOR_DARK]
        f = self.config[COLORS][COLOR_BRIGHT]
        fs = int(self.bounding_box.h * 0.07)
        bb = self.menu_layout
        t = self.factory.create_output_text(self.LOADING, bb, b, f, fs)
        t.set_text(self.LOADING)
        self.screen_title.set_text(name)
        self.set_visible(True)
        self.add_component(t)
        self.clean_draw_update()
        self.notify_loading_listeners()

    def reset_loading(self):
        """ Remove Loading... sign """

        del self.components[-1]
        self.notify_loading_listeners()

    def add_loading_listener(self, listener):
        """ Add loading listener
        
        :param listener: event listener
        """
        if listener not in self.loading_listeners:
            self.loading_listeners.append(listener)

    def notify_loading_listeners(self):
        """ Notify all loading listeners """

        for listener in self.loading_listeners:
            listener(None)