Upload most recent update of standard plugin prior to any personal tweaks
This commit is contained in:
21
LICENSE.txt
Normal file
21
LICENSE.txt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 Lena2309
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
63
README.md
Normal file
63
README.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# pinpad_screenlock_plugin
|
||||||
|
|
||||||
|
[](https://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
A small plugin to enable locking the screen of KOReader with a PIN code.
|
||||||
|
|
||||||
|
This work was originally based on the work of yogi81 and their plugin `screenlock_koreader_plugin`.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
1. Put the latest release of `pinpadlockscreen.koplugin` into the `koreader/plugins` directory.
|
||||||
|
2. Activate and change your password through the menu in Settings -> Screen -> PIN Pad Lock.
|
||||||
|
The default code is "1234". You can also add a custom message to display with the pin pad (e.g. contact details) and change its position and text alignment. You can also jump lines using "\n" in the message.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
**Note:**
|
||||||
|
|
||||||
|
- There's no limit to the number of digits your code may contain, but good luck if you forget your code (you'll have to dig into your memory or KOReader to find it back).
|
||||||
|
- You can change the lock logo by replacing the image from the icons folder. The new icon must be SVG file and be named `lock.svg`.
|
||||||
|
|
||||||
|
## Features and Gestures
|
||||||
|
|
||||||
|
- `Manage PIN Code`:
|
||||||
|
- `Change PIN Code` will allow you to change your code after entering your current one.
|
||||||
|
- `Reset PIN Code` will reset the code at `1234`, thought for people with long codes.
|
||||||
|
|
||||||
|
- `PIN pad lock message` allows you to manage the custom message you can add to the PIN Pad. This is optional.
|
||||||
|
|
||||||
|
- `Cancel` button: a quick tap will delete a digit of the code you entered, a long hold will delete every digits.
|
||||||
|
|
||||||
|
- `Advanced Settings`
|
||||||
|
- You can choose the timeout time, the max number of tries before timeout, among other things.
|
||||||
|
|
||||||
|
- The pad will appear on the current screensaver you're using, except when first hooking into KOReader where it will appear on a black background.
|
||||||
|
|
||||||
|
- Check for updates directly from your device, without having to open GitHub. This feature needs the device to be connected to Internet.
|
||||||
|
|
||||||
|
## Future work
|
||||||
|
|
||||||
|
- Features : Currently have no idea, do not hesitate to bring up issues !
|
||||||
|
- Fix : Screen becomes full black and untouchable when suspending/powering off the device before unlocking the "hook Pin Pad"
|
||||||
|
|
||||||
|
**Note:** I do not know when I'll be implementing these features. Also, my work could probably be optimized so I'm open to any new ideas and remarks.
|
||||||
|
|
||||||
|
## Recent Features
|
||||||
|
|
||||||
|
- Customizable message on PIN pad lock.
|
||||||
|
- Menu Entry where everything is customizable without the need to restart KOReader or modify the code.
|
||||||
|
- Using dynamic persistence instead of hardcoded variables.
|
||||||
|
- Cancel button deletes one digits when entering PIN Code, hold it to delete everything.
|
||||||
|
- 3 tries limit before a 30 seconds timeout.
|
||||||
|
- PIN Pad appears on the screensaver background (without sleep message)
|
||||||
|
- When launching KOReader (on a jailbroken kindle), PIN Pad now appears right away, not leaving the possibility to deactivate or reset the lock.
|
||||||
|
- Easier installation process with the icon directly in the plugin.
|
||||||
|
- PIN Pad appearing on the current screensaver without having to rebuild everything.
|
||||||
|
- Can show digits when typing.
|
||||||
|
- Less flashy overall.
|
||||||
|
- Pin pad disappears when suspending device before unlocking the pad.
|
||||||
|
|
||||||
|
:)
|
||||||
8
pinpadlockscreen.koplugin/_meta.lua
Normal file
8
pinpadlockscreen.koplugin/_meta.lua
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
local _ = require("gettext")
|
||||||
|
|
||||||
|
return {
|
||||||
|
name = "pinpadlock",
|
||||||
|
fullname = _("PIN Pad Lock Screen"),
|
||||||
|
description = _([[Lock the device with a PIN code]]),
|
||||||
|
version = "v1.1.0"
|
||||||
|
}
|
||||||
165
pinpadlockscreen.koplugin/main.lua
Normal file
165
pinpadlockscreen.koplugin/main.lua
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
--[[
|
||||||
|
Author: Lena2309 (better lock management, boot hooking, event listening, ...), yogi81 (original inspiration and main skeleton)
|
||||||
|
Inspiration and original skeleton from `https://github.com/yogi81/screenlock_koreader_plugin/tree/main`
|
||||||
|
Description: implements a screen lock mechanism for KOReader
|
||||||
|
using a PIN pad interface. Also adds a menu entry in Settings -> Screen
|
||||||
|
]]
|
||||||
|
|
||||||
|
local Dispatcher = require("dispatcher")
|
||||||
|
local PinPadDialog = require("ui/pinpaddialog")
|
||||||
|
local EventListener = require("ui/widget/eventlistener")
|
||||||
|
local _ = require("gettext")
|
||||||
|
local UIManager = require("ui/uimanager")
|
||||||
|
local MenuEntryItems = require("menu/menuentryitems")
|
||||||
|
local logger = require("logger")
|
||||||
|
|
||||||
|
-- Default settings
|
||||||
|
if G_reader_settings:hasNot("pinpadlock_pin_code") then
|
||||||
|
G_reader_settings:saveSetting("pinpadlock_pin_code", "1234")
|
||||||
|
end
|
||||||
|
if G_reader_settings:hasNot("pinpadlock_activated") then
|
||||||
|
G_reader_settings:makeFalse("pinpadlock_activated")
|
||||||
|
end
|
||||||
|
if G_reader_settings:hasNot("pinpadlock_correct_pin_message_activated") then
|
||||||
|
G_reader_settings:makeTrue("pinpadlock_correct_pin_message_activated")
|
||||||
|
end
|
||||||
|
if G_reader_settings:hasNot("pinpadlock_timeout_time") then
|
||||||
|
G_reader_settings:saveSetting("pinpadlock_timeout_time", "30")
|
||||||
|
end
|
||||||
|
if G_reader_settings:hasNot("pinpadlock_max_tries") then
|
||||||
|
G_reader_settings:saveSetting("pinpadlock_max_tries", "3")
|
||||||
|
end
|
||||||
|
if G_reader_settings:hasNot("pinpadlock_show_message") then
|
||||||
|
G_reader_settings:makeFalse("pinpadlock_show_message")
|
||||||
|
end
|
||||||
|
if G_reader_settings:hasNot("pinpadlock_message") then
|
||||||
|
G_reader_settings:saveSetting("pinpadlock_message", "Locked")
|
||||||
|
end
|
||||||
|
if G_reader_settings:hasNot("pinpadlock_message_position") then
|
||||||
|
G_reader_settings:saveSetting("pinpadlock_message_position", "top")
|
||||||
|
end
|
||||||
|
if G_reader_settings:hasNot("pinpadlock_message_alignment") then
|
||||||
|
G_reader_settings:saveSetting("pinpadlock_message_alignment", "center")
|
||||||
|
end
|
||||||
|
if G_reader_settings:hasNot("suspended_device") then
|
||||||
|
G_reader_settings:makeTrue("suspended_device")
|
||||||
|
end
|
||||||
|
|
||||||
|
local ScreenLock = EventListener:extend {
|
||||||
|
pinPadDialog = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
function ScreenLock:erasePinPadDialog()
|
||||||
|
if self.pinPadDialog then
|
||||||
|
self.pinPadDialog:close(function()
|
||||||
|
self.pinPadDialog = nil
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
--- DEVICE LISTENER OVERRIDE
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
local ref_self = nil
|
||||||
|
local _original_PowerOff = UIManager.poweroff_action
|
||||||
|
UIManager.poweroff_action = function()
|
||||||
|
logger.warn("in suspend ref_self: " .. tostring(ref_self))
|
||||||
|
if ref_self then
|
||||||
|
logger.warn("before erase dialog: " .. tostring(ref_self))
|
||||||
|
ref_self:erasePinPadDialog()
|
||||||
|
logger.warn("after erase dialog: " .. tostring(ref_self))
|
||||||
|
end
|
||||||
|
UIManager:nextTick(function()
|
||||||
|
_original_PowerOff()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
--- REGISTER DISPATCHER ACTIONS
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
function ScreenLock:onDispatcherRegisterActions()
|
||||||
|
Dispatcher:registerAction("screenlock_pin_pad_lock_screen", {
|
||||||
|
category = "none",
|
||||||
|
event = "LockScreenPinPad",
|
||||||
|
title = _("Lock Screen (PinPad)"),
|
||||||
|
filemanager = true,
|
||||||
|
device = true,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
--- EVENT LISTENING
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
---KOReader exit and restart
|
||||||
|
function ScreenLock:onExit()
|
||||||
|
G_reader_settings:makeTrue("suspended_device")
|
||||||
|
end
|
||||||
|
|
||||||
|
function ScreenLock:onRestart()
|
||||||
|
G_reader_settings:makeTrue("suspended_device")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Device suspension, reboot or power off
|
||||||
|
function ScreenLock:onRequestSuspend()
|
||||||
|
G_reader_settings:makeTrue("suspended_device")
|
||||||
|
end
|
||||||
|
|
||||||
|
function ScreenLock:onRequestReboot()
|
||||||
|
G_reader_settings:makeTrue("suspended_device")
|
||||||
|
end
|
||||||
|
|
||||||
|
function ScreenLock:onRequestPowerOff()
|
||||||
|
G_reader_settings:makeTrue("suspended_device")
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
--- INIT & WAKE-UP HANDLING
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
function ScreenLock:init()
|
||||||
|
self:onDispatcherRegisterActions()
|
||||||
|
self.ui.menu:registerToMainMenu(self)
|
||||||
|
|
||||||
|
ref_self = self
|
||||||
|
if G_reader_settings:isTrue("pinpadlock_activated") and G_reader_settings:isTrue("suspended_device") then
|
||||||
|
ref_self:lockScreen()
|
||||||
|
end
|
||||||
|
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function ScreenLock:onResume()
|
||||||
|
if G_reader_settings:isTrue("pinpadlock_activated") then
|
||||||
|
self:lockScreen()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
--- DISPATCHER HANDLER
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
function ScreenLock:onLockScreen()
|
||||||
|
self:lockScreen()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
--- LOCK SCREEN
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
function ScreenLock:lockScreen()
|
||||||
|
ref_self = self
|
||||||
|
UIManager:nextTick(function()
|
||||||
|
if self.pinPadDialog then self.pinPadDialog:closeDialogs() end
|
||||||
|
|
||||||
|
self.pinPadDialog = PinPadDialog:init()
|
||||||
|
self.pinPadDialog:showPinPad()
|
||||||
|
end)
|
||||||
|
ref_self = self
|
||||||
|
end
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
--- MAIN MENU ENTRY
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
function ScreenLock:addToMainMenu(menu_items)
|
||||||
|
menu_items.pinpad = MenuEntryItems
|
||||||
|
end
|
||||||
|
|
||||||
|
return ScreenLock
|
||||||
135
pinpadlockscreen.koplugin/menu/menuentryitems.lua
Normal file
135
pinpadlockscreen.koplugin/menu/menuentryitems.lua
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
--[[
|
||||||
|
Author: Lena2309
|
||||||
|
Description: Displays items in the Screen Menu Entry to manage the plugin
|
||||||
|
]]
|
||||||
|
|
||||||
|
local PinPadMenuEntry = require("menu/pinpadmenuentry")
|
||||||
|
local _ = require("gettext")
|
||||||
|
|
||||||
|
return {
|
||||||
|
text = _("PIN Pad Lock"),
|
||||||
|
sorting_hint = "screen",
|
||||||
|
sub_item_table = {
|
||||||
|
{
|
||||||
|
text = _("Activated"),
|
||||||
|
checked_func = function()
|
||||||
|
return PinPadMenuEntry:pinPadEnabled()
|
||||||
|
end,
|
||||||
|
callback = function()
|
||||||
|
G_reader_settings:toggle("pinpadlock_activated")
|
||||||
|
end,
|
||||||
|
separator = true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text = _("Manage PIN Code"),
|
||||||
|
keep_menu_open = true,
|
||||||
|
sub_item_table = {
|
||||||
|
{
|
||||||
|
text = _("Change PIN Code"),
|
||||||
|
callback = function()
|
||||||
|
PinPadMenuEntry:changePinCode()
|
||||||
|
end
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text = _("Reset PIN Code"),
|
||||||
|
callback = function()
|
||||||
|
PinPadMenuEntry:resetPinCode()
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text = _("PIN pad lock message"),
|
||||||
|
separator = true,
|
||||||
|
sub_item_table = {
|
||||||
|
{
|
||||||
|
text = _("Add custom message to lock"),
|
||||||
|
checked_func = function()
|
||||||
|
return PinPadMenuEntry:showMessageEnabled()
|
||||||
|
end,
|
||||||
|
callback = function()
|
||||||
|
G_reader_settings:toggle("pinpadlock_show_message")
|
||||||
|
end,
|
||||||
|
separator = true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text = _("Edit PIN pad lock message"),
|
||||||
|
enabled_func = function()
|
||||||
|
return PinPadMenuEntry:showMessageEnabled()
|
||||||
|
end,
|
||||||
|
keep_menu_open = true,
|
||||||
|
callback = function()
|
||||||
|
PinPadMenuEntry:setMessage()
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text = _("Message position"),
|
||||||
|
enabled_func = function()
|
||||||
|
return PinPadMenuEntry:showMessageEnabled()
|
||||||
|
end,
|
||||||
|
sub_item_table = {
|
||||||
|
PinPadMenuEntry:genRadioMenuItem(_("Top"), "pinpadlock_message_position", "top"),
|
||||||
|
PinPadMenuEntry:genRadioMenuItem(_("Middle"), "pinpadlock_message_position", "middle"),
|
||||||
|
PinPadMenuEntry:genRadioMenuItem(_("Bottom"), "pinpadlock_message_position", "bottom"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text = _("Message alignment"),
|
||||||
|
enabled_func = function()
|
||||||
|
return PinPadMenuEntry:showMessageEnabled()
|
||||||
|
end,
|
||||||
|
sub_item_table = {
|
||||||
|
PinPadMenuEntry:genRadioMenuItem(_("Left"), "pinpadlock_message_alignment", "left"),
|
||||||
|
PinPadMenuEntry:genRadioMenuItem(_("Center"), "pinpadlock_message_alignment", "center"),
|
||||||
|
PinPadMenuEntry:genRadioMenuItem(_("Right"), "pinpadlock_message_alignment", "right"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text = _("Advanced Settings"),
|
||||||
|
sub_item_table = {
|
||||||
|
{
|
||||||
|
text = _("Activate correct PIN pop-up"),
|
||||||
|
checked_func = function()
|
||||||
|
return PinPadMenuEntry:correctPinMessageEnabled()
|
||||||
|
end,
|
||||||
|
callback = function()
|
||||||
|
G_reader_settings:toggle("pinpadlock_correct_pin_message_activated")
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text = _("Display entered digit before hiding it"),
|
||||||
|
checked_func = function()
|
||||||
|
return PinPadMenuEntry:displayDigitEnabled()
|
||||||
|
end,
|
||||||
|
callback = function()
|
||||||
|
G_reader_settings:toggle("pinpadlock_display_digit_activated")
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text = _("Set Timeout time"),
|
||||||
|
sub_item_table = {
|
||||||
|
PinPadMenuEntry:genRadioMenuItem(_("10 seconds"), "pinpadlock_timeout_time", "10"),
|
||||||
|
PinPadMenuEntry:genRadioMenuItem(_("30 seconds"), "pinpadlock_timeout_time", "30"),
|
||||||
|
PinPadMenuEntry:genRadioMenuItem(_("60 seconds"), "pinpadlock_timeout_time", "60"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text = _("Set max tries before timeout"),
|
||||||
|
sub_item_table = {
|
||||||
|
PinPadMenuEntry:genRadioMenuItem(_("1"), "pinpadlock_max_tries", "1"),
|
||||||
|
PinPadMenuEntry:genRadioMenuItem(_("3"), "pinpadlock_max_tries", "3"),
|
||||||
|
PinPadMenuEntry:genRadioMenuItem(_("6"), "pinpadlock_max_tries", "6"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text = _("Check for updates"),
|
||||||
|
callback = function()
|
||||||
|
PinPadMenuEntry:checkForUpdates()
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
187
pinpadlockscreen.koplugin/menu/pinpadmenuentry.lua
Normal file
187
pinpadlockscreen.koplugin/menu/pinpadmenuentry.lua
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
--[[
|
||||||
|
Author: Lena2309
|
||||||
|
Description: Execute actions when tapping on a menu entry item
|
||||||
|
]]
|
||||||
|
|
||||||
|
local ConfirmBox = require("ui/widget/confirmbox")
|
||||||
|
local InfoMessage = require("ui/widget/infomessage")
|
||||||
|
local InputDialog = require("ui/widget/inputdialog")
|
||||||
|
local PinPadDialog = require("ui/pinpaddialog")
|
||||||
|
local UIManager = require("ui/uimanager")
|
||||||
|
local _ = require("gettext")
|
||||||
|
local http = require("socket.http")
|
||||||
|
local ltn12 = require("ltn12")
|
||||||
|
local json = require("dkjson")
|
||||||
|
|
||||||
|
local PinPadMenuEntry = {}
|
||||||
|
|
||||||
|
function PinPadMenuEntry:setMessage()
|
||||||
|
local lock_message = G_reader_settings:readSetting("pinpadlock_message")
|
||||||
|
local input_dialog
|
||||||
|
input_dialog = InputDialog:new {
|
||||||
|
title = _("PIN pad lock message"),
|
||||||
|
description = _("Enter a custom message to be displayed on the PIN pad lock."),
|
||||||
|
input = lock_message,
|
||||||
|
buttons = {
|
||||||
|
{
|
||||||
|
{
|
||||||
|
text = _("Cancel"),
|
||||||
|
id = "close",
|
||||||
|
callback = function()
|
||||||
|
UIManager:close(input_dialog)
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text = _("Set message"),
|
||||||
|
is_enter_default = true,
|
||||||
|
callback = function()
|
||||||
|
G_reader_settings:saveSetting("pinpadlock_message", input_dialog:getInputText())
|
||||||
|
UIManager:close(input_dialog)
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
UIManager:show(input_dialog)
|
||||||
|
input_dialog:onShowKeyboard()
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadMenuEntry:showMessageEnabled()
|
||||||
|
return G_reader_settings:isTrue("pinpadlock_show_message")
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadMenuEntry:pinPadEnabled()
|
||||||
|
return G_reader_settings:isTrue("pinpadlock_activated")
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadMenuEntry:correctPinMessageEnabled()
|
||||||
|
return G_reader_settings:isTrue("pinpadlock_correct_pin_message_activated")
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadMenuEntry:displayDigitEnabled()
|
||||||
|
return G_reader_settings:isTrue("pinpadlock_display_digit_activated")
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadMenuEntry:genRadioMenuItem(text, setting, value)
|
||||||
|
return {
|
||||||
|
text = text,
|
||||||
|
checked_func = function()
|
||||||
|
return G_reader_settings:readSetting(setting) == value
|
||||||
|
end,
|
||||||
|
callback = function()
|
||||||
|
G_reader_settings:saveSetting(setting, value)
|
||||||
|
end,
|
||||||
|
radio = true,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadMenuEntry:changePinCode()
|
||||||
|
local confirmCurrentCode = PinPadDialog:new { stage = "confirm_current_code" }
|
||||||
|
confirmCurrentCode:showPinPad()
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadMenuEntry:resetPinCode()
|
||||||
|
local confirmBox
|
||||||
|
confirmBox = ConfirmBox:new {
|
||||||
|
text = _("Do you really want to reset the PIN code to \"1234\" ?"),
|
||||||
|
ok_text = _("Yes"),
|
||||||
|
ok_callback = function()
|
||||||
|
G_reader_settings:saveSetting("pinpadlock_pin_code", "1234")
|
||||||
|
UIManager:close(confirmBox)
|
||||||
|
UIManager:show(InfoMessage:new { text = _("PIN Code resetted successfully."), timeout = 1 })
|
||||||
|
end,
|
||||||
|
cancel_callback = function()
|
||||||
|
UIManager:close(confirmBox)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
UIManager:show(confirmBox)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Parse a version string like "v1.2.3"
|
||||||
|
local function parseVersion(version)
|
||||||
|
local major, minor, patch = version:match("^v(%d+)%.(%d+)%.(%d+)$")
|
||||||
|
return {
|
||||||
|
major = tonumber(major) or 0,
|
||||||
|
minor = tonumber(minor) or 0,
|
||||||
|
patch = tonumber(patch) or 0
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Returns -1 if a < b, 0 if equal, 1 if a > b
|
||||||
|
local function compareVersions(local_version, remote_version)
|
||||||
|
if local_version.major ~= remote_version.major then
|
||||||
|
if local_version.major > remote_version.major then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return -1
|
||||||
|
end
|
||||||
|
elseif local_version.minor ~= remote_version.minor then
|
||||||
|
if local_version.minor > remote_version.minor then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return -1
|
||||||
|
end
|
||||||
|
elseif local_version.patch ~= remote_version.patch then
|
||||||
|
if local_version.patch > remote_version.patch then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return -1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadMenuEntry:checkForUpdates()
|
||||||
|
local meta = dofile("plugins/pinpadlockscreen.koplugin/_meta.lua")
|
||||||
|
local local_version = meta.version or "unknown"
|
||||||
|
|
||||||
|
local response_body = {}
|
||||||
|
local ok, status = http.request {
|
||||||
|
url = "https://api.github.com/repos/Lena2309/pinpad_screenlock_plugin/releases/latest",
|
||||||
|
sink = ltn12.sink.table(response_body),
|
||||||
|
redirect = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if not ok or status ~= 200 then
|
||||||
|
UIManager:show(InfoMessage:new {
|
||||||
|
text = _("Unable to check for updates. Make sure your device is connected to the Internet."),
|
||||||
|
timeout = 3,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local body = table.concat(response_body)
|
||||||
|
local data, pos, err = json.decode(body, 1, nil)
|
||||||
|
|
||||||
|
if not data or not data.tag_name then
|
||||||
|
UIManager:show(InfoMessage:new {
|
||||||
|
text = _("Error parsing GitHub release info."),
|
||||||
|
timeout = 3,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local remote_version = data.tag_name
|
||||||
|
local cmp = compareVersions(parseVersion(local_version), parseVersion(remote_version))
|
||||||
|
if cmp < 0 then
|
||||||
|
UIManager:show(InfoMessage:new {
|
||||||
|
text = _("New version available: ") .. remote_version ..
|
||||||
|
_("\nYou are running: ") .. local_version,
|
||||||
|
timeout = 5,
|
||||||
|
})
|
||||||
|
else
|
||||||
|
if cmp > 0 then
|
||||||
|
UIManager:show(InfoMessage:new {
|
||||||
|
text = _("You’re ahead of the official release.\nLatest official version: " .. remote_version),
|
||||||
|
timeout = 5,
|
||||||
|
})
|
||||||
|
else
|
||||||
|
UIManager:show(InfoMessage:new {
|
||||||
|
text = _("You are up to date!"),
|
||||||
|
timeout = 3,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return PinPadMenuEntry
|
||||||
18
pinpadlockscreen.koplugin/ui/icons/lock.svg
Normal file
18
pinpadlockscreen.koplugin/ui/icons/lock.svg
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 512 512">
|
||||||
|
<g transform="translate(0, 512) scale(0.1, -0.1)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M2390 5110 c-157 -22 -329 -75 -461 -140 -95 -48 -234 -147 -319
|
||||||
|
-227 -203 -191 -334 -415 -407 -697 -27 -101 -27 -102 -30 -573 l-4 -473 -123
|
||||||
|
0 c-201 0 -285 -41 -348 -167 l-33 -68 0 -1260 c0 -1052 2 -1267 14 -1300 32
|
||||||
|
-93 104 -163 197 -191 73 -22 3296 -21 3371 1 78 23 136 74 175 152 l33 68 0
|
||||||
|
1265 0 1265 -33 68 c-63 127 -147 167 -349 167 l-123 0 0 428 c0 461 -5 523
|
||||||
|
-55 697 -86 295 -296 581 -557 756 -162 107 -310 170 -496 209 -111 24 -350
|
||||||
|
34 -452 20z m405 -519 c317 -91 554 -334 637 -653 20 -77 21 -113 25 -510 l5
|
||||||
|
-428 -902 0 -902 0 5 428 c4 397 5 433 25 510 87 335 351 591 687 666 99 22
|
||||||
|
324 15 420 -13z m-114 -2497 c151 -48 252 -192 253 -361 0 -74 -4 -88 -37
|
||||||
|
-157 -25 -50 -53 -89 -86 -118 l-49 -43 54 -250 c29 -137 53 -258 54 -267 0
|
||||||
|
-17 -21 -18 -310 -18 -289 0 -310 1 -309 18 0 9 24 130 53 267 l53 250 -48 43
|
||||||
|
c-94 83 -143 229 -119 349 47 228 269 357 491 287z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
235
pinpadlockscreen.koplugin/ui/pinpadbuttondialog.lua
Normal file
235
pinpadlockscreen.koplugin/ui/pinpadbuttondialog.lua
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
--[[
|
||||||
|
Author: Lena2309
|
||||||
|
Description: customizes KOReader's existing ButtonDialog class solely
|
||||||
|
for aesthetic purposes (icon widget, vertical layout...),
|
||||||
|
with the primary modification in the `init` function.
|
||||||
|
]]
|
||||||
|
|
||||||
|
local Blitbuffer = require("ffi/blitbuffer")
|
||||||
|
local ButtonDialog = require("ui/widget/buttondialog")
|
||||||
|
local ButtonTable = require("ui/widget/buttontable")
|
||||||
|
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 ImageWidget = require("ui/widget/imagewidget")
|
||||||
|
local LineWidget = require("ui/widget/linewidget")
|
||||||
|
local MovableContainer = require("ui/widget/container/movablecontainer")
|
||||||
|
local ScrollTextWidget = require("ui/widget/scrolltextwidget")
|
||||||
|
local Size = require("ui/size")
|
||||||
|
local TextBoxWidget = require("ui/widget/textboxwidget")
|
||||||
|
local UIManager = require("ui/uimanager")
|
||||||
|
local VerticalGroup = require("ui/widget/verticalgroup")
|
||||||
|
local VerticalSpan = require("ui/widget/verticalspan")
|
||||||
|
local Screen = Device.screen
|
||||||
|
local util = require("util")
|
||||||
|
|
||||||
|
local DGENERIC_ICON_SIZE = G_defaults:readSetting("DGENERIC_ICON_SIZE")
|
||||||
|
|
||||||
|
local PinpadButtonDialog = ButtonDialog:extend {
|
||||||
|
override_show_message = false, -- will prevent showing custom lock message even if enabled (specific for changing PIN Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
function PinpadButtonDialog:init()
|
||||||
|
if not self.width_factor then
|
||||||
|
self.width_factor = 2 / 3
|
||||||
|
end
|
||||||
|
self.width = math.floor(math.min(Screen:getWidth(), Screen:getHeight()) * self.width_factor)
|
||||||
|
|
||||||
|
if self.dismissable then
|
||||||
|
if Device:hasKeys() then
|
||||||
|
local back_group = util.tableDeepCopy(Device.input.group.Back)
|
||||||
|
if Device:hasFewKeys() then
|
||||||
|
table.insert(back_group, "Left")
|
||||||
|
self.key_events.Close = { { back_group } }
|
||||||
|
else
|
||||||
|
table.insert(back_group, "Menu")
|
||||||
|
self.key_events.Close = { { back_group } }
|
||||||
|
end
|
||||||
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
local title_face
|
||||||
|
if self.use_info_style then
|
||||||
|
title_face = self.info_face
|
||||||
|
else
|
||||||
|
title_face = self.title_face
|
||||||
|
end
|
||||||
|
|
||||||
|
local currentFileSource = debug.getinfo(1, "S").source
|
||||||
|
local plugin_dir
|
||||||
|
if currentFileSource:find("^@") then
|
||||||
|
plugin_dir = currentFileSource:gsub("^@(.*)/[^/]*", "%1")
|
||||||
|
end
|
||||||
|
|
||||||
|
self.title_widget = TextBoxWidget:new {
|
||||||
|
text = self.title,
|
||||||
|
face = title_face,
|
||||||
|
width = self.width,
|
||||||
|
alignment = self.title_align,
|
||||||
|
}
|
||||||
|
|
||||||
|
local aesthetic_space = VerticalSpan:new { width = Size.margin.default + Size.padding.default }
|
||||||
|
local text_pin_content = VerticalGroup:new {
|
||||||
|
align = "center",
|
||||||
|
ImageWidget:new {
|
||||||
|
file = plugin_dir .. "/icons/lock.svg",
|
||||||
|
alpha = true,
|
||||||
|
width = Screen:scaleBySize(DGENERIC_ICON_SIZE) * 1.25,
|
||||||
|
height = Screen:scaleBySize(DGENERIC_ICON_SIZE) * 1.25,
|
||||||
|
scale_factor = 0,
|
||||||
|
original_in_nightmode = false,
|
||||||
|
},
|
||||||
|
aesthetic_space,
|
||||||
|
VerticalGroup:new {
|
||||||
|
align = "center",
|
||||||
|
self.title_widget
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
self.buttontable = ButtonTable:new {
|
||||||
|
buttons = self.buttons,
|
||||||
|
width = text_pin_content:getSize().w,
|
||||||
|
shrink_unneeded_width = self.shrink_unneeded_width,
|
||||||
|
shrink_min_width = self.shrink_min_width,
|
||||||
|
show_parent = self,
|
||||||
|
}
|
||||||
|
|
||||||
|
local separator = LineWidget:new {
|
||||||
|
background = Blitbuffer.COLOR_GRAY,
|
||||||
|
dimen = Geom:new {
|
||||||
|
w = text_pin_content:getSize().w,
|
||||||
|
h = Size.line.medium,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local content
|
||||||
|
if G_reader_settings:isTrue("pinpadlock_show_message") and not self.override_show_message then
|
||||||
|
local lock_message = G_reader_settings:readSetting("pinpadlock_message")
|
||||||
|
lock_message = lock_message:gsub("\\n", "\n") -- enabling jumping lines in the message
|
||||||
|
|
||||||
|
local lock_message_alignment = G_reader_settings:readSetting("pinpadlock_message_alignment")
|
||||||
|
local lock_message_position = G_reader_settings:readSetting("pinpadlock_message_position")
|
||||||
|
|
||||||
|
local lock_message_widget = TextBoxWidget:new {
|
||||||
|
text = lock_message,
|
||||||
|
face = title_face,
|
||||||
|
width = self.width,
|
||||||
|
alignment = lock_message_alignment,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- If the custom message ends up being too tall and makes the Pin Pad taller than the screen,
|
||||||
|
-- wrap it inside a ScrollableContainer
|
||||||
|
local max_height = self.buttontable:getSize().h + 3 * text_pin_content:getSize().h + Size.line.medium
|
||||||
|
local height = self.buttontable:getSize().h + text_pin_content:getSize().h + Size.line.medium +
|
||||||
|
lock_message_widget:getSize().h
|
||||||
|
if height > max_height then
|
||||||
|
local scroll_height = 3 * text_pin_content:getSize().h
|
||||||
|
|
||||||
|
lock_message_widget = ScrollTextWidget:new {
|
||||||
|
text = lock_message,
|
||||||
|
face = title_face,
|
||||||
|
width = self.width,
|
||||||
|
alignment = lock_message_alignment,
|
||||||
|
dialog = self,
|
||||||
|
height = scroll_height,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
if lock_message_position == "top" then
|
||||||
|
content = VerticalGroup:new {
|
||||||
|
align = "center",
|
||||||
|
aesthetic_space,
|
||||||
|
lock_message_widget,
|
||||||
|
aesthetic_space,
|
||||||
|
separator,
|
||||||
|
aesthetic_space,
|
||||||
|
text_pin_content,
|
||||||
|
aesthetic_space,
|
||||||
|
separator,
|
||||||
|
self.buttontable,
|
||||||
|
}
|
||||||
|
elseif lock_message_position == "middle" then
|
||||||
|
content = VerticalGroup:new {
|
||||||
|
align = "center",
|
||||||
|
aesthetic_space,
|
||||||
|
text_pin_content,
|
||||||
|
aesthetic_space,
|
||||||
|
separator,
|
||||||
|
aesthetic_space,
|
||||||
|
lock_message_widget,
|
||||||
|
aesthetic_space,
|
||||||
|
separator,
|
||||||
|
self.buttontable,
|
||||||
|
}
|
||||||
|
else
|
||||||
|
content = VerticalGroup:new {
|
||||||
|
align = "center",
|
||||||
|
aesthetic_space,
|
||||||
|
text_pin_content,
|
||||||
|
aesthetic_space,
|
||||||
|
separator,
|
||||||
|
self.buttontable,
|
||||||
|
separator,
|
||||||
|
aesthetic_space,
|
||||||
|
lock_message_widget,
|
||||||
|
aesthetic_space,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
else
|
||||||
|
content = VerticalGroup:new {
|
||||||
|
align = "center",
|
||||||
|
aesthetic_space,
|
||||||
|
text_pin_content,
|
||||||
|
aesthetic_space,
|
||||||
|
separator,
|
||||||
|
self.buttontable,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
self.movable = MovableContainer:new {
|
||||||
|
alpha = self.alpha,
|
||||||
|
anchor = self.anchor,
|
||||||
|
FrameContainer:new {
|
||||||
|
background = Blitbuffer.COLOR_WHITE,
|
||||||
|
bordersize = Size.border.window,
|
||||||
|
radius = Size.radius.window,
|
||||||
|
padding = Size.padding.default,
|
||||||
|
padding_top = 0,
|
||||||
|
padding_bottom = 0,
|
||||||
|
content,
|
||||||
|
},
|
||||||
|
unmovable = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.layout = self.buttontable.layout
|
||||||
|
self.buttontable.layout = nil
|
||||||
|
|
||||||
|
self[1] = CenterContainer:new {
|
||||||
|
dimen = Screen:getSize(),
|
||||||
|
self.movable,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinpadButtonDialog:updateTitle(text)
|
||||||
|
if self.title_widget then
|
||||||
|
self.title = text
|
||||||
|
self.title_widget:setText(text)
|
||||||
|
UIManager:setDirty(self, "ui")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return PinpadButtonDialog
|
||||||
484
pinpadlockscreen.koplugin/ui/pinpaddialog.lua
Normal file
484
pinpadlockscreen.koplugin/ui/pinpaddialog.lua
Normal file
@@ -0,0 +1,484 @@
|
|||||||
|
--[[
|
||||||
|
Author: Lena2309
|
||||||
|
Description: represents a PIN pad interface and its behavior within KOReader.
|
||||||
|
It handles user input, PIN validation, and UI interactions.
|
||||||
|
]]
|
||||||
|
|
||||||
|
local Blitbuffer = require("ffi/blitbuffer")
|
||||||
|
local BookStatusWidget = require("ui/widget/bookstatuswidget")
|
||||||
|
local Button = require("ui/widget/button")
|
||||||
|
local Device = require("device")
|
||||||
|
local FrameContainer = require("ui/widget/container/framecontainer")
|
||||||
|
local InfoMessage = require("ui/widget/infomessage")
|
||||||
|
local ImageWidget = require("ui/widget/imagewidget")
|
||||||
|
local PinPadButtonDialog = require("ui/pinpadbuttondialog")
|
||||||
|
local RenderImage = require("ui/renderimage")
|
||||||
|
local Screensaver = require("ui/screensaver")
|
||||||
|
local ScreenSaverWidget = require("ui/widget/screensaverwidget")
|
||||||
|
local UIManager = require("ui/uimanager")
|
||||||
|
local ffiUtil = require("ffi/util")
|
||||||
|
local util = require("util")
|
||||||
|
local _ = require("gettext")
|
||||||
|
local Screen = Device.screen
|
||||||
|
|
||||||
|
local ScreensaverUtil = require("util/screensaverutil")
|
||||||
|
|
||||||
|
local DGENERIC_ICON_SIZE = G_defaults:readSetting("DGENERIC_ICON_SIZE")
|
||||||
|
|
||||||
|
local LOCKED_TEXT = _("Enter your PIN")
|
||||||
|
local CONFIRM_CURRENT_CODE_TEXT = _("Enter the current PIN Code")
|
||||||
|
local NEW_CODE_TEXT = _("Enter the new PIN Code")
|
||||||
|
|
||||||
|
local MAX_TRIES_LIMIT = tonumber(G_reader_settings:readSetting("pinpadlock_max_tries"))
|
||||||
|
local TIMEOUT_TIME = tonumber(G_reader_settings:readSetting("pinpadlock_timeout_time"))
|
||||||
|
|
||||||
|
if G_reader_settings:hasNot("current_tries_number") then
|
||||||
|
G_reader_settings:saveSetting("current_tries_number", 0)
|
||||||
|
end
|
||||||
|
if G_reader_settings:hasNot("block_start_time") then
|
||||||
|
G_reader_settings:saveSetting("block_start_time", 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local PinPadDialog = FrameContainer:extend {
|
||||||
|
stage = "locked", -- "confirm_current_code" or "enter_new_code"
|
||||||
|
icon_size = Screen:scaleBySize(DGENERIC_ICON_SIZE) * 1.25,
|
||||||
|
}
|
||||||
|
|
||||||
|
function PinPadDialog:init()
|
||||||
|
self:setDialogText()
|
||||||
|
self.pin = ""
|
||||||
|
self.buttons = self:initializeButtons()
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadDialog:setDialogText()
|
||||||
|
if self.stage == "locked" then
|
||||||
|
self.dialog_text = LOCKED_TEXT
|
||||||
|
elseif self.stage == "confirm_current_code" then
|
||||||
|
self.dialog_text = CONFIRM_CURRENT_CODE_TEXT
|
||||||
|
else
|
||||||
|
self.dialog_text = NEW_CODE_TEXT
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadDialog:createButton(text, callback, hold_callback)
|
||||||
|
local button = Button:new {
|
||||||
|
text = text,
|
||||||
|
callback = callback,
|
||||||
|
hold_callback = hold_callback,
|
||||||
|
}
|
||||||
|
return button
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadDialog:initializeButtons()
|
||||||
|
local ref_self = self
|
||||||
|
local buttons = {
|
||||||
|
{
|
||||||
|
self:createButton("1", function() ref_self:onAppendToPin("1") end),
|
||||||
|
self:createButton("2", function() ref_self:onAppendToPin("2") end),
|
||||||
|
self:createButton("3", function() ref_self:onAppendToPin("3") end),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
self:createButton("4", function() ref_self:onAppendToPin("4") end),
|
||||||
|
self:createButton("5", function() ref_self:onAppendToPin("5") end),
|
||||||
|
self:createButton("6", function() ref_self:onAppendToPin("6") end),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
self:createButton("7", function() ref_self:onAppendToPin("7") end),
|
||||||
|
self:createButton("8", function() ref_self:onAppendToPin("8") end),
|
||||||
|
self:createButton("9", function() ref_self:onAppendToPin("9") end),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
self:createButton("Cancel", function() ref_self:onDelete() end, function() ref_self:onCancel() end),
|
||||||
|
self:createButton("0", function() ref_self:onAppendToPin("0") end),
|
||||||
|
self:createButton("OK", function() ref_self:onOk() end),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buttons
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadDialog:initializeScreensaverBackground()
|
||||||
|
if Screensaver.screensaver_type == "disable" and not Screensaver.show_message and not Screensaver.overlay_message then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local rotation_mode = Screen:getRotationMode()
|
||||||
|
|
||||||
|
if Screensaver:modeExpectsPortrait() then
|
||||||
|
Device.orig_rotation_mode = rotation_mode
|
||||||
|
if bit.band(Device.orig_rotation_mode, 1) == 1 then
|
||||||
|
Screen:setRotationMode(Screen.DEVICE_ROTATED_UPRIGHT)
|
||||||
|
else
|
||||||
|
Device.orig_rotation_mode = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if Device:hasEinkScreen() and Screensaver:modeIsImage() then
|
||||||
|
if Screensaver:withBackground() then
|
||||||
|
Screen:clear()
|
||||||
|
end
|
||||||
|
Screen:refreshFull(0, 0, Screen:getWidth(), Screen:getHeight())
|
||||||
|
|
||||||
|
if Device:isKobo() and Device:isSunxi() then
|
||||||
|
ffiUtil.usleep(150 * 1000)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Device.orig_rotation_mode = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local widget = nil
|
||||||
|
if Screensaver.screensaver_type == "cover" or Screensaver.screensaver_type == "random_image" then
|
||||||
|
local widget_settings = {
|
||||||
|
width = Screen:getWidth(),
|
||||||
|
height = Screen:getHeight(),
|
||||||
|
scale_factor = G_reader_settings:isFalse("screensaver_stretch_images") and 0 or nil,
|
||||||
|
stretch_limit_percentage = G_reader_settings:readSetting("screensaver_stretch_limit_percentage"),
|
||||||
|
}
|
||||||
|
if Screensaver.image then
|
||||||
|
widget_settings.image = Screensaver.image
|
||||||
|
widget_settings.image_disposable = true
|
||||||
|
elseif Screensaver.image_file then
|
||||||
|
if G_reader_settings:isTrue("screensaver_rotate_auto_for_best_fit") then
|
||||||
|
if util.getFileNameSuffix(Screensaver.image_file) == "svg" then
|
||||||
|
widget_settings.image = RenderImage:renderSVGImageFile(Screensaver.image_file, nil, nil, 1)
|
||||||
|
else
|
||||||
|
widget_settings.image = RenderImage:renderImageFile(Screensaver.image_file, false, nil, nil)
|
||||||
|
end
|
||||||
|
if not widget_settings.image then
|
||||||
|
widget_settings.image = RenderImage:renderCheckerboard(Screen:getWidth(), Screen:getHeight(),
|
||||||
|
Screen.bb:getType())
|
||||||
|
end
|
||||||
|
widget_settings.image_disposable = true
|
||||||
|
else
|
||||||
|
widget_settings.file = Screensaver.image_file
|
||||||
|
widget_settings.file_do_cache = false
|
||||||
|
end
|
||||||
|
widget_settings.alpha = true
|
||||||
|
end
|
||||||
|
if G_reader_settings:isTrue("screensaver_rotate_auto_for_best_fit") then
|
||||||
|
local angle = rotation_mode == 3 and 180 or 0
|
||||||
|
if (widget_settings.image:getWidth() < widget_settings.image:getHeight()) ~= (widget_settings.width < widget_settings.height) then
|
||||||
|
angle = angle + (G_reader_settings:isTrue("imageviewer_rotation_landscape_invert") and -90 or 90)
|
||||||
|
end
|
||||||
|
widget_settings.rotation_angle = angle
|
||||||
|
end
|
||||||
|
widget = ImageWidget:new(widget_settings)
|
||||||
|
elseif Screensaver.screensaver_type == "bookstatus" then
|
||||||
|
local ReaderUI = require("apps/reader/readerui")
|
||||||
|
widget = BookStatusWidget:new {
|
||||||
|
ui = ReaderUI.instance,
|
||||||
|
readonly = true,
|
||||||
|
}
|
||||||
|
elseif Screensaver.screensaver_type == "readingprogress" then
|
||||||
|
widget = Screensaver.getReaderProgress()
|
||||||
|
end
|
||||||
|
|
||||||
|
local covers_fullscreen = true
|
||||||
|
local background
|
||||||
|
if Screensaver.screensaver_background == "white" then
|
||||||
|
background = Blitbuffer.COLOR_WHITE
|
||||||
|
elseif Screensaver.screensaver_background == "none" then
|
||||||
|
background = nil
|
||||||
|
else
|
||||||
|
background = Blitbuffer.COLOR_BLACK
|
||||||
|
end
|
||||||
|
|
||||||
|
UIManager:setIgnoreTouchInput(false)
|
||||||
|
|
||||||
|
if widget then
|
||||||
|
self.screensaver_widget = ScreenSaverWidget:new {
|
||||||
|
widget = widget,
|
||||||
|
background = background,
|
||||||
|
covers_fullscreen = covers_fullscreen,
|
||||||
|
}
|
||||||
|
self.screensaver_widget.dithered = true
|
||||||
|
else
|
||||||
|
local currentFileSource = debug.getinfo(1, "S").source
|
||||||
|
local plugin_dir
|
||||||
|
if currentFileSource:find("^@") then
|
||||||
|
plugin_dir = currentFileSource:gsub("^@(.*)/[^/]*", "%1")
|
||||||
|
end
|
||||||
|
-- dummy widget
|
||||||
|
widget = ImageWidget:new {
|
||||||
|
file = plugin_dir .. "/icons/lock.svg",
|
||||||
|
alpha = true,
|
||||||
|
width = self.icon_size,
|
||||||
|
height = self.icon_size,
|
||||||
|
scale_factor = 0,
|
||||||
|
original_in_nightmode = false,
|
||||||
|
}
|
||||||
|
self.screensaver_widget = ScreenSaverWidget:new {
|
||||||
|
widget = widget,
|
||||||
|
background = Blitbuffer.COLOR_BLACK,
|
||||||
|
covers_fullscreen = covers_fullscreen,
|
||||||
|
}
|
||||||
|
self.screensaver_widget.dithered = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadDialog:isBlocked()
|
||||||
|
local block_start = G_reader_settings:readSetting("block_start_time") or 0
|
||||||
|
if block_start == 0 then
|
||||||
|
if self.blocking_dialog then
|
||||||
|
UIManager:close(self.blocking_dialog, "ui")
|
||||||
|
self.blocking_dialog = nil
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local elapsed = os.time() - block_start
|
||||||
|
|
||||||
|
if elapsed < 0 then
|
||||||
|
G_reader_settings:saveSetting("block_start_time", 0)
|
||||||
|
G_reader_settings:saveSetting("current_tries_number", 0)
|
||||||
|
if self.blocking_dialog then
|
||||||
|
UIManager:close(self.blocking_dialog, "ui")
|
||||||
|
self.blocking_dialog = nil
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if elapsed >= TIMEOUT_TIME then
|
||||||
|
if self.blocking_dialog then
|
||||||
|
UIManager:close(self.blocking_dialog, "ui")
|
||||||
|
self.blocking_dialog = nil
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
self.remaining_block_time = TIMEOUT_TIME - elapsed
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadDialog:showPinPad()
|
||||||
|
local screensaver_visible = UIManager:isWidgetShown(Screensaver.screensaver_widget)
|
||||||
|
|
||||||
|
if screensaver_visible then
|
||||||
|
ScreensaverUtil.freeze()
|
||||||
|
self.reused_screensaver = true
|
||||||
|
else
|
||||||
|
Screensaver:setup()
|
||||||
|
self:initializeScreensaverBackground()
|
||||||
|
if self.screensaver_widget then
|
||||||
|
UIManager:show(self.screensaver_widget)
|
||||||
|
end
|
||||||
|
self.reused_screensaver = false
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local currentFileSource = debug.getinfo(1, "S").source
|
||||||
|
local plugin_dir
|
||||||
|
if currentFileSource:find("^@") then
|
||||||
|
plugin_dir = currentFileSource:gsub("^@(.*)/[^/]*", "%1")
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.stage == "locked" then
|
||||||
|
self.dialog = PinPadButtonDialog:new {
|
||||||
|
title = self.dialog_text,
|
||||||
|
title_align = "center",
|
||||||
|
use_info_style = false,
|
||||||
|
buttons = self.buttons,
|
||||||
|
dismissable = false,
|
||||||
|
ImageWidget:new {
|
||||||
|
file = plugin_dir .. "/icons/lock.svg",
|
||||||
|
alpha = true,
|
||||||
|
width = self.icon_size,
|
||||||
|
height = self.icon_size,
|
||||||
|
scale_factor = 0,
|
||||||
|
original_in_nightmode = false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
self.dialog = PinPadButtonDialog:new {
|
||||||
|
title = self.dialog_text,
|
||||||
|
title_align = "center",
|
||||||
|
use_info_style = false,
|
||||||
|
buttons = self.buttons,
|
||||||
|
dismissable = true,
|
||||||
|
override_show_message = true,
|
||||||
|
ImageWidget:new {
|
||||||
|
file = plugin_dir .. "/icons/lock.svg",
|
||||||
|
alpha = true,
|
||||||
|
width = self.icon_size,
|
||||||
|
height = self.icon_size,
|
||||||
|
scale_factor = 0,
|
||||||
|
original_in_nightmode = false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
UIManager:show(self.dialog, "ui")
|
||||||
|
UIManager:nextTick(function()
|
||||||
|
for i = 1, #UIManager._window_stack do
|
||||||
|
if UIManager._window_stack[i].widget == self.dialog then
|
||||||
|
local dialog_entry = table.remove(UIManager._window_stack, i)
|
||||||
|
table.insert(UIManager._window_stack, dialog_entry)
|
||||||
|
UIManager:setDirty(self.dialog, "ui")
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
if self.stage == "locked" and self:isBlocked() then
|
||||||
|
self:showBlockingDialog(self.remaining_block_time)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadDialog:showBlockingDialog(remaining_time)
|
||||||
|
self.blocking_dialog = InfoMessage:new {
|
||||||
|
text = _("Too many failed attempts. Wait " .. remaining_time .. " seconds."),
|
||||||
|
timeout = remaining_time,
|
||||||
|
dismissable = false,
|
||||||
|
}
|
||||||
|
|
||||||
|
UIManager:show(self.blocking_dialog, "ui")
|
||||||
|
UIManager:nextTick(function()
|
||||||
|
if not self.blocking_dialog then return end
|
||||||
|
for i = 1, #UIManager._window_stack do
|
||||||
|
if UIManager._window_stack[i].widget == self.blocking_dialog then
|
||||||
|
local blocking_entry = table.remove(UIManager._window_stack, i)
|
||||||
|
table.insert(UIManager._window_stack, blocking_entry)
|
||||||
|
UIManager:setDirty(self.blocking_dialog, "ui")
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadDialog:reset()
|
||||||
|
self.pin = ""
|
||||||
|
self:setDialogText()
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadDialog:closeDialogs()
|
||||||
|
if self.digit_display_timer then
|
||||||
|
self.digit_display_timer:stop()
|
||||||
|
self.digit_display_timer = nil
|
||||||
|
end
|
||||||
|
if self.blocking_dialog then
|
||||||
|
UIManager:close(self.blocking_dialog, "ui")
|
||||||
|
end
|
||||||
|
if self.dialog then
|
||||||
|
UIManager:close(self.dialog, "ui")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadDialog:close(callback_function)
|
||||||
|
self:reset()
|
||||||
|
if not callback_function then
|
||||||
|
self:closeDialogs()
|
||||||
|
end
|
||||||
|
if self.reused_screensaver then
|
||||||
|
ScreensaverUtil.forceClose(function()
|
||||||
|
if callback_function then
|
||||||
|
self:closeDialogs()
|
||||||
|
callback_function()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
if self.screensaver_widget then
|
||||||
|
ScreensaverUtil.forceClose(function()
|
||||||
|
if callback_function then
|
||||||
|
self:closeDialogs()
|
||||||
|
callback_function()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
UIManager:close(self.screensaver_widget)
|
||||||
|
self.screensaver_widget = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadDialog:onAppendToPin(digit)
|
||||||
|
if self.digit_display_timer then
|
||||||
|
self.digit_display_timer:stop()
|
||||||
|
self.digit_display_timer = nil
|
||||||
|
end
|
||||||
|
if self.dialog_text == LOCKED_TEXT or self.dialog_text == CONFIRM_CURRENT_CODE_TEXT or self.dialog_text == NEW_CODE_TEXT then
|
||||||
|
self.dialog_text = ""
|
||||||
|
end
|
||||||
|
self.pin = self.pin .. digit
|
||||||
|
|
||||||
|
if G_reader_settings:isTrue("pinpadlock_display_digit_activated") then
|
||||||
|
local temp_display_text = self.dialog_text .. digit
|
||||||
|
self.dialog:updateTitle(temp_display_text)
|
||||||
|
|
||||||
|
self.dialog_text = self.dialog_text .. "*"
|
||||||
|
|
||||||
|
self.digit_display_timer = UIManager:scheduleIn(1, function()
|
||||||
|
self.dialog:updateTitle(self.dialog_text)
|
||||||
|
self.digit_display_timer = nil
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
self.dialog_text = self.dialog_text .. "*"
|
||||||
|
self.dialog:updateTitle(self.dialog_text)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadDialog:onOk()
|
||||||
|
if self.stage == "locked" then
|
||||||
|
if self.pin == G_reader_settings:readSetting("pinpadlock_pin_code") then
|
||||||
|
self:close()
|
||||||
|
if G_reader_settings:isTrue("pinpadlock_correct_pin_message_activated") then
|
||||||
|
UIManager:show(InfoMessage:new { text = _("Correct PIN, have fun !"), timeout = 2 })
|
||||||
|
end
|
||||||
|
G_reader_settings:saveSetting("current_tries_number", 0)
|
||||||
|
G_reader_settings:saveSetting("block_start_time", 0)
|
||||||
|
G_reader_settings:makeFalse("suspended_device")
|
||||||
|
else
|
||||||
|
if self.pin == "" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local current_tries = G_reader_settings:readSetting("current_tries_number")
|
||||||
|
if (current_tries + 1) >= MAX_TRIES_LIMIT then
|
||||||
|
G_reader_settings:saveSetting("block_start_time", os.time())
|
||||||
|
self:showBlockingDialog(TIMEOUT_TIME)
|
||||||
|
else
|
||||||
|
G_reader_settings:saveSetting("current_tries_number", current_tries + 1)
|
||||||
|
UIManager:show(InfoMessage:new { text = _("Wrong PIN, try again."), timeout = 2 })
|
||||||
|
end
|
||||||
|
self:onCancel()
|
||||||
|
end
|
||||||
|
elseif self.stage == "confirm_current_code" then
|
||||||
|
if self.pin == G_reader_settings:readSetting("pinpadlock_pin_code") then
|
||||||
|
self:close()
|
||||||
|
UIManager:show(InfoMessage:new { text = _("Correct PIN, you may change your PIN Code !"), timeout = 2 })
|
||||||
|
local enterNewCode = PinPadDialog:new { stage = "enter_new_code" }
|
||||||
|
enterNewCode:showPinPad()
|
||||||
|
else
|
||||||
|
UIManager:show(InfoMessage:new { text = _("Wrong PIN, try again."), timeout = 2 })
|
||||||
|
self:onCancel()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
G_reader_settings:saveSetting("pinpadlock_pin_code", self.pin)
|
||||||
|
self:close()
|
||||||
|
UIManager:show(InfoMessage:new { text = _("PIN Code changed successfully !"), timeout = 2 })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadDialog:onDelete()
|
||||||
|
if self.pin == "" then
|
||||||
|
return
|
||||||
|
elseif #self.pin == 1 then
|
||||||
|
self.pin = ""
|
||||||
|
else
|
||||||
|
self.pin = self.pin:sub(1, #self.pin - 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
if #self.dialog_text == 1 then
|
||||||
|
self:setDialogText()
|
||||||
|
elseif not (self.dialog_text == LOCKED_TEXT or self.dialog_text == CONFIRM_CURRENT_CODE_TEXT or self.dialog_text == NEW_CODE_TEXT) then
|
||||||
|
self.dialog_text = self.dialog_text:sub(1, #self.dialog_text - 1)
|
||||||
|
end
|
||||||
|
self.dialog:updateTitle(self.dialog_text)
|
||||||
|
end
|
||||||
|
|
||||||
|
function PinPadDialog:onCancel()
|
||||||
|
if self.pin == "" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self:reset()
|
||||||
|
self.dialog:updateTitle(self.dialog_text)
|
||||||
|
end
|
||||||
|
|
||||||
|
return PinPadDialog
|
||||||
53
pinpadlockscreen.koplugin/util/screensaverutil.lua
Normal file
53
pinpadlockscreen.koplugin/util/screensaverutil.lua
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
--[[
|
||||||
|
Author: Lena2309, oleasteo (original inspiration)
|
||||||
|
Inspiration and original skeleton from `https://github.com/oleasteo/koreader-screenlockpin`
|
||||||
|
Description: Utility to prevent screensaver from closing and manage z-order
|
||||||
|
]]
|
||||||
|
|
||||||
|
local Device = require("device")
|
||||||
|
local Screensaver = require("ui/screensaver")
|
||||||
|
|
||||||
|
local ScreensaverUtil = {}
|
||||||
|
|
||||||
|
local _original_setup = nil
|
||||||
|
local _original_close = nil
|
||||||
|
local _frozen = false
|
||||||
|
|
||||||
|
-- Prevent screensaver from closing
|
||||||
|
function ScreensaverUtil.freeze()
|
||||||
|
if _frozen then return end
|
||||||
|
Device.screen_saver_lock = false
|
||||||
|
Device.screen_saver_mode = false
|
||||||
|
if not _original_setup then
|
||||||
|
_original_setup = Screensaver.setup
|
||||||
|
end
|
||||||
|
_original_close = Screensaver.close
|
||||||
|
Screensaver.setup = function() end
|
||||||
|
Screensaver.close = function() end
|
||||||
|
_frozen = true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Restore screensaver normal behavior
|
||||||
|
function ScreensaverUtil.unfreeze(callback)
|
||||||
|
if callback and _original_setup then
|
||||||
|
Screensaver.setup = function()
|
||||||
|
callback()
|
||||||
|
_original_setup(Screensaver)
|
||||||
|
end
|
||||||
|
elseif _original_setup then
|
||||||
|
Screensaver.setup = _original_setup
|
||||||
|
_original_setup = nil
|
||||||
|
end
|
||||||
|
if _original_close then
|
||||||
|
Screensaver.close = _original_close
|
||||||
|
_original_close = nil
|
||||||
|
end
|
||||||
|
_frozen = false
|
||||||
|
end
|
||||||
|
|
||||||
|
function ScreensaverUtil.forceClose(callback)
|
||||||
|
ScreensaverUtil.unfreeze(callback)
|
||||||
|
Screensaver:close_widget()
|
||||||
|
end
|
||||||
|
|
||||||
|
return ScreensaverUtil
|
||||||
BIN
screenshots/lockscreen.png
Normal file
BIN
screenshots/lockscreen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 147 KiB |
BIN
screenshots/menu_entry.png
Normal file
BIN
screenshots/menu_entry.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 101 KiB |
Reference in New Issue
Block a user