def update_ui_time(self, widget): """ Displays the value of the progress slider in the text boxes as time. """ val = int(self.progress_scale.get_value()) if tools.get_glib_settings().get_boolean("titlebar-remaining-time"): label_text = tools.seconds_to_str(val, display_zero_h=True) else: label_text = tools.seconds_to_str(val) self.current_label.set_markup("<tt><b>" + label_text + "</b></tt>") track = player.get_current_track() if track: if tools.get_glib_settings().get_boolean( "titlebar-remaining-time"): total = self.progress_scale.get_adjustment().get_upper() remaining_secs: int = int((total - val)) self.remaining_label.set_markup( "<tt><b>-" + tools.seconds_to_str(remaining_secs, display_zero_h=True) + "</b></tt>") else: remaining_secs: int = int((track.length / self.ui.speed.get_speed()) - val) self.remaining_label.set_markup( "<tt><b>-" + tools.seconds_to_str( remaining_secs, display_zero_h=False) + "</b></tt>") if self.ui.book_overview.book and self.current_book.id == self.ui.book_overview.book.id: self.ui.book_overview.update_time()
def update_ui_time(self, widget): """ Displays the value of the progress slider in the text boxes as time. """ val = int(self.progress_scale.get_value()) if tools.get_glib_settings().get_boolean("titlebar-remaining-time"): label_text = tools.seconds_to_str(val, display_zero_h=True) else: label_text = tools.seconds_to_str(val) self.current_label.set_markup("<tt><b>" + label_text + "</b></tt>") track = player.get_current_track() if track is not None: if tools.get_glib_settings().get_boolean( "titlebar-remaining-time"): total = self.progress_scale.get_adjustment().get_upper() remaining_secs = int(((total - val))) self.remaining_label.set_markup( "<tt><b>-" + tools.seconds_to_str(remaining_secs, display_zero_h=True) + "</b></tt>") else: remaining_secs = int((track.length / self.ui.speed.get_speed()) - val) remaining_mins, remaining_secs = divmod(remaining_secs, 60) self.remaining_label.set_markup("<tt><b>-" + str(remaining_mins).zfill(2) + ":" + str(remaining_secs).zfill(2) + "</b></tt>") self.ui.update_book_popover_time()
def __on_hide_offline(self, action, value): """ Show/Hide offline books action handler. """ action.set_state(value) tools.get_glib_settings().set_boolean("hide-offline", value.get_boolean())
def __on_timer_changed(self, spinner): """ Start/Stop the timer depending on the current adjustment value. """ adjustment = self.timer_scale.get_adjustment() value = adjustment.get_value() if value > 0: if not self.sleep_timer or not self.sleep_timer.isAlive(): self.set_icon(True) if player.get_gst_player_state() == Gst.State.PLAYING: self.start(force=True) self.timer_label.set_visible(True) self.min_label.set_text(_("min")) else: self.set_time(value) else: self.set_icon(False) if self.sleep_timer: self.sleep_timer.stop() self.min_label.set_text(_("Off")) self.timer_label.set_visible(False) return if self.sleep_timer and not self.sleep_timer.isAlive: tools.get_glib_settings().set_int("timer", int(value)) text = str(int(value)) self.timer_label.set_text(text)
def __on_external_cover_switch_changed(self, switch, state): """ Set the glib setting prefer-external-cover. This is needed because the binding gets called after this function. Then refresh the artwork cache. """ tools.get_glib_settings().set_boolean("prefer-external-cover", state) artwork_cache.delete_artwork_cache() self.ui.refresh_content()
def __on_hide_offline(self, action, value): """ Show/Hide offline books action handler. """ action.set_state(value) tools.get_glib_settings().set_boolean("hide-offline", value.get_boolean()) self.book_box.invalidate_filter() self.filter_author_reader(value.get_boolean())
def set_time(self, value): """ Sets the timer to the new given value respecting the fadeout setting. :param value: Time in minutes. """ fadeout = 0 if tools.get_glib_settings().get_boolean("sleep-timer-fadeout"): fadeout = tools.get_glib_settings().get_int("sleep-timer-fadeout-duration") self.current_timer_time = value * 60 - fadeout
def __on_external_cover_switch_changed(self, switch, state): """ Set the glib setting prefer-external-cover. This is needed because the binding gets called after this function. Then refresh the artwork cache. """ # We have to test if everything is initialized before triggering the refresh # otherwise this might be just the initial call when starting up if self.ui.is_initialized: tools.get_glib_settings().set_boolean("prefer-external-cover", state) artwork_cache.delete_artwork_cache() self.ui.refresh_content()
def _on_remaining_clicked(self, widget, sender): """ Switch between displaying the time for a track or the whole book. """ if widget.get_name is not "titlebar_remaining_time_eventbox": if tools.get_glib_settings().get_boolean("titlebar-remaining-time"): tools.get_glib_settings().set_boolean("titlebar-remaining-time", False) else: tools.get_glib_settings().set_boolean("titlebar-remaining-time", True) self._on_progress_setting_changed() return True
def __init__(self): self.ui = cozy.ui.main_view.CozyUI() # init buttons self.play_button = self.ui.get_object("play_button") self.prev_button = self.ui.get_object("prev_button") self.volume_button = self.ui.get_object("volume_button") self.volume_button.set_value( tools.get_glib_settings().get_double("volume")) self.timer_button = self.ui.get_object("timer_button") self.playback_speed_button = self.ui.get_object( "playback_speed_button") self.search_button = self.ui.get_object("search_button") self.warnings_button = self.ui.get_object("warnings_button") self.menu_button = self.ui.get_object("menu_button") self.remaining_event_box = self.ui.get_object("remaining_event_box") # init labels self.title_label = self.ui.get_object("title_label") self.subtitle_label = self.ui.get_object("subtitle_label") self.current_label = self.ui.get_object("current_label") self.current_label.set_visible(False) self.remaining_label = self.ui.get_object("remaining_label") self.remaining_label.set_visible(False) # init images self.play_img = self.ui.get_object("play_img") self.pause_img = self.ui.get_object("pause_img") self.cover_img = self.ui.get_object("cover_img") self.cover_img_box = self.ui.get_object("cover_img_box") # init progress scale self.progress_scale = self.ui.get_object("progress_scale") self.progress_scale.set_increments(30.0, 60.0) self.progress_scale.set_visible(False) self.status_stack = self.ui.get_object("status_stack") self.status_label = self.ui.get_object("status_label") self.update_progress_bar = self.ui.get_object("update_progress_bar") self.throbber = self.ui.get_object("spinner") self.throbber.set_visible(False) self.progress_bar = self.ui.get_object("progress_bar") self.__init_signals() # elementaryos specific stuff if tools.is_elementary(): self.cover_img_box.props.width_request = 28 self.cover_img_box.props.height_request = 28 self.volume_button.props.relief = Gtk.ReliefStyle.NONE else: self.volume_button.get_style_context().remove_class("flat") # app menu self.menu_builder = Gtk.Builder.new_from_resource( "/de/geigi/cozy/titlebar_menu.ui") menu = self.menu_builder.get_object("titlebar_menu") self.menu_button.set_menu_model(menu)
def __filter_books(self, book, data, notify_destroy): """ Filter the books in the book view according to the selected author/reader or "All". """ selected_stack = self.sort_stack.props.visible_child_name if tools.get_glib_settings().get_boolean("hide-offline"): if not self.fs_monitor.is_book_online(book.book): offline_available = Book.get( Book.id == book.book.id).downloaded else: offline_available = True else: offline_available = True if selected_stack == "author": row = self.author_box.get_selected_row() elif selected_stack == "reader": row = self.reader_box.get_selected_row() if selected_stack == "author" or selected_stack == "reader": if row is None: return True and offline_available field = row.data if field is None or field == _("All"): return True and offline_available else: if selected_stack == "author": return True and offline_available if book.book.author == field else False if selected_stack == "reader": return True and offline_available if book.book.reader == field else False elif selected_stack == "recent": return True and offline_available if book.book.last_played > 0 else False
def update_ui_time(self, widget): """ Displays the value of the progress slider in the text boxes as time. """ track = player.get_current_track() if not track: log.debug("update_ui_time: track was None.") return val = int(self.progress_scale.get_value()) if tools.get_glib_settings().get_boolean("titlebar-remaining-time"): total = self.progress_scale.get_adjustment().get_upper() remaining_secs: int = int((total - val)) current_text = seconds_to_str(val, total) remaining_text = seconds_to_str(remaining_secs, total) else: remaining_secs = int((track.length / self.ui.speed.get_speed()) - val) remaining_text = seconds_to_str(remaining_secs, track.length) current_text = seconds_to_str(val, track.length) self.current_label.set_markup("<tt><b>" + current_text + "</b></tt>") self.remaining_label.set_markup("<tt><b>-" + remaining_text + "</b></tt>") if self.ui.book_overview.book and self.current_book.id == self.ui.book_overview.book.id: self.ui.book_overview.update_time()
def __on_timer_changed(self, spinner): """ Add "min" to the timer text box on change. """ if not self.timer_switch.get_active(): self.timer_switch.set_active(True) adjustment = self.timer_spinner.get_adjustment() value = adjustment.get_value() if self.sleep_timer is not None and not self.sleep_timer.is_running: tools.get_glib_settings().set_int("timer", int(value)) self.current_timer_time = value * 60 text = str(int(value)) + " " + _("min") self.timer_buffer.set_text(text, len(text))
def __stop_playback(self): """ Stops playback after gradually fading out (if enabled). """ if tools.get_glib_settings().get_boolean("sleep-timer-fadeout"): duration = tools.get_glib_settings().get_int("sleep-timer-fadeout-duration") * 20 current_vol = player.get_volume() for i in range(0, duration): player.set_volume(current_vol - (i / duration)) time.sleep(0.05) player.set_volume(current_vol) if player.get_gst_player_state() == Gst.State.PLAYING: player.play_pause(None) Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, self.timer_scale.get_adjustment().set_value, 0.0)
def __set_progress_scale_value(self, value): """ Set a given progress scale value. :param value: This value already needs playback speed compensation. """ if tools.get_glib_settings().get_boolean("titlebar-remaining-time"): value += (self.current_elapsed / self.ui.speed.get_speed()) self.progress_scale.set_value(value)
def __get_last_modified(crc, path): global settings if tools.get_glib_settings().get_boolean("use-crc32"): if crc is None: crc = __crc32_from_file(path) modified = crc else: modified = os.path.getmtime(path) return modified
def __update_progress_scale_range(self): """ Update the progress scale range including the current playback speed. """ if tools.get_glib_settings().get_boolean("titlebar-remaining-time"): total = db.get_book_duration( self.current_book) / self.ui.speed.get_speed() else: total = player.get_current_track().length / self.ui.speed.get_speed() self.progress_scale.set_range(0, total)
def __init_timer_buffer(self): """ Add "min" to the timer text field on startup. """ value = tools.get_glib_settings().get_int("timer") adjustment = self.timer_spinner.get_adjustment() adjustment.set_value(value) text = str(int(value)) + " " + _("min") self.timer_buffer.set_text(text, len(text)) return True
def set_darkmode(self): settings = Gtk.Settings.get_default() if self.default_dark_mode is None: self.default_dark_mode = settings.get_property( "gtk-application-prefer-dark-theme") user_enabled = tools.get_glib_settings().get_boolean("dark-mode") if user_enabled: settings.set_property("gtk-application-prefer-dark-theme", True) else: settings.set_property("gtk-application-prefer-dark-theme", self.default_dark_mode)
def __init_actions(self): """ Init all app actions. """ self.accel = Gtk.AccelGroup() help_action = Gio.SimpleAction.new("help", None) help_action.connect("activate", self.help) self.app.add_action(help_action) about_action = Gio.SimpleAction.new("about", None) about_action.connect("activate", self.about) self.app.add_action(about_action) quit_action = Gio.SimpleAction.new("quit", None) quit_action.connect("activate", self.quit) self.app.add_action(quit_action) self.app.set_accels_for_action("app.quit", ["<Control>q", "<Control>w"]) pref_action = Gio.SimpleAction.new("prefs", None) pref_action.connect("activate", self.show_prefs) self.app.add_action(pref_action) self.app.set_accels_for_action("app.prefs", ["<Control>comma"]) self.scan_action = Gio.SimpleAction.new("scan", None) self.scan_action.connect("activate", self.scan) self.app.add_action(self.scan_action) self.play_pause_action = Gio.SimpleAction.new("play_pause", None) self.play_pause_action.connect("activate", self.play_pause) self.app.add_action(self.play_pause_action) self.app.set_accels_for_action("app.play_pause", ["space"]) back_action = Gio.SimpleAction.new("back", None) back_action.connect("activate", self.back) self.app.add_action(back_action) self.app.set_accels_for_action("app.back", ["Escape"]) self.hide_offline_action = Gio.SimpleAction.new_stateful( "hide_offline", None, GLib.Variant.new_boolean( tools.get_glib_settings().get_boolean("hide-offline"))) self.hide_offline_action.connect("change-state", self.__on_hide_offline) self.app.add_action(self.hide_offline_action) builder = Gtk.Builder.new_from_resource("/de/geigi/cozy/app_menu.ui") menu = builder.get_object("app_menu") if not tools.is_elementary(): self.app.set_app_menu(menu)
def __on_mount_added(self, monitor, mount): """ A volume was mounted. Disable offline mode for this volume. """ mount_path = mount.get_root().get_path() log.debug("Volume mounted: " + mount_path) storage = next((s for s in self.external_storage if mount_path in s[0]), None) if storage: log.info("Storage online: " + mount_path) self.emit_event("storage-online", storage[0]) storage[1] = True cozy.ui.main_view.CozyUI().book_box.invalidate_filter() cozy.ui.main_view.CozyUI().filter_author_reader(tools.get_glib_settings().get_boolean("hide-offline"))
def load_last_book(self): if Settings.get().last_played_book: self.update_track_ui() self.update_ui_time(self.progress_scale) cur_m, cur_s = player.get_current_duration_ui() self.__set_progress_scale_value(cur_m * 60 + cur_s) pos = int(player.get_current_track().position) if tools.get_glib_settings().get_boolean("replay"): log.info("Replaying the previous 30 seconds.") amount = 30 * 1000000000 if (pos < amount): pos = 0 else: pos = pos - amount self.__set_progress_scale_value( int(pos / 1000000000 / self.ui.speed.get_speed()))
def __init_actions(self): """ Init all app actions. """ self.accel = Gtk.AccelGroup() help_action = Gio.SimpleAction.new("help", None) help_action.connect("activate", self.help) self.app.add_action(help_action) about_action = Gio.SimpleAction.new("about", None) about_action.connect("activate", self.about) self.app.add_action(about_action) quit_action = Gio.SimpleAction.new("quit", None) quit_action.connect("activate", self.quit) self.app.add_action(quit_action) self.app.set_accels_for_action("app.quit", ["<Control>q", "<Control>w"]) pref_action = Gio.SimpleAction.new("prefs", None) pref_action.connect("activate", self.show_prefs) self.app.add_action(pref_action) self.app.set_accels_for_action("app.prefs", ["<Control>comma"]) self.scan_action = Gio.SimpleAction.new("scan", None) self.scan_action.connect("activate", self.scan) self.app.add_action(self.scan_action) self.play_pause_action = Gio.SimpleAction.new("play_pause", None) self.play_pause_action.connect("activate", self.play_pause) self.app.add_action(self.play_pause_action) self.app.set_accels_for_action("app.play_pause", ["space"]) back_action = Gio.SimpleAction.new("back", None) back_action.connect("activate", self.back) self.app.add_action(back_action) self.app.set_accels_for_action("app.back", ["Escape"]) self.hide_offline_action = Gio.SimpleAction.new_stateful( "hide_offline", None, GLib.Variant.new_boolean( tools.get_glib_settings().get_boolean("hide-offline"))) self.hide_offline_action.connect("change-state", self.__on_hide_offline) self.app.add_action(self.hide_offline_action)
def refresh_content(self): """ Refresh all content. """ # First clear the boxes childs = self.book_box.get_children() for element in childs: self.book_box.remove(element) self.populate_author_reader() self.filter_author_reader(tools.get_glib_settings().get_boolean("hide-offline")) for b in db.books(): self.book_box.add(BookElement(b)) self.book_box.show_all() return False
def get_playback_start_position(self): """ Returns the position where to start playback of the current track. This checks for the automatic replay option. :return: Position in ns """ pos = player.get_current_track().position if self.first_play: self.first_play = False if tools.get_glib_settings().get_boolean("replay"): amount = 30 * 1000000000 if pos < amount: pos = 0 else: pos = pos - amount return pos
def __on_mount_removed(self, monitor, mount): """ A volume was unmounted. Enable offline mode for this volume. """ mount_path = mount.get_root().get_path() log.debug("Volume unmounted: " + mount_path) storage = next( (s for s in self.external_storage if mount_path in s[0]), None) if storage: log.info("Storage offline: " + mount_path) self.emit_event("storage-offline", storage[0]) storage[1] = False # switch to offline version if currently playing cozy.ui.CozyUI().book_box.invalidate_filter() cozy.ui.CozyUI().filter_author_reader( tools.get_glib_settings().get_boolean("hide-offline"))
def __load_cover_pixbuf(book): """ Load the cover from a given book and create a pixbuf object with a given from it. :param book: The book object :param size: The size of the bigger side in pixels :return: pixbuf object containing the cover """ pixbuf = None if tools.get_glib_settings().get_boolean("prefer-external-cover"): pixbuf = __load_pixbuf_from_file(book) if pixbuf is None: pixbuf = __load_pixbuf_from_db(book) else: pixbuf = __load_pixbuf_from_db(book) if pixbuf is None: pixbuf = __load_pixbuf_from_file(book) return pixbuf
def __on_progress_clicked(self, widget, sender): """ Jump to the slided time and release the progress scale update lock. """ value = self.progress_scale.get_value() * self.ui.speed.get_speed() if tools.get_glib_settings().get_boolean("titlebar-remaining-time"): track, time = get_track_from_book_time(self.current_book, value) if track.id == player.get_current_track().id: player.jump_to(time) else: player.load_file(track) player.play_pause(None, True) self.__set_progress_scale_value(time / self.ui.speed.get_speed()) player.jump_to(time) else: player.jump_to(value) self.progress_scale_clicked = False return False
def update_track_ui(self): # set data of new stream in ui track = player.get_current_track() if track is None: return self.title_label.set_text(track.book.name) self.subtitle_label.set_text(track.name) self.block_ui_buttons(False) self.progress_scale.set_sensitive(True) self.progress_scale.set_visible(True) # only change cover when book has changed if self.current_book is not track.book: self.current_book = track.book if tools.is_elementary(): size = 28 else: size = 40 self.set_title_cover( artwork_cache.get_cover_pixbuf( track.book, self.ui.window.get_scale_factor(), size), size) self.current_remaining = db.get_book_remaining(self.current_book, False) self.current_elapsed = db.get_book_progress(self.current_book, False) self.__update_progress_scale_range() if tools.get_glib_settings().get_boolean("titlebar-remaining-time"): self.progress_scale.set_value(self.current_elapsed / self.ui.speed.get_speed()) else: self.progress_scale.set_value(0) self.update_ui_time(None) self.current_label.set_visible(True) self.remaining_label.set_visible(True)
def __init_bindings(self): """ Bind Gio.Settings to widgets in settings dialog. """ sl_switch = self.builder.get_object("symlinks_switch") tools.get_glib_settings().bind("symlinks", sl_switch, "active", Gio.SettingsBindFlags.DEFAULT) auto_scan_switch = self.builder.get_object("auto_scan_switch") tools.get_glib_settings().bind("autoscan", auto_scan_switch, "active", Gio.SettingsBindFlags.DEFAULT) timer_suspend_switch = self.builder.get_object("timer_suspend_switch") tools.get_glib_settings().bind("suspend", timer_suspend_switch, "active", Gio.SettingsBindFlags.DEFAULT) replay_switch = self.builder.get_object("replay_switch") tools.get_glib_settings().bind("replay", replay_switch, "active", Gio.SettingsBindFlags.DEFAULT) titlebar_remaining_time_switch = self.builder.get_object( "titlebar_remaining_time_switch") tools.get_glib_settings().bind("titlebar-remaining-time", titlebar_remaining_time_switch, "active", Gio.SettingsBindFlags.DEFAULT) dark_mode_switch = self.builder.get_object("dark_mode_switch") tools.get_glib_settings().bind("dark-mode", dark_mode_switch, "active", Gio.SettingsBindFlags.DEFAULT) swap_author_reader_switch = self.builder.get_object( "swap_author_reader_switch") tools.get_glib_settings().bind("swap-author-reader", swap_author_reader_switch, "active", Gio.SettingsBindFlags.DEFAULT) tools.get_glib_settings().bind("prefer-external-cover", self.external_cover_switch, "active", Gio.SettingsBindFlags.DEFAULT) tools.get_glib_settings().bind("sleep-timer-fadeout", self.sleep_fadeout_switch, "active", Gio.SettingsBindFlags.DEFAULT) tools.get_glib_settings().bind("sleep-timer-fadeout-duration", self.fadeout_duration_adjustment, "value", Gio.SettingsBindFlags.DEFAULT) tools.get_glib_settings().connect("changed", self.__on_settings_changed)