feat: Added BmpViewer activity for viewing .bmp images in file browser#887
feat: Added BmpViewer activity for viewing .bmp images in file browser#887osteotek merged 19 commits intocrosspoint-reader:masterfrom
Conversation
Empty Button Icons (Back button in the home menu) were still rendering the full sized white rectangles. This was not visible on the home screen due to the white background.
Added basic functionality for opening and closing bmp files from the library browser requiring UI update from menu-bar-fix to improve aesthetics.
Fixed Empty Button Icon Rendering
Fixed the back button in the BmpViewer app to return to the library instead of all the way home.
Fixed formating with ./bin/clang-format-fix
|
I hope this counts as being in scope. I think being able to just view a .bmp is good for choosing wallpapers. I also think it is strange that when viewing the sleep folder in the file browser it shows as completely empty. I think the baseline ability to view an image file on demand instead of having to set it as a wallpaper and turn the device off is well within the idealogical bounds of Library Management and User Experience. Happy to take any critiques on optimizing performance or better fitting in with existing directory structure. I did consider putting the activity in the reader directory, but ultimately decided that it functions more as a util than anything else. |
Buttons are now updated if they have been remapped and added « to keep consistent
|
@Levrk You could move to the next or previous image once one of them is open? |
CaptainFrito
left a comment
There was a problem hiding this comment.
Good feature idea, this has been missing since the beginning!
Fixed button fills to be rounded
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds BMP support: library now includes Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ReaderActivity
participant BmpViewerActivity
participant Storage
participant GfxRenderer
participant MappedInputManager
User->>ReaderActivity: open(path)
ReaderActivity->>ReaderActivity: isBmpFile(path)?
alt BMP file
ReaderActivity->>BmpViewerActivity: instantiate(path, onGoBack)
ReaderActivity->>BmpViewerActivity: onEnter()
BmpViewerActivity->>Storage: open(path)
Storage-->>BmpViewerActivity: file stream / error
BmpViewerActivity->>BmpViewerActivity: parse BMP
BmpViewerActivity->>GfxRenderer: render centered bitmap
GfxRenderer-->>BmpViewerActivity: draw complete
BmpViewerActivity->>MappedInputManager: show button hints
User->>BmpViewerActivity: press Back
BmpViewerActivity->>BmpViewerActivity: loop() detects Back
BmpViewerActivity->>BmpViewerActivity: onExit()
BmpViewerActivity->>ReaderActivity: onGoBack()
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
Good catch @CaptainFrito! added rounded corner fills. Here is a screenshot where you can see that clearly: |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
src/activities/util/BmpViewerActivity.cpp (2)
26-33: Large images are clipped rather than scaled.When the BMP dimensions exceed screen size, the image is drawn at its original size and clipped. This may cut off parts of larger images. If full visibility is desired, consider scaling the image to fit within screen bounds while maintaining aspect ratio.
💡 Optional: Scale large images to fit
// Calculate centering - int32_t xOffset = (renderer.getScreenWidth() - bmpW) / 2; - int32_t yOffset = (renderer.getScreenHeight() - bmpH) / 2; - - if (xOffset < 0) xOffset = 0; - if (yOffset < 0) yOffset = 0; - - renderer.drawBitmap(bmp, xOffset, yOffset, bmpW, bmpH); + int32_t screenW = renderer.getScreenWidth(); + int32_t screenH = renderer.getScreenHeight(); + int32_t drawW = bmpW; + int32_t drawH = bmpH; + + // Scale down if image exceeds screen dimensions + if (bmpW > screenW || bmpH > screenH) { + float scaleX = static_cast<float>(screenW) / bmpW; + float scaleY = static_cast<float>(screenH) / bmpH; + float scale = std::min(scaleX, scaleY); + drawW = static_cast<int32_t>(bmpW * scale); + drawH = static_cast<int32_t>(bmpH * scale); + } + + int32_t xOffset = (screenW - drawW) / 2; + int32_t yOffset = (screenH - drawH) / 2; + + renderer.drawBitmap(bmp, xOffset, yOffset, drawW, drawH);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/activities/util/BmpViewerActivity.cpp` around lines 26 - 33, The code currently centers the BMP using xOffset/yOffset and bmpW/bmpH but does not scale images larger than the screen, causing clipping; modify the drawing logic (around renderer.drawBitmap) to compute a scale = min(1.0, renderer.getScreenWidth() / float(bmpW), renderer.getScreenHeight() / float(bmpH)) to preserve aspect ratio, then set drawW = int(bmpW * scale), drawH = int(bmpH * scale), recalc xOffset/yOffset using drawW/drawH to center, and call renderer.drawBitmap(bmp, xOffset, yOffset, drawW, drawH) so large images are downscaled to fit while small images remain unscaled.
43-44: Consider localizing the "« Back" button label.Other activities use the
tr()function for button labels (e.g.,tr(STR_BACK)in MyLibraryActivity.cpp). For consistency and internationalization support, this hardcoded string should use the localization system.💬 Proposed fix
Add the I18n include and use the localized string:
+#include <I18n.h>- const auto labels = mappedInput.mapLabels("« Back", "", "", ""); + const auto labels = mappedInput.mapLabels(tr(STR_BACK), "", "", "");🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/activities/util/BmpViewerActivity.cpp` around lines 43 - 44, The hardcoded "« Back" label passed to mappedInput.mapLabels should be replaced with the localized string using tr(STR_BACK); update the include list to pull in the I18n header (so tr/STR_BACK are available), then call mappedInput.mapLabels(tr(STR_BACK), "", "", ""); keep the rest (GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4)) unchanged to preserve behavior.src/activities/reader/ReaderActivity.cpp (1)
94-97:currentBookPathis not updated for BMP files.Other reader navigation methods (e.g.,
onGoToEpubReader,onGoToXtcReader,onGoToTxtReader) updatecurrentBookPathbefore transitioning. This is skipped for BMP files. While BMP is not a "book," consider if consistency is desired for any tracking or navigation purposes.💡 Optional: Set currentBookPath for consistency
void ReaderActivity::onGoToBmpViewer(const std::string& path) { + currentBookPath = path; exitActivity(); enterNewActivity(new BmpViewerActivity(renderer, mappedInput, path, [this, path] { goToLibrary(path); })); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/activities/reader/ReaderActivity.cpp` around lines 94 - 97, The onGoToBmpViewer path transition doesn't set currentBookPath like the other readers; update currentBookPath (e.g., assign currentBookPath = path) before calling exitActivity()/enterNewActivity so the BmpViewerActivity transition behaves consistently with onGoToEpubReader/onGoToXtcReader/onGoToTxtReader and any navigation/tracking logic that relies on currentBookPath (affecting symbols: onGoToBmpViewer, currentBookPath, exitActivity, enterNewActivity, BmpViewerActivity, goToLibrary).
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/activities/home/MyLibraryActivity.cppsrc/activities/reader/ReaderActivity.cppsrc/activities/reader/ReaderActivity.hsrc/activities/util/BmpViewerActivity.cppsrc/activities/util/BmpViewerActivity.hsrc/components/themes/lyra/LyraTheme.cpp
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-02-16T20:43:19.339Z
Learnt from: Levrk
Repo: crosspoint-reader/crosspoint-reader PR: 909
File: src/activities/reader/EpubReaderActivity.cpp:461-461
Timestamp: 2026-02-16T20:43:19.339Z
Learning: In src/activities/reader/EpubReaderActivity.cpp, when using ConfirmationActivity with enterNewActivity(), it's not necessary to call exitActivity() beforehand. The ConfirmationActivity operates as a modal dialog and cleanup is handled via the pendingSubactivityExit flag in the callback lambda. This differs from other activities like EpubReaderChapterSelectionActivity or KOReaderSyncActivity which do require exitActivity() before enterNewActivity().
Applied to files:
src/activities/util/BmpViewerActivity.hsrc/activities/reader/ReaderActivity.cppsrc/activities/util/BmpViewerActivity.cppsrc/activities/home/MyLibraryActivity.cppsrc/activities/reader/ReaderActivity.h
🧬 Code graph analysis (4)
src/components/themes/lyra/LyraTheme.cpp (1)
src/components/themes/BaseTheme.h (1)
x(11-121)
src/activities/util/BmpViewerActivity.h (2)
src/activities/util/BmpViewerActivity.cpp (3)
BmpViewerActivity(10-12)onEnter(14-46)onEnter(14-14)src/activities/reader/ReaderActivity.cpp (2)
onEnter(115-148)onEnter(115-115)
src/activities/reader/ReaderActivity.cpp (2)
src/util/StringUtils.cpp (4)
checkFileExtension(38-50)checkFileExtension(38-38)checkFileExtension(52-62)checkFileExtension(52-52)src/main.cpp (5)
exitActivity(133-139)exitActivity(133-133)enterNewActivity(141-144)enterNewActivity(141-141)renderer(37-37)
src/activities/reader/ReaderActivity.h (2)
src/main.cpp (3)
onGoHome(212-212)onGoHome(251-255)onGoHome(251-251)src/activities/reader/ReaderActivity.cpp (8)
isBmpFile(33-33)isBmpFile(33-33)extractFolderPath(16-22)extractFolderPath(16-16)goToLibrary(80-84)goToLibrary(80-80)onGoToBmpViewer(94-97)onGoToBmpViewer(94-94)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: build
- GitHub Check: cppcheck
🔇 Additional comments (4)
src/activities/home/MyLibraryActivity.cpp (1)
93-96: LGTM!The
.bmpextension is correctly added following the existing pattern. TheStringUtils::checkFileExtensionfunction handles case-insensitive matching, so this will properly detect BMP files regardless of case.src/activities/util/BmpViewerActivity.h (1)
1-21: LGTM!The header is well-structured and follows the existing activity patterns in the codebase. The class correctly inherits from
Activity, declares the necessary lifecycle overrides, and uses appropriate member types for the file path and callback.src/activities/reader/ReaderActivity.cpp (2)
33-34: LGTM!The
isBmpFileimplementation is consistent with the existingisXtcFileandisTxtFilehelpers.
124-126: LGTM!BMP file detection is correctly integrated into the
onEnterflow, routing to the BMP viewer before other format checks.
🤖 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/ReaderActivity.h`:
- Line 15: The onGoHome std::function member in ReaderActivity.h is declared but
not initialized; update the ReaderActivity constructor to accept a
std::function<void()> onGoHome parameter (matching
XtcReaderActivity/TxtReaderActivity/EpubReaderActivity patterns) and initialize
the onGoHome member in the constructor initializer list so the member is not
left uninitialized.
In `@src/components/themes/lyra/LyraTheme.cpp`:
- Around line 247-257: Replace the unqualified color identifier used in the
button rendering calls with the namespaced enum to match the rest of the file:
update the two occurrences where fillRoundedRect is called with White (and the
corresponding drawRoundedRect nearby) to use Color::White instead; you can find
them in the LyraTheme.cpp button-drawing block where renderer.fillRoundedRect /
renderer.drawRoundedRect are invoked for the regular and SMALL-sized button
(references: SMALL_FONT_ID, labels[i], smallButtonHeight).
---
Nitpick comments:
In `@src/activities/reader/ReaderActivity.cpp`:
- Around line 94-97: The onGoToBmpViewer path transition doesn't set
currentBookPath like the other readers; update currentBookPath (e.g., assign
currentBookPath = path) before calling exitActivity()/enterNewActivity so the
BmpViewerActivity transition behaves consistently with
onGoToEpubReader/onGoToXtcReader/onGoToTxtReader and any navigation/tracking
logic that relies on currentBookPath (affecting symbols: onGoToBmpViewer,
currentBookPath, exitActivity, enterNewActivity, BmpViewerActivity,
goToLibrary).
In `@src/activities/util/BmpViewerActivity.cpp`:
- Around line 26-33: The code currently centers the BMP using xOffset/yOffset
and bmpW/bmpH but does not scale images larger than the screen, causing
clipping; modify the drawing logic (around renderer.drawBitmap) to compute a
scale = min(1.0, renderer.getScreenWidth() / float(bmpW),
renderer.getScreenHeight() / float(bmpH)) to preserve aspect ratio, then set
drawW = int(bmpW * scale), drawH = int(bmpH * scale), recalc xOffset/yOffset
using drawW/drawH to center, and call renderer.drawBitmap(bmp, xOffset, yOffset,
drawW, drawH) so large images are downscaled to fit while small images remain
unscaled.
- Around line 43-44: The hardcoded "« Back" label passed to
mappedInput.mapLabels should be replaced with the localized string using
tr(STR_BACK); update the include list to pull in the I18n header (so tr/STR_BACK
are available), then call mappedInput.mapLabels(tr(STR_BACK), "", "", ""); keep
the rest (GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3,
labels.btn4)) unchanged to preserve behavior.
removed unused function declaration and changing White to Color::White
clang clang clang
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@osteotek You know what fair enough I did not realize the backwards compatibility with a visible sleep folder. |
|
Maybe this is more of a feature for another PR after this gets merged, but: It would be great if one could use another button for a one-off "display and sleep". That would fit nicely with the display-without-power-consumption capabilities of the device. |
Totally agree, I like the idea of being able to have a big collection of random sleep images but still being able to select one in particular if you so choose. Hoping to get this merged with the most basic functionality and then work on improving it later just to make sure I stay in scope. |
|
Does it take into account the settings for I think a big use case of this feature will be to see what the image would look like as the cover, so it would be good to take that into account. |
|
This would be very useful with #759 |
There was a problem hiding this comment.
Pull request overview
Adds support for opening and viewing .bmp files directly from the file browser by introducing a dedicated BmpViewerActivity, and updates the Lyra theme’s button-hint rendering to avoid drawing artifacts.
Changes:
- Added
BmpViewerActivityto load and display BMP images with a simple “Back” exit path. - Updated
ReaderActivityandMyLibraryActivityto recognize.bmpfiles and route them to the viewer. - Switched Lyra theme button hint background fills to rounded-rect fills (aligning with the existing rounded border rendering).
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/components/themes/lyra/LyraTheme.cpp |
Uses fillRoundedRect for button hint backgrounds to match rounded borders and prevent visual artifacts. |
src/activities/util/BmpViewerActivity.h |
Declares new activity for BMP viewing. |
src/activities/util/BmpViewerActivity.cpp |
Implements BMP loading/rendering and back navigation UI. |
src/activities/reader/ReaderActivity.h |
Adds BMP detection and navigation hook to launch BMP viewer. |
src/activities/reader/ReaderActivity.cpp |
Routes .bmp files to BmpViewerActivity when opened. |
src/activities/home/MyLibraryActivity.cpp |
Includes .bmp in the file-browser extension filter. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@Levrk Looks good to me, just a few suggestions for small fixes, as suggested by Copilot. |
Co-authored-by: Copilot <[email protected]>
Merging in master for testing
Co-authored-by: Copilot <[email protected]>
|
fixed scaling/cropping to work for larger files. Larger files made me add a loading indicator so it doesn't feel like it is just hanging when you opening something big Verified this works with a bunch of different .bmp files |
crosspoint-reader#887) ## Summary * **What is the goal of this PR?** (e.g., Implements the new feature for file uploading.) Implements new feature for viewing .bmp files directly from the "Browse Files" menu. * **What changes are included?** You can now view .bmp files when browsing. You can click the select button to open the file, and then click back to close it and continue browsing in the same location. Once open a file will display on the screen with no additional options to interact outside of exiting with the back button. The attached video shows this feature in action: https://github.com/user-attachments/assets/9659b6da-abf7-4458-b158-e11c248c8bef ## Additional Context * Add any other information that might be helpful for the reviewer (e.g., performance implications, potential risks, specific areas to focus on). The changes implemented in crosspoint-reader#884 are also present here as this feature is actually what led to me noticing this issue. I figured I would add that PR as a separate request in case that one could be more easily merged given this feature is significantly more complicated and will likely be subject to more intense review. --- ### 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** --------- Co-authored-by: Copilot <[email protected]>

Summary
Implements new feature for viewing .bmp files directly from the "Browse Files" menu.
You can now view .bmp files when browsing. You can click the select button to open the file, and then click back to close it and continue browsing in the same location. Once open a file will display on the screen with no additional options to interact outside of exiting with the back button.
The attached video shows this feature in action:
Untitled.mov
Additional Context
specific areas to focus on).
The changes implemented in #884 are also present here as this feature is actually what led to me noticing this issue. I figured I would add that PR as a separate request in case that one could be more easily merged given this feature is significantly more complicated and will likely be subject to more intense review.
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