feat: add charging indicator to battery icon (#516)

This commit is contained in:
didacta 2026-01-24 20:13:19 -05:00
parent 3ce11f14ce
commit 0f29de49f8
6 changed files with 44 additions and 8 deletions

View File

@ -1,6 +1,13 @@
#pragma once
#include <Arduino.h>
#include <BatteryMonitor.h>
#define BAT_GPIO0 0 // Battery voltage
static BatteryMonitor battery(BAT_GPIO0);
// Returns true when USB is connected (device is charging)
// Uses GPIO20 (U0RXD) which reads HIGH when USB is connected
inline bool isCharging() {
return digitalRead(20) == HIGH;
}

View File

@ -9,7 +9,7 @@
#include "fontIds.h"
void ScreenComponents::drawBattery(const GfxRenderer& renderer, const int left, const int top,
const bool showPercentage) {
const bool showPercentage, const bool charging) {
// Left aligned battery icon and percentage
const uint16_t percentage = battery.readPercentage();
const auto percentageText = showPercentage ? std::to_string(percentage) + "%" : "";
@ -34,12 +34,38 @@ void ScreenComponents::drawBattery(const GfxRenderer& renderer, const int left,
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
int filledWidth = percentage * (batteryWidth - 5) / 100 + 1;
if (filledWidth > batteryWidth - 5) {
filledWidth = batteryWidth - 5; // Ensure we don't overflow
constexpr int maxFillWidth = batteryWidth - 5;
int filledWidth = percentage * maxFillWidth / 100 + 1;
if (filledWidth > maxFillWidth) {
filledWidth = maxFillWidth;
}
// When charging, ensure minimum fill so lightning bolt is fully visible
constexpr int minFillForBolt = 8; // Bolt extends 6px wide, needs padding
if (charging && filledWidth < minFillForBolt) {
filledWidth = minFillForBolt;
}
renderer.fillRect(x + 2, y + 2, filledWidth, batteryHeight - 4);
// Draw lightning bolt when charging (white/inverted on black fill for visibility)
if (charging) {
// Lightning bolt: 6px wide, 8px tall, centered in battery
const int boltX = x + 4;
const int boltY = y + 2;
// Draw bolt in white (state=false) for visibility on black fill
// Upper diagonal pointing right
renderer.drawLine(boltX + 4, boltY + 0, boltX + 5, boltY + 0, false);
renderer.drawLine(boltX + 3, boltY + 1, boltX + 4, boltY + 1, false);
renderer.drawLine(boltX + 2, boltY + 2, boltX + 5, boltY + 2, false); // Wide middle
renderer.drawLine(boltX + 3, boltY + 3, boltX + 4, boltY + 3, false);
// Lower diagonal pointing left
renderer.drawLine(boltX + 2, boltY + 4, boltX + 3, boltY + 4, false);
renderer.drawLine(boltX + 1, boltY + 5, boltX + 4, boltY + 5, false); // Wide middle
renderer.drawLine(boltX + 2, boltY + 6, boltX + 3, boltY + 6, false);
renderer.drawLine(boltX + 1, boltY + 7, boltX + 2, boltY + 7, false);
}
}
int ScreenComponents::drawTabBar(const GfxRenderer& renderer, const int y, const std::vector<TabInfo>& tabs) {

View File

@ -13,7 +13,8 @@ struct TabInfo {
class ScreenComponents {
public:
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 charging = false);
// Draw a horizontal tab bar with underline indicator for selected tab
// Returns the height of the tab bar (for positioning content below)

View File

@ -550,7 +550,7 @@ void HomeActivity::render() {
const uint16_t percentage = battery.readPercentage();
const auto percentageText = showBatteryPercentage ? std::to_string(percentage) + "%" : "";
const auto batteryX = pageWidth - 25 - renderer.getTextWidth(SMALL_FONT_ID, percentageText.c_str());
ScreenComponents::drawBattery(renderer, batteryX, 10, showBatteryPercentage);
ScreenComponents::drawBattery(renderer, batteryX, 10, showBatteryPercentage, isCharging());
renderer.displayBuffer();
}

View File

@ -5,6 +5,7 @@
#include <GfxRenderer.h>
#include <SDCardManager.h>
#include "Battery.h"
#include "CrossPointSettings.h"
#include "CrossPointState.h"
#include "EpubReaderChapterSelectionActivity.h"
@ -457,7 +458,7 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in
}
if (showBattery) {
ScreenComponents::drawBattery(renderer, orientedMarginLeft + 1, textY, showBatteryPercentage);
ScreenComponents::drawBattery(renderer, orientedMarginLeft + 1, textY, showBatteryPercentage, isCharging());
}
if (showChapterTitle) {

View File

@ -5,6 +5,7 @@
#include <Serialization.h>
#include <Utf8.h>
#include "Battery.h"
#include "CrossPointSettings.h"
#include "CrossPointState.h"
#include "MappedInputManager.h"
@ -517,7 +518,7 @@ void TxtReaderActivity::renderStatusBar(const int orientedMarginRight, const int
}
if (showBattery) {
ScreenComponents::drawBattery(renderer, orientedMarginLeft, textY);
ScreenComponents::drawBattery(renderer, orientedMarginLeft, textY, true, isCharging());
}
if (showTitle) {