Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add back system power control for sleep timer #981

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion com.github.geigi.cozy.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
"--filesystem=host",
"--filesystem=xdg-run/gvfs",
"--filesystem=xdg-run/gvfsd",
"--talk-name=org.gtk.vfs.*"
"--talk-name=org.gtk.vfs.*",
"--talk-name=org.gnome.SessionManager",
"--system-talk-name=org.freedesktop.login1"
],
"modules": [
{
Expand Down
8 changes: 1 addition & 7 deletions cozy/app_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,7 @@ def open_library(self):
self.app_view_model.view = View.LIBRARY_FILTER

def _connect_search_button(self):
self.headerbar.search_button.connect(
"notify::active",
self.search_view.on_state_changed
)
self.headerbar.search_button.connect("notify::active", self.search_view.on_state_changed)

def _on_open_view(self, event, data):
if event == OpenView.AUTHOR:
Expand Down Expand Up @@ -147,6 +144,3 @@ def _on_working_event(self, event: str, data) -> None:
def _on_main_window_event(self, event: str, data):
if event == "open_view":
self._on_open_view(data, None)

def quit(self):
self.player.destroy()
9 changes: 6 additions & 3 deletions cozy/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Application(Adw.Application):
def __init__(self, pkgdatadir: str):
self.pkgdatadir = pkgdatadir

super().__init__(application_id='com.github.geigi.cozy')
super().__init__(application_id="com.github.geigi.cozy")
self.init_custom_widgets()

GLib.setenv("PULSE_PROP_media.role", "music", True)
Expand Down Expand Up @@ -83,12 +83,15 @@ def handle_exception(self, _):
return

try:
reporter.exception("uncaught", exc_value, "\n".join(format_exception(exc_type, exc_value, exc_traceback)))
reporter.exception(
"uncaught",
exc_value,
"\n".join(format_exception(exc_type, exc_value, exc_traceback)),
)
finally:
sys.excepthook(exc_type, exc_value, exc_traceback)

def quit(self):
self.app_controller.quit()
super().quit()

@staticmethod
Expand Down
2 changes: 2 additions & 0 deletions cozy/media/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,8 @@ def _on_gst_player_event(self, event: str, message):
self._next_chapter()
else:
self._stop_playback()
self.emit_event_main_thread("fadeout-finished")
self._play_next_chapter = True
elif event == "resource-not-found":
self._handle_file_not_found()
elif event == "state" and message == Gst.State.PLAYING:
Expand Down
27 changes: 10 additions & 17 deletions cozy/ui/main_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,9 @@ def __init_actions(self):
self.create_action("mark_book_as_read", self.mark_book_as_read)
self.create_action("jump_to_book_folder", self.jump_to_book_folder)

self.create_action("prefs", self.show_preferences_window, ["<primary>comma"], global_shorcut=True)
self.create_action(
"prefs", self.show_preferences_window, ["<primary>comma"], global_shorcut=True
)
self.create_action("quit", self.quit, ["<primary>q", "<primary>w"], global_shorcut=True)

self.scan_action = self.create_action("scan", self.scan)
Expand Down Expand Up @@ -173,12 +175,8 @@ def jump_to_book_folder(self, *_) -> None:
def get_object(self, name):
return self.window_builder.get_object(name)

def quit(self, action, parameter):
"""
Quit app.
"""
self.on_close(None)
self.app.quit()
def get_builder(self):
return self.window_builder

def _dialog_close_callback(self, dialog):
dialog.disconnect_by_func(self._dialog_close_callback)
Expand Down Expand Up @@ -275,30 +273,25 @@ def _set_audiobook_path(self, path: str | None) -> None:
self.scan(None, None)
self.fs_monitor.init_offline_mode()

def on_close(self, widget, data=None):
def on_close(self, *_):
"""
Close and dispose everything that needs to be when window is closed.
"""
log.info("Closing.")
log.info("Releasing resources.")
self.fs_monitor.close()

self._save_window_size()

self._player.destroy()

close_db()

report.close()

log.info("Saving settings.")
self._gio_settings.apply()

def quit(self, *_):
self.on_close()
log.info("Closing app.")
self.app.quit()
log.info("App closed.")

def get_builder(self):
return self.window_builder

def _on_importer_event(self, event: str, message):
if event == "scan" and message == ScanStatus.SUCCESS:
self.check_for_tracks()
Expand Down
13 changes: 12 additions & 1 deletion cozy/ui/widgets/sleep_timer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from gi.repository import Adw, Gio, GLib, Gtk

from cozy.control.time_format import min_to_human_readable, seconds_to_time
from cozy.view_model.sleep_timer_view_model import SleepTimerViewModel
from cozy.view_model.sleep_timer_view_model import SleepTimerViewModel, SystemPowerAction


@Gtk.Template.from_resource("/com/github/geigi/cozy/ui/sleep_timer_dialog.ui")
Expand All @@ -19,6 +19,7 @@ class SleepTimer(Adw.Dialog):
timer_state: Adw.StatusPage = Gtk.Template.Child()
toolbarview: Adw.ToolbarView = Gtk.Template.Child()
till_end_of_chapter_button_row: Adw.ButtonRow = Gtk.Template.Child()
power_action_combo_row: Adw.ComboRow() = Gtk.Template.Child()

def __init__(self, parent_button: Gtk.Button):
super().__init__()
Expand Down Expand Up @@ -46,6 +47,10 @@ def __init__(self, parent_button: Gtk.Button):
self.custom_adjustment.connect("value-changed", self._update_custom_interval_text)
self._update_custom_interval_text()

self.power_action_list = [_("None"), _("Suspend"), _("Shutdown")]
power_action_list_model = Gtk.StringList.new(self.power_action_list)
self.power_action_combo_row.props.model = power_action_list_model

self._connect_view_model()

def _connect_view_model(self):
Expand Down Expand Up @@ -148,3 +153,9 @@ def cancel_timer(self, *_):
super().close()
self._view_model.remaining_seconds = 0
self._view_model.stop_after_chapter = False

@Gtk.Template.Callback()
def on_power_action_selected(self, obj, _):
selected_string = obj.props.selected_item.get_string()
selected_string_index = self.power_action_list.index(selected_string)
self._view_model.system_power_action = SystemPowerAction(selected_string_index)
92 changes: 62 additions & 30 deletions cozy/view_model/sleep_timer_view_model.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import logging
import os
import sys
from enum import Enum, auto

from gi.repository import Gst
from enum import Enum

import inject
from gi.repository import Gio, GLib, Gst

from cozy.architecture.observable import Observable
from cozy.media.player import Player
Expand All @@ -16,10 +14,10 @@
FADEOUT_DURATION = 20


class SystemPowerControl(Enum):
OFF = auto()
SUSPEND = auto()
SHUTDOWN = auto()
class SystemPowerAction(Enum):
NONE = 0
SUSPEND = 1
SHUTDOWN = 2


class SleepTimerViewModel(Observable):
Expand All @@ -30,7 +28,7 @@ def __init__(self):
super().__init__()

self._remaining_seconds: int = 0
self._system_power_control: SystemPowerControl = SystemPowerControl.OFF
self._system_power_action = SystemPowerAction.NONE
self._timer_running = False
self._fadeout_running = False

Expand All @@ -54,12 +52,12 @@ def remaining_seconds(self, new_value: int):
self._stop_timer()

@property
def system_power_control(self) -> SystemPowerControl:
return self._system_power_control
def system_power_action(self) -> SystemPowerAction:
return self._system_power_action

@system_power_control.setter
def system_power_control(self, new_value: SystemPowerControl):
self._system_power_control = new_value
@system_power_action.setter
def system_power_action(self, new_value: SystemPowerAction) -> None:
self._system_power_action = new_value

@property
def stop_after_chapter(self) -> bool:
Expand Down Expand Up @@ -111,28 +109,62 @@ def _on_timer_tick(self):
if self._remaining_seconds <= 0:
self._stop_timer()
self._player.pause()
self._handle_system_power_event()

def _on_player_changed(self, event, _):
if event == "position":
if self._timer_running:
self._on_timer_tick()
elif event == "chapter-changed":
self.stop_after_chapter = False
elif event == "fadeout-finished":
self._handle_system_power_event()

def _handle_system_power_event(self):
# TODO: This doesn't work in Flatpak. Either remove it completely, or make it conditional
command = None

if self.system_power_control == SystemPowerControl.SHUTDOWN:
log.info("system will attempt to shutdown now!")
if "linux" in sys.platform.lower():
command = "systemctl poweroff"
else:
command = "shutdown -h now"
elif self.system_power_control == SystemPowerControl.SUSPEND:
log.info("system will attempt to suspend now!")
if "linux" in sys.platform.lower():
command = "systemctl suspend"

if command:
os.system(command)
match self.system_power_action:
case SystemPowerAction.SHUTDOWN:
self._shutdown()
case SystemPowerAction.SUSPEND:
self._suspend()
case _:
return

def _shutdown(self):
inject.instance("MainWindow").quit() # Exit gracefully
if os.getenv("XDG_CURRENT_DESKTOP") == "GNOME":
Gio.bus_get_sync(Gio.BusType.SESSION, None).call_sync(
"org.gnome.SessionManager",
"/org/gnome/SessionManager",
"org.gnome.SessionManager",
"Shutdown",
None,
None,
Gio.DBusCallFlags.NONE,
-1,
None,
)
else:
Gio.bus_get_sync(Gio.BusType.SYSTEM, None).call_sync(
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"PowerOff",
GLib.Variant.new_tuple(GLib.Variant.new_boolean(True)),
None,
Gio.DBusCallFlags.NONE,
-1,
None,
)

def _suspend(self):
Gio.bus_get_sync(Gio.BusType.SYSTEM, None).call_sync(
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"Suspend",
GLib.Variant.new_tuple(GLib.Variant.new_boolean(True)),
None,
Gio.DBusCallFlags.NONE,
-1,
None,
)
14 changes: 13 additions & 1 deletion data/ui/sleep_timer_dialog.blp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,19 @@ template $SleepTimer: Adw.Dialog {

StackPage {
name: "uninitiated";
child: Adw.PreferencesGroup list {};
child: Box {
orientation: vertical;
spacing: 12;

Adw.PreferencesGroup list {}
Adw.PreferencesGroup {
Adw.ComboRow power_action_combo_row {
title: _("System Power Control");
subtitle: _("Action to perform when timer finishes");
notify::selected-item => $on_power_action_selected();
}
}
};
}

visible-child-name: "uninitiated";
Expand Down
Loading