2025-12-17 23:32:18 +11:00
|
|
|
#include "HomeActivity.h"
|
2025-12-17 20:47:43 +11:00
|
|
|
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
#include <Bitmap.h>
|
2025-12-30 22:18:10 +10:00
|
|
|
#include <Epub.h>
|
2025-12-17 20:47:43 +11:00
|
|
|
#include <GfxRenderer.h>
|
2025-12-30 15:09:30 +10:00
|
|
|
#include <SDCardManager.h>
|
2026-02-01 16:23:48 +05:00
|
|
|
#include <Utf8.h>
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
#include <Xtc.h>
|
2025-12-17 20:47:43 +11:00
|
|
|
|
2026-01-07 03:58:37 -05:00
|
|
|
#include <cstring>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
2026-01-12 10:53:58 +01:00
|
|
|
#include "Battery.h"
|
2026-01-07 03:58:37 -05:00
|
|
|
#include "CrossPointSettings.h"
|
2025-12-26 09:55:23 +09:00
|
|
|
#include "CrossPointState.h"
|
2025-12-30 15:09:30 +10:00
|
|
|
#include "MappedInputManager.h"
|
2025-12-30 22:41:47 +10:00
|
|
|
#include "ScreenComponents.h"
|
Aleo, Noto Sans, Open Dyslexic fonts (#163)
## Summary
* Swap out Bookerly font due to licensing issues, replace default font
with Aleo
* I did a bunch of searching around for a nice replacement font, and
this trumped several other like Literata, Merriwether, Vollkorn, etc
* Add Noto Sans, and Open Dyslexic as font options
* They can be selected in the settings screen
* Add font size options (Small, Medium, Large, Extra Large)
* Adjustable in settings
* Swap out uses of reader font in headings and replaced with slightly
larger Ubuntu font
* Replaced PixelArial14 font as it was difficult to track down, replace
with Space Grotesk
* Remove auto formatting on generated font files
* Massively speeds up formatting step now that there is a lot more CPP
font source
* Include fonts with their licenses in the repo
## Additional Context
Line compression setting will follow
| Font | Small | Medium | Large | X Large |
| --- | --- | --- | --- | --- |
| Aleo |

|

|

|

|
| Noto Sans |

|

|

|

|
| Open Dyslexic |

|

|

|

|
2025-12-30 18:21:47 +10:00
|
|
|
#include "fontIds.h"
|
2026-01-07 20:07:23 +10:00
|
|
|
#include "util/StringUtils.h"
|
2025-12-17 20:47:43 +11:00
|
|
|
|
2025-12-17 23:32:18 +11:00
|
|
|
void HomeActivity::taskTrampoline(void* param) {
|
|
|
|
|
auto* self = static_cast<HomeActivity*>(param);
|
2025-12-17 20:47:43 +11:00
|
|
|
self->displayTaskLoop();
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-07 03:58:37 -05:00
|
|
|
int HomeActivity::getMenuItemCount() const {
|
My Library: Tab bar w/ Recent Books + File Browser (#250)
# Summary
This PR introduces a reusable Tab Bar component and combines the Recent
Books and File Browser into a unified tabbed page called "My Library"
accessible from the Home screen.
## Features
### New Tab Bar Component
A flexible, reusable tab bar component added to `ScreenComponents` that
can be used throughout the application.
### New Scroll Indicator Component
A page position indicator for lists that span multiple pages.
**Features:**
- Up/down arrow indicators
- Current page fraction display (e.g., "1/3")
- Only renders when content spans multiple pages
### My Library Activity
A new unified view combining Recent Books and File Browser into a single
tabbed page.
**Tabs:**
- **Recent** - Shows recently opened books
- **Files** - Browse SD card directory structure
**Navigation:**
- Up/Down or Left/Right: Navigate through list items
- Left/Right (when first item selected): Switch between tabs
- Confirm: Open selected book or enter directory
- Back: Go up directory (Files tab) or return home
- Long press Back: Jump to root directory (Files tab)
**UI Elements:**
- Tab bar with selection indicator
- Scroll/page indicator on right side
- Side button hints (up/down arrows)
- Dynamic bottom button labels ("BACK" in subdirectories, "HOME" at
root)
## Tab Bar Usage
The tab bar component is designed to be reusable across different
activities. Here's how to use it:
### Basic Example
```cpp
#include "ScreenComponents.h"
void MyActivity::render() const {
renderer.clearScreen();
// Define tabs with labels and selection state
std::vector<TabInfo> tabs = {
{"Tab One", currentTab == 0}, // Selected when currentTab is 0
{"Tab Two", currentTab == 1}, // Selected when currentTab is 1
{"Tab Three", currentTab == 2} // Selected when currentTab is 2
};
// Draw tab bar at Y position 15, returns height of the tab bar
int tabBarHeight = ScreenComponents::drawTabBar(renderer, 15, tabs);
// Position your content below the tab bar
int contentStartY = 15 + tabBarHeight + 10; // Add some padding
// Draw content based on selected tab
if (currentTab == 0) {
renderTabOneContent(contentStartY);
} else if (currentTab == 1) {
renderTabTwoContent(contentStartY);
} else {
renderTabThreeContent(contentStartY);
}
renderer.displayBuffer();
}
```
Video Demo: https://share.cleanshot.com/P6NBncFS
<img width="250"
src="https://github.com/user-attachments/assets/07de4418-968e-4a88-9b42-ac5f53d8a832"
/>
<img width="250"
src="https://github.com/user-attachments/assets/e40201ed-dcc8-4568-b008-cd2bf13ebb2a"
/>
<img width="250"
src="https://github.com/user-attachments/assets/73db269f-e629-4696-b8ca-0b8443451a05"
/>
---------
Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-21 05:38:38 -06:00
|
|
|
int count = 3; // My Library, File transfer, Settings
|
2026-01-07 03:58:37 -05:00
|
|
|
if (hasContinueReading) count++;
|
|
|
|
|
if (hasOpdsUrl) count++;
|
|
|
|
|
return count;
|
|
|
|
|
}
|
2025-12-26 09:55:23 +09:00
|
|
|
|
2025-12-17 23:32:18 +11:00
|
|
|
void HomeActivity::onEnter() {
|
2025-12-21 21:17:00 +11:00
|
|
|
Activity::onEnter();
|
|
|
|
|
|
2025-12-17 20:47:43 +11:00
|
|
|
renderingMutex = xSemaphoreCreateMutex();
|
|
|
|
|
|
2025-12-26 09:55:23 +09:00
|
|
|
// Check if we have a book to continue reading
|
2025-12-30 15:09:30 +10:00
|
|
|
hasContinueReading = !APP_STATE.openEpubPath.empty() && SdMan.exists(APP_STATE.openEpubPath.c_str());
|
2025-12-26 09:55:23 +09:00
|
|
|
|
2026-01-07 03:58:37 -05:00
|
|
|
// Check if OPDS browser URL is configured
|
|
|
|
|
hasOpdsUrl = strlen(SETTINGS.opdsServerUrl) > 0;
|
|
|
|
|
|
2025-12-30 22:18:10 +10:00
|
|
|
if (hasContinueReading) {
|
|
|
|
|
// Extract filename from path for display
|
|
|
|
|
lastBookTitle = APP_STATE.openEpubPath;
|
|
|
|
|
const size_t lastSlash = lastBookTitle.find_last_of('/');
|
|
|
|
|
if (lastSlash != std::string::npos) {
|
|
|
|
|
lastBookTitle = lastBookTitle.substr(lastSlash + 1);
|
|
|
|
|
}
|
|
|
|
|
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
// If epub, try to load the metadata for title/author and cover
|
2026-01-07 20:07:23 +10:00
|
|
|
if (StringUtils::checkFileExtension(lastBookTitle, ".epub")) {
|
2025-12-30 22:18:10 +10:00
|
|
|
Epub epub(APP_STATE.openEpubPath, "/.crosspoint");
|
feat: Add CSS parsing and CSS support in EPUBs (#411)
## Summary
* **What is the goal of this PR?**
- Adds basic CSS parsing to EPUBs and determine the CSS rules when
rendering to the screen so that text is styled correctly. Currently
supports bold, underline, italics, margin, padding, and text alignment
## Additional Context
- My main reason for wanting this is that the book I'm currently
reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl
series), relies _a lot_ on styled text for telling parts of the story.
When text is bolded, it's supposed to be a message that's rendered
"on-screen" in the story. When characters are "chatting" with each
other, the text is bolded and their names are underlined. Plus, normal
emphasis is provided with italicizing words here and there. So, this
greatly improves my experience reading this book on the Xteink, and I
figured it was useful enough for others too.
- For transparency: I'm a software engineer, but I'm mostly frontend and
TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I
would not be surprised if I'm doing something dumb along the way in this
code. Please don't hesitate to ask for changes if something looks off. I
heavily relied on Claude Code for help, and I had a lot of inspiration
from how [microreader](https://github.com/CidVonHighwind/microreader)
achieves their CSS parsing and styling. I did give this as good of a
code review as I could and went through everything, and _it works on my
machine_ 😄
### Before


### After


---
### AI Usage
Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
|
|
|
// Skip loading css since we only need metadata here
|
|
|
|
|
epub.load(false, true);
|
2025-12-30 22:18:10 +10:00
|
|
|
if (!epub.getTitle().empty()) {
|
|
|
|
|
lastBookTitle = std::string(epub.getTitle());
|
|
|
|
|
}
|
|
|
|
|
if (!epub.getAuthor().empty()) {
|
|
|
|
|
lastBookAuthor = std::string(epub.getAuthor());
|
|
|
|
|
}
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
// Try to generate thumbnail image for Continue Reading card
|
|
|
|
|
if (epub.generateThumbBmp()) {
|
|
|
|
|
coverBmpPath = epub.getThumbBmpPath();
|
|
|
|
|
hasCoverImage = true;
|
|
|
|
|
}
|
|
|
|
|
} else if (StringUtils::checkFileExtension(lastBookTitle, ".xtch") ||
|
|
|
|
|
StringUtils::checkFileExtension(lastBookTitle, ".xtc")) {
|
|
|
|
|
// Handle XTC file
|
|
|
|
|
Xtc xtc(APP_STATE.openEpubPath, "/.crosspoint");
|
|
|
|
|
if (xtc.load()) {
|
|
|
|
|
if (!xtc.getTitle().empty()) {
|
|
|
|
|
lastBookTitle = std::string(xtc.getTitle());
|
|
|
|
|
}
|
2026-01-27 22:56:51 +11:00
|
|
|
if (!xtc.getAuthor().empty()) {
|
|
|
|
|
lastBookAuthor = std::string(xtc.getAuthor());
|
|
|
|
|
}
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
// Try to generate thumbnail image for Continue Reading card
|
|
|
|
|
if (xtc.generateThumbBmp()) {
|
|
|
|
|
coverBmpPath = xtc.getThumbBmpPath();
|
|
|
|
|
hasCoverImage = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Remove extension from title if we don't have metadata
|
|
|
|
|
if (StringUtils::checkFileExtension(lastBookTitle, ".xtch")) {
|
|
|
|
|
lastBookTitle.resize(lastBookTitle.length() - 5);
|
|
|
|
|
} else if (StringUtils::checkFileExtension(lastBookTitle, ".xtc")) {
|
|
|
|
|
lastBookTitle.resize(lastBookTitle.length() - 4);
|
|
|
|
|
}
|
2025-12-30 22:18:10 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 20:47:43 +11:00
|
|
|
selectorIndex = 0;
|
|
|
|
|
|
|
|
|
|
// Trigger first update
|
|
|
|
|
updateRequired = true;
|
|
|
|
|
|
2025-12-17 23:32:18 +11:00
|
|
|
xTaskCreate(&HomeActivity::taskTrampoline, "HomeActivityTask",
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
4096, // Stack size (increased for cover image rendering)
|
2025-12-17 20:47:43 +11:00
|
|
|
this, // Parameters
|
|
|
|
|
1, // Priority
|
|
|
|
|
&displayTaskHandle // Task handle
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 23:32:18 +11:00
|
|
|
void HomeActivity::onExit() {
|
2025-12-21 21:17:00 +11:00
|
|
|
Activity::onExit();
|
|
|
|
|
|
2025-12-17 20:47:43 +11:00
|
|
|
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
|
|
|
|
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
|
|
|
|
if (displayTaskHandle) {
|
|
|
|
|
vTaskDelete(displayTaskHandle);
|
|
|
|
|
displayTaskHandle = nullptr;
|
|
|
|
|
}
|
|
|
|
|
vSemaphoreDelete(renderingMutex);
|
|
|
|
|
renderingMutex = nullptr;
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
|
|
|
|
|
// Free the stored cover buffer if any
|
|
|
|
|
freeCoverBuffer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool HomeActivity::storeCoverBuffer() {
|
|
|
|
|
uint8_t* frameBuffer = renderer.getFrameBuffer();
|
|
|
|
|
if (!frameBuffer) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Free any existing buffer first
|
|
|
|
|
freeCoverBuffer();
|
|
|
|
|
|
|
|
|
|
const size_t bufferSize = GfxRenderer::getBufferSize();
|
|
|
|
|
coverBuffer = static_cast<uint8_t*>(malloc(bufferSize));
|
|
|
|
|
if (!coverBuffer) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy(coverBuffer, frameBuffer, bufferSize);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool HomeActivity::restoreCoverBuffer() {
|
|
|
|
|
if (!coverBuffer) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t* frameBuffer = renderer.getFrameBuffer();
|
|
|
|
|
if (!frameBuffer) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const size_t bufferSize = GfxRenderer::getBufferSize();
|
|
|
|
|
memcpy(frameBuffer, coverBuffer, bufferSize);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HomeActivity::freeCoverBuffer() {
|
|
|
|
|
if (coverBuffer) {
|
|
|
|
|
free(coverBuffer);
|
|
|
|
|
coverBuffer = nullptr;
|
|
|
|
|
}
|
|
|
|
|
coverBufferStored = false;
|
2025-12-17 20:47:43 +11:00
|
|
|
}
|
|
|
|
|
|
2025-12-17 23:32:18 +11:00
|
|
|
void HomeActivity::loop() {
|
2025-12-28 21:59:14 -06:00
|
|
|
const bool prevPressed = mappedInput.wasPressed(MappedInputManager::Button::Up) ||
|
|
|
|
|
mappedInput.wasPressed(MappedInputManager::Button::Left);
|
|
|
|
|
const bool nextPressed = mappedInput.wasPressed(MappedInputManager::Button::Down) ||
|
|
|
|
|
mappedInput.wasPressed(MappedInputManager::Button::Right);
|
2025-12-17 20:47:43 +11:00
|
|
|
|
2025-12-26 09:55:23 +09:00
|
|
|
const int menuCount = getMenuItemCount();
|
|
|
|
|
|
2025-12-28 21:59:14 -06:00
|
|
|
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
2026-01-07 03:58:37 -05:00
|
|
|
// Calculate dynamic indices based on which options are available
|
|
|
|
|
int idx = 0;
|
|
|
|
|
const int continueIdx = hasContinueReading ? idx++ : -1;
|
My Library: Tab bar w/ Recent Books + File Browser (#250)
# Summary
This PR introduces a reusable Tab Bar component and combines the Recent
Books and File Browser into a unified tabbed page called "My Library"
accessible from the Home screen.
## Features
### New Tab Bar Component
A flexible, reusable tab bar component added to `ScreenComponents` that
can be used throughout the application.
### New Scroll Indicator Component
A page position indicator for lists that span multiple pages.
**Features:**
- Up/down arrow indicators
- Current page fraction display (e.g., "1/3")
- Only renders when content spans multiple pages
### My Library Activity
A new unified view combining Recent Books and File Browser into a single
tabbed page.
**Tabs:**
- **Recent** - Shows recently opened books
- **Files** - Browse SD card directory structure
**Navigation:**
- Up/Down or Left/Right: Navigate through list items
- Left/Right (when first item selected): Switch between tabs
- Confirm: Open selected book or enter directory
- Back: Go up directory (Files tab) or return home
- Long press Back: Jump to root directory (Files tab)
**UI Elements:**
- Tab bar with selection indicator
- Scroll/page indicator on right side
- Side button hints (up/down arrows)
- Dynamic bottom button labels ("BACK" in subdirectories, "HOME" at
root)
## Tab Bar Usage
The tab bar component is designed to be reusable across different
activities. Here's how to use it:
### Basic Example
```cpp
#include "ScreenComponents.h"
void MyActivity::render() const {
renderer.clearScreen();
// Define tabs with labels and selection state
std::vector<TabInfo> tabs = {
{"Tab One", currentTab == 0}, // Selected when currentTab is 0
{"Tab Two", currentTab == 1}, // Selected when currentTab is 1
{"Tab Three", currentTab == 2} // Selected when currentTab is 2
};
// Draw tab bar at Y position 15, returns height of the tab bar
int tabBarHeight = ScreenComponents::drawTabBar(renderer, 15, tabs);
// Position your content below the tab bar
int contentStartY = 15 + tabBarHeight + 10; // Add some padding
// Draw content based on selected tab
if (currentTab == 0) {
renderTabOneContent(contentStartY);
} else if (currentTab == 1) {
renderTabTwoContent(contentStartY);
} else {
renderTabThreeContent(contentStartY);
}
renderer.displayBuffer();
}
```
Video Demo: https://share.cleanshot.com/P6NBncFS
<img width="250"
src="https://github.com/user-attachments/assets/07de4418-968e-4a88-9b42-ac5f53d8a832"
/>
<img width="250"
src="https://github.com/user-attachments/assets/e40201ed-dcc8-4568-b008-cd2bf13ebb2a"
/>
<img width="250"
src="https://github.com/user-attachments/assets/73db269f-e629-4696-b8ca-0b8443451a05"
/>
---------
Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-21 05:38:38 -06:00
|
|
|
const int myLibraryIdx = idx++;
|
2026-01-07 03:58:37 -05:00
|
|
|
const int opdsLibraryIdx = hasOpdsUrl ? idx++ : -1;
|
|
|
|
|
const int fileTransferIdx = idx++;
|
|
|
|
|
const int settingsIdx = idx;
|
|
|
|
|
|
|
|
|
|
if (selectorIndex == continueIdx) {
|
|
|
|
|
onContinueReading();
|
My Library: Tab bar w/ Recent Books + File Browser (#250)
# Summary
This PR introduces a reusable Tab Bar component and combines the Recent
Books and File Browser into a unified tabbed page called "My Library"
accessible from the Home screen.
## Features
### New Tab Bar Component
A flexible, reusable tab bar component added to `ScreenComponents` that
can be used throughout the application.
### New Scroll Indicator Component
A page position indicator for lists that span multiple pages.
**Features:**
- Up/down arrow indicators
- Current page fraction display (e.g., "1/3")
- Only renders when content spans multiple pages
### My Library Activity
A new unified view combining Recent Books and File Browser into a single
tabbed page.
**Tabs:**
- **Recent** - Shows recently opened books
- **Files** - Browse SD card directory structure
**Navigation:**
- Up/Down or Left/Right: Navigate through list items
- Left/Right (when first item selected): Switch between tabs
- Confirm: Open selected book or enter directory
- Back: Go up directory (Files tab) or return home
- Long press Back: Jump to root directory (Files tab)
**UI Elements:**
- Tab bar with selection indicator
- Scroll/page indicator on right side
- Side button hints (up/down arrows)
- Dynamic bottom button labels ("BACK" in subdirectories, "HOME" at
root)
## Tab Bar Usage
The tab bar component is designed to be reusable across different
activities. Here's how to use it:
### Basic Example
```cpp
#include "ScreenComponents.h"
void MyActivity::render() const {
renderer.clearScreen();
// Define tabs with labels and selection state
std::vector<TabInfo> tabs = {
{"Tab One", currentTab == 0}, // Selected when currentTab is 0
{"Tab Two", currentTab == 1}, // Selected when currentTab is 1
{"Tab Three", currentTab == 2} // Selected when currentTab is 2
};
// Draw tab bar at Y position 15, returns height of the tab bar
int tabBarHeight = ScreenComponents::drawTabBar(renderer, 15, tabs);
// Position your content below the tab bar
int contentStartY = 15 + tabBarHeight + 10; // Add some padding
// Draw content based on selected tab
if (currentTab == 0) {
renderTabOneContent(contentStartY);
} else if (currentTab == 1) {
renderTabTwoContent(contentStartY);
} else {
renderTabThreeContent(contentStartY);
}
renderer.displayBuffer();
}
```
Video Demo: https://share.cleanshot.com/P6NBncFS
<img width="250"
src="https://github.com/user-attachments/assets/07de4418-968e-4a88-9b42-ac5f53d8a832"
/>
<img width="250"
src="https://github.com/user-attachments/assets/e40201ed-dcc8-4568-b008-cd2bf13ebb2a"
/>
<img width="250"
src="https://github.com/user-attachments/assets/73db269f-e629-4696-b8ca-0b8443451a05"
/>
---------
Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-21 05:38:38 -06:00
|
|
|
} else if (selectorIndex == myLibraryIdx) {
|
|
|
|
|
onMyLibraryOpen();
|
2026-01-07 03:58:37 -05:00
|
|
|
} else if (selectorIndex == opdsLibraryIdx) {
|
|
|
|
|
onOpdsBrowserOpen();
|
|
|
|
|
} else if (selectorIndex == fileTransferIdx) {
|
|
|
|
|
onFileTransferOpen();
|
|
|
|
|
} else if (selectorIndex == settingsIdx) {
|
|
|
|
|
onSettingsOpen();
|
2025-12-17 20:47:43 +11:00
|
|
|
}
|
|
|
|
|
} else if (prevPressed) {
|
2025-12-26 09:55:23 +09:00
|
|
|
selectorIndex = (selectorIndex + menuCount - 1) % menuCount;
|
2025-12-17 20:47:43 +11:00
|
|
|
updateRequired = true;
|
|
|
|
|
} else if (nextPressed) {
|
2025-12-26 09:55:23 +09:00
|
|
|
selectorIndex = (selectorIndex + 1) % menuCount;
|
2025-12-17 20:47:43 +11:00
|
|
|
updateRequired = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 23:32:18 +11:00
|
|
|
void HomeActivity::displayTaskLoop() {
|
2025-12-17 20:47:43 +11:00
|
|
|
while (true) {
|
|
|
|
|
if (updateRequired) {
|
|
|
|
|
updateRequired = false;
|
|
|
|
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
|
|
|
|
render();
|
|
|
|
|
xSemaphoreGive(renderingMutex);
|
|
|
|
|
}
|
|
|
|
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
void HomeActivity::render() {
|
|
|
|
|
// If we have a stored cover buffer, restore it instead of clearing
|
|
|
|
|
const bool bufferRestored = coverBufferStored && restoreCoverBuffer();
|
|
|
|
|
if (!bufferRestored) {
|
|
|
|
|
renderer.clearScreen();
|
|
|
|
|
}
|
2025-12-17 20:47:43 +11:00
|
|
|
|
2025-12-22 00:31:25 +11:00
|
|
|
const auto pageWidth = renderer.getScreenWidth();
|
2025-12-30 22:18:10 +10:00
|
|
|
const auto pageHeight = renderer.getScreenHeight();
|
2025-12-17 20:47:43 +11:00
|
|
|
|
2025-12-30 22:18:10 +10:00
|
|
|
constexpr int margin = 20;
|
|
|
|
|
constexpr int bottomMargin = 60;
|
2025-12-26 09:55:23 +09:00
|
|
|
|
2025-12-30 22:18:10 +10:00
|
|
|
// --- Top "book" card for the current title (selectorIndex == 0) ---
|
|
|
|
|
const int bookWidth = pageWidth / 2;
|
|
|
|
|
const int bookHeight = pageHeight / 2;
|
|
|
|
|
const int bookX = (pageWidth - bookWidth) / 2;
|
|
|
|
|
constexpr int bookY = 30;
|
|
|
|
|
const bool bookSelected = hasContinueReading && selectorIndex == 0;
|
|
|
|
|
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
// Bookmark dimensions (used in multiple places)
|
|
|
|
|
const int bookmarkWidth = bookWidth / 8;
|
|
|
|
|
const int bookmarkHeight = bookHeight / 5;
|
|
|
|
|
const int bookmarkX = bookX + bookWidth - bookmarkWidth - 10;
|
|
|
|
|
const int bookmarkY = bookY + 5;
|
|
|
|
|
|
2025-12-30 22:18:10 +10:00
|
|
|
// Draw book card regardless, fill with message based on `hasContinueReading`
|
|
|
|
|
{
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
// Draw cover image as background if available (inside the box)
|
|
|
|
|
// Only load from SD on first render, then use stored buffer
|
|
|
|
|
if (hasContinueReading && hasCoverImage && !coverBmpPath.empty() && !coverRendered) {
|
|
|
|
|
// First time: load cover from SD and render
|
|
|
|
|
FsFile file;
|
|
|
|
|
if (SdMan.openFileForRead("HOME", coverBmpPath, file)) {
|
|
|
|
|
Bitmap bitmap(file);
|
|
|
|
|
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
|
|
|
|
// Calculate position to center image within the book card
|
|
|
|
|
int coverX, coverY;
|
|
|
|
|
|
|
|
|
|
if (bitmap.getWidth() > bookWidth || bitmap.getHeight() > bookHeight) {
|
|
|
|
|
const float imgRatio = static_cast<float>(bitmap.getWidth()) / static_cast<float>(bitmap.getHeight());
|
|
|
|
|
const float boxRatio = static_cast<float>(bookWidth) / static_cast<float>(bookHeight);
|
|
|
|
|
|
|
|
|
|
if (imgRatio > boxRatio) {
|
|
|
|
|
coverX = bookX;
|
|
|
|
|
coverY = bookY + (bookHeight - static_cast<int>(bookWidth / imgRatio)) / 2;
|
|
|
|
|
} else {
|
|
|
|
|
coverX = bookX + (bookWidth - static_cast<int>(bookHeight * imgRatio)) / 2;
|
|
|
|
|
coverY = bookY;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
coverX = bookX + (bookWidth - bitmap.getWidth()) / 2;
|
|
|
|
|
coverY = bookY + (bookHeight - bitmap.getHeight()) / 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Draw the cover image centered within the book card
|
|
|
|
|
renderer.drawBitmap(bitmap, coverX, coverY, bookWidth, bookHeight);
|
|
|
|
|
|
|
|
|
|
// Draw border around the card
|
|
|
|
|
renderer.drawRect(bookX, bookY, bookWidth, bookHeight);
|
|
|
|
|
|
|
|
|
|
// No bookmark ribbon when cover is shown - it would just cover the art
|
|
|
|
|
|
|
|
|
|
// Store the buffer with cover image for fast navigation
|
|
|
|
|
coverBufferStored = storeCoverBuffer();
|
|
|
|
|
coverRendered = true;
|
|
|
|
|
|
|
|
|
|
// First render: if selected, draw selection indicators now
|
|
|
|
|
if (bookSelected) {
|
|
|
|
|
renderer.drawRect(bookX + 1, bookY + 1, bookWidth - 2, bookHeight - 2);
|
|
|
|
|
renderer.drawRect(bookX + 2, bookY + 2, bookWidth - 4, bookHeight - 4);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
file.close();
|
|
|
|
|
}
|
|
|
|
|
} else if (!bufferRestored && !coverRendered) {
|
|
|
|
|
// No cover image: draw border or fill, plus bookmark as visual flair
|
|
|
|
|
if (bookSelected) {
|
|
|
|
|
renderer.fillRect(bookX, bookY, bookWidth, bookHeight);
|
|
|
|
|
} else {
|
|
|
|
|
renderer.drawRect(bookX, bookY, bookWidth, bookHeight);
|
|
|
|
|
}
|
2025-12-30 22:18:10 +10:00
|
|
|
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
// Draw bookmark ribbon when no cover image (visual decoration)
|
|
|
|
|
if (hasContinueReading) {
|
|
|
|
|
const int notchDepth = bookmarkHeight / 3;
|
|
|
|
|
const int centerX = bookmarkX + bookmarkWidth / 2;
|
|
|
|
|
|
|
|
|
|
const int xPoints[5] = {
|
|
|
|
|
bookmarkX, // top-left
|
|
|
|
|
bookmarkX + bookmarkWidth, // top-right
|
|
|
|
|
bookmarkX + bookmarkWidth, // bottom-right
|
|
|
|
|
centerX, // center notch point
|
|
|
|
|
bookmarkX // bottom-left
|
|
|
|
|
};
|
|
|
|
|
const int yPoints[5] = {
|
|
|
|
|
bookmarkY, // top-left
|
|
|
|
|
bookmarkY, // top-right
|
|
|
|
|
bookmarkY + bookmarkHeight, // bottom-right
|
|
|
|
|
bookmarkY + bookmarkHeight - notchDepth, // center notch point
|
|
|
|
|
bookmarkY + bookmarkHeight // bottom-left
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Draw bookmark ribbon (inverted if selected)
|
|
|
|
|
renderer.fillPolygon(xPoints, yPoints, 5, !bookSelected);
|
2025-12-30 22:18:10 +10:00
|
|
|
}
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If buffer was restored, draw selection indicators if needed
|
|
|
|
|
if (bufferRestored && bookSelected && coverRendered) {
|
|
|
|
|
// Draw selection border (no bookmark inversion needed since cover has no bookmark)
|
|
|
|
|
renderer.drawRect(bookX + 1, bookY + 1, bookWidth - 2, bookHeight - 2);
|
|
|
|
|
renderer.drawRect(bookX + 2, bookY + 2, bookWidth - 4, bookHeight - 4);
|
|
|
|
|
} else if (!coverRendered && !bufferRestored) {
|
|
|
|
|
// Selection border already handled above in the no-cover case
|
2025-12-30 22:18:10 +10:00
|
|
|
}
|
|
|
|
|
}
|
2025-12-26 09:55:23 +09:00
|
|
|
|
|
|
|
|
if (hasContinueReading) {
|
2026-01-19 06:57:39 -05:00
|
|
|
// Invert text colors based on selection state:
|
|
|
|
|
// - With cover: selected = white text on black box, unselected = black text on white box
|
|
|
|
|
// - Without cover: selected = white text on black card, unselected = black text on white card
|
|
|
|
|
|
2025-12-30 22:18:10 +10:00
|
|
|
// Split into words (avoid stringstream to keep this light on the MCU)
|
|
|
|
|
std::vector<std::string> words;
|
|
|
|
|
words.reserve(8);
|
|
|
|
|
size_t pos = 0;
|
|
|
|
|
while (pos < lastBookTitle.size()) {
|
|
|
|
|
while (pos < lastBookTitle.size() && lastBookTitle[pos] == ' ') {
|
|
|
|
|
++pos;
|
|
|
|
|
}
|
|
|
|
|
if (pos >= lastBookTitle.size()) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
const size_t start = pos;
|
|
|
|
|
while (pos < lastBookTitle.size() && lastBookTitle[pos] != ' ') {
|
|
|
|
|
++pos;
|
|
|
|
|
}
|
|
|
|
|
words.emplace_back(lastBookTitle.substr(start, pos - start));
|
2025-12-26 09:55:23 +09:00
|
|
|
}
|
2025-12-30 22:18:10 +10:00
|
|
|
|
|
|
|
|
std::vector<std::string> lines;
|
|
|
|
|
std::string currentLine;
|
|
|
|
|
// Extra padding inside the card so text doesn't hug the border
|
|
|
|
|
const int maxLineWidth = bookWidth - 40;
|
|
|
|
|
const int spaceWidth = renderer.getSpaceWidth(UI_12_FONT_ID);
|
|
|
|
|
|
|
|
|
|
for (auto& i : words) {
|
|
|
|
|
// If we just hit the line limit (3), stop processing words
|
|
|
|
|
if (lines.size() >= 3) {
|
|
|
|
|
// Limit to 3 lines
|
|
|
|
|
// Still have words left, so add ellipsis to last line
|
|
|
|
|
lines.back().append("...");
|
|
|
|
|
|
|
|
|
|
while (!lines.back().empty() && renderer.getTextWidth(UI_12_FONT_ID, lines.back().c_str()) > maxLineWidth) {
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
// Remove "..." first, then remove one UTF-8 char, then add "..." back
|
|
|
|
|
lines.back().resize(lines.back().size() - 3); // Remove "..."
|
2026-02-01 16:23:48 +05:00
|
|
|
utf8RemoveLastChar(lines.back());
|
2025-12-30 22:18:10 +10:00
|
|
|
lines.back().append("...");
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int wordWidth = renderer.getTextWidth(UI_12_FONT_ID, i.c_str());
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
while (wordWidth > maxLineWidth && !i.empty()) {
|
|
|
|
|
// Word itself is too long, trim it (UTF-8 safe)
|
2026-02-01 16:23:48 +05:00
|
|
|
utf8RemoveLastChar(i);
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
// Check if we have room for ellipsis
|
|
|
|
|
std::string withEllipsis = i + "...";
|
|
|
|
|
wordWidth = renderer.getTextWidth(UI_12_FONT_ID, withEllipsis.c_str());
|
|
|
|
|
if (wordWidth <= maxLineWidth) {
|
|
|
|
|
i = withEllipsis;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2025-12-30 22:18:10 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int newLineWidth = renderer.getTextWidth(UI_12_FONT_ID, currentLine.c_str());
|
|
|
|
|
if (newLineWidth > 0) {
|
|
|
|
|
newLineWidth += spaceWidth;
|
|
|
|
|
}
|
|
|
|
|
newLineWidth += wordWidth;
|
|
|
|
|
|
|
|
|
|
if (newLineWidth > maxLineWidth && !currentLine.empty()) {
|
|
|
|
|
// New line too long, push old line
|
|
|
|
|
lines.push_back(currentLine);
|
|
|
|
|
currentLine = i;
|
|
|
|
|
} else {
|
|
|
|
|
currentLine.append(" ").append(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If lower than the line limit, push remaining words
|
|
|
|
|
if (!currentLine.empty() && lines.size() < 3) {
|
|
|
|
|
lines.push_back(currentLine);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Book title text
|
|
|
|
|
int totalTextHeight = renderer.getLineHeight(UI_12_FONT_ID) * static_cast<int>(lines.size());
|
|
|
|
|
if (!lastBookAuthor.empty()) {
|
|
|
|
|
totalTextHeight += renderer.getLineHeight(UI_10_FONT_ID) * 3 / 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Vertically center the title block within the card
|
|
|
|
|
int titleYStart = bookY + (bookHeight - totalTextHeight) / 2;
|
|
|
|
|
|
2026-01-19 06:57:39 -05:00
|
|
|
// If cover image was rendered, draw box behind title and author
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
if (coverRendered) {
|
|
|
|
|
constexpr int boxPadding = 8;
|
|
|
|
|
// Calculate the max text width for the box
|
|
|
|
|
int maxTextWidth = 0;
|
|
|
|
|
for (const auto& line : lines) {
|
|
|
|
|
const int lineWidth = renderer.getTextWidth(UI_12_FONT_ID, line.c_str());
|
|
|
|
|
if (lineWidth > maxTextWidth) {
|
|
|
|
|
maxTextWidth = lineWidth;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!lastBookAuthor.empty()) {
|
|
|
|
|
std::string trimmedAuthor = lastBookAuthor;
|
|
|
|
|
while (renderer.getTextWidth(UI_10_FONT_ID, trimmedAuthor.c_str()) > maxLineWidth && !trimmedAuthor.empty()) {
|
2026-02-01 16:23:48 +05:00
|
|
|
utf8RemoveLastChar(trimmedAuthor);
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
}
|
|
|
|
|
if (renderer.getTextWidth(UI_10_FONT_ID, trimmedAuthor.c_str()) <
|
|
|
|
|
renderer.getTextWidth(UI_10_FONT_ID, lastBookAuthor.c_str())) {
|
|
|
|
|
trimmedAuthor.append("...");
|
|
|
|
|
}
|
|
|
|
|
const int authorWidth = renderer.getTextWidth(UI_10_FONT_ID, trimmedAuthor.c_str());
|
|
|
|
|
if (authorWidth > maxTextWidth) {
|
|
|
|
|
maxTextWidth = authorWidth;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const int boxWidth = maxTextWidth + boxPadding * 2;
|
|
|
|
|
const int boxHeight = totalTextHeight + boxPadding * 2;
|
|
|
|
|
const int boxX = (pageWidth - boxWidth) / 2;
|
|
|
|
|
const int boxY = titleYStart - boxPadding;
|
|
|
|
|
|
2026-01-19 06:57:39 -05:00
|
|
|
// Draw box (inverted when selected: black box instead of white)
|
|
|
|
|
renderer.fillRect(boxX, boxY, boxWidth, boxHeight, bookSelected);
|
|
|
|
|
// Draw border around the box (inverted when selected: white border instead of black)
|
|
|
|
|
renderer.drawRect(boxX, boxY, boxWidth, boxHeight, !bookSelected);
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
}
|
|
|
|
|
|
2025-12-30 22:18:10 +10:00
|
|
|
for (const auto& line : lines) {
|
2026-01-19 06:57:39 -05:00
|
|
|
renderer.drawCenteredText(UI_12_FONT_ID, titleYStart, line.c_str(), !bookSelected);
|
2025-12-30 22:18:10 +10:00
|
|
|
titleYStart += renderer.getLineHeight(UI_12_FONT_ID);
|
2025-12-26 09:55:23 +09:00
|
|
|
}
|
2025-12-29 13:18:23 +01:00
|
|
|
|
2025-12-30 22:18:10 +10:00
|
|
|
if (!lastBookAuthor.empty()) {
|
|
|
|
|
titleYStart += renderer.getLineHeight(UI_10_FONT_ID) / 2;
|
|
|
|
|
std::string trimmedAuthor = lastBookAuthor;
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
// Trim author if too long (UTF-8 safe)
|
|
|
|
|
bool wasTrimmed = false;
|
2025-12-30 22:18:10 +10:00
|
|
|
while (renderer.getTextWidth(UI_10_FONT_ID, trimmedAuthor.c_str()) > maxLineWidth && !trimmedAuthor.empty()) {
|
2026-02-01 16:23:48 +05:00
|
|
|
utf8RemoveLastChar(trimmedAuthor);
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
wasTrimmed = true;
|
|
|
|
|
}
|
|
|
|
|
if (wasTrimmed && !trimmedAuthor.empty()) {
|
|
|
|
|
// Make room for ellipsis
|
|
|
|
|
while (renderer.getTextWidth(UI_10_FONT_ID, (trimmedAuthor + "...").c_str()) > maxLineWidth &&
|
|
|
|
|
!trimmedAuthor.empty()) {
|
2026-02-01 16:23:48 +05:00
|
|
|
utf8RemoveLastChar(trimmedAuthor);
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
}
|
2025-12-30 22:18:10 +10:00
|
|
|
trimmedAuthor.append("...");
|
|
|
|
|
}
|
2026-01-19 06:57:39 -05:00
|
|
|
renderer.drawCenteredText(UI_10_FONT_ID, titleYStart, trimmedAuthor.c_str(), !bookSelected);
|
2025-12-29 13:18:23 +01:00
|
|
|
}
|
|
|
|
|
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
// "Continue Reading" label at the bottom
|
|
|
|
|
const int continueY = bookY + bookHeight - renderer.getLineHeight(UI_10_FONT_ID) * 3 / 2;
|
|
|
|
|
if (coverRendered) {
|
2026-01-19 06:57:39 -05:00
|
|
|
// Draw box behind "Continue Reading" text (inverted when selected: black box instead of white)
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
const char* continueText = "Continue Reading";
|
|
|
|
|
const int continueTextWidth = renderer.getTextWidth(UI_10_FONT_ID, continueText);
|
|
|
|
|
constexpr int continuePadding = 6;
|
|
|
|
|
const int continueBoxWidth = continueTextWidth + continuePadding * 2;
|
|
|
|
|
const int continueBoxHeight = renderer.getLineHeight(UI_10_FONT_ID) + continuePadding;
|
|
|
|
|
const int continueBoxX = (pageWidth - continueBoxWidth) / 2;
|
|
|
|
|
const int continueBoxY = continueY - continuePadding / 2;
|
2026-01-19 06:57:39 -05:00
|
|
|
renderer.fillRect(continueBoxX, continueBoxY, continueBoxWidth, continueBoxHeight, bookSelected);
|
|
|
|
|
renderer.drawRect(continueBoxX, continueBoxY, continueBoxWidth, continueBoxHeight, !bookSelected);
|
|
|
|
|
renderer.drawCenteredText(UI_10_FONT_ID, continueY, continueText, !bookSelected);
|
Add cover image display in *Continue Reading* card with framebuffer caching (#200)
## Summary
* **What is the goal of this PR?** (e.g., Fixes a bug in the user
authentication module,
Display the book cover image in the **"Continue Reading"** card on the
home screen, with fast navigation using framebuffer caching.
* **What changes are included?**
- Display book cover image in the "Continue Reading" card on home screen
- Load cover from cached BMP (same as sleep screen cover)
- Add framebuffer store/restore functions (`copyStoredBwBuffer`,
`freeStoredBwBuffer`) for fast navigation after initial render
- Fix `drawBitmap` scaling bug: apply scale to offset only, not to base
coordinates
- Add white text boxes behind title/author/continue reading label for
readability on cover
- Support both EPUB and XTC file cover images
- Increase HomeActivity task stack size from 2048 to 4096 for cover
image rendering
## Additional Context
* Add any other information that might be helpful for the reviewer
(e.g., performance implications, potential risks, specific areas to
focus on).
- Performance: First render loads cover from SD card (~800ms),
subsequent navigation uses cached framebuffer (~instant)
- Memory: Framebuffer cache uses ~48KB (6 chunks × 8KB) while on home
screen, freed on exit
- Fallback: If cover image is not available, falls back to standard
text-only display
- The `drawBitmap` fix corrects a bug where screenY = (y + offset) scale
was incorrectly scaling the base coordinates. Now correctly uses screenY
= y + (offset scale)
2026-01-14 19:24:02 +09:00
|
|
|
} else {
|
|
|
|
|
renderer.drawCenteredText(UI_10_FONT_ID, continueY, "Continue Reading", !bookSelected);
|
|
|
|
|
}
|
2025-12-30 22:18:10 +10:00
|
|
|
} else {
|
|
|
|
|
// No book to continue reading
|
|
|
|
|
const int y =
|
|
|
|
|
bookY + (bookHeight - renderer.getLineHeight(UI_12_FONT_ID) - renderer.getLineHeight(UI_10_FONT_ID)) / 2;
|
|
|
|
|
renderer.drawCenteredText(UI_12_FONT_ID, y, "No open book");
|
|
|
|
|
renderer.drawCenteredText(UI_10_FONT_ID, y + renderer.getLineHeight(UI_12_FONT_ID), "Start reading below");
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-07 03:58:37 -05:00
|
|
|
// --- Bottom menu tiles ---
|
|
|
|
|
// Build menu items dynamically
|
My Library: Tab bar w/ Recent Books + File Browser (#250)
# Summary
This PR introduces a reusable Tab Bar component and combines the Recent
Books and File Browser into a unified tabbed page called "My Library"
accessible from the Home screen.
## Features
### New Tab Bar Component
A flexible, reusable tab bar component added to `ScreenComponents` that
can be used throughout the application.
### New Scroll Indicator Component
A page position indicator for lists that span multiple pages.
**Features:**
- Up/down arrow indicators
- Current page fraction display (e.g., "1/3")
- Only renders when content spans multiple pages
### My Library Activity
A new unified view combining Recent Books and File Browser into a single
tabbed page.
**Tabs:**
- **Recent** - Shows recently opened books
- **Files** - Browse SD card directory structure
**Navigation:**
- Up/Down or Left/Right: Navigate through list items
- Left/Right (when first item selected): Switch between tabs
- Confirm: Open selected book or enter directory
- Back: Go up directory (Files tab) or return home
- Long press Back: Jump to root directory (Files tab)
**UI Elements:**
- Tab bar with selection indicator
- Scroll/page indicator on right side
- Side button hints (up/down arrows)
- Dynamic bottom button labels ("BACK" in subdirectories, "HOME" at
root)
## Tab Bar Usage
The tab bar component is designed to be reusable across different
activities. Here's how to use it:
### Basic Example
```cpp
#include "ScreenComponents.h"
void MyActivity::render() const {
renderer.clearScreen();
// Define tabs with labels and selection state
std::vector<TabInfo> tabs = {
{"Tab One", currentTab == 0}, // Selected when currentTab is 0
{"Tab Two", currentTab == 1}, // Selected when currentTab is 1
{"Tab Three", currentTab == 2} // Selected when currentTab is 2
};
// Draw tab bar at Y position 15, returns height of the tab bar
int tabBarHeight = ScreenComponents::drawTabBar(renderer, 15, tabs);
// Position your content below the tab bar
int contentStartY = 15 + tabBarHeight + 10; // Add some padding
// Draw content based on selected tab
if (currentTab == 0) {
renderTabOneContent(contentStartY);
} else if (currentTab == 1) {
renderTabTwoContent(contentStartY);
} else {
renderTabThreeContent(contentStartY);
}
renderer.displayBuffer();
}
```
Video Demo: https://share.cleanshot.com/P6NBncFS
<img width="250"
src="https://github.com/user-attachments/assets/07de4418-968e-4a88-9b42-ac5f53d8a832"
/>
<img width="250"
src="https://github.com/user-attachments/assets/e40201ed-dcc8-4568-b008-cd2bf13ebb2a"
/>
<img width="250"
src="https://github.com/user-attachments/assets/73db269f-e629-4696-b8ca-0b8443451a05"
/>
---------
Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-21 05:38:38 -06:00
|
|
|
std::vector<const char*> menuItems = {"My Library", "File Transfer", "Settings"};
|
2026-01-07 03:58:37 -05:00
|
|
|
if (hasOpdsUrl) {
|
2026-01-27 06:02:38 -05:00
|
|
|
// Insert OPDS Browser after My Library
|
|
|
|
|
menuItems.insert(menuItems.begin() + 1, "OPDS Browser");
|
2026-01-07 03:58:37 -05:00
|
|
|
}
|
|
|
|
|
|
2025-12-30 22:18:10 +10:00
|
|
|
const int menuTileWidth = pageWidth - 2 * margin;
|
2026-01-07 03:58:37 -05:00
|
|
|
constexpr int menuTileHeight = 45;
|
|
|
|
|
constexpr int menuSpacing = 8;
|
|
|
|
|
const int totalMenuHeight =
|
|
|
|
|
static_cast<int>(menuItems.size()) * menuTileHeight + (static_cast<int>(menuItems.size()) - 1) * menuSpacing;
|
2025-12-30 22:18:10 +10:00
|
|
|
|
2026-01-07 03:58:37 -05:00
|
|
|
int menuStartY = bookY + bookHeight + 15;
|
2025-12-30 22:18:10 +10:00
|
|
|
// Ensure we don't collide with the bottom button legend
|
|
|
|
|
const int maxMenuStartY = pageHeight - bottomMargin - totalMenuHeight - margin;
|
|
|
|
|
if (menuStartY > maxMenuStartY) {
|
|
|
|
|
menuStartY = maxMenuStartY;
|
2025-12-26 09:55:23 +09:00
|
|
|
}
|
|
|
|
|
|
2026-01-07 03:58:37 -05:00
|
|
|
for (size_t i = 0; i < menuItems.size(); ++i) {
|
|
|
|
|
const int overallIndex = static_cast<int>(i) + (hasContinueReading ? 1 : 0);
|
2025-12-30 22:18:10 +10:00
|
|
|
constexpr int tileX = margin;
|
2026-01-07 03:58:37 -05:00
|
|
|
const int tileY = menuStartY + static_cast<int>(i) * (menuTileHeight + menuSpacing);
|
2025-12-30 22:18:10 +10:00
|
|
|
const bool selected = selectorIndex == overallIndex;
|
|
|
|
|
|
|
|
|
|
if (selected) {
|
|
|
|
|
renderer.fillRect(tileX, tileY, menuTileWidth, menuTileHeight);
|
|
|
|
|
} else {
|
|
|
|
|
renderer.drawRect(tileX, tileY, menuTileWidth, menuTileHeight);
|
|
|
|
|
}
|
2025-12-26 09:55:23 +09:00
|
|
|
|
2026-01-07 03:58:37 -05:00
|
|
|
const char* label = menuItems[i];
|
2025-12-30 22:18:10 +10:00
|
|
|
const int textWidth = renderer.getTextWidth(UI_10_FONT_ID, label);
|
|
|
|
|
const int textX = tileX + (menuTileWidth - textWidth) / 2;
|
|
|
|
|
const int lineHeight = renderer.getLineHeight(UI_10_FONT_ID);
|
|
|
|
|
const int textY = tileY + (menuTileHeight - lineHeight) / 2; // vertically centered assuming y is top of text
|
2025-12-26 09:55:23 +09:00
|
|
|
|
2025-12-30 22:18:10 +10:00
|
|
|
// Invert text when the tile is selected, to contrast with the filled background
|
|
|
|
|
renderer.drawText(UI_10_FONT_ID, textX, textY, label, !selected);
|
|
|
|
|
}
|
2025-12-17 20:47:43 +11:00
|
|
|
|
My Library: Tab bar w/ Recent Books + File Browser (#250)
# Summary
This PR introduces a reusable Tab Bar component and combines the Recent
Books and File Browser into a unified tabbed page called "My Library"
accessible from the Home screen.
## Features
### New Tab Bar Component
A flexible, reusable tab bar component added to `ScreenComponents` that
can be used throughout the application.
### New Scroll Indicator Component
A page position indicator for lists that span multiple pages.
**Features:**
- Up/down arrow indicators
- Current page fraction display (e.g., "1/3")
- Only renders when content spans multiple pages
### My Library Activity
A new unified view combining Recent Books and File Browser into a single
tabbed page.
**Tabs:**
- **Recent** - Shows recently opened books
- **Files** - Browse SD card directory structure
**Navigation:**
- Up/Down or Left/Right: Navigate through list items
- Left/Right (when first item selected): Switch between tabs
- Confirm: Open selected book or enter directory
- Back: Go up directory (Files tab) or return home
- Long press Back: Jump to root directory (Files tab)
**UI Elements:**
- Tab bar with selection indicator
- Scroll/page indicator on right side
- Side button hints (up/down arrows)
- Dynamic bottom button labels ("BACK" in subdirectories, "HOME" at
root)
## Tab Bar Usage
The tab bar component is designed to be reusable across different
activities. Here's how to use it:
### Basic Example
```cpp
#include "ScreenComponents.h"
void MyActivity::render() const {
renderer.clearScreen();
// Define tabs with labels and selection state
std::vector<TabInfo> tabs = {
{"Tab One", currentTab == 0}, // Selected when currentTab is 0
{"Tab Two", currentTab == 1}, // Selected when currentTab is 1
{"Tab Three", currentTab == 2} // Selected when currentTab is 2
};
// Draw tab bar at Y position 15, returns height of the tab bar
int tabBarHeight = ScreenComponents::drawTabBar(renderer, 15, tabs);
// Position your content below the tab bar
int contentStartY = 15 + tabBarHeight + 10; // Add some padding
// Draw content based on selected tab
if (currentTab == 0) {
renderTabOneContent(contentStartY);
} else if (currentTab == 1) {
renderTabTwoContent(contentStartY);
} else {
renderTabThreeContent(contentStartY);
}
renderer.displayBuffer();
}
```
Video Demo: https://share.cleanshot.com/P6NBncFS
<img width="250"
src="https://github.com/user-attachments/assets/07de4418-968e-4a88-9b42-ac5f53d8a832"
/>
<img width="250"
src="https://github.com/user-attachments/assets/e40201ed-dcc8-4568-b008-cd2bf13ebb2a"
/>
<img width="250"
src="https://github.com/user-attachments/assets/73db269f-e629-4696-b8ca-0b8443451a05"
/>
---------
Co-authored-by: Dave Allie <dave@daveallie.com>
2026-01-21 05:38:38 -06:00
|
|
|
const auto labels = mappedInput.mapLabels("", "Select", "Up", "Down");
|
Aleo, Noto Sans, Open Dyslexic fonts (#163)
## Summary
* Swap out Bookerly font due to licensing issues, replace default font
with Aleo
* I did a bunch of searching around for a nice replacement font, and
this trumped several other like Literata, Merriwether, Vollkorn, etc
* Add Noto Sans, and Open Dyslexic as font options
* They can be selected in the settings screen
* Add font size options (Small, Medium, Large, Extra Large)
* Adjustable in settings
* Swap out uses of reader font in headings and replaced with slightly
larger Ubuntu font
* Replaced PixelArial14 font as it was difficult to track down, replace
with Space Grotesk
* Remove auto formatting on generated font files
* Massively speeds up formatting step now that there is a lot more CPP
font source
* Include fonts with their licenses in the repo
## Additional Context
Line compression setting will follow
| Font | Small | Medium | Large | X Large |
| --- | --- | --- | --- | --- |
| Aleo |

|

|

|

|
| Noto Sans |

|

|

|

|
| Open Dyslexic |

|

|

|

|
2025-12-30 18:21:47 +10:00
|
|
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
2025-12-17 20:47:43 +11:00
|
|
|
|
2026-01-12 10:53:58 +01:00
|
|
|
const bool showBatteryPercentage =
|
|
|
|
|
SETTINGS.hideBatteryPercentage != CrossPointSettings::HIDE_BATTERY_PERCENTAGE::HIDE_ALWAYS;
|
|
|
|
|
// get percentage so we can align text properly
|
|
|
|
|
const uint16_t percentage = battery.readPercentage();
|
|
|
|
|
const auto percentageText = showBatteryPercentage ? std::to_string(percentage) + "%" : "";
|
|
|
|
|
const auto batteryX = pageWidth - 25 - renderer.getTextWidth(SMALL_FONT_ID, percentageText.c_str());
|
|
|
|
|
ScreenComponents::drawBattery(renderer, batteryX, 10, showBatteryPercentage);
|
2025-12-30 22:41:47 +10:00
|
|
|
|
2025-12-17 20:47:43 +11:00
|
|
|
renderer.displayBuffer();
|
|
|
|
|
}
|