Something went wrong. Try again.
A Material 3 inspired desktop shell for Niri and Hyprland created with Ignis.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214from __future__ import annotations
from dataclasses import dataclass
from .model import ( Availability, BluetoothError, BluetoothSnapshot, Device, ErrorCode, LinkState, PairingRequest, RequestKind, battery_icon, device_icon, list_order, profile_labels, signal_quality, signal_strength,)
ERROR_TEXT = { ErrorCode.BLOCKED: "Bluetooth is blocked. Check the airplane mode or the hardware switch.", ErrorCode.ADAPTER_OFF: "Turn Bluetooth on first.", ErrorCode.PAIRING_FAILED: "Pairing failed. Check the code and try again.", ErrorCode.PAIRING_REJECTED: "Pairing was rejected.", ErrorCode.PAIRING_TIMEOUT: "The device didn't answer in time. Put it in pairing mode and retry.", ErrorCode.CONNECTION_FAILED: "Couldn't connect. Make sure the device is on and nearby.", ErrorCode.BUSY: "Bluetooth is busy, try again in a moment.", ErrorCode.NOT_FOUND: "That device is no longer available.", ErrorCode.INVALID_INPUT: "That value isn't accepted.", ErrorCode.UNAVAILABLE: "Bluetooth isn't available right now.", ErrorCode.FAILED: "Couldn't complete that. Please try again.",}
SECTION_TITLES = { "connected": "Connected", "paired": "My devices", "nearby": "Nearby devices",}
def error_message(error: Exception) -> str: if isinstance(error, BluetoothError): return ERROR_TEXT.get(error.code, ERROR_TEXT[ErrorCode.FAILED]) return ERROR_TEXT[ErrorCode.FAILED]
def should_ignore(error: Exception) -> bool: return isinstance(error, BluetoothError) and error.code is ErrorCode.PAIRING_REJECTED
def passphrase_problem(kind: RequestKind, text: str) -> str | None: text = text.strip() if not text: return "Enter the code shown on the device." if kind is RequestKind.ENTER_PASSKEY: if not text.isdigit() or int(text) > 999_999: return "The passkey is up to 6 digits." elif len(text) > 16: return "A PIN has at most 16 characters." return None
def device_glyph(device: Device) -> str: return device_icon(device.icon)
def row_subtitle(device: Device) -> str: parts = [] if device.paired: parts.append("Paired") elif not device.named: parts.append(device.address.upper()) if device.battery is not None: parts.append(f"{device.battery}%") strength = signal_strength(device.rssi) if strength is not None and not device.is_connected: parts.append(signal_quality(strength)) return " · ".join(parts) or "Not paired"
def row_status(device: Device) -> str: return { LinkState.CONNECTED: "Connected", LinkState.CONNECTING: "Connecting…", LinkState.DISCONNECTING: "Disconnecting…", LinkState.PAIRING: "Pairing…", LinkState.IDLE: "", }[device.state]
def device_facts(device: Device) -> list[tuple[str, str]]: facts = [("fingerprint", device.address.upper())] if device.battery is not None: facts.append((battery_icon(device.battery), f"{device.battery}%")) strength = signal_strength(device.rssi) if strength is not None: facts.append(("signal_cellular_alt", f"{signal_quality(strength)} · {device.rssi} dBm")) facts.append(("bluetooth", "Low Energy" if device.low_energy_only else "Classic / dual")) return facts
def device_profiles(device: Device) -> str: return ", ".join(profile_labels(device.uuids))
def visible(device: Device, show_unnamed: bool, query: str) -> bool: if not show_unnamed and not device.named and not device.paired and not device.is_busy: return False query = query.strip().casefold() return not query or query in device.name.casefold()
def sections( devices: tuple[Device, ...], show_unnamed: bool = False, query: str = "") -> list[tuple[str, str, list[Device]]]: groups: dict[str, list[Device]] = {"connected": [], "paired": [], "nearby": []} for device in sorted((d for d in devices if visible(d, show_unnamed, query)), key=list_order): if device.is_connected or device.is_busy: groups["connected"].append(device) elif device.paired: groups["paired"].append(device) else: groups["nearby"].append(device) return [(key, SECTION_TITLES[key], members) for key, members in groups.items() if members]
def hidden_count(devices: tuple[Device, ...]) -> int: return sum(1 for d in devices if not visible(d, False, ""))
@dataclass(frozen=True)class Headline: icon: str title: str subtitle: str tone: str
def headline(snapshot: BluetoothSnapshot) -> Headline: if snapshot.availability is Availability.SERVICE_MISSING: return Headline( "bluetooth_disabled", "Bluetooth service not running", "Start bluetoothd to manage devices", "idle", ) adapter = snapshot.adapter if adapter is None: return Headline("bluetooth_disabled", "No Bluetooth adapter", "Plug in or enable an adapter", "idle") if not adapter.powered: return Headline("bluetooth_disabled", "Bluetooth is off", "Turn it on to connect devices", "idle")
pending = snapshot.pending_device if pending is not None: verb = { LinkState.PAIRING: "Pairing with", LinkState.CONNECTING: "Connecting to", LinkState.DISCONNECTING: "Disconnecting from", }[pending.state] return Headline(device_glyph(pending), pending.name, f"{verb} device…", "busy")
connected = snapshot.connected_devices if connected: first = connected[0] extra = f" and {len(connected) - 1} more" if len(connected) > 1 else "" battery = f" · {first.battery}%" if first.battery is not None else "" return Headline("bluetooth_connected", f"{first.name}{extra}", f"Connected{battery}", "ok") if adapter.discovering: return Headline("bluetooth_searching", "Searching…", "Looking for devices nearby", "busy") if adapter.discoverable: return Headline("visibility", adapter.name, "Visible to nearby devices", "warn") return Headline("bluetooth", "Not connected", "Pick a device below", "idle")
def request_text(request: PairingRequest) -> tuple[str, str, str]: name = request.device_name kind = request.kind if kind is RequestKind.CONFIRM_PASSKEY: return ("pin", f"Pair with {name}?", f"Make sure {name} shows {request.code}.") if kind is RequestKind.ENTER_PIN: return ("password", f"PIN for {name}", "Enter the PIN printed on the device (try 0000).") if kind is RequestKind.ENTER_PASSKEY: return ("password", f"Passkey for {name}", "Enter the 6-digit passkey shown on the device.") if kind is RequestKind.DISPLAY_PASSKEY: done = "●" * request.entered + "○" * max(0, 6 - request.entered) return ("keyboard", f"Type this on {name}", f"{request.code} {done} then press Enter.") if kind is RequestKind.DISPLAY_PIN: return ("keyboard", f"Type this on {name}", f"{request.code}, then press Enter.") if kind is RequestKind.AUTHORIZE_PAIRING: return ("bluetooth_connected", f"{name} wants to pair", "Allow this device to pair with the computer.") labels = profile_labels((request.service_uuid or "",)) service = labels[0].lower() if labels else "a service" return ("bluetooth_connected", f"{name} wants to connect", f"It asks to use {service}.")
@dataclass(frozen=True)class BarState: icon: str | None tooltip: str
def bar_state(snapshot: BluetoothSnapshot) -> BarState: summary = headline(snapshot) tooltip = f"{summary.title}\n{summary.subtitle}" if snapshot.availability is not Availability.READY or snapshot.adapter is None: return BarState(None, tooltip) if not snapshot.adapter.powered: return BarState("bluetooth_disabled", tooltip) if snapshot.connected_devices: return BarState("bluetooth_connected", tooltip) if snapshot.adapter.discovering: return BarState("bluetooth_searching", tooltip) return BarState("bluetooth", tooltip)