diff --git a/src/mobile/hubs.bend b/src/mobile/hubs.bend index c0fcbdbbb5..934dbbd32f 100644 --- a/src/mobile/hubs.bend +++ b/src/mobile/hubs.bend @@ -585,12 +585,42 @@ def Hubs.recv(hs: Hubs, +key: String, o: J.Json) -> HAct: def Hubs.online(hs: Hubs, +key: String, b: Bool) -> HAct: Hubs.step(hs, False{}, key, On{b}) +# what a phone shows over its screens (sheets, menus, forms, questions, +# an error) is this device's moment, never its state: the saved copy may +# have been written while one was up (the app goes to the background with +# Find open), and loading it put the sheet back over the app at every +# launch. Each is shut on load: the flags Find, Settings, the pairing QR, +# the key form and the folder picker; the scratch row menu, delete, +# remove and rename questions, the bot, room and routine forms; the error. +def Hubs.calm.flags(fs: List<&2, String>, u: U.Ui) -> U.Ui: + match fs: + case Nil{}: + u + case f <> t: + Hubs.calm.flags(t, U.Ui.flag_off(u, f)) + +def Hubs.calm.keys(ks: List<&2, String>, u: U.Ui) -> U.Ui: + match ks: + case Nil{}: + u + case k <> t: + Hubs.calm.keys(t, U.Ui.scratch_set(u, k, "")) + +def Hubs.calm.flag_names() -> List<&2, String>: + ["palette", "settings", "pairqr", "keyform", "proj"] + +def Hubs.calm.scratch_names() -> List<&2, String>: + ["@menu", "@del", "@rm", "@ren", "@bnew", "@rnew", "@onew"] + +def Hubs.calm(u: U.Ui) -> U.Ui: + U.Ui.error_set(Hubs.calm.keys(Hubs.calm.scratch_names(), Hubs.calm.flags(Hubs.calm.flag_names(), u)), "") + def Hubs.stale.go(l: List<&2, Hub>) -> List<&2, Hub>: match l: case Nil{}: Nil{} case Hub{+k, +u} <> t: - Hub{k, U.Ui.unsync(u)} <> Hubs.stale.go(t) + Hub{k, U.Ui.unsync(Hubs.calm(u))} <> Hubs.stale.go(t) # state loaded from the phone's saved copy: no hub has answered yet def Hubs.stale(hs: Hubs) -> Hubs: diff --git a/test/mcalm_test.bend b/test/mcalm_test.bend new file mode 100644 index 0000000000..20c1c3ef0e --- /dev/null +++ b/test/mcalm_test.bend @@ -0,0 +1,37 @@ +import Base +import ./check.bend as C +import ./mbots_test.bend as Bots +import ../src/core/json.bend as J +import ../src/mobile/hubs.bend as H + +# A phone's saved state loaded at launch (Hubs.stale) never puts a sheet, +# menu, form or error back over the app: the state may have been saved +# while one was up. What the person had selected stays. +def act(+h: H.Hubs, +a: String, +v: String) -> H.Hubs: + H.Hubs.after(H.Hubs.act(h, a, v)) + +def none(j: J.Json) -> Bool: + match j: + case J.Null{}: + True{} + case _: + False{} + +def up(+s: J.Json, +k: String) -> String: + Bool.show(Bool.not(none(J.Json.get_obj(s, k)))) + +def opened() -> H.Hubs: + act(act(act(Bots.two(), "find-open", "search"), "flag", "settings"), "bot-new", "") + +def main() -> IO(Unit): + do IO: + C.Check.str("find up before", up(H.Hubs.screen(opened()), "find"), "True") + C.Check.str("settings up before", up(H.Hubs.screen(opened()), "settings"), "True") + C.Check.str("bot form up before", up(H.Hubs.screen(opened()), "newBot"), "True") + C.Check.str("find shut after load", up(H.Hubs.screen(H.Hubs.stale(opened())), "find"), "False") + C.Check.str("settings shut after load", up(H.Hubs.screen(H.Hubs.stale(opened())), "settings"), "False") + C.Check.str("bot form shut after load", up(H.Hubs.screen(H.Hubs.stale(opened())), "newBot"), "False") + C.Check.str("error cleared after load", J.Json.get_str(H.Hubs.screen(H.Hubs.stale(opened())), "error", ""), "") + C.Check.str("selection kept", J.Json.get_str(H.Hubs.screen(H.Hubs.stale(act(opened(), "select", "box:3787|t1"))), "sel", "x"), + J.Json.get_str(H.Hubs.screen(act(opened(), "select", "box:3787|t1")), "sel", "y")) + IO.print("mobile calm-on-load tests passed\n")