diff --git a/system/ui/.gitignore b/system/ui/.gitignore index 1d32f7d8777bcf..cc405473cd104f 100644 --- a/system/ui/.gitignore +++ b/system/ui/.gitignore @@ -1 +1,2 @@ spinner +wifi_demo diff --git a/system/ui/SConscript b/system/ui/SConscript index e97282b54e6ad8..2dd790a6f921bb 100644 --- a/system/ui/SConscript +++ b/system/ui/SConscript @@ -21,3 +21,4 @@ if not UBUNTU_FOCAL: if arch != 'aarch64': renv.Program("spinner", ["raylib/spinner.cc"], LIBS=linked_libs, FRAMEWORKS=mac_frameworks) + renv.Program("wifi_demo", ["raylib/wifi_manager/wifi_manager.cc", "raylib/wifi_manager/nmcli_backend.cc", "raylib/wifi_manager/main.cc"], LIBS=linked_libs, FRAMEWORKS=mac_frameworks) diff --git a/system/ui/raylib/wifi_manager/main.cc b/system/ui/raylib/wifi_manager/main.cc new file mode 100644 index 00000000000000..5478f2ba500c24 --- /dev/null +++ b/system/ui/raylib/wifi_manager/main.cc @@ -0,0 +1,17 @@ +#include "system/ui/raylib/util.h" +#include "system/ui/raylib/wifi_manager/wifi_manager.h" + +int main() { + initApp("Wi-Fi Manager", 30); + + WifiManager wifi_manager; + while (!WindowShouldClose()) { + BeginDrawing(); + ClearBackground(RAYLIB_BLACK); + wifi_manager.draw({0, 0, (float)GetScreenWidth(), (float)GetScreenHeight()}); + EndDrawing(); + } + + CloseWindow(); + return 0; +} diff --git a/system/ui/raylib/wifi_manager/nmcli_backend.cc b/system/ui/raylib/wifi_manager/nmcli_backend.cc new file mode 100644 index 00000000000000..510ef7c7bdf6a3 --- /dev/null +++ b/system/ui/raylib/wifi_manager/nmcli_backend.cc @@ -0,0 +1,38 @@ +#include "system/ui/raylib/wifi_manager/nmcli_backend.h" + +#include "common/util.h" + +std::vector split(std::string_view source, char delimiter) { + std::vector fields; + size_t last = 0; + for (size_t i = 0; i < source.length(); ++i) { + if (source[i] == delimiter) { + fields.emplace_back(source.substr(last, i - last)); + last = i + 1; + } + } + fields.emplace_back(source.substr(last)); + return fields; +} + +std::vector list_wifi_networks() { + std::vector networks; + std::string output = util::check_output("nmcli -t -f IN-USE,SSID --colors no device wifi list"); + for (const auto& line : split(output, '\n')) { + auto items = split(line, ':'); + if (items.size() != 2 || items[1].empty()) continue; + + networks.emplace_back(Network{items[0] == "*", items[1]}); + } + return networks; +} + +bool connect_to_wifi(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) { + std::string command = "nmcli connection delete id '" + ssid + "'"; + return system(command.c_str()) == 0; +} diff --git a/system/ui/raylib/wifi_manager/nmcli_backend.h b/system/ui/raylib/wifi_manager/nmcli_backend.h new file mode 100644 index 00000000000000..ce4d405fe7d20f --- /dev/null +++ b/system/ui/raylib/wifi_manager/nmcli_backend.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +struct Network { + bool connected; + std::string ssid; +}; + +std::vector list_wifi_networks(); +bool connect_to_wifi(const std::string& ssid, const std::string& password); +bool forget_wifi(const std::string& ssid); diff --git a/system/ui/raylib/wifi_manager/wifi_manager.cc b/system/ui/raylib/wifi_manager/wifi_manager.cc new file mode 100644 index 00000000000000..8202cb95634f85 --- /dev/null +++ b/system/ui/raylib/wifi_manager/wifi_manager.cc @@ -0,0 +1,53 @@ + +#include "system/ui/raylib/wifi_manager/wifi_manager.h" +#define RAYGUI_IMPLEMENTATION +#include "raygui.h" // Raylib's GUI extension +#include "system/ui/raylib/util.h" + +WifiManager::WifiManager() { + auto font = getFont(); + font.baseSize = 50; + GuiSetFont(font); + wifi_networks_ = list_wifi_networks(); +} + +void WifiManager::draw(const Rectangle& rect) { + if (is_connecting_) { + showPasswordDialog(); + return; + } + + // Handle scrollable panel for displaying Wi-Fi networks + Rectangle content_rect = {0, 0, rect.width - 20, wifi_networks_.size() * item_height_}; + Rectangle scissor = {0}; + GuiScrollPanel(rect, nullptr, content_rect, &scroll_offset_, &scissor); + + BeginScissorMode(scissor.x, scissor.y, scissor.width, scissor.height); + // Draw Wi-Fi networks inside the scrollable area + 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")) { + 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 + } + } + EndScissorMode(); +} + +void WifiManager::showPasswordDialog() { + const auto& ssid = wifi_networks_[selected_network_index_].ssid; + int result = GuiTextInputBox( + (Rectangle){GetScreenWidth() / 2.0f - 120, GetScreenHeight() / 2.0f - 60, 240, 140}, + ("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_); + } +} diff --git a/system/ui/raylib/wifi_manager/wifi_manager.h b/system/ui/raylib/wifi_manager/wifi_manager.h new file mode 100644 index 00000000000000..1335cbdf394201 --- /dev/null +++ b/system/ui/raylib/wifi_manager/wifi_manager.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include "system/ui/raylib/raylib.h" +#include "system/ui/raylib/wifi_manager/nmcli_backend.h" + +class WifiManager { +public: + WifiManager(); + void draw(const Rectangle &rect); + +protected: + void showPasswordDialog(); + + std::vector wifi_networks_; + Vector2 scroll_offset_ = {0, 0}; + int selected_network_index_ = 0; + const float item_height_ = 40; + bool is_connecting_ = false; + char password_input_[128] = {}; +};