mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
267f53fccd
Add a Colour setting to Settings > Home: Accents, the default, colours each widget's marks and draws Continue reading in its cover's deep shade; Tinted also washes every tile in its widget's colour; Off keeps the greys. Black-and- white screens draw as before, colour e-readers get stronger shades, and night mode keeps each colour's hue.
474 lines
27 KiB
Lua
474 lines
27 KiB
Lua
--[[--
|
|
Customizing the widget dashboard.
|
|
|
|
Hold any widget (or choose Customize dashboard in the menu) to edit. A tap
|
|
selects a widget and shows its bar: Earlier, Later, Size, Page and Remove.
|
|
There is no dragging, so editing works on e-ink and on D-pad devices alike.
|
|
Add widget opens a sheet of live previews.
|
|
|
|
The first edit turns the starter layout into the reader's own pages for this
|
|
column count. Every change is checked against the board's smallest row
|
|
height before it is kept, so a page can never hold more than fits.
|
|
]]
|
|
|
|
local T = require("ffi/util").template
|
|
local _ = require("gettext")
|
|
|
|
local BoardLayout = require("bookorbit_board_layout")
|
|
local BoardMetrics = require("bookorbit_board_metrics")
|
|
local BoardStore = require("bookorbit_board_store")
|
|
|
|
local px = BoardMetrics.px
|
|
|
|
local BoardEdit = {}
|
|
|
|
-- The widgets a reader can add. Sizes are the codes in BoardLayout.sizeDims;
|
|
-- the first is the size a new widget gets.
|
|
BoardEdit.LIBRARY = {
|
|
{ type = "forecast", name = function() return _("Finish forecast") end, desc = function() return _("When your book ends at your pace") end, sizes = { "M", "S", "L" }, tab = "reading", new = true },
|
|
{ type = "heatmap", name = function() return _("Year in reading") end, desc = function() return _("One square a day for a whole year") end, sizes = { "XL", "L" }, tab = "stats", new = true },
|
|
{ type = "goalpace", name = function() return _("Goal pace") end, desc = function() return _("Ahead or behind on your yearly goal") end, sizes = { "M", "S" }, tab = "stats", new = true },
|
|
{ type = "light", name = function() return _("Light") end, desc = function() return _("Brightness and warmth steppers") end, sizes = { "M", "S" }, tab = "device", new = true },
|
|
{ type = "word", name = function() return _("Word of the day") end, desc = function() return _("A word you looked up, in context") end, sizes = { "M", "L" }, tab = "reading", new = true },
|
|
{ type = "yearago", name = function() return _("A year ago") end, desc = function() return _("What you were reading last year") end, sizes = { "M", "L" }, tab = "reading", new = true },
|
|
{ type = "toggles", name = function() return _("Quick settings") end, desc = function() return _("Wi-Fi, light, night mode, rotate, sync") end, sizes = { "M", "S" }, tab = "device", new = true },
|
|
{ type = "records", name = function() return _("Reading records") end, desc = function() return _("Your longest and average sessions") end, sizes = { "L", "M" }, tab = "stats", new = true },
|
|
{ type = "hours", name = function() return _("When you read") end, desc = function() return _("Your reading by hour of the day") end, sizes = { "M", "L" }, tab = "stats", new = true },
|
|
{ type = "shelf", name = function() return _("Finished this year") end, desc = function() return _("Covers of the books you finished") end, sizes = { "L", "XL" }, tab = "stats", new = true, props = { source = "finished" } },
|
|
{ type = "shelf", name = function() return _("Pick back up") end, desc = function() return _("Books you put down a while ago") end, sizes = { "XL", "L" }, tab = "library", new = true, props = { source = "pick-back-up" } },
|
|
{ type = "shelf", name = function() return _("Want to read") end, desc = function() return _("Books waiting for their turn") end, sizes = { "L", "XL" }, tab = "library", new = true, props = { source = "want-to-read" } },
|
|
{ type = "hero", name = function() return _("Continue reading") end, desc = function() return _("Your current book with Resume") end, sizes = { "W", "M", "L" }, tab = "reading", chrome = "ink" },
|
|
{ type = "also", name = function() return _("Also reading") end, desc = function() return _("The rest of your pile") end, sizes = { "L", "M" }, tab = "reading" },
|
|
{ type = "highlight", name = function() return _("Highlight of the day") end, desc = function() return _("One of your highlights, daily") end, sizes = { "L", "M", "W" }, tab = "reading", chrome = "fill" },
|
|
{ type = "streak", name = function() return _("Streak") end, desc = function() return _("Days in a row, and your best") end, sizes = { "S", "M" }, tab = "stats" },
|
|
{ type = "week", name = function() return _("This week") end, desc = function() return _("Minutes read each day") end, sizes = { "M", "S" }, tab = "stats" },
|
|
{ type = "today", name = function() return _("Today") end, desc = function() return _("Minutes read today") end, sizes = { "S" }, tab = "stats" },
|
|
{ type = "calendar", name = function() return _("Reading calendar") end, desc = function() return _("This month, one square a day") end, sizes = { "M", "L" }, tab = "stats" },
|
|
{ type = "shelf", name = function() return _("Up next in series") end, desc = function() return _("The next book in each series you read") end, sizes = { "L", "XL" }, tab = "library", props = { source = "up-next-in-series" } },
|
|
{ type = "shelf", name = function() return _("Discover") end, desc = function() return _("A shuffle of your library") end, sizes = { "XL", "L" }, tab = "library", props = { source = "random", shuffle = true } },
|
|
{ type = "shelf", name = function() return _("Recently added") end, desc = function() return _("The newest books in your library") end, sizes = { "XL", "L" }, tab = "library", props = { source = "recently-added" } },
|
|
{ type = "shelf", name = function() return _("Shelf from your library") end, desc = function() return _("One library, collection, SmartScope, author or series") end, sizes = { "XL", "L" }, tab = "library", pick = true, props = { source = "random" } },
|
|
{ type = "link", name = function() return _("Library") end, desc = function() return _("All your books") end, sizes = { "S" }, tab = "library", props = { link = "library" } },
|
|
{ type = "link", name = function() return _("Series") end, desc = function() return _("Every series") end, sizes = { "S" }, tab = "library", props = { link = "series" } },
|
|
{ type = "link", name = function() return _("Authors") end, desc = function() return _("Every author") end, sizes = { "S" }, tab = "library", props = { link = "authors" } },
|
|
{ type = "link", name = function() return _("Collections") end, desc = function() return _("Your collections") end, sizes = { "S" }, tab = "library", props = { link = "collections" } },
|
|
{ type = "link", name = function() return _("SmartScopes") end, desc = function() return _("Your saved SmartScopes") end, sizes = { "S" }, tab = "library", props = { link = "scopes" } },
|
|
{ type = "link", name = function() return _("On device") end, desc = function() return _("Books on this device, and space left") end, sizes = { "S" }, tab = "device", props = { link = "device" } },
|
|
{ type = "link", name = function() return _("Search") end, desc = function() return _("Search your library") end, sizes = { "S" }, tab = "library", props = { link = "search" } },
|
|
{ type = "clock", name = function() return _("Clock") end, desc = function() return _("Time and date, each minute") end, sizes = { "S", "M" }, tab = "device", chrome = "ink" },
|
|
{ type = "sync", name = function() return _("Sync status") end, desc = function() return _("Last sync, with Sync now") end, sizes = { "S" }, tab = "device" },
|
|
{ type = "buddy", name = function() return _("Reading buddy") end, desc = function() return _("A cat that keeps you company") end, sizes = { "L", "M", "S" }, tab = "decor", new = true },
|
|
{ type = "buddy", name = function() return _("Reading dog") end, desc = function() return _("A floppy-eared friend for every chapter") end, sizes = { "L", "M", "S" }, tab = "decor", new = true, props = { animal = "dog" } },
|
|
{ type = "buddy", name = function() return _("Reading rabbit") end, desc = function() return _("A quiet companion with a curious nose") end, sizes = { "L", "M", "S" }, tab = "decor", new = true, props = { animal = "rabbit" } },
|
|
{ type = "buddy", name = function() return _("Reading owl") end, desc = function() return _("A feathered friend for one more page") end, sizes = { "L", "M", "S" }, tab = "decor", new = true, props = { animal = "owl" } },
|
|
{ type = "buddy", name = function() return _("Reading penguin") end, desc = function() return _("A little bookworm in a feathered coat") end, sizes = { "L", "M", "S" }, tab = "decor", new = true, props = { animal = "penguin" } },
|
|
{ type = "buddy", name = function() return _("Reading robot") end, desc = function() return _("Recharges with a good book") end, sizes = { "L", "M", "S" }, tab = "decor", new = true, props = { animal = "robot" } },
|
|
{ type = "buddy", name = function() return _("Reading vampire") end, desc = function() return _("A tiny night owl with a cape and fangs") end, sizes = { "L", "M", "S" }, tab = "decor", new = true, props = { animal = "vampire" } },
|
|
{ type = "buddy", name = function() return _("Reading dragon") end, desc = function() return _("A little dragon guarding a hoard of stories") end, sizes = { "L", "M", "S" }, tab = "decor", new = true, props = { animal = "dragon" } },
|
|
{ type = "buddy", name = function() return _("Reading ghost") end, desc = function() return _("A friendly spirit between the pages") end, sizes = { "L", "M", "S" }, tab = "decor", new = true, props = { animal = "ghost" } },
|
|
{ type = "buddy", name = function() return _("Reading mimic") end, desc = function() return _("A book that reads you back") end, sizes = { "L", "M", "S" }, tab = "decor", new = true, props = { animal = "mimic" } },
|
|
{ type = "buddy", name = function() return _("Reading mummy") end, desc = function() return _("Three thousand years of catching up") end, sizes = { "L", "M", "S" }, tab = "decor", new = true, props = { animal = "mummy" } },
|
|
{ type = "buddy", name = function() return _("Reading witch") end, desc = function() return _("Never without her spellbook") end, sizes = { "L", "M", "S" }, tab = "decor", new = true, props = { animal = "witch" } },
|
|
{ type = "buddy", name = function() return _("Reading skeleton") end, desc = function() return _("Reads to the bone") end, sizes = { "L", "M", "S" }, tab = "decor", new = true, props = { animal = "skeleton" } },
|
|
{ type = "buddy", name = function() return _("Reading candle") end, desc = function() return _("Burns the midnight oil") end, sizes = { "L", "M", "S" }, tab = "decor", new = true, props = { animal = "candle" } },
|
|
{ type = "buddy", name = function() return _("Reading alien") end, desc = function() return _("Came a long way for a good book") end, sizes = { "L", "M", "S" }, tab = "decor", new = true, props = { animal = "alien" } },
|
|
{ type = "chapters", name = function() return _("Chapter line") end, desc = function() return _("Your book as a line, chapters as stops") end, sizes = { "L", "M", "W", "S" }, tab = "decor", new = true },
|
|
{ type = "badge", name = function() return _("Next badge") end, desc = function() return _("The badge you are closest to earning") end, sizes = { "M", "L", "S" }, tab = "decor", new = true },
|
|
{ type = "dust", name = function() return _("Gathering dust") end, desc = function() return _("Books you downloaded and never opened") end, sizes = { "M", "L", "S" }, tab = "decor", new = true },
|
|
{ type = "rings", name = function() return _("Tree rings") end, desc = function() return _("A ring for every month you read") end, sizes = { "L", "M" }, tab = "decor", new = true },
|
|
{ type = "odometer", name = function() return _("Pages turned") end, desc = function() return _("Every page, on a counter") end, sizes = { "M", "S" }, tab = "decor", new = true },
|
|
{ type = "glyph", name = function() return _("Glyph of the day") end, desc = function() return _("One letter from your fonts") end, sizes = { "S", "M", "L" }, tab = "decor", new = true },
|
|
{ type = "analog", name = function() return _("Analog clock") end, desc = function() return _("A clock face, each minute") end, sizes = { "S", "M" }, tab = "decor", new = true, chrome = "ink" },
|
|
{ type = "moon", name = function() return _("Moon phase") end, desc = function() return _("Tonight's moon") end, sizes = { "S", "M" }, tab = "decor", new = true, chrome = "ink" },
|
|
}
|
|
|
|
BoardEdit.TABS = {
|
|
{ id = "new", label = function() return _("New") end },
|
|
{ id = "reading", label = function() return _("Reading") end },
|
|
{ id = "stats", label = function() return _("Stats") end },
|
|
{ id = "library", label = function() return _("Library") end },
|
|
{ id = "device", label = function() return _("Device") end },
|
|
{ id = "decor", label = function() return _("Decor") end },
|
|
}
|
|
|
|
local function sameProps(a, b)
|
|
a, b = a or {}, b or {}
|
|
return a.source == b.source and a.link == b.link and (a.animal or "cat") == (b.animal or "cat")
|
|
end
|
|
|
|
-- The library entry an item came from, for its supported sizes.
|
|
function BoardEdit.entryFor(item)
|
|
local picked = item.type == "shelf" and item.props
|
|
and require("bookorbit_dashboard_sections").isCatalogSelector(item.props.source)
|
|
for _i, entry in ipairs(BoardEdit.LIBRARY) do
|
|
if picked and entry.pick then return entry end
|
|
if entry.type == item.type and (entry.type ~= "shelf" and entry.type ~= "link" and entry.type ~= "buddy" or sameProps(entry.props, item.props)) then
|
|
return entry
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function BoardEdit.sizeCode(item, cols)
|
|
for _i, code in ipairs({ "S", "M", "L", "W", "XL" }) do
|
|
local cw, rh = BoardLayout.sizeDims(code, cols)
|
|
if cw == math.min(item.cw, cols) and rh == item.rh then return code end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
local function copyItem(it)
|
|
local props = nil
|
|
if it.props then
|
|
props = {}
|
|
for k, v in pairs(it.props) do props[k] = v end
|
|
end
|
|
return { type = it.type, cw = it.cw, rh = it.rh, chrome = it.chrome, props = props }
|
|
end
|
|
|
|
-- ------------------------------------------------------------- state
|
|
function BoardEdit:boardEditing()
|
|
return self.board_edit ~= nil
|
|
end
|
|
|
|
function BoardEdit:boardGeometry()
|
|
local m = BoardMetrics.get()
|
|
local _top, bottom = self:menuChromeHeight()
|
|
return BoardLayout.geometry(px, self.inner_dimen.w, self.inner_dimen.h - bottom, m.LW)
|
|
end
|
|
|
|
-- The pages being edited, as they are currently drawn: the reader's own or
|
|
-- the starter layout, fitted to this screen. A saved page that no longer fits
|
|
-- (a larger interface size, a shelf grown to two rows) is edited as shown,
|
|
-- never as an overfull grid the editor could not change; the widgets it has
|
|
-- no room for are kept aside as hidden.
|
|
function BoardEdit:boardEditablePages(g)
|
|
local pages = self:boardPages(g.cols)
|
|
local out = {}
|
|
for index = 1, BoardStore.PAGE_COUNT do
|
|
local page = pages[index] or { base = {} }
|
|
local items, hidden = {}, {}
|
|
local packed = BoardLayout.fitPage(g, page.base, page.extras)
|
|
for _i, it in ipairs(packed.placed) do table.insert(items, copyItem(it)) end
|
|
for _i, it in ipairs(packed.dropped) do table.insert(hidden, copyItem(it)) end
|
|
out[index] = { id = page.id, items = items, hidden = hidden }
|
|
end
|
|
return out
|
|
end
|
|
|
|
-- Hidden widgets are saved after the ones on screen, so a smaller interface
|
|
-- size shows them again.
|
|
function BoardEdit:boardSavePages(g, pages)
|
|
local m = BoardMetrics.get()
|
|
local saved = {}
|
|
for index, page in ipairs(pages) do
|
|
local items = {}
|
|
for _i, it in ipairs(page.items or {}) do table.insert(items, it) end
|
|
for _i, it in ipairs(page.hidden or {}) do table.insert(items, it) end
|
|
saved[index] = { id = page.id, items = items }
|
|
end
|
|
self:persistSetting(BoardStore.SETTING_KEY, BoardStore.withCustomPages(self.settings, g.cols, saved, m.w > m.h))
|
|
end
|
|
|
|
function BoardEdit:boardPageFits(g, items)
|
|
if #items == 0 then return true end
|
|
local packed = BoardLayout.pack(items, g.cols)
|
|
return BoardLayout.rowHeight(g, packed.rows) >= g.min_row
|
|
end
|
|
|
|
function BoardEdit:boardEnterEdit(select_index)
|
|
if not self:dashboardMode() then return end
|
|
local g = self:boardGeometry()
|
|
self.board_edit = {
|
|
pages = self:boardEditablePages(g),
|
|
selected = select_index,
|
|
sheet = false,
|
|
sheet_tab = "new",
|
|
sheet_page = 1,
|
|
cols = g.cols,
|
|
}
|
|
self:updateItems(nil, true)
|
|
end
|
|
|
|
function BoardEdit:boardExitEdit()
|
|
local edit = self.board_edit
|
|
if not edit then return end
|
|
self.board_edit = nil
|
|
if edit.changed then
|
|
self:boardSavePages(self:boardGeometry(), edit.pages)
|
|
end
|
|
self:boardRefreshIfMissing()
|
|
end
|
|
|
|
-- Redraws the board, then fetches the dashboard again only when it now shows
|
|
-- a shelf or a list of names the cached body does not hold. Drawing first
|
|
-- keeps the screen current while offline; covers stay cached either way.
|
|
function BoardEdit:boardRefreshIfMissing()
|
|
self:updateItems(nil, true)
|
|
local body = self.current_context and self.current_context.dashboard
|
|
local sources, names = self:boardSources()
|
|
local missing = body == nil
|
|
for source in pairs(sources) do
|
|
if source ~= "in-progress" and not (body and type(body.boardShelves) == "table" and body.boardShelves[source]) then missing = true end
|
|
end
|
|
for key in pairs(names) do
|
|
if not (body and type(body.boardNames) == "table" and body.boardNames[key]) then missing = true end
|
|
end
|
|
if missing then
|
|
self:loadDashboardRoot(true, { invisible = true })
|
|
end
|
|
end
|
|
|
|
local function full(text)
|
|
require("bookorbit_toast").error(text)
|
|
end
|
|
|
|
-- ------------------------------------------------------------- actions
|
|
function BoardEdit:boardEditRun(action)
|
|
local edit = self.board_edit
|
|
if not edit then return end
|
|
local g = self:boardGeometry()
|
|
local page = self:boardPage()
|
|
local items = edit.pages[page].items
|
|
local kind = action.kind
|
|
if kind == "edit-done" then
|
|
return self:boardExitEdit()
|
|
elseif kind == "edit-select" then
|
|
edit.selected = edit.selected == action.index and nil or action.index
|
|
elseif kind == "edit-move" then
|
|
local i = edit.selected
|
|
local j = i and i + action.delta
|
|
if i and j and j >= 1 and j <= #items then
|
|
items[i], items[j] = items[j], items[i]
|
|
edit.selected = j
|
|
edit.changed = true
|
|
end
|
|
elseif kind == "edit-size" then
|
|
local it = items[edit.selected or 0]
|
|
if it then
|
|
local cw, rh = BoardLayout.sizeDims(action.code, g.cols)
|
|
local old_cw, old_rh = it.cw, it.rh
|
|
it.cw, it.rh = cw, rh
|
|
if not self:boardPageFits(g, items) then
|
|
it.cw, it.rh = old_cw, old_rh
|
|
return full(_("There is not enough room on this page for that size."))
|
|
end
|
|
edit.changed = true
|
|
end
|
|
elseif kind == "edit-remove" then
|
|
local i = action.index or edit.selected
|
|
if i and items[i] then
|
|
table.remove(items, i)
|
|
edit.selected = nil
|
|
edit.changed = true
|
|
end
|
|
elseif kind == "edit-page" then
|
|
local i = edit.selected
|
|
if i and items[i] then
|
|
local target = page % BoardStore.PAGE_COUNT + 1
|
|
local moved = items[i]
|
|
local dest = edit.pages[target].items
|
|
table.insert(dest, moved)
|
|
if not self:boardPageFits(g, dest) then
|
|
table.remove(dest)
|
|
return full(T(_("%1 is full. Remove a widget there first."), BoardStore.pageNames(edit.pages)[target]))
|
|
end
|
|
table.remove(items, i)
|
|
edit.selected = nil
|
|
edit.changed = true
|
|
full(T(_("Moved to %1."), BoardStore.pageNames(edit.pages)[target]))
|
|
end
|
|
elseif kind == "edit-add" then
|
|
edit.sheet = true
|
|
edit.sheet_page = 1
|
|
elseif kind == "sheet-close" then
|
|
edit.sheet = false
|
|
elseif kind == "sheet-tab" then
|
|
edit.sheet_tab = action.tab
|
|
edit.sheet_page = 1
|
|
elseif kind == "sheet-page" then
|
|
edit.sheet_page = math.max(1, (edit.sheet_page or 1) + action.delta)
|
|
elseif kind == "sheet-add" and action.entry.pick then
|
|
edit.sheet = false
|
|
self:updateItems(nil, true)
|
|
return self:boardPickShelfSource()
|
|
elseif kind == "sheet-add" then
|
|
local entry = action.entry
|
|
local cw, rh = BoardLayout.sizeDims(entry.sizes[1], g.cols)
|
|
local item = { type = entry.type, cw = cw, rh = rh, chrome = entry.chrome or "line", props = entry.props and copyItem(entry).props or nil }
|
|
table.insert(items, item)
|
|
if not self:boardPageFits(g, items) then
|
|
-- Try the smallest size it offers before giving up.
|
|
local smallest = entry.sizes[#entry.sizes]
|
|
item.cw, item.rh = BoardLayout.sizeDims(smallest, g.cols)
|
|
for _i, code in ipairs(entry.sizes) do
|
|
local tcw, trh = BoardLayout.sizeDims(code, g.cols)
|
|
if tcw * trh < item.cw * item.rh then item.cw, item.rh = tcw, trh end
|
|
end
|
|
if not self:boardPageFits(g, items) then
|
|
table.remove(items)
|
|
return full(_("This page is full. Remove a widget first, or add it on another page."))
|
|
end
|
|
end
|
|
edit.sheet = false
|
|
edit.selected = #items
|
|
edit.changed = true
|
|
elseif kind == "edit-pages" then
|
|
return self:boardShowPagesMenu()
|
|
end
|
|
self:updateItems(nil, true)
|
|
end
|
|
|
|
-- Which list to pick a shelf from. The list opens in pick mode: tapping an
|
|
-- entry adds it as a shelf instead of opening it.
|
|
function BoardEdit:boardPickShelfSource()
|
|
require("bookorbit_dialog_ui").actions{
|
|
title = _("Show a shelf of"),
|
|
sub = _("Pick where its books come from"),
|
|
rows = {
|
|
{ icon = "library", label = _("A library, collection or SmartScope"), opens = true, run = function()
|
|
self:loadShelves({ dashboard_source_index = "board" })
|
|
end },
|
|
{ icon = "user", label = _("An author"), opens = true, run = function()
|
|
self:loadSection("authors", { dashboard_source_index = "board" })
|
|
end },
|
|
{ icon = "layers-2", label = _("A series"), opens = true, run = function()
|
|
self:loadSection("series", { dashboard_source_index = "board" })
|
|
end },
|
|
},
|
|
}
|
|
end
|
|
|
|
-- The picked list becomes a full-width shelf on the page being edited.
|
|
function BoardEdit:boardAddPickedShelf(source)
|
|
self:onReturn()
|
|
while self.stack and #self.stack > 0 and not self:dashboardMode() do self:onReturn() end
|
|
local edit = self.board_edit
|
|
if not edit or not self:dashboardMode() then return end
|
|
local g = self:boardGeometry()
|
|
local items = edit.pages[self:boardPage()].items
|
|
local params = {}
|
|
for k, v in pairs(source.params or {}) do params[k] = v end
|
|
table.insert(items, { type = "shelf", cw = g.cols, rh = 2, chrome = "line",
|
|
props = { source = source.type, params = params, title = source.sourceName } })
|
|
if not self:boardPageFits(g, items) then
|
|
table.remove(items)
|
|
self:updateItems(nil, true)
|
|
return full(_("This page is full. Remove a widget first, or add it on another page."))
|
|
end
|
|
edit.selected = #items
|
|
edit.changed = true
|
|
-- The new shelf's books are fetched now, not when editing ends.
|
|
self:boardRefreshIfMissing()
|
|
end
|
|
|
|
function BoardEdit:boardShowPagesMenu()
|
|
local DialogUI = require("bookorbit_dialog_ui")
|
|
DialogUI.actions{
|
|
title = _("Pages"),
|
|
rows = {
|
|
{ icon = "rotate-ccw", label = _("Reset this page"), sub = _("Back to how it started"), run = function()
|
|
self:boardResetPage(self:boardPage())
|
|
end },
|
|
{ icon = "rotate-ccw", label = _("Reset all pages"), sub = _("Every page back to how it started"), run = function()
|
|
DialogUI.confirm{
|
|
title = _("Reset all pages?"),
|
|
text = _("Every page goes back to its starting layout."),
|
|
ok_label = _("Reset"),
|
|
on_ok = function() self:boardResetAll() end,
|
|
}
|
|
end },
|
|
},
|
|
}
|
|
end
|
|
|
|
function BoardEdit:boardResetPage(page)
|
|
local edit = self.board_edit
|
|
if not edit then return end
|
|
local g = self:boardGeometry()
|
|
local state = BoardStore.read(self.settings)
|
|
local m = BoardMetrics.get()
|
|
local starter = BoardStore.starterPages(g.cols, state.preset, self:boardHasLight(), m.w > m.h)[page]
|
|
local packed = BoardLayout.fitPage(g, starter.base, starter.extras)
|
|
local items = {}
|
|
for _i, it in ipairs(packed.placed) do table.insert(items, copyItem(it)) end
|
|
edit.pages[page].items = items
|
|
edit.selected = nil
|
|
edit.changed = true
|
|
self:updateItems(nil, true)
|
|
end
|
|
|
|
function BoardEdit:boardResetAll()
|
|
local state = BoardStore.read(self.settings)
|
|
self:persistSetting(BoardStore.SETTING_KEY, BoardStore.withPreset(self.settings, state.preset))
|
|
self.board_edit = nil
|
|
self:boardRefreshIfMissing()
|
|
end
|
|
|
|
-- Shelves a reader picked for the old four-slot dashboard (one library,
|
|
-- collection, SmartScope, author or series) carry over onto the board once it
|
|
-- has started, on the first page with room for them. The old setting is then
|
|
-- dropped, so this runs once. Returns true when it ran.
|
|
function BoardEdit:boardMigrateLegacyShelves()
|
|
local DashboardSections = require("bookorbit_dashboard_sections")
|
|
local stored = self.settings[DashboardSections.SETTING_KEY]
|
|
if stored == nil or not BoardStore.read(self.settings).started then return false end
|
|
local legacy = DashboardSections.normalize(stored)
|
|
local g = self:boardGeometry()
|
|
local shelves = {}
|
|
for index = 1, DashboardSections.SLOT_COUNT do
|
|
local entry = legacy[index]
|
|
if entry and DashboardSections.isCatalogSelector(entry.type) and type(entry.params) == "table" then
|
|
table.insert(shelves, { type = "shelf", cw = g.cols, rh = 2, chrome = "line",
|
|
props = { source = entry.type, params = entry.params, title = entry.sourceName } })
|
|
end
|
|
end
|
|
if #shelves > 0 then
|
|
local pages = self:boardEditablePages(g)
|
|
for _i, shelf in ipairs(shelves) do
|
|
local placed = false
|
|
for _j, page in ipairs({ 1, 3, 2 }) do
|
|
local items = pages[page].items
|
|
table.insert(items, shelf)
|
|
if self:boardPageFits(g, items) then
|
|
placed = true
|
|
break
|
|
end
|
|
table.remove(items)
|
|
end
|
|
-- The reader chose this shelf; the starter's last widgets on the
|
|
-- Library page give way to it.
|
|
if not placed then
|
|
local items = pages[3].items
|
|
table.insert(items, 1, shelf)
|
|
while #items > 1 and not self:boardPageFits(g, items) do table.remove(items) end
|
|
end
|
|
end
|
|
self:boardSavePages(g, pages)
|
|
end
|
|
self:persistSetting(DashboardSections.SETTING_KEY, nil)
|
|
return true
|
|
end
|
|
|
|
-- ------------------------------------------------------------- settings
|
|
function BoardEdit:boardSetTiles(tiles)
|
|
self:persistSetting(BoardStore.SETTING_KEY, BoardStore.withTiles(self.settings, tiles))
|
|
if self:dashboardMode() then self:updateItems(nil, true) end
|
|
end
|
|
|
|
function BoardEdit:boardSetColour(colour)
|
|
self:persistSetting(BoardStore.SETTING_KEY, BoardStore.withColour(self.settings, colour))
|
|
require("bookorbit_board_ui").clearSnapshots()
|
|
if self:dashboardMode() then self:updateItems(nil, true) end
|
|
end
|
|
|
|
function BoardEdit.install(Catalog)
|
|
for name, fn in pairs(BoardEdit) do
|
|
if name ~= "install" and type(fn) == "function" and name:match("^board") then
|
|
Catalog[name] = fn
|
|
end
|
|
end
|
|
end
|
|
|
|
return BoardEdit
|