Refactor submenu creation logic
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "MappedInputManager.h"
|
||||
#include "components/UITheme.h"
|
||||
#include "settings/SettingsSubmenuActivity.h"
|
||||
|
||||
void MenuListActivity::initMenuList() {
|
||||
const int count = static_cast<int>(menuItems.size());
|
||||
@@ -16,6 +17,10 @@ void MenuListActivity::initMenuList() {
|
||||
|
||||
void MenuListActivity::onEnter() {
|
||||
Activity::onEnter();
|
||||
if (!submenusPrepared) {
|
||||
prepareSubmenus();
|
||||
submenusPrepared = true;
|
||||
}
|
||||
initMenuList();
|
||||
requestUpdate();
|
||||
}
|
||||
@@ -37,6 +42,10 @@ void MenuListActivity::toggleCurrentItem() {
|
||||
if (item.isSeparator) return;
|
||||
|
||||
if (item.type == SettingType::ACTION) {
|
||||
if (item.action == SettingAction::Submenu) {
|
||||
openSubmenu(item);
|
||||
return;
|
||||
}
|
||||
onActionSelected(selectedIndex);
|
||||
return;
|
||||
}
|
||||
@@ -55,6 +64,18 @@ void MenuListActivity::drawMenuList(const Rect& rect) {
|
||||
[this](int index) { return getItemValueString(index); }, true);
|
||||
}
|
||||
|
||||
void MenuListActivity::prepareSubmenus() { SettingInfo::prepareSubmenus(menuItems, submenuData); }
|
||||
|
||||
void MenuListActivity::openSubmenu(const SettingInfo& submenuEntry) {
|
||||
auto it = std::find_if(submenuData.begin(), submenuData.end(),
|
||||
[&submenuEntry](const SettingInfo::SubmenuData& d) { return d.id == submenuEntry.nameId; });
|
||||
if (it == submenuData.end()) return;
|
||||
|
||||
startActivityForResult(
|
||||
std::make_unique<SettingsSubmenuActivity>(renderer, mappedInput, submenuEntry.nameId, it->items),
|
||||
[this](const ActivityResult&) { requestUpdate(); });
|
||||
}
|
||||
|
||||
void MenuListActivity::loop() {
|
||||
if (mappedInput.wasPressed(MappedInputManager::Button::Back)) {
|
||||
onBackPressed();
|
||||
|
||||
@@ -70,12 +70,18 @@ struct Rect;
|
||||
class MenuListActivity : public Activity {
|
||||
protected:
|
||||
std::vector<SettingInfo> menuItems;
|
||||
std::vector<SettingInfo::SubmenuData> submenuData;
|
||||
int selectedIndex = 0;
|
||||
ButtonNavigator buttonNavigator;
|
||||
bool submenusPrepared = false;
|
||||
|
||||
// Call after building/rebuilding menuItems to wire up the selectable predicate.
|
||||
void initMenuList();
|
||||
|
||||
// Process SettingInfo items marked with withSubmenu() into submenu placeholders.
|
||||
void prepareSubmenus();
|
||||
void openSubmenu(const SettingInfo& submenuEntry);
|
||||
|
||||
// Handle up/down navigation via buttonNavigator. Call from loop() if overriding.
|
||||
void handleNavigation();
|
||||
|
||||
|
||||
@@ -252,8 +252,12 @@ std::string EpubReaderMenuActivity::getItemValueString(int index) const {
|
||||
return currentPageStarred ? std::string(tr(STR_STATE_ON)) : std::string(tr(STR_STATE_OFF));
|
||||
}
|
||||
|
||||
// Plain ACTION items (select chapter, screenshot, etc.) show no value
|
||||
if (item.type == SettingType::ACTION) return {};
|
||||
// Plain ACTION items (select chapter, screenshot, etc.) show no value.
|
||||
// Submenu placeholders should still show the standard submenu indicator.
|
||||
if (item.type == SettingType::ACTION) {
|
||||
if (item.action == SettingAction::Submenu) return MenuListActivity::getItemValueString(index);
|
||||
return {};
|
||||
}
|
||||
|
||||
// DynamicEnum items use the standard display
|
||||
return MenuListActivity::getItemValueString(index);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
#include <I18n.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -88,6 +90,13 @@ struct SettingInfo {
|
||||
stringSetter(accessorCtx, v);
|
||||
}
|
||||
|
||||
struct SubmenuData {
|
||||
StrId id = StrId::STR_NONE_OPT;
|
||||
std::vector<SettingInfo> items;
|
||||
};
|
||||
|
||||
static void prepareSubmenus(std::vector<SettingInfo>& items, std::vector<SubmenuData>& submenuData);
|
||||
|
||||
SettingInfo& withObfuscated() {
|
||||
obfuscated = true;
|
||||
return *this;
|
||||
@@ -237,3 +246,41 @@ struct SettingInfo {
|
||||
// not the SettingInfo itself.
|
||||
void toggleValue() const;
|
||||
};
|
||||
|
||||
inline void SettingInfo::prepareSubmenus(std::vector<SettingInfo>& items,
|
||||
std::vector<SettingInfo::SubmenuData>& submenuData) {
|
||||
if (items.empty()) return;
|
||||
|
||||
std::vector<SettingInfo> preparedItems;
|
||||
std::vector<SubmenuData> preparedSubmenus;
|
||||
preparedItems.reserve(items.size());
|
||||
|
||||
for (auto& item : items) {
|
||||
if (item.submenu == StrId::STR_NONE_OPT) {
|
||||
preparedItems.push_back(std::move(item));
|
||||
continue;
|
||||
}
|
||||
|
||||
auto it = std::find_if(preparedSubmenus.begin(), preparedSubmenus.end(),
|
||||
[&item](const SubmenuData& d) { return d.id == item.submenu; });
|
||||
if (it == preparedSubmenus.end()) {
|
||||
preparedItems.push_back(SettingInfo::SubmenuEntry(item.submenu));
|
||||
preparedSubmenus.push_back({item.submenu, {}});
|
||||
it = preparedSubmenus.end() - 1;
|
||||
}
|
||||
it->items.push_back(std::move(item));
|
||||
}
|
||||
|
||||
items.swap(preparedItems);
|
||||
|
||||
for (auto& submenu : preparedSubmenus) {
|
||||
auto it = std::find_if(submenuData.begin(), submenuData.end(),
|
||||
[&submenu](const SubmenuData& d) { return d.id == submenu.id; });
|
||||
if (it == submenuData.end()) {
|
||||
submenuData.push_back(std::move(submenu));
|
||||
} else {
|
||||
it->items.insert(it->items.end(), std::make_move_iterator(submenu.items.begin()),
|
||||
std::make_move_iterator(submenu.items.end()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,33 +41,19 @@ void SettingsActivity::onEnter() {
|
||||
StrId lastControlsSub = StrId::STR_NONE_OPT;
|
||||
StrId lastSystemSub = StrId::STR_NONE_OPT;
|
||||
|
||||
// Shared placement logic — locates submenu target or inserts separator.
|
||||
// Returns the vector the caller should push into (either `vec` or a submenu's items).
|
||||
auto locateTarget = [this](std::vector<SettingInfo>& vec, StrId& lastSub,
|
||||
const SettingInfo& s) -> std::vector<SettingInfo>* {
|
||||
if (s.submenu != StrId::STR_NONE_OPT) {
|
||||
auto it = std::find_if(submenuData.begin(), submenuData.end(),
|
||||
[&s](const SubmenuData& d) { return d.id == s.submenu; });
|
||||
if (it == submenuData.end()) {
|
||||
vec.push_back(SettingInfo::SubmenuEntry(s.submenu));
|
||||
submenuData.push_back({s.submenu, {}});
|
||||
it = submenuData.end() - 1;
|
||||
}
|
||||
return &it->items;
|
||||
}
|
||||
auto addTo = [](std::vector<SettingInfo>& vec, StrId& lastSub, const SettingInfo& s) {
|
||||
if (s.subcategory != StrId::STR_NONE_OPT && s.subcategory != lastSub) {
|
||||
vec.push_back(SettingInfo::Separator(s.subcategory));
|
||||
lastSub = s.subcategory;
|
||||
}
|
||||
return &vec;
|
||||
vec.push_back(s);
|
||||
};
|
||||
|
||||
auto addTo = [&locateTarget](std::vector<SettingInfo>& vec, StrId& lastSub, const SettingInfo& s) {
|
||||
locateTarget(vec, lastSub, s)->push_back(s);
|
||||
};
|
||||
auto addToMoved = [&locateTarget](std::vector<SettingInfo>& vec, StrId& lastSub, SettingInfo&& s) {
|
||||
auto* target = locateTarget(vec, lastSub, s);
|
||||
target->push_back(std::move(s));
|
||||
auto addToMoved = [](std::vector<SettingInfo>& vec, StrId& lastSub, SettingInfo&& s) {
|
||||
if (s.subcategory != StrId::STR_NONE_OPT && s.subcategory != lastSub) {
|
||||
vec.push_back(SettingInfo::Separator(s.subcategory));
|
||||
lastSub = s.subcategory;
|
||||
}
|
||||
vec.push_back(std::move(s));
|
||||
};
|
||||
|
||||
for (const auto& setting : getSettingsList()) {
|
||||
@@ -122,6 +108,11 @@ void SettingsActivity::onEnter() {
|
||||
std::move(SettingInfo::Action(StrId::STR_SYSTEM_INFO, SettingAction::SystemInfo)
|
||||
.withSubcategory(StrId::STR_MENU_SYS_SYSTEM)));
|
||||
|
||||
SettingInfo::prepareSubmenus(displaySettings, submenuData);
|
||||
SettingInfo::prepareSubmenus(readerSettings, submenuData);
|
||||
SettingInfo::prepareSubmenus(controlsSettings, submenuData);
|
||||
SettingInfo::prepareSubmenus(systemSettings, submenuData);
|
||||
|
||||
// Reset selection to first category
|
||||
selectedCategoryIndex = 0;
|
||||
selectedSettingIndex = 0;
|
||||
@@ -226,7 +217,7 @@ void SettingsActivity::toggleCurrentSetting() {
|
||||
|
||||
if (setting.action == SettingAction::Submenu) {
|
||||
auto it = std::find_if(submenuData.begin(), submenuData.end(),
|
||||
[&setting](const SubmenuData& d) { return d.id == setting.nameId; });
|
||||
[&setting](const SettingInfo::SubmenuData& d) { return d.id == setting.nameId; });
|
||||
if (it != submenuData.end()) {
|
||||
startActivityForResult(
|
||||
std::make_unique<SettingsSubmenuActivity>(renderer, mappedInput, setting.nameId, it->items), resultHandler);
|
||||
|
||||
@@ -24,11 +24,7 @@ class SettingsActivity final : public Activity {
|
||||
static constexpr int categoryCount = 4;
|
||||
static const StrId categoryNames[categoryCount];
|
||||
|
||||
struct SubmenuData {
|
||||
StrId id;
|
||||
std::vector<SettingInfo> items;
|
||||
};
|
||||
std::vector<SubmenuData> submenuData;
|
||||
std::vector<SettingInfo::SubmenuData> submenuData;
|
||||
|
||||
void enterCategory(int categoryIndex);
|
||||
void toggleCurrentSetting();
|
||||
|
||||
@@ -9,6 +9,12 @@
|
||||
#include "components/UITheme.h"
|
||||
#include "fontIds.h"
|
||||
|
||||
void SettingsSubmenuActivity::onEnter() {
|
||||
Activity::onEnter();
|
||||
initMenuList();
|
||||
requestUpdate();
|
||||
}
|
||||
|
||||
void SettingsSubmenuActivity::onActionSelected(int index) {
|
||||
const auto& setting = menuItems[index];
|
||||
auto resultHandler = [this](const ActivityResult&) { SETTINGS.saveToFile(); };
|
||||
|
||||
@@ -12,6 +12,7 @@ class SettingsSubmenuActivity final : public MenuListActivity {
|
||||
StrId titleId;
|
||||
|
||||
// MenuListActivity overrides
|
||||
void onEnter() override;
|
||||
void onActionSelected(int index) override;
|
||||
void onSettingToggled(int index) override;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user