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

Added support for automatically preloading screens

This commit is contained in:
Björn Ritzl 2019-01-11 08:47:06 +01:00
parent 7f770d6b3b
commit 7740499821
6 changed files with 103 additions and 14 deletions

View File

@ -33,6 +33,7 @@ For proxies the recommended setup is to create one game object per screen and pe
* **Timestep below Popup (number)** - Timestep to set on screen proxy when it is below a popup. This is useful when pausing animations and gameplay while a popup is open. * **Timestep below Popup (number)** - Timestep to set on screen proxy when it is below a popup. This is useful when pausing animations and gameplay while a popup is open.
* **Transition Url (url)** - Optional URL to call when the screen is about to be shown/hidden. Use this to trigger a transition (see the section on [transitions](#transitions)). * **Transition Url (url)** - Optional URL to call when the screen is about to be shown/hidden. Use this to trigger a transition (see the section on [transitions](#transitions)).
* **Focus Url (url)** - Optional URL to call when the screen gains or loses focus (see the section on [screen focus](#screen-focus-gainloss)). * **Focus Url (url)** - Optional URL to call when the screen gains or loses focus (see the section on [screen focus](#screen-focus-gainloss)).
* **Preload (boolean)** - Check this if the screen should be preloaded and kept loaded at all times. For a collection proxy it means that it will be async loaded but not enabled at all times while not visible. This can also temporarily be achieved through the `monarch.preload()` function.
![](docs/setup_proxy.png) ![](docs/setup_proxy.png)
@ -45,6 +46,7 @@ For factories the recommended setup is to create one game object per screen and
* **Popup on Popup (boolean)** - Check this if the screen is a [popup](#popups) and it can be shown on top of other popups. * **Popup on Popup (boolean)** - Check this if the screen is a [popup](#popups) and it can be shown on top of other popups.
* **Transition Id (url)** - Optional id of the game object to send a message to when the screen is about to be shown/hidden. Use this to trigger a transition (see the section on [transitions](#transitions)). * **Transition Id (url)** - Optional id of the game object to send a message to when the screen is about to be shown/hidden. Use this to trigger a transition (see the section on [transitions](#transitions)).
* **Focus Id (url)** - Optional id of the game object to send a message to when the screen gains or loses focus (see the section on [screen focus](#screen-focus-gainloss)). * **Focus Id (url)** - Optional id of the game object to send a message to when the screen gains or loses focus (see the section on [screen focus](#screen-focus-gainloss)).
* **Preload (boolean)** - Check this if the screen should be preloaded and kept loaded at all times. For a collection factory this means that its resources will be dynamically loaded at all times. This can also temporarily be achieved through the `monarch.preload()` function.
![](docs/setup_factory.png) ![](docs/setup_factory.png)
@ -358,6 +360,26 @@ Check if Monarch is busy showing and/or hiding a screen.
* ```busy``` (boolean) - True if busy hiding and/or showing a screen. * ```busy``` (boolean) - True if busy hiding and/or showing a screen.
### monarch.is_top(id)
Check if a Monarch screen is at the top of the view stack.
**PARAMETERS**
* ```screen_id``` (hash) - Id of the screen to check
**RETURN**
* ```exists``` (boolean) - True if the screen is at the top of the stack.
### monarch.is_visible(id)
Check if a Monarch screen is visible.
**PARAMETERS**
* ```screen_id``` (hash) - Id of the screen to check
**RETURN**
* ```exists``` (boolean) - True if the screen is visible.
### monarch.add_listener([url]) ### monarch.add_listener([url])
Add a URL that will be notified of navigation events. Add a URL that will be notified of navigation events.

View File

@ -280,6 +280,11 @@ embedded_instances {
" value: \"about:/go#about\"\n" " value: \"about:/go#about\"\n"
" type: PROPERTY_TYPE_URL\n" " type: PROPERTY_TYPE_URL\n"
" }\n" " }\n"
" properties {\n"
" id: \"preload\"\n"
" value: \"true\"\n"
" type: PROPERTY_TYPE_BOOLEAN\n"
" }\n"
"}\n" "}\n"
"embedded_components {\n" "embedded_components {\n"
" id: \"collectionproxy\"\n" " id: \"collectionproxy\"\n"

View File

@ -11,6 +11,7 @@ local ACQUIRE_INPUT_FOCUS = hash("acquire_input_focus")
local ASYNC_LOAD = hash("async_load") local ASYNC_LOAD = hash("async_load")
local UNLOAD = hash("unload") local UNLOAD = hash("unload")
local ENABLE = hash("enable") local ENABLE = hash("enable")
local DISABLE = hash("disable")
-- transition messages -- transition messages
M.TRANSITION = {} M.TRANSITION = {}
@ -112,6 +113,17 @@ function M.is_top(id)
end end
--- Check if a screen is visible
-- @param id (string|hash)
-- @return true if the screen is visible
function M.is_visible(id)
assert(id, "You must provide a screen id")
id = tohash(id)
assert(screens[id], ("There is no screen registered with id %s"):format(tostring(id)))
return screens[id].loaded
end
local function register(id, settings) local function register(id, settings)
assert(id, "You must provide a screen id") assert(id, "You must provide a screen id")
id = tohash(id) id = tohash(id)
@ -142,12 +154,17 @@ end
-- * focus_url - URL to a script that is to be notified of focus -- * focus_url - URL to a script that is to be notified of focus
-- lost/gained events -- lost/gained events
-- * timestep_below_popup - Timestep to set on proxy when below a popup -- * timestep_below_popup - Timestep to set on proxy when below a popup
-- * auto_preload - true if the screen should be automatically preloaded
function M.register_proxy(id, proxy, settings) function M.register_proxy(id, proxy, settings)
assert(proxy, "You must provide a collection proxy URL") assert(proxy, "You must provide a collection proxy URL")
local screen = register(id, settings) local screen = register(id, settings)
screen.proxy = proxy screen.proxy = proxy
screen.transition_url = settings and settings.transition_url screen.transition_url = settings and settings.transition_url
screen.focus_url = settings and settings.focus_url screen.focus_url = settings and settings.focus_url
screen.auto_preload = settings and settings.auto_preload
if screen.auto_preload then
M.preload(id)
end
end end
M.register = M.register_proxy M.register = M.register_proxy
@ -167,12 +184,17 @@ M.register = M.register_proxy
-- for the screen transitions -- for the screen transitions
-- * focus_id - Id of the game object in the collection that is to be notified -- * focus_id - Id of the game object in the collection that is to be notified
-- of focus lost/gained events -- of focus lost/gained events
-- * auto_preload - true if the screen should be automatically preloaded
function M.register_factory(id, factory, settings) function M.register_factory(id, factory, settings)
assert(factory, "You must provide a collection factory URL") assert(factory, "You must provide a collection factory URL")
local screen = register(id, settings) local screen = register(id, settings)
screen.factory = factory screen.factory = factory
screen.transition_id = settings and settings.transition_id screen.transition_id = settings and settings.transition_id
screen.focus_id = settings and settings.focus_id screen.focus_id = settings and settings.focus_id
screen.auto_preload = settings and settings.auto_preload
if screen.auto_preload then
M.preload(id)
end
end end
--- Unregister a screen --- Unregister a screen
@ -225,18 +247,31 @@ local function unload(screen)
log("unload()", screen.id) log("unload()", screen.id)
if screen.proxy then if screen.proxy then
if screen.auto_preload then
msg.post(screen.proxy, DISABLE)
screen.loaded = false
screen.preloaded = true
else
screen.wait_for = PROXY_UNLOADED screen.wait_for = PROXY_UNLOADED
msg.post(screen.proxy, UNLOAD) msg.post(screen.proxy, UNLOAD)
coroutine.yield() coroutine.yield()
screen.loaded = false screen.loaded = false
screen.preloaded = false
screen.wait_for = nil screen.wait_for = nil
end
elseif screen.factory then elseif screen.factory then
for id, instance in pairs(screen.factory_ids) do for id, instance in pairs(screen.factory_ids) do
go.delete(instance) go.delete(instance)
end end
screen.factory_ids = nil screen.factory_ids = nil
if screen.auto_preload then
screen.loaded = false
screen.preloaded = true
else
collectionfactory.unload(screen.factory) collectionfactory.unload(screen.factory)
screen.loaded = false screen.loaded = false
screen.preloaded = false
end
end end
end end
@ -634,7 +669,7 @@ function M.preload(id, cb)
log("preload()", screen.id) log("preload()", screen.id)
if screen.preloaded or screen.loaded then if screen.preloaded or screen.loaded then
if cb then cb() end if cb then cb() end
return return true
end end
local co local co
co = coroutine.create(function() co = coroutine.create(function()
@ -644,6 +679,7 @@ function M.preload(id, cb)
if cb then cb() end if cb then cb() end
end) end)
assert(coroutine.resume(co)) assert(coroutine.resume(co))
return true
end end

View File

@ -6,6 +6,7 @@ go.property("popup", false)
go.property("popup_on_popup", false) go.property("popup_on_popup", false)
go.property("transition_id", hash("")) go.property("transition_id", hash(""))
go.property("focus_id", hash("")) go.property("focus_id", hash(""))
go.property("preload", false)
function init(self) function init(self)
@ -18,6 +19,7 @@ function init(self)
popup_on_popup = self.popup_on_popup, popup_on_popup = self.popup_on_popup,
transition_id = self.transition_id, transition_id = self.transition_id,
focus_id = self.focus_id, focus_id = self.focus_id,
auto_preload = self.preload,
} }
monarch.register_factory(self.screen_id, self.screen_factory, settings) monarch.register_factory(self.screen_id, self.screen_factory, settings)
end end

View File

@ -7,6 +7,7 @@ go.property("popup_on_popup", false)
go.property("timestep_below_popup", 1) go.property("timestep_below_popup", 1)
go.property("transition_url", msg.url()) go.property("transition_url", msg.url())
go.property("focus_url", msg.url()) go.property("focus_url", msg.url())
go.property("preload", false)
function init(self) function init(self)
@ -22,6 +23,7 @@ function init(self)
transition_url = self.transition_url ~= url and self.transition_url or nil, transition_url = self.transition_url ~= url and self.transition_url or nil,
focus_url = self.focus_url ~= url and self.focus_url or nil, focus_url = self.focus_url ~= url and self.focus_url or nil,
timestep_below_popup = self.timestep_below_popup, timestep_below_popup = self.timestep_below_popup,
auto_preload = self.preload,
} }
monarch.register_proxy(self.screen_id, self.screen_proxy, settings) monarch.register_proxy(self.screen_id, self.screen_proxy, settings)

View File

@ -103,6 +103,28 @@ return function()
assert_stack({ }) assert_stack({ })
end) end)
it("should be able to tell if a screen is visible or not", function()
assert(not monarch.is_visible(SCREEN1))
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(monarch.is_visible(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 })
assert(not monarch.is_visible(SCREEN1))
assert(monarch.is_visible(SCREEN2))
monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown")
assert_stack({ SCREEN1, SCREEN2, POPUP1 })
assert(not monarch.is_visible(SCREEN1))
assert(monarch.is_visible(SCREEN2))
assert(monarch.is_visible(POPUP1))
end)
it("should be able to pass data to a screen when showning it or going back to it", function() it("should be able to pass data to a screen when showning it or going back to it", function()
local data1 = { foo = "bar" } local data1 = { foo = "bar" }
@ -147,7 +169,7 @@ return function()
end) end)
it("should be able to show one popup on top of another the Popup On Popup flag is set", function() it("should be able to show one popup on top of another if the Popup On Popup flag is set", 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")
assert_stack({ SCREEN1 }) assert_stack({ SCREEN1 })