v2 Phase 2: app-launcher navigation shell
Replace the splash<->usage tap-toggle with a home + launcher model. Tapping the Claude logo on the home (usage) screen opens a scrollable 2-column launcher driven by an app registry — adding a screen is one registry line plus a builder, no edits to shared navigation. A shared back chevron returns launcher->home and app->launcher; tapping the splash returns to home. Screens wired: Usage (home) and Animations (splash) are real; Bluetooth shows live connection state + device name + MAC; Soundpad/Session/Now Playing/Home point at a shared "coming soon" stub until their phases land. Enable Montserrat 20/28 for the LVGL symbol glyphs used by tile icons and the back chevron (the brand Styrene/Tiempos fonts are Latin-only). Flash 20.3% -> 20.9%. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -157,6 +157,11 @@ build_flags =
|
|||||||
-DLV_USE_ANIMIMG=0
|
-DLV_USE_ANIMIMG=0
|
||||||
-DLV_TICK_CUSTOM=1
|
-DLV_TICK_CUSTOM=1
|
||||||
-DLV_USE_SNAPSHOT=1
|
-DLV_USE_SNAPSHOT=1
|
||||||
|
; Montserrat carries the LVGL symbol glyphs (FontAwesome subset) used for the
|
||||||
|
; v2 launcher tile icons and the back chevron. The brand Styrene/Tiempos fonts
|
||||||
|
; are Latin-only and have no symbols.
|
||||||
|
-DLV_FONT_MONTSERRAT_20=1
|
||||||
|
-DLV_FONT_MONTSERRAT_28=1
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
; 1.6.4+ ships Arduino_CO5300 in mainline
|
; 1.6.4+ ships Arduino_CO5300 in mainline
|
||||||
|
|||||||
+253
-9
@@ -119,6 +119,36 @@ static lv_obj_t* battery_img;
|
|||||||
static lv_obj_t* logo_img;
|
static lv_obj_t* logo_img;
|
||||||
static lv_image_dsc_t battery_dscs[5]; // empty, low, medium, full, charging
|
static lv_image_dsc_t battery_dscs[5]; // empty, low, medium, full, charging
|
||||||
|
|
||||||
|
// ---- v2 navigation: launcher, stub & bluetooth screens ----
|
||||||
|
static lv_obj_t* nav_back_btn; // top-left back chevron (shown off the home screen)
|
||||||
|
static lv_obj_t* menu_container; // app launcher (scrollable tile grid)
|
||||||
|
static lv_obj_t* stub_container; // generic "coming soon" screen, retitled per app
|
||||||
|
static lv_obj_t* stub_title;
|
||||||
|
static lv_obj_t* stub_icon;
|
||||||
|
static lv_obj_t* bt_container; // BLE connection info
|
||||||
|
static lv_obj_t* bt_status_lbl;
|
||||||
|
static lv_obj_t* bt_name_lbl;
|
||||||
|
static lv_obj_t* bt_mac_lbl;
|
||||||
|
|
||||||
|
// App registry — the launcher renders one tile per entry, so adding a screen is
|
||||||
|
// one line here plus its builder. Order = tile order. "Animations" reuses the
|
||||||
|
// splash; the four future apps open the shared stub until their phase lands.
|
||||||
|
struct AppEntry {
|
||||||
|
screen_t screen;
|
||||||
|
const char* label;
|
||||||
|
const char* symbol; // LVGL/Montserrat symbol glyph
|
||||||
|
};
|
||||||
|
static const AppEntry APPS[] = {
|
||||||
|
{ SCREEN_USAGE, "Usage", LV_SYMBOL_CHARGE },
|
||||||
|
{ SCREEN_SPLASH, "Animations", LV_SYMBOL_IMAGE },
|
||||||
|
{ SCREEN_SOUNDPAD, "Soundpad", LV_SYMBOL_AUDIO },
|
||||||
|
{ SCREEN_SESSION, "Session", LV_SYMBOL_LIST },
|
||||||
|
{ SCREEN_NOWPLAYING, "Now Playing", LV_SYMBOL_PLAY },
|
||||||
|
{ SCREEN_HOMEASSIST, "Home", LV_SYMBOL_HOME },
|
||||||
|
{ SCREEN_BLUETOOTH, "Bluetooth", LV_SYMBOL_BLUETOOTH },
|
||||||
|
};
|
||||||
|
#define APP_COUNT (sizeof(APPS) / sizeof(APPS[0]))
|
||||||
|
|
||||||
// ---- Live-data freshness → which usage sub-view to show ----
|
// ---- Live-data freshness → which usage sub-view to show ----
|
||||||
// usage panels when data is flowing, an idle "Zzz" screen when the host is
|
// usage panels when data is flowing, an idle "Zzz" screen when the host is
|
||||||
// connected but no usage update landed within DATA_FRESH_MS, the pairing hint
|
// connected but no usage update landed within DATA_FRESH_MS, the pairing hint
|
||||||
@@ -209,6 +239,8 @@ static void format_reset_time(int mins, char* buf, size_t len) {
|
|||||||
|
|
||||||
// Forward decls — callbacks defined near ui_show_screen below
|
// Forward decls — callbacks defined near ui_show_screen below
|
||||||
static void global_click_cb(lv_event_t* e);
|
static void global_click_cb(lv_event_t* e);
|
||||||
|
static void logo_click_cb(lv_event_t* e);
|
||||||
|
static void nav_back_cb(lv_event_t* e);
|
||||||
|
|
||||||
static lv_obj_t* make_panel(lv_obj_t* parent, int x, int y, int w, int h) {
|
static lv_obj_t* make_panel(lv_obj_t* parent, int x, int y, int w, int h) {
|
||||||
lv_obj_t* panel = lv_obj_create(parent);
|
lv_obj_t* panel = lv_obj_create(parent);
|
||||||
@@ -362,7 +394,6 @@ static void init_usage_screen(lv_obj_t* scr) {
|
|||||||
lv_obj_set_style_border_width(usage_container, 0, 0);
|
lv_obj_set_style_border_width(usage_container, 0, 0);
|
||||||
lv_obj_set_style_pad_all(usage_container, 0, 0);
|
lv_obj_set_style_pad_all(usage_container, 0, 0);
|
||||||
lv_obj_clear_flag(usage_container, LV_OBJ_FLAG_SCROLLABLE);
|
lv_obj_clear_flag(usage_container, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
lv_obj_add_event_cb(usage_container, global_click_cb, LV_EVENT_CLICKED, NULL);
|
|
||||||
|
|
||||||
lbl_title = lv_label_create(usage_container);
|
lbl_title = lv_label_create(usage_container);
|
||||||
lv_label_set_text(lbl_title, "Usage");
|
lv_label_set_text(lbl_title, "Usage");
|
||||||
@@ -400,6 +431,166 @@ static void init_usage_screen(lv_obj_t* scr) {
|
|||||||
lv_obj_align(lbl_anim, LV_ALIGN_BOTTOM_MID, 0, -15);
|
lv_obj_align(lbl_anim, LV_ALIGN_BOTTOM_MID, 0, -15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ======== v2: launcher, stub & bluetooth screens ========
|
||||||
|
|
||||||
|
static const AppEntry* app_for_screen(screen_t s) {
|
||||||
|
for (size_t i = 0; i < APP_COUNT; i++)
|
||||||
|
if (APPS[i].screen == s) return &APPS[i];
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Centered screen title for the navigation screens. The back chevron lives in
|
||||||
|
// the shared top-left chrome (nav_back_btn), so only the title is drawn here.
|
||||||
|
static lv_obj_t* make_screen_title(lv_obj_t* parent, const char* text) {
|
||||||
|
lv_obj_t* t = lv_label_create(parent);
|
||||||
|
lv_label_set_text(t, text);
|
||||||
|
lv_obj_set_style_text_font(t, &font_styrene_28, 0);
|
||||||
|
lv_obj_set_style_text_color(t, COL_TEXT, 0);
|
||||||
|
lv_obj_align(t, LV_ALIGN_TOP_MID, 16, L.title_y);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tile_click_cb(lv_event_t* e) {
|
||||||
|
screen_t s = (screen_t)(intptr_t)lv_event_get_user_data(e);
|
||||||
|
ui_show_screen(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static lv_obj_t* make_tile(lv_obj_t* parent, const AppEntry* app, int w, int h) {
|
||||||
|
lv_obj_t* tile = lv_obj_create(parent);
|
||||||
|
lv_obj_set_size(tile, w, h);
|
||||||
|
lv_obj_set_style_bg_color(tile, COL_PANEL, 0);
|
||||||
|
lv_obj_set_style_bg_opa(tile, LV_OPA_COVER, 0);
|
||||||
|
lv_obj_set_style_radius(tile, 16, 0);
|
||||||
|
lv_obj_set_style_border_width(tile, 0, 0);
|
||||||
|
lv_obj_set_style_pad_all(tile, 6, 0);
|
||||||
|
lv_obj_set_flex_flow(tile, LV_FLEX_FLOW_COLUMN);
|
||||||
|
lv_obj_set_flex_align(tile, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||||
|
lv_obj_clear_flag(tile, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
lv_obj_add_flag(tile, LV_OBJ_FLAG_CLICKABLE);
|
||||||
|
lv_obj_add_event_cb(tile, tile_click_cb, LV_EVENT_CLICKED, (void*)(intptr_t)app->screen);
|
||||||
|
|
||||||
|
lv_obj_t* icon = lv_label_create(tile);
|
||||||
|
lv_label_set_text(icon, app->symbol);
|
||||||
|
lv_obj_set_style_text_font(icon, &lv_font_montserrat_28, 0);
|
||||||
|
lv_obj_set_style_text_color(icon, COL_ACCENT, 0);
|
||||||
|
|
||||||
|
lv_obj_t* lbl = lv_label_create(tile);
|
||||||
|
lv_label_set_text(lbl, app->label);
|
||||||
|
lv_obj_set_style_text_font(lbl, &font_styrene_16, 0);
|
||||||
|
lv_obj_set_style_text_color(lbl, COL_TEXT, 0);
|
||||||
|
lv_obj_set_style_pad_top(lbl, 6, 0);
|
||||||
|
return tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_menu_screen(lv_obj_t* scr) {
|
||||||
|
menu_container = lv_obj_create(scr);
|
||||||
|
lv_obj_set_size(menu_container, L.scr_w, L.scr_h);
|
||||||
|
lv_obj_set_pos(menu_container, 0, 0);
|
||||||
|
lv_obj_set_style_bg_opa(menu_container, LV_OPA_TRANSP, 0);
|
||||||
|
lv_obj_set_style_border_width(menu_container, 0, 0);
|
||||||
|
lv_obj_set_style_pad_all(menu_container, 0, 0);
|
||||||
|
lv_obj_clear_flag(menu_container, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
|
||||||
|
make_screen_title(menu_container, "Menu");
|
||||||
|
|
||||||
|
// Scrollable 2-column tile grid — wraps and scrolls vertically as the app
|
||||||
|
// registry grows, so new screens need no layout changes here.
|
||||||
|
lv_obj_t* grid = lv_obj_create(menu_container);
|
||||||
|
lv_obj_set_size(grid, L.content_w, L.scr_h - L.content_y - L.margin);
|
||||||
|
lv_obj_set_pos(grid, L.margin, L.content_y);
|
||||||
|
lv_obj_set_style_bg_opa(grid, LV_OPA_TRANSP, 0);
|
||||||
|
lv_obj_set_style_border_width(grid, 0, 0);
|
||||||
|
lv_obj_set_style_pad_all(grid, 0, 0);
|
||||||
|
lv_obj_set_style_pad_row(grid, 12, 0);
|
||||||
|
lv_obj_set_style_pad_column(grid, 12, 0);
|
||||||
|
lv_obj_set_flex_flow(grid, LV_FLEX_FLOW_ROW_WRAP);
|
||||||
|
lv_obj_set_flex_align(grid, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||||
|
lv_obj_set_scroll_dir(grid, LV_DIR_VER);
|
||||||
|
lv_obj_set_scrollbar_mode(grid, LV_SCROLLBAR_MODE_AUTO);
|
||||||
|
|
||||||
|
int tile_w = (L.content_w - 16) / 2; // 4px slack so two fit per row beside a scrollbar
|
||||||
|
int tile_h = 116;
|
||||||
|
for (size_t i = 0; i < APP_COUNT; i++)
|
||||||
|
make_tile(grid, &APPS[i], tile_w, tile_h);
|
||||||
|
|
||||||
|
lv_obj_add_flag(menu_container, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// One generic "coming soon" screen, retitled per app in stub_show_for(). The
|
||||||
|
// four future apps (Soundpad/Session/Now Playing/Home) point here until built.
|
||||||
|
static void init_stub_screen(lv_obj_t* scr) {
|
||||||
|
stub_container = lv_obj_create(scr);
|
||||||
|
lv_obj_set_size(stub_container, L.scr_w, L.scr_h);
|
||||||
|
lv_obj_set_pos(stub_container, 0, 0);
|
||||||
|
lv_obj_set_style_bg_opa(stub_container, LV_OPA_TRANSP, 0);
|
||||||
|
lv_obj_set_style_border_width(stub_container, 0, 0);
|
||||||
|
lv_obj_set_style_pad_all(stub_container, 0, 0);
|
||||||
|
lv_obj_clear_flag(stub_container, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
|
||||||
|
stub_title = make_screen_title(stub_container, "");
|
||||||
|
|
||||||
|
stub_icon = lv_label_create(stub_container);
|
||||||
|
lv_label_set_text(stub_icon, LV_SYMBOL_SETTINGS);
|
||||||
|
lv_obj_set_style_text_font(stub_icon, &lv_font_montserrat_28, 0);
|
||||||
|
lv_obj_set_style_text_color(stub_icon, COL_DIM, 0);
|
||||||
|
lv_obj_align(stub_icon, LV_ALIGN_CENTER, 0, -20);
|
||||||
|
|
||||||
|
lv_obj_t* soon = lv_label_create(stub_container);
|
||||||
|
lv_label_set_text(soon, "coming soon");
|
||||||
|
lv_obj_set_style_text_font(soon, &font_styrene_20, 0);
|
||||||
|
lv_obj_set_style_text_color(soon, COL_DIM, 0);
|
||||||
|
lv_obj_align(soon, LV_ALIGN_CENTER, 0, 30);
|
||||||
|
|
||||||
|
lv_obj_add_flag(stub_container, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_bt_screen(lv_obj_t* scr) {
|
||||||
|
bt_container = lv_obj_create(scr);
|
||||||
|
lv_obj_set_size(bt_container, L.scr_w, L.scr_h);
|
||||||
|
lv_obj_set_pos(bt_container, 0, 0);
|
||||||
|
lv_obj_set_style_bg_opa(bt_container, LV_OPA_TRANSP, 0);
|
||||||
|
lv_obj_set_style_border_width(bt_container, 0, 0);
|
||||||
|
lv_obj_set_style_pad_all(bt_container, 0, 0);
|
||||||
|
lv_obj_clear_flag(bt_container, LV_OBJ_FLAG_SCROLLABLE);
|
||||||
|
|
||||||
|
make_screen_title(bt_container, "Bluetooth");
|
||||||
|
|
||||||
|
bt_status_lbl = lv_label_create(bt_container);
|
||||||
|
lv_label_set_text(bt_status_lbl, "");
|
||||||
|
lv_obj_set_style_text_font(bt_status_lbl, &font_styrene_28, 0);
|
||||||
|
lv_obj_align(bt_status_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 20);
|
||||||
|
|
||||||
|
bt_name_lbl = lv_label_create(bt_container);
|
||||||
|
lv_label_set_text(bt_name_lbl, "");
|
||||||
|
lv_obj_set_style_text_font(bt_name_lbl, &font_styrene_20, 0);
|
||||||
|
lv_obj_set_style_text_color(bt_name_lbl, COL_DIM, 0);
|
||||||
|
lv_obj_align(bt_name_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 80);
|
||||||
|
|
||||||
|
bt_mac_lbl = lv_label_create(bt_container);
|
||||||
|
lv_label_set_text(bt_mac_lbl, "");
|
||||||
|
lv_obj_set_style_text_font(bt_mac_lbl, &font_styrene_20, 0);
|
||||||
|
lv_obj_set_style_text_color(bt_mac_lbl, COL_DIM, 0);
|
||||||
|
lv_obj_align(bt_mac_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 120);
|
||||||
|
|
||||||
|
lv_obj_add_flag(bt_container, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bt_refresh(void) {
|
||||||
|
if (!bt_container) return;
|
||||||
|
lv_label_set_text(bt_status_lbl, s_ble_connected ? "Connected" : "Waiting");
|
||||||
|
lv_obj_set_style_text_color(bt_status_lbl, s_ble_connected ? COL_GREEN : COL_AMBER, 0);
|
||||||
|
lv_label_set_text_fmt(bt_name_lbl, "%s", ble_get_device_name());
|
||||||
|
lv_label_set_text_fmt(bt_mac_lbl, "%s", ble_get_mac_address());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stub_show_for(screen_t s) {
|
||||||
|
const AppEntry* app = app_for_screen(s);
|
||||||
|
if (app) {
|
||||||
|
lv_label_set_text(stub_title, app->label);
|
||||||
|
lv_label_set_text(stub_icon, app->symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ======== Public API ========
|
// ======== Public API ========
|
||||||
|
|
||||||
void ui_init(void) {
|
void ui_init(void) {
|
||||||
@@ -419,14 +610,32 @@ void ui_init(void) {
|
|||||||
lv_obj_add_event_cb(splash_get_root(), global_click_cb, LV_EVENT_CLICKED, NULL);
|
lv_obj_add_event_cb(splash_get_root(), global_click_cb, LV_EVENT_CLICKED, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// v2 screens — created hidden, shown on navigation.
|
||||||
|
init_menu_screen(scr);
|
||||||
|
init_stub_screen(scr);
|
||||||
|
init_bt_screen(scr);
|
||||||
|
|
||||||
logo_img = lv_image_create(scr);
|
logo_img = lv_image_create(scr);
|
||||||
lv_image_set_src(logo_img, &logo_dsc);
|
lv_image_set_src(logo_img, &logo_dsc);
|
||||||
lv_obj_set_pos(logo_img, L.margin, L.title_y - 10);
|
lv_obj_set_pos(logo_img, L.margin, L.title_y - 10);
|
||||||
|
lv_obj_add_flag(logo_img, LV_OBJ_FLAG_CLICKABLE); // tap the Claude logo → launcher
|
||||||
|
lv_obj_set_ext_click_area(logo_img, 14);
|
||||||
|
lv_obj_add_event_cb(logo_img, logo_click_cb, LV_EVENT_CLICKED, NULL);
|
||||||
|
|
||||||
|
// Back chevron — shared across the menu/app screens, hidden on home/splash.
|
||||||
|
nav_back_btn = lv_label_create(scr);
|
||||||
|
lv_label_set_text(nav_back_btn, LV_SYMBOL_LEFT);
|
||||||
|
lv_obj_set_style_text_font(nav_back_btn, &lv_font_montserrat_28, 0);
|
||||||
|
lv_obj_set_style_text_color(nav_back_btn, COL_TEXT, 0);
|
||||||
|
lv_obj_set_pos(nav_back_btn, L.margin, L.title_y);
|
||||||
|
lv_obj_add_flag(nav_back_btn, LV_OBJ_FLAG_CLICKABLE);
|
||||||
|
lv_obj_set_ext_click_area(nav_back_btn, 18);
|
||||||
|
lv_obj_add_event_cb(nav_back_btn, nav_back_cb, LV_EVENT_CLICKED, NULL);
|
||||||
|
lv_obj_add_flag(nav_back_btn, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
|
||||||
battery_img = lv_image_create(scr);
|
battery_img = lv_image_create(scr);
|
||||||
lv_image_set_src(battery_img, &battery_dscs[0]);
|
lv_image_set_src(battery_img, &battery_dscs[0]);
|
||||||
lv_obj_set_pos(battery_img, L.scr_w - 48 - L.margin, L.title_y);
|
lv_obj_set_pos(battery_img, L.scr_w - 48 - L.margin, L.title_y);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ui_update(const UsageData* data) {
|
void ui_update(const UsageData* data) {
|
||||||
@@ -520,29 +729,64 @@ static void apply_battery_visibility(void) {
|
|||||||
else lv_obj_clear_flag(battery_img, LV_OBJ_FLAG_HIDDEN);
|
else lv_obj_clear_flag(battery_img, LV_OBJ_FLAG_HIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tapping the splash/animations screen returns to the home (usage) screen.
|
||||||
static void global_click_cb(lv_event_t* e) {
|
static void global_click_cb(lv_event_t* e) {
|
||||||
(void)e;
|
(void)e;
|
||||||
if (current_screen == SCREEN_SPLASH) ui_show_screen(prev_non_splash_screen);
|
if (current_screen == SCREEN_SPLASH) ui_show_screen(SCREEN_USAGE);
|
||||||
else ui_show_screen(SCREEN_SPLASH);
|
}
|
||||||
|
|
||||||
|
// The Claude logo on the home screen opens the launcher.
|
||||||
|
static void logo_click_cb(lv_event_t* e) {
|
||||||
|
(void)e;
|
||||||
|
ui_show_screen(SCREEN_MENU);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Back chevron: from the launcher → home; from any app screen → launcher.
|
||||||
|
static void nav_back_cb(lv_event_t* e) {
|
||||||
|
(void)e;
|
||||||
|
ui_show_screen(current_screen == SCREEN_MENU ? SCREEN_USAGE : SCREEN_MENU);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top-left chrome: the Claude logo (tap → menu) on home, the back chevron on the
|
||||||
|
// screens below it, neither on the splash.
|
||||||
|
static void update_nav_chrome(screen_t screen) {
|
||||||
|
bool show_logo = (screen == SCREEN_USAGE);
|
||||||
|
bool show_back = (screen != SCREEN_USAGE && screen != SCREEN_SPLASH);
|
||||||
|
if (logo_img) {
|
||||||
|
if (show_logo) lv_obj_clear_flag(logo_img, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
else lv_obj_add_flag(logo_img, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
}
|
||||||
|
if (nav_back_btn) {
|
||||||
|
if (show_back) lv_obj_clear_flag(nav_back_btn, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
else lv_obj_add_flag(nav_back_btn, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ui_show_screen(screen_t screen) {
|
void ui_show_screen(screen_t screen) {
|
||||||
lv_obj_add_flag(usage_container, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(usage_container, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
if (menu_container) lv_obj_add_flag(menu_container, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
if (stub_container) lv_obj_add_flag(stub_container, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
if (bt_container) lv_obj_add_flag(bt_container, LV_OBJ_FLAG_HIDDEN);
|
||||||
splash_hide();
|
splash_hide();
|
||||||
|
|
||||||
switch (screen) {
|
switch (screen) {
|
||||||
case SCREEN_SPLASH: splash_show(); break;
|
case SCREEN_SPLASH: splash_show(); break;
|
||||||
case SCREEN_USAGE: lv_obj_clear_flag(usage_container, LV_OBJ_FLAG_HIDDEN); break;
|
case SCREEN_USAGE: lv_obj_clear_flag(usage_container, LV_OBJ_FLAG_HIDDEN); break;
|
||||||
|
case SCREEN_MENU: lv_obj_clear_flag(menu_container, LV_OBJ_FLAG_HIDDEN); break;
|
||||||
|
case SCREEN_BLUETOOTH: bt_refresh(); lv_obj_clear_flag(bt_container, LV_OBJ_FLAG_HIDDEN); break;
|
||||||
|
case SCREEN_SOUNDPAD:
|
||||||
|
case SCREEN_SESSION:
|
||||||
|
case SCREEN_NOWPLAYING:
|
||||||
|
case SCREEN_HOMEASSIST:
|
||||||
|
stub_show_for(screen);
|
||||||
|
lv_obj_clear_flag(stub_container, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logo_img) {
|
|
||||||
if (screen == SCREEN_SPLASH) lv_obj_add_flag(logo_img, LV_OBJ_FLAG_HIDDEN);
|
|
||||||
else lv_obj_clear_flag(logo_img, LV_OBJ_FLAG_HIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (screen != SCREEN_SPLASH) prev_non_splash_screen = screen;
|
if (screen != SCREEN_SPLASH) prev_non_splash_screen = screen;
|
||||||
current_screen = screen;
|
current_screen = screen;
|
||||||
|
update_nav_chrome(screen);
|
||||||
apply_battery_visibility();
|
apply_battery_visibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -3,8 +3,14 @@
|
|||||||
#include "ble.h"
|
#include "ble.h"
|
||||||
|
|
||||||
enum screen_t {
|
enum screen_t {
|
||||||
SCREEN_SPLASH,
|
SCREEN_SPLASH, // brand animation (boot) + "Animations" app
|
||||||
SCREEN_USAGE,
|
SCREEN_USAGE, // home: Claude usage
|
||||||
|
SCREEN_MENU, // app launcher (opened by tapping the Claude logo)
|
||||||
|
SCREEN_SOUNDPAD, // 6-key HID soundpad (Phase 3)
|
||||||
|
SCREEN_SESSION, // today's tokens / cost (Phase 4)
|
||||||
|
SCREEN_NOWPLAYING, // media now-playing (Phase 5)
|
||||||
|
SCREEN_HOMEASSIST, // Home Assistant controls (Phase 6)
|
||||||
|
SCREEN_BLUETOOTH, // BLE connection info
|
||||||
SCREEN_COUNT,
|
SCREEN_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user