feat(root): implement dynamic todo list refresh and UI enhancements
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.
This commit is contained in:
267 files changed
+24582
-394
No files matched your search
@@ -0,0 +1,70 @@
|
||||
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
|
||||
Reference in new issue
Block a user