mirror of
https://github.com/koreader/koreader
synced 2024-11-16 06:12:56 +00:00
datetimewidget: simpler usage, allows 2 to 6 numberpickers for date and time (#9070)
This commit is contained in:
parent
8f316b1e8c
commit
13274d6212
@ -133,11 +133,11 @@ if Device:setDateTime() then
|
||||
local curr_hour = now_t.hour
|
||||
local curr_min = now_t.min
|
||||
local time_widget = DateTimeWidget:new{
|
||||
is_date = false,
|
||||
hour = curr_hour,
|
||||
min = curr_min,
|
||||
ok_text = _("Set time"),
|
||||
title_text = _("Set time"),
|
||||
info_text =_("Time is in hours and minutes."),
|
||||
callback = function(time)
|
||||
if Device:setDateTime(nil, nil, nil, time.hour, time.min) then
|
||||
now_t = os.date("*t")
|
||||
@ -169,6 +169,7 @@ if Device:setDateTime() then
|
||||
day = curr_day,
|
||||
ok_text = _("Set date"),
|
||||
title_text = _("Set date"),
|
||||
info_text = _("Date is in years, months and days."),
|
||||
callback = function(time)
|
||||
now_t = os.date("*t")
|
||||
if Device:setDateTime(time.year, time.month, time.day, now_t.hour, now_t.min, now_t.sec) then
|
||||
|
@ -6,11 +6,11 @@ Example for input a time:
|
||||
local @{gettext|_} = require("gettext")
|
||||
|
||||
local time_widget = DateTimeWidget:new{
|
||||
is_date = false,
|
||||
hour = 10,
|
||||
min = 30,
|
||||
ok_text = _("Set time"),
|
||||
title_text = _("Set time"),
|
||||
info_text = _("Some information"),
|
||||
callback = function(time)
|
||||
-- use time.hour and time.min here
|
||||
end
|
||||
@ -33,6 +33,21 @@ Example for input a date:
|
||||
}
|
||||
UIManager:show(date_widget)
|
||||
|
||||
Example to input a duration in days, hours and minutes:
|
||||
local DateTimeWidget = require("ui/widget/datetimewidget")
|
||||
local @{gettext|_} = require("gettext")
|
||||
|
||||
local date_widget = DateTimeWidget:new{
|
||||
day = 5,
|
||||
hour = 12,
|
||||
min = 0,
|
||||
ok_text = _("Set"),
|
||||
title_text = _("Set duration"),
|
||||
callback = function(time)
|
||||
-- use time.day, time.hour, time.min here
|
||||
end
|
||||
}
|
||||
UIManager:show(date_widget)
|
||||
--]]--
|
||||
|
||||
local Blitbuffer = require("ffi/blitbuffer")
|
||||
@ -47,7 +62,7 @@ local Font = require("ui/font")
|
||||
local HorizontalGroup = require("ui/widget/horizontalgroup")
|
||||
local NumberPickerWidget = require("ui/widget/numberpickerwidget")
|
||||
local Size = require("ui/size")
|
||||
local TextBoxWidget = require("ui/widget/textboxwidget")
|
||||
local TextWidget = require("ui/widget/textwidget")
|
||||
local TitleBar = require("ui/widget/titlebar")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local VerticalGroup = require("ui/widget/verticalgroup")
|
||||
@ -61,12 +76,6 @@ local DateTimeWidget = FocusManager:new{
|
||||
info_text = nil,
|
||||
width = nil,
|
||||
height = nil,
|
||||
is_date = true,
|
||||
day = 1,
|
||||
month = 1,
|
||||
year = 2021,
|
||||
hour = 12,
|
||||
min = 0,
|
||||
ok_text = _("Apply"),
|
||||
cancel_text = _("Close"),
|
||||
-- Optional extra button on bottom
|
||||
@ -75,11 +84,38 @@ local DateTimeWidget = FocusManager:new{
|
||||
}
|
||||
|
||||
function DateTimeWidget:init()
|
||||
self.nb_pickers = 0
|
||||
if self.year then
|
||||
self.nb_pickers = self.nb_pickers + 1
|
||||
end
|
||||
if self.month then
|
||||
self.nb_pickers = self.nb_pickers + 1
|
||||
end
|
||||
if self.day then
|
||||
self.nb_pickers = self.nb_pickers + 1
|
||||
end
|
||||
if self.hour then
|
||||
self.nb_pickers = self.nb_pickers + 1
|
||||
end
|
||||
if self.min then
|
||||
self.nb_pickers = self.nb_pickers + 1
|
||||
end
|
||||
if self.sec then
|
||||
self.nb_pickers = self.nb_pickers + 1
|
||||
end
|
||||
|
||||
self.layout = {}
|
||||
self.screen_width = Screen:getWidth()
|
||||
self.screen_height = Screen:getHeight()
|
||||
self.width = self.width or math.floor(math.min(self.screen_width, self.screen_height) *
|
||||
(self.is_date and 0.8 or 0.6))
|
||||
local width_scale_factor = 0.6
|
||||
if self.nb_pickers == 3 then
|
||||
width_scale_factor = 0.8
|
||||
elseif self.nb_pickers == 4 then
|
||||
width_scale_factor = 0.85
|
||||
elseif self.nb_pickers >=5 then
|
||||
width_scale_factor = 0.95
|
||||
end
|
||||
self.width = self.width or math.floor(math.min(self.screen_width, self.screen_height) * width_scale_factor)
|
||||
if Device:hasKeys() then
|
||||
self.key_events.Close = { {Device.input.group.Back}, doc = "close date widget" }
|
||||
end
|
||||
@ -101,57 +137,148 @@ function DateTimeWidget:init()
|
||||
self:createLayout()
|
||||
end
|
||||
|
||||
local year_widget, month_hour_widget, day_min_widget
|
||||
-- Just a dummy with no operation
|
||||
local dummy_widget = {}
|
||||
function dummy_widget:free() end
|
||||
function dummy_widget:getValue() end
|
||||
function dummy_widget:update() end
|
||||
|
||||
local year_widget, month_widget, day_widget, hour_widget, min_widget, sec_widget
|
||||
local separator_date, separator_date_time, separator_time
|
||||
|
||||
function DateTimeWidget:createLayout()
|
||||
year_widget = NumberPickerWidget:new{
|
||||
show_parent = self,
|
||||
value = self.year,
|
||||
value_min = 2021,
|
||||
value_max = 2041,
|
||||
value_step = 1,
|
||||
value_hold_step = self.year_hold_step or 4,
|
||||
}
|
||||
if self.is_date then
|
||||
self:mergeLayoutInHorizontal(year_widget)
|
||||
-- the following calculation is stolen from NumberPickerWidget
|
||||
local number_picker_widgets_width = math.floor(math.min(self.screen_width, self.screen_height) * 0.2)
|
||||
if self.nb_pickers > 3 then
|
||||
number_picker_widgets_width = math.floor(number_picker_widgets_width * 3 / self.nb_pickers)
|
||||
end
|
||||
month_hour_widget = NumberPickerWidget:new{
|
||||
show_parent = self,
|
||||
value = self.is_date and self.month or self.hour,
|
||||
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 23),
|
||||
value_step = 1,
|
||||
value_hold_step = self.hour_hold_step or self.month_hold_step or 3,
|
||||
}
|
||||
self:mergeLayoutInHorizontal(month_hour_widget)
|
||||
day_min_widget = NumberPickerWidget:new{
|
||||
show_parent = self,
|
||||
value = self.is_date and self.day or self.min,
|
||||
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.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,
|
||||
}
|
||||
self:mergeLayoutInHorizontal(day_min_widget)
|
||||
local separator_space = TextBoxWidget:new{
|
||||
text = self.is_date and "–" or ":",
|
||||
alignment = "center",
|
||||
|
||||
if self.year then
|
||||
year_widget = NumberPickerWidget:new{
|
||||
show_parent = self,
|
||||
value = self.year,
|
||||
value_min = self.year_min or 2021,
|
||||
value_max = self.year_max or 2525,
|
||||
value_step = 1,
|
||||
value_hold_step = self.year_hold_step or 4,
|
||||
width = number_picker_widgets_width,
|
||||
}
|
||||
self:mergeLayoutInHorizontal(year_widget)
|
||||
else
|
||||
year_widget = dummy_widget
|
||||
end
|
||||
if self.month then
|
||||
month_widget = NumberPickerWidget:new{
|
||||
show_parent = self,
|
||||
value = self.month,
|
||||
value_min = self.month_min or 1,
|
||||
value_max = self.month_max or 12,
|
||||
value_step = 1,
|
||||
value_hold_step = self.month_hold_step or 3,
|
||||
width = number_picker_widgets_width,
|
||||
}
|
||||
self:mergeLayoutInHorizontal(month_widget)
|
||||
else
|
||||
month_widget = dummy_widget
|
||||
end
|
||||
if self.day then
|
||||
day_widget = NumberPickerWidget:new{
|
||||
show_parent = self,
|
||||
value = self.day,
|
||||
value_min = self.day_min or 1,
|
||||
value_max = self.day_max or 31,
|
||||
value_step = 1,
|
||||
value_hold_step = self.day_hold_step or 3,
|
||||
width = number_picker_widgets_width,
|
||||
}
|
||||
self:mergeLayoutInHorizontal(day_widget)
|
||||
else
|
||||
day_widget = dummy_widget
|
||||
end
|
||||
|
||||
if self.hour then
|
||||
hour_widget = NumberPickerWidget:new{
|
||||
show_parent = self,
|
||||
value = self.hour,
|
||||
value_min = self.hour_min or 0,
|
||||
value_max = self.hour_max or 23,
|
||||
value_step = 1,
|
||||
value_hold_step = self.hour_hold_step or 4,
|
||||
width = number_picker_widgets_width,
|
||||
}
|
||||
self:mergeLayoutInHorizontal(hour_widget)
|
||||
else
|
||||
hour_widget = dummy_widget
|
||||
end
|
||||
if self.min then
|
||||
min_widget = NumberPickerWidget:new{
|
||||
show_parent = self,
|
||||
value = self.min,
|
||||
value_min = self.min_min or 0,
|
||||
value_max = self.min_max or 59,
|
||||
value_step = 1,
|
||||
value_hold_step = self.min_hold_step or 10,
|
||||
width = number_picker_widgets_width,
|
||||
}
|
||||
self:mergeLayoutInHorizontal(min_widget)
|
||||
else
|
||||
min_widget = dummy_widget
|
||||
end
|
||||
if self.sec then
|
||||
sec_widget = NumberPickerWidget:new{
|
||||
show_parent = self,
|
||||
value = self.sec,
|
||||
value_min = self.sec_min or 0,
|
||||
value_max = self.sec_max or 59,
|
||||
value_step = 1,
|
||||
value_hold_step = self.sec_hold_step or 10,
|
||||
width = number_picker_widgets_width,
|
||||
}
|
||||
self:mergeLayoutInHorizontal(sec_widget)
|
||||
else
|
||||
sec_widget = dummy_widget
|
||||
end
|
||||
|
||||
separator_date = TextWidget:new{
|
||||
text = "–",
|
||||
face = self.title_face,
|
||||
bold = true,
|
||||
}
|
||||
separator_time = TextWidget:new{
|
||||
text = _(":"),
|
||||
face = self.title_face,
|
||||
bold = true,
|
||||
}
|
||||
separator_date_time = TextWidget:new{
|
||||
text = _("/"),
|
||||
face = self.title_face,
|
||||
bold = true,
|
||||
width = math.floor(math.min(self.screen_width, self.screen_height) *
|
||||
(self.is_date and 0.02 or 0.05)),
|
||||
}
|
||||
local date_group = HorizontalGroup:new{
|
||||
align = "center",
|
||||
year_widget,
|
||||
separator_space,
|
||||
month_hour_widget,
|
||||
separator_space,
|
||||
day_min_widget,
|
||||
}
|
||||
if not self.is_date then
|
||||
table.remove(date_group, 2)
|
||||
align = "center",
|
||||
year_widget, -- 1
|
||||
separator_date, -- 2
|
||||
month_widget, -- 3
|
||||
separator_date, -- 4
|
||||
day_widget, -- 5
|
||||
separator_date_time, -- 6
|
||||
hour_widget, -- 7
|
||||
separator_time, -- 8
|
||||
min_widget, -- 9
|
||||
separator_time, -- 10
|
||||
sec_widget, -- 11
|
||||
}
|
||||
|
||||
-- remove empty widgets plus trailling placeholder
|
||||
for i = #date_group, 1, -2 do
|
||||
if date_group[i] == dummy_widget then
|
||||
table.remove(date_group, i)
|
||||
table.remove(date_group, i-1)
|
||||
end
|
||||
end
|
||||
|
||||
-- clean up leading separator
|
||||
if date_group[1] == separator_date or date_group[1] == separator_date_time or date_group[1] == separator_time then
|
||||
table.remove(date_group, 1)
|
||||
end
|
||||
|
||||
@ -172,8 +299,14 @@ function DateTimeWidget:createLayout()
|
||||
text = self.default_text or T(_("Default value: %1"), self.default_value),
|
||||
callback = function()
|
||||
if self.default_callback then
|
||||
self.default_callback(year_widget:getValue(), month_hour_widget:getValue(),
|
||||
day_min_widget:getValue())
|
||||
self.default_callback({
|
||||
year = year_widget:getValue(),
|
||||
month = month_widget:getValue(),
|
||||
day = day_widget:getValue(),
|
||||
hour = hour_widget:getValue(),
|
||||
minute = min_widget:getValue(),
|
||||
second = sec_widget:getValue(),
|
||||
})
|
||||
end
|
||||
if not self.keep_shown_on_apply then -- assume extra wants it same as ok
|
||||
self:onClose()
|
||||
@ -196,6 +329,9 @@ function DateTimeWidget:createLayout()
|
||||
{
|
||||
text = self.cancel_text,
|
||||
callback = function()
|
||||
if self.cancel_callback then
|
||||
self.cancel_callback(self)
|
||||
end
|
||||
self:onClose()
|
||||
end,
|
||||
},
|
||||
@ -204,13 +340,11 @@ function DateTimeWidget:createLayout()
|
||||
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.month = month_widget:getValue()
|
||||
self.day = day_widget:getValue()
|
||||
self.hour = hour_widget:getValue()
|
||||
self.min = min_widget:getValue()
|
||||
self.sec = sec_widget:getValue()
|
||||
self:callback(self)
|
||||
end
|
||||
self:onClose()
|
||||
@ -270,16 +404,32 @@ function DateTimeWidget:createLayout()
|
||||
end)
|
||||
end
|
||||
|
||||
function DateTimeWidget:update(left, mid, right)
|
||||
year_widget.value = left
|
||||
function DateTimeWidget:update(year, month, day, hour, min, sec)
|
||||
year_widget.value = year
|
||||
year_widget:update()
|
||||
month_hour_widget.value = mid
|
||||
month_hour_widget:update()
|
||||
day_min_widget.value = right
|
||||
day_min_widget:update()
|
||||
month_widget.value = month
|
||||
month_widget:update()
|
||||
day_widget.value = day
|
||||
day_widget:update()
|
||||
hour_widget.value = hour
|
||||
hour_widget:update()
|
||||
min_widget.value = min
|
||||
min_widget:update()
|
||||
sec_widget.value = sec
|
||||
sec_widget:update()
|
||||
end
|
||||
|
||||
function DateTimeWidget:onCloseWidget()
|
||||
year_widget:free()
|
||||
month_widget:free()
|
||||
day_widget:free()
|
||||
hour_widget:free()
|
||||
min_widget:free()
|
||||
sec_widget:free()
|
||||
separator_date:free()
|
||||
separator_date_time:free()
|
||||
separator_time:free()
|
||||
|
||||
UIManager:setDirty(nil, function()
|
||||
return "ui", self.date_frame.dimen
|
||||
end)
|
||||
|
@ -360,45 +360,47 @@ function AutoSuspend:pickTimeoutValue(touchmenu_instance, title, info, setting,
|
||||
-- Standby uses a different scheduled task than suspend/shutdown
|
||||
local is_standby = setting == "auto_standby_timeout_seconds"
|
||||
|
||||
local left_val
|
||||
local day, hour, minute, second
|
||||
local day_max, hour_max, min_max, sec_max
|
||||
if time_scale == 2 then
|
||||
left_val = math.floor(setting_val / (24*3600))
|
||||
day = math.floor(setting_val / (24*3600))
|
||||
hour = math.floor(setting_val / 3600) % 24
|
||||
day_max = math.floor(range[2] / (24*3600)) - 1
|
||||
hour_max = 23
|
||||
elseif time_scale == 1 then
|
||||
left_val = math.floor(setting_val / 3600)
|
||||
hour = math.floor(setting_val / 3600)
|
||||
minute = math.floor(setting_val / 60) % 60
|
||||
hour_max = math.floor(range[2] / 3600) - 1
|
||||
min_max = 59
|
||||
else
|
||||
left_val = math.floor(setting_val / 60)
|
||||
minute = math.floor(setting_val / 60)
|
||||
second = math.floor(setting_val) % 60
|
||||
min_max = math.floor(range[2] / 60) - 1
|
||||
sec_max = 59
|
||||
end
|
||||
|
||||
local right_val
|
||||
if time_scale == 2 then
|
||||
right_val = math.floor(setting_val / 3600) % 24
|
||||
elseif time_scale == 1 then
|
||||
right_val = math.floor(setting_val / 60) % 60
|
||||
else
|
||||
right_val = math.floor(setting_val) % 60
|
||||
end
|
||||
local time_spinner
|
||||
time_spinner = DateTimeWidget:new {
|
||||
is_date = false,
|
||||
hour = left_val,
|
||||
min = right_val,
|
||||
day = day,
|
||||
hour = hour,
|
||||
min = minute,
|
||||
sec = second,
|
||||
day_hold_step = 5,
|
||||
hour_hold_step = 5,
|
||||
min_hold_step = 10,
|
||||
hour_max = (time_scale == 2 and math.floor(range[2] / (24*3600)))
|
||||
or (time_scale == 1 and math.floor(range[2] / 3600))
|
||||
or math.floor(range[2] / 60),
|
||||
min_max = (time_scale == 2 and 23) or 59,
|
||||
sec_hold_step = 10,
|
||||
day_max = day_max,
|
||||
hour_max = hour_max,
|
||||
min_max = min_max,
|
||||
sec_max = sec_max,
|
||||
ok_text = _("Set timeout"),
|
||||
title_text = title,
|
||||
info_text = info,
|
||||
callback = function(spinner)
|
||||
if time_scale == 2 then
|
||||
self[setting] = (spinner.hour * 24 + spinner.min) * 3600
|
||||
elseif time_scale == 1 then
|
||||
self[setting] = spinner.hour * 3600 + spinner.min * 60
|
||||
else
|
||||
self[setting] = spinner.hour * 60 + spinner.min
|
||||
end
|
||||
callback = function(t)
|
||||
self[setting] = (((t.day or 0) * 24 +
|
||||
(t.hour or 0)) * 60 +
|
||||
(t.min or 0)) * 60 +
|
||||
(t.sec or 0)
|
||||
self[setting] = Math.clamp(self[setting], range[1], range[2])
|
||||
G_reader_settings:saveSetting(setting, self[setting])
|
||||
if is_standby then
|
||||
@ -421,23 +423,18 @@ function AutoSuspend:pickTimeoutValue(touchmenu_instance, title, info, setting,
|
||||
default_value = util.secondsToClockDuration("modern", default_value,
|
||||
time_scale == 2 or time_scale == 1, true, true):gsub("00m$", ""):gsub("^00m:", ""),
|
||||
default_callback = function()
|
||||
local hour
|
||||
local day, hour, min, sec -- luacheck: ignore 431
|
||||
if time_scale == 2 then
|
||||
hour = math.floor(default_value / (24*3600))
|
||||
day = math.floor(default_value / (24*3600))
|
||||
hour = math.floor(default_value / 3600) % 24
|
||||
elseif time_scale == 1 then
|
||||
hour = math.floor(default_value / 3600)
|
||||
else
|
||||
hour = math.floor(default_value / 60)
|
||||
end
|
||||
local min
|
||||
if time_scale == 2 then
|
||||
min = math.floor(default_value / 3600) % 24
|
||||
elseif time_scale == 1 then
|
||||
min = math.floor(default_value / 60) % 60
|
||||
else
|
||||
min = math.floor(default_value % 60)
|
||||
min = math.floor(default_value / 60)
|
||||
sec = math.floor(default_value % 60)
|
||||
end
|
||||
time_spinner:update(nil, hour, min)
|
||||
time_spinner:update(nil, nil, day, hour, min, sec) -- It is ok to pass nils here.
|
||||
end,
|
||||
extra_text = _("Disable"),
|
||||
extra_callback = function(this)
|
||||
@ -480,7 +477,7 @@ function AutoSuspend:addToMainMenu(menu_items)
|
||||
callback = function(touchmenu_instance)
|
||||
-- 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.
|
||||
-- But it might make sense for battery testing.
|
||||
self:pickTimeoutValue(touchmenu_instance,
|
||||
_("Timeout for autosuspend"), _("Enter time in hours and minutes."),
|
||||
"auto_suspend_timeout_seconds", default_auto_suspend_timeout_seconds,
|
||||
@ -509,7 +506,7 @@ function AutoSuspend:addToMainMenu(menu_items)
|
||||
-- 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:pickTimeoutValue(touchmenu_instance,
|
||||
_("Timeout for autoshutdown"), _("Enter time in days and hours."),
|
||||
_("Timeout for autoshutdown"), _("Enter time in days and hours."),
|
||||
"autoshutdown_timeout_seconds", default_autoshutdown_timeout_seconds,
|
||||
{5*60, 28*24*3600}, 2)
|
||||
end,
|
||||
|
@ -591,7 +591,6 @@ function AutoWarmth:getScheduleMenu()
|
||||
UIManager:show(DateTimeWidget:new{
|
||||
title_text = _("Set time"),
|
||||
info_text = _("Enter time in hours and minutes."),
|
||||
is_date = false,
|
||||
hour = hh,
|
||||
min = mm,
|
||||
ok_text = _("Set time"),
|
||||
|
@ -87,7 +87,6 @@ function ReadTimer:addToMainMenu(menu_items)
|
||||
local curr_hour = now_t.hour
|
||||
local curr_min = now_t.min
|
||||
local time_widget = DateTimeWidget:new{
|
||||
is_date = false,
|
||||
hour = curr_hour,
|
||||
min = curr_min,
|
||||
ok_text = _("Set alarm"),
|
||||
@ -136,7 +135,6 @@ function ReadTimer:addToMainMenu(menu_items)
|
||||
end
|
||||
end
|
||||
local time_widget = DateTimeWidget:new{
|
||||
is_date = false,
|
||||
hour = remain_hours or 0,
|
||||
min = remain_minutes or 0,
|
||||
hour_max = 17,
|
||||
|
Loading…
Reference in New Issue
Block a user