rewritten network module, not finished yet

This commit is contained in:
Rene Kievits
2023-05-15 13:02:59 +02:00
parent 1c7d2be751
commit 2d68ee71da
4 changed files with 805 additions and 1109 deletions

View File

@@ -0,0 +1,805 @@
local setmetatable = setmetatable
local table = table
local pairs = pairs
local ipairs = ipairs
local base = require('wibox.widget.base')
local beautiful = require('beautiful')
local dpi = beautiful.xresources.apply_dpi
local gcolor = require('gears.color')
local gfilesystem = require('gears.filesystem')
local gshape = require('gears.shape')
local wibox = require('wibox')
local gtable = require('gears.table')
local abutton = require('awful.button')
local apopup = require('awful.popup')
local aplacement = require('awful.placement')
local rubato = require('src.lib.rubato')
local dnd_widget = require('awful.widget.toggle_widget')
local networkManager = require('src.tools.network')()
local inputbox = require('src.modules.inputbox')
local context_menu = require('src.modules.context_menu')
local icondir = gfilesystem.get_configuration_dir() .. 'src/assets/icons/network/'
local capi = {
mouse = mouse,
}
local network = {}
--- Called when a connection does not exist yet and the user needs to ender a password
--- And Autoconnect or not.
---@param ap AccessPoint The access point to connect to
---@param callback function The callback to call when the conenct button is pressed
function network:open_connection_form(ap, callback)
if self.form_popup then
self.form_popup.visible = false
end
--Password inputbox
local password = inputbox {
mouse_focus = true,
text = 'testtext',
}
--New form widget
local w = base.make_widget_from_value {
{
{
{
{ -- Header
{
nil,
{ -- SSID
{
widget = wibox.widget.textbox,
text = ap.SSID,
halign = 'center',
valign = 'center',
},
widget = wibox.container.margin,
margins = dpi(5),
},
{ -- Close button
{
{
{
widget = wibox.widget.imagebox,
image = gcolor.recolor_image(icondir .. 'close.svg', beautiful.colorscheme.bg),
resize = true,
valign = 'center',
halign = 'center',
},
widget = wibox.container.margin,
margins = dpi(5),
},
widget = wibox.container.background,
id = 'close_button',
bg = beautiful.colorscheme.bg_red,
shape = beautiful.shape[8],
},
widget = wibox.container.constraint,
width = dpi(30),
height = dpi(30),
strategy = 'exact',
},
layout = wibox.layout.align.horizontal,
},
widget = wibox.container.background,
fg = beautiful.colorscheme.bg_red,
},
{ -- Form
{ -- Password text
widget = wibox.widget.textbox,
text = 'Password',
halign = 'center',
valign = 'center',
},
{ -- Spacing
widget = wibox.container.margin,
left = dpi(20),
right = dpi(20),
},
{ -- Passwort inputbox
{
{
{
{
password.widget,
step = dpi(50),
scrollbar_width = 0,
id = 'scroll',
layout = require('src.lib.overflow_widget.overflow').horizontal,
},
widget = wibox.container.margin,
left = dpi(5),
right = dpi(5),
},
widget = wibox.container.place,
halign = 'left',
},
widget = wibox.container.background,
bg = beautiful.colorscheme.bg,
fg = beautiful.colorscheme.fg,
border_color = beautiful.colorscheme.border_color,
border_width = dpi(2),
shape = beautiful.shape[8],
id = 'password_container',
},
widget = wibox.container.constraint,
strategy = 'exact',
width = dpi(300),
height = dpi(50),
},
layout = wibox.layout.align.horizontal,
},
{ -- Actions
{ -- Auto Connect
{
{
{
checked = false,
shape = beautiful.shape[4],
color = beautiful.colorscheme.bg,
paddings = dpi(3),
check_color = beautiful.colorscheme.bg_red,
border_color = beautiful.colorscheme.bg_red,
border_width = dpi(2),
id = 'checkbox',
widget = wibox.widget.checkbox,
},
widget = wibox.container.constraint,
strategy = 'exact',
width = dpi(30),
height = dpi(30),
},
widget = wibox.container.place,
},
{
widget = wibox.widget.textbox,
text = 'Auto connect',
halign = 'center',
valign = 'center',
},
layout = wibox.layout.fixed.horizontal,
spacing = dpi(10),
},
nil,
{ -- Connect
{
{
{
widget = wibox.widget.textbox,
text = 'Connect',
valign = 'center',
halign = 'center',
},
widget = wibox.container.margin,
margins = dpi(10),
},
widget = wibox.container.background,
bg = beautiful.colorscheme.bg_blue,
fg = beautiful.colorscheme.bg,
shape = beautiful.shape[8],
id = 'connect_button',
},
widget = wibox.container.margin,
margins = dpi(10),
},
layout = wibox.layout.align.horizontal,
},
layout = wibox.layout.fixed.vertical,
spacing = dpi(20),
},
widget = wibox.container.margin,
margins = dpi(10),
},
bg = beautiful.colorscheme.bg,
fg = beautiful.colorscheme.fg,
widget = wibox.container.background,
},
widget = wibox.container.constraint,
strategy = 'max',
height = dpi(400),
width = dpi(600),
buttons = gtable.join {
abutton({}, 1, function()
password:unfocus()
end),
},
}
-- Popup for the form
self.form_popup = apopup {
widget = w,
visible = true,
type = 'dialog',
screen = capi.mouse.screen,
border_color = beautiful.colorscheme.border_color,
border_width = dpi(2),
ontop = true,
placement = aplacement.centered,
}
-- Automatically scroll to the right when typing to keep the password visible
local scroll_layout = w:get_children_by_id('scroll')[1]
password:connect_signal('inputbox::keypressed', function(_, m, k)
scroll_layout:set_scroll_factor(1)
end)
-- Connect button pressed when the user is done typing and ready to connect
--TODO: Don't just close the form, try to connect first and check if the password is correct or not
local connect_button = w:get_children_by_id('connect_button')[1]
connect_button:buttons(gtable.join {
abutton({}, 1, function()
local res = {
autoconnect = w:get_children_by_id('checkbox')[1].checked,
passwd = password:get_text(),
ssid = ap.SSID,
security = ap.Security,
}
password:unfocus()
networkManager:ConnectToAccessPointAsync(ap, self.device, networkManager.NetworkManagerSettings:NewConnectionProfile(res), function(succ)
if succ then
w = nil
self.form_popup.visible = false
else
--TODO: Add a little text under/above the password box and make it visible here telling the user that the password was
--TODO: wrong
end
end)
end),
})
-- Autoconnect true/false
local checkbox = w:get_children_by_id('checkbox')[1]
checkbox:buttons(gtable.join {
abutton({}, 1, function()
checkbox.checked = not checkbox.checked
end),
})
-- Close the form and do nothing
local close_button = w:get_children_by_id('close_button')[1]
close_button:buttons(gtable.join {
abutton({}, 1, function()
password:unfocus()
w = nil
self.form_popup.visible = false
end),
})
-- Focus the inputbox when clicked
--TODO: Add some keys to the inputbox to make it possible to lose focus on enter/escape etc
local password_container = w:get_children_by_id('password_container')[1]
password_container:buttons(gtable.join {
abutton({}, 1, function()
password:focus()
end),
})
end
---Sort the wifi list by active access point first, then by strength descending
function network:resort_wifi_list()
local wifi_list = self:get_children_by_id('wifi_list')[1]
--Make sure that the active AP is always on top, there is only one active AP
table.sort(wifi_list.children, function(a, b)
if self.device:IsApActive(a) then
return true
elseif self.device:IsApActive(b) then
return false
end
return a.Strength > b.Strength
end)
end
---If an Access Point is lost then remove it from the list
---@param ap AccessPoint Lost AP
---@return boolean deleted
function network:delete_ap_from_list(ap)
local wifi_list = self:get_children_by_id('wifi_list')[1]
for i, w in ipairs(wifi_list.children) do
if w.object_path == ap then
table.remove(wifi_list.children, i)
return true
end
end
return false
end
---If an access point needs to be added to the list
---@param ap AccessPoint
function network:add_ap_to_list(ap)
if not ap then return end
local wifi_list = self:get_children_by_id('wifi_list')[1]
local fg, bg
if self.device:IsApActive(ap) then
fg = beautiful.colorscheme.bg
bg = beautiful.colorscheme.bg_red
else
fg = beautiful.colorscheme.bg_red
bg = beautiful.colorscheme.bg
end
-- New AP widget
local w = base.make_widget_from_value {
{
{
{
{
{
id = 'icon_role',
image = gcolor.recolor_image(icondir .. 'wifi-strength-1.svg', fg),
resize = true,
valign = 'center',
halign = 'center',
widget = wibox.widget.imagebox,
},
strategy = 'max',
width = dpi(24),
height = dpi(24),
widget = wibox.container.constraint,
},
{
{
{
text = ap.SSID,
widget = wibox.widget.textbox,
},
strategy = 'exact',
width = dpi(300),
widget = wibox.container.constraint,
},
width = dpi(260),
height = dpi(40),
strategy = 'max',
widget = wibox.container.constraint,
},
spacing = dpi(10),
layout = wibox.layout.fixed.horizontal,
},
{ -- Spacing
width = dpi(10),
widget = wibox.container.constraint,
},
{
{
{
resize = false,
id = 'con_icon',
image = gcolor.recolor_image(icondir .. 'link-off.svg', fg),
valign = 'center',
halign = 'center',
widget = wibox.widget.imagebox,
},
strategy = 'max',
height = dpi(24),
width = dpi(24),
widget = wibox.container.constraint,
},
margins = dpi(5),
widget = wibox.container.margin,
},
layout = wibox.layout.align.horizontal,
},
margins = dpi(5),
widget = wibox.container.margin,
},
shape = beautiful.shape[4],
bg = bg,
fg = fg,
border_color = beautiful.colorscheme.border_color,
border_width = dpi(2),
widget = wibox.container.background,
Strength = ap.Strength,
object_path = ap.object_path,
}
local icon = w:get_children_by_id('icon_role')[1]
local con_icon = w:get_children_by_id('con_icon')[1]
-- Update the strength icon and resort the list afterwards
ap:connect_signal('NetworkManagerAccessPoint::Strength', function(_, strength)
local s
if strength >= 80 then
s = 5
elseif strength >= 60 and strength < 80 then
s = 4
elseif strength >= 40 and strength < 60 then
s = 3
elseif strength >= 20 and strength < 40 then
s = 2
else
s = 1
end
w.Strength = strength
icon.image = gcolor.recolor_image(icondir .. 'wifi-strength-' .. s .. '.svg', fg)
self:resort_wifi_list()
end)
-- Manually fire once to set the icon, as some AP's need a few seconds to update
ap:emit_signal('NetworkManagerAccessPoint::Strength', ap.Strength)
-- Update the active connection, and the old one (color and icon change)
self.device:connect_signal('NetworkManagerDeviceWireless::ActiveAccessPoint', function(_, old_ap, new_ap)
local function active_ap_signal(_, strength)
self:emit_signal('ActiveAccessPointStrength', strength)
--!Why does the above signal not work outside of this module?
--This is a workaournd until I foundout why it doesn't work
awesome.emit_signal('ActiveAccessPointStrength', strength)
end
if old_ap == ap.object_path then
w.bg = beautiful.colorscheme.bg
w.fg = beautiful.colorscheme.bg_red
bg = beautiful.colorscheme.bg
fg = beautiful.colorscheme.bg_red
con_icon.image = gcolor.recolor_image(icondir .. 'link-off.svg', fg)
icon.image = gcolor.recolor_image(icondir .. 'wifi-strength-1.svg', fg)
ap:disconnect_signal('NetworkManagerAccessPoint::Strength', active_ap_signal)
end
if new_ap == ap.object_path then
w.bg = beautiful.colorscheme.bg_red
w.fg = beautiful.colorscheme.bg
fg = beautiful.colorscheme.bg
bg = beautiful.colorscheme.bg_red
con_icon.image = gcolor.recolor_image(icondir .. 'link.svg', fg)
icon.image = gcolor.recolor_image(icondir .. 'wifi-strength-1.svg', fg)
ap:connect_signal('NetworkManagerAccessPoint::Strength', active_ap_signal)
end
end)
-- Again manually update
self.device:emit_signal('NetworkManagerDeviceWireless::ActiveAccessPoint', nil, self.device.NetworkManagerDeviceWireless.ActiveAccessPoint)
-- Context menu for connecting, disconnecting, etc.
--TODO: Needs to update its entries when the active AP changes to it has a disconnect button
local cm = context_menu {
widget_template = wibox.widget {
{
{
{
{
widget = wibox.widget.imagebox,
resize = true,
valign = 'center',
halign = 'center',
id = 'icon_role',
},
widget = wibox.container.constraint,
stragety = 'exact',
width = dpi(24),
height = dpi(24),
id = 'const',
},
{
widget = wibox.widget.textbox,
valign = 'center',
halign = 'left',
id = 'text_role',
},
layout = wibox.layout.fixed.horizontal,
},
widget = wibox.container.margin,
},
widget = wibox.container.background,
},
spacing = dpi(10),
entries = {
{
name = self.device:IsApActive(ap) and 'Disconnect' or 'Connect',
icon = self.device:IsApActive(ap) and gcolor.recolor_image(icondir .. 'link-off.svg', bg) or gcolor.recolor_image(icondir .. 'link.svg', fg),
callback = function()
if self.device:IsApActive(ap) then
networkManager:DisconnectFromAP();
else
networkManager:ConnectToAccessPointAsync(ap, self.device, nil, function(res)
if not res then
self:open_connection_form(ap, function(res)
end)
end
end)
end
end,
},
{
name = 'Remove connection',
icon = gcolor.recolor_image(icondir .. 'delete.svg', bg),
callback = function()
for path, value in pairs(networkManager.NetworkManagerSettings.ConnectionList or {}) do
if ap.SSID == value:GetSettings().connection.id then
networkManager.NetworkManagerSettings:RemoveConnection(value)
end
end
end,
},
},
}
-- Hide context menu on leave
cm:connect_signal('mouse::leave', function()
cm.visible = false
end)
-- Left click should try to connect/disconnect to AP
--TODO: Check if active ap is clicked and try to disconnect, instead of trying to reconnect to the same AP
-- Right click toggles the context menu
w:buttons(gtable.join {
abutton({}, 1, function()
networkManager:ConnectToAccessPointAsync(ap, self.device, nil, function(res)
if not res then
self:open_connection_form(ap, function(res)
end)
end
end)
end),
abutton({}, 3, function()
cm:toggle()
end),
})
-- Add ap into table
table.insert(wifi_list.children, w)
-- Resort after adding the new AP
self:resort_wifi_list()
end
---Check if an AP is already in the list by comparing its object path
---@param ap AccessPoint
---@return boolean inlist Is in list or not
function network:is_ap_in_list(ap)
if not ap then return false end
local wifi_list = self:get_children_by_id('wifi_list')[1]
for _, w in ipairs(wifi_list.children) do
if w.object_path == ap.object_path then
return true
end
end
return false
end
---Add the list to the widget hierarchy, and clears the previous entries
---Usually used when the user requests a new scan
---@param ap_list table<ap_list>
function network:set_wifi_list(ap_list)
if not ap_list or #ap_list < 1 then return end
local wifi_list = self:get_children_by_id('wifi_list')[1]
wifi_list:reset()
for _, ap in ipairs(ap_list) do
self:add_ap_to_list(ap)
end
end
return setmetatable(network, {
__call = function(self)
local dnd = dnd_widget {
color = beautiful.colorscheme.bg_red,
size = dpi(40),
}
local w = base.make_widget_from_value {
{
{
{
{
{
{
{
widget = wibox.widget.imagebox,
resize = false,
id = 'wifi_icon',
image = gcolor.recolor_image(icondir .. 'menu-down.svg', beautiful.colorscheme.bg_red),
},
widget = wibox.container.place,
},
{
{
text = 'Wifi Networks',
widget = wibox.widget.textbox,
},
margins = dpi(5),
widget = wibox.container.margin,
},
layout = wibox.layout.fixed.horizontal,
},
id = 'wifi_list_bar',
bg = beautiful.colorscheme.bg1,
fg = beautiful.colorscheme.bg_red,
shape = beautiful.shape[4],
widget = wibox.container.background,
},
{
{
{
{
step = dpi(50),
spacing = dpi(10),
scrollbar_width = 0,
id = 'wifi_list',
layout = require('src.lib.overflow_widget.overflow').vertical,
},
margins = dpi(10),
widget = wibox.container.margin,
},
border_color = beautiful.colorscheme.border_color,
border_width = dpi(2),
shape = function(cr, width, height)
gshape.partially_rounded_rect(cr, width, height, false, false, true, true, dpi(4))
end,
widget = wibox.container.background,
},
id = 'wifi_list_height',
strategy = 'exact',
height = 0,
widget = wibox.container.constraint,
},
{
{
{
dnd,
widget = wibox.container.place,
},
nil,
{
{
{
image = gcolor.recolor_image(icondir .. 'refresh.svg', beautiful.colorscheme.bg_red),
resize = false,
valign = 'center',
halign = 'center',
widget = wibox.widget.imagebox,
},
widget = wibox.container.margin,
margins = dpi(5),
},
id = 'refresh_button',
border_color = beautiful.colorscheme.border_color,
border_width = dpi(2),
bg = beautiful.colorscheme.bg,
shape = beautiful.shape[4],
widget = wibox.container.background,
},
layout = wibox.layout.align.horizontal,
},
top = dpi(10),
widget = wibox.container.margin,
},
layout = wibox.layout.fixed.vertical,
},
margins = dpi(15),
widget = wibox.container.margin,
},
shape = beautiful.shape[8],
border_color = beautiful.colorscheme.border_color,
bg = beautiful.colorscheme.bg,
border_width = dpi(2),
widget = wibox.container.background,
},
strategy = 'exact',
width = dpi(400),
widget = wibox.container.constraint,
}
gtable.crush(self, w)
--- Get the current wifi device.
---! In theory its not needed to update, why would the wifi card change? Needs validation.
self.device = networkManager:get_wireless_device()
local wifi_list = w:get_children_by_id('wifi_list')[1]
local wifi_list_height = w:get_children_by_id('wifi_list_height')[1]
local wifi_list_bar = w:get_children_by_id('wifi_list_bar')[1]
local wifi_icon = w:get_children_by_id('wifi_icon')[1]
-- Dropdown animation
local wifi_list_anim = rubato.timed {
duration = 0.2,
pos = wifi_list_height.height,
clamp_position = true,
rate = 24,
subscribed = function(v)
wifi_list_height.height = v
end,
}
-- Dropdown toggle
wifi_list_bar:buttons(gtable.join {
abutton({}, 1, function()
if wifi_list_height.height == 0 then
local size = (wifi_list.children and #wifi_list.children or 0) * dpi(50)
if size > dpi(330) then
size = dpi(330)
end
wifi_list_anim.target = dpi(size)
wifi_list_bar.shape = function(cr, width, height)
gshape.partially_rounded_rect(cr, width, height, true, true, false, false, dpi(4))
end
if #wifi_list.children > 0 then
wifi_icon:set_image(gcolor.recolor_image(icondir .. 'menu-up.svg',
beautiful.colorscheme.bg_red))
else
wifi_icon:set_image(gcolor.recolor_image(icondir .. 'menu-down.svg',
beautiful.colorscheme.bg_red))
end
else
wifi_list_anim.target = 0
wifi_list_bar.shape = function(cr, width, height)
gshape.partially_rounded_rect(cr, width, height, true, true, true, true, dpi(4))
end
wifi_icon:set_image(gcolor.recolor_image(icondir .. 'menu-down.svg',
beautiful.colorscheme.bg_red))
end
end),
})
--- Manual rescan request, this gets all AP's and updates the list
local refresh_button = w:get_children_by_id('refresh_button')[1]
refresh_button:buttons(gtable.join {
abutton({}, 1, nil, function()
local wifi_device = networkManager:get_wireless_device()
if not wifi_device then return end
wifi_device:RequestScan(function(ap_list)
self:set_wifi_list(ap_list)
end)
end),
})
do
local wifi_device = networkManager:get_wireless_device()
if not wifi_device then return end
wifi_device:RequestScan(function(ap_list)
self:set_wifi_list(ap_list)
end)
dnd:buttons(gtable.join {
abutton({}, 1, function()
networkManager:toggle_wifi()
end),
})
end
--- Automatically toggle the Wifi toggle when the wifi state changed
networkManager:connect_signal('NetworkManager::WirelessEnabled', function(_, enabled)
if enabled then
dnd:set_enabled()
else
dnd:set_disabled()
end
end)
---TODO:Toggle a general network switch, where should the widget be added?
networkManager:connect_signal('NetworkManager::NetworkingEnabled', function(_, enabled)
--[[ if enabled then
dnd:set_enabled()
else
dnd:set_disabled()
end ]]
end)
--- Automatically delete a lost AP from the list
self.device:connect_signal('NetworkManagerDeviceWireless::AccessPointRemoved', function(_, ap)
self:delete_ap_from_list(ap)
end)
--- Automatically add a new AP to the list, if it is not already in the list
self.device:connect_signal('NetworkManagerDeviceWireless::AccessPointAdded', function(_, ap)
if not self:is_ap_in_list(ap) then
self:add_ap_to_list(ap)
end
end)
--- Automatically resort the list when the active AP changed
--- This is needed because otherwise the active AP would be where the new one currently is in the list
self.device:connect_signal('NetworkManagerDeviceWireless::ActiveAccessPoint', function()
self:resort_wifi_list()
end)
return self
end,
})

View File

@@ -1,377 +0,0 @@
------------------------------------
-- This is the network controller --
------------------------------------
-- Awesome Libs
local abutton = require('awful.button')
local awidget = require('awful.widget')
local beautiful = require('beautiful')
local dpi = require('beautiful').xresources.apply_dpi
local gtable = require('gears').table
local gfilesystem = require('gears').filesystem
local gcolor = require('gears').color
local lgi = require('lgi')
local wibox = require('wibox')
local base = require('wibox.widget.base')
local NM = lgi.NM
-- Third party libs
local dbus_proxy = require('src.lib.lua-dbus_proxy.src.dbus_proxy')
-- Own libs
local ap_form = require('src.modules.network_controller.ap_form')
local cm = require('src.modules.context_menu')
local hover = require('src.tools.hover')
local icondir = gfilesystem.get_configuration_dir() .. 'src/assets/icons/network/'
local access_point = { mt = {} }
local function flags_to_security(flags, wpa_flags, rsn_flags)
local str = ''
if flags == 1 and wpa_flags == 0 and rsn_flags == 0 then
str = str .. ' WEP'
end
if wpa_flags ~= 0 then
str = str .. ' WPA1'
end
if not rsn_flags ~= 0 then
str = str .. ' WPA2'
end
if wpa_flags == 512 or rsn_flags == 512 then
str = str .. ' 802.1X'
end
return (str:gsub('^%s', ''))
end
function access_point:get_access_point_connections(ssid)
local cn = {}
local connections = self.NetworkManagerSettings:ListConnections()
for _, connection_path in ipairs(connections) do
local NetworkManagerSettingsConnection = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = 'org.freedesktop.NetworkManager',
interface = 'org.freedesktop.NetworkManager.Settings.Connection',
path = connection_path,
}
if NetworkManagerSettingsConnection.Filename:find(ssid) then
table.insert(cn, NetworkManagerSettingsConnection)
end
end
return cn
end
function access_point:create_profile(ap, password, auto_connect)
local s_wsec = {}
local security = flags_to_security(ap.Flags, ap.WpaFlags, ap.RsnFlags)
if security ~= '' then
if security:match('WPA') then
s_wsec['key-mgmt'] = lgi.GLib.Variant('s', 'wpa-psk')
s_wsec['auth-alg'] = lgi.GLib.Variant('s', 'open')
s_wsec['psk'] = lgi.GLib.Variant('s', password)
else
s_wsec['key-mgmt'] = lgi.GLib.Variant('s', 'None')
s_wsec['wep-key-type'] = lgi.GLib.Variant('s', NM.WepKeyType.PASSPHRASE)
s_wsec['wep-key0'] = lgi.GLib.Variant('s', password)
end
end
return {
['connection'] = {
-- ["interface-name"] = lgi.GLib.Variant("s", ap.device_interface),
['uuid'] = lgi.GLib.Variant('s', string.gsub('xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx', '[xy]', function(c)
local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb)
return string.format('%x', v)
end)),
['id'] = lgi.GLib.Variant('s', NM.utils_ssid_to_utf8(ap.Ssid)),
['type'] = lgi.GLib.Variant('s', '802-11-wireless'),
['autoconnect'] = lgi.GLib.Variant('b', auto_connect),
},
['ipv4'] = {
['method'] = lgi.GLib.Variant('s', 'auto'),
},
['ipv6'] = {
['method'] = lgi.GLib.Variant('s', 'auto'),
},
['802-11-wireless'] = {
['mode'] = lgi.GLib.Variant('s', 'infrastructure'),
},
['802-11-wireless-security'] = s_wsec,
}
end
function access_point:disconnect()
self.NetworkManager:DeactivateConnection(self.NetworkManagerDevice.ActiveConnection)
end
function access_point:connect(ap, password, auto_connect)
local connections = self:get_access_point_connections(NM.utils_ssid_to_utf8(ap.Ssid))
local profile = self:create_profile(self.NetworkManagerAccessPoint, password, auto_connect)
if #connections == 0 then
self.NetworkManager:AddAndActivateConnectionAsync(function(proxy, context, success, fail)
if fail ~= nil then
self:emit_signal('NetworkManager::failed', tostring(fail), tostring(fail.code))
return
end
self:emit_signal('NetworkManager::connected', success)
end, { call_id = 'my-id' }, profile, self.NetworkManagerDevice.object_path,
self.NetworkManagerAccessPoint.object_path)
--88ALYLNxo9Kk*RwRxMfN
else
connections[1]:Update(profile)
self.NetworkManager:ActivateConnectionAsync(function(proxy, context, success, failure)
if failure then
self:emit_signal('NM::AccessPointFailed', tostring(failure))
return
end
self:emit_signal('NM::AccessPointConnected', NM.utils_ssid_to_utf8(ap.Ssid))
end,
{ call_id = 'my-id' }, connections[1].object_path, self.NetworkManagerDevice.object_path,
self.NetworkManagerAccessPoint.object_path)
end
end
function access_point:toggle_connection(ap, password, auto_connect)
if self:is_ap_active(ap) then
self:disconnect()
else
self:connect(ap, password, auto_connect)
end
end
function access_point:is_ap_active(ap)
return ap.object_path == self.NetworkManagerDeviceWireless.ActiveAccessPoint
end
function access_point.new(args)
args = args or {}
if not args.NetworkManagerAccessPoint then return end
local ssid_text = awidget.inputbox {
text = NM.utils_ssid_to_utf8(args.NetworkManagerAccessPoint.Ssid) or
args.NetworkManagerAccessPoint.hw_address or 'Unknown',
halign = 'left',
valign = 'center',
}
local ret = base.make_widget_from_value(wibox.widget {
{
{
{
{
{
image = gcolor.recolor_image(
icondir .. 'wifi-strength-' .. math.floor(args.NetworkManagerAccessPoint.Strength / 25) + 1 .. '.svg',
beautiful.colorscheme.bg_red),
id = 'icon',
resize = true,
valign = 'center',
halign = 'center',
forced_width = dpi(24),
forced_height = dpi(24),
widget = wibox.widget.imagebox,
},
id = 'icon_container',
strategy = 'max',
width = dpi(24),
height = dpi(24),
widget = wibox.container.constraint,
},
{
{
ssid_text,
widget = wibox.container.constraint,
strategy = 'exact',
width = dpi(300),
id = 'alias',
},
width = dpi(260),
height = dpi(40),
strategy = 'max',
widget = wibox.container.constraint,
},
spacing = dpi(10),
layout = wibox.layout.fixed.horizontal,
},
{ -- Spacing
forced_width = dpi(10),
widget = wibox.container.background,
},
{
{
{
{
id = 'con',
resize = false,
valign = 'center',
halign = 'center',
forced_width = dpi(24),
forced_height = dpi(24),
widget = wibox.widget.imagebox,
},
id = 'place',
strategy = 'max',
width = dpi(24),
height = dpi(24),
widget = wibox.container.constraint,
},
id = 'margin',
margins = dpi(2),
widget = wibox.container.margin,
},
id = 'margin0',
margin = dpi(5),
widget = wibox.container.margin,
},
id = 'device_layout',
layout = wibox.layout.align.horizontal,
},
id = 'device_margin',
margins = dpi(5),
widget = wibox.container.margin,
},
bg = beautiful.colorscheme.bg,
fg = beautiful.colorscheme.bg_red,
border_color = beautiful.colorscheme.border_color,
border_width = dpi(2),
id = 'background',
shape = beautiful.shape[8],
widget = wibox.container.background,
})
assert(type(ret) == 'table', 'access_point:ret is not a table')
gtable.crush(ret, access_point, true)
ret.NetworkManagerAccessPoint = args.NetworkManagerAccessPoint
ret.NetworkManagerSettings = args.NetworkManagerSettings
ret.NetworkManagerDeviceWireless = args.NetworkManagerDeviceWireless
ret.NetworkManagerDevice = args.NetworkManagerDevice
ret.NetworkManager = args.NetworkManager
ret.NetworkManagerAccessPointProperties = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = 'org.freedesktop.NetworkManager',
interface = 'org.freedesktop.DBus.Properties',
path = ret.NetworkManagerAccessPoint.object_path,
}
-- Update the access point strength
ret.NetworkManagerAccessPointProperties:connect_signal(function(_, properties, data)
if data.Strength then
awesome.emit_signal('NM::AccessPointStrength', data.Strength)
if ret.is_ap_active(ret.NetworkManagerAccessPoint) then
ret:get_children_by_id('icon')[1].image = gcolor.recolor_image(
icondir .. 'wifi-strength-' .. math.floor(data.Strength / 25) + 1 .. '.svg',
beautiful.colorscheme.bg)
else
ret:get_children_by_id('icon')[1].image = gcolor.recolor_image(
icondir .. 'wifi-strength-' .. math.floor(data.Strength / 25) + 1 .. '.svg',
beautiful.colorscheme.bg_red)
end
end
end, 'PropertiesChanged')
if ret:is_ap_active(ret.NetworkManagerAccessPoint) then
ret.bg = beautiful.colorscheme.bg_red
ret.fg = beautiful.colorscheme.bg
ret:get_children_by_id('icon')[1].image = gcolor.recolor_image(
icondir .. 'wifi-strength-' .. math.floor(ret.NetworkManagerAccessPoint.Strength / 25) + 1 .. '.svg',
beautiful.colorscheme.bg)
ret:get_children_by_id('con')[1].image = gcolor.recolor_image(
icondir .. 'link.svg', beautiful.colorscheme.bg)
else
ret.bg = beautiful.colorscheme.bg
ret.fg = beautiful.colorscheme.bg_red
ret:get_children_by_id('icon')[1].image = gcolor.recolor_image(
icondir .. 'wifi-strength-' .. math.floor(ret.NetworkManagerAccessPoint.Strength / 25) + 1 .. '.svg',
beautiful.colorscheme.bg_red)
ret:get_children_by_id('con')[1].image = gcolor.recolor_image(
icondir .. 'link.svg', beautiful.colorscheme.bg_red)
end
ret.ap_form = ap_form {
screen = args.screen,
NetworkManagerAccessPoint = args.NetworkManagerAccessPoint,
ap = ret,
}
ret.cm = cm {
widget_template = wibox.widget {
{
{
{
{
widget = wibox.widget.imagebox,
resize = true,
valign = 'center',
halign = 'center',
id = 'icon_role',
},
widget = wibox.container.constraint,
stragety = 'exact',
width = dpi(24),
height = dpi(24),
id = 'const',
},
{
widget = wibox.widget.textbox,
valign = 'center',
halign = 'left',
id = 'text_role',
},
layout = wibox.layout.fixed.horizontal,
},
widget = wibox.container.margin,
},
widget = wibox.container.background,
}, spacing = dpi(10),
entries = {
{ -- Connect/Disconnect a device
name = 'ret.device.Connected' and 'Disconnect' or 'Connect',
icon = gcolor.recolor_image('ret.device.Connected' and icondir .. 'link-off.svg' or
icondir .. 'link.svg',
beautiful.colorscheme.bg_red),
callback = function()
ret:toggle_connection(ret.NetworkManagerAccessPoint)
end,
id = 'connected',
},
},
}
ret:buttons(gtable.join(
abutton({}, 1, nil,
function()
if ret:is_ap_active(ret.NetworkManagerAccessPoint) then
ret:disconnect()
else
ret.ap_form:popup_toggle()
end
end
),
abutton({}, 3, nil,
function()
ret.cm:toggle()
end
)
))
hover.bg_hover { widget = ret }
return ret
end
function access_point.mt:__call(...)
return access_point.new(...)
end
return setmetatable(access_point, access_point.mt)

