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

Added navigation listeners

This commit is contained in:
Björn Ritzl 2018-06-20 07:30:38 +02:00
parent e570eac40b
commit 3947e86169
5 changed files with 173 additions and 6 deletions

View File

@ -1,7 +1,7 @@
[project] [project]
title = Monarch title = Monarch
version = 0.9 version = 0.9
dependencies = https://github.com/britzl/deftest/archive/1.2.1.zip dependencies = https://github.com/britzl/deftest/archive/2.3.0.zip
[bootstrap] [bootstrap]
main_collection = /example/example.collectionc main_collection = /example/example.collectionc

View File

@ -10,6 +10,7 @@ local ASYNC_LOAD = hash("async_load")
local UNLOAD = hash("unload") local UNLOAD = hash("unload")
local ENABLE = hash("enable") local ENABLE = hash("enable")
-- transition messages
M.TRANSITION = {} M.TRANSITION = {}
M.TRANSITION.DONE = hash("transition_done") M.TRANSITION.DONE = hash("transition_done")
M.TRANSITION.SHOW_IN = hash("transition_show_in") M.TRANSITION.SHOW_IN = hash("transition_show_in")
@ -17,16 +18,25 @@ M.TRANSITION.SHOW_OUT = hash("transition_show_out")
M.TRANSITION.BACK_IN = hash("transition_back_in") M.TRANSITION.BACK_IN = hash("transition_back_in")
M.TRANSITION.BACK_OUT = hash("transition_back_out") M.TRANSITION.BACK_OUT = hash("transition_back_out")
-- focus messages
M.FOCUS = {} 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")
-- listener messages
M.SCREEN_VISIBLE = hash("monarch_screen_visible")
M.SCREEN_HIDDEN = hash("monarch_screen_hidden")
-- all registered screens -- all registered screens
local screens = {} local screens = {}
-- the current stack of screens -- the current stack of screens
local stack = {} local stack = {}
-- navigation listeners
local listeners = {}
-- the number of active transitions -- the number of active transitions
-- monarch is considered busy while there are active transitions -- monarch is considered busy while there are active transitions
local active_transition_count = 0 local active_transition_count = 0
@ -46,9 +56,15 @@ local function tohash(s)
return hash_lookup[s] return hash_lookup[s]
end end
local function notify_listeners(message_id, message)
log("notify_listeners()", message_id)
for _,url in pairs(listeners) do
msg.post(url, message_id, message or {})
end
end
local function screen_from_proxy(proxy) local function screen_from_proxy(proxy)
for _, screen in pairs(screens) do for _,screen in pairs(screens) do
if screen.proxy == proxy then if screen.proxy == proxy then
return screen return screen
end end
@ -57,7 +73,7 @@ end
local function screen_from_script() local function screen_from_script()
local url = msg.url() local url = msg.url()
for _, screen in pairs(screens) do for _,screen in pairs(screens) do
if screen.script == url then if screen.script == url then
return screen return screen
end end
@ -188,14 +204,14 @@ end
local function focus_gained(screen, previous_screen) local function focus_gained(screen, previous_screen)
log("focus_gained()", screen.id) log("focus_gained()", screen.id)
if screen.focus_url then if screen.focus_url then
msg.post(screen.focus_url, M.FOCUS.GAINED, {id = previous_screen and previous_screen.id}) msg.post(screen.focus_url, M.FOCUS.GAINED, { id = previous_screen and previous_screen.id })
end end
end end
local function focus_lost(screen, next_screen) local function focus_lost(screen, next_screen)
log("focus_lost()", screen.id) log("focus_lost()", screen.id)
if screen.focus_url then if screen.focus_url then
msg.post(screen.focus_url, M.FOCUS.LOST, {id = next_screen and next_screen.id}) msg.post(screen.focus_url, M.FOCUS.LOST, { id = next_screen and next_screen.id })
end end
end end
@ -247,6 +263,7 @@ local function show_out(screen, next_screen, cb)
screen.co = nil screen.co = nil
active_transition_count = active_transition_count - 1 active_transition_count = active_transition_count - 1
if cb then cb() end if cb then cb() end
notify_listeners(M.SCREEN_HIDDEN, { screen = screen.id, next_screen = next_screen.id })
end) end)
coroutine.resume(co) coroutine.resume(co)
end end
@ -282,12 +299,14 @@ local function show_in(screen, previous_screen, reload, cb)
screen.co = nil screen.co = nil
active_transition_count = active_transition_count - 1 active_transition_count = active_transition_count - 1
if cb then cb() end if cb then cb() end
notify_listeners(M.SCREEN_VISIBLE, { screen = screen.id, previous_screen = previous_screen and previous_screen.id })
end) end)
coroutine.resume(co) coroutine.resume(co)
end end
local function back_in(screen, previous_screen, cb) local function back_in(screen, previous_screen, cb)
log("back_in()", screen.id) log("back_in()", screen.id)
print("back_in()", screen.id)
local co local co
co = coroutine.create(function() co = coroutine.create(function()
active_transition_count = active_transition_count + 1 active_transition_count = active_transition_count + 1
@ -310,12 +329,14 @@ local function back_in(screen, previous_screen, cb)
screen.co = nil screen.co = nil
active_transition_count = active_transition_count - 1 active_transition_count = active_transition_count - 1
if cb then cb() end if cb then cb() end
notify_listeners(M.SCREEN_VISIBLE, { screen = screen.id, previous_screen = previous_screen.id })
end) end)
coroutine.resume(co) coroutine.resume(co)
end end
local function back_out(screen, next_screen, cb) local function back_out(screen, next_screen, cb)
log("back_out()", screen.id) log("back_out()", screen.id)
print("back_out()", screen.id)
local co local co
co = coroutine.create(function() co = coroutine.create(function()
active_transition_count = active_transition_count + 1 active_transition_count = active_transition_count + 1
@ -328,6 +349,7 @@ local function back_out(screen, next_screen, cb)
screen.co = nil screen.co = nil
active_transition_count = active_transition_count - 1 active_transition_count = active_transition_count - 1
if cb then cb() end if cb then cb() end
notify_listeners(M.SCREEN_HIDDEN, { screen = screen.id, next_screen = next_screen and next_screen.id })
end) end)
coroutine.resume(co) coroutine.resume(co)
end end
@ -549,6 +571,26 @@ function M.bottom(offset)
return screen and screen.id return screen and screen.id
end end
local function url_to_key(url)
return (url.socket or hash("")) .. (url.path or hash("")) .. (url.fragment or hash(""))
end
--- Add a listener to be notified of when screens are shown or hidden
-- @param url The url to notify, nil for current url
function M.add_listener(url)
url = url or msg.url()
listeners[url_to_key(url)] = url
end
--- Remove a previously added listener
-- @param url The url to remove, nil for current url
function M.remove_listener(url)
url = url or msg.url()
listeners[url_to_key(url)] = nil
end
function M.dump_stack() function M.dump_stack()
local s = "" local s = ""

