414 lines
15 KiB
C++
414 lines
15 KiB
C++
#include "WifiSetting.hpp"
|
|
#include "../Wifi.hpp"
|
|
#include "../Fonts.hpp"
|
|
#include "esp_lv_adapter.h"
|
|
#include "esp_log.h"
|
|
#include <cstring>
|
|
|
|
static const char* TAG = "WifiSetting";
|
|
|
|
WifiSetting& WifiSetting::instance() {
|
|
static WifiSetting instance;
|
|
return instance;
|
|
}
|
|
|
|
void WifiSetting::show() {
|
|
if (visible_) {
|
|
return;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Showing WiFi settings");
|
|
|
|
if (esp_lv_adapter_lock(-1) == ESP_OK) {
|
|
createUI();
|
|
visible_ = true;
|
|
|
|
Wifi::instance().setStatusCallback([](bool connected) {
|
|
if (esp_lv_adapter_lock(100) == ESP_OK) {
|
|
WifiSetting::instance().updateStatusDisplay();
|
|
esp_lv_adapter_unlock();
|
|
}
|
|
});
|
|
|
|
refreshNetworkList();
|
|
refreshSavedNetworks();
|
|
updateStatusDisplay();
|
|
|
|
esp_lv_adapter_unlock();
|
|
}
|
|
}
|
|
|
|
void WifiSetting::hide() {
|
|
if (!visible_) {
|
|
return;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Hiding WiFi settings");
|
|
|
|
if (esp_lv_adapter_lock(-1) == ESP_OK) {
|
|
Wifi::instance().setStatusCallback(nullptr);
|
|
|
|
if (overlay_) {
|
|
lv_obj_del(overlay_);
|
|
overlay_ = nullptr;
|
|
statusLabel_ = nullptr;
|
|
disconnectBtn_ = nullptr;
|
|
networkList_ = nullptr;
|
|
savedList_ = nullptr;
|
|
passwordDialog_ = nullptr;
|
|
passwordInput_ = nullptr;
|
|
keyboard_ = nullptr;
|
|
}
|
|
visible_ = false;
|
|
esp_lv_adapter_unlock();
|
|
}
|
|
}
|
|
|
|
bool WifiSetting::isVisible() {
|
|
return visible_;
|
|
}
|
|
|
|
void WifiSetting::createUI() {
|
|
overlay_ = lv_obj_create(lv_scr_act());
|
|
lv_obj_set_size(overlay_, LV_PCT(100), LV_PCT(100));
|
|
lv_obj_set_style_bg_color(overlay_, lv_color_hex(0x202020), 0);
|
|
lv_obj_set_style_bg_opa(overlay_, LV_OPA_COVER, 0);
|
|
lv_obj_set_style_text_font(overlay_, Fonts::bySizeIndex(0), 0);
|
|
lv_obj_set_style_pad_all(overlay_, 10, 0);
|
|
lv_obj_clear_flag(overlay_, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
lv_obj_t* header = lv_obj_create(overlay_);
|
|
lv_obj_set_size(header, LV_PCT(100), 50);
|
|
lv_obj_align(header, LV_ALIGN_TOP_MID, 0, 0);
|
|
lv_obj_set_style_bg_color(header, lv_color_hex(0x303030), 0);
|
|
lv_obj_set_style_pad_all(header, 5, 0);
|
|
lv_obj_clear_flag(header, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
lv_obj_t* closeBtn = lv_btn_create(header);
|
|
lv_obj_set_size(closeBtn, 40, 40);
|
|
lv_obj_align(closeBtn, LV_ALIGN_LEFT_MID, 0, 0);
|
|
lv_obj_set_style_bg_color(closeBtn, lv_color_hex(0x804040), 0);
|
|
//lv_obj_add_event_cb(closeBtn, onCloseClick, LV_EVENT_CLICKED, nullptr);
|
|
|
|
lv_obj_t* closeLbl = lv_label_create(closeBtn);
|
|
lv_label_set_text(closeLbl, "X");
|
|
lv_obj_center(closeLbl);
|
|
|
|
lv_obj_t* titleLbl = lv_label_create(header);
|
|
lv_label_set_text(titleLbl, "WiFi Settings");
|
|
lv_obj_set_style_text_font(titleLbl, Fonts::bySizeIndex(0), 0);
|
|
lv_obj_align(titleLbl, LV_ALIGN_CENTER, 0, 0);
|
|
|
|
lv_obj_t* statusSection = lv_obj_create(overlay_);
|
|
lv_obj_set_size(statusSection, LV_PCT(100), 80);
|
|
lv_obj_align_to(statusSection, header, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
|
|
lv_obj_set_style_bg_color(statusSection, lv_color_hex(0x303030), 0);
|
|
lv_obj_set_style_pad_all(statusSection, 10, 0);
|
|
lv_obj_clear_flag(statusSection, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
statusLabel_ = lv_label_create(statusSection);
|
|
lv_label_set_text(statusLabel_, "Status: Nicht verbunden");
|
|
lv_obj_align(statusLabel_, LV_ALIGN_LEFT_MID, 0, 0);
|
|
|
|
disconnectBtn_ = lv_btn_create(statusSection);
|
|
lv_obj_set_size(disconnectBtn_, 100, 40);
|
|
lv_obj_align(disconnectBtn_, LV_ALIGN_RIGHT_MID, 0, 0);
|
|
//lv_obj_add_event_cb(disconnectBtn_, onDisconnectClick, LV_EVENT_CLICKED, nullptr);
|
|
lv_obj_add_flag(disconnectBtn_, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
lv_obj_t* disconnectLbl = lv_label_create(disconnectBtn_);
|
|
lv_label_set_text(disconnectLbl, "Trennen");
|
|
lv_obj_center(disconnectLbl);
|
|
|
|
lv_obj_t* availableSection = lv_obj_create(overlay_);
|
|
lv_obj_set_size(availableSection, LV_PCT(100), 280);
|
|
lv_obj_align_to(availableSection, statusSection, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
|
|
lv_obj_set_style_bg_color(availableSection, lv_color_hex(0x303030), 0);
|
|
lv_obj_set_style_pad_all(availableSection, 10, 0);
|
|
lv_obj_clear_flag(availableSection, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
lv_obj_t* availableHeader = lv_obj_create(availableSection);
|
|
lv_obj_set_size(availableHeader, LV_PCT(100), 40);
|
|
lv_obj_align(availableHeader, LV_ALIGN_TOP_MID, 0, 0);
|
|
lv_obj_set_style_bg_opa(availableHeader, LV_OPA_TRANSP, 0);
|
|
lv_obj_set_style_border_width(availableHeader, 0, 0);
|
|
lv_obj_set_style_pad_all(availableHeader, 0, 0);
|
|
lv_obj_clear_flag(availableHeader, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
lv_obj_t* availableLbl = lv_label_create(availableHeader);
|
|
lv_label_set_text(availableLbl, "Verfuegbare Netzwerke:");
|
|
lv_obj_align(availableLbl, LV_ALIGN_LEFT_MID, 0, 0);
|
|
|
|
lv_obj_t* scanBtn = lv_btn_create(availableHeader);
|
|
lv_obj_set_size(scanBtn, 100, 35);
|
|
lv_obj_align(scanBtn, LV_ALIGN_RIGHT_MID, 0, 0);
|
|
//lv_obj_add_event_cb(scanBtn, onScanClick, LV_EVENT_CLICKED, nullptr);
|
|
|
|
lv_obj_t* scanLbl = lv_label_create(scanBtn);
|
|
lv_label_set_text(scanLbl, "Scannen");
|
|
lv_obj_center(scanLbl);
|
|
|
|
networkList_ = lv_list_create(availableSection);
|
|
lv_obj_set_size(networkList_, LV_PCT(100), 220);
|
|
lv_obj_align_to(networkList_, availableHeader, LV_ALIGN_OUT_BOTTOM_MID, 0, 5);
|
|
lv_obj_set_style_bg_color(networkList_, lv_color_hex(0x252525), 0);
|
|
|
|
lv_obj_t* savedSection = lv_obj_create(overlay_);
|
|
lv_obj_set_size(savedSection, LV_PCT(100), 200);
|
|
lv_obj_align_to(savedSection, availableSection, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
|
|
lv_obj_set_style_bg_color(savedSection, lv_color_hex(0x303030), 0);
|
|
lv_obj_set_style_pad_all(savedSection, 10, 0);
|
|
lv_obj_clear_flag(savedSection, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
lv_obj_t* savedLbl = lv_label_create(savedSection);
|
|
lv_label_set_text(savedLbl, "Gespeicherte Netzwerke:");
|
|
lv_obj_align(savedLbl, LV_ALIGN_TOP_LEFT, 0, 0);
|
|
|
|
savedList_ = lv_list_create(savedSection);
|
|
lv_obj_set_size(savedList_, LV_PCT(100), 150);
|
|
lv_obj_align(savedList_, LV_ALIGN_BOTTOM_MID, 0, 0);
|
|
lv_obj_set_style_bg_color(savedList_, lv_color_hex(0x252525), 0);
|
|
}
|
|
|
|
void WifiSetting::refreshNetworkList() {
|
|
ESP_LOGI(TAG, "Starting network scan");
|
|
|
|
if (networkList_) {
|
|
lv_obj_clean(networkList_);
|
|
lv_obj_t* scanningLbl = lv_list_add_text(networkList_, "Scanning...");
|
|
(void)scanningLbl;
|
|
}
|
|
|
|
Wifi::instance().scan([](std::vector<wifi_ap_record_t>& networks) {
|
|
WifiSetting& settings = WifiSetting::instance();
|
|
settings.scannedNetworks_ = networks;
|
|
|
|
if (esp_lv_adapter_lock(100) == ESP_OK) {
|
|
if (settings.networkList_) {
|
|
lv_obj_clean(settings.networkList_);
|
|
|
|
for (const auto& ap : networks) {
|
|
char signalStr[64];
|
|
int bars = 0;
|
|
if (ap.rssi >= -50) bars = 4;
|
|
else if (ap.rssi >= -60) bars = 3;
|
|
else if (ap.rssi >= -70) bars = 2;
|
|
else bars = 1;
|
|
|
|
const char* barSymbols[] = {"[# ]", "[## ]", "[### ]", "[####]"};
|
|
snprintf(signalStr, sizeof(signalStr), "%s %s %ddBm",
|
|
(const char*)ap.ssid, barSymbols[bars - 1], ap.rssi);
|
|
|
|
lv_obj_t* btn = lv_list_add_btn(settings.networkList_, LV_SYMBOL_WIFI, signalStr);
|
|
//lv_obj_add_event_cb(btn, onNetworkSelect, LV_EVENT_CLICKED, nullptr);
|
|
|
|
size_t ssidLen = strlen((const char*)ap.ssid);
|
|
char* ssidCopy = (char*)lv_malloc(ssidLen + 1);
|
|
strcpy(ssidCopy, (const char*)ap.ssid);
|
|
lv_obj_set_user_data(btn, ssidCopy);
|
|
}
|
|
|
|
if (networks.empty()) {
|
|
lv_list_add_text(settings.networkList_, "Keine Netzwerke gefunden");
|
|
}
|
|
}
|
|
esp_lv_adapter_unlock();
|
|
}
|
|
});
|
|
}
|
|
|
|
void WifiSetting::refreshSavedNetworks() {
|
|
if (!savedList_) return;
|
|
|
|
lv_obj_clean(savedList_);
|
|
|
|
auto savedNetworks = Wifi::instance().getSavedNetworks();
|
|
|
|
for (const auto& ssid : savedNetworks) {
|
|
lv_obj_t* item = lv_obj_create(savedList_);
|
|
lv_obj_set_size(item, LV_PCT(100), 40);
|
|
lv_obj_set_style_bg_color(item, lv_color_hex(0x353535), 0);
|
|
lv_obj_set_style_pad_all(item, 5, 0);
|
|
lv_obj_clear_flag(item, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
lv_obj_t* nameLbl = lv_label_create(item);
|
|
lv_label_set_text(nameLbl, ssid.c_str());
|
|
lv_obj_align(nameLbl, LV_ALIGN_LEFT_MID, 0, 0);
|
|
|
|
lv_obj_t* deleteBtn = lv_btn_create(item);
|
|
lv_obj_set_size(deleteBtn, 80, 30);
|
|
lv_obj_align(deleteBtn, LV_ALIGN_RIGHT_MID, 0, 0);
|
|
lv_obj_set_style_bg_color(deleteBtn, lv_color_hex(0x804040), 0);
|
|
//lv_obj_add_event_cb(deleteBtn, onDeleteSavedClick, LV_EVENT_CLICKED, nullptr);
|
|
|
|
char* ssidCopy = (char*)lv_malloc(ssid.size() + 1);
|
|
strcpy(ssidCopy, ssid.c_str());
|
|
lv_obj_set_user_data(deleteBtn, ssidCopy);
|
|
|
|
lv_obj_t* deleteLbl = lv_label_create(deleteBtn);
|
|
lv_label_set_text(deleteLbl, "Loeschen");
|
|
lv_obj_center(deleteLbl);
|
|
}
|
|
|
|
if (savedNetworks.empty()) {
|
|
lv_list_add_text(savedList_, "Keine gespeicherten Netzwerke");
|
|
}
|
|
}
|
|
|
|
void WifiSetting::updateStatusDisplay() {
|
|
if (!statusLabel_ || !disconnectBtn_) return;
|
|
|
|
Wifi& wifi = Wifi::instance();
|
|
|
|
if (wifi.isConnected()) {
|
|
char statusText[64];
|
|
snprintf(statusText, sizeof(statusText), "Verbunden: %s", wifi.getCurrentSSID().c_str());
|
|
lv_label_set_text(statusLabel_, statusText);
|
|
lv_obj_clear_flag(disconnectBtn_, LV_OBJ_FLAG_HIDDEN);
|
|
} else {
|
|
lv_label_set_text(statusLabel_, "Status: Nicht verbunden");
|
|
lv_obj_add_flag(disconnectBtn_, LV_OBJ_FLAG_HIDDEN);
|
|
}
|
|
}
|
|
|
|
static void showPasswordDialogAsync(void* arg) {
|
|
WifiSetting::instance().createPasswordDialogUI();
|
|
}
|
|
|
|
void WifiSetting::showPasswordDialog(const char* ssid) {
|
|
selectedSSID_ = ssid;
|
|
lv_async_call(showPasswordDialogAsync, nullptr);
|
|
}
|
|
|
|
void WifiSetting::createPasswordDialogUI() {
|
|
if (passwordDialog_) return;
|
|
|
|
ESP_LOGI(TAG, "Creating password dialog for: %s", selectedSSID_.c_str());
|
|
|
|
passwordDialog_ = lv_obj_create(lv_scr_act());
|
|
lv_obj_set_size(passwordDialog_, LV_PCT(100), LV_PCT(100));
|
|
lv_obj_set_pos(passwordDialog_, 0, 0);
|
|
lv_obj_set_style_bg_color(passwordDialog_, lv_color_hex(0x303030), 0);
|
|
lv_obj_set_style_bg_opa(passwordDialog_, LV_OPA_COVER, 0);
|
|
lv_obj_set_style_pad_all(passwordDialog_, 20, 0);
|
|
lv_obj_clear_flag(passwordDialog_, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
char title[64];
|
|
snprintf(title, sizeof(title), "Verbinden mit: %s", selectedSSID_.c_str());
|
|
lv_obj_t* titleLbl = lv_label_create(passwordDialog_);
|
|
lv_label_set_text(titleLbl, title);
|
|
lv_obj_align(titleLbl, LV_ALIGN_TOP_MID, 0, 10);
|
|
|
|
lv_obj_t* pwLabel = lv_label_create(passwordDialog_);
|
|
lv_label_set_text(pwLabel, "Passwort:");
|
|
lv_obj_align(pwLabel, LV_ALIGN_TOP_LEFT, 10, 50);
|
|
|
|
passwordInput_ = lv_textarea_create(passwordDialog_);
|
|
lv_obj_set_size(passwordInput_, LV_PCT(90), 50);
|
|
lv_obj_align(passwordInput_, LV_ALIGN_TOP_MID, 0, 80);
|
|
lv_textarea_set_password_mode(passwordInput_, true);
|
|
lv_textarea_set_one_line(passwordInput_, true);
|
|
lv_textarea_set_placeholder_text(passwordInput_, "Passwort eingeben...");
|
|
|
|
lv_obj_t* cancelBtn = lv_btn_create(passwordDialog_);
|
|
lv_obj_set_size(cancelBtn, 150, 50);
|
|
lv_obj_align(cancelBtn, LV_ALIGN_TOP_LEFT, 20, 150);
|
|
lv_obj_set_style_bg_color(cancelBtn, lv_color_hex(0x606060), 0);
|
|
//lv_obj_add_event_cb(cancelBtn, onCancelClick, LV_EVENT_CLICKED, nullptr);
|
|
|
|
lv_obj_t* cancelLbl = lv_label_create(cancelBtn);
|
|
lv_label_set_text(cancelLbl, "Abbrechen");
|
|
lv_obj_center(cancelLbl);
|
|
|
|
lv_obj_t* connectBtn = lv_btn_create(passwordDialog_);
|
|
lv_obj_set_size(connectBtn, 150, 50);
|
|
lv_obj_align(connectBtn, LV_ALIGN_TOP_RIGHT, -20, 150);
|
|
lv_obj_set_style_bg_color(connectBtn, lv_color_hex(0x408040), 0);
|
|
//lv_obj_add_event_cb(connectBtn, onConnectClick, LV_EVENT_CLICKED, nullptr);
|
|
|
|
lv_obj_t* connectLbl = lv_label_create(connectBtn);
|
|
lv_label_set_text(connectLbl, "Verbinden");
|
|
lv_obj_center(connectLbl);
|
|
|
|
keyboard_ = lv_keyboard_create(passwordDialog_);
|
|
lv_obj_set_size(keyboard_, LV_PCT(100), 300);
|
|
lv_obj_align(keyboard_, LV_ALIGN_BOTTOM_MID, 0, 0);
|
|
lv_keyboard_set_textarea(keyboard_, passwordInput_);
|
|
//lv_obj_add_event_cb(keyboard_, onKeyboardReady, LV_EVENT_READY, nullptr);
|
|
|
|
ESP_LOGI(TAG, "Password dialog created");
|
|
}
|
|
|
|
void WifiSetting::hidePasswordDialog() {
|
|
if (passwordDialog_) {
|
|
lv_obj_del(passwordDialog_);
|
|
passwordDialog_ = nullptr;
|
|
passwordInput_ = nullptr;
|
|
keyboard_ = nullptr;
|
|
}
|
|
selectedSSID_.clear();
|
|
}
|
|
|
|
void WifiSetting::onCloseClick(lv_event_t* e) {
|
|
(void)e;
|
|
WifiSetting::instance().hide();
|
|
}
|
|
|
|
void WifiSetting::onNetworkSelect(lv_event_t* e) {
|
|
lv_obj_t* btn = (lv_obj_t*)lv_event_get_target(e);
|
|
char* ssid = (char*)lv_obj_get_user_data(btn);
|
|
if (ssid) {
|
|
ESP_LOGI(TAG, "Selected network: %s", ssid);
|
|
WifiSetting::instance().showPasswordDialog(ssid);
|
|
}
|
|
}
|
|
|
|
void WifiSetting::onScanClick(lv_event_t* e) {
|
|
(void)e;
|
|
WifiSetting::instance().refreshNetworkList();
|
|
}
|
|
|
|
void WifiSetting::onDisconnectClick(lv_event_t* e) {
|
|
(void)e;
|
|
Wifi::instance().disconnect();
|
|
WifiSetting::instance().updateStatusDisplay();
|
|
}
|
|
|
|
void WifiSetting::onConnectClick(lv_event_t* e) {
|
|
(void)e;
|
|
WifiSetting& settings = WifiSetting::instance();
|
|
|
|
if (settings.passwordInput_ && !settings.selectedSSID_.empty()) {
|
|
const char* password = lv_textarea_get_text(settings.passwordInput_);
|
|
|
|
ESP_LOGI(TAG, "Connecting to %s", settings.selectedSSID_.c_str());
|
|
|
|
Wifi::instance().connect(settings.selectedSSID_.c_str(), password);
|
|
Wifi::instance().saveNetwork(settings.selectedSSID_.c_str(), password);
|
|
|
|
settings.hidePasswordDialog();
|
|
settings.refreshSavedNetworks();
|
|
}
|
|
}
|
|
|
|
void WifiSetting::onCancelClick(lv_event_t* e) {
|
|
(void)e;
|
|
WifiSetting::instance().hidePasswordDialog();
|
|
}
|
|
|
|
void WifiSetting::onDeleteSavedClick(lv_event_t* e) {
|
|
lv_obj_t* btn = (lv_obj_t*)lv_event_get_target(e);
|
|
char* ssid = (char*)lv_obj_get_user_data(btn);
|
|
if (ssid) {
|
|
ESP_LOGI(TAG, "Deleting saved network: %s", ssid);
|
|
Wifi::instance().removeNetwork(ssid);
|
|
lv_free(ssid);
|
|
WifiSetting::instance().refreshSavedNetworks();
|
|
}
|
|
}
|
|
|
|
void WifiSetting::onKeyboardReady(lv_event_t* e) {
|
|
(void)e;
|
|
onConnectClick(nullptr);
|
|
}
|