v2.3.2: Add info button to WiFi Manager screen explaining multi-network support
This commit is contained in:
@@ -145,6 +145,10 @@ enum class StringId : uint8_t {
|
||||
WIFI_NETWORKS_TITLE,
|
||||
WIFI_ADD_NETWORK,
|
||||
WIFI_EMPTY_SLOT,
|
||||
WIFI_INFO_TITLE,
|
||||
WIFI_INFO_PARA1,
|
||||
WIFI_INFO_PARA2,
|
||||
WIFI_INFO_PARA3,
|
||||
|
||||
COUNT
|
||||
};
|
||||
|
||||
@@ -145,6 +145,11 @@ static const char* const I18N_DE[] = {
|
||||
"WLAN-Netzwerke",
|
||||
"Netzwerk hinzufügen",
|
||||
"(leer)",
|
||||
|
||||
"Wie WLAN-Netzwerke funktionieren",
|
||||
"Du kannst bis zu 3 WLAN-Netzwerke speichern. Beim Start verbindet sich das Gerät automatisch mit dem, das gerade erreichbar ist.",
|
||||
"Praktisch für unterwegs (Büro, Freunde, Ferienhaus), für Gast- und Haupt-WLAN am selben Router, oder wenn du mehrere Access Points im Haus hast.",
|
||||
"Über das rote 'X' kannst du ein gespeichertes Netzwerk jederzeit wieder entfernen, um Platz für ein neues zu schaffen.",
|
||||
};
|
||||
|
||||
static_assert(sizeof(I18N_DE) / sizeof(I18N_DE[0]) == (size_t)StringId::COUNT,
|
||||
|
||||
@@ -146,6 +146,11 @@ static const char* const I18N_EN[] = {
|
||||
"WiFi networks",
|
||||
"Add network",
|
||||
"(empty)",
|
||||
|
||||
"How WiFi networks work",
|
||||
"You can save up to 3 WiFi networks. On boot, the device automatically connects to whichever one it can currently reach.",
|
||||
"Handy for portable use (office, friends, holiday home), for guest + main WiFi on the same router, or if you have multiple access points around the house.",
|
||||
"Remove a saved network anytime via the red 'X' to free up a slot for a new one.",
|
||||
};
|
||||
|
||||
static_assert(sizeof(I18N_EN) / sizeof(I18N_EN[0]) == (size_t)StringId::COUNT,
|
||||
|
||||
@@ -145,6 +145,11 @@ static const char* const I18N_ES[] = {
|
||||
"Redes WiFi",
|
||||
"Añadir red",
|
||||
"(vacío)",
|
||||
|
||||
"Cómo funcionan las redes WiFi",
|
||||
"Puede guardar hasta 3 redes WiFi. Al iniciar, el dispositivo se conecta automáticamente a la que pueda alcanzar en ese momento.",
|
||||
"Útil para uso móvil (oficina, amigos, casa de vacaciones), para WiFi de invitados + principal en el mismo router, o si tiene varios puntos de acceso en casa.",
|
||||
"Elimine una red guardada en cualquier momento con la 'X' roja para liberar un espacio para una nueva.",
|
||||
};
|
||||
|
||||
static_assert(sizeof(I18N_ES) / sizeof(I18N_ES[0]) == (size_t)StringId::COUNT,
|
||||
|
||||
@@ -145,6 +145,11 @@ static const char* const I18N_FR[] = {
|
||||
"Réseaux WiFi",
|
||||
"Ajouter un réseau",
|
||||
"(vide)",
|
||||
|
||||
"Comment marchent les réseaux WiFi",
|
||||
"Vous pouvez enregistrer jusqu'à 3 réseaux WiFi. Au démarrage, l'appareil se connecte automatiquement à celui qu'il peut atteindre.",
|
||||
"Pratique en déplacement (bureau, amis, maison de vacances), pour un WiFi invité + principal sur le même routeur, ou si vous avez plusieurs points d'accès.",
|
||||
"Supprimez un réseau enregistré à tout moment via le 'X' rouge pour libérer une place pour un nouveau.",
|
||||
};
|
||||
|
||||
static_assert(sizeof(I18N_FR) / sizeof(I18N_FR[0]) == (size_t)StringId::COUNT,
|
||||
|
||||
@@ -145,6 +145,11 @@ static const char* const I18N_IT[] = {
|
||||
"Reti WiFi",
|
||||
"Aggiungi rete",
|
||||
"(vuoto)",
|
||||
|
||||
"Come funzionano le reti WiFi",
|
||||
"Puoi salvare fino a 3 reti WiFi. All'avvio, il dispositivo si connette automaticamente a quella che riesce a raggiungere in quel momento.",
|
||||
"Utile per l'uso portatile (ufficio, amici, casa vacanze), per WiFi ospiti + principale sullo stesso router, o se hai più punti di accesso in casa.",
|
||||
"Rimuovi una rete salvata in qualsiasi momento tramite la 'X' rossa per liberare uno slot per una nuova.",
|
||||
};
|
||||
|
||||
static_assert(sizeof(I18N_IT) / sizeof(I18N_IT[0]) == (size_t)StringId::COUNT,
|
||||
|
||||
@@ -145,6 +145,11 @@ static const char* const I18N_TR[] = {
|
||||
"WiFi ağları",
|
||||
"Ağ ekle",
|
||||
"(boş)",
|
||||
|
||||
"WiFi ağları nasıl çalışır",
|
||||
"3 adete kadar WiFi ağı kaydedebilirsiniz. Başlangıçta cihaz, o an erişebildiği ağa otomatik olarak bağlanır.",
|
||||
"Taşınabilir kullanım için kullanışlıdır (ofis, arkadaşlar, tatil evi), aynı yönlendiricide misafir + ana WiFi için, veya evde birden fazla erişim noktanız varsa.",
|
||||
"Kayıtlı bir ağı istediğiniz zaman kırmızı 'X' ile kaldırarak yeni bir ağ için yer açabilirsiniz.",
|
||||
};
|
||||
|
||||
static_assert(sizeof(I18N_TR) / sizeof(I18N_TR[0]) == (size_t)StringId::COUNT,
|
||||
|
||||
@@ -25,6 +25,104 @@ namespace {
|
||||
tft.drawString(label, r.x + r.w / 2, r.y + r.h / 2);
|
||||
tft.setTextDatum(TL_DATUM);
|
||||
}
|
||||
|
||||
int16_t layoutWrapped(TFT_eSPI& tft, int16_t x, int16_t startY, int16_t maxWidth,
|
||||
int16_t lineHeight, const String& text, int16_t scrollY,
|
||||
int16_t viewTop, int16_t viewBottom, bool draw) {
|
||||
int16_t y = startY;
|
||||
int32_t start = 0;
|
||||
int32_t len = text.length();
|
||||
while (start < len) {
|
||||
while (start < len && text[start] == ' ') start++;
|
||||
if (start >= len) break;
|
||||
|
||||
String line = text.substring(start, len);
|
||||
while (tft.textWidth(line) > maxWidth) {
|
||||
int32_t lastSpace = line.lastIndexOf(' ');
|
||||
if (lastSpace <= 0) break;
|
||||
line = line.substring(0, lastSpace);
|
||||
}
|
||||
|
||||
if (draw) {
|
||||
int16_t screenY = y - scrollY;
|
||||
if (screenY >= viewTop && screenY <= viewBottom) {
|
||||
tft.setCursor(x, screenY);
|
||||
tft.print(line);
|
||||
}
|
||||
}
|
||||
y += lineHeight;
|
||||
start += line.length();
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
void runInfoScreen(TFT_eSPI& tft) {
|
||||
MenuStars::reset();
|
||||
|
||||
constexpr int16_t textMaxWidth = Config::SCREEN_WIDTH - 20;
|
||||
constexpr int16_t LINE_H = 16;
|
||||
constexpr int16_t VIEW_TOP = 40;
|
||||
Rect backBtn = {10, (int16_t)(Config::SCREEN_HEIGHT - 50), (int16_t)(Config::SCREEN_WIDTH - 20), 40};
|
||||
constexpr int16_t VIEW_BOTTOM = Config::SCREEN_HEIGHT - 60;
|
||||
|
||||
int16_t totalH = VIEW_TOP;
|
||||
totalH = layoutWrapped(tft, 10, totalH, textMaxWidth, LINE_H, I18n::t(StringId::WIFI_INFO_PARA1), 0, 0, 0, false);
|
||||
totalH += 8;
|
||||
totalH = layoutWrapped(tft, 10, totalH, textMaxWidth, LINE_H, I18n::t(StringId::WIFI_INFO_PARA2), 0, 0, 0, false);
|
||||
totalH += 8;
|
||||
totalH = layoutWrapped(tft, 10, totalH, textMaxWidth, LINE_H, I18n::t(StringId::WIFI_INFO_PARA3), 0, 0, 0, false);
|
||||
|
||||
int16_t maxScroll = totalH - VIEW_BOTTOM;
|
||||
if (maxScroll < 0) maxScroll = 0;
|
||||
bool scrollable = maxScroll > 0;
|
||||
int16_t scrollY = 0;
|
||||
|
||||
Rect upBtn = {(int16_t)(Config::SCREEN_WIDTH - 34), 4, 30, 24};
|
||||
Rect downBtn = {(int16_t)(Config::SCREEN_WIDTH - 34), 30, 30, 24};
|
||||
constexpr int16_t SCROLL_STEP = 48;
|
||||
|
||||
auto redraw = [&]() {
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
tft.setTextColor(TFT_GREEN, TFT_BLACK);
|
||||
tft.setCursor(10, 14);
|
||||
tft.println(I18n::t(StringId::WIFI_INFO_TITLE));
|
||||
|
||||
if (scrollable) {
|
||||
drawButton(tft, upBtn, "^");
|
||||
drawButton(tft, downBtn, "v");
|
||||
}
|
||||
|
||||
tft.setTextColor(TFT_GREEN, TFT_BLACK);
|
||||
int16_t y = VIEW_TOP;
|
||||
y = layoutWrapped(tft, 10, y, textMaxWidth, LINE_H, I18n::t(StringId::WIFI_INFO_PARA1), scrollY, VIEW_TOP, VIEW_BOTTOM, true);
|
||||
y += 8;
|
||||
y = layoutWrapped(tft, 10, y, textMaxWidth, LINE_H, I18n::t(StringId::WIFI_INFO_PARA2), scrollY, VIEW_TOP, VIEW_BOTTOM, true);
|
||||
y += 8;
|
||||
layoutWrapped(tft, 10, y, textMaxWidth, LINE_H, I18n::t(StringId::WIFI_INFO_PARA3), scrollY, VIEW_TOP, VIEW_BOTTOM, true);
|
||||
|
||||
drawButton(tft, backBtn, I18n::t(StringId::BACK));
|
||||
};
|
||||
|
||||
redraw();
|
||||
|
||||
while (true) {
|
||||
TouchInput::Point tap;
|
||||
if (TouchInput::wasTapped(tap)) {
|
||||
if (backBtn.contains(tap.x, tap.y)) return;
|
||||
if (scrollable && upBtn.contains(tap.x, tap.y) && scrollY > 0) {
|
||||
scrollY -= SCROLL_STEP;
|
||||
if (scrollY < 0) scrollY = 0;
|
||||
redraw();
|
||||
} else if (scrollable && downBtn.contains(tap.x, tap.y) && scrollY < maxScroll) {
|
||||
scrollY += SCROLL_STEP;
|
||||
if (scrollY > maxScroll) scrollY = maxScroll;
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
MenuStars::update(tft);
|
||||
delay(20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void run(TFT_eSPI& tft) {
|
||||
@@ -40,6 +138,9 @@ void run(TFT_eSPI& tft) {
|
||||
tft.setCursor(10, 14);
|
||||
tft.println(I18n::t(StringId::WIFI_NETWORKS_TITLE));
|
||||
|
||||
Rect infoBtn = {(int16_t)(Config::SCREEN_WIDTH - 40), 2, 30, 24};
|
||||
drawButton(tft, infoBtn, "?");
|
||||
|
||||
uint8_t count = WifiMgr::networkCount();
|
||||
int16_t y = 40;
|
||||
|
||||
@@ -84,6 +185,10 @@ void run(TFT_eSPI& tft) {
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
if (infoBtn.contains(tap.x, tap.y)) {
|
||||
runInfoScreen(tft);
|
||||
handled = true;
|
||||
}
|
||||
for (uint8_t i = 0; i < count && !handled; i++) {
|
||||
if (removeRects[i].contains(tap.x, tap.y)) {
|
||||
WifiMgr::removeNetwork(i);
|
||||
|
||||
Reference in New Issue
Block a user