mirror of
https://github.com/britzl/monarch.git
synced 2025-06-27 10:27:49 +02:00
Make sure that callbacks aren't invoked more than once
This commit is contained in:
parent
76d4ca2927
commit
d3799a93ff
@ -1,4 +1,5 @@
|
|||||||
local callback_tracker = require "monarch.utils.callback_tracker"
|
local callback_tracker = require "monarch.utils.callback_tracker"
|
||||||
|
local async = require "monarch.utils.async"
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
@ -744,8 +745,9 @@ function M.show(id, options, data, cb)
|
|||||||
pop = pop - 1
|
pop = pop - 1
|
||||||
end
|
end
|
||||||
stack[#stack] = nil
|
stack[#stack] = nil
|
||||||
show_out(top, screen, WAIT_FOR_TRANSITION, callbacks.track())
|
async(function(await, resume)
|
||||||
callbacks.yield_until_done()
|
await(show_out, top, screen, WAIT_FOR_TRANSITION, resume)
|
||||||
|
end)
|
||||||
top = stack[#stack]
|
top = stack[#stack]
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -784,8 +786,9 @@ function M.show(id, options, data, cb)
|
|||||||
local same_screen = top and top.id == screen.id
|
local same_screen = top and top.id == screen.id
|
||||||
if same_screen or (options and options.sequential) then
|
if same_screen or (options and options.sequential) then
|
||||||
if top then
|
if top then
|
||||||
show_out(top, screen, WAIT_FOR_TRANSITION, callbacks.track())
|
async(function(await, resume)
|
||||||
callbacks.yield_until_done()
|
await(show_out, top, screen, WAIT_FOR_TRANSITION, resume)
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
show_in(screen, top, options and options.reload, add_to_stack, WAIT_FOR_TRANSITION, callbacks.track())
|
show_in(screen, top, options and options.reload, add_to_stack, WAIT_FOR_TRANSITION, callbacks.track())
|
||||||
else
|
else
|
||||||
@ -872,16 +875,11 @@ function M.clear(cb)
|
|||||||
log("clear() queuing action")
|
log("clear() queuing action")
|
||||||
|
|
||||||
queue_action(function(action_done, action_error)
|
queue_action(function(action_done, action_error)
|
||||||
local co
|
async(function(await, resume)
|
||||||
co = coroutine.create(function()
|
|
||||||
|
|
||||||
local callbacks = callback_tracker()
|
|
||||||
|
|
||||||
local top = stack[#stack]
|
local top = stack[#stack]
|
||||||
while top and top.visible do
|
while top and top.visible do
|
||||||
stack[#stack] = nil
|
stack[#stack] = nil
|
||||||
back_out(top, screen, WAIT_FOR_TRANSITION, callbacks.track())
|
await(back_out, top, screen, WAIT_FOR_TRANSITION, resume)
|
||||||
callbacks.yield_until_done()
|
|
||||||
top = stack[#stack]
|
top = stack[#stack]
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -889,13 +887,10 @@ function M.clear(cb)
|
|||||||
table.remove(stack)
|
table.remove(stack)
|
||||||
end
|
end
|
||||||
|
|
||||||
callbacks.when_done(function()
|
|
||||||
pcallfn(cb)
|
pcallfn(cb)
|
||||||
pcallfn(action_done)
|
pcallfn(action_done)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
assert(coroutine.resume(co))
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -907,6 +902,7 @@ function M.back(data, cb)
|
|||||||
|
|
||||||
queue_action(function(action_done)
|
queue_action(function(action_done)
|
||||||
local callbacks = callback_tracker()
|
local callbacks = callback_tracker()
|
||||||
|
local back_cb = callbacks.track()
|
||||||
local screen = table.remove(stack)
|
local screen = table.remove(stack)
|
||||||
if screen then
|
if screen then
|
||||||
log("back()", screen.id)
|
log("back()", screen.id)
|
||||||
@ -918,7 +914,7 @@ function M.back(data, cb)
|
|||||||
if data then
|
if data then
|
||||||
top.data = data
|
top.data = data
|
||||||
end
|
end
|
||||||
back_in(top, screen, WAIT_FOR_TRANSITION, callbacks.track())
|
back_in(top, screen, WAIT_FOR_TRANSITION, back_cb)
|
||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
if top then
|
if top then
|
||||||
@ -926,10 +922,10 @@ function M.back(data, cb)
|
|||||||
top.data = data
|
top.data = data
|
||||||
end
|
end
|
||||||
back_in(top, screen, DO_NOT_WAIT_FOR_TRANSITION, function()
|
back_in(top, screen, DO_NOT_WAIT_FOR_TRANSITION, function()
|
||||||
back_out(screen, top, WAIT_FOR_TRANSITION, callbacks.track())
|
back_out(screen, top, WAIT_FOR_TRANSITION, back_cb)
|
||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
back_out(screen, top, WAIT_FOR_TRANSITION, callbacks.track())
|
back_out(screen, top, WAIT_FOR_TRANSITION, back_cb)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
47
monarch/utils/async.lua
Normal file
47
monarch/utils/async.lua
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
local M = {}
|
||||||
|
|
||||||
|
local NOT_STARTED = "not_started"
|
||||||
|
local YIELDED = "yielded"
|
||||||
|
local RESUMED = "resumed"
|
||||||
|
local RUNNING = "running"
|
||||||
|
|
||||||
|
function M.async(fn)
|
||||||
|
local co = coroutine.running()
|
||||||
|
|
||||||
|
local state = NOT_STARTED
|
||||||
|
|
||||||
|
local function await(fn, ...)
|
||||||
|
state = RUNNING
|
||||||
|
fn(...)
|
||||||
|
if state ~= RUNNING then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
state = YIELDED
|
||||||
|
local r = { coroutine.yield() }
|
||||||
|
return unpack(r)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function resume(...)
|
||||||
|
if state ~= RUNNING then
|
||||||
|
state = RUNNING
|
||||||
|
local ok, err = coroutine.resume(co, ...)
|
||||||
|
if not ok then
|
||||||
|
print(err)
|
||||||
|
print(debug.traceback())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if co then
|
||||||
|
return fn(await, resume)
|
||||||
|
else
|
||||||
|
co = coroutine.create(fn)
|
||||||
|
return resume(await, resume)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return setmetatable(M, {
|
||||||
|
__call = function(t, ...)
|
||||||
|
return M.async(...)
|
||||||
|
end
|
||||||
|
})
|
@ -6,13 +6,18 @@ function M.create()
|
|||||||
|
|
||||||
local callback = nil
|
local callback = nil
|
||||||
local callback_count = 0
|
local callback_count = 0
|
||||||
|
local all_callbacks_done = false
|
||||||
|
|
||||||
local function is_done()
|
local function is_done()
|
||||||
return callback_count == 0
|
return callback_count == 0
|
||||||
end
|
end
|
||||||
|
|
||||||
local function invoke_if_done()
|
local function invoke_if_done()
|
||||||
|
if all_callbacks_done then
|
||||||
|
print("Warning: The same callback will be invoked twice from the callback tracker!", id or "")
|
||||||
|
end
|
||||||
if callback_count == 0 and callback then
|
if callback_count == 0 and callback then
|
||||||
|
all_callbacks_done = true
|
||||||
local ok, err = pcall(callback)
|
local ok, err = pcall(callback)
|
||||||
if not ok then print(err) end
|
if not ok then print(err) end
|
||||||
end
|
end
|
||||||
@ -41,20 +46,6 @@ function M.create()
|
|||||||
invoke_if_done()
|
invoke_if_done()
|
||||||
end
|
end
|
||||||
|
|
||||||
function instance.yield_until_done()
|
|
||||||
local co = coroutine.running()
|
|
||||||
callback = function()
|
|
||||||
local ok, err = coroutine.resume(co)
|
|
||||||
if not ok then
|
|
||||||
print(err)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
invoke_if_done()
|
|
||||||
if not is_done() then
|
|
||||||
coroutine.yield()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return instance
|
return instance
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user