Skip to content

Instantly share code, notes, and snippets.

@sebdelsol
Last active June 27, 2025 10:52
Show Gist options
  • Save sebdelsol/eba2e492473ac1f9e0ecb003d403b7de to your computer and use it in GitHub Desktop.
Save sebdelsol/eba2e492473ac1f9e0ecb003d403b7de to your computer and use it in GitHub Desktop.
KOReader user patch: change status bar progress color
-- MOVED TO https://github.com/sebdelsol/KOReader.patches
-- based on https://gist.github.com/IntrovertedMage/d759ff214f799cfb5e1f8c85daab6cae
-- Menu added in the Reader menu:
-- settings > Status bar > Progress bar > Thickness, height & colors > Read color
-- settings > Status bar > Progress bar > Thickness, height & colors > Unread color
local Blitbuffer = require("ffi/blitbuffer")
local Math = require("optmath")
local ProgressWidget = require("ui/widget/progresswidget")
local ReaderFooter = require("apps/reader/modules/readerfooter")
local SpinWidget = require("ui/widget/spinwidget")
local UIManager = require("ui/uimanager")
local _ = require("gettext")
local T = require("ffi/util").template
-- local logger = require("logger")
-- Utils
local function serializeColor(color) return color.a end
local function deserializeColor(value) return Blitbuffer.Color8(value) end
local function blackPctOfColor(color) return Math.round((0xFF - color.a) * 100 / 0xFF) end
local function colorFromBlackPct(percent) return Blitbuffer.gray(Math.round(percent / 100)) end
-- Settings
local Settings = {}
local function colorAttrib(read) return read and "fillcolor" or "bgcolor" end
local function getStyle(thin) return thin and "progress_style_thin_colors" or "progress_style_thick_colors" end
function Settings:init(footer)
local function defaultColor(thin)
ProgressWidget:updateStyle(not thin, nil, false) -- no object needed, since height is nil, do no set colors
local read, unread = colorAttrib(true), colorAttrib(false)
return {
[read] = serializeColor(ProgressWidget[read]),
[unread] = serializeColor(ProgressWidget[unread]),
}
end
self.footer = footer
self.default = {
[getStyle(true)] = defaultColor(true),
[getStyle(false)] = defaultColor(false),
}
end
function Settings:getDefault(thin, color_attrib)
local default = self.default[getStyle(thin)]
return deserializeColor(self.default[getStyle(thin)][color_attrib])
end
function Settings:get(thin, color_attrib)
local settings = self.footer.settings and self.footer.settings[getStyle(thin)]
local color = settings and settings[color_attrib]
return color and deserializeColor(color) or self:getDefault(thin, color_attrib)
end
function Settings:set(thin, color_attrib, color)
local style = getStyle(thin)
local settings = self.footer.settings[style] or {}
settings[color_attrib] = serializeColor(color)
self.footer.settings[style] = settings
end
-- ReaderFooter
local orig_ReadFooter_init = ReaderFooter.init
function ReaderFooter:init()
Settings:init(self)
orig_ReadFooter_init(self)
self.progress_bar:setColors(self.settings.progress_style_thin)
end
-- ProgressWidget
local orig_ProgressWidget_updateStyle = ProgressWidget.updateStyle
function ProgressWidget:updateStyle(thick, height, do_setcolors)
do_setcolors = do_setcolors or do_setcolors == nil -- default: do_setcolors = true
orig_ProgressWidget_updateStyle(self, thick, height)
if do_setcolors then self:setColors(not thick) end
end
function ProgressWidget:setColors(thin)
local read, unread = colorAttrib(true), colorAttrib(false)
self[read] = Settings:get(thin, read)
self[unread] = Settings:get(thin, unread)
end
-- Menu
local function getMenuItem(menu, ...) -- path
local function findItem(sub_items, texts)
local find = {}
local texts = type(texts) == "table" and texts or { texts }
-- stylua: ignore
for _, text in ipairs(texts) do find[text] = true end
for _, item in ipairs(sub_items) do
local text = item.text or (item.text_func and item.text_func())
if text and find[text] then return item end
end
end
local sub_items, item
for _, texts in ipairs { ... } do -- walk path
sub_items = (item or menu).sub_item_table
if not sub_items then return end
item = findItem(sub_items, texts)
if not item then return end
end
return item
end
function ReaderFooter:statusBarColorMenu(read)
local color_attrib = colorAttrib(read)
return {
text_func = function()
return T(
read and _("Read color: %1% black") or _("Unread color: %1% black"),
blackPctOfColor(self.progress_bar[color_attrib])
)
end,
keep_menu_open = true,
enabled_func = function() return not self.settings.disable_progress_bar end,
callback = function(touchmenu_instance)
local spin_widget = SpinWidget:new {
title_text = read and _("Read color % black") or _("Unread color % black"),
default_value = blackPctOfColor(Settings:getDefault(self.settings.progress_style_thin, color_attrib)),
value = blackPctOfColor(self.progress_bar[color_attrib]),
value_min = 0,
value_step = 1,
value_hold_step = 10,
value_max = 100,
unit = "% " .. _("black"),
callback = function(spin)
local color = colorFromBlackPct(spin.value)
Settings:set(self.settings.progress_style_thin, color_attrib, color)
self.progress_bar[color_attrib] = color
touchmenu_instance:updateItems()
self:refreshFooter(true)
end,
}
UIManager:show(spin_widget)
end,
}
end
local orig_ReaderFooter_addToMainMenu = ReaderFooter.addToMainMenu
function ReaderFooter:addToMainMenu(menu_items)
orig_ReaderFooter_addToMainMenu(self, menu_items)
local item = getMenuItem(
menu_items.status_bar,
_("Progress bar"),
{ _("Thickness and height: thin"), _("Thickness and height: thick") }
)
if item then
item.text_func = function()
return self.settings.progress_style_thin and _("Thickness, height & colors: thin")
or _("Thickness, height & colors: thick")
end
table.insert(item.sub_item_table, self:statusBarColorMenu(true))
table.insert(item.sub_item_table, self:statusBarColorMenu(false))
end
end
@HahBikes
Copy link

