diff --git a/src/MappedInputManager.cpp b/src/MappedInputManager.cpp index e37995e..04270e1 100644 --- a/src/MappedInputManager.cpp +++ b/src/MappedInputManager.cpp @@ -74,6 +74,8 @@ bool MappedInputManager::wasAnyReleased() const { return gpio.wasAnyReleased(); unsigned long MappedInputManager::getHeldTime() const { return gpio.getHeldTime(); } +bool MappedInputManager::isUsbConnected() const { return gpio.isUsbConnected(); } + MappedInputManager::Labels MappedInputManager::mapLabels(const char* back, const char* confirm, const char* previous, const char* next) const { const auto layout = static_cast(SETTINGS.frontButtonLayout); diff --git a/src/MappedInputManager.h b/src/MappedInputManager.h index f507a92..068b5be 100644 --- a/src/MappedInputManager.h +++ b/src/MappedInputManager.h @@ -21,6 +21,7 @@ class MappedInputManager { bool wasAnyPressed() const; bool wasAnyReleased() const; unsigned long getHeldTime() const; + bool isUsbConnected() const; Labels mapLabels(const char* back, const char* confirm, const char* previous, const char* next) const; private: diff --git a/src/ScreenComponents.cpp b/src/ScreenComponents.cpp index c46a767..e5279e0 100644 --- a/src/ScreenComponents.cpp +++ b/src/ScreenComponents.cpp @@ -11,14 +11,14 @@ #include "fontIds.h" void ScreenComponents::drawBattery(const GfxRenderer& renderer, const int left, const int top, - const bool showPercentage) { + const bool showPercentage, const bool isCharging) { // Left aligned battery icon and percentage const uint16_t percentage = battery.readPercentage(); const auto percentageText = showPercentage ? std::to_string(percentage) + "%" : ""; - renderer.drawText(SMALL_FONT_ID, left + 20, top, percentageText.c_str()); + renderer.drawText(SMALL_FONT_ID, left + 28, top, percentageText.c_str()); - // 1 column on left, 2 columns on right, 5 columns of battery body - constexpr int batteryWidth = 15; + // 1.5x original width: 23px wide, 12px tall + constexpr int batteryWidth = 23; constexpr int batteryHeight = 12; const int x = left; const int y = top + 6; @@ -29,30 +29,69 @@ void ScreenComponents::drawBattery(const GfxRenderer& renderer, const int left, renderer.drawLine(x + 1, y + batteryHeight - 1, x + batteryWidth - 3, y + batteryHeight - 1); // Left line renderer.drawLine(x, y + 1, x, y + batteryHeight - 2); - // Battery end + // Battery end (right side with nub) renderer.drawLine(x + batteryWidth - 2, y + 1, x + batteryWidth - 2, y + batteryHeight - 2); renderer.drawPixel(x + batteryWidth - 1, y + 3); renderer.drawPixel(x + batteryWidth - 1, y + batteryHeight - 4); renderer.drawLine(x + batteryWidth - 0, y + 4, x + batteryWidth - 0, y + batteryHeight - 5); // The +1 is to round up, so that we always fill at least one pixel + // Fill area is batteryWidth - 5 = 18px int filledWidth = percentage * (batteryWidth - 5) / 100 + 1; if (filledWidth > batteryWidth - 5) { filledWidth = batteryWidth - 5; // Ensure we don't overflow } renderer.fillRect(x + 2, y + 2, filledWidth, batteryHeight - 4); + + // Draw 8x8 lightning bolt overlay when charging, centered in fill area + if (isCharging) { + // Center bolt in the full fill area (as if 100% charged) + const int fillAreaWidth = batteryWidth - 5; // 18px + const int fillAreaHeight = batteryHeight - 4; // 8px + const int boltX = x + 2 + (fillAreaWidth - 8) / 2; // Center 8px bolt in 18px fill area + const int boltY = y + 2 + (fillAreaHeight - 8) / 2; // Center 8px bolt in 8px fill area + // 8x8 lightning bolt from SVG: m8 22l1-7H4l9-13h2l-1 8h6L10 22z + // Row 0 + renderer.drawPixel(boltX + 4, boltY + 0, false); + renderer.drawPixel(boltX + 5, boltY + 0, false); + // Row 1 + renderer.drawPixel(boltX + 3, boltY + 1, false); + renderer.drawPixel(boltX + 4, boltY + 1, false); + // Row 2 + renderer.drawPixel(boltX + 2, boltY + 2, false); + renderer.drawPixel(boltX + 3, boltY + 2, false); + renderer.drawPixel(boltX + 4, boltY + 2, false); + // Row 3 + renderer.drawPixel(boltX + 1, boltY + 3, false); + renderer.drawPixel(boltX + 2, boltY + 3, false); + renderer.drawPixel(boltX + 3, boltY + 3, false); + renderer.drawPixel(boltX + 4, boltY + 3, false); + renderer.drawPixel(boltX + 5, boltY + 3, false); + // Row 4 + renderer.drawPixel(boltX + 3, boltY + 4, false); + renderer.drawPixel(boltX + 4, boltY + 4, false); + renderer.drawPixel(boltX + 5, boltY + 4, false); + // Row 5 + renderer.drawPixel(boltX + 3, boltY + 5, false); + renderer.drawPixel(boltX + 4, boltY + 5, false); + // Row 6 + renderer.drawPixel(boltX + 2, boltY + 6, false); + renderer.drawPixel(boltX + 3, boltY + 6, false); + // Row 7 + renderer.drawPixel(boltX + 2, boltY + 7, false); + } } void ScreenComponents::drawBatteryLarge(const GfxRenderer& renderer, const int left, const int top, - const bool showPercentage) { + const bool showPercentage, const bool isCharging) { // Larger battery icon with UI_10 font for bottom button hint area const uint16_t percentage = battery.readPercentage(); const auto percentageText = showPercentage ? std::to_string(percentage) + "%" : ""; - renderer.drawText(UI_10_FONT_ID, left + 28, top, percentageText.c_str()); + renderer.drawText(UI_10_FONT_ID, left + 38, top, percentageText.c_str()); - // Scaled up battery dimensions (~33% larger) - constexpr int batteryWidth = 20; + // 1.5x original width: 30px wide, 16px tall + constexpr int batteryWidth = 30; constexpr int batteryHeight = 16; const int x = left; const int y = top + 6; @@ -71,12 +110,70 @@ void ScreenComponents::drawBatteryLarge(const GfxRenderer& renderer, const int l renderer.drawLine(x + batteryWidth - 1, y + 5, x + batteryWidth - 1, y + batteryHeight - 6); // The +1 is to round up, so that we always fill at least one pixel + // Fill area is batteryWidth - 6 = 24px int filledWidth = percentage * (batteryWidth - 6) / 100 + 1; if (filledWidth > batteryWidth - 6) { filledWidth = batteryWidth - 6; // Ensure we don't overflow } renderer.fillRect(x + 2, y + 2, filledWidth, batteryHeight - 4); + + // Draw 12x12 lightning bolt overlay when charging, centered in fill area + if (isCharging) { + // Center bolt in the full fill area (as if 100% charged) + const int fillAreaWidth = batteryWidth - 6; // 24px + const int fillAreaHeight = batteryHeight - 4; // 12px + const int boltX = x + 2 + (fillAreaWidth - 12) / 2; // Center 12px bolt in 24px fill area + const int boltY = y + 2 + (fillAreaHeight - 12) / 2; // Center 12px bolt in 12px fill area + // 12x12 lightning bolt from SVG: m8 22l1-7H4l9-13h2l-1 8h6L10 22z + // Row 0 + renderer.drawPixel(boltX + 6, boltY + 0, false); + renderer.drawPixel(boltX + 7, boltY + 0, false); + // Row 1 + renderer.drawPixel(boltX + 5, boltY + 1, false); + renderer.drawPixel(boltX + 6, boltY + 1, false); + renderer.drawPixel(boltX + 7, boltY + 1, false); + // Row 2 + renderer.drawPixel(boltX + 4, boltY + 2, false); + renderer.drawPixel(boltX + 5, boltY + 2, false); + renderer.drawPixel(boltX + 6, boltY + 2, false); + // Row 3 + renderer.drawPixel(boltX + 3, boltY + 3, false); + renderer.drawPixel(boltX + 4, boltY + 3, false); + renderer.drawPixel(boltX + 5, boltY + 3, false); + // Row 4 + renderer.drawPixel(boltX + 2, boltY + 4, false); + renderer.drawPixel(boltX + 3, boltY + 4, false); + renderer.drawPixel(boltX + 4, boltY + 4, false); + renderer.drawPixel(boltX + 5, boltY + 4, false); + renderer.drawPixel(boltX + 6, boltY + 4, false); + renderer.drawPixel(boltX + 7, boltY + 4, false); + renderer.drawPixel(boltX + 8, boltY + 4, false); + // Row 5 + renderer.drawPixel(boltX + 4, boltY + 5, false); + renderer.drawPixel(boltX + 5, boltY + 5, false); + renderer.drawPixel(boltX + 6, boltY + 5, false); + renderer.drawPixel(boltX + 7, boltY + 5, false); + renderer.drawPixel(boltX + 8, boltY + 5, false); + // Row 6 + renderer.drawPixel(boltX + 5, boltY + 6, false); + renderer.drawPixel(boltX + 6, boltY + 6, false); + renderer.drawPixel(boltX + 7, boltY + 6, false); + // Row 7 + renderer.drawPixel(boltX + 5, boltY + 7, false); + renderer.drawPixel(boltX + 6, boltY + 7, false); + // Row 8 + renderer.drawPixel(boltX + 4, boltY + 8, false); + renderer.drawPixel(boltX + 5, boltY + 8, false); + // Row 9 + renderer.drawPixel(boltX + 3, boltY + 9, false); + renderer.drawPixel(boltX + 4, boltY + 9, false); + // Row 10 + renderer.drawPixel(boltX + 3, boltY + 10, false); + renderer.drawPixel(boltX + 4, boltY + 10, false); + // Row 11 + renderer.drawPixel(boltX + 3, boltY + 11, false); + } } void ScreenComponents::drawBookProgressBar(const GfxRenderer& renderer, const size_t bookProgress) { diff --git a/src/ScreenComponents.h b/src/ScreenComponents.h index 886f1d4..c8eae82 100644 --- a/src/ScreenComponents.h +++ b/src/ScreenComponents.h @@ -15,11 +15,13 @@ class ScreenComponents { public: static const int BOOK_PROGRESS_BAR_HEIGHT = 4; - static void drawBattery(const GfxRenderer& renderer, int left, int top, bool showPercentage = true); + static void drawBattery(const GfxRenderer& renderer, int left, int top, bool showPercentage = true, + bool isCharging = false); static void drawBookProgressBar(const GfxRenderer& renderer, size_t bookProgress); // Draw a larger battery icon suitable for bottom button hint area - static void drawBatteryLarge(const GfxRenderer& renderer, int left, int top, bool showPercentage = true); + static void drawBatteryLarge(const GfxRenderer& renderer, int left, int top, bool showPercentage = true, + bool isCharging = false); // Draw a horizontal tab bar with underline indicator for selected tab // Returns the height of the tab bar (for positioning content below) diff --git a/src/activities/home/HomeActivity.cpp b/src/activities/home/HomeActivity.cpp index cf546a1..5e6330d 100644 --- a/src/activities/home/HomeActivity.cpp +++ b/src/activities/home/HomeActivity.cpp @@ -751,7 +751,7 @@ void HomeActivity::render() { SETTINGS.hideBatteryPercentage != CrossPointSettings::HIDE_BATTERY_PERCENTAGE::HIDE_ALWAYS; constexpr int batteryX = 25; // Align with first button hint position const int batteryY = pageHeight - 34; // Vertically centered in button hint area - ScreenComponents::drawBatteryLarge(renderer, batteryX, batteryY, showBatteryPercentage); + ScreenComponents::drawBatteryLarge(renderer, batteryX, batteryY, showBatteryPercentage, mappedInput.isUsbConnected()); renderer.displayBuffer(); } diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 970eb44..4357ffa 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -919,7 +919,8 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in } if (showBattery) { - ScreenComponents::drawBattery(renderer, orientedMarginLeft + 1, textY, showBatteryPercentage); + ScreenComponents::drawBattery(renderer, orientedMarginLeft + 1, textY, showBatteryPercentage, + mappedInput.isUsbConnected()); } if (showChapterTitle) { @@ -927,7 +928,7 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in // Page width minus existing content with 30px padding on each side const int rendererableScreenWidth = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight; - const int batterySize = showBattery ? (showBatteryPercentage ? 50 : 20) : 0; + const int batterySize = showBattery ? (showBatteryPercentage ? 65 : 28) : 0; const int titleMarginLeft = batterySize + 30; const int titleMarginRight = progressTextWidth + 30; diff --git a/src/activities/reader/TxtReaderActivity.cpp b/src/activities/reader/TxtReaderActivity.cpp index 9c05656..f962e2c 100644 --- a/src/activities/reader/TxtReaderActivity.cpp +++ b/src/activities/reader/TxtReaderActivity.cpp @@ -642,11 +642,13 @@ void TxtReaderActivity::renderStatusBar(const int orientedMarginRight, const int } if (showBattery) { - ScreenComponents::drawBattery(renderer, orientedMarginLeft, textY, showBatteryPercentage); + ScreenComponents::drawBattery(renderer, orientedMarginLeft, textY, showBatteryPercentage, + mappedInput.isUsbConnected()); } if (showTitle) { - const int titleMarginLeft = 50 + 30 + orientedMarginLeft; + const int batterySize = showBattery ? (showBatteryPercentage ? 65 : 28) : 0; + const int titleMarginLeft = batterySize + 30 + orientedMarginLeft; const int titleMarginRight = progressTextWidth + 30 + orientedMarginRight; const int availableTextWidth = renderer.getScreenWidth() - titleMarginLeft - titleMarginRight;