Merge pull request #154 from CanonicalLtd/mwhudson/wifi-ui

Add a basic UI for entering wifi config details.
This commit is contained in:
Mathieu Trudel-Lapierre 2016-09-09 15:33:48 -04:00 committed by GitHub
commit e608362b34
5 changed files with 140 additions and 8 deletions

View File

@ -29,7 +29,8 @@ from subiquitycore.ui.views import (NetworkView,
NetworkSetDefaultRouteView,
NetworkBondInterfacesView,
NetworkConfigureInterfaceView,
NetworkConfigureIPv4InterfaceView)
NetworkConfigureIPv4InterfaceView,
NetworkConfigureWLANView)
from subiquitycore.ui.views.network import ApplyingConfigWidget
from subiquitycore.ui.dummy import DummyView
from subiquitycore.controller import BaseController
@ -289,6 +290,14 @@ class NetworkController(BaseController):
self.signal,
iface))
def network_configure_wlan_interface(self, iface):
self.model.prev_signal = ('Back to configure interface menu',
'network:configure-interface-menu',
'network_configure_interface')
self.ui.set_header("Network interface {} manual IPv4 "
"configuration".format(iface))
self.ui.set_body(NetworkConfigureWLANView(self.model, self.signal, iface))
def network_configure_ipv6_interface(self, iface):
self.model.prev_signal = ('Back to configure interface menu',
'network:configure-interface-menu',

View File

@ -43,6 +43,8 @@ class Networkdev():
self.search_domains = []
self.nameservers = []
self.gateway = None
self.essid = None
self.wpa_psk = None
def configure(self, probe_info=None):
log.debug('Configuring iface {}'.format(self.ifname))
@ -53,6 +55,9 @@ class Networkdev():
def configure_from_info(self):
log.debug('configuring netdev from info source')
if self.iftype == 'wlan':
self.essid = self.probe_info.raw['essid']
ip_info = self.probe_info.ip
sources = ip_info.get('sources', None)
@ -113,6 +118,15 @@ class Networkdev():
if self.iftype == 'bond':
result[self.ifname]['interfaces'] = self.probe_info.bond['slaves']
if self.iftype == 'wlan':
if self.essid is not None:
aps = result[self.ifname]['access-points'] = {}
ap = aps[self.essid] = {
'mode': 'infrastructure',
}
if self.wpa_psk is not None:
ap['password'] = self.wpa_psk
return result
@property
@ -284,7 +298,10 @@ class NetworkModel(BaseModel):
'network_configure_interface'),
('Network configure ipv4 interface',
base_signal + ':configure-ipv4-interface',
'network_configure_ipv4_interface')
'network_configure_ipv4_interface'),
('Network configure wlan interface',
base_signal + ':configure-wlan-interface',
'network_configure_wlan_interface'),
]
additional_options = [
@ -640,15 +657,20 @@ class NetworkModel(BaseModel):
}
ethernets = {}
bonds = {}
wifis = {}
for iface in self.devices.values():
if iface.iftype == 'eth':
ethernets.update(iface.render())
if iface.iftype == 'bond':
bonds.update(iface.render())
if iface.iftype == 'wlan':
wifis.update(iface.render())
if any(ethernets):
config['network']['ethernets'] = ethernets
if any(bonds):
config['network']['bonds'] = bonds
if any(wifis):
config['network']['wifis'] = wifis
routes = self.get_default_route()
nw_routes = []

View File

@ -15,7 +15,7 @@
from .network import NetworkView # NOQA
from .network_default_route import NetworkSetDefaultRouteView # NOQA
from .network_configure_interface import NetworkConfigureInterfaceView # NOQA
from .network_configure_interface import NetworkConfigureInterfaceView, NetworkConfigureWLANView # NOQA
from .network_configure_ipv4_interface import NetworkConfigureIPv4InterfaceView # NOQA
from .network_bond_interfaces import NetworkBondInterfacesView # NOQA
from .welcome import CoreWelcomeView as WelcomeView # NOQA

View File

@ -177,6 +177,12 @@ class NetworkView(BaseView):
col_1.append(Text(""))
col_2.append(Color.info_primary(Text(template)))
if interface.iftype == 'wlan':
if interface.essid is not None:
col_2.append(Text("Associated to '" + interface.essid + "'"))
else:
col_2.append(Text("Not associated."))
# Other device info (MAC, vendor/model, speed)
info = self.model.get_iface_info(iface)
hwaddr = self.model.get_hw_addr(iface)

View File

@ -13,9 +13,10 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from urwid import Text, Pile, ListBox
from urwid import Text, Pile, ListBox, Columns
from subiquitycore.view import BaseView
from subiquitycore.ui.buttons import done_btn, menu_btn
from subiquitycore.ui.buttons import cancel_btn, done_btn, menu_btn
from subiquitycore.ui.interactive import PasswordEditor, StringEditor
from subiquitycore.ui.utils import Color, Padding
import logging
@ -28,11 +29,28 @@ class NetworkConfigureInterfaceView(BaseView):
self.signal = signal
self.iface = iface
self.iface_obj = self.model.get_interface(iface)
self._build_widgets()
super().__init__(ListBox(self._build_body()))
def _build_widgets(self):
self.ipv4_info = Pile(self._build_gateway_ipv4_info())
self.ipv4_method = Pile(self._build_ipv4_method_buttons())
self.ipv6_info = Pile(self._build_gateway_ipv6_info())
self.ipv6_method = Pile(self._build_ipv6_method_buttons())
body = [
if self.iface_obj.type == 'wlan':
self.wifi_info = Pile(self._build_wifi_info())
self.wifi_method = Pile(self._build_wifi_config())
def _build_body(self):
body = []
if self.iface_obj.type == 'wlan':
body.extend([
Padding.center_79(self.wifi_info),
Padding.center_79(self.wifi_method),
Padding.line_break(""),
])
body.extend([
Padding.center_79(self.ipv4_info),
Padding.center_79(self.ipv4_method),
Padding.line_break(""),
@ -41,8 +59,8 @@ class NetworkConfigureInterfaceView(BaseView):
Padding.center_79(self.ipv6_method),
Padding.line_break(""),
Padding.fixed_10(self._build_buttons())
]
super().__init__(ListBox(body))
])
return body
def _build_gateway_ipv4_info(self):
addresses = self.iface_obj.ipv4_addresses
@ -140,6 +158,17 @@ class NetworkConfigureInterfaceView(BaseView):
return buttons
def _build_wifi_info(self):
if self.iface_obj.essid is not None:
return [Text("Will associate with '%s'" % (self.iface_obj.essid,))]
else:
return [Text("No access point configured.")]
def _build_wifi_config(self):
return [Padding.left_40(menu_btn(label="Configure WIFI settings",
on_press=self.show_wlan_configuration))]
def _build_buttons(self):
done = done_btn(on_press=self.done)
@ -172,6 +201,10 @@ class NetworkConfigureInterfaceView(BaseView):
self.iface_obj.dhcp6 = True
self.update_interface()
def show_wlan_configuration(self, btn):
self.signal.emit_signal(
'menu:network:main:configure-wlan-interface', self.iface)
def show_ipv4_configuration(self, btn):
self.signal.emit_signal(
'menu:network:main:configure-ipv4-interface', self.iface)
@ -184,3 +217,65 @@ class NetworkConfigureInterfaceView(BaseView):
def done(self, result):
self.signal.prev_signal()
class NetworkConfigureWLANView(BaseView):
def __init__(self, model, signal, iface):
self.model = model
self.signal = signal
self.iface = iface
self.iface_obj = self.model.get_interface(iface)
self.essid_input = StringEditor(caption="")
self.psk_input = PasswordEditor(caption="")
self.body = [
Padding.center_79(self._build_iface_inputs()),
Padding.line_break(""),
Padding.fixed_10(self._build_buttons())
]
super().__init__(ListBox(self.body))
def _build_iface_inputs(self):
col = [
Padding.center_79(Color.info_minor(Text("Only open or WPA2/PSK networks are supported at this time."))),
Padding.line_break(""),
Columns(
[
("weight", 0.2, Text("Network name:")),
("weight", 0.3,
Color.string_input(self.essid_input,
focus_map="string_input focus")),
], dividechars=2
),
Columns(
[
("weight", 0.2, Text("Password:")),
("weight", 0.3,
Color.string_input(self.psk_input,
focus_map="string_input focus")),
], dividechars=2
),
]
return Pile(col)
def _build_buttons(self):
cancel = Color.button(cancel_btn(on_press=self.cancel),
focus_map='button focus')
done = Color.button(done_btn(on_press=self.done),
focus_map='button focus')
buttons = [done, cancel]
return Pile(buttons, focus_item=done)
def done(self, btn):
if self.iface_obj.essid is None and self.essid_input.value:
# Turn DHCP4 on by default when specifying an ESSID for the first time...
self.iface_obj.dhcp4 = True
if self.essid_input.value:
self.iface_obj.essid = self.essid_input.value
else:
self.iface_obj.essid = None
self.iface_obj.wpa_psk = self.psk_input.value
self.signal.prev_signal()
def cancel(self, btn):
self.signal.prev_signal()