HahBikes commented May 18, 2025

Does this only work in black and white, or can I use actual colors, too? I can only update the % value, so it just adjusts the bar's blackness. But it's always xx% black. There's no way to change it to any other color?

@sebdelsol
Copy link
Author

sebdelsol commented May 18, 2025

so it just adjusts the bar's blackness.

At the moment, it's only in B&W (I have a B&W e-reader).
It works great for enhancing contrast when you've got a thin progress bar with chapter marks: that’s another user patch of mine.
Reader_Fugitive Telemetry - Martha Wells (468) epub_p11_2025-05-19_012341

But I could add RGB color if needed. It should have its own dedicated menu, though.
I was actually rewriting this user patch to make that easier to implement.

@sebdelsol
Copy link
Author

By the way how would you like to edit a RGB color in the menu ?

  1. by entering its RGB value ?
  2. with 3 spin widgets (one for each component) ?

@HahBikes
Copy link

Entering the RGB value will work I guess

@sebdelsol
Copy link
Author

sebdelsol commented May 25, 2025

Sorry, I didn’t do anything about your request earlier because my e-reader is B&W. I’ve now installed the KOReader emulator, so it’ll be easier to code & test that kind of stuff.

@sebdelsol
Copy link
Author

@mih198830
Copy link

Sorry for silly question, i am libra colour user,
how can i change default color instead black without touching lua file?

@sebdelsol
Copy link
Author

sebdelsol commented Jun 26, 2025

There are no silly questions.
It's not supported at the moment. Please raise an issue in my repository, and I’ll look into how to implement it.

@mih198830
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment