Public Access
- lib/wifi (host-tested): channel occupancy (neighbour spill, signal weighting, quietest of 1/6/11) and a signal tracker (history, lost detection, click interval) - WifiService: scan results carry BSSID, channel and security; a scan can target one channel for quick tracker refreshes; endListScans() turns the radio back off when Wi-Fi is disabled - Wi-Fi Tools App: networks nearby, channel occupancy bars, signal tracker with clicks (m to mute) - M1 plan: Monitoring-mode views and captures deferred Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
199 lines
7.7 KiB
C++
199 lines
7.7 KiB
C++
#include "wifi_settings_page.h"
|
|
|
|
#include "ui/fonts.h"
|
|
#include "ui/widgets.h"
|
|
|
|
namespace roro {
|
|
|
|
using State = WifiController::State;
|
|
|
|
void WifiSettingsPage::enter() {
|
|
view_ = View::Main;
|
|
forgetDialog_.reset();
|
|
refreshMain();
|
|
}
|
|
|
|
void WifiSettingsPage::refreshMain() { main_.setCount(kFixedRows + saved_.count()); }
|
|
|
|
void WifiSettingsPage::warn(const std::string& text, NotificationLevel level) {
|
|
bus_.publish(Event::withText(EventType::Notification, text.c_str(), static_cast<int32_t>(level)));
|
|
}
|
|
|
|
std::string WifiSettingsPage::statusText() const {
|
|
switch (wifi_.state()) {
|
|
case State::Off: return "Off";
|
|
case State::Scanning: return "Searching...";
|
|
case State::Waiting: return "No saved network in range";
|
|
case State::Connecting: return "Joining " + wifi_.ssid() + "...";
|
|
case State::Connected: return wifi_.ssid() + " (" + std::to_string(wifi_.rssi()) + " dBm)";
|
|
case State::Monitoring: return "Monitoring";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
bool WifiSettingsPage::onKey(const KeyEvent& e) {
|
|
if (forgetDialog_) {
|
|
forgetDialog_->onKey(e);
|
|
if (forgetDialog_->result() == 1) {
|
|
saved_.forget(saved_.at(main_.selected() - kFixedRows).ssid);
|
|
refreshMain();
|
|
}
|
|
if (forgetDialog_->result() != DialogModel::kPending) forgetDialog_.reset();
|
|
return true;
|
|
}
|
|
|
|
switch (view_) {
|
|
case View::Main:
|
|
switch (e.key) {
|
|
case Key::Up: main_.up(); return true;
|
|
case Key::Down: main_.down(); return true;
|
|
case Key::Back: return false;
|
|
case Key::Left:
|
|
case Key::Right:
|
|
if (main_.selected() != kToggle) return true;
|
|
[[fallthrough]];
|
|
case Key::Select:
|
|
switch (main_.selected()) {
|
|
case kToggle: settings_.setBool(Setting::WifiEnabled, !settings_.getBool(Setting::WifiEnabled)); break;
|
|
case kStatus: break;
|
|
case kAddScanned:
|
|
wifi_.startListScan();
|
|
scan_.setCount(0);
|
|
view_ = View::Scan;
|
|
break;
|
|
case kAddHidden:
|
|
newHidden_ = true;
|
|
editor_ = LineEditor(32);
|
|
view_ = View::Ssid;
|
|
break;
|
|
default: forgetDialog_.reset(new DialogModel({"Cancel", "Forget"})); break;
|
|
}
|
|
return true;
|
|
default: return true;
|
|
}
|
|
|
|
case View::Scan: {
|
|
std::vector<ScanEntry> found;
|
|
for (auto& n : wifi_.listScan())
|
|
if (!n.ssid.empty()) found.push_back(n);
|
|
if (wifi_.listScanDone()) scan_.setCount(static_cast<int>(found.size()));
|
|
switch (e.key) {
|
|
case Key::Up: scan_.up(); break;
|
|
case Key::Down: scan_.down(); break;
|
|
case Key::Back: view_ = View::Main; break;
|
|
case Key::Select:
|
|
if (scan_.selected() < 0) break;
|
|
newSsid_ = found[scan_.selected()].ssid;
|
|
newHidden_ = false;
|
|
if (found[scan_.selected()].open) {
|
|
std::string error = saved_.add(newSsid_, "", false);
|
|
if (!error.empty()) warn(error);
|
|
wifi_.savedNetworksChanged();
|
|
enter();
|
|
} else {
|
|
editor_ = LineEditor(63);
|
|
view_ = View::Password;
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
case View::Ssid:
|
|
case View::Password:
|
|
switch (e.key) {
|
|
case Key::Char: editor_.insert(e.ch); break;
|
|
case Key::Delete: editor_.backspace(); break;
|
|
case Key::Left: editor_.left(); break;
|
|
case Key::Right: editor_.right(); break;
|
|
case Key::Back: enter(); break;
|
|
case Key::Select:
|
|
if (view_ == View::Ssid) {
|
|
newSsid_ = editor_.text();
|
|
editor_ = LineEditor(63);
|
|
view_ = View::Password;
|
|
} else {
|
|
std::string error = saved_.add(newSsid_, editor_.text(), newHidden_);
|
|
if (!error.empty()) {
|
|
warn(error);
|
|
} else {
|
|
warn("Saved " + newSsid_, NotificationLevel::Info);
|
|
wifi_.savedNetworksChanged();
|
|
enter();
|
|
}
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void WifiSettingsPage::draw(Canvas& c) {
|
|
const auto& area = theme::kContent;
|
|
switch (view_) {
|
|
case View::Main:
|
|
widgets::list(
|
|
c, main_, area,
|
|
[this](int i) -> std::string {
|
|
switch (i) {
|
|
case kToggle: return "Wi-Fi";
|
|
case kStatus: return "Status";
|
|
case kAddScanned: return "Add a network";
|
|
case kAddHidden: return "Add a hidden network";
|
|
default: {
|
|
const auto& n = saved_.at(i - kFixedRows);
|
|
return " " + n.ssid + (n.hidden ? " (hidden)" : "");
|
|
}
|
|
}
|
|
},
|
|
[this](int i) -> std::string {
|
|
switch (i) {
|
|
case kToggle: return settings_.getBool(Setting::WifiEnabled) ? "On" : "Off";
|
|
case kStatus: return statusText();
|
|
case kAddScanned:
|
|
case kAddHidden: return ">";
|
|
default: return "";
|
|
}
|
|
});
|
|
if (forgetDialog_ && main_.selected() >= kFixedRows)
|
|
widgets::dialog(c, "Forget network?", saved_.at(main_.selected() - kFixedRows).ssid, *forgetDialog_);
|
|
break;
|
|
|
|
case View::Scan: {
|
|
if (!wifi_.listScanDone()) {
|
|
widgets::textLines(c, {"Scanning..."}, 0, area);
|
|
break;
|
|
}
|
|
std::vector<ScanEntry> found;
|
|
for (auto& n : wifi_.listScan())
|
|
if (!n.ssid.empty()) found.push_back(n);
|
|
if (scan_.count() != static_cast<int>(found.size())) scan_.setCount(static_cast<int>(found.size()));
|
|
if (found.empty()) {
|
|
widgets::textLines(c, {"No networks found.", "", "`: back"}, 0, area);
|
|
break;
|
|
}
|
|
widgets::list(
|
|
c, scan_, area, [&](int i) { return found[i].ssid + (found[i].open ? " (open)" : ""); },
|
|
[&](int i) { return std::to_string(found[i].rssi) + " dBm"; });
|
|
break;
|
|
}
|
|
|
|
case View::Ssid:
|
|
case View::Password: {
|
|
c.setFont(&fonts::body);
|
|
c.setTextColor(theme::kMuted);
|
|
std::string title = view_ == View::Ssid ? "Hidden network name" : "Password for " + newSsid_;
|
|
c.drawString(title.c_str(), 4, area.y + 4);
|
|
widgets::lineEditor(c, editor_, {4, area.y + 22, area.w - 8, 0});
|
|
c.drawString(view_ == View::Ssid ? "Enter: next `: cancel" : "Enter: save (empty = open) `: cancel", 4,
|
|
area.y + 44);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace roro
|