A fork of https://github.com/crosspoint-reader/crosspoint-reader
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: Deduplicate battery drawing code and fix Lyra charging indicator (#1437)

## Summary

**What is the goal of this PR?**

Following up on #1427:
- Extracted shared battery drawing logic, including lightning bolt, to
reduce duplication.
- In Lyra with segmented battery the lightning bolt was hard to see, so
when charging Lyra now uses a solid battery fill.

---

### AI Usage

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? _**PARTIALLY**_

authored by

Zach Nelson and committed by
GitHub
1bd7a1de 23aad213

+59 -63
+34 -26
src/components/themes/BaseTheme.cpp
··· 16 16 17 17 // Internal constants 18 18 namespace { 19 - constexpr int batteryPercentSpacing = 4; 20 19 constexpr int homeMenuMargin = 20; 21 20 constexpr int homeMarginTop = 30; 22 21 constexpr int subtitleY = 738; 23 22 24 23 // Helper: draw battery icon at given position 25 24 void drawBatteryIcon(const GfxRenderer& renderer, int x, int y, int battWidth, int rectHeight, uint16_t percentage) { 26 - // Top line 27 - renderer.drawLine(x + 1, y, x + battWidth - 3, y); 28 - // Bottom line 29 - renderer.drawLine(x + 1, y + rectHeight - 1, x + battWidth - 3, y + rectHeight - 1); 30 - // Left line 31 - renderer.drawLine(x, y + 1, x, y + rectHeight - 2); 32 - // Battery end 33 - renderer.drawLine(x + battWidth - 2, y + 1, x + battWidth - 2, y + rectHeight - 2); 34 - renderer.drawPixel(x + battWidth - 1, y + 3); 35 - renderer.drawPixel(x + battWidth - 1, y + rectHeight - 4); 36 - renderer.drawLine(x + battWidth - 0, y + 4, x + battWidth - 0, y + rectHeight - 5); 25 + // Draw battery outline (shared code) 26 + BaseTheme::drawBatteryOutline(renderer, x, y, battWidth, rectHeight); 37 27 38 28 const bool charging = gpio.isUsbConnected(); 39 29 ··· 58 48 59 49 // Draw lightning bolt when charging (white/inverted on black fill for visibility) 60 50 if (charging) { 61 - const int boltX = x + 4; 62 - const int boltY = y + 2; 63 - renderer.drawLine(boltX + 4, boltY + 0, boltX + 5, boltY + 0, false); 64 - renderer.drawLine(boltX + 3, boltY + 1, boltX + 4, boltY + 1, false); 65 - renderer.drawLine(boltX + 2, boltY + 2, boltX + 5, boltY + 2, false); 66 - renderer.drawLine(boltX + 3, boltY + 3, boltX + 4, boltY + 3, false); 67 - renderer.drawLine(boltX + 2, boltY + 4, boltX + 3, boltY + 4, false); 68 - renderer.drawLine(boltX + 1, boltY + 5, boltX + 4, boltY + 5, false); 69 - renderer.drawLine(boltX + 2, boltY + 6, boltX + 3, boltY + 6, false); 70 - renderer.drawLine(boltX + 1, boltY + 7, boltX + 2, boltY + 7, false); 51 + BaseTheme::drawBatteryLightningBolt(renderer, x + 4, y + 2); 71 52 } 72 53 } 73 54 } // namespace 74 55 56 + void BaseTheme::drawBatteryOutline(const GfxRenderer& renderer, int x, int y, int battWidth, int rectHeight) { 57 + // Top line 58 + renderer.drawLine(x + 1, y, x + battWidth - 3, y); 59 + // Bottom line 60 + renderer.drawLine(x + 1, y + rectHeight - 1, x + battWidth - 3, y + rectHeight - 1); 61 + // Left line 62 + renderer.drawLine(x, y + 1, x, y + rectHeight - 2); 63 + // Battery end 64 + renderer.drawLine(x + battWidth - 2, y + 1, x + battWidth - 2, y + rectHeight - 2); 65 + renderer.drawPixel(x + battWidth - 1, y + 3); 66 + renderer.drawPixel(x + battWidth - 1, y + rectHeight - 4); 67 + renderer.drawLine(x + battWidth - 0, y + 4, x + battWidth - 0, y + rectHeight - 5); 68 + } 69 + 70 + void BaseTheme::drawBatteryLightningBolt(const GfxRenderer& renderer, int boltX, int boltY) { 71 + // Draw lightning bolt (white/inverted on black fill for visibility) 72 + renderer.drawLine(boltX + 4, boltY + 0, boltX + 5, boltY + 0, false); 73 + renderer.drawLine(boltX + 3, boltY + 1, boltX + 4, boltY + 1, false); 74 + renderer.drawLine(boltX + 2, boltY + 2, boltX + 5, boltY + 2, false); 75 + renderer.drawLine(boltX + 3, boltY + 3, boltX + 4, boltY + 3, false); 76 + renderer.drawLine(boltX + 2, boltY + 4, boltX + 3, boltY + 4, false); 77 + renderer.drawLine(boltX + 1, boltY + 5, boltX + 4, boltY + 5, false); 78 + renderer.drawLine(boltX + 2, boltY + 6, boltX + 3, boltY + 6, false); 79 + renderer.drawLine(boltX + 1, boltY + 7, boltX + 2, boltY + 7, false); 80 + } 81 + 75 82 void BaseTheme::drawBatteryLeft(const GfxRenderer& renderer, Rect rect, const bool showPercentage) const { 76 83 // Left aligned: icon on left, percentage on right (reader mode) 77 84 const uint16_t percentage = powerManager.getBatteryPercentage(); ··· 79 86 80 87 if (showPercentage) { 81 88 const auto percentageText = std::to_string(percentage) + "%"; 82 - renderer.drawText(SMALL_FONT_ID, rect.x + batteryPercentSpacing + BaseMetrics::values.batteryWidth, rect.y, 83 - percentageText.c_str()); 89 + renderer.drawText(SMALL_FONT_ID, rect.x + BaseTheme::batteryPercentSpacing + BaseMetrics::values.batteryWidth, 90 + rect.y, percentageText.c_str()); 84 91 } 85 92 86 93 drawBatteryIcon(renderer, rect.x, y, BaseMetrics::values.batteryWidth, rect.height, percentage); ··· 97 104 const int textWidth = renderer.getTextWidth(SMALL_FONT_ID, percentageText.c_str()); 98 105 // Clear the area where we're going to draw the text to prevent ghosting 99 106 const auto textHeight = renderer.getTextHeight(SMALL_FONT_ID); 100 - renderer.fillRect(rect.x - textWidth - batteryPercentSpacing, rect.y, textWidth, textHeight, false); 107 + renderer.fillRect(rect.x - textWidth - BaseTheme::batteryPercentSpacing, rect.y, textWidth, textHeight, false); 101 108 // Draw text to the left of the icon 102 - renderer.drawText(SMALL_FONT_ID, rect.x - textWidth - batteryPercentSpacing, rect.y, percentageText.c_str()); 109 + renderer.drawText(SMALL_FONT_ID, rect.x - textWidth - BaseTheme::batteryPercentSpacing, rect.y, 110 + percentageText.c_str()); 103 111 } 104 112 105 113 // Icon is already at correct position from rect.x
+5
src/components/themes/BaseTheme.h
··· 142 142 virtual void drawTextField(const GfxRenderer& renderer, Rect rect, const int textWidth) const; 143 143 virtual void drawKeyboardKey(const GfxRenderer& renderer, Rect rect, const char* label, const bool isSelected) const; 144 144 virtual bool showsFileIcons() const { return false; } 145 + 146 + // Shared constants and helpers for battery drawing (used by all themes) 147 + static constexpr int batteryPercentSpacing = 4; 148 + static void drawBatteryOutline(const GfxRenderer& renderer, int x, int y, int battWidth, int rectHeight); 149 + static void drawBatteryLightningBolt(const GfxRenderer& renderer, int boltX, int boltY); 145 150 };
+20 -37
src/components/themes/lyra/LyraTheme.cpp
··· 30 30 31 31 // Internal constants 32 32 namespace { 33 - constexpr int batteryPercentSpacing = 4; 34 33 constexpr int hPaddingInSelection = 8; 35 34 constexpr int cornerRadius = 6; 36 35 constexpr int topHintButtonY = 345; ··· 45 44 46 45 void drawLyraBatteryIcon(const GfxRenderer& renderer, int x, int y, int battWidth, int rectHeight, 47 46 uint16_t percentage) { 48 - // Top line 49 - renderer.drawLine(x + 1, y, x + battWidth - 3, y); 50 - // Bottom line 51 - renderer.drawLine(x + 1, y + rectHeight - 1, x + battWidth - 3, y + rectHeight - 1); 52 - // Left line 53 - renderer.drawLine(x, y + 1, x, y + rectHeight - 2); 54 - // Battery end 55 - renderer.drawLine(x + battWidth - 2, y + 1, x + battWidth - 2, y + rectHeight - 2); 56 - renderer.drawPixel(x + battWidth - 1, y + 3); 57 - renderer.drawPixel(x + battWidth - 1, y + rectHeight - 4); 58 - renderer.drawLine(x + battWidth - 0, y + 4, x + battWidth - 0, y + rectHeight - 5); 47 + BaseTheme::drawBatteryOutline(renderer, x, y, battWidth, rectHeight); 59 48 60 49 const bool charging = gpio.isUsbConnected(); 61 50 62 - // Draw bars 63 - if (percentage > 10 || charging) { 64 - renderer.fillRect(x + 2, y + 2, 3, rectHeight - 4); 65 - } 66 - if (percentage > 40 || charging) { 67 - renderer.fillRect(x + 6, y + 2, 3, rectHeight - 4); 68 - } 69 - if (percentage > 70) { 70 - renderer.fillRect(x + 10, y + 2, 3, rectHeight - 4); 71 - } 72 - 73 51 if (charging) { 74 - const int boltX = x + 4; 75 - const int boltY = y + 2; 76 - renderer.drawLine(boltX + 4, boltY + 0, boltX + 5, boltY + 0, false); 77 - renderer.drawLine(boltX + 3, boltY + 1, boltX + 4, boltY + 1, false); 78 - renderer.drawLine(boltX + 2, boltY + 2, boltX + 5, boltY + 2, false); 79 - renderer.drawLine(boltX + 3, boltY + 3, boltX + 4, boltY + 3, false); 80 - renderer.drawLine(boltX + 2, boltY + 4, boltX + 3, boltY + 4, false); 81 - renderer.drawLine(boltX + 1, boltY + 5, boltX + 4, boltY + 5, false); 82 - renderer.drawLine(boltX + 2, boltY + 6, boltX + 3, boltY + 6, false); 83 - renderer.drawLine(boltX + 1, boltY + 7, boltX + 2, boltY + 7, false); 52 + // Draw solid fill when charging so lightning bolt is visible 53 + renderer.fillRect(x + 2, y + 2, battWidth - 5, rectHeight - 4); 54 + BaseTheme::drawBatteryLightningBolt(renderer, x + 4, y + 2); 55 + } else { 56 + // Draw bars when not charging 57 + if (percentage > 10) { 58 + renderer.fillRect(x + 2, y + 2, 3, rectHeight - 4); 59 + } 60 + if (percentage > 40) { 61 + renderer.fillRect(x + 6, y + 2, 3, rectHeight - 4); 62 + } 63 + if (percentage > 70) { 64 + renderer.fillRect(x + 10, y + 2, 3, rectHeight - 4); 65 + } 84 66 } 85 67 } 86 68 ··· 132 114 133 115 if (showPercentage) { 134 116 const auto percentageText = std::to_string(percentage) + "%"; 135 - renderer.drawText(SMALL_FONT_ID, rect.x + batteryPercentSpacing + LyraMetrics::values.batteryWidth, rect.y, 136 - percentageText.c_str()); 117 + renderer.drawText(SMALL_FONT_ID, rect.x + BaseTheme::batteryPercentSpacing + LyraMetrics::values.batteryWidth, 118 + rect.y, percentageText.c_str()); 137 119 } 138 120 139 121 drawLyraBatteryIcon(renderer, rect.x, rect.y + 6, LyraMetrics::values.batteryWidth, rect.height, percentage); ··· 148 130 const int textWidth = renderer.getTextWidth(SMALL_FONT_ID, percentageText.c_str()); 149 131 // Clear the area where we're going to draw the text to prevent ghosting 150 132 const auto textHeight = renderer.getTextHeight(SMALL_FONT_ID); 151 - renderer.fillRect(rect.x - textWidth - batteryPercentSpacing, rect.y, textWidth, textHeight, false); 133 + renderer.fillRect(rect.x - textWidth - BaseTheme::batteryPercentSpacing, rect.y, textWidth, textHeight, false); 152 134 // Draw text to the left of the icon 153 - renderer.drawText(SMALL_FONT_ID, rect.x - textWidth - batteryPercentSpacing, rect.y, percentageText.c_str()); 135 + renderer.drawText(SMALL_FONT_ID, rect.x - textWidth - BaseTheme::batteryPercentSpacing, rect.y, 136 + percentageText.c_str()); 154 137 } 155 138 156 139 drawLyraBatteryIcon(renderer, rect.x, rect.y + 6, LyraMetrics::values.batteryWidth, rect.height, percentage);