diff --git a/docs/theme-creation.md b/docs/theme-creation.md index 2ed064b9..3ff4c1fb 100644 --- a/docs/theme-creation.md +++ b/docs/theme-creation.md @@ -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. diff --git a/src/activities/home/HomeActivity.cpp b/src/activities/home/HomeActivity.cpp index af9baa25..d27ada33 100644 --- a/src/activities/home/HomeActivity.cpp +++ b/src/activities/home/HomeActivity.cpp @@ -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(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(recentBooks.size()) - 1); + coverSelectorIndex = !recentBooks.empty() && selectorIndex < static_cast(actions.size()) && + actions[selectorIndex].action == ThemeHomeAction::RecentBook + ? actions[selectorIndex].value + : 0; // Trigger first update requestUpdate(); diff --git a/src/components/themes/SdCardThemeRegistry.cpp b/src/components/themes/SdCardThemeRegistry.cpp index 1c9a389d..23d0b1d8 100644 --- a/src/components/themes/SdCardThemeRegistry.cpp +++ b/src/components/themes/SdCardThemeRegistry.cpp @@ -688,6 +688,11 @@ void parseHomeScreenSpec(JsonObjectConst obj, ThemeHomeScreenSpec& out) { out.enabled = true; out.navigation = parseHomeNavigationMode(obj["navigation"].as(), out.navigation); + const char* initialAction = obj["initialAction"].as(); + if (initialAction != nullptr) { + out.hasInitialAction = true; + out.initialAction = parseHomeAction(initialAction); + } out.layout = ThemeLayoutNode{}; out.layout.id = "root"; out.layout.sizeType = ThemeLayoutSizeType::Flex; diff --git a/src/components/themes/ThemeLayout.h b/src/components/themes/ThemeLayout.h index edf91c70..b404b260 100644 --- a/src/components/themes/ThemeLayout.h +++ b/src/components/themes/ThemeLayout.h @@ -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 widgets; };