diff --git a/README.md b/README.md index ec0fedf..37d41b7 100644 --- a/README.md +++ b/README.md @@ -311,6 +311,7 @@ Smart-plug keys (outlets.json) are never copied. page gets a blue band naming it ("SC", "SC WS", "SC?" when it stops answering). It flashes until that location acknowledges, then stays; the page's own name and number shrink into the top 60% so they stay readable. Red stays for NA's own problems. +- **Page-number key holds at NA** (`nav_hold_ms` 2000 + `nav_hold_more`): tap = page 1, hold 2 s = the status page (19), keep holding to 3 s = the LOCATIONS page (98) to pick a location. WS and SC keep a 1 s hold to their status page. - **ALL AUTO-FIX** (LOCATIONS page 98, bottom-left): blue "ALL ON", or grey naming the paused locations. Tap: pause auto-fix at NA, WS and SC at once; tap again: every one back to its own auto-fix hours (`autofix auto`). Alarms stay on and holds still fix. diff --git a/config.json b/config.json index 2ae354e..f8bd413 100644 --- a/config.json +++ b/config.json @@ -855,7 +855,7 @@ "ssh": "studio@10.1.7.39" } }, - "nav_hold_ms": 1000, + "nav_hold_ms": 2000, "nav_keys": [ "pagenum" ], @@ -2299,5 +2299,11 @@ "heartbeat": "sp_hb", "state": "sp_state" }, - "nav_locations_band": true + "nav_locations_band": true, + "nav_hold_more": [ + { + "ms": 3000, + "page": 98 + } + ] } diff --git a/make_page.py b/make_page.py index 6ea2469..9d77517 100644 --- a/make_page.py +++ b/make_page.py @@ -333,6 +333,14 @@ def nav_key(kind, names, status_page=None, hold_ms=1000, tap_page=1, cfg=None): "options": {"surfaceId": prop("self"), "page": prop(status_page)}, "children": {}}] step["action_sets"] = {"down": [], "up": tap, str(hold_ms): hold} step["options"]["runWhileHeld"] = [hold_ms] + # Longer holds go further (NA, 2026-10-21: 2 s the status page, still held at 3 s the LOCATIONS page). + for i, more in enumerate(sorted((cfg or {}).get("nav_hold_more") or [], key=lambda m: m["ms"])): + if more["ms"] > hold_ms: + step["action_sets"][str(more["ms"])] = [{"type": "action", "id": stable_id("nav", "hold%d" % (i + 2)), + "definitionId": "set_page", "connectionId": "internal", + "options": {"surfaceId": prop("self"), "page": prop(more["page"])}, + "children": {}}] + step["options"]["runWhileHeld"].append(more["ms"]) key["options"]["notes"] = ("%s (%s): colour follows the ALL button on the status page. " "Undo on every page with: python3 nav_keys.py --revert" % (NAV_MARKER, kind)) return key diff --git a/ready-page.companionconfig b/ready-page.companionconfig index 657322c..d882e16 100644 Binary files a/ready-page.companionconfig and b/ready-page.companionconfig differ diff --git a/restart-page.companionconfig b/restart-page.companionconfig index 4cfc36b..c659c0c 100644 Binary files a/restart-page.companionconfig and b/restart-page.companionconfig differ diff --git a/schema.py b/schema.py index e74831e..c6d4954 100644 --- a/schema.py +++ b/schema.py @@ -71,6 +71,8 @@ field("nav_keys", "list", ["pagenum"], "Which of Companion's page keys (page up, apply="pages") field("nav_hold_ms", "int", 1000, "Holding the page-number key this long jumps to the Status page.", "Companion", advanced=True, lo=200, hi=5000, apply="pages") +field("nav_hold_more", "list", [], "Longer holds on the page-number key: [{\"ms\": 3000, \"page\": 98}] - still held at 3 s, " + "it goes on to page 98 (NA: 2 s the status page, 3 s the LOCATIONS page).", "Companion", advanced=True, apply="pages") field("nav_tap_page", "int", 1, "Tapping the page-number key goes to this page.", "Companion", advanced=True, lo=1, apply="pages") field("variables", "dict", {}, "The custom variables the panel uses inside Companion.", "Companion", required=True) diff --git a/status-page.companionconfig b/status-page.companionconfig index a5f8b73..ea57e65 100644 Binary files a/status-page.companionconfig and b/status-page.companionconfig differ diff --git a/tests/test_campus.py b/tests/test_campus.py index acefcf2..f2f9427 100644 --- a/tests/test_campus.py +++ b/tests/test_campus.py @@ -616,3 +616,14 @@ class TestAllAutoFix(unittest.TestCase): key = page["page"]["controls"]["3"]["1"] self.assertIn("all autofix", key["options"]["notes"]) self.assertIn("sp_all_cmd", json.dumps(key["steps"])) + + +class TestLongerHolds(unittest.TestCase): + def test_na_page_key_goes_to_status_at_2s_and_locations_at_3s(self): + na = json.load(open(os.path.join(ROOT, "config.json"))) + cfg = dict(na, nav_hold_ms=2000, nav_hold_more=[{"ms": 3000, "page": 98}]) + st = make_page.nav_key("pagenum", cfg["variables"], 19, 2000, 1, cfg)["steps"]["0"] + pages = {k: [a["options"]["page"]["value"] for a in v] for k, v in st["action_sets"].items()} + self.assertEqual(pages, {"down": [], "up": [1], "2000": [19], "3000": [98]}) + self.assertEqual(st["options"]["runWhileHeld"], [2000, 3000]) + self.assertEqual(schema.validate(cfg)[0], []) diff --git a/tests/test_status_panel.py b/tests/test_status_panel.py index 4ade477..918883b 100644 --- a/tests/test_status_panel.py +++ b/tests/test_status_panel.py @@ -2274,10 +2274,11 @@ class TestPage(unittest.TestCase): self.assertTrue(key["options"]["notes"].startswith("STATUS nav key (%s)" % kind)) step = key["steps"]["0"] self.assertEqual(step["action_sets"]["down"], []) - tap, hold = step["action_sets"]["up"][0], step["action_sets"]["1000"][0] + tap, hold = step["action_sets"]["up"][0], step["action_sets"]["2000"][0] # NA: 2 s ... self.assertEqual((tap["definitionId"], tap["options"]["page"]["value"]), (action, 1)) # page 1 outright, not "startup" self.assertEqual((hold["definitionId"], hold["options"]["page"]["value"]), ("set_page", 19)) - self.assertEqual(step["options"]["runWhileHeld"], [1000]) + self.assertEqual(step["action_sets"]["3000"][0]["options"]["page"]["value"], 98) # ... then 3 s: LOCATIONS + self.assertEqual(step["options"]["runWhileHeld"], [2000, 3000]) box = [l for l in key["style"]["layers"] if l["type"] == "box"][0] self.assertTrue(box["color"]["isExpression"]) self.assertIn("'$.all.b'", box["color"]["value"]) # follows the ALL button @@ -2297,7 +2298,7 @@ class TestPage(unittest.TestCase): for r in c.values(): for ctl in r.values(): sets = ctl.get("steps", {}).get("0", {}).get("action_sets", {}) - if "2000" in sets: + if "2000" in sets and sets["2000"][0]["definitionId"] != "set_page": # not the page-number key's hold holds[sets["2000"][0]["options"]["value"]["value"]] = sets["up"] self.assertEqual(len(holds), len(CONFIG["restart_page"]["keys"])) self.assertIn("$(custom:sp_cmd);force rs_tascam $(internal:time_unix)", holds)