diff --git a/iridium_installer/ui/pages/partitioning.py b/iridium_installer/ui/pages/partitioning.py index b6a5bcb..bab365e 100644 --- a/iridium_installer/ui/pages/partitioning.py +++ b/iridium_installer/ui/pages/partitioning.py @@ -476,10 +476,14 @@ class PartitioningPage(Adw.Bin): dropdown = Gtk.DropDown.new_from_strings(options) current_mp = data.get("mount_point") + # Ensure we have a valid string comparison + if not current_mp: + current_mp = "None" + if current_mp in options: dropdown.set_selected(options.index(current_mp)) - elif not current_mp: - dropdown.set_selected(options.index("None")) + else: + dropdown.set_selected(options.index("None")) box.append(Gtk.Label(label=f"Mount point for {data['name']}:")) box.append(dropdown) @@ -511,6 +515,13 @@ class PartitioningPage(Adw.Bin): box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12, margin_top=24, margin_bottom=24, margin_start=24, margin_end=24) win.set_content(box) + # Type dropdown + types = {"Root (Linux)": "8300", "EFI System": "ef00", "Swap": "8200"} + type_names = list(types.keys()) + type_dropdown = Gtk.DropDown.new_from_strings(type_names) + box.append(Gtk.Label(label="Partition Type:")) + box.append(type_dropdown) + # Size entry size_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12) size_entry = Gtk.Entry(text=str(int(data["bytes"] / (1024*1024)))) @@ -519,13 +530,6 @@ class PartitioningPage(Adw.Bin): box.append(Gtk.Label(label="Size:")) box.append(size_box) - # Type dropdown - types = {"Root (Linux)": "8300", "EFI System": "ef00", "Swap": "8200"} - type_names = list(types.keys()) - type_dropdown = Gtk.DropDown.new_from_strings(type_names) - box.append(Gtk.Label(label="Partition Type:")) - box.append(type_dropdown) - error_label = Gtk.Label(label="") error_label.add_css_class("error") box.append(error_label) diff --git a/iridium_installer/ui/window.py b/iridium_installer/ui/window.py index a716d1c..ba70a3d 100644 --- a/iridium_installer/ui/window.py +++ b/iridium_installer/ui/window.py @@ -1,8 +1,10 @@ import gi +import threading +import logging gi.require_version("Gtk", "4.0") gi.require_version("Adw", "1") -from gi.repository import Adw, Gtk +from gi.repository import Adw, Gtk, GLib from .pages.additional_modules import ModulesPage from .pages.install_mode import InstallModePage @@ -13,6 +15,16 @@ from .pages.user import UserPage from .pages.welcome import WelcomePage +class LogHandler(logging.Handler): + def __init__(self, callback): + super().__init__() + self.callback = callback + + def emit(self, record): + msg = self.format(record) + GLib.idle_add(self.callback, msg) + + class InstallerWindow(Adw.ApplicationWindow): def __init__(self, mock_mode=False, *args, **kwargs): super().__init__(*args, **kwargs) @@ -90,6 +102,8 @@ class InstallerWindow(Adw.ApplicationWindow): if self.page_ids: self.stack.set_visible_child_name(self.page_ids[0]) self.update_buttons() + + self.log_handler = None def add_page(self, widget, name): self.stack.add_named(widget, name) @@ -157,6 +171,28 @@ class InstallerWindow(Adw.ApplicationWindow): box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12) box.append(spinner) + + # Log view + self.log_buffer = Gtk.TextBuffer() + self.log_view = Gtk.TextView(buffer=self.log_buffer) + self.log_view.set_editable(False) + self.log_view.set_monospace(True) + self.log_view.set_wrap_mode(Gtk.WrapMode.WORD_CHAR) + + scrolled = Gtk.ScrolledWindow() + scrolled.set_child(self.log_view) + scrolled.set_vexpand(True) + scrolled.set_size_request(-1, 200) + + # Style the log view background + # css_provider = Gtk.CssProvider() + # css_provider.load_from_data(b"textview { background-color: #1e1e1e; color: #ffffff; }") + # self.log_view.get_style_context().add_provider(css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) + + expander = Gtk.Expander(label="Detailed Logs") + expander.set_child(scrolled) + box.append(expander) + prog_page.set_child(box) name = "progress_install" @@ -165,8 +201,24 @@ class InstallerWindow(Adw.ApplicationWindow): # Hide navigation buttons during install self.bottom_bar.set_visible(False) + + # Attach log handler + self.log_handler = LogHandler(self.append_log) + logging.getLogger().addHandler(self.log_handler) + logging.getLogger().setLevel(logging.INFO) + + def append_log(self, msg): + end_iter = self.log_buffer.get_end_iter() + self.log_buffer.insert(end_iter, msg + "\n") + # Auto-scroll + mark = self.log_buffer.create_mark("end", end_iter, False) + self.log_view.scroll_to_mark(mark, 0.0, True, 0.0, 1.0) def show_finish_page(self, message, success=True): + if self.log_handler: + logging.getLogger().removeHandler(self.log_handler) + self.log_handler = None + finish_page = Adw.StatusPage() finish_page.set_title(message) if success: @@ -189,6 +241,35 @@ class InstallerWindow(Adw.ApplicationWindow): self.stack.add_named(finish_page, name) self.stack.set_visible_child_name(name) + def run_installation(self, disk, mode, modules, user_info): + try: + from ..backend.disk import auto_partition_disk, mount_partitions + from ..backend.os_install import install_minimal_os, configure_system + + # Step 1: Partitioning + logging.info("Step 1: Partitioning...") + parts = auto_partition_disk(disk) + + # Step 2: Mounting + logging.info("Step 2: Mounting...") + mount_root = "/mnt" + mount_partitions(parts, mount_root) + + # Step 3: OS Installation + logging.info("Step 3: OS Installation...") + install_minimal_os(mount_root) + + # Step 4: Configure + logging.info("Step 4: Configuration...") + configure_system(mount_root, parts) + + GLib.idle_add(self.show_finish_page, "Installation Successful!", True) + except Exception as e: + logging.error(f"Installation failed: {e}") + import traceback + traceback.print_exc() + GLib.idle_add(self.show_finish_page, f"Installation Failed: {e}", False) + def on_next_clicked(self, button): # Logic before transition current_page_name = self.page_ids[self.current_page_index] @@ -250,36 +331,13 @@ class InstallerWindow(Adw.ApplicationWindow): # Show success in UI even in mock self.show_finish_page("Mock Installation Complete!") else: - from ..backend.disk import auto_partition_disk, mount_partitions - from ..backend.os_install import install_minimal_os, configure_system - - # Simple progress UI transition self.show_progress_page("Installing Iridium OS...") - - # We should really run this in a thread to keep UI responsive, - # but for "barely bootable" requirement and simplicity: - try: - # Step 1: Partitioning - print("Step 1: Partitioning...") - parts = auto_partition_disk(disk) - - # Step 2: Mounting - print("Step 2: Mounting...") - mount_root = "/mnt" - mount_partitions(parts, mount_root) - - # Step 3: OS Installation - print("Step 3: OS Installation...") - install_minimal_os(mount_root) - - # Step 4: Configure - print("Step 4: Configuration...") - configure_system(mount_root, parts) - - self.show_finish_page("Installation Successful!") - except Exception as e: - print(f"Installation failed: {e}") - self.show_finish_page(f"Installation Failed: {e}", success=False) + thread = threading.Thread( + target=self.run_installation, + args=(disk, mode, modules, user_info), + daemon=True + ) + thread.start() return