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 5 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")
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

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

@ -42,6 +42,7 @@ local UIManager = {
_gated_quit = nil,
_prevent_standby_count = 0,
_prev_prevent_standby_count = 0,
_input_gestures_disabled = false,
event_hook = require("ui/hook_container"):new()
}
@ -113,6 +114,12 @@ function UIManager:init()
self:unsetRunForeverMode()
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.
@ -165,6 +172,13 @@ function UIManager:show(widget, refreshtype, refreshregion, x, y, refreshdither)
Input.disable_double_tap = widget.disable_double_tap ~= false
-- a widget may override tap interval (when it doesn't, nil restores the default)
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
--[[--
@ -245,6 +259,10 @@ function UIManager:close(widget, refreshtype, refreshregion, refreshdither)
end
self:_refresh(refreshtype, refreshregion, refreshdither)
end
if widget._restored_input_gestures then
logger.dbg("Widget is gone, disabling gesture handling again")
self:setIgnoreTouchInput(true)
end
end
--- Shift the execution times of all scheduled tasks.

@ -41,6 +41,7 @@ local Geom = require("ui/geometry")
local GestureRange = require("ui/gesturerange")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local logger = require("logger")
local Screen = Device.screen
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.
-- 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.
function InputContainer:onIgnoreTouchInput(toggle)
local Notification = require("ui/widget/notification")
if toggle == false then
function InputContainer:setIgnoreTouchInput(state)
logger.dbg("InputContainer:setIgnoreTouchInput", state)
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
if InputContainer._onGesture then
InputContainer.onGesture = InputContainer._onGesture
InputContainer._onGesture = nil
Notification:notify("Restored touch input")
UIManager._input_gestures_disabled = false
logger.dbg("Restored InputContainer gesture handler")
return true
end
elseif toggle == 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
Notification:notify("Disabled touch input")
end
-- We did not actually change the state
return false
end
-- 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
else
-- Toggle the current state
if InputContainer._onGesture then
return self:onIgnoreTouchInput(false)
else
return self:onIgnoreTouchInput(true)
end
return self:onIgnoreTouchInput(not UIManager._input_gestures_disabled)
end
-- We only affect the base class, once is enough ;).
return true
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)
local InputDialog = require("ui/widget/inputdialog")
self.input_dialog = InputDialog:new{

Loading…
Cancel
Save