Public Access
Settings: its rows in five groups
Settings had grown to 21 rows in one list. It opens on five groups (This device, Display, GNSS and radio, Network, System); Enter opens one, Back returns to the groups, and Back from the groups leaves Settings. SettingsMenu holds the groups and which one is open (host-tested: every setting is in exactly one group). The guide, the how-tos, the README, the scripts' messages and the firmware's own name the new paths, such as "Settings > System > Firmware". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0162FokPdvY2KsS4NBfwyWPk
This commit is contained in:
@@ -16,19 +16,50 @@ struct RowDef {
|
||||
const char* label;
|
||||
};
|
||||
|
||||
const RowDef kRows[] = {
|
||||
{Row::LongName, Kind::Text, "Long name"}, {Row::ShortName, Kind::Text, "Short name"},
|
||||
{Row::Region, Kind::Choice, "Region"}, {Row::Timezone, Kind::Choice, "Timezone"},
|
||||
{Row::Brightness, Kind::Slider, "Brightness"}, {Row::DimTimeout, Kind::Choice, "Dim after"},
|
||||
{Row::OffTimeout, Kind::Choice, "Screen off after"}, {Row::Launcher, Kind::Toggle, "Launcher"},
|
||||
{Row::Theme, Kind::Choice, "Theme"}, {Row::ThemeLight, Kind::Toggle, "Light or dark"}, {Row::Sound, Kind::Toggle, "Sound & LED"},
|
||||
{Row::Gnss, Kind::Toggle, "GNSS"}, {Row::GnssQuiet, Kind::Toggle, "Pause GNSS for LoRa"},
|
||||
{Row::Coordinates, Kind::Toggle, "Coordinates"},
|
||||
{Row::ProbeMacs, Kind::Toggle, "Probe MACs"}, {Row::Wifi, Kind::Page, "Wi-Fi"},
|
||||
{Row::CheckUpdates, Kind::Toggle, "Check for updates"}, {Row::Firmware, Kind::Page, "Firmware"},
|
||||
{Row::Vpn, Kind::Page, "VPN"},
|
||||
{Row::DebugConsole, Kind::Page, "Debug Console"}, {Row::About, Kind::Page, "About"},
|
||||
const RowDef kGroups[] = {
|
||||
{Row::GroupDevice, Kind::Group, "This device"}, {Row::GroupDisplay, Kind::Group, "Display"},
|
||||
{Row::GroupPosition, Kind::Group, "GNSS and radio"}, {Row::GroupNetwork, Kind::Group, "Network"},
|
||||
{Row::GroupSystem, Kind::Group, "System"},
|
||||
};
|
||||
constexpr int kGroupCount = sizeof(kGroups) / sizeof(kGroups[0]);
|
||||
|
||||
struct Member {
|
||||
int group; // an index into kGroups
|
||||
RowDef def;
|
||||
};
|
||||
|
||||
// In the order each group lists them.
|
||||
const Member kRows[] = {
|
||||
{0, {Row::LongName, Kind::Text, "Long name"}},
|
||||
{0, {Row::ShortName, Kind::Text, "Short name"}},
|
||||
{0, {Row::Region, Kind::Choice, "Region"}},
|
||||
{0, {Row::Timezone, Kind::Choice, "Timezone"}},
|
||||
{0, {Row::Sound, Kind::Toggle, "Sound & LED"}},
|
||||
{1, {Row::Brightness, Kind::Slider, "Brightness"}},
|
||||
{1, {Row::DimTimeout, Kind::Choice, "Dim after"}},
|
||||
{1, {Row::OffTimeout, Kind::Choice, "Screen off after"}},
|
||||
{1, {Row::Theme, Kind::Choice, "Theme"}},
|
||||
{1, {Row::ThemeLight, Kind::Toggle, "Light or dark"}},
|
||||
{1, {Row::Launcher, Kind::Toggle, "Launcher"}},
|
||||
{2, {Row::Gnss, Kind::Toggle, "GNSS"}},
|
||||
{2, {Row::GnssQuiet, Kind::Toggle, "Pause GNSS for LoRa"}},
|
||||
{2, {Row::Coordinates, Kind::Toggle, "Coordinates"}},
|
||||
{2, {Row::ProbeMacs, Kind::Toggle, "Probe MACs"}},
|
||||
{3, {Row::Wifi, Kind::Page, "Wi-Fi"}},
|
||||
{3, {Row::Vpn, Kind::Page, "VPN"}},
|
||||
{4, {Row::CheckUpdates, Kind::Toggle, "Check for updates"}},
|
||||
{4, {Row::Firmware, Kind::Page, "Firmware"}},
|
||||
{4, {Row::DebugConsole, Kind::Page, "Debug Console"}},
|
||||
{4, {Row::About, Kind::Page, "About"}},
|
||||
};
|
||||
|
||||
// Row i of what is listed: a group, or the i-th row of the open one.
|
||||
const RowDef& at(int group, int i) {
|
||||
if (group < 0) return kGroups[i < 0 || i >= kGroupCount ? 0 : i];
|
||||
for (const Member& m : kRows)
|
||||
if (m.group == group && i-- == 0) return m.def;
|
||||
return kGroups[group]; // out of range: harmless
|
||||
}
|
||||
|
||||
const int kDimSeconds[] = {10, 15, 30, 60, 120, 300};
|
||||
const int kOffSeconds[] = {30, 60, 120, 300, 600, 1800};
|
||||
@@ -65,10 +96,42 @@ int indexOf(const int (&table)[N], int value) {
|
||||
|
||||
} // namespace
|
||||
|
||||
int SettingsMenu::count() const { return sizeof(kRows) / sizeof(kRows[0]); }
|
||||
SettingsMenu::Row SettingsMenu::row(int i) const { return kRows[i].row; }
|
||||
SettingsMenu::Kind SettingsMenu::kind(int i) const { return kRows[i].kind; }
|
||||
std::string SettingsMenu::label(int i) const { return kRows[i].label; }
|
||||
bool SettingsMenu::open(int i) {
|
||||
if (group_ >= 0 || i < 0 || i >= kGroupCount) return false;
|
||||
group_ = lastGroup_ = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SettingsMenu::close() {
|
||||
if (group_ < 0) return false;
|
||||
group_ = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string SettingsMenu::title() const { return group_ < 0 ? "" : kGroups[group_].label; }
|
||||
|
||||
bool SettingsMenu::reveal(Row r, int& index) {
|
||||
int seen[kGroupCount] = {};
|
||||
for (const Member& m : kRows) {
|
||||
if (m.def.row == r) {
|
||||
group_ = lastGroup_ = m.group;
|
||||
index = seen[m.group];
|
||||
return true;
|
||||
}
|
||||
seen[m.group]++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int SettingsMenu::count() const {
|
||||
if (group_ < 0) return kGroupCount;
|
||||
int n = 0;
|
||||
for (const Member& m : kRows) n += m.group == group_;
|
||||
return n;
|
||||
}
|
||||
SettingsMenu::Row SettingsMenu::row(int i) const { return at(group_, i).row; }
|
||||
SettingsMenu::Kind SettingsMenu::kind(int i) const { return at(group_, i).kind; }
|
||||
std::string SettingsMenu::label(int i) const { return at(group_, i).label; }
|
||||
|
||||
std::string SettingsMenu::value(int i) const {
|
||||
switch (row(i)) {
|
||||
|
||||
@@ -7,15 +7,26 @@
|
||||
|
||||
namespace roro {
|
||||
|
||||
// What the Settings App lists: one row per user-facing setting (plus sub-pages), with readable
|
||||
// values, choice lists and validation messages. Rendering and navigation live in the App.
|
||||
// What the Settings App lists: the groups first, then, with one open, a row per user-facing setting
|
||||
// of that group (plus sub-pages), with readable values, choice lists and validation messages.
|
||||
// Rendering and navigation live in the App. Every index is into what is listed now.
|
||||
class SettingsMenu {
|
||||
public:
|
||||
enum class Row { LongName, ShortName, Region, Timezone, Brightness, DimTimeout, OffTimeout, Launcher, Theme, ThemeLight, Sound, Gnss, GnssQuiet, Coordinates, ProbeMacs, Wifi, CheckUpdates, Firmware, Vpn, DebugConsole, About };
|
||||
enum class Kind { Text, Choice, Toggle, Slider, Page };
|
||||
enum class Row { LongName, ShortName, Region, Timezone, Brightness, DimTimeout, OffTimeout, Launcher, Theme, ThemeLight, Sound, Gnss, GnssQuiet, Coordinates, ProbeMacs, Wifi, CheckUpdates, Firmware, Vpn, DebugConsole, About,
|
||||
GroupDevice, GroupDisplay, GroupPosition, GroupNetwork, GroupSystem };
|
||||
enum class Kind { Text, Choice, Toggle, Slider, Page, Group };
|
||||
|
||||
explicit SettingsMenu(Settings& settings) : settings_(settings) {}
|
||||
|
||||
// The groups are listed until one is opened; close() lists them again.
|
||||
bool open(int i); // false when row i isn't a group
|
||||
bool close(); // false when the groups were listed already
|
||||
bool inGroup() const { return group_ >= 0; }
|
||||
std::string title() const; // the open group's name, or ""
|
||||
int groupIndex() const { return lastGroup_; } // where the group last opened is among the groups
|
||||
// Opens the group a row is in, and says where the row is in it. False for a row there isn't.
|
||||
bool reveal(Row r, int& index);
|
||||
|
||||
int count() const;
|
||||
Row row(int i) const;
|
||||
Kind kind(int i) const;
|
||||
@@ -37,6 +48,7 @@ class SettingsMenu {
|
||||
|
||||
private:
|
||||
Settings& settings_;
|
||||
int group_ = -1, lastGroup_ = 0;
|
||||
};
|
||||
|
||||
} // namespace roro
|
||||
|
||||
@@ -414,8 +414,9 @@ inline constexpr KeyHelp kSystemSystem[] = {
|
||||
// settings: Settings
|
||||
inline constexpr KeyHelp kSettings[] = {
|
||||
{"; .", "up, down"},
|
||||
{"Enter", "edit, or open the page"},
|
||||
{"Enter", "open the group or the page, or edit"},
|
||||
{", /", "change a switch or a slider"},
|
||||
{"`", "back to the groups"},
|
||||
};
|
||||
|
||||
// settings-choice: Settings, a choice
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace roro::gnss {
|
||||
|
||||
// "50.86920° N": five decimals, about a metre.
|
||||
std::string formatDecimal(double degrees, bool latitude);
|
||||
// "50° 52' 09.1\" N" (Settings → Coordinates, Q64).
|
||||
// "50° 52' 09.1\" N" (Settings → GNSS and radio → Coordinates, Q64).
|
||||
std::string formatDms(double degrees, bool latitude);
|
||||
// The 6-character Maidenhead locator ("JO20ef"), as radio amateurs give their square.
|
||||
std::string maidenhead(double latitude, double longitude);
|
||||
|
||||
Reference in New Issue
Block a user