organize files and classes consistently
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from .app import (
|
from clan_cli.clan_uri import ClanURI
|
||||||
register_join_parser,
|
|
||||||
register_overview_parser,
|
from clan_vm_manager.models.interfaces import ClanConfig
|
||||||
show_overview,
|
|
||||||
)
|
from .app import MainApplication
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
@@ -24,3 +24,26 @@ def main() -> None:
|
|||||||
parser.set_defaults(func=show_overview)
|
parser.set_defaults(func=show_overview)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
args.func(args)
|
args.func(args)
|
||||||
|
|
||||||
|
|
||||||
|
def show_join(args: argparse.Namespace) -> None:
|
||||||
|
app = MainApplication(
|
||||||
|
config=ClanConfig(url=args.clan_uri, initial_view="join.trust"),
|
||||||
|
)
|
||||||
|
return app.run()
|
||||||
|
|
||||||
|
|
||||||
|
def register_join_parser(parser: argparse.ArgumentParser) -> None:
|
||||||
|
parser.add_argument("clan_uri", type=ClanURI, help="clan URI to join")
|
||||||
|
parser.set_defaults(func=show_join)
|
||||||
|
|
||||||
|
|
||||||
|
def show_overview(args: argparse.Namespace) -> None:
|
||||||
|
app = MainApplication(
|
||||||
|
config=ClanConfig(url=None, initial_view="list"),
|
||||||
|
)
|
||||||
|
return app.run()
|
||||||
|
|
||||||
|
|
||||||
|
def register_overview_parser(parser: argparse.ArgumentParser) -> None:
|
||||||
|
parser.set_defaults(func=show_overview)
|
||||||
|
|||||||
@@ -1,62 +1,21 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import argparse
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
|
|
||||||
from clan_vm_manager.interfaces import InitialJoinValues
|
|
||||||
from clan_vm_manager.model.use_views import Views
|
|
||||||
from clan_vm_manager.views.list import ClanList
|
|
||||||
from clan_vm_manager.views.trust_join import Trust
|
|
||||||
|
|
||||||
gi.require_version("Gtk", "4.0")
|
gi.require_version("Gtk", "4.0")
|
||||||
gi.require_version("Adw", "1")
|
gi.require_version("Adw", "1")
|
||||||
|
|
||||||
from clan_cli.clan_uri import ClanURI
|
|
||||||
from gi.repository import Adw, Gdk, Gio, Gtk
|
from gi.repository import Adw, Gdk, Gio, Gtk
|
||||||
|
|
||||||
|
from clan_vm_manager.models.interfaces import ClanConfig
|
||||||
|
from clan_vm_manager.models.use_vms import VMS
|
||||||
|
|
||||||
from .constants import constants
|
from .constants import constants
|
||||||
from .model.use_vms import VMS
|
from .windows.main_window import MainWindow
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class MainApplication(Adw.Application):
|
||||||
class ClanConfig:
|
|
||||||
initial_view: str
|
|
||||||
url: ClanURI | None
|
|
||||||
|
|
||||||
|
|
||||||
class MainWindow(Adw.ApplicationWindow):
|
|
||||||
def __init__(self, config: ClanConfig) -> None:
|
|
||||||
super().__init__()
|
|
||||||
self.set_title("cLAN Manager")
|
|
||||||
self.set_default_size(980, 650)
|
|
||||||
|
|
||||||
view = Adw.ToolbarView()
|
|
||||||
self.set_content(view)
|
|
||||||
|
|
||||||
header = Adw.HeaderBar()
|
|
||||||
view.add_top_bar(header)
|
|
||||||
|
|
||||||
# Initialize all views
|
|
||||||
stack_view = Views.use().view
|
|
||||||
stack_view.add_named(ClanList(), "list")
|
|
||||||
stack_view.add_named(
|
|
||||||
Trust(initial_values=InitialJoinValues(url=config.url)), "join.trust"
|
|
||||||
)
|
|
||||||
|
|
||||||
stack_view.set_visible_child_name(config.initial_view)
|
|
||||||
|
|
||||||
clamp = Adw.Clamp()
|
|
||||||
clamp.set_child(stack_view)
|
|
||||||
clamp.set_maximum_size(1000)
|
|
||||||
|
|
||||||
view.set_content(clamp)
|
|
||||||
|
|
||||||
# Push the first page to the navigation view
|
|
||||||
|
|
||||||
|
|
||||||
class Application(Adw.Application):
|
|
||||||
def __init__(self, config: ClanConfig) -> None:
|
def __init__(self, config: ClanConfig) -> None:
|
||||||
super().__init__(
|
super().__init__(
|
||||||
application_id=constants["APPID"], flags=Gio.ApplicationFlags.FLAGS_NONE
|
application_id=constants["APPID"], flags=Gio.ApplicationFlags.FLAGS_NONE
|
||||||
@@ -84,26 +43,3 @@ class Application(Adw.Application):
|
|||||||
css_provider,
|
css_provider,
|
||||||
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION,
|
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def show_join(args: argparse.Namespace) -> None:
|
|
||||||
app = Application(
|
|
||||||
config=ClanConfig(url=args.clan_uri, initial_view="join.trust"),
|
|
||||||
)
|
|
||||||
return app.run()
|
|
||||||
|
|
||||||
|
|
||||||
def register_join_parser(parser: argparse.ArgumentParser) -> None:
|
|
||||||
parser.add_argument("clan_uri", type=ClanURI, help="clan URI to join")
|
|
||||||
parser.set_defaults(func=show_join)
|
|
||||||
|
|
||||||
|
|
||||||
def show_overview(args: argparse.Namespace) -> None:
|
|
||||||
app = Application(
|
|
||||||
config=ClanConfig(url=None, initial_view="list"),
|
|
||||||
)
|
|
||||||
return app.run()
|
|
||||||
|
|
||||||
|
|
||||||
def register_overview_parser(parser: argparse.ArgumentParser) -> None:
|
|
||||||
parser.set_defaults(func=show_overview)
|
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
from collections.abc import Callable
|
|
||||||
from dataclasses import dataclass
|
|
||||||
|
|
||||||
from clan_cli.clan_uri import ClanURI
|
|
||||||
|
|
||||||
|
|
||||||
# url is only set, if the app was started with "join <url>"
|
|
||||||
# Url is usually None, when user clicks "New" clan
|
|
||||||
@dataclass
|
|
||||||
class InitialJoinValues:
|
|
||||||
url: ClanURI | None
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class InitialFlashValues:
|
|
||||||
selected: str | None
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Callbacks:
|
|
||||||
show_list: Callable[[], None]
|
|
||||||
show_join: Callable[[], None]
|
|
||||||
show_flash: Callable[[], None]
|
|
||||||
spawn_vm: Callable[[str, str], None]
|
|
||||||
stop_vm: Callable[[str, str], None]
|
|
||||||
running_vms: Callable[[], list[str]]
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
from collections.abc import Callable
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
from gi.repository import Gio
|
|
||||||
|
|
||||||
from clan_vm_manager.models import VM, get_initial_vms
|
|
||||||
|
|
||||||
|
|
||||||
class VMS:
|
|
||||||
"""
|
|
||||||
This is a singleton.
|
|
||||||
It is initialized with the first call of use()
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
|
|
||||||
VMS.use().get_running_vms()
|
|
||||||
|
|
||||||
VMS.use() can also be called before the data is needed. e.g. to eliminate/reduce waiting time.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
list_store: Gio.ListStore
|
|
||||||
_instance: "None | VMS" = None
|
|
||||||
|
|
||||||
# Make sure the VMS class is used as a singleton
|
|
||||||
def __init__(self) -> None:
|
|
||||||
raise RuntimeError("Call use() instead")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def use(cls: Any) -> "VMS":
|
|
||||||
if cls._instance is None:
|
|
||||||
print("Creating new instance")
|
|
||||||
cls._instance = cls.__new__(cls)
|
|
||||||
cls.list_store = Gio.ListStore.new(VM)
|
|
||||||
|
|
||||||
for vm in get_initial_vms():
|
|
||||||
cls.list_store.append(vm)
|
|
||||||
return cls._instance
|
|
||||||
|
|
||||||
def handle_vm_stopped(self, func: Callable[[VM, VM], None]) -> None:
|
|
||||||
for vm in self.list_store:
|
|
||||||
vm.connect("vm_stopped", func)
|
|
||||||
|
|
||||||
def handle_vm_started(self, func: Callable[[VM, VM], None]) -> None:
|
|
||||||
for vm in self.list_store:
|
|
||||||
vm.connect("vm_started", func)
|
|
||||||
|
|
||||||
def get_running_vms(self) -> list[VM]:
|
|
||||||
return list(filter(lambda vm: vm.is_running(), self.list_store))
|
|
||||||
|
|
||||||
def kill_all(self) -> None:
|
|
||||||
for vm in self.get_running_vms():
|
|
||||||
vm.stop()
|
|
||||||
23
pkgs/clan-vm-manager/clan_vm_manager/models/interfaces.py
Normal file
23
pkgs/clan-vm-manager/clan_vm_manager/models/interfaces.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import StrEnum
|
||||||
|
|
||||||
|
import gi
|
||||||
|
from clan_cli.clan_uri import ClanURI
|
||||||
|
|
||||||
|
gi.require_version("Gtk", "4.0")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class InitialJoinValues:
|
||||||
|
url: ClanURI | None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ClanConfig:
|
||||||
|
initial_view: str
|
||||||
|
url: ClanURI | None
|
||||||
|
|
||||||
|
|
||||||
|
class VMStatus(StrEnum):
|
||||||
|
RUNNING = "Running"
|
||||||
|
STOPPED = "Stopped"
|
||||||
@@ -1,31 +1,26 @@
|
|||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import weakref
|
import weakref
|
||||||
from enum import StrEnum
|
from collections.abc import Callable
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import ClassVar
|
from typing import Any, ClassVar
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
from clan_cli import vms
|
from clan_cli import vms
|
||||||
from clan_cli.errors import ClanError
|
from clan_cli.errors import ClanError
|
||||||
from clan_cli.history.add import HistoryEntry
|
from clan_cli.history.add import HistoryEntry
|
||||||
from clan_cli.history.list import list_history
|
from clan_cli.history.list import list_history
|
||||||
from gi.repository import GObject
|
|
||||||
|
|
||||||
from clan_vm_manager import assets
|
from clan_vm_manager import assets
|
||||||
|
from clan_vm_manager.errors.show_error import show_error_dialog
|
||||||
|
from clan_vm_manager.models.interfaces import VMStatus
|
||||||
|
|
||||||
from .errors.show_error import show_error_dialog
|
|
||||||
from .executor import MPProcess, spawn
|
from .executor import MPProcess, spawn
|
||||||
|
|
||||||
gi.require_version("Gtk", "4.0")
|
gi.require_version("Gtk", "4.0")
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from gi.repository import GLib
|
from gi.repository import Gio, GLib, GObject
|
||||||
|
|
||||||
|
|
||||||
class VMStatus(StrEnum):
|
|
||||||
RUNNING = "Running"
|
|
||||||
STOPPED = "Stopped"
|
|
||||||
|
|
||||||
|
|
||||||
class VM(GObject.Object):
|
class VM(GObject.Object):
|
||||||
@@ -82,7 +77,7 @@ class VM(GObject.Object):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def get_id(self) -> str:
|
def get_id(self) -> str:
|
||||||
return self.data.flake.flake_url + self.data.flake.flake_attr
|
return f"{self.data.flake.flake_url}#{self.data.flake.flake_attr}"
|
||||||
|
|
||||||
def stop_async(self) -> None:
|
def stop_async(self) -> None:
|
||||||
threading.Thread(target=self.stop).start()
|
threading.Thread(target=self.stop).start()
|
||||||
@@ -101,6 +96,53 @@ class VM(GObject.Object):
|
|||||||
return self.process.out_file.read_text()
|
return self.process.out_file.read_text()
|
||||||
|
|
||||||
|
|
||||||
|
class VMS:
|
||||||
|
"""
|
||||||
|
This is a singleton.
|
||||||
|
It is initialized with the first call of use()
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
VMS.use().get_running_vms()
|
||||||
|
|
||||||
|
VMS.use() can also be called before the data is needed. e.g. to eliminate/reduce waiting time.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
list_store: Gio.ListStore
|
||||||
|
_instance: "None | VMS" = None
|
||||||
|
|
||||||
|
# Make sure the VMS class is used as a singleton
|
||||||
|
def __init__(self) -> None:
|
||||||
|
raise RuntimeError("Call use() instead")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def use(cls: Any) -> "VMS":
|
||||||
|
if cls._instance is None:
|
||||||
|
print("Creating new instance")
|
||||||
|
cls._instance = cls.__new__(cls)
|
||||||
|
cls.list_store = Gio.ListStore.new(VM)
|
||||||
|
|
||||||
|
for vm in get_initial_vms():
|
||||||
|
cls.list_store.append(vm)
|
||||||
|
return cls._instance
|
||||||
|
|
||||||
|
def handle_vm_stopped(self, func: Callable[[VM, VM], None]) -> None:
|
||||||
|
for vm in self.list_store:
|
||||||
|
vm.connect("vm_stopped", func)
|
||||||
|
|
||||||
|
def handle_vm_started(self, func: Callable[[VM, VM], None]) -> None:
|
||||||
|
for vm in self.list_store:
|
||||||
|
vm.connect("vm_started", func)
|
||||||
|
|
||||||
|
def get_running_vms(self) -> list[VM]:
|
||||||
|
return list(filter(lambda vm: vm.is_running(), self.list_store))
|
||||||
|
|
||||||
|
def kill_all(self) -> None:
|
||||||
|
for vm in self.get_running_vms():
|
||||||
|
vm.stop()
|
||||||
|
|
||||||
|
|
||||||
def get_initial_vms() -> list[VM]:
|
def get_initial_vms() -> list[VM]:
|
||||||
vm_list = []
|
vm_list = []
|
||||||
|
|
||||||
@@ -113,7 +155,7 @@ def get_initial_vms() -> list[VM]:
|
|||||||
icon = entry.flake.icon
|
icon = entry.flake.icon
|
||||||
|
|
||||||
base = VM(
|
base = VM(
|
||||||
icon=icon,
|
icon=Path(icon),
|
||||||
status=VMStatus.STOPPED,
|
status=VMStatus.STOPPED,
|
||||||
data=entry,
|
data=entry,
|
||||||
)
|
)
|
||||||
@@ -2,12 +2,10 @@ from functools import partial
|
|||||||
|
|
||||||
import gi
|
import gi
|
||||||
|
|
||||||
from ..model.use_vms import VMS
|
|
||||||
|
|
||||||
gi.require_version("Adw", "1")
|
gi.require_version("Adw", "1")
|
||||||
from gi.repository import Adw, Gdk, Gtk
|
from gi.repository import Adw, Gdk, Gtk
|
||||||
|
|
||||||
from ..models import VM
|
from clan_vm_manager.models.use_vms import VM, VMS
|
||||||
|
|
||||||
|
|
||||||
class ClanList(Gtk.Box):
|
class ClanList(Gtk.Box):
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ from clan_cli.errors import ClanError
|
|||||||
from clan_cli.history.add import 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.errors.show_error import show_error_dialog
|
||||||
|
from clan_vm_manager.models.interfaces import InitialJoinValues
|
||||||
from ..interfaces import InitialJoinValues
|
|
||||||
|
|
||||||
gi.require_version("Gtk", "4.0")
|
gi.require_version("Gtk", "4.0")
|
||||||
gi.require_version("Adw", "1")
|
gi.require_version("Adw", "1")
|
||||||
|
|||||||
38
pkgs/clan-vm-manager/clan_vm_manager/windows/main_window.py
Normal file
38
pkgs/clan-vm-manager/clan_vm_manager/windows/main_window.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import gi
|
||||||
|
|
||||||
|
from clan_vm_manager.models.interfaces import ClanConfig, InitialJoinValues
|
||||||
|
from clan_vm_manager.models.use_views import Views
|
||||||
|
from clan_vm_manager.views.list import ClanList
|
||||||
|
from clan_vm_manager.views.trust_join import Trust
|
||||||
|
|
||||||
|
gi.require_version("Adw", "1")
|
||||||
|
|
||||||
|
from gi.repository import Adw
|
||||||
|
|
||||||
|
|
||||||
|
class MainWindow(Adw.ApplicationWindow):
|
||||||
|
def __init__(self, config: ClanConfig) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.set_title("cLAN Manager")
|
||||||
|
self.set_default_size(980, 650)
|
||||||
|
|
||||||
|
view = Adw.ToolbarView()
|
||||||
|
self.set_content(view)
|
||||||
|
|
||||||
|
header = Adw.HeaderBar()
|
||||||
|
view.add_top_bar(header)
|
||||||
|
|
||||||
|
# Initialize all views
|
||||||
|
stack_view = Views.use().view
|
||||||
|
stack_view.add_named(ClanList(), "list")
|
||||||
|
stack_view.add_named(
|
||||||
|
Trust(initial_values=InitialJoinValues(url=config.url)), "join.trust"
|
||||||
|
)
|
||||||
|
|
||||||
|
stack_view.set_visible_child_name(config.initial_view)
|
||||||
|
|
||||||
|
clamp = Adw.Clamp()
|
||||||
|
clamp.set_child(stack_view)
|
||||||
|
clamp.set_maximum_size(1000)
|
||||||
|
|
||||||
|
view.set_content(clamp)
|
||||||
Reference in New Issue
Block a user