feat: add network management UI for kobo
2
base
@@ -4,8 +4,10 @@ local lfs = require("libs/libkoreader-lfs")
|
||||
|
||||
local DataStorage = {}
|
||||
|
||||
local data_dir
|
||||
function DataStorage:getDataDir()
|
||||
local data_dir
|
||||
if data_dir then return data_dir end
|
||||
|
||||
if isAndroid then
|
||||
data_dir = "/sdcard/koreader"
|
||||
elseif os.getenv("UBUNTU_APPLICATION_ISOLATION") then
|
||||
@@ -19,6 +21,7 @@ function DataStorage:getDataDir()
|
||||
if lfs.attributes(data_dir, "mode") ~= "directory" then
|
||||
lfs.mkdir(data_dir)
|
||||
end
|
||||
|
||||
return data_dir
|
||||
end
|
||||
|
||||
@@ -26,9 +29,16 @@ function DataStorage:getHistoryDir()
|
||||
return self:getDataDir() .. "/history"
|
||||
end
|
||||
|
||||
function DataStorage:getSettingsDir()
|
||||
return self:getDataDir() .. "/settings"
|
||||
end
|
||||
|
||||
local function initDataDir()
|
||||
local data_dir = DataStorage:getDataDir()
|
||||
local sub_data_dirs = {"cache", "clipboard", "data", "history", "ota", "screenshots"}
|
||||
local sub_data_dirs = {
|
||||
"cache", "clipboard", "data", "history",
|
||||
"ota", "screenshots", "settings",
|
||||
}
|
||||
for _, dir in ipairs(sub_data_dirs) do
|
||||
local sub_data_dir = data_dir .. "/" .. dir
|
||||
if lfs.attributes(sub_data_dir, "mode") ~= "directory" then
|
||||
|
||||
@@ -2,19 +2,19 @@ local Generic = require("device/generic/device")
|
||||
local TimeVal = require("ui/timeval")
|
||||
local Geom = require("ui/geometry")
|
||||
local dbg = require("dbg")
|
||||
local sleep = require("ffi/util").sleep
|
||||
local _ = require("gettext")
|
||||
|
||||
local function yes() return true end
|
||||
|
||||
local function koboEnableWifi(toggle)
|
||||
if toggle == 1 then
|
||||
os.execute("lsmod | grep -q sdio_wifi_pwr || insmod /drivers/$PLATFORM/wifi/sdio_wifi_pwr.ko")
|
||||
os.execute("lsmod | grep -q dhd || insmod /drivers/$PLATFORM/wifi/dhd.ko")
|
||||
os.execute("sleep 2")
|
||||
os.execute("ifconfig eth0 up")
|
||||
os.execute("/sbin/lsmod | grep -q sdio_wifi_pwr || /sbin/insmod /drivers/$PLATFORM/wifi/sdio_wifi_pwr.ko")
|
||||
os.execute("/sbin/lsmod | grep -q dhd || /sbin/insmod /drivers/$PLATFORM/wifi/dhd.ko")
|
||||
sleep(1)
|
||||
os.execute("/sbin/ifconfig eth0 up")
|
||||
os.execute("wlarm_le -i eth0 up")
|
||||
os.execute("pidof wpa_supplicant >/dev/null || cd / && env -u LD_LIBRARY_PATH wpa_supplicant -s -i eth0 -c /etc/wpa_supplicant/wpa_supplicant.conf -C /var/run/wpa_supplicant -B")
|
||||
os.execute("sleep 1")
|
||||
os.execute("cd / && env -u LD_LIBRARY_PATH /sbin/udhcpc -S -i eth0 -s /etc/udhcpc.d/default.script -t15 -T10 -A3 -b -q >/dev/null 2>&1 &")
|
||||
os.execute("pidof wpa_supplicant >/dev/null || env -u LD_LIBRARY_PATH wpa_supplicant -s -ieth0 -O /var/run/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant.conf -B")
|
||||
else
|
||||
os.execute("killall udhcpc default.script wpa_supplicant 2>/dev/null")
|
||||
os.execute("wlarm_le -i eth0 down")
|
||||
@@ -159,12 +159,28 @@ function Kobo:init()
|
||||
end
|
||||
|
||||
function Kobo:initNetworkManager(NetworkMgr)
|
||||
NetworkMgr.turnOffWifi = function()
|
||||
function NetworkMgr:turnOffWifi(complete_callback)
|
||||
koboEnableWifi(0)
|
||||
if complete_callback then
|
||||
complete_callback()
|
||||
end
|
||||
end
|
||||
|
||||
NetworkMgr.turnOnWifi = function()
|
||||
function NetworkMgr:turnOnWifi(complete_callback)
|
||||
koboEnableWifi(1)
|
||||
self:showNetworkMenu(complete_callback)
|
||||
end
|
||||
|
||||
NetworkMgr:setWirelessBackend(
|
||||
"wpa_supplicant", {ctrl_interface = "/var/run/wpa_supplicant/eth0"})
|
||||
|
||||
function NetworkMgr:obtainIP()
|
||||
os.execute("env -u LD_LIBRARY_PATH /sbin/udhcpc -S -i eth0 -s /etc/udhcpc.d/default.script -t15 -T10 -A3 -b -q")
|
||||
end
|
||||
|
||||
function NetworkMgr:releaseIP()
|
||||
os.execute("pkill -9 -f '/bin/sh /etc/udhcpc.d/default.script';")
|
||||
os.execute("/sbin/ifconfig eth0 0.0.0.0")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ local purgeDir = require("ffi/util").purgeDir
|
||||
local DocSettings = {}
|
||||
|
||||
local HISTORY_DIR = DataStorage:getHistoryDir()
|
||||
local READER_SETTING_FILE = DataStorage:getDataDir() .. "/settings.reader.lua"
|
||||
|
||||
local function buildCandidate(file_path)
|
||||
if lfs.attributes(file_path, "mode") == "file" then
|
||||
@@ -42,62 +41,55 @@ end
|
||||
|
||||
function DocSettings:open(docfile)
|
||||
-- TODO(zijiehe): Remove history_path, use only sidecar.
|
||||
local new = { data = {} }
|
||||
local new = {}
|
||||
local ok, stored
|
||||
if docfile == ".reader" then
|
||||
-- we handle reader setting as special case
|
||||
new.history_file = READER_SETTING_FILE
|
||||
ok, stored = pcall(dofile, new.history_file)
|
||||
else
|
||||
new.history_file = self:getHistoryPath(docfile)
|
||||
new.history_file = self:getHistoryPath(docfile)
|
||||
|
||||
local sidecar = self:getSidecarDir(docfile)
|
||||
new.sidecar = sidecar
|
||||
if lfs.attributes(sidecar, "mode") ~= "directory" then
|
||||
lfs.mkdir(sidecar)
|
||||
end
|
||||
-- If there is a file which has a same name as the sidecar directory, or
|
||||
-- the file system is read-only, we should not waste time to read it.
|
||||
if lfs.attributes(sidecar, "mode") == "directory" then
|
||||
-- New sidecar file name is metadata.{file last suffix}.lua. So we
|
||||
-- can handle two files with only different suffixes.
|
||||
new.sidecar_file = sidecar.."/metadata."..
|
||||
docfile:match(".*%.(.*)")..".lua"
|
||||
if docfile:find("/") then
|
||||
new.legacy_sidecar_file = sidecar.."/"..
|
||||
docfile:match(".*%/(.*)")..".lua"
|
||||
else
|
||||
new.legacy_sidecar_file = sidecar.."/"..docfile..".lua"
|
||||
end
|
||||
end
|
||||
local sidecar = self:getSidecarDir(docfile)
|
||||
new.sidecar = sidecar
|
||||
if lfs.attributes(sidecar, "mode") ~= "directory" then
|
||||
lfs.mkdir(sidecar)
|
||||
end
|
||||
-- If there is a file which has a same name as the sidecar directory, or
|
||||
-- the file system is read-only, we should not waste time to read it.
|
||||
if lfs.attributes(sidecar, "mode") == "directory" then
|
||||
-- New sidecar file name is metadata.{file last suffix}.lua. So we
|
||||
-- can handle two files with only different suffixes.
|
||||
new.sidecar_file = sidecar.."/metadata."..
|
||||
docfile:match(".*%.(.+)")..".lua"
|
||||
new.legacy_sidecar_file = sidecar.."/"..
|
||||
docfile:match("([^%/]+%..+)")..".lua"
|
||||
end
|
||||
|
||||
new.candidates = {}
|
||||
-- New sidecar file
|
||||
table.insert(new.candidates, buildCandidate(new.sidecar_file))
|
||||
-- Legacy sidecar file
|
||||
table.insert(new.candidates, buildCandidate(new.legacy_sidecar_file))
|
||||
-- Legacy history folder
|
||||
table.insert(new.candidates, buildCandidate(new.history_file))
|
||||
-- Legacy kpdfview setting
|
||||
table.insert(new.candidates, buildCandidate(docfile..".kpdfview.lua"))
|
||||
table.sort(new.candidates, function(l, r)
|
||||
if l == nil then
|
||||
return false
|
||||
elseif r == nil then
|
||||
return true
|
||||
else
|
||||
return l[2] > r[2]
|
||||
end
|
||||
end)
|
||||
for _, k in pairs(new.candidates) do
|
||||
ok, stored = pcall(dofile, k[1])
|
||||
if ok then
|
||||
break
|
||||
end
|
||||
local candidates = {}
|
||||
-- New sidecar file
|
||||
table.insert(candidates, buildCandidate(new.sidecar_file))
|
||||
-- Legacy sidecar file
|
||||
table.insert(candidates, buildCandidate(new.legacy_sidecar_file))
|
||||
-- Legacy history folder
|
||||
table.insert(candidates, buildCandidate(new.history_file))
|
||||
-- Legacy kpdfview setting
|
||||
table.insert(candidates, buildCandidate(docfile..".kpdfview.lua"))
|
||||
table.sort(candidates, function(l, r)
|
||||
if l == nil then
|
||||
return false
|
||||
elseif r == nil then
|
||||
return true
|
||||
else
|
||||
return l[2] > r[2]
|
||||
end
|
||||
end)
|
||||
for _, k in pairs(candidates) do
|
||||
ok, stored = pcall(dofile, k[1])
|
||||
if ok then
|
||||
break
|
||||
end
|
||||
end
|
||||
if ok and stored then
|
||||
new.data = stored
|
||||
new.candidates = candidates
|
||||
else
|
||||
new.data = {}
|
||||
end
|
||||
|
||||
return setmetatable(new, {__index = DocSettings})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
local Device = require("device")
|
||||
local Language = require("ui/language")
|
||||
local NetworkMgr = require("ui/networkmgr")
|
||||
local NetworkMgr = require("ui/network/manager")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local Screen = require("device").screen
|
||||
local _ = require("gettext")
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local LuaSettings = require("luasettings")
|
||||
local DataStorage = require("datastorage")
|
||||
local Device = require("device")
|
||||
local T = require("ffi/util").template
|
||||
local _ = require("gettext")
|
||||
@@ -8,26 +10,37 @@ local _ = require("gettext")
|
||||
|
||||
local NetworkMgr = {}
|
||||
|
||||
-- Device specific method, needs to be initialized in Device:initNetworkManager
|
||||
function NetworkMgr:init()
|
||||
self.nw_settings = LuaSettings:open(DataStorage:getSettingsDir().."/network.lua")
|
||||
end
|
||||
|
||||
-- Following methods are Device specific which need to be initialized in
|
||||
-- Device:initNetworkManager. Some of them can be set by calling
|
||||
-- NetworkMgr:setWirelessBackend
|
||||
function NetworkMgr:turnOnWifi() end
|
||||
|
||||
-- Device specific method, needs to be initialized in Device:initNetworkManager
|
||||
function NetworkMgr:turnOffWifi() end
|
||||
function NetworkMgr:getNetworkList() end
|
||||
function NetworkMgr:getCurrentNetwork() end
|
||||
function NetworkMgr:authenticateNetwork() end
|
||||
function NetworkMgr:disconnectNetwork() end
|
||||
function NetworkMgr:obtainIP() end
|
||||
function NetworkMgr:releaseIP() end
|
||||
-- End of device specific methods
|
||||
|
||||
function NetworkMgr:promptWifiOn()
|
||||
function NetworkMgr:promptWifiOn(complete_callback)
|
||||
UIManager:show(ConfirmBox:new{
|
||||
text = _("Do you want to turn on Wi-Fi?"),
|
||||
ok_callback = function()
|
||||
self:turnOnWifi()
|
||||
self:turnOnWifi(complete_callback)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
function NetworkMgr:promptWifiOff()
|
||||
function NetworkMgr:promptWifiOff(complete_callback)
|
||||
UIManager:show(ConfirmBox:new{
|
||||
text = _("Do you want to turn off Wi-Fi?"),
|
||||
ok_callback = function()
|
||||
self:turnOffWifi()
|
||||
self:turnOffWifi(complete_callback)
|
||||
end,
|
||||
})
|
||||
end
|
||||
@@ -53,11 +66,15 @@ function NetworkMgr:getWifiMenuTable()
|
||||
text = _("Wi-Fi connection"),
|
||||
enabled_func = function() return Device:isKindle() or Device:isKobo() end,
|
||||
checked_func = function() return NetworkMgr:getWifiStatus() end,
|
||||
callback = function()
|
||||
callback = function(menu)
|
||||
local complete_callback = function()
|
||||
-- notify touch menu to update item check state
|
||||
menu:updateItems()
|
||||
end
|
||||
if NetworkMgr:getWifiStatus() then
|
||||
NetworkMgr:promptWifiOff()
|
||||
NetworkMgr:promptWifiOff(complete_callback)
|
||||
else
|
||||
NetworkMgr:promptWifiOn()
|
||||
NetworkMgr:promptWifiOn(complete_callback)
|
||||
end
|
||||
end
|
||||
}
|
||||
@@ -100,6 +117,44 @@ function NetworkMgr:getProxyMenuTable()
|
||||
}
|
||||
end
|
||||
|
||||
function NetworkMgr:showNetworkMenu(complete_callback)
|
||||
local info = InfoMessage:new{text = _("Scanning…")}
|
||||
UIManager:show(info)
|
||||
UIManager:nextTick(function()
|
||||
local network_list = self:getNetworkList()
|
||||
UIManager:close(info)
|
||||
UIManager:show(require("ui/widget/networksetting"):new{
|
||||
network_list = network_list,
|
||||
connect_callback = complete_callback,
|
||||
})
|
||||
end)
|
||||
end
|
||||
|
||||
function NetworkMgr:saveNetwork(setting)
|
||||
if not self.nw_settings then self:init() end
|
||||
self.nw_settings:saveSetting(setting.ssid, {
|
||||
ssid = setting.ssid,
|
||||
password = setting.password,
|
||||
flags = setting.flags,
|
||||
})
|
||||
self.nw_settings:flush()
|
||||
end
|
||||
|
||||
function NetworkMgr:deleteNetwork(setting)
|
||||
if not self.nw_settings then self:init() end
|
||||
self.nw_settings:delSetting(setting.ssid)
|
||||
self.nw_settings:flush()
|
||||
end
|
||||
|
||||
function NetworkMgr:getAllSavedNetworks()
|
||||
if not self.nw_settings then self:init() end
|
||||
return self.nw_settings
|
||||
end
|
||||
|
||||
function NetworkMgr:setWirelessBackend(name, options)
|
||||
require("ui/network/"..name).init(self, options)
|
||||
end
|
||||
|
||||
-- set network proxy if global variable NETWORK_PROXY is defined
|
||||
if NETWORK_PROXY then
|
||||
NetworkMgr:setHTTPProxy(NETWORK_PROXY)
|
||||
113
frontend/ui/network/wpa_supplicant.lua
Normal file
@@ -0,0 +1,113 @@
|
||||
local UIManager = require("ui/uimanager")
|
||||
local WpaClient = require('lj-wpaclient/wpaclient')
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local sleep = require("ffi/util").sleep
|
||||
local _ = require("gettext")
|
||||
|
||||
local WpaSupplicant = {}
|
||||
|
||||
function WpaSupplicant:getNetworkList()
|
||||
local wcli, _ = WpaClient.new(self.wpa_supplicant.ctrl_interface)
|
||||
local list = wcli:scanThenGetResults()
|
||||
wcli:close()
|
||||
|
||||
local saved_networks = self:getAllSavedNetworks()
|
||||
local curr_network = self:getCurrentNetwork()
|
||||
|
||||
for _,network in ipairs(list) do
|
||||
network.signal_quality = network:getSignalQuality()
|
||||
local saved_nw = saved_networks:readSetting(network.ssid)
|
||||
if saved_nw and saved_nw.flags == network.flags then
|
||||
network.password = saved_nw.password
|
||||
end
|
||||
-- TODO: also verify bssid if it is not set to any
|
||||
if curr_network and curr_network.ssid == network.ssid then
|
||||
network.connected = true
|
||||
network.wpa_supplicant_id = curr_network.id
|
||||
end
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
function WpaSupplicant:authenticateNetwork(network)
|
||||
-- TODO: support passwordless network
|
||||
local err, wcli, nw_id
|
||||
wcli, err = WpaClient.new(self.wpa_supplicant.ctrl_interface)
|
||||
|
||||
if not wcli then
|
||||
return false, _("Failed to initialize network control client: ")..err
|
||||
end
|
||||
|
||||
nw_id, err = wcli:addNetwork()
|
||||
if err then return false, err end
|
||||
|
||||
wcli:setNetwork(nw_id, "ssid", network.ssid)
|
||||
wcli:setNetwork(nw_id, "psk", network.password)
|
||||
wcli:enableNetworkByID(nw_id)
|
||||
|
||||
wcli:attach()
|
||||
local cnt = 0
|
||||
local failure_cnt = 0
|
||||
local max_retry = 30
|
||||
local info = InfoMessage:new{text = _("Authenticating…")}
|
||||
local re, msg
|
||||
UIManager:show(info)
|
||||
UIManager:forceRePaint()
|
||||
while cnt < max_retry do
|
||||
local ev = wcli:readEvent()
|
||||
if ev ~= nil then
|
||||
if not ev:isScanEvent() then
|
||||
UIManager:close(info)
|
||||
info = InfoMessage:new{text = ev.msg}
|
||||
UIManager:show(info)
|
||||
UIManager:forceRePaint()
|
||||
end
|
||||
if ev:isAuthSuccessful() then
|
||||
network.wpa_supplicant_id = nw_id
|
||||
re = true
|
||||
break
|
||||
elseif ev:isAuthFailed() then
|
||||
failure_cnt = failure_cnt + 1
|
||||
if failure_cnt > 3 then
|
||||
re, msg = false, _('Failed to authenticate')
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
sleep(1)
|
||||
cnt = cnt + 1
|
||||
end
|
||||
end
|
||||
if re ~= true then wcli:removeNetwork(nw_id) end
|
||||
wcli:close()
|
||||
UIManager:close(info)
|
||||
UIManager:forceRePaint()
|
||||
if cnt >= max_retry then
|
||||
re, msg = false, _('Timed out')
|
||||
end
|
||||
return re, msg
|
||||
end
|
||||
|
||||
function WpaSupplicant:disconnectNetwork(network)
|
||||
if not network.wpa_supplicant_id then return end
|
||||
local wcli, _ = WpaClient.new(self.wpa_supplicant.ctrl_interface)
|
||||
wcli:removeNetwork(network.wpa_supplicant_id)
|
||||
wcli:close()
|
||||
end
|
||||
|
||||
function WpaSupplicant:getCurrentNetwork()
|
||||
local wcli, _ = WpaClient.new(self.wpa_supplicant.ctrl_interface)
|
||||
local nw = wcli:getCurrentNetwork()
|
||||
wcli:close()
|
||||
return nw
|
||||
end
|
||||
|
||||
function WpaSupplicant.init(network_mgr, options)
|
||||
network_mgr.wpa_supplicant = {ctrl_interface = options.ctrl_interface}
|
||||
network_mgr.getNetworkList = WpaSupplicant.getNetworkList
|
||||
network_mgr.getCurrentNetwork = WpaSupplicant.getCurrentNetwork
|
||||
network_mgr.authenticateNetwork = WpaSupplicant.authenticateNetwork
|
||||
network_mgr.disconnectNetwork = WpaSupplicant.disconnectNetwork
|
||||
end
|
||||
|
||||
return WpaSupplicant
|
||||
@@ -1,6 +1,6 @@
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local NetworkMgr = require("ui/networkmgr")
|
||||
local NetworkMgr = require("ui/network/manager")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
local DataStorage = require("datastorage")
|
||||
local UIManager = require("ui/uimanager")
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
--[[--
|
||||
Widget that shows a message and OK/Cancel buttons
|
||||
|
||||
Example:
|
||||
|
||||
UIManager:show(ConfirmBox:new{
|
||||
text = _("Save the document?"),
|
||||
ok_text = _("Save"), -- ok_text defaults to _("OK")
|
||||
ok_callback = function()
|
||||
-- save document
|
||||
end,
|
||||
})
|
||||
|
||||
]]
|
||||
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local CenterContainer = require("ui/widget/container/centercontainer")
|
||||
local FrameContainer = require("ui/widget/container/framecontainer")
|
||||
@@ -15,11 +30,7 @@ local DEBUG = require("dbg")
|
||||
local _ = require("gettext")
|
||||
local Blitbuffer = require("ffi/blitbuffer")
|
||||
|
||||
-- screen
|
||||
|
||||
--[[
|
||||
Widget that shows a message and OK/Cancel buttons
|
||||
]]
|
||||
local ConfirmBox = InputContainer:new{
|
||||
modal = true,
|
||||
text = _("no text"),
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
--[[--
|
||||
ImageWidget shows an image from a file
|
||||
|
||||
Example:
|
||||
|
||||
UIManager:show(ImageWidget:new{
|
||||
file = "resources/info-i.png",
|
||||
-- Make sure alpha is set to true if png has transparent background
|
||||
-- alpha = true,
|
||||
})
|
||||
|
||||
]]
|
||||
|
||||
local Widget = require("ui/widget/widget")
|
||||
local Screen = require("device").screen
|
||||
local CacheItem = require("cacheitem")
|
||||
@@ -23,9 +36,6 @@ function ImageCacheItem:onFree()
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
ImageWidget shows an image from a file
|
||||
--]]
|
||||
local ImageWidget = Widget:new{
|
||||
file = nil,
|
||||
image = nil,
|
||||
|
||||
@@ -11,6 +11,7 @@ Example:
|
||||
input = "default value",
|
||||
input_hint = "hint text",
|
||||
input_type = "text",
|
||||
-- text_type = "password",
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
|
||||
@@ -73,23 +73,33 @@ end
|
||||
|
||||
function InputText:initTextBox(text)
|
||||
self.text = text
|
||||
self.charlist = util.splitToChars(text)
|
||||
if self.charpos == nil then
|
||||
self.charpos = #self.charlist + 1
|
||||
end
|
||||
local fgcolor = Blitbuffer.gray(self.text == "" and 0.5 or 1.0)
|
||||
|
||||
local show_text = self.text
|
||||
if self.text_type == "password" and show_text ~= "" then
|
||||
show_text = self.text:gsub("(.-).", function() return "*" end)
|
||||
show_text = show_text:gsub("(.)$", function() return self.text:sub(-1) end)
|
||||
elseif show_text == "" then
|
||||
local fgcolor
|
||||
local show_charlist
|
||||
local show_text = text
|
||||
if show_text == "" or show_text == nil then
|
||||
-- no preset value, use hint text if set
|
||||
show_text = self.hint
|
||||
fgcolor = Blitbuffer.COLOR_GREY
|
||||
self.charlist = {}
|
||||
self.charpos = 1
|
||||
else
|
||||
fgcolor = Blitbuffer.COLOR_BLACK
|
||||
if self.text_type == "password" then
|
||||
show_text = self.text:gsub(
|
||||
"(.-).", function() return "*" end)
|
||||
show_text = show_text:gsub(
|
||||
"(.)$", function() return self.text:sub(-1) end)
|
||||
end
|
||||
self.charlist = util.splitToChars(text)
|
||||
if self.charpos == nil then
|
||||
self.charpos = #self.charlist + 1
|
||||
end
|
||||
end
|
||||
show_charlist = util.splitToChars(show_text)
|
||||
if self.scroll then
|
||||
self.text_widget = ScrollTextWidget:new{
|
||||
text = show_text,
|
||||
charlist = self.charlist,
|
||||
charlist = show_charlist,
|
||||
charpos = self.charpos,
|
||||
editable = self.focused,
|
||||
face = self.face,
|
||||
@@ -100,7 +110,7 @@ function InputText:initTextBox(text)
|
||||
else
|
||||
self.text_widget = TextBoxWidget:new{
|
||||
text = show_text,
|
||||
charlist = self.charlist,
|
||||
charlist = show_charlist,
|
||||
charpos = self.charpos,
|
||||
editable = self.focused,
|
||||
face = self.face,
|
||||
|
||||
@@ -39,7 +39,7 @@ local Device = require("device")
|
||||
local Screen = Device.screen
|
||||
|
||||
|
||||
local ellipsis, space = "...", " "
|
||||
local ellipsis, space = "…", " "
|
||||
local ellipsis_width, space_width
|
||||
local function truncateTextByWidth(text, face, max_width, prepend_space)
|
||||
if not ellipsis_width then
|
||||
|
||||
123
frontend/ui/widget/listview.lua
Normal file
@@ -0,0 +1,123 @@
|
||||
--[[--
|
||||
Widget compoent that handles pagination for a list of items.
|
||||
|
||||
Example:
|
||||
|
||||
local list_view = ListView:new{
|
||||
height = 400,
|
||||
width = 200,
|
||||
page_update_cb = function(curr_page_num, total_pages)
|
||||
-- This callback function will be called whenever there is a
|
||||
-- page turn event triggered. You can use it to update information
|
||||
-- on parent widget.
|
||||
end,
|
||||
items = {
|
||||
FrameContainer:new{
|
||||
bordersize = 0,
|
||||
background = Blitbuffer.COLOR_WHITE
|
||||
TextWidget:new{
|
||||
text = "foo",
|
||||
fact = Font:getFace("cfont"),
|
||||
}
|
||||
},
|
||||
FrameContainer:new{
|
||||
bordersize = 0,
|
||||
background = Blitbuffer.COLOR_LIGHT_GREY
|
||||
TextWidget:new{
|
||||
text = "bar",
|
||||
fact = Font:getFace("cfont"),
|
||||
}
|
||||
},
|
||||
-- You can add as many widgets as you want here...
|
||||
}
|
||||
}
|
||||
|
||||
Note that ListView is created mainly to be used as a building block for other
|
||||
widgets like NetworkSetting so they can share the same pagination code.
|
||||
]]
|
||||
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local FrameContainer = require("ui/widget/container/framecontainer")
|
||||
local VerticalGroup = require("ui/widget/verticalgroup")
|
||||
local GestureRange = require("ui/gesturerange")
|
||||
local Blitbuffer = require("ffi/blitbuffer")
|
||||
local Device = require("device")
|
||||
local Screen = Device.screen
|
||||
local Geom = require("ui/geometry")
|
||||
|
||||
local ListView = InputContainer:new{
|
||||
width = nil,
|
||||
height = nil,
|
||||
padding = nil,
|
||||
item_height = nil,
|
||||
itmes = nil,
|
||||
}
|
||||
|
||||
function ListView:init()
|
||||
self.show_page = 1
|
||||
self.dimen = Geom:new{w = self.width, h = self.height}
|
||||
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events.Swipe = {
|
||||
GestureRange:new{
|
||||
ges = "swipe",
|
||||
range = self.dimen,
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
local padding = self.padding or Screen:scaleBySize(10)
|
||||
self.item_height = self.item_height or self.items[1]:getSize().h
|
||||
self.item_width = self.dimen.w - 2 * padding
|
||||
self.items_per_page = math.floor(self.height / self.item_height)
|
||||
self.main_content = VerticalGroup:new{}
|
||||
self:_populateItems()
|
||||
self[1] = FrameContainer:new{
|
||||
height = self.dimen.h,
|
||||
padding = padding,
|
||||
bordersize = 0,
|
||||
background = Blitbuffer.COLOR_WHITE,
|
||||
self.main_content,
|
||||
}
|
||||
end
|
||||
|
||||
-- make sure self.item_height are set before calling this
|
||||
function ListView:_populateItems()
|
||||
self.pages = math.ceil(#self.items / self.items_per_page)
|
||||
self.main_content:clear()
|
||||
local idx_offset = (self.show_page - 1) * self.items_per_page
|
||||
for idx = 1, self.items_per_page do
|
||||
local item = self.items[idx_offset + idx]
|
||||
if item == nil then break end
|
||||
table.insert(self.main_content, item)
|
||||
end
|
||||
self.page_update_cb(self.show_page, self.pages)
|
||||
end
|
||||
|
||||
function ListView:nextPage()
|
||||
local new_page = math.min(self.show_page+1, self.pages)
|
||||
if new_page > self.show_page then
|
||||
self.show_page = new_page
|
||||
self:_populateItems()
|
||||
end
|
||||
end
|
||||
|
||||
function ListView:prevPage()
|
||||
local new_page = math.max(self.show_page-1, 1)
|
||||
if new_page < self.show_page then
|
||||
self.show_page = new_page
|
||||
self:_populateItems()
|
||||
end
|
||||
end
|
||||
|
||||
function ListView:onSwipe(arg, ges_ev)
|
||||
if ges_ev.direction == "west" then
|
||||
self:nextPage()
|
||||
return true
|
||||
elseif ges_ev.direction == "east" then
|
||||
self:prevPage()
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return ListView
|
||||
466
frontend/ui/widget/networksetting.lua
Normal file
@@ -0,0 +1,466 @@
|
||||
--[[--
|
||||
Network setting widget.
|
||||
|
||||
Example:
|
||||
|
||||
local network_list = {
|
||||
{
|
||||
ssid = "foo",
|
||||
signal_level = -58,
|
||||
flags = "[WPA2-PSK-CCMP][ESS]",
|
||||
signal_quality = 84,
|
||||
password = "123abc",
|
||||
connected = true,
|
||||
},
|
||||
{
|
||||
ssid = "bar",
|
||||
signal_level = -258,
|
||||
signal_quality = 44,
|
||||
flags = "[WEP][ESS]",
|
||||
},
|
||||
}
|
||||
UIManager:show(require("ui/widget/networksetting"):new{
|
||||
network_list = network_list,
|
||||
connect_callback = function()
|
||||
-- connect_callback will be called when an connect/disconnect
|
||||
-- attempt has been made. you can update UI widgets in the
|
||||
-- callback.
|
||||
end,
|
||||
})
|
||||
|
||||
]]
|
||||
|
||||
local FrameContainer = require("ui/widget/container/framecontainer")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local LeftContainer = require("ui/widget/container/leftcontainer")
|
||||
local CenterContainer = require("ui/widget/container/centercontainer")
|
||||
local RightContainer = require("ui/widget/container/rightcontainer")
|
||||
local HorizontalGroup = require("ui/widget/horizontalgroup")
|
||||
local HorizontalSpan = require("ui/widget/horizontalspan")
|
||||
local VerticalGroup = require("ui/widget/verticalgroup")
|
||||
local OverlapGroup = require("ui/widget/overlapgroup")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local InputDialog = require("ui/widget/inputdialog")
|
||||
local NetworkMgr = require("ui/network/manager")
|
||||
local ListView = require("ui/widget/listview")
|
||||
local ImageWidget = require("ui/widget/imagewidget")
|
||||
local Widget = require("ui/widget/widget")
|
||||
local TextWidget = require("ui/widget/textwidget")
|
||||
local GestureRange = require("ui/gesturerange")
|
||||
local Blitbuffer = require("ffi/blitbuffer")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local Geom = require("ui/geometry")
|
||||
local Device = require("device")
|
||||
local Screen = Device.screen
|
||||
local Font = require("ui/font")
|
||||
local _ = require("gettext")
|
||||
|
||||
|
||||
local MinimalPaginator = Widget:new{
|
||||
width = nil,
|
||||
height = nil,
|
||||
progress = nil,
|
||||
}
|
||||
|
||||
function MinimalPaginator:getSize()
|
||||
return Geom:new{w = self.width, h = self.height}
|
||||
end
|
||||
|
||||
function MinimalPaginator:paintTo(bb, x, y)
|
||||
self.dimen = self:getSize()
|
||||
self.dimen.x, self.dimen.y = x, y
|
||||
-- paint background
|
||||
bb:paintRoundedRect(x, y,
|
||||
self.dimen.w, self.dimen.h,
|
||||
Blitbuffer.COLOR_LIGHT_GREY)
|
||||
-- paint percentage infill
|
||||
bb:paintRect(x, y,
|
||||
math.ceil(self.dimen.w*self.progress), self.dimen.h,
|
||||
Blitbuffer.COLOR_GREY)
|
||||
end
|
||||
|
||||
function MinimalPaginator:setProgress(progress) self.progress = progress end
|
||||
|
||||
|
||||
local NetworkItem = InputContainer:new{
|
||||
dimen = nil,
|
||||
height = Screen:scaleBySize(44),
|
||||
width = nil,
|
||||
info = nil,
|
||||
background = Blitbuffer.COLOR_WHITE,
|
||||
}
|
||||
|
||||
function NetworkItem:init()
|
||||
self.dimen = Geom:new{w = self.width, h = self.height}
|
||||
if not self.info.ssid then
|
||||
self.info.ssid = "[hidden]"
|
||||
end
|
||||
|
||||
local wifi_icon_path
|
||||
if string.find(self.info.flags, "WPA") then
|
||||
wifi_icon_path = "resources/icons/koicon.wifi.secure.%d.medium.png"
|
||||
else
|
||||
wifi_icon_path = "resources/icons/koicon.wifi.open.%d.medium.png"
|
||||
end
|
||||
if self.info.signal_quality == 0 or self.info.signal_quality == 100 then
|
||||
wifi_icon_path = string.format(wifi_icon_path, self.info.signal_quality)
|
||||
else
|
||||
wifi_icon_path = string.format(
|
||||
wifi_icon_path,
|
||||
self.info.signal_quality + 25 - self.info.signal_quality % 25)
|
||||
end
|
||||
local horizontal_space = HorizontalSpan:new{width = Screen:scaleBySize(8)}
|
||||
self.content_container = OverlapGroup:new{
|
||||
dimen = self.dimen:copy(),
|
||||
LeftContainer:new{
|
||||
dimen = self.dimen:copy(),
|
||||
HorizontalGroup:new{
|
||||
horizontal_space,
|
||||
ImageWidget:new{
|
||||
alpha = true,
|
||||
file = wifi_icon_path,
|
||||
},
|
||||
horizontal_space,
|
||||
TextWidget:new{
|
||||
text = self.info.ssid,
|
||||
face = Font:getFace("cfont"),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
self.btn_disconnect = nil
|
||||
self.btn_edit_nw = nil
|
||||
if self.info.connected then
|
||||
self.btn_disconnect = FrameContainer:new{
|
||||
bordersize = 0,
|
||||
padding = 0,
|
||||
TextWidget:new{
|
||||
text = _("disconnect"),
|
||||
face = Font:getFace("cfont"),
|
||||
}
|
||||
}
|
||||
|
||||
table.insert(self.content_container, RightContainer:new{
|
||||
dimen = self.dimen:copy(),
|
||||
HorizontalGroup:new{
|
||||
self.btn_disconnect,
|
||||
horizontal_space,
|
||||
}
|
||||
})
|
||||
elseif self.info.password then
|
||||
self.btn_edit_nw = FrameContainer:new{
|
||||
bordersize = 0,
|
||||
padding = 0,
|
||||
TextWidget:new{
|
||||
text = _("edit"),
|
||||
face = Font:getFace("cfont"),
|
||||
}
|
||||
}
|
||||
|
||||
table.insert(self.content_container, RightContainer:new{
|
||||
dimen = self.dimen:copy(),
|
||||
HorizontalGroup:new{
|
||||
self.btn_edit_nw,
|
||||
horizontal_space,
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
self[1] = FrameContainer:new{
|
||||
padding = 0,
|
||||
margin = 0,
|
||||
background = self.background,
|
||||
bordersize = 0,
|
||||
width = self.width,
|
||||
self.content_container,
|
||||
}
|
||||
|
||||
if Device:isTouchDevice() then
|
||||
self.ges_events = {
|
||||
TapSelect = {
|
||||
GestureRange:new{
|
||||
ges = "tap",
|
||||
range = self.dimen,
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function NetworkItem:refresh()
|
||||
self:init()
|
||||
UIManager:setDirty(self.setting_ui, function() return "ui", self.dimen end)
|
||||
end
|
||||
|
||||
function NetworkItem:connect()
|
||||
local connected_item = self.setting_ui:getConnectedItem(self)
|
||||
if connected_item then connected_item:disconnect() end
|
||||
|
||||
local success, err_msg = NetworkMgr:authenticateNetwork(self.info)
|
||||
|
||||
local text
|
||||
if success then
|
||||
local info = InfoMessage:new{text = _("Obtaining IP address…")}
|
||||
UIManager:show(info)
|
||||
UIManager:forceRePaint()
|
||||
NetworkMgr:obtainIP()
|
||||
UIManager:close(info)
|
||||
self.info.connected = true
|
||||
self.setting_ui:setConnectedItem(self)
|
||||
text = _("Connected.")
|
||||
else
|
||||
text = err_msg
|
||||
end
|
||||
|
||||
if self.setting_ui.connect_callback then
|
||||
self.setting_ui.connect_callback()
|
||||
end
|
||||
UIManager:show(InfoMessage:new{text = text})
|
||||
end
|
||||
|
||||
function NetworkItem:disconnect()
|
||||
local info = InfoMessage:new{text = _("Disconnecting…")}
|
||||
UIManager:show(info)
|
||||
UIManager:forceRePaint()
|
||||
|
||||
NetworkMgr:disconnectNetwork(self.info)
|
||||
NetworkMgr:releaseIP()
|
||||
|
||||
UIManager:close(info)
|
||||
self.info.connected = nil
|
||||
self:refresh()
|
||||
if self.setting_ui.connect_callback then
|
||||
self.setting_ui.connect_callback()
|
||||
end
|
||||
end
|
||||
|
||||
function NetworkItem:saveAndConnectToNetwork(password_input)
|
||||
local new_passwd = password_input:getInputText()
|
||||
if new_passwd == nil or string.len(new_passwd) == 0 then
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Password cannot be empty."),
|
||||
})
|
||||
else
|
||||
if new_passwd ~= self.info.password then
|
||||
self.info.password = new_passwd
|
||||
NetworkMgr:saveNetwork(self.info)
|
||||
end
|
||||
self:connect()
|
||||
self:refresh()
|
||||
end
|
||||
|
||||
UIManager:close(password_input)
|
||||
end
|
||||
|
||||
function NetworkItem:onEditNetwork()
|
||||
local password_input
|
||||
password_input = InputDialog:new{
|
||||
title = self.info.ssid,
|
||||
input = self.info.password,
|
||||
input_hint = "password",
|
||||
input_type = "text",
|
||||
text_type = "password",
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Cancel"),
|
||||
callback = function()
|
||||
UIManager:close(password_input)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Forget"),
|
||||
callback = function()
|
||||
NetworkMgr:deleteNetwork(self.info)
|
||||
self.info.password = nil
|
||||
-- remove edit button
|
||||
table.remove(self.content_container, 2)
|
||||
UIManager:close(password_input)
|
||||
self:refresh()
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Connect"),
|
||||
is_enter_default = true,
|
||||
callback = function()
|
||||
self:saveAndConnectToNetwork(password_input)
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
password_input:onShowKeyboard()
|
||||
UIManager:show(password_input)
|
||||
return true
|
||||
end
|
||||
|
||||
function NetworkItem:onAddNetwork()
|
||||
local password_input
|
||||
password_input = InputDialog:new{
|
||||
title = self.info.ssid,
|
||||
input = "",
|
||||
input_hint = "password",
|
||||
input_type = "text",
|
||||
text_type = "password",
|
||||
buttons = {
|
||||
{
|
||||
{
|
||||
text = _("Cancel"),
|
||||
callback = function()
|
||||
UIManager:close(password_input)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Connect"),
|
||||
is_enter_default = true,
|
||||
callback = function()
|
||||
self:saveAndConnectToNetwork(password_input)
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
password_input:onShowKeyboard()
|
||||
UIManager:show(password_input)
|
||||
return true
|
||||
end
|
||||
|
||||
function NetworkItem:onTapSelect(arg, ges_ev)
|
||||
if not string.find(self.info.flags, "WPA") then
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Networks without WPA/WPA2 encryption are not supported.")
|
||||
})
|
||||
return
|
||||
end
|
||||
if self.btn_disconnect then
|
||||
-- noop if touch is not on disconnect button
|
||||
if ges_ev.pos:intersectWith(self.btn_disconnect.dimen) then
|
||||
self:disconnect()
|
||||
end
|
||||
elseif self.info.password then
|
||||
if self.btn_edit_nw and ges_ev.pos:intersectWith(self.btn_edit_nw.dimen) then
|
||||
self:onEditNetwork()
|
||||
else
|
||||
self:connect()
|
||||
self:refresh()
|
||||
end
|
||||
else
|
||||
self:onAddNetwork()
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
local NetworkSetting = InputContainer:new{
|
||||
width = nil,
|
||||
height = nil,
|
||||
-- sample network_list entry: {
|
||||
-- bssid = "any",
|
||||
-- ssid = "foo",
|
||||
-- signal_level = -58,
|
||||
-- signal_quality = 84,
|
||||
-- frequency = 5660,
|
||||
-- flags = "[WPA2-PSK-CCMP][ESS]",
|
||||
-- }
|
||||
network_list = nil,
|
||||
connect_callback = nil,
|
||||
}
|
||||
|
||||
function NetworkSetting:init()
|
||||
self.width = self.width or Screen:getWidth() - Screen:scaleBySize(50)
|
||||
self.width = math.min(self.width, Screen:scaleBySize(600))
|
||||
|
||||
local gray_bg = Blitbuffer.gray(0.1)
|
||||
local items = {}
|
||||
table.sort(self.network_list,
|
||||
function(l, r) return l.signal_quality > r.signal_quality end)
|
||||
for idx,network in ipairs(self.network_list) do
|
||||
local bg
|
||||
if idx % 2 == 0 then
|
||||
bg = gray_bg
|
||||
else
|
||||
bg = Blitbuffer.COLOR_WHITE
|
||||
end
|
||||
table.insert(items, NetworkItem:new{
|
||||
width = self.width,
|
||||
info = network,
|
||||
background = bg,
|
||||
setting_ui = self,
|
||||
})
|
||||
end
|
||||
|
||||
self.status_text = TextWidget:new{
|
||||
text = "",
|
||||
face = Font:getFace("ffont"),
|
||||
}
|
||||
self.page_text = TextWidget:new{
|
||||
text = "",
|
||||
face = Font:getFace("ffont"),
|
||||
}
|
||||
|
||||
self.pagination = MinimalPaginator:new{
|
||||
width = self.width,
|
||||
height = Screen:scaleBySize(8),
|
||||
percentage = 0,
|
||||
}
|
||||
|
||||
self.height = self.height or math.min(Screen:getHeight()*3/4,
|
||||
Screen:scaleBySize(800))
|
||||
self.popup = FrameContainer:new{
|
||||
background = Blitbuffer.COLOR_WHITE,
|
||||
padding = 0,
|
||||
bordersize = 3,
|
||||
VerticalGroup:new{
|
||||
align = "left",
|
||||
self.pagination,
|
||||
ListView:new{
|
||||
padding = 0,
|
||||
items = items,
|
||||
width = self.width,
|
||||
height = self.height-self.pagination:getSize().h,
|
||||
page_update_cb = function(curr_page, total_pages)
|
||||
self.pagination:setProgress(curr_page/total_pages)
|
||||
-- self.page_text:setText(curr_page .. "/" .. total_pages)
|
||||
UIManager:setDirty(self, function()
|
||||
return "ui", self.dimen
|
||||
end)
|
||||
end
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
self[1] = CenterContainer:new{
|
||||
dimen = {w = Screen:getWidth(), h = Screen:getHeight()},
|
||||
self.popup,
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
function NetworkSetting:setConnectedItem(item)
|
||||
self.connected_item = item
|
||||
end
|
||||
|
||||
function NetworkSetting:getConnectedItem()
|
||||
return self.connected_item
|
||||
end
|
||||
|
||||
function NetworkSetting:onTapClose(arg, ges_ev)
|
||||
if ges_ev.pos:notIntersectWith(self.popup.dimen) then
|
||||
UIManager:close(self)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return NetworkSetting
|
||||
@@ -3,7 +3,7 @@ local ButtonDialog = require("ui/widget/buttondialog")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local LoginDialog = require("ui/widget/logindialog")
|
||||
local OPDSParser = require("ui/opdsparser")
|
||||
local NetworkMgr = require("ui/networkmgr")
|
||||
local NetworkMgr = require("ui/network/manager")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local CacheItem = require("cacheitem")
|
||||
local Menu = require("ui/widget/menu")
|
||||
|
||||
@@ -87,9 +87,7 @@ end
|
||||
|
||||
-- Split the text into logical lines to fit into the text box.
|
||||
function TextBoxWidget:_splitCharWidthList()
|
||||
self.vertical_string_list = {
|
||||
{text = self.text, offset = 1, width = 0} -- hint for empty string
|
||||
}
|
||||
self.vertical_string_list = {}
|
||||
|
||||
local idx = 1
|
||||
local size = #self.char_width_list
|
||||
@@ -178,10 +176,17 @@ end
|
||||
-- Return the position of the cursor corresponding to `self.charpos`,
|
||||
-- Be aware of virtual line number of the scorllTextWidget.
|
||||
function TextBoxWidget:_findCharPos()
|
||||
if self.text == nil or string.len(self.text) == 0 then
|
||||
return 0, 0
|
||||
end
|
||||
-- Find the line number.
|
||||
local ln = self.height == nil and 1 or self.virtual_line_num
|
||||
while ln + 1 <= #self.vertical_string_list do
|
||||
if self.vertical_string_list[ln + 1].offset > self.charpos then break else ln = ln + 1 end
|
||||
if self.vertical_string_list[ln + 1].offset > self.charpos then
|
||||
break
|
||||
else
|
||||
ln = ln + 1
|
||||
end
|
||||
end
|
||||
-- Find the offset at the current line.
|
||||
local x = 0
|
||||
@@ -193,6 +198,12 @@ function TextBoxWidget:_findCharPos()
|
||||
return x + 1, (ln - 1) * self.line_height_px -- offset `x` by 1 to avoid overlap
|
||||
end
|
||||
|
||||
function TextBoxWidget:moveCursorToCharpos(charpos)
|
||||
self.charpos = charpos
|
||||
local x, y = self:_findCharPos()
|
||||
self.cursor_line:paintTo(self._bb, x, y)
|
||||
end
|
||||
|
||||
-- Click event: Move the cursor to a new location with (x, y), in pixels.
|
||||
-- Be aware of virtual line number of the scorllTextWidget.
|
||||
function TextBoxWidget:moveCursor(x, y)
|
||||
|
||||
@@ -564,7 +564,7 @@ function TouchMenu:onMenuSelect(item)
|
||||
-- put stuff in scheduler so we can see
|
||||
-- the effect of inverted menu item
|
||||
UIManager:scheduleIn(0.1, function()
|
||||
callback()
|
||||
callback(self)
|
||||
if refresh then
|
||||
self:updateItems()
|
||||
else
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local LoginDialog = require("ui/widget/logindialog")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local NetworkMgr = require("ui/networkmgr")
|
||||
local NetworkMgr = require("ui/network/manager")
|
||||
local DataStorage = require("datastorage")
|
||||
local DocSettings = require("docsettings")
|
||||
local UIManager = require("ui/uimanager")
|
||||
|
||||
@@ -3,7 +3,7 @@ local LoginDialog = require("ui/widget/logindialog")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local DocSettings = require("docsettings")
|
||||
local NetworkMgr = require("ui/networkmgr")
|
||||
local NetworkMgr = require("ui/network/manager")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local Screen = require("device").screen
|
||||
local Device = require("device")
|
||||
|
||||
BIN
resources/icons/koicon.wifi.open.0.medium.png
Normal file
|
After Width: | Height: | Size: 729 B |
BIN
resources/icons/koicon.wifi.open.100.medium.png
Normal file
|
After Width: | Height: | Size: 774 B |
BIN
resources/icons/koicon.wifi.open.25.medium.png
Normal file
|
After Width: | Height: | Size: 758 B |
BIN
resources/icons/koicon.wifi.open.50.medium.png
Normal file
|
After Width: | Height: | Size: 792 B |
BIN
resources/icons/koicon.wifi.open.75.medium.png
Normal file
|
After Width: | Height: | Size: 800 B |
BIN
resources/icons/koicon.wifi.secure.0.medium.png
Normal file
|
After Width: | Height: | Size: 877 B |
BIN
resources/icons/koicon.wifi.secure.100.medium.png
Normal file
|
After Width: | Height: | Size: 846 B |
BIN
resources/icons/koicon.wifi.secure.25.medium.png
Normal file
|
After Width: | Height: | Size: 865 B |
BIN
resources/icons/koicon.wifi.secure.50.medium.png
Normal file
|
After Width: | Height: | Size: 870 B |
BIN
resources/icons/koicon.wifi.secure.75.medium.png
Normal file
|
After Width: | Height: | Size: 874 B |
@@ -6,7 +6,7 @@ package.cpath = "?.so;common/?.so;/usr/lib/lua/?.so;rocks/lib/lua/5.1/?.so;" ..
|
||||
local DataStorage = require("datastorage")
|
||||
os.remove(DataStorage:getDataDir().."/settings.reader.lua")
|
||||
local DocSettings = require("docsettings")
|
||||
G_reader_settings = DocSettings:open(".reader")
|
||||
G_reader_settings = require("luasettings"):open(".reader")
|
||||
|
||||
-- global einkfb for Screen (do not show SDL window)
|
||||
einkfb = require("ffi/framebuffer")
|
||||
|
||||
@@ -6,13 +6,14 @@ print(package.path)
|
||||
package.path = "common/?.lua;rocks/share/lua/5.1/?.lua;frontend/?.lua;" .. package.path
|
||||
package.cpath = "common/?.so;common/?.dll;/usr/lib/lua/?.so;rocks/lib/lua/5.1/?.so;" .. package.cpath
|
||||
|
||||
local DocSettings = require("docsettings")
|
||||
local DataStorage = require("datastorage")
|
||||
local _ = require("gettext")
|
||||
|
||||
-- read settings and check for language override
|
||||
-- has to be done before requiring other files because
|
||||
-- they might call gettext on load
|
||||
G_reader_settings = DocSettings:open(".reader")
|
||||
G_reader_settings = require("luasettings"):open(
|
||||
DataStorage:getDataDir().."/settings.reader.lua")
|
||||
local lang_locale = G_reader_settings:readSetting("language")
|
||||
if lang_locale then
|
||||
_.changeLang(lang_locale)
|
||||
@@ -397,6 +398,49 @@ function testTouchProbe()
|
||||
UIManager:show(TouchProbe:new{})
|
||||
end
|
||||
|
||||
function testNetworkSetting()
|
||||
local list = {
|
||||
{
|
||||
ssid = "CMU-SECURE",
|
||||
signal_level = -58,
|
||||
flags = "[WPA2-PSK-CCMP][ESS]",
|
||||
signal_quality = 84,
|
||||
},
|
||||
{
|
||||
ssid = "CMU-SECURE 2",
|
||||
signal_level = -258,
|
||||
signal_quality = 44,
|
||||
flags = "[WPA2-PSK-CCMP][ESS]",
|
||||
password = "okgo",
|
||||
},
|
||||
{
|
||||
ssid = "218",
|
||||
signal_level = 58,
|
||||
signal_quality = 100,
|
||||
flags = "[WEP][ESS]",
|
||||
},
|
||||
{
|
||||
ssid = "318",
|
||||
signal_level = 100,
|
||||
signal_quality = 100,
|
||||
flags = "[WPA2-PSK-CCMP][ESS]",
|
||||
},
|
||||
}
|
||||
|
||||
for i=1,10 do
|
||||
table.insert(list, {
|
||||
ssid = "918-"..tostring(i),
|
||||
signal_level = -58-i*2,
|
||||
signal_quality = 84-i*2,
|
||||
flags = "[WPA2-PSK-CCMP][ESS]",
|
||||
})
|
||||
end
|
||||
|
||||
local nw = require("ui/widget/networksetting"):new{network_list = list}
|
||||
UIManager:show(nw)
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- you may want to uncomment following show calls to see the changes
|
||||
-----------------------------------------------------------------------
|
||||
@@ -413,5 +457,6 @@ UIManager:show(Clock:new())
|
||||
--TestInputText:onShowKeyboard()
|
||||
-- testKeyValuePage()
|
||||
-- testTouchProbe()
|
||||
testBookStatus()
|
||||
-- testBookStatus()
|
||||
testNetworkSetting()
|
||||
UIManager:run()
|
||||
|
||||