Skip to content

Commit 7b2b75f

Browse files
committed
allow default tab without enabling tab, fix opening banner confirmation, page browser fixes
1 parent cccd614 commit 7b2b75f

11 files changed

Lines changed: 412 additions & 21 deletions

common/library_navigation.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ local function closeConfigMenuForTransition(ui)
1111
if not ok then error(err) end
1212
end
1313

14+
local function closeReaderOverlays(ui)
15+
local was_tearing_down = ui.tearing_down
16+
ui.tearing_down = true
17+
local ok, err = pcall(
18+
require("common/utils").closeWidgetsAbove, ui.dialog or ui)
19+
ui.tearing_down = was_tearing_down
20+
if not ok then error(err) end
21+
end
22+
1423
function M.restoreEnabled(plugin)
1524
local features = plugin and plugin.config and plugin.config.features
1625
return type(features) == "table" and features.restore_library_view == true
@@ -56,6 +65,7 @@ function M.showFromReader(ui, plugin, opts)
5665
_G.__ZEN_UI_LAST_READ_FILE = file
5766

5867
closeConfigMenuForTransition(ui)
68+
closeReaderOverlays(ui)
5969
if M.returnToRakuyomiReader(restore, plugin) then
6070
return true
6171
end

modules/filebrowser/patches/navbar.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,15 +1367,15 @@ local function apply_navbar()
13671367
return first_enabled_default_tab()
13681368
end
13691369
if tab_id:sub(1, 3) == "ct_" then
1370-
if tab_callbacks[tab_id] and is_tab_enabled(tab_id) then
1370+
if tab_callbacks[tab_id] then
13711371
return tab_id
13721372
end
13731373
return first_enabled_default_tab()
13741374
end
13751375
if not default_tab_whitelist[tab_id] then
13761376
return first_enabled_default_tab()
13771377
end
1378-
if tab_callbacks[tab_id] and is_tab_enabled(tab_id) then
1378+
if tab_callbacks[tab_id] then
13791379
return tab_id
13801380
end
13811381
return first_enabled_default_tab()

modules/reader/patches/bookmarks.lua

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,19 @@ local function apply_bookmarks()
66
local ReaderBookmark = require("apps/reader/modules/readerbookmark")
77
local Device = require("device")
88

9+
local _orig_gotoBookmark = ReaderBookmark.gotoBookmark
10+
if type(_orig_gotoBookmark) == "function" then
11+
ReaderBookmark.gotoBookmark = function(self, ...)
12+
local bm_menu = self.bookmark_menu and self.bookmark_menu[1]
13+
local page_browser = bm_menu and bm_menu._zen_page_browser_parent
14+
if page_browser then
15+
bm_menu._zen_page_browser_parent = nil
16+
page_browser:onClose()
17+
end
18+
return _orig_gotoBookmark(self, ...)
19+
end
20+
end
21+
922
local function supports_hardware_focus()
1023
local has_dpad = type(Device.hasDPad) == "function" and Device:hasDPad()
1124
local has_keyboard = type(Device.hasKeyboard) == "function" and Device:hasKeyboard()

modules/reader/patches/opening_banner.lua

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,28 @@ local function apply_opening_banner()
393393
-- Tiny inline widget: black rect + centred "Opening" text
394394
local OpeningBanner = Widget:extend{}
395395

396+
function OpeningBanner:onShow()
397+
self._timeout_func = function()
398+
self._timeout_func = nil
399+
UIManager:close(self)
400+
end
401+
UIManager:scheduleIn(10, self._timeout_func)
402+
end
403+
404+
function OpeningBanner:onCloseWidget()
405+
if self._timeout_func then
406+
UIManager:unschedule(self._timeout_func)
407+
self._timeout_func = nil
408+
end
409+
if pending_banner == self then
410+
pending_banner = nil
411+
pending_banner_seq = nil
412+
end
413+
UIManager:setDirty(nil, function()
414+
return "ui", self.dimen
415+
end)
416+
end
417+
396418
function OpeningBanner:paintTo(bb, x, y)
397419
self.dimen.x = x
398420
self.dimen.y = y
@@ -484,6 +506,36 @@ local function apply_opening_banner()
484506
pending_banner_seq = nil
485507
end
486508

509+
rawset(_G, "__ZEN_UI_CANCEL_OPENING_BANNER", function()
510+
if pending_banner then
511+
clear_pending_banner()
512+
_last_cover_dimen = nil
513+
end
514+
end)
515+
516+
local ok_confirm, ConfirmBox = pcall(require, "ui/widget/confirmbox")
517+
if ok_confirm and type(ConfirmBox.new) == "function"
518+
and not ConfirmBox._zen_opening_banner_cancel_callback_patched then
519+
ConfirmBox._zen_opening_banner_cancel_callback_patched = true
520+
local orig_new = ConfirmBox.new
521+
local prompt_prefix = _("Open this file?") .. "\n\n"
522+
local open_text = _("Open")
523+
ConfirmBox.new = function(class, props, ...)
524+
if type(props) == "table" and type(props.text) == "string"
525+
and props.text:sub(1, #prompt_prefix) == prompt_prefix
526+
and props.ok_text == open_text
527+
and G_reader_settings and G_reader_settings:isTrue("file_ask_to_open") then
528+
local orig_cancel = props.cancel_callback
529+
props.cancel_callback = function(...)
530+
if orig_cancel then orig_cancel(...) end
531+
local cancel_banner = rawget(_G, "__ZEN_UI_CANCEL_OPENING_BANNER")
532+
if type(cancel_banner) == "function" then cancel_banner() end
533+
end
534+
end
535+
return orig_new(class, props, ...)
536+
end
537+
end
538+
487539
show_prepared_banner = function()
488540
if _banner_active or not _last_cover_dimen then return end
489541
clear_pending_banner()

modules/reader/patches/page_browser.lua

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,19 @@ local function apply_page_browser()
124124
canvas:paintRect(0, title_h - 1, slot_w, 1, Blitbuffer.COLOR_LIGHT_GRAY)
125125
local stock_icons_dir = _stock_icons_dir
126126
local header_icons = {
127-
"appbar.search", "info", "appbar.textsize", "bookmark",
127+
{ "appbar.search", stock_icons_dir },
128+
{ "info", _icons_dir },
129+
{ "appbar.textsize", stock_icons_dir },
130+
{ "bookmark", stock_icons_dir },
128131
}
129-
for i, icon_name in ipairs(header_icons) do
130-
local icon_dir = icon_name == "info" and _icons_dir or stock_icons_dir
131-
local icon_path = icon_dir and utils.resolveLocalIcon(icon_dir, icon_name)
132+
local vocab_icon_path = package.loaded["db"]
133+
and _icons_dir and utils.resolveLocalIcon(_icons_dir, "tab_vocab")
134+
if vocab_icon_path then
135+
table.insert(header_icons, 4, { nil, nil, vocab_icon_path })
136+
end
137+
for i, icon in ipairs(header_icons) do
138+
local icon_path = icon[3]
139+
or (icon[2] and utils.resolveLocalIcon(icon[2], icon[1]))
132140
paint_icon(nil, icon_path, slot_btn_w * (i - 1) + btn_pad, title_y, btn_sz)
133141
end
134142
local toc_icon_path = _icons_dir and utils.resolveLocalIcon(_icons_dir, "toc")
@@ -983,10 +991,18 @@ local function apply_page_browser()
983991
local function open_bookmarks()
984992
-- Keep the page browser underneath so closing bookmarks returns here.
985993
if pbw_ref.ui.bookmark then
986-
pbw_ref.ui.bookmark:onShowBookmark()
994+
local bookmark = pbw_ref.ui.bookmark
995+
bookmark:onShowBookmark()
996+
local bm_menu = bookmark.bookmark_menu and bookmark.bookmark_menu[1]
997+
if bm_menu then bm_menu._zen_page_browser_parent = pbw_ref end
987998
end
988999
end
9891000

1001+
local function open_vocab()
1002+
pbw_ref:onClose()
1003+
pbw_ref.ui:handleEvent(Event:new("ShowVocabBuilder"))
1004+
end
1005+
9901006
local function open_reader_menu()
9911007
local ui_ref = pbw_ref.ui
9921008
if not (ui_ref and ui_ref.config) then
@@ -1039,8 +1055,13 @@ local function apply_page_browser()
10391055
{ "bookmark", open_bookmarks, true },
10401056
{ "toc", open_toc },
10411057
}
1058+
local vocab_icon_path = package.loaded["db"]
1059+
and _icons_dir and utils.resolveLocalIcon(_icons_dir, "tab_vocab")
1060+
if vocab_icon_path then
1061+
table.insert(action_icons, 4, { nil, open_vocab, nil, vocab_icon_path })
1062+
end
10421063
for i, action in ipairs(action_icons) do
1043-
local icon_path = action[3] and resolve_stock_icon(action[1])
1064+
local icon_path = action[4] or (action[3] and resolve_stock_icon(action[1]))
10441065
or (_icons_dir and utils.resolveLocalIcon(_icons_dir, action[1]))
10451066
local button = make_header_btn(icon_path, slot_w * (i - 1), action[2])
10461067
table.insert(self.title_bar, button)

spec/lua/unit/library_navigation_spec.lua

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ describe("library navigation", function()
1818
})
1919
ZenSpec.replace("config/manager", { get = function() return {} end })
2020
ZenSpec.replace("MangaReader", { is_showing = false })
21+
ZenSpec.replace("common/utils", {
22+
closeWidgetsAbove = function(anchor)
23+
assert.is_true(anchor.tearing_down)
24+
anchor.overlays_closed = true
25+
end,
26+
})
2127
ZenSpec.unload("common/paths")
2228
ZenSpec.unload("common/library_navigation")
2329
Navigation = require("common/library_navigation")
@@ -35,6 +41,7 @@ describe("library navigation", function()
3541
end
3642
function state:onClose()
3743
assert.is_false(self.tearing_down)
44+
assert.is_true(self.overlays_closed)
3845
self.closed = true
3946
end
4047
function state:showFileManager(file_path)
@@ -43,6 +50,26 @@ describe("library navigation", function()
4350
return state
4451
end
4552

53+
it("closes reader overlays before rebuilding the library", function()
54+
local ui = reader()
55+
local dialog = {}
56+
ui.dialog = dialog
57+
ZenSpec.replace("common/utils", {
58+
closeWidgetsAbove = function(anchor)
59+
assert.are.equal(dialog, anchor)
60+
assert.is_true(ui.tearing_down)
61+
ui.overlays_closed = true
62+
end,
63+
})
64+
65+
Navigation.showFromReader(ui, {
66+
config = { features = { restore_library_view = false } },
67+
})
68+
69+
assert.is_true(ui.closed)
70+
assert.is_true(_G.__ZEN_UI_FORCE_DEFAULT_LIBRARY_TAB)
71+
end)
72+
4673
it("returns to the file manager with a requested non-retained tab", function()
4774
local ui = reader()
4875
local plugin = { config = { features = { restore_library_view = true } } }

spec/lua/unit/navbar_navigation_spec.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ describe("file browser navbar navigation", function()
252252
for _i, name in ipairs({
253253
"__ZEN_UI_PLUGIN", "__ZEN_UI_NAVBAR_OPEN_DEFAULT_TAB", "__ZEN_UI_NAVBAR_OPEN_TAB",
254254
"__ZEN_UI_NAVBAR_RESOLVE_DEFAULT_TAB", "__ZEN_UI_NAVBAR_IS_DEFAULT_TAB_ACTIVE",
255+
"__ZEN_UI_NAVBAR_DEFAULT_TAB_ICON",
255256
"__ZEN_UI_ACTIVE_TAB_LABEL",
256257
"__ZEN_UI_REINJECT_FM_NAVBAR", "__ZEN_UI_REINJECT_NAVBARS",
257258
"__ZEN_UI_LIBRARY_STATE", "__ZEN_UI_OPEN_HOME_AFTER_FILEMANAGER",
@@ -296,6 +297,15 @@ describe("file browser navbar navigation", function()
296297
assert.are.equal("Home", _G.__ZEN_UI_ACTIVE_TAB_LABEL)
297298
end)
298299

300+
it("opens a hidden default tab and keeps its top-menu icon", function()
301+
_G.__ZEN_UI_PLUGIN.config.navbar.show_tabs.home = false
302+
303+
assert.are.equal("home", _G.__ZEN_UI_NAVBAR_RESOLVE_DEFAULT_TAB())
304+
assert.are.equal("home", _G.__ZEN_UI_NAVBAR_DEFAULT_TAB_ICON())
305+
assert.are.equal("home", _G.__ZEN_UI_NAVBAR_OPEN_DEFAULT_TAB())
306+
assert.are.same({ "home" }, calls)
307+
end)
308+
299309
it("recognizes an already-active default tab", function()
300310
local fm = make_instance()
301311
UIManager._window_stack = { { widget = { _zen_navbar_tab_id = "home" } } }
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
describe("navbar settings", function()
2+
local arrange_options
3+
local config
4+
local saved
5+
local shown
6+
local touch_menu
7+
8+
local function find_arrange_item(id)
9+
for _i, item in ipairs(arrange_options.item_table) do
10+
if item.orig_item == id then return item end
11+
end
12+
end
13+
14+
before_each(function()
15+
arrange_options = nil
16+
saved = 0
17+
shown = {}
18+
touch_menu = {
19+
backToSettingsRoot = function() end,
20+
backToUpperMenu = function(self)
21+
self.back_count = (self.back_count or 0) + 1
22+
end,
23+
updateItems = function(self)
24+
self.update_count = (self.update_count or 0) + 1
25+
end,
26+
}
27+
config = {
28+
navbar = {
29+
default_tab = "home",
30+
show_tabs = { books = true, home = true },
31+
tab_order = { "books", "home" },
32+
custom_tabs = {},
33+
},
34+
}
35+
36+
ZenSpec.replace("gettext", function(text) return text end)
37+
ZenSpec.replace("ffi/util", {
38+
template = function(text, value)
39+
return text:gsub("%%1", tostring(value))
40+
end,
41+
})
42+
ZenSpec.replace("ui/uimanager", {
43+
scheduleIn = function(_self, _delay, callback) callback() end,
44+
show = function(_self, widget) shown[#shown + 1] = widget end,
45+
})
46+
ZenSpec.replace("ui/widget/confirmbox", {
47+
new = function(_self, opts) return opts end,
48+
})
49+
ZenSpec.replace("ui/widget/infomessage", {
50+
new = function(_self, opts) return opts end,
51+
})
52+
ZenSpec.replace("modules/settings/zen_settings_utils", {
53+
buildColorSubMenu = function(opts) return opts end,
54+
get_current_dir = function() return "/current" end,
55+
get_last_dir = function() return "/last" end,
56+
})
57+
ZenSpec.replace("common/utils", {
58+
copyDefaultCustomTabIcon = function() end,
59+
getIconPickerList = function() return {} end,
60+
suggestIcon = function() return "lightning" end,
61+
})
62+
ZenSpec.replace("common/paths", {
63+
getHomeDir = function() return "/home" end,
64+
})
65+
ZenSpec.replace("common/inline_icon_map", setmetatable({}, {
66+
__index = function(_self, key) return key end,
67+
}))
68+
ZenSpec.replace("common/ui/icon_menu_item", {
69+
decorate = function(item) return item end,
70+
})
71+
ZenSpec.replace("modules/menu/app_launcher/plugin_scan", {
72+
scan = function() return {} end,
73+
})
74+
ZenSpec.replace("common/dispatcher_menu", { wrap = function() end })
75+
ZenSpec.replace("dispatcher", {
76+
addSubMenu = function() end,
77+
menuTextFunc = function() return "Nothing" end,
78+
})
79+
ZenSpec.replace("common/ui/zen_icon_picker", function() end)
80+
ZenSpec.replace("common/ui/zen_arrange_list", {
81+
show = function(opts) arrange_options = opts end,
82+
})
83+
ZenSpec.replace("common/plugin_root", "/plugin")
84+
ZenSpec.unload("modules/settings/sections/library_settings/navbar_settings")
85+
end)
86+
87+
local function build_navbar()
88+
return require("modules/settings/sections/library_settings/navbar_settings").build({
89+
config = config,
90+
plugin = { saveConfig = function() saved = saved + 1 end },
91+
save_and_apply = function() end,
92+
settings_apply = { refresh_navbar_on_menu_close = function() end },
93+
})
94+
end
95+
96+
it("keeps the default when its tab is hidden", function()
97+
local navbar = build_navbar()
98+
navbar.sub_item_table[1].callback()
99+
100+
find_arrange_item("home").callback(touch_menu)
101+
102+
assert.is_false(config.navbar.show_tabs.home)
103+
assert.are.equal("home", config.navbar.default_tab)
104+
assert.are.equal(1, saved)
105+
assert.are.equal(0, #shown)
106+
end)
107+
108+
it("keeps the default when its built-in tab is deleted from the navbar", function()
109+
local navbar = build_navbar()
110+
navbar.sub_item_table[1].callback()
111+
local home_item = find_arrange_item("home")
112+
local home_settings = home_item.sub_item_table_func()
113+
114+
home_settings[#home_settings].callback(touch_menu)
115+
shown[1].ok_callback()
116+
117+
assert.is_false(config.navbar.show_tabs.home)
118+
assert.are.same({ "books" }, config.navbar.tab_order)
119+
assert.are.equal("home", config.navbar.default_tab)
120+
assert.are.equal(1, touch_menu.back_count)
121+
assert.are.equal(1, saved)
122+
end)
123+
end)

0 commit comments

Comments
 (0)