mirror of
https://github.com/koreader/koreader
synced 2024-10-31 21:20:20 +00:00
876 lines
34 KiB
Lua
876 lines
34 KiB
Lua
--[[--
|
|
@module koplugin.autowarmth
|
|
|
|
Plugin for setting screen warmth based on the sun position and/or a time schedule
|
|
]]
|
|
|
|
local Device = require("device")
|
|
|
|
local ConfirmBox = require("ui/widget/confirmbox")
|
|
local DoubleSpinWidget = require("/ui/widget/doublespinwidget")
|
|
local DeviceListener = require("device/devicelistener")
|
|
local Dispatcher = require("dispatcher")
|
|
local FFIUtil = require("ffi/util")
|
|
local InfoMessage = require("ui/widget/infomessage")
|
|
local InputDialog = require("ui/widget/inputdialog")
|
|
local Font = require("ui/font")
|
|
local Notification = require("ui/widget/notification")
|
|
local SpinWidget = require("ui/widget/spinwidget")
|
|
local SunTime = require("suntime")
|
|
local TextWidget = require("ui/widget/textwidget")
|
|
local UIManager = require("ui/uimanager")
|
|
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
|
local _ = require("gettext")
|
|
local T = FFIUtil.template
|
|
local Screen = require("device").screen
|
|
local util = require("util")
|
|
|
|
local activate_sun = 1
|
|
local activate_schedule = 2
|
|
local activate_closer_noon = 3
|
|
local activate_closer_midnight =4
|
|
|
|
local midnight_index = 11
|
|
|
|
local device_max_warmth = Device:hasNaturalLight() and Device.powerd.fl_warmth_max or 100
|
|
local device_warmth_fit_scale = device_max_warmth / 100
|
|
|
|
local function frac(x)
|
|
return x - math.floor(x)
|
|
end
|
|
|
|
local AutoWarmth = WidgetContainer:new{
|
|
name = "autowarmth",
|
|
sched_times = {},
|
|
sched_funcs = {}, -- necessary for unschedule, function, warmth
|
|
}
|
|
|
|
-- get timezone offset in hours (including dst)
|
|
function AutoWarmth:getTimezoneOffset()
|
|
local utcdate = os.date("!*t")
|
|
local localdate = os.date("*t")
|
|
return os.difftime(os.time(localdate), os.time(utcdate))/3600
|
|
end
|
|
|
|
function AutoWarmth:init()
|
|
self:onDispatcherRegisterActions()
|
|
self.ui.menu:registerToMainMenu(self)
|
|
|
|
self.easy_mode = G_reader_settings:nilOrTrue("autowarmth_easy_mode")
|
|
self.activate = G_reader_settings:readSetting("autowarmth_activate") or 0
|
|
self.location = G_reader_settings:readSetting("autowarmth_location") or "Geysir"
|
|
self.latitude = G_reader_settings:readSetting("autowarmth_latitude") or 64.31 --great Geysir in Iceland
|
|
self.longitude = G_reader_settings:readSetting("autowarmth_longitude") or -20.30
|
|
self.altitude = G_reader_settings:readSetting("autowarmth_altitude") or 200
|
|
self.timezone = G_reader_settings:readSetting("autowarmth_timezone") or 0
|
|
self.scheduler_times = G_reader_settings:readSetting("autowarmth_scheduler_times") or
|
|
{0.0, 5.5, 6.0, 6.5, 7.0, 13.0, 21.5, 22.0, 22.5, 23.0, 24.0}
|
|
self.warmth = G_reader_settings:readSetting("autowarmth_warmth")
|
|
or { 90, 90, 80, 60, 20, 20, 20, 60, 80, 90, 90}
|
|
|
|
-- schedule recalculation shortly afer midnight
|
|
self:scheduleMidnightUpdate()
|
|
end
|
|
|
|
function AutoWarmth:onDispatcherRegisterActions()
|
|
Dispatcher:registerAction("show_ephemeris",
|
|
{category="none", event="ShowEphemeris", title=_("Show ephemeris"), general=true})
|
|
Dispatcher:registerAction("auto_warmth_off",
|
|
{category="none", event="AutoWarmthOff", title=_("Auto warmth off"), screen=true})
|
|
Dispatcher:registerAction("auto_warmth_cycle_trough",
|
|
{category="none", event="AutoWarmthMode", title=_("Auto warmth cycle through modes"), screen=true})
|
|
end
|
|
|
|
function AutoWarmth:onShowEphemeris()
|
|
self:showTimesInfo(_("Information about the sun in"), true, activate_sun, false)
|
|
end
|
|
|
|
function AutoWarmth:onAutoWarmthOff()
|
|
self.activate = 0
|
|
G_reader_settings:saveSetting("autowarmth_activate", self.activate)
|
|
Notification:notify(_("Auto warmth turned off"))
|
|
self:scheduleMidnightUpdate()
|
|
end
|
|
|
|
function AutoWarmth:onAutoWarmthMode()
|
|
if self.activate > 0 then
|
|
self.activate = self.activate - 1
|
|
else
|
|
self.activate = activate_closer_midnight
|
|
end
|
|
local notify_text
|
|
if self.activate == 0 then
|
|
notify_text = _("Auto warmth turned off")
|
|
elseif self.activate == activate_sun then
|
|
notify_text = _("Auto warmth use sun position")
|
|
elseif self.activate == activate_schedule then
|
|
notify_text = _("Auto warmth use schedule")
|
|
elseif self.activate == activate_closer_midnight then
|
|
notify_text = _("Auto warmth use whatever is closer to midnight")
|
|
elseif self.activate == activate_closer_noon then
|
|
notify_text = _("Auto warmth use whatever is closer to noon")
|
|
end
|
|
G_reader_settings:saveSetting("autowarmth_activate", self.activate)
|
|
Notification:notify(notify_text)
|
|
self:scheduleMidnightUpdate()
|
|
end
|
|
|
|
function AutoWarmth:onResume()
|
|
if self.activate == 0 then return end
|
|
|
|
local resume_date = os.date("*t")
|
|
|
|
-- check if resume and suspend are done on the same day
|
|
if resume_date.day == SunTime.date.day and resume_date.month == SunTime.date.month
|
|
and resume_date.year == SunTime.date.year then
|
|
local now = SunTime:getTimeInSec(resume_date)
|
|
self:scheduleWarmthChanges(now)
|
|
else
|
|
self:scheduleMidnightUpdate() -- resume is on the other day, do all calcs again
|
|
end
|
|
end
|
|
|
|
-- wrapper for unscheduling, so that only our setWarmth gets unscheduled
|
|
function AutoWarmth.setWarmth(val)
|
|
if val then
|
|
if val > 100 then
|
|
DeviceListener:onSetNightMode(true)
|
|
else
|
|
DeviceListener:onSetNightMode(false)
|
|
end
|
|
if Device:hasNaturalLight() then
|
|
val = math.min(val, 100)
|
|
Device.powerd:setWarmth(val)
|
|
end
|
|
end
|
|
end
|
|
|
|
function AutoWarmth:scheduleMidnightUpdate()
|
|
-- first unschedule all old functions
|
|
UIManager:unschedule(self.scheduleMidnightUpdate) -- when called from menu or resume
|
|
|
|
local toRad = math.pi / 180
|
|
SunTime:setPosition(self.location, self.latitude * toRad, self.longitude * toRad,
|
|
self.timezone, self.altitude)
|
|
SunTime:setAdvanced()
|
|
SunTime:setDate() -- today
|
|
SunTime:calculateTimes()
|
|
|
|
self.sched_times = {}
|
|
self.sched_funcs = {}
|
|
|
|
local function prepareSchedule(times, index1, index2)
|
|
local time1 = times[index1]
|
|
if not time1 then return end
|
|
|
|
local time = SunTime:getTimeInSec(time1)
|
|
table.insert(self.sched_times, time)
|
|
table.insert(self.sched_funcs, {AutoWarmth.setWarmth, self.warmth[index1]})
|
|
|
|
local time2 = times[index2]
|
|
if not time2 then return end -- to near to the pole
|
|
local warmth_diff = math.min(self.warmth[index2], 100) - math.min(self.warmth[index1], 100)
|
|
if warmth_diff ~= 0 then
|
|
local time_diff = SunTime:getTimeInSec(time2) - time
|
|
local delta_t = time_diff / math.abs(warmth_diff) -- can be inf, no problem
|
|
local delta_w = warmth_diff > 0 and 1 or -1
|
|
for i = 1, math.abs(warmth_diff)-1 do
|
|
local next_warmth = math.min(self.warmth[index1], 100) + delta_w * i
|
|
-- only apply warmth for steps the hardware has (e.g. Tolino has 0-10 hw steps
|
|
-- which map to warmth 0, 10, 20, 30 ... 100)
|
|
if frac(next_warmth * device_warmth_fit_scale) == 0 then
|
|
table.insert(self.sched_times, time + delta_t * i)
|
|
table.insert(self.sched_funcs, {self.setWarmth,
|
|
math.floor(math.min(self.warmth[index1], 100) + delta_w * i)})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if self.activate == activate_sun then
|
|
self.current_times = {unpack(SunTime.times, 1, midnight_index)}
|
|
elseif self.activate == activate_schedule then
|
|
self.current_times = {unpack(self.scheduler_times, 1, midnight_index)}
|
|
else
|
|
self.current_times = {unpack(SunTime.times, 1, midnight_index)}
|
|
if self.activate == activate_closer_noon then
|
|
for i = 1, midnight_index do
|
|
if not self.current_times[i] then
|
|
self.current_times[i] = self.scheduler_times[i]
|
|
elseif self.scheduler_times[i] and
|
|
math.abs(self.current_times[i]%24 - 12) > math.abs(self.scheduler_times[i]%24 - 12) then
|
|
self.current_times[i] = self.scheduler_times[i]
|
|
end
|
|
end
|
|
else -- activate_closer_midnight
|
|
for i = 1, midnight_index do
|
|
if not self.current_times[i] then
|
|
self.current_times[i] = self.scheduler_times[i]
|
|
elseif self.scheduler_times[i] and
|
|
math.abs(self.current_times[i]%24 - 12) < math.abs(self.scheduler_times[i]%24 - 12) then
|
|
self.current_times[i] = self.scheduler_times[i]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if self.easy_mode then
|
|
self.current_times[1] = nil
|
|
self.current_times[2] = nil
|
|
self.current_times[3] = nil
|
|
self.current_times[6] = nil
|
|
self.current_times[9] = nil
|
|
self.current_times[10] = nil
|
|
self.current_times[11] = nil
|
|
end
|
|
|
|
-- here are dragons
|
|
local i = 1
|
|
-- find first valid entry
|
|
while not self.current_times[i] and i <= midnight_index do
|
|
i = i + 1
|
|
end
|
|
local next
|
|
while i <= midnight_index do
|
|
next = i + 1
|
|
-- find next valid entry
|
|
while not self.current_times[next] and next <= midnight_index do
|
|
next = next + 1
|
|
end
|
|
prepareSchedule(self.current_times, i, next)
|
|
i = next
|
|
end
|
|
|
|
local now = SunTime:getTimeInSec()
|
|
|
|
-- reschedule 5sec after midnight
|
|
UIManager:scheduleIn(24*3600 + 5 - now, self.scheduleMidnightUpdate, self )
|
|
|
|
self:scheduleWarmthChanges(now)
|
|
end
|
|
|
|
function AutoWarmth:scheduleWarmthChanges(time)
|
|
for i = 1, #self.sched_funcs do -- loop not essential, as unschedule unschedules all functions at once
|
|
if not UIManager:unschedule(self.sched_funcs[i][1]) then
|
|
break
|
|
end
|
|
end
|
|
|
|
if self.activate == 0 then return end
|
|
|
|
local actual_warmth
|
|
for i = 1, #self.sched_funcs do
|
|
if self.sched_times[i] > time then
|
|
UIManager:scheduleIn( self.sched_times[i] - time,
|
|
self.sched_funcs[i][1], self.sched_funcs[i][2])
|
|
else
|
|
actual_warmth = self.sched_funcs[i][2] or actual_warmth
|
|
end
|
|
end
|
|
-- update current warmth directly
|
|
self.setWarmth(actual_warmth)
|
|
end
|
|
|
|
function AutoWarmth:hoursToClock(hours)
|
|
if hours then
|
|
hours = hours % 24 * 3600 + 0.01 -- round up, due to reduced precision in settings.reader.lua
|
|
end
|
|
return util.secondsToClock(hours, self.easy_mode)
|
|
end
|
|
|
|
function AutoWarmth:addToMainMenu(menu_items)
|
|
menu_items.autowarmth = {
|
|
text = Device:hasNaturalLight() and _("Auto warmth and night mode")
|
|
or _("Auto night mode"),
|
|
checked_func = function() return self.activate ~= 0 end,
|
|
sub_item_table_func = function()
|
|
return self:getSubMenuItems()
|
|
end,
|
|
}
|
|
end
|
|
|
|
local function tidy_menu(menu, request)
|
|
for i = #menu, 1, -1 do
|
|
if menu[i].mode ~=nil then
|
|
if menu[i].mode ~= request then
|
|
table.remove(menu,i)
|
|
else
|
|
menu[i].mode = nil
|
|
end
|
|
end
|
|
end
|
|
return menu
|
|
end
|
|
|
|
local about_text = _([[Set the frontlight warmth (if available) and night mode based on a time schedule or the sun's position.
|
|
|
|
There are three types of twilight:
|
|
|
|
• Civil: You can read a newspaper
|
|
• Nautical: You can see the first stars
|
|
• Astronomical: It is really dark
|
|
|
|
Custom warmth values can be set for every kind of twilight and sunrise, noon, sunset and midnight.
|
|
The screen warmth is continuously adjusted to the current time.
|
|
|
|
To use the sun's position, a geographical location must be entered. The calculations are very precise, with a deviation less than minute and a half.]])
|
|
function AutoWarmth:getSubMenuItems()
|
|
return {
|
|
{
|
|
text = Device:hasNaturalLight() and _("About auto warmth and night mode")
|
|
or _("About auto night mode"),
|
|
callback = function()
|
|
UIManager:show(InfoMessage:new{
|
|
text = about_text,
|
|
width = math.floor(Screen:getWidth() * 0.9),
|
|
})
|
|
end,
|
|
keep_menu_open = true,
|
|
separator = true,
|
|
},
|
|
{
|
|
text = _("Expert mode"),
|
|
checked_func = function()
|
|
return not self.easy_mode
|
|
end,
|
|
help_text = _("In the expert mode, different types of twilight can be used in addition to civil twilight."),
|
|
callback = function(touchmenu_instance)
|
|
self.easy_mode = not self.easy_mode
|
|
G_reader_settings:saveSetting("autowarmth_easy_mode", self.easy_mode)
|
|
self:scheduleMidnightUpdate()
|
|
touchmenu_instance.item_table = self:getSubMenuItems()
|
|
touchmenu_instance:updateItems()
|
|
end,
|
|
keep_menu_open = true,
|
|
},
|
|
{
|
|
text = _("Activate"),
|
|
checked_func = function()
|
|
return self.activate ~= 0
|
|
end,
|
|
sub_item_table = self:getActivateMenu(),
|
|
},
|
|
{
|
|
text = _("Location settings"),
|
|
enabled_func = function() return self.activate ~= activate_schedule end,
|
|
sub_item_table = self:getLocationMenu(),
|
|
},
|
|
{
|
|
text = _("Schedule settings"),
|
|
enabled_func = function() return self.activate ~= activate_sun end,
|
|
sub_item_table = self:getScheduleMenu(),
|
|
},
|
|
{
|
|
text = Device:hasNaturalLight() and _("Warmth and night mode settings")
|
|
or _("Night mode settings"),
|
|
sub_item_table = self:getWarmthMenu(),
|
|
separator = true,
|
|
},
|
|
self:getTimesMenu(_("Active parameters")),
|
|
self:getTimesMenu(_("Information about the sun in"), true, activate_sun),
|
|
self:getTimesMenu(_("Information about the schedule"), false, activate_schedule),
|
|
}
|
|
end
|
|
|
|
function AutoWarmth:getActivateMenu()
|
|
local function getActivateMenuEntry(text, activator)
|
|
return {
|
|
text = text,
|
|
checked_func = function() return self.activate == activator end,
|
|
callback = function()
|
|
if self.activate ~= activator then
|
|
self.activate = activator
|
|
else
|
|
self.activate = 0
|
|
end
|
|
G_reader_settings:saveSetting("autowarmth_activate", self.activate)
|
|
self:scheduleMidnightUpdate()
|
|
end,
|
|
}
|
|
end
|
|
|
|
return {
|
|
getActivateMenuEntry(_("Sun position"), activate_sun),
|
|
getActivateMenuEntry(_("Time schedule"), activate_schedule),
|
|
getActivateMenuEntry(_("Whatever is closer to noon"), activate_closer_noon),
|
|
getActivateMenuEntry(_("Whatever is closer to midnight"), activate_closer_midnight),
|
|
}
|
|
end
|
|
|
|
function AutoWarmth:getLocationMenu()
|
|
return {{
|
|
text_func = function()
|
|
if self.location ~= "" then
|
|
return T(_("Location: %1"), self.location)
|
|
else
|
|
return _("Location")
|
|
end
|
|
end,
|
|
callback = function(touchmenu_instance)
|
|
local location_name_dialog
|
|
location_name_dialog = InputDialog:new{
|
|
title = _("Location name"),
|
|
input = self.location,
|
|
buttons = {
|
|
{
|
|
{
|
|
text = _("Cancel"),
|
|
callback = function()
|
|
UIManager:close(location_name_dialog)
|
|
end,
|
|
},
|
|
{
|
|
text = _("OK"),
|
|
callback = function()
|
|
self.location = location_name_dialog:getInputText()
|
|
G_reader_settings:saveSetting("autowarmth_location",
|
|
self.location)
|
|
UIManager:close(location_name_dialog)
|
|
if touchmenu_instance then touchmenu_instance:updateItems() end
|
|
end,
|
|
},
|
|
}}
|
|
}
|
|
UIManager:show(location_name_dialog)
|
|
location_name_dialog:onShowKeyboard()
|
|
end,
|
|
keep_menu_open = true,
|
|
},
|
|
{
|
|
text_func = function()
|
|
return T(_("Coordinates: (%1, %2)"), self.latitude, self.longitude)
|
|
end,
|
|
callback = function(touchmenu_instance)
|
|
local location_widget = DoubleSpinWidget:new{
|
|
title_text = _("Set location"),
|
|
info_text = _("Enter decimal degrees, northern hemisphere and eastern length are '+'."),
|
|
left_text = _("Latitude"),
|
|
left_value = self.latitude,
|
|
left_default = 0,
|
|
left_min = -90,
|
|
left_max = 90,
|
|
left_step = 0.1,
|
|
precision = "%0.2f",
|
|
left_hold_step = 5,
|
|
right_text = _("Longitude"),
|
|
right_value = self.longitude,
|
|
right_default = 0,
|
|
right_min = -180,
|
|
right_max = 180,
|
|
right_step = 0.1,
|
|
right_hold_step = 5,
|
|
callback = function(lat, long)
|
|
self.latitude = lat
|
|
self.longitude = long
|
|
self.timezone = self:getTimezoneOffset() -- use timezone of device
|
|
G_reader_settings:saveSetting("autowarmth_latitude", self.latitude)
|
|
G_reader_settings:saveSetting("autowarmth_longitude", self.longitude)
|
|
G_reader_settings:saveSetting("autowarmth_timezone", self.timezone)
|
|
self:scheduleMidnightUpdate()
|
|
if touchmenu_instance then touchmenu_instance:updateItems() end
|
|
end,
|
|
}
|
|
UIManager:show(location_widget)
|
|
end,
|
|
keep_menu_open = true,
|
|
},
|
|
{
|
|
text_func = function()
|
|
return T(_("Altitude: %1m"), self.altitude)
|
|
end,
|
|
callback = function(touchmenu_instance)
|
|
UIManager:show(SpinWidget:new{
|
|
title_text = _("Altitude"),
|
|
value = self.altitude,
|
|
value_min = -100,
|
|
value_max = 15000, -- intercontinental flight
|
|
wrap = false,
|
|
value_step = 10,
|
|
value_hold_step = 100,
|
|
ok_text = _("Set"),
|
|
callback = function(spin)
|
|
self.altitude = spin.value
|
|
G_reader_settings:saveSetting("autowarmth_altitude", self.altitude)
|
|
self:scheduleMidnightUpdate()
|
|
if touchmenu_instance then touchmenu_instance:updateItems() end
|
|
end,
|
|
extra_text = _("Default"),
|
|
extra_callback = function()
|
|
self.altitude = 200
|
|
G_reader_settings:saveSetting("autowarmth_altitude", self.altitude)
|
|
self:scheduleMidnightUpdate()
|
|
if touchmenu_instance then touchmenu_instance:updateItems() end
|
|
end,
|
|
})
|
|
end,
|
|
keep_menu_open = true,
|
|
}}
|
|
end
|
|
|
|
function AutoWarmth:getScheduleMenu()
|
|
local function store_times(touchmenu_instance, new_time, num)
|
|
self.scheduler_times[num] = new_time
|
|
if num == 1 then
|
|
if new_time then
|
|
self.scheduler_times[midnight_index]
|
|
= new_time + 24 -- next day
|
|
else
|
|
self.scheduler_times[midnight_index] = nil
|
|
end
|
|
end
|
|
G_reader_settings:saveSetting("autowarmth_scheduler_times",
|
|
self.scheduler_times)
|
|
self:scheduleMidnightUpdate()
|
|
if touchmenu_instance then touchmenu_instance:updateItems() end
|
|
end
|
|
-- mode == nil ... show alway
|
|
-- == true ... easy mode
|
|
-- == false ... expert mode
|
|
local function getScheduleMenuEntry(text, num, mode)
|
|
return {
|
|
mode = mode,
|
|
text_func = function()
|
|
return T(_"%1: %2", text,
|
|
self:hoursToClock(self.scheduler_times[num]))
|
|
end,
|
|
checked_func = function()
|
|
return self.scheduler_times[num] ~= nil
|
|
end,
|
|
callback = function(touchmenu_instance)
|
|
local hh = 12
|
|
local mm = 0
|
|
if self.scheduler_times[num] then
|
|
hh = math.floor(self.scheduler_times[num])
|
|
mm = math.floor(frac(self.scheduler_times[num]) * 60 + 0.5)
|
|
end
|
|
UIManager:show(DoubleSpinWidget:new{
|
|
title_text = _("Set time"),
|
|
left_text = _("HH"),
|
|
left_value = hh,
|
|
left_default = 0,
|
|
left_min = 0,
|
|
left_max = 23,
|
|
left_step = 1,
|
|
left_hold_step = 3,
|
|
left_wrap = true,
|
|
right_text = _("MM"),
|
|
right_value = mm,
|
|
right_default = 0,
|
|
right_min = 0,
|
|
right_max = 59,
|
|
right_step = 1,
|
|
right_hold_step = 5,
|
|
right_wrap = true,
|
|
callback = function(left, right)
|
|
local new_time = left + right / 60
|
|
local function get_valid_time(n, dir)
|
|
for i = n+dir, dir > 0 and midnight_index or 1, dir do
|
|
if self.scheduler_times[i] then
|
|
return self.scheduler_times[i]
|
|
end
|
|
end
|
|
return dir > 0 and 0 or 26
|
|
end
|
|
if num > 1 and new_time < get_valid_time(num, -1) then
|
|
UIManager:show(ConfirmBox:new{
|
|
text = _("This time is before the previous time.\nAdjust the previous time?"),
|
|
ok_callback = function()
|
|
for i = num-1, 1, -1 do
|
|
if self.scheduler_times[i] then
|
|
if new_time < self.scheduler_times[i] then
|
|
self.scheduler_times[i] = new_time
|
|
else
|
|
break
|
|
end
|
|
end
|
|
end
|
|
store_times(touchmenu_instance, new_time, num)
|
|
end,
|
|
})
|
|
elseif num < 10 and new_time > get_valid_time(num, 1) then
|
|
UIManager:show(ConfirmBox:new{
|
|
text = _("This time is after the subsequent time.\nAdjust the subsequent time?"),
|
|
ok_callback = function()
|
|
for i = num + 1, midnight_index - 1 do
|
|
if self.scheduler_times[i] then
|
|
if new_time > self.scheduler_times[i] then
|
|
self.scheduler_times[i] = new_time
|
|
else
|
|
break
|
|
end
|
|
end
|
|
end
|
|
store_times(touchmenu_instance, new_time, num)
|
|
end,
|
|
})
|
|
else
|
|
store_times(touchmenu_instance, new_time, num)
|
|
end
|
|
end,
|
|
extra_text = _("Invalidate"),
|
|
extra_callback = function()
|
|
store_times(touchmenu_instance, nil, num)
|
|
end,
|
|
})
|
|
end,
|
|
keep_menu_open = true,
|
|
}
|
|
end
|
|
|
|
local retval = {
|
|
getScheduleMenuEntry(_("Solar midnight"), 1, false ),
|
|
getScheduleMenuEntry(_("Astronomical dawn"), 2, false),
|
|
getScheduleMenuEntry(_("Nautical dawn"), 3, false),
|
|
getScheduleMenuEntry(_("Civil dawn"), 4),
|
|
getScheduleMenuEntry(_("Sunrise"), 5),
|
|
getScheduleMenuEntry(_("Solar noon"), 6, false),
|
|
getScheduleMenuEntry(_("Sunset"), 7),
|
|
getScheduleMenuEntry(_("Civil dusk"), 8),
|
|
getScheduleMenuEntry(_("Nautical dusk"), 9, false),
|
|
getScheduleMenuEntry(_("Astronomical dusk"), 10, false),
|
|
}
|
|
|
|
return tidy_menu(retval, self.easy_mode)
|
|
end
|
|
|
|
function AutoWarmth:getWarmthMenu()
|
|
-- mode == nil ... show alway
|
|
-- == true ... easy mode
|
|
-- == false ... expert mode
|
|
local function getWarmthMenuEntry(text, num, mode)
|
|
return {
|
|
mode = mode,
|
|
text_func = function()
|
|
if Device:hasNaturalLight() then
|
|
if self.warmth[num] <= 100 then
|
|
return T(_("%1: %2%"), text, self.warmth[num])
|
|
else
|
|
return T(_("%1: 100% + ☾"), text)
|
|
end
|
|
else
|
|
if self.warmth[num] <= 100 then
|
|
return T(_("%1: ☼"), text)
|
|
else
|
|
return T(_("%1: ☾"), text)
|
|
end
|
|
end
|
|
end,
|
|
callback = function(touchmenu_instance)
|
|
if Device:hasNaturalLight() then
|
|
UIManager:show(SpinWidget:new{
|
|
title_text = text,
|
|
value = self.warmth[num],
|
|
value_min = 0,
|
|
value_max = 100,
|
|
wrap = false,
|
|
value_step = math.floor(100 / device_max_warmth),
|
|
value_hold_step = 10,
|
|
ok_text = _("Set"),
|
|
callback = function(spin)
|
|
self.warmth[num] = spin.value
|
|
self.warmth[#self.warmth - num + 1] = spin.value
|
|
G_reader_settings:saveSetting("autowarmth_warmth", self.warmth)
|
|
self:scheduleMidnightUpdate()
|
|
if touchmenu_instance then touchmenu_instance:updateItems() end
|
|
end,
|
|
extra_text = _("Use night mode"),
|
|
extra_callback = function()
|
|
self.warmth[num] = 110
|
|
self.warmth[#self.warmth - num + 1] = 110
|
|
G_reader_settings:saveSetting("autowarmth_warmth", self.warmth)
|
|
self:scheduleMidnightUpdate()
|
|
if touchmenu_instance then touchmenu_instance:updateItems() end
|
|
end,
|
|
})
|
|
else
|
|
UIManager:show(ConfirmBox:new{
|
|
text = _("Nightmode"),
|
|
ok_text = _("Set"),
|
|
ok_callback = function()
|
|
self.warmth[num] = 110
|
|
self.warmth[#self.warmth - num + 1] = 110
|
|
G_reader_settings:saveSetting("autowarmth_warmth", self.warmth)
|
|
self:scheduleMidnightUpdate()
|
|
if touchmenu_instance then touchmenu_instance:updateItems() end
|
|
end,
|
|
cancel_text = _("Unset"),
|
|
cancel_callback = function()
|
|
self.warmth[num] = 0
|
|
self.warmth[#self.warmth - num + 1] = 0
|
|
G_reader_settings:saveSetting("autowarmth_warmth", self.warmth)
|
|
self:scheduleMidnightUpdate()
|
|
if touchmenu_instance then touchmenu_instance:updateItems() end
|
|
end,
|
|
other_buttons = {{
|
|
{
|
|
text = _("Cancel"),
|
|
}
|
|
}},
|
|
|
|
})
|
|
end
|
|
end,
|
|
|
|
keep_menu_open = true,
|
|
}
|
|
end
|
|
|
|
local retval = {
|
|
{
|
|
text = Device:hasNaturalLight() and _("Set warmth and night mode for:")
|
|
or _("Set night mode for:"),
|
|
enabled_func = function() return false end,
|
|
},
|
|
getWarmthMenuEntry(_("Solar noon"), 6, false),
|
|
getWarmthMenuEntry(_("Daytime"), 5),
|
|
getWarmthMenuEntry(_("Darkest time of civil twilight"), 4),
|
|
getWarmthMenuEntry(_("Darkest time of nautical twilight"), 3, false),
|
|
getWarmthMenuEntry(_("Darkest time of astronomical twilight"), 2, false),
|
|
getWarmthMenuEntry(_("Solar midnight"), 1, false),
|
|
}
|
|
|
|
return tidy_menu(retval, self.easy_mode)
|
|
end
|
|
|
|
-- title
|
|
-- location: add a location string
|
|
-- activator: nil .. current_times,
|
|
-- activate_sun .. sun times
|
|
-- activate_schedule .. scheduler times
|
|
-- request_easy: true if easy_mode should be used
|
|
function AutoWarmth:showTimesInfo(title, location, activator, request_easy)
|
|
local times
|
|
if not activator then
|
|
times = self.current_times
|
|
elseif activator == activate_sun then
|
|
times = SunTime.times
|
|
elseif activator == activate_schedule then
|
|
times = self.scheduler_times
|
|
end
|
|
|
|
-- text to show
|
|
-- t .. times
|
|
-- num .. index in times
|
|
local function info_line(indent, text, t, num, face, easy)
|
|
-- get width of space
|
|
local unit = " "
|
|
local tmp = TextWidget:new{
|
|
text = unit,
|
|
face = face,
|
|
}
|
|
local space_w = tmp:getSize().w
|
|
|
|
-- get width of text
|
|
unit = text
|
|
tmp = TextWidget:new{
|
|
text = unit,
|
|
face = face,
|
|
}
|
|
local text_w = tmp:getSize().w
|
|
tmp:free()
|
|
|
|
-- width of text in spaces
|
|
local str_len = math.floor(text_w / space_w + 0.5)
|
|
|
|
local tab_width = 18 - indent
|
|
local retval = string.rep(" ", indent) .. text .. string.rep(" ", tab_width - str_len)
|
|
.. self:hoursToClock(t[num])
|
|
if easy then
|
|
if t[num] and self.current_times[num] and self.current_times[num] ~= t[num] then
|
|
return text .. "\n"
|
|
else
|
|
return ""
|
|
end
|
|
end
|
|
|
|
if not t[num] then -- entry deactivated
|
|
return retval .. "\n"
|
|
elseif Device:hasNaturalLight() then
|
|
if self.current_times[num] == t[num] then
|
|
if self.warmth[num] <= 100 then
|
|
return retval .. " (💡" .. self.warmth[num] .."%)\n"
|
|
else
|
|
return retval .. " (💡100% + ☾)\n"
|
|
end
|
|
else
|
|
return retval .. "\n"
|
|
end
|
|
else
|
|
if self.current_times[num] == t[num] then
|
|
if self.warmth[num] <= 100 then
|
|
return retval .. " (☼)\n"
|
|
else
|
|
return retval .. " (☾)\n"
|
|
end
|
|
else
|
|
return retval .. "\n"
|
|
end
|
|
end
|
|
end
|
|
|
|
local location_string = ""
|
|
if location then
|
|
location_string = " " .. self:getLocationString()
|
|
end
|
|
|
|
local function add_line(text, easy)
|
|
return easy and "" or (" " .. text .. "\n")
|
|
end
|
|
|
|
local face = Font:getFace("scfont")
|
|
UIManager:show(InfoMessage:new{
|
|
face = face,
|
|
width = math.floor(Screen:getWidth() * (self.easy_mode and 0.75 or 0.90)),
|
|
text = title .. location_string .. ":\n\n" ..
|
|
info_line(0, _("Solar midnight:"), times, 1, face, request_easy) ..
|
|
add_line(_("Dawn"), request_easy) ..
|
|
info_line(4, _("Astronomic:"), times, 2, face, request_easy) ..
|
|
info_line(4, _("Nautical:"), times, 3, face, request_easy)..
|
|
info_line(request_easy and 0 or 4,
|
|
request_easy and _("Twilight:") or _("Civil:"), times, 4, face) ..
|
|
add_line(_("Dawn"), request_easy) ..
|
|
info_line(0, _("Sunrise:"), times, 5, face) ..
|
|
"\n" ..
|
|
info_line(0, _("Solar noon:"), times, 6, face, request_easy) ..
|
|
add_line("", request_easy) ..
|
|
info_line(0, _("Sunset:"), times, 7, face) ..
|
|
add_line(_("Dusk"), request_easy) ..
|
|
info_line(request_easy and 0 or 4,
|
|
request_easy and _("Twilight:") or _("Civil:"), times, 8, face) ..
|
|
info_line(4, _("Nautical:"), times, 9, face, request_easy) ..
|
|
info_line(4, _("Astronomic:"), times, 10, face, request_easy) ..
|
|
add_line(_("Dusk"), request_easy) ..
|
|
info_line(0, _("Solar midnight:"), times, midnight_index, face, request_easy)
|
|
})
|
|
end
|
|
|
|
-- title
|
|
-- location: add a location string
|
|
-- activator: nil .. current_times,
|
|
-- activate_sun .. sun times
|
|
-- activate_schedule .. scheduler times
|
|
function AutoWarmth:getTimesMenu(title, location, activator)
|
|
return {
|
|
text_func = function()
|
|
if location then
|
|
return title .. " " .. self:getLocationString()
|
|
end
|
|
return title
|
|
end,
|
|
callback = function()
|
|
self:showTimesInfo(title, location, activator, self.easy_mode)
|
|
end,
|
|
keep_menu_open = true,
|
|
}
|
|
end
|
|
|
|
function AutoWarmth:getLocationString()
|
|
if self.location ~= "" then
|
|
return self.location
|
|
else
|
|
return "(" .. self.latitude .. "," .. self.longitude .. ")"
|
|
end
|
|
end
|
|
|
|
return AutoWarmth
|