diff --git a/plugins/batterystat.koplugin/main.lua b/plugins/batterystat.koplugin/main.lua index 8f92a6679..8523ed1e2 100644 --- a/plugins/batterystat.koplugin/main.lua +++ b/plugins/batterystat.koplugin/main.lua @@ -1,14 +1,12 @@ - +local ConfirmBox = require("ui/widget/confirmbox") 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 util = require("util") local _ = require("gettext") local State = {} @@ -29,6 +27,7 @@ function State:toString() end local Usage = {} +local INDENTATION = " " -- Three spaces. function Usage:new(o) o = o or {} @@ -43,7 +42,7 @@ end function Usage:append(state) local curr = State:new() - self.percentage = self.percentage + (state.percentage - curr.percentage) + self.percentage = self.percentage + math.abs(state.percentage - curr.percentage) self.time = self.time + os.difftime(curr.timestamp - state.timestamp) end @@ -64,59 +63,64 @@ function Usage:percentagePerHour() end function Usage:remainingHours() + if self:percentagePerHour() == 0 then return "n/a" end local curr = State:new() return curr.percentage / self:percentagePerHour() end function Usage:chargingHours() + if self:percentagePerHour() == 0 then return "n/a" end local curr = State:new() - return (curr.percentage - 100) / self:percentagePerHour() + return math.abs(curr.percentage - 100) / self:percentagePerHour() end local function shorten(number) + if number == "n/a" then return _("n/a") end 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())}) + table.insert(kv_pairs, {INDENTATION .. _("Consumed %"), shorten(self.percentage)}) + table.insert(kv_pairs, {INDENTATION .. _("Total time"), util.secondsToHClock(self.time, true, true)}) + table.insert(kv_pairs, {INDENTATION .. _("% per hour"), shorten(self:percentagePerHour())}) end function Usage:dumpRemaining(kv_pairs) - table.insert(kv_pairs, {_(" Estimated remaining hours"), shorten(self:remainingHours())}) + table.insert(kv_pairs, {INDENTATION .. _("Estimated remaining hours"), shorten(self:remainingHours())}) end function Usage:dumpCharging(kv_pairs) - table.insert(kv_pairs, {_(" Estimated hours for charging"), shorten(self:chargingHours())}) + table.insert(kv_pairs, {INDENTATION .. _("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, + settings = LuaSettings:open(DataStorage:getSettingsDir() .. "/battery_stats.lua"), 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")) + self.charging = Usage:new(self.settings:readSetting("charging")) + self.discharging = Usage:new(self.settings:readSetting("discharging")) -- 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")) + self.awake_state = State:new() + self.charging_state = State:new() + -- 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 + if self.was_charging then + self:reset(true, false) + end + -- Check if the battery was charging when KO was turned off. + local battery_before_off = self.settings:readSetting("awake_state") + if battery_before_off and battery_before_off.percentage + and self.awake_state.percentage > battery_before_off.percentage then + self:reset(false, true) end end @@ -133,10 +137,10 @@ function BatteryStat:onFlushSettings() end function BatteryStat:accumulate() - if self.was_suspending then + if self.was_suspending and not self.was_charging then -- Suspending to awake. self.sleeping:append(self.awake_state) - else + elseif not self.was_suspending and not self.was_charging then -- Awake to suspending, time between self.awake_state and now should belong to awake. self.awake:append(self.awake_state) end @@ -150,24 +154,7 @@ function BatteryStat:accumulate() 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 @@ -175,7 +162,6 @@ function BatteryStat:onSuspend() end function BatteryStat:onResume() - self:debugOutput("onResume") if self.was_suspending then self:accumulate() end @@ -183,16 +169,14 @@ function BatteryStat:onResume() end function BatteryStat:onCharging() - self:debugOutput("onCharging") if not self.was_charging then - self:reset(true, false) + self:reset(true, true) 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() @@ -201,21 +185,33 @@ function BatteryStat:onNotCharging() end function BatteryStat:showStatistics() + local function askResetData() + UIManager:show(ConfirmBox:new{ + text = _("Are you sure that you want to clear battery statistics?"), + ok_text = _("Clear"), + ok_callback = function() + self:resetAll() + self:restart() + end, + }) + end + 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() + UIManager:setDirty(self.kv_page, "fast") + UIManager:scheduleIn(0.1, function() + askResetData() + end) end}) table.insert(kv_pairs, {_("please tap here."), "", callback = function() - self:resetAll() - self:restart() + UIManager:setDirty(self.kv_page, "fast") + UIManager:scheduleIn(0.1, function() + askResetData() + end) end}) self.kv_page = KeyValuePage:new{ title = _("Battery statistics"), @@ -225,7 +221,6 @@ function BatteryStat:showStatistics() end function BatteryStat:reset(withCharging, withDischarging) - self:dumpToText() self.awake = Usage:new() self.sleeping = Usage:new() @@ -235,6 +230,7 @@ function BatteryStat:reset(withCharging, withDischarging) if withDischarging then self.discharging = Usage:new() end + self.awake_state = State:new() end function BatteryStat:resetAll() @@ -249,18 +245,6 @@ function BatteryStat:restart() 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"), ""}) diff --git a/spec/unit/batterystat_spec.lua b/spec/unit/batterystat_spec.lua index 058ad0bfe..b64f298a4 100644 --- a/spec/unit/batterystat_spec.lua +++ b/spec/unit/batterystat_spec.lua @@ -40,10 +40,10 @@ describe("BatteryState plugin tests #nocov", function() assert.is_false(widget.was_suspending) MockTime:increase(1) widget:accumulate() - -- awake & charging time should be reset. - assert.are.equal(1, widget.awake.time) + -- Awake charging & discharging time should be reset. + assert.are.equal(0, widget.awake.time) assert.are.equal(0, widget.sleeping.time) - assert.are.equal(1, widget.discharging.time) + assert.are.equal(0, widget.discharging.time) assert.are.equal(1, widget.charging.time) widget:onNotCharging() @@ -62,10 +62,10 @@ describe("BatteryState plugin tests #nocov", function() assert.is_false(widget.was_suspending) MockTime:increase(1) widget:accumulate() - -- awake & charging time should be reset. - assert.are.equal(1, widget.awake.time) + -- Awake charging & discharging time should be reset. + assert.are.equal(0, widget.awake.time) assert.are.equal(0, widget.sleeping.time) - assert.are.equal(1, widget.discharging.time) + assert.are.equal(0, widget.discharging.time) assert.are.equal(1, widget.charging.time) end) @@ -129,10 +129,10 @@ describe("BatteryState plugin tests #nocov", function() assert.is_false(widget.was_suspending) MockTime:increase(1) widget:accumulate() - -- awake & charging time should be reset. - assert.are.equal(1, widget.awake.time) + -- Awake charging & discharging time should be reset. + assert.are.equal(0, widget.awake.time) assert.are.equal(0, widget.sleeping.time) - assert.are.equal(1, widget.discharging.time) + assert.are.equal(0, widget.discharging.time) assert.are.equal(1, widget.charging.time) widget:onCharging() @@ -140,9 +140,9 @@ describe("BatteryState plugin tests #nocov", function() assert.is_false(widget.was_suspending) MockTime:increase(1) widget:accumulate() - assert.are.equal(2, widget.awake.time) + assert.are.equal(0, widget.awake.time) assert.are.equal(0, widget.sleeping.time) - assert.are.equal(1, widget.discharging.time) + assert.are.equal(0, widget.discharging.time) assert.are.equal(2, widget.charging.time) end)