class BookAuthor(MenuScreen): """ Authors screen """ def __init__(self, util, listeners, ch, f, go_author, parser, base_url, voice_assistant, d): """ Initializer :param util: utility object :param listeners: screen listeners :param ch: selected character :param f: selected filter :param go_authors: callback :param parser: authors parser :param base_url: url :param d: dictionary with menu button flags """ self.util = util self.factory = Factory(util) self.base_url = base_url self.config = util.config self.parser = parser self.current_author_char = ch self.current_author_filter = f self.go_author = go_author self.author_cache = {} self.title = self.config[LABELS][KEY_AUTHORS] MenuScreen.__init__(self, util, listeners, MENU_ROWS, MENU_COLUMNS, voice_assistant, d, self.turn_page) m = self.create_book_author_menu_button self.navigator = BookNavigator(util, self.layout.BOTTOM, listeners, d[4]) self.back_button = self.navigator.get_button_by_name(KEY_BACK) 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.add_navigator(self.navigator) font_size = int(((self.menu_layout.h / MENU_ROWS) / 100) * self.config[FONT_HEIGHT_PERCENT]) self.authors_menu = MultiPageMenu(util, self.next_page, self.previous_page, self.set_title, self.reset_title, self.go_to_page, m, MENU_ROWS, MENU_COLUMNS, None, (0, 0, 0), self.menu_layout, font_size=font_size) self.set_menu(self.authors_menu) def create_book_author_menu_button(self, s, constr, action, scale, font_size): """ Create Author Menu button :param s: button state :param constr: bounding box :param action: button event listener :param show_img: True - show image, False - don't show image :param show_label: True - show label, False - don't show label :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 = False s.show_label = True 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.fixed_height = font_size button = Button(self.util, s) button.add_release_listener(action) return button def create_book_author_items(self, authors): """ Create dictionary with author books :param authors: list of author books :return: dictionary with author books """ items = {} for i, g in enumerate(authors): state = State() state.name = g[AUTHOR_NAME] state.url = g[AUTHOR_URL] + "/" state.author_books = int(g[AUTHOR_BOOKS]) try: state.l_name = state.name + " (" + g[AUTHOR_BOOKS] + ")" except: state.l_name = state.name state.bgr = self.config[COLORS][COLOR_DARK] state.img_x = None state.img_y = None state.auto_update = True state.show_bgr = True state.show_img = False state.show_label = True state.comparator_item = state.name state.index = i items[state.name] = state return items def set_current(self, ch=None, f=None): """ Apply selected character and filter :param ch: selected character :param f: selected filter """ if not ch and not f: return self.set_loading(self.config[LABELS][KEY_AUTHORS]) self.total_pages = 0 self.current_page = 1 self.current_author_char = ch self.current_author_filter = f try: self.author_cache[ch] except: self.get_authors() self.turn_page() self.reset_loading() def get_authors(self): """ Get authors from parser """ self.parser.author_parser.current_author_char = self.current_author_char self.parser.author_parser.url = self.base_url authors = self.parser.get_authors() if authors: self.author_cache[self.current_author_char] = authors def turn_page(self): """ Turn authors page """ self.authors_menu.set_items({}, 0, self.go_author) filtered_authors = [] for a in self.author_cache[self.current_author_char]: if self.current_author_filter: if a[AUTHOR_NAME].startswith(self.current_author_filter): filtered_authors.append(a) else: filtered_authors.append(a) start = (self.current_page - 1) * PAGE_SIZE end = self.current_page * PAGE_SIZE page = filtered_authors[start:end] self.author_dict = self.create_book_author_items(page) self.authors_menu.set_items(self.author_dict, 0, self.go_author, False) self.authors_menu.align_content(ALIGN_LEFT) self.total_pages = math.ceil(len(filtered_authors) / PAGE_SIZE) left = str(self.current_page - 1) if self.total_pages == 0: right = "0" else: right = str(self.total_pages - self.current_page) self.left_button.change_label(left) self.right_button.change_label(right) self.set_title(self.current_page) if self.authors_menu.get_selected_item() != None: self.navigator.unselect() else: if not self.navigator.is_selected(): self.back_button.set_selected(True) self.back_button.clean_draw_update() self.authors_menu.clean_draw_update() self.link_borders() def handle_event(self, event): """ Handle screen event :param event: the event to handle """ self.handle_event_common(event) 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.authors_menu.add_menu_loaded_listener(redraw_observer) self.authors_menu.add_menu_observers(update_observer, redraw_observer, release=False)
class WiFiScreen(MenuScreen): """ Wi-Fi 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_keyboard = listeners[KEY_KEYBOARD_KEY] self.keyboard_callback = listeners[KEY_CALLBACK] self.wifi_selection_listeners = [] self.wifi_util = WiFiUtil(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_WIFI, MENU_COLUMNS_WIFI] MenuScreen.__init__(self, util, listeners, MENU_ROWS_WIFI, MENU_COLUMNS_WIFI, voice_assistant, d, self.turn_page, page_in_title=False, show_loading=False) self.title = self.config[LABELS]["select.wifi"] self.set_title(1) listeners[KEY_REFRESH] = self.set_current listeners[KEY_SORT] = self.sort_abc self.navigator = WiFiNavigator(self.util, self.layout.BOTTOM, listeners, PAGE_SIZE_WIFI + 1) self.add_component(self.navigator) self.network_button = self.navigator.get_button_by_name(KEY_NETWORK) m = self.factory.create_wifi_menu_button font_height = 32 font_size = int( ((self.menu_layout.h / MENU_ROWS_WIFI) / 100) * font_height) self.wifi_menu = MultiPageMenu(util, self.next_page, self.previous_page, self.set_title, self.reset_title, self.go_to_page, m, MENU_ROWS_WIFI, MENU_COLUMNS_WIFI, None, (0, 0, 0), self.menu_layout, align=ALIGN_CENTER, font_size=font_size) self.set_menu(self.wifi_menu) self.original_networks = None self.networks = None self.sort_direction = False self.current_network = None self.link_borders() def set_current(self, state): """ Set current state :param state: button state """ self.set_loading(self.title) info = self.wifi_util.get_wifi_networks() self.original_networks = info["networks"] if not self.original_networks: self.reset_loading() if not self.navigator.is_selected(): self.network_button.set_selected(True) self.clean_draw_update() return self.networks = self.sort_networks(SORT_ALPHABETICALLY) self.current_network = info["profile"] self.total_pages = math.ceil(len(self.networks) / PAGE_SIZE_WIFI) self.reset_loading() self.current_page = self.wifi_util.get_page_num( self.current_network, self.networks) self.turn_page() def sort_networks(self, order): """ Sort networks :param order: sort order :return: sorted networks """ sorted_networks = [] if order == SORT_ALPHABETICALLY: sorted_networks = sorted(self.original_networks, key=lambda i: i["name"], reverse=self.sort_direction) else: sorted_networks = sorted(self.original_networks, key=lambda i: i["strength"], reverse=self.sort_direction) states = {} h = self.layout.CENTER.h / MENU_ROWS_WIFI bb = pygame.Rect(0, 0, h, h) for i, n in enumerate(sorted_networks): s = self.wifi_util.get_network_info(i, n["name"], n["strength"], bb) states[s.name] = s return states def sort_abc(self, state): """ Sort in alphabetical order :param state: button state """ self.sort(SORT_ALPHABETICALLY) def select_network(self, state=None): """ Select network from menu :param state: button state """ self.current_network = state.name self.notify_wifi_selection_listeners(self.current_network) state.title = self.config[LABELS]["enter.password"] state.callback = self.keyboard_callback self.go_keyboard(state) def sort(self, order): """ Sort by order :param order: sort order :return: """ self.sort_direction = not self.sort_direction self.current_page = 1 self.networks = self.sort_networks(order) self.turn_page() def turn_page(self): """ Turn page """ p = self.wifi_util.get_network_page(self.current_page, self.networks) self.wifi_menu.set_items(p, 0, self.select_network, False) keys = list(p.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.wifi_menu.clean_draw_update() if hasattr(self, "update_observer"): self.wifi_menu.add_menu_observers(self.update_observer, self.redraw_observer) self.wifi_menu.unselect() for b in self.wifi_menu.buttons.values(): if self.current_network == b.state.name: self.wifi_menu.select_by_index(b.state.index) break if self.wifi_menu.get_selected_item() != None: self.navigator.unselect() else: if not self.navigator.is_selected(): self.network_button.set_selected(True) self.link_borders() def add_wifi_selection_listener(self, listener): """ Add listener :param listener: event listener """ if listener not in self.wifi_selection_listeners: self.wifi_selection_listeners.append(listener) def notify_wifi_selection_listeners(self, selected_wifi): """ Notify all listeners :param selected_wifi: """ for listener in self.wifi_selection_listeners: listener(selected_wifi) 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 RadioGroupScreen(MenuScreen): """ Radio group screen """ def __init__(self, util, listeners, voice_assistant): self.util = util self.config = util.config self.groups_list = self.util.get_stations_folders() self.factory = Factory(util) d = [MENU_ROWS, MENU_COLUMNS] MenuScreen.__init__(self, util, listeners, MENU_ROWS, MENU_COLUMNS, voice_assistant, d, self.turn_page, page_in_title=False) self.total_pages = math.ceil(len(self.groups_list) / PAGE_SIZE) self.title = util.get_stations_top_folder() m = self.create_genre_menu_button label_area = ( (self.menu_layout.h / MENU_ROWS) / 100) * (100 - ICON_AREA) font_size = int((label_area / 100) * FONT_HEIGHT) self.navigator = RadioGroupNavigator(self.util, self.layout.BOTTOM, listeners, self.total_pages) self.add_navigator(self.navigator) self.player_button = self.navigator.get_button_by_name(KEY_PLAYER) if self.total_pages > 1: 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.groups_menu = MultiPageMenu(util, self.next_page, self.previous_page, self.set_title, self.reset_title, self.go_to_page, m, MENU_ROWS, MENU_COLUMNS, None, (0, 0, 0, 0), self.menu_layout, align=ALIGN_CENTER, font_size=font_size) self.groups_menu.add_listener(listeners[KEY_GENRE]) self.set_menu(self.groups_menu) current_name = self.get_current_group_name() if current_name == None: self.current_page = 1 else: try: current_group_index = self.groups_list.index(current_name) self.current_page = int(current_group_index / PAGE_SIZE) + 1 except: current_group_index = 0 self.turn_page() def create_genre_menu_button(self, s, constr, action, scale, font_size): """ Create Genre 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.padding = BUTTON_PADDING s.image_area_percent = ICON_AREA s.fixed_height = font_size s.v_align = CENTER return self.factory.create_menu_button(s, constr, action, scale, font_size=font_size) def get_current_group_name(self): group = self.util.get_current_genre() if group != None: return group.name else: return None def get_page(self): start = (self.current_page - 1) * PAGE_SIZE end = self.current_page * PAGE_SIZE tmp_layout = self.groups_menu.get_layout(self.groups_list) button_rect = tmp_layout.constraints[0] image_box = self.factory.get_icon_bounding_box(button_rect, ICON_LOCATION, ICON_AREA, ICON_SIZE, BUTTON_PADDING) groups_dict = self.util.load_stations_folders(image_box) return self.util.get_radio_group_slice(groups_dict, start, end) def turn_page(self): """ Turn book genre page """ group_page = self.get_page() self.groups_menu.set_items(group_page, 0, self.change_group, False) current_name = self.get_current_group_name() self.current_genre = None try: self.current_genre = group_page[current_name] except: pass self.groups_menu.item_selected(self.current_genre) 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)) for b in self.groups_menu.buttons.values(): b.parent_screen = self self.groups_menu.clean_draw_update() menu_selected = self.groups_menu.get_selected_item() != None if menu_selected: self.navigator.unselect() self.link_borders() navigator_selected = self.navigator.is_selected() if (len(group_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() self.set_title(self.current_page) def change_group(self, state): """ Change group event listener :param state: button state """ if not self.visible: return self.current_genre = state key = STATIONS + "." + self.config[CURRENT][LANGUAGE] self.config[key][CURRENT_STATIONS] = state.genre state.source = GENRE self.groups_menu.notify_listeners(state) def handle_event(self, event): """ Handle screen event :param event: the event to handle """ self.handle_event_common(event) 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.groups_menu.add_menu_observers(update_observer, redraw_observer, release=False)
class BluetoothScreen(MenuScreen): """ Bluetooth 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_network = listeners[KEY_NETWORK] self.go_player = listeners[KEY_PLAYER] self.wifi_selection_listeners = [] self.bluetooth_util = self.util.get_bluetooth_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_BLUETOOTH, MENU_COLUMNS_BLUETOOTH] MenuScreen.__init__(self, util, listeners, MENU_ROWS_BLUETOOTH, MENU_COLUMNS_BLUETOOTH, voice_assistant, d, self.turn_page, page_in_title=False, show_loading=False) self.title = self.config[LABELS]["select.bluetooth.device"] self.set_title(1) listeners[KEY_HOME] = self.before_home listeners[KEY_NETWORK] = self.before_network listeners[KEY_PLAYER] = self.before_player listeners[KEY_REFRESH] = self.set_current self.navigator = BluetoothNavigator(self.util, self.layout.BOTTOM, listeners, PAGE_SIZE_BLUETOOTH + 1) self.add_navigator(self.navigator) self.network_button = self.navigator.get_button_by_name(KEY_NETWORK) self.left_button = self.navigator.get_button_by_name(KEY_PAGE_DOWN) self.right_button = self.navigator.get_button_by_name(KEY_PAGE_UP) m = self.factory.create_wifi_menu_button font_height = 32 font_size = int( ((self.menu_layout.h / MENU_ROWS_BLUETOOTH) / 100) * font_height) self.bluetooth_menu = MultiPageMenu(util, self.next_page, self.previous_page, self.set_title, self.reset_title, self.go_to_page, m, MENU_ROWS_BLUETOOTH, MENU_COLUMNS_BLUETOOTH, None, (0, 0, 0), self.menu_layout, align=ALIGN_LEFT, font_size=font_size) self.set_menu(self.bluetooth_menu) self.devices = None self.networks = None self.sort_direction = False self.current_device = None def set_current(self, state): """ Set current state :param state: button state """ self.set_loading(self.title) self.bluetooth_util.start_scan() self.devices = self.bluetooth_util.get_available_devices() if not self.devices: self.reset_loading() self.left_button.change_label("0") self.right_button.change_label("0") if not self.navigator.is_selected(): self.network_button.set_selected(True) self.link_borders() self.clean_draw_update() return d = self.bluetooth_util.get_connected_device() if d: self.current_device = d else: self.current_device = None self.total_pages = math.ceil(len(self.devices) / PAGE_SIZE_BLUETOOTH) self.reset_loading() self.current_page = self.bluetooth_util.get_page_num( self.current_device, self.devices) if not self.current_page: self.current_page = 1 self.turn_page() def select_network(self, state=None): """ Select network from menu :param state: button state """ if hasattr(state, "mac_address") and self.bluetooth_util.is_device_connected( state.mac_address): self.before_network(state) return state.source = "bluetooth" self.notify_wifi_selection_listeners(state.name) self.before_network(state) def turn_page(self): """ Turn page """ p = self.bluetooth_util.get_page(self.current_page, self.devices) try: self.bluetooth_menu.set_items(p, 0, self.select_network, False) except Exception as e: logging.debug(e) if len(self.devices) != 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.set_title(self.current_page) self.bluetooth_menu.clean_draw_update() if hasattr(self, "update_observer"): self.bluetooth_menu.add_menu_observers(self.update_observer, self.redraw_observer) self.bluetooth_menu.unselect() for b in self.bluetooth_menu.buttons.values(): if self.current_device and self.current_device[ "name"] == b.state.name: self.bluetooth_menu.select_by_index(b.state.index) break if self.bluetooth_menu.get_selected_item() != None: self.navigator.unselect() else: if not self.navigator.is_selected(): self.network_button.set_selected(True) self.link_borders() def before_home(self, state): """ Stop bluetooth scanning and go to home screen :param state: button state """ self.bluetooth_util.stop_scan() self.go_home(state) def before_network(self, state): """ Stop bluetooth scanning and go to network screen :param state: button state """ self.bluetooth_util.stop_scan() self.go_network(state) def before_player(self, state): """ Stop bluetooth scanning and go to player screen :param state: button state """ self.bluetooth_util.stop_scan() self.go_player(state) def add_bluetooth_selection_listener(self, listener): """ Add listener :param listener: event listener """ if listener not in self.wifi_selection_listeners: self.wifi_selection_listeners.append(listener) def notify_wifi_selection_listeners(self, selected_wifi): """ Notify all listeners :param selected_wifi: """ for listener in self.wifi_selection_listeners: listener(selected_wifi) 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) def handle_event(self, event): """ Handle screen event :param event: the event to handle """ self.handle_event_common(event)
class BookGenre(MenuScreen): """ Book genre screen """ def __init__(self, util, listeners, go_book_by_genre, genres, base_url, voice_assistant, d): self.util = util self.go_book_by_genre = go_book_by_genre self.config = util.config self.genres_list = genres self.base_url = base_url self.factory = Factory(util) MenuScreen.__init__(self, util, listeners, MENU_ROWS, MENU_COLUMNS, voice_assistant, d, self.turn_page) self.total_pages = math.ceil(len(genres) / PAGE_SIZE) self.title = self.config[LABELS][KEY_CHOOSE_GENRE] self.navigator = BookNavigator(util, self.layout.BOTTOM, listeners, d[4]) self.back_button = self.navigator.get_button_by_name(KEY_BACK) 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.add_navigator(self.navigator) m = self.create_book_genre_menu_button font_size = int(((self.menu_layout.h / MENU_ROWS) / 100) * self.config[FONT_HEIGHT_PERCENT]) self.genre_menu = MultiPageMenu(util, self.next_page, self.previous_page, self.set_title, self.reset_title, self.go_to_page, m, MENU_ROWS, MENU_COLUMNS, None, (0, 0, 0, 0), self.menu_layout, font_size=font_size) self.set_menu(self.genre_menu) self.turn_page() def create_book_genre_menu_button(self, s, constr, action, show_img=True, show_label=True): """ Create Genre Menu button :param s: button state :param constr: bounding box :param action: button event listener :param show_img: True - show image, False - don't show image :param show_label: True - show label, False - don't show label :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 = show_img s.show_label = show_label 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.label_text_height = 35 s.bgr = self.config[BACKGROUND][MENU_BGR_COLOR] button = Button(self.util, s) button.add_release_listener(action) return button def turn_page(self): """ Turn book genre page """ start = (self.current_page - 1) * PAGE_SIZE end = self.current_page * PAGE_SIZE page = self.genres_list[start:end] self.genres_dict = self.factory.create_book_genre_items( page, self.base_url) self.genre_menu.set_items(self.genres_dict, 0, self.go_book_by_genre, False) self.genre_menu.align_content(ALIGN_LEFT) for b in self.genre_menu.buttons.values(): b.parent_screen = self self.genre_menu.clean_draw_update() self.left_button.change_label(str(self.current_page - 1)) self.right_button.change_label( str(self.total_pages - self.current_page)) self.set_title(self.current_page) if self.genre_menu.get_selected_item() != None: self.navigator.unselect() else: if not self.navigator.is_selected(): self.back_button.set_selected(True) self.back_button.clean_draw_update() self.link_borders() def handle_event(self, event): """ Handle screen event :param event: the event to handle """ self.handle_event_common(event) 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.genre_menu.add_menu_observers(update_observer, redraw_observer, release=False)