From 02d973f8b1ec31f58247a93ba0d0caebb6fdbc01 Mon Sep 17 00:00:00 2001 From: Thomas Bittner Date: Tue, 15 Aug 2023 23:11:25 +0200 Subject: [PATCH] Updated user interface with wifi settings page --- Platformio/HAL/HardwareAbstract.cpp | 24 +- Platformio/HAL/HardwareAbstract.hpp | 12 + Platformio/HAL/Targets/ESP32/HardwareRevX.hpp | 4 +- .../Targets/ESP32/wifiHandler/wifihandler.cpp | 10 - .../Targets/ESP32/wifiHandler/wifihandler.hpp | 16 - Platformio/OmoteUI/OmoteUI.cpp | 422 ++++++++---------- Platformio/OmoteUI/OmoteUI.hpp | 175 +++++++- Platformio/OmoteUI/displaySettings.cpp | 56 +++ Platformio/OmoteUI/wifiSettings.cpp | 171 +++++++ 9 files changed, 613 insertions(+), 277 deletions(-) create mode 100644 Platformio/OmoteUI/displaySettings.cpp create mode 100644 Platformio/OmoteUI/wifiSettings.cpp diff --git a/Platformio/HAL/HardwareAbstract.cpp b/Platformio/HAL/HardwareAbstract.cpp index 0de7a1b..7752d9c 100644 --- a/Platformio/HAL/HardwareAbstract.cpp +++ b/Platformio/HAL/HardwareAbstract.cpp @@ -23,4 +23,26 @@ std::optional HardwareAbstract::getBatteryStatu void HardwareAbstract::onBatteryChange(std::function onBatteryStatusChangeHandler){ mBatteryNotification.onNotify(std::move(onBatteryStatusChangeHandler)); -} \ No newline at end of file +} + +void HardwareAbstract::onStartWifiScan(std::function cb_func){ + this->wifi_scan_start_cb.push_back(cb_func); +} + +void HardwareAbstract::onWifiScanDone(std::function>)> cb_func){ + this->wifi_scan_done_cb.push_back(cb_func); +} + +void HardwareAbstract::notifyStartWifiScan(){ + for (std::function cb_func:this->wifi_scan_start_cb) + { + cb_func(); + } +} + +void HardwareAbstract::notifyWifiScanDone(std::shared_ptr> info){ + for (std::function>)> cb_func: this->wifi_scan_done_cb) + { + cb_func(info); + } +} diff --git a/Platformio/HAL/HardwareAbstract.hpp b/Platformio/HAL/HardwareAbstract.hpp index 32a32e4..e1ebc84 100644 --- a/Platformio/HAL/HardwareAbstract.hpp +++ b/Platformio/HAL/HardwareAbstract.hpp @@ -13,6 +13,11 @@ #include "wifiHandlerInterface.h" #include "Notification.hpp" +typedef struct { + std::string ssid; + int rssi; +} WifiInfo; + class HardwareAbstract { public: HardwareAbstract( @@ -35,6 +40,11 @@ public: /// @param onBatteryStatusChangeHandler - Callable to be ran when batter status changes void onBatteryChange(std::function onBatteryStatusChangeHandler); + void onStartWifiScan(std::function cb_func); + void onWifiScanDone(std::function>)> cb_func); + void notifyStartWifiScan(); + void notifyWifiScanDone(std::shared_ptr> info); + /// @brief Override in order to do setup of hardware devices virtual void init() = 0; @@ -46,6 +56,8 @@ public: Notification mBatteryNotification; private: + std::vector> wifi_scan_start_cb; + std::vector>)>> wifi_scan_done_cb; std::shared_ptr mBattery; std::shared_ptr mWifiHandler; std::shared_ptr mDisplay; diff --git a/Platformio/HAL/Targets/ESP32/HardwareRevX.hpp b/Platformio/HAL/Targets/ESP32/HardwareRevX.hpp index cfd9bc9..82417b9 100644 --- a/Platformio/HAL/Targets/ESP32/HardwareRevX.hpp +++ b/Platformio/HAL/Targets/ESP32/HardwareRevX.hpp @@ -17,6 +17,7 @@ #include "omoteconfig.h" + class HardwareRevX : public HardwareAbstract { public: enum class WakeReason { RESET, IMU, KEYPAD }; @@ -70,9 +71,6 @@ private: IRrecv IrReceiver = IRrecv(IR_RX); - - lv_color_t color_primary = lv_color_hex(0x303030); // gray - // Keypad declarations static const byte ROWS = 5; // four rows static const byte COLS = 5; // four columns diff --git a/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.cpp b/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.cpp index e75bbec..7e32afb 100644 --- a/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.cpp +++ b/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.cpp @@ -51,16 +51,6 @@ std::shared_ptr wifiHandler::getInstance() return std::shared_ptr(new wifiHandler()); }; -String wifiHandler::getFoundSSID(unsigned int index) -{ - return WiFi.SSID(index); -} - -int wifiHandler::getFoundRSSI(unsigned int index) -{ - return WiFi.RSSI(index); -} - wifiHandler::wifiHandler() { this->password[0] = '\0'; diff --git a/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.hpp b/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.hpp index 11748a9..02c6eef 100644 --- a/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.hpp +++ b/Platformio/HAL/Targets/ESP32/wifiHandler/wifihandler.hpp @@ -27,22 +27,6 @@ class wifiHandler: public wifiHandlerInterface { */ void disconnect(); - /** - * @brief Get the SSID of the found wifi - * - * @param index index of the found wifi - * @return String SSID of the wifi - */ - String getFoundSSID(unsigned int index); - - /** - * @brief Get the RSSI of the found wifi - * - * @param index index of the found wifi - * @return int RSSI value of the found wifi - */ - int getFoundRSSI(unsigned int index); - /** * @brief Function to determine wether or not we are connected to a network * diff --git a/Platformio/OmoteUI/OmoteUI.cpp b/Platformio/OmoteUI/OmoteUI.cpp index fcd1bd8..f8376ca 100644 --- a/Platformio/OmoteUI/OmoteUI.cpp +++ b/Platformio/OmoteUI/OmoteUI.cpp @@ -90,39 +90,137 @@ void OmoteUI::loopHandler(){ lv_timer_handler(); } +void OmoteUI::create_status_bar(){ + // Create a status bar + lv_obj_t* statusbar = lv_btn_create(lv_scr_act()); + lv_obj_set_size(statusbar, 240, 20); + lv_obj_set_style_shadow_width(statusbar, 0, LV_PART_MAIN); + lv_obj_set_style_bg_color(statusbar, lv_color_black(), LV_PART_MAIN); + lv_obj_set_style_radius(statusbar, 0, LV_PART_MAIN); + lv_obj_align(statusbar, LV_ALIGN_TOP_MID, 0, 0); + + this->WifiLabel = lv_label_create(statusbar); + lv_label_set_text(this->WifiLabel, ""); + lv_obj_align(this->WifiLabel, LV_ALIGN_LEFT_MID, -8, 0); + lv_obj_set_style_text_font(this->WifiLabel, &lv_font_montserrat_12, LV_PART_MAIN); + + this->objBattPercentage = lv_label_create(statusbar); + lv_label_set_text(this->objBattPercentage, ""); + lv_obj_align(this->objBattPercentage, LV_ALIGN_RIGHT_MID, -16, 0); + lv_obj_set_style_text_font(this->objBattPercentage, &lv_font_montserrat_12, LV_PART_MAIN); + + this->objBattIcon = lv_label_create(statusbar); + lv_label_set_text(this->objBattIcon, LV_SYMBOL_BATTERY_EMPTY); + lv_obj_align(this->objBattIcon, LV_ALIGN_RIGHT_MID, 8, 0); + lv_obj_set_style_text_font(this->objBattIcon, &lv_font_montserrat_16, LV_PART_MAIN); +} + +void OmoteUI::setup_settings(lv_obj_t* parent) +{ + // Add content to the settings tab + // With a flex layout, setting groups/boxes will position themselves automatically + lv_obj_set_layout(parent, LV_LAYOUT_FLEX); + lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN); + lv_obj_set_scrollbar_mode(parent, LV_SCROLLBAR_MODE_ACTIVE); + // Add a label, then a box for the display settings + this->settingsMenu = lv_menu_create(parent); + lv_obj_set_width(this->settingsMenu, 210); + + /* Create main page for settings this->settingsMenu*/ + this->settingsMainPage = lv_menu_page_create(this->settingsMenu, NULL); + lv_obj_t* cont = lv_menu_cont_create(this->settingsMainPage); + lv_obj_set_layout(cont, LV_LAYOUT_FLEX); + lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN); + lv_obj_set_scrollbar_mode(cont, LV_SCROLLBAR_MODE_ACTIVE); + //lv_obj_set_width(cont, lv_obj_get_width(parent)); + this->display_settings(cont); + + this->create_wifi_settings(this->settingsMenu, cont); + + // Another setting for the battery + lv_obj_t* menuLabel = lv_label_create(cont); + lv_label_set_text(menuLabel, "Battery"); + lv_obj_t* menuBox = lv_obj_create(cont); + lv_obj_set_size(menuBox, lv_pct(100), 125); + lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN); + lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN); + + lv_menu_set_page(this->settingsMenu, this->settingsMainPage); +} + +void OmoteUI::ta_kb_event_cb(lv_event_t* e) +{ + lv_event_code_t code = lv_event_get_code(e); + lv_obj_t * ta = lv_event_get_target(e); + lv_obj_t * kb = (lv_obj_t*) lv_event_get_user_data(e); + switch(code){ + case LV_EVENT_FOCUSED: + lv_keyboard_set_textarea(kb, ta); + lv_obj_clear_flag(kb, LV_OBJ_FLAG_HIDDEN); + lv_obj_move_foreground(kb); + break; + case LV_EVENT_DEFOCUSED: + lv_keyboard_set_textarea(kb, NULL); + lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN); + break; + default: + break; + } +} + +void OmoteUI::create_keyboard() +{ + this->kb = lv_keyboard_create(lv_scr_act()); + lv_obj_add_flag(this->kb, LV_OBJ_FLAG_HIDDEN); + lv_obj_set_y(this->kb, 0); +} + +void OmoteUI::hide_keyboard() +{ + lv_obj_add_flag(this->kb, LV_OBJ_FLAG_HIDDEN); +} + +void OmoteUI::reset_settings_menu() +{ + lv_menu_set_page(this->settingsMenu, this->settingsMainPage); +} + +void OmoteUI::attach_keyboard(lv_obj_t* textarea) +{ + if (this->kb == NULL) + { + this->create_keyboard(); + } + lv_keyboard_set_textarea(this->kb, textarea); + lv_obj_add_event_cb(textarea, [] (lv_event_t* e) {mInstance->ta_kb_event_cb(e);}, LV_EVENT_FOCUSED, this->kb); + lv_obj_add_event_cb(textarea, [] (lv_event_t* e) {mInstance->ta_kb_event_cb(e);}, LV_EVENT_DEFOCUSED, this->kb); +} + void OmoteUI::layout_UI() { - // --- LVGL UI Configuration --- - - // Set the background color +// Set the background color lv_obj_set_style_bg_color(lv_scr_act(), lv_color_black(), LV_PART_MAIN); - + this->create_keyboard(); // Setup a scrollable tabview for devices and settings - lv_obj_t *tabview; - tabview = - lv_tabview_create(lv_scr_act(), LV_DIR_TOP, - 0); // Hide tab labels by setting their height to 0 + lv_obj_t* tabview; + tabview = lv_tabview_create(lv_scr_act(), LV_DIR_TOP, 0); // Hide tab labels by setting their height to 0 lv_obj_set_style_bg_color(tabview, lv_color_black(), LV_PART_MAIN); - lv_obj_set_size(tabview, SCREEN_WIDTH, - 270); // 270 = screenHeight(320) - panel(30) - statusbar(20) + lv_obj_set_size(tabview, SCREEN_WIDTH, 270); // 270 = screenHeight(320) - panel(30) - statusbar(20) lv_obj_align(tabview, LV_ALIGN_TOP_MID, 0, 20); // Add 4 tabs (names are irrelevant since the labels are hidden) - lv_obj_t *tab1 = lv_tabview_add_tab(tabview, "Settings"); - lv_obj_t *tab2 = lv_tabview_add_tab(tabview, "Technisat"); - lv_obj_t *tab3 = lv_tabview_add_tab(tabview, "Apple TV"); - lv_obj_t *tab4 = lv_tabview_add_tab(tabview, "Smart Home"); + lv_obj_t* tab1 = lv_tabview_add_tab(tabview, "Settings"); + lv_obj_t* tab2 = lv_tabview_add_tab(tabview, "Technisat"); + lv_obj_t* tab3 = lv_tabview_add_tab(tabview, "Apple TV"); + lv_obj_t* tab4 = lv_tabview_add_tab(tabview, "Smart Home"); - // Configure number button grid - static lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), - LV_GRID_TEMPLATE_LAST}; // equal x distribution - static lv_coord_t row_dsc[] = { - 52, 52, 52, 52, LV_GRID_TEMPLATE_LAST}; // manual y distribution to - // compress the grid a bit + // Configure number button grid + static lv_coord_t col_dsc[] = { LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST }; // equal x distribution + static lv_coord_t row_dsc[] = { 52, 52, 52, 52, LV_GRID_TEMPLATE_LAST }; // manual y distribution to compress the grid a bit // Create a container with grid for tab2 lv_obj_set_style_pad_all(tab2, 0, LV_PART_MAIN); - lv_obj_t *cont = lv_obj_create(tab2); + lv_obj_t* cont = lv_obj_create(tab2); lv_obj_set_style_shadow_width(cont, 0, LV_PART_MAIN); lv_obj_set_style_bg_color(cont, lv_color_black(), LV_PART_MAIN); lv_obj_set_style_border_width(cont, 0, LV_PART_MAIN); @@ -133,64 +231,50 @@ void OmoteUI::layout_UI() { lv_obj_align(cont, LV_ALIGN_TOP_MID, 0, 0); lv_obj_set_style_radius(cont, 0, LV_PART_MAIN); - lv_obj_t *buttonLabel; - lv_obj_t *obj; + lv_obj_t* buttonLabel; + lv_obj_t* obj; - // Iterate through grid buttons and configure them + // Iterate through grid buttons configure them for (int i = 0; i < 12; i++) { uint8_t col = i % 3; uint8_t row = i / 3; // Create the button object - if ((row == 3) && ((col == 0) || (col == 2))) - continue; // Do not create a complete fourth row, only a 0 button + if ((row == 3) && ((col == 0) || (col == 2))) continue; // Do not create a complete fourth row, only a 0 button obj = lv_btn_create(cont); - lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1, - LV_GRID_ALIGN_STRETCH, row, 1); - lv_obj_set_style_bg_color(obj, color_primary, LV_PART_MAIN); + lv_obj_set_grid_cell(obj, LV_GRID_ALIGN_STRETCH, col, 1, LV_GRID_ALIGN_STRETCH, row, 1); + lv_obj_set_style_bg_color(obj, this->color_primary, LV_PART_MAIN); lv_obj_set_style_radius(obj, 14, LV_PART_MAIN); - lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE); // Clicking a button causes - // a event in its container + lv_obj_set_style_shadow_color(obj, lv_color_hex(0x404040), LV_PART_MAIN); + lv_obj_add_flag(obj, LV_OBJ_FLAG_EVENT_BUBBLE); // Clicking a button causes a event in its container // Create Labels for each button - buttonLabel = lv_label_create(obj); - if (i < 9) { - lv_label_set_text_fmt(buttonLabel, std::to_string(i + 1).c_str(), col, - row); - lv_obj_set_user_data(obj, - (void *)i); // Add user data so we can identify which - // button caused the container event - } else { - lv_label_set_text_fmt(buttonLabel, "0", col, row); - lv_obj_set_user_data(obj, (void *)9); + buttonLabel = lv_label_create(obj); + if(i < 9){ + lv_label_set_text_fmt(buttonLabel, std::to_string(i+1).c_str(), col, row); + lv_obj_set_user_data(obj, (void*)i); // Add user data so we can identify which button caused the container event } - lv_obj_set_style_text_font(buttonLabel, &lv_font_montserrat_24, - LV_PART_MAIN); + else{ + lv_label_set_text_fmt(buttonLabel, "0", col, row); + lv_obj_set_user_data(obj, (void*)9); + } + lv_obj_set_style_text_font(buttonLabel, &lv_font_montserrat_24, LV_PART_MAIN); lv_obj_center(buttonLabel); } // Create a shared event for all button inside container - lv_obj_add_event_cb( - cont, [](lv_event_t *e) { mInstance->virtualKeypad_event_cb(e); }, - LV_EVENT_CLICKED, NULL); + lv_obj_add_event_cb(cont, [] (lv_event_t* e) {mInstance->virtualKeypad_event_cb(e);}, LV_EVENT_CLICKED, NULL); + // Add content to the Apple TV tab (3) // Add a nice apple tv logo - lv_obj_t* appleImg = imgs.addAppleTVIcon(tab3); - lv_obj_align(appleImg, LV_ALIGN_CENTER, 0, -60); - // create two buttons and add their icons accordingly - lv_obj_t *button = lv_btn_create(tab3); + lv_obj_t* button = lv_btn_create(tab3); lv_obj_align(button, LV_ALIGN_BOTTOM_LEFT, 10, 0); lv_obj_set_size(button, 60, 60); lv_obj_set_style_radius(button, 30, LV_PART_MAIN); lv_obj_set_style_bg_color(button, color_primary, LV_PART_MAIN); - lv_obj_add_event_cb( - button, [](lv_event_t *e) { mInstance->appleKey_event_cb(e); }, - LV_EVENT_CLICKED, (void *)1); + lv_obj_add_event_cb(button, [] (lv_event_t* e) {mInstance->appleKey_event_cb(e);}, LV_EVENT_CLICKED, (void*)1); - appleImg = imgs.addAppleBackIcon(button); - lv_obj_align(appleImg, LV_ALIGN_CENTER, -3, 0); - lv_obj_set_style_img_recolor(appleImg, lv_color_white(), LV_PART_MAIN); - lv_obj_set_style_img_recolor_opa(appleImg, LV_OPA_COVER, LV_PART_MAIN); + appleImg = imgs.addAppleDisplayImage(button); lv_obj_align(appleImg, LV_ALIGN_CENTER, -3, 0); button = lv_btn_create(tab3); @@ -198,172 +282,54 @@ void OmoteUI::layout_UI() { lv_obj_set_size(button, 60, 60); lv_obj_set_style_radius(button, 30, LV_PART_MAIN); lv_obj_set_style_bg_color(button, color_primary, LV_PART_MAIN); - lv_obj_add_event_cb( - button, [](lv_event_t *e) { mInstance->appleKey_event_cb(e); }, - LV_EVENT_CLICKED, (void *)2); + lv_obj_add_event_cb(button, [] (lv_event_t* e) {mInstance->appleKey_event_cb(e);}, LV_EVENT_CLICKED, (void*)2); appleImg = imgs.addAppleDisplayImage(button); lv_obj_align(appleImg, LV_ALIGN_CENTER, 0, 0); - lv_obj_set_style_img_recolor(appleImg, lv_color_white(), LV_PART_MAIN); - lv_obj_set_style_img_recolor_opa(appleImg, LV_OPA_COVER, LV_PART_MAIN); - lv_obj_align(appleImg, LV_ALIGN_CENTER, 0, 0); - // Add content to the settings tab - // With a flex layout, setting groups/boxes will position themselves - // automatically - lv_obj_set_layout(tab1, LV_LAYOUT_FLEX); - lv_obj_set_flex_flow(tab1, LV_FLEX_FLOW_COLUMN); - lv_obj_set_scrollbar_mode(tab1, LV_SCROLLBAR_MODE_ACTIVE); - - - // Add a label, then a box for the display settings - lv_obj_t *menuLabel = lv_label_create(tab1); - lv_label_set_text(menuLabel, "Display"); - - lv_obj_t *menuBox = lv_obj_create(tab1); - lv_obj_set_size(menuBox, lv_pct(100), 109); - lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN); - lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN); - - lv_obj_t *brightnessIcon = imgs.addLowBrightnessIcon(menuBox); - lv_obj_align(brightnessIcon, LV_ALIGN_TOP_LEFT, 0, 0); - - lv_obj_t *slider = lv_slider_create(menuBox); - lv_slider_set_range(slider, 60, 255); - lv_obj_set_style_bg_color(slider, lv_color_white(), LV_PART_KNOB); - lv_obj_set_style_bg_opa(slider, LV_OPA_COVER, LV_PART_MAIN); - lv_obj_set_style_bg_color(slider, lv_color_lighten(color_primary, 50), - LV_PART_MAIN); - lv_slider_set_value(slider, backlight_brightness, LV_ANIM_OFF); - lv_obj_set_size(slider, lv_pct(66), 10); - lv_obj_align(slider, LV_ALIGN_TOP_MID, 0, 3); - - brightnessIcon = imgs.addHighBrightnessIcon(menuBox); - lv_obj_align(brightnessIcon, LV_ALIGN_TOP_RIGHT, 0, -1); - - lv_obj_add_event_cb( - slider, [](lv_event_t *e) { mInstance->bl_slider_event_cb(e); }, - LV_EVENT_VALUE_CHANGED, NULL); - - menuLabel = lv_label_create(menuBox); - lv_label_set_text(menuLabel, "Lift to Wake"); - lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 0, 32); - lv_obj_t *wakeToggle = lv_switch_create(menuBox); - lv_obj_set_size(wakeToggle, 40, 22); - lv_obj_align(wakeToggle, LV_ALIGN_TOP_RIGHT, 0, 29); - lv_obj_set_style_bg_color(wakeToggle, lv_color_lighten(color_primary, 50), - LV_PART_MAIN); - lv_obj_add_event_cb( - wakeToggle, - [](lv_event_t *e) { mInstance->WakeEnableSetting_event_cb(e); }, - LV_EVENT_VALUE_CHANGED, NULL); - if (wakeupByIMUEnabled) - lv_obj_add_state(wakeToggle, LV_STATE_CHECKED); // set default state - - menuLabel = lv_label_create(menuBox); - lv_label_set_text(menuLabel, "Timeout"); - lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 0, 64); - lv_obj_t *drop = lv_dropdown_create(menuBox); - lv_dropdown_set_options(drop, "10s\n" - "30s\n" - "1m\n" - "3m"); - lv_obj_align(drop, LV_ALIGN_TOP_RIGHT, 0, 61); - lv_obj_set_size(drop, 70, 22); - lv_obj_set_style_pad_top(drop, 1, LV_PART_MAIN); - lv_obj_set_style_bg_color(drop, color_primary, LV_PART_MAIN); - lv_obj_set_style_border_width(drop, 0, LV_PART_MAIN); - lv_obj_set_style_bg_color(lv_dropdown_get_list(drop), color_primary, - LV_PART_MAIN); - lv_obj_set_style_border_width(lv_dropdown_get_list(drop), 1, LV_PART_MAIN); - lv_obj_set_style_border_color(lv_dropdown_get_list(drop), - lv_color_darken(color_primary, 40), - LV_PART_MAIN); - - // Add another label, then a settings box for WiFi - menuLabel = lv_label_create(tab1); - lv_label_set_text(menuLabel, "Wi-Fi"); - menuBox = lv_obj_create(tab1); - lv_obj_set_size(menuBox, lv_pct(100), 80); - lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN); - lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN); - menuLabel = lv_label_create(menuBox); - lv_label_set_text(menuLabel, "Network"); - menuLabel = lv_label_create(menuBox); - lv_label_set_text(menuLabel, LV_SYMBOL_RIGHT); - lv_obj_align(menuLabel, LV_ALIGN_TOP_RIGHT, 0, 0); - menuLabel = lv_label_create(menuBox); - lv_label_set_text(menuLabel, "Password"); - lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 0, 32); - menuLabel = lv_label_create(menuBox); - lv_label_set_text(menuLabel, LV_SYMBOL_RIGHT); - lv_obj_align(menuLabel, LV_ALIGN_TOP_RIGHT, 0, 32); - - // Another setting for the battery - menuLabel = lv_label_create(tab1); - lv_label_set_text(menuLabel, "Battery"); - menuBox = lv_obj_create(tab1); - lv_obj_set_size(menuBox, lv_pct(100), 125); - lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN); - lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN); - - mHardware->onBatteryChange([menuLabel](HardwareAbstract::batteryStatus aCurrentBattery){ - // I dont know enough about lvgl to do this but basically take aCurrentBattery and update UI elements here. - // See Notice menuLabel is captured and useable here. - }); + this->setup_settings(tab1); // Add content to the smart home tab (4) - lv_obj_set_layout(tab4, LV_LAYOUT_FLEX); lv_obj_set_flex_flow(tab4, LV_FLEX_FLOW_COLUMN); lv_obj_set_scrollbar_mode(tab4, LV_SCROLLBAR_MODE_ACTIVE); // Add a label, then a box for the light controls - menuLabel = lv_label_create(tab4); + lv_obj_t* menuLabel = lv_label_create(tab4); lv_label_set_text(menuLabel, "Living Room"); - menuBox = lv_obj_create(tab4); + lv_obj_t* menuBox = lv_obj_create(tab4); lv_obj_set_size(menuBox, lv_pct(100), 79); lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN); lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN); - lv_obj_t *bulbIcon = imgs.addLightBulbIcon(menuBox); + lv_obj_t* bulbIcon = imgs.addLightBulbIcon(menuBox); lv_obj_align(bulbIcon, LV_ALIGN_TOP_LEFT, 0, 0); menuLabel = lv_label_create(menuBox); lv_label_set_text(menuLabel, "Floor Lamp"); lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 22, 3); - lv_obj_t *lightToggleA = lv_switch_create(menuBox); + lv_obj_t* lightToggleA = lv_switch_create(menuBox); lv_obj_set_size(lightToggleA, 40, 22); lv_obj_align(lightToggleA, LV_ALIGN_TOP_RIGHT, 0, 0); - lv_obj_set_style_bg_color(lightToggleA, lv_color_lighten(color_primary, 50), - LV_PART_MAIN); + lv_obj_set_style_bg_color(lightToggleA, lv_color_lighten(color_primary, 50), LV_PART_MAIN); lv_obj_set_style_bg_color(lightToggleA, color_primary, LV_PART_INDICATOR); - lv_obj_add_event_cb( - lightToggleA, - [](lv_event_t *e) { mInstance->smartHomeToggle_event_cb(e); }, - LV_EVENT_VALUE_CHANGED, (void *)1); + lv_obj_add_event_cb(lightToggleA, [] (lv_event_t* e) {mInstance->smartHomeToggle_event_cb(e);}, LV_EVENT_VALUE_CHANGED, (void*)1); - slider = lv_slider_create(menuBox); - lv_slider_set_range(slider, 60, 255); - lv_obj_set_style_bg_color(slider, lv_color_lighten(lv_color_black(), 30), - LV_PART_INDICATOR); - lv_obj_set_style_bg_grad_color( - slider, lv_color_lighten(lv_palette_main(LV_PALETTE_AMBER), 180), - LV_PART_INDICATOR); + lv_obj_t *slider = lv_slider_create(menuBox); + lv_slider_set_range(slider, 0, 100); + lv_obj_set_style_bg_color(slider, lv_color_lighten(lv_color_black(), 30), LV_PART_INDICATOR); + lv_obj_set_style_bg_grad_color(slider, lv_color_lighten(lv_palette_main(LV_PALETTE_AMBER), 180), LV_PART_INDICATOR); lv_obj_set_style_bg_grad_dir(slider, LV_GRAD_DIR_HOR, LV_PART_INDICATOR); lv_obj_set_style_bg_color(slider, lv_color_white(), LV_PART_KNOB); lv_obj_set_style_bg_opa(slider, 255, LV_PART_MAIN); - lv_obj_set_style_bg_color(slider, lv_color_lighten(color_primary, 50), - LV_PART_MAIN); + lv_obj_set_style_bg_color(slider, lv_color_lighten(color_primary, 50), LV_PART_MAIN); lv_slider_set_value(slider, 255, LV_ANIM_OFF); lv_obj_set_size(slider, lv_pct(90), 10); lv_obj_align(slider, LV_ALIGN_TOP_MID, 0, 37); - lv_obj_add_event_cb( - slider, [](lv_event_t *e) { mInstance->smartHomeSlider_event_cb(e); }, - LV_EVENT_VALUE_CHANGED, (void *)1); + lv_obj_add_event_cb(slider, [] (lv_event_t* e) {mInstance->smartHomeSlider_event_cb(e);}, LV_EVENT_VALUE_CHANGED, (void*)1); - // Add another menu box for a second appliance + // Add another this->settingsMenu box for a second appliance menuBox = lv_obj_create(tab4); lv_obj_set_size(menuBox, lv_pct(100), 79); lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN); @@ -375,35 +341,26 @@ void OmoteUI::layout_UI() { menuLabel = lv_label_create(menuBox); lv_label_set_text(menuLabel, "Ceiling Light"); lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 22, 3); - lv_obj_t *lightToggleB = lv_switch_create(menuBox); + lv_obj_t* lightToggleB = lv_switch_create(menuBox); lv_obj_set_size(lightToggleB, 40, 22); lv_obj_align(lightToggleB, LV_ALIGN_TOP_RIGHT, 0, 0); - lv_obj_set_style_bg_color(lightToggleB, lv_color_lighten(color_primary, 50), - LV_PART_MAIN); + lv_obj_set_style_bg_color(lightToggleB, lv_color_lighten(color_primary, 50), LV_PART_MAIN); lv_obj_set_style_bg_color(lightToggleB, color_primary, LV_PART_INDICATOR); - lv_obj_add_event_cb( - lightToggleB, - [](lv_event_t *e) { mInstance->smartHomeToggle_event_cb(e); }, - LV_EVENT_VALUE_CHANGED, (void *)2); + lv_obj_add_event_cb(lightToggleB, [] (lv_event_t* e) {mInstance->smartHomeToggle_event_cb(e);}, LV_EVENT_VALUE_CHANGED, (void*)2); slider = lv_slider_create(menuBox); - lv_slider_set_range(slider, 60, 255); - lv_obj_set_style_bg_color(slider, lv_color_lighten(lv_color_black(), 30), - LV_PART_INDICATOR); - lv_obj_set_style_bg_grad_color( - slider, lv_color_lighten(lv_palette_main(LV_PALETTE_AMBER), 180), - LV_PART_INDICATOR); + lv_slider_set_range(slider, 0, 100); + lv_obj_set_style_bg_color(slider, lv_color_lighten(lv_color_black(), 30), LV_PART_INDICATOR); + lv_obj_set_style_bg_grad_color(slider, lv_color_lighten(lv_palette_main(LV_PALETTE_AMBER), 180), LV_PART_INDICATOR); lv_obj_set_style_bg_grad_dir(slider, LV_GRAD_DIR_HOR, LV_PART_INDICATOR); lv_obj_set_style_bg_color(slider, lv_color_white(), LV_PART_KNOB); lv_obj_set_style_bg_opa(slider, 255, LV_PART_MAIN); - lv_obj_set_style_bg_color(slider, lv_color_lighten(color_primary, 50), - LV_PART_MAIN); + lv_obj_set_style_bg_color(slider, lv_color_lighten(color_primary, 50), LV_PART_MAIN); lv_slider_set_value(slider, 255, LV_ANIM_OFF); lv_obj_set_size(slider, lv_pct(90), 10); lv_obj_align(slider, LV_ALIGN_TOP_MID, 0, 37); - lv_obj_add_event_cb( - slider, [](lv_event_t *e) { mInstance->smartHomeSlider_event_cb(e); }, - LV_EVENT_VALUE_CHANGED, (void *)2); + lv_obj_add_event_cb(slider, [] (lv_event_t* e) {mInstance->smartHomeSlider_event_cb(e);}, LV_EVENT_VALUE_CHANGED, (void*)2); + // Add another room (empty for now) menuLabel = lv_label_create(tab4); @@ -414,19 +371,20 @@ void OmoteUI::layout_UI() { lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN); lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN); + // Set current page according to the current Device - lv_tabview_set_act(tabview, currentDevice, LV_ANIM_OFF); + lv_tabview_set_act(tabview, 0, LV_ANIM_OFF); + // Create a page indicator panel = lv_obj_create(lv_scr_act()); - lv_obj_clear_flag( - panel, LV_OBJ_FLAG_CLICKABLE); // this indicator will not be clickable + lv_obj_clear_flag(panel, LV_OBJ_FLAG_CLICKABLE); // This indicator will not be clickable lv_obj_set_size(panel, SCREEN_WIDTH, 30); lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_ROW); lv_obj_align(panel, LV_ALIGN_BOTTOM_MID, 0, 0); lv_obj_set_scrollbar_mode(panel, LV_SCROLLBAR_MODE_OFF); // This small hidden button enables the page indicator to scroll further - lv_obj_t *btn = lv_btn_create(panel); + lv_obj_t* btn = lv_btn_create(panel); lv_obj_set_size(btn, 50, lv_pct(100)); lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN); lv_obj_set_style_opa(btn, LV_OPA_TRANSP, LV_PART_MAIN); @@ -434,7 +392,7 @@ void OmoteUI::layout_UI() { btn = lv_btn_create(panel); lv_obj_clear_flag(btn, LV_OBJ_FLAG_CLICKABLE); lv_obj_set_size(btn, 150, lv_pct(100)); - lv_obj_t *label = lv_label_create(btn); + lv_obj_t* label = lv_label_create(btn); lv_label_set_text_fmt(label, "Settings"); lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN); @@ -471,15 +429,10 @@ void OmoteUI::layout_UI() { lv_obj_set_size(btn, 50, lv_pct(100)); lv_obj_set_style_shadow_width(btn, 0, LV_PART_MAIN); lv_obj_set_style_opa(btn, LV_OPA_TRANSP, LV_PART_MAIN); - + // Make the indicator scroll together with the tabs by creating a scroll event - lv_obj_add_event_cb( - lv_tabview_get_content(tabview), - [](lv_event_t *e) { mInstance->store_scroll_value_event_cb(e); }, - LV_EVENT_SCROLL, NULL); - lv_obj_add_event_cb( - tabview, [](lv_event_t *e) { mInstance->tabview_device_event_cb(e); }, - LV_EVENT_VALUE_CHANGED, NULL); + lv_obj_add_event_cb(lv_tabview_get_content(tabview), [] (lv_event_t* e) {mInstance->store_scroll_value_event_cb(e);}, LV_EVENT_SCROLL, NULL); + lv_obj_add_event_cb(tabview, [] (lv_event_t* e) {mInstance->tabview_device_event_cb(e);}, LV_EVENT_VALUE_CHANGED, NULL); // Initialize scroll position for the indicator lv_event_send(lv_tabview_get_content(tabview), LV_EVENT_SCROLL, NULL); @@ -492,35 +445,12 @@ void OmoteUI::layout_UI() { lv_obj_add_style(panel, &style_btn, 0); // Make the indicator fade out at the sides using gradient bitmaps - lv_obj_t *img1 = imgs.addLeftGradiant(lv_scr_act()); + lv_obj_t* img1 = imgs.addLeftGradiant(lv_scr_act()); lv_obj_align(img1, LV_ALIGN_BOTTOM_LEFT, 0, 0); lv_obj_set_size(img1, 30, 30); // stretch the 1-pixel high image to 30px - lv_obj_t* img2 = imgs.addRightGradiant(lv_scr_act()); lv_obj_align(img2, LV_ALIGN_BOTTOM_RIGHT, 0, 0); lv_obj_set_size(img2, 30, 30); - // Create a status bar - lv_obj_t *statusbar = lv_btn_create(lv_scr_act()); - lv_obj_set_size(statusbar, 240, 20); - lv_obj_set_style_shadow_width(statusbar, 0, LV_PART_MAIN); - lv_obj_set_style_bg_color(statusbar, lv_color_black(), LV_PART_MAIN); - lv_obj_set_style_radius(statusbar, 0, LV_PART_MAIN); - lv_obj_align(statusbar, LV_ALIGN_TOP_MID, 0, 0); - - lv_obj_t *WifiLabel = lv_label_create(statusbar); - lv_label_set_text(WifiLabel, LV_SYMBOL_WIFI); - lv_obj_align(WifiLabel, LV_ALIGN_LEFT_MID, -8, 0); - lv_obj_set_style_text_font(WifiLabel, &lv_font_montserrat_14, LV_PART_MAIN); - - lv_obj_t *objBattPercentage = lv_label_create(statusbar); - lv_label_set_text(objBattPercentage, ""); - lv_obj_align(objBattPercentage, LV_ALIGN_RIGHT_MID, -16, 0); - lv_obj_set_style_text_font(objBattPercentage, &lv_font_montserrat_14, - LV_PART_MAIN); - - lv_obj_t *objBattIcon = lv_label_create(statusbar); - lv_label_set_text(objBattIcon, LV_SYMBOL_BATTERY_EMPTY); - lv_obj_align(objBattIcon, LV_ALIGN_RIGHT_MID, 8, 0); - lv_obj_set_style_text_font(objBattIcon, &lv_font_montserrat_14, LV_PART_MAIN); + this->create_status_bar(); } diff --git a/Platformio/OmoteUI/OmoteUI.hpp b/Platformio/OmoteUI/OmoteUI.hpp index 1e5f300..912ad9b 100644 --- a/Platformio/OmoteUI/OmoteUI.hpp +++ b/Platformio/OmoteUI/OmoteUI.hpp @@ -46,23 +46,196 @@ public: void smartHomeSlider_event_cb(lv_event_t *e); // Virtual Keypad Event handler void virtualKeypad_event_cb(lv_event_t *e); + void wifi_settings_cb(lv_event_t* event); + void connect_btn_cb(lv_event_t* event); + + void password_field_event_cb(lv_event_t* e); // Use LVGL to layout the ui and register the callbacks void layout_UI(); + void ta_kb_event_cb(lv_event_t* e); + + void wifi_scan_done(std::shared_ptr> info); void loopHandler(); + /** + * @brief Function to hide the keyboard. If the keyboard is attached to a text area, it will be hidden when the + * text area is defocused. This function can be used if the keyboard need to be hidden due to some script event. + * + */ + void hide_keyboard(); + + /** + * @brief Function to show the keyboard. If a text area needs the keybaord, it should be attached to the text area + * using the approbiate function. The keyboard will then show up when the text area is focused. This function is + * needed if the keyboard should be shown due to some script or other trigger. + * + */ + void show_keyboard(); private: static std::shared_ptr mInstance; std::shared_ptr mHardware; + void reset_settings_menu(); + void attach_keyboard(lv_obj_t* textarea); + + /** + * @brief Keyboard object used whenever a keyboard is needed. + * + */ +lv_obj_t* kb; + +/** + * @brief Function to create the keyboard object which can then be attached to different text areas. + * + */ +void create_keyboard(); + + /** + * @brief Set the up settings object + * + * @param parent + */ + void setup_settings(lv_obj_t* parent); + + /** + * @brief LVGL Menu for settings pages as needed. + * + */ + lv_obj_t* settingsMenu; + + /** + * @brief Main page of the settings menu + * + */ + lv_obj_t* settingsMainPage; + + /** + * @brief Battery percentage label + * + */ + lv_obj_t* objBattPercentage; + + /** + * @brief Battery icon object in the status bar + * + */ + lv_obj_t* objBattIcon; + + void create_status_bar(); lv_obj_t *panel = nullptr; Images imgs = Images(); uint_fast8_t currentDevice = 4; - int backlight_brightness = 255; lv_color_t color_primary = lv_color_hex(0x303030); // gray bool wakeupByIMUEnabled = true; inline static const uint_fast8_t virtualKeyMapTechnisat[10] = { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x0}; + +/************************************** WIFI Settings Menu *******************************************************/ + /** + * @brief Container within the wifi selection page + */ + lv_obj_t* wifi_setting_cont; + + /** + * @brief Wifi settings entry point on the settings tab + * + */ + lv_obj_t* wifiOverview; + + /** + * @brief Label in the wifi password page. This label is updated with the selected SSID when the credentials for + * a wifi network is entered. + * + */ + lv_obj_t* wifi_password_label; + + /** + * @brief Menu Subpage for the wifi password + */ + lv_obj_t* wifi_password_page; + + /** + * @brief Menu Subpage for wifi selection + */ + lv_obj_t* wifi_selection_page; + + /** + * @brief Wifi Label shown in the top status bar + */ + lv_obj_t* WifiLabel; + + /** + * @brief Number of wifi subpage needed to display the found wifi networks + * + */ + unsigned int no_subpages; + + /** + * @brief number of wifi networks found + * + */ + unsigned int no_wifi_networks; + + + /** + * @brief callback function to get next wifi subpage. This callback can be used to get the next or previous page + * + * @param e lvgl event object + */ + void next_wifi_selection_subpage(lv_event_t* e); + + /** + * @brief Create a wifi selection sub page object + * + * @param menu LVGL Menu where the sub page should be added to + * @return lv_obj_t* Menu sub page object pointer + */ + lv_obj_t* create_wifi_selection_page(lv_obj_t* menu); + + /** + * @brief Method to create the wifi password sub page + * + * @param menu Menu where the sub page should be created + * @return lv_obj_t* menu sub page object pointer + */ + lv_obj_t* create_wifi_password_page(lv_obj_t* menu); + + /** + * @brief Method to create the wifi settings on the main page + * + * @param parent lv object parent where the main settings page should be added to + */ + void create_wifi_main_page(lv_obj_t* parent); + + /** + * @brief Method to create wifi settings. This method will call the create_wifi_selection_page, + * the create_wifi_password_page, and the create_wifi_main_page + * + * @param menu Settings menu where the sub pages should be added to + * @param parent lv object parent where the main settings page should be added to + */ + void create_wifi_settings(lv_obj_t* menu, lv_obj_t* parent); + + /** + * @brief Function to update the wifi selection sub page + * + * @param page index of the page to display + */ + void update_wifi_selection_subpage(int page); + +/************************************** Display settings menu ********************************************************/ + /** + * Variable to store the current backlight brightness level + */ + unsigned int backlight_brightness; + + /** + * @brief Function to create the display settings page. + * + * @param parent LVGL object acting as a parent for the display settings page + */ + void display_settings(lv_obj_t* parent); }; diff --git a/Platformio/OmoteUI/displaySettings.cpp b/Platformio/OmoteUI/displaySettings.cpp new file mode 100644 index 0000000..ffa421c --- /dev/null +++ b/Platformio/OmoteUI/displaySettings.cpp @@ -0,0 +1,56 @@ +#include "OmoteUI.hpp" + +void OmoteUI::display_settings(lv_obj_t* parent) +{ + + lv_obj_t* menuLabel = lv_label_create(parent); + lv_label_set_text(menuLabel, "Display"); + + lv_obj_t* menuBox = lv_obj_create(parent); + lv_obj_set_size(menuBox, lv_pct(100), 109); + lv_obj_set_style_bg_color(menuBox, color_primary, LV_PART_MAIN); + lv_obj_set_style_border_width(menuBox, 0, LV_PART_MAIN); + + lv_obj_t* brightnessIcon = imgs.addLowBrightnessIcon(menuBox); + lv_obj_align(brightnessIcon, LV_ALIGN_TOP_LEFT, 0, 0); + lv_obj_t* slider = lv_slider_create(menuBox); + lv_slider_set_range(slider, 30, 255); + lv_obj_set_style_bg_color(slider, lv_color_white(), LV_PART_KNOB); + lv_obj_set_style_bg_opa(slider, LV_OPA_COVER, LV_PART_MAIN); + lv_obj_set_style_bg_color(slider, lv_color_lighten(color_primary, 50), LV_PART_MAIN); + lv_slider_set_value(slider, this->backlight_brightness, LV_ANIM_OFF); + lv_obj_set_size(slider, lv_pct(66), 10); + lv_obj_align(slider, LV_ALIGN_TOP_MID, 0, 3); + brightnessIcon = imgs.addHighBrightnessIcon(menuBox); + lv_obj_align(brightnessIcon, LV_ALIGN_TOP_RIGHT, 0, -1); + lv_obj_add_event_cb(slider, [] (lv_event_t* e) {mInstance->bl_slider_event_cb(e);}, LV_EVENT_VALUE_CHANGED, &this->backlight_brightness); + + menuLabel = lv_label_create(menuBox); + lv_label_set_text(menuLabel, "Lift to Wake"); + lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 0, 32); + lv_obj_t* wakeToggle = lv_switch_create(menuBox); + lv_obj_set_size(wakeToggle, 40, 22); + lv_obj_align(wakeToggle, LV_ALIGN_TOP_RIGHT, 0, 29); + lv_obj_set_style_bg_color(wakeToggle, lv_color_hex(0x505050), LV_PART_MAIN); + lv_obj_add_event_cb(wakeToggle, [] (lv_event_t* e) {mInstance->WakeEnableSetting_event_cb(e);}, LV_EVENT_VALUE_CHANGED, NULL); + if(wakeupByIMUEnabled) lv_obj_add_state(wakeToggle, LV_STATE_CHECKED); // set default state + + menuLabel = lv_label_create(menuBox); + lv_label_set_text(menuLabel, "Timeout"); + lv_obj_align(menuLabel, LV_ALIGN_TOP_LEFT, 0, 64); + lv_obj_t* drop = lv_dropdown_create(menuBox); + lv_dropdown_set_options(drop, "10s\n" + "30s\n" + "1m\n" + "3m"); + lv_obj_align(drop, LV_ALIGN_TOP_RIGHT, 0, 61); + lv_obj_set_size(drop, 70, 22); + //lv_obj_set_style_text_font(drop, &lv_font_montserrat_12, LV_PART_MAIN); + //lv_obj_set_style_text_font(lv_dropdown_get_list(drop), &lv_font_montserrat_12, LV_PART_MAIN); + lv_obj_set_style_pad_top(drop, 1, LV_PART_MAIN); + lv_obj_set_style_bg_color(drop, color_primary, LV_PART_MAIN); + lv_obj_set_style_bg_color(lv_dropdown_get_list(drop), color_primary, LV_PART_MAIN); + lv_obj_set_style_border_width(lv_dropdown_get_list(drop), 1, LV_PART_MAIN); + lv_obj_set_style_border_color(lv_dropdown_get_list(drop), lv_color_hex(0x505050), LV_PART_MAIN); + +} \ No newline at end of file diff --git a/Platformio/OmoteUI/wifiSettings.cpp b/Platformio/OmoteUI/wifiSettings.cpp new file mode 100644 index 0000000..2745668 --- /dev/null +++ b/Platformio/OmoteUI/wifiSettings.cpp @@ -0,0 +1,171 @@ +#include "OmoteUI.hpp" + +lv_obj_t* OmoteUI::create_wifi_selection_page(lv_obj_t* menu) +{ + /* Create sub page for wifi*/ + lv_obj_t* subpage = lv_menu_page_create(menu, NULL); + this->wifi_setting_cont = lv_menu_cont_create(subpage); + lv_obj_set_layout(this->wifi_setting_cont, LV_LAYOUT_FLEX); + lv_obj_set_flex_flow(this->wifi_setting_cont, LV_FLEX_FLOW_COLUMN); + lv_obj_set_scrollbar_mode(this->wifi_setting_cont, LV_SCROLLBAR_MODE_ACTIVE); + + lv_obj_t* menuLabel = lv_label_create(this->wifi_setting_cont); + lv_label_set_text(menuLabel, "Searching for wifi networks"); + + + return subpage; +} + +/** + * @brief Callback function for the show password checkbox. Checking the box will show the password while unchecked the + * password will be shown as dots. + * + * @param e Pointer to event object for the event where this callback is called + */ +static void show_password_cb(lv_event_t* e) +{ + lv_obj_t* password_field = (lv_obj_t*) e->user_data; + if (lv_obj_has_state(e->target, LV_STATE_CHECKED)){ + lv_textarea_set_password_mode(password_field, false); + } + else{ + lv_textarea_set_password_mode(password_field, true); + } + +} + +/** + * @brief Textarea callback function for the password field. In case the enter key is pressed in the text area, the + * function will try to connect to the network with the provided password. + * + * @param e Pointer to event object for the event where this callback is called + */ +void OmoteUI::password_field_event_cb(lv_event_t* e) +{ + lv_event_code_t code = lv_event_get_code(e); + lv_obj_t * ta = lv_event_get_target(e); + lv_obj_t * kb = (lv_obj_t*) lv_event_get_user_data(e); + + const char* password = lv_textarea_get_text(ta); + switch(code){ + case LV_EVENT_READY: + //wifihandler.connect(ssid, password); + lv_obj_clear_state(ta, LV_STATE_FOCUSED); + this->hide_keyboard(); + this->reset_settings_menu(); + /* Fall through on purpose. Pressing enter should disable the keyboard as well*/ + default: + break; + + } +} + +/** + * @brief Callback which is triggered when clicking the connect button. It triggers the wifi connection. + * + * @param event Pointer to event object for the event where this callback is called + */ +void OmoteUI::connect_btn_cb(lv_event_t* event) +{ + lv_obj_t* ta = (lv_obj_t*) event->user_data; + const char* password = lv_textarea_get_text(ta); + +//Trigger wifi connection here + //wifihandler.connect(ssid, password); + lv_obj_clear_state(ta, LV_STATE_FOCUSED); + this->hide_keyboard(); + this->reset_settings_menu(); +} + +void OmoteUI::create_wifi_main_page(lv_obj_t* parent) +{ + lv_obj_t* menuLabel = lv_label_create(parent); + lv_label_set_text(menuLabel, "Wi-Fi"); + this->wifiOverview = lv_obj_create(parent); + lv_obj_set_size(this->wifiOverview, lv_pct(100), 80); + lv_obj_set_style_bg_color(this->wifiOverview, color_primary, LV_PART_MAIN); + lv_obj_set_style_border_width(this->wifiOverview, 0, LV_PART_MAIN); + menuLabel = lv_label_create(this->wifiOverview); + + lv_obj_t* arrow = lv_label_create(this->wifiOverview); + lv_label_set_text(arrow, LV_SYMBOL_RIGHT); + lv_obj_align(arrow, LV_ALIGN_TOP_RIGHT, 0, 0); + + lv_obj_t* ip_label = lv_label_create(this->wifiOverview); + lv_label_set_text(ip_label, "IP:"); + lv_obj_align(ip_label, LV_ALIGN_BOTTOM_LEFT, 0, 0); + + lv_obj_t* ip = lv_label_create(this->wifiOverview); + lv_obj_align(ip, LV_ALIGN_BOTTOM_RIGHT, 0, 0); + + lv_label_set_text(menuLabel, "Disconnected"); + lv_label_set_text(ip, "-"); + + lv_menu_set_load_page_event(this->settingsMenu, this->wifiOverview, this->wifi_selection_page); + lv_obj_add_event_cb(this->wifiOverview, [] (lv_event_t* e) {mInstance->wifi_settings_cb(e);}, LV_EVENT_CLICKED, this->wifi_setting_cont); +} + +void OmoteUI::wifi_scan_done(std::shared_ptr> info) +{ + for (WifiInfo i:*info) + { + mHardware->debugPrint(i.ssid); + } +} + +void OmoteUI::create_wifi_settings(lv_obj_t* menu, lv_obj_t* parent) +{ + this->wifi_selection_page = this->create_wifi_selection_page(menu); + this->wifi_password_page = this->create_wifi_password_page(this->settingsMenu); + this->create_wifi_main_page(parent); + this->mHardware->onWifiScanDone([this] (std::shared_ptr> info) {this->wifi_scan_done(info);}); +} + +lv_obj_t* OmoteUI::create_wifi_password_page(lv_obj_t* menu) +{ + lv_obj_t* ret_val = lv_menu_page_create(menu, NULL); + lv_obj_t* cont = lv_menu_cont_create(ret_val); + lv_obj_set_layout(cont, LV_LAYOUT_FLEX); + lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN); + lv_obj_set_scrollbar_mode(cont, LV_SCROLLBAR_MODE_ACTIVE); + + this->wifi_password_label = lv_label_create(cont); + lv_label_set_text(this->wifi_password_label, "Password"); + lv_obj_t* password_input = lv_textarea_create(cont); + lv_obj_set_width(password_input, lv_pct(100)); + lv_textarea_set_password_mode(password_input, true); + lv_textarea_set_one_line(password_input, true); + lv_textarea_set_placeholder_text(password_input, "Password"); + lv_obj_add_event_cb(password_input, [] (lv_event_t* e) {mInstance->password_field_event_cb(e);} , LV_EVENT_READY, NULL ); + this->attach_keyboard(password_input); + + lv_obj_t* show_password = lv_checkbox_create(cont); + lv_checkbox_set_text(show_password, "Show password"); + lv_obj_add_event_cb(show_password, show_password_cb, LV_EVENT_VALUE_CHANGED, password_input); + + lv_obj_t* connect_button = lv_btn_create(cont); + lv_obj_t* label = lv_label_create(connect_button); + lv_label_set_text(label, "Connect"); + lv_obj_add_event_cb(connect_button,[] (lv_event_t* e) { mInstance->connect_btn_cb(e);}, LV_EVENT_CLICKED, password_input); + + return ret_val; +} + +/** + * @brief Callback which is triggered when the wifi settings are opened (the wifi settings are pressed in the settings + * main page). This function will trigger the asynchronous scan for wifi networks and update the label of the wifi + * selection page to indicate that wifi networks are being searched for. The wifi event callback function then has to + * call the API function to fill the page with the found networks. + * + * @param event Pointer to event object for the event where this callback is called + */ +void OmoteUI::wifi_settings_cb(lv_event_t* event) +{ + lv_obj_t* cont = (lv_obj_t*) lv_event_get_user_data(event); + lv_obj_clean(cont); + lv_obj_t* label = lv_label_create(cont); + lv_label_set_text(label, "Searching for wifi networks"); + //This will trigger an asynchronouse network scan + // We need to trigger wifi search via HAL + //wifihandler.scan(); +} \ No newline at end of file