class PodcastsScreen(MenuScreen): """ Podcasts Screen """ def __init__(self, util, listeners, voice_assistant): """ Initializer :param util: utility object :param listeners: listeners :param voice_assistant: voice assistant """ self.util = util self.config = util.config self.listeners = listeners self.factory = Factory(util) self.podcasts_util = util.get_podcasts_util() self.bounding_box = util.screen_rect layout = BorderLayout(self.bounding_box) layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, 0, 0) d = [MENU_ROWS_PODCASTS, MENU_COLUMNS_PODCASTS] MenuScreen.__init__(self, util, listeners, MENU_ROWS_PODCASTS, MENU_COLUMNS_PODCASTS, voice_assistant, d, self.turn_page, page_in_title=False, show_loading=True) self.title = self.config[LABELS][PODCASTS] self.current_item = self.config[PODCASTS][PODCAST_URL] self.navigator = PodcastNavigator(self.util, self.layout.BOTTOM, listeners, PAGE_SIZE_PODCASTS + 1) self.add_navigator(self.navigator) m = self.create_podcast_menu_button font_size = int(((self.menu_layout.h / MENU_ROWS_PODCASTS) / 100) * FONT_HEIGHT) h = self.config[HORIZONTAL_LAYOUT] bgr = self.config[BACKGROUND][MENU_BGR_COLOR] self.podcasts_menu = Menu(util, bgr, self.menu_layout, MENU_ROWS_PODCASTS, MENU_COLUMNS_PODCASTS, create_item_method=m, align=ALIGN_CENTER, horizontal_layout=h, font_size=font_size) self.set_menu(self.podcasts_menu) url = self.config[PODCASTS][PODCAST_URL] if url and len(url) > 0: self.current_page = self.podcasts_util.get_podcast_page(url, PAGE_SIZE_PODCASTS) else: self.current_page = 1 self.animated_title = True def create_podcast_menu_button(self, s, constr, action, scale, font_size): """ Create podcast menu button :param s: button state :param constr: scaling constraints :param action: button event listener :param scale: True - scale images, False - don't scale images :return: genre menu button """ s.bounding_box = constr s.img_x = None s.img_y = None s.auto_update = True s.show_bgr = True s.show_img = True s.show_label = True s.image_location = ICON_LOCATION s.label_location = CENTER s.label_area_percent = 30 s.image_size_percent = ICON_SIZE s.text_color_normal = self.config[COLORS][COLOR_BRIGHT] s.text_color_selected = self.config[COLORS][COLOR_CONTRAST] s.text_color_disabled = self.config[COLORS][COLOR_MEDIUM] s.text_color_current = s.text_color_normal s.scale = scale s.source = None s.v_align = V_ALIGN_TOP s.h_align = H_ALIGN_LEFT s.v_offset = (constr.h/100) * 5 s.bgr = self.config[BACKGROUND][MENU_BGR_COLOR] s.image_area_percent = ICON_AREA s.fixed_height = font_size button = PodcastButton(self.util, s) button.add_release_listener(action) if not getattr(s, "enabled", True): button.set_enabled(False) elif getattr(s, "icon_base", False) and not getattr(s, "scaled", False): button.components[1].content = s.icon_base button.scaled = scale return button def set_current(self, state): """ Set current state :param state: button state """ if self.util.connected_to_internet: podcast_links_num = len(self.podcasts_util.get_podcasts_links()) else: podcast_links_num = len(self.podcasts_util.load_podcasts()) self.total_pages = math.ceil(podcast_links_num / PAGE_SIZE_PODCASTS) self.set_loading(self.title) self.turn_page() self.reset_loading() def select_item(self, s=None): """ Select item from menu :param s: button state """ if not s: return self.current_item = s.url self.listeners[KEY_PODCAST_EPISODES](s) def turn_page(self): """ Turn podcasts page """ page = {} if self.util.connected_to_internet: page = self.podcasts_util.get_podcasts(self.current_page, PAGE_SIZE_PODCASTS) if len(list(page.keys())) == 0 or not self.util.connected_to_internet: page = self.podcasts_util.get_podcasts_from_disk(self.current_page, PAGE_SIZE_PODCASTS) self.podcasts_menu.set_items(page, 0, self.select_item, False) keys = list(page.keys()) if len(keys) != 0 and self.navigator and self.total_pages > 1: self.navigator.get_button_by_name(KEY_PAGE_DOWN).change_label(str(self.current_page - 1)) self.navigator.get_button_by_name(KEY_PAGE_UP).change_label(str(self.total_pages - self.current_page)) self.set_title(self.current_page) self.podcasts_menu.clean_draw_update() if hasattr(self, "update_observer"): self.podcasts_menu.add_menu_observers(self.update_observer, self.redraw_observer) for b in self.podcasts_menu.buttons.values(): b.parent_screen = self self.podcasts_menu.unselect() self.link_borders() self.current_item = self.config[PODCASTS][PODCAST_URL] menu_selected = self.menu.get_selected_index() if menu_selected == None: if self.current_item == None or len(self.current_item) == 0: self.podcasts_menu.select_by_index(0) item = self.podcasts_menu.get_selected_item() if item != None: self.current_item = item.state.url for b in self.podcasts_menu.buttons.values(): b.parent_screen = self if self.current_item == b.state.url: self.podcasts_menu.select_by_index(b.state.index) self.navigator.unselect() return def add_screen_observers(self, update_observer, redraw_observer): """ Add screen observers :param update_observer: observer for updating the screen :param redraw_observer: observer to redraw the whole screen """ MenuScreen.add_screen_observers(self, update_observer, redraw_observer) self.update_observer = update_observer self.redraw_observer = redraw_observer self.add_loading_listener(redraw_observer) self.navigator.add_observers(update_observer, redraw_observer)
class TopicDetailScreen(MenuScreen): """ Topic Detail Screen """ def __init__(self, util, listeners, voice_assistant): """ Initializer :param util: utility object :param listeners: listeners :param voice_assistant: voice assistant """ self.util = util self.config = util.config self.listeners = listeners self.factory = Factory(util) self.go_home = listeners[KEY_HOME] self.go_file_playback = listeners[KEY_PLAY_COLLECTION] dbutil = util.get_db_util() self.selector = Selector(dbutil) self.bounding_box = util.screen_rect layout = BorderLayout(self.bounding_box) layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, 0, 0) MenuScreen.__init__(self, util, listeners, ROWS, COLUMNS, voice_assistant, [ROWS, COLUMNS], self.turn_page, page_in_title=False, show_loading=False) self.navigator = TopicDetailNavigator(self.util, self.layout.BOTTOM, listeners) self.add_navigator(self.navigator) self.left_button = self.navigator.get_button_by_name(KEY_PAGE_DOWN) self.right_button = self.navigator.get_button_by_name(KEY_PAGE_UP) self.player_button = self.navigator.get_button_by_name(KEY_PLAYER) m = self.factory.create_collection_menu_button font_size = int(((self.menu_layout.h / ROWS) / 100) * FONT_HEIGHT) h = self.config[HORIZONTAL_LAYOUT] bgr = self.config[BACKGROUND][MENU_BGR_COLOR] self.collection_list_menu = Menu(util, bgr, self.menu_layout, ROWS, COLUMNS, create_item_method=m, align=ALIGN_LEFT, horizontal_layout=h, font_size=font_size) self.set_menu(self.collection_list_menu) self.current_item = None self.current_page_items = None self.first_item = None self.last_item = None self.collection_topic = None self.selection = None self.prev_page = 1 self.animated_title = True def set_current(self, state): """ Set current state :param state: button state """ source = getattr(state, KEY_SOURCE, None) if source == KEY_NAVIGATOR or source == KEY_BACK: self.link_borders() if self.collection_list_menu.get_selected_item( ) == None and not self.navigator.is_selected(): self.player_button.set_selected(True) self.player_button.clean_draw_update() return if hasattr(state, "collection_topic"): self.collection_topic = getattr(state, "collection_topic", "") if hasattr(state, "name") and hasattr(state, "collection_topic"): self.selection = getattr(state, "name", "") self.title = self.config[LABELS][ self.collection_topic] + ": " + self.selection self.set_title(1) self.current_page = 1 self.prev_page = 1 self.left_button.change_label("0") self.right_button.change_label("0") self.set_loading(self.title) topic = self.get_topic() self.total_pages = self.selector.get_page_count_by_column( topic, self.selection, PAGE_SIZE) if self.total_pages == 0: self.reset_loading() return self.filename = None self.title = None if self.collection_topic == KEY_FILE: self.filename = state.name elif self.collection_topic == TITLE: self.title = state.name self.turn_page() self.reset_loading() def turn_page(self): """ Turn page """ topic = self.get_topic() self.current_page_items = self.selector.get_topic_detail_page( topic, self.selection, self.current_page, self.prev_page, self.first_item, self.last_item, PAGE_SIZE) self.prev_page = self.current_page if not self.current_page_items: self.current_page_items = [] self.link_borders() return self.current_item = self.current_page_items[0] self.first_item = self.current_item self.last_item = self.current_page_items[len(self.current_page_items) - 1] p = {} for i, f in enumerate(self.current_page_items): s = State() s.index = i s.folder = f if "\x00" in f: f = f.replace("\x00", "") if "/" in f: parts = f.split("/") if len(parts) > 1: last = parts[len(parts) - 1] if len(last) > 6: f = last else: f = parts[len(parts) - 2] + "/" + last s.name = f s.l_name = s.name if self.filename: s.file_name = self.filename if self.title: s.title = self.title p[str(i)] = s self.collection_list_menu.set_items(p, 0, self.select_item, False) keys = list(p.keys()) if len(keys) != 0 and self.navigator and self.total_pages > 1: self.left_button.change_label(str(self.current_page - 1)) self.right_button.change_label( str(self.total_pages - self.current_page)) self.collection_list_menu.clean_draw_update() if hasattr(self, "update_observer"): self.collection_list_menu.add_menu_observers( self.update_observer, self.redraw_observer) for b in self.collection_list_menu.buttons.values(): b.parent_screen = self self.collection_list_menu.unselect() self.link_borders() menu_selected = self.menu.get_selected_index() if menu_selected == None: if self.current_item == None: self.collection_list_menu.select_by_index(0) item = self.collection_list_menu.get_selected_item() if item != None: self.current_item = item.state.name if self.navigator.is_selected(): return for b in self.collection_list_menu.buttons.values(): b.parent_screen = self if self.current_item == b.state.name: self.collection_list_menu.select_by_index(b.state.index) return def get_topic(self): """ Get topic :return: proper topic name """ topic = self.collection_topic if topic == KEY_AUDIO_FOLDER: topic = FOLDER elif topic == KEY_FILE: topic = FILENAME return topic def select_item(self, s=None): """ Select item from menu :param state: button state """ self.current_item = s.name state = State() state.folder = os.path.join(self.config[COLLECTION][BASE_FOLDER], s.folder[1:]) state.topic = self.collection_topic if state.topic == KEY_FILE: state.file_name = s.file_name state.url = os.path.join(state.folder, state.file_name) elif state.topic == TITLE: state.file_name = self.selector.get_filename_by_title( s.folder, self.title) state.url = os.path.join(state.folder, state.file_name) else: files = self.util.get_audio_files_in_folder( state.folder, False, False) if files: f = files[0] state.file_name = f.file_name state.url = os.path.join(state.folder, state.file_name) else: state.file_name = None state.url = None state.source = "detail" self.collection_list_menu.select_by_index(s.index) self.go_file_playback(state) def add_screen_observers(self, update_observer, redraw_observer): """ Add screen observers :param update_observer: observer for updating the screen :param redraw_observer: observer to redraw the whole screen """ MenuScreen.add_screen_observers(self, update_observer, redraw_observer) self.update_observer = update_observer self.redraw_observer = redraw_observer self.add_loading_listener(redraw_observer) self.navigator.add_observers(update_observer, redraw_observer)
class RadioBrowserScreen(MenuScreen): """ Radio Browser Screen """ def __init__(self, util, listeners, voice_assistant): """ Initializer :param util: utility object :param listeners: screen event listeners :param voice_assistant: the voice assistant """ self.util = util self.config = util.config self.groups_list = self.util.get_stations_folders() self.factory = Factory(util) self.favorites_util = FavoritesUtil(self.util) rows = self.config[FILE_BROWSER_ROWS] columns = self.config[FILE_BROWSER_COLUMNS] d = [rows, columns] self.page_size = rows * columns MenuScreen.__init__(self, util, listeners, rows, columns, voice_assistant, d, self.turn_page, page_in_title=False) self.total_pages = 0 self.title = "" m = self.create_radio_browser_menu_button button_height = (self.menu_layout.h / rows) - (self.config[PADDING] * 2) bgr = self.config[BACKGROUND][MENU_BGR_COLOR] if self.config[ALIGN_BUTTON_CONTENT_X] == 'center': font_size = int(((100 - STATION_IMAGE_AREA) / 100) * self.config[FONT_HEIGHT_PERCENT]) else: font_size = int( (button_height / 100) * self.config[FONT_HEIGHT_PERCENT]) self.navigator = RadioNavigator(self.util, self.layout.BOTTOM, listeners) self.add_navigator(self.navigator) self.left_button = self.navigator.get_button_by_name(KEY_PAGE_DOWN) self.right_button = self.navigator.get_button_by_name(KEY_PAGE_UP) self.player_button = self.navigator.get_button_by_name(KEY_PLAYER) h = self.config[HORIZONTAL_LAYOUT] self.stations_menu = Menu(util, bgr, self.menu_layout, rows, columns, create_item_method=m, align=ALIGN_CENTER, horizontal_layout=h, font_size=font_size) self.set_menu(self.stations_menu) self.current_page = None self.current_language = self.config[CURRENT][LANGUAGE] self.current_genre = self.util.get_current_genre() self.turn_page() self.animated_title = True def create_radio_browser_menu_button(self, state, constr, action, scale, font_size): """ Factory function for menu button :param state: button state :param constr: bounding box :param action: action listener :param scale: True - sacle, False - don't scale :param font_size: the label font size :return: menu button """ s = copy(state) s.bounding_box = constr s.padding = self.config[PADDING] s.image_area_percent = STATION_IMAGE_AREA label_area_percent = 100 - s.image_area_percent if self.config[ALIGN_BUTTON_CONTENT_X] == 'left': s.image_location = LEFT s.label_location = LEFT s.h_align = H_ALIGN_LEFT elif self.config[ALIGN_BUTTON_CONTENT_X] == 'right': s.image_location = RIGHT s.label_location = RIGHT s.h_align = H_ALIGN_RIGHT elif self.config[ALIGN_BUTTON_CONTENT_X] == 'center': s.image_location = TOP s.label_location = BOTTOM s.h_align = H_ALIGN_CENTER s.v_align = CENTER s.wrap_labels = self.config[WRAP_LABELS] s.fixed_height = font_size s.scaled = True self.util.add_icon(s, self.get_scale_factor(s)) scale = True if hasattr(s, "show_label"): b = self.factory.create_menu_button( s, constr, action, scale, label_area_percent=label_area_percent, show_label=s.show_label, font_size=font_size) else: b = self.factory.create_menu_button( s, constr, action, scale, label_area_percent=label_area_percent, font_size=font_size) b.state.icon_selected_scaled = b.state.icon_base_scaled b.state.icon_selected = s.icon_base return b def get_scale_factor(self, s): """ Calculate scale factor :param s: button state object :return: scale width and height tuple """ bb = s.bounding_box if self.config[ALIGN_BUTTON_CONTENT_X] == 'center': location = TOP else: location = self.config[ALIGN_BUTTON_CONTENT_X] icon_box = self.factory.get_icon_bounding_box(bb, location, self.config[IMAGE_AREA], self.config[IMAGE_SIZE], self.config[PADDING]) icon_box_without_label = self.factory.get_icon_bounding_box( bb, location, 100, 100, self.config[PADDING], False) if self.config[HIDE_FOLDER_NAME]: s.show_label = False w = icon_box_without_label.w h = icon_box_without_label.h else: s.show_label = True w = icon_box.w h = icon_box.h return (w, h) def get_playlist(self, genre=None): """ Get playlist :param genre: the genre :return: the playlist """ if self.current_genre.name == KEY_FAVORITES: return self.favorites_util.get_favorites_playlist() else: return self.util.get_radio_browser_playlist(genre) def get_page(self): """ Get the current page from the playlist :return: the page """ language = self.config[CURRENT][LANGUAGE] genre = self.util.get_current_genre() playlist = self.get_playlist(genre.l_name) playlist_length = len(playlist) self.total_pages = math.ceil(playlist_length / self.page_size) if self.current_page == None or language != self.current_language or self.current_genre != genre: self.current_language = language self.current_genre = genre playlist = self.get_playlist(genre.l_name) playlist_length = len(playlist) self.total_pages = math.ceil(playlist_length / self.page_size) if self.total_pages == 0: self.left_button.change_label("0") self.right_button.change_label("0") self.set_title() return [] self.current_page = self.get_page_by_index() self.set_title() start = (self.current_page - 1) * self.page_size end = self.current_page * self.page_size return playlist[start:end] def get_page_by_index(self): """ Get the page by index :return: the page """ page = None index = self.util.get_current_radio_station_index() if index < self.page_size: page = 1 else: page = math.ceil(index / self.page_size) return page def set_title(self): """ Set the screen title """ genre = self.util.get_current_genre() if genre.name == KEY_FAVORITES: station = self.favorites_util.get_current_favorites_station() else: station = self.util.get_current_radio_station() if station: title = station.comparator_item else: title = "" d = {"current_title": title} self.screen_title.set_text(d) def turn_page(self): """ Turn page """ page = self.get_page() d = self.stations_menu.make_dict(page) self.stations_menu.set_items(d, 0, self.change_station, False) self.favorites_util.mark_favorites(self.stations_menu.buttons) index = self.util.get_current_radio_station_index() menu_selected = self.stations_menu.select_by_index(index) if self.navigator and self.total_pages > 1: self.left_button.change_label(str(self.current_page - 1)) self.right_button.change_label( str(self.total_pages - self.current_page)) else: self.left_button.change_label("0") self.right_button.change_label("0") for b in self.stations_menu.buttons.values(): b.parent_screen = self b.release_listeners.insert(0, self.handle_favorite) self.stations_menu.clean_draw_update() if menu_selected: self.navigator.unselect() self.link_borders() navigator_selected = self.navigator.is_selected() if (len(page) == 0 or (not menu_selected and not navigator_selected)) and self.navigator: self.navigator.unselect() self.player_button.set_selected(True) self.player_button.clean_draw_update() def change_station(self, state): """ Change station :param state: state object """ found = False for b in self.stations_menu.buttons.values(): if b.state == state: found = True break if not found: # after deleting favorite playlist = self.get_playlist(self.current_genre.l_name) index = self.util.get_current_radio_station_index() if playlist and len(playlist) > 0: state = playlist[index] else: state = None if state: state.source = KEY_RADIO_BROWSER state.name = self.util.get_current_genre().name self.util.set_radio_station_index(state.index) else: self.util.set_radio_station_index(None) self.go_player(state) self.set_title() def add_screen_observers(self, update_observer, redraw_observer): """ Add screen observers :param update_observer: observer for updating the screen :param redraw_observer: observer to redraw the whole screen """ self.navigator.add_observers(update_observer, redraw_observer) self.stations_menu.add_menu_observers(update_observer, redraw_observer, release=False) def set_current(self, state=None): """ Set current screen :param state: the source button state object """ self.turn_page() def handle_event(self, event): """ Handle screen event :param event: the event to handle """ self.handle_event_common(event) def handle_favorite(self, state): """ Add/Remove station to/from the favorites :param state: button state """ if state == None or not getattr(state, "long_press", False): return favorites, lang_dict = self.favorites_util.get_favorites_from_config() if self.favorites_util.is_favorite(favorites, state): self.favorites_util.remove_favorite(favorites, state) if self.current_genre.name == KEY_FAVORITES: current_index = state.index if len(favorites) == 0: self.util.set_radio_station_index(None) else: if current_index == 0: self.util.set_radio_station_index(0) else: self.util.set_radio_station_index(current_index - 1) self.turn_page() else: selected_button = self.stations_menu.get_selected_item() if selected_button and len(selected_button.components) == 4: del selected_button.components[3] selected_button.clean_draw_update() else: self.favorites_util.add_favorite(favorites, state) self.favorites_util.mark_favorites(self.stations_menu.buttons)