diff --git a/base b/base index 444a70965..a4dab90a4 160000 --- a/base +++ b/base @@ -1 +1 @@ -Subproject commit 444a70965acb8348e8e15bed1af41560e9786831 +Subproject commit a4dab90a4c6bd2b7fdb51736dc0d3a5fcfe94c13 diff --git a/frontend/ui/elements/filemanager_menu_order.lua b/frontend/ui/elements/filemanager_menu_order.lua index 58a6dafee..47d09d553 100644 --- a/frontend/ui/elements/filemanager_menu_order.lua +++ b/frontend/ui/elements/filemanager_menu_order.lua @@ -106,6 +106,7 @@ local order = { "send2ebook", "text_editor", "profiles", + "qrclipboard", "----------------------------", "more_tools", }, diff --git a/frontend/ui/elements/reader_menu_order.lua b/frontend/ui/elements/reader_menu_order.lua index f7ece2078..fc0c1cbba 100644 --- a/frontend/ui/elements/reader_menu_order.lua +++ b/frontend/ui/elements/reader_menu_order.lua @@ -130,6 +130,7 @@ local order = { "news_downloader", "send2ebook", "text_editor", + "qrclipboard", "profiles", "----------------------------", "more_tools", diff --git a/frontend/ui/widget/qrmessage.lua b/frontend/ui/widget/qrmessage.lua new file mode 100644 index 000000000..cb39d2d86 --- /dev/null +++ b/frontend/ui/widget/qrmessage.lua @@ -0,0 +1,114 @@ +--[[-- +Widget that displays a qr code. + +It vanishes on key press or after a given timeout. + +Example: + local UIManager = require("ui/uimanager") + local _ = require("gettext") + local Screen = require("device").screen + local sample + sample = QRMessage:new{ + text = _("my message"), + height = Screen:scaleBySize(400), + width = Screen:scaleBySize(400), + timeout = 5, -- This widget will vanish in 5 seconds. + } + UIManager:show(sample) +]] + +local Blitbuffer = require("ffi/blitbuffer") +local CenterContainer = require("ui/widget/container/centercontainer") +local Device = require("device") +local FrameContainer = require("ui/widget/container/framecontainer") +local Geom = require("ui/geometry") +local GestureRange = require("ui/gesturerange") +local QRWidget = require("ui/widget/qrwidget") +local InputContainer = require("ui/widget/container/inputcontainer") +local UIManager = require("ui/uimanager") +local Input = Device.input +local Screen = Device.screen +local Size = require("ui/size") + +local QRMessage = InputContainer:new{ + modal = true, + timeout = nil, -- in seconds + text = nil, -- The text to encode. + width = nil, -- The width. Keep it nil to use original width. + height = nil, -- The height. Keep it nil to use original height. + dismiss_callback = function() end, + alpha = nil, + scale_factor = 1, +} + +function QRMessage:init() + if Device:hasKeys() then + self.key_events = { + AnyKeyPressed = { { Input.group.Any }, + seqtext = "any key", doc = "close dialog" } + } + end + if Device:isTouchDevice() then + self.ges_events.TapClose = { + GestureRange:new{ + ges = "tap", + range = Geom:new{ + x = 0, y = 0, + w = Screen:getWidth(), + h = Screen:getHeight(), + } + } + } + end + + local padding = Size.padding.fullscreen + + local image_widget = QRWidget:new{ + text = self.text, + width = self.width and (self.width - 2 * padding), + height = self.height and (self.height - 2 * padding), + alpha = self.alpha, + scale_factor = self.scale_factor, + } + + local frame = FrameContainer:new{ + background = Blitbuffer.COLOR_WHITE, + padding = padding, + image_widget, + } + self[1] = CenterContainer:new{ + dimen = Screen:getSize(), + frame, + } +end + +function QRMessage:onCloseWidget() + UIManager:setDirty(nil, function() + return "ui", self[1][1].dimen + end) + return true +end + +function QRMessage:onShow() + -- triggered by the UIManager after we got successfully shown (not yet painted) + UIManager:setDirty(self, function() + return "ui", self[1][1].dimen + end) + if self.timeout then + UIManager:scheduleIn(self.timeout, function() UIManager:close(self) end) + end + return true +end + +function QRMessage:onAnyKeyPressed() + -- triggered by our defined key events + self.dismiss_callback() + UIManager:close(self) +end + +function QRMessage:onTapClose() + self.dismiss_callback() + UIManager:close(self) +end + +return QRMessage diff --git a/frontend/ui/widget/qrwidget.lua b/frontend/ui/widget/qrwidget.lua new file mode 100644 index 000000000..81c218976 --- /dev/null +++ b/frontend/ui/widget/qrwidget.lua @@ -0,0 +1,54 @@ +--[[ +QRWidget shows a QR code for a given text. +]] + +local Blitbuffer = require("ffi/blitbuffer") +local ImageWidget = require("ui/widget/imagewidget") +local logger = require("logger") +local qrencode = require("ffi/qrencode") +local _ = require("gettext") + +local QRWidget = ImageWidget:extend{ + scale_factor = nil, + text = "" + -- see ImageWidget for other options. +} + +function QRWidget:init() + local text = self.text + if #text > 2953 then + local truncated = _("... (truncated...)") + text = text:sub(1, 2953 - #truncated) .. truncated + end + local ok, grid = qrencode.qrcode(text) + if not ok then + logger.info("QRWidget: failed to generate QR code.") + return + else + local sq_size + if self.width then + if self.height then + sq_size = math.min(self.width, self.height)/#grid + else + sq_size = self.width/#grid + end + elseif self.height then + sq_size = self.height/#grid + else sq_size = 1 + end + sq_size = math.floor(sq_size) + local grid_size = sq_size * #grid + local bb = Blitbuffer.new(grid_size, grid_size) + local white = Blitbuffer.COLOR_WHITE + for x, col in ipairs(grid) do + for y, lgn in ipairs(col) do + if lgn < 0 then + bb:paintRect((x - 1) * sq_size, (y - 1) * sq_size, sq_size, sq_size, white) + end + end + end + self.image = bb + end +end + +return QRWidget diff --git a/plugins/qrclipboard.koplugin/_meta.lua b/plugins/qrclipboard.koplugin/_meta.lua new file mode 100644 index 000000000..33c33203a --- /dev/null +++ b/plugins/qrclipboard.koplugin/_meta.lua @@ -0,0 +1,6 @@ +local _ = require("gettext") +return { + name = "qrclipboard", + fullname = _("QR from clipboard"), + description = _([[This plugin generates a QR code from clipboard content.]]), +} diff --git a/plugins/qrclipboard.koplugin/main.lua b/plugins/qrclipboard.koplugin/main.lua new file mode 100644 index 000000000..6c3f94d5b --- /dev/null +++ b/plugins/qrclipboard.koplugin/main.lua @@ -0,0 +1,33 @@ +--[[-- +This plugin generates a QR code from clipboard content. +--]]-- + +local Device = require("device") +local QRMessage = require("ui/widget/qrmessage") +local UIManager = require("ui/uimanager") +local WidgetContainer = require("ui/widget/container/widgetcontainer") +local _ = require("gettext") + +local QRClipboard = WidgetContainer:new{ + name = "qrclipboard", + is_doc_only = false, +} + +function QRClipboard:init() + self.ui.menu:registerToMainMenu(self) +end + +function QRClipboard:addToMainMenu(menu_items) + menu_items.qrclipboard = { + text = _("QR from clipboard"), + callback = function() + UIManager:show(QRMessage:new{ + text = Device.input.getClipboardText(), + width = Device.screen:getWidth(), + height = Device.screen:getHeight() + }) + end, + } +end + +return QRClipboard diff --git a/plugins/texteditor.koplugin/main.lua b/plugins/texteditor.koplugin/main.lua index 71316b4c7..8fb5befa4 100644 --- a/plugins/texteditor.koplugin/main.lua +++ b/plugins/texteditor.koplugin/main.lua @@ -3,6 +3,7 @@ local ConfirmBox = require("ui/widget/confirmbox") local DataStorage = require("datastorage") local Dispatcher = require("dispatcher") local Font = require("ui/font") +local QRMessage = require("ui/widget/qrmessage") local InfoMessage = require("ui/widget/infomessage") local InputDialog = require("ui/widget/inputdialog") local LuaSettings = require("luasettings") @@ -63,6 +64,7 @@ function TextEditor:loadSettings() end self.auto_para_direction = self.settings:readSetting("auto_para_direction") or true self.force_ltr_para_direction = self.settings:readSetting("force_ltr_para_direction") or false + self.qr_code_export = self.settings:readSetting("qr_code_export") or true end function TextEditor:onFlushSettings() @@ -74,6 +76,7 @@ function TextEditor:onFlushSettings() self.settings:saveSetting("font_size", self.font_size) self.settings:saveSetting("auto_para_direction", self.auto_para_direction) self.settings:saveSetting("force_ltr_para_direction", self.force_ltr_para_direction) + self.settings:saveSetting("qr_code_export", self.qr_code_export) self.settings:flush() end end @@ -152,6 +155,17 @@ Enable this if you are mostly editing code, HTML, CSS…]]), self.force_ltr_para_direction = not self.force_ltr_para_direction end, }, + { + text = _("Enable QR code export"), + help_text = _([[ +Export text to QR code, that can be scanned, for example, by a phone.]]), + checked_func = function() + return self.qr_code_export + end, + callback = function() + self.qr_code_export = not self.qr_code_export + end, + }, }, separator = true, }, @@ -447,6 +461,37 @@ function TextEditor:editFile(file_path, readonly) if self.force_ltr_para_direction then para_direction_rtl = false -- force LTR end + local buttons_first_row = {} -- First button on first row, that will be filled with Reset|Save|Close + if is_lua then + table.insert(buttons_first_row, { + text = _("Check Lua"), + callback = function() + local parse_error = util.checkLuaSyntax(input:getInputText()) + if parse_error then + UIManager:show(InfoMessage:new{ + text = T(_("Lua syntax check failed:\n\n%1"), parse_error) + }) + else + UIManager:show(Notification:new{ + text = T(_("Lua syntax OK")), + timeout = 2, + }) + end + end, + }) + end + if self.qr_code_export then + table.insert(buttons_first_row, { + text = _("QR"), + callback = function() + UIManager:show(QRMessage:new{ + text = input:getInputText(), + height = Screen:getHeight(), + width = Screen:getWidth() + }) + end, + }) + end input = InputDialog:new{ title = filename, input = self:readFileContent(file_path), @@ -460,25 +505,7 @@ function TextEditor:editFile(file_path, readonly) readonly = readonly, add_nav_bar = true, scroll_by_pan = true, - buttons = is_lua and {{ - -- First button on first row, that will be filled with Reset|Save|Close - { - text = _("Check Lua"), - callback = function() - local parse_error = util.checkLuaSyntax(input:getInputText()) - if parse_error then - UIManager:show(InfoMessage:new{ - text = T(_("Lua syntax check failed:\n\n%1"), parse_error) - }) - else - UIManager:show(Notification:new{ - text = T(_("Lua syntax OK")), - timeout = 2, - }) - end - end, - }, - }}, + buttons = {buttons_first_row}, -- Set/save view and cursor position callback view_pos_callback = function(top_line_num, charpos) -- This same callback is called with no argument to get initial position,