This change adds a mechanism to refresh the todo list dynamically when the underlying service updates, improving UI responsiveness and user experience. It also updates documentation and removes deprecated files. - New Features: - Added `_refresh_todos` method to rebuild the todo list when `get_todo_service().todos` changes. - Introduced `TodoListCapture` class for mouse capture handling of the todo list window. - Enhancements: - Updated README with corrected image paths, installation tips, and manual installation commands. - Introduced `start.py` to launch the application or lock mode. - Removed deprecated `config.json` and `debug_memory.py`. - Bug Fixes: - Fixed lock screen screenshot path in README.
71 lines
2.0 KiB
Python
71 lines
2.0 KiB
Python
import asyncio
|
|
import functools
|
|
import typing as t
|
|
|
|
from fabric.utils import GLib
|
|
|
|
|
|
def debounce(delay: float) -> t.Callable[..., t.Any]:
|
|
def decorator(func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:
|
|
task: asyncio.Task[None] | None = None
|
|
|
|
@functools.wraps(func)
|
|
async def wrapper(*args: t.Any, **kwargs: t.Any) -> None:
|
|
nonlocal task
|
|
|
|
if task is not None and not task.done():
|
|
task.cancel()
|
|
try:
|
|
await task
|
|
except asyncio.CancelledError:
|
|
pass
|
|
|
|
async def delayed_call() -> None:
|
|
await asyncio.sleep(delay)
|
|
await func(*args, **kwargs)
|
|
|
|
task = asyncio.create_task(delayed_call())
|
|
|
|
return wrapper
|
|
|
|
return decorator
|
|
|
|
|
|
def sync_debounce(
|
|
delay: int, min_n_times: int = 0, immediate: bool = False
|
|
) -> t.Callable[..., t.Any]:
|
|
def decorator(func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:
|
|
n_times = 0
|
|
timeout_id: int | None = None
|
|
last_args: tuple[t.Any, ...] = ()
|
|
last_kwargs: dict[str, t.Any] = {}
|
|
|
|
def call_func() -> bool:
|
|
nonlocal timeout_id, n_times
|
|
if n_times > min_n_times:
|
|
func(*last_args, **last_kwargs)
|
|
n_times = 0
|
|
timeout_id = None
|
|
return False
|
|
|
|
def wrapper(*args: t.Any, **kwargs: t.Any) -> None:
|
|
nonlocal timeout_id, last_args, last_kwargs, n_times
|
|
|
|
last_args = args
|
|
last_kwargs = kwargs
|
|
|
|
if timeout_id is not None:
|
|
GLib.source_remove(timeout_id)
|
|
|
|
if not immediate or n_times < min_n_times:
|
|
n_times += 1
|
|
timeout_id = GLib.timeout_add(delay, call_func)
|
|
else:
|
|
n_times = 0
|
|
timeout_id = None
|
|
func(*last_args, **last_kwargs)
|
|
|
|
return functools.wraps(func)(wrapper)
|
|
|
|
return decorator
|