Something went wrong. Try again.
A Material 3 inspired desktop shell for Niri and Hyprland created with Ignis.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225from __future__ import annotations
from dataclasses import dataclassfrom enum import Enum
class Availability(Enum): SERVICE_MISSING = "service_missing" NO_ADAPTER = "no_adapter" READY = "ready"
class LinkState(Enum): IDLE = "idle" PAIRING = "pairing" CONNECTING = "connecting" CONNECTED = "connected" DISCONNECTING = "disconnecting"
class Transport(Enum): AUTO = "auto" CLASSIC = "bredr" LOW_ENERGY = "le"
class ErrorCode(Enum): BLOCKED = "blocked" ADAPTER_OFF = "adapter_off" PAIRING_FAILED = "pairing_failed" PAIRING_REJECTED = "pairing_rejected" PAIRING_TIMEOUT = "pairing_timeout" CONNECTION_FAILED = "connection_failed" BUSY = "busy" NOT_FOUND = "not_found" INVALID_INPUT = "invalid_input" UNAVAILABLE = "unavailable" FAILED = "failed"
class BluetoothError(Exception): def __init__(self, code: ErrorCode, detail: str = ""): super().__init__(f"{code.value}: {detail}" if detail else code.value) self.code = code self.detail = detail
class RequestKind(Enum): CONFIRM_PASSKEY = "confirm_passkey" ENTER_PIN = "enter_pin" ENTER_PASSKEY = "enter_passkey" DISPLAY_PIN = "display_pin" DISPLAY_PASSKEY = "display_passkey" AUTHORIZE_PAIRING = "authorize_pairing" AUTHORIZE_SERVICE = "authorize_service"
@property def needs_text(self) -> bool: return self in (RequestKind.ENTER_PIN, RequestKind.ENTER_PASSKEY)
@property def is_display_only(self) -> bool: return self in (RequestKind.DISPLAY_PIN, RequestKind.DISPLAY_PASSKEY)
@dataclass(frozen=True)class PairingRequest: request_id: int kind: RequestKind device_id: str device_name: str code: str | None = None entered: int = 0 service_uuid: str | None = None
@dataclass(frozen=True)class Adapter: adapter_id: str name: str address: str powered: bool discoverable: bool discoverable_timeout: int pairable: bool pairable_timeout: int discovering: bool
@dataclass(frozen=True)class Device: device_id: str name: str address: str named: bool icon: str paired: bool connected: bool trusted: bool blocked: bool state: LinkState = LinkState.IDLE rssi: int | None = None battery: int | None = None uuids: tuple[str, ...] = () low_energy_only: bool = False
@property def is_connected(self) -> bool: return self.state is LinkState.CONNECTED
@property def is_busy(self) -> bool: return self.state in ( LinkState.PAIRING, LinkState.CONNECTING, LinkState.DISCONNECTING, )
@dataclass(frozen=True)class BluetoothSnapshot: availability: Availability = Availability.SERVICE_MISSING adapters: tuple[Adapter, ...] = () adapter: Adapter | None = None devices: tuple[Device, ...] = () transport: Transport = Transport.AUTO request: PairingRequest | None = None
@property def connected_devices(self) -> tuple[Device, ...]: return tuple(d for d in self.devices if d.is_connected)
@property def pending_device(self) -> Device | None: return next((d for d in self.devices if d.is_busy), None)
ICON_BY_BLUEZ = { "audio-headset": "headset_mic", "audio-headphones": "headphones", "audio-card": "speaker", "input-keyboard": "keyboard", "input-mouse": "mouse", "input-gaming": "sports_esports", "input-tablet": "tablet_mac", "phone": "smartphone", "computer": "computer", "camera-photo": "photo_camera", "camera-video": "videocam", "printer": "print", "modem": "router", "network-wireless": "router", "video-display": "tv",}
PROFILE_BY_UUID = { "0000110a": "Audio source", "0000110b": "Audio output", "0000110c": "Remote control target", "0000110e": "Remote control", "0000111e": "Hands-free", "0000111f": "Hands-free gateway", "00001108": "Headset", "00001124": "Keyboard, mouse or gamepad", "00001812": "Keyboard, mouse or gamepad", "00001105": "File transfer", "00001106": "File transfer", "00001132": "Message access", "00001130": "Phone book access", "00001115": "Personal network", "0000180f": "Battery service",}
DISCOVERABLE_TIMEOUTS = ((60, "1 min"), (180, "3 min"), (300, "5 min"), (0, "Always"))
def device_icon(icon: str) -> str: return ICON_BY_BLUEZ.get(icon, "bluetooth")
def profile_labels(uuids: tuple[str, ...]) -> tuple[str, ...]: seen: list[str] = [] for uuid in uuids: label = PROFILE_BY_UUID.get(uuid[:8].lower()) if label and label not in seen: seen.append(label) return tuple(seen)
def signal_strength(rssi: int | None) -> int | None: if rssi is None: return None return max(0, min(100, int(2 * (rssi + 100))))
def signal_quality(strength: int) -> str: if strength >= 70: return "Strong" if strength >= 45: return "Good" if strength >= 25: return "Fair" return "Weak"
def battery_icon(percent: int) -> str: if percent >= 90: return "battery_full" steps = ("battery_0_bar", "battery_1_bar", "battery_2_bar", "battery_3_bar", "battery_4_bar", "battery_5_bar", "battery_6_bar") return steps[min(6, percent * 7 // 100)]
def list_order(device: Device) -> tuple: if device.is_connected: tier = 0 elif device.is_busy: tier = 1 elif device.paired: tier = 2 else: tier = 3 strength = signal_strength(device.rssi) or 0 return (tier, -(strength // 15), device.name.casefold())