From 53ca4f30d5d89da528cb11a7b2fe2167bcca571e Mon Sep 17 00:00:00 2001 From: pablohc Date: Mon, 20 Apr 2026 19:47:57 +0200 Subject: [PATCH] fix: keyboard feedback #1644 (#1697) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses reviewer feedback from #1644: - **Localize keyboard hint strings** — 13 hardcoded English strings replaced with \`tr()\` macro (\`STR_KB_HINT_*\`), making them translatable across all 22 languages (fallback to English when not yet translated) - **Deduplicate \`Lyra3CoversMetrics\`** — now derives from \`LyraMetrics\` via lambda copy, overriding only \`homeCoverTileHeight\` and \`homeRecentBooksCount\` (eliminates ~30 duplicated metric fields) - **Unify keyboard drawing in \`BaseTheme\`** — \`drawTextField\` and \`drawKeyboardKey\` overrides removed from \`LyraTheme\`; variability controlled via \`keyboardKeyCornerRadius\` metric (0=Base, 6=Lyra). Unified text field padding to 6, adopted Lyra's secondary label draw order (main first, then secondary) - **Add URL-optimized keyboard layout** — \`urlLayout\` with \`:\` and \`/\` replacing \`=\` and \`,\` for easier URL input without switching to SYM mode --- 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? _** YES **_ --- lib/I18n/translations/english.yaml | 15 ++++++ src/activities/util/KeyboardEntryActivity.cpp | 48 ++++++++++--------- src/activities/util/KeyboardEntryActivity.h | 43 +++++++++++++++++ 3 files changed, 83 insertions(+), 23 deletions(-) diff --git a/lib/I18n/translations/english.yaml b/lib/I18n/translations/english.yaml index 3b001ead..c667b1a7 100644 --- a/lib/I18n/translations/english.yaml +++ b/lib/I18n/translations/english.yaml @@ -583,3 +583,18 @@ STR_BTN_ACT_PREV_SECTION: "Previous Section / Chapter" STR_BTN_ACT_EXIT_READER: "Exit Reader" STR_BTN_ACT_READER_MENU: "Reader Menu" STR_BTN_ACT_KOREADER_SYNC: "KOReader Sync" +STR_KB_HINT_MOVE_CURSOR: "Press LEFT or RIGHT to move cursor" +STR_KB_HINT_RETURN_CURSOR: "Press LEFT to return to cursor position" +STR_KB_HINT_HIDE_PASSWORD: "Hold RIGHT then press [***] to hide password" +STR_KB_HINT_SHOW_PASSWORD: "Hold RIGHT then press [abc] to show password" +STR_KB_HINT_TOGGLE_HIDE_PASSWORD: "Press [***] to hide password" +STR_KB_HINT_TOGGLE_SHOW_PASSWORD: "Press [abc] to show password" +STR_KB_HINT_EDIT_ENTRY: "Hold UP to edit entry" +STR_KB_TIPS: "Tips:" +STR_KB_HINT_RETURN_KEYBOARD: "Press DOWN to return to keyboard" +STR_KB_HINT_EXIT_URL_MODE: "Press ABC to exit URL mode" +STR_KB_HINT_CLEAR_TEXT: "Hold DEL to clear all text" +STR_KB_HINT_SECONDARY_CHAR: "Hold SELECT for secondary char" +STR_KB_HINT_UPPER_SECONDARY: "Hold SELECT for UPPERCASE or secondary char" +STR_KB_HINT_LOWER_SECONDARY: "Hold SELECT for lowercase or secondary char" +STR_KB_HINT_URL_SNIPPETS: "Press URL for snippets" diff --git a/src/activities/util/KeyboardEntryActivity.cpp b/src/activities/util/KeyboardEntryActivity.cpp index 7f25f685..eebd0b5d 100644 --- a/src/activities/util/KeyboardEntryActivity.cpp +++ b/src/activities/util/KeyboardEntryActivity.cpp @@ -49,7 +49,7 @@ int KeyboardEntryActivity::getTotalRowCount() const { return getContentRowCount( bool KeyboardEntryActivity::isBottomRow(const int row) const { return row == getContentRowCount(); } char KeyboardEntryActivity::getSelectedChar() const { - const KeyDef(*layout)[COLS] = symMode ? symLayout : abcLayout; + const KeyDef(*layout)[COLS] = symMode ? symLayout : (inputType == InputType::Url ? urlLayout : abcLayout); if (selectedRow < 0 || selectedRow >= getContentRowCount()) return '\0'; if (selectedCol < 0 || selectedCol >= COLS) return '\0'; @@ -526,20 +526,22 @@ void KeyboardEntryActivity::render(RenderLock&&) { const int hintY = underlineY + 4; if (cursorMode) { int hintLineY = hintY; - renderer.drawCenteredText(SMALL_FONT_ID, hintLineY, "Press < or > to move cursor", true); - hintLineY += hintLh; - if (inputType == InputType::Password) { - const char* passTip; - if (togglePos) { - passTip = "Press < to return to cursor position"; - } else { - passTip = - passwordVisible ? "Hold > then press [***] to hide password" : "Hold > then press [abc] to show password"; + if (inputType == InputType::Password && togglePos) { + renderer.drawCenteredText( + SMALL_FONT_ID, hintLineY, + passwordVisible ? tr(STR_KB_HINT_TOGGLE_HIDE_PASSWORD) : tr(STR_KB_HINT_TOGGLE_SHOW_PASSWORD), true); + hintLineY += hintLh; + renderer.drawCenteredText(SMALL_FONT_ID, hintLineY, tr(STR_KB_HINT_RETURN_CURSOR), true); + } else { + renderer.drawCenteredText(SMALL_FONT_ID, hintLineY, tr(STR_KB_HINT_MOVE_CURSOR), true); + hintLineY += hintLh; + if (inputType == InputType::Password) { + const char* passTip = passwordVisible ? tr(STR_KB_HINT_HIDE_PASSWORD) : tr(STR_KB_HINT_SHOW_PASSWORD); + renderer.drawCenteredText(SMALL_FONT_ID, hintLineY, passTip, true); } - renderer.drawCenteredText(SMALL_FONT_ID, hintLineY, passTip, true); } } else { - renderer.drawCenteredText(SMALL_FONT_ID, hintY, "Hold UP to edit entry", true); + renderer.drawCenteredText(SMALL_FONT_ID, hintY, tr(STR_KB_HINT_EDIT_ENTRY), true); } } @@ -575,37 +577,37 @@ void KeyboardEntryActivity::render(RenderLock&&) { if (tipCount > 0) { int y = (underlineBottom + keyboardStartY) / 2 - (tipCount + 1) * tipsLh / 2; - drawTip("Tips:", y); + drawTip(tr(STR_KB_TIPS), y); y += tipsLh; if (cursorMode) { - drawTip("Press DOWN to return to keyboard", y); + drawTip(tr(STR_KB_HINT_RETURN_KEYBOARD), y); } else if (urlMode) { - drawTip("Press ABC to exit URL mode", y); + drawTip(tr(STR_KB_HINT_EXIT_URL_MODE), y); y += tipsLh; if (!text.empty()) { - drawTip("Hold DEL to clear all text", y); + drawTip(tr(STR_KB_HINT_CLEAR_TEXT), y); } } else if (symMode) { if (!text.empty()) { - drawTip("Hold DEL to clear all text", y); + drawTip(tr(STR_KB_HINT_CLEAR_TEXT), y); } } else { const char* altCharTip; if (inputType == InputType::Url) { - altCharTip = "Hold SELECT for secondary char"; + altCharTip = tr(STR_KB_HINT_SECONDARY_CHAR); } else if (shiftState > 0) { - altCharTip = "Hold SELECT for lowercase or secondary char"; + altCharTip = tr(STR_KB_HINT_LOWER_SECONDARY); } else { - altCharTip = "Hold SELECT for UPPERCASE or secondary char"; + altCharTip = tr(STR_KB_HINT_UPPER_SECONDARY); } drawTip(altCharTip, y); y += tipsLh; if (inputType == InputType::Url) { - drawTip("Press URL for snippets", y); + drawTip(tr(STR_KB_HINT_URL_SNIPPETS), y); y += tipsLh; } if (!text.empty()) { - drawTip("Hold DEL to clear all text", y); + drawTip(tr(STR_KB_HINT_CLEAR_TEXT), y); } } } @@ -625,7 +627,7 @@ void KeyboardEntryActivity::render(RenderLock&&) { urlLeftMargin = urlCenterX - urlTotalWidth / 2; } - const KeyDef(*layout)[COLS] = symMode ? symLayout : abcLayout; + const KeyDef(*layout)[COLS] = symMode ? symLayout : (inputType == InputType::Url ? urlLayout : abcLayout); const int contentRows = getContentRowCount(); for (int row = 0; row < contentRows; row++) { diff --git a/src/activities/util/KeyboardEntryActivity.h b/src/activities/util/KeyboardEntryActivity.h index c6b659cb..0a86febf 100644 --- a/src/activities/util/KeyboardEntryActivity.h +++ b/src/activities/util/KeyboardEntryActivity.h @@ -125,6 +125,49 @@ class KeyboardEntryActivity : public Activity { {',', '<'}}, }; + static constexpr KeyDef urlLayout[ABC_ROWS][COLS] = { + {{'1', '!'}, + {'2', '@'}, + {'3', '#'}, + {'4', '$'}, + {'5', '%'}, + {'6', '^'}, + {'7', '&'}, + {'8', '*'}, + {'9', '('}, + {'0', ')'}}, + {{'q', 'Q'}, + {'w', 'W'}, + {'e', 'E'}, + {'r', 'R'}, + {'t', 'T'}, + {'y', 'Y'}, + {'u', 'U'}, + {'i', 'I'}, + {'o', 'O'}, + {'p', 'P'}}, + {{'a', 'A'}, + {'s', 'S'}, + {'d', 'D'}, + {'f', 'F'}, + {'g', 'G'}, + {'h', 'H'}, + {'j', 'J'}, + {'k', 'K'}, + {'l', 'L'}, + {'-', '_'}}, + {{'z', 'Z'}, + {'x', 'X'}, + {'c', 'C'}, + {'v', 'V'}, + {'b', 'B'}, + {'n', 'N'}, + {'m', 'M'}, + {':', '+'}, + {'.', '>'}, + {'/', '<'}}, + }; + static constexpr KeyDef symLayout[SYM_ROWS][COLS] = { {{'1', '\0'}, {'2', '\0'},