mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-06 23:57:39 +03:00
Traduction initiale
This commit is contained in:
parent
d4ae108d9b
commit
624586ec03
@ -14,7 +14,7 @@ void BootActivity::onEnter() {
|
|||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
renderer.drawImage(CrossLarge, (pageWidth + 128) / 2, (pageHeight - 128) / 2, 128, 128);
|
renderer.drawImage(CrossLarge, (pageWidth + 128) / 2, (pageHeight - 128) / 2, 128, 128);
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 70, "CrossPoint", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 70, "CrossPoint", true, EpdFontFamily::BOLD);
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight / 2 + 95, "BOOTING");
|
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight / 2 + 95, "DÉMARRAGE");
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, CROSSPOINT_VERSION);
|
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, CROSSPOINT_VERSION);
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
void SleepActivity::onEnter() {
|
void SleepActivity::onEnter() {
|
||||||
Activity::onEnter();
|
Activity::onEnter();
|
||||||
renderPopup("Entering Sleep...");
|
renderPopup("Mise en veille...");
|
||||||
|
|
||||||
if (SETTINGS.sleepScreen == CrossPointSettings::SLEEP_SCREEN_MODE::BLANK) {
|
if (SETTINGS.sleepScreen == CrossPointSettings::SLEEP_SCREEN_MODE::BLANK) {
|
||||||
return renderBlankSleepScreen();
|
return renderBlankSleepScreen();
|
||||||
@ -64,13 +64,13 @@ void SleepActivity::renderCustomSleepScreen() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (filename.substr(filename.length() - 4) != ".bmp") {
|
if (filename.substr(filename.length() - 4) != ".bmp") {
|
||||||
Serial.printf("[%lu] [SLP] Skipping non-.bmp file name: %s\n", millis(), name);
|
Serial.printf("[%lu] [SLP] Ignorer les noms de fichiers non-.bmp: %s\n", millis(), name);
|
||||||
file.close();
|
file.close();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Bitmap bitmap(file);
|
Bitmap bitmap(file);
|
||||||
if (bitmap.parseHeaders() != BmpReaderError::Ok) {
|
if (bitmap.parseHeaders() != BmpReaderError::Ok) {
|
||||||
Serial.printf("[%lu] [SLP] Skipping invalid BMP file: %s\n", millis(), name);
|
Serial.printf("[%lu] [SLP] Ignorer le fichier BMP invalide: %s\n", millis(), name);
|
||||||
file.close();
|
file.close();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@ void SleepActivity::renderCustomSleepScreen() const {
|
|||||||
const auto filename = "/sleep/" + files[randomFileIndex];
|
const auto filename = "/sleep/" + files[randomFileIndex];
|
||||||
FsFile file;
|
FsFile file;
|
||||||
if (SdMan.openFileForRead("SLP", filename, file)) {
|
if (SdMan.openFileForRead("SLP", filename, file)) {
|
||||||
Serial.printf("[%lu] [SLP] Randomly loading: /sleep/%s\n", millis(), files[randomFileIndex].c_str());
|
Serial.printf("[%lu] [SLP] Chargement aléatoire: /sleep/%s\n", millis(), files[randomFileIndex].c_str());
|
||||||
delay(100);
|
delay(100);
|
||||||
Bitmap bitmap(file);
|
Bitmap bitmap(file);
|
||||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||||
@ -103,7 +103,7 @@ void SleepActivity::renderCustomSleepScreen() const {
|
|||||||
if (SdMan.openFileForRead("SLP", "/sleep.bmp", file)) {
|
if (SdMan.openFileForRead("SLP", "/sleep.bmp", file)) {
|
||||||
Bitmap bitmap(file);
|
Bitmap bitmap(file);
|
||||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||||
Serial.printf("[%lu] [SLP] Loading: /sleep.bmp\n", millis());
|
Serial.printf("[%lu] [SLP] Chargement: /sleep.bmp\n", millis());
|
||||||
renderBitmapSleepScreen(bitmap);
|
renderBitmapSleepScreen(bitmap);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -119,7 +119,7 @@ void SleepActivity::renderDefaultSleepScreen() const {
|
|||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
renderer.drawImage(CrossLarge, (pageWidth + 128) / 2, (pageHeight - 128) / 2, 128, 128);
|
renderer.drawImage(CrossLarge, (pageWidth + 128) / 2, (pageHeight - 128) / 2, 128, 128);
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 70, "CrossPoint", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 70, "CrossPoint", true, EpdFontFamily::BOLD);
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight / 2 + 95, "SLEEPING");
|
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight / 2 + 95, "EN VEILLE");
|
||||||
|
|
||||||
// Make sleep screen dark unless light is selected in settings
|
// Make sleep screen dark unless light is selected in settings
|
||||||
if (SETTINGS.sleepScreen != CrossPointSettings::SLEEP_SCREEN_MODE::LIGHT) {
|
if (SETTINGS.sleepScreen != CrossPointSettings::SLEEP_SCREEN_MODE::LIGHT) {
|
||||||
@ -135,34 +135,34 @@ void SleepActivity::renderBitmapSleepScreen(const Bitmap& bitmap) const {
|
|||||||
const auto pageHeight = renderer.getScreenHeight();
|
const auto pageHeight = renderer.getScreenHeight();
|
||||||
float cropX = 0, cropY = 0;
|
float cropX = 0, cropY = 0;
|
||||||
|
|
||||||
Serial.printf("[%lu] [SLP] bitmap %d x %d, screen %d x %d\n", millis(), bitmap.getWidth(), bitmap.getHeight(),
|
Serial.printf("[%lu] [SLP] bitmap %d x %d, écran %d x %d\n", millis(), bitmap.getWidth(), bitmap.getHeight(),
|
||||||
pageWidth, pageHeight);
|
pageWidth, pageHeight);
|
||||||
if (bitmap.getWidth() > pageWidth || bitmap.getHeight() > pageHeight) {
|
if (bitmap.getWidth() > pageWidth || bitmap.getHeight() > pageHeight) {
|
||||||
// image will scale, make sure placement is right
|
// image will scale, make sure placement is right
|
||||||
float ratio = static_cast<float>(bitmap.getWidth()) / static_cast<float>(bitmap.getHeight());
|
float ratio = static_cast<float>(bitmap.getWidth()) / static_cast<float>(bitmap.getHeight());
|
||||||
const float screenRatio = static_cast<float>(pageWidth) / static_cast<float>(pageHeight);
|
const float screenRatio = static_cast<float>(pageWidth) / static_cast<float>(pageHeight);
|
||||||
|
|
||||||
Serial.printf("[%lu] [SLP] bitmap ratio: %f, screen ratio: %f\n", millis(), ratio, screenRatio);
|
Serial.printf("[%lu] [SLP] ratio bitmap: %f, ratio écran: %f\n", millis(), ratio, screenRatio);
|
||||||
if (ratio > screenRatio) {
|
if (ratio > screenRatio) {
|
||||||
// image wider than viewport ratio, scaled down image needs to be centered vertically
|
// image wider than viewport ratio, scaled down image needs to be centered vertically
|
||||||
if (SETTINGS.sleepScreenCoverMode == CrossPointSettings::SLEEP_SCREEN_COVER_MODE::CROP) {
|
if (SETTINGS.sleepScreenCoverMode == CrossPointSettings::SLEEP_SCREEN_COVER_MODE::CROP) {
|
||||||
cropX = 1.0f - (screenRatio / ratio);
|
cropX = 1.0f - (screenRatio / ratio);
|
||||||
Serial.printf("[%lu] [SLP] Cropping bitmap x: %f\n", millis(), cropX);
|
Serial.printf("[%lu] [SLP] Recadrage de bitmap x: %f\n", millis(), cropX);
|
||||||
ratio = (1.0f - cropX) * static_cast<float>(bitmap.getWidth()) / static_cast<float>(bitmap.getHeight());
|
ratio = (1.0f - cropX) * static_cast<float>(bitmap.getWidth()) / static_cast<float>(bitmap.getHeight());
|
||||||
}
|
}
|
||||||
x = 0;
|
x = 0;
|
||||||
y = std::round((static_cast<float>(pageHeight) - static_cast<float>(pageWidth) / ratio) / 2);
|
y = std::round((static_cast<float>(pageHeight) - static_cast<float>(pageWidth) / ratio) / 2);
|
||||||
Serial.printf("[%lu] [SLP] Centering with ratio %f to y=%d\n", millis(), ratio, y);
|
Serial.printf("[%lu] [SLP] Centrage avec ratio de %f à y=%d\n", millis(), ratio, y);
|
||||||
} else {
|
} else {
|
||||||
// image taller than viewport ratio, scaled down image needs to be centered horizontally
|
// image taller than viewport ratio, scaled down image needs to be centered horizontally
|
||||||
if (SETTINGS.sleepScreenCoverMode == CrossPointSettings::SLEEP_SCREEN_COVER_MODE::CROP) {
|
if (SETTINGS.sleepScreenCoverMode == CrossPointSettings::SLEEP_SCREEN_COVER_MODE::CROP) {
|
||||||
cropY = 1.0f - (ratio / screenRatio);
|
cropY = 1.0f - (ratio / screenRatio);
|
||||||
Serial.printf("[%lu] [SLP] Cropping bitmap y: %f\n", millis(), cropY);
|
Serial.printf("[%lu] [SLP] Recadrage bitmap y: %f\n", millis(), cropY);
|
||||||
ratio = static_cast<float>(bitmap.getWidth()) / ((1.0f - cropY) * static_cast<float>(bitmap.getHeight()));
|
ratio = static_cast<float>(bitmap.getWidth()) / ((1.0f - cropY) * static_cast<float>(bitmap.getHeight()));
|
||||||
}
|
}
|
||||||
x = std::round((pageWidth - pageHeight * ratio) / 2);
|
x = std::round((pageWidth - pageHeight * ratio) / 2);
|
||||||
y = 0;
|
y = 0;
|
||||||
Serial.printf("[%lu] [SLP] Centering with ratio %f to x=%d\n", millis(), ratio, x);
|
Serial.printf("[%lu] [SLP] Centrage avec ratio de %f à x=%d\n", millis(), ratio, x);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// center the image
|
// center the image
|
||||||
@ -170,7 +170,7 @@ void SleepActivity::renderBitmapSleepScreen(const Bitmap& bitmap) const {
|
|||||||
y = (pageHeight - bitmap.getHeight()) / 2;
|
y = (pageHeight - bitmap.getHeight()) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.printf("[%lu] [SLP] drawing to %d x %d\n", millis(), x, y);
|
Serial.printf("[%lu] [SLP] dessinage à %d x %d\n", millis(), x, y);
|
||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY);
|
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY);
|
||||||
renderer.displayBuffer(EInkDisplay::HALF_REFRESH);
|
renderer.displayBuffer(EInkDisplay::HALF_REFRESH);
|
||||||
@ -205,12 +205,12 @@ void SleepActivity::renderCoverSleepScreen() const {
|
|||||||
// Handle XTC file
|
// Handle XTC file
|
||||||
Xtc lastXtc(APP_STATE.openEpubPath, "/.crosspoint");
|
Xtc lastXtc(APP_STATE.openEpubPath, "/.crosspoint");
|
||||||
if (!lastXtc.load()) {
|
if (!lastXtc.load()) {
|
||||||
Serial.println("[SLP] Failed to load last XTC");
|
Serial.println("[SLP] Chargement échoué du dernier XTC");
|
||||||
return renderDefaultSleepScreen();
|
return renderDefaultSleepScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lastXtc.generateCoverBmp()) {
|
if (!lastXtc.generateCoverBmp()) {
|
||||||
Serial.println("[SLP] Failed to generate XTC cover bmp");
|
Serial.println("[SLP] Génération échoué de bmp de couverture XTC");
|
||||||
return renderDefaultSleepScreen();
|
return renderDefaultSleepScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,12 +219,12 @@ void SleepActivity::renderCoverSleepScreen() const {
|
|||||||
// Handle EPUB file
|
// Handle EPUB file
|
||||||
Epub lastEpub(APP_STATE.openEpubPath, "/.crosspoint");
|
Epub lastEpub(APP_STATE.openEpubPath, "/.crosspoint");
|
||||||
if (!lastEpub.load()) {
|
if (!lastEpub.load()) {
|
||||||
Serial.println("[SLP] Failed to load last epub");
|
Serial.println("[SLP] Chargement échoué du dernier epub");
|
||||||
return renderDefaultSleepScreen();
|
return renderDefaultSleepScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lastEpub.generateCoverBmp()) {
|
if (!lastEpub.generateCoverBmp()) {
|
||||||
Serial.println("[SLP] Failed to generate cover bmp");
|
Serial.println("[SLP] Génération échoué de bmp de couverture");
|
||||||
return renderDefaultSleepScreen();
|
return renderDefaultSleepScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,7 +34,7 @@ void OpdsBookBrowserActivity::onEnter() {
|
|||||||
currentPath = OPDS_ROOT_PATH;
|
currentPath = OPDS_ROOT_PATH;
|
||||||
selectorIndex = 0;
|
selectorIndex = 0;
|
||||||
errorMessage.clear();
|
errorMessage.clear();
|
||||||
statusMessage = "Checking WiFi...";
|
statusMessage = "Verification du WiFi...";
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
|
|
||||||
xTaskCreate(&OpdsBookBrowserActivity::taskTrampoline, "OpdsBookBrowserTask",
|
xTaskCreate(&OpdsBookBrowserActivity::taskTrampoline, "OpdsBookBrowserTask",
|
||||||
@ -70,7 +70,7 @@ void OpdsBookBrowserActivity::loop() {
|
|||||||
if (state == BrowserState::ERROR) {
|
if (state == BrowserState::ERROR) {
|
||||||
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
|
||||||
state = BrowserState::LOADING;
|
state = BrowserState::LOADING;
|
||||||
statusMessage = "Loading...";
|
statusMessage = "Chargement...";
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
fetchFeed(currentPath);
|
fetchFeed(currentPath);
|
||||||
} else if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
} else if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
|
||||||
@ -155,11 +155,11 @@ void OpdsBookBrowserActivity::render() const {
|
|||||||
const auto pageWidth = renderer.getScreenWidth();
|
const auto pageWidth = renderer.getScreenWidth();
|
||||||
const auto pageHeight = renderer.getScreenHeight();
|
const auto pageHeight = renderer.getScreenHeight();
|
||||||
|
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Calibre Library", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Bilbiothèque Calibre", true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
if (state == BrowserState::CHECK_WIFI) {
|
if (state == BrowserState::CHECK_WIFI) {
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2, statusMessage.c_str());
|
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2, statusMessage.c_str());
|
||||||
const auto labels = mappedInput.mapLabels("« Back", "", "", "");
|
const auto labels = mappedInput.mapLabels("« Retour", "", "", "");
|
||||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
return;
|
return;
|
||||||
@ -167,23 +167,23 @@ void OpdsBookBrowserActivity::render() const {
|
|||||||
|
|
||||||
if (state == BrowserState::LOADING) {
|
if (state == BrowserState::LOADING) {
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2, statusMessage.c_str());
|
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2, statusMessage.c_str());
|
||||||
const auto labels = mappedInput.mapLabels("« Back", "", "", "");
|
const auto labels = mappedInput.mapLabels("« Retour", "", "", "");
|
||||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == BrowserState::ERROR) {
|
if (state == BrowserState::ERROR) {
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 20, "Error:");
|
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 20, "Erreur:");
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 10, errorMessage.c_str());
|
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 + 10, errorMessage.c_str());
|
||||||
const auto labels = mappedInput.mapLabels("« Back", "Retry", "", "");
|
const auto labels = mappedInput.mapLabels("« Retour", "Reéssay.", "", "");
|
||||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == BrowserState::DOWNLOADING) {
|
if (state == BrowserState::DOWNLOADING) {
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 40, "Downloading...");
|
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 40, "Téléchargement...");
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 10, statusMessage.c_str());
|
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2 - 10, statusMessage.c_str());
|
||||||
if (downloadTotal > 0) {
|
if (downloadTotal > 0) {
|
||||||
const int barWidth = pageWidth - 100;
|
const int barWidth = pageWidth - 100;
|
||||||
@ -198,15 +198,15 @@ void OpdsBookBrowserActivity::render() const {
|
|||||||
|
|
||||||
// Browsing state
|
// Browsing state
|
||||||
// Show appropriate button hint based on selected entry type
|
// Show appropriate button hint based on selected entry type
|
||||||
const char* confirmLabel = "Open";
|
const char* confirmLabel = "Ouvrir";
|
||||||
if (!entries.empty() && entries[selectorIndex].type == OpdsEntryType::BOOK) {
|
if (!entries.empty() && entries[selectorIndex].type == OpdsEntryType::BOOK) {
|
||||||
confirmLabel = "Download";
|
confirmLabel = "Télécharger";
|
||||||
}
|
}
|
||||||
const auto labels = mappedInput.mapLabels("« Back", confirmLabel, "", "");
|
const auto labels = mappedInput.mapLabels("« Retour", confirmLabel, "", "");
|
||||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||||
|
|
||||||
if (entries.empty()) {
|
if (entries.empty()) {
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2, "No entries found");
|
renderer.drawCenteredText(UI_10_FONT_ID, pageHeight / 2, "Aucune entrée trouvée");
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -241,18 +241,18 @@ void OpdsBookBrowserActivity::fetchFeed(const std::string& path) {
|
|||||||
const char* serverUrl = SETTINGS.opdsServerUrl;
|
const char* serverUrl = SETTINGS.opdsServerUrl;
|
||||||
if (strlen(serverUrl) == 0) {
|
if (strlen(serverUrl) == 0) {
|
||||||
state = BrowserState::ERROR;
|
state = BrowserState::ERROR;
|
||||||
errorMessage = "No server URL configured";
|
errorMessage = "Aucun URL serveur configuré";
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string url = UrlUtils::buildUrl(serverUrl, path);
|
std::string url = UrlUtils::buildUrl(serverUrl, path);
|
||||||
Serial.printf("[%lu] [OPDS] Fetching: %s\n", millis(), url.c_str());
|
Serial.printf("[%lu] [OPDS] Récupération: %s\n", millis(), url.c_str());
|
||||||
|
|
||||||
std::string content;
|
std::string content;
|
||||||
if (!HttpDownloader::fetchUrl(url, content)) {
|
if (!HttpDownloader::fetchUrl(url, content)) {
|
||||||
state = BrowserState::ERROR;
|
state = BrowserState::ERROR;
|
||||||
errorMessage = "Failed to fetch feed";
|
errorMessage = "Récupération du flux échouée";
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -260,7 +260,7 @@ void OpdsBookBrowserActivity::fetchFeed(const std::string& path) {
|
|||||||
OpdsParser parser;
|
OpdsParser parser;
|
||||||
if (!parser.parse(content.c_str(), content.size())) {
|
if (!parser.parse(content.c_str(), content.size())) {
|
||||||
state = BrowserState::ERROR;
|
state = BrowserState::ERROR;
|
||||||
errorMessage = "Failed to parse feed";
|
errorMessage = "Analyse du flux échouée";
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -270,7 +270,7 @@ void OpdsBookBrowserActivity::fetchFeed(const std::string& path) {
|
|||||||
|
|
||||||
if (entries.empty()) {
|
if (entries.empty()) {
|
||||||
state = BrowserState::ERROR;
|
state = BrowserState::ERROR;
|
||||||
errorMessage = "No entries found";
|
errorMessage = "Aucune entrée trouvée";
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -285,7 +285,7 @@ void OpdsBookBrowserActivity::navigateToEntry(const OpdsEntry& entry) {
|
|||||||
currentPath = entry.href;
|
currentPath = entry.href;
|
||||||
|
|
||||||
state = BrowserState::LOADING;
|
state = BrowserState::LOADING;
|
||||||
statusMessage = "Loading...";
|
statusMessage = "Chargement...";
|
||||||
entries.clear();
|
entries.clear();
|
||||||
selectorIndex = 0;
|
selectorIndex = 0;
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
@ -303,7 +303,7 @@ void OpdsBookBrowserActivity::navigateBack() {
|
|||||||
navigationHistory.pop_back();
|
navigationHistory.pop_back();
|
||||||
|
|
||||||
state = BrowserState::LOADING;
|
state = BrowserState::LOADING;
|
||||||
statusMessage = "Loading...";
|
statusMessage = "Chargement...";
|
||||||
entries.clear();
|
entries.clear();
|
||||||
selectorIndex = 0;
|
selectorIndex = 0;
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
@ -329,7 +329,7 @@ void OpdsBookBrowserActivity::downloadBook(const OpdsEntry& book) {
|
|||||||
}
|
}
|
||||||
std::string filename = "/" + StringUtils::sanitizeFilename(baseName) + ".epub";
|
std::string filename = "/" + StringUtils::sanitizeFilename(baseName) + ".epub";
|
||||||
|
|
||||||
Serial.printf("[%lu] [OPDS] Downloading: %s -> %s\n", millis(), downloadUrl.c_str(), filename.c_str());
|
Serial.printf("[%lu] [OPDS] Téléchargement: %s -> %s\n", millis(), downloadUrl.c_str(), filename.c_str());
|
||||||
|
|
||||||
const auto result =
|
const auto result =
|
||||||
HttpDownloader::downloadToFile(downloadUrl, filename, [this](const size_t downloaded, const size_t total) {
|
HttpDownloader::downloadToFile(downloadUrl, filename, [this](const size_t downloaded, const size_t total) {
|
||||||
@ -339,12 +339,12 @@ void OpdsBookBrowserActivity::downloadBook(const OpdsEntry& book) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (result == HttpDownloader::OK) {
|
if (result == HttpDownloader::OK) {
|
||||||
Serial.printf("[%lu] [OPDS] Download complete: %s\n", millis(), filename.c_str());
|
Serial.printf("[%lu] [OPDS] Téléchargement terminé: %s\n", millis(), filename.c_str());
|
||||||
state = BrowserState::BROWSING;
|
state = BrowserState::BROWSING;
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
} else {
|
} else {
|
||||||
state = BrowserState::ERROR;
|
state = BrowserState::ERROR;
|
||||||
errorMessage = "Download failed";
|
errorMessage = "Téléchargement échoué";
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -353,21 +353,21 @@ void OpdsBookBrowserActivity::checkAndConnectWifi() {
|
|||||||
// Already connected?
|
// Already connected?
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
state = BrowserState::LOADING;
|
state = BrowserState::LOADING;
|
||||||
statusMessage = "Loading...";
|
statusMessage = "Chargement...";
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
fetchFeed(currentPath);
|
fetchFeed(currentPath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to connect using saved credentials
|
// Try to connect using saved credentials
|
||||||
statusMessage = "Connecting to WiFi...";
|
statusMessage = "Connexion au WiFi...";
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
|
|
||||||
WIFI_STORE.loadFromFile();
|
WIFI_STORE.loadFromFile();
|
||||||
const auto& credentials = WIFI_STORE.getCredentials();
|
const auto& credentials = WIFI_STORE.getCredentials();
|
||||||
if (credentials.empty()) {
|
if (credentials.empty()) {
|
||||||
state = BrowserState::ERROR;
|
state = BrowserState::ERROR;
|
||||||
errorMessage = "No WiFi credentials saved";
|
errorMessage = "Aucun identifiants sauvegardés";
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -385,14 +385,14 @@ void OpdsBookBrowserActivity::checkAndConnectWifi() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
Serial.printf("[%lu] [OPDS] WiFi connected: %s\n", millis(), WiFi.localIP().toString().c_str());
|
Serial.printf("[%lu] [OPDS] WiFi connecté: %s\n", millis(), WiFi.localIP().toString().c_str());
|
||||||
state = BrowserState::LOADING;
|
state = BrowserState::LOADING;
|
||||||
statusMessage = "Loading...";
|
statusMessage = "Chargement...";
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
fetchFeed(currentPath);
|
fetchFeed(currentPath);
|
||||||
} else {
|
} else {
|
||||||
state = BrowserState::ERROR;
|
state = BrowserState::ERROR;
|
||||||
errorMessage = "WiFi connection failed";
|
errorMessage = "Connexion WiFi échouée";
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -277,21 +277,21 @@ void HomeActivity::render() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, bookY + bookHeight - renderer.getLineHeight(UI_10_FONT_ID) * 3 / 2,
|
renderer.drawCenteredText(UI_10_FONT_ID, bookY + bookHeight - renderer.getLineHeight(UI_10_FONT_ID) * 3 / 2,
|
||||||
"Continue Reading", !bookSelected);
|
"Continuer la lecture", !bookSelected);
|
||||||
} else {
|
} else {
|
||||||
// No book to continue reading
|
// No book to continue reading
|
||||||
const int y =
|
const int y =
|
||||||
bookY + (bookHeight - renderer.getLineHeight(UI_12_FONT_ID) - renderer.getLineHeight(UI_10_FONT_ID)) / 2;
|
bookY + (bookHeight - renderer.getLineHeight(UI_12_FONT_ID) - renderer.getLineHeight(UI_10_FONT_ID)) / 2;
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, y, "No open book");
|
renderer.drawCenteredText(UI_12_FONT_ID, y, "Aucun livre ouvert");
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, y + renderer.getLineHeight(UI_12_FONT_ID), "Start reading below");
|
renderer.drawCenteredText(UI_10_FONT_ID, y + renderer.getLineHeight(UI_12_FONT_ID), "Commencer la lecture au-dessous");
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Bottom menu tiles ---
|
// --- Bottom menu tiles ---
|
||||||
// Build menu items dynamically
|
// Build menu items dynamically
|
||||||
std::vector<const char*> menuItems = {"Browse Files", "File Transfer", "Settings"};
|
std::vector<const char*> menuItems = {"Parcourir les fichiers", "Transfert de fichiers", "Paramètres"};
|
||||||
if (hasOpdsUrl) {
|
if (hasOpdsUrl) {
|
||||||
// Insert Calibre Library after Browse Files
|
// Insert Calibre Library after Browse Files
|
||||||
menuItems.insert(menuItems.begin() + 1, "Calibre Library");
|
menuItems.insert(menuItems.begin() + 1, "Blibliothèque Calibre");
|
||||||
}
|
}
|
||||||
|
|
||||||
const int menuTileWidth = pageWidth - 2 * margin;
|
const int menuTileWidth = pageWidth - 2 * margin;
|
||||||
@ -329,7 +329,7 @@ void HomeActivity::render() const {
|
|||||||
renderer.drawText(UI_10_FONT_ID, textX, textY, label, !selected);
|
renderer.drawText(UI_10_FONT_ID, textX, textY, label, !selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto labels = mappedInput.mapLabels("", "Confirm", "Up", "Down");
|
const auto labels = mappedInput.mapLabels("", "Confirmer", "Haut", "Bas");
|
||||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||||
|
|
||||||
const auto batteryX = pageWidth - 25 - renderer.getTextWidth(SMALL_FONT_ID, "100 %");
|
const auto batteryX = pageWidth - 25 - renderer.getTextWidth(SMALL_FONT_ID, "100 %");
|
||||||
|
|||||||
@ -34,7 +34,7 @@ void CalibreWirelessActivity::onEnter() {
|
|||||||
stateMutex = xSemaphoreCreateMutex();
|
stateMutex = xSemaphoreCreateMutex();
|
||||||
|
|
||||||
state = WirelessState::DISCOVERING;
|
state = WirelessState::DISCOVERING;
|
||||||
statusMessage = "Discovering Calibre...";
|
statusMessage = "Recherche de Calibre...";
|
||||||
errorMessage.clear();
|
errorMessage.clear();
|
||||||
calibreHostname.clear();
|
calibreHostname.clear();
|
||||||
calibreHost.clear();
|
calibreHost.clear();
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// AP Mode configuration
|
// AP Mode configuration
|
||||||
constexpr const char* AP_SSID = "CrossPoint-Reader";
|
constexpr const char* AP_SSID = "CrossPoint-Liseuse";
|
||||||
constexpr const char* AP_PASSWORD = nullptr; // Open network for ease of use
|
constexpr const char* AP_PASSWORD = nullptr; // Open network for ease of use
|
||||||
constexpr const char* AP_HOSTNAME = "crosspoint";
|
constexpr const char* AP_HOSTNAME = "crosspoint";
|
||||||
constexpr uint8_t AP_CHANNEL = 1;
|
constexpr uint8_t AP_CHANNEL = 1;
|
||||||
@ -34,7 +34,7 @@ void CrossPointWebServerActivity::taskTrampoline(void* param) {
|
|||||||
void CrossPointWebServerActivity::onEnter() {
|
void CrossPointWebServerActivity::onEnter() {
|
||||||
ActivityWithSubactivity::onEnter();
|
ActivityWithSubactivity::onEnter();
|
||||||
|
|
||||||
Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onEnter: %d bytes\n", millis(), ESP.getFreeHeap());
|
Serial.printf("[%lu] [WEBACT] [MEM] Pile libre à onEnter: %d octets\n", millis(), ESP.getFreeHeap());
|
||||||
|
|
||||||
renderingMutex = xSemaphoreCreateMutex();
|
renderingMutex = xSemaphoreCreateMutex();
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ void CrossPointWebServerActivity::onEnter() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Launch network mode selection subactivity
|
// Launch network mode selection subactivity
|
||||||
Serial.printf("[%lu] [WEBACT] Launching NetworkModeSelectionActivity...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Lancement de NetworkModeSelectionActivity...\n", millis());
|
||||||
enterNewActivity(new NetworkModeSelectionActivity(
|
enterNewActivity(new NetworkModeSelectionActivity(
|
||||||
renderer, mappedInput, [this](const NetworkMode mode) { onNetworkModeSelected(mode); },
|
renderer, mappedInput, [this](const NetworkMode mode) { onNetworkModeSelected(mode); },
|
||||||
[this]() { onGoBack(); } // Cancel goes back to home
|
[this]() { onGoBack(); } // Cancel goes back to home
|
||||||
@ -65,7 +65,7 @@ void CrossPointWebServerActivity::onEnter() {
|
|||||||
void CrossPointWebServerActivity::onExit() {
|
void CrossPointWebServerActivity::onExit() {
|
||||||
ActivityWithSubactivity::onExit();
|
ActivityWithSubactivity::onExit();
|
||||||
|
|
||||||
Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onExit start: %d bytes\n", millis(), ESP.getFreeHeap());
|
Serial.printf("[%lu] [WEBACT] [MEM] Pile libre au début de onExit: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||||
|
|
||||||
state = WebServerActivityState::SHUTTING_DOWN;
|
state = WebServerActivityState::SHUTTING_DOWN;
|
||||||
|
|
||||||
@ -77,56 +77,56 @@ void CrossPointWebServerActivity::onExit() {
|
|||||||
|
|
||||||
// Stop DNS server if running (AP mode)
|
// Stop DNS server if running (AP mode)
|
||||||
if (dnsServer) {
|
if (dnsServer) {
|
||||||
Serial.printf("[%lu] [WEBACT] Stopping DNS server...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Arrêt du serveur DNS...\n", millis());
|
||||||
dnsServer->stop();
|
dnsServer->stop();
|
||||||
delete dnsServer;
|
delete dnsServer;
|
||||||
dnsServer = nullptr;
|
dnsServer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CRITICAL: Wait for LWIP stack to flush any pending packets
|
// CRITICAL: Wait for LWIP stack to flush any pending packets
|
||||||
Serial.printf("[%lu] [WEBACT] Waiting 500ms for network stack to flush pending packets...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Attente de 500ms de pile réseau pour vider les paquets en attente...\n", millis());
|
||||||
delay(500);
|
delay(500);
|
||||||
|
|
||||||
// Disconnect WiFi gracefully
|
// Disconnect WiFi gracefully
|
||||||
if (isApMode) {
|
if (isApMode) {
|
||||||
Serial.printf("[%lu] [WEBACT] Stopping WiFi AP...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Arrêt du WiFi AP...\n", millis());
|
||||||
WiFi.softAPdisconnect(true);
|
WiFi.softAPdisconnect(true);
|
||||||
} else {
|
} else {
|
||||||
Serial.printf("[%lu] [WEBACT] Disconnecting WiFi (graceful)...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Déconnexion du WiFi (gracieuse)...\n", millis());
|
||||||
WiFi.disconnect(false); // false = don't erase credentials, send disconnect frame
|
WiFi.disconnect(false); // false = don't erase credentials, send disconnect frame
|
||||||
}
|
}
|
||||||
delay(100); // Allow disconnect frame to be sent
|
delay(100); // Allow disconnect frame to be sent
|
||||||
|
|
||||||
Serial.printf("[%lu] [WEBACT] Setting WiFi mode OFF...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Désactivation du WiFi...\n", millis());
|
||||||
WiFi.mode(WIFI_OFF);
|
WiFi.mode(WIFI_OFF);
|
||||||
delay(100); // Allow WiFi hardware to fully power down
|
delay(100); // Allow WiFi hardware to fully power down
|
||||||
|
|
||||||
Serial.printf("[%lu] [WEBACT] [MEM] Free heap after WiFi disconnect: %d bytes\n", millis(), ESP.getFreeHeap());
|
Serial.printf("[%lu] [WEBACT] [MEM] Pile libre après déconnexion du WiFi: %d octets\n", millis(), ESP.getFreeHeap());
|
||||||
|
|
||||||
// Acquire mutex before deleting task
|
// Acquire mutex before deleting task
|
||||||
Serial.printf("[%lu] [WEBACT] Acquiring rendering mutex before task deletion...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Acquisition du mutex de rendu avant la suppression de la tâche...\n", millis());
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
|
|
||||||
// Delete the display task
|
// Delete the display task
|
||||||
Serial.printf("[%lu] [WEBACT] Deleting display task...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Suppression de la tâche d'affichage...\n", millis());
|
||||||
if (displayTaskHandle) {
|
if (displayTaskHandle) {
|
||||||
vTaskDelete(displayTaskHandle);
|
vTaskDelete(displayTaskHandle);
|
||||||
displayTaskHandle = nullptr;
|
displayTaskHandle = nullptr;
|
||||||
Serial.printf("[%lu] [WEBACT] Display task deleted\n", millis());
|
Serial.printf("[%lu] [WEBACT] Tâche d'affichage supprimée\n", millis());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete the mutex
|
// Delete the mutex
|
||||||
Serial.printf("[%lu] [WEBACT] Deleting mutex...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Suppression du mutex...\n", millis());
|
||||||
vSemaphoreDelete(renderingMutex);
|
vSemaphoreDelete(renderingMutex);
|
||||||
renderingMutex = nullptr;
|
renderingMutex = nullptr;
|
||||||
Serial.printf("[%lu] [WEBACT] Mutex deleted\n", millis());
|
Serial.printf("[%lu] [WEBACT] Mutex supprimé\n", millis());
|
||||||
|
|
||||||
Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onExit end: %d bytes\n", millis(), ESP.getFreeHeap());
|
Serial.printf("[%lu] [WEBACT] [MEM] Pile libre à la fin de onExit: %d octets\n", millis(), ESP.getFreeHeap());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrossPointWebServerActivity::onNetworkModeSelected(const NetworkMode mode) {
|
void CrossPointWebServerActivity::onNetworkModeSelected(const NetworkMode mode) {
|
||||||
Serial.printf("[%lu] [WEBACT] Network mode selected: %s\n", millis(),
|
Serial.printf("[%lu] [WEBACT] Mode de réseau selectionné: %s\n", millis(),
|
||||||
mode == NetworkMode::JOIN_NETWORK ? "Join Network" : "Create Hotspot");
|
mode == NetworkMode::JOIN_NETWORK ? "Réjoindre le réseau" : "Créer un point d'accès");
|
||||||
|
|
||||||
networkMode = mode;
|
networkMode = mode;
|
||||||
isApMode = (mode == NetworkMode::CREATE_HOTSPOT);
|
isApMode = (mode == NetworkMode::CREATE_HOTSPOT);
|
||||||
@ -136,11 +136,11 @@ void CrossPointWebServerActivity::onNetworkModeSelected(const NetworkMode mode)
|
|||||||
|
|
||||||
if (mode == NetworkMode::JOIN_NETWORK) {
|
if (mode == NetworkMode::JOIN_NETWORK) {
|
||||||
// STA mode - launch WiFi selection
|
// STA mode - launch WiFi selection
|
||||||
Serial.printf("[%lu] [WEBACT] Turning on WiFi (STA mode)...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Lancement du WiFi (Mode STA)...\n", millis());
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
|
|
||||||
state = WebServerActivityState::WIFI_SELECTION;
|
state = WebServerActivityState::WIFI_SELECTION;
|
||||||
Serial.printf("[%lu] [WEBACT] Launching WifiSelectionActivity...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Lancement de WifiSelectionActivity...\n", millis());
|
||||||
enterNewActivity(new WifiSelectionActivity(renderer, mappedInput,
|
enterNewActivity(new WifiSelectionActivity(renderer, mappedInput,
|
||||||
[this](const bool connected) { onWifiSelectionComplete(connected); }));
|
[this](const bool connected) { onWifiSelectionComplete(connected); }));
|
||||||
} else {
|
} else {
|
||||||
@ -152,7 +152,7 @@ void CrossPointWebServerActivity::onNetworkModeSelected(const NetworkMode mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CrossPointWebServerActivity::onWifiSelectionComplete(const bool connected) {
|
void CrossPointWebServerActivity::onWifiSelectionComplete(const bool connected) {
|
||||||
Serial.printf("[%lu] [WEBACT] WifiSelectionActivity completed, connected=%d\n", millis(), connected);
|
Serial.printf("[%lu] [WEBACT] WifiSelectionActivity terminé, connecté=%d\n", millis(), connected);
|
||||||
|
|
||||||
if (connected) {
|
if (connected) {
|
||||||
// Get connection info before exiting subactivity
|
// Get connection info before exiting subactivity
|
||||||
@ -164,7 +164,7 @@ void CrossPointWebServerActivity::onWifiSelectionComplete(const bool connected)
|
|||||||
|
|
||||||
// Start mDNS for hostname resolution
|
// Start mDNS for hostname resolution
|
||||||
if (MDNS.begin(AP_HOSTNAME)) {
|
if (MDNS.begin(AP_HOSTNAME)) {
|
||||||
Serial.printf("[%lu] [WEBACT] mDNS started: http://%s.local/\n", millis(), AP_HOSTNAME);
|
Serial.printf("[%lu] [WEBACT] mDNS lancé: http://%s.local/\n", millis(), AP_HOSTNAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the web server
|
// Start the web server
|
||||||
@ -180,8 +180,8 @@ void CrossPointWebServerActivity::onWifiSelectionComplete(const bool connected)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CrossPointWebServerActivity::startAccessPoint() {
|
void CrossPointWebServerActivity::startAccessPoint() {
|
||||||
Serial.printf("[%lu] [WEBACT] Starting Access Point mode...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Lancement du mode Access Point...\n", millis());
|
||||||
Serial.printf("[%lu] [WEBACT] [MEM] Free heap before AP start: %d bytes\n", millis(), ESP.getFreeHeap());
|
Serial.printf("[%lu] [WEBACT] [MEM] Pile libre avant le début de AP: %d octets\n", millis(), ESP.getFreeHeap());
|
||||||
|
|
||||||
// Configure and start the AP
|
// Configure and start the AP
|
||||||
WiFi.mode(WIFI_AP);
|
WiFi.mode(WIFI_AP);
|
||||||
@ -197,7 +197,7 @@ void CrossPointWebServerActivity::startAccessPoint() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!apStarted) {
|
if (!apStarted) {
|
||||||
Serial.printf("[%lu] [WEBACT] ERROR: Failed to start Access Point!\n", millis());
|
Serial.printf("[%lu] [WEBACT] ERROR: Lancement de Access Point échoué!\n", millis());
|
||||||
onGoBack();
|
onGoBack();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -211,15 +211,15 @@ void CrossPointWebServerActivity::startAccessPoint() {
|
|||||||
connectedIP = ipStr;
|
connectedIP = ipStr;
|
||||||
connectedSSID = AP_SSID;
|
connectedSSID = AP_SSID;
|
||||||
|
|
||||||
Serial.printf("[%lu] [WEBACT] Access Point started!\n", millis());
|
Serial.printf("[%lu] [WEBACT] Access Point lancé!\n", millis());
|
||||||
Serial.printf("[%lu] [WEBACT] SSID: %s\n", millis(), AP_SSID);
|
Serial.printf("[%lu] [WEBACT] SSID: %s\n", millis(), AP_SSID);
|
||||||
Serial.printf("[%lu] [WEBACT] IP: %s\n", millis(), connectedIP.c_str());
|
Serial.printf("[%lu] [WEBACT] IP: %s\n", millis(), connectedIP.c_str());
|
||||||
|
|
||||||
// Start mDNS for hostname resolution
|
// Start mDNS for hostname resolution
|
||||||
if (MDNS.begin(AP_HOSTNAME)) {
|
if (MDNS.begin(AP_HOSTNAME)) {
|
||||||
Serial.printf("[%lu] [WEBACT] mDNS started: http://%s.local/\n", millis(), AP_HOSTNAME);
|
Serial.printf("[%lu] [WEBACT] mDNS lancé: http://%s.local/\n", millis(), AP_HOSTNAME);
|
||||||
} else {
|
} else {
|
||||||
Serial.printf("[%lu] [WEBACT] WARNING: mDNS failed to start\n", millis());
|
Serial.printf("[%lu] [WEBACT] ATTENTION: lancement de mDNS échoué\n", millis());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start DNS server for captive portal behavior
|
// Start DNS server for captive portal behavior
|
||||||
@ -227,16 +227,16 @@ void CrossPointWebServerActivity::startAccessPoint() {
|
|||||||
dnsServer = new DNSServer();
|
dnsServer = new DNSServer();
|
||||||
dnsServer->setErrorReplyCode(DNSReplyCode::NoError);
|
dnsServer->setErrorReplyCode(DNSReplyCode::NoError);
|
||||||
dnsServer->start(DNS_PORT, "*", apIP);
|
dnsServer->start(DNS_PORT, "*", apIP);
|
||||||
Serial.printf("[%lu] [WEBACT] DNS server started for captive portal\n", millis());
|
Serial.printf("[%lu] [WEBACT] Serveur DNS lancé pour portail captif\n", millis());
|
||||||
|
|
||||||
Serial.printf("[%lu] [WEBACT] [MEM] Free heap after AP start: %d bytes\n", millis(), ESP.getFreeHeap());
|
Serial.printf("[%lu] [WEBACT] [MEM] Pile libre après lancement de AP: %d octets\n", millis(), ESP.getFreeHeap());
|
||||||
|
|
||||||
// Start the web server
|
// Start the web server
|
||||||
startWebServer();
|
startWebServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrossPointWebServerActivity::startWebServer() {
|
void CrossPointWebServerActivity::startWebServer() {
|
||||||
Serial.printf("[%lu] [WEBACT] Starting web server...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Lancement du server web...\n", millis());
|
||||||
|
|
||||||
// Create the web server instance
|
// Create the web server instance
|
||||||
webServer.reset(new CrossPointWebServer());
|
webServer.reset(new CrossPointWebServer());
|
||||||
@ -244,16 +244,16 @@ void CrossPointWebServerActivity::startWebServer() {
|
|||||||
|
|
||||||
if (webServer->isRunning()) {
|
if (webServer->isRunning()) {
|
||||||
state = WebServerActivityState::SERVER_RUNNING;
|
state = WebServerActivityState::SERVER_RUNNING;
|
||||||
Serial.printf("[%lu] [WEBACT] Web server started successfully\n", millis());
|
Serial.printf("[%lu] [WEBACT] Serveur web lancé avec succès!\n", millis());
|
||||||
|
|
||||||
// Force an immediate render since we're transitioning from a subactivity
|
// Force an immediate render since we're transitioning from a subactivity
|
||||||
// that had its own rendering task. We need to make sure our display is shown.
|
// that had its own rendering task. We need to make sure our display is shown.
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
render();
|
render();
|
||||||
xSemaphoreGive(renderingMutex);
|
xSemaphoreGive(renderingMutex);
|
||||||
Serial.printf("[%lu] [WEBACT] Rendered File Transfer screen\n", millis());
|
Serial.printf("[%lu] [WEBACT] Écran File Transfer rendu\n", millis());
|
||||||
} else {
|
} else {
|
||||||
Serial.printf("[%lu] [WEBACT] ERROR: Failed to start web server!\n", millis());
|
Serial.printf("[%lu] [WEBACT] ERREUR: Lancement du serveur web échoué!\n", millis());
|
||||||
webServer.reset();
|
webServer.reset();
|
||||||
// Go back on error
|
// Go back on error
|
||||||
onGoBack();
|
onGoBack();
|
||||||
@ -262,9 +262,9 @@ void CrossPointWebServerActivity::startWebServer() {
|
|||||||
|
|
||||||
void CrossPointWebServerActivity::stopWebServer() {
|
void CrossPointWebServerActivity::stopWebServer() {
|
||||||
if (webServer && webServer->isRunning()) {
|
if (webServer && webServer->isRunning()) {
|
||||||
Serial.printf("[%lu] [WEBACT] Stopping web server...\n", millis());
|
Serial.printf("[%lu] [WEBACT] Arrêt du serveur web...\n", millis());
|
||||||
webServer->stop();
|
webServer->stop();
|
||||||
Serial.printf("[%lu] [WEBACT] Web server stopped\n", millis());
|
Serial.printf("[%lu] [WEBACT] Serveur web arrêté\n", millis());
|
||||||
}
|
}
|
||||||
webServer.reset();
|
webServer.reset();
|
||||||
}
|
}
|
||||||
@ -290,7 +290,7 @@ void CrossPointWebServerActivity::loop() {
|
|||||||
|
|
||||||
// Log if there's a significant gap between handleClient calls (>100ms)
|
// Log if there's a significant gap between handleClient calls (>100ms)
|
||||||
if (lastHandleClientTime > 0 && timeSinceLastHandleClient > 100) {
|
if (lastHandleClientTime > 0 && timeSinceLastHandleClient > 100) {
|
||||||
Serial.printf("[%lu] [WEBACT] WARNING: %lu ms gap since last handleClient\n", millis(),
|
Serial.printf("[%lu] [WEBACT] ATTENTION: %lu ms intervalle depuis le dernier handleClient\n", millis(),
|
||||||
timeSinceLastHandleClient);
|
timeSinceLastHandleClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,7 +334,7 @@ void CrossPointWebServerActivity::render() const {
|
|||||||
} else if (state == WebServerActivityState::AP_STARTING) {
|
} else if (state == WebServerActivityState::AP_STARTING) {
|
||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
const auto pageHeight = renderer.getScreenHeight();
|
const auto pageHeight = renderer.getScreenHeight();
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, pageHeight / 2 - 20, "Starting Hotspot...", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, pageHeight / 2 - 20, "Lancement du point d'accès...", true, EpdFontFamily::BOLD);
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -344,7 +344,7 @@ void drawQRCode(const GfxRenderer& renderer, const int x, const int y, const std
|
|||||||
// The structure to manage the QR code
|
// The structure to manage the QR code
|
||||||
QRCode qrcode;
|
QRCode qrcode;
|
||||||
uint8_t qrcodeBytes[qrcode_getBufferSize(4)];
|
uint8_t qrcodeBytes[qrcode_getBufferSize(4)];
|
||||||
Serial.printf("[%lu] [WEBACT] QR Code (%lu): %s\n", millis(), data.length(), data.c_str());
|
Serial.printf("[%lu] [WEBACT] Code QR (%lu): %s\n", millis(), data.length(), data.c_str());
|
||||||
|
|
||||||
qrcode_initText(&qrcode, qrcodeBytes, 4, ECC_LOW, data.c_str());
|
qrcode_initText(&qrcode, qrcodeBytes, 4, ECC_LOW, data.c_str());
|
||||||
const uint8_t px = 6; // pixels per module
|
const uint8_t px = 6; // pixels per module
|
||||||
@ -365,21 +365,21 @@ void CrossPointWebServerActivity::renderServerRunning() const {
|
|||||||
// Use consistent line spacing
|
// Use consistent line spacing
|
||||||
constexpr int LINE_SPACING = 28; // Space between lines
|
constexpr int LINE_SPACING = 28; // Space between lines
|
||||||
|
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, 15, "File Transfer", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Transfert de fichiers", true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
if (isApMode) {
|
if (isApMode) {
|
||||||
// AP mode display - center the content block
|
// AP mode display - center the content block
|
||||||
int startY = 55;
|
int startY = 55;
|
||||||
|
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, startY, "Hotspot Mode", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_10_FONT_ID, startY, "Mode de point d'accès", true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
std::string ssidInfo = "Network: " + connectedSSID;
|
std::string ssidInfo = "Réseau: " + connectedSSID;
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, startY + LINE_SPACING, ssidInfo.c_str());
|
renderer.drawCenteredText(UI_10_FONT_ID, startY + LINE_SPACING, ssidInfo.c_str());
|
||||||
|
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 2, "Connect your device to this WiFi network");
|
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 2, "Connectez votre appareil à ce réseau");
|
||||||
|
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 3,
|
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 3,
|
||||||
"or scan QR code with your phone to connect to Wifi.");
|
"ou scannez le code QR avec votre cellulaire pour connecter au WiFi.");
|
||||||
// Show QR code for URL
|
// Show QR code for URL
|
||||||
const std::string wifiConfig = std::string("WIFI:S:") + connectedSSID + ";;";
|
const std::string wifiConfig = std::string("WIFI:S:") + connectedSSID + ";;";
|
||||||
drawQRCode(renderer, (480 - 6 * 33) / 2, startY + LINE_SPACING * 4, wifiConfig);
|
drawQRCode(renderer, (480 - 6 * 33) / 2, startY + LINE_SPACING * 4, wifiConfig);
|
||||||
@ -390,24 +390,24 @@ void CrossPointWebServerActivity::renderServerRunning() const {
|
|||||||
renderer.drawCenteredText(UI_10_FONT_ID, startY + LINE_SPACING * 3, hostnameUrl.c_str(), true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_10_FONT_ID, startY + LINE_SPACING * 3, hostnameUrl.c_str(), true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
// Show IP address as fallback
|
// Show IP address as fallback
|
||||||
std::string ipUrl = "or http://" + connectedIP + "/";
|
std::string ipUrl = "ou http://" + connectedIP + "/";
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 4, ipUrl.c_str());
|
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 4, ipUrl.c_str());
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 5, "Open this URL in your browser");
|
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 5, "Ouvrez cet URL dans votre navigateur");
|
||||||
|
|
||||||
// Show QR code for URL
|
// Show QR code for URL
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 6, "or scan QR code with your phone:");
|
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 6, "ou scannez le code QR avec votre cellulaire:");
|
||||||
drawQRCode(renderer, (480 - 6 * 33) / 2, startY + LINE_SPACING * 7, hostnameUrl);
|
drawQRCode(renderer, (480 - 6 * 33) / 2, startY + LINE_SPACING * 7, hostnameUrl);
|
||||||
} else {
|
} else {
|
||||||
// STA mode display (original behavior)
|
// STA mode display (original behavior)
|
||||||
const int startY = 65;
|
const int startY = 65;
|
||||||
|
|
||||||
std::string ssidInfo = "Network: " + connectedSSID;
|
std::string ssidInfo = "Réseau: " + connectedSSID;
|
||||||
if (ssidInfo.length() > 28) {
|
if (ssidInfo.length() > 28) {
|
||||||
ssidInfo.replace(25, ssidInfo.length() - 25, "...");
|
ssidInfo.replace(25, ssidInfo.length() - 25, "...");
|
||||||
}
|
}
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, startY, ssidInfo.c_str());
|
renderer.drawCenteredText(UI_10_FONT_ID, startY, ssidInfo.c_str());
|
||||||
|
|
||||||
std::string ipInfo = "IP Address: " + connectedIP;
|
std::string ipInfo = "Adresse IP: " + connectedIP;
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, startY + LINE_SPACING, ipInfo.c_str());
|
renderer.drawCenteredText(UI_10_FONT_ID, startY + LINE_SPACING, ipInfo.c_str());
|
||||||
|
|
||||||
// Show web server URL prominently
|
// Show web server URL prominently
|
||||||
@ -415,16 +415,16 @@ void CrossPointWebServerActivity::renderServerRunning() const {
|
|||||||
renderer.drawCenteredText(UI_10_FONT_ID, startY + LINE_SPACING * 2, webInfo.c_str(), true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_10_FONT_ID, startY + LINE_SPACING * 2, webInfo.c_str(), true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
// Also show hostname URL
|
// Also show hostname URL
|
||||||
std::string hostnameUrl = std::string("or http://") + AP_HOSTNAME + ".local/";
|
std::string hostnameUrl = std::string("ou http://") + AP_HOSTNAME + ".local/";
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 3, hostnameUrl.c_str());
|
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 3, hostnameUrl.c_str());
|
||||||
|
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 4, "Open this URL in your browser");
|
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 4, "Ouvrez cet URL dans votre navigateur");
|
||||||
|
|
||||||
// Show QR code for URL
|
// Show QR code for URL
|
||||||
drawQRCode(renderer, (480 - 6 * 33) / 2, startY + LINE_SPACING * 6, webInfo);
|
drawQRCode(renderer, (480 - 6 * 33) / 2, startY + LINE_SPACING * 6, webInfo);
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 5, "or scan QR code with your phone:");
|
renderer.drawCenteredText(SMALL_FONT_ID, startY + LINE_SPACING * 5, "ou scannez le code QR avec votre cellulaire:");
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto labels = mappedInput.mapLabels("« Exit", "", "", "");
|
const auto labels = mappedInput.mapLabels("« Sortie", "", "", "");
|
||||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,9 +7,9 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr int MENU_ITEM_COUNT = 2;
|
constexpr int MENU_ITEM_COUNT = 2;
|
||||||
const char* MENU_ITEMS[MENU_ITEM_COUNT] = {"Join a Network", "Create Hotspot"};
|
const char* MENU_ITEMS[MENU_ITEM_COUNT] = {"Réjoindre un réseau", "Créer un point d'accès"};
|
||||||
const char* MENU_DESCRIPTIONS[MENU_ITEM_COUNT] = {"Connect to an existing WiFi network",
|
const char* MENU_DESCRIPTIONS[MENU_ITEM_COUNT] = {"Connecter à un réseau WiFi existant",
|
||||||
"Create a WiFi network others can join"};
|
"Créez un réseau Wi-Fi auquel d'autres peuvent se connecter"};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void NetworkModeSelectionActivity::taskTrampoline(void* param) {
|
void NetworkModeSelectionActivity::taskTrampoline(void* param) {
|
||||||
@ -97,10 +97,10 @@ void NetworkModeSelectionActivity::render() const {
|
|||||||
const auto pageHeight = renderer.getScreenHeight();
|
const auto pageHeight = renderer.getScreenHeight();
|
||||||
|
|
||||||
// Draw header
|
// Draw header
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, 15, "File Transfer", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Transfert de fichiers", true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
// Draw subtitle
|
// Draw subtitle
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, 50, "How would you like to connect?");
|
renderer.drawCenteredText(UI_10_FONT_ID, 50, "Comment voulez-vous connecter?");
|
||||||
|
|
||||||
// Draw menu items centered on screen
|
// Draw menu items centered on screen
|
||||||
constexpr int itemHeight = 50; // Height for each menu item (including description)
|
constexpr int itemHeight = 50; // Height for each menu item (including description)
|
||||||
@ -122,7 +122,7 @@ void NetworkModeSelectionActivity::render() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw help text at bottom
|
// Draw help text at bottom
|
||||||
const auto labels = mappedInput.mapLabels("« Back", "Select", "", "");
|
const auto labels = mappedInput.mapLabels("« Retour", "Select.", "", "");
|
||||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||||
|
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
|
|||||||
@ -54,36 +54,36 @@ void WifiSelectionActivity::onEnter() {
|
|||||||
void WifiSelectionActivity::onExit() {
|
void WifiSelectionActivity::onExit() {
|
||||||
Activity::onExit();
|
Activity::onExit();
|
||||||
|
|
||||||
Serial.printf("[%lu] [WIFI] [MEM] Free heap at onExit start: %d bytes\n", millis(), ESP.getFreeHeap());
|
Serial.printf("[%lu] [WIFI] [MEM] Pile libre au début de onExit: %d octets\n", millis(), ESP.getFreeHeap());
|
||||||
|
|
||||||
// Stop any ongoing WiFi scan
|
// Stop any ongoing WiFi scan
|
||||||
Serial.printf("[%lu] [WIFI] Deleting WiFi scan...\n", millis());
|
Serial.printf("[%lu] [WIFI] Suppression du scan WiFi...\n", millis());
|
||||||
WiFi.scanDelete();
|
WiFi.scanDelete();
|
||||||
Serial.printf("[%lu] [WIFI] [MEM] Free heap after scanDelete: %d bytes\n", millis(), ESP.getFreeHeap());
|
Serial.printf("[%lu] [WIFI] [MEM] Pile libre après scanDelete: %d octets\n", millis(), ESP.getFreeHeap());
|
||||||
|
|
||||||
// Note: We do NOT disconnect WiFi here - the parent activity (CrossPointWebServerActivity)
|
// Note: We do NOT disconnect WiFi here - the parent activity (CrossPointWebServerActivity)
|
||||||
// manages WiFi connection state. We just clean up the scan and task.
|
// manages WiFi connection state. We just clean up the scan and task.
|
||||||
|
|
||||||
// Acquire mutex before deleting task to ensure task isn't using it
|
// Acquire mutex before deleting task to ensure task isn't using it
|
||||||
// This prevents hangs/crashes if the task holds the mutex when deleted
|
// This prevents hangs/crashes if the task holds the mutex when deleted
|
||||||
Serial.printf("[%lu] [WIFI] Acquiring rendering mutex before task deletion...\n", millis());
|
Serial.printf("[%lu] [WIFI] Acquisition du mutex de rendu avant la suppression de la tâche...\n", millis());
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
|
|
||||||
// Delete the display task (we now hold the mutex, so task is blocked if it needs it)
|
// Delete the display task (we now hold the mutex, so task is blocked if it needs it)
|
||||||
Serial.printf("[%lu] [WIFI] Deleting display task...\n", millis());
|
Serial.printf("[%lu] [WIFI] Suppression de la tâche d'affichage...\n", millis());
|
||||||
if (displayTaskHandle) {
|
if (displayTaskHandle) {
|
||||||
vTaskDelete(displayTaskHandle);
|
vTaskDelete(displayTaskHandle);
|
||||||
displayTaskHandle = nullptr;
|
displayTaskHandle = nullptr;
|
||||||
Serial.printf("[%lu] [WIFI] Display task deleted\n", millis());
|
Serial.printf("[%lu] [WIFI] Tâche d'affichage supprimée\n", millis());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now safe to delete the mutex since we own it
|
// Now safe to delete the mutex since we own it
|
||||||
Serial.printf("[%lu] [WIFI] Deleting mutex...\n", millis());
|
Serial.printf("[%lu] [WIFI] Suppression de mutex...\n", millis());
|
||||||
vSemaphoreDelete(renderingMutex);
|
vSemaphoreDelete(renderingMutex);
|
||||||
renderingMutex = nullptr;
|
renderingMutex = nullptr;
|
||||||
Serial.printf("[%lu] [WIFI] Mutex deleted\n", millis());
|
Serial.printf("[%lu] [WIFI] Mutex supprimé\n", millis());
|
||||||
|
|
||||||
Serial.printf("[%lu] [WIFI] [MEM] Free heap at onExit end: %d bytes\n", millis(), ESP.getFreeHeap());
|
Serial.printf("[%lu] [WIFI] [MEM] Pile libre à la fin de onExit: %d octets\n", millis(), ESP.getFreeHeap());
|
||||||
}
|
}
|
||||||
|
|
||||||
void WifiSelectionActivity::startWifiScan() {
|
void WifiSelectionActivity::startWifiScan() {
|
||||||
@ -179,7 +179,7 @@ void WifiSelectionActivity::selectNetwork(const int index) {
|
|||||||
// Use saved password - connect directly
|
// Use saved password - connect directly
|
||||||
enteredPassword = savedCred->password;
|
enteredPassword = savedCred->password;
|
||||||
usedSavedPassword = true;
|
usedSavedPassword = true;
|
||||||
Serial.printf("[%lu] [WiFi] Using saved password for %s, length: %zu\n", millis(), selectedSSID.c_str(),
|
Serial.printf("[%lu] [WiFi] Utilisation du mot de passe sauvegardé pour %s, longueur: %zu\n", millis(), selectedSSID.c_str(),
|
||||||
enteredPassword.size());
|
enteredPassword.size());
|
||||||
attemptConnection();
|
attemptConnection();
|
||||||
return;
|
return;
|
||||||
@ -191,7 +191,7 @@ void WifiSelectionActivity::selectNetwork(const int index) {
|
|||||||
// Don't allow screen updates while changing activity
|
// Don't allow screen updates while changing activity
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
enterNewActivity(new KeyboardEntryActivity(
|
enterNewActivity(new KeyboardEntryActivity(
|
||||||
renderer, mappedInput, "Enter WiFi Password",
|
renderer, mappedInput, "Entrez le mot de passe du WiFi",
|
||||||
"", // No initial text
|
"", // No initial text
|
||||||
50, // Y position
|
50, // Y position
|
||||||
64, // Max password length
|
64, // Max password length
|
||||||
@ -251,16 +251,16 @@ void WifiSelectionActivity::checkConnectionStatus() {
|
|||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
} else {
|
} else {
|
||||||
// Using saved password or open network - complete immediately
|
// Using saved password or open network - complete immediately
|
||||||
Serial.printf("[%lu] [WIFI] Connected with saved/open credentials, completing immediately\n", millis());
|
Serial.printf("[%lu] [WIFI] Connecté avec les identifiants sauvegardés/ouverts, complétion immédiate\n", millis());
|
||||||
onComplete(true);
|
onComplete(true);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == WL_CONNECT_FAILED || status == WL_NO_SSID_AVAIL) {
|
if (status == WL_CONNECT_FAILED || status == WL_NO_SSID_AVAIL) {
|
||||||
connectionError = "Connection failed";
|
connectionError = "Connexion échouée";
|
||||||
if (status == WL_NO_SSID_AVAIL) {
|
if (status == WL_NO_SSID_AVAIL) {
|
||||||
connectionError = "Network not found";
|
connectionError = "Réseau introuvable";
|
||||||
}
|
}
|
||||||
state = WifiSelectionState::CONNECTION_FAILED;
|
state = WifiSelectionState::CONNECTION_FAILED;
|
||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
@ -505,14 +505,14 @@ void WifiSelectionActivity::renderNetworkList() const {
|
|||||||
const auto pageHeight = renderer.getScreenHeight();
|
const auto pageHeight = renderer.getScreenHeight();
|
||||||
|
|
||||||
// Draw header
|
// Draw header
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, 15, "WiFi Networks", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Réseaux WiFi", true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
if (networks.empty()) {
|
if (networks.empty()) {
|
||||||
// No networks found or scan failed
|
// No networks found or scan failed
|
||||||
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
|
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
|
||||||
const auto top = (pageHeight - height) / 2;
|
const auto top = (pageHeight - height) / 2;
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, top, "No networks found");
|
renderer.drawCenteredText(UI_10_FONT_ID, top, "Aucun réseau trouvé");
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, top + height + 10, "Press OK to scan again");
|
renderer.drawCenteredText(SMALL_FONT_ID, top + height + 10, "Appuyez OK pour scanner à nouveau");
|
||||||
} else {
|
} else {
|
||||||
// Calculate how many networks we can display
|
// Calculate how many networks we can display
|
||||||
constexpr int startY = 60;
|
constexpr int startY = 60;
|
||||||
@ -568,13 +568,13 @@ void WifiSelectionActivity::renderNetworkList() const {
|
|||||||
|
|
||||||
// Show network count
|
// Show network count
|
||||||
char countStr[32];
|
char countStr[32];
|
||||||
snprintf(countStr, sizeof(countStr), "%zu networks found", networks.size());
|
snprintf(countStr, sizeof(countStr), "%zu réseaux trouvés", networks.size());
|
||||||
renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 90, countStr);
|
renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 90, countStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw help text
|
// Draw help text
|
||||||
renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 75, "* = Encrypted | + = Saved");
|
renderer.drawText(SMALL_FONT_ID, 20, pageHeight - 75, "* = Crypté | + = Sauvegardé");
|
||||||
const auto labels = mappedInput.mapLabels("« Back", "Connect", "", "");
|
const auto labels = mappedInput.mapLabels("« Retour", "Connecter", "", "");
|
||||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -584,9 +584,9 @@ void WifiSelectionActivity::renderConnecting() const {
|
|||||||
const auto top = (pageHeight - height) / 2;
|
const auto top = (pageHeight - height) / 2;
|
||||||
|
|
||||||
if (state == WifiSelectionState::SCANNING) {
|
if (state == WifiSelectionState::SCANNING) {
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, top, "Scanning...");
|
renderer.drawCenteredText(UI_10_FONT_ID, top, "Recherche...");
|
||||||
} else {
|
} else {
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, top - 40, "Connecting...", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, top - 40, "Connexion...", true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
std::string ssidInfo = "to " + selectedSSID;
|
std::string ssidInfo = "to " + selectedSSID;
|
||||||
if (ssidInfo.length() > 25) {
|
if (ssidInfo.length() > 25) {
|
||||||
@ -601,18 +601,18 @@ void WifiSelectionActivity::renderConnected() const {
|
|||||||
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
|
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
|
||||||
const auto top = (pageHeight - height * 4) / 2;
|
const auto top = (pageHeight - height * 4) / 2;
|
||||||
|
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, top - 30, "Connected!", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, top - 30, "Connecté!", true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
std::string ssidInfo = "Network: " + selectedSSID;
|
std::string ssidInfo = "Réseau: " + selectedSSID;
|
||||||
if (ssidInfo.length() > 28) {
|
if (ssidInfo.length() > 28) {
|
||||||
ssidInfo.replace(25, ssidInfo.length() - 25, "...");
|
ssidInfo.replace(25, ssidInfo.length() - 25, "...");
|
||||||
}
|
}
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, top + 10, ssidInfo.c_str());
|
renderer.drawCenteredText(UI_10_FONT_ID, top + 10, ssidInfo.c_str());
|
||||||
|
|
||||||
const std::string ipInfo = "IP Address: " + connectedIP;
|
const std::string ipInfo = "Adresse IP: " + connectedIP;
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, top + 40, ipInfo.c_str());
|
renderer.drawCenteredText(UI_10_FONT_ID, top + 40, ipInfo.c_str());
|
||||||
|
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "Press any button to continue");
|
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "Appuyez sur n'importe quel bouton pour continuer");
|
||||||
}
|
}
|
||||||
|
|
||||||
void WifiSelectionActivity::renderSavePrompt() const {
|
void WifiSelectionActivity::renderSavePrompt() const {
|
||||||
@ -621,15 +621,15 @@ void WifiSelectionActivity::renderSavePrompt() const {
|
|||||||
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
|
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
|
||||||
const auto top = (pageHeight - height * 3) / 2;
|
const auto top = (pageHeight - height * 3) / 2;
|
||||||
|
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, top - 40, "Connected!", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, top - 40, "Connecté!", true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
std::string ssidInfo = "Network: " + selectedSSID;
|
std::string ssidInfo = "Réseaux: " + selectedSSID;
|
||||||
if (ssidInfo.length() > 28) {
|
if (ssidInfo.length() > 28) {
|
||||||
ssidInfo.replace(25, ssidInfo.length() - 25, "...");
|
ssidInfo.replace(25, ssidInfo.length() - 25, "...");
|
||||||
}
|
}
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, top, ssidInfo.c_str());
|
renderer.drawCenteredText(UI_10_FONT_ID, top, ssidInfo.c_str());
|
||||||
|
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, top + 40, "Save password for next time?");
|
renderer.drawCenteredText(UI_10_FONT_ID, top + 40, "Enregistrer le mot de passe pour la prochaine fois?");
|
||||||
|
|
||||||
// Draw Yes/No buttons
|
// Draw Yes/No buttons
|
||||||
const int buttonY = top + 80;
|
const int buttonY = top + 80;
|
||||||
@ -640,19 +640,19 @@ void WifiSelectionActivity::renderSavePrompt() const {
|
|||||||
|
|
||||||
// Draw "Yes" button
|
// Draw "Yes" button
|
||||||
if (savePromptSelection == 0) {
|
if (savePromptSelection == 0) {
|
||||||
renderer.drawText(UI_10_FONT_ID, startX, buttonY, "[Yes]");
|
renderer.drawText(UI_10_FONT_ID, startX, buttonY, "[Oui]");
|
||||||
} else {
|
} else {
|
||||||
renderer.drawText(UI_10_FONT_ID, startX + 4, buttonY, "Yes");
|
renderer.drawText(UI_10_FONT_ID, startX + 4, buttonY, "Oui");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw "No" button
|
// Draw "No" button
|
||||||
if (savePromptSelection == 1) {
|
if (savePromptSelection == 1) {
|
||||||
renderer.drawText(UI_10_FONT_ID, startX + buttonWidth + buttonSpacing, buttonY, "[No]");
|
renderer.drawText(UI_10_FONT_ID, startX + buttonWidth + buttonSpacing, buttonY, "[Non]");
|
||||||
} else {
|
} else {
|
||||||
renderer.drawText(UI_10_FONT_ID, startX + buttonWidth + buttonSpacing + 4, buttonY, "No");
|
renderer.drawText(UI_10_FONT_ID, startX + buttonWidth + buttonSpacing + 4, buttonY, "Non");
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "LEFT/RIGHT: Select | OK: Confirm");
|
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "GAUCHE/DROITE: Selectionner | OK: Confirmer");
|
||||||
}
|
}
|
||||||
|
|
||||||
void WifiSelectionActivity::renderConnectionFailed() const {
|
void WifiSelectionActivity::renderConnectionFailed() const {
|
||||||
@ -660,9 +660,9 @@ void WifiSelectionActivity::renderConnectionFailed() const {
|
|||||||
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
|
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
|
||||||
const auto top = (pageHeight - height * 2) / 2;
|
const auto top = (pageHeight - height * 2) / 2;
|
||||||
|
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, top - 20, "Connection Failed", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, top - 20, "Connexion échouée", true, EpdFontFamily::BOLD);
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, top + 20, connectionError.c_str());
|
renderer.drawCenteredText(UI_10_FONT_ID, top + 20, connectionError.c_str());
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "Press any button to continue");
|
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "Appuyez sur n'importe quel bouton pour continuer");
|
||||||
}
|
}
|
||||||
|
|
||||||
void WifiSelectionActivity::renderForgetPrompt() const {
|
void WifiSelectionActivity::renderForgetPrompt() const {
|
||||||
@ -671,15 +671,15 @@ void WifiSelectionActivity::renderForgetPrompt() const {
|
|||||||
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
|
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
|
||||||
const auto top = (pageHeight - height * 3) / 2;
|
const auto top = (pageHeight - height * 3) / 2;
|
||||||
|
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, top - 40, "Forget Network?", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, top - 40, "Oublier le réseau?", true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
std::string ssidInfo = "Network: " + selectedSSID;
|
std::string ssidInfo = "Réseau: " + selectedSSID;
|
||||||
if (ssidInfo.length() > 28) {
|
if (ssidInfo.length() > 28) {
|
||||||
ssidInfo.replace(25, ssidInfo.length() - 25, "...");
|
ssidInfo.replace(25, ssidInfo.length() - 25, "...");
|
||||||
}
|
}
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, top, ssidInfo.c_str());
|
renderer.drawCenteredText(UI_10_FONT_ID, top, ssidInfo.c_str());
|
||||||
|
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, top + 40, "Remove saved password?");
|
renderer.drawCenteredText(UI_10_FONT_ID, top + 40, "Supprimer le mot de passe sauvegardé?");
|
||||||
|
|
||||||
// Draw Yes/No buttons
|
// Draw Yes/No buttons
|
||||||
const int buttonY = top + 80;
|
const int buttonY = top + 80;
|
||||||
@ -690,17 +690,17 @@ void WifiSelectionActivity::renderForgetPrompt() const {
|
|||||||
|
|
||||||
// Draw "Yes" button
|
// Draw "Yes" button
|
||||||
if (forgetPromptSelection == 0) {
|
if (forgetPromptSelection == 0) {
|
||||||
renderer.drawText(UI_10_FONT_ID, startX, buttonY, "[Yes]");
|
renderer.drawText(UI_10_FONT_ID, startX, buttonY, "[Oui]");
|
||||||
} else {
|
} else {
|
||||||
renderer.drawText(UI_10_FONT_ID, startX + 4, buttonY, "Yes");
|
renderer.drawText(UI_10_FONT_ID, startX + 4, buttonY, "Oui");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw "No" button
|
// Draw "No" button
|
||||||
if (forgetPromptSelection == 1) {
|
if (forgetPromptSelection == 1) {
|
||||||
renderer.drawText(UI_10_FONT_ID, startX + buttonWidth + buttonSpacing, buttonY, "[No]");
|
renderer.drawText(UI_10_FONT_ID, startX + buttonWidth + buttonSpacing, buttonY, "[Non]");
|
||||||
} else {
|
} else {
|
||||||
renderer.drawText(UI_10_FONT_ID, startX + buttonWidth + buttonSpacing + 4, buttonY, "No");
|
renderer.drawText(UI_10_FONT_ID, startX + buttonWidth + buttonSpacing + 4, buttonY, "Non");
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "LEFT/RIGHT: Select | OK: Confirm");
|
renderer.drawCenteredText(SMALL_FONT_ID, pageHeight - 30, "GAUCHE/DROITE: Selectionner | OK: Confirmer");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,7 +59,7 @@ void EpubReaderActivity::onEnter() {
|
|||||||
if (f.read(data, 4) == 4) {
|
if (f.read(data, 4) == 4) {
|
||||||
currentSpineIndex = data[0] + (data[1] << 8);
|
currentSpineIndex = data[0] + (data[1] << 8);
|
||||||
nextPageNumber = data[2] + (data[3] << 8);
|
nextPageNumber = data[2] + (data[3] << 8);
|
||||||
Serial.printf("[%lu] [ERS] Loaded cache: %d, %d\n", millis(), currentSpineIndex, nextPageNumber);
|
Serial.printf("[%lu] [ERS] Cache chargée: %d, %d\n", millis(), currentSpineIndex, nextPageNumber);
|
||||||
}
|
}
|
||||||
f.close();
|
f.close();
|
||||||
}
|
}
|
||||||
@ -69,7 +69,7 @@ void EpubReaderActivity::onEnter() {
|
|||||||
int textSpineIndex = epub->getSpineIndexForTextReference();
|
int textSpineIndex = epub->getSpineIndexForTextReference();
|
||||||
if (textSpineIndex != 0) {
|
if (textSpineIndex != 0) {
|
||||||
currentSpineIndex = textSpineIndex;
|
currentSpineIndex = textSpineIndex;
|
||||||
Serial.printf("[%lu] [ERS] Opened for first time, navigating to text reference at index %d\n", millis(),
|
Serial.printf("[%lu] [ERS] Ouvert pour la première fois, navigation à la référence textuel à l'indice %d\n", millis(),
|
||||||
textSpineIndex);
|
textSpineIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -242,7 +242,7 @@ void EpubReaderActivity::renderScreen() {
|
|||||||
// Show end of book screen
|
// Show end of book screen
|
||||||
if (currentSpineIndex == epub->getSpineItemsCount()) {
|
if (currentSpineIndex == epub->getSpineItemsCount()) {
|
||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, 300, "End of book", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, 300, "Fin du livre", true, EpdFontFamily::BOLD);
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -258,7 +258,7 @@ void EpubReaderActivity::renderScreen() {
|
|||||||
|
|
||||||
if (!section) {
|
if (!section) {
|
||||||
const auto filepath = epub->getSpineItem(currentSpineIndex).href;
|
const auto filepath = epub->getSpineItem(currentSpineIndex).href;
|
||||||
Serial.printf("[%lu] [ERS] Loading file: %s, index: %d\n", millis(), filepath.c_str(), currentSpineIndex);
|
Serial.printf("[%lu] [ERS] Chargement du fichier: %s, indice: %d\n", millis(), filepath.c_str(), currentSpineIndex);
|
||||||
section = std::unique_ptr<Section>(new Section(epub, currentSpineIndex, renderer));
|
section = std::unique_ptr<Section>(new Section(epub, currentSpineIndex, renderer));
|
||||||
|
|
||||||
const uint16_t viewportWidth = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight;
|
const uint16_t viewportWidth = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight;
|
||||||
@ -267,13 +267,13 @@ void EpubReaderActivity::renderScreen() {
|
|||||||
if (!section->loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
if (!section->loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||||
viewportHeight)) {
|
viewportHeight)) {
|
||||||
Serial.printf("[%lu] [ERS] Cache not found, building...\n", millis());
|
Serial.printf("[%lu] [ERS] Aucune cache trouvée, création...\n", millis());
|
||||||
|
|
||||||
// Progress bar dimensions
|
// Progress bar dimensions
|
||||||
constexpr int barWidth = 200;
|
constexpr int barWidth = 200;
|
||||||
constexpr int barHeight = 10;
|
constexpr int barHeight = 10;
|
||||||
constexpr int boxMargin = 20;
|
constexpr int boxMargin = 20;
|
||||||
const int textWidth = renderer.getTextWidth(UI_12_FONT_ID, "Indexing...");
|
const int textWidth = renderer.getTextWidth(UI_12_FONT_ID, "Indexage...");
|
||||||
const int boxWidthWithBar = (barWidth > textWidth ? barWidth : textWidth) + boxMargin * 2;
|
const int boxWidthWithBar = (barWidth > textWidth ? barWidth : textWidth) + boxMargin * 2;
|
||||||
const int boxWidthNoBar = textWidth + boxMargin * 2;
|
const int boxWidthNoBar = textWidth + boxMargin * 2;
|
||||||
const int boxHeightWithBar = renderer.getLineHeight(UI_12_FONT_ID) + barHeight + boxMargin * 3;
|
const int boxHeightWithBar = renderer.getLineHeight(UI_12_FONT_ID) + barHeight + boxMargin * 3;
|
||||||
@ -287,7 +287,7 @@ void EpubReaderActivity::renderScreen() {
|
|||||||
// Always show "Indexing..." text first
|
// Always show "Indexing..." text first
|
||||||
{
|
{
|
||||||
renderer.fillRect(boxXNoBar, boxY, boxWidthNoBar, boxHeightNoBar, false);
|
renderer.fillRect(boxXNoBar, boxY, boxWidthNoBar, boxHeightNoBar, false);
|
||||||
renderer.drawText(UI_12_FONT_ID, boxXNoBar + boxMargin, boxY + boxMargin, "Indexing...");
|
renderer.drawText(UI_12_FONT_ID, boxXNoBar + boxMargin, boxY + boxMargin, "Indexage...");
|
||||||
renderer.drawRect(boxXNoBar + 5, boxY + 5, boxWidthNoBar - 10, boxHeightNoBar - 10);
|
renderer.drawRect(boxXNoBar + 5, boxY + 5, boxWidthNoBar - 10, boxHeightNoBar - 10);
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
pagesUntilFullRefresh = 0;
|
pagesUntilFullRefresh = 0;
|
||||||
@ -296,7 +296,7 @@ void EpubReaderActivity::renderScreen() {
|
|||||||
// Setup callback - only called for chapters >= 50KB, redraws with progress bar
|
// Setup callback - only called for chapters >= 50KB, redraws with progress bar
|
||||||
auto progressSetup = [this, boxXWithBar, boxWidthWithBar, boxHeightWithBar, barX, barY] {
|
auto progressSetup = [this, boxXWithBar, boxWidthWithBar, boxHeightWithBar, barX, barY] {
|
||||||
renderer.fillRect(boxXWithBar, boxY, boxWidthWithBar, boxHeightWithBar, false);
|
renderer.fillRect(boxXWithBar, boxY, boxWidthWithBar, boxHeightWithBar, false);
|
||||||
renderer.drawText(UI_12_FONT_ID, boxXWithBar + boxMargin, boxY + boxMargin, "Indexing...");
|
renderer.drawText(UI_12_FONT_ID, boxXWithBar + boxMargin, boxY + boxMargin, "Indexage...");
|
||||||
renderer.drawRect(boxXWithBar + 5, boxY + 5, boxWidthWithBar - 10, boxHeightWithBar - 10);
|
renderer.drawRect(boxXWithBar + 5, boxY + 5, boxWidthWithBar - 10, boxHeightWithBar - 10);
|
||||||
renderer.drawRect(barX, barY, barWidth, barHeight);
|
renderer.drawRect(barX, barY, barWidth, barHeight);
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
@ -312,12 +312,12 @@ void EpubReaderActivity::renderScreen() {
|
|||||||
if (!section->createSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
if (!section->createSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
|
||||||
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
|
||||||
viewportHeight, progressSetup, progressCallback)) {
|
viewportHeight, progressSetup, progressCallback)) {
|
||||||
Serial.printf("[%lu] [ERS] Failed to persist page data to SD\n", millis());
|
Serial.printf("[%lu] [ERS] Persistence des données de page au SD échouée\n", millis());
|
||||||
section.reset();
|
section.reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Serial.printf("[%lu] [ERS] Cache found, skipping build...\n", millis());
|
Serial.printf("[%lu] [ERS] Cache trouvée, sauter sa construction...\n", millis());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextPageNumber == UINT16_MAX) {
|
if (nextPageNumber == UINT16_MAX) {
|
||||||
@ -330,16 +330,16 @@ void EpubReaderActivity::renderScreen() {
|
|||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
|
|
||||||
if (section->pageCount == 0) {
|
if (section->pageCount == 0) {
|
||||||
Serial.printf("[%lu] [ERS] No pages to render\n", millis());
|
Serial.printf("[%lu] [ERS] Aucune page à afficher\n", millis());
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, 300, "Empty chapter", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, 300, "Chapitre vide", true, EpdFontFamily::BOLD);
|
||||||
renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft);
|
renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft);
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (section->currentPage < 0 || section->currentPage >= section->pageCount) {
|
if (section->currentPage < 0 || section->currentPage >= section->pageCount) {
|
||||||
Serial.printf("[%lu] [ERS] Page out of bounds: %d (max %d)\n", millis(), section->currentPage, section->pageCount);
|
Serial.printf("[%lu] [ERS] Page hors limites: %d (max %d)\n", millis(), section->currentPage, section->pageCount);
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, 300, "Out of bounds", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, 300, "Hors limites", true, EpdFontFamily::BOLD);
|
||||||
renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft);
|
renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft);
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
return;
|
return;
|
||||||
@ -348,14 +348,14 @@ void EpubReaderActivity::renderScreen() {
|
|||||||
{
|
{
|
||||||
auto p = section->loadPageFromSectionFile();
|
auto p = section->loadPageFromSectionFile();
|
||||||
if (!p) {
|
if (!p) {
|
||||||
Serial.printf("[%lu] [ERS] Failed to load page from SD - clearing section cache\n", millis());
|
Serial.printf("[%lu] [ERS] Chargment de page du SD échoué - suppression de la cache de section\n", millis());
|
||||||
section->clearCache();
|
section->clearCache();
|
||||||
section.reset();
|
section.reset();
|
||||||
return renderScreen();
|
return renderScreen();
|
||||||
}
|
}
|
||||||
const auto start = millis();
|
const auto start = millis();
|
||||||
renderContents(std::move(p), orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft);
|
renderContents(std::move(p), orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft);
|
||||||
Serial.printf("[%lu] [ERS] Rendered page in %dms\n", millis(), millis() - start);
|
Serial.printf("[%lu] [ERS] Page rendue en %dms\n", millis(), millis() - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
FsFile f;
|
FsFile f;
|
||||||
@ -451,8 +451,8 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in
|
|||||||
std::string title;
|
std::string title;
|
||||||
int titleWidth;
|
int titleWidth;
|
||||||
if (tocIndex == -1) {
|
if (tocIndex == -1) {
|
||||||
title = "Unnamed";
|
title = "Sans nom";
|
||||||
titleWidth = renderer.getTextWidth(SMALL_FONT_ID, "Unnamed");
|
titleWidth = renderer.getTextWidth(SMALL_FONT_ID, "Sans nom");
|
||||||
} else {
|
} else {
|
||||||
const auto tocItem = epub->getTocItem(tocIndex);
|
const auto tocItem = epub->getTocItem(tocIndex);
|
||||||
title = tocItem.title;
|
title = tocItem.title;
|
||||||
|
|||||||
@ -180,14 +180,14 @@ void FileSelectionActivity::render() const {
|
|||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
|
|
||||||
const auto pageWidth = renderer.getScreenWidth();
|
const auto pageWidth = renderer.getScreenWidth();
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Books", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Livres", true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
// Help text
|
// Help text
|
||||||
const auto labels = mappedInput.mapLabels("« Home", "Open", "", "");
|
const auto labels = mappedInput.mapLabels("« Accueil", "Ouvrir", "", "");
|
||||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||||
|
|
||||||
if (files.empty()) {
|
if (files.empty()) {
|
||||||
renderer.drawText(UI_10_FONT_ID, 20, 60, "No books found");
|
renderer.drawText(UI_10_FONT_ID, 20, 60, "Aucun livre trouvé");
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@ bool ReaderActivity::isXtcFile(const std::string& path) {
|
|||||||
|
|
||||||
std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
|
std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
|
||||||
if (!SdMan.exists(path.c_str())) {
|
if (!SdMan.exists(path.c_str())) {
|
||||||
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
|
Serial.printf("[%lu] [ ] Le fichier n'existe pas: %s\n", millis(), path.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,13 +31,13 @@ std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
|
|||||||
return epub;
|
return epub;
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.printf("[%lu] [ ] Failed to load epub\n", millis());
|
Serial.printf("[%lu] [ ] Chargement de l'epub échoué\n", millis());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Xtc> ReaderActivity::loadXtc(const std::string& path) {
|
std::unique_ptr<Xtc> ReaderActivity::loadXtc(const std::string& path) {
|
||||||
if (!SdMan.exists(path.c_str())) {
|
if (!SdMan.exists(path.c_str())) {
|
||||||
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
|
Serial.printf("[%lu] [ ] Le fichier n'existe pas: %s\n", millis(), path.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,14 +46,14 @@ std::unique_ptr<Xtc> ReaderActivity::loadXtc(const std::string& path) {
|
|||||||
return xtc;
|
return xtc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.printf("[%lu] [ ] Failed to load XTC\n", millis());
|
Serial.printf("[%lu] [ ] Chargement du XTC échoué\n", millis());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReaderActivity::onSelectBookFile(const std::string& path) {
|
void ReaderActivity::onSelectBookFile(const std::string& path) {
|
||||||
currentBookPath = path; // Track current book path
|
currentBookPath = path; // Track current book path
|
||||||
exitActivity();
|
exitActivity();
|
||||||
enterNewActivity(new FullScreenMessageActivity(renderer, mappedInput, "Loading..."));
|
enterNewActivity(new FullScreenMessageActivity(renderer, mappedInput, "Chargement..."));
|
||||||
|
|
||||||
if (isXtcFile(path)) {
|
if (isXtcFile(path)) {
|
||||||
// Load XTC file
|
// Load XTC file
|
||||||
@ -62,7 +62,7 @@ void ReaderActivity::onSelectBookFile(const std::string& path) {
|
|||||||
onGoToXtcReader(std::move(xtc));
|
onGoToXtcReader(std::move(xtc));
|
||||||
} else {
|
} else {
|
||||||
exitActivity();
|
exitActivity();
|
||||||
enterNewActivity(new FullScreenMessageActivity(renderer, mappedInput, "Failed to load XTC",
|
enterNewActivity(new FullScreenMessageActivity(renderer, mappedInput, "Chargement du XTC échoué",
|
||||||
EpdFontFamily::REGULAR, EInkDisplay::HALF_REFRESH));
|
EpdFontFamily::REGULAR, EInkDisplay::HALF_REFRESH));
|
||||||
delay(2000);
|
delay(2000);
|
||||||
onGoToFileSelection();
|
onGoToFileSelection();
|
||||||
@ -74,7 +74,7 @@ void ReaderActivity::onSelectBookFile(const std::string& path) {
|
|||||||
onGoToEpubReader(std::move(epub));
|
onGoToEpubReader(std::move(epub));
|
||||||
} else {
|
} else {
|
||||||
exitActivity();
|
exitActivity();
|
||||||
enterNewActivity(new FullScreenMessageActivity(renderer, mappedInput, "Failed to load epub",
|
enterNewActivity(new FullScreenMessageActivity(renderer, mappedInput, "Chargement de l'epub échoué",
|
||||||
EpdFontFamily::REGULAR, EInkDisplay::HALF_REFRESH));
|
EpdFontFamily::REGULAR, EInkDisplay::HALF_REFRESH));
|
||||||
delay(2000);
|
delay(2000);
|
||||||
onGoToFileSelection();
|
onGoToFileSelection();
|
||||||
|
|||||||
@ -251,7 +251,7 @@ void XtcReaderActivity::renderPage() {
|
|||||||
pixelCounts[getPixelValue(x, y)]++;
|
pixelCounts[getPixelValue(x, y)]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Serial.printf("[%lu] [XTR] Pixel distribution: White=%lu, DarkGrey=%lu, LightGrey=%lu, Black=%lu\n", millis(),
|
Serial.printf("[%lu] [XTR] Distribution des pixels: Blanc=%lu, GrisFoncé=%lu, GrisPâle=%lu, Noir=%lu\n", millis(),
|
||||||
pixelCounts[0], pixelCounts[1], pixelCounts[2], pixelCounts[3]);
|
pixelCounts[0], pixelCounts[1], pixelCounts[2], pixelCounts[3]);
|
||||||
|
|
||||||
// Pass 1: BW buffer - draw all non-white pixels as black
|
// Pass 1: BW buffer - draw all non-white pixels as black
|
||||||
@ -315,7 +315,7 @@ void XtcReaderActivity::renderPage() {
|
|||||||
|
|
||||||
free(pageBuffer);
|
free(pageBuffer);
|
||||||
|
|
||||||
Serial.printf("[%lu] [XTR] Rendered page %lu/%lu (2-bit grayscale)\n", millis(), currentPage + 1,
|
Serial.printf("[%lu] [XTR] Page rendue %lu/%lu en niveaux de gris (2-bits)\n", millis(), currentPage + 1,
|
||||||
xtc->getPageCount());
|
xtc->getPageCount());
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -352,7 +352,7 @@ void XtcReaderActivity::renderPage() {
|
|||||||
pagesUntilFullRefresh--;
|
pagesUntilFullRefresh--;
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.printf("[%lu] [XTR] Rendered page %lu/%lu (%u-bit)\n", millis(), currentPage + 1, xtc->getPageCount(),
|
Serial.printf("[%lu] [XTR] Page rendue %lu/%lu (%u-bits)\n", millis(), currentPage + 1, xtc->getPageCount(),
|
||||||
bitDepth);
|
bitDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,7 +375,7 @@ void XtcReaderActivity::loadProgress() {
|
|||||||
uint8_t data[4];
|
uint8_t data[4];
|
||||||
if (f.read(data, 4) == 4) {
|
if (f.read(data, 4) == 4) {
|
||||||
currentPage = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
|
currentPage = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
|
||||||
Serial.printf("[%lu] [XTR] Loaded progress: page %lu\n", millis(), currentPage);
|
Serial.printf("[%lu] [XTR] Progrès chargé: page %lu\n", millis(), currentPage);
|
||||||
|
|
||||||
// Validate page number
|
// Validate page number
|
||||||
if (currentPage >= xtc->getPageCount()) {
|
if (currentPage >= xtc->getPageCount()) {
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr int MENU_ITEMS = 2;
|
constexpr int MENU_ITEMS = 2;
|
||||||
const char* menuNames[MENU_ITEMS] = {"Calibre Web URL", "Connect as Wireless Device"};
|
const char* menuNames[MENU_ITEMS] = {"URL web Calibre", "Connecter en tant qu'un appareil sans fil"};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void CalibreSettingsActivity::taskTrampoline(void* param) {
|
void CalibreSettingsActivity::taskTrampoline(void* param) {
|
||||||
@ -83,7 +83,7 @@ void CalibreSettingsActivity::handleSelection() {
|
|||||||
// Calibre Web URL
|
// Calibre Web URL
|
||||||
exitActivity();
|
exitActivity();
|
||||||
enterNewActivity(new KeyboardEntryActivity(
|
enterNewActivity(new KeyboardEntryActivity(
|
||||||
renderer, mappedInput, "Calibre Web URL", SETTINGS.opdsServerUrl, 10,
|
renderer, mappedInput, "URL web Calibre", SETTINGS.opdsServerUrl, 10,
|
||||||
127, // maxLength
|
127, // maxLength
|
||||||
false, // not password
|
false, // not password
|
||||||
[this](const std::string& url) {
|
[this](const std::string& url) {
|
||||||
@ -155,14 +155,14 @@ void CalibreSettingsActivity::render() {
|
|||||||
|
|
||||||
// Draw status for URL setting
|
// Draw status for URL setting
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
const char* status = (strlen(SETTINGS.opdsServerUrl) > 0) ? "[Set]" : "[Not Set]";
|
const char* status = (strlen(SETTINGS.opdsServerUrl) > 0) ? "[Défini]" : "[Indéfini]";
|
||||||
const auto width = renderer.getTextWidth(UI_10_FONT_ID, status);
|
const auto width = renderer.getTextWidth(UI_10_FONT_ID, status);
|
||||||
renderer.drawText(UI_10_FONT_ID, pageWidth - 20 - width, settingY, status, !isSelected);
|
renderer.drawText(UI_10_FONT_ID, pageWidth - 20 - width, settingY, status, !isSelected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw button hints
|
// Draw button hints
|
||||||
const auto labels = mappedInput.mapLabels("« Back", "Select", "", "");
|
const auto labels = mappedInput.mapLabels("« Retour", "Select.", "", "");
|
||||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||||
|
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
|
|||||||
@ -17,12 +17,12 @@ void OtaUpdateActivity::onWifiSelectionComplete(const bool success) {
|
|||||||
exitActivity();
|
exitActivity();
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
Serial.printf("[%lu] [OTA] WiFi connection failed, exiting\n", millis());
|
Serial.printf("[%lu] [OTA] Connexion au WiFi a échouée, arrêt en cours\n", millis());
|
||||||
goBack();
|
goBack();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.printf("[%lu] [OTA] WiFi connected, checking for update\n", millis());
|
Serial.printf("[%lu] [OTA] WiFi connecté, recherche de mises à jour\n", millis());
|
||||||
|
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
state = CHECKING_FOR_UPDATE;
|
state = CHECKING_FOR_UPDATE;
|
||||||
@ -31,7 +31,7 @@ void OtaUpdateActivity::onWifiSelectionComplete(const bool success) {
|
|||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
const auto res = updater.checkForUpdate();
|
const auto res = updater.checkForUpdate();
|
||||||
if (res != OtaUpdater::OK) {
|
if (res != OtaUpdater::OK) {
|
||||||
Serial.printf("[%lu] [OTA] Update check failed: %d\n", millis(), res);
|
Serial.printf("[%lu] [OTA] Recherce de mises à jour échouée: %d\n", millis(), res);
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
state = FAILED;
|
state = FAILED;
|
||||||
xSemaphoreGive(renderingMutex);
|
xSemaphoreGive(renderingMutex);
|
||||||
@ -40,7 +40,7 @@ void OtaUpdateActivity::onWifiSelectionComplete(const bool success) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!updater.isUpdateNewer()) {
|
if (!updater.isUpdateNewer()) {
|
||||||
Serial.printf("[%lu] [OTA] No new update available\n", millis());
|
Serial.printf("[%lu] [OTA] Aucune nouvelle mise à jour disponible\n", millis());
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
state = NO_UPDATE;
|
state = NO_UPDATE;
|
||||||
xSemaphoreGive(renderingMutex);
|
xSemaphoreGive(renderingMutex);
|
||||||
@ -67,11 +67,11 @@ void OtaUpdateActivity::onEnter() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Turn on WiFi immediately
|
// Turn on WiFi immediately
|
||||||
Serial.printf("[%lu] [OTA] Turning on WiFi...\n", millis());
|
Serial.printf("[%lu] [OTA] Activation du WiFi...\n", millis());
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
|
|
||||||
// Launch WiFi selection subactivity
|
// Launch WiFi selection subactivity
|
||||||
Serial.printf("[%lu] [OTA] Launching WifiSelectionActivity...\n", millis());
|
Serial.printf("[%lu] [OTA] Lancement de WifiSelectionActivity...\n", millis());
|
||||||
enterNewActivity(new WifiSelectionActivity(renderer, mappedInput,
|
enterNewActivity(new WifiSelectionActivity(renderer, mappedInput,
|
||||||
[this](const bool connected) { onWifiSelectionComplete(connected); }));
|
[this](const bool connected) { onWifiSelectionComplete(connected); }));
|
||||||
}
|
}
|
||||||
@ -115,7 +115,7 @@ void OtaUpdateActivity::render() {
|
|||||||
|
|
||||||
float updaterProgress = 0;
|
float updaterProgress = 0;
|
||||||
if (state == UPDATE_IN_PROGRESS) {
|
if (state == UPDATE_IN_PROGRESS) {
|
||||||
Serial.printf("[%lu] [OTA] Update progress: %d / %d\n", millis(), updater.processedSize, updater.totalSize);
|
Serial.printf("[%lu] [OTA] Progrès de la mise à jour : %d / %d\n", millis(), updater.processedSize, updater.totalSize);
|
||||||
updaterProgress = static_cast<float>(updater.processedSize) / static_cast<float>(updater.totalSize);
|
updaterProgress = static_cast<float>(updater.processedSize) / static_cast<float>(updater.totalSize);
|
||||||
// Only update every 2% at the most
|
// Only update every 2% at the most
|
||||||
if (static_cast<int>(updaterProgress * 50) == lastUpdaterPercentage / 2) {
|
if (static_cast<int>(updaterProgress * 50) == lastUpdaterPercentage / 2) {
|
||||||
@ -127,27 +127,27 @@ void OtaUpdateActivity::render() {
|
|||||||
const auto pageWidth = renderer.getScreenWidth();
|
const auto pageWidth = renderer.getScreenWidth();
|
||||||
|
|
||||||
renderer.clearScreen();
|
renderer.clearScreen();
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Update", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Mise à jour", true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
if (state == CHECKING_FOR_UPDATE) {
|
if (state == CHECKING_FOR_UPDATE) {
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, 300, "Checking for update...", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_10_FONT_ID, 300, "Recherche de mises à jour...", true, EpdFontFamily::BOLD);
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == WAITING_CONFIRMATION) {
|
if (state == WAITING_CONFIRMATION) {
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, 200, "New update available!", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_10_FONT_ID, 200, "Une mise à jour est disponible!", true, EpdFontFamily::BOLD);
|
||||||
renderer.drawText(UI_10_FONT_ID, 20, 250, "Current Version: " CROSSPOINT_VERSION);
|
renderer.drawText(UI_10_FONT_ID, 20, 250, "Version actuelle: " CROSSPOINT_VERSION);
|
||||||
renderer.drawText(UI_10_FONT_ID, 20, 270, ("New Version: " + updater.getLatestVersion()).c_str());
|
renderer.drawText(UI_10_FONT_ID, 20, 270, ("Nouvelle version: " + updater.getLatestVersion()).c_str());
|
||||||
|
|
||||||
const auto labels = mappedInput.mapLabels("Cancel", "Update", "", "");
|
const auto labels = mappedInput.mapLabels("Annuler", "M-à-j", "", "");
|
||||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == UPDATE_IN_PROGRESS) {
|
if (state == UPDATE_IN_PROGRESS) {
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, 310, "Updating...", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_10_FONT_ID, 310, "Mise à jour...", true, EpdFontFamily::BOLD);
|
||||||
renderer.drawRect(20, 350, pageWidth - 40, 50);
|
renderer.drawRect(20, 350, pageWidth - 40, 50);
|
||||||
renderer.fillRect(24, 354, static_cast<int>(updaterProgress * static_cast<float>(pageWidth - 44)), 42);
|
renderer.fillRect(24, 354, static_cast<int>(updaterProgress * static_cast<float>(pageWidth - 44)), 42);
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, 420,
|
renderer.drawCenteredText(UI_10_FONT_ID, 420,
|
||||||
@ -160,20 +160,20 @@ void OtaUpdateActivity::render() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state == NO_UPDATE) {
|
if (state == NO_UPDATE) {
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, 300, "No update available", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_10_FONT_ID, 300, "Aucune novelle mise à jour disponible", true, EpdFontFamily::BOLD);
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == FAILED) {
|
if (state == FAILED) {
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, 300, "Update failed", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_10_FONT_ID, 300, "Mise à jour échouée", true, EpdFontFamily::BOLD);
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == FINISHED) {
|
if (state == FINISHED) {
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, 300, "Update complete", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_10_FONT_ID, 300, "Mise à jour terminée", true, EpdFontFamily::BOLD);
|
||||||
renderer.drawCenteredText(UI_10_FONT_ID, 350, "Press and hold power button to turn back on");
|
renderer.drawCenteredText(UI_10_FONT_ID, 350, "Appuyez longuement sur le bouton d'alimentation pour rallumer");
|
||||||
renderer.displayBuffer();
|
renderer.displayBuffer();
|
||||||
state = SHUTTING_DOWN;
|
state = SHUTTING_DOWN;
|
||||||
return;
|
return;
|
||||||
@ -188,7 +188,7 @@ void OtaUpdateActivity::loop() {
|
|||||||
|
|
||||||
if (state == WAITING_CONFIRMATION) {
|
if (state == WAITING_CONFIRMATION) {
|
||||||
if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) {
|
if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) {
|
||||||
Serial.printf("[%lu] [OTA] New update available, starting download...\n", millis());
|
Serial.printf("[%lu] [OTA] Nouvelle mise à jour disponible, téléchargement commencé...\n", millis());
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
state = UPDATE_IN_PROGRESS;
|
state = UPDATE_IN_PROGRESS;
|
||||||
xSemaphoreGive(renderingMutex);
|
xSemaphoreGive(renderingMutex);
|
||||||
@ -197,7 +197,7 @@ void OtaUpdateActivity::loop() {
|
|||||||
const auto res = updater.installUpdate([this](const size_t, const size_t) { updateRequired = true; });
|
const auto res = updater.installUpdate([this](const size_t, const size_t) { updateRequired = true; });
|
||||||
|
|
||||||
if (res != OtaUpdater::OK) {
|
if (res != OtaUpdater::OK) {
|
||||||
Serial.printf("[%lu] [OTA] Update failed: %d\n", millis(), res);
|
Serial.printf("[%lu] [OTA] Mise à jour échouée: %d\n", millis(), res);
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
state = FAILED;
|
state = FAILED;
|
||||||
xSemaphoreGive(renderingMutex);
|
xSemaphoreGive(renderingMutex);
|
||||||
|
|||||||
@ -16,31 +16,31 @@ namespace {
|
|||||||
constexpr int settingsCount = 18;
|
constexpr int settingsCount = 18;
|
||||||
const SettingInfo settingsList[settingsCount] = {
|
const SettingInfo settingsList[settingsCount] = {
|
||||||
// Should match with SLEEP_SCREEN_MODE
|
// Should match with SLEEP_SCREEN_MODE
|
||||||
SettingInfo::Enum("Sleep Screen", &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover", "None"}),
|
SettingInfo::Enum("Écran de veille", &CrossPointSettings::sleepScreen, {"Sombre", "Clair", "Personnalisé", "Couverture", "Aucun"}),
|
||||||
SettingInfo::Enum("Sleep Screen Cover Mode", &CrossPointSettings::sleepScreenCoverMode, {"Fit", "Crop"}),
|
SettingInfo::Enum("Mode de couverture de veille", &CrossPointSettings::sleepScreenCoverMode, {"Étirée", "Recadrée"}),
|
||||||
SettingInfo::Enum("Status Bar", &CrossPointSettings::statusBar, {"None", "No Progress", "Full"}),
|
SettingInfo::Enum("Barre d'état", &CrossPointSettings::statusBar, {"Aucune", "Sans progrès", "Pleine"}),
|
||||||
SettingInfo::Toggle("Extra Paragraph Spacing", &CrossPointSettings::extraParagraphSpacing),
|
SettingInfo::Toggle("Espace supplé. entre paragraphes", &CrossPointSettings::extraParagraphSpacing),
|
||||||
SettingInfo::Toggle("Text Anti-Aliasing", &CrossPointSettings::textAntiAliasing),
|
SettingInfo::Toggle("Anticrénelage du texte", &CrossPointSettings::textAntiAliasing),
|
||||||
SettingInfo::Toggle("Short Power Button Click", &CrossPointSettings::shortPwrBtn),
|
SettingInfo::Toggle("Clic court du bouton alim.", &CrossPointSettings::shortPwrBtn),
|
||||||
SettingInfo::Enum("Reading Orientation", &CrossPointSettings::orientation,
|
SettingInfo::Enum("Orientation de lecture", &CrossPointSettings::orientation,
|
||||||
{"Portrait", "Landscape CW", "Inverted", "Landscape CCW"}),
|
{"Portrait", "Paysage à droite", "Inversée", "Paysage à gauche"}),
|
||||||
SettingInfo::Enum("Front Button Layout", &CrossPointSettings::frontButtonLayout,
|
SettingInfo::Enum("Disposition des boutons au front", &CrossPointSettings::frontButtonLayout,
|
||||||
{"Bck, Cnfrm, Lft, Rght", "Lft, Rght, Bck, Cnfrm", "Lft, Bck, Cnfrm, Rght"}),
|
{"Rtr, Cnfrmr, Gche, Drte", "Gche, Drte, Rtr, Cnfrmr", "Gche, Rtr, Cnfrmr, Drte"}),
|
||||||
SettingInfo::Enum("Side Button Layout (reader)", &CrossPointSettings::sideButtonLayout,
|
SettingInfo::Enum("Disposition des boutons à droite (lis.)", &CrossPointSettings::sideButtonLayout,
|
||||||
{"Prev, Next", "Next, Prev"}),
|
{"Précédent, Prochaine", "Prochaine, Précédent"}),
|
||||||
SettingInfo::Enum("Reader Font Family", &CrossPointSettings::fontFamily,
|
SettingInfo::Enum("Police", &CrossPointSettings::fontFamily,
|
||||||
{"Bookerly", "Noto Sans", "Open Dyslexic"}),
|
{"Bookerly", "Noto Sans", "Open Dyslexic"}),
|
||||||
SettingInfo::Enum("Reader Font Size", &CrossPointSettings::fontSize, {"Small", "Medium", "Large", "X Large"}),
|
SettingInfo::Enum("Taille de police", &CrossPointSettings::fontSize, {"Petit", "Medium", "Large", "Très Large"}),
|
||||||
SettingInfo::Enum("Reader Line Spacing", &CrossPointSettings::lineSpacing, {"Tight", "Normal", "Wide"}),
|
SettingInfo::Enum("Espacement des lignes", &CrossPointSettings::lineSpacing, {"Fin", "Normal", "Large"}),
|
||||||
SettingInfo::Value("Reader Screen Margin", &CrossPointSettings::screenMargin, {5, 40, 5}),
|
SettingInfo::Value("Marge d'écran", &CrossPointSettings::screenMargin, {5, 40, 5}),
|
||||||
SettingInfo::Enum("Reader Paragraph Alignment", &CrossPointSettings::paragraphAlignment,
|
SettingInfo::Enum("Alignement des lignes", &CrossPointSettings::paragraphAlignment,
|
||||||
{"Justify", "Left", "Center", "Right"}),
|
{"Justifié", "Gauche", "Centré", "Droite"}),
|
||||||
SettingInfo::Enum("Time to Sleep", &CrossPointSettings::sleepTimeout,
|
SettingInfo::Enum("Temps de veille", &CrossPointSettings::sleepTimeout,
|
||||||
{"1 min", "5 min", "10 min", "15 min", "30 min"}),
|
{"1 min", "5 min", "10 min", "15 min", "30 min"}),
|
||||||
SettingInfo::Enum("Refresh Frequency", &CrossPointSettings::refreshFrequency,
|
SettingInfo::Enum("Fréquence de rafraîche.", &CrossPointSettings::refreshFrequency,
|
||||||
{"1 page", "5 pages", "10 pages", "15 pages", "30 pages"}),
|
{"1 page", "5 pages", "10 pages", "15 pages", "30 pages"}),
|
||||||
SettingInfo::Action("Calibre Settings"),
|
SettingInfo::Action("Paramètres Calibre"),
|
||||||
SettingInfo::Action("Check for updates")};
|
SettingInfo::Action("Vérifier les mises à jour")};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void SettingsActivity::taskTrampoline(void* param) {
|
void SettingsActivity::taskTrampoline(void* param) {
|
||||||
@ -137,7 +137,7 @@ void SettingsActivity::toggleCurrentSetting() {
|
|||||||
SETTINGS.*(setting.valuePtr) = currentValue + setting.valueRange.step;
|
SETTINGS.*(setting.valuePtr) = currentValue + setting.valueRange.step;
|
||||||
}
|
}
|
||||||
} else if (setting.type == SettingType::ACTION) {
|
} else if (setting.type == SettingType::ACTION) {
|
||||||
if (strcmp(setting.name, "Calibre Settings") == 0) {
|
if (strcmp(setting.name, "Paramètres Calibre") == 0) {
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
exitActivity();
|
exitActivity();
|
||||||
enterNewActivity(new CalibreSettingsActivity(renderer, mappedInput, [this] {
|
enterNewActivity(new CalibreSettingsActivity(renderer, mappedInput, [this] {
|
||||||
@ -145,7 +145,7 @@ void SettingsActivity::toggleCurrentSetting() {
|
|||||||
updateRequired = true;
|
updateRequired = true;
|
||||||
}));
|
}));
|
||||||
xSemaphoreGive(renderingMutex);
|
xSemaphoreGive(renderingMutex);
|
||||||
} else if (strcmp(setting.name, "Check for updates") == 0) {
|
} else if (strcmp(setting.name, "Verifier les mises à jour") == 0) {
|
||||||
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
xSemaphoreTake(renderingMutex, portMAX_DELAY);
|
||||||
exitActivity();
|
exitActivity();
|
||||||
enterNewActivity(new OtaUpdateActivity(renderer, mappedInput, [this] {
|
enterNewActivity(new OtaUpdateActivity(renderer, mappedInput, [this] {
|
||||||
@ -182,7 +182,7 @@ void SettingsActivity::render() const {
|
|||||||
const auto pageHeight = renderer.getScreenHeight();
|
const auto pageHeight = renderer.getScreenHeight();
|
||||||
|
|
||||||
// Draw header
|
// Draw header
|
||||||
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Settings", true, EpdFontFamily::BOLD);
|
renderer.drawCenteredText(UI_12_FONT_ID, 15, "Paramètres", true, EpdFontFamily::BOLD);
|
||||||
|
|
||||||
// Draw selection
|
// Draw selection
|
||||||
renderer.fillRect(0, 60 + selectedSettingIndex * 30 - 2, pageWidth - 1, 30);
|
renderer.fillRect(0, 60 + selectedSettingIndex * 30 - 2, pageWidth - 1, 30);
|
||||||
@ -198,7 +198,7 @@ void SettingsActivity::render() const {
|
|||||||
std::string valueText = "";
|
std::string valueText = "";
|
||||||
if (settingsList[i].type == SettingType::TOGGLE && settingsList[i].valuePtr != nullptr) {
|
if (settingsList[i].type == SettingType::TOGGLE && settingsList[i].valuePtr != nullptr) {
|
||||||
const bool value = SETTINGS.*(settingsList[i].valuePtr);
|
const bool value = SETTINGS.*(settingsList[i].valuePtr);
|
||||||
valueText = value ? "ON" : "OFF";
|
valueText = value ? "OUI" : "NON";
|
||||||
} else if (settingsList[i].type == SettingType::ENUM && settingsList[i].valuePtr != nullptr) {
|
} else if (settingsList[i].type == SettingType::ENUM && settingsList[i].valuePtr != nullptr) {
|
||||||
const uint8_t value = SETTINGS.*(settingsList[i].valuePtr);
|
const uint8_t value = SETTINGS.*(settingsList[i].valuePtr);
|
||||||
valueText = settingsList[i].enumValues[value];
|
valueText = settingsList[i].enumValues[value];
|
||||||
@ -214,7 +214,7 @@ void SettingsActivity::render() const {
|
|||||||
pageHeight - 60, CROSSPOINT_VERSION);
|
pageHeight - 60, CROSSPOINT_VERSION);
|
||||||
|
|
||||||
// Draw help text
|
// Draw help text
|
||||||
const auto labels = mappedInput.mapLabels("« Save", "Toggle", "", "");
|
const auto labels = mappedInput.mapLabels("« Enreg.", "Basculer", "", "");
|
||||||
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||||
|
|
||||||
// Always use standard refresh for settings screen
|
// Always use standard refresh for settings screen
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user