From 4ad86d41fcf48a251d5504152501b615bb571b29 Mon Sep 17 00:00:00 2001 From: Marius Petcu Date: Wed, 20 May 2020 16:36:29 +0300 Subject: [PATCH] Implement monarch.replace() (#61) --- README.md | 4 ++++ monarch/monarch.lua | 34 ++++++++++++++++++++++++++++++++++ test/test_monarch.lua | 30 ++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/README.md b/README.md index 411dd78..9d18d90 100644 --- a/README.md +++ b/README.md @@ -319,6 +319,10 @@ The options table can contain the following fields: * ```reload``` (boolean) - If the `reload` flag is set Monarch will reload the collection proxy if it's already loaded (this can happen if the previous screen was a popup). * ```no_stack``` (boolean) - If the `no_stack` flag is set Monarch will load the screen without adding it to the screen stack. * ```sequential``` (boolean) - If the `sequential` flag is set Monarch will start loading the screen only after the previous screen finished transitioning out. +* ```pop``` (number) - If `pop` is set to a number, Monarch will pop that number of screens from the stack before adding the new one. + +### monarch.replace(screen_id, [options], [data], [callback]) +Replace the top of the stack with a new screen. Equivalent to calling `monarch.show()` with `pop = 1`. It takes the same parameters as `monarch.show()`. ### monarch.hide(screen_id, [callback]) diff --git a/monarch/monarch.lua b/monarch/monarch.lua index 3012a7d..0964857 100644 --- a/monarch/monarch.lua +++ b/monarch/monarch.lua @@ -69,6 +69,16 @@ local function pcallfn(fn, ...) end end +local function assign(to, from) + if not from then + return to + end + for k, v in pairs(from) do + to[k] = v + end + return to +end + local function cowait(delay) local co = coroutine.running() assert(co, "You must run this from within a coroutine") @@ -649,6 +659,8 @@ end -- This would be the case if doing a show() from a popup on the screen just below the popup. -- * sequential - Set to true to wait for the previous screen to show itself out before starting the -- show in transition even when transitioning to a different scene ID. +-- * no_stack - Set to true to load the screen without adding it to the screen stack. +-- * pop - The number of screens to pop from the stack before adding the new one. -- @param data (*) - Optional data to set on the screen. Can be retrieved by the data() function -- @param cb (function) - Optional callback to invoke when screen is shown function M.show(id, options, data, cb) @@ -712,6 +724,14 @@ function M.show(id, options, data, cb) end end + if options and options.pop then + for i = 1, options.pop do + local stack_top = #stack + if stack_top < 1 then break end + stack[stack_top] = nil + end + end + -- show screen, wait until preloaded if it is already preloading -- this can typpically happen if you do a show() on app start for a -- screen that has Preload set to true @@ -734,6 +754,20 @@ function M.show(id, options, data, cb) end +--- Replace the top of the stack with a new screen +-- @param id (string|hash) - Id of the screen to show +-- @param options (table) - Table with options when showing the screen (can be nil). Valid values: +-- * clear - Set to true if the stack should be cleared down to an existing instance of the screen +-- * reload - Set to true if screen should be reloaded if it already exists in the stack and is loaded. +-- This would be the case if doing a show() from a popup on the screen just below the popup. +-- * no_stack - Set to true to load the screen without adding it to the screen stack. +-- @param data (*) - Optional data to set on the screen. Can be retrieved by the data() function +-- @param cb (function) - Optional callback to invoke when screen is shown +function M.replace(id, options, data, cb) + return M.show(id, assign({ pop = 1 }, options), data, cb) +end + + -- Hide a screen. The screen must either be at the top of the stack or -- visible but not added to the stack (through the no_stack option) -- @param id (string|hash) - Id of the screen to show diff --git a/test/test_monarch.lua b/test/test_monarch.lua index 195390e..b4ab5e6 100644 --- a/test/test_monarch.lua +++ b/test/test_monarch.lua @@ -133,6 +133,22 @@ return function() assert_stack({ }) end) + it("should be able to replace screens at the top of the stack", function() + monarch.show(SCREEN1_STR) + assert(wait_until_shown(SCREEN1), "Screen1 was never shown") + assert_stack({ SCREEN1 }) + + monarch.show(SCREEN2) + assert(wait_until_hidden(SCREEN1), "Screen1 was never hidden") + assert(wait_until_shown(SCREEN2), "Screen2 was never shown") + assert_stack({ SCREEN1, SCREEN2 }) + + monarch.replace(SCREEN1) + assert(wait_until_hidden(SCREEN2), "Screen2 was never hidden") + assert(wait_until_shown(SCREEN1), "Screen1 was never shown") + assert_stack({ SCREEN1, SCREEN1 }) + end) + it("should be able to tell if a screen is visible or not", function() assert(not monarch.is_visible(SCREEN1)) monarch.show(SCREEN1) @@ -302,6 +318,20 @@ return function() assert_stack({ SCREEN1, SCREEN2 }) end) + it("should close any open popups when replacing a non-popup", function() + monarch.show(SCREEN1) + assert(wait_until_shown(SCREEN1), "Screen1 was never shown") + assert_stack({ SCREEN1 }) + monarch.show(POPUP1) + assert(wait_until_shown(POPUP1), "Popup1 was never shown") + assert_stack({ SCREEN1, POPUP1 }) + monarch.show(POPUP2) + assert(wait_until_shown(POPUP2), "Popup2 was never shown") + assert_stack({ SCREEN1, POPUP1, POPUP2 }) + monarch.replace(SCREEN2) + assert(wait_until_shown(SCREEN2), "Popup2 was never shown") + assert_stack({ SCREEN2 }) + end) it("should be able to get the id of the screen at the top and bottom of the stack", function() assert(monarch.top() == nil)