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

Wait with screen unload until next screen is loaded and ready to be shown (#74)

* Removed screen flicker when transitioning between screens

* Moved advanced example to subfolder. Added basic example.

* Remove flicker on back navigation too

* Fix issue with no_stack screens added at any time
This commit is contained in:
Björn Ritzl
2021-06-24 07:45:09 +02:00
committed by GitHub
parent 466b558e73
commit 20cf731fdb
4 changed files with 181 additions and 173 deletions

View File

@@ -4,7 +4,10 @@ function M.seconds(amount)
local co = coroutine.running()
assert(co, "You must run this from within a coroutine")
timer.delay(amount, false, function()
coroutine.resume(co)
local ok, err = coroutine.resume(co)
if not ok then
print(err)
end
end)
coroutine.yield()
end
@@ -13,10 +16,13 @@ function M.eval(fn, timeout)
local co = coroutine.running()
assert(co, "You must run this from within a coroutine")
local start = socket.gettime()
timer.delay(0.01, true, function(self, handle, time_elapsed)
timer.delay(0.02, true, function(self, handle, time_elapsed)
if fn() or (timeout and socket.gettime() > (start + timeout)) then
timer.cancel(handle)
coroutine.resume(co)
local ok, err = coroutine.resume(co)
if not ok then
print(err)
end
end
end)
coroutine.yield()

View File

@@ -1,5 +1,5 @@
function init(self)
local monarch = require "monarch.monarch"
local data = monarch.data(hash("screen_preload"))
data.count = data.count + 1
if data then data.count = data.count + 1 end
end

View File

@@ -77,6 +77,9 @@ return function()
local function wait_until_not_busy()
return wait_timeout(function() return not monarch.is_busy() end)
end
local function wait_until_stack(expected_screens)
return wait_timeout(function() return check_stack(expected_screens) end)
end
local function wait_until_loaded(screen_id)
wait_until_done(function(done)
monarch.when_preloaded(screen_id, done)
@@ -115,57 +118,42 @@ return function()
it("should be able to show screens and go back to previous screens", function()
monarch.show(SCREEN1_STR)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(wait_until_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 })
assert(wait_until_stack({ SCREEN1, SCREEN2 }))
monarch.back()
assert(wait_until_hidden(SCREEN2), "Screen2 was never hidden")
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(wait_until_stack({ SCREEN1 }))
monarch.back()
assert(wait_until_hidden(SCREEN1), "Screen1 was never hidden")
assert_stack({ })
assert(wait_until_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 })
assert(wait_until_stack({ SCREEN1 }), "Screen1 was never shown")
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(wait_until_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 })
assert(wait_until_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)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(wait_until_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(wait_until_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(wait_until_stack({ SCREEN1, SCREEN2, POPUP1 }))
assert(not monarch.is_visible(SCREEN1))
assert(monarch.is_visible(SCREEN2))
assert(monarch.is_visible(POPUP1))
@@ -174,13 +162,32 @@ return function()
it("should be able to show a screen without adding it to the stack", function()
monarch.show(BACKGROUND, { no_stack = true })
assert(wait_until_shown(BACKGROUND), "Background was never shown")
assert_stack({ })
assert(wait_until_stack({ }))
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(wait_until_stack({ SCREEN1 }))
end)
it("should be able to show a screen without adding it to the stack at any time", function()
monarch.show(SCREEN1)
assert(wait_until_not_busy())
assert(wait_until_stack({ SCREEN1 }))
monarch.show(BACKGROUND, { no_stack = true })
assert(wait_until_not_busy())
assert(wait_until_shown(BACKGROUND))
assert(wait_until_stack({ SCREEN1 }))
monarch.show(SCREEN2)
assert(wait_until_not_busy())
assert(wait_until_stack({ SCREEN1, SCREEN2 }))
monarch.back()
assert(wait_until_not_busy())
assert(wait_until_shown(SCREEN1))
assert(wait_until_stack({ SCREEN1 }))
end)
it("should be able to hide a screen not added to the stack", function()
monarch.show(BACKGROUND, { no_stack = true })
assert(wait_until_shown(BACKGROUND), "Background was never shown")
@@ -190,22 +197,17 @@ return function()
assert(wait_until_hidden(BACKGROUND), "Background was never hidden")
assert_stack({ })
end)
it("should be able to hide the top screen", function()
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(wait_until_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 })
assert(wait_until_stack({ SCREEN1, SCREEN2 }))
assert(monarch.hide(SCREEN1) == false)
assert(monarch.hide(SCREEN2) == true)
assert(wait_until_hidden(SCREEN2), "Screen2 was never hidden")
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(wait_until_stack({ SCREEN1 }))
end)
it("should be able to pass data to a screen when showing it or going back to it", function()
@@ -230,51 +232,40 @@ return function()
it("should be able to show the same screen twice", function()
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(wait_until_stack({ SCREEN1 }))
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1, SCREEN1 })
assert(wait_until_stack({ SCREEN1, SCREEN1 }))
end)
it("should be able to clear the stack if trying to show the same screen twice", function()
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(wait_until_stack({ SCREEN1 }))
monarch.show(SCREEN2)
assert(wait_until_shown(SCREEN2), "Screen2 was never shown")
assert_stack({ SCREEN1, SCREEN2 })
assert(wait_until_stack({ SCREEN1, SCREEN2 }))
monarch.show(SCREEN1, { clear = true })
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(wait_until_stack({ SCREEN1 }))
end)
it("should be able to show one popup on top of another if the Popup On Popup flag is set", function()
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(wait_until_stack({ SCREEN1 }))
monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown")
assert_stack({ SCREEN1, POPUP1 })
assert(wait_until_stack({ SCREEN1, POPUP1 }))
monarch.show(POPUP2)
assert(wait_until_shown(POPUP2), "Popup2 was never shown")
assert_stack({ SCREEN1, POPUP1, POPUP2 })
assert(wait_until_stack({ SCREEN1, POPUP1, POPUP2 }))
end)
it("should prevent further operations while hiding/showing a screen", function()
it("should be able to queue multiple display commands", function()
monarch.show(SCREEN1)
monarch.show(SCREEN2)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert(wait_until_shown(SCREEN2), "Screen2 was never shown")
assert_stack({ SCREEN1, SCREEN2 })
assert(wait_until_stack({ SCREEN1, SCREEN2 }))
assert(monarch.back())
assert(monarch.back())
assert(wait_until_hidden(SCREEN1), "Screen1 was never hidden")
assert(wait_until_hidden(SCREEN2), "Screen2 was never hidden")
assert(wait_until_stack({}), "Stack never became empty")
end)
@@ -292,84 +283,63 @@ return function()
it("should close any open popups when showing a popup without the Popup On Popup flag", function()
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(wait_until_stack({ SCREEN1 }))
monarch.show(POPUP2)
assert(wait_until_shown(POPUP2), "Popup2 was never shown")
assert_stack({ SCREEN1, POPUP2 })
assert(wait_until_stack({ SCREEN1, POPUP2 }))
monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown")
assert_stack({ SCREEN1, POPUP1 })
assert(wait_until_stack({ SCREEN1, POPUP1 }))
end)
it("should close any open popups when showing a non-popup", function()
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(wait_until_stack({ SCREEN1 }))
monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown")
assert_stack({ SCREEN1, POPUP1 })
assert(wait_until_stack({ SCREEN1, POPUP1 }))
monarch.show(POPUP2)
assert(wait_until_shown(POPUP2), "Popup2 was never shown")
assert_stack({ SCREEN1, POPUP1, POPUP2 })
assert(wait_until_stack({ SCREEN1, POPUP1, POPUP2 }))
monarch.show(SCREEN2)
assert(wait_until_shown(SCREEN2), "Popup2 was never shown")
assert_stack({ SCREEN1, SCREEN2 })
assert(wait_until_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 })
assert(wait_until_stack({ SCREEN1 }))
monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown")
assert_stack({ SCREEN1, POPUP1 })
assert(wait_until_stack({ SCREEN1, POPUP1 }))
monarch.show(POPUP2)
assert(wait_until_shown(POPUP2), "Popup2 was never shown")
assert_stack({ SCREEN1, POPUP1, POPUP2 })
assert(wait_until_stack({ SCREEN1, POPUP1, POPUP2 }))
monarch.replace(SCREEN2)
assert(wait_until_shown(SCREEN2), "Screen2 was never shown")
assert_stack({ SCREEN2 })
assert(wait_until_stack({ SCREEN2 }))
end)
it("should replace a popup", function()
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(wait_until_stack({ SCREEN1 }))
monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown")
assert_stack({ SCREEN1, POPUP1 })
assert(wait_until_stack({ SCREEN1, POPUP1 }))
monarch.replace(POPUP2)
assert(wait_until_shown(POPUP2), "Popup2 was never shown")
assert_stack({ SCREEN1, POPUP2 })
assert(wait_until_stack({ SCREEN1, POPUP2 }))
end)
it("should replace a pop-up two levels down", function()
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(wait_until_stack({ SCREEN1 }))
monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown")
assert_stack({ SCREEN1, POPUP1 })
assert(wait_until_stack({ SCREEN1, POPUP1 }))
monarch.show(POPUP2)
assert(wait_until_shown(POPUP2), "Popup2 was never shown")
assert_stack({ SCREEN1, POPUP1, POPUP2 })
assert(wait_until_stack({ SCREEN1, POPUP1, POPUP2 }))
monarch.show(POPUP2, { pop = 2 })
assert(wait_until_shown(POPUP2), "Popup2 was never shown")
assert_stack({ SCREEN1, POPUP2 })
assert(wait_until_stack({ SCREEN1, POPUP2 }))
end)
it("shouldn't over-pop popups", function()
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert_stack({ SCREEN1 })
assert(wait_until_stack({ SCREEN1 }))
monarch.show(POPUP1)
assert(wait_until_shown(POPUP1), "Popup1 was never shown")
assert_stack({ SCREEN1, POPUP1 })
assert(wait_until_stack({ SCREEN1, POPUP1 }))
monarch.show(POPUP2, { pop = 10 })
assert(wait_until_shown(POPUP2), "Popup2 was never shown")
assert_stack({ SCREEN1, POPUP2 })
assert(wait_until_stack({ SCREEN1, POPUP2 }))
end)
it("should be able to get the id of the screen at the top and bottom of the stack", function()
@@ -379,7 +349,7 @@ return function()
assert(monarch.bottom(-1) == nil)
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert(wait_until_stack({ SCREEN1 }))
assert(monarch.top() == SCREEN1)
assert(monarch.top(0) == SCREEN1)
assert(monarch.top(1) == nil)
@@ -388,9 +358,7 @@ return function()
assert(monarch.bottom(-1) == nil)
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(wait_until_stack({ SCREEN1, SCREEN2 }))
assert(monarch.top(0) == SCREEN2)
assert(monarch.top(-1) == SCREEN1)
assert(monarch.bottom(0) == SCREEN1)
@@ -399,8 +367,8 @@ return function()
it("should be busy while transition is running", function()
monarch.show(TRANSITION1)
assert(wait_until_shown(TRANSITION1), "Transition1 was never shown")
assert(monarch.is_busy())
assert(wait_until_shown(TRANSITION1), "Transition1 was never shown")
assert(wait_until_not_busy())
end)
@@ -428,11 +396,11 @@ return function()
monarch.add_listener(URL2)
monarch.show(SCREEN1)
assert(wait_until_not_busy())
assert(mock_msg.messages(URL1)[1].message_id == monarch.SCREEN_TRANSITION_IN_STARTED)
assert(mock_msg.messages(URL1)[1].message.screen == SCREEN1)
assert(mock_msg.messages(URL2)[1].message_id == monarch.SCREEN_TRANSITION_IN_STARTED)
assert(mock_msg.messages(URL2)[1].message.screen == SCREEN1)
assert(wait_until_not_busy())
assert(mock_msg.messages(URL1)[2].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED)
assert(mock_msg.messages(URL1)[2].message.screen == SCREEN1)
assert(mock_msg.messages(URL2)[2].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED)
@@ -444,30 +412,30 @@ return function()
assert(#mock_msg.messages(URL1) == 6)
assert(#mock_msg.messages(URL2) == 2)
assert(mock_msg.messages(URL1)[3].message_id == monarch.SCREEN_TRANSITION_OUT_STARTED)
assert(mock_msg.messages(URL1)[3].message.screen == SCREEN1)
assert(mock_msg.messages(URL1)[4].message_id == monarch.SCREEN_TRANSITION_IN_STARTED)
assert(mock_msg.messages(URL1)[3].message_id == monarch.SCREEN_TRANSITION_IN_STARTED)
assert(mock_msg.messages(URL1)[3].message.screen == SCREEN2)
assert(mock_msg.messages(URL1)[4].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED)
assert(mock_msg.messages(URL1)[4].message.screen == SCREEN2)
assert(mock_msg.messages(URL1)[5].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED)
assert(mock_msg.messages(URL1)[5].message.screen == SCREEN2)
assert(mock_msg.messages(URL1)[5].message_id == monarch.SCREEN_TRANSITION_OUT_STARTED)
assert(mock_msg.messages(URL1)[5].message.screen == SCREEN1)
assert(mock_msg.messages(URL1)[6].message_id == monarch.SCREEN_TRANSITION_OUT_FINISHED)
assert(mock_msg.messages(URL1)[6].message.screen == SCREEN1)
monarch.back()
assert(wait_until_not_busy())
assert(#mock_msg.messages(URL1) == 10)
assert(#mock_msg.messages(URL2) == 2)
assert(mock_msg.messages(URL1)[7].message_id == monarch.SCREEN_TRANSITION_OUT_STARTED)
assert(mock_msg.messages(URL1)[7].message.screen == SCREEN2)
assert(mock_msg.messages(URL1)[8].message_id == monarch.SCREEN_TRANSITION_IN_STARTED)
assert(mock_msg.messages(URL1)[7].message_id == monarch.SCREEN_TRANSITION_IN_STARTED)
assert(mock_msg.messages(URL1)[7].message.screen == SCREEN1)
assert(mock_msg.messages(URL1)[8].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED)
assert(mock_msg.messages(URL1)[8].message.screen == SCREEN1)
assert(mock_msg.messages(URL1)[9].message_id == monarch.SCREEN_TRANSITION_IN_FINISHED)
assert(mock_msg.messages(URL1)[9].message.screen == SCREEN1)
assert(mock_msg.messages(URL1)[9].message_id == monarch.SCREEN_TRANSITION_OUT_STARTED)
assert(mock_msg.messages(URL1)[9].message.screen == SCREEN2)
assert(mock_msg.messages(URL1)[10].message_id == monarch.SCREEN_TRANSITION_OUT_FINISHED)
assert(mock_msg.messages(URL1)[10].message.screen == SCREEN2)
end)
it("should be able to show a screen even while it is preloading", function()
monarch.show(SCREEN_PRELOAD, nil, { count = 1 })
assert(wait_until_shown(SCREEN_PRELOAD), "Screen_preload was never shown")
@@ -499,13 +467,12 @@ return function()
_G.focus1_lost = nil
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert(wait_until_stack({ SCREEN1 }))
monarch.show(FOCUS1)
assert(wait_until_shown(FOCUS1), "Screen1 was never shown")
assert(wait_until_stack({ SCREEN1, FOCUS1 }))
assert(_G.focus1_gained)
monarch.show(SCREEN1)
assert(wait_until_shown(SCREEN1), "Screen1 was never shown")
assert(wait_until_hidden(FOCUS1), "Focus1 was never hidden")
assert(wait_until_stack({ SCREEN1, FOCUS1, SCREEN1 }))
assert(_G.focus1_lost)
end)
@@ -556,9 +523,8 @@ return function()
_G.screen1_foobar = nil
monarch.show(SCREEN1)
wait_until_shown(SCREEN1)
monarch.show(SCREEN2)
wait_until_shown(SCREEN2)
assert(wait_until_stack({ SCREEN1, SCREEN2 }))
local ok, err = monarch.post(SCREEN1, "foobar")
assert(not ok and err, "Expected monarch.post() to return false plus an error message")
cowait(0.1)