-
-
Save sebdelsol/494c897446deefe6995d8e38adc0a4b6 to your computer and use it in GitHub Desktop.
-- **MOVED to https://github.com/sebdelsol/KOReader.patches** | |
-- KOReader userpatch to show info in the file manager title bar | |
-- based on https://gist.github.com/hius07/c53bc1ed00e0490cb1a0709c5ed6e735#file-2-fm-title-info-lua | |
-- Menu added in the File browser menu (1st icon) to change all the settings and rearrange the items in the title bar | |
-- Items added: Custom text, Brightness Level, Warmth Level, Up time, Time spent awake, Time in suspend | |
-- Settings added: Auto refresh clock, Custom separator, Number of spaces around separator, Show wifi when disabled, Show frontlight when off, Show path | |
-- Fix screen rotation (path was disappearing) | |
-- Arrange items reorders the items the menu | |
local BD = require("ui/bidi") | |
local Device = require("device") | |
local FileManager = require("apps/filemanager/filemanager") | |
local FileManagerMenu = require("apps/filemanager/filemanagermenu") | |
local FileManagerMenuOrder = require("ui/elements/filemanager_menu_order") | |
local InputDialog = require("ui/widget/inputdialog") | |
local NetworkMgr = require("ui/network/manager") | |
local SortWidget = require("ui/widget/sortwidget") | |
local SpinWidget = require("ui/widget/spinwidget") | |
local UIManager = require("ui/uimanager") | |
local datetime = require("datetime") | |
local time = require("ui/time") | |
local T = require("ffi/util").template | |
local _ = require("gettext") | |
local Screen = Device.screen | |
local logger = require("logger") | |
-- Title bar config | |
local separators = { | |
bar = "|", | |
bullet = "•", | |
dot = "·", | |
en_dash = "-", | |
em_dash = "—", | |
none = "", | |
} | |
local config_default = { | |
-- items | |
show = { | |
wifi = true, | |
memory = false, | |
storage = false, | |
custom_text = false, | |
clock = true, | |
battery = true, | |
frontlight = false, | |
frontlight_warmth = false, | |
up_time = false, | |
awake_time = false, | |
suspend_time = false, | |
}, | |
-- items order | |
order = { | |
"wifi", | |
"memory", | |
"storage", | |
"custom_text", | |
"clock", | |
"battery", | |
"frontlight", | |
"frontlight_warmth", | |
"up_time", | |
"awake_time", | |
"suspend_time", | |
}, | |
-- settings | |
custom_text = "KOReader", | |
separator = "dot", | |
separator_space = 1, | |
separator_custom = "*", | |
show_path = true, | |
auto_refresh_clock = true, | |
wifi_show_disabled = false, | |
frontlight_show_off = true, | |
bold = false, | |
} | |
local function load_and_update_config() | |
local config = G_reader_settings:readSetting("filemanager_title_bar", config_default) | |
local updated = false | |
local function compare_and_update_config(config_to_browse, config_to_compare) | |
for setting, setting_value in pairs(config_to_browse) do | |
if type(setting_value) ~= "table" then -- only the settings | |
if config_to_compare[setting] == nil then -- missing ? | |
updated = true | |
if config_to_compare == config then -- missing in config: add it | |
config[setting] = setting_value | |
else -- missing in config_default: remove it | |
config[setting] = nil | |
end | |
end | |
end | |
end | |
for item, item_value in pairs(config_to_browse.show) do | |
if config_to_compare.show[item] == nil then -- missing ? | |
updated = true | |
if config_to_compare == config then -- missing in config: add it | |
config.show[item] = item_value | |
table.insert(config.order, item) | |
else -- missing in config_default: remove it | |
config.show[item] = nil | |
for i, _item in ipairs(config.order) do | |
if _item == item then | |
table.remove(config.order, i) | |
break | |
end | |
end | |
end | |
end | |
end | |
end | |
compare_and_update_config(config, config_default) | |
compare_and_update_config(config_default, config) | |
if updated then logger.info("Updated title bar config", config) end | |
separators.custom = config.separator_custom | |
return config | |
end | |
local config = load_and_update_config() | |
-- Title bar update | |
local genItemText = { | |
custom_text = function() return config.custom_text end, | |
clock = function() return datetime.secondsToHour(os.time(), G_reader_settings:isTrue("twelve_hour_clock")) end, | |
wifi = function() return NetworkMgr:isWifiOn() and "" or (config.wifi_show_disabled and "") end, | |
frontlight_warmth = function() | |
if Device:hasNaturalLight() then | |
local prefix = "💡" | |
local powerd = Device:getPowerDevice() | |
if powerd:isFrontlightOn() then | |
local warmth = powerd:frontlightWarmth() | |
if warmth then return (prefix .. "%d%%"):format(warmth) end | |
else | |
return config.frontlight_show_off and T(_("%1Off"), prefix) | |
end | |
end | |
end, | |
frontlight = function() | |
if Device:hasFrontlight() then | |
local prefix = "☼" | |
local powerd = Device:getPowerDevice() | |
if powerd:isFrontlightOn() then | |
if Device:isCervantes() or Device:isKobo() then | |
return (prefix .. "%d%%"):format(powerd:frontlightIntensity()) | |
else | |
return (prefix .. "%d"):format(powerd:frontlightIntensity()) | |
end | |
else | |
return config.frontlight_show_off and T(_("%1Off"), prefix) | |
end | |
end | |
end, | |
battery = function() | |
if Device:hasBattery() then | |
local powerd = Device:getPowerDevice() | |
local batt_lvl = powerd:getCapacity() | |
local batt_symbol = powerd:getBatterySymbol(powerd:isCharged(), powerd:isCharging(), batt_lvl) | |
local text = BD.wrap(batt_symbol) .. BD.wrap(batt_lvl .. "%") | |
if Device:hasAuxBattery() and powerd:isAuxBatteryConnected() then | |
local aux_batt_lvl = powerd:getAuxCapacity() | |
local aux_batt_symbol = | |
powerd:getBatterySymbol(powerd:isAuxCharged(), powerd:isAuxCharging(), aux_batt_lvl) | |
text = text .. " " .. BD.wrap("+") .. BD.wrap(aux_batt_symbol) .. BD.wrap(aux_batt_lvl .. "%") | |
end | |
return text | |
end | |
end, | |
up_time = function(self) | |
local SystemStat = self:_getSystemStat() | |
if SystemStat then | |
local uptime = time.boottime_or_realtime_coarse() - SystemStat.start_monotonic_time | |
return "⏻" .. datetime.secondsToClockDuration("modern", time.to_s(uptime), true, false, true) -- ⏽ | |
end | |
end, | |
awake_time = function(self) | |
local SystemStat = self:_getSystemStat() | |
if SystemStat and (Device:canSuspend() or Device:canStandby()) then | |
local uptime = time.boottime_or_realtime_coarse() - SystemStat.start_monotonic_time | |
local suspend = Device:canSuspend() and Device.total_suspend_time or 0 | |
local standby = Device:canStandby() and Device.total_standby_time or 0 | |
local awake = uptime - suspend - standby | |
return "☀️" .. datetime.secondsToClockDuration("modern", time.to_s(awake), true, false, true) -- ☀☉⚡☀️ | |
end | |
end, | |
suspend_time = function(self) | |
local SystemStat = self:_getSystemStat() | |
if SystemStat and Device:canSuspend() then | |
local suspend = Device.total_suspend_time | |
return "⏾" .. datetime.secondsToClockDuration("modern", time.to_s(suspend), true, false, true) -- ⏾💤😴⏸️ | |
end | |
end, | |
storage = function(self) | |
local SystemStat = self:_getSystemStat() | |
if SystemStat then | |
SystemStat.kv_pairs = {} | |
SystemStat:appendStorageInfo() | |
return SystemStat.kv_pairs[3][2] -- available storage | |
end | |
end, | |
memory = function() | |
local statm = io.open("/proc/self/statm", "r") | |
if statm then | |
local _, rss = statm:read("*number", "*number") | |
statm:close() | |
return rss and ("%d"):format(math.floor(rss / 256)) | |
end | |
end, | |
} | |
-- get SystemStat | |
function FileManager:_getSystemStat() | |
if self.systemstat then | |
local userpatch = require("userpatch") | |
return userpatch.getUpValue(self.systemstat.addToMainMenu, "SystemStat") | |
end | |
end | |
-- handle close : need to remove schedule update for clock auto refresh | |
local orig_FileManager_onClose = FileManager.onClose | |
FileManager.onClose = function(self) | |
orig_FileManager_onClose(self) | |
UIManager:unschedule(self.updateTitleBarTitle) | |
end | |
-- handle screen rotation | |
local orig_FileManager_onSetRotationMode = FileManager.onSetRotationMode | |
FileManager.onSetRotationMode = function(self, mode) | |
orig_FileManager_onSetRotationMode(self, mode) | |
self:updateTitleBarTitle() | |
end | |
-- redraw the title bar | |
function FileManager:updateTitleBarTitle() | |
if self.title_bar == nil then return end | |
local titlebar_texts = {} | |
for _, item in ipairs(config.order) do | |
if config.show[item] then | |
local text = genItemText[item](self) | |
if text then table.insert(titlebar_texts, text) end | |
end | |
end | |
-- logger.info("FileManager:updateTitleBarTitle CALLED") | |
local font_has_changed | |
local not_bold_font = self.title_bar.info_text_face | |
if config.bold then | |
font_has_changed = self.title_bar.title_face == not_bold_font | |
else | |
font_has_changed = self.title_bar.title_face ~= not_bold_font | |
end | |
if font_has_changed then | |
if config.bold then | |
self.title_bar.title_face = nil | |
self.title_bar.bottom_v_padding = self._title_bar_bottom_v_padding_saved | |
else | |
self.title_bar.title_face = not_bold_font | |
self.title_bar.bottom_v_padding = self._title_bar_bottom_v_padding_saved + Screen:scaleBySize(5) | |
end | |
self.title_bar:clear() | |
self.title_bar:init() | |
end | |
local spaces = string.rep(" ", config.separator_space) | |
local seperator = spaces .. (separators[config.separator] or "") .. spaces | |
self.title_bar:setTitle(table.concat(titlebar_texts, seperator)) | |
self:updateTitleBarPath(config.show_path and self._title_bar_path_saved or "") | |
-- autorefresh time | |
UIManager:unschedule(self.updateTitleBarTitle) | |
if config.show.clock and config.auto_refresh_clock then | |
UIManager:scheduleIn(61 - tonumber(os.date("%S")), self.updateTitleBarTitle, self) | |
end | |
end | |
FileManager.onNetworkConnected = FileManager.updateTitleBarTitle | |
FileManager.onNetworkDisconnected = FileManager.updateTitleBarTitle | |
FileManager.onCharging = FileManager.updateTitleBarTitle | |
FileManager.onNotCharging = FileManager.updateTitleBarTitle | |
FileManager.onResume = FileManager.updateTitleBarTitle | |
FileManager.onTimeFormatChanged = FileManager.updateTitleBarTitle | |
FileManager.onFrontlightStateChanged = FileManager.updateTitleBarTitle | |
function FileManager:onPathChanged(path) | |
-- logger.info("FileManager:onPathChanged CALLED") | |
if not self._title_bar_bottom_v_padding_saved then | |
self._title_bar_bottom_v_padding_saved = self.title_bar.bottom_v_padding | |
end | |
self._title_bar_path_saved = path | |
self:updateTitleBarTitle() -- updateTitleBarPath done in updateTitleBarTitle | |
end | |
-- Title bar menu | |
function FileManagerMenu:_title_bar_input_text(touchmenu_instance, title, input, onChanged) | |
local text_dialog | |
text_dialog = InputDialog:new { | |
title = title, | |
input = input, | |
buttons = { | |
{ | |
{ | |
text = _("Cancel"), | |
id = "close", | |
callback = function() UIManager:close(text_dialog) end, | |
}, | |
{ | |
text = _("Set"), | |
is_enter_default = true, | |
callback = function() | |
onChanged(text_dialog:getInputText()) | |
UIManager:close(text_dialog) | |
touchmenu_instance:updateItems() | |
self.ui:updateTitleBarTitle() | |
end, | |
}, | |
}, | |
}, | |
} | |
UIManager:show(text_dialog) | |
text_dialog:onShowKeyboard() | |
end | |
-- Separators | |
local setting_menu_texts | |
function FileManagerMenu:_set_title_bar_separator_space(touchmenu_instance) | |
local spin_widget = SpinWidget:new { | |
title_text = setting_menu_texts.separator_space(true), | |
value = config.separator_space, | |
value_min = 1, | |
value_step = 1, | |
value_max = 5, | |
callback = function(spin) | |
config.separator_space = spin.value | |
touchmenu_instance:updateItems() | |
self.ui:updateTitleBarTitle() | |
end, | |
} | |
UIManager:show(spin_widget) | |
end | |
function FileManagerMenu:_set_title_bar_custom_separator_text(touchmenu_instance) | |
self:_title_bar_input_text(touchmenu_instance, _("Enter a custom separator"), separators.custom, function(text) | |
config.separator_custom = text | |
separators.custom = text | |
end) | |
end | |
local separator_menu_texts = { | |
dot = _("Dot"), | |
bullet = _("Bullet"), | |
en_dash = _("En dash"), | |
em_dash = _("Em dash"), | |
bar = _("Vertical bar"), | |
none = _("No separator"), | |
custom = function(concise) return concise and _("Custom separator") or _("Custom separator (long-press to edit)") end, | |
} | |
local separators_menu_help_text_funcs = { | |
custom = FileManagerMenu._set_title_bar_custom_separator_text, | |
} | |
local separators_order = { | |
"dot", | |
"bullet", | |
"en_dash", | |
"em_dash", | |
"bar", | |
"custom", | |
"none", | |
} | |
local function get_separator_menu_texts(separator, concise) | |
text = separator_menu_texts[separator] | |
if type(text) == "function" then text = text(concise) end | |
local spaces = string.rep(" ", config.separator_space) | |
local seperator = separators[config.separator] or "" | |
return T(text .. " '" .. spaces .. "%1" .. spaces .. "'", separators[separator]) | |
end | |
function FileManagerMenu:_get_title_bar_separators_submenu() | |
local items = {} | |
for _, separator in ipairs(separators_order) do | |
local help_text_func = separators_menu_help_text_funcs[separator] | |
table.insert(items, { | |
text_func = function() return get_separator_menu_texts(separator) end, | |
help_text_func = help_text_func | |
and function(touchmenu_instance) help_text_func(self, touchmenu_instance) end, | |
checked_func = function() return config.separator == separator end, | |
callback = function(touchmenu_instance) | |
config.separator = separator | |
touchmenu_instance:updateItems() | |
self.ui:updateTitleBarTitle() | |
end, | |
}) | |
end | |
items[#items].separator = true | |
table.insert(items, { | |
text_func = setting_menu_texts.separator_space, | |
keep_menu_open = true, | |
callback = function(touchmenu_instance) self:_set_title_bar_separator_space(touchmenu_instance) end, | |
}) | |
return items | |
end | |
-- items | |
function FileManagerMenu:_set_title_bar_custom_text(touchmenu_instance) | |
self:_title_bar_input_text( | |
touchmenu_instance, | |
_("Enter a custom text"), | |
config.custom_text or "", | |
function(text) config.custom_text = text end | |
) | |
end | |
local item_menu_texts = { | |
wifi = _("Wifi"), | |
memory = _("Memory"), | |
storage = _("Storage"), | |
clock = _("Clock"), | |
battery = _("Battery"), | |
frontlight = _("Brightness level"), | |
frontlight_warmth = _("Warmth level"), | |
up_time = _("Up time"), | |
awake_time = _("Time spent awake"), | |
suspend_time = _("Time in suspend"), | |
custom_text = function(concise) | |
return concise and _("Custom text") or T(_("Custom text (long-press to edit): '%1'"), config.custom_text) | |
end, | |
} | |
local item_menu_help_texts = { | |
memory = _("RAM used, MiB"), | |
storage = _("Free storage, requires SystemStat plugin"), | |
custom_text = FileManagerMenu._set_title_bar_custom_text, | |
} | |
function FileManagerMenu:_title_bar_arrange_items(item_table_rebuild) | |
return { | |
text = _("Arrange title bar items"), | |
keep_menu_open = true, | |
enabled_func = function() | |
local show_count = 0 -- count shown items | |
for _, item in ipairs(config.order) do | |
show_count = show_count + (config.show[item] and 1 or 0) | |
if show_count >= 1 then return true end | |
end | |
return false | |
end, | |
callback = function(touchmenu_instance) | |
local item_table = {} | |
for _, item in ipairs(config.order) do | |
local text = item_menu_texts[item] | |
table.insert(item_table, { | |
text = type(text) == "function" and text(true) or text, | |
orig_item = item, | |
dim = not config.show[item], | |
}) | |
end | |
local sort_item | |
sort_item = SortWidget:new { | |
title = _("Arrange title bar items"), | |
item_table = item_table, | |
callback = function() | |
for i, item in ipairs(item_table) do | |
config.order[i] = item.orig_item | |
end | |
if item_table_rebuild then -- rebuild the item_table, so the items in the menu are reordered | |
touchmenu_instance.item_table = item_table_rebuild() | |
touchmenu_instance:updateItems() | |
end | |
self.ui:updateTitleBarTitle() | |
UIManager:setDirty(nil, "ui") | |
end, | |
} | |
UIManager:show(sort_item) | |
end, | |
} | |
end | |
function FileManagerMenu:_get_title_bar_item(item) | |
local text = item_menu_texts[item] | |
local help_text = item_menu_help_texts[item] | |
return { | |
text = type(text) == "string" and text, | |
text_func = type(text) == "function" and function() return text() end, | |
help_text = type(help_text) == "string" and help_text, | |
help_text_func = type(help_text) == "function" | |
and function(touchmenu_instance) help_text(self, touchmenu_instance) end, | |
checked_func = function() return config.show[item] end, | |
callback = function(touchmenu_instance) | |
config.show[item] = not config.show[item] | |
touchmenu_instance:updateItems() | |
self.ui:updateTitleBarTitle() | |
end, | |
} | |
end | |
-- settings | |
setting_menu_texts = { -- already declared above | |
auto_refresh_clock = _("Auto refresh clock"), | |
show_path = _("Show file browser path"), | |
wifi_show_disabled = _("Show wifi status even when disabled"), | |
frontlight_show_off = _("Show frontlight when off"), | |
bold = _("Bold font"), | |
separator = function() return T(_("Item separator: %1"), get_separator_menu_texts(config.separator, true)) end, | |
custom_text = function() return T(_("Custom text: '%1'"), config.custom_text) end, | |
separator_space = function(concise) | |
return concise and _("Number of spaces around separator") | |
or T(_("Number of spaces around separator: %1"), config.separator_space) | |
end, | |
} | |
local setting_menu_callback = { | |
custom_text = FileManagerMenu._set_title_bar_custom_text, | |
separator_space = FileManagerMenu._set_title_bar_separator_space, | |
} | |
local setting_submenu_items = { | |
separator = FileManagerMenu._get_title_bar_separators_submenu, | |
} | |
local setting_menu_enable_func = { | |
auto_refresh_clock = function() return config.show.clock end, | |
wifi_show_disabled = function() return config.show.wifi end, | |
frontlight_show_off = function() return config.show.frontlight or config.show.frontlight_warmth end, | |
custom_text = function() return config.show.custom_text end, | |
} | |
local setting_menu_order = { | |
"bold", | |
"wifi_show_disabled", | |
"frontlight_show_off", | |
"auto_refresh_clock", | |
"show_path", | |
"custom_text", | |
"separator", | |
} | |
function FileManagerMenu:_get_title_bar_setting(setting) | |
local text = setting_menu_texts[setting] | |
local submenu = setting_submenu_items[setting] | |
local enabled_func = setting_menu_enable_func[setting] | |
local callback_func = setting_menu_callback[setting] | |
return { | |
text = type(text) == "string" and text, | |
text_func = type(text) == "function" and function() return text() end, | |
enabled_func = enabled_func and function() return enabled_func() end, | |
checked_func = not (submenu or callback_func) and function() return config[setting] end, | |
callback = not submenu and function(touchmenu_instance) | |
if callback_func then | |
callback_func(self, touchmenu_instance) | |
else | |
config[setting] = not config[setting] | |
touchmenu_instance:updateItems() | |
end | |
self.ui:updateTitleBarTitle() | |
end, | |
keep_menu_open = callback_func ~= nil, | |
sub_item_table = submenu and submenu(self), | |
} | |
end | |
-- Patch title bar menu | |
local orig_FileManagerMenu_setUpdateItemTable = FileManagerMenu.setUpdateItemTable | |
FileManagerMenu.setUpdateItemTable = function(self) | |
orig_FileManagerMenu_setUpdateItemTable(self) | |
local buttons = FileManagerMenuOrder["KOMenu:menu_buttons"] | |
for i, button in ipairs(buttons) do | |
if button == "filemanager_settings" then | |
logger.info("Add title bar options in the file manager settings menu") | |
local setting_table = {} | |
for _, setting in ipairs(setting_menu_order) do | |
table.insert(setting_table, self:_get_title_bar_setting(setting)) | |
end | |
local sub_item_table_func | |
sub_item_table_func = function() | |
local _table = { | |
{ | |
text = _("Configure title bar"), | |
sub_item_table = setting_table, | |
}, | |
self:_title_bar_arrange_items(sub_item_table_func), | |
} | |
_table[#_table].separator = true | |
for _, item in ipairs(config.order) do | |
table.insert(_table, self:_get_title_bar_item(item)) | |
end | |
return _table | |
end | |
table.insert(self.tab_item_table[i], 1, { | |
text = _("Title bar"), | |
separator = true, | |
sub_item_table_func = sub_item_table_func, | |
}) | |
break | |
end | |
end | |
end |
Nice, thankyou for the repo. There is something similar for https://github.com/kiwidude68/calibre_plugins who compiled all his calibre plugins in one repo.
Maybe create your own thread at https://www.mobileread.com/forums/forumdisplay.php?f=276 for more user visibility/feedback?
with something like "My custom user patch collection" title?
Also please do add any foss license file to the repo.
Oh I always forget about that. Tx for reminding me
I've tried to reproduce the bug (on a Kindle as well). In the file manager, I toggled on the title bar with the clock visible and enabled Auto refresh clock
. However, I wasn't able to reproduce the bug. By the way, the clock placement doesn't align with the title bar: It should be centered.
Is there a way to change the font?
There this new user patch : 2-ui-font.lua that allows to change the UI font.
I've to check that. It uses the default UI font. Should it uses its own font, whatever the UI one is ?
If you want to change all the UI fonts, which would be a more consistent solution UX wise, you can use this user patch.