mirror of
https://github.com/koreader/koreader
synced 2024-10-31 21:20:20 +00:00
e502bf04d3
* [VirtualKeyboard] Add support for keynaviguation Also rename the variable "layout" to "keyboard_layout" because conflict with the layout from the focusmanager * Make the goto dialog compatible with key naviguation My solution is to change the order of the widget. The last one will the virtualkeybard so it catch all the keybinding, and below it, make the dialog "is_always_active = true" so it can receive touch event. * Correctly show the virtual keyboard on dpad devices * change the order to call the virtualKeyboard so it end up on top * Handle the multi input dialog * Support reopening the virtualKeyboard by the Press key * add check focusmanager * Fix https://github.com/koreader/koreader/issues/3797 * MultiInputDialog : Now work on non touch-device * Set the virtualkeyboard to be a modal widget * Fix the layout in multiinputwidget * Fix for the various combination of hasKeys,hasDpad,isTouchDevice * [Focusmanager] Better handling of malformed layout
491 lines
14 KiB
Lua
491 lines
14 KiB
Lua
--[[--
|
|
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 Blitbuffer = require("ffi/blitbuffer")
|
|
local CenterContainer = require("ui/widget/container/centercontainer")
|
|
local Device = require("device")
|
|
local Font = require("ui/font")
|
|
local Geom = require("ui/geometry")
|
|
local FrameContainer = require("ui/widget/container/framecontainer")
|
|
local GestureRange = require("ui/gesturerange")
|
|
local HorizontalGroup = require("ui/widget/horizontalgroup")
|
|
local HorizontalSpan = require("ui/widget/horizontalspan")
|
|
local ImageWidget = require("ui/widget/imagewidget")
|
|
local InfoMessage = require("ui/widget/infomessage")
|
|
local InputContainer = require("ui/widget/container/inputcontainer")
|
|
local InputDialog = require("ui/widget/inputdialog")
|
|
local LeftContainer = require("ui/widget/container/leftcontainer")
|
|
local ListView = require("ui/widget/listview")
|
|
local RightContainer = require("ui/widget/container/rightcontainer")
|
|
local NetworkMgr = require("ui/network/manager")
|
|
local OverlapGroup = require("ui/widget/overlapgroup")
|
|
local Size = require("ui/size")
|
|
local TextWidget = require("ui/widget/textwidget")
|
|
local UIManager = require("ui/uimanager")
|
|
local VerticalGroup = require("ui/widget/verticalgroup")
|
|
local Widget = require("ui/widget/widget")
|
|
local _ = require("gettext")
|
|
local T = require("ffi/util").template
|
|
local Screen = Device.screen
|
|
|
|
local function obtainIP()
|
|
-- TODO: check for DHCP result
|
|
local info = InfoMessage:new{text = _("Obtaining IP address…")}
|
|
UIManager:show(info)
|
|
UIManager:forceRePaint()
|
|
NetworkMgr:obtainIP()
|
|
UIManager:close(info)
|
|
end
|
|
|
|
|
|
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 = Size.span.horizontal_default}
|
|
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,
|
|
}
|
|
})
|
|
self.setting_ui:setConnectedItem(self)
|
|
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()
|
|
if connected_item then connected_item:disconnect() end
|
|
|
|
local success, err_msg = NetworkMgr:authenticateNetwork(self.info)
|
|
|
|
local text
|
|
if success then
|
|
obtainIP()
|
|
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
|
|
|
|
self:refresh()
|
|
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()
|
|
self.setting_ui:setConnectedItem(nil)
|
|
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
|
|
self.info.psk = nil
|
|
NetworkMgr:saveNetwork(self.info)
|
|
end
|
|
self:connect()
|
|
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,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
UIManager:show(password_input)
|
|
password_input:onShowKeyboard()
|
|
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,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
UIManager:show(password_input)
|
|
password_input:onShowKeyboard()
|
|
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()
|
|
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,
|
|
progress = 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 = Size.border.window,
|
|
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
|
|
|
|
UIManager:nextTick(function()
|
|
local connected_item = self:getConnectedItem()
|
|
if connected_item ~= nil then
|
|
obtainIP()
|
|
UIManager:show(InfoMessage:new{
|
|
text = T(_("Connected to network %1"), connected_item.info.ssid)
|
|
})
|
|
if self.connect_callback then
|
|
self.connect_callback()
|
|
end
|
|
end
|
|
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
|