feat: A web editor for settings (#667)
## Summary This is an updated version of @itsthisjustin's #346 that builds on current master and also deduplicates the settings list so we don't have two copies of the settings. In the Web UI, it should organize the settings a little closer to what you see on device. ## Additional Context I tested this live on device and it seems to play nicely for me. It's re-based on master since master's settings stuff has moved somewhat since the original PR and addresses the sole review comment #346 - it also means that I don't need to manually key in the URL for my OPDS server. :) --- ### AI Usage My changes were implemented with Claude Opus 4.5 and Claude Code 2.1.25. I don't know if @itsthisjustin's original work used AI assistance. Co-authored-by: Dave Allie <dave@daveallie.com>
This commit is contained in:
@@ -11,12 +11,12 @@
|
||||
|
||||
class CrossPointSettings;
|
||||
|
||||
enum class SettingType { TOGGLE, ENUM, ACTION, VALUE };
|
||||
enum class SettingType { TOGGLE, ENUM, ACTION, VALUE, STRING };
|
||||
|
||||
struct SettingInfo {
|
||||
const char* name;
|
||||
SettingType type;
|
||||
uint8_t CrossPointSettings::* valuePtr;
|
||||
uint8_t CrossPointSettings::* valuePtr = nullptr;
|
||||
std::vector<std::string> enumValues;
|
||||
|
||||
struct ValueRange {
|
||||
@@ -24,20 +24,100 @@ struct SettingInfo {
|
||||
uint8_t max;
|
||||
uint8_t step;
|
||||
};
|
||||
ValueRange valueRange;
|
||||
ValueRange valueRange = {};
|
||||
|
||||
static SettingInfo Toggle(const char* name, uint8_t CrossPointSettings::* ptr) {
|
||||
return {name, SettingType::TOGGLE, ptr};
|
||||
const char* key = nullptr; // JSON API key (nullptr for ACTION types)
|
||||
const char* category = nullptr; // Category for web UI grouping
|
||||
|
||||
// Direct char[] string fields (for settings stored in CrossPointSettings)
|
||||
char* stringPtr = nullptr;
|
||||
size_t stringMaxLen = 0;
|
||||
|
||||
// Dynamic accessors (for settings stored outside CrossPointSettings, e.g. KOReaderCredentialStore)
|
||||
std::function<uint8_t()> valueGetter;
|
||||
std::function<void(uint8_t)> valueSetter;
|
||||
std::function<std::string()> stringGetter;
|
||||
std::function<void(const std::string&)> stringSetter;
|
||||
|
||||
static SettingInfo Toggle(const char* name, uint8_t CrossPointSettings::* ptr, const char* key = nullptr,
|
||||
const char* category = nullptr) {
|
||||
SettingInfo s;
|
||||
s.name = name;
|
||||
s.type = SettingType::TOGGLE;
|
||||
s.valuePtr = ptr;
|
||||
s.key = key;
|
||||
s.category = category;
|
||||
return s;
|
||||
}
|
||||
|
||||
static SettingInfo Enum(const char* name, uint8_t CrossPointSettings::* ptr, std::vector<std::string> values) {
|
||||
return {name, SettingType::ENUM, ptr, std::move(values)};
|
||||
static SettingInfo Enum(const char* name, uint8_t CrossPointSettings::* ptr, std::vector<std::string> values,
|
||||
const char* key = nullptr, const char* category = nullptr) {
|
||||
SettingInfo s;
|
||||
s.name = name;
|
||||
s.type = SettingType::ENUM;
|
||||
s.valuePtr = ptr;
|
||||
s.enumValues = std::move(values);
|
||||
s.key = key;
|
||||
s.category = category;
|
||||
return s;
|
||||
}
|
||||
|
||||
static SettingInfo Action(const char* name) { return {name, SettingType::ACTION, nullptr}; }
|
||||
static SettingInfo Action(const char* name) {
|
||||
SettingInfo s;
|
||||
s.name = name;
|
||||
s.type = SettingType::ACTION;
|
||||
return s;
|
||||
}
|
||||
|
||||
static SettingInfo Value(const char* name, uint8_t CrossPointSettings::* ptr, const ValueRange valueRange) {
|
||||
return {name, SettingType::VALUE, ptr, {}, valueRange};
|
||||
static SettingInfo Value(const char* name, uint8_t CrossPointSettings::* ptr, const ValueRange valueRange,
|
||||
const char* key = nullptr, const char* category = nullptr) {
|
||||
SettingInfo s;
|
||||
s.name = name;
|
||||
s.type = SettingType::VALUE;
|
||||
s.valuePtr = ptr;
|
||||
s.valueRange = valueRange;
|
||||
s.key = key;
|
||||
s.category = category;
|
||||
return s;
|
||||
}
|
||||
|
||||
static SettingInfo String(const char* name, char* ptr, size_t maxLen, const char* key = nullptr,
|
||||
const char* category = nullptr) {
|
||||
SettingInfo s;
|
||||
s.name = name;
|
||||
s.type = SettingType::STRING;
|
||||
s.stringPtr = ptr;
|
||||
s.stringMaxLen = maxLen;
|
||||
s.key = key;
|
||||
s.category = category;
|
||||
return s;
|
||||
}
|
||||
|
||||
static SettingInfo DynamicEnum(const char* name, std::vector<std::string> values, std::function<uint8_t()> getter,
|
||||
std::function<void(uint8_t)> setter, const char* key = nullptr,
|
||||
const char* category = nullptr) {
|
||||
SettingInfo s;
|
||||
s.name = name;
|
||||
s.type = SettingType::ENUM;
|
||||
s.enumValues = std::move(values);
|
||||
s.valueGetter = std::move(getter);
|
||||
s.valueSetter = std::move(setter);
|
||||
s.key = key;
|
||||
s.category = category;
|
||||
return s;
|
||||
}
|
||||
|
||||
static SettingInfo DynamicString(const char* name, std::function<std::string()> getter,
|
||||
std::function<void(const std::string&)> setter, const char* key = nullptr,
|
||||
const char* category = nullptr) {
|
||||
SettingInfo s;
|
||||
s.name = name;
|
||||
s.type = SettingType::STRING;
|
||||
s.stringGetter = std::move(getter);
|
||||
s.stringSetter = std::move(setter);
|
||||
s.key = key;
|
||||
s.category = category;
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -48,7 +128,13 @@ class SettingsActivity final : public ActivityWithSubactivity {
|
||||
int selectedCategoryIndex = 0; // Currently selected category
|
||||
int selectedSettingIndex = 0;
|
||||
int settingsCount = 0;
|
||||
const SettingInfo* settingsList = nullptr;
|
||||
|
||||
// Per-category settings derived from shared list + device-only actions
|
||||
std::vector<SettingInfo> displaySettings;
|
||||
std::vector<SettingInfo> readerSettings;
|
||||
std::vector<SettingInfo> controlsSettings;
|
||||
std::vector<SettingInfo> systemSettings;
|
||||
const std::vector<SettingInfo>* currentSettings = nullptr;
|
||||
|
||||
const std::function<void()> onGoHome;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user