3
0
mirror of https://github.com/britzl/monarch.git synced 2025-06-27 10:27:49 +02:00

Prevent show/back operations while busy

Fixes #22
This commit is contained in:
Björn Ritzl 2018-06-10 16:17:41 +02:00
parent c2239d67e5
commit 4231b0b89c
3 changed files with 54 additions and 4 deletions

View File

@ -245,6 +245,10 @@ The options table can contain the following fields:
* ```clear``` (boolean) - If the clear flag is set Monarch will search the stack for the screen that is to be shown. If the screen already exists in the stack and the clear flag is set Monarch will remove all screens between the current top and the screen in question. * ```clear``` (boolean) - If the clear flag is set Monarch will search the stack for the screen that is to be shown. If the screen already exists in the stack and the clear flag is set Monarch will remove all screens between the current top and the screen in question.
* ```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). * ```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).
**RETURN**
* ```success``` (boolean) - True if the process of showing the screen was started successfully. False if already busy showing/hiding a screen.
### monarch.back([data], [callback]) ### monarch.back([data], [callback])
Go back to a previous Monarch screen Go back to a previous Monarch screen
@ -252,6 +256,9 @@ Go back to a previous Monarch screen
* ```data``` (table) - Optional data to associate with the screen you are going back to. Retrieve using ```monarch.data()```. * ```data``` (table) - Optional data to associate with the screen you are going back to. Retrieve using ```monarch.data()```.
* ```callback``` (function) - Optional function to call when the previous screen is visible. * ```callback``` (function) - Optional function to call when the previous screen is visible.
**RETURN**
* ```success``` (boolean) - True if the process of going back to a previous screen was started successfully. False if already busy showing/hiding a screen.
### monarch.preload(screen_id, [callback]) ### monarch.preload(screen_id, [callback])
Preload a Monarch screen. This will load but not enable the screen. This is useful for content heavy screens that you wish to be able to show without having to wait for it load. Preload a Monarch screen. This will load but not enable the screen. This is useful for content heavy screens that you wish to be able to show without having to wait for it load.

View File

