feat: add network management UI for kobo

pull/2151/head
Qingping Hou 8 years ago
parent ab9a86788f
commit 20eb36a03d

@ -1 +1 @@
Subproject commit b1eb0b5bc1e6f49536bce550e93342155494d78d
Subproject commit f52fbec914e54ac24be68161951788e9fb12253c

@ -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:turnOnWifi() end
function NetworkMgr:init()
self.nw_settings = LuaSettings:open(DataStorage:getSettingsDir().."/network.lua")
end
-- Device specific method, needs to be initialized in Device:initNetworkManager
-- 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
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)

@ -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

@ -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

@ -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")

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 758 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 800 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 870 B

Binary file not shown.

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()

Loading…
Cancel
Save