mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-04 06:37:38 +03:00
feat(extensions): polish app install UX
This commit is contained in:
parent
e55fe71145
commit
4ffbc2a641
@ -86,9 +86,12 @@ void AppsActivity::launchApp() {
|
||||
|
||||
CrossPoint::AppLoader loader;
|
||||
bool success = loader.flashApp(binPath, [this](size_t written, size_t total) {
|
||||
flashProgress_ = static_cast<int>((written * 100) / total);
|
||||
needsUpdate_ = true;
|
||||
renderProgress();
|
||||
const int nextProgress = (total > 0) ? static_cast<int>((written * 100) / total) : 0;
|
||||
if (nextProgress != flashProgress_) {
|
||||
flashProgress_ = nextProgress;
|
||||
needsUpdate_ = true;
|
||||
renderProgress();
|
||||
}
|
||||
});
|
||||
|
||||
if (!success) {
|
||||
@ -134,7 +137,8 @@ void AppsActivity::render() {
|
||||
int textWidth = renderer_.getTextWidth(UI_12_FONT_ID, buf);
|
||||
int x = (pageWidth - textWidth) / 2 - 10;
|
||||
renderer_.fillRect(x, y - 5, textWidth + 20, lineHeight - 5);
|
||||
renderer_.drawText(UI_12_FONT_ID, x + 10, y, buf, true); // inverted
|
||||
// Draw white text on black highlight.
|
||||
renderer_.drawText(UI_12_FONT_ID, x + 10, y, buf, false);
|
||||
} else {
|
||||
renderer_.drawCenteredText(UI_10_FONT_ID, y, buf);
|
||||
}
|
||||
|
||||
@ -506,7 +506,8 @@ void HomeActivity::render() {
|
||||
|
||||
// --- Bottom menu tiles ---
|
||||
// Build menu items dynamically
|
||||
std::vector<const char*> menuItems = {"My Library", "File Transfer", "Settings"};
|
||||
// Keep this list in sync with getMenuItemCount() and loop() index mapping.
|
||||
std::vector<const char*> menuItems = {"My Library", "File Transfer", "Apps", "Settings"};
|
||||
if (hasOpdsUrl) {
|
||||
// Insert OPDS Browser after My Library
|
||||
menuItems.insert(menuItems.begin() + 1, "OPDS Browser");
|
||||
|
||||
@ -19,7 +19,7 @@ EpdFont ui12BoldFont(&ubuntu_12_bold);
|
||||
EpdFontFamily ui12FontFamily(&ui12RegularFont, &ui12BoldFont);
|
||||
}
|
||||
|
||||
HelloWorldActivity::HelloWorldActivity(EInkDisplay& display, InputManager& input)
|
||||
HelloWorldActivity::HelloWorldActivity(HalDisplay& display, HalGPIO& input)
|
||||
: display_(display), input_(input), needsUpdate_(true) {}
|
||||
|
||||
void HelloWorldActivity::onEnter() {
|
||||
@ -35,7 +35,7 @@ void HelloWorldActivity::onEnter() {
|
||||
}
|
||||
|
||||
void HelloWorldActivity::loop() {
|
||||
if (input_.wasPressed(InputManager::BTN_BACK)) {
|
||||
if (input_.wasPressed(HalGPIO::BTN_BACK)) {
|
||||
returnToLauncher();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <EInkDisplay.h>
|
||||
#include <InputManager.h>
|
||||
#include <HalDisplay.h>
|
||||
#include <HalGPIO.h>
|
||||
|
||||
class HelloWorldActivity {
|
||||
public:
|
||||
HelloWorldActivity(EInkDisplay& display, InputManager& input);
|
||||
HelloWorldActivity(HalDisplay& display, HalGPIO& input);
|
||||
|
||||
void onEnter();
|
||||
void loop();
|
||||
void onExit();
|
||||
|
||||
private:
|
||||
EInkDisplay& display_;
|
||||
InputManager& input_;
|
||||
HalDisplay& display_;
|
||||
HalGPIO& input_;
|
||||
bool needsUpdate_;
|
||||
|
||||
void render();
|
||||
|
||||
@ -1,32 +1,31 @@
|
||||
#include <Arduino.h>
|
||||
#include <EInkDisplay.h>
|
||||
#include <InputManager.h>
|
||||
#include <HalDisplay.h>
|
||||
#include <HalGPIO.h>
|
||||
|
||||
#include "HelloWorldActivity.h"
|
||||
|
||||
// Display SPI pins for Xteink X4
|
||||
#define EPD_SCLK 8
|
||||
#define EPD_MOSI 10
|
||||
#define EPD_CS 21
|
||||
#define EPD_DC 4
|
||||
#define EPD_RST 5
|
||||
#define EPD_BUSY 6
|
||||
|
||||
EInkDisplay display(EPD_SCLK, EPD_MOSI, EPD_CS, EPD_DC, EPD_RST, EPD_BUSY);
|
||||
InputManager input;
|
||||
HelloWorldActivity activity(display, input);
|
||||
HalDisplay display;
|
||||
HalGPIO gpio;
|
||||
HelloWorldActivity activity(display, gpio);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("[HelloWorld] Starting...");
|
||||
|
||||
input.begin();
|
||||
gpio.begin();
|
||||
|
||||
// Only start serial if USB connected
|
||||
if (gpio.isUsbConnected()) {
|
||||
Serial.begin(115200);
|
||||
Serial.println("[HelloWorld] Starting...");
|
||||
}
|
||||
|
||||
activity.onEnter();
|
||||
|
||||
Serial.println("[HelloWorld] Activity started");
|
||||
|
||||
if (Serial) {
|
||||
Serial.println("[HelloWorld] Activity started");
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
input.update();
|
||||
gpio.update();
|
||||
activity.loop();
|
||||
delay(10);
|
||||
}
|
||||
|
||||
@ -102,8 +102,15 @@ AppManifest AppLoader::parseManifest(const String& path) {
|
||||
return manifest;
|
||||
}
|
||||
|
||||
// Handle UTF-8 BOM if the manifest was created by an editor that writes it.
|
||||
const char* json = buffer.get();
|
||||
if (bytesRead >= 3 && static_cast<uint8_t>(json[0]) == 0xEF && static_cast<uint8_t>(json[1]) == 0xBB &&
|
||||
static_cast<uint8_t>(json[2]) == 0xBF) {
|
||||
json += 3;
|
||||
}
|
||||
|
||||
JsonDocument doc;
|
||||
const DeserializationError error = deserializeJson(doc, buffer.get());
|
||||
const DeserializationError error = deserializeJson(doc, json);
|
||||
|
||||
if (error) {
|
||||
Serial.printf("[%lu] [AppLoader] JSON parse error in %s: %s\n",
|
||||
@ -230,12 +237,16 @@ bool AppLoader::flashApp(const String& binPath, ProgressCallback callback) {
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback(0, 100);
|
||||
callback(0, fileSize);
|
||||
}
|
||||
|
||||
size_t totalWritten = 0;
|
||||
static constexpr size_t flashChunkSize = 1024;
|
||||
uint8_t buffer[flashChunkSize];
|
||||
// Larger chunks reduce SD/OTA overhead significantly.
|
||||
// 32KB is a good balance on ESP32-C3: faster writes without blowing RAM.
|
||||
static constexpr size_t flashChunkSize = 32 * 1024;
|
||||
static uint8_t buffer[flashChunkSize];
|
||||
|
||||
size_t lastNotifiedPercent = 0;
|
||||
|
||||
while (totalWritten < fileSize) {
|
||||
const size_t remaining = fileSize - totalWritten;
|
||||
@ -260,7 +271,11 @@ bool AppLoader::flashApp(const String& binPath, ProgressCallback callback) {
|
||||
|
||||
if (callback) {
|
||||
const size_t percent = (totalWritten * 100) / fileSize;
|
||||
callback(percent, 100);
|
||||
// Throttle UI updates; each screen refresh is ~400ms.
|
||||
if (percent >= lastNotifiedPercent + 10 || percent == 100) {
|
||||
lastNotifiedPercent = percent;
|
||||
callback(totalWritten, fileSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user