diff --git a/ext_components/cp0_lvgl/src/cp0/cp0_lvgl_keyboard.c b/ext_components/cp0_lvgl/src/cp0/cp0_lvgl_keyboard.c index db217a9..aaf7db6 100644 --- a/ext_components/cp0_lvgl/src/cp0/cp0_lvgl_keyboard.c +++ b/ext_components/cp0_lvgl/src/cp0/cp0_lvgl_keyboard.c @@ -110,15 +110,6 @@ __attribute__((weak)) void ui_global_hint_on_key(const struct key_item *elm) (void)elm; } -/* Optional idle screen-blanking ("DarkTime") hook, provided by the launcher. - * Returns 1 if the key was swallowed only to wake the screen and must not be - * delivered to the UI. Weak no-op for apps that don't implement it. */ -__attribute__((weak)) int ui_darkscreen_filter_key(const struct key_item *elm) -{ - (void)elm; - return 0; -} - static const char *getenv_default(const char *name, const char *dflt) { const char *value = getenv(name); @@ -185,23 +176,15 @@ static void cp0_keypad_read_cb(lv_indev_t *indev, lv_indev_data_t *data) elm->key_code, kbd_state_name(elm->key_state), elm->sym_name, utf8_dbg, elm->codepoint, (void *)lv_screen_active()); - /* DarkTime: if the screen is blanked this key only wakes it and must - * not reach the UI (nor the keypad indev) so it doesn't also act. */ - int swallowed = ui_darkscreen_filter_key(elm); - - if (!swallowed) { - lv_obj_t *root = lv_screen_active(); - if (root) - lv_obj_send_event(root, (lv_event_code_t)LV_EVENT_KEYBOARD, elm); + lv_obj_t *root = lv_screen_active(); + if (root) + lv_obj_send_event(root, (lv_event_code_t)LV_EVENT_KEYBOARD, elm); - ui_global_hint_on_key(elm); + ui_global_hint_on_key(elm); - data->key = cp0_evdev_process_key(elm->key_code); - if (data->key) { - data->state = (lv_indev_state_t)elm->key_state; - data->continue_reading = !STAILQ_EMPTY(&keyboard_queue); - } - } else { + data->key = cp0_evdev_process_key(elm->key_code); + if (data->key) { + data->state = (lv_indev_state_t)elm->key_state; data->continue_reading = !STAILQ_EMPTY(&keyboard_queue); } free(elm); diff --git a/ext_components/cp0_lvgl/src/cp0/cp0_lvgl_network.cpp b/ext_components/cp0_lvgl/src/cp0/cp0_lvgl_network.cpp index b927d24..40d7000 100644 --- a/ext_components/cp0_lvgl/src/cp0/cp0_lvgl_network.cpp +++ b/ext_components/cp0_lvgl/src/cp0/cp0_lvgl_network.cpp @@ -403,8 +403,16 @@ class WifiSystem if (state_connected || has_connection) { st.connected = 1; wifi_iface = device; - if (has_connection) - cp0_copy_string(st.ssid, sizeof(st.ssid), connection); + if (has_connection) { + // Imager/netplan-provisioned networks are named + // "netplan--". Strip that prefix so the UI + // shows the plain SSID instead of the profile name (#66). + std::string display = connection; + const std::string prefix = "netplan-" + device + "-"; + if (display.rfind(prefix, 0) == 0) + display = display.substr(prefix.size()); + cp0_copy_string(st.ssid, sizeof(st.ssid), display.c_str()); + } } } } diff --git a/ext_components/cp0_lvgl/src/sdl/sdl_lvgl_keyboard.c b/ext_components/cp0_lvgl/src/sdl/sdl_lvgl_keyboard.c index ef830f6..3599633 100644 --- a/ext_components/cp0_lvgl/src/sdl/sdl_lvgl_keyboard.c +++ b/ext_components/cp0_lvgl/src/sdl/sdl_lvgl_keyboard.c @@ -26,12 +26,6 @@ typedef struct { static void cp0_sdl_keyboard_read(lv_indev_t *indev, lv_indev_data_t *data); static void cp0_sdl_keyboard_delete_cb(lv_event_t *event); -__attribute__((weak)) int ui_darkscreen_filter_key(const struct key_item *elm) -{ - (void)elm; - return 0; -} - __attribute__((weak)) void ui_global_hint_on_key(const struct key_item *elm) { (void)elm; @@ -519,21 +513,15 @@ static void cp0_sdl_keyboard_read(lv_indev_t *indev, lv_indev_data_t *data) struct key_item *elm = STAILQ_FIRST(&keyboard_queue); STAILQ_REMOVE_HEAD(&keyboard_queue, entries); - int swallowed = ui_darkscreen_filter_key(elm); - - if (!swallowed) { - lv_obj_t *root = lv_screen_active(); - if (root != NULL) - lv_obj_send_event(root, (lv_event_code_t)LV_EVENT_KEYBOARD, elm); + lv_obj_t *root = lv_screen_active(); + if (root != NULL) + lv_obj_send_event(root, (lv_event_code_t)LV_EVENT_KEYBOARD, elm); - ui_global_hint_on_key(elm); + ui_global_hint_on_key(elm); - data->key = cp0_evdev_process_key(elm->key_code); - if (data->key) { - data->state = (lv_indev_state_t)elm->key_state; - data->continue_reading = !STAILQ_EMPTY(&keyboard_queue); - } - } else { + data->key = cp0_evdev_process_key(elm->key_code); + if (data->key) { + data->state = (lv_indev_state_t)elm->key_state; data->continue_reading = !STAILQ_EMPTY(&keyboard_queue); } free(elm); diff --git a/projects/APPLaunch/main/src/main.cpp b/projects/APPLaunch/main/src/main.cpp index e32332e..41d9361 100644 --- a/projects/APPLaunch/main/src/main.cpp +++ b/projects/APPLaunch/main/src/main.cpp @@ -12,7 +12,6 @@ #include #include #include "ui/ui.h" -#include "ui/ui_darkscreen.h" #include "keyboard_input.h" #include "cp0_lvgl_app.h" #include "cp0_lvgl_file.hpp" @@ -95,12 +94,6 @@ int main(void) /*Handle LVGL tasks*/ SLOGI("Entering main loop (FULL render mode)..."); - // while(1) { - // // APPLaunch_lock(); - // // ui_darkscreen_tick(); - // lv_timer_handler(); - // usleep(5000); - // } while (1) { uint32_t ms = lv_timer_handler(); if (ms == LV_NO_TIMER_READY) { diff --git a/projects/APPLaunch/main/ui/launch.cpp b/projects/APPLaunch/main/ui/launch.cpp index 0dd570d..45e65ef 100644 --- a/projects/APPLaunch/main/ui/launch.cpp +++ b/projects/APPLaunch/main/ui/launch.cpp @@ -360,6 +360,25 @@ void Launch::applications_load() continue; } + // Never let a third-party *.desktop shadow a built-in app: if the Exec + // matches a built-in, the built-in registry owns visibility. Otherwise a + // built-in the user hid (removed from app_list) would silently reappear + // here as a "third-party" entry (#59). + bool shadows_builtin = false; + for (const auto ®istration : kBuiltinApps) + { + if (registration.exec && app_exec == registration.exec) + { + shadows_builtin = true; + break; + } + } + if (shadows_builtin) + { + fprintf(stderr, "applications_load: skip %s (shadows built-in app)\n", filepath.c_str()); + continue; + } + app_list.emplace_back(page_title, cp0_file_path(app_icon), app_exec, app_terminal, app_sysplause); } diff --git a/projects/APPLaunch/main/ui/page_app/ui_app_setup.hpp b/projects/APPLaunch/main/ui/page_app/ui_app_setup.hpp index 2a63022..0b13e42 100644 --- a/projects/APPLaunch/main/ui/page_app/ui_app_setup.hpp +++ b/projects/APPLaunch/main/ui/page_app/ui_app_setup.hpp @@ -251,7 +251,6 @@ class UISetupPage : public AppPage m.label = "Screen"; m.sub_items = { {"Brightness", false, false, [this]() { enter_brightness_adjust(); }}, - {"DarkTime", false, false, [this]() { enter_darktime_adjust(); }}, }; menu_items_.push_back(m); } @@ -422,16 +421,6 @@ class UISetupPage : public AppPage m.on_enter = [this]() { refresh_version_info(); }; menu_items_.push_back(m); } - // --- Reset --- - { - MenuItem m; - m.label = "Reset"; - m.sub_items = { - {"Run Setup Wizard", false, false, [this]() { enter_confirm_action("Run Setup?", [this](){ rearm_oobe_and_reboot(); }); }}, - {"Factory Reset", false, false, [this]() { factory_reset(); }}, - }; - menu_items_.push_back(m); - } // --- SoundCard --- { MenuItem m; @@ -445,20 +434,6 @@ class UISetupPage : public AppPage } // ==================== Placeholder functions for new menus ==================== - void enter_darktime_adjust() - { - val_title_ = "DarkTime"; - val_options_ = {"Never", "10S", "30S", "60S", "300S"}; - const int times[] = {0, 10, 30, 60, 300}; - int saved = config_get_int("dark_time", 30); // default 30S - val_sel_idx_ = 2; - for (int i = 0; i < (int)(sizeof(times) / sizeof(times[0])); ++i) { - if (times[i] == saved) { val_sel_idx_ = i; break; } - } - view_state_ = ViewState::VALUE_SELECT; - transition_enter_level(); - } - void enter_volume_adjust() { val_title_ = "Volume"; @@ -1104,6 +1079,13 @@ class UISetupPage : public AppPage void save_app_toggle(const std::string &config_key) { + // Locate the Launcher menu by label instead of assuming a fixed index, + // so reordering the menu list can't desync the toggle from its app. + int launcher_idx = find_menu("Launcher"); + if (launcher_idx < 0) + return; + MenuItem &launcher_menu = menu_items_[launcher_idx]; + std::size_t app_count = 0; const AppDescriptor *apps = launcher_app_registry_entries(&app_count); int visible_idx = 0; @@ -1112,7 +1094,9 @@ class UISetupPage : public AppPage if (!desc.configurable) continue; if (config_key == desc.config_key) { - bool enabled = menu_items_[0].sub_items[visible_idx].toggle_state; + if (visible_idx >= (int)launcher_menu.sub_items.size()) + return; + bool enabled = launcher_menu.sub_items[visible_idx].toggle_state; launcher_app_registry_set_enabled(desc, enabled); config_save(); launcher_app_registry_notify_changed(); @@ -1976,12 +1960,6 @@ class UISetupPage : public AppPage config_save(); } else if (val_title_ == "Volume") { apply_volume(); - } else if (val_title_ == "DarkTime") { - // Idle screen-blank timeout in seconds (0 = Never); consumed by - // ui_darkscreen_tick() in the launcher main loop (#72). - int times[] = {0, 10, 30, 60, 300}; - config_set_int("dark_time", times[val_sel_idx_]); - config_save(); } else if (val_title_ == "Resolution") { config_set_int("cam_resolution", val_sel_idx_); config_save(); @@ -2442,7 +2420,7 @@ class UISetupPage : public AppPage else if (cur_sub.is_toggle && item.label == "Bluetooth" && cur_sub.label == "Named Only") lv_label_set_text(hint, cur_sub.toggle_state ? "ok:show all" : "ok:named"); else if (cur_sub.is_toggle) - lv_label_set_text(hint, cur_sub.toggle_state ? "ok:hide" : "ok:select"); + lv_label_set_text(hint, cur_sub.toggle_state ? "ok:hide" : "ok:show"); else if (item.label == "RTC" && rtc_ntp_on_) lv_label_set_text(hint, "ntp on"); else @@ -2491,7 +2469,7 @@ class UISetupPage : public AppPage lv_obj_set_style_border_width(bar, 0, LV_PART_MAIN); lv_obj_clear_flag(bar, LV_OBJ_FLAG_SCROLLABLE); - // Left column: sub-items (Brightness/DarkTime) as carousel at MENU_X + // Left column: sub-items (Brightness) as carousel at MENU_X lv_obj_t *val_left_lbl = nullptr; for (int vi = 0; vi < ROWS_VISIBLE; ++vi) { int si = sub_selected_idx_ - ROW_CENTER + vi; diff --git a/projects/APPLaunch/main/ui/ui_darkscreen.cpp b/projects/APPLaunch/main/ui/ui_darkscreen.cpp deleted file mode 100644 index bcc48c4..0000000 --- a/projects/APPLaunch/main/ui/ui_darkscreen.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD - * - * SPDX-License-Identifier: MIT - */ - -/* - * ui_darkscreen.cpp — see ui_darkscreen.h for the feature description (#72). - */ - -#include "ui_darkscreen.h" - -#include "lvgl/lvgl.h" -#include "keyboard_input.h" -#include "cp0_lvgl_app.h" -#include "hal_lvgl_bsp.h" - -#include - -/* Cached state ----------------------------------------------------------- */ -static uint32_t s_last_activity_tick = 0; /* lv_tick_get() of last key */ -static bool s_dark = false; /* screen currently blanked */ -static int s_saved_backlight = -1; /* brightness before blanking */ -static lv_obj_t *s_black = nullptr; - -/* The key that woke the screen is swallowed (press + repeats + its release) - * so it does not also trigger a UI action. */ -static uint32_t s_swallow_code = 0; -static bool s_swallow_active = false; - -/* Tracks LVGL_RUN_FLAGE edges so we can reset the idle timer when the - * launcher regains the foreground after a sub-app exits. */ -static int s_prev_run = 1; - -static int config_get_int(const char *key, int default_val) -{ - int val = default_val; - cp0_signal_config_api({"GetInt", key ? std::string(key) : std::string(), std::to_string(default_val)}, - [&](int code, std::string data) { - if (code == 0) val = std::atoi(data.c_str()); - }); - return val; -} - -/* Configured idle timeout in seconds (0 = Never). Defaults to 30s. */ -static int darkscreen_timeout_secs() -{ - return config_get_int("dark_time", 30); -} - -static void ensure_black_overlay() -{ - if (s_black != nullptr) return; - lv_obj_t *parent = lv_layer_top(); - if (parent == nullptr) return; - - s_black = lv_obj_create(parent); - lv_obj_remove_style_all(s_black); - - lv_display_t *disp = lv_display_get_default(); - int w = disp ? lv_display_get_horizontal_resolution(disp) : 320; - int h = disp ? lv_display_get_vertical_resolution(disp) : 170; - lv_obj_set_size(s_black, w, h); - lv_obj_set_pos(s_black, 0, 0); - - lv_obj_set_style_bg_color(s_black, lv_color_black(), 0); - lv_obj_set_style_bg_opa(s_black, LV_OPA_COVER, 0); - lv_obj_set_style_border_width(s_black, 0, 0); - lv_obj_set_style_radius(s_black, 0, 0); - lv_obj_set_style_pad_all(s_black, 0, 0); - - lv_obj_clear_flag(s_black, LV_OBJ_FLAG_CLICKABLE); - lv_obj_clear_flag(s_black, LV_OBJ_FLAG_SCROLLABLE); - lv_obj_add_flag(s_black, LV_OBJ_FLAG_IGNORE_LAYOUT); - lv_obj_add_flag(s_black, LV_OBJ_FLAG_HIDDEN); -} - -static void darkscreen_go_dark() -{ - if (s_dark) return; - - s_saved_backlight = cp0_backlight_read(); - if (s_saved_backlight <= 0) - s_saved_backlight = config_get_int("brightness", -1); - if (s_saved_backlight <= 0) - s_saved_backlight = cp0_backlight_max(); - - ensure_black_overlay(); - if (s_black) { - lv_obj_move_foreground(s_black); - lv_obj_clear_flag(s_black, LV_OBJ_FLAG_HIDDEN); - } - /* Paint the black frame before cutting the backlight so no stale UI flashes. */ - lv_refr_now(NULL); - cp0_backlight_write(0); - s_dark = true; -} - -static void darkscreen_wake() -{ - if (!s_dark) return; - - int b = s_saved_backlight; - if (b <= 0) b = config_get_int("brightness", -1); - if (b <= 0) b = cp0_backlight_max(); - if (b <= 0) b = 50; - cp0_backlight_write(b); - - if (s_black) - lv_obj_add_flag(s_black, LV_OBJ_FLAG_HIDDEN); - lv_obj_invalidate(lv_screen_active()); - - s_dark = false; - s_last_activity_tick = lv_tick_get(); -} - -extern "C" int ui_darkscreen_filter_key(const struct key_item *elm) -{ - if (elm == nullptr) return 0; - - s_last_activity_tick = lv_tick_get(); - - /* Mid-swallow: keep eating the waking key's events until it is released. */ - if (s_swallow_active) { - if (elm->key_code == s_swallow_code) { - if (elm->key_state == KBD_KEY_RELEASED) - s_swallow_active = false; - return 1; - } - s_swallow_active = false; /* a different key: stop swallowing */ - } - - if (s_dark) { - darkscreen_wake(); - s_swallow_code = elm->key_code; - s_swallow_active = (elm->key_state != KBD_KEY_RELEASED); - return 1; - } - return 0; -} - -extern "C" void ui_darkscreen_tick(void) -{ - int run = LVGL_RUN_FLAGE; - - /* Just regained the foreground (a sub-app exited): restart the idle clock - * so we don't immediately blank, and drop any pending swallow state. */ - if (run == 1 && s_prev_run != 1) { - s_last_activity_tick = lv_tick_get(); - s_swallow_active = false; - } - s_prev_run = run; - - /* Only the foreground launcher blanks; leave sub-apps untouched. */ - if (run != 1) return; - - int secs = darkscreen_timeout_secs(); - if (secs <= 0) { /* Never */ - if (s_dark) darkscreen_wake(); - return; - } - if (s_dark) return; - - if (s_last_activity_tick == 0) - s_last_activity_tick = lv_tick_get(); - - if (lv_tick_elaps(s_last_activity_tick) >= (uint32_t)secs * 1000u) - darkscreen_go_dark(); -} diff --git a/projects/APPLaunch/main/ui/ui_darkscreen.h b/projects/APPLaunch/main/ui/ui_darkscreen.h deleted file mode 100644 index 6ae5519..0000000 --- a/projects/APPLaunch/main/ui/ui_darkscreen.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD - * - * SPDX-License-Identifier: MIT - */ - -/* - * ui_darkscreen.h - * - * "DarkTime" idle screen blanking for the launcher (#72). - * - * After the configured idle timeout ("dark_time" seconds, 0 = Never) with no - * key activity, the launcher turns the backlight off AND paints a full-screen - * black overlay so the panel is fully dark. Any key press wakes it again; that - * waking key is swallowed so it does not also trigger an action. - * - * Only active while the launcher is the foreground process - * (LVGL_RUN_FLAGE == 1); sub-apps are unaffected. - */ - -#ifndef UI_DARKSCREEN_H -#define UI_DARKSCREEN_H - -#ifdef __cplusplus -extern "C" { -#endif - -struct key_item; - -/* Call once per main-loop iteration. Blanks the screen after the configured - * idle timeout while the launcher is in the foreground. */ -void ui_darkscreen_tick(void); - -/* Per-key hook, invoked from the central keyboard dispatch BEFORE the key is - * delivered to the UI. Resets the idle timer on every key. Returns 1 if the - * key was swallowed (used only to wake the screen) and must NOT reach the UI; - * returns 0 otherwise. */ -int ui_darkscreen_filter_key(const struct key_item *elm); - -#ifdef __cplusplus -} -#endif - -#endif /* UI_DARKSCREEN_H */