From 404b505a41362f340e79374ee3ad4dbd468da3e4 Mon Sep 17 00:00:00 2001 From: cirakg Date: Sun, 25 Oct 2026 13:13:39 +0100 Subject: fix(ui): vertical swipes and drags scroll the list and text screens The Forerunner 70 sends no page behaviour for a swipe on a custom view, so the list and info screens only scrolled with the buttons. Swipes and drags now scroll them directly; one gesture scrolls once even when the device also sends the page behaviour, and a drag's release opens no row. Co-Authored-By: Claude Opus 5.5 --- tools/lint_project.py | 12 +++++++++++- tools/ui_flow.py | 26 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/lint_project.py b/tools/lint_project.py index 04d525f..c1c225a 100644 --- a/tools/lint_project.py +++ b/tools/lint_project.py @@ -42,7 +42,17 @@ AUTHOR = "cirakg & claude ai" HEADER_LINES = 15 DIAG_FILE = Path("source/util/Diag.mc") # Folders that hold local tool state or generated output, never project files. -SKIP_DIRS = {".git", ".cache", ".claude", "build", "node_modules", "__pycache__", ".pytest_cache", ".mypy_cache", ".ruff_cache"} +SKIP_DIRS = { + ".git", + ".cache", + ".claude", + "build", + "node_modules", + "__pycache__", + ".pytest_cache", + ".mypy_cache", + ".ruff_cache", +} # Written by a tool that would drop a hand-added header on the next run. GENERATED = {Path("docker/docs/package-lock.json")} diff --git a/tools/ui_flow.py b/tools/ui_flow.py index 8c08caf..3c7afb2 100644 --- a/tools/ui_flow.py +++ b/tools/ui_flow.py @@ -437,8 +437,33 @@ def flow_locked_entry(f: Flow) -> None: f.expect("list", AUTO_LOCK_TIMEOUT_S) +def flow_swipes(f: Flow, screen: str) -> None: + """On touch screens a vertical swipe scrolls `screen` once, whatever the + watch does with page behaviour; checked through the debug logs so no + image is involved. A swipe up must report one scroll; on the list the + focus must move and a swipe back must return it.""" + if not f.touch: + return + pattern = r"DIAG list_move focus=(\d+)" if screen == "list" else r"DIAG info_scroll first=(\d+)" + regex = re.compile(pattern) + x, top, bottom = f._w() // 2, f._h() // 4, f._h() * 3 // 4 + seen: list[str] = [] + for start, end in ((bottom, top), (top, bottom)): # swipe up: next; down: previous + f.act() + f.sim.swipe(x, start, x, end) + f.log.wait_for(pattern, SCREEN_TIMEOUT_S) + time.sleep(SETTLE_S) + found = [m.group(1) for line in f.log.lines()[f.log.mark :] if (m := regex.search(line))] + if len(found) != 1: + raise FlowError(f"one swipe on {screen} scrolled {len(found)} times, not once") + seen.append(found[0]) + if screen == "list" and seen[0] == seen[1]: + raise FlowError("a swipe on the list didn't move the focus") + + def flow_menu(f: Flow) -> None: """The menu, and About on watches whose menu has a focus to move.""" + flow_swipes(f, "list") f.menu() time.sleep(MENU_SETTLE_S) f.shot("menu") @@ -454,6 +479,7 @@ def flow_menu(f: Flow) -> None: f.select() f.expect("about") f.shot("about") + flow_swipes(f, "about") f.act() # Touch-only watches show the menu as a freely scrolling list without # focus, so there is no reliable "select About"; just close it. -- cgit v1.2.3