From 2d68ee71da6ab14075c2549aa349e67c9d05bc97 Mon Sep 17 00:00:00 2001 From: Rene Kievits Date: Mon, 15 May 2023 13:02:59 +0200 Subject: [PATCH] rewritten network module, not finished yet --- awesome/src/modules/network/init.lua | 805 ++++++++++++++++++ .../network_controller/access_point.lua | 377 -------- .../modules/network_controller/ap_form.lua | 244 ------ .../src/modules/network_controller/init.lua | 488 ----------- 4 files changed, 805 insertions(+), 1109 deletions(-) create mode 100644 awesome/src/modules/network/init.lua delete mode 100644 awesome/src/modules/network_controller/access_point.lua delete mode 100644 awesome/src/modules/network_controller/ap_form.lua delete mode 100644 awesome/src/modules/network_controller/init.lua diff --git a/awesome/src/modules/network/init.lua b/awesome/src/modules/network/init.lua new file mode 100644 index 0000000..03593cd --- /dev/null +++ b/awesome/src/modules/network/init.lua @@ -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 +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, +}) diff --git a/awesome/src/modules/network_controller/access_point.lua b/awesome/src/modules/network_controller/access_point.lua deleted file mode 100644 index 861eaee..0000000 --- a/awesome/src/modules/network_controller/access_point.lua +++ /dev/null @@ -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) diff --git a/awesome/src/modules/network_controller/ap_form.lua b/awesome/src/modules/network_controller/ap_form.lua deleted file mode 100644 index 19fa642..0000000 --- a/awesome/src/modules/network_controller/ap_form.lua +++ /dev/null @@ -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) diff --git a/awesome/src/modules/network_controller/init.lua b/awesome/src/modules/network_controller/init.lua deleted file mode 100644 index 9517731..0000000 --- a/awesome/src/modules/network_controller/init.lua +++ /dev/null @@ -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)