#include "apps/debug_console_page.h" #include "debug_auth.h" #include "services/debug_console.h" #include "ui/fonts.h" #include "ui/widgets.h" namespace roro { void DebugConsolePage::enter() { list_.setCount(kRows); confirm_.reset(); typing_ = false; refusal_.clear(); } bool DebugConsolePage::onKey(const KeyEvent& e) { if (confirm_) { confirm_->onKey(e); if (confirm_->result() == 1) { if (ask_ == Ask::SwitchOn) DebugConsole::switchOn(settings_); else settings_.setString(Setting::DebugToken, DebugConsole::freshToken()); } if (confirm_->result() != DialogModel::kPending) confirm_.reset(); return true; } if (typing_) { 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: typing_ = false; break; case Key::Select: { std::string token = debug::tidyToken(editor_.text()); if (debug::validToken(token) && settings_.setString(Setting::DebugToken, token)) typing_ = false; else refusal_ = "16 to 64 characters, please"; break; } default: break; } return true; } switch (e.key) { case Key::Up: list_.up(); break; case Key::Down: list_.down(); break; case Key::Back: return false; case Key::Left: case Key::Right: case Key::Select: if (e.key != Key::Select && list_.selected() != kSwitch) break; switch (list_.selected()) { case kSwitch: if (settings_.getBool(Setting::DebugConsole)) settings_.setBool(Setting::DebugConsole, false); else { // on is the one to think about ask_ = Ask::SwitchOn; confirm_.reset(new DialogModel({"Cancel", "Switch on"})); } break; case kNewToken: ask_ = Ask::NewToken; confirm_.reset(new DialogModel({"Cancel", "New token"})); break; case kTypeToken: editor_ = LineEditor(64); refusal_.clear(); typing_ = true; break; default: break; } break; default: break; } return true; } void DebugConsolePage::help(std::vector& out) const { if (confirm_) return help::dialog(out); if (typing_) return help::textEntry(out); help::list(out, "switch, or open"); out.push_back({", /", "switch the console on or off"}); } void DebugConsolePage::draw(Canvas& c) { const auto& area = theme::kContent; c.setTextDatum(top_left); if (typing_) { c.setFont(&fonts::body); c.setTextColor(theme::kMuted); c.drawString("A token of your own", 4, area.y + 4); widgets::lineEditor(c, editor_, {4, area.y + 22, area.w - 8, 0}); c.setTextColor(refusal_.empty() ? theme::kMuted : theme::kWarning); c.drawString(refusal_.empty() ? "16 to 64 characters. Capitals or not, it's the same." : refusal_.c_str(), 4, area.y + 44); return; } bool on = settings_.getBool(Setting::DebugConsole); std::string ip = wifi_.ip(); widgets::list( c, list_, {area.x, area.y, area.w, kRows * theme::kLineHeight}, [](int i) -> std::string { switch (i) { case kSwitch: return "Debug Console"; case kAddress: return "Connect to"; case kNewToken: return "New token"; default: return "Type a token"; } }, [&](int i) -> std::string { switch (i) { case kSwitch: return on ? "On" : "Off"; case kAddress: return !on ? "-" : ip.empty() ? "Wi-Fi not connected" : ip + ":" + std::to_string(DebugConsole::kPort); default: return ">"; } }); // The token: here, in full, and nowhere else (it's never printed on a console). One the device // made is drawn at twice the size, three groups then two: it has to be read and typed. int y = area.y + kRows * theme::kLineHeight + 4; c.drawFastHLine(4, y - 2, area.w - 8, theme::kMuted); const std::string& token = settings_.getString(Setting::DebugToken); std::string shown = debug::groupToken(token); c.setFont(&fonts::body); if (token.empty()) { c.setTextColor(theme::kMuted); c.drawString("No token yet: one is made when", 4, y + 4); c.drawString("you switch the console on.", 4, y + 4 + theme::kLineHeight); } else if (token.size() <= debug::kTokenChars) { c.setTextColor(theme::kText); c.setTextSize(2); c.drawString(shown.substr(0, 14).c_str(), 4, y + 2); if (shown.size() > 15) c.drawString(shown.substr(15).c_str(), 4, y + 2 + 2 * theme::kLineHeight - 3); c.setTextSize(1); } else { c.setTextColor(theme::kText); for (size_t at = 0; at < shown.size(); at += 35, y += theme::kLineHeight) c.drawString(shown.substr(at, 35).c_str(), 4, y + 2); } c.setFont(&fonts::small); c.setTextColor(on ? theme::kWarning : theme::kMuted); c.drawString(on ? "On this Wi-Fi, the token is full control." : "Off: nothing listens.", 4, area.y + area.h - 9); if (confirm_) { if (ask_ == Ask::SwitchOn) widgets::dialog(c, "Switch it on?", "With the token, anyone on this Wi-Fi can read the console, press keys and copy files.", *confirm_); else widgets::dialog(c, "A new token?", "The one in use stops working, and whoever is connected is cut off.", *confirm_); } } } // namespace roro