Add configurable default home screen action

Themes can now specify an initialAction in home screen config to set the default selected action when entering home normally. Falls back to this theme setting when no explicit action is requested, but explicit firmware navigation still takes precedence.
This commit is contained in:
Justin Mitchell
2026-06-28 02:38:53 -04:00
parent 48aa3c8e02
commit 79f5657fb2
4 changed files with 28 additions and 3 deletions
+8
View File
@@ -217,6 +217,14 @@ Home `navigation` modes:
- `splitAxis`: front left/right move through launcher actions; side up/down move through recent-book actions. Bottom button hints show Left/Right.
- `carousel`: front left/right move through recent-book actions; side up/down move through launcher actions. Use this when left/right should stay inside a cover carousel and up/down should enter or leave the launcher menu.
Home `initialAction` can optionally choose the default selected action when entering home normally:
```json
"initialAction": "reader:recent"
```
Supported values match launcher `action` values. Explicit firmware navigation, such as returning to Settings from a settings submenu, still overrides this default.
### Layouts vs widgets
Layouts only create named rectangles. They do not choose whether a screen is a list, cover grid, carousel, or any other presentation.
+13 -3
View File
@@ -145,7 +145,9 @@ void HomeActivity::onEnter() {
metrics.homeRecentBooksCount);
const auto& actions = refreshHomeActions();
const ThemeHomeScreenSpec* homeSpec = UITheme::getInstance().getHomeScreenSpec();
selectorIndex = 0;
bool hasWantedAction = initialMenuItem != HomeMenuItem::NONE;
const auto wantedAction = [this]() {
switch (initialMenuItem) {
case HomeMenuItem::RECENTS:
@@ -162,15 +164,23 @@ void HomeActivity::onEnter() {
return ThemeHomeAction::FileBrowser;
}
}();
if (initialMenuItem != HomeMenuItem::NONE) {
ThemeHomeAction selectedEntryAction = wantedAction;
if (!hasWantedAction && homeSpec != nullptr && homeSpec->hasInitialAction) {
hasWantedAction = true;
selectedEntryAction = homeSpec->initialAction;
}
if (hasWantedAction) {
for (int i = 0; i < static_cast<int>(actions.size()); ++i) {
if (actions[i].action == wantedAction) {
if (actions[i].action == selectedEntryAction) {
selectorIndex = i;
break;
}
}
}
coverSelectorIndex = recentBooks.empty() ? 0 : std::min(selectorIndex, static_cast<int>(recentBooks.size()) - 1);
coverSelectorIndex = !recentBooks.empty() && selectorIndex < static_cast<int>(actions.size()) &&
actions[selectorIndex].action == ThemeHomeAction::RecentBook
? actions[selectorIndex].value
: 0;
// Trigger first update
requestUpdate();
@@ -688,6 +688,11 @@ void parseHomeScreenSpec(JsonObjectConst obj, ThemeHomeScreenSpec& out) {
out.enabled = true;
out.navigation = parseHomeNavigationMode(obj["navigation"].as<const char*>(), out.navigation);
const char* initialAction = obj["initialAction"].as<const char*>();
if (initialAction != nullptr) {
out.hasInitialAction = true;
out.initialAction = parseHomeAction(initialAction);
}
out.layout = ThemeLayoutNode{};
out.layout.id = "root";
out.layout.sizeType = ThemeLayoutSizeType::Flex;
+2
View File
@@ -120,6 +120,8 @@ struct ThemeHomeWidgetSpec {
struct ThemeHomeScreenSpec {
bool enabled = false;
ThemeHomeNavigationMode navigation = ThemeHomeNavigationMode::Linear;
bool hasInitialAction = false;
ThemeHomeAction initialAction = ThemeHomeAction::FileBrowser;
ThemeLayoutNode layout;
std::vector<ThemeHomeWidgetSpec> widgets;
};