Various UI/UX improvements

- Implemented keyboard in gui service
- Various UI/UX improvements in wifi apps
This commit is contained in:
Ken Van Hoeylandt 2024-01-14 23:26:37 +01:00
parent ba1f81f599
commit 16dc1e385c
8 changed files with 102 additions and 62 deletions

View File

@ -2,6 +2,7 @@
#include "log.h"
#include "lvgl.h"
#include "services/gui/gui.h"
#include "services/wifi/wifi_credentials.h"
#include "ui/spacer.h"
#include "ui/style.h"
@ -12,17 +13,13 @@
#define TAG "wifi_connect"
static void show_keyboard(lv_event_t* event) {
WifiConnectView* view = (WifiConnectView*)event->user_data;
lv_obj_clear_flag(view->keyboard, LV_OBJ_FLAG_HIDDEN);
lv_keyboard_set_textarea(view->keyboard, event->current_target);
// TODO: This doesn't work yet as most content is not scrollable
lv_obj_scroll_to_view(event->current_target, LV_ANIM_OFF);
gui_keyboard_show(event->current_target);
lv_obj_scroll_to_view(event->current_target, LV_ANIM_ON);
}
static void hide_keyboard(lv_event_t* event) {
WifiConnectView* view = (WifiConnectView*)event->user_data;
lv_obj_add_flag(view->keyboard, LV_OBJ_FLAG_HIDDEN);
lv_keyboard_set_textarea(view->keyboard, event->current_target);
UNUSED(event);
gui_keyboard_hide();
}
static void on_connect(lv_event_t* event) {
@ -51,6 +48,31 @@ static void on_connect(lv_event_t* event) {
}
}
void wifi_connect_view_create_bottom_buttons(WifiConnect* wifi, lv_obj_t* parent) {
WifiConnectView* view = &wifi->view;
lv_obj_t* button_container = lv_obj_create(parent);
lv_obj_set_width(button_container, LV_PCT(100));
lv_obj_set_height(button_container, LV_SIZE_CONTENT);
tt_lv_obj_set_style_no_padding(button_container);
lv_obj_set_style_border_width(button_container, 0, 0);
view->remember_switch = lv_switch_create(button_container);
lv_obj_add_state(view->remember_switch, LV_STATE_CHECKED);
lv_obj_align(view->remember_switch, LV_ALIGN_LEFT_MID, 0, 0);
lv_obj_t* remember_label = lv_label_create(button_container);
lv_label_set_text(remember_label, "Remember");
lv_obj_align(remember_label, LV_ALIGN_CENTER, 0, 0);
lv_obj_align_to(remember_label, view->remember_switch, LV_ALIGN_OUT_RIGHT_MID, 4, 0);
view->connect_button = lv_btn_create(button_container);
lv_obj_t* connect_label = lv_label_create(view->connect_button);
lv_label_set_text(connect_label, "Connect");
lv_obj_align(view->connect_button, LV_ALIGN_RIGHT_MID, 0, 0);
lv_obj_add_event_cb(view->connect_button, &on_connect, LV_EVENT_CLICKED, wifi);
}
// TODO: Standardize dialogs
void wifi_connect_view_create(App app, void* wifi, lv_obj_t* parent) {
WifiConnect* wifi_connect = (WifiConnect*)wifi;
@ -70,48 +92,24 @@ void wifi_connect_view_create(App app, void* wifi, lv_obj_t* parent) {
view->ssid_textarea = lv_textarea_create(parent);
lv_textarea_set_one_line(view->ssid_textarea, true);
tt_lv_spacer_create(parent, 1, 8);
lv_obj_t* password_label = lv_label_create(parent);
lv_label_set_text(password_label, "Password:");
view->password_textarea = lv_textarea_create(parent);
lv_textarea_set_one_line(view->password_textarea, true);
lv_textarea_set_password_show_time(view->password_textarea, 0);
lv_textarea_set_password_mode(view->password_textarea, true);
tt_lv_spacer_create(parent, 1, 2);
tt_lv_spacer_create(parent, 1, 8);
lv_obj_t* button_container = lv_obj_create(parent);
lv_obj_set_width(button_container, LV_PCT(100));
lv_obj_set_height(button_container, LV_SIZE_CONTENT);
tt_lv_obj_set_style_no_padding(button_container);
lv_obj_set_style_border_width(button_container, 0, 0);
lv_obj_set_flex_flow(button_container, LV_FLEX_FLOW_ROW);
wifi_connect_view_create_bottom_buttons(wifi, parent);
view->remember_switch = lv_switch_create(button_container);
lv_obj_add_state(view->remember_switch, LV_STATE_CHECKED);
tt_lv_spacer_create(button_container, 2, 1);
lv_obj_t* remember_label = lv_label_create(button_container);
lv_label_set_text(remember_label, "Remember");
lv_obj_t* spacer_center = tt_lv_spacer_create(button_container, 1, 1);
lv_obj_set_flex_grow(spacer_center, 1);
view->connect_button = lv_btn_create(button_container);
lv_obj_t* connect_label = lv_label_create(view->connect_button);
lv_label_set_text(connect_label, "Connect");
lv_obj_center(connect_label);
lv_obj_add_event_cb(view->connect_button, &on_connect, LV_EVENT_CLICKED, wifi);
view->keyboard = lv_keyboard_create(lv_scr_act());
lv_obj_add_flag(view->keyboard, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_event_cb(view->ssid_textarea, show_keyboard, LV_EVENT_FOCUSED, view);
lv_obj_add_event_cb(view->ssid_textarea, hide_keyboard, LV_EVENT_DEFOCUSED, view);
lv_obj_add_event_cb(view->ssid_textarea, hide_keyboard, LV_EVENT_READY, view);
lv_obj_add_event_cb(view->password_textarea, show_keyboard, LV_EVENT_FOCUSED, view);
lv_obj_add_event_cb(view->password_textarea, hide_keyboard, LV_EVENT_DEFOCUSED, view);
lv_obj_add_event_cb(view->password_textarea, hide_keyboard, LV_EVENT_READY, view);
lv_obj_add_event_cb(view->ssid_textarea, show_keyboard, LV_EVENT_FOCUSED, NULL);
lv_obj_add_event_cb(view->ssid_textarea, hide_keyboard, LV_EVENT_DEFOCUSED, NULL);
lv_obj_add_event_cb(view->ssid_textarea, hide_keyboard, LV_EVENT_READY, NULL);
lv_obj_add_event_cb(view->password_textarea, show_keyboard, LV_EVENT_FOCUSED, NULL);
lv_obj_add_event_cb(view->password_textarea, hide_keyboard, LV_EVENT_DEFOCUSED, NULL);
lv_obj_add_event_cb(view->password_textarea, hide_keyboard, LV_EVENT_READY, NULL);
// Init from app parameters
Bundle* _Nullable bundle = tt_app_get_parameters(app);
@ -129,8 +127,6 @@ void wifi_connect_view_create(App app, void* wifi, lv_obj_t* parent) {
}
void wifi_connect_view_destroy(WifiConnectView* view) {
lv_obj_del(view->keyboard);
view->keyboard = NULL;
}
void wifi_connect_view_update(WifiConnectView* view, WifiConnectBindings* bindings, WifiConnectState* state) {

View File

@ -15,7 +15,6 @@ typedef struct {
lv_obj_t* connect_button;
lv_obj_t* cancel_button;
lv_obj_t* remember_switch;
lv_obj_t* keyboard;
} WifiConnectView;
void wifi_connect_view_create(App app, void* wifi, lv_obj_t* parent);

View File

@ -122,6 +122,7 @@ static void app_show(App app, lv_obj_t* parent) {
// View update
wifi_manage_lock(wifi);
wifi->view_enabled = true;
strcpy((char*)wifi->state.connect_ssid, "Connected"); // TODO update with proper SSID
wifi_manage_view_create(&wifi->view, &wifi->bindings, parent);
wifi_manage_view_update(&wifi->view, &wifi->bindings, &wifi->state);
wifi_manage_unlock(wifi);

View File

@ -174,35 +174,37 @@ void wifi_manage_view_create(WifiManageView* view, WifiManageBindings* bindings,
lv_obj_set_align(view->enable_switch, LV_ALIGN_RIGHT_MID);
view->connected_ap_container = lv_obj_create(parent);
lv_obj_set_width(view->connected_ap_container, LV_PCT(100));
lv_obj_set_height(view->connected_ap_container, LV_SIZE_CONTENT);
lv_obj_set_size(view->connected_ap_container, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_style_min_height(view->connected_ap_container, SPINNER_HEIGHT, 0);
tt_lv_obj_set_style_no_padding(view->connected_ap_container);
tt_lv_obj_set_style_bg_invisible(view->connected_ap_container);
lv_obj_set_style_border_width(view->connected_ap_container, 0, 0);
view->connected_ap_label = lv_label_create(view->connected_ap_container);
lv_label_set_text(view->connected_ap_label, "");
lv_obj_set_align(view->connected_ap_label, LV_ALIGN_LEFT_MID);
lv_obj_align(view->connected_ap_label, LV_ALIGN_LEFT_MID, 0, 0);
lv_obj_t* disconnect_button = lv_btn_create(view->connected_ap_container);
lv_obj_add_event_cb(disconnect_button, &on_disconnect_pressed, LV_EVENT_CLICKED, bindings);
lv_obj_t* disconnect_label = lv_label_create(disconnect_button);
lv_label_set_text(disconnect_label, "Disconnect");
lv_obj_center(disconnect_label);
lv_obj_align(disconnect_button, LV_ALIGN_RIGHT_MID, 0, 0);
// Networks
view->networks_label = lv_label_create(parent);
lv_label_set_text(view->networks_label, "Networks");
lv_obj_set_style_text_align(view->networks_label, LV_TEXT_ALIGN_CENTER, 0);
lv_obj_set_style_pad_top(view->networks_label, 8, 0);
lv_obj_set_style_pad_bottom(view->networks_label, 8, 0);
lv_obj_set_style_pad_left(view->networks_label, 2, 0);
lv_obj_set_align(view->networks_label, LV_ALIGN_LEFT_MID);
lv_obj_t* networks_header = lv_obj_create(parent);
lv_obj_set_size(networks_header, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_style_min_height(networks_header, SPINNER_HEIGHT, 0);
tt_lv_obj_set_style_no_padding(networks_header);
lv_obj_set_style_border_width(networks_header, 0, 0);
view->scanning_spinner = lv_spinner_create(parent, 1000, 60);
view->networks_label = lv_label_create(networks_header);
lv_label_set_text(view->networks_label, "Networks");
lv_obj_align(view->networks_label, LV_ALIGN_LEFT_MID, 0, 0);
view->scanning_spinner = lv_spinner_create(networks_header, 1000, 60);
lv_obj_set_size(view->scanning_spinner, SPINNER_HEIGHT, SPINNER_HEIGHT);
lv_obj_set_style_pad_top(view->scanning_spinner, 4, 0);
lv_obj_set_style_pad_bottom(view->scanning_spinner, 4, 0);
lv_obj_align_to(view->scanning_spinner, view->networks_label, LV_ALIGN_OUT_RIGHT_MID, 8, 0);
view->networks_list = lv_obj_create(parent);
lv_obj_set_flex_flow(view->networks_list, LV_FLEX_FLOW_COLUMN);

View File

@ -25,6 +25,7 @@ Gui* gui_alloc() {
NULL
);
instance->mutex = tt_mutex_alloc(MutexTypeRecursive);
instance->keyboard = NULL;
tt_check(lvgl_port_lock(100));
instance->lvgl_parent = lv_scr_act();
@ -66,6 +67,35 @@ void gui_show_app(App app, ViewPortShowCallback on_show, ViewPortHideCallback on
gui_request_draw();
}
void gui_keyboard_show(lv_obj_t* textarea) {
if (gui->keyboard) {
gui_lock();
lv_obj_clear_flag(gui->keyboard, LV_OBJ_FLAG_HIDDEN);
lv_keyboard_set_textarea(gui->keyboard, textarea);
if (gui->toolbar) {
lv_obj_add_flag(gui->toolbar, LV_OBJ_FLAG_HIDDEN);
}
gui_unlock();
}
}
void gui_keyboard_hide() {
if (gui->keyboard) {
gui_lock();
lv_obj_add_flag(gui->keyboard, LV_OBJ_FLAG_HIDDEN);
if (gui->toolbar) {
lv_obj_clear_flag(gui->toolbar, LV_OBJ_FLAG_HIDDEN);
}
gui_unlock();
}
}
void gui_hide_app() {
gui_lock();
ViewPort* view_port = gui->app_view_port;

View File

@ -14,6 +14,10 @@ void gui_show_app(App app, ViewPortShowCallback on_show, ViewPortHideCallback on
void gui_hide_app();
void gui_keyboard_show(lv_obj_t* textarea);
void gui_keyboard_hide();
#ifdef __cplusplus
}
#endif

View File

@ -10,7 +10,7 @@
#define TAG "gui"
static lv_obj_t* create_app_views(lv_obj_t* parent, App app) {
static lv_obj_t* create_app_views(Gui* gui, lv_obj_t* parent, App app) {
tt_lv_obj_set_style_bg_blacken(parent);
lv_obj_t* vertical_container = lv_obj_create(parent);
@ -25,6 +25,7 @@ static lv_obj_t* create_app_views(lv_obj_t* parent, App app) {
tt_lv_statusbar_create(vertical_container);
}
gui->toolbar = NULL;
if (flags.show_toolbar) {
const AppManifest* manifest = tt_app_get_manifest(app);
if (manifest != NULL) {
@ -40,6 +41,7 @@ static lv_obj_t* create_app_views(lv_obj_t* parent, App app) {
// Black area between toolbar and content below
lv_obj_t* spacer = tt_lv_spacer_create(vertical_container, 1, 2);
tt_lv_obj_set_style_bg_blacken(spacer);
gui->toolbar = toolbar_widget;
}
}
@ -47,6 +49,9 @@ static lv_obj_t* create_app_views(lv_obj_t* parent, App app) {
lv_obj_set_width(child_container, LV_PCT(100));
lv_obj_set_flex_grow(child_container, 1);
gui->keyboard = lv_keyboard_create(vertical_container);
lv_obj_add_flag(gui->keyboard, LV_OBJ_FLAG_HIDDEN);
return child_container;
}
@ -60,9 +65,9 @@ void gui_redraw(Gui* gui) {
lv_obj_clean(gui->lvgl_parent);
ViewPort* view_port = gui->app_view_port;
if (view_port!= NULL) {
if (view_port != NULL) {
App app = view_port->app;
lv_obj_t* container = create_app_views(gui->lvgl_parent, app);
lv_obj_t* container = create_app_views(gui, gui->lvgl_parent, app);
view_port_show(view_port, container);
} else {
TT_LOG_W(TAG, "nothing to draw");

View File

@ -24,6 +24,9 @@ struct Gui {
// App-specific
ViewPort* app_view_port;
lv_obj_t* _Nullable toolbar;
lv_obj_t* _Nullable keyboard;
};
/** Update GUI, request redraw