View File

@ -315,3 +315,43 @@ embedded_instances {
z: 1.0 z: 1.0
} }
} }
embedded_instances {
id: "listener1"
data: ""
position {
x: 0.0
y: 0.0
z: 0.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale3 {
x: 1.0
y: 1.0
z: 1.0
}
}
embedded_instances {
id: "listener2"
data: ""
position {
x: 0.0
y: 0.0
z: 0.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale3 {
x: 1.0
y: 1.0
z: 1.0
}
}

52
test/msg.lua Normal file
View File

@ -0,0 +1,52 @@
local mock = require "deftest.mock.mock"
local M = {}
local recipients = {}
local history = {}
local function get_recipient(url)
recipients[url] = recipients[url] or {}
return recipients[url]
end
local function post(url, message_id, message)
local data = { url = url, message_id = message_id, message = message }
history[#history + 1] = data
local recipient = get_recipient(url)
recipient[#recipient + 1] = data
msg.post.original(url, message_id, message or {})
end
function M.mock()
recipients = {}
history = {}
mock.mock(msg)
msg.post.replace(post)
end
function M.unmock()
mock.unmock(msg)
end
function M.messages(url)
return url and get_recipient(url) or history
end
function M.first(url)
local messages = url and get_recipient(url) or history
return messages[1]
end
function M.last(url)
local messages = url and get_recipient(url) or history
return messages[#messages]
end
return M

View File

@ -1,4 +1,6 @@
local cowait = require "test.cowait" local cowait = require "test.cowait"
local mock_msg = require "test.msg"
local unload = require "deftest.util.unload"
local monarch = require "monarch.monarch" local monarch = require "monarch.monarch"
local SCREEN1_STR = hash("screen1") local SCREEN1_STR = hash("screen1")
@ -55,12 +57,14 @@ return function()
describe("monarch", function() describe("monarch", function()
before(function() before(function()
mock_msg.mock()
monarch = require "monarch.monarch" monarch = require "monarch.monarch"
screens_instances = collectionfactory.create("#screensfactory") screens_instances = collectionfactory.create("#screensfactory")
end) end)
after(function() after(function()
package.loaded["monarch.monarch"] = nil mock_msg.unmock()
unload.unload("monarch%..*")
for id,instance_id in pairs(screens_instances) do for id,instance_id in pairs(screens_instances) do
go.delete(instance_id) go.delete(instance_id)
end end
@ -229,5 +233,34 @@ return function()
assert(monarch.is_busy()) assert(monarch.is_busy())
assert(wait_until_not_busy()) assert(wait_until_not_busy())
end) end)
it("should be able to notify listeners of navigation events", function()
local URL1 = msg.url(screens_instances[hash("/listener1")])
local URL2 = msg.url(screens_instances[hash("/listener2")])
monarch.add_listener(URL1)
monarch.add_listener(URL2)
monarch.show(SCREEN1)
assert(wait_until_not_busy())
monarch.remove_listener(URL2)
monarch.show(SCREEN2)
assert(wait_until_not_busy())
monarch.back()
assert(wait_until_not_busy())
local messages_1 = mock_msg.messages(URL1)
local messages_2 = mock_msg.messages(URL2)
assert(#messages_1 == 5)
assert(#messages_2 == 1)
assert(messages_2[1].message_id == monarch.SCREEN_VISIBLE and messages_1[1].message.screen == SCREEN1)
assert(messages_1[1].message_id == monarch.SCREEN_VISIBLE and messages_1[1].message.screen == SCREEN1)
assert(messages_1[2].message_id == monarch.SCREEN_HIDDEN and messages_1[2].message.screen == SCREEN1)
assert(messages_1[3].message_id == monarch.SCREEN_VISIBLE and messages_1[3].message.screen == SCREEN2)
assert(messages_1[4].message_id == monarch.SCREEN_HIDDEN and messages_1[4].message.screen == SCREEN2)
assert(messages_1[5].message_id == monarch.SCREEN_VISIBLE and messages_1[5].message.screen == SCREEN1)
end)
end) end)
end end