@ -1,9 +1,5 @@
local M = {} local M = {}
local screens = {}
local stack = {}
local CONTEXT = hash("monarch_context") local CONTEXT = hash("monarch_context")
local PROXY_LOADED = hash("proxy_loaded") local PROXY_LOADED = hash("proxy_loaded")
local PROXY_UNLOADED = hash("proxy_unloaded") local PROXY_UNLOADED = hash("proxy_unloaded")
@ -25,6 +21,15 @@ M.FOCUS = {}
M.FOCUS.GAINED = hash("monarch_focus_gained") M.FOCUS.GAINED = hash("monarch_focus_gained")
M.FOCUS.LOST = hash("monarch_focus_lost") M.FOCUS.LOST = hash("monarch_focus_lost")
-- all registered screens
local screens = {}
-- the current stack of screens
local stack = {}
-- true while busy showing/hiding something
local busy = false
local function log(...) end local function log(...) end
@ -225,6 +230,7 @@ local function show_out(screen, next_screen, cb)
log("show_out()", screen.id) log("show_out()", screen.id)
local co local co
co = coroutine.create(function() co = coroutine.create(function()
busy = true
screen.co = co screen.co = co
change_context(screen) change_context(screen)
release_input(screen) release_input(screen)
@ -238,6 +244,7 @@ local function show_out(screen, next_screen, cb)
unload(screen) unload(screen)
end end
screen.co = nil screen.co = nil
busy = false
if cb then cb() end if cb then cb() end
end) end)
coroutine.resume(co) coroutine.resume(co)
@ -247,6 +254,7 @@ local function show_in(screen, previous_screen, reload, cb)
log("show_in()", screen.id) log("show_in()", screen.id)
local co local co
co = coroutine.create(function() co = coroutine.create(function()
busy = true
screen.co = co screen.co = co
change_context(screen) change_context(screen)
if reload and screen.loaded then if reload and screen.loaded then
@ -271,6 +279,7 @@ local function show_in(screen, previous_screen, reload, cb)
acquire_input(screen) acquire_input(screen)
focus_gained(screen, previous_screen) focus_gained(screen, previous_screen)
screen.co = nil screen.co = nil
busy = false
if cb then cb() end if cb then cb() end
end) end)
coroutine.resume(co) coroutine.resume(co)
@ -280,6 +289,7 @@ local function back_in(screen, previous_screen, cb)
log("back_in()", screen.id) log("back_in()", screen.id)
local co local co
co = coroutine.create(function() co = coroutine.create(function()
busy = true
screen.co = co screen.co = co
change_context(screen) change_context(screen)
if screen.preloaded then if screen.preloaded then
@ -297,6 +307,7 @@ local function back_in(screen, previous_screen, cb)
acquire_input(screen) acquire_input(screen)
focus_gained(screen, previous_screen) focus_gained(screen, previous_screen)
screen.co = nil screen.co = nil
busy = false
if cb then cb() end if cb then cb() end
end) end)
coroutine.resume(co) coroutine.resume(co)
@ -306,6 +317,7 @@ local function back_out(screen, next_screen, cb)
log("back_out()", screen.id) log("back_out()", screen.id)
local co local co
co = coroutine.create(function() co = coroutine.create(function()
busy = true
screen.co = co screen.co = co
change_context(screen) change_context(screen)
release_input(screen) release_input(screen)
@ -313,6 +325,7 @@ local function back_out(screen, next_screen, cb)
transition(screen, M.TRANSITION.BACK_OUT, { next_screen = next_screen and next_screen.id }) transition(screen, M.TRANSITION.BACK_OUT, { next_screen = next_screen and next_screen.id })
unload(screen) unload(screen)
screen.co = nil screen.co = nil
busy = false
if cb then cb() end if cb then cb() end
end) end)
coroutine.resume(co) coroutine.resume(co)
@ -346,8 +359,13 @@ end
-- This would be the case if doing a show() from a popup on the screen just below the popup. -- This would be the case if doing a show() from a popup on the screen just below the popup.
-- @param data (*) - Optional data to set on the screen. Can be retrieved by the data() function -- @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 -- @param cb (function) - Optional callback to invoke when screen is shown
-- @return success True if screen is successfully shown, false if busy performing another operation
function M.show(id, options, data, cb) function M.show(id, options, data, cb)
assert(id, "You must provide a screen id") assert(id, "You must provide a screen id")
if busy then
return false
end
id = tohash(id) id = tohash(id)
assert(screens[id], ("There is no screen registered with id %s"):format(tostring(id))) assert(screens[id], ("There is no screen registered with id %s"):format(tostring(id)))
@ -392,13 +410,20 @@ function M.show(id, options, data, cb)
-- show screen -- show screen
show_in(screen, top, options and options.reload, cb) show_in(screen, top, options and options.reload, cb)
return true
end end
-- Go back to the previous screen in the stack -- Go back to the previous screen in the stack
-- @param data (*) - Optional data to set for the previous screen -- @param data (*) - Optional data to set for the previous screen
-- @param cb (function) - Optional callback to invoke when the previous screen is visible again -- @param cb (function) - Optional callback to invoke when the previous screen is visible again
-- @return true if successfully going back, false if busy performing another operation
function M.back(data, cb) function M.back(data, cb)
if busy then
return false
end
local screen = table.remove(stack) local screen = table.remove(stack)
if screen then if screen then
log("back()", screen.id) log("back()", screen.id)
@ -424,6 +449,7 @@ function M.back(data, cb)
elseif cb then elseif cb then
cb() cb()
end end
return true
end end
--- Preload a screen. This will load but not enable and show a screen. Useful for "heavier" screens --- Preload a screen. This will load but not enable and show a screen. Useful for "heavier" screens

View File

@ -148,6 +148,23 @@ return function()
end) end)
it("should prevent further operations while hiding/showing a screen", function()
assert(monarch.show(SCREEN1) == true)
assert(monarch.show(SCREEN2) == false)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(monarch.show(SCREEN2) == true)
assert(wait_until_shown(SCREEN2), "Screen1 was never shown")
assert_stack({ SCREEN1, SCREEN2 })
assert(monarch.back() == true)
assert(monarch.back() == false)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
end)
it("should close any open popups when showing a popup without the Popup On Popup flag", function() it("should close any open popups when showing a popup without the Popup On Popup flag", function()
monarch.show(SCREEN1) monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown") assert(wait_until_shown(SCREEN1), "Screen1 was never shown")