Skip to content

Commit

Permalink
Implement async Wi-Fi scan and enhance list item
Browse files Browse the repository at this point in the history
  • Loading branch information
deanlee committed Jan 13, 2025
1 parent 643bf09 commit 7eed4ee
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 26 deletions.
36 changes: 30 additions & 6 deletions system/ui/raylib/wifi_manager/nmcli_backend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,48 @@ std::vector<std::string> split(std::string_view source, char delimiter) {
return fields;
}

std::vector<Network> list_wifi_networks() {
SecurityType getSecurityType(const std::string& security) {
if (security.empty() || security == "--") {
return SecurityType::OPEN;
} else if (security.find("WPA") != std::string::npos || security.find("RSN") != std::string::npos) {
return SecurityType::WPA;
}
return SecurityType::UNSUPPORTED;
}
namespace wifi {

std::vector<Network> scan_networks() {
std::vector<Network> networks;
std::string output = util::check_output("nmcli -t -f IN-USE,SSID --colors no device wifi list");

std::string output = util::check_output("nmcli -t -f SSID,IN-USE,SIGNAL,SECURITY --colors no device wifi list");
for (const auto& line : split(output, '\n')) {
auto items = split(line, ':');
if (items.size() != 2 || items[1].empty()) continue;
if (items.size() != 4 || items[0].empty()) continue;

networks.emplace_back(Network{items[0] == "*", items[1]});
networks.emplace_back(Network{items[0], items[1] == "*", std::stoi(items[2]), getSecurityType(items[3])});
}

std::sort(networks.begin(), networks.end(), [](const Network& a, const Network& b) {
return std::tie(b.connected, b.strength, b.ssid) < std::tie(a.connected, a.strength, a.ssid);
});

return networks;
}

bool connect_to_wifi(const std::string& ssid, const std::string& password) {
std::set<std::string> saved_networks() {
std::string cmd = "nmcli -t -f NAME,TYPE --colors no connection show | grep \":802-11-wireless\" | sed 's/^Auto //g' | cut -d':' -f1";
auto networks = split(util::check_output(cmd), '\n');
return std::set<std::string>(networks.begin(), networks.end());
}

bool connect(const std::string& ssid, const std::string& password) {
std::string command = "nmcli device wifi connect '" + ssid + "' password '" + password + "'";
return system(command.c_str()) == 0;
}

bool forget_wifi(const std::string& ssid) {
bool forget(const std::string& ssid) {
std::string command = "nmcli connection delete id '" + ssid + "'";
return system(command.c_str()) == 0;
}

} // namespace wifi
20 changes: 16 additions & 4 deletions system/ui/raylib/wifi_manager/nmcli_backend.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
#pragma once

#include <set>
#include <string>
#include <vector>

enum class SecurityType {
OPEN,
WPA,
UNSUPPORTED
};

struct Network {
bool connected;
std::string ssid;
bool connected;
int strength;
SecurityType security_type;
};

std::vector<Network> list_wifi_networks();
bool connect_to_wifi(const std::string& ssid, const std::string& password);
bool forget_wifi(const std::string& ssid);
namespace wifi {
std::vector<Network> scan_networks();
std::set<std::string> saved_networks();
bool connect(const std::string& ssid, const std::string& password);
bool forget(const std::string& ssid);
} // namespace wifi
53 changes: 40 additions & 13 deletions system/ui/raylib/wifi_manager/wifi_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,27 @@
#include "system/ui/raylib/wifi_manager/wifi_manager.h"
#define RAYGUI_IMPLEMENTATION
#define BLANK RAYLIB_BLANK
#include "third_party/raylib/include/raygui.h"
#include "system/ui/raylib/util.h"
#include <cassert>

#include "system/ui/raylib/util.h"
#include "third_party/raylib/include/raygui.h"
WifiManager::WifiManager() {
auto font = getFont();
font.baseSize = 50;
GuiSetFont(font);
wifi_networks_ = list_wifi_networks();
GuiSetFont(getFont());
GuiSetStyle(DEFAULT, TEXT_SIZE, 40);
GuiSetStyle(DEFAULT, BACKGROUND_COLOR, ColorToInt((Color){30, 30, 30, 255})); // Dark grey background
GuiSetStyle(DEFAULT, BASE_COLOR_NORMAL, ColorToInt((Color){50, 50, 50, 255})); // Dark button background
GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, ColorToInt((Color){200, 200, 200, 255})); // Light grey text

loadWifiNetworksAsync();
}

void WifiManager::draw(const Rectangle& rect) {
std::unique_lock lock(mutex_);
if (wifi_networks_.empty()) {
GuiDrawText("Loading Wi-Fi networks...", rect, TEXT_ALIGN_CENTER, RAYLIB_WHITE);
return;
}

if (is_connecting_) {
showPasswordDialog();
return;
Expand All @@ -26,17 +36,22 @@ void WifiManager::draw(const Rectangle& rect) {
// Draw Wi-Fi networks inside the scrollable area
BeginScissorMode(scissor.x, scissor.y, scissor.width, scissor.height);
for (int i = 0; i < wifi_networks_.size(); ++i) {
// Draw network SSID and buttons for each network
float yPos = i * item_height_ + scroll_offset_.y;
GuiLabel((Rectangle){20, yPos, 500, item_height_}, wifi_networks_[i].ssid.c_str());
if (GuiButton((Rectangle){550, yPos + 2, 80, item_height_ - 4}, "Connect")) {
const auto& network = wifi_networks_[i];

// Draw network SSID and buttons for each network
GuiLabel((Rectangle){20, yPos, 500, item_height_}, network.ssid.c_str());
if (network.connected) {
GuiLabel((Rectangle){550, yPos + 3, 220, item_height_ - 6}, "Connected");
} else if (GuiButton((Rectangle){550, yPos + 3, 180, item_height_ - 6}, "Connect")) {
selected_network_index_ = i;
memset(password_input_, 0, sizeof(password_input_));
is_connecting_ = true;
}
if (GuiButton((Rectangle){670, yPos + 2, 80, item_height_ - 4}, "Forget")) {
forget_wifi(wifi_networks_[i].ssid);
wifi_networks_ = list_wifi_networks(); // Refresh the list
if (saved_networks_.count(network.ssid) && GuiButton((Rectangle){780, yPos + 3, 150, item_height_ - 6}, "Forget")) {
wifi::forget(network.ssid);
saved_networks_.erase(network.ssid);
wifi_networks_ = wifi::scan_networks(); // Refresh the list
}
}
EndScissorMode();
Expand All @@ -50,6 +65,18 @@ void WifiManager::showPasswordDialog() {
("Connect to " + ssid).c_str(), "Password:", "Ok;Cancel", password_input_, 128, NULL);
is_connecting_ = (result < 0);
if (result == 1) {
connect_to_wifi(ssid, password_input_);
wifi::connect(ssid, password_input_);
saved_networks_.insert(ssid);
}
}

void WifiManager::loadWifiNetworksAsync() {
async_task_ = std::async(std::launch::async, [this]() {
auto networks = wifi::scan_networks();
auto known_networks = wifi::saved_networks();

std::unique_lock lock(mutex_);
wifi_networks_.swap(networks);
saved_networks_.swap(known_networks);
});
}
11 changes: 8 additions & 3 deletions system/ui/raylib/wifi_manager/wifi_manager.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#pragma once

#include <string>
#include <vector>
#include <future>
#include <mutex>
#include <thread>

#include "system/ui/raylib/raylib.h"
#include "system/ui/raylib/wifi_manager/nmcli_backend.h"
Expand All @@ -13,11 +14,15 @@ class WifiManager {

protected:
void showPasswordDialog();
void loadWifiNetworksAsync();

std::mutex mutex_;
std::vector<Network> wifi_networks_;
std::set<std::string> saved_networks_;
Vector2 scroll_offset_ = {0, 0};
int selected_network_index_ = 0;
const float item_height_ = 40;
const float item_height_ = 60;
bool is_connecting_ = false;
char password_input_[128] = {};
std::future<void> async_task_;
};

0 comments on commit 7eed4ee

Please sign in to comment.