mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
TouchMenu: added options to menu items with the following defaults:
keep_menu_open = false
hold_keep_menu_open = true
So, default for Tap callback is to close menu, and for Hold callback
to keep menu open.
In both cases, provide the TouchMenu instance as the 1st argument to
the callback functions (instead of a refresh_menu_func I added in #3941)
so the callback can do more things, like closing, refreshing,
changing menu items text and re-ordering...
ReaderZooming: show symbol for default (like it was done for
ReaderFont, ReaderHyphenation...)
TextEditor plugin: update the previously opened files list in real
time, so the menu can be kept open and used as the TextEditor main
interface.
SSH plugin: keep menu open and update the Start/Stop state in real time
ReadTimer plugin: tried to do what feels right (but I don't use it)
Also remove forgotten cp in the move/paste file code
329 lines
9.0 KiB
Lua
329 lines
9.0 KiB
Lua
|
|
local DataStorage = require("datastorage")
|
|
local KeyValuePage = require("ui/widget/keyvaluepage")
|
|
local LuaSettings = require("luasettings")
|
|
local PowerD = require("device"):getPowerDevice()
|
|
local UIManager = require("ui/uimanager")
|
|
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
|
local T = require("ffi/util").template
|
|
local dbg = require("dbg")
|
|
local logger = require("logger")
|
|
local util = require("ffi/util")
|
|
local _ = require("gettext")
|
|
|
|
local State = {}
|
|
|
|
function State:new(o)
|
|
o = o or {}
|
|
setmetatable(o, self)
|
|
self.__index = self
|
|
if o.percentage == nil or o.timestamp == nil then
|
|
o.percentage = PowerD:getCapacityHW()
|
|
o.timestamp = os.time()
|
|
end
|
|
return o
|
|
end
|
|
|
|
function State:toString()
|
|
return string.format("{%d @ %s}", self.percentage, os.date("%c", self.timestamp))
|
|
end
|
|
|
|
local Usage = {}
|
|
|
|
function Usage:new(o)
|
|
o = o or {}
|
|
setmetatable(o, self)
|
|
self.__index = self
|
|
if o.percentage == nil or o.time == nil then
|
|
o.percentage = 0
|
|
o.time = 0
|
|
end
|
|
return o
|
|
end
|
|
|
|
function Usage:append(state)
|
|
local curr = State:new()
|
|
self.percentage = self.percentage + (state.percentage - curr.percentage)
|
|
self.time = self.time + os.difftime(curr.timestamp - state.timestamp)
|
|
end
|
|
|
|
function Usage:minutes()
|
|
return self.time / 60
|
|
end
|
|
|
|
function Usage:hours()
|
|
return self:minutes() / 60
|
|
end
|
|
|
|
function Usage:percentagePerHour()
|
|
if self.time == 0 then
|
|
return 0
|
|
else
|
|
return self.percentage / self:hours()
|
|
end
|
|
end
|
|
|
|
function Usage:remainingHours()
|
|
local curr = State:new()
|
|
return curr.percentage / self:percentagePerHour()
|
|
end
|
|
|
|
function Usage:chargingHours()
|
|
local curr = State:new()
|
|
return (curr.percentage - 100) / self:percentagePerHour()
|
|
end
|
|
|
|
local function shorten(number)
|
|
return string.format("%.2f", number);
|
|
end
|
|
|
|
function Usage:dump(kv_pairs)
|
|
table.insert(kv_pairs, {_(" Consumed %"), shorten(self.percentage)})
|
|
table.insert(kv_pairs, {_(" Total minutes"), shorten(self:minutes())})
|
|
table.insert(kv_pairs, {_(" % per hour"), shorten(self:percentagePerHour())})
|
|
end
|
|
|
|
function Usage:dumpRemaining(kv_pairs)
|
|
table.insert(kv_pairs, {_(" Estimated remaining hours"), shorten(self:remainingHours())})
|
|
end
|
|
|
|
function Usage:dumpCharging(kv_pairs)
|
|
table.insert(kv_pairs, {_(" Estimated hours for charging"), shorten(self:chargingHours())})
|
|
end
|
|
|
|
local BatteryStat = {
|
|
settings = LuaSettings:open(DataStorage:getSettingsDir() .. "/batterstat.lua"),
|
|
dump_file = util.realpath(DataStorage:getDataDir()) .. "/batterystat.log",
|
|
debugging = false,
|
|
kv_page = nil,
|
|
}
|
|
|
|
function BatteryStat:init()
|
|
self.charging = Usage:new(self.settings:readSetting("charging"))
|
|
self.discharging = Usage:new(self.settings:readSetting("discharging"))
|
|
self.awake = Usage:new(self.settings:readSetting("awake"))
|
|
self.sleeping = Usage:new(self.settings:readSetting("sleeping"))
|
|
|
|
-- Note: these fields are not the "real" timestamp and battery usage, but
|
|
-- the unaccumulated values.
|
|
self.charging_state = State:new(self.settings:readSetting("charging_state"))
|
|
self.awake_state = State:new(self.settings:readSetting("awake_state"))
|
|
-- Whether the device was suspending before current timestamp.
|
|
self.was_suspending = false
|
|
-- Whether the device was charging before current timestamp.
|
|
self.was_charging = PowerD:isCharging()
|
|
|
|
if self.debugging then
|
|
self.debugOutput = self._debugOutput
|
|
else
|
|
self.debugOutput = function() end
|
|
end
|
|
end
|
|
|
|
function BatteryStat:onFlushSettings()
|
|
self.settings:reset({
|
|
charging = self.charging,
|
|
discharging = self.discharging,
|
|
awake = self.awake,
|
|
sleeping = self.sleeping,
|
|
charging_state = self.charging_state,
|
|
awake_state = self.awake_state,
|
|
})
|
|
self.settings:flush()
|
|
end
|
|
|
|
function BatteryStat:accumulate()
|
|
if self.was_suspending then
|
|
-- Suspending to awake.
|
|
self.sleeping:append(self.awake_state)
|
|
else
|
|
-- Awake to suspending, time between self.awake_state and now should belong to awake.
|
|
self.awake:append(self.awake_state)
|
|
end
|
|
if self.was_charging then
|
|
-- Decharging to charging.
|
|
self.charging:append(self.charging_state)
|
|
else
|
|
self.discharging:append(self.charging_state)
|
|
end
|
|
self.awake_state = State:new()
|
|
self.charging_state = State:new()
|
|
end
|
|
|
|
function BatteryStat:dumpOrLog(content)
|
|
local file = io.open(self.dump_file, "a")
|
|
if file then
|
|
file:write(content .. "\n")
|
|
file:close()
|
|
else
|
|
logger.warn("Failed to dump output ", content, " into ", self.dump_file )
|
|
end
|
|
end
|
|
|
|
function BatteryStat:_debugOutput(event)
|
|
self:dumpOrLog(event .. " @ " .. State:new():toString() ..
|
|
", awake_state " .. self.awake_state:toString() ..
|
|
", charging_state " .. self.charging_state:toString())
|
|
end
|
|
|
|
function BatteryStat:onSuspend()
|
|
self:debugOutput("onSuspend")
|
|
if not self.was_suspending then
|
|
self:accumulate()
|
|
end
|
|
self.was_suspending = true
|
|
end
|
|
|
|
function BatteryStat:onResume()
|
|
self:debugOutput("onResume")
|
|
if self.was_suspending then
|
|
self:accumulate()
|
|
end
|
|
self.was_suspending = false
|
|
end
|
|
|
|
function BatteryStat:onCharging()
|
|
self:debugOutput("onCharging")
|
|
if not self.was_charging then
|
|
self:reset(true, false)
|
|
self:accumulate()
|
|
end
|
|
self.was_charging = true
|
|
end
|
|
|
|
function BatteryStat:onNotCharging()
|
|
self:debugOutput("onNotCharging")
|
|
if self.was_charging then
|
|
self:reset(false, true)
|
|
self:accumulate()
|
|
end
|
|
self.was_charging = false
|
|
end
|
|
|
|
function BatteryStat:showStatistics()
|
|
self:accumulate()
|
|
local kv_pairs = self:dump()
|
|
table.insert(kv_pairs, "----------")
|
|
table.insert(kv_pairs, {_("Historical records are dumped to"), ""})
|
|
table.insert(kv_pairs, {self.dump_file, ""})
|
|
table.insert(kv_pairs, "----------")
|
|
table.insert(kv_pairs, {_("If you would like to reset the data,"), "",
|
|
callback = function()
|
|
self:resetAll()
|
|
self:restart()
|
|
end})
|
|
table.insert(kv_pairs, {_("please tap here."), "",
|
|
callback = function()
|
|
self:resetAll()
|
|
self:restart()
|
|
end})
|
|
self.kv_page = KeyValuePage:new{
|
|
title = _("Battery statistics"),
|
|
kv_pairs = kv_pairs,
|
|
}
|
|
UIManager:show(self.kv_page)
|
|
end
|
|
|
|
function BatteryStat:reset(withCharging, withDischarging)
|
|
self:dumpToText()
|
|
self.awake = Usage:new()
|
|
self.sleeping = Usage:new()
|
|
|
|
if withCharging then
|
|
self.charging = Usage:new()
|
|
end
|
|
if withDischarging then
|
|
self.discharging = Usage:new()
|
|
end
|
|
end
|
|
|
|
function BatteryStat:resetAll()
|
|
self:reset(true, true)
|
|
self.charging_state = State:new()
|
|
self.awake_state = State:new()
|
|
end
|
|
|
|
function BatteryStat:restart()
|
|
dbg.dassert(self.kv_page ~= nil)
|
|
UIManager:close(self.kv_page)
|
|
self:showStatistics()
|
|
end
|
|
|
|
function BatteryStat:dumpToText()
|
|
local kv_pairs = self:dump()
|
|
local content = T(_("Dump at %1"), os.date("%c"))
|
|
for _, pair in ipairs(kv_pairs) do
|
|
content = content .. "\n" .. pair[1]
|
|
if pair[2] ~= nil and pair[2] ~= "" then
|
|
content = content .. "\t" .. pair[2]
|
|
end
|
|
end
|
|
self:dumpOrLog(content .. "\n-=-=-=-=-=-\n")
|
|
end
|
|
|
|
function BatteryStat:dump()
|
|
local kv_pairs = {}
|
|
table.insert(kv_pairs, {_("Awake since last charge"), ""})
|
|
self.awake:dump(kv_pairs)
|
|
self.awake:dumpRemaining(kv_pairs)
|
|
table.insert(kv_pairs, {_("Sleeping since last charge"), ""})
|
|
self.sleeping:dump(kv_pairs)
|
|
self.sleeping:dumpRemaining(kv_pairs)
|
|
table.insert(kv_pairs, {_("During last charge"), ""})
|
|
self.charging:dump(kv_pairs)
|
|
self.charging:dumpCharging(kv_pairs)
|
|
table.insert(kv_pairs, {_("Since last charge"), ""})
|
|
self.discharging:dump(kv_pairs)
|
|
self.discharging:dumpRemaining(kv_pairs)
|
|
return kv_pairs
|
|
end
|
|
|
|
BatteryStat:init()
|
|
|
|
local BatteryStatWidget = WidgetContainer:new{
|
|
name = "batterystat",
|
|
}
|
|
|
|
function BatteryStatWidget:init()
|
|
-- self.ui is nil in test cases.
|
|
if not self.ui or not self.ui.menu then return end
|
|
self.ui.menu:registerToMainMenu(self)
|
|
end
|
|
|
|
function BatteryStatWidget:addToMainMenu(menu_items)
|
|
menu_items.battery_statistics = {
|
|
text = _("Battery statistics"),
|
|
keep_menu_open = true,
|
|
callback = function()
|
|
BatteryStat:showStatistics()
|
|
end,
|
|
}
|
|
end
|
|
|
|
function BatteryStatWidget:onFlushSettings()
|
|
BatteryStat:onFlushSettings()
|
|
end
|
|
|
|
function BatteryStatWidget:onSuspend()
|
|
BatteryStat:onSuspend()
|
|
end
|
|
|
|
function BatteryStatWidget:onResume()
|
|
BatteryStat:onResume()
|
|
end
|
|
|
|
function BatteryStatWidget:onCharging()
|
|
BatteryStat:onCharging()
|
|
end
|
|
|
|
function BatteryStatWidget:onNotCharging()
|
|
BatteryStat:onNotCharging()
|
|
end
|
|
|
|
-- Test only
|
|
function BatteryStatWidget:stat()
|
|
return BatteryStat
|
|
end
|
|
|
|
return BatteryStatWidget
|