diff --git a/src/wifi_setup_page.cpp b/src/wifi_setup_page.cpp index a06d496..ce289d5 100644 --- a/src/wifi_setup_page.cpp +++ b/src/wifi_setup_page.cpp @@ -3,6 +3,7 @@ #include "provisioning.h" #include #include +#include #include void WiFiSetupPage::onPush(AppState& state) { @@ -123,6 +124,17 @@ void WiFiSetupPage::refreshNetworkState() { savedSsids_ = state_->network.savedNetworks(); networks_ = state_->network.getScanResults(); + if (inputMode_ != InputMode::Normal && !selectedSsid_.empty()) { + // Pin the selection to the SSID while a password is being entered or a + // connection is in progress, so list reordering (strength changes, + // APs appearing/vanishing) cannot silently switch the target network. + auto it = std::find_if(networks_.begin(), networks_.end(), + [this](const radiantwave::network::NetworkInfo& n) { return n.ssid == selectedSsid_; }); + if (it != networks_.end()) { + selectedIndex_ = static_cast(std::distance(networks_.begin(), it)); + } + } + if (selectedIndex_ >= static_cast(networks_.size())) { selectedIndex_ = std::max(0, static_cast(networks_.size()) - 1); } @@ -136,7 +148,15 @@ void WiFiSetupPage::startConnectAsync(const std::string& ssid, const std::string statusMessage_ = "Connecting to " + ssid + "..."; connectFuture_ = std::async(std::launch::async, [this, ssid, password]() { - return state_->network.connect(ssid, password); + // Never let an exception escape the worker thread — a transient + // D-Bus failure must surface as a graceful connection error, not a + // crash when update() calls future.get(). + try { + return state_->network.connect(ssid, password); + } catch (const std::exception& e) { + return radiantwave::network::ConnectResult{ + radiantwave::network::ConnectionState::Failed, e.what(), ""}; + } }); } @@ -158,9 +178,8 @@ void WiFiSetupPage::handleEvent(const SDL_Event& event) { if (state_->window) { SDL_StopTextInput(state_->window); } - if (selectedIndex_ >= 0 && selectedIndex_ < static_cast(networks_.size())) { - std::string ssid = networks_[selectedIndex_].ssid; - startConnectAsync(ssid, passwordInput_); + if (!selectedSsid_.empty()) { + startConnectAsync(selectedSsid_, passwordInput_); } } else if (event.key.key == SDLK_ESCAPE) { if (state_->window) { @@ -190,6 +209,7 @@ void WiFiSetupPage::handleEvent(const SDL_Event& event) { if (net.security == radiantwave::network::SecurityType::Open) { startConnectAsync(net.ssid, ""); } else { + selectedSsid_ = net.ssid; inputMode_ = InputMode::PasswordEntry; passwordInput_ = ""; statusMessage_ = "Type password and press ENTER to submit"; @@ -256,14 +276,22 @@ void WiFiSetupPage::update(float dt) { if (connectInProgress_ && connectFuture_.valid()) { auto status = connectFuture_.wait_for(std::chrono::milliseconds(0)); if (status == std::future_status::ready) { - auto result = connectFuture_.get(); + radiantwave::network::ConnectResult result; + try { + result = connectFuture_.get(); + } catch (const std::exception& e) { + // Backstop: a stray exception must never reach the render + // loop. Convert it to a visible, non-fatal connection error. + result = radiantwave::network::ConnectResult{ + radiantwave::network::ConnectionState::Failed, e.what(), ""}; + } connectInProgress_ = false; if (result.state == radiantwave::network::ConnectionState::Activated) { statusMessage_ = "Connected successfully!"; inputMode_ = InputMode::Normal; } else { - statusMessage_ = "Connection failed: " + (result.error_message.empty() ? "Authentication or signal error" : result.error_message); + statusMessage_ = "Connection failed: " + (result.error_message.empty() ? "Incorrect password or authentication error" : result.error_message); inputMode_ = InputMode::Normal; } refreshNetworkState(); @@ -427,8 +455,8 @@ void WiFiSetupPage::render(SDL_Renderer* renderer) { SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); SDL_RenderRect(renderer, &boxRect); - if (selectedIndex_ >= 0 && selectedIndex_ < static_cast(networks_.size())) { - std::string promptStr = "Enter Password for " + networks_[selectedIndex_].ssid + ":"; + if (!selectedSsid_.empty()) { + std::string promptStr = "Enter Password for " + selectedSsid_ + ":"; passwordPromptText_.ensure(renderer, fontHeader_, promptStr, white); if (passwordPromptText_.texture) { SDL_FRect dst{boxX + 30.0f, boxY + 25.0f, passwordPromptText_.width, passwordPromptText_.height}; diff --git a/src/wifi_setup_page.h b/src/wifi_setup_page.h index 82443d1..0bc76bd 100644 --- a/src/wifi_setup_page.h +++ b/src/wifi_setup_page.h @@ -37,6 +37,7 @@ private: AppState* state_ = nullptr; InputMode inputMode_ = InputMode::Normal; int selectedIndex_ = 0; + std::string selectedSsid_ = ""; std::string passwordInput_ = ""; std::string statusMessage_ = "Press F5 to scan for available networks";