mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-06 23:57:39 +03:00
Add cover art picker setting and update file handling accordingly
- Added new `useCoverArtPicker` setting to CrossPointSettings. - Updated saveToFile and loadFromFile methods to handle the new setting. - Modified ReaderActivity to use CoverArtPickerActivity if enabled. - Adjusted settings count in SettingsActivity.
This commit is contained in:
parent
2c5c5503a5
commit
490ae79ede
@ -26,7 +26,7 @@ This project is **not affiliated with Xteink**; it's built as a community projec
|
|||||||
## Features & Usage
|
## Features & Usage
|
||||||
|
|
||||||
- [x] EPUB parsing and rendering
|
- [x] EPUB parsing and rendering
|
||||||
- [ ] Image support within EPUB
|
- [x] Image support within EPUB
|
||||||
- [x] Saved reading position
|
- [x] Saved reading position
|
||||||
- [x] File explorer with file picker
|
- [x] File explorer with file picker
|
||||||
- [x] Basic EPUB picker from root directory
|
- [x] Basic EPUB picker from root directory
|
||||||
@ -40,6 +40,7 @@ This project is **not affiliated with Xteink**; it's built as a community projec
|
|||||||
- [ ] User provided fonts
|
- [ ] User provided fonts
|
||||||
- [ ] Full UTF support
|
- [ ] Full UTF support
|
||||||
- [x] Screen rotation
|
- [x] Screen rotation
|
||||||
|
- [x] Bluetooth LE Support
|
||||||
|
|
||||||
See [the user guide](./USER_GUIDE.md) for instructions on operating CrossPoint.
|
See [the user guide](./USER_GUIDE.md) for instructions on operating CrossPoint.
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ CrossPointSettings CrossPointSettings::instance;
|
|||||||
namespace {
|
namespace {
|
||||||
constexpr uint8_t SETTINGS_FILE_VERSION = 1;
|
constexpr uint8_t SETTINGS_FILE_VERSION = 1;
|
||||||
// Increment this when adding new persisted settings fields
|
// Increment this when adding new persisted settings fields
|
||||||
constexpr uint8_t SETTINGS_COUNT = 11;
|
constexpr uint8_t SETTINGS_COUNT = 12;
|
||||||
constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin";
|
constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin";
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -38,6 +38,7 @@ bool CrossPointSettings::saveToFile() const {
|
|||||||
serialization::writePod(outputFile, fontSize);
|
serialization::writePod(outputFile, fontSize);
|
||||||
serialization::writePod(outputFile, lineSpacing);
|
serialization::writePod(outputFile, lineSpacing);
|
||||||
serialization::writePod(outputFile, bluetoothEnabled);
|
serialization::writePod(outputFile, bluetoothEnabled);
|
||||||
|
serialization::writePod(outputFile, useCoverArtPicker);
|
||||||
outputFile.close();
|
outputFile.close();
|
||||||
|
|
||||||
Serial.printf("[%lu] [CPS] Settings saved to file\n", millis());
|
Serial.printf("[%lu] [CPS] Settings saved to file\n", millis());
|
||||||
@ -86,6 +87,8 @@ bool CrossPointSettings::loadFromFile() {
|
|||||||
if (++settingsRead >= fileSettingsCount) break;
|
if (++settingsRead >= fileSettingsCount) break;
|
||||||
serialization::readPod(inputFile, bluetoothEnabled);
|
serialization::readPod(inputFile, bluetoothEnabled);
|
||||||
if (++settingsRead >= fileSettingsCount) break;
|
if (++settingsRead >= fileSettingsCount) break;
|
||||||
|
serialization::readPod(inputFile, useCoverArtPicker);
|
||||||
|
if (++settingsRead >= fileSettingsCount) break;
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
inputFile.close();
|
inputFile.close();
|
||||||
|
|||||||
@ -64,6 +64,8 @@ class CrossPointSettings {
|
|||||||
uint8_t lineSpacing = NORMAL;
|
uint8_t lineSpacing = NORMAL;
|
||||||
// Bluetooth settings
|
// Bluetooth settings
|
||||||
uint8_t bluetoothEnabled = 0;
|
uint8_t bluetoothEnabled = 0;
|
||||||
|
// File browser settings
|
||||||
|
uint8_t useCoverArtPicker = 0;
|
||||||
|
|
||||||
~CrossPointSettings() = default;
|
~CrossPointSettings() = default;
|
||||||
|
|
||||||
|
|||||||
325
src/activities/reader/CoverArtPickerActivity.cpp
Normal file
325
src/activities/reader/CoverArtPickerActivity.cpp
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
#include "CoverArtPickerActivity.h"
|
||||||
|
|
||||||
|
#include <Epub.h>
|
||||||
|
#include <GfxRenderer.h>
|
||||||
|
#include <SDCardManager.h>
|
||||||
|
#include <Xtc.h>
|
||||||
|
|
||||||
|
#include "Bitmap.h"
|
||||||
|
#include "MappedInputManager.h"
|
||||||
|
#include "fontIds.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr int GRID_COLS = 3;
|
||||||
|
constexpr int GRID_ROWS = 4;
|
||||||
|
constexpr int PAGE_ITEMS = GRID_COLS * GRID_ROWS; // 12 items per page
|
||||||
|
constexpr int CELL_WIDTH = 160;
|
||||||
|
constexpr int CELL_HEIGHT = 180;
|
||||||
|
constexpr int COVER_WIDTH = 120; // Leave some spacing
|
||||||
|
constexpr int COVER_HEIGHT = 160; // Leave some spacing
|
||||||
|
constexpr int GRID_START_Y = 50;
|
||||||
|
constexpr int SKIP_PAGE_MS = 700;
|
||||||
|
constexpr unsigned long GO_HOME_MS = 1000;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void sortFileList(std::vector<std::string>& strs); // Declared in FileSelectionActivity.cpp
|
||||||
|
|
||||||
|
void CoverArtPickerActivity::taskTrampoline(void* param) {
|
||||||
|
auto* self = static_cast<CoverArtPickerActivity*>(param);
|
||||||
|
self->displayTaskLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverArtPickerActivity::loadFiles() {
|
||||||
|
files.clear();
|
||||||
|
selectorIndex = 0;
|
||||||
|
|
||||||
|
auto root = SdMan.open(basepath.c_str());
|
||||||
|
if (!root || !root.isDirectory()) {
|
||||||
|
if (root) root.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
root.rewindDirectory();
|
||||||
|
|
||||||
|
char name[128];
|
||||||
|
for (auto file = root.openNextFile(); file; file = root.openNextFile()) {
|
||||||
|
file.getName(name, sizeof(name));
|
||||||
|
if (name[0] == '.' || strcmp(name, "System Volume Information") == 0) {
|
||||||
|
file.close();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
files.emplace_back(std::string(name) + "/");
|
||||||
|
} else {
|
||||||
|
auto filename = std::string(name);
|
||||||
|
std::string ext4 = filename.length() >= 4 ? filename.substr(filename.length() - 4) : "";
|
||||||
|
std::string ext5 = filename.length() >= 5 ? filename.substr(filename.length() - 5) : "";
|
||||||
|
if (ext5 == ".epub" || ext5 == ".xtch" || ext4 == ".xtc") {
|
||||||
|
files.emplace_back(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
root.close();
|
||||||
|
sortFileList(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverArtPickerActivity::onEnter() {
|
||||||
|
Activity::onEnter();
|
||||||
|
|
||||||
|
renderingMutex = xSemaphoreCreateMutex();
|
||||||
|
|
||||||
|
loadFiles();
|
||||||
|
selectorIndex = 0;
|
||||||
|
|
||||||
|
// Trigger first update
|
||||||
|
updateRequired = true;
|
||||||
|
|
||||||
|
xTaskCreate(&CoverArtPickerActivity::taskTrampoline, "CoverArtPickerActivityTask",
|
||||||
|
4096, // Stack size (need more for EPUB loading)
|
||||||
|
this, // Parameters
|
||||||
|
1, // Priority
|
||||||
|
&displayTaskHandle // Task handle
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverArtPickerActivity::onExit() {
|
||||||
|
Activity::onExit();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
files.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverArtPickerActivity::loop() {
|
||||||
|
// Long press BACK (1s+) goes to root folder
|
||||||
|
if (mappedInput.isPressed(MappedInputManager::Button::Back) && mappedInput.getHeldTime() >= GO_HOME_MS) {
|
||||||
|
if (basepath != "/") {
|
||||||
|
basepath = "/";
|
||||||
|
loadFiles();
|
||||||
|
updateRequired = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool leftPressed = mappedInput.wasReleased(MappedInputManager::Button::Left);
|
||||||
|
const bool rightPressed = mappedInput.wasReleased(MappedInputManager::Button::Right);
|
||||||
|
const bool upPressed = mappedInput.wasReleased(MappedInputManager::Button::Up);
|
||||||
|
const bool downPressed = mappedInput.wasReleased(MappedInputManager::Button::Down);
|
||||||
|
|
||||||
|
const bool skipPage = mappedInput.getHeldTime() > SKIP_PAGE_MS;
|
||||||
|
|
||||||
|
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||||
|
if (files.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (basepath.back() != '/') basepath += "/";
|
||||||
|
if (files[selectorIndex].back() == '/') {
|
||||||
|
basepath += files[selectorIndex].substr(0, files[selectorIndex].length() - 1);
|
||||||
|
loadFiles();
|
||||||
|
updateRequired = true;
|
||||||
|
} else {
|
||||||
|
onSelect(basepath + files[selectorIndex]);
|
||||||
|
}
|
||||||
|
} else if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
||||||
|
// Short press: go up one directory, or go home if at root
|
||||||
|
if (mappedInput.getHeldTime() < GO_HOME_MS) {
|
||||||
|
if (basepath != "/") {
|
||||||
|
basepath.replace(basepath.find_last_of('/'), std::string::npos, "");
|
||||||
|
if (basepath.empty()) basepath = "/";
|
||||||
|
loadFiles();
|
||||||
|
updateRequired = true;
|
||||||
|
} else {
|
||||||
|
onGoHome();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (leftPressed) {
|
||||||
|
if (skipPage) {
|
||||||
|
selectorIndex = ((selectorIndex / PAGE_ITEMS - 1) * PAGE_ITEMS + files.size()) % files.size();
|
||||||
|
} else {
|
||||||
|
selectorIndex = (selectorIndex + files.size() - 1) % files.size();
|
||||||
|
}
|
||||||
|
updateRequired = true;
|
||||||
|
} else if (rightPressed) {
|
||||||
|
if (skipPage) {
|
||||||
|
selectorIndex = ((selectorIndex / PAGE_ITEMS + 1) * PAGE_ITEMS) % files.size();
|
||||||
|
} else {
|
||||||
|
selectorIndex = (selectorIndex + 1) % files.size();
|
||||||
|
}
|
||||||
|
updateRequired = true;
|
||||||
|
} else if (upPressed) {
|
||||||
|
// Move up one row
|
||||||
|
selectorIndex = (selectorIndex - GRID_COLS + files.size()) % files.size();
|
||||||
|
updateRequired = true;
|
||||||
|
} else if (downPressed) {
|
||||||
|
// Move down one row
|
||||||
|
selectorIndex = (selectorIndex + GRID_COLS) % files.size();
|
||||||
|
updateRequired = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverArtPickerActivity::displayTaskLoop() {
|
||||||
|
while (true) {
|
||||||
|
if (updateRequired) {
|
||||||
|
updateRequired = false;
|
||||||
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
|
render();
|
||||||
|
xSemaphoreGive(renderingMutex);
|
||||||
|
}
|
||||||
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverArtPickerActivity::drawCoverThumbnail(const std::string& filePath, int gridX, int gridY,
|
||||||
|
bool selected) const {
|
||||||
|
const int x = gridX * CELL_WIDTH + (CELL_WIDTH - COVER_WIDTH) / 2;
|
||||||
|
const int y = GRID_START_Y + gridY * CELL_HEIGHT + (CELL_HEIGHT - COVER_HEIGHT) / 2;
|
||||||
|
|
||||||
|
// Draw selection box
|
||||||
|
if (selected) {
|
||||||
|
renderer.drawRect(x - 2, y - 2, COVER_WIDTH + 4, COVER_HEIGHT + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's a directory, draw a folder icon
|
||||||
|
if (filePath.back() == '/') {
|
||||||
|
std::string dirName = filePath.substr(0, filePath.length() - 1);
|
||||||
|
if (dirName.length() > 12) {
|
||||||
|
dirName = dirName.substr(0, 12) + "...";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a folder outline (like a book but with a tab)
|
||||||
|
const int folderX = x + 30;
|
||||||
|
const int folderY = y + 30;
|
||||||
|
const int folderW = COVER_WIDTH - 60;
|
||||||
|
const int folderH = COVER_HEIGHT - 80;
|
||||||
|
|
||||||
|
// Main folder body
|
||||||
|
renderer.drawRect(folderX, folderY + 10, folderW, folderH - 10);
|
||||||
|
// Folder tab
|
||||||
|
renderer.drawRect(folderX, folderY, folderW / 2, 10);
|
||||||
|
|
||||||
|
// Draw folder label with background if selected
|
||||||
|
const int labelY = y + COVER_HEIGHT - 25;
|
||||||
|
const int labelWidth = renderer.getTextWidth(SMALL_FONT_ID, dirName.c_str());
|
||||||
|
const int labelX = x + (COVER_WIDTH - labelWidth) / 2;
|
||||||
|
|
||||||
|
if (selected) {
|
||||||
|
// Fill background for selected text
|
||||||
|
renderer.fillRect(labelX - 2, labelY - 2, labelWidth + 4, renderer.getLineHeight(SMALL_FONT_ID) + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always draw black text on white background, or white text on black background
|
||||||
|
renderer.drawText(SMALL_FONT_ID, labelX, labelY, dirName.c_str(), !selected);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare display name
|
||||||
|
std::string displayName = filePath;
|
||||||
|
if (displayName.length() > 5 && displayName.substr(displayName.length() - 5) == ".epub") {
|
||||||
|
displayName = displayName.substr(0, displayName.length() - 5);
|
||||||
|
} else if (displayName.length() > 5 && displayName.substr(displayName.length() - 5) == ".xtch") {
|
||||||
|
displayName = displayName.substr(0, displayName.length() - 5);
|
||||||
|
} else if (displayName.length() > 4 && displayName.substr(displayName.length() - 4) == ".xtc") {
|
||||||
|
displayName = displayName.substr(0, displayName.length() - 4);
|
||||||
|
}
|
||||||
|
if (displayName.length() > 15) {
|
||||||
|
displayName = displayName.substr(0, 15) + "...";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build full path
|
||||||
|
std::string fullPath = basepath;
|
||||||
|
if (fullPath.back() != '/') fullPath += "/";
|
||||||
|
fullPath += filePath;
|
||||||
|
|
||||||
|
// Determine if XTC or EPUB
|
||||||
|
bool isXtc = false;
|
||||||
|
if (filePath.length() >= 4) {
|
||||||
|
std::string ext4 = filePath.substr(filePath.length() - 4);
|
||||||
|
if (ext4 == ".xtc") isXtc = true;
|
||||||
|
}
|
||||||
|
if (!isXtc && filePath.length() >= 5) {
|
||||||
|
std::string ext5 = filePath.substr(filePath.length() - 5);
|
||||||
|
if (ext5 == ".xtch") isXtc = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to get cover using the same pattern as sleep screen
|
||||||
|
std::string coverBmpPath;
|
||||||
|
bool coverGenerated = false;
|
||||||
|
|
||||||
|
if (isXtc) {
|
||||||
|
Xtc book(fullPath, "/.crosspoint");
|
||||||
|
if (book.load()) {
|
||||||
|
if (book.generateCoverBmp()) { // This is fast if cover already exists
|
||||||
|
coverBmpPath = book.getCoverBmpPath();
|
||||||
|
coverGenerated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Epub book(fullPath, "/.crosspoint");
|
||||||
|
if (book.load(false)) { // Load without building metadata if missing
|
||||||
|
if (book.generateCoverBmp()) { // This is fast if cover already exists
|
||||||
|
coverBmpPath = book.getCoverBmpPath();
|
||||||
|
coverGenerated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the cover if we got one
|
||||||
|
if (coverGenerated) {
|
||||||
|
FsFile coverFile;
|
||||||
|
if (SdMan.openFileForRead("COVER", coverBmpPath.c_str(), coverFile)) {
|
||||||
|
Bitmap coverBitmap(coverFile);
|
||||||
|
if (coverBitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||||
|
renderer.drawBitmap(coverBitmap, x, y, COVER_WIDTH, COVER_HEIGHT);
|
||||||
|
// Don't close file here - Bitmap holds a reference to it and needs it open
|
||||||
|
// File will close when coverFile goes out of scope
|
||||||
|
return; // Success - cover rendered
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: show filename with border
|
||||||
|
renderer.drawRect(x + 20, y + 20, COVER_WIDTH - 40, COVER_HEIGHT - 60);
|
||||||
|
renderer.drawCenteredText(SMALL_FONT_ID, y + COVER_HEIGHT - 30, displayName.c_str(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoverArtPickerActivity::render() const {
|
||||||
|
renderer.clearScreen();
|
||||||
|
|
||||||
|
const auto pageWidth = renderer.getScreenWidth();
|
||||||
|
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Books", true, BOLD);
|
||||||
|
|
||||||
|
// Help text
|
||||||
|
const auto labels = mappedInput.mapLabels("« Home", "Open", "", "");
|
||||||
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||||
|
|
||||||
|
if (files.empty()) {
|
||||||
|
renderer.drawText(UI_10_FONT_ID, 20, 60, "No books found");
|
||||||
|
renderer.displayBuffer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate page
|
||||||
|
const auto pageStartIndex = selectorIndex / PAGE_ITEMS * PAGE_ITEMS;
|
||||||
|
|
||||||
|
// Draw covers in grid
|
||||||
|
for (int i = pageStartIndex; i < files.size() && i < pageStartIndex + PAGE_ITEMS; i++) {
|
||||||
|
const int gridIndex = i - pageStartIndex;
|
||||||
|
const int gridX = gridIndex % GRID_COLS;
|
||||||
|
const int gridY = gridIndex / GRID_COLS;
|
||||||
|
const bool selected = (i == selectorIndex);
|
||||||
|
|
||||||
|
drawCoverThumbnail(files[i], gridX, gridY, selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.displayBuffer();
|
||||||
|
}
|
||||||
39
src/activities/reader/CoverArtPickerActivity.h
Normal file
39
src/activities/reader/CoverArtPickerActivity.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/semphr.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "../Activity.h"
|
||||||
|
|
||||||
|
class CoverArtPickerActivity final : public Activity {
|
||||||
|
TaskHandle_t displayTaskHandle = nullptr;
|
||||||
|
SemaphoreHandle_t renderingMutex = nullptr;
|
||||||
|
std::string basepath = "/";
|
||||||
|
std::vector<std::string> files;
|
||||||
|
int selectorIndex = 0;
|
||||||
|
bool updateRequired = false;
|
||||||
|
const std::function<void(const std::string&)> onSelect;
|
||||||
|
const std::function<void()> onGoHome;
|
||||||
|
|
||||||
|
static void taskTrampoline(void* param);
|
||||||
|
[[noreturn]] void displayTaskLoop();
|
||||||
|
void render() const;
|
||||||
|
void loadFiles();
|
||||||
|
void drawCoverThumbnail(const std::string& filePath, int gridX, int gridY, bool selected) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CoverArtPickerActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
|
||||||
|
const std::function<void(const std::string&)>& onSelect,
|
||||||
|
const std::function<void()>& onGoHome, std::string initialPath = "/")
|
||||||
|
: Activity("CoverArtPicker", renderer, mappedInput),
|
||||||
|
basepath(initialPath.empty() ? "/" : std::move(initialPath)),
|
||||||
|
onSelect(onSelect),
|
||||||
|
onGoHome(onGoHome) {}
|
||||||
|
void onEnter() override;
|
||||||
|
void onExit() override;
|
||||||
|
void loop() override;
|
||||||
|
};
|
||||||
@ -1,5 +1,7 @@
|
|||||||
#include "ReaderActivity.h"
|
#include "ReaderActivity.h"
|
||||||
|
|
||||||
|
#include "CrossPointSettings.h"
|
||||||
|
#include "CoverArtPickerActivity.h"
|
||||||
#include "Epub.h"
|
#include "Epub.h"
|
||||||
#include "EpubReaderActivity.h"
|
#include "EpubReaderActivity.h"
|
||||||
#include "FileSelectionActivity.h"
|
#include "FileSelectionActivity.h"
|
||||||
@ -92,8 +94,15 @@ void ReaderActivity::onGoToFileSelection(const std::string& fromBookPath) {
|
|||||||
exitActivity();
|
exitActivity();
|
||||||
// If coming from a book, start in that book's folder; otherwise start from root
|
// If coming from a book, start in that book's folder; otherwise start from root
|
||||||
const auto initialPath = fromBookPath.empty() ? "/" : extractFolderPath(fromBookPath);
|
const auto initialPath = fromBookPath.empty() ? "/" : extractFolderPath(fromBookPath);
|
||||||
enterNewActivity(new FileSelectionActivity(
|
|
||||||
renderer, mappedInput, [this](const std::string& path) { onSelectBookFile(path); }, onGoBack, initialPath));
|
// Check if cover art picker is enabled
|
||||||
|
if (SETTINGS.useCoverArtPicker) {
|
||||||
|
enterNewActivity(new CoverArtPickerActivity(
|
||||||
|
renderer, mappedInput, [this](const std::string& path) { onSelectBookFile(path); }, onGoBack, initialPath));
|
||||||
|
} else {
|
||||||
|
enterNewActivity(new FileSelectionActivity(
|
||||||
|
renderer, mappedInput, [this](const std::string& path) { onSelectBookFile(path); }, onGoBack, initialPath));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReaderActivity::onGoToEpubReader(std::unique_ptr<Epub> epub) {
|
void ReaderActivity::onGoToEpubReader(std::unique_ptr<Epub> epub) {
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
// Define the static settings list
|
// Define the static settings list
|
||||||
namespace {
|
namespace {
|
||||||
constexpr int settingsCount = 12;
|
constexpr int settingsCount = 13;
|
||||||
const SettingInfo settingsList[settingsCount] = {
|
const SettingInfo settingsList[settingsCount] = {
|
||||||
// Should match with SLEEP_SCREEN_MODE
|
// Should match with SLEEP_SCREEN_MODE
|
||||||
{"Sleep Screen", SettingType::ENUM, &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover"}},
|
{"Sleep Screen", SettingType::ENUM, &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover"}},
|
||||||
@ -34,6 +34,7 @@ const SettingInfo settingsList[settingsCount] = {
|
|||||||
{"Bookerly", "Noto Sans", "Open Dyslexic"}},
|
{"Bookerly", "Noto Sans", "Open Dyslexic"}},
|
||||||
{"Reader Font Size", SettingType::ENUM, &CrossPointSettings::fontSize, {"Small", "Medium", "Large", "X Large"}},
|
{"Reader Font Size", SettingType::ENUM, &CrossPointSettings::fontSize, {"Small", "Medium", "Large", "X Large"}},
|
||||||
{"Reader Line Spacing", SettingType::ENUM, &CrossPointSettings::lineSpacing, {"Tight", "Normal", "Wide"}},
|
{"Reader Line Spacing", SettingType::ENUM, &CrossPointSettings::lineSpacing, {"Tight", "Normal", "Wide"}},
|
||||||
|
{"Cover Art Picker", SettingType::TOGGLE, &CrossPointSettings::useCoverArtPicker, {}},
|
||||||
{"Bluetooth", SettingType::TOGGLE, &CrossPointSettings::bluetoothEnabled, {}},
|
{"Bluetooth", SettingType::TOGGLE, &CrossPointSettings::bluetoothEnabled, {}},
|
||||||
{"Check for updates", SettingType::ACTION, nullptr, {}},
|
{"Check for updates", SettingType::ACTION, nullptr, {}},
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user