UIManager: Don't block gestures for new widgets when input is disabled (#11122)

They'll be disabled again when the widget in question is dismissed.

This exposes a couple of semi-obvious but edge-casey footguns to the user, but a hardened implementation is way uglier. See PR for details.
reviewable/pr11148/r1
NiLuJe 6 months ago committed by GitHub
parent f92c0eae3b
commit bc7ea8602e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -355,4 +355,10 @@ function DeviceListener:onFullRefresh()
UIManager:setDirty(nil, "full") UIManager:setDirty(nil, "full")
end end
-- On resume, make sure we restore Gestures handling in InputContainer, to avoid confusion for scatter-brained users ;).
-- It's also helpful when the IgnoreTouchInput event is emitted by Dispatcher through other means than Gestures.
function DeviceListener:onResume()
UIManager:setIgnoreTouchInput(false)
end
return DeviceListener return DeviceListener

@ -753,6 +753,9 @@ function Screensaver:show()
widget = addOverlayMessage(widget, message_height, self.overlay_message) widget = addOverlayMessage(widget, message_height, self.overlay_message)
end end
-- NOTE: Make sure InputContainer gestures are not disabled, to prevent stupid interactions with UIManager on close.
UIManager:setIgnoreTouchInput(false)
if widget then if widget then
self.screensaver_widget = ScreenSaverWidget:new{ self.screensaver_widget = ScreenSaverWidget:new{
widget = widget, widget = widget,

@ -42,6 +42,7 @@ local UIManager = {
_gated_quit = nil, _gated_quit = nil,
_prevent_standby_count = 0, _prevent_standby_count = 0,
_prev_prevent_standby_count = 0, _prev_prevent_standby_count = 0,
_input_gestures_disabled = false,
event_hook = require("ui/hook_container"):new() event_hook = require("ui/hook_container"):new()
} }
@ -113,6 +114,12 @@ function UIManager:init()
self:unsetRunForeverMode() self:unsetRunForeverMode()
end end
-- Crappy wrapper because of circular dependencies
function UIManager:setIgnoreTouchInput(state)
local InputContainer = require("ui/widget/container/inputcontainer")
InputContainer:setIgnoreTouchInput(state)
end
--[[-- --[[--
Registers and shows a widget. Registers and shows a widget.
@ -165,6 +172,13 @@ function UIManager:show(widget, refreshtype, refreshregion, x, y, refreshdither)
Input.disable_double_tap = widget.disable_double_tap ~= false Input.disable_double_tap = widget.disable_double_tap ~= false
-- a widget may override tap interval (when it doesn't, nil restores the default) -- a widget may override tap interval (when it doesn't, nil restores the default)
Input.tap_interval_override = widget.tap_interval_override Input.tap_interval_override = widget.tap_interval_override
-- If input was disabled, re-enable it while this widget is shown so we can actually interact with it.
-- The only thing that could actually call show in this state is something automatic, so we need to be able to deal with it.
if UIManager._input_gestures_disabled then
logger.dbg("Gestures were disabled, temporarily re-enabling them to allow interaction with widget")
self:setIgnoreTouchInput(false)
widget._restored_input_gestures = true
end
end end
--[[-- --[[--
@ -245,6 +259,10 @@ function UIManager:close(widget, refreshtype, refreshregion, refreshdither)
end end
self:_refresh(refreshtype, refreshregion, refreshdither) self:_refresh(refreshtype, refreshregion, refreshdither)
end end
if widget._restored_input_gestures then
logger.dbg("Widget is gone, disabling gesture handling again")
self:setIgnoreTouchInput(true)
end
end end
--- Shift the execution times of all scheduled tasks. --- Shift the execution times of all scheduled tasks.

@ -41,6 +41,7 @@ local Geom = require("ui/geometry")
local GestureRange = require("ui/gesturerange") local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager") local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer") local WidgetContainer = require("ui/widget/container/widgetcontainer")
local logger = require("logger")
local Screen = Device.screen local Screen = Device.screen
local _ = require("gettext") local _ = require("gettext")
@ -304,41 +305,56 @@ end
-- [1] The most common implementation you'll see is a NOP for ReaderUI modules that defer gesture handling to ReaderUI. -- [1] The most common implementation you'll see is a NOP for ReaderUI modules that defer gesture handling to ReaderUI.
-- Notification also implements a simple one to dismiss notifications on any user input, -- Notification also implements a simple one to dismiss notifications on any user input,
-- which is something that doesn't impede our goal, which is why we don't need to deal with it. -- which is something that doesn't impede our goal, which is why we don't need to deal with it.
function InputContainer:onIgnoreTouchInput(toggle) function InputContainer:setIgnoreTouchInput(state)
local Notification = require("ui/widget/notification") logger.dbg("InputContainer:setIgnoreTouchInput", state)
if toggle == false then if state == true then
-- Replace the onGesture handler w/ the minimal one if that's not already the case
if not InputContainer._onGesture then
InputContainer._onGesture = InputContainer.onGesture
InputContainer.onGesture = InputContainer._onGestureFiltered
-- Notify UIManager so it knows what to do if a random popup shows up
UIManager._input_gestures_disabled = true
logger.dbg("Disabled InputContainer gesture handler")
-- Notify our caller that the state changed
return true
end
elseif state == false then
-- Restore the proper onGesture handler if we disabled it -- Restore the proper onGesture handler if we disabled it
if InputContainer._onGesture then if InputContainer._onGesture then
InputContainer.onGesture = InputContainer._onGesture InputContainer.onGesture = InputContainer._onGesture
InputContainer._onGesture = nil InputContainer._onGesture = nil
Notification:notify("Restored touch input") UIManager._input_gestures_disabled = false
logger.dbg("Restored InputContainer gesture handler")
return true
end end
elseif toggle == true then end
-- Replace the onGesture handler w/ the minimal one if that's not already the case
if not InputContainer._onGesture then -- We did not actually change the state
InputContainer._onGesture = InputContainer.onGesture return false
InputContainer.onGesture = InputContainer._onGestureFiltered end
Notification:notify("Disabled touch input")
-- And the matching Event handler
function InputContainer:onIgnoreTouchInput(toggle)
local Notification = require("ui/widget/notification")
if toggle == true then
if self:setIgnoreTouchInput(true) then
Notification:notify(_("Disabled touch input"))
end
elseif toggle == false then
if self:setIgnoreTouchInput(false) then
Notification:notify(_("Restored touch input"))
end end
else else
-- Toggle the current state -- Toggle the current state
if InputContainer._onGesture then return self:onIgnoreTouchInput(not UIManager._input_gestures_disabled)
return self:onIgnoreTouchInput(false)
else
return self:onIgnoreTouchInput(true)
end
end end
-- We only affect the base class, once is enough ;). -- We only affect the base class, once is enough ;).
return true return true
end end
function InputContainer:onResume()
-- Always restore touch input on resume, to avoid confusion for scatter-brained users ;).
-- It's also helpful when the IgnoreTouchInput event is emitted by Dispatcher through other means than Gestures.
self:onIgnoreTouchInput(false)
end
function InputContainer:onInput(input, ignore_first_hold_release) function InputContainer:onInput(input, ignore_first_hold_release)
local InputDialog = require("ui/widget/inputdialog") local InputDialog = require("ui/widget/inputdialog")
self.input_dialog = InputDialog:new{ self.input_dialog = InputDialog:new{

Loading…
Cancel
Save