mirror of
https://github.com/koreader/koreader.git
synced 2025-12-18 12:02:09 +01:00
Dict, Trapper: prevent dismissal by past events
Add UIManager:discardEvents(), to allow dropping events for a period of time. Default duration of 600ms on eInk, 300ms otherwise. Used when showing the dict result window, so that a tap happening just when it's being shown won't discard it. Used with Trapper:confirm()/:info(), to avoid taps made in a previous processing to dismiss (and so, select the cancel action) a ConfirmBox not yet painted/visible.
This commit is contained in:
@@ -889,6 +889,12 @@ function ReaderDictionary:showDict(word, results, box, link)
|
||||
self:dismissLookupInfo()
|
||||
if results and results[1] then
|
||||
UIManager:show(self.dict_window)
|
||||
if not results[1].lookup_cancelled then
|
||||
-- Discard queued and coming up events to avoid accidental
|
||||
-- dismissal (but not if lookup interrupted, so 2 quick
|
||||
-- taps can discard everything)
|
||||
UIManager:discardEvents(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -165,6 +165,9 @@ function Trapper:info(text, fast_refresh)
|
||||
ok_callback = function()
|
||||
coroutine.resume(_coroutine, false)
|
||||
end,
|
||||
-- flush any pending tap, so past events won't be considered
|
||||
-- action on the yet to be displayed widget
|
||||
flush_events_on_show = true,
|
||||
}
|
||||
UIManager:show(abort_box)
|
||||
-- no need to forceRePaint, UIManager will do it when we yield()
|
||||
@@ -186,10 +189,6 @@ function Trapper:info(text, fast_refresh)
|
||||
-- continue processing
|
||||
end
|
||||
|
||||
--- @todo We should try to flush any pending tap, so past
|
||||
-- events won't be considered action on the yet to be displayed
|
||||
-- widget
|
||||
|
||||
-- If fast_refresh option, avoid UIManager refresh overhead
|
||||
if fast_refresh and self.current_widget and self.current_widget.is_infomessage then
|
||||
local orig_moved_offset = self.current_widget.movable:getMovedOffset()
|
||||
@@ -214,7 +213,10 @@ function Trapper:info(text, fast_refresh)
|
||||
dismiss_callback = function()
|
||||
coroutine.resume(_coroutine, false)
|
||||
end,
|
||||
is_infomessage = true -- flag on our InfoMessages
|
||||
is_infomessage = true, -- flag on our InfoMessages
|
||||
-- flush any pending tap, so past events won't be considered
|
||||
-- action on the yet to be displayed widget
|
||||
flush_events_on_show = true,
|
||||
}
|
||||
logger.dbg("Showing InfoMessage:", text)
|
||||
UIManager:show(self.current_widget)
|
||||
@@ -268,10 +270,6 @@ function Trapper:confirm(text, cancel_text, ok_text)
|
||||
return true -- always select "OK" in ConfirmBox if no UI
|
||||
end
|
||||
|
||||
--- @todo We should try to flush any pending tap, so past
|
||||
-- events won't be considered action on the yet to be displayed
|
||||
-- widget
|
||||
|
||||
-- Close any previous widget
|
||||
if self.current_widget then
|
||||
UIManager:close(self.current_widget)
|
||||
@@ -289,6 +287,9 @@ function Trapper:confirm(text, cancel_text, ok_text)
|
||||
ok_callback = function()
|
||||
coroutine.resume(_coroutine, true)
|
||||
end,
|
||||
-- flush any pending tap, so past events won't be considered
|
||||
-- action on the yet to be displayed widget
|
||||
flush_events_on_show = true,
|
||||
}
|
||||
logger.dbg("Showing ConfirmBox and waiting for answer:", text)
|
||||
UIManager:show(self.current_widget)
|
||||
|
||||
@@ -39,6 +39,7 @@ local UIManager = {
|
||||
_exit_code = nil,
|
||||
_prevent_standby_count = 0,
|
||||
_prev_prevent_standby_count = 0,
|
||||
_discard_events_till = nil,
|
||||
|
||||
event_hook = require("ui/hook_container"):new()
|
||||
}
|
||||
@@ -797,10 +798,48 @@ function UIManager:quit()
|
||||
end
|
||||
end
|
||||
|
||||
--- Request events to be ignored for some duration
|
||||
function UIManager:discardEvents(set_or_seconds)
|
||||
if not set_or_seconds then -- remove any previously set
|
||||
self._discard_events_till = nil
|
||||
return
|
||||
end
|
||||
local usecs
|
||||
if set_or_seconds == true then
|
||||
-- Use an adequate delay to account for device refresh duration
|
||||
-- so any events happening in this delay (ie. before a widget
|
||||
-- is really painted on screen) are discarded.
|
||||
if Device:hasEinkScreen() then
|
||||
-- A screen refresh can take a few 100ms,
|
||||
-- sometimes > 500ms on some devices/temperatures
|
||||
usecs = 600000
|
||||
else
|
||||
-- On non-eInk screen, it's usually instantaneous
|
||||
usecs = 300000
|
||||
end
|
||||
else -- we expect a number
|
||||
usecs = set_or_seconds * MILLION
|
||||
end
|
||||
local now = { util.gettime() }
|
||||
local now_us = now[1] * MILLION + now[2]
|
||||
self._discard_events_till = now_us + usecs
|
||||
end
|
||||
|
||||
--- Transmits an event to an active widget.
|
||||
function UIManager:sendEvent(event)
|
||||
if #self._window_stack == 0 then return end
|
||||
|
||||
-- Ensure discardEvents
|
||||
if self._discard_events_till then
|
||||
local now = { util.gettime() }
|
||||
local now_us = now[1] * MILLION + now[2]
|
||||
if now_us < self._discard_events_till then
|
||||
return
|
||||
else
|
||||
self._discard_events_till = nil
|
||||
end
|
||||
end
|
||||
|
||||
local top_widget = self._window_stack[#self._window_stack]
|
||||
-- top level widget has first access to the event
|
||||
if top_widget.widget:handleEvent(event) then
|
||||
|
||||
@@ -51,6 +51,8 @@ local ConfirmBox = InputContainer:new{
|
||||
margin = Size.margin.default,
|
||||
padding = Size.padding.default,
|
||||
dismissable = true, -- set to false if any button callback is required
|
||||
flush_events_on_show = false, -- set to true when it might be displayed after
|
||||
-- some processing, to avoid accidental dismissal
|
||||
}
|
||||
|
||||
function ConfirmBox:init()
|
||||
@@ -182,6 +184,10 @@ function ConfirmBox:onShow()
|
||||
UIManager:setDirty(self, function()
|
||||
return "ui", self[1][1].dimen
|
||||
end)
|
||||
if self.flush_events_on_show then
|
||||
-- Discard queued and coming up events to avoid accidental dismissal
|
||||
UIManager:discardEvents(true)
|
||||
end
|
||||
end
|
||||
|
||||
function ConfirmBox:onCloseWidget()
|
||||
|
||||
@@ -69,6 +69,8 @@ local InfoMessage = InputContainer:new{
|
||||
no_refresh_on_close = nil,
|
||||
-- Only have it painted after this delay (dismissing still works before it's shown)
|
||||
show_delay = nil,
|
||||
-- Set to true when it might be displayed after some processing, to avoid accidental dismissal
|
||||
flush_events_on_show = false,
|
||||
}
|
||||
|
||||
function InfoMessage:init()
|
||||
@@ -224,6 +226,10 @@ function InfoMessage:onShow()
|
||||
UIManager:setDirty(self, function()
|
||||
return "ui", self[1][1].dimen
|
||||
end)
|
||||
if self.flush_events_on_show then
|
||||
-- Discard queued and coming up events to avoid accidental dismissal
|
||||
UIManager:discardEvents(true)
|
||||
end
|
||||
-- schedule us to close ourself if timeout provided
|
||||
if self.timeout then
|
||||
UIManager:scheduleIn(self.timeout, function() UIManager:close(self) end)
|
||||
|
||||
Reference in New Issue
Block a user