## Summary Extract shared reader utilities (`ReaderUtils.h`) to reduce duplication across `EpubReaderActivity`, `TxtReaderActivity`, and (upcoming) `MarkdownReaderActivity`. Utilities extracted: - `applyOrientation()` — orientation switch logic - `detectPageTurn()` — page navigation input detection - `renderAntiAliased()` — grayscale anti-aliasing pass - `displayWithRefreshCycle()` — refresh mode cadence - `GO_HOME_MS` — back button timing constant ## Impact Flash: 32 bytes saved (6006441 → 6006409 bytes). Minimal immediate gain, but meaningful once markdown reader and future reader types share these functions. Code quality: Eliminates ~100 lines of duplicated logic spread across multiple files. All readers now follow the same patterns for orientation, input handling, and rendering. ## Rationale This refactor is preparation for markdown support, which requires identical input and rendering logic. Instead of copy-pasting these patterns a third time, all readers now share a single, tested implementation. Future reader types can reuse `ReaderUtils` without duplication. --- ## AI Usage Did you use AI tools to help write this code? YES Claude extracted the code, under my guidance. Tested on my device and seems to work fine.
90 lines
3.2 KiB
C++
90 lines
3.2 KiB
C++
#pragma once
|
|
|
|
#include <CrossPointSettings.h>
|
|
#include <GfxRenderer.h>
|
|
#include <Logging.h>
|
|
|
|
#include "MappedInputManager.h"
|
|
|
|
namespace ReaderUtils {
|
|
|
|
constexpr unsigned long GO_HOME_MS = 1000;
|
|
|
|
inline void applyOrientation(GfxRenderer& renderer, const uint8_t orientation) {
|
|
switch (orientation) {
|
|
case CrossPointSettings::ORIENTATION::PORTRAIT:
|
|
renderer.setOrientation(GfxRenderer::Orientation::Portrait);
|
|
break;
|
|
case CrossPointSettings::ORIENTATION::LANDSCAPE_CW:
|
|
renderer.setOrientation(GfxRenderer::Orientation::LandscapeClockwise);
|
|
break;
|
|
case CrossPointSettings::ORIENTATION::INVERTED:
|
|
renderer.setOrientation(GfxRenderer::Orientation::PortraitInverted);
|
|
break;
|
|
case CrossPointSettings::ORIENTATION::LANDSCAPE_CCW:
|
|
renderer.setOrientation(GfxRenderer::Orientation::LandscapeCounterClockwise);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
struct PageTurnResult {
|
|
bool prev;
|
|
bool next;
|
|
};
|
|
|
|
inline PageTurnResult detectPageTurn(const MappedInputManager& input) {
|
|
const bool usePress = !SETTINGS.longPressChapterSkip;
|
|
const bool prev = usePress ? (input.wasPressed(MappedInputManager::Button::PageBack) ||
|
|
input.wasPressed(MappedInputManager::Button::Left))
|
|
: (input.wasReleased(MappedInputManager::Button::PageBack) ||
|
|
input.wasReleased(MappedInputManager::Button::Left));
|
|
const bool powerTurn = SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::PAGE_TURN &&
|
|
input.wasReleased(MappedInputManager::Button::Power);
|
|
const bool next = usePress ? (input.wasPressed(MappedInputManager::Button::PageForward) || powerTurn ||
|
|
input.wasPressed(MappedInputManager::Button::Right))
|
|
: (input.wasReleased(MappedInputManager::Button::PageForward) || powerTurn ||
|
|
input.wasReleased(MappedInputManager::Button::Right));
|
|
return {prev, next};
|
|
}
|
|
|
|
inline void displayWithRefreshCycle(const GfxRenderer& renderer, int& pagesUntilFullRefresh) {
|
|
if (pagesUntilFullRefresh <= 1) {
|
|
renderer.displayBuffer(HalDisplay::HALF_REFRESH);
|
|
pagesUntilFullRefresh = SETTINGS.getRefreshFrequency();
|
|
} else {
|
|
renderer.displayBuffer();
|
|
pagesUntilFullRefresh--;
|
|
}
|
|
}
|
|
|
|
// Grayscale anti-aliasing pass. Renders content twice (LSB + MSB) to build
|
|
// the grayscale buffer. Only the content callback is re-rendered — status bars
|
|
// and other overlays should be drawn before calling this.
|
|
// Kept as a template to avoid std::function overhead; instantiated once per reader type.
|
|
template <typename RenderFn>
|
|
void renderAntiAliased(GfxRenderer& renderer, RenderFn&& renderFn) {
|
|
if (!renderer.storeBwBuffer()) {
|
|
LOG_ERR("READER", "Failed to store BW buffer for anti-aliasing");
|
|
return;
|
|
}
|
|
|
|
renderer.clearScreen(0x00);
|
|
renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB);
|
|
renderFn();
|
|
renderer.copyGrayscaleLsbBuffers();
|
|
|
|
renderer.clearScreen(0x00);
|
|
renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB);
|
|
renderFn();
|
|
renderer.copyGrayscaleMsbBuffers();
|
|
|
|
renderer.displayGrayBuffer();
|
|
renderer.setRenderMode(GfxRenderer::BW);
|
|
|
|
renderer.restoreBwBuffer();
|
|
}
|
|
|
|
} // namespace ReaderUtils
|