2
0
mirror of https://github.com/koreader/koreader synced 2024-11-02 15:40:16 +00:00
koreader/plugins/autoturn.koplugin/main.lua
zwim 4dbaca180a
PM: Optimize task queue handling around standby (#10203)
Instead of firing on(Enter|Leave)Standby Events, and having every other piece of code that might care about that handle re-scheduling their stuff themselves; simply make the standby implementation (i.e., AutoSuspend's) shift the whole task queue by the amount of time spent in standby to re-sync everything automatically.

(This is necessary in the first place because Linux, as the task queue ticks in CLOCK_MONOTONIC, which does *not* tick during suspend/standby; while we expect most of the tasks scheduled to actually reflect real world clock delays).
2023-04-05 20:54:47 +02:00

199 lines
7.0 KiB
Lua

local Event = require("ui/event")
local PluginShare = require("pluginshare")
local UIManager = require("ui/uimanager")
local WidgetContainer = require("ui/widget/container/widgetcontainer")
local datetime = require("datetime")
local logger = require("logger")
local time = require("ui/time")
local _ = require("gettext")
local T = require("ffi/util").template
local AutoTurn = WidgetContainer:extend{
name = "autoturn",
is_doc_only = true,
autoturn_sec = 0,
autoturn_distance = 1,
enabled = false,
last_action_time = 0,
task = nil,
}
function AutoTurn:_enabled()
return self.enabled and self.autoturn_sec > 0
end
function AutoTurn:_schedule()
if not self:_enabled() then
logger.dbg("AutoTurn:_schedule is disabled")
return
end
local delay = self.last_action_time + time.s(self.autoturn_sec) - UIManager:getElapsedTimeSinceBoot()
if delay <= 0 then
local top_wg = UIManager:getTopmostVisibleWidget() or {}
if top_wg.name == "ReaderUI" then
logger.dbg("AutoTurn: go to next page")
self.ui:handleEvent(Event:new("GotoViewRel", self.autoturn_distance))
self.last_action_time = UIManager:getElapsedTimeSinceBoot()
end
logger.dbg("AutoTurn: schedule in", self.autoturn_sec)
UIManager:scheduleIn(self.autoturn_sec, self.task)
self.scheduled = true
else
local delay_s = time.to_number(delay)
logger.dbg("AutoTurn: schedule in", delay_s, "s")
UIManager:scheduleIn(delay_s, self.task)
self.scheduled = true
end
end
function AutoTurn:_unschedule()
PluginShare.pause_auto_suspend = false
if self.scheduled then
logger.dbg("AutoTurn: unschedule")
UIManager:unschedule(self.task)
self.scheduled = false
end
end
function AutoTurn:_start()
if self:_enabled() then
local time_since_boot = UIManager:getElapsedTimeSinceBoot()
logger.dbg("AutoTurn: start at", time.format_time(time_since_boot))
PluginShare.pause_auto_suspend = true
self.last_action_time = time_since_boot
self:_schedule()
local text
if self.autoturn_distance == 1 then
local time_string = datetime.secondsToClockDuration("letters", self.autoturn_sec, false, true, true)
text = T(_("Autoturn is now active and will automatically turn the page every %1."), time_string)
else
text = T(_("Autoturn is now active and will automatically scroll %1 % of the page every %2 seconds."),
self.autoturn_distance * 100,
self.autoturn_sec)
end
local InfoMessage = require("ui/widget/infomessage")
UIManager:show(InfoMessage:new{
text = text,
timeout = 3,
})
end
end
function AutoTurn:init()
UIManager.event_hook:registerWidget("InputEvent", self)
self.autoturn_sec = G_reader_settings:readSetting("autoturn_timeout_seconds", 0)
self.autoturn_distance = G_reader_settings:readSetting("autoturn_distance", 1)
self.enabled = G_reader_settings:isTrue("autoturn_enabled")
self.ui.menu:registerToMainMenu(self)
self.task = function()
self:_schedule()
end
self:_start()
end
function AutoTurn:onCloseWidget()
logger.dbg("AutoTurn: onCloseWidget")
self:_unschedule()
self.task = nil
end
function AutoTurn:onCloseDocument()
logger.dbg("AutoTurn: onCloseDocument")
self:_unschedule()
end
function AutoTurn:onInputEvent()
logger.dbg("AutoTurn: onInputEvent")
self.last_action_time = UIManager:getElapsedTimeSinceBoot()
end
-- We do not want autoturn to turn pages during the suspend process.
-- Unschedule it and restart after resume.
function AutoTurn:onSuspend()
logger.dbg("AutoTurn: onSuspend")
self:_unschedule()
end
function AutoTurn:_onResume()
logger.dbg("AutoTurn: onResume")
self:_start()
end
function AutoTurn:addToMainMenu(menu_items)
menu_items.autoturn = {
sorting_hint = "navi",
text_func = function()
local time_string = datetime.secondsToClockDuration("letters", self.autoturn_sec, false, true, true)
return self:_enabled() and T(_("Autoturn: %1"), time_string) or _("Autoturn")
end,
checked_func = function() return self:_enabled() end,
callback = function(menu)
local DateTimeWidget = require("ui/widget/datetimewidget")
local autoturn_seconds = G_reader_settings:readSetting("autoturn_timeout_seconds", 30)
local autoturn_minutes = math.floor(autoturn_seconds * (1/60))
autoturn_seconds = autoturn_seconds % 60
local autoturn_spin = DateTimeWidget:new {
title_text = _("Autoturn time"),
info_text = _("Enter time in minutes and seconds."),
min = autoturn_minutes,
min_max = 60 * 24, -- maximum one day
min_default = 0,
sec = autoturn_seconds,
sec_default = 30,
keep_shown_on_apply = true,
ok_text = _("Set timeout"),
cancel_text = _("Disable"),
cancel_callback = function()
self.enabled = false
G_reader_settings:makeFalse("autoturn_enabled")
self:_unschedule()
menu:updateItems()
self.onResume = nil
end,
ok_always_enabled = true,
callback = function(t)
self.autoturn_sec = t.min * 60 + t.sec
G_reader_settings:saveSetting("autoturn_timeout_seconds", self.autoturn_sec)
self.enabled = true
G_reader_settings:makeTrue("autoturn_enabled")
self:_unschedule()
self:_start()
menu:updateItems()
self.onResume = self._onResume
end,
}
UIManager:show(autoturn_spin)
end,
hold_callback = function(menu)
local SpinWidget = require("ui/widget/spinwidget")
local curr_items = G_reader_settings:readSetting("autoturn_distance") or 1
local autoturn_spin = SpinWidget:new {
value = curr_items,
value_min = -20,
value_max = 20,
precision = "%.2f",
value_step = .1,
value_hold_step = .5,
ok_text = _("Set distance"),
title_text = _("Scrolling distance"),
callback = function(autoturn_spin)
self.autoturn_distance = autoturn_spin.value
G_reader_settings:saveSetting("autoturn_distance", autoturn_spin.value)
if self.enabled then
self:_unschedule()
self:_start()
end
menu:updateItems()
end,
}
UIManager:show(autoturn_spin)
end,
}
end
return AutoTurn