forked from clan/clan-core
Merge pull request 'async join' (#807) from hsjobeki-main into main
This commit is contained in:
commit
08c1e13dce
@ -4,8 +4,6 @@ from pathlib import Path
|
||||
|
||||
import gi
|
||||
|
||||
from clan_vm_manager.models.use_join import Join
|
||||
|
||||
gi.require_version("Gtk", "4.0")
|
||||
gi.require_version("Adw", "1")
|
||||
|
||||
@ -28,9 +26,6 @@ class MainApplication(Adw.Application):
|
||||
self.config = config
|
||||
self.connect("shutdown", self.on_shutdown)
|
||||
|
||||
if config.url:
|
||||
Join.use().push(config.url)
|
||||
|
||||
def on_shutdown(self, app: Gtk.Application) -> None:
|
||||
log.debug("Shutting down")
|
||||
VMS.use().kill_all()
|
||||
|
@ -1,30 +1,45 @@
|
||||
import logging
|
||||
import threading
|
||||
from collections.abc import Callable
|
||||
from typing import Any
|
||||
from typing import Any, ClassVar
|
||||
|
||||
import gi
|
||||
from clan_cli import ClanError
|
||||
from clan_cli.clan_uri import ClanURI
|
||||
from clan_cli.history.add import HistoryEntry, add_history
|
||||
from clan_cli.history.add import add_history
|
||||
|
||||
from clan_vm_manager.errors.show_error import show_error_dialog
|
||||
from clan_vm_manager.models.use_vms import VMS, Clans
|
||||
|
||||
gi.require_version("Gtk", "4.0")
|
||||
gi.require_version("Adw", "1")
|
||||
from gi.repository import Gio, GObject
|
||||
from gi.repository import Gio, GLib, GObject
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class JoinValue(GObject.Object):
|
||||
# TODO: custom signals for async join
|
||||
# __gsignals__: ClassVar = {}
|
||||
|
||||
__gsignals__: ClassVar = {
|
||||
"join_finished": (GObject.SignalFlags.RUN_FIRST, None, [GObject.Object]),
|
||||
}
|
||||
|
||||
url: ClanURI
|
||||
|
||||
def __init__(self, url: ClanURI) -> None:
|
||||
def __init__(
|
||||
self, url: ClanURI, on_join: Callable[["JoinValue", Any], None]
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.url = url
|
||||
self.connect("join_finished", on_join)
|
||||
|
||||
def __join(self) -> None:
|
||||
add_history(self.url, all_machines=False)
|
||||
GLib.idle_add(lambda: self.emit("join_finished", self))
|
||||
|
||||
def join(self) -> None:
|
||||
threading.Thread(target=self.__join).start()
|
||||
|
||||
|
||||
class Join:
|
||||
@ -48,26 +63,27 @@ class Join:
|
||||
|
||||
return cls._instance
|
||||
|
||||
def push(self, url: ClanURI) -> None:
|
||||
def push(self, url: ClanURI, on_join: Callable[[JoinValue], None]) -> None:
|
||||
"""
|
||||
Add a join request.
|
||||
This method can add multiple join requests if called subsequently for each request.
|
||||
"""
|
||||
self.list_store.append(JoinValue(url))
|
||||
|
||||
def join(self, item: JoinValue, cb: Callable[[list[HistoryEntry]], None]) -> None:
|
||||
# TODO: remove the item that was accepted join from this list
|
||||
# and call the success function. (The caller is responsible for handling the success)
|
||||
def after_join(item: JoinValue, _: Any) -> None:
|
||||
self.discard(item)
|
||||
Clans.use().refresh()
|
||||
VMS.use().refresh()
|
||||
print("Refreshed list after join")
|
||||
on_join(item)
|
||||
|
||||
self.list_store.append(JoinValue(url, after_join))
|
||||
|
||||
def join(self, item: JoinValue) -> None:
|
||||
try:
|
||||
log.info(f"trying to join: {item.url}")
|
||||
|
||||
history = add_history(item.url)
|
||||
cb(history)
|
||||
self.discard(item)
|
||||
|
||||
item.join()
|
||||
except ClanError as e:
|
||||
show_error_dialog(e)
|
||||
pass
|
||||
|
||||
def discard(self, item: JoinValue) -> None:
|
||||
(has, idx) = self.list_store.find(item)
|
||||
|
@ -38,6 +38,18 @@ class ClanGroup(GObject.Object):
|
||||
self.list_store.append(vm)
|
||||
|
||||
|
||||
def init_grp_store(list_store: Gio.ListStore) -> None:
|
||||
groups: dict[str | Path, list["VM"]] = {}
|
||||
for vm in get_saved_vms():
|
||||
ll = groups.get(vm.data.flake.flake_url, [])
|
||||
ll.append(vm)
|
||||
groups[vm.data.flake.flake_url] = ll
|
||||
|
||||
for url, vm_list in groups.items():
|
||||
grp = ClanGroup(url, vm_list)
|
||||
list_store.append(grp)
|
||||
|
||||
|
||||
class Clans:
|
||||
list_store: Gio.ListStore
|
||||
_instance: "None | ClanGroup" = None
|
||||
@ -51,19 +63,14 @@ class Clans:
|
||||
if cls._instance is None:
|
||||
cls._instance = cls.__new__(cls)
|
||||
cls.list_store = Gio.ListStore.new(ClanGroup)
|
||||
|
||||
groups: dict[str | Path, list["VM"]] = {}
|
||||
for vm in get_saved_vms():
|
||||
ll = groups.get(vm.data.flake.flake_url, [])
|
||||
ll.append(vm)
|
||||
groups[vm.data.flake.flake_url] = ll
|
||||
|
||||
for url, vms in groups.items():
|
||||
grp = ClanGroup(url, vms)
|
||||
cls.list_store.append(grp)
|
||||
init_grp_store(cls.list_store)
|
||||
|
||||
return cls._instance
|
||||
|
||||
def refresh(self) -> None:
|
||||
self.list_store.remove_all()
|
||||
init_grp_store(self.list_store)
|
||||
|
||||
|
||||
class VM(GObject.Object):
|
||||
# Define a custom signal with the name "vm_stopped" and a string argument for the message
|
||||
|
@ -3,8 +3,9 @@ from collections.abc import Callable
|
||||
from functools import partial
|
||||
|
||||
import gi
|
||||
from clan_cli.history.add import HistoryEntry
|
||||
from clan_cli import history
|
||||
|
||||
from clan_vm_manager.models.interfaces import ClanConfig
|
||||
from clan_vm_manager.models.use_join import Join, JoinValue
|
||||
from clan_vm_manager.models.use_views import Views
|
||||
|
||||
@ -42,12 +43,16 @@ class ClanList(Gtk.Box):
|
||||
# ------------------------#
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
def __init__(self, config: ClanConfig) -> None:
|
||||
super().__init__(orientation=Gtk.Orientation.VERTICAL)
|
||||
|
||||
groups = Clans.use()
|
||||
join = Join.use()
|
||||
|
||||
if config.url:
|
||||
join.push(config.url, self.after_join)
|
||||
|
||||
self.__init_machines = history.add.list_history()
|
||||
self.join_boxed_list = create_boxed_list(
|
||||
model=join.list_store, render_row=self.render_join_row
|
||||
)
|
||||
@ -152,6 +157,7 @@ class ClanList(Gtk.Box):
|
||||
cancel_button = Gtk.Button(label="Cancel")
|
||||
cancel_button.add_css_class("error")
|
||||
cancel_button.connect("clicked", partial(self.on_discard_clicked, item))
|
||||
self.cancel_button = cancel_button
|
||||
|
||||
trust_button = Gtk.Button(label="Join")
|
||||
trust_button.add_css_class("success")
|
||||
@ -178,18 +184,20 @@ class ClanList(Gtk.Box):
|
||||
dialog.set_transient_for(p) # set the parent window of the dialog
|
||||
dialog.choose()
|
||||
|
||||
def after_join(self, item: JoinValue) -> None:
|
||||
# If the join request list is empty disable the shadow artefact
|
||||
if not Join.use().list_store.get_n_items():
|
||||
self.join_boxed_list.add_css_class("no-shadow")
|
||||
print("after join in list")
|
||||
|
||||
def on_trust_clicked(self, item: JoinValue, widget: Gtk.Widget) -> None:
|
||||
def on_join(_history: list[HistoryEntry]) -> None:
|
||||
VMS.use().refresh()
|
||||
widget.set_sensitive(False)
|
||||
self.cancel_button.set_sensitive(False)
|
||||
|
||||
# TODO(@hsjobeki): Confirm and edit details
|
||||
# Views.use().view.set_visible_child_name("details")
|
||||
|
||||
Join.use().join(item, cb=on_join)
|
||||
|
||||
# If the join request list is empty disable the shadow artefact
|
||||
if not Join.use().list_store.get_n_items():
|
||||
self.join_boxed_list.add_css_class("no-shadow")
|
||||
Join.use().join(item)
|
||||
|
||||
def on_discard_clicked(self, item: JoinValue, widget: Gtk.Widget) -> None:
|
||||
Join.use().discard(item)
|
||||
|
@ -29,7 +29,7 @@ class MainWindow(Adw.ApplicationWindow):
|
||||
scroll = Gtk.ScrolledWindow()
|
||||
scroll.set_propagate_natural_height(True)
|
||||
scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
|
||||
scroll.set_child(ClanList())
|
||||
scroll.set_child(ClanList(config))
|
||||
|
||||
stack_view.add_named(scroll, "list")
|
||||
stack_view.add_named(Details(), "details")
|
||||
|
Loading…
Reference in New Issue
Block a user