fix: Scrolling page items calculation (#716)

## Summary

Fix for the page skip issue detected
https://github.com/crosspoint-reader/crosspoint-reader/pull/700#issuecomment-3856374323
by user @whyte-j

Skipping down on the last page now skips to the last item, and up on the
first page to the first item, rather than wrapping around the list in a
weird way.

## Additional Context

The calculation was outdated after several changes were added afterwards

---

### 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? _**NO**_
This commit is contained in:
CaptainFrito
2026-02-09 00:58:46 +07:00
committed by Dave Allie
parent b45eaf7ded
commit bb983d0ef4
4 changed files with 14 additions and 10 deletions

View File

@@ -3,6 +3,8 @@
#include <GfxRenderer.h> #include <GfxRenderer.h>
#include <SDCardManager.h> #include <SDCardManager.h>
#include <algorithm>
#include "MappedInputManager.h" #include "MappedInputManager.h"
#include "components/UITheme.h" #include "components/UITheme.h"
#include "fontIds.h" #include "fontIds.h"
@@ -114,7 +116,7 @@ void MyLibraryActivity::loop() {
mappedInput.wasReleased(MappedInputManager::Button::Down); mappedInput.wasReleased(MappedInputManager::Button::Down);
const bool skipPage = mappedInput.getHeldTime() > SKIP_PAGE_MS; const bool skipPage = mappedInput.getHeldTime() > SKIP_PAGE_MS;
const int pageItems = UITheme::getInstance().getNumberOfItemsPerPage(renderer, true, false, true, true); const int pageItems = UITheme::getInstance().getNumberOfItemsPerPage(renderer, true, false, true, false);
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
if (files.empty()) { if (files.empty()) {
@@ -157,14 +159,14 @@ void MyLibraryActivity::loop() {
int listSize = static_cast<int>(files.size()); int listSize = static_cast<int>(files.size());
if (upReleased) { if (upReleased) {
if (skipPage) { if (skipPage) {
selectorIndex = ((selectorIndex / pageItems - 1) * pageItems + listSize) % listSize; selectorIndex = std::max(static_cast<int>((selectorIndex / pageItems - 1) * pageItems), 0);
} else { } else {
selectorIndex = (selectorIndex + listSize - 1) % listSize; selectorIndex = (selectorIndex + listSize - 1) % listSize;
} }
updateRequired = true; updateRequired = true;
} else if (downReleased) { } else if (downReleased) {
if (skipPage) { if (skipPage) {
selectorIndex = ((selectorIndex / pageItems + 1) * pageItems) % listSize; selectorIndex = std::min(static_cast<int>((selectorIndex / pageItems + 1) * pageItems), listSize - 1);
} else { } else {
selectorIndex = (selectorIndex + 1) % listSize; selectorIndex = (selectorIndex + 1) % listSize;
} }
@@ -195,7 +197,7 @@ void MyLibraryActivity::render() const {
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, folderName); GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, folderName);
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing; const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing * 2; const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing;
if (files.empty()) { if (files.empty()) {
renderer.drawText(UI_10_FONT_ID, metrics.contentSidePadding, contentTop + 20, "No books found"); renderer.drawText(UI_10_FONT_ID, metrics.contentSidePadding, contentTop + 20, "No books found");
} else { } else {

View File

@@ -3,6 +3,8 @@
#include <GfxRenderer.h> #include <GfxRenderer.h>
#include <SDCardManager.h> #include <SDCardManager.h>
#include <algorithm>
#include "MappedInputManager.h" #include "MappedInputManager.h"
#include "RecentBooksStore.h" #include "RecentBooksStore.h"
#include "components/UITheme.h" #include "components/UITheme.h"
@@ -92,14 +94,14 @@ void RecentBooksActivity::loop() {
int listSize = static_cast<int>(recentBooks.size()); int listSize = static_cast<int>(recentBooks.size());
if (upReleased) { if (upReleased) {
if (skipPage) { if (skipPage) {
selectorIndex = ((selectorIndex / pageItems - 1) * pageItems + listSize) % listSize; selectorIndex = std::max(static_cast<int>((selectorIndex / pageItems - 1) * pageItems), 0);
} else { } else {
selectorIndex = (selectorIndex + listSize - 1) % listSize; selectorIndex = (selectorIndex + listSize - 1) % listSize;
} }
updateRequired = true; updateRequired = true;
} else if (downReleased) { } else if (downReleased) {
if (skipPage) { if (skipPage) {
selectorIndex = ((selectorIndex / pageItems + 1) * pageItems) % listSize; selectorIndex = std::min(static_cast<int>((selectorIndex / pageItems + 1) * pageItems), listSize - 1);
} else { } else {
selectorIndex = (selectorIndex + 1) % listSize; selectorIndex = (selectorIndex + 1) % listSize;
} }
@@ -129,7 +131,7 @@ void RecentBooksActivity::render() const {
GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, "Recent Books"); GUI.drawHeader(renderer, Rect{0, metrics.topPadding, pageWidth, metrics.headerHeight}, "Recent Books");
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing; const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing * 2; const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing;
// Recent tab // Recent tab
if (recentBooks.empty()) { if (recentBooks.empty()) {

View File

@@ -40,10 +40,10 @@ int UITheme::getNumberOfItemsPerPage(const GfxRenderer& renderer, bool hasHeader
const ThemeMetrics& metrics = UITheme::getInstance().getMetrics(); const ThemeMetrics& metrics = UITheme::getInstance().getMetrics();
int reservedHeight = metrics.topPadding; int reservedHeight = metrics.topPadding;
if (hasHeader) { if (hasHeader) {
reservedHeight += metrics.headerHeight; reservedHeight += metrics.headerHeight + metrics.verticalSpacing;
} }
if (hasTabBar) { if (hasTabBar) {
reservedHeight += metrics.tabBarHeight + metrics.verticalSpacing; reservedHeight += metrics.tabBarHeight;
} }
if (hasButtonHints) { if (hasButtonHints) {
reservedHeight += metrics.verticalSpacing + metrics.buttonHintsHeight; reservedHeight += metrics.verticalSpacing + metrics.buttonHintsHeight;

View File

@@ -174,7 +174,7 @@ void BaseTheme::drawList(const GfxRenderer& renderer, Rect rect, int itemCount,
const int centerX = rect.x + rect.width - indicatorWidth / 2 - margin; const int centerX = rect.x + rect.width - indicatorWidth / 2 - margin;
const int indicatorTop = rect.y; // Offset to avoid overlapping side button hints const int indicatorTop = rect.y; // Offset to avoid overlapping side button hints
const int indicatorBottom = rect.y + rect.height - 30; const int indicatorBottom = rect.y + rect.height - arrowSize;
// Draw up arrow at top (^) - narrow point at top, wide base at bottom // Draw up arrow at top (^) - narrow point at top, wide base at bottom
for (int i = 0; i < arrowSize; ++i) { for (int i = 0; i < arrowSize; ++i) {