mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
14caaa58b9
Keep the reading view as the default exit while exposing KOReader's file browser as a separate action that closes the open book safely. Bypass the BookOrbit home preference for this explicit navigation. Closes #2013
210 lines
9.2 KiB
Lua
210 lines
9.2 KiB
Lua
-- Proves KOReader's side of BookOrbit: a trimmed Tools entry, the menu bar
|
|
-- tab that acts as a button (and its opt-out), the icon path the tab bar can
|
|
-- resolve, and where each of the menu sheet's actions goes.
|
|
|
|
package.loaded["gettext"] = function(text)
|
|
return text
|
|
end
|
|
|
|
package.loaded["ffi/util"] = {
|
|
template = function(text, ...)
|
|
local values = { ... }
|
|
return (text:gsub("%%(%d+)", function(index)
|
|
return tostring(values[tonumber(index)])
|
|
end))
|
|
end,
|
|
}
|
|
|
|
local ticks = {}
|
|
local sent_events = {}
|
|
package.loaded["device"] = { model = "test-device" }
|
|
package.loaded["ui/event"] = { new = function(_, name) return { name = name } end }
|
|
package.loaded["ui/widget/infomessage"] = { new = function(_, opts) return opts end }
|
|
package.loaded["ui/widget/inputdialog"] = {}
|
|
package.loaded["ui/network/manager"] = {
|
|
runWhenConnected = function(_, callback) callback() end,
|
|
}
|
|
package.loaded["ui/widget/notification"] = {}
|
|
package.loaded["ui/uimanager"] = {
|
|
nextTick = function(_, callback) table.insert(ticks, callback) end,
|
|
tickAfterNext = function(_, callback) table.insert(ticks, callback) end,
|
|
sendEvent = function(_, event) table.insert(sent_events, event.name) end,
|
|
show = function() end,
|
|
}
|
|
package.loaded["ffi/sha2"] = { md5 = function(value) return value end }
|
|
package.loaded["libs/libkoreader-lfs"] = { currentdir = function() return "/opt/koreader" end }
|
|
package.loaded["bookorbit_api"] = {}
|
|
package.loaded["bookorbit_highlight_diagnostics"] = {}
|
|
package.loaded["bookorbit_sweep"] = {
|
|
syncStatus = function()
|
|
return { lastSweepAt = 0, matched = 0, unmatched = 0 }
|
|
end,
|
|
}
|
|
|
|
package.path = "koreader-plugin/bookorbit.koplugin/?.lua;" .. package.path
|
|
|
|
local MainMenu = require("bookorbit_main_menu")
|
|
|
|
local function assertEqual(actual, expected, label)
|
|
if actual ~= expected then
|
|
error(string.format("%s: expected %s, got %s", label, tostring(expected), tostring(actual)))
|
|
end
|
|
end
|
|
|
|
local function itemText(item)
|
|
if item.text then return item.text end
|
|
if item.text_func then return item:text_func() end
|
|
end
|
|
|
|
local function texts(items)
|
|
local out = {}
|
|
for _, item in ipairs(items) do table.insert(out, itemText(item)) end
|
|
return table.concat(out, "|")
|
|
end
|
|
|
|
local function newPlugin(opts)
|
|
opts = opts or {}
|
|
local calls = {}
|
|
local plugin = {
|
|
settings = { menu_bar_icon = opts.menu_bar_icon },
|
|
path = opts.path or "plugins/bookorbit.koplugin",
|
|
ui = opts.reader and { document = { file = "/books/Book.epub" }, menu = {} } or { menu = {} },
|
|
isLoggedIn = function() return opts.logged_out ~= true end,
|
|
calls = calls,
|
|
}
|
|
MainMenu.install(plugin)
|
|
for _, name in ipairs({ "browseCatalog", "openSignIn", "openBookSheet", "openSettings", "openSyncStatus", "startSweep", "applyUpdate", "customizeHome" }) do
|
|
plugin[name] = function(_, ...) table.insert(calls, { name, ... }) end
|
|
end
|
|
return plugin, calls
|
|
end
|
|
|
|
local function menuItems(plugin)
|
|
local menu_items = {}
|
|
plugin:addToMainMenu(menu_items)
|
|
return menu_items
|
|
end
|
|
|
|
local function runTicks()
|
|
while #ticks > 0 do table.remove(ticks, 1)() end
|
|
end
|
|
|
|
-- The file browser's Tools entry: open BookOrbit, or its settings.
|
|
local plugin, calls = newPlugin()
|
|
local items = menuItems(plugin)
|
|
assertEqual(texts(items.bookorbit.sub_item_table), "Open BookOrbit|Settings", "the Tools entry is two rows in the file browser")
|
|
assertEqual(items.bookorbit.sorting_hint, "tools", "the entry still falls back to the Tools menu")
|
|
|
|
-- In a book it adds This book.
|
|
local reader = newPlugin({ reader = true })
|
|
assertEqual(texts(menuItems(reader).bookorbit.sub_item_table), "Open BookOrbit|This book|Settings", "a book adds This book")
|
|
|
|
-- The menu bar tab is a button: never remembered, never a list.
|
|
local tab = items.bookorbit_tab
|
|
assertEqual(tab ~= nil, true, "the menu bar tab is offered by default")
|
|
assertEqual(tab.remember, false, "the tab is never remembered, so opening the menu never fires it")
|
|
assertEqual(#tab, 0, "the tab holds no rows")
|
|
assertEqual(type(tab.callback), "function", "the tab acts on a tap")
|
|
|
|
-- Its icon is the shipped SVG, reached from KOReader's icon folders by a
|
|
-- climb to the root, with the extension the tab bar adds stripped.
|
|
assertEqual(tab.icon:sub(1, 9), "../../../", "the icon name climbs out of the icon folders")
|
|
assertEqual(tab.icon:find("opt/koreader/plugins/bookorbit.koplugin/assets/bookorbit.tab", 1, true) ~= nil, true, "a relative plugin path is made absolute")
|
|
assertEqual(tab.icon:sub(-4) ~= ".svg", true, "the extension is left to the tab bar")
|
|
local user_plugin = newPlugin({ path = "/mnt/onboard/.adds/koreader/plugins/bookorbit.koplugin" })
|
|
assertEqual(user_plugin:menuBarIconName():find("../mnt/onboard/.adds/koreader/plugins/bookorbit.koplugin/assets/bookorbit.tab", 1, true) ~= nil, true,
|
|
"an absolute plugin path is used as it is")
|
|
|
|
-- Turned off, the tab is not registered at all (an unordered item would show
|
|
-- up as a NEW: row in the first menu).
|
|
local hidden = newPlugin({ menu_bar_icon = false })
|
|
assertEqual(menuItems(hidden).bookorbit_tab, nil, "no tab when the icon is turned off")
|
|
|
|
-- Tapping the tab: BookOrbit in the file browser, This book in a book, and
|
|
-- sign-in when signed out, each after the menu's own close.
|
|
plugin.ui.menu.onCloseFileManagerMenu = function() table.insert(calls, { "close_fm_menu" }) end
|
|
tab.callback()
|
|
assertEqual(calls[1][1], "close_fm_menu", "the KOReader menu closes first")
|
|
assertEqual(#calls, 1, "nothing opens before the close has painted")
|
|
runTicks()
|
|
assertEqual(calls[2][1], "browseCatalog", "the file browser's tab opens BookOrbit")
|
|
|
|
local book, book_calls = newPlugin({ reader = true })
|
|
book.ui.menu.onCloseReaderMenu = function() table.insert(book_calls, { "close_reader_menu" }) end
|
|
menuItems(book).bookorbit_tab.callback()
|
|
runTicks()
|
|
assertEqual(book_calls[1][1], "close_reader_menu", "the reader menu closes first")
|
|
assertEqual(book_calls[2][1], "openBookSheet", "in a book the tab opens This book")
|
|
|
|
local out, out_calls = newPlugin({ logged_out = true })
|
|
menuItems(out).bookorbit_tab.callback()
|
|
runTicks()
|
|
assertEqual(out_calls[1][1], "openSignIn", "signed out, the tab opens sign-in")
|
|
|
|
-- Open BookOrbit from Tools signs in first when needed.
|
|
out_calls[1] = nil
|
|
out:openBookOrbit()
|
|
assertEqual(out_calls[#out_calls][1], "openSignIn", "Open BookOrbit asks for a sign-in when signed out")
|
|
|
|
-- The sheet's actions close it, then act.
|
|
local sheet_plugin, sheet_calls = newPlugin()
|
|
local events = {}
|
|
local catalog = {
|
|
goDashboard = function() table.insert(events, "home") end,
|
|
onCloseAllMenus = function() table.insert(events, "exit") end,
|
|
onSearchButtonTap = function() table.insert(events, "search") end,
|
|
boardOpenLink = function(_, link) table.insert(events, "link:" .. link) end,
|
|
showBookActions = function() table.insert(events, "list-options") end,
|
|
}
|
|
local closes, refreshes = 0, 0
|
|
local page = {
|
|
close = function() closes = closes + 1 end,
|
|
refresh = function() refreshes = refreshes + 1 end,
|
|
sheet_data = {},
|
|
}
|
|
package.loaded["bookorbit_menu_sheet"] = { data = function() return { reloaded = true } end }
|
|
local function run(action)
|
|
sheet_plugin:onMenuSheetAction(page, catalog, action)
|
|
runTicks()
|
|
end
|
|
run({ kind = "home" })
|
|
run({ kind = "exit" })
|
|
run({ kind = "files" })
|
|
run({ kind = "search" })
|
|
run({ kind = "link", link = "authors" })
|
|
run({ kind = "list-options" })
|
|
assertEqual(table.concat(events, ","), "home,exit,exit,search,link:authors,list-options", "catalog actions reach the catalog")
|
|
assertEqual(table.concat(sent_events, ","), "Home", "Files asks KOReader to open its file browser")
|
|
assertEqual(sheet_plugin.skip_return_home_once, true, "Files bypasses the BookOrbit home preference once")
|
|
assertEqual(closes, 6, "every action closes the sheet first")
|
|
|
|
-- Sync now keeps the sheet open: its tile shows the run, then the outcome.
|
|
run({ kind = "sync" })
|
|
assertEqual(closes, 6, "Sync now leaves the sheet open")
|
|
assertEqual(sheet_calls[1][1], "startSweep", "Sync now starts a library sync")
|
|
local sweep = sheet_calls[1][2]
|
|
assertEqual(sweep.quiet, true, "the sync reports to the sheet, not a dialog")
|
|
assertEqual(page.sheet_data.sync.running, true, "the tile says the sync is running")
|
|
sweep.on_progress("Matching books")
|
|
assertEqual(page.sheet_data.sync.text, "Matching books", "the short progress line is shown")
|
|
sweep.on_done(nil)
|
|
assertEqual(page.sheet_data.reloaded, true, "the sheet's numbers are reloaded when the sync ends")
|
|
assertEqual(page.sheet_data.sync.done, true, "the tile says the sync finished")
|
|
assertEqual(refreshes, 3, "the sheet redraws at start, on progress and at the end")
|
|
plugin.errorLabel = function() return "fallback" end
|
|
sheet_plugin.errorLabel = plugin.errorLabel
|
|
sweep.on_done("not_started")
|
|
assertEqual(page.sheet_data.sync.err, "Another sync is running", "a sync that did not start says why")
|
|
|
|
table.remove(sheet_calls, 1)
|
|
run({ kind = "settings" })
|
|
run({ kind = "status" })
|
|
run({ kind = "about" })
|
|
run({ kind = "customize" })
|
|
local names = {}
|
|
for _, call in ipairs(sheet_calls) do table.insert(names, call[1]) end
|
|
assertEqual(table.concat(names, ","), "openSettings,openSyncStatus,openSettings,customizeHome", "plugin actions reach the plugin")
|
|
assertEqual(sheet_calls[3][3], "about", "Help & about opens settings on About")
|
|
|
|
print("bookorbit_menu_context_test.lua: ok")
|