feat(root): add keyboard layouts, OSDWindow, and update services & utilities
Introduce a new OSDWindow implementation, expose keyboard layout configuration, and modernize dependency handling and helper utilities. - **New Features** - Added `keyboard_layouts` list (`us`, `np`) to `config.json` - Created `OSDWindow` class and updated `main.py` to use it - Introduced new service modules (`battery`, `brightness`, `capslock`, `network`, `mpris`, `todo`, `modus`) and expanded `services/__init__.py` - Added `CommandResult` and `run_command` helper in `utils/functions.py` - **Enhancements** - Upgraded numerous dependencies to newer versions and switched `fabric` to a git source - Replaced bare `except:` with `except Exception:` in `WiFiPasswordDialog` - Improved type hints (`NamedTuple`, `TypeVar`) and refactored JSON file helpers - Added property notifications for battery percentage, state, and presence - **Bug Fixes** - Fixed incorrect return type annotation in `read_json_file` - Corrected tick‑handler logic to avoid double registration - Properly notify listeners on battery property changes - Ensured proper exception handling and cleanup in utility functions
This commit is contained in:
12 files changed
+504
-96
No files matched your search
+47
-4
@@ -4,9 +4,15 @@ import json
|
||||
import os
|
||||
import subprocess
|
||||
import threading
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Dict, NamedTuple, Optional, TypeVar
|
||||
|
||||
from fabric.utils import exec_shell_command, exec_shell_command_async, logger
|
||||
from fabric.utils import (
|
||||
exec_shell_command,
|
||||
exec_shell_command_async,
|
||||
logger,
|
||||
)
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def set_process_name(name: str):
|
||||
@@ -66,7 +72,6 @@ def run_in_thread(func):
|
||||
return wrapper
|
||||
|
||||
|
||||
# @run_in_thread
|
||||
def write_json_file(data: Dict, path: str):
|
||||
try:
|
||||
with open(path, "w") as f:
|
||||
@@ -75,7 +80,7 @@ def write_json_file(data: Dict, path: str):
|
||||
logger.warning(f"Failed to write json: {e}")
|
||||
|
||||
|
||||
def read_json_file(file_path: str) -> Optional[List]:
|
||||
def read_json_file(file_path: str) -> Optional[Dict]:
|
||||
if not os.path.exists(file_path):
|
||||
logger.error(f"JSON file {file_path} does not exist.")
|
||||
return None
|
||||
@@ -253,3 +258,41 @@ def clear_children(container) -> None:
|
||||
child.destroy()
|
||||
except Exception as e:
|
||||
logger.warning(f"clear_children failed: {e}")
|
||||
|
||||
|
||||
class CommandResult(NamedTuple):
|
||||
returncode: int
|
||||
stdout: bytes | str
|
||||
stderr: bytes | str
|
||||
|
||||
|
||||
def run_command(
|
||||
args: list[str],
|
||||
timeout: float | None = None,
|
||||
cwd: Optional[str] = None,
|
||||
env: Optional[Dict[str, str]] = None,
|
||||
*,
|
||||
input: bytes | str | None = None,
|
||||
text: bool = True,
|
||||
) -> CommandResult:
|
||||
try:
|
||||
result = subprocess.run(
|
||||
args,
|
||||
capture_output=True,
|
||||
text=text,
|
||||
timeout=timeout,
|
||||
cwd=cwd,
|
||||
env=env,
|
||||
input=input,
|
||||
)
|
||||
return CommandResult(result.returncode, result.stdout, result.stderr)
|
||||
except subprocess.TimeoutExpired as e:
|
||||
return CommandResult(
|
||||
-1,
|
||||
(e.stdout or b"" if not text else e.stdout or ""),
|
||||
(e.stderr or (b"timeout" if not text else "timeout")),
|
||||
)
|
||||
except FileNotFoundError as e:
|
||||
return CommandResult(127, "", str(e))
|
||||
except Exception as e:
|
||||
return CommandResult(1, "", str(e))
|
||||
Reference in new issue
Block a user