mirror of
https://github.com/koreader/koreader.git
synced 2025-12-13 20:36:53 +01:00
[autosuspend, plugin] Switch to datetimewidget and provide default values (#8480)
This commit is contained in:
@@ -3,6 +3,7 @@ Simple math helper functions
|
||||
]]
|
||||
|
||||
local bit = require("bit")
|
||||
local dbg = require("dbg")
|
||||
|
||||
local Math = {}
|
||||
|
||||
@@ -102,4 +103,26 @@ function Math.tmax(tab, func)
|
||||
return tmin_max(tab, func, "max")
|
||||
end
|
||||
|
||||
--[[--
|
||||
Restricts a value within an interval.
|
||||
|
||||
@number value
|
||||
@number min
|
||||
@number max
|
||||
@treturn number value clamped to the interval [min,max]
|
||||
]]
|
||||
function Math.clamp(value, min, max)
|
||||
if value <= min then
|
||||
return min
|
||||
elseif value >= max then
|
||||
return max
|
||||
end
|
||||
return value
|
||||
end
|
||||
dbg:guard(Math, "minmax",
|
||||
function(value, min, max)
|
||||
assert(min ~= nil and max ~= nil, "Math.clamp: min " .. min .. " and max " .. nil .. " must not be nil")
|
||||
assert(min < max, "Math.clamp: min .. " .. min .. " must be less than max " .. max)
|
||||
end)
|
||||
|
||||
return Math
|
||||
|
||||
@@ -19,6 +19,7 @@ local VerticalSpan = require("ui/widget/verticalspan")
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local _ = require("gettext")
|
||||
local Screen = Device.screen
|
||||
local T = require("ffi/util").template
|
||||
|
||||
local DateTimeWidget = InputContainer:new{
|
||||
title_face = Font:getFace("x_smalltfont"),
|
||||
@@ -64,33 +65,34 @@ function DateTimeWidget:init()
|
||||
end
|
||||
|
||||
-- Actually the widget layout
|
||||
self:update()
|
||||
self:layout()
|
||||
end
|
||||
|
||||
function DateTimeWidget:update()
|
||||
local year_widget = NumberPickerWidget:new{
|
||||
local year_widget, month_hour_widget, day_min_widget
|
||||
function DateTimeWidget:layout()
|
||||
year_widget = NumberPickerWidget:new{
|
||||
show_parent = self,
|
||||
value = self.year,
|
||||
value_min = 2021,
|
||||
value_max = 2041,
|
||||
value_step = 1,
|
||||
value_hold_step = 4,
|
||||
value_hold_step = self.year_hold_step or 4,
|
||||
}
|
||||
local month_hour_widget = NumberPickerWidget:new{
|
||||
month_hour_widget = NumberPickerWidget:new{
|
||||
show_parent = self,
|
||||
value = self.is_date and self.month or self.hour,
|
||||
value_min = self.is_date and 1 or 0,
|
||||
value_max = self.is_date and 12 or self.hour_max,
|
||||
value_min = self.hour_min or self.month_min or (self.is_date and 1 or 0),
|
||||
value_max = self.hour_max or self.month_max or (self.is_date and 12 or 24),
|
||||
value_step = 1,
|
||||
value_hold_step = 3,
|
||||
value_hold_step = self.hour_hold_step or self.month_hold_step or 3,
|
||||
}
|
||||
local day_min_widget = NumberPickerWidget:new{
|
||||
day_min_widget = NumberPickerWidget:new{
|
||||
show_parent = self,
|
||||
value = self.is_date and self.day or self.min,
|
||||
value_min = self.is_date and 1 or 0,
|
||||
value_max = self.is_date and 31 or 59,
|
||||
value_min = self.min_min or self.day_min or (self.is_date and 1 or 0),
|
||||
value_max = self.min_max or self.day_max or (self.is_date and 31 or 59),
|
||||
value_step = 1,
|
||||
value_hold_step = self.is_date and 5 or 10,
|
||||
value_hold_step = self.day_hold_step or self.min_hold_step or (self.is_date and 5 or 10),
|
||||
date_month_hour = month_hour_widget,
|
||||
date_year = year_widget,
|
||||
}
|
||||
@@ -146,40 +148,15 @@ function DateTimeWidget:update()
|
||||
else
|
||||
date_info = VerticalSpan:new{ width = 0 }
|
||||
end
|
||||
local buttons = {
|
||||
{
|
||||
|
||||
local buttons = {}
|
||||
if self.default_value then
|
||||
table.insert(buttons, {
|
||||
{
|
||||
text = self.cancel_text,
|
||||
text = self.default_text or T(_("Default value: %1"), self.default_value),
|
||||
callback = function()
|
||||
self:onClose()
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = self.ok_text,
|
||||
callback = function()
|
||||
if self.callback then
|
||||
self.year = year_widget:getValue()
|
||||
if self.is_date then
|
||||
self.month = month_hour_widget:getValue()
|
||||
self.day = day_min_widget:getValue()
|
||||
else
|
||||
self.hour = month_hour_widget:getValue()
|
||||
self.min = day_min_widget:getValue()
|
||||
end
|
||||
self:callback(self)
|
||||
end
|
||||
self:onClose()
|
||||
end,
|
||||
},
|
||||
}
|
||||
}
|
||||
if self.extra_text then
|
||||
table.insert(buttons,{
|
||||
{
|
||||
text = self.extra_text,
|
||||
callback = function()
|
||||
if self.extra_callback then
|
||||
self.extra_callback(year_widget:getValue(), month_hour_widget:getValue(),
|
||||
if self.default_callback then
|
||||
self.default_callback(year_widget:getValue(), month_hour_widget:getValue(),
|
||||
day_min_widget:getValue())
|
||||
end
|
||||
if not self.keep_shown_on_apply then -- assume extra wants it same as ok
|
||||
@@ -189,6 +166,41 @@ function DateTimeWidget:update()
|
||||
},
|
||||
})
|
||||
end
|
||||
if self.extra_text then
|
||||
table.insert(buttons, {
|
||||
{
|
||||
text = self.extra_text,
|
||||
callback = function()
|
||||
self.extra_callback(self)
|
||||
end,
|
||||
},
|
||||
})
|
||||
end
|
||||
table.insert(buttons, {
|
||||
{
|
||||
text = self.cancel_text,
|
||||
callback = function()
|
||||
self:onClose()
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = self.ok_text,
|
||||
callback = function()
|
||||
if self.callback then
|
||||
self.year = year_widget:getValue()
|
||||
if self.is_date then
|
||||
self.month = month_hour_widget:getValue()
|
||||
self.day = day_min_widget:getValue()
|
||||
else
|
||||
self.hour = month_hour_widget:getValue()
|
||||
self.min = day_min_widget:getValue()
|
||||
end
|
||||
self:callback(self)
|
||||
end
|
||||
self:onClose()
|
||||
end,
|
||||
},
|
||||
})
|
||||
|
||||
local ok_cancel_buttons = ButtonTable:new{
|
||||
width = self.width - 2*Size.padding.default,
|
||||
@@ -242,6 +254,15 @@ function DateTimeWidget:update()
|
||||
end)
|
||||
end
|
||||
|
||||
function DateTimeWidget:update(left, mid, right)
|
||||
year_widget.value = left
|
||||
year_widget:update()
|
||||
month_hour_widget.value = mid
|
||||
month_hour_widget:update()
|
||||
day_min_widget.value = right
|
||||
day_min_widget:update()
|
||||
end
|
||||
|
||||
function DateTimeWidget:onCloseWidget()
|
||||
UIManager:setDirty(nil, function()
|
||||
return "ui", self.date_frame.dimen
|
||||
|
||||
@@ -111,7 +111,7 @@ Source: <a href="https://gist.github.com/jesseadams/791673">https://gist.github.
|
||||
---- @int seconds number of seconds
|
||||
---- @bool withoutSeconds if true 00:00, if false 00:00:00
|
||||
---- @treturn string clock string in the form of 00:00 or 00:00:00
|
||||
function util.secondsToClock(seconds, withoutSeconds)
|
||||
function util.secondsToClock(seconds, withoutSeconds, withDays)
|
||||
seconds = tonumber(seconds)
|
||||
if not seconds then
|
||||
if withoutSeconds then
|
||||
@@ -127,7 +127,14 @@ function util.secondsToClock(seconds, withoutSeconds)
|
||||
end
|
||||
else
|
||||
local round = withoutSeconds and require("optmath").round or passthrough
|
||||
local hours = string.format("%02d", seconds / 3600)
|
||||
local days = "0"
|
||||
local hours
|
||||
if withDays then
|
||||
days = string.format("%d", seconds / (24*3600)) -- implicit math.floor for string.format
|
||||
hours = string.format("%02d", (seconds / 3600) % 24)
|
||||
else
|
||||
hours = string.format("%02d", seconds / 3600)
|
||||
end
|
||||
local mins = string.format("%02d", round(seconds % 3600 / 60))
|
||||
if withoutSeconds then
|
||||
if mins == "60" then
|
||||
@@ -135,10 +142,10 @@ function util.secondsToClock(seconds, withoutSeconds)
|
||||
mins = string.format("%02d", 0)
|
||||
hours = string.format("%02d", hours + 1)
|
||||
end
|
||||
return hours .. ":" .. mins
|
||||
return (days ~= "0" and (days .. "d") or "") .. hours .. ":" .. mins
|
||||
else
|
||||
local secs = string.format("%02d", seconds % 60)
|
||||
return hours .. ":" .. mins .. ":" .. secs
|
||||
return (days ~= "0" and (days .. "d") or "") .. hours .. ":" .. mins .. ":" .. secs
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -147,8 +154,9 @@ end
|
||||
---- @int seconds number of seconds
|
||||
---- @bool withoutSeconds if true 1h30', if false 1h30'10''
|
||||
---- @bool hmsFormat, if true format 1h30m10s
|
||||
---- @bool withDays, if true format 1d12h30m10s
|
||||
---- @treturn string clock string in the form of 1h30'10'' or 1h30m10s
|
||||
function util.secondsToHClock(seconds, withoutSeconds, hmsFormat)
|
||||
function util.secondsToHClock(seconds, withoutSeconds, hmsFormat, withDays)
|
||||
local SECONDS_SYMBOL = "\""
|
||||
seconds = tonumber(seconds)
|
||||
if seconds == 0 then
|
||||
@@ -189,7 +197,7 @@ function util.secondsToHClock(seconds, withoutSeconds, hmsFormat)
|
||||
end
|
||||
end
|
||||
else
|
||||
local time_string = util.secondsToClock(seconds, withoutSeconds)
|
||||
local time_string = util.secondsToClock(seconds, withoutSeconds, withDays)
|
||||
if withoutSeconds then
|
||||
time_string = time_string .. ":"
|
||||
end
|
||||
@@ -198,15 +206,15 @@ function util.secondsToHClock(seconds, withoutSeconds, hmsFormat)
|
||||
time_string = time_string:gsub(":", _("h"), 1)
|
||||
-- @translators This is the 'm' for minute, like in 1h30m30s. This is a duration.
|
||||
time_string = time_string:gsub(":", _("m"), 1)
|
||||
-- @translators This is the 's' for second, like in 1h30m30s. This is a duration.
|
||||
time_string = time_string:gsub("00" .. _("h"), "") -- delete leading "00h"
|
||||
time_string = time_string:gsub("^00" .. _("h"), "") -- delete leading "00h"
|
||||
time_string = time_string:gsub("^0", "") -- delete leading "0"
|
||||
-- @translators This is the 's' for second, like in 1h30m30s. This is a duration.
|
||||
return withoutSeconds and time_string or (time_string .. _("s"))
|
||||
else
|
||||
-- @translators This is the 'h' for hour, like in 1h30m30s. This is a duration.
|
||||
time_string = time_string:gsub(":", _("h"), 1)
|
||||
time_string = time_string:gsub(":", "'", 1)
|
||||
time_string = time_string:gsub("00" .. _("h"), "") -- delete leading "00h"
|
||||
time_string = time_string:gsub("^00" .. _("h"), "") -- delete leading "00h"
|
||||
time_string = time_string:gsub("^0", "") -- delete leading "0"
|
||||
return withoutSeconds and time_string or (time_string .. SECONDS_SYMBOL)
|
||||
end
|
||||
@@ -218,13 +226,14 @@ end
|
||||
---- @string Either "modern" for 1h30'10" or "classic" for 1:30:10
|
||||
---- @bool withoutSeconds if true 1h30' or 1h30m, if false 1h30'10" or 1h30m10s
|
||||
---- @bool hmsFormat, modern format only, if true format 1h30m or 1h30m10s
|
||||
---- @bool withDays, if hours>=24 include days in clock string 1d12h10m10s
|
||||
---- @treturn string clock string in the specific format of 1h30', 1h30'10" resp. 1h30m, 1h30m10s
|
||||
function util.secondsToClockDuration(format, seconds, withoutSeconds, hmsFormat)
|
||||
function util.secondsToClockDuration(format, seconds, withoutSeconds, hmsFormat, withDays)
|
||||
if format == "modern" then
|
||||
return util.secondsToHClock(seconds, withoutSeconds, hmsFormat)
|
||||
return util.secondsToHClock(seconds, withoutSeconds, hmsFormat, withDays)
|
||||
else
|
||||
-- Assume "classic" to give safe default
|
||||
return util.secondsToClock(seconds, withoutSeconds)
|
||||
return util.secondsToClock(seconds, withoutSeconds, withDays)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -17,10 +17,11 @@ local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local logger = require("logger")
|
||||
local util = require("util")
|
||||
local _ = require("gettext")
|
||||
local Math = require("optmath")
|
||||
local T = require("ffi/util").template
|
||||
|
||||
local default_autoshutdown_timeout_seconds = 3*24*60*60
|
||||
local default_auto_suspend_timeout_seconds = 60*60
|
||||
local default_autoshutdown_timeout_seconds = 3*24*60*60 -- three days
|
||||
local default_auto_suspend_timeout_seconds = 15*60 -- 15 minutes
|
||||
|
||||
local AutoSuspend = WidgetContainer:new{
|
||||
name = "autosuspend",
|
||||
@@ -107,8 +108,10 @@ end
|
||||
function AutoSuspend:init()
|
||||
logger.dbg("AutoSuspend: init")
|
||||
if Device:isPocketBook() and not Device:canSuspend() then return end
|
||||
self.autoshutdown_timeout_seconds = G_reader_settings:readSetting("autoshutdown_timeout_seconds") or default_autoshutdown_timeout_seconds
|
||||
self.auto_suspend_timeout_seconds = G_reader_settings:readSetting("auto_suspend_timeout_seconds") or default_auto_suspend_timeout_seconds
|
||||
self.autoshutdown_timeout_seconds = G_reader_settings:readSetting("autoshutdown_timeout_seconds",
|
||||
default_autoshutdown_timeout_seconds)
|
||||
self.auto_suspend_timeout_seconds = G_reader_settings:readSetting("auto_suspend_timeout_seconds",
|
||||
default_auto_suspend_timeout_seconds)
|
||||
|
||||
UIManager.event_hook:registerWidget("InputEvent", self)
|
||||
-- We need an instance-specific function reference to schedule, because in some rare cases,
|
||||
@@ -169,87 +172,121 @@ function AutoSuspend:onPreventStandby()
|
||||
self.standby_prevented = true
|
||||
end
|
||||
|
||||
function AutoSuspend:setSuspendShutdownTimes(touchmenu_instance, title, info, setting,
|
||||
default_value, range, is_day_hour)
|
||||
-- Attention if is_day_hour then time.hour stands for days and time.min for hours
|
||||
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local DateTimeWidget = require("ui/widget/datetimewidget")
|
||||
|
||||
local setting_val = self[setting] > 0 and self[setting] or default_value
|
||||
|
||||
local left_val = is_day_hour and math.floor(setting_val / (24*3600))
|
||||
or math.floor(setting_val / 3600)
|
||||
local right_val = is_day_hour and math.floor(setting_val / 3600) % 24
|
||||
or math.floor((setting_val / 60) % 60)
|
||||
local time_spinner
|
||||
time_spinner = DateTimeWidget:new {
|
||||
is_date = false,
|
||||
hour = left_val,
|
||||
min = right_val,
|
||||
hour_hold_step = 5,
|
||||
min_hold_step = 10,
|
||||
hour_max = is_day_hour and math.floor(range[2] / (24*3600)) or math.floor(range[2] / 3600),
|
||||
min_max = is_day_hour and 23 or 59,
|
||||
ok_text = _("Set timeout"),
|
||||
title_text = title,
|
||||
info_text = info,
|
||||
callback = function(time)
|
||||
self[setting] = is_day_hour and (time.hour * 24 * 3600 + time.min * 3600)
|
||||
or (time.hour * 3600 + time.min * 60)
|
||||
self[setting] = Math.clamp(self[setting], range[1], range[2])
|
||||
G_reader_settings:saveSetting(setting, self[setting])
|
||||
self:_unschedule()
|
||||
self:_start()
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
local time_string = util.secondsToClockDuration("modern", self[setting], true, true, true)
|
||||
time_string = time_string:gsub("00m","")
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = T(_("%1: %2"), title, time_string),
|
||||
timeout = 3,
|
||||
})
|
||||
end,
|
||||
default_value = util.secondsToClockDuration("modern", default_value, true, true, true):gsub("00m$",""),
|
||||
default_callback = function()
|
||||
local hour = is_day_hour and math.floor(default_value / (24*3600))
|
||||
or math.floor(default_value / 3600)
|
||||
local min = is_day_hour and math.floor(default_value / 3600) % 24
|
||||
or math.floor(default_value / 60) % 60
|
||||
time_spinner:update(nil, hour, min)
|
||||
end,
|
||||
extra_text = _("Disable"),
|
||||
extra_callback = function(_self)
|
||||
self[setting] = -1 -- disable with a negative time/number
|
||||
self:_unschedule()
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = T(_("%1: disabled"), title),
|
||||
timeout = 3,
|
||||
})
|
||||
_self:onClose()
|
||||
end,
|
||||
keep_shown_on_apply = true,
|
||||
}
|
||||
UIManager:show(time_spinner)
|
||||
end
|
||||
|
||||
function AutoSuspend:addToMainMenu(menu_items)
|
||||
menu_items.autosuspend = {
|
||||
sorting_hint = "device",
|
||||
checked_func = function()
|
||||
return self:_enabled()
|
||||
end,
|
||||
text_func = function()
|
||||
if self.auto_suspend_timeout_seconds then
|
||||
local duration_format = G_reader_settings:readSetting("duration_format", "classic")
|
||||
return T(_("Autosuspend timeout: %1"),
|
||||
util.secondsToClockDuration(duration_format, self.auto_suspend_timeout_seconds, true))
|
||||
if self.auto_suspend_timeout_seconds and self.auto_suspend_timeout_seconds > 0 then
|
||||
local time_string = util.secondsToClockDuration("modern",
|
||||
self.auto_suspend_timeout_seconds, true, true, true):gsub("00m$","")
|
||||
return T(_("Autosuspend timeout: %1"), time_string)
|
||||
else
|
||||
return _("Autosuspend timeout")
|
||||
end
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
callback = function(touchmenu_instance)
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local SpinWidget = require("ui/widget/spinwidget")
|
||||
local autosuspend_spin = SpinWidget:new {
|
||||
value = self.auto_suspend_timeout_seconds / 60,
|
||||
value_min = 5,
|
||||
value_max = 240,
|
||||
value_hold_step = 15,
|
||||
ok_text = _("Set timeout"),
|
||||
title_text = _("Timeout in minutes"),
|
||||
callback = function(autosuspend_spin)
|
||||
self.auto_suspend_timeout_seconds = autosuspend_spin.value * 60
|
||||
G_reader_settings:saveSetting("auto_suspend_timeout_seconds", self.auto_suspend_timeout_seconds)
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = T(_("The system will automatically suspend after %1 minutes of inactivity."),
|
||||
string.format("%.2f", self.auto_suspend_timeout_seconds / 60)),
|
||||
timeout = 3,
|
||||
})
|
||||
self:_unschedule()
|
||||
self:_start()
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
end
|
||||
}
|
||||
UIManager:show(autosuspend_spin)
|
||||
-- 60 sec (1') is the minimum and 24*3600 sec (1day) is the maximum suspend time.
|
||||
-- A suspend time of one day seems to be excessive.
|
||||
-- But or battery testing it might give some sense.
|
||||
self:setSuspendShutdownTimes(touchmenu_instance,
|
||||
_("Timeout for autosuspend"), _("Enter time in hours and minutes."),
|
||||
"auto_suspend_timeout_seconds", default_auto_suspend_timeout_seconds,
|
||||
{60, 24*3600}, false)
|
||||
end,
|
||||
}
|
||||
if not (Device:canPowerOff() or Device:isEmulator()) then return end
|
||||
menu_items.autoshutdown = {
|
||||
sorting_hint = "device",
|
||||
checked_func = function()
|
||||
return self:_enabledShutdown()
|
||||
end,
|
||||
text_func = function()
|
||||
if self.autoshutdown_timeout_seconds then
|
||||
local duration_format = G_reader_settings:readSetting("duration_format", "classic")
|
||||
return T(_("Autoshutdown timeout: %1"),
|
||||
util.secondsToClockDuration(duration_format, self.autoshutdown_timeout_seconds, true))
|
||||
if self.autoshutdown_timeout_seconds and self.autoshutdown_timeout_seconds > 0 then
|
||||
local time_string = util.secondsToClockDuration("modern",
|
||||
self.autoshutdown_timeout_seconds, true, true, true):gsub("00m$","")
|
||||
return T(_("Autoshutdown timeout: %1"), time_string)
|
||||
else
|
||||
return _("Autoshutdown timeout")
|
||||
end
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
callback = function(touchmenu_instance)
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local SpinWidget = require("ui/widget/spinwidget")
|
||||
local autosuspend_spin = SpinWidget:new {
|
||||
value = self.autoshutdown_timeout_seconds / 60 / 60,
|
||||
-- About a minute, good for testing and battery life fanatics.
|
||||
-- Just high enough to avoid an instant shutdown death scenario.
|
||||
value_min = 0.017,
|
||||
-- More than three weeks seems a bit excessive if you want to enable authoshutdown,
|
||||
-- even if the battery can last up to three months.
|
||||
value_max = 28*24,
|
||||
value_hold_step = 24,
|
||||
precision = "%.2f",
|
||||
ok_text = _("Set timeout"),
|
||||
title_text = _("Timeout in hours"),
|
||||
callback = function(autosuspend_spin)
|
||||
self.autoshutdown_timeout_seconds = math.floor(autosuspend_spin.value * 60 * 60)
|
||||
G_reader_settings:saveSetting("autoshutdown_timeout_seconds", self.autoshutdown_timeout_seconds)
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = T(_("The system will automatically shut down after %1 hours of inactivity."),
|
||||
string.format("%.2f", self.autoshutdown_timeout_seconds / 60 / 60)),
|
||||
timeout = 3,
|
||||
})
|
||||
self:_unschedule()
|
||||
self:_start()
|
||||
if touchmenu_instance then touchmenu_instance:updateItems() end
|
||||
end
|
||||
}
|
||||
UIManager:show(autosuspend_spin)
|
||||
-- 5*60 sec (5') is the minimum and 28*24*3600 (28days) is the maximum shutdown time.
|
||||
-- Minimum time has to be big enough, to avoid start-stop death scenarious.
|
||||
-- Maximum more than four weeks seems a bit excessive if you want to enable authoshutdown,
|
||||
-- even if the battery can last up to three months.
|
||||
self:setSuspendShutdownTimes(touchmenu_instance,
|
||||
_("Timeout for autoshutdown"), _("Enter time in days and hours."),
|
||||
"autoshutdown_timeout_seconds", default_autoshutdown_timeout_seconds,
|
||||
{5*60, 28*24*3600}, true)
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
@@ -58,4 +58,16 @@ describe("Math module", function()
|
||||
assert.are.same("even", Math.oddEven(0))
|
||||
end)
|
||||
|
||||
describe("minmax", function()
|
||||
it("should return a value within a range", function()
|
||||
assert.are.same(-1, Math.clamp(-2, -1, 10))
|
||||
assert.are.same(-1, Math.clamp(-1, -1, 10))
|
||||
assert.are.same(0, Math.clamp(0, -1, 10))
|
||||
assert.are.same(5, Math.clamp(5, -1, 10))
|
||||
assert.are.same(9, Math.clamp(9, -1, 10))
|
||||
assert.are.same(10, Math.clamp(10, -1, 10))
|
||||
assert.are.same(10, Math.clamp(11, -1, 10))
|
||||
end)
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user