diff --git a/config/settings/appearance_tab.py b/config/settings/appearance_tab.py index fca92e9..fcc29f0 100644 --- a/config/settings/appearance_tab.py +++ b/config/settings/appearance_tab.py @@ -1,12 +1,13 @@ import os + import gi from fabric.widgets.box import Box from fabric.widgets.button import Button from fabric.widgets.grid import Grid from fabric.widgets.image import Image from fabric.widgets.label import Label -from fabric.widgets.scrolledwindow import ScrolledWindow from fabric.widgets.scale import Scale +from fabric.widgets.scrolledwindow import ScrolledWindow from gi.repository import GdkPixbuf, Gtk from config.data import NOTIF_POS_DEFAULT, NOTIF_POS_KEY @@ -22,7 +23,7 @@ class AppearanceTab: self.themes = themes self.parent_window = parent_window self.selected_face_icon = None - + # Widget references self.wall_dir_chooser = None self.face_image = None @@ -60,7 +61,7 @@ class AppearanceTab: # Create wallpaper and profile icon section self._create_wallpaper_profile_section(vbox) - + # Add separator separator1 = Box( style="min-height: 1px; background-color: alpha(@fg_color, 0.2); margin: 5px 0px;", @@ -85,11 +86,7 @@ class AppearanceTab: def _create_wallpaper_profile_section(self, vbox): """Create wallpaper and profile icon section""" - top_grid = Grid( - column_spacing=20, - row_spacing=5, - style="margin-bottom: 10px;" - ) + top_grid = Grid(column_spacing=20, row_spacing=5, style="margin-bottom: 10px;") vbox.add(top_grid) # Wallpaper section @@ -99,9 +96,7 @@ class AppearanceTab: top_grid.attach(wall_label, 0, 1, 1, 1) chooser_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) self.wall_dir_chooser = Gtk.FileChooserButton( title="Select a folder", action=Gtk.FileChooserAction.SELECT_FOLDER @@ -135,9 +130,7 @@ class AppearanceTab: top_grid.attach(face_image_container, 2, 1, 1, 1) browse_btn_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) face_btn = Button( label="Browse...", @@ -156,7 +149,7 @@ class AppearanceTab: layout_grid = Grid( column_spacing=20, row_spacing=10, - style="margin-left: 10px; margin-top: 5px;" + style="margin-left: 10px; margin-top: 5px;", ) vbox.add(layout_grid) @@ -165,9 +158,7 @@ class AppearanceTab: layout_grid.attach(ws_mode_label, 0, 0, 1, 1) ws_mode_combo_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) self.ws_mode_combo = Gtk.ComboBoxText() self.ws_mode_combo.set_tooltip_text("Select how workspaces are displayed") @@ -200,9 +191,7 @@ class AppearanceTab: ) layout_grid.attach(ws_chinese_label, 2, 0, 1, 1) ws_chinese_switch_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) self.ws_chinese_switch = Gtk.Switch( active=bind_vars.get("workspace_use_chinese_numerals", False), @@ -218,9 +207,7 @@ class AppearanceTab: position_label = Label(label="Dock Position", h_align="start", v_align="center") layout_grid.attach(position_label, 0, 1, 1, 1) position_combo_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) self.position_combo = Gtk.ComboBoxText() self.position_combo.set_tooltip_text("Select the position of the dock") @@ -240,9 +227,7 @@ class AppearanceTab: dock_theme_label = Label(label="Dock Theme", h_align="start", v_align="center") layout_grid.attach(dock_theme_label, 2, 1, 1, 1) dock_theme_combo_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) self.dock_theme_combo = Gtk.ComboBoxText() self.dock_theme_combo.set_tooltip_text("Select the visual theme for the dock") @@ -260,9 +245,7 @@ class AppearanceTab: dock_label = Label(label="Show Dock", h_align="start", v_align="center") layout_grid.attach(dock_label, 0, 2, 1, 1) dock_switch_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) self.dock_switch = Gtk.Switch(active=bind_vars.get("dock_enabled", True)) self.dock_switch.connect("notify::active", self.on_dock_enabled_changed) @@ -275,9 +258,7 @@ class AppearanceTab: ) layout_grid.attach(dock_hover_label, 2, 2, 1, 1) dock_hover_switch_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) self.dock_hover_switch = Gtk.Switch( active=bind_vars.get("dock_always_occluded", False), @@ -292,9 +273,7 @@ class AppearanceTab: ) layout_grid.attach(dock_auto_hide_label, 0, 3, 1, 1) dock_auto_hide_switch_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) self.dock_auto_hide_switch = Gtk.Switch( active=bind_vars.get("dock_auto_hide", False), @@ -309,9 +288,7 @@ class AppearanceTab: ) layout_grid.attach(dock_hide_special_label, 2, 3, 1, 1) dock_hide_special_switch_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) self.dock_hide_special_switch = Gtk.Switch( active=bind_vars.get("dock_hide_special_workspace", True), @@ -351,7 +328,7 @@ class AppearanceTab: self.application_switcher_scale = Scale( min_value=5, max_value=20, - value=bind_vars.get("window_switcher_items_per_row",13), + value=bind_vars.get("window_switcher_items_per_row", 13), increments=(2, 4), draw_value=True, value_position="right", @@ -361,7 +338,9 @@ class AppearanceTab: self.application_switcher_scale.set_tooltip_text( "Adjust the number of items per row in the application switcher" ) - layout_grid.attach(self.application_switcher_scale, 1, 5, 3, 1) # Span 3 columns + layout_grid.attach( + self.application_switcher_scale, 1, 5, 3, 1 + ) # Span 3 columns # Hide Special Workspace Apps dock_hide_special_apps_label = Label( @@ -369,9 +348,7 @@ class AppearanceTab: ) layout_grid.attach(dock_hide_special_apps_label, 0, 6, 1, 1) dock_hide_special_apps_switch_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) self.dock_hide_special_apps_switch = Gtk.Switch( active=bind_vars.get("dock_hide_special_workspace_apps", True), @@ -390,9 +367,7 @@ class AppearanceTab: layout_grid.attach(notification_pos_label, 2, 6, 1, 1) notification_pos_combo_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) self.notification_pos_combo = Gtk.ComboBoxText() @@ -426,7 +401,7 @@ class AppearanceTab: components_grid = Grid( column_spacing=15, row_spacing=8, - style="margin-left: 10px; margin-top: 5px;" + style="margin-left: 10px; margin-top: 5px;", ) vbox.add(components_grid) @@ -452,9 +427,7 @@ class AppearanceTab: ) components_grid.attach(corners_label, 0, 0, 1, 1) switch_container_corners = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) switch_container_corners.add(self.corners_switch) components_grid.attach(switch_container_corners, 1, 0, 1, 1) @@ -472,9 +445,7 @@ class AppearanceTab: components_grid.attach(component_label, col, row, 1, 1) switch_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) component_switch = Gtk.Switch( active=bind_vars.get(f"dock_{name}_visible", True) @@ -568,10 +539,16 @@ class AppearanceTab: values["dock_enabled"] = self.dock_switch.get_active() values["dock_auto_hide"] = self.dock_auto_hide_switch.get_active() values["dock_always_occluded"] = self.dock_hover_switch.get_active() - values["dock_hide_special_workspace"] = self.dock_hide_special_switch.get_active() - values["dock_hide_special_workspace_apps"] = self.dock_hide_special_apps_switch.get_active() + values["dock_hide_special_workspace"] = ( + self.dock_hide_special_switch.get_active() + ) + values["dock_hide_special_workspace_apps"] = ( + self.dock_hide_special_apps_switch.get_active() + ) values["dock_icon_size"] = int(self.icon_size_scale.get_value()) - values["window_switcher_items_per_row"] = int(self.application_switcher_scale.get_value()) + values["window_switcher_items_per_row"] = int( + self.application_switcher_scale.get_value() + ) values["corners_visible"] = self.corners_switch.get_active() values["dock_theme"] = self.dock_theme_combo.get_active_text() @@ -615,8 +592,12 @@ class AppearanceTab: self.dock_switch.set_active(defaults.get("dock_enabled", True)) self.dock_auto_hide_switch.set_active(defaults.get("dock_auto_hide", False)) self.dock_hover_switch.set_active(defaults.get("dock_always_occluded", False)) - self.dock_hide_special_switch.set_active(defaults.get("dock_hide_special_workspace", True)) - self.dock_hide_special_apps_switch.set_active(defaults.get("dock_hide_special_workspace_apps", True)) + self.dock_hide_special_switch.set_active( + defaults.get("dock_hide_special_workspace", True) + ) + self.dock_hide_special_apps_switch.set_active( + defaults.get("dock_hide_special_workspace_apps", True) + ) # Update sensitivity based on dock enabled state dock_enabled = self.dock_switch.get_active() @@ -659,7 +640,9 @@ class AppearanceTab: except ValueError: self.ws_mode_combo.set_active(0) - self.ws_chinese_switch.set_active(defaults.get("workspace_use_chinese_numerals", False)) + self.ws_chinese_switch.set_active( + defaults.get("workspace_use_chinese_numerals", False) + ) self.ws_chinese_switch.set_sensitive(default_nums) self.corners_switch.set_active(defaults.get("corners_visible", True)) @@ -679,4 +662,6 @@ class AppearanceTab: # Reset scales self.icon_size_scale.set_value(defaults.get("dock_icon_size", 20)) - self.application_switcher_scale.set_value(defaults.get("window_switcher_items_per_row", 13)) + self.application_switcher_scale.set_value( + defaults.get("window_switcher_items_per_row", 13) + ) diff --git a/config/settings/bluetooth_tab.py b/config/settings/bluetooth_tab.py index a891ac2..b93b98f 100644 --- a/config/settings/bluetooth_tab.py +++ b/config/settings/bluetooth_tab.py @@ -1,3 +1,5 @@ +import subprocess + from fabric.bluetooth import BluetoothClient, BluetoothDevice from fabric.widgets.box import Box from fabric.widgets.button import Button @@ -6,7 +8,6 @@ from fabric.widgets.image import Image from fabric.widgets.label import Label from fabric.widgets.scrolledwindow import ScrolledWindow from gi.repository import GLib, Gtk -import subprocess import utils.icons as icons @@ -20,18 +21,20 @@ class BluetoothDeviceSlot(CenterBox): "notify::closed", lambda *_: self.device.closed and self.destroy() ) - self.connection_label = Label(markup=icons.bluetooth_disconnected, style="font-size: 22px;") + self.connection_label = Label( + markup=icons.bluetooth_disconnected, style="font-size: 22px;" + ) self.connect_button = Button( label="Connect", on_clicked=lambda *_: self._handle_device_action(), ) - + # Create device name label that we can update self.device_name_label = Label( label=device.alias or device.name, h_expand=True, h_align="start", - ellipsization="end" + ellipsization="end", ) self.start_children = [ @@ -50,8 +53,6 @@ class BluetoothDeviceSlot(CenterBox): self.device.emit("changed") - - def _handle_device_action(self): """Handle connect/disconnect button click""" if self.device.connected: @@ -71,23 +72,31 @@ class BluetoothDeviceSlot(CenterBox): device_address = self.device.address # Show pairing notification - subprocess.run([ - "notify-send", - "Bluetooth Pairing", - f"Attempting to pair with {device_name}...", - "--icon=bluetooth", - "--urgency=normal", - "--app-name=Bluetooth" - ], check=False) + subprocess.run( + [ + "notify-send", + "Bluetooth Pairing", + f"Attempting to pair with {device_name}...", + "--icon=bluetooth", + "--urgency=normal", + "--app-name=Bluetooth", + ], + check=False, + ) # Use bluetoothctl to pair the device # This will trigger the system's pairing agent which should show the pairing dialog - pairing_process = subprocess.Popen([ - "bluetoothctl", "pair", device_address - ], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + pairing_process = subprocess.Popen( + ["bluetoothctl", "pair", device_address], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) # Monitor the pairing process in a separate thread - GLib.timeout_add(100, self._monitor_pairing_process, pairing_process, device_name) + GLib.timeout_add( + 100, self._monitor_pairing_process, pairing_process, device_name + ) except Exception as e: print(f"Failed to start pairing process: {e}") @@ -121,7 +130,7 @@ class BluetoothDeviceSlot(CenterBox): subprocess.run(["bluetoothctl", "trust", device_address], check=False) # Connect to the device - GLib.timeout_add(1000, lambda: setattr(self.device, 'connected', True)) + GLib.timeout_add(1000, lambda: setattr(self.device, "connected", True)) except Exception as e: print(f"Failed to trust/connect device: {e}") @@ -130,14 +139,17 @@ class BluetoothDeviceSlot(CenterBox): """Show notification when pairing succeeds""" try: device_name = self.device.alias or self.device.name - subprocess.run([ - "notify-send", - "Bluetooth Paired", - f"Successfully paired with {device_name}", - "--icon=bluetooth", - "--urgency=normal", - "--app-name=Bluetooth" - ], check=False) + subprocess.run( + [ + "notify-send", + "Bluetooth Paired", + f"Successfully paired with {device_name}", + "--icon=bluetooth", + "--urgency=normal", + "--app-name=Bluetooth", + ], + check=False, + ) except Exception as e: print(f"Failed to send pairing success notification: {e}") @@ -145,28 +157,33 @@ class BluetoothDeviceSlot(CenterBox): """Show notification when pairing fails""" try: device_name = self.device.alias or self.device.name - subprocess.run([ - "notify-send", - "Bluetooth Pairing Failed", - f"Failed to pair with {device_name}", - "--icon=bluetooth-disabled", - "--urgency=normal", - "--app-name=Bluetooth" - ], check=False) + subprocess.run( + [ + "notify-send", + "Bluetooth Pairing Failed", + f"Failed to pair with {device_name}", + "--icon=bluetooth-disabled", + "--urgency=normal", + "--app-name=Bluetooth", + ], + check=False, + ) except Exception as e: print(f"Failed to send pairing failed notification: {e}") def on_changed(self, *_): # Update connection icon self.connection_label.set_markup( - icons.bluetooth_connected if self.device.connected else icons.bluetooth_disconnected + icons.bluetooth_connected + if self.device.connected + else icons.bluetooth_disconnected ) # Check for pairing state changes and show notifications base_name = self.device.alias or self.device.name # Track pairing success/failure - if hasattr(self, '_was_pairing') and self._was_pairing: + if hasattr(self, "_was_pairing") and self._was_pairing: if self.device.paired and not self.device.connecting: # Pairing succeeded self._show_pairing_success_notification() @@ -201,7 +218,6 @@ class BluetoothDeviceSlot(CenterBox): self.device_name_label.set_label(status_text) - class BluetoothTab: """Bluetooth device management tab for settings""" @@ -219,32 +235,27 @@ class BluetoothTab: """Set the window size enforcer function from the main GUI""" self.window_size_enforcer = enforcer_func - - def create_bluetooth_tab(self): """Create the Bluetooth tab content""" - main_vbox = Box( - orientation="v", - spacing=0, - style="padding: 0; margin: 15px;" - ) + main_vbox = Box(orientation="v", spacing=0, style="padding: 0; margin: 15px;") # Set fixed size for the main container to match tab stack dimensions main_vbox.set_size_request(580, 580) # Create widgets first self.bluetooth_subtitle = Label( - markup="Find and connect to Bluetooth devices", - h_align="start" + markup="Find and connect to Bluetooth devices", h_align="start" ) self.bluetooth_switch = Gtk.Switch() - self.scan_icon = Label(name="bluetooth-tab-icon", markup=icons.radar, style="font-size: 18px;") + self.scan_icon = Label( + name="bluetooth-tab-icon", markup=icons.radar, style="font-size: 18px;" + ) self.scan_button = Button( name="bluetooth-scan", child=self.scan_icon, tooltip_text="Scan for devices", on_clicked=lambda *_: self.bluetooth_client.toggle_scan(), - style="margin:10px;" + style="margin:10px;", ) # Header section with title and controls @@ -258,10 +269,10 @@ class BluetoothTab: children=[ Label( markup="Bluetooth", - h_align="start" + h_align="start", ), self.bluetooth_subtitle, - ] + ], ) ], end_children=[ @@ -271,14 +282,16 @@ class BluetoothTab: children=[ self.bluetooth_switch, self.scan_button, - ] + ], ) - ] + ], ) # Set up switch self.bluetooth_switch.set_valign(Gtk.Align.CENTER) - self.bluetooth_switch.connect("notify::active", self._on_bluetooth_switch_toggled) + self.bluetooth_switch.connect( + "notify::active", self._on_bluetooth_switch_toggled + ) main_vbox.add(header_box) @@ -292,11 +305,19 @@ class BluetoothTab: spacing=8, orientation="v", children=[ - Label(name="bluetooth-section", markup="Paired Devices", h_align="start"), + Label( + name="bluetooth-section", + markup="Paired Devices", + h_align="start", + ), self.paired_box, - Label(name="bluetooth-section", markup="Available Devices", h_align="start"), + Label( + name="bluetooth-section", + markup="Available Devices", + h_align="start", + ), self.available_box, - ] + ], ) # Set size constraints for content box content_box.set_size_request(560, -1) @@ -335,9 +356,7 @@ class BluetoothTab: self.scan_button.set_sensitive(True) else: self.bluetooth_switch.set_active(False) - self.bluetooth_subtitle.set_markup( - "Bluetooth is turned off" - ) + self.bluetooth_subtitle.set_markup("Bluetooth is turned off") self.scan_button.set_sensitive(False) def _on_bluetooth_changed(self, *args): @@ -362,9 +381,8 @@ class BluetoothTab: """Populate existing devices when tab is created""" if not self.bluetooth_client or not self.bluetooth_client.enabled: return - + devices = self.bluetooth_client.devices - for device in devices: self.on_device_added(self.bluetooth_client, device.address) @@ -430,7 +448,3 @@ class BluetoothTab: """Clear and repopulate all devices""" self._clear_all_devices() self._populate_existing_devices() - - - - diff --git a/config/settings/gui.py b/config/settings/gui.py index 1335caa..dbf3a56 100644 --- a/config/settings/gui.py +++ b/config/settings/gui.py @@ -7,23 +7,19 @@ import time import gi from fabric.widgets.box import Box from fabric.widgets.button import Button -from fabric.widgets.entry import Entry -from fabric.widgets.image import Image as FabricImage -from fabric.widgets.label import Label -from fabric.widgets.scrolledwindow import ScrolledWindow from fabric.widgets.stack import Stack from fabric.widgets.window import Window from gi.repository import Gdk, GdkPixbuf, GLib, Gtk from PIL import Image from config.data import APP_NAME, APP_NAME_CAP -from config.settings.utils import backup_and_replace, start_config -from config.settings.wifi_tab import WiFiTab +from config.settings.about_tab import AboutTab +from config.settings.appearance_tab import AppearanceTab from config.settings.bluetooth_tab import BluetoothTab from config.settings.key_bindings_tab import KeyBindingsTab -from config.settings.appearance_tab import AppearanceTab from config.settings.system_tab import SystemTab -from config.settings.about_tab import AboutTab +from config.settings.utils import backup_and_replace, start_config +from config.settings.wifi_tab import WiFiTab gi.require_version("Gtk", "3.0") @@ -47,8 +43,9 @@ class HyprConfGUI(Window): geometry.max_width = 640 geometry.min_height = 640 geometry.max_height = 640 - self.set_geometry_hints(None, geometry, - Gdk.WindowHints.MIN_SIZE | Gdk.WindowHints.MAX_SIZE) + self.set_geometry_hints( + None, geometry, Gdk.WindowHints.MIN_SIZE | Gdk.WindowHints.MAX_SIZE + ) self.themes = ["Pills", "Dense", "Edge"] self.selected_face_icon = None @@ -60,7 +57,9 @@ class HyprConfGUI(Window): self.bluetooth_tab = BluetoothTab() self.key_bindings_tab = KeyBindingsTab() self.appearance_tab = AppearanceTab(self.themes, self) - self.system_tab = SystemTab(show_lock_checkbox, show_idle_checkbox, self.enforce_window_size) + self.system_tab = SystemTab( + show_lock_checkbox, show_idle_checkbox, self.enforce_window_size + ) self.about_tab = AboutTab() # Pass window size enforcement method to tabs @@ -72,7 +71,9 @@ class HyprConfGUI(Window): root_box.set_size_request(620, 620) self.add(root_box) - main_content_box = Box(orientation="h", spacing=6, v_expand=False, h_expand=False) + main_content_box = Box( + orientation="h", spacing=6, v_expand=False, h_expand=False + ) # Set fixed size for main content to prevent expansion main_content_box.set_size_request(620, 580) root_box.add(main_content_box) @@ -93,12 +94,8 @@ class HyprConfGUI(Window): self.system_tab_content = self.system_tab.create_system_tab() self.about_tab_content = self.about_tab.create_about_tab() - self.tab_stack.add_titled( - self.wifi_tab_content, "Wifi", "Wifi" - ) - self.tab_stack.add_titled( - self.bluetooth_tab_content, "Bluetooth", "Bluetooth" - ) + self.tab_stack.add_titled(self.wifi_tab_content, "Wifi", "Wifi") + self.tab_stack.add_titled(self.bluetooth_tab_content, "Bluetooth", "Bluetooth") self.tab_stack.add_titled( self.key_bindings_tab_content, "key_bindings", "Key Bindings" ) @@ -145,15 +142,15 @@ class HyprConfGUI(Window): """Public method to enforce window size - can be called by tabs""" self._force_window_size(self) - - # Event handlers moved to respective tab classes def on_accept(self, _widget): current_bind_vars_snapshot = {} # Get values from key bindings tab - current_bind_vars_snapshot.update(self.key_bindings_tab.get_key_binding_values()) + current_bind_vars_snapshot.update( + self.key_bindings_tab.get_key_binding_values() + ) # Get values from appearance tab current_bind_vars_snapshot.update(self.appearance_tab.get_appearance_values()) diff --git a/config/settings/key_bindings_tab.py b/config/settings/key_bindings_tab.py index 08b6d26..3725175 100644 --- a/config/settings/key_bindings_tab.py +++ b/config/settings/key_bindings_tab.py @@ -8,7 +8,6 @@ from config.data import APP_NAME_CAP from config.settings.utils import bind_vars - class KeyBindingsTab: """Key bindings management tab for settings""" @@ -31,11 +30,7 @@ class KeyBindingsTab: main_vbox = Box(orientation="v", spacing=10, style="margin: 15px;") scrolled_window.add(main_vbox) - keybind_grid = Grid( - column_spacing=10, - row_spacing=8, - style="margin: 5px;" - ) + keybind_grid = Grid(column_spacing=10, row_spacing=8, style="margin: 5px;") action_label = Label( markup="Action", h_align="start", style="margin-bottom: 5px;" diff --git a/config/settings/system_tab.py b/config/settings/system_tab.py index bb690b8..ddaf3de 100644 --- a/config/settings/system_tab.py +++ b/config/settings/system_tab.py @@ -15,11 +15,16 @@ gi.require_version("Gtk", "3.0") class SystemTab: """System settings and metrics management tab for settings""" - def __init__(self, show_lock_checkbox=False, show_idle_checkbox=False, window_size_enforcer=None): + def __init__( + self, + show_lock_checkbox=False, + show_idle_checkbox=False, + window_size_enforcer=None, + ): self.show_lock_checkbox = show_lock_checkbox self.show_idle_checkbox = show_idle_checkbox self.window_size_enforcer = window_size_enforcer - + # Widget references self.terminal_entry = None self.lock_switch = None @@ -60,9 +65,7 @@ class SystemTab: def _create_terminal_hyprland_section(self, vbox): """Create terminal and Hyprland integration section""" system_grid = Grid( - column_spacing=20, - row_spacing=10, - style="margin-bottom: 15px;" + column_spacing=20, row_spacing=10, style="margin-bottom: 15px;" ) vbox.add(system_grid) @@ -94,9 +97,7 @@ class SystemTab: ) system_grid.attach(lock_label, 2, row, 1, 1) lock_switch_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) self.lock_switch = Gtk.Switch( tooltip_text="Replace Hyprlock configuration with Modus's custom config" @@ -111,9 +112,7 @@ class SystemTab: ) system_grid.attach(idle_label, 2, row, 1, 1) idle_switch_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" + orientation="horizontal", h_align="start", v_align="center" ) self.idle_switch = Gtk.Switch( tooltip_text="Replace Hypridle configuration with Modus's custom config" @@ -138,7 +137,7 @@ class SystemTab: notif_grid = Grid( column_spacing=20, row_spacing=10, - style="margin-left: 10px; margin-top: 5px; margin-bottom: 15px;" + style="margin-left: 10px; margin-top: 5px; margin-bottom: 15px;", ) vbox.add(notif_grid) @@ -191,7 +190,7 @@ class SystemTab: metrics_grid = Grid( column_spacing=15, row_spacing=8, - style="margin-left: 10px; margin-top: 5px;" + style="margin-left: 10px; margin-top: 5px;", ) vbox.add(metrics_grid) @@ -251,17 +250,15 @@ class SystemTab: self.disk_entries.set_size_request(530, -1) disk_entries_scrolled.add(self.disk_entries) - self._create_disk_edit_entry_func = lambda path: self._add_disk_entry_widget(path) + self._create_disk_edit_entry_func = lambda path: self._add_disk_entry_widget( + path + ) for p in bind_vars.get("metrics_disks", ["/"]): self._create_disk_edit_entry_func(p) vbox.add(disk_entries_scrolled) - add_container = Box( - orientation="horizontal", - h_align="start", - v_align="center" - ) + add_container = Box(orientation="horizontal", h_align="start", v_align="center") add_btn = Button( label="Add new disk", on_clicked=lambda _: self._create_disk_edit_entry_func("/"), @@ -279,7 +276,9 @@ class SystemTab: x_btn = Button(label="X") x_btn.connect( "clicked", - lambda _, current_bar_to_remove=bar: self._remove_disk_entry(current_bar_to_remove), + lambda _, current_bar_to_remove=bar: self._remove_disk_entry( + current_bar_to_remove + ), ) bar.add(x_btn) self.disk_entries.add(bar) @@ -341,7 +340,7 @@ class SystemTab: """Get the state of Hyprland integration switches""" return { "replace_lock": self.lock_switch and self.lock_switch.get_active(), - "replace_idle": self.idle_switch and self.idle_switch.get_active() + "replace_idle": self.idle_switch and self.idle_switch.get_active(), } def reset_to_defaults(self, defaults): @@ -356,9 +355,7 @@ class SystemTab: enabled_switches = [s for s in switch_dict.values() if s.get_active()] can_disable = len(enabled_switches) > 1 for s in switch_dict.values(): - s.set_sensitive( - True if can_disable or not s.get_active() else False - ) + s.set_sensitive(True if can_disable or not s.get_active() else False) enforce_minimum_metrics(self.metrics_switches) diff --git a/config/settings/wifi_tab.py b/config/settings/wifi_tab.py index 1422d5a..5fd4f2f 100644 --- a/config/settings/wifi_tab.py +++ b/config/settings/wifi_tab.py @@ -1,3 +1,5 @@ +import subprocess + import gi from fabric.widgets.box import Box from fabric.widgets.button import Button @@ -8,7 +10,6 @@ from gi.repository import GLib, Gtk from services.network import NetworkClient from utils import icons -import subprocess gi.require_version("Gtk", "3.0") @@ -64,11 +65,7 @@ class WiFiTab: def create_wifi_tab(self): """Create the WiFi tab content""" - main_vbox = Box( - orientation="v", - spacing=0, - style="padding: 0; margin: 15px;" - ) + main_vbox = Box(orientation="v", spacing=0, style="padding: 0; margin: 15px;") # Set fixed size for the main container to match tab stack dimensions main_vbox.set_size_request(580, 580) @@ -84,15 +81,13 @@ class WiFiTab: # WiFi title wifi_title = Label( - markup="Wi-Fi", - h_align="start" + markup="Wi-Fi", h_align="start" ) wifi_section.add(wifi_title) # WiFi subtitle self.wifi_subtitle = Label( - markup="Find and connect to Wi-Fi networks", - h_align="start" + markup="Find and connect to Wi-Fi networks", h_align="start" ) wifi_section.add(self.wifi_subtitle) @@ -114,7 +109,9 @@ class WiFiTab: # Refresh button self.refresh_button = Button() - self.refresh_icon = Label(name="wifi-tab-icon", markup=icons.reload, style="font-size: 18px;") + self.refresh_icon = Label( + name="wifi-tab-icon", markup=icons.reload, style="font-size: 18px;" + ) self.refresh_button.add(self.refresh_icon) self.refresh_button.set_size_request(40, 40) self.refresh_button.set_tooltip_text("Refresh networks") @@ -164,8 +161,10 @@ class WiFiTab: self._update_wifi_status() # Show available networks if WiFi is enabled - if (self.network_client.wifi_device and - self.network_client.wifi_device.wireless_enabled): + if ( + self.network_client.wifi_device + and self.network_client.wifi_device.wireless_enabled + ): self._populate_networks() self.networks_container.show_all() @@ -177,9 +176,7 @@ class WiFiTab: def _update_wifi_status(self): """Update WiFi status display""" if not self.network_client.wifi_device: - self.wifi_subtitle.set_markup( - "No WiFi device available" - ) + self.wifi_subtitle.set_markup("No WiFi device available") self.wifi_switch.set_sensitive(False) return @@ -191,9 +188,7 @@ class WiFiTab: self.refresh_button.set_sensitive(True) else: self.wifi_switch.set_active(False) - self.wifi_subtitle.set_markup( - "Wi-Fi is turned off" - ) + self.wifi_subtitle.set_markup("Wi-Fi is turned off") self.refresh_button.set_sensitive(False) def _populate_networks(self): @@ -205,15 +200,13 @@ class WiFiTab: access_points = self.network_client.wifi_device.access_points if not access_points: self._show_status_message( - "No networks found\nClick 'Scan for Networks' to refresh", - "info" + "No networks found\nClick 'Scan for Networks' to refresh", "info" ) return # Sort access points by signal strength (connected first, then by strength) sorted_aps = sorted( - access_points, - key=lambda ap: (not ap.is_active, -ap.strength) + access_points, key=lambda ap: (not ap.is_active, -ap.strength) ) for ap in sorted_aps: @@ -221,11 +214,7 @@ class WiFiTab: def _show_status_message(self, message, message_type="info"): """Show a status message in the networks container""" - status_box = Box( - orientation="v", - spacing=16, - style="padding: 60px;" - ) + status_box = Box(orientation="v", spacing=16, style="padding: 60px;") status_box.set_halign(Gtk.Align.CENTER) status_box.set_valign(Gtk.Align.CENTER) @@ -235,24 +224,26 @@ class WiFiTab: message_label = Label( markup=f"{message}", h_align="center", - style="color: var(--error);" + style="color: var(--error);", ) elif message_type == "scanning": icon_markup = icons.loader message_label = Label( markup=f"{message}", h_align="center", - style="color: var(--blue);" + style="color: var(--blue);", ) else: # info icon_markup = icons.wifi_off message_label = Label( markup=f"{message}", h_align="center", - style="color: var(--outline);" + style="color: var(--outline);", ) - icon_label = Label(name="wifi-tab-icon", markup=icon_markup, style="font-size: 18px;") + icon_label = Label( + name="wifi-tab-icon", markup=icon_markup, style="font-size: 18px;" + ) icon_label.set_halign(Gtk.Align.CENTER) status_box.add(icon_label) message_label.set_line_wrap(True) @@ -271,7 +262,10 @@ class WiFiTab: network_button = Button( style="background-color: transparent; border: none; padding: 0; margin: 0;" ) - network_button.connect("clicked", lambda btn, access_point=ap: self._on_network_clicked(access_point)) + network_button.connect( + "clicked", + lambda btn, access_point=ap: self._on_network_clicked(access_point), + ) # Network info row info_box = Box(orientation="h", spacing=12) @@ -291,7 +285,9 @@ class WiFiTab: else: icon_markup = icons.wifi_0 - signal_label = Label(name="wifi-tab-icon", markup=icon_markup, style="font-size: 24px;") + signal_label = Label( + name="wifi-tab-icon", markup=icon_markup, style="font-size: 24px;" + ) signal_label.set_size_request(30, -1) info_box.add(signal_label) @@ -299,10 +295,18 @@ class WiFiTab: network_name = ap.ssid if ap.is_active: network_markup = f"{network_name}\nConnected" - network_label = Label(markup=network_markup, h_align="start", style="color: var(--foreground);") + network_label = Label( + markup=network_markup, + h_align="start", + style="color: var(--foreground);", + ) else: network_markup = f"{network_name}" - network_label = Label(markup=network_markup, h_align="start", style="color: var(--foreground);") + network_label = Label( + markup=network_markup, + h_align="start", + style="color: var(--foreground);", + ) network_label.set_line_wrap(True) info_box.add(network_label) @@ -313,7 +317,9 @@ class WiFiTab: # Lock icon for secured networks if ap.requires_password: - lock_label = Label(name="wifi-tab-icon", markup=icons.lock, style="font-size: 22px;") + lock_label = Label( + name="wifi-tab-icon", markup=icons.lock, style="font-size: 22px;" + ) info_box.add(lock_label) network_button.add(info_box) @@ -321,11 +327,11 @@ class WiFiTab: # Store reference self.access_point_widgets[ap.ssid] = { - 'container': network_container, - 'button': network_button, - 'info_box': info_box, - 'network_label': network_label, - 'ap': ap + "container": network_container, + "button": network_button, + "info_box": info_box, + "network_label": network_label, + "ap": ap, } self.networks_container.add(network_container) @@ -353,7 +359,10 @@ class WiFiTab: def _on_refresh_clicked(self, button): """Handle refresh button click""" - if self.network_client.wifi_device and self.network_client.wifi_device.wireless_enabled: + if ( + self.network_client.wifi_device + and self.network_client.wifi_device.wireless_enabled + ): self.refresh_icon.set_markup(icons.loader) button.set_sensitive(False) @@ -366,11 +375,14 @@ class WiFiTab: self.network_client.wifi_device.scan() # Re-enable button after scan - GLib.timeout_add(3000, lambda: [ - self.refresh_icon.set_markup(icons.reload), - button.set_sensitive(True), - self._refresh_networks() - ]) + GLib.timeout_add( + 3000, + lambda: [ + self.refresh_icon.set_markup(icons.reload), + button.set_sensitive(True), + self._refresh_networks(), + ], + ) def _connect_network(self, ap): """Connect to a network""" @@ -380,7 +392,7 @@ class WiFiTab: if ap.ssid in self.password_entries: # Get password from stored entry widget password_widget = self.password_entries[ap.ssid] - if hasattr(password_widget, 'get_text'): + if hasattr(password_widget, "get_text"): password = password_widget.get_text() else: password = str(password_widget) # If it's stored as string @@ -397,7 +409,7 @@ class WiFiTab: # Update network widget to show connecting state if ap.ssid in self.access_point_widgets: - network_label = self.access_point_widgets[ap.ssid]['network_label'] + network_label = self.access_point_widgets[ap.ssid]["network_label"] network_label.set_markup(f"{ap.ssid}\nConnecting...") network_label.set_style("color: var(--blue);") @@ -416,24 +428,25 @@ class WiFiTab: self._reset_connection_state(ap.ssid) def _show_connection_error(self, ssid, error_message): - try: - - subprocess.run([ - "notify-send", - "WiFi Connection Failed", - f"Failed to connect to {ssid}\n{error_message}", - "--icon=network-wireless-offline", - "--urgency=normal", - "--app-name=WiFi" - ], check=False) + subprocess.run( + [ + "notify-send", + "WiFi Connection Failed", + f"Failed to connect to {ssid}\n{error_message}", + "--icon=network-wireless-offline", + "--urgency=normal", + "--app-name=WiFi", + ], + check=False, + ) except Exception as e: print(f"Failed to send connection error notification: {e}") def _show_password_entry(self, ap): """Show password entry for a network""" if ap.ssid in self.access_point_widgets: - container = self.access_point_widgets[ap.ssid]['container'] + container = self.access_point_widgets[ap.ssid]["container"] # Check if password entry is already shown if len(container.get_children()) > 1: @@ -443,42 +456,60 @@ class WiFiTab: password_box = Box( orientation="h", spacing=8, - style="padding: 8px; margin: 4px 16px 8px 16px; border-radius: 8px;" + style="padding: 8px; margin: 4px 16px 8px 16px; border-radius: 8px;", ) password_entry = Entry( placeholder_text="Enter network password", - style="background-color: var(--surface-bright); border: 1px solid var(--outline); border-radius: 8px;" + style="background-color: var(--surface-bright); border: 1px solid var(--outline); border-radius: 8px;", ) password_entry.set_visibility(False) # Hide password characters password_entry.set_hexpand(True) - password_entry.connect("activate", lambda entry, access_point=ap: self._on_password_entered(access_point, entry)) + password_entry.connect( + "activate", + lambda entry, access_point=ap: self._on_password_entered( + access_point, entry + ), + ) password_box.add(password_entry) # Show/Hide password toggle - show_password_btn = Button( - style="border-radius: 8px;" + show_password_btn = Button(style="border-radius: 8px;") + self.show_password_icon = Label( + name="wifi-tab-icon", markup=icons.spy, style="font-size: 18px;" ) - self.show_password_icon = Label(name="wifi-tab-icon", markup=icons.spy,style="font-size: 18px;") show_password_btn.add(self.show_password_icon) show_password_btn.set_tooltip_text("Show/Hide password") - show_password_btn.connect("clicked", lambda btn, entry=password_entry: self._toggle_password_visibility(entry, btn)) + show_password_btn.connect( + "clicked", + lambda btn, entry=password_entry: self._toggle_password_visibility( + entry, btn + ), + ) password_box.add(show_password_btn) - connect_btn = Button( - style="border-radius: 8px;" + connect_btn = Button(style="border-radius: 8px;") + connect_icon = Label( + name="wifi-tab-icon", markup=icons.connect, style="font-size: 18px;" ) - connect_icon = Label(name="wifi-tab-icon", markup=icons.connect,style="font-size: 18px;") connect_btn.add(connect_icon) - connect_btn.connect("clicked", lambda btn, access_point=ap, entry=password_entry: self._on_password_entered(access_point, entry)) + connect_btn.connect( + "clicked", + lambda btn, + access_point=ap, + entry=password_entry: self._on_password_entered(access_point, entry), + ) password_box.add(connect_btn) - cancel_btn = Button( - style="border-radius: 8px;" + cancel_btn = Button(style="border-radius: 8px;") + cancel_icon = Label( + name="wifi-tab-icon", markup=icons.cancel, style="font-size: 18px;" ) - cancel_icon = Label(name="wifi-tab-icon", markup=icons.cancel,style="font-size: 18px;") cancel_btn.add(cancel_icon) - cancel_btn.connect("clicked", lambda btn, access_point=ap: self._hide_password_entry(access_point)) + cancel_btn.connect( + "clicked", + lambda btn, access_point=ap: self._hide_password_entry(access_point), + ) password_box.add(cancel_btn) container.add(password_box) @@ -493,7 +524,9 @@ class WiFiTab: current_visibility = entry.get_visibility() entry.set_visibility(not current_visibility) # Use spy icon for hidden, key icon for visible - self.show_password_icon.set_markup(icons.key if not current_visibility else icons.spy) + self.show_password_icon.set_markup( + icons.key if not current_visibility else icons.spy + ) def _on_password_entered(self, ap, entry): """Handle password entry""" @@ -505,7 +538,7 @@ class WiFiTab: def _hide_password_entry(self, ap): """Hide password entry for a network""" if ap.ssid in self.access_point_widgets: - container = self.access_point_widgets[ap.ssid]['container'] + container = self.access_point_widgets[ap.ssid]["container"] children = container.get_children() if len(children) > 1: # Remove password entry box container.remove(children[-1]) @@ -520,8 +553,8 @@ class WiFiTab: """Reset connection state for a network""" if ssid in self.access_point_widgets: # Reset the network label to normal state - ap = self.access_point_widgets[ssid]['ap'] - network_label = self.access_point_widgets[ssid]['network_label'] + ap = self.access_point_widgets[ssid]["ap"] + network_label = self.access_point_widgets[ssid]["network_label"] if ap.is_active: network_markup = f"{ap.ssid}\nConnected" network_label.set_style("color: var(--foreground);")