mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-14 08:23:59 +08:00
6cfbf1deb8
Render the stopped timer in projected driving views and preview scenes, with layout migration and runtime coverage. Include the matching prebuilt receipt.
71 lines
2.3 KiB
Python
71 lines
2.3 KiB
Python
"""Monotonic, drive-scoped standstill duration for native and Android Auto widgets."""
|
|
|
|
from dataclasses import dataclass
|
|
|
|
|
|
SHOW_AFTER_DRIVE_NS = 60_000_000_000
|
|
SECOND_NS = 1_000_000_000
|
|
ENGAGED = (22, 127, 64)
|
|
EXPERIMENTAL = (218, 111, 37)
|
|
TRAFFIC = (201, 34, 49)
|
|
PREVIEW_DURATION_S = 134
|
|
|
|
|
|
def timer_size(profile: str) -> tuple[int, int]:
|
|
return (660, 168) if profile == "large" else (440, 112)
|
|
|
|
|
|
@dataclass
|
|
class StoppedTimer:
|
|
drive_key: tuple[int, int] | None = None
|
|
drive_started_ns: int | None = None
|
|
standstill_started_ns: int | None = None
|
|
last_ns: int | None = None
|
|
|
|
def reset(self) -> None:
|
|
self.drive_key = None
|
|
self.drive_started_ns = None
|
|
self.standstill_started_ns = None
|
|
self.last_ns = None
|
|
|
|
def step(self, *, now_ns: int, drive_key: tuple[int, int] | None, car_fresh: bool,
|
|
standstill: bool, reverse: bool, enabled: bool) -> int | None:
|
|
if drive_key is None or (self.last_ns is not None and now_ns < self.last_ns):
|
|
self.reset()
|
|
if drive_key is None:
|
|
return None
|
|
self.last_ns = now_ns
|
|
if drive_key != self.drive_key:
|
|
self.drive_key = drive_key
|
|
self.drive_started_ns = now_ns
|
|
self.standstill_started_ns = None
|
|
if not enabled or not car_fresh or not standstill or reverse:
|
|
self.standstill_started_ns = None
|
|
return None
|
|
if self.standstill_started_ns is None:
|
|
self.standstill_started_ns = now_ns
|
|
if self.drive_started_ns is None or now_ns - self.drive_started_ns < SHOW_AFTER_DRIVE_NS:
|
|
return None
|
|
seconds = (now_ns - self.standstill_started_ns) // SECOND_NS
|
|
return seconds if seconds > 0 else None
|
|
|
|
|
|
def duration_text(seconds: int) -> tuple[str, str]:
|
|
minutes, remainder = divmod(seconds, 60)
|
|
return (f"{minutes} minute{'s' if minutes != 1 else ''}",
|
|
f"{remainder} second{'s' if remainder != 1 else ''}")
|
|
|
|
|
|
def duration_color(seconds: int) -> tuple[int, int, int]:
|
|
if seconds < 60:
|
|
return ENGAGED
|
|
if seconds < 150:
|
|
start, end, amount = ENGAGED, EXPERIMENTAL, (seconds - 60) / 90
|
|
elif seconds < 300:
|
|
start, end, amount = EXPERIMENTAL, TRAFFIC, (seconds - 150) / 150
|
|
else:
|
|
return TRAFFIC
|
|
return (int(start[0] + amount * (end[0] - start[0])),
|
|
int(start[1] + amount * (end[1] - start[1])),
|
|
int(start[2] + amount * (end[2] - start[2])))
|