Skip to content

Commit 3116668

Browse files
authored
chore: merge 4 clean upstream commits, skip crosspoint-reader#2288 (#8)
Cherry-picked 4 clean upstream commits, skipping conflicting crosspoint-reader#2288 (Korean line breaks): - crosspoint-reader#2357 fix: enable Shift key for URL keyboard input - crosspoint-reader#2290 feat: drag-and-drop upload modal - crosspoint-reader#1808 feat: long-press Confirm -> KOReader sync - crosspoint-reader#2368 fix: submodule pointer (open-x4-sdk net-unchanged at 26648d64) No overlap with our Japanese CJK/font work. CI build green.
1 parent fabafa9 commit 3116668

9 files changed

Lines changed: 207 additions & 60 deletions

File tree

USER_GUIDE.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,10 @@ The Settings screen allows you to configure the device's behavior. There are a f
241241

242242
- "Chapter Skip" (default) - Long-pressing skips to next/previous chapter
243243
- "Page Scroll" - Long-pressing scrolls a page up/down
244+
- **Long-press Menu**: Selects the function bound to holding the menu button (Confirm) while reading an EPUB. **Cycles through the available functions** each time the setting is selected — additional functions may be added in future releases, so this is not a binary on/off toggle. A short press of Confirm always opens the reader menu as normal:
245+
- "Bookmark" (default) - Hold Confirm (~0.4 second) to drop a bookmark at the current page.
246+
- "KOSync" - Hold Confirm (~1 second) to launch KOReader sync directly.
247+
- "Disabled" - Long-press is ignored; only short-press opens the reader menu.
244248

245249
- **Short Power Button Click**: Controls the effect of a short click of the power button:
246250

@@ -528,6 +532,7 @@ When reading an EPUB that contains footnotes, you can navigate to the footnote t
528532
* **Return to Home:** Press the **Back** button to close the book and return to the **[Home](#31-home-screen)** screen.
529533
* **Return to Browse Files:** Press and hold the **Back** button to close the book and return to the **[Browse Files](#33-browse-files-screen)** screen.
530534
* **Reader Menu:** Press **Confirm** to open the **[Reader Menu](#5-reader-menu)**, which includes chapter navigation, reading options, and more.
535+
* **Long-press Confirm (configurable):** Holding **Confirm** runs the function chosen by the **Long-press Menu** setting in **[Controls Settings](#363-controls)** — "Bookmark" (default) drops a bookmark, "KOSync" launches KOReader Sync, "Disabled" does nothing. A short press always opens the Reader Menu.
531536

532537
### Supported Languages
533538

@@ -574,9 +579,9 @@ Accessible by selecting **Chapters** from the Reader Menu.
574579

575580
Bookmarks can be created to quickly save and restore your place in a book.
576581

577-
To create a bookmark, hold **Confirm** for 1 second while inside a book. A popup will appear letting you know a bookmark was created. The popup message will automatically disappear in a couple of seconds.
582+
To create a bookmark, hold **Confirm** for about half a second while inside a book. A popup will appear letting you know a bookmark was created. The popup message will automatically disappear in a couple of seconds.
578583

579-
To open bookmarks, press **Confirm** while inside a book. Then navigate to the **Bookmarks** menu. Bookmarks can be opened by navigating to them and pressing **Confirm**, which will redirect you to that place in the book. You can delete bookmarks by holding **Confirm** for 1 second, and then pressing **Confirm** again to confirm deletion, or **Back** to cancel.
584+
To open bookmarks, press **Confirm** while inside a book. Then navigate to the **Bookmarks** menu. Bookmarks can be opened by navigating to them and pressing **Confirm**, which will redirect you to that place in the book. You can delete bookmarks by holding **Confirm** for about 0.7 seconds, and then pressing **Confirm** again to confirm deletion, or **Back** to cancel.
580585

581586
Bookmarks are stored in the `.crosspoint/bookmarks` folder in the JSON format.
582587

233 KB
Loading

lib/I18n/translations/english.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ STR_LONG_PRESS_BEHAVIOR: "Long-press button behavior"
7878
STR_LONG_PRESS_BEHAVIOR_OFF: "OFF"
7979
STR_LONG_PRESS_BEHAVIOR_SKIP: "Chapter skip"
8080
STR_LONG_PRESS_BEHAVIOR_ORIENTATION: "Orientation change"
81+
STR_LONG_PRESS_MENU: "Long-press Menu"
8182
STR_FONT_FAMILY: "Reader Font Family"
8283
STR_FONT_SIZE: "Reader Font Size"
8384
STR_LINE_SPACING: "Reader Line Spacing"
@@ -140,6 +141,8 @@ STR_INVERTED: "Inverted"
140141
STR_LANDSCAPE_CCW: "Landscape CCW"
141142
STR_PREV_NEXT: "Prev/Next"
142143
STR_NEXT_PREV: "Next/Prev"
144+
STR_KOSYNC: "KOSync"
145+
STR_BOOKMARK_OPTION: "Bookmark"
143146
STR_DISABLED: "Disabled"
144147
STR_NOTO_SERIF: "Noto Serif"
145148
STR_NOTO_SANS: "Noto Sans"

src/CrossPointSettings.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,17 @@ class CrossPointSettings {
136136
// Short power button press actions
137137
enum SHORT_PWRBTN { IGNORE = 0, SLEEP = 1, PAGE_TURN = 2, FORCE_REFRESH = 3, FOOTNOTES = 4, SHORT_PWRBTN_COUNT };
138138

139+
// Long-press Confirm action while reading an EPUB. The setting cycles through these values.
140+
// Persisted in settings.json by index: any new function (e.g. dictionary, bookmark) MUST use a
141+
// value >= 2 and be appended at the END of the enumValues array in SettingsList.h, otherwise the
142+
// stored indices shift and existing saves are silently misinterpreted.
143+
enum LONG_PRESS_MENU_FUNCTION {
144+
LP_MENU_KOSYNC = 0,
145+
LP_MENU_DISABLED = 1,
146+
LP_MENU_BOOKMARK = 2,
147+
LONG_PRESS_MENU_FUNCTION_COUNT
148+
};
149+
139150
// Hide battery percentage
140151
enum HIDE_BATTERY_PERCENTAGE { HIDE_NEVER = 0, HIDE_READER = 1, HIDE_ALWAYS = 2, HIDE_BATTERY_PERCENTAGE_COUNT };
141152

@@ -226,6 +237,9 @@ class CrossPointSettings {
226237
uint8_t hideBatteryPercentage = HIDE_NEVER;
227238
// Long-press page turn button behavior
228239
uint8_t longPressButtonBehavior = OFF;
240+
// Long-press Confirm function in EPUB reader (cycles through LONG_PRESS_MENU_FUNCTION values).
241+
// Defaults to Bookmark to preserve the upstream long-press-Confirm-adds-bookmark behavior.
242+
uint8_t longPressMenuFunction = LP_MENU_BOOKMARK;
229243
// UI Theme
230244
uint8_t uiTheme = LYRA;
231245
// Sunlight fading compensation

src/SettingsList.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,16 @@ inline std::vector<SettingInfo> getSettingsList(const SdCardFontRegistry* regist
171171
{StrId::STR_LONG_PRESS_BEHAVIOR_OFF, StrId::STR_LONG_PRESS_BEHAVIOR_SKIP,
172172
StrId::STR_LONG_PRESS_BEHAVIOR_ORIENTATION},
173173
"longPressButtonBehavior", StrId::STR_CAT_CONTROLS),
174+
SettingInfo::Enum(StrId::STR_LONG_PRESS_MENU, &CrossPointSettings::longPressMenuFunction,
175+
{StrId::STR_KOSYNC, StrId::STR_DISABLED, StrId::STR_BOOKMARK_OPTION}, "longPressMenuFunction",
176+
StrId::STR_CAT_CONTROLS),
174177
SettingInfo::Enum(
175178
StrId::STR_SHORT_PWR_BTN, &CrossPointSettings::shortPwrBtn,
176179
{StrId::STR_IGNORE, StrId::STR_SLEEP, StrId::STR_PAGE_TURN, StrId::STR_FORCE_REFRESH, StrId::STR_FOOTNOTES},
177180
"shortPwrBtn", StrId::STR_CAT_CONTROLS),
178181
SettingInfo::Toggle(StrId::STR_PWR_BTN_FOOTNOTE_BACK, &CrossPointSettings::pwrBtnFootnoteBack,
179182
"pwrBtnFootnoteBack", StrId::STR_CAT_CONTROLS),
183+
180184
// --- System ---
181185
SettingInfo::Value(
182186
StrId::STR_TIME_TO_SLEEP, &CrossPointSettings::sleepTimeoutMinutes,

src/activities/reader/EpubReaderActivity.cpp

Lines changed: 78 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,9 @@ void EpubReaderActivity::loop() {
256256
requestUpdate();
257257
}
258258

259-
// Enter reader menu activity.
259+
// Enter reader menu activity on short-press Confirm. A long-press that fired a bound
260+
// function (bookmark or KOReader sync) sets ignoreNextConfirmRelease so the release
261+
// following the hold does not also open the menu.
260262
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
261263
if (ignoreNextConfirmRelease) {
262264
ignoreNextConfirmRelease = false;
@@ -284,14 +286,32 @@ void EpubReaderActivity::loop() {
284286
}
285287
}
286288

287-
if (mappedInput.isPressed(MappedInputManager::Button::Confirm) &&
288-
mappedInput.getHeldTime() >= ReaderUtils::BOOKMARK_HOLD_MS) {
289-
if (!showBookmarkMessage) {
290-
addBookmark();
291-
showBookmarkMessage = true;
292-
ignoreNextConfirmRelease = true; // Prevent accidental menu open after adding bookmark
293-
bookmarkMessageTime = millis();
294-
requestUpdate();
289+
// Long-press Confirm runs the user-selected function (SETTINGS.longPressMenuFunction).
290+
if (mappedInput.isPressed(MappedInputManager::Button::Confirm)) {
291+
switch (SETTINGS.longPressMenuFunction) {
292+
case CrossPointSettings::LP_MENU_BOOKMARK:
293+
// Hold ~0.4s drops a bookmark at the current page.
294+
if (mappedInput.getHeldTime() >= ReaderUtils::BOOKMARK_HOLD_MS && !showBookmarkMessage) {
295+
addBookmark();
296+
showBookmarkMessage = true;
297+
ignoreNextConfirmRelease = true; // Prevent accidental menu open after adding bookmark
298+
bookmarkMessageTime = millis();
299+
requestUpdate();
300+
}
301+
break;
302+
case CrossPointSettings::LP_MENU_KOSYNC:
303+
// Hold ~1s launches KOReader sync. If sync can't run (no credentials stored), fall
304+
// through so the normal Confirm-release still opens the reader menu.
305+
if (mappedInput.getHeldTime() >= ReaderUtils::GO_HOME_MS) {
306+
if (launchKOReaderSync()) {
307+
ignoreNextConfirmRelease = true; // sync launched or error shown; suppress menu open
308+
return;
309+
}
310+
}
311+
break;
312+
case CrossPointSettings::LP_MENU_DISABLED:
313+
default:
314+
break;
295315
}
296316
}
297317

@@ -578,50 +598,7 @@ void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction
578598
break;
579599
}
580600
case EpubReaderMenuActivity::MenuAction::SYNC: {
581-
if (KOREADER_STORE.hasCredentials()) {
582-
const int currentPage = section ? section->currentPage : nextPageNumber;
583-
const int totalPages = section ? section->pageCount : cachedChapterTotalPageCount;
584-
std::optional<uint16_t> paragraphIndex;
585-
if (section && currentPage >= 0 && currentPage < section->pageCount) {
586-
const uint16_t paragraphPage =
587-
currentPage > 0 ? static_cast<uint16_t>(currentPage - 1) : static_cast<uint16_t>(currentPage);
588-
if (const auto pIdx = section->getParagraphIndexForPage(paragraphPage)) {
589-
paragraphIndex = *pIdx;
590-
}
591-
}
592-
593-
// Pre-compute local KO position and chapter name while Epub is still in RAM.
594-
CrossPointPosition localPos = getCurrentPosition();
595-
SavedProgressPosition localKoPos = ProgressMapper::toSavedProgress(epub, localPos);
596-
const int tocIdx = epub->getTocIndexForSpineIndex(currentSpineIndex);
597-
std::string localChapterName = (tocIdx >= 0) ? epub->getTocItem(tocIdx).title : "";
598-
const std::string savedEpubPath = epub->getPath();
599-
600-
// Persist current position so the reader resumes at the right page on return.
601-
// goToReader() depends on this file, so abort the sync if the write fails.
602-
if (!saveProgress(currentSpineIndex, currentPage, totalPages)) {
603-
LOG_ERR("KOSync", "Aborting sync because current progress could not be saved");
604-
pendingSyncSaveError = true;
605-
requestUpdate();
606-
return;
607-
}
608-
609-
// Release Epub and Section to free ~65KB RAM for the TLS handshake.
610-
LOG_DBG("KOSync", "Releasing epub for sync (heap before: %u)", (unsigned)ESP.getFreeHeap());
611-
{
612-
RenderLock lock(*this);
613-
if (section) {
614-
nextPageNumber = section->currentPage;
615-
}
616-
section.reset();
617-
epub.reset();
618-
}
619-
LOG_DBG("KOSync", "Epub released (heap after: %u)", (unsigned)ESP.getFreeHeap());
620-
621-
activityManager.replaceActivity(std::make_unique<KOReaderSyncActivity>(
622-
renderer, mappedInput, savedEpubPath, currentSpineIndex, currentPage, totalPages, std::move(localKoPos),
623-
std::move(localChapterName), paragraphIndex));
624-
}
601+
launchKOReaderSync();
625602
break;
626603
}
627604
case EpubReaderMenuActivity::MenuAction::BOOKMARKS: {
@@ -633,6 +610,54 @@ void EpubReaderActivity::onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction
633610
}
634611
}
635612

613+
bool EpubReaderActivity::launchKOReaderSync() {
614+
if (!KOREADER_STORE.hasCredentials()) return false; // no-op: nothing to launch
615+
616+
const int currentPage = section ? section->currentPage : nextPageNumber;
617+
const int totalPages = section ? section->pageCount : cachedChapterTotalPageCount;
618+
std::optional<uint16_t> paragraphIndex;
619+
if (section && currentPage >= 0 && currentPage < section->pageCount) {
620+
const uint16_t paragraphPage =
621+
currentPage > 0 ? static_cast<uint16_t>(currentPage - 1) : static_cast<uint16_t>(currentPage);
622+
if (const auto pIdx = section->getParagraphIndexForPage(paragraphPage)) {
623+
paragraphIndex = *pIdx;
624+
}
625+
}
626+
627+
// Pre-compute local KO position and chapter name while Epub is still in RAM.
628+
CrossPointPosition localPos = getCurrentPosition();
629+
SavedProgressPosition localKoPos = ProgressMapper::toSavedProgress(epub, localPos);
630+
const int tocIdx = epub->getTocIndexForSpineIndex(currentSpineIndex);
631+
std::string localChapterName = (tocIdx >= 0) ? epub->getTocItem(tocIdx).title : "";
632+
const std::string savedEpubPath = epub->getPath();
633+
634+
// Persist current position so the reader resumes at the right page on return.
635+
// goToReader() depends on this file, so abort the sync if the write fails.
636+
if (!saveProgress(currentSpineIndex, currentPage, totalPages)) {
637+
LOG_ERR("KOSync", "Aborting sync because current progress could not be saved");
638+
pendingSyncSaveError = true;
639+
requestUpdate();
640+
return true; // acted: surfaced a save error to the user
641+
}
642+
643+
// Release Epub and Section to free ~65KB RAM for the TLS handshake.
644+
LOG_DBG("KOSync", "Releasing epub for sync (heap before: %u)", (unsigned)ESP.getFreeHeap());
645+
{
646+
RenderLock lock(*this);
647+
if (section) {
648+
nextPageNumber = section->currentPage;
649+
}
650+
section.reset();
651+
epub.reset();
652+
}
653+
LOG_DBG("KOSync", "Epub released (heap after: %u)", (unsigned)ESP.getFreeHeap());
654+
655+
activityManager.replaceActivity(std::make_unique<KOReaderSyncActivity>(
656+
renderer, mappedInput, savedEpubPath, currentSpineIndex, currentPage, totalPages, std::move(localKoPos),
657+
std::move(localChapterName), paragraphIndex));
658+
return true; // acted: launched the sync activity
659+
}
660+
636661
void EpubReaderActivity::applyOrientation(const uint8_t orientation) {
637662
// No-op if the selected orientation matches current settings.
638663
if (SETTINGS.orientation == orientation) {

src/activities/reader/EpubReaderActivity.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ class EpubReaderActivity final : public Activity {
6060
// Jump to a percentage of the book (0-100), mapping it to spine and page.
6161
void jumpToPercent(int percent);
6262
void onReaderMenuConfirm(EpubReaderMenuActivity::MenuAction action);
63+
// Returns true if sync acted (launched, or surfaced a save error); false if it was a no-op
64+
// because no KOReader credentials are stored.
65+
bool launchKOReaderSync();
6366
void applyOrientation(uint8_t orientation);
6467
void toggleAutoPageTurn(uint8_t selectedPageTurnOption);
6568
void pageTurn(bool isForwardTurn);

src/activities/util/KeyboardEntryActivity.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,9 @@ bool KeyboardEntryActivity::handleKeyPress() {
9999
case SpecialKeyType::Shift:
100100
delPressCount = 0;
101101
hintVisible = false;
102-
if (urlMode || inputType == InputType::Url) return true;
102+
// Shift is meaningless in the URL-snippet panel and the symbol layout, but
103+
// must work for the URL letter layout so uppercase letters can be entered (#2178).
104+
if (urlMode) return true;
103105
if (symMode) return true;
104106
shiftState = (shiftState + 1) % 2;
105107
return true;
@@ -675,8 +677,8 @@ void KeyboardEntryActivity::render(RenderLock&&) {
675677
const char* label;
676678
};
677679
const BottomKeyInfo bottomKeys[BOTTOM_KEY_COUNT] = {
678-
{(symMode || urlMode || inputType == InputType::Url) ? KeyboardKeyType::Disabled : KeyboardKeyType::Shift,
679-
(symMode || urlMode || inputType == InputType::Url) ? shiftString[0] : shiftString[shiftState]},
680+
{(symMode || urlMode) ? KeyboardKeyType::Disabled : KeyboardKeyType::Shift,
681+
(symMode || urlMode) ? shiftString[0] : shiftString[shiftState]},
680682
{KeyboardKeyType::Mode, urlMode ? "abc" : (symMode ? "abc" : "#@!")},
681683
{inputType == InputType::Url ? KeyboardKeyType::Mode : KeyboardKeyType::Space,
682684
inputType == InputType::Url ? "URL" : nullptr},

0 commit comments

Comments
 (0)