1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
from typing import Callable
from gi.repository import Adw, Gio, GLib, GObject, Gtk
import inject
from cozy.model.storage import Storage
from cozy.view_model.storages_view_model import StoragesViewModel
def ask_storage_location(callback: Callable[[str | None], None], initial_folder: str | None = None):
location_chooser = Gtk.FileDialog(title=_("Set Audiobooks Directory"))
if initial_folder:
gfile = Gio.File.new_for_path(initial_folder)
location_chooser.set_initial_folder(gfile)
def finish_callback(dialog, result):
try:
file = dialog.select_folder_finish(result)
except GLib.GError:
pass
else:
callback(None if file is None else file.get_path())
location_chooser.select_folder(inject.instance("MainWindow").window, None, finish_callback)
@Gtk.Template.from_resource("/com/github/geigi/cozy/storage_row.ui")
class StorageRow(Adw.ActionRow):
__gtype_name__ = "StorageRow"
icon: Gtk.Image = Gtk.Template.Child()
default_icon: Gtk.Image = Gtk.Template.Child()
menu_button: Gtk.MenuButton = Gtk.Template.Child()
def __init__(self, model: Storage, menu_model: Gio.Menu) -> None:
self._model = model
super().__init__(title=model.path)
self.connect("activated", self.ask_for_new_location)
self.menu_button.set_menu_model(menu_model)
self.menu_button.connect("notify::active", self._on_menu_opened)
self._set_default_icon()
self._set_drive_icon()
@property
def model(self) -> Storage:
return self._model
def ask_for_new_location(self, *_) -> None:
ask_storage_location(self._on_folder_changed, initial_folder=self._model.path)
def _on_folder_changed(self, new_path: str | None) -> None:
if new_path is not None:
self.emit("location-changed", new_path)
def _on_menu_opened(self, *_) -> None:
self.emit("menu-opened")
def _set_drive_icon(self) -> None:
if self._model.external:
self.icon.set_from_icon_name("network-server-symbolic")
self.icon.set_tooltip_text(_("External drive"))
else:
self.icon.set_from_icon_name("folder-open-symbolic")
self.icon.set_tooltip_text(_("Internal drive"))
def _set_default_icon(self) -> None:
self.default_icon.set_visible(self._model.default)
GObject.signal_new(
"location-changed",
StorageRow,
GObject.SIGNAL_RUN_LAST,
GObject.TYPE_PYOBJECT,
(GObject.TYPE_PYOBJECT,),
)
GObject.signal_new("menu-opened", StorageRow, GObject.SIGNAL_RUN_LAST, GObject.TYPE_PYOBJECT, ())
@Gtk.Template.from_resource("/com/github/geigi/cozy/storage_locations.ui")
class StorageLocations(Adw.PreferencesGroup):
__gtype_name__ = "StorageLocations"
_view_model: StoragesViewModel = inject.attr(StoragesViewModel)
storage_locations_list: Gtk.ListBox = Gtk.Template.Child()
storage_menu: Gio.Menu = Gtk.Template.Child()
def __init__(self) -> None:
super().__init__()
self._view_model.bind_to("storage_locations", self._reload_storage_list)
self._view_model.bind_to("storage_attributes", self._reload_storage_list)
self._create_actions()
self.new_storage_button = self._create_new_storage_button()
self._reload_storage_list()
def _create_actions(self) -> None:
self.action_group = Gio.SimpleActionGroup.new()
self.insert_action_group("storage", self.action_group)
self.set_external_action = Gio.SimpleAction.new_stateful(
"mark-external", None, GLib.Variant.new_boolean(False)
)
self._set_external_signal_handler = self.set_external_action.connect(
"notify::state", self._mark_storage_location_external
)
self.action_group.add_action(self.set_external_action)
self.remove_action = Gio.SimpleAction.new("remove", None)
self.remove_action.connect("activate", self._remove_storage_location)
self.action_group.add_action(self.remove_action)
self.make_default_action = Gio.SimpleAction.new("make-default", None)
self.make_default_action.connect("activate", self._set_default_storage_location)
self.action_group.add_action(self.make_default_action)
def _create_new_storage_button(self) -> Adw.ActionRow:
icon = Gtk.Image(icon_name="list-add-symbolic", margin_top=18, margin_bottom=18)
row = Adw.ActionRow(selectable=False, activatable=True)
row.connect("activated", self._on_new_storage_clicked)
row.set_child(icon)
return row
def _reload_storage_list(self) -> None:
self.storage_locations_list.remove_all()
for storage in self._view_model.storages:
row = StorageRow(storage, menu_model=self.storage_menu)
row.connect("location-changed", self._on_storage_location_changed)
row.connect("menu-opened", self._on_storage_menu_opened)
self.storage_locations_list.append(row)
self.storage_locations_list.append(self.new_storage_button)
def _remove_storage_location(self, *_) -> None:
self._view_model.remove(self._view_model.selected_storage)
def _set_default_storage_location(self, *_) -> None:
self._view_model.set_default(self._view_model.selected_storage)
def _mark_storage_location_external(
self, action: Gio.SimpleAction, value: GObject.ParamSpec
) -> None:
value = action.get_property(value.name)
self._view_model.set_external(self._view_model.selected_storage, value)
def _on_new_storage_clicked(self, *_) -> None:
ask_storage_location(self._view_model.add_storage_location)
def _on_storage_location_changed(self, widget: StorageRow, new_location: str) -> None:
self._view_model.change_storage_location(widget.model, new_location)
def _on_storage_menu_opened(self, widget: StorageRow) -> None:
with self.set_external_action.handler_block(self._set_external_signal_handler):
self.set_external_action.props.state = GLib.Variant.new_boolean(widget.model.external)
self.remove_action.props.enabled = (
not widget.model.default and len(self._view_model.storages) > 1
)
self.make_default_action.props.enabled = widget.model is not self._view_model.default
self._view_model.selected_storage = widget.model
|