View File

@@ -1,244 +0,0 @@
local abutton = require('awful.button')
local aplacement = require('awful.placement')
local apopup = require('awful.popup')
local awidget = require('awful.widget')
local beautiful = require('beautiful')
local dpi = require('beautiful').xresources.apply_dpi
local gtable = require('gears.table')
local gcolor = require('gears.color')
local gshape = require('gears.shape')
local gfilesystem = require('gears.filesystem')
local NM = require('lgi').NM
local wibox = require('wibox')
local hover = require('src.tools.hover')
local icondir = gfilesystem.get_configuration_dir() .. 'src/assets/icons/network/'
local capi = {
awesome = awesome,
mouse = mouse,
mousegrabber = mousegrabber,
}
local ap_form = { mt = {} }
function ap_form:popup_toggle()
self.visible = not self.visible
end
function ap_form.new(args)
args = args or {}
args.screen = args.screen
local password = awidget.inputbox { hint_text = 'Password...' }
local ret = apopup {
widget = {
{
{ -- Header
{
nil,
{
{
widget = wibox.widget.textbox,
text = NM.utils_ssid_to_utf8(args.NetworkManagerAccessPoint.Ssid),
font = beautiful.user_config.font .. ' extra bold 16',
halign = 'center',
valign = 'center',
},
widget = wibox.container.margin,
margins = dpi(5),
},
{ -- Close button
{
{
widget = wibox.widget.imagebox,
image = gcolor.recolor_image(icondir .. 'close.svg', beautiful.colorscheme.bg),
resize = false,
valign = 'center',
halign = 'center',
},
widget = wibox.container.margin,
margins = dpi(5),
},
widget = wibox.container.background,
shape = beautiful.shape[8],
id = 'close_button',
bg = beautiful.colorscheme.bg_red,
},
layout = wibox.layout.align.horizontal,
},
widget = wibox.container.background,
bg = beautiful.colorscheme.bg,
fg = beautiful.colorscheme.bg_red,
},
{ -- Form
{ -- Password
widget = wibox.widget.textbox,
text = 'Password',
halign = 'center',
valign = 'center',
},
{
widget = wibox.container.margin,
left = dpi(20),
right = dpi(20),
},
-- Change to inputtextbox container
{
{
{
password,
widget = wibox.container.margin,
margins = 5,
id = 'marg',
},
widget = wibox.container.constraint,
strategy = 'exact',
width = 400,
height = 50,
id = 'const',
},
widget = wibox.container.background,
bg = beautiful.colorscheme.bg,
fg = beautiful.colorscheme.fg,
border_color = beautiful.colorscheme.border_color,
border_width = dpi(2),
shape = gshape.rounded_rect,
forced_width = 300,
forced_height = 50,
id = 'password_container',
},
layout = wibox.layout.align.horizontal,
},
{ -- Actions
{ -- Auto connect
{
{
{
checked = false,
shape = beautiful.shape[4],
color = beautiful.colorscheme.bg,
paddings = dpi(3),
check_color = beautiful.colorscheme.bg_red,
border_color = beautiful.colorscheme.bg_red,
border_width = dpi(2),
id = 'checkbox',
widget = wibox.widget.checkbox,
},
widget = wibox.container.constraint,
strategy = 'exact',
width = dpi(30),
height = dpi(30),
},
widget = wibox.container.place,
halign = 'center',
valign = 'center',
},
{
widget = wibox.widget.textbox,
text = 'Auto connect',
halign = 'center',
valign = 'center',
},
spacing = dpi(10),
layout = wibox.layout.fixed.horizontal,
},
nil,
{ -- Connect
{
{
{
widget = wibox.widget.textbox,
text = 'Connect',
halign = 'center',
valign = 'center',
},
widget = wibox.container.margin,
margins = dpi(10),
},
widget = wibox.container.background,
bg = beautiful.colorscheme.bg_blue,
fg = beautiful.colorscheme.bg,
shape = beautiful.shape[8],
id = 'connect_button',
},
widget = wibox.container.margin,
margins = dpi(10),
},
layout = wibox.layout.align.horizontal,
},
spacing = dpi(20),
layout = wibox.layout.fixed.vertical,
},
widget = wibox.container.margin,
margins = dpi(10),
},
placement = aplacement.centered,
ontop = true,
visible = false,
width = dpi(600),
height = dpi(400),
bg = beautiful.colorscheme.bg,
fg = beautiful.colorscheme.fg,
border_color = beautiful.colorscheme.border_color,
border_width = dpi(2),
type = 'dialog',
screen = args.screen,
}
local password_container = ret.widget:get_children_by_id('password_container')[1]
gtable.crush(ret, ap_form, true)
-- Focus the searchbar when its left clicked
password_container:buttons(gtable.join {
abutton({}, 1, function()
password:focus()
end),
})
--#region Hover signals to change the cursor to a text cursor
local old_cursor, old_wibox
password_container:connect_signal('mouse::enter', function()
local wid = capi.mouse.current_wibox
if wid then
old_cursor, old_wibox = wid.cursor, wid
wid.cursor = 'xterm'
end
end)
password_container:connect_signal('mouse::leave', function()
old_wibox.cursor = old_cursor
old_wibox = nil
end)
--#endregion
local checkbox = ret.widget:get_children_by_id('checkbox')[1]
checkbox:connect_signal('button::press', function()
checkbox.checked = not checkbox.checked
end)
local close_button = ret.widget:get_children_by_id('close_button')[1]
close_button:connect_signal('button::press', function()
ret:popup_toggle()
end)
hover.bg_hover { widget = close_button }
local connect_button = ret.widget:get_children_by_id('connect_button')[1]
connect_button:connect_signal('button::press', function()
password:stop()
args.ap:connect(args.NetworkManagerAccessPoint, password:get_text(),
ret.widget:get_children_by_id('checkbox')[1].checked)
ret:popup_toggle()
end)
hover.bg_hover { widget = connect_button }
return ret
end
function ap_form.mt:__call(...)
return ap_form.new(...)
end
return setmetatable(ap_form, ap_form.mt)

View File

@@ -1,488 +0,0 @@
------------------------------------
-- This is the network controller --
------------------------------------
-- Awesome Libs
local abutton = require('awful.button')
local base = require('wibox.widget.base')
local dbus_proxy = require('src.lib.lua-dbus_proxy.src.dbus_proxy')
local beautiful = require('beautiful')
local dpi = require('beautiful').xresources.apply_dpi
local gcolor = require('gears.color')
local gfilesystem = require('gears.filesystem')
local gshape = require('gears.shape')
local gtable = require('gears.table')
local gtimer = require('gears.timer')
local lgi = require('lgi')
local NM = lgi.NM
local naughty = require('naughty')
local wibox = require('wibox')
-- Third party libs
local rubato = require('src.lib.rubato')
local hover = require('src.tools.hover')
-- Local libs
local access_point = require('src.modules.network_controller.access_point')
local dnd_widget = require('awful.widget.toggle_widget')
local icondir = gfilesystem.get_configuration_dir() .. 'src/assets/icons/network/'
local network = { mt = {} }
network.NMState = {
UNKNOWN = 0,
ASLEEP = 10,
DISCONNECTED = 20,
DISCONNECTING = 30,
CONNECTING = 40,
CONNECTED_LOCAL = 50,
CONNECTED_SITE = 60,
CONNECTED_GLOBAL = 70,
}
network.DeviceType = {
ETHERNET = 1,
WIFI = 2,
}
network.DeviceState = {
UNKNOWN = 0,
UNMANAGED = 10,
UNAVAILABLE = 20,
DISCONNECTED = 30,
PREPARE = 40,
CONFIG = 50,
NEED_AUTH = 60,
IP_CONFIG = 70,
IP_CHECK = 80,
SECONDARIES = 90,
ACTIVATED = 100,
DEACTIVATING = 110,
FAILED = 120,
}
---Get the wifi and or ethernet proxy and connect to their PropertiesChanged signal
-- The signals will return the following
-- wifi: { "Bitrate", "Strength" }
-- ethernet: { "Carrier", "Speed" }
function network:get_active_device()
--Get all devices
local devices = self._private.NetworkManager:GetDevices()
if (not devices) or (#devices == 0) then return end
-- Loop trough every found device
for _, path in ipairs(devices) do
--Create a new proxy for every device
local NetworkManagerDevice = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = 'org.freedesktop.NetworkManager',
interface = 'org.freedesktop.NetworkManager.Device',
path = path,
}
--Check if the device is either a wifi or ethernet device, and if its activated
-- if its activated then its currently in use
if (NetworkManagerDevice.DeviceType == network.DeviceType.WIFI) and
(NetworkManagerDevice.State == network.DeviceState.ACTIVATED) then
-- Set the wifi device as the main device
self._private.NetworkManagerDevice = NetworkManagerDevice
--New wifi proxy to check the bitrate
self._private.NetworkManagerDeviceWireless = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = 'org.freedesktop.NetworkManager',
interface = 'org.freedesktop.NetworkManager.Device.Wireless',
path = path,
}
-- Watch PropertiesChanged and update the bitrate
local NetworkManagerDeviceWirelessProperties = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = 'org.freedesktop.NetworkManager',
interface = 'org.freedesktop.DBus.Properties',
path = self._private.NetworkManagerDeviceWireless.object_path,
}
NetworkManagerDeviceWirelessProperties:connect_signal(function(_, properties, data)
if data.Bitrate then
self:emit_signal('NM::Bitrate', data.Bitrate)
end
end, 'PropertiesChanged')
-- Watch the StateChanged signal, update and notify when a new AP is connected
self._private.NetworkManagerDevice:connect_signal(function(proxy, new_state)
local NetworkManagerAccessPoint = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = 'org.freedesktop.NetworkManager',
interface = 'org.freedesktop.NetworkManager.AccessPoint',
path = self._private.NetworkManagerDeviceWireless.ActiveAccessPoint,
}
if new_state == network.DeviceState.ACTIVATED then
local ssid = NM.utils_ssid_to_utf8(NetworkManagerAccessPoint.Ssid)
self:emit_signal('NM::AccessPointConnected', ssid, NetworkManagerAccessPoint.Strength)
end
end, 'StateChanged')
elseif (NetworkManagerDevice.DeviceType == network.DeviceType.ETHERNET) and
(NetworkManagerDevice.State == network.DeviceState.ACTIVATED) then
self._private.NetworkManagerDevice = NetworkManagerDevice
self._private.NetworkManagerDeviceWired = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = 'org.freedesktop.NetworkManager',
interface = 'org.freedesktop.NetworkManager.Device.Wired',
path = path,
}
if self._private.NetworkManagerDevice.State == network.DeviceState.ACTIVATED then
awesome.emit_signal('NM::EthernetStatus', true, self._private.NetworkManagerDeviceWired.Speed)
end
-- Connect to the StateChanged signal and notify when the wired connection is ready
self._private.NetworkManagerDevice:connect_signal(function(_, new_state)
if new_state == network.DeviceState.ACTIVATED then
awesome.emit_signal('NM::EthernetStatus', true, self._private.NetworkManagerDeviceWired.Speed)
elseif new_state == network.DeviceState.DISCONNECTED then
awesome.emit_signal('NM::EthernetStatus', false)
end
end, 'StateChanged')
end
end
end
function network:get_active_ap_ssid()
local d = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = 'org.freedesktop.NetworkManager',
interface = 'org.freedesktop.NetworkManager.Device.Wireless',
path = self._private.NetworkManagerDeviceWireless.ActiveAccessPoint,
}
return NM.utils_ssid_to_utf8(d.Ssid)
end
---Scan for access points and create a widget for each one.
function network:scan_access_points()
if not self._private.NetworkManagerDeviceWireless then return end
local ap_list = self:get_children_by_id('wifi_ap_list')[1]
ap_list:reset()
local ap_table = {}
self._private.NetworkManagerDeviceWireless:RequestScanAsync(function(_, _, _, failure)
if failure then
naughty.notification {
app_icon = icondir .. 'ethernet.svg',
app_name = 'Network Manager',
title = 'Error: Scan failed!',
message = 'Failed to scan for access points.\n' .. failure,
icon = gcolor.recolor_image(icondir .. 'ethernet.svg', beautiful.colorscheme.bg),
timeout = 5,
}
return
end
-- Get every access point even those who hide their ssid
for _, ap in ipairs(self._private.NetworkManagerDeviceWireless:GetAllAccessPoints()) do
-- Create a new proxy for every ap
local NetworkManagerAccessPoint = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = 'org.freedesktop.NetworkManager',
interface = 'org.freedesktop.NetworkManager.AccessPoint',
path = ap,
}
-- We are only interested in those with a ssid
if NM.utils_ssid_to_utf8(NetworkManagerAccessPoint.Ssid) and NetworkManagerAccessPoint.Strength then
if (ap_table[NetworkManagerAccessPoint.Ssid] == nil) or
NetworkManagerAccessPoint.Strength > ap_table[NetworkManagerAccessPoint.Ssid].Strength then
ap_table[NetworkManagerAccessPoint.Ssid] = NetworkManagerAccessPoint
end
end
end
--sort ap_table first by strength
local sorted_ap_table = {}
for _, NetworkManagerAccessPoint in pairs(ap_table) do
table.insert(sorted_ap_table, NetworkManagerAccessPoint)
end
--sort the table by strength but have the active_ap at the top
table.sort(sorted_ap_table, function(a, b)
if a.object_path == self._private.NetworkManagerDeviceWireless.ActiveAccessPoint then
return true
else
return a.Strength > b.Strength
end
end)
for _, NetworkManagerAccessPoint in ipairs(sorted_ap_table) do
ap_list:add(access_point {
NetworkManagerAccessPoint = NetworkManagerAccessPoint,
NetworkManagerDevice = self._private.NetworkManagerDevice,
NetworkManagerSettings = self._private.NetworkManagerSettings,
NetworkManager = self._private.NetworkManager,
NetworkManagerDeviceWireless = self._private.NetworkManagerDeviceWireless,
})
end
end, { call_id = 'my-id' }, {})
end
---Toggles networking on or off
function network:toggle_wifi()
local enable = not self._private.NetworkManager.WirelessEnabled
self._private.NetworkManager:Set('org.freedesktop.NetworkManager', 'WirelessEnabled', lgi.GLib.Variant('b', enable))
self._private.NetworkManager.WirelessEnabled = { signature = 'b', value = enable }
end
function network.new(args)
args = args or {}
local ret = base.make_widget_from_value(wibox.widget {
{
{
{
{
{
{
{
{
resize = false,
image = gcolor.recolor_image(icondir .. 'menu-down.svg',
beautiful.colorscheme.bg_red),
widget = wibox.widget.imagebox,
valign = 'center',
halign = 'center',
id = 'icon',
},
id = 'center',
halign = 'center',
valign = 'center',
widget = wibox.container.place,
},
{
{
text = 'Wifi Networks',
widget = wibox.widget.textbox,
id = 'ap_name',
},
margins = dpi(5),
widget = wibox.container.margin,
},
id = 'wifi',
layout = wibox.layout.fixed.horizontal,
},
id = 'wifi_bg',
bg = beautiful.colorscheme.bg1,
fg = beautiful.colorscheme.bg_red,
shape = beautiful.shape[4],
widget = wibox.container.background,
},
id = 'wifi_margin',
widget = wibox.container.margin,
},
{
id = 'wifi_list',
{
{
step = dpi(50),
spacing = dpi(10),
layout = require('src.lib.overflow_widget.overflow').vertical,
scrollbar_width = 0,
id = 'wifi_ap_list',
},
id = 'margin',
margins = dpi(10),
widget = wibox.container.margin,
},
border_color = beautiful.colorscheme.border_color,
border_width = dpi(2),
shape = function(cr, width, height)
gshape.partially_rounded_rect(cr, width, height, false, false, true, true, dpi(4))
end,
widget = wibox.container.background,
forced_height = 0,
},
{
{ -- action buttons
{
dnd_widget {
color = beautiful.colorscheme.bg_red,
size = dpi(40),
},
id = 'dnd',
widget = wibox.container.place,
valign = 'center',
halign = 'center',
},
nil,
{ -- refresh
{
{
image = gcolor.recolor_image(icondir .. 'refresh.svg',
beautiful.colorscheme.bg_red),
resize = false,
valign = 'center',
halign = 'center',
widget = wibox.widget.imagebox,
id = 'icon',
},
widget = wibox.container.margin,
margins = dpi(5),
id = 'center',
},
border_width = dpi(2),
border_color = beautiful.colorscheme.border_color,
shape = beautiful.shape[4],
bg = beautiful.colorscheme.bg,
widget = wibox.container.background,
id = 'refresh',
},
layout = wibox.layout.align.horizontal,
},
widget = wibox.container.margin,
top = dpi(10),
id = 'action_buttons',
},
id = 'layout1',
layout = wibox.layout.fixed.vertical,
},
id = 'margin',
margins = dpi(15),
widget = wibox.container.margin,
},
shape = beautiful.shape[8],
border_color = beautiful.colorscheme.border_color,
border_width = dpi(2),
bg = beautiful.colorscheme.bg,
id = 'background',
widget = wibox.container.background,
},
width = dpi(400),
strategy = 'exact',
widget = wibox.container.constraint,
})
assert(type(ret) == 'table', 'NetworkManager is not running')
local dnd = ret:get_children_by_id('dnd')[1]:get_widget()
dnd:connect_signal('dnd::toggle', function(enable)
ret:toggle_wifi()
end)
gtable.crush(ret, network, true)
--#region Wifi Proxies
ret._private.NetworkManager = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = 'org.freedesktop.NetworkManager',
interface = 'org.freedesktop.NetworkManager',
path = '/org/freedesktop/NetworkManager',
}
ret._private.NetworkManagerSettings = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = 'org.freedesktop.NetworkManager',
interface = 'org.freedesktop.NetworkManager.Settings',
path = '/org/freedesktop/NetworkManager/Settings',
}
ret._private.NetworkManagerProperties = dbus_proxy.Proxy:new {
bus = dbus_proxy.Bus.SYSTEM,
name = 'org.freedesktop.NetworkManager',
interface = 'org.freedesktop.DBus.Properties',
path = '/org/freedesktop/NetworkManager',
}
ret._private.NetworkManagerProperties:connect_signal(function(_, properties, data)
if data.WirelessEnabled ~= nil and ret._private.WirelessEnabled ~= data.WirelessEnabled then
ret._private.WirelessEnabled = data.WirelessEnabled
if ret._private.WirelessEnabled then
dnd:set_enabled()
else
dnd:set_disabled()
end
ret:emit_signal('NetworkManager::status', ret._private.WirelessEnabled)
if data.WirelessEnabled then
gtimer {
timeout = 5,
autostart = true,
call_now = false,
single_shot = true,
callback = function()
ret:scan_access_points()
end,
}
end
end
end, 'PropertiesChanged')
ret:get_active_device()
ret:scan_access_points()
if ret._private.NetworkManager.WirelessEnabled then
dnd:set_enabled()
else
dnd:set_disabled()
end
--#endregion
--#region Dropdown logic
local wifi_margin = ret:get_children_by_id('wifi_margin')[1]
local wifi_list = ret:get_children_by_id('wifi_list')[1]
local wifi = ret:get_children_by_id('wifi')[1].center
local rubato_timer = rubato.timed {
duration = 0.2,
pos = wifi_list.forced_height,
easing = rubato.linear,
subscribed = function(v)
wifi_list.forced_height = v
end,
}
wifi_margin:buttons(gtable.join(
abutton({}, 1, nil,
function()
if wifi_list.forced_height == 0 then
if not ret:get_children_by_id('wifi_ap_list')[1].children then
return
end
local size = (5 * 49) + 1
size = size > 210 and 210 or size
rubato_timer.target = dpi(size)
wifi_margin.wifi_bg.shape = function(cr, width, height)
gshape.partially_rounded_rect(cr, width, height, true, true, false, false, dpi(4))
end
wifi.icon:set_image(gcolor.recolor_image(icondir .. 'menu-up.svg',
beautiful.colorscheme.bg_red))
else
rubato_timer.target = 0
wifi_margin.wifi_bg.shape = function(cr, width, height)
gshape.partially_rounded_rect(cr, width, height, true, true, true, true, dpi(4))
end
wifi.icon:set_image(gcolor.recolor_image(icondir .. 'menu-down.svg',
beautiful.colorscheme.bg_red))
end
end
)
))
hover.bg_hover { widget = wifi_margin.wifi_bg }
--#endregion
local refresh_button = ret:get_children_by_id('refresh')[1]
refresh_button:buttons(gtable.join(
abutton({}, 1, nil, function()
ret:scan_access_points()
end)
))
hover.bg_hover { widget = refresh_button }
return ret
end
function network.mt:__call(...)
return network.new(...)
end
return setmetatable(network, network.mt)