Skip to content

refactor: make epub reader menu theme aware#53

Merged
jpirnay merged 9 commits intomasterfrom
refactor-list
Apr 9, 2026
Merged

refactor: make epub reader menu theme aware#53
jpirnay merged 9 commits intomasterfrom
refactor-list

Conversation

@jpirnay
Copy link
Copy Markdown
Owner

@jpirnay jpirnay commented Apr 9, 2026

Summary

  • What is the goal of this PR? (e.g., Implements the new feature for file uploading.)
  • What changes are included?

Additional Context

  • Add any other information that might be helpful for the reviewer (e.g., performance implications, potential risks,
    specific areas to focus on).

AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? < YES | PARTIALLY | NO >

Summary by CodeRabbit

  • New Features

    • Menus now include labeled, non-selectable separator sections (Navigation, Appearance, Tools); navigation and confirmation skip separators.
    • Added reader UI translations: "Tools", "Navigation", "Appearance"; restored "Sun".
  • Refactor

    • Menu and list rendering unified to use a list renderer with explicit separator handling and theme hooks for separator styling.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: edcb4613-29fe-4692-bff4-b63282c237ef

📥 Commits

Reviewing files that changed from the base of the PR and between 348d113 and 85df3cb.

📒 Files selected for processing (3)
  • src/activities/reader/EpubReaderMenuActivity.cpp
  • src/components/themes/BaseTheme.cpp
  • src/components/themes/lyra/LyraTheme.cpp
✅ Files skipped from review due to trivial changes (1)
  • src/components/themes/lyra/LyraTheme.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/themes/BaseTheme.cpp

📝 Walkthrough

Walkthrough

Introduce non-selectable separator rows in menus, add selectable-aware navigation to ButtonNavigator, provide UITheme separator helpers and themed separator rendering, refactor reader and clock settings to runtime menu models, and update English translations (restore "Sun", add reader UI keys).

Changes

Cohort / File(s) Summary
Translations
lib/I18n/translations/english.yaml
Restored STR_WEATHER_SUN_INFO: "Sun" and added STR_READER_TOOLS: "Tools", STR_READER_NAVIGATION: "Navigation", STR_READER_APPEARANCE: "Appearance".
ButtonNavigator
src/util/ButtonNavigator.h, src/util/ButtonNavigator.cpp
Added selectable-predicate state (selectablePredicate, selectableTotalItems), APIs setSelectablePredicate/clearSelectablePredicate, and overloads of nextIndex/previousIndex that skip non-selectable entries using vector or predicate, plus member overloads using stored predicate.
Activities: Reader
src/activities/reader/EpubReaderMenuActivity.h, src/activities/reader/EpubReaderMenuActivity.cpp
Added MenuAction::NONE, MenuItem.isSeparator, buildSelectablePredicate(); rebuilt menu with separator rows and conditional groups, switched to GUI.drawList(...), and updated navigation/confirm handling to respect separators.
Activities: Settings (Clock)
src/activities/settings/ClockSettingsActivity.h, src/activities/settings/ClockSettingsActivity.cpp
Replaced static menu arrays with runtime MenuItem model (including separators), added buildMenuItems() and buildSelectablePredicate(), migrated navigation to selectable-aware ButtonNavigator calls and action-based selection dispatch.
UI Theme Helpers
src/components/UITheme.h, src/components/UITheme.cpp
Added makeSeparatorTitle (string & StrId), isSeparatorTitle, and stripSeparatorTitle to mark and inspect separator titles (prefix "__").
Theme Rendering
src/components/themes/BaseTheme.h, src/components/themes/BaseTheme.cpp, src/components/themes/lyra/LyraTheme.cpp
Added virtual drawListSeparator(...); list drawing now detects separator titles, strips prefix for display, suppresses selection highlight for separators, and routes separator rendering to drawListSeparator.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Activity as Activity (Reader / Clock)
participant Navigator as ButtonNavigator
participant GUI as GUI.drawList
participant Theme as BaseTheme / LyraTheme
participant UI as UITheme
participant I18n as I18n

Activity->>Navigator: setSelectablePredicate(predicate, total)
Activity->>GUI: GUI.drawList(menuItems, callbacks)
GUI->>Theme: drawList(rowIndex, rowTitle, isSelected)
Theme->>UI: isSeparatorTitle(rowTitle)?
alt separator
    Theme->>UI: stripSeparatorTitle(rowTitle)
    Theme->>Theme: drawListSeparator(...rgba(200,200,200,0.5))
else normal row
    Theme->>I18n: fetch localized strings
    Theme->>Theme: draw name/subtitle/value (normal rendering)
end
Navigator->>Navigator: nextIndex(current) / previousIndex(current)
Navigator-->>Activity: returns selectable index

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 I hopped through menus, separators in tow,
Grouped Navigation, Appearance, Tools in a row,
ButtonNavigator skips dividers with cheer,
Themes draw titles tidy and clear,
Sun and reader labels back — joy, hop here! 🌤️

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor: make epub reader menu theme aware' accurately describes the main change: refactoring the EpubReaderMenuActivity to be theme-aware by switching from manual rendering to using GUI.drawList() with theme-aware separator rendering.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor-list

Comment @coderabbitai help to get the list of available commands and usage tips.

@jpirnay
Copy link
Copy Markdown
Owner Author

jpirnay commented Apr 9, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@jpirnay
Copy link
Copy Markdown
Owner Author

jpirnay commented Apr 9, 2026

@coderabbitai help

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
    • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
    • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve merge conflict to automatically resolve merge conflicts.
  • @coderabbitai autofix to automatically fix issues identified in unresolved review comments.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit configuration file (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

@jpirnay
Copy link
Copy Markdown
Owner Author

jpirnay commented Apr 9, 2026

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/activities/settings/SettingsActivity.cpp (1)

161-181: ⚠️ Potential issue | 🟠 Major

Advance to the first selectable row after category changes.

Line 162 forces selectedSettingIndex to 1 when switching categories from inside the list, but the System category now always starts with SettingInfo::Separator(...) at Line 40. That leaves the focus on a non-selectable row, so Confirm becomes a no-op until the user navigates again.

💡 Suggested fix
   if (hasChangedCategory) {
     selectedSettingIndex = (selectedSettingIndex == 0) ? 0 : 1;
     switch (selectedCategoryIndex) {
       case 0:
         currentSettings = &displaySettings;
         break;
@@
     }
     settingsCount = static_cast<int>(currentSettings->size());
-    buttonNavigator.setSelectablePredicate(makeSelectablePredicate(*currentSettings, 1, true), settingsCount + 1);
+    auto predicate = buildSelectablePredicate();
+    buttonNavigator.setSelectablePredicate(predicate, settingsCount + 1);
+    if (selectedSettingIndex > 0 && !predicate(selectedSettingIndex)) {
+      selectedSettingIndex = buttonNavigator.nextIndex(selectedSettingIndex);
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/activities/settings/SettingsActivity.cpp` around lines 161 - 181, When
the category changes we must advance focus to the first selectable setting (not
assume index 1); after assigning currentSettings (based on
selectedCategoryIndex) compute the first selectable index in *currentSettings
(skip entries like SettingInfo::Separator) and set selectedSettingIndex to that
index (or 0 if none) before updating settingsCount and calling
buttonNavigator.setSelectablePredicate with
makeSelectablePredicate(*currentSettings, 1, true). Use the same selectable
check used by makeSelectablePredicate to locate the first selectable row so
Confirm is active immediately in categories such as System that start with a
Separator.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/themes/BaseTheme.cpp`:
- Around line 306-307: The code contains a duplicated renderer.drawText(...)
call (the identical call using font, rect.x +
BaseMetrics::values.contentSidePadding, itemY, item.c_str(), true) which will
render the same text twice; remove the redundant second call so only a single
renderer.drawText(...) invocation remains (refer to the renderer.drawText call
that uses font, rect, BaseMetrics::values.contentSidePadding, itemY and
item.c_str()).

---

Outside diff comments:
In `@src/activities/settings/SettingsActivity.cpp`:
- Around line 161-181: When the category changes we must advance focus to the
first selectable setting (not assume index 1); after assigning currentSettings
(based on selectedCategoryIndex) compute the first selectable index in
*currentSettings (skip entries like SettingInfo::Separator) and set
selectedSettingIndex to that index (or 0 if none) before updating settingsCount
and calling buttonNavigator.setSelectablePredicate with
makeSelectablePredicate(*currentSettings, 1, true). Use the same selectable
check used by makeSelectablePredicate to locate the first selectable row so
Confirm is active immediately in categories such as System that start with a
Separator.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b3c86648-2aa2-4cf5-8a11-7005dd725b1c

📥 Commits

Reviewing files that changed from the base of the PR and between 0b9618c and 62d15a5.

📒 Files selected for processing (15)
  • lib/I18n/translations/english.yaml
  • src/activities/reader/EpubReaderMenuActivity.cpp
  • src/activities/reader/EpubReaderMenuActivity.h
  • src/activities/settings/ClockSettingsActivity.cpp
  • src/activities/settings/ClockSettingsActivity.h
  • src/activities/settings/SettingsActivity.cpp
  • src/activities/settings/SettingsActivity.h
  • src/components/UITheme.cpp
  • src/components/UITheme.h
  • src/components/themes/BaseTheme.cpp
  • src/components/themes/BaseTheme.h
  • src/components/themes/lyra/LyraTheme.cpp
  • src/util/ButtonNavigator.cpp
  • src/util/ButtonNavigator.h
  • src/util/MenuItemHelpers.h

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
src/components/themes/BaseTheme.cpp (1)

306-307: ⚠️ Potential issue | 🟡 Minor

Duplicate drawText call - likely copy-paste error.

Line 307 duplicates the exact same drawText call from Line 306, which will render the same text twice at the same position.

🐛 Proposed fix to remove duplicate line
     auto item = renderer.truncatedText(font, itemName.c_str(), textWidth);
     renderer.drawText(font, rect.x + BaseMetrics::values.contentSidePadding, itemY, item.c_str(), true);
-    renderer.drawText(font, rect.x + BaseMetrics::values.contentSidePadding, itemY, item.c_str(), true);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/themes/BaseTheme.cpp` around lines 306 - 307, Remove the
duplicate draw call: the two consecutive calls to renderer.drawText(font, rect.x
+ BaseMetrics::values.contentSidePadding, itemY, item.c_str(), true) render the
same text twice; keep a single invocation and delete the redundant one (search
for renderer.drawText usage in BaseTheme::... where font, rect, itemY, and
item.c_str() are used to locate the duplicated lines).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/activities/reader/EpubReaderMenuActivity.cpp`:
- Around line 71-75: The current onEnter() always advances selectedIndex by
calling buttonNavigator.nextIndex(selectedIndex), shifting a restored valid
selection; change it to only normalize when the current row is not selectable by
checking the selectable predicate first (use the same predicate passed to
buttonNavigator.setSelectablePredicate — or
buttonNavigator.isSelectable(selectedIndex) if available) and only call
buttonNavigator.nextIndex(selectedIndex) and assign selectedIndex when that
check fails so that valid selections are preserved.

In `@src/components/themes/BaseTheme.cpp`:
- Around line 291-302: The duplicate `if (isSeparator)` check should be merged:
compute bool isSeparator = UITheme::isSeparatorTitle(itemName), and if true call
UITheme::stripSeparatorTitle(itemName) and immediately call
drawListSeparator(...) then continue; remove the second separate `if
(isSeparator)` block. Update the block surrounding UITheme::isSeparatorTitle,
UITheme::stripSeparatorTitle, drawListSeparator, and the variables itemName,
itemY, contentWidth, rowHeight, textWidth, rect, renderer so the strip and draw
happen inside a single conditional.

In `@src/components/themes/lyra/LyraTheme.cpp`:
- Around line 446-457: The duplicate check of isSeparator should be removed by
combining the logic: call UITheme::isSeparatorTitle(itemName) into isSeparator,
and if true then immediately set itemName =
UITheme::stripSeparatorTitle(itemName), call drawListSeparator(...) with the
same parameters (using itemY, contentWidth, rowHeight, textX, rowTextWidth,
LyraMetrics::values.contentSidePadding), and continue; i.e. replace the two
separate if (isSeparator) blocks with a single if (isSeparator) { itemName =
UITheme::stripSeparatorTitle(itemName); drawListSeparator(...); continue; }
ensuring drawListSeparator and the strip call remain intact.

---

Duplicate comments:
In `@src/components/themes/BaseTheme.cpp`:
- Around line 306-307: Remove the duplicate draw call: the two consecutive calls
to renderer.drawText(font, rect.x + BaseMetrics::values.contentSidePadding,
itemY, item.c_str(), true) render the same text twice; keep a single invocation
and delete the redundant one (search for renderer.drawText usage in
BaseTheme::... where font, rect, itemY, and item.c_str() are used to locate the
duplicated lines).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b6e8902d-7e99-458c-b019-5be33b365e4e

📥 Commits

Reviewing files that changed from the base of the PR and between 0b9618c and 348d113.

📒 Files selected for processing (12)
  • lib/I18n/translations/english.yaml
  • src/activities/reader/EpubReaderMenuActivity.cpp
  • src/activities/reader/EpubReaderMenuActivity.h
  • src/activities/settings/ClockSettingsActivity.cpp
  • src/activities/settings/ClockSettingsActivity.h
  • src/components/UITheme.cpp
  • src/components/UITheme.h
  • src/components/themes/BaseTheme.cpp
  • src/components/themes/BaseTheme.h
  • src/components/themes/lyra/LyraTheme.cpp
  • src/util/ButtonNavigator.cpp
  • src/util/ButtonNavigator.h

@jpirnay jpirnay merged commit 79e996b into master Apr 9, 2026
6 checks passed
@jpirnay jpirnay deleted the refactor-list branch April 9, 2026 21:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant