From 6a6ee41a070033b1b632428565269f3b4911d582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=A8=E9=9C=96=E9=93=83?= <2712495353@qq.com> Date: Sun, 5 Jul 2026 20:52:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E5=8F=8A=E5=85=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/CMakeLists.txt | 7 +- main/app/ui_handlers.c | 82 +++++++++++++ main/app/ui_handlers.h | 9 ++ main/bsp/board_config.h | 9 ++ main/bsp/lvgl_port.c | 40 +++++- main/bsp/touch.c | 6 +- main/ui/screens/ui_Settings.c | 154 ++++++++++++++++++++++++ main/ui/screens/ui_Settings.h | 14 +++ main/ui/settings/settings_store.c | 121 +++++++++++++++++++ main/ui/settings/settings_store.h | 11 ++ main/ui/settings/settings_tabs.c | 194 ++++++++++++++++++++++++++++++ main/ui/settings/settings_tabs.h | 17 +++ main/ui/settings/settings_types.h | 18 +++ main/ui/ui.c | 4 +- main/ui/ui.h | 1 + 15 files changed, 676 insertions(+), 11 deletions(-) create mode 100644 main/ui/screens/ui_Settings.c create mode 100644 main/ui/screens/ui_Settings.h create mode 100644 main/ui/settings/settings_store.c create mode 100644 main/ui/settings/settings_store.h create mode 100644 main/ui/settings/settings_tabs.c create mode 100644 main/ui/settings/settings_tabs.h create mode 100644 main/ui/settings/settings_types.h diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 04401aa..fb133d7 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -14,6 +14,9 @@ idf_component_register(SRCS "ui/screens/ui_Screen1.c" "ui/screens/ui_Screen2.c" "ui/screens/ui_Screen3.c" + "ui/screens/ui_Settings.c" + "ui/settings/settings_store.c" + "ui/settings/settings_tabs.c" "ui/widgets/ui_comp_hook.c" PRIV_REQUIRES bt @@ -30,4 +33,6 @@ idf_component_register(SRCS "app" "bsp" "services" - "ui") + "ui" + "ui/settings" + ) diff --git a/main/app/ui_handlers.c b/main/app/ui_handlers.c index dc33315..e37ccd4 100644 --- a/main/app/ui_handlers.c +++ b/main/app/ui_handlers.c @@ -1,10 +1,15 @@ #include "ui_handlers.h" #include +#include #include "ble_hid.h" #include "boot_button.h" #include "esp_log.h" +#include "esp_system.h" +#include "screens/ui_Settings.h" +#include "settings/settings_store.h" +#include "settings/settings_tabs.h" #include "ui_events.h" static const char *TAG = "ui_handlers"; @@ -37,6 +42,83 @@ void ui_handlers_init(void) boot_button_init(on_boot_press); } +void settings_on_tab_clicked(lv_event_t *e) +{ + settings_tab_t tab = (settings_tab_t)(intptr_t)lv_event_get_user_data(e); + ui_Settings_switch_tab(tab); +} + +void settings_on_save_clicked(lv_event_t *e) +{ + (void)e; + settings_data_t buf = *settings_store_get(); + settings_tabs_collect(ui_Settings_get_active_tab(), &buf); + settings_store_update(&buf); + esp_err_t err = settings_store_commit(); + if (err == ESP_OK) { + settings_store_apply(); + ESP_LOGI(TAG, "Settings saved"); + } else { + ESP_LOGW(TAG, "Settings save failed"); + } +} + +void settings_on_factory_reset(lv_event_t *e) +{ + (void)e; + ESP_LOGW(TAG, "Factory reset"); + settings_store_factory_reset(); + settings_store_apply(); + esp_restart(); +} + +void settings_on_brightness_changed(lv_event_t *e) +{ + lv_obj_t *slider = lv_event_get_target(e); + uint8_t pct = (uint8_t)lv_slider_get_value(slider); + + settings_data_t buf = *settings_store_get(); + buf.brightness_pct = pct; + settings_store_update(&buf); + settings_store_apply(); + + lv_obj_t *pct_label = lv_obj_get_user_data(slider); + if (pct_label != NULL) { + lv_label_set_text_fmt(pct_label, "%u%%", pct); + } +} + +void settings_on_value_changed(lv_event_t *e) +{ + settings_field_t field = + (settings_field_t)(intptr_t)lv_event_get_user_data(e); + lv_obj_t *target = lv_event_get_target(e); + settings_data_t buf = *settings_store_get(); + + switch (field) { + case SETTINGS_FIELD_NOTIFICATION: + buf.notification_enabled = lv_obj_has_state(target, LV_STATE_CHECKED); + break; + case SETTINGS_FIELD_VOLUME: + buf.volume_pct = (uint8_t)lv_slider_get_value(target); + break; + case SETTINGS_FIELD_MUTE: + buf.mute = lv_obj_has_state(target, LV_STATE_CHECKED); + break; + default: + LV_ASSERT_MSG(false, "unexpected settings_field_t"); + break; + } + + settings_store_update(&buf); +} + +void settings_on_network_scan_clicked(lv_event_t *e) +{ + (void)e; + ESP_LOGI(TAG, "Not available"); +} + void update_year_action(lv_event_t * e) { (void)e; diff --git a/main/app/ui_handlers.h b/main/app/ui_handlers.h index 339e2a4..1c0e596 100644 --- a/main/app/ui_handlers.h +++ b/main/app/ui_handlers.h @@ -1,4 +1,13 @@ #pragma once +#include "lvgl.h" + /* UI event callbacks declared in ui_events.h are implemented in ui_handlers.c */ void ui_handlers_init(void); + +void settings_on_tab_clicked(lv_event_t *e); +void settings_on_save_clicked(lv_event_t *e); +void settings_on_factory_reset(lv_event_t *e); +void settings_on_brightness_changed(lv_event_t *e); +void settings_on_value_changed(lv_event_t *e); +void settings_on_network_scan_clicked(lv_event_t *e); diff --git a/main/bsp/board_config.h b/main/bsp/board_config.h index b738e5e..a9e37ac 100644 --- a/main/bsp/board_config.h +++ b/main/bsp/board_config.h @@ -9,6 +9,15 @@ #define BOARD_LCD_PIXEL_CLOCK_HZ (20 * 1000 * 1000) #define BOARD_LCD_H_RES 170 #define BOARD_LCD_V_RES 320 + +/* LVGL logical resolution after 90° rotation (landscape) */ +#define BOARD_LCD_LOGIC_H_RES 320 +#define BOARD_LCD_LOGIC_V_RES 170 + +/* Touch IC → physical panel alignment (not LVGL logical rotation) */ +#define BOARD_TOUCH_SWAP_XY 0 +#define BOARD_TOUCH_MIRROR_X 0 +#define BOARD_TOUCH_MIRROR_Y 0 #define BOARD_LCD_PANEL_H_RES 240 #define BOARD_LCD_GAP_X ((BOARD_LCD_PANEL_H_RES - BOARD_LCD_H_RES) / 2) #define BOARD_LCD_GAP_Y 0 diff --git a/main/bsp/lvgl_port.c b/main/bsp/lvgl_port.c index 291a350..6474b03 100644 --- a/main/bsp/lvgl_port.c +++ b/main/bsp/lvgl_port.c @@ -2,6 +2,7 @@ #include "board_config.h" +#include "draw/sw/lv_draw_sw.h" #include "driver/spi_master.h" #include "esp_lcd_panel_ops.h" #include "esp_log.h" @@ -31,14 +32,40 @@ static bool notify_flush_ready(esp_lcd_panel_io_handle_t panel_io, static void flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map) { esp_lcd_panel_handle_t panel_handle = lv_display_get_user_data(disp); - int offsetx1 = area->x1; - int offsetx2 = area->x2; - int offsety1 = area->y1; - int offsety2 = area->y2; - lv_draw_sw_rgb565_swap(px_map, + const lv_area_t *draw_area = area; + uint8_t *draw_buf = px_map; + + static uint8_t rotated_buf[BOARD_LCD_H_RES * BOARD_LVGL_DRAW_BUF_LINES * + sizeof(lv_color16_t)]; + + lv_display_rotation_t rotation = lv_display_get_rotation(disp); + lv_area_t rotated_area; + if (rotation != LV_DISPLAY_ROTATION_0) { + lv_color_format_t cf = lv_display_get_color_format(disp); + rotated_area = *area; + lv_display_rotate_area(disp, &rotated_area); + + int32_t src_w = lv_area_get_width(area); + int32_t src_h = lv_area_get_height(area); + uint32_t src_stride = lv_draw_buf_width_to_stride(src_w, cf); + uint32_t dest_stride = + lv_draw_buf_width_to_stride(lv_area_get_width(&rotated_area), cf); + + lv_draw_sw_rotate(px_map, rotated_buf, src_w, src_h, src_stride, + dest_stride, rotation, cf); + + draw_area = &rotated_area; + draw_buf = rotated_buf; + } + + int offsetx1 = draw_area->x1; + int offsetx2 = draw_area->x2; + int offsety1 = draw_area->y1; + int offsety2 = draw_area->y2; + lv_draw_sw_rgb565_swap(draw_buf, (offsetx2 + 1 - offsetx1) * (offsety2 + 1 - offsety1)); esp_lcd_panel_draw_bitmap(panel_handle, offsetx1, offsety1, offsetx2 + 1, - offsety2 + 1, px_map); + offsety2 + 1, draw_buf); } static void increase_lvgl_tick(void *arg) @@ -80,6 +107,7 @@ lv_display_t *lvgl_port_init(esp_lcd_panel_io_handle_t io_handle, lv_display_t *display = lv_display_create(BOARD_LCD_H_RES, BOARD_LCD_V_RES); + lv_display_set_rotation(display, LV_DISPLAY_ROTATION_270); size_t draw_buffer_sz = BOARD_LCD_H_RES * BOARD_LVGL_DRAW_BUF_LINES * sizeof(lv_color16_t); diff --git a/main/bsp/touch.c b/main/bsp/touch.c index ed6da62..80a9571 100644 --- a/main/bsp/touch.c +++ b/main/bsp/touch.c @@ -86,9 +86,9 @@ esp_err_t touch_init(lv_display_t *display) .interrupt = 0, }, .flags = { - .swap_xy = 0, - .mirror_x = 0, - .mirror_y = 0, + .swap_xy = BOARD_TOUCH_SWAP_XY, + .mirror_x = BOARD_TOUCH_MIRROR_X, + .mirror_y = BOARD_TOUCH_MIRROR_Y, }, .interrupt_callback = touch_isr_cb, }; diff --git a/main/ui/screens/ui_Settings.c b/main/ui/screens/ui_Settings.c new file mode 100644 index 0000000..8f04b18 --- /dev/null +++ b/main/ui/screens/ui_Settings.c @@ -0,0 +1,154 @@ +#include "ui_Settings.h" + +#include "board_config.h" +#include "settings/settings_store.h" +#include "settings/settings_tabs.h" +#include "ui_handlers.h" + +#include + +lv_obj_t *ui_Settings; +lv_obj_t *ui_Settings_sidebar; +lv_obj_t *ui_Settings_content; + +static settings_tab_t s_active_tab = SETTINGS_TAB_SYSTEM; +static lv_obj_t *s_nav_buttons[4]; + +static lv_style_t s_style_sidebar_btn_active; +static lv_style_t s_style_content_bg; +static bool s_styles_inited; + +static const char *s_tab_labels[] = { + "System", + "Display", + "Audio", + "Network", +}; + +static void init_styles(void) +{ + if (s_styles_inited) { + return; + } + + lv_style_init(&s_style_sidebar_btn_active); + lv_style_set_bg_color(&s_style_sidebar_btn_active, + lv_palette_main(LV_PALETTE_BLUE)); + lv_style_set_bg_opa(&s_style_sidebar_btn_active, LV_OPA_COVER); + + lv_style_init(&s_style_content_bg); + lv_style_set_bg_color(&s_style_content_bg, + lv_palette_lighten(LV_PALETTE_GREY, 2)); + lv_style_set_bg_opa(&s_style_content_bg, LV_OPA_COVER); + + s_styles_inited = true; +} + +static void sidebar_update_highlight(settings_tab_t tab) +{ + for (size_t i = 0; i < 4; i++) { + if (s_nav_buttons[i] == NULL) { + continue; + } + if ((settings_tab_t)i == tab) { + lv_obj_add_style(s_nav_buttons[i], &s_style_sidebar_btn_active, 0); + } else { + lv_obj_remove_style(s_nav_buttons[i], &s_style_sidebar_btn_active, 0); + } + } +} + +settings_tab_t ui_Settings_get_active_tab(void) +{ + return s_active_tab; +} + +void ui_Settings_switch_tab(settings_tab_t tab) +{ + settings_data_t buf = *settings_store_get(); + settings_tabs_collect(s_active_tab, &buf); + settings_store_update(&buf); + + s_active_tab = tab; + sidebar_update_highlight(tab); + + lv_obj_clean(ui_Settings_content); + switch (tab) { + case SETTINGS_TAB_SYSTEM: + load_system_settings(ui_Settings_content, settings_store_get()); + break; + case SETTINGS_TAB_DISPLAY: + load_display_settings(ui_Settings_content, settings_store_get()); + break; + case SETTINGS_TAB_AUDIO: + load_audio_settings(ui_Settings_content, settings_store_get()); + break; + case SETTINGS_TAB_NETWORK: + load_network_settings(ui_Settings_content, settings_store_get()); + break; + default: + LV_ASSERT_MSG(false, "unexpected settings_tab_t"); + break; + } +} + +void ui_Settings_screen_init(void) +{ + init_styles(); + + ui_Settings = lv_obj_create(NULL); + lv_obj_set_size(ui_Settings, BOARD_LCD_LOGIC_H_RES, BOARD_LCD_LOGIC_V_RES); + lv_obj_set_style_pad_all(ui_Settings, 2, 0); + lv_obj_remove_flag(ui_Settings, LV_OBJ_FLAG_SCROLLABLE); + + ui_Settings_sidebar = lv_list_create(ui_Settings); + lv_obj_set_size(ui_Settings_sidebar, 90, 170); + lv_obj_set_pos(ui_Settings_sidebar, 0, 0); + lv_obj_set_style_pad_all(ui_Settings_sidebar, 2, 0); + lv_obj_set_style_pad_row(ui_Settings_sidebar, 2, 0); + lv_obj_remove_flag(ui_Settings_sidebar, LV_OBJ_FLAG_SCROLLABLE); + + for (size_t i = 0; i < 4; i++) { + s_nav_buttons[i] = + lv_list_add_button(ui_Settings_sidebar, NULL, s_tab_labels[i]); + lv_obj_set_size(s_nav_buttons[i], 86, 28); + lv_obj_add_event_cb(s_nav_buttons[i], settings_on_tab_clicked, + LV_EVENT_CLICKED, (void *)(intptr_t)i); + } + + lv_obj_t *save_btn = lv_button_create(ui_Settings); + lv_obj_set_size(save_btn, 86, 28); + lv_obj_set_pos(save_btn, 2, 138); + lv_obj_t *save_label = lv_label_create(save_btn); + lv_label_set_text(save_label, "Save"); + lv_obj_center(save_label); + lv_obj_add_event_cb(save_btn, settings_on_save_clicked, LV_EVENT_CLICKED, + NULL); + + ui_Settings_content = lv_obj_create(ui_Settings); + lv_obj_set_size(ui_Settings_content, 230, 170); + lv_obj_set_pos(ui_Settings_content, 90, 0); + lv_obj_set_style_pad_all(ui_Settings_content, 2, 0); + lv_obj_add_style(ui_Settings_content, &s_style_content_bg, 0); + lv_obj_remove_flag(ui_Settings_content, LV_OBJ_FLAG_SCROLLABLE); + + settings_store_load(); + settings_store_apply(); + + s_active_tab = SETTINGS_TAB_SYSTEM; + sidebar_update_highlight(s_active_tab); + load_system_settings(ui_Settings_content, settings_store_get()); +} + +void ui_Settings_screen_destroy(void) +{ + if (ui_Settings != NULL) { + lv_obj_del(ui_Settings); + ui_Settings = NULL; + ui_Settings_sidebar = NULL; + ui_Settings_content = NULL; + } + for (size_t i = 0; i < 4; i++) { + s_nav_buttons[i] = NULL; + } +} diff --git a/main/ui/screens/ui_Settings.h b/main/ui/screens/ui_Settings.h new file mode 100644 index 0000000..0c2b5bc --- /dev/null +++ b/main/ui/screens/ui_Settings.h @@ -0,0 +1,14 @@ +#pragma once + +#include "lvgl.h" +#include "settings_types.h" + +extern lv_obj_t *ui_Settings; +extern lv_obj_t *ui_Settings_sidebar; +extern lv_obj_t *ui_Settings_content; + +void ui_Settings_screen_init(void); +void ui_Settings_screen_destroy(void); + +void ui_Settings_switch_tab(settings_tab_t tab); +settings_tab_t ui_Settings_get_active_tab(void); diff --git a/main/ui/settings/settings_store.c b/main/ui/settings/settings_store.c new file mode 100644 index 0000000..031f490 --- /dev/null +++ b/main/ui/settings/settings_store.c @@ -0,0 +1,121 @@ +#include "settings_store.h" + +#include "display.h" + +#include "esp_log.h" +#include "nvs.h" +#include "nvs_flash.h" + +static const char *TAG = "settings_store"; + +static const char *SETTINGS_NAMESPACE = "settings"; + +static const settings_data_t SETTINGS_DEFAULTS = { + .notification_enabled = false, + .brightness_pct = 70, + .volume_pct = 50, + .mute = false, +}; + +static settings_data_t s_data; + +static void load_key_u8(nvs_handle_t handle, const char *key, uint8_t *out, + uint8_t default_val) +{ + uint8_t val = default_val; + if (nvs_get_u8(handle, key, &val) != ESP_OK) { + val = default_val; + } + *out = val; +} + +void settings_store_load(void) +{ + s_data = SETTINGS_DEFAULTS; + + nvs_handle_t handle; + esp_err_t err = nvs_open(SETTINGS_NAMESPACE, NVS_READONLY, &handle); + if (err != ESP_OK) { + ESP_LOGI(TAG, "No saved settings, using defaults"); + return; + } + + uint8_t val; + load_key_u8(handle, "notif", &val, SETTINGS_DEFAULTS.notification_enabled); + s_data.notification_enabled = val != 0; + load_key_u8(handle, "bright", &s_data.brightness_pct, + SETTINGS_DEFAULTS.brightness_pct); + load_key_u8(handle, "vol", &s_data.volume_pct, SETTINGS_DEFAULTS.volume_pct); + load_key_u8(handle, "mute", &val, SETTINGS_DEFAULTS.mute); + s_data.mute = val != 0; + + nvs_close(handle); + ESP_LOGI(TAG, "Settings loaded (bright=%u vol=%u)", s_data.brightness_pct, + s_data.volume_pct); +} + +const settings_data_t *settings_store_get(void) +{ + return &s_data; +} + +void settings_store_update(const settings_data_t *data) +{ + s_data = *data; +} + +esp_err_t settings_store_commit(void) +{ + nvs_handle_t handle; + esp_err_t err = nvs_open(SETTINGS_NAMESPACE, NVS_READWRITE, &handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "nvs_open failed: %s", esp_err_to_name(err)); + return err; + } + + err = nvs_set_u8(handle, "notif", s_data.notification_enabled ? 1 : 0); + if (err == ESP_OK) { + err = nvs_set_u8(handle, "bright", s_data.brightness_pct); + } + if (err == ESP_OK) { + err = nvs_set_u8(handle, "vol", s_data.volume_pct); + } + if (err == ESP_OK) { + err = nvs_set_u8(handle, "mute", s_data.mute ? 1 : 0); + } + if (err == ESP_OK) { + err = nvs_commit(handle); + } + + nvs_close(handle); + if (err != ESP_OK) { + ESP_LOGE(TAG, "commit failed: %s", esp_err_to_name(err)); + } + return err; +} + +esp_err_t settings_store_factory_reset(void) +{ + nvs_handle_t handle; + esp_err_t err = nvs_open(SETTINGS_NAMESPACE, NVS_READWRITE, &handle); + if (err == ESP_OK) { + err = nvs_erase_all(handle); + if (err == ESP_OK) { + err = nvs_commit(handle); + } + nvs_close(handle); + } + + s_data = SETTINGS_DEFAULTS; + esp_err_t commit_err = settings_store_commit(); + if (err != ESP_OK) { + return err; + } + return commit_err; +} + +void settings_store_apply(void) +{ + uint16_t duty = (uint16_t)((s_data.brightness_pct * 1023U) / 100U); + display_backlight_set_brightness(duty); +} diff --git a/main/ui/settings/settings_store.h b/main/ui/settings/settings_store.h new file mode 100644 index 0000000..5baa507 --- /dev/null +++ b/main/ui/settings/settings_store.h @@ -0,0 +1,11 @@ +#pragma once + +#include "esp_err.h" +#include "settings_types.h" + +void settings_store_load(void); +const settings_data_t *settings_store_get(void); +void settings_store_update(const settings_data_t *data); +esp_err_t settings_store_commit(void); +esp_err_t settings_store_factory_reset(void); +void settings_store_apply(void); diff --git a/main/ui/settings/settings_tabs.c b/main/ui/settings/settings_tabs.c new file mode 100644 index 0000000..515302e --- /dev/null +++ b/main/ui/settings/settings_tabs.c @@ -0,0 +1,194 @@ +#include "settings_tabs.h" + +#include "ui_handlers.h" + +static lv_obj_t *s_notif_switch; +static lv_obj_t *s_brightness_slider; +static lv_obj_t *s_brightness_pct_label; +static lv_obj_t *s_volume_slider; +static lv_obj_t *s_mute_switch; + +static lv_obj_t *create_status_bar(lv_obj_t *content, const char *title) +{ + lv_obj_t *status_bar = lv_obj_create(content); + lv_obj_set_size(status_bar, 230, 25); + lv_obj_set_pos(status_bar, 0, 0); + lv_obj_set_style_pad_all(status_bar, 2, 0); + lv_obj_set_style_border_width(status_bar, 1, 0); + lv_obj_set_style_border_side(status_bar, LV_BORDER_SIDE_BOTTOM, 0); + lv_obj_remove_flag(status_bar, LV_OBJ_FLAG_SCROLLABLE); + + lv_obj_t *title_label = lv_label_create(status_bar); + lv_label_set_text(title_label, title); + lv_obj_align(title_label, LV_ALIGN_LEFT_MID, 2, 0); + + lv_obj_t *time_label = lv_label_create(status_bar); + lv_label_set_text(time_label, "--:--"); + lv_obj_align(time_label, LV_ALIGN_RIGHT_MID, -2, 0); + + return status_bar; +} + +static lv_obj_t *create_settings_body(lv_obj_t *content) +{ + lv_obj_t *body = lv_obj_create(content); + lv_obj_set_size(body, 230, 145); + lv_obj_set_pos(body, 0, 25); + lv_obj_set_style_pad_all(body, 2, 0); + lv_obj_set_style_border_width(body, 0, 0); + lv_obj_remove_flag(body, LV_OBJ_FLAG_SCROLLABLE); + return body; +} + +void load_system_settings(lv_obj_t *content, const settings_data_t *data) +{ + s_notif_switch = NULL; + + create_status_bar(content, "System Settings"); + lv_obj_t *body = create_settings_body(content); + + lv_obj_t *notif_label = lv_label_create(body); + lv_label_set_text(notif_label, "Enable Notification"); + lv_obj_set_pos(notif_label, 4, 4); + lv_obj_set_size(notif_label, 120, 28); + + s_notif_switch = lv_switch_create(body); + lv_obj_set_pos(s_notif_switch, 180, 4); + lv_obj_set_size(s_notif_switch, 40, 28); + if (data->notification_enabled) { + lv_obj_add_state(s_notif_switch, LV_STATE_CHECKED); + } + lv_obj_add_event_cb(s_notif_switch, settings_on_value_changed, + LV_EVENT_VALUE_CHANGED, + (void *)(intptr_t)SETTINGS_FIELD_NOTIFICATION); + + lv_obj_t *reset_btn = lv_button_create(body); + lv_obj_set_pos(reset_btn, 4, 112); + lv_obj_set_size(reset_btn, 100, 28); + lv_obj_set_style_text_color(reset_btn, lv_palette_main(LV_PALETTE_RED), 0); + lv_obj_t *reset_label = lv_label_create(reset_btn); + lv_label_set_text(reset_label, "Factory Reset"); + lv_obj_center(reset_label); + lv_obj_add_event_cb(reset_btn, settings_on_factory_reset, LV_EVENT_CLICKED, + NULL); +} + +void load_display_settings(lv_obj_t *content, const settings_data_t *data) +{ + s_brightness_slider = NULL; + s_brightness_pct_label = NULL; + + create_status_bar(content, "Display Settings"); + lv_obj_t *body = create_settings_body(content); + + lv_obj_t *bright_label = lv_label_create(body); + lv_label_set_text(bright_label, "Brightness"); + lv_obj_set_pos(bright_label, 4, 4); + lv_obj_set_size(bright_label, 80, 28); + + s_brightness_slider = lv_slider_create(body); + lv_obj_set_pos(s_brightness_slider, 88, 8); + lv_obj_set_size(s_brightness_slider, 100, 12); + lv_slider_set_range(s_brightness_slider, 0, 100); + lv_slider_set_value(s_brightness_slider, data->brightness_pct, LV_ANIM_OFF); + + s_brightness_pct_label = lv_label_create(body); + lv_label_set_text_fmt(s_brightness_pct_label, "%u%%", data->brightness_pct); + lv_obj_set_pos(s_brightness_pct_label, 196, 4); + lv_obj_set_size(s_brightness_pct_label, 30, 28); + + lv_obj_set_user_data(s_brightness_slider, s_brightness_pct_label); + lv_obj_add_event_cb(s_brightness_slider, settings_on_brightness_changed, + LV_EVENT_VALUE_CHANGED, NULL); +} + +void load_audio_settings(lv_obj_t *content, const settings_data_t *data) +{ + s_volume_slider = NULL; + s_mute_switch = NULL; + + create_status_bar(content, "Audio Settings"); + lv_obj_t *body = create_settings_body(content); + + lv_obj_t *vol_label = lv_label_create(body); + lv_label_set_text(vol_label, "Volume"); + lv_obj_set_pos(vol_label, 4, 4); + lv_obj_set_size(vol_label, 80, 28); + + s_volume_slider = lv_slider_create(body); + lv_obj_set_pos(s_volume_slider, 88, 8); + lv_obj_set_size(s_volume_slider, 100, 12); + lv_slider_set_range(s_volume_slider, 0, 100); + lv_slider_set_value(s_volume_slider, data->volume_pct, LV_ANIM_OFF); + lv_obj_add_event_cb(s_volume_slider, settings_on_value_changed, + LV_EVENT_VALUE_CHANGED, + (void *)(intptr_t)SETTINGS_FIELD_VOLUME); + + lv_obj_t *mute_label = lv_label_create(body); + lv_label_set_text(mute_label, "Mute"); + lv_obj_set_pos(mute_label, 4, 40); + lv_obj_set_size(mute_label, 80, 28); + + s_mute_switch = lv_switch_create(body); + lv_obj_set_pos(s_mute_switch, 180, 40); + lv_obj_set_size(s_mute_switch, 40, 28); + if (data->mute) { + lv_obj_add_state(s_mute_switch, LV_STATE_CHECKED); + } + lv_obj_add_event_cb(s_mute_switch, settings_on_value_changed, + LV_EVENT_VALUE_CHANGED, + (void *)(intptr_t)SETTINGS_FIELD_MUTE); +} + +void load_network_settings(lv_obj_t *content, const settings_data_t *data) +{ + (void)data; + + create_status_bar(content, "Network Settings"); + lv_obj_t *body = create_settings_body(content); + + lv_obj_t *wifi_label = lv_label_create(body); + lv_label_set_text(wifi_label, "WiFi: Disabled"); + lv_obj_set_pos(wifi_label, 4, 4); + lv_obj_set_size(wifi_label, 140, 28); + + lv_obj_t *scan_btn = lv_button_create(body); + lv_obj_set_pos(scan_btn, 4, 40); + lv_obj_set_size(scan_btn, 80, 28); + lv_obj_t *scan_label = lv_label_create(scan_btn); + lv_label_set_text(scan_label, "Scan"); + lv_obj_center(scan_label); + lv_obj_add_event_cb(scan_btn, settings_on_network_scan_clicked, + LV_EVENT_CLICKED, NULL); +} + +void settings_tabs_collect(settings_tab_t tab, settings_data_t *out) +{ + switch (tab) { + case SETTINGS_TAB_SYSTEM: + if (s_notif_switch != NULL) { + out->notification_enabled = + lv_obj_has_state(s_notif_switch, LV_STATE_CHECKED); + } + break; + case SETTINGS_TAB_DISPLAY: + if (s_brightness_slider != NULL) { + out->brightness_pct = + (uint8_t)lv_slider_get_value(s_brightness_slider); + } + break; + case SETTINGS_TAB_AUDIO: + if (s_volume_slider != NULL) { + out->volume_pct = (uint8_t)lv_slider_get_value(s_volume_slider); + } + if (s_mute_switch != NULL) { + out->mute = lv_obj_has_state(s_mute_switch, LV_STATE_CHECKED); + } + break; + case SETTINGS_TAB_NETWORK: + break; + default: + LV_ASSERT_MSG(false, "unexpected settings_tab_t"); + break; + } +} diff --git a/main/ui/settings/settings_tabs.h b/main/ui/settings/settings_tabs.h new file mode 100644 index 0000000..9fc4f9b --- /dev/null +++ b/main/ui/settings/settings_tabs.h @@ -0,0 +1,17 @@ +#pragma once + +#include "lvgl.h" +#include "settings_types.h" + +typedef enum { + SETTINGS_FIELD_NOTIFICATION = 0, + SETTINGS_FIELD_VOLUME, + SETTINGS_FIELD_MUTE, +} settings_field_t; + +void load_system_settings(lv_obj_t *content, const settings_data_t *data); +void load_display_settings(lv_obj_t *content, const settings_data_t *data); +void load_audio_settings(lv_obj_t *content, const settings_data_t *data); +void load_network_settings(lv_obj_t *content, const settings_data_t *data); + +void settings_tabs_collect(settings_tab_t tab, settings_data_t *out); diff --git a/main/ui/settings/settings_types.h b/main/ui/settings/settings_types.h new file mode 100644 index 0000000..df036ad --- /dev/null +++ b/main/ui/settings/settings_types.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +typedef enum { + SETTINGS_TAB_SYSTEM = 0, + SETTINGS_TAB_DISPLAY, + SETTINGS_TAB_AUDIO, + SETTINGS_TAB_NETWORK, +} settings_tab_t; + +typedef struct { + bool notification_enabled; + uint8_t brightness_pct; + uint8_t volume_pct; + bool mute; +} settings_data_t; diff --git a/main/ui/ui.c b/main/ui/ui.c index 28c7bef..f633b35 100644 --- a/main/ui/ui.c +++ b/main/ui/ui.c @@ -33,8 +33,9 @@ void ui_init(void) ui_Screen1_screen_init(); ui_Screen2_screen_init(); ui_Screen3_screen_init(); + ui_Settings_screen_init(); ui____initial_actions0 = lv_obj_create(NULL); - lv_disp_load_scr(ui_Screen3); + lv_disp_load_scr(ui_Settings); } void ui_destroy(void) @@ -42,4 +43,5 @@ void ui_destroy(void) ui_Screen1_screen_destroy(); ui_Screen2_screen_destroy(); ui_Screen3_screen_destroy(); + ui_Settings_screen_destroy(); } diff --git a/main/ui/ui.h b/main/ui/ui.h index d8a0c81..932abe6 100644 --- a/main/ui/ui.h +++ b/main/ui/ui.h @@ -21,6 +21,7 @@ extern "C" { #include "screens/ui_Screen1.h" #include "screens/ui_Screen2.h" #include "screens/ui_Screen3.h" +#include "screens/ui_Settings.h" ///////////////////// VARIABLES ////////////////////