diff --git a/base b/base index 502bba07e..96c002d52 160000 --- a/base +++ b/base @@ -1 +1 @@ -Subproject commit 502bba07e57e652dcf85f0b2a5c6b1d52fbc0f75 +Subproject commit 96c002d5260b09148def07913b5e4363d9a58c23 diff --git a/frontend/apps/reader/modules/readerdictionary.lua b/frontend/apps/reader/modules/readerdictionary.lua index cd72bbf01..06293296b 100644 --- a/frontend/apps/reader/modules/readerdictionary.lua +++ b/frontend/apps/reader/modules/readerdictionary.lua @@ -800,7 +800,7 @@ function ReaderDictionary:startSdcv(word, dict_names, fuzzy_search) -- dummy results final_results = { { - dict = "", + dict = _("Not available"), word = word, definition = lookup_cancelled and _("Dictionary lookup interrupted.") or _("No results."), no_result = true, @@ -849,6 +849,22 @@ function ReaderDictionary:stardictLookup(word, dict_names, fuzzy_search, box, li return end + -- If the user disabled all the dictionaries, go away. + if dict_names and #dict_names == 0 then + -- Dummy result + local nope = { + { + dict = _("Not available"), + word = word, + definition = _("There are no enabled dictionaries.\nPlease check the 'Dictionary settings' menu."), + no_result = true, + lookup_cancelled = false, + } + } + self:showDict(word, nope, box, link) + return + end + self:showLookupInfo(word, self.lookup_msg_delay) self._lookup_start_tv = UIManager:getTime() diff --git a/frontend/apps/reader/modules/readerfont.lua b/frontend/apps/reader/modules/readerfont.lua index 2deb7abca..6fd82b6c9 100644 --- a/frontend/apps/reader/modules/readerfont.lua +++ b/frontend/apps/reader/modules/readerfont.lua @@ -209,7 +209,7 @@ function ReaderFont:onSetFontSize(new_size) self.font_size = new_size self.ui.document:setFontSize(Screen:scaleBySize(new_size)) self.ui:handleEvent(Event:new("UpdatePos")) - Notification:notify(T(_("Font size set to %1."), self.font_size)) + Notification:notify(T(_("Font size set to: %1."), self.font_size)) return true end @@ -217,7 +217,7 @@ function ReaderFont:onSetLineSpace(space) self.line_space_percent = math.min(200, math.max(50, space)) self.ui.document:setInterlineSpacePercent(self.line_space_percent) self.ui:handleEvent(Event:new("UpdatePos")) - Notification:notify(T(_("Line spacing set to %1%."), self.line_space_percent)) + Notification:notify(T(_("Line spacing set to: %1%."), self.line_space_percent)) return true end @@ -225,7 +225,7 @@ function ReaderFont:onSetFontBaseWeight(weight) self.font_base_weight = weight self.ui.document:setFontBaseWeight(weight) self.ui:handleEvent(Event:new("UpdatePos")) - Notification:notify(T(_("Font weight set to %1."), optionsutil:getOptionText("SetFontBaseWeight", weight))) + Notification:notify(T(_("Font weight set to: %1."), optionsutil:getOptionText("SetFontBaseWeight", weight))) return true end @@ -233,7 +233,7 @@ function ReaderFont:onSetFontHinting(mode) self.font_hinting = mode self.ui.document:setFontHinting(mode) self.ui:handleEvent(Event:new("UpdatePos")) - Notification:notify(T(_("Font hinting set to %1."), optionsutil:getOptionText("SetFontHinting", mode))) + Notification:notify(T(_("Font hinting set to: %1"), optionsutil:getOptionText("SetFontHinting", mode))) return true end @@ -241,7 +241,7 @@ function ReaderFont:onSetFontKerning(mode) self.font_kerning = mode self.ui.document:setFontKerning(mode) self.ui:handleEvent(Event:new("UpdatePos")) - Notification:notify(T(_("Font kerning set to %1."), optionsutil:getOptionText("SetFontKerning", mode))) + Notification:notify(T(_("Font kerning set to: %1"), optionsutil:getOptionText("SetFontKerning", mode))) return true end @@ -249,7 +249,7 @@ function ReaderFont:onSetWordSpacing(values) self.word_spacing = values self.ui.document:setWordSpacing(values) self.ui:handleEvent(Event:new("UpdatePos")) - Notification:notify(T(_("Word spacing set to %1%, %2%."), values[1], values[2])) + Notification:notify(T(_("Word spacing set to: %1%, %2%"), values[1], values[2])) return true end @@ -257,7 +257,7 @@ function ReaderFont:onSetWordExpansion(value) self.word_expansion = value self.ui.document:setWordExpansion(value) self.ui:handleEvent(Event:new("UpdatePos")) - Notification:notify(T(_("Word expansion set to %1%."), value)) + Notification:notify(T(_("Word expansion set to: %1%."), value)) return true end @@ -266,7 +266,7 @@ function ReaderFont:onSetFontGamma(gamma) self.ui.document:setGammaIndex(self.gamma_index) local gamma_level = self.ui.document:getGammaLevel() self.ui:handleEvent(Event:new("RedrawCurrentView")) - Notification:notify(T(_("Font gamma set to %1."), optionsutil:getOptionText("SetFontGamma", gamma_level))) + Notification:notify(T(_("Font gamma set to: %1."), optionsutil:getOptionText("SetFontGamma", gamma_level))) return true end diff --git a/frontend/apps/reader/modules/readerhighlight.lua b/frontend/apps/reader/modules/readerhighlight.lua index 2e0047b1f..e3cc9296f 100644 --- a/frontend/apps/reader/modules/readerhighlight.lua +++ b/frontend/apps/reader/modules/readerhighlight.lua @@ -174,20 +174,6 @@ function ReaderHighlight:init() } end) - -- User hyphenation dict - self:addToHighlightDialog("11_user_dict", function(_self) - return { - text= _("Hyphenate"), - show_in_highlight_dialog_func = function() - return _self.ui.userHyph and _self.ui.userhyph:isAvailable() and not _self.selected_text.text:find("[ ,;-%.\n]") - end, - callback = function() - _self.ui.userhyph:modifyUserEntry(_self.selected_text.text) - _self:onClose() - end, - } - end) - self.ui:registerPostInitCallback(function() self.ui.menu:registerToMainMenu(self) end) diff --git a/frontend/apps/reader/modules/readertypeset.lua b/frontend/apps/reader/modules/readertypeset.lua index c9e1b9179..53e7afa60 100644 --- a/frontend/apps/reader/modules/readertypeset.lua +++ b/frontend/apps/reader/modules/readertypeset.lua @@ -138,19 +138,27 @@ end function ReaderTypeset:onToggleEmbeddedStyleSheet(toggle) self:toggleEmbeddedStyleSheet(toggle) - Notification:notify(T( _("Embedded styles are %1."), optionsutil:getOptionText("ToggleEmbeddedStyleSheet", toggle))) + if toggle then + Notification:notify(_("Enabled embedded styles.")) + else + Notification:notify(_("Disabled embedded styles.")) + end return true end function ReaderTypeset:onToggleEmbeddedFonts(toggle) self:toggleEmbeddedFonts(toggle) - Notification:notify(T( _("Embedded fonts are %1."), optionsutil:getOptionText("ToggleEmbeddedFonts", toggle))) + if toggle then + Notification:notify(_("Enabled embedded fonts.")) + else + Notification:notify(_("Disabled embedded fonts.")) + end return true end function ReaderTypeset:onToggleImageScaling(toggle) self:toggleImageScaling(toggle) - Notification:notify(T( _("Image scaling set to %1."), optionsutil:getOptionText("ToggleImageScaling", toggle))) + Notification:notify(T( _("Image scaling set to: %1"), optionsutil:getOptionText("ToggleImageScaling", toggle))) return true end @@ -161,7 +169,7 @@ end function ReaderTypeset:onSetBlockRenderingMode(mode) self:setBlockRenderingMode(mode) - Notification:notify(T( _("Render mode set to %1."), optionsutil:getOptionText("SetBlockRenderingMode", mode))) + Notification:notify(T( _("Render mode set to: %1"), optionsutil:getOptionText("SetBlockRenderingMode", mode))) return true end @@ -183,7 +191,7 @@ local OBSOLETED_CSS = { function ReaderTypeset:onSetRenderDPI(dpi) self:setRenderDPI(dpi) - Notification:notify(T( _("Zoom set to %1."), optionsutil:getOptionText("SetRenderDPI", dpi))) + Notification:notify(T( _("Zoom set to: %1"), optionsutil:getOptionText("SetRenderDPI", dpi))) return true end diff --git a/frontend/apps/reader/modules/readertypography.lua b/frontend/apps/reader/modules/readertypography.lua index 660c4d7ea..5ad82e922 100644 --- a/frontend/apps/reader/modules/readertypography.lua +++ b/frontend/apps/reader/modules/readertypography.lua @@ -237,7 +237,6 @@ When the book's language tag is not among our presets, no specific features will }) self.text_lang_tag = lang_tag self.ui.document:setTextMainLang(lang_tag) - self.ui:handleEvent(Event:new("TypographyLanguageChanged")) self.ui:handleEvent(Event:new("UpdatePos")) end, hold_callback = function(touchmenu_instance) @@ -428,8 +427,8 @@ These settings will apply to all books with any hyphenation dictionary. enabled_func = function() return self.hyphenation and not self.hyph_soft_hyphens_only end, + separator = true, }) - table.insert(hyphenation_submenu, self.ui.userhyph:getMenuEntry()) table.insert(hyphenation_submenu, { text_func = function() -- Show the current language default hyph dict (ie: English_US for zh) @@ -489,7 +488,7 @@ These settings will apply to all books with any hyphenation dictionary. end, }) table.insert(hyphenation_submenu, { - text = _("Soft hyphens only"), + text = _("Soft-hyphens only"), callback = function() self.hyph_soft_hyphens_only = not self.hyph_soft_hyphens_only self.hyph_force_algorithmic = false @@ -761,7 +760,6 @@ function ReaderTypography:onReadSettings(config) logger.dbg("Typography lang: no lang set, using", self.text_lang_tag) end self.ui.document:setTextMainLang(self.text_lang_tag) - self.ui:handleEvent(Event:new("TypographyLanguageChanged")) end function ReaderTypography:onPreRenderDocument(config) @@ -782,7 +780,6 @@ function ReaderTypography:onPreRenderDocument(config) self.text_lang_tag = self.book_lang_tag self.ui.doc_settings:saveSetting("text_lang", self.text_lang_tag) self.ui.document:setTextMainLang(self.text_lang_tag) - self.ui:handleEvent(Event:new("TypographyLanguageChanged")) self.ui:handleEvent(Event:new("UpdatePos")) end, enabled_func = function() @@ -812,7 +809,6 @@ function ReaderTypography:onPreRenderDocument(config) end self.text_lang_tag = self.book_lang_tag self.ui.document:setTextMainLang(self.text_lang_tag) - self.ui:handleEvent(Event:new("TypographyLanguageChanged")) end end diff --git a/frontend/apps/reader/modules/readeruserhyph.lua b/frontend/apps/reader/modules/readeruserhyph.lua deleted file mode 100644 index c9863b349..000000000 --- a/frontend/apps/reader/modules/readeruserhyph.lua +++ /dev/null @@ -1,228 +0,0 @@ -local DataStorage = require("datastorage") -local Event = require("ui/event") -local FFIUtil = require("ffi/util") -local InfoMessage = require("ui/widget/infomessage") -local InputDialog = require("ui/widget/inputdialog") -local UIManager = require("ui/uimanager") -local WidgetContainer = require("ui/widget/container/widgetcontainer") -local lfs = require("libs/libkoreader-lfs") -local logger = require("logger") -local _ = require("gettext") -local T = require("ffi/util").template - -local ReaderUserHyph = WidgetContainer:new{ - -- return values from setUserHyphenationDict (crengine's UserHyphDict::init()) - USER_DICT_RELOAD = 0, - USER_DICT_NOCHANGE = 1, - USER_DICT_MALFORMED = 2, - USER_DICT_ERROR_NOT_SORTED = 3, -} - --- returns path to the user dictionary -function ReaderUserHyph:getDictionaryPath() - return FFIUtil.joinPath(DataStorage:getSettingsDir(), - "user-" .. tostring(self.ui.document:getTextMainLangDefaultHyphDictionary():gsub(".pattern$", "")) .. ".hyph") -end - --- Load the user dictionary suitable for the actual language --- if reload==true, force a reload --- Unload is done automatically when a new dictionary is loaded. -function ReaderUserHyph:loadDictionary(name, reload) - if G_reader_settings:isTrue("hyph_user_dict") and lfs.attributes(name, "mode") == "file" then - local ret = self.ui.document:setUserHyphenationDict(name, reload) - -- this should only happen, if a user edits a dictionary by hand or the user messed - -- with the dictionary file by hand. -> Warning and disable. - if ret == self.USER_DICT_ERROR_NOT_SORTED then - UIManager:show(InfoMessage:new{ - text = T(_("The user dictionary\n%1\nis not alphabetically sorted.\n\nIt has been disabled."), name), - }) - logger.warn("UserHyph: Dictionary " .. name .. " is not sorted alphabetically.") - G_reader_settings:makeFalse("hyph_user_dict") - elseif ret == self.USER_DICT_MALFORMED then - UIManager:show(InfoMessage:new{ - text = T(_("The user dictionary\n%1\nhas corrupted entries.\n\nOnly valid entries will be used."), name), - }) - logger.warn("UserHyph: Dictionary " .. name .. " has corrupted entries.") - end - else - self.ui.document:setUserHyphenationDict() -- clear crengine user hyph dict - end -end - --- Reload on change of the hyphenation language -function ReaderUserHyph:onTypographyLanguageChanged() - self:loadUserDictionary() -end - --- Reload on "ChangedUserDictionary" event, --- doesn't load dictionary if filesize and filename haven't changed --- if reload==true reload -function ReaderUserHyph:loadUserDictionary(reload) - self:loadDictionary(self:isAvailable() and self:getDictionaryPath() or "", reload and true or false) - self.ui:handleEvent(Event:new("UpdatePos")) -end - --- Functions to use with the UI - -function ReaderUserHyph:isAvailable() - return G_reader_settings:isTrue("hyph_user_dict") and self:_enabled() -end - -function ReaderUserHyph:_enabled() - return self.ui.typography.hyphenation -end - --- add Menu entry -function ReaderUserHyph:getMenuEntry() - return { - text = _("Custom hyphenation rules"), - help_text = _("The hyphenation of a word can be changed from its default by long pressing for 3 seconds and selecting 'Hyphenate'."), - callback = function() - local hyph_user_dict = not G_reader_settings:isTrue("hyph_user_dict") - G_reader_settings:saveSetting("hyph_user_dict", hyph_user_dict) - self:loadUserDictionary() -- not needed to force a reload here - end, - checked_func = function() - return self:isAvailable() - end, - enabled_func = function() - return self:_enabled() - end, - separator = true, - } -end - --- Helper functions for dictionary entries------------------------------------------- - --- checks if suggestion is well formated -function ReaderUserHyph:checkHyphenation(suggestion, word) - if suggestion:find("%-%-") then - return false -- two or more consecutive '-' - end - - suggestion = suggestion:gsub("-","") - if self.ui.document:getLowercasedWord(suggestion) == self.ui.document:getLowercasedWord(word) then - return true -- characters match (case insensitive) - end - return false -end - -function ReaderUserHyph:updateDictionary(word, hyphenation) - local dict_file = self:getDictionaryPath() - local new_dict_file = dict_file .. ".new" - - local new_dict = io.open(new_dict_file, "w") - if not new_dict then - logger.err("UserHyph: could not open " .. new_dict_file) - return - end - - local word_lower = self.ui.document:getLowercasedWord(word) - local line - - local dict = io.open(dict_file, "r") - if dict then - line = dict:read() - --search entry - while line and self.ui.document:getLowercasedWord(line:sub(1, line:find(";") - 1)) < word_lower do - new_dict:write(line .. "\n") - line = dict:read() - end - - -- last word = nil if EOF, else last_word=word if found in file, else last_word is word after the new entry - if line then - local last_word = self.ui.document:getLowercasedWord(line:sub(1, line:find(";") - 1)) - if last_word == self.ui.document:getLowercasedWord(word) then - line = nil -- word found - end - else - line = nil -- EOF - end - end - - -- write new entry - if hyphenation and hyphenation ~= "" then - new_dict:write(string.format("%s;%s\n", word, hyphenation)) - end - - -- write old entry if there was one - if line then - new_dict:write(line .. "\n") - end - - if dict then - repeat - line = dict:read() - if line then - new_dict:write(line .. "\n") - end - until (not line) - dict:close() - os.remove(dict_file) - end - - new_dict:close() - os.rename(new_dict_file, dict_file) - - self:loadUserDictionary(true) -- dictionary has changed, force a reload here -end - -function ReaderUserHyph:modifyUserEntry(word) - if word:find("[ ,;-%.]") then return end -- no button if more than one word - - if not self.ui.document then return end - - local suggested_hyphenation = self.ui.document:getHyphenationForWord(word) - - local input_dialog - input_dialog = InputDialog:new{ - title = T(_("Hyphenate: %1"), word), - description = _("Add hyphenation positions with hyphens ('-') or spaces (' ')."), - input = suggested_hyphenation, - old_hyph_lowercase = self.ui.document:getLowercasedWord(suggested_hyphenation), - input_type = "string", - buttons = { - { - { - text = _("Cancel"), - callback = function() - UIManager:close(input_dialog) - end, - }, - { - text = _("Remove"), - callback = function() - UIManager:close(input_dialog) - self:updateDictionary(word) - end, - }, - { - text = _("Save"), - is_enter_default = true, - callback = function() - local new_suggestion = input_dialog:getInputText() - new_suggestion = new_suggestion:gsub(" ","-") -- replace spaces with hyphens - new_suggestion = new_suggestion:gsub("^-","") -- remove leading hypenations - new_suggestion = new_suggestion:gsub("-$","") -- remove trailing hypenations - - if self:checkHyphenation(new_suggestion, word) then - -- don't save if no changes - if self.ui.document:getLowercasedWord(new_suggestion) ~= input_dialog.old_hyph_lowercase then - self:updateDictionary(word, new_suggestion) - end - UIManager:close(input_dialog) - else - UIManager:show(InfoMessage:new{ - text = T(_("Invalid hyphenation!"), self.dict_file), - }) - end - end, - }, - }, - }, - } - UIManager:show(input_dialog) - input_dialog:onShowKeyboard() -end - -return ReaderUserHyph diff --git a/frontend/apps/reader/modules/readerview.lua b/frontend/apps/reader/modules/readerview.lua index 4b6132983..efc55d3ae 100644 --- a/frontend/apps/reader/modules/readerview.lua +++ b/frontend/apps/reader/modules/readerview.lua @@ -715,7 +715,7 @@ function ReaderView:onSetRotationMode(rotation) self.ui:handleEvent(Event:new("SetDimensions", new_screen_size)) self.ui:onScreenResize(new_screen_size) self.ui:handleEvent(Event:new("InitScrollPageStates")) - Notification:notify(T(_("Rotation mode set to %1."), optionsutil:getOptionText("SetRotationMode", rotation))) + Notification:notify(T(_("Rotation mode set to: %1"), optionsutil:getOptionText("SetRotationMode", rotation))) return true end @@ -849,12 +849,12 @@ function ReaderView:onGammaUpdate(gamma) if self.page_scroll then self.ui:handleEvent(Event:new("UpdateScrollPageGamma", gamma)) end - Notification:notify(T(_("Font gamma set to %1."), gamma)) + Notification:notify(T(_("Font gamma set to: %1."), gamma)) end function ReaderView:onFontSizeUpdate(font_size) self.ui:handleEvent(Event:new("ReZoom", font_size)) - Notification:notify(T(_("Font zoom set to %1."), font_size)) + Notification:notify(T(_("Font zoom set to: %1."), font_size)) end function ReaderView:onDefectSizeUpdate() @@ -874,7 +874,7 @@ function ReaderView:onSetViewMode(new_mode) self.view_mode = new_mode self.ui.document:setViewMode(new_mode) self.ui:handleEvent(Event:new("ChangeViewMode")) - Notification:notify(T( _("View mode set to %1."), optionsutil:getOptionText("SetViewMode", new_mode))) + Notification:notify(T( _("View mode set to: %1"), optionsutil:getOptionText("SetViewMode", new_mode))) end end diff --git a/frontend/apps/reader/readerui.lua b/frontend/apps/reader/readerui.lua index 03452a04a..85e0c7772 100644 --- a/frontend/apps/reader/readerui.lua +++ b/frontend/apps/reader/readerui.lua @@ -48,7 +48,6 @@ local ReaderStyleTweak = require("apps/reader/modules/readerstyletweak") local ReaderToc = require("apps/reader/modules/readertoc") local ReaderTypeset = require("apps/reader/modules/readertypeset") local ReaderTypography = require("apps/reader/modules/readertypography") -local ReaderUserHyph = require("apps/reader/modules/readeruserhyph") local ReaderView = require("apps/reader/modules/readerview") local ReaderWikipedia = require("apps/reader/modules/readerwikipedia") local ReaderZooming = require("apps/reader/modules/readerzooming") @@ -315,12 +314,6 @@ function ReaderUI:init() view = self.view, ui = self }) - -- user hyphenation (must be registered before typography) - self:registerModule("userhyph", ReaderUserHyph:new{ - dialog = self.dialog, - view = self.view, - ui = self - }) -- typography menu (replaces previous hyphenation menu / ReaderHyphenation) self:registerModule("typography", ReaderTypography:new{ dialog = self.dialog, diff --git a/frontend/device/android/device.lua b/frontend/device/android/device.lua index 908442705..47ac0e464 100644 --- a/frontend/device/android/device.lua +++ b/frontend/device/android/device.lua @@ -132,10 +132,11 @@ function Device:init() device = self, event_map = require("device/android/event_map"), handleMiscEv = function(this, ev) + local Event = require("ui/event") local UIManager = require("ui/uimanager") logger.dbg("Android application event", ev.code) if ev.code == C.APP_CMD_SAVE_STATE then - return "SaveState" + UIManager:broadcastEvent(Event:new("SaveSettings")) elseif ev.code == C.APP_CMD_DESTROY then UIManager:quit() elseif ev.code == C.APP_CMD_GAINED_FOCUS @@ -152,7 +153,6 @@ function Device:init() this.device.screen:resize() local new_size = this.device.screen:getSize() logger.info("Resizing screen to", new_size) - local Event = require("ui/event") local FileManager = require("apps/filemanager/filemanager") UIManager:broadcastEvent(Event:new("SetDimensions", new_size)) UIManager:broadcastEvent(Event:new("ScreenResize", new_size)) @@ -166,10 +166,8 @@ function Device:init() end end -- to-do: keyboard connected, disconnected - elseif ev.code == C.APP_CMD_START then - local Event = require("ui/event") - UIManager:broadcastEvent(Event:new("Resume")) elseif ev.code == C.APP_CMD_RESUME then + UIManager:broadcastEvent(Event:new("Resume")) if external.when_back_callback then external.when_back_callback() external.when_back_callback = nil @@ -207,14 +205,11 @@ function Device:init() end end end - elseif ev.code == C.APP_CMD_STOP then - local Event = require("ui/event") + elseif ev.code == C.APP_CMD_PAUSE then UIManager:broadcastEvent(Event:new("Suspend")) elseif ev.code == C.AEVENT_POWER_CONNECTED then - local Event = require("ui/event") UIManager:broadcastEvent(Event:new("Charging")) elseif ev.code == C.AEVENT_POWER_DISCONNECTED then - local Event = require("ui/event") UIManager:broadcastEvent(Event:new("NotCharging")) elseif ev.code == C.AEVENT_DOWNLOAD_COMPLETE then android.ota.isRunning = false @@ -462,9 +457,9 @@ function Device:untar(archive, extract_to) end function Device:download(link, name, ok_text) - local UIManager = require("ui/uimanager") local ConfirmBox = require("ui/widget/confirmbox") local InfoMessage = require("ui/widget/infomessage") + local UIManager = require("ui/uimanager") local ok = android.download(link, name) if ok == C.ADOWNLOAD_EXISTS then self:install() @@ -484,12 +479,14 @@ function Device:download(link, name, ok_text) end function Device:install() - local UIManager = require("ui/uimanager") local ConfirmBox = require("ui/widget/confirmbox") + local Event = require("ui/event") + local UIManager = require("ui/uimanager") UIManager:show(ConfirmBox:new{ text = _("Update is ready. Install it now?"), ok_text = _("Install"), ok_callback = function() + UIManager:broadcastEvent(Event:new("SaveSettings")) android.ota.install() android.ota.isPending = false end, diff --git a/frontend/device/pocketbook/device.lua b/frontend/device/pocketbook/device.lua index 1d10075ef..ed55ef5f9 100644 --- a/frontend/device/pocketbook/device.lua +++ b/frontend/device/pocketbook/device.lua @@ -488,6 +488,7 @@ local PocketBook626 = PocketBook:new{ local PocketBook627 = PocketBook:new{ model = "PBLux4", display_dpi = 212, + isAlwaysPortrait = yes, } -- PocketBook Touch Lux 5 (628) @@ -576,6 +577,16 @@ local PocketBook740_2 = PocketBook:new{ } } +-- PocketBook InkPad Color (741) +local PocketBook741 = PocketBook:new{ + model = "PBInkPadColor", + display_dpi = 300, + hasColorScreen = yes, + canUseCBB = no, -- 24bpp + isAlwaysPortrait = yes, + usingForcedRotation = landscape_ccw, +} + -- PocketBook Color Lux (801) local PocketBookColorLux = PocketBook:new{ model = "PBColorLux", @@ -662,6 +673,8 @@ elseif codename == "PB740" then return PocketBook740 elseif codename == "PB740-2" then return PocketBook740_2 +elseif codename == "PB741" then + return PocketBook741 elseif codename == "PocketBook 840" then return PocketBook840 elseif codename == "PB1040" then diff --git a/frontend/device/thirdparty.lua b/frontend/device/thirdparty.lua index 65bdfc41e..553fc8881 100644 --- a/frontend/device/thirdparty.lua +++ b/frontend/device/thirdparty.lua @@ -33,7 +33,9 @@ function M:new(o) end end end - logger.info(o:dump()) + if o.is_user_list then + logger.info(o:dump()) + end return o end @@ -54,7 +56,7 @@ function M:checkMethod(role, method) end function M:dump() - local str = (self.is_user_list and "user" or "platform") .. " thirdparty apps\n" + local str = "user defined thirdparty apps\n" for i, role in ipairs(roles) do local apps = self[role.."s"] for index, _ in ipairs(apps or {}) do diff --git a/frontend/document/credocument.lua b/frontend/document/credocument.lua index 745908e89..a8b52029c 100644 --- a/frontend/document/credocument.lua +++ b/frontend/document/credocument.lua @@ -980,25 +980,6 @@ function CreDocument:setTextHyphenationSoftHyphensOnly(toggle) self._document:setStringProperty("crengine.textlang.hyphenation.soft.hyphens.only", toggle and 1 or 0) end -function CreDocument:setUserHyphenationDict(dict, reload) - logger.dbg("CreDocument: set textlang hyphenation dict", dict or "none") - return self._document:setUserHyphenationDict(dict or "", reload or false) -end - -function CreDocument:getHyphenationForWord(word) - if word then - return self._document:getHyphenationForWord(word) - end - return word -end - -function CreDocument:getLowercasedWord(word) - if word then - return self._document:getLowercasedWord(word) - end - return word -end - function CreDocument:setTextHyphenationForceAlgorithmic(toggle) logger.dbg("CreDocument: set textlang hyphenation force algorithmic", toggle) self._document:setStringProperty("crengine.textlang.hyphenation.force.algorithmic", toggle and 1 or 0) diff --git a/frontend/ui/uimanager.lua b/frontend/ui/uimanager.lua index 6aca33208..fa13cbe8a 100644 --- a/frontend/ui/uimanager.lua +++ b/frontend/ui/uimanager.lua @@ -467,16 +467,16 @@ function UIManager:close(widget, refreshtype, refreshregion, refreshdither) end logger.dbg("close widget:", widget.name or widget.id or tostring(widget)) local dirty = false - -- Ensure all the widgets can get onFlushSettings event. + -- First notify the closed widget to save its settings... widget:handleEvent(Event:new("FlushSettings")) - -- first send close event to widget + -- ...and notify it that it ought to be gone now. widget:handleEvent(Event:new("CloseWidget")) - -- make it disabled by default and check if any widget wants it disabled or enabled + -- Make sure it's disabled by default and check if there are any widgets that want it disabled or enabled. Input.disable_double_tap = true local requested_disable_double_tap = nil local is_covered = false local start_idx = 1 - -- then remove all references to that widget on stack and refresh + -- Then remove all references to that widget on stack and refresh. for i = #self._window_stack, 1, -1 do if self._window_stack[i].widget == widget then self._dirty[self._window_stack[i].widget] = nil diff --git a/frontend/ui/widget/datewidget.lua b/frontend/ui/widget/datewidget.lua index 4fdef411d..2f3291523 100644 --- a/frontend/ui/widget/datewidget.lua +++ b/frontend/ui/widget/datewidget.lua @@ -210,7 +210,6 @@ function DateWidget:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self.date_frame.dimen end) - return true end function DateWidget:onShow() diff --git a/frontend/ui/widget/dictquicklookup.lua b/frontend/ui/widget/dictquicklookup.lua index 3d45cf472..b2a345821 100644 --- a/frontend/ui/widget/dictquicklookup.lua +++ b/frontend/ui/widget/dictquicklookup.lua @@ -909,7 +909,6 @@ function DictQuickLookup:onCloseWidget() UIManager:setDirty(nil, function() return "flashui", nil end) - return true end function DictQuickLookup:onShow() diff --git a/frontend/ui/widget/doublespinwidget.lua b/frontend/ui/widget/doublespinwidget.lua index e24e71e30..cfba7505a 100644 --- a/frontend/ui/widget/doublespinwidget.lua +++ b/frontend/ui/widget/doublespinwidget.lua @@ -295,7 +295,6 @@ function DoubleSpinWidget:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self.widget_frame.dimen end) - return true end function DoubleSpinWidget:onShow() diff --git a/frontend/ui/widget/frontlightwidget.lua b/frontend/ui/widget/frontlightwidget.lua index 5fd241670..c73f9af28 100644 --- a/frontend/ui/widget/frontlightwidget.lua +++ b/frontend/ui/widget/frontlightwidget.lua @@ -583,7 +583,6 @@ function FrontLightWidget:onCloseWidget() UIManager:setDirty(nil, function() return "flashui", self.light_frame.dimen end) - return true end function FrontLightWidget:onShow() diff --git a/frontend/ui/widget/imageviewer.lua b/frontend/ui/widget/imageviewer.lua index c69eff1f4..7cd9f5cd2 100644 --- a/frontend/ui/widget/imageviewer.lua +++ b/frontend/ui/widget/imageviewer.lua @@ -850,7 +850,6 @@ function ImageViewer:onCloseWidget() UIManager:setDirty(nil, function() return "flashui", self.main_frame.dimen end) - return true end return ImageViewer diff --git a/frontend/ui/widget/infomessage.lua b/frontend/ui/widget/infomessage.lua index dec9f6d75..7ae72ff08 100644 --- a/frontend/ui/widget/infomessage.lua +++ b/frontend/ui/widget/infomessage.lua @@ -206,16 +206,15 @@ function InfoMessage:onCloseWidget() end if self.invisible then -- Still invisible, no setDirty needed - return true + return end if self.no_refresh_on_close then - return true + return end UIManager:setDirty(nil, function() return "ui", self[1][1].dimen end) - return true end function InfoMessage:onShow() diff --git a/frontend/ui/widget/inputdialog.lua b/frontend/ui/widget/inputdialog.lua index 759acd736..f5609ffcb 100644 --- a/frontend/ui/widget/inputdialog.lua +++ b/frontend/ui/widget/inputdialog.lua @@ -391,6 +391,7 @@ function InputDialog:init() scroll_callback = self._buttons_scroll_callback, -- nil if no Nav or Scroll buttons scroll = true, scroll_by_pan = self.scroll_by_pan, + has_nav_bar = self.add_nav_bar, cursor_at_end = self.cursor_at_end, readonly = self.readonly, parent = self, diff --git a/frontend/ui/widget/inputtext.lua b/frontend/ui/widget/inputtext.lua index 2483b76ab..d565264cc 100644 --- a/frontend/ui/widget/inputtext.lua +++ b/frontend/ui/widget/inputtext.lua @@ -61,6 +61,7 @@ local InputText = InputContainer:new{ for_measurement_only = nil, -- When the widget is a one-off used to compute text height do_select = false, -- to start text selection selection_start_pos = nil, -- selection start position + is_keyboard_hidden = false, -- to be able to show the keyboard again when it was hidden (by VK itself) } -- only use PhysicalKeyboard if the device does not have touch screen @@ -121,6 +122,11 @@ if Device:isTouchDevice() or Device:hasDPad() then function InputText:onTapTextBox(arg, ges) if self.parent.onSwitchFocus then self.parent:onSwitchFocus(self) + else + if self.is_keyboard_hidden == true then + self:onShowKeyboard() + self.is_keyboard_hidden = false + end end if #self.charlist > 0 then -- Avoid cursor moving within a hint. local textwidget_offset = self.margin + self.bordersize + self.padding @@ -563,12 +569,21 @@ end function InputText:onShowKeyboard(ignore_first_hold_release) Device:startTextInput() - self.keyboard.ignore_first_hold_release = ignore_first_hold_release UIManager:show(self.keyboard) return true end +function InputText:onHideKeyboard() + if not self.has_nav_bar then + UIManager:close(self.keyboard) + Device:stopTextInput() + self.is_keyboard_hidden = true + end + + return self.is_keyboard_hiddenend +end + function InputText:onCloseKeyboard() UIManager:close(self.keyboard) Device:stopTextInput() diff --git a/frontend/ui/widget/keyboardlayoutdialog.lua b/frontend/ui/widget/keyboardlayoutdialog.lua index 8fadc4439..5296afcd6 100644 --- a/frontend/ui/widget/keyboardlayoutdialog.lua +++ b/frontend/ui/widget/keyboardlayoutdialog.lua @@ -157,7 +157,6 @@ function KeyboardLayoutDialog:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self[1][1].dimen end) - return true end return KeyboardLayoutDialog diff --git a/frontend/ui/widget/linkbox.lua b/frontend/ui/widget/linkbox.lua index 59f03bf65..1003621a9 100644 --- a/frontend/ui/widget/linkbox.lua +++ b/frontend/ui/widget/linkbox.lua @@ -38,7 +38,6 @@ function LinkBox:onCloseWidget() UIManager:setDirty(nil, function() return "partial", self.box end) - return true end function LinkBox:onShow() diff --git a/frontend/ui/widget/naturallightwidget.lua b/frontend/ui/widget/naturallightwidget.lua index 594b65ce5..d10714b0c 100644 --- a/frontend/ui/widget/naturallightwidget.lua +++ b/frontend/ui/widget/naturallightwidget.lua @@ -381,7 +381,6 @@ function NaturalLightWidget:onCloseWidget() end) -- Tell frontlight widget that we're closed self.fl_widget:naturalLightConfigClose() - return true end function NaturalLightWidget:onShow() diff --git a/frontend/ui/widget/notification.lua b/frontend/ui/widget/notification.lua index c4c9ceccf..13b815b6f 100644 --- a/frontend/ui/widget/notification.lua +++ b/frontend/ui/widget/notification.lua @@ -182,7 +182,6 @@ function Notification:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self.frame.dimen end) - return true end function Notification:onShow() diff --git a/frontend/ui/widget/openwithdialog.lua b/frontend/ui/widget/openwithdialog.lua index 8bb1b377a..cf8acc982 100644 --- a/frontend/ui/widget/openwithdialog.lua +++ b/frontend/ui/widget/openwithdialog.lua @@ -188,7 +188,6 @@ function OpenWithDialog:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self.dialog_frame.dimen end) - return true end return OpenWithDialog diff --git a/frontend/ui/widget/qrmessage.lua b/frontend/ui/widget/qrmessage.lua index cb39d2d86..684bbb2aa 100644 --- a/frontend/ui/widget/qrmessage.lua +++ b/frontend/ui/widget/qrmessage.lua @@ -86,7 +86,6 @@ function QRMessage:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self[1][1].dimen end) - return true end function QRMessage:onShow() diff --git a/frontend/ui/widget/screensaverwidget.lua b/frontend/ui/widget/screensaverwidget.lua index d03f0a70d..2d004241a 100644 --- a/frontend/ui/widget/screensaverwidget.lua +++ b/frontend/ui/widget/screensaverwidget.lua @@ -88,7 +88,6 @@ function ScreenSaverWidget:onCloseWidget() UIManager:setDirty(nil, function() return "full", self.main_frame.dimen end) - return true end return ScreenSaverWidget diff --git a/frontend/ui/widget/skimtowidget.lua b/frontend/ui/widget/skimtowidget.lua index d7ec7fbdb..b6b1bcadb 100644 --- a/frontend/ui/widget/skimtowidget.lua +++ b/frontend/ui/widget/skimtowidget.lua @@ -338,7 +338,6 @@ function SkimToWidget:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self.skimto_frame.dimen end) - return true end function SkimToWidget:onShow() diff --git a/frontend/ui/widget/spinwidget.lua b/frontend/ui/widget/spinwidget.lua index b83d15477..a2d5b1c52 100644 --- a/frontend/ui/widget/spinwidget.lua +++ b/frontend/ui/widget/spinwidget.lua @@ -248,7 +248,6 @@ function SpinWidget:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self.spin_frame.dimen end) - return true end function SpinWidget:onShow() diff --git a/frontend/ui/widget/textviewer.lua b/frontend/ui/widget/textviewer.lua index 602c957f2..096e5ac38 100644 --- a/frontend/ui/widget/textviewer.lua +++ b/frontend/ui/widget/textviewer.lua @@ -229,7 +229,6 @@ function TextViewer:onCloseWidget() UIManager:setDirty(nil, function() return "partial", self.frame.dimen end) - return true end function TextViewer:onShow() diff --git a/frontend/ui/widget/timewidget.lua b/frontend/ui/widget/timewidget.lua index 63bd95aac..a3bf01a02 100644 --- a/frontend/ui/widget/timewidget.lua +++ b/frontend/ui/widget/timewidget.lua @@ -195,7 +195,6 @@ function TimeWidget:onCloseWidget() UIManager:setDirty(nil, function() return "ui", self.time_frame.dimen end) - return true end function TimeWidget:onShow() diff --git a/frontend/ui/widget/trapwidget.lua b/frontend/ui/widget/trapwidget.lua index 7dba76521..b33d14b98 100644 --- a/frontend/ui/widget/trapwidget.lua +++ b/frontend/ui/widget/trapwidget.lua @@ -155,7 +155,6 @@ function TrapWidget:onCloseWidget() return "ui", self.frame.dimen end) end - return true end return TrapWidget diff --git a/frontend/ui/widget/virtualkeyboard.lua b/frontend/ui/widget/virtualkeyboard.lua index 519a30c7d..5dbd4868d 100644 --- a/frontend/ui/widget/virtualkeyboard.lua +++ b/frontend/ui/widget/virtualkeyboard.lua @@ -111,7 +111,7 @@ function VirtualKey:init() self.keyboard:delToStartOfLine() end --self.skiphold = true - elseif self.label =="←" then + elseif self.label == "←" then self.callback = function() self.keyboard:leftChar() end self.hold_callback = function() self.ignore_key_release = true @@ -127,6 +127,13 @@ function VirtualKey:init() self.callback = function() self.keyboard:upLine() end elseif self.label == "↓" then self.callback = function() self.keyboard:downLine() end + self.hold_callback = function() + self.ignore_key_release = true + if not self.keyboard:onHideKeyboard() then + -- Keyboard was *not* actually hidden: refresh the key to clear the highlight + self:update_keyboard(false, true) + end + end else self.callback = function () self.keyboard:addChar(self.key) end self.hold_callback = function() @@ -520,6 +527,17 @@ function VirtualKeyPopup:init() virtual_key.hold_callback = nil -- close popup on hold release virtual_key.onHoldReleaseKey = function() + -- NOTE: Check our *parent* key! + if parent_key.ignore_key_release then + parent_key.ignore_key_release = nil + return true + end + Device:performHapticFeedback("LONG_PRESS") + if virtual_key.keyboard.ignore_first_hold_release then + virtual_key.keyboard.ignore_first_hold_release = false + return true + end + virtual_key:onTapSelect(true) UIManager:close(self) return true @@ -630,13 +648,19 @@ function VirtualKeyPopup:init() } if position_container.dimen.x < 0 then position_container.dimen.x = 0 + -- We effectively move the popup, which means the key underneath our finger may no longer *exactly* be parent_key. + -- Make sure we won't close the popup right away, as that would risk being a *different* key, in order to make that less confusing. + parent_key.ignore_key_release = true elseif position_container.dimen.x + keyboard_frame.dimen.w > Screen:getWidth() then position_container.dimen.x = Screen:getWidth() - keyboard_frame.dimen.w + parent_key.ignore_key_release = true end if position_container.dimen.y < 0 then position_container.dimen.y = 0 + parent_key.ignore_key_release = true elseif position_container.dimen.y + keyboard_frame.dimen.h > Screen:getHeight() then position_container.dimen.y = Screen:getHeight() - keyboard_frame.dimen.h + parent_key.ignore_key_release = true end self[1] = position_container @@ -745,6 +769,10 @@ function VirtualKeyboard:onClose() return true end +function VirtualKeyboard:onHideKeyboard() + return self.inputbox:onHideKeyboard() +end + function VirtualKeyboard:onPressKey() self:getFocusItem():handleEvent(Event:new("TapSelect")) return true @@ -771,7 +799,6 @@ end function VirtualKeyboard:onCloseWidget() self:_refresh(false) - return true end function VirtualKeyboard:initLayer(layer) diff --git a/platform/cervantes/koreader.sh b/platform/cervantes/koreader.sh index 3bdb84424..6f975f88d 100755 --- a/platform/cervantes/koreader.sh +++ b/platform/cervantes/koreader.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash export LC_ALL="en_US.UTF-8" @@ -83,6 +83,9 @@ if [ "${STANDALONE}" != "true" ]; then [ -x /etc/init.d/connman ] && /etc/init.d/connman stop fi +CRASH_COUNT=0 +CRASH_TS=0 +CRASH_PREV_TS=0 # **magic** values to request shell stuff. It starts at 85, # any number lower than that will exit this script. RESTART_KOREADER=85 @@ -91,18 +94,101 @@ ENTER_QBOOKAPP=87 RETURN_VALUE="${RESTART_KOREADER}" # Loop forever until KOReader requests a normal exit. -while [ "${RETURN_VALUE}" -ge "${RESTART_KOREADER}" ]; do +while [ "${RETURN_VALUE}" -ne 0 ]; do # move dictionaries from external storage to koreader private partition. find /mnt/public/dict -type f -exec mv -v \{\} /mnt/private/koreader/data/dict \; 2>/dev/null - # Do an update check now, so we can actually update KOReader via the "Restart KOReader" menu entry ;). - ko_update_check + if [ ${RETURN_VALUE} -eq ${RESTART_KOREADER} ]; then + # Do an update check now, so we can actually update KOReader via the "Restart KOReader" menu entry ;). + ko_update_check + fi # run KOReader ./reader.lua "$@" >>crash.log 2>&1 RETURN_VALUE=$? + if [ ${RETURN_VALUE} -ne 0 ] && [ "${RETURN_VALUE}" -ne "${ENTER_USBMS}" ] && [ "${RETURN_VALUE}" -ne "${ENTER_QBOOKAPP}" ] && [ "${RETURN_VALUE}" -ne "${RESTART_KOREADER}" ]; then + # Increment the crash counter + CRASH_COUNT=$((CRASH_COUNT + 1)) + CRASH_TS=$(date +'%s') + # Reset it to a first crash if it's been a while since our last crash... + if [ $((CRASH_TS - CRASH_PREV_TS)) -ge 20 ]; then + CRASH_COUNT=1 + fi + + # Check if the user requested to always abort on crash + if grep -q '\["dev_abort_on_crash"\] = true' 'settings.reader.lua' 2>/dev/null; then + ALWAYS_ABORT="true" + # In which case, make sure we pause on *every* crash + CRASH_COUNT=1 + else + ALWAYS_ABORT="false" + fi + + # Show a fancy bomb on screen + viewWidth=600 + viewHeight=800 + FONTH=16 + eval "$(./fbink -e | tr ';' '\n' | grep -e viewWidth -e viewHeight -e FONTH | tr '\n' ';')" + # Compute margins & sizes relative to the screen's resolution, so we end up with a similar layout, no matter the device. + # Height @ ~56.7%, w/ a margin worth 1.5 lines + bombHeight=$((viewHeight / 2 + viewHeight / 15)) + bombMargin=$((FONTH + FONTH / 2)) + # With a little notice at the top of the screen, on a big gray screen of death ;). + ./fbink -q -b -c -B GRAY9 -m -y 1 "Don't Panic! (Crash n°${CRASH_COUNT} -> ${RETURN_VALUE})" + if [ ${CRASH_COUNT} -eq 1 ]; then + # Warn that we're waiting on a tap to continue... + ./fbink -q -b -O -m -y 2 "Tap the screen to continue." + fi + # U+1F4A3, the hard way, because we can't use \u or \U escape sequences... + ./fbink -q -b -O -m -t regular=./fonts/freefont/FreeSerif.ttf,px=${bombHeight},top=${bombMargin} -- $'\xf0\x9f\x92\xa3' + # And then print the tail end of the log on the bottom of the screen... + crashLog="$(tail -n 25 crash.log | sed -e 's/\t/ /g')" + # The idea for the margins being to leave enough room for an fbink -Z bar, small horizontal margins, and a font size based on what 6pt looked like @ 265dpi + ./fbink -q -b -O -t regular=./fonts/droid/DroidSansMono.ttf,top=$((viewHeight / 2 + FONTH * 2 + FONTH / 2)),left=$((viewWidth / 60)),right=$((viewWidth / 60)),px=$((viewHeight / 64)) -- "${crashLog}" + # So far, we hadn't triggered an actual screen refresh, do that now, to make sure everything is bundled in a single flashing refresh. + ./fbink -q -f -s + # Cue a lemming's faceplant sound effect! + + { + echo "!!!!" + echo "Uh oh, something went awry... (Crash n°${CRASH_COUNT}: $(date +'%x @ %X'))" + echo "Running on Linux $(uname -r) ($(uname -v))" + } >>crash.log 2>&1 + if [ ${CRASH_COUNT} -lt 5 ] && [ "${ALWAYS_ABORT}" = "false" ]; then + echo "Attempting to restart KOReader . . ." >>crash.log 2>&1 + echo "!!!!" >>crash.log 2>&1 + fi + + # Pause a bit if it's the first crash in a while, so that it actually has a chance of getting noticed ;). + if [ ${CRASH_COUNT} -eq 1 ]; then + # NOTE: We don't actually care about what head reads, we're just using it as a fancy sleep ;). + # i.e., we pause either until the 15s timeout, or until the user touches the screen. + timeout 15 head -c 24 /dev/input/event1 >/dev/null + fi + # Cycle the last crash timestamp + CRASH_PREV_TS=${CRASH_TS} + + # But if we've crashed more than 5 consecutive times, exit, because we wouldn't want to be stuck in a loop... + # NOTE: No need to check for ALWAYS_ABORT, CRASH_COUNT will always be 1 when it's true ;). + if [ ${CRASH_COUNT} -ge 5 ]; then + echo "Too many consecutive crashes, aborting . . ." >>crash.log 2>&1 + echo "!!!! ! !!!!" >>crash.log 2>&1 + break + fi + + # If the user requested to always abort on crash, do so. + if [ "${ALWAYS_ABORT}" = "true" ]; then + echo "Aborting . . ." >>crash.log 2>&1 + echo "!!!! ! !!!!" >>crash.log 2>&1 + break + fi + else + # Reset the crash counter if that was a sane exit/restart + CRASH_COUNT=0 + fi + # check if KOReader requested to enter in mass storage mode. if [ "${RETURN_VALUE}" -eq "${ENTER_USBMS}" ]; then # NOTE: at this point we're sure that the safemode tool diff --git a/platform/pocketbook/koreader.app b/platform/pocketbook/koreader.app index cf8ea5529..2f3ad9b8d 100755 --- a/platform/pocketbook/koreader.app +++ b/platform/pocketbook/koreader.app @@ -33,13 +33,16 @@ ko_update_check() { # NOTE: See frontend/ui/otamanager.lua for a few more details on how we squeeze a percentage out of tar's checkpoint feature # NOTE: %B should always be 512 in our case, so let stat do part of the maths for us instead of using %s ;). FILESIZE="$(stat -c %b "${NEWUPDATE}")" - BLOCKS="$((FILESIZE / 20))" - export CPOINTS="$((BLOCKS / 100))" + # shellcheck disable=SC2003 + BLOCKS="$(expr "${FILESIZE}" / 20)" + # shellcheck disable=SC2003 + CPOINTS="$(expr "${BLOCKS}" / 100)" + export CPOINTS # NOTE: We don't run as root, but folders created over USBMS are owned by root, which yields fun permission shenanigans... # c.f., https://github.com/koreader/koreader/issues/7581 KO_PB_TARLOG="/tmp/.koreader.tar" # shellcheck disable=SC2016 - "${KOREADER_DIR}/tar" --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='printf "%s" $((TAR_CHECKPOINT / CPOINTS)) > ${FBINK_NAMED_PIPE}' -C "/mnt/ext1" -xf "${NEWUPDATE}" 2>"${KO_PB_TARLOG}" + "${KOREADER_DIR}/tar" --no-same-permissions --no-same-owner --checkpoint="${CPOINTS}" --checkpoint-action=exec='printf "%s" $(expr ${TAR_CHECKPOINT} / ${CPOINTS}) > ${FBINK_NAMED_PIPE}' -C "/mnt/ext1" -xf "${NEWUPDATE}" 2>"${KO_PB_TARLOG}" fail=$? kill -TERM "${FBINK_PID}" # As mentioned above, filter out potential chmod & utime failures... @@ -116,10 +119,12 @@ while [ "${RETURN_VALUE}" -ne 0 ]; do # Did we crash? if [ "${RETURN_VALUE}" -ne 0 ] && [ "${RETURN_VALUE}" -ne ${KO_RC_RESTART} ]; then # Increment the crash counter - CRASH_COUNT=$((CRASH_COUNT + 1)) - CRASH_TS=$(date +'%s') + # shellcheck disable=SC2003 + CRASH_COUNT="$(expr ${CRASH_COUNT} + 1)" + CRASH_TS="$(date +'%s')" # Reset it to a first crash if it's been a while since our last crash... - if [ $((CRASH_TS - CRASH_PREV_TS)) -ge 20 ]; then + # shellcheck disable=SC2003 + if [ "$(expr "${CRASH_TS}" - "${CRASH_PREV_TS}")" -ge 20 ]; then CRASH_COUNT=1 fi @@ -139,8 +144,10 @@ while [ "${RETURN_VALUE}" -ne 0 ]; do eval "$("${KOREADER_DIR}/fbink" -e | tr ';' '\n' | grep -e viewWidth -e viewHeight -e FONTH | tr '\n' ';')" # Compute margins & sizes relative to the screen's resolution, so we end up with a similar layout, no matter the device. # Height @ ~56.7%, w/ a margin worth 1.5 lines - bombHeight=$((viewHeight / 2 + viewHeight / 15)) - bombMargin=$((FONTH + FONTH / 2)) + # shellcheck disable=SC2003 + bombHeight="$(expr ${viewHeight} / 2 + ${viewHeight} / 15)" + # shellcheck disable=SC2003 + bombMargin="$(expr ${FONTH} + ${FONTH} / 2)" # With a little notice at the top of the screen, on a big gray screen of death ;). "${KOREADER_DIR}/fbink" -q -b -c -B GRAY9 -m -y 1 "Don't Panic! (Crash n°${CRASH_COUNT} -> ${RETURN_VALUE})" if [ ${CRASH_COUNT} -eq 1 ]; then @@ -149,11 +156,12 @@ while [ "${RETURN_VALUE}" -ne 0 ]; do fi # U+1F4A3, the hard way, because we can't use \u or \U escape sequences... # shellcheck disable=SC2039,SC3003 - "${KOREADER_DIR}/fbink" -q -b -O -m -t regular=${KOREADER_DIR}/fonts/freefont/FreeSerif.ttf,px=${bombHeight},top=${bombMargin} -- $'\xf0\x9f\x92\xa3' + "${KOREADER_DIR}/fbink" -q -b -O -m -t regular=${KOREADER_DIR}/fonts/freefont/FreeSerif.ttf,px="${bombHeight}",top="${bombMargin}" -- $'\xf0\x9f\x92\xa3' # And then print the tail end of the log on the bottom of the screen... crashLog="$(tail -n 25 crash.log | sed -e 's/\t/ /g')" # The idea for the margins being to leave enough room for an fbink -Z bar, small horizontal margins, and a font size based on what 6pt looked like @ 265dpi - "${KOREADER_DIR}/fbink" -q -b -O -t regular=${KOREADER_DIR}/fonts/droid/DroidSansMono.ttf,top=$((viewHeight / 2 + FONTH * 2 + FONTH / 2)),left=$((viewWidth / 60)),right=$((viewWidth / 60)),px=$((viewHeight / 64)) -- "${crashLog}" + # shellcheck disable=SC2003 + "${KOREADER_DIR}/fbink" -q -b -O -t regular=${KOREADER_DIR}/fonts/droid/DroidSansMono.ttf,top="$(expr ${viewHeight} / 2 + ${FONTH} '*' 2 + ${FONTH} / 2)",left="$(expr ${viewWidth} / 60)",right="$(expr ${viewWidth} / 60)",px="$(expr ${viewHeight} / 64)" -- "${crashLog}" # So far, we hadn't triggered an actual screen refresh, do that now, to make sure everything is bundled in a single flashing refresh. ${KOREADER_DIR}/fbink -q -f -s # Cue a lemming's faceplant sound effect! diff --git a/plugins/opds.koplugin/opdsbrowser.lua b/plugins/opds.koplugin/opdsbrowser.lua index d8b0ac00f..8715a23d5 100644 --- a/plugins/opds.koplugin/opdsbrowser.lua +++ b/plugins/opds.koplugin/opdsbrowser.lua @@ -612,6 +612,7 @@ end function OPDSBrowser:createNewDownloadDialog(path, buttons) self.download_dialog = ButtonDialogTitle:new{ title = T(_("Download folder:\n%1\n\nDownload file type:"), BD.dirpath(path)), + use_info_style = true, buttons = buttons } end @@ -650,10 +651,10 @@ function OPDSBrowser:showDownloads(item) table.insert(buttons, line) end table.insert(buttons, {}) - -- Set download folder button. + -- Set download folder and book info buttons. table.insert(buttons, { { - text = _("Select another folder"), + text = _("Select folder"), callback = function() require("ui/downloadmgr"):new{ onConfirm = function(path) @@ -667,7 +668,18 @@ function OPDSBrowser:showDownloads(item) end, }:chooseDir() end, - } + }, + { + text = _("Book information"), + enabled = type(item.content) == "string", + callback = function() + local TextViewer = require("ui/widget/textviewer") + UIManager:show(TextViewer:new{ + title = item.text, + text = util.htmlToPlainTextIfHtml(item.content), + }) + end, + }, }) self:createNewDownloadDialog(self.getCurrentDownloadDir(), buttons) diff --git a/plugins/opds.koplugin/opdsparser.lua b/plugins/opds.koplugin/opdsparser.lua index 20ee727ed..a1c247a99 100644 --- a/plugins/opds.koplugin/opdsparser.lua +++ b/plugins/opds.koplugin/opdsparser.lua @@ -72,10 +72,6 @@ function OPDSParser:createFlatXTable(xlex, curr_element) end function OPDSParser:parse(text) - -- Murder Calibre's whole "content" block, because luxl doesn't really deal well with various XHTML quirks, - -- as the list of crappy replacements below attests to... - -- There's also a high probability of finding orphaned tags or badly nested ones in there, which will screw everything up. - text = text:gsub('.-', '') -- luxl doesn't handle XML comments, so strip them text = text:gsub("", "") -- luxl is also particular about the syntax for self-closing, empty & orphaned tags... @@ -84,8 +80,18 @@ function OPDSParser:parse(text) text = text:gsub("<([bh]r)>", "<%1 />") -- Some OPDS catalogs wrap text in a CDATA section, remove it as it causes parsing problems text = text:gsub("", function (s) - return s:gsub( "%p", {["&"] = "&", ["<"] = "<", [">"] = ">" } ) + return s:gsub("%p", {["&"] = "&", ["<"] = "<", [">"] = ">"}) end ) + + -- NOTE: OPDS content tags are likely to contain a bunch of HTML or XHTML. We do *NOT* want to let luxl parse that, + -- because it doesn't really deal well with various XHTML quirks, as the list of crappy replacements above attests to... + -- There's also a high probability of finding orphaned tags or badly nested ones in there, which would screw everything up. + -- In any case, we just want to treat the whole thing as a single text node anyway, so, just mangle the markup to force luxl's hand. + text = text:gsub('', "") + text = text:gsub("(.-)", function (s) + return '' .. s:gsub("%p", {["<"] = "<", [">"] = ">", ['"'] = """, ["'"] = "'"}) .. "" + end ) + local xlex = luxl.new(text, #text) return assert(self:createFlatXTable(xlex)) end