mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-04 22:57:50 +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;
|
CrossPoint::AppLoader loader;
|
||||||
bool success = loader.flashApp(binPath, [this](size_t written, size_t total) {
|
bool success = loader.flashApp(binPath, [this](size_t written, size_t total) {
|
||||||
flashProgress_ = static_cast<int>((written * 100) / total);
|
const int nextProgress = (total > 0) ? static_cast<int>((written * 100) / total) : 0;
|
||||||
needsUpdate_ = true;
|
if (nextProgress != flashProgress_) {
|
||||||
renderProgress();
|
flashProgress_ = nextProgress;
|
||||||
|
needsUpdate_ = true;
|
||||||
|
renderProgress();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@ -134,7 +137,8 @@ void AppsActivity::render() {
|
|||||||
int textWidth = renderer_.getTextWidth(UI_12_FONT_ID, buf);
|
int textWidth = renderer_.getTextWidth(UI_12_FONT_ID, buf);
|
||||||
int x = (pageWidth - textWidth) / 2 - 10;
|
int x = (pageWidth - textWidth) / 2 - 10;
|
||||||
renderer_.fillRect(x, y - 5, textWidth + 20, lineHeight - 5);
|
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 {
|
} else {
|
||||||
renderer_.drawCenteredText(UI_10_FONT_ID, y, buf);
|
renderer_.drawCenteredText(UI_10_FONT_ID, y, buf);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -506,7 +506,8 @@ void HomeActivity::render() {
|
|||||||
|
|
||||||
// --- Bottom menu tiles ---
|
// --- Bottom menu tiles ---
|
||||||
// Build menu items dynamically
|
// 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) {
|
if (hasOpdsUrl) {
|
||||||
// Insert OPDS Browser after My Library
|
// Insert OPDS Browser after My Library
|
||||||
menuItems.insert(menuItems.begin() + 1, "OPDS Browser");
|
menuItems.insert(menuItems.begin() + 1, "OPDS Browser");
|
||||||
|
|||||||
@ -19,7 +19,7 @@ EpdFont ui12BoldFont(&ubuntu_12_bold);
|
|||||||
EpdFontFamily ui12FontFamily(&ui12RegularFont, &ui12BoldFont);
|
EpdFontFamily ui12FontFamily(&ui12RegularFont, &ui12BoldFont);
|
||||||
}
|
}
|
||||||
|
|
||||||
HelloWorldActivity::HelloWorldActivity(EInkDisplay& display, InputManager& input)
|
HelloWorldActivity::HelloWorldActivity(HalDisplay& display, HalGPIO& input)
|
||||||
: display_(display), input_(input), needsUpdate_(true) {}
|
: display_(display), input_(input), needsUpdate_(true) {}
|
||||||
|
|
||||||
void HelloWorldActivity::onEnter() {
|
void HelloWorldActivity::onEnter() {
|
||||||
@ -35,7 +35,7 @@ void HelloWorldActivity::onEnter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HelloWorldActivity::loop() {
|
void HelloWorldActivity::loop() {
|
||||||
if (input_.wasPressed(InputManager::BTN_BACK)) {
|
if (input_.wasPressed(HalGPIO::BTN_BACK)) {
|
||||||
returnToLauncher();
|
returnToLauncher();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <EInkDisplay.h>
|
#include <HalDisplay.h>
|
||||||
#include <InputManager.h>
|
#include <HalGPIO.h>
|
||||||
|
|
||||||
class HelloWorldActivity {
|
class HelloWorldActivity {
|
||||||
public:
|
public:
|
||||||
HelloWorldActivity(EInkDisplay& display, InputManager& input);
|
HelloWorldActivity(HalDisplay& display, HalGPIO& input);
|
||||||
|
|
||||||
void onEnter();
|
void onEnter();
|
||||||
void loop();
|
void loop();
|
||||||
void onExit();
|
void onExit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EInkDisplay& display_;
|
HalDisplay& display_;
|
||||||
InputManager& input_;
|
HalGPIO& input_;
|
||||||
bool needsUpdate_;
|
bool needsUpdate_;
|
||||||
|
|
||||||
void render();
|
void render();
|
||||||
|
|||||||
@ -1,32 +1,31 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <EInkDisplay.h>
|
#include <HalDisplay.h>
|
||||||
#include <InputManager.h>
|
#include <HalGPIO.h>
|
||||||
|
|
||||||
#include "HelloWorldActivity.h"
|
#include "HelloWorldActivity.h"
|
||||||
|
|
||||||
// Display SPI pins for Xteink X4
|
HalDisplay display;
|
||||||
#define EPD_SCLK 8
|
HalGPIO gpio;
|
||||||
#define EPD_MOSI 10
|
HelloWorldActivity activity(display, gpio);
|
||||||
#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);
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
gpio.begin();
|
||||||
Serial.println("[HelloWorld] Starting...");
|
|
||||||
|
// Only start serial if USB connected
|
||||||
input.begin();
|
if (gpio.isUsbConnected()) {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("[HelloWorld] Starting...");
|
||||||
|
}
|
||||||
|
|
||||||
activity.onEnter();
|
activity.onEnter();
|
||||||
|
|
||||||
Serial.println("[HelloWorld] Activity started");
|
if (Serial) {
|
||||||
|
Serial.println("[HelloWorld] Activity started");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
input.update();
|
gpio.update();
|
||||||
activity.loop();
|
activity.loop();
|
||||||
delay(10);
|
delay(10);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -102,8 +102,15 @@ AppManifest AppLoader::parseManifest(const String& path) {
|
|||||||
return manifest;
|
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;
|
JsonDocument doc;
|
||||||
const DeserializationError error = deserializeJson(doc, buffer.get());
|
const DeserializationError error = deserializeJson(doc, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
Serial.printf("[%lu] [AppLoader] JSON parse error in %s: %s\n",
|
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) {
|
if (callback) {
|
||||||
callback(0, 100);
|
callback(0, fileSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t totalWritten = 0;
|
size_t totalWritten = 0;
|
||||||
static constexpr size_t flashChunkSize = 1024;
|
// Larger chunks reduce SD/OTA overhead significantly.
|
||||||
uint8_t buffer[flashChunkSize];
|
// 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) {
|
while (totalWritten < fileSize) {
|
||||||
const size_t remaining = fileSize - totalWritten;
|
const size_t remaining = fileSize - totalWritten;
|
||||||
@ -260,7 +271,11 @@ bool AppLoader::flashApp(const String& binPath, ProgressCallback callback) {
|
|||||||
|
|
||||||
if (callback) {
|
if (callback) {
|
||||||
const size_t percent = (totalWritten * 100) / fileSize;
|
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