#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(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 found; for (auto& n : wifi_.listScan()) if (!n.ssid.empty()) found.push_back(n); if (wifi_.listScanDone()) scan_.setCount(static_cast(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 found; for (auto& n : wifi_.listScan()) if (!n.ssid.empty()) found.push_back(n); if (scan_.count() != static_cast(found.size())) scan_.setCount(static_cast(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