// Native app-shell bindings. Visual creation stays in menu_layout/menu_runtime. // Names, icons and PIO order follow ui/app_catalog_builder.cpp. #include "ui/app_runtime.h" #include "ui/app_catalog.h" #include "ui/app_catalog_builder.h" #include #include "ui/menu/menu_layout.h" #include "ui/menu/menu_runtime.h" #include "ui/runtime/ui_feedback.h" #include extern "C" void native_open_page(int page); static bool menu_created=false; static AppScreen* active_app=nullptr; static ui::AppCatalog catalog; static int page_for(const char* id) { const char* ids[]={"calculator","sky_plot","usb_mass_storage","walkie_talkie","sstv","chat","","","extensions","network","","settings","contacts","team","tracker","map","energy_sweep"}; for(int i=0;i<17;++i)if(std::strcmp(ids[i],id)==0)return i; return -1; } void preview_menu_enter() { if(!menu_created) { auto* previous_group=app_g; ui::app_catalog_builder::FeatureFlags flags; flags.include_usb=true;flags.include_network=true;flags.include_walkie_talkie=true;flags.include_power_off=true; #if defined(ARDUINO_T_DECK) flags.include_sstv=false; flags.include_walkie_talkie=false; #endif catalog=ui::app_catalog_builder::build(flags); ui::menu_layout::InitOptions options; options.apps=catalog; ui::menu_layout::init(options); if(previous_group) lv_group_delete(previous_group); ui::menu_runtime::Hooks hooks; hooks.format_time=[](char* out,size_t n){std::snprintf(out,n,"09:41");return true;}; hooks.show_main_menu=[](){native_open_page(10);}; ui::menu_runtime::init(lv_screen_active(),main_screen,ui::menu_layout::menuPanel(),hooks); menu_created=true; } lv_obj_clear_flag(main_screen,LV_OBJ_FLAG_HIDDEN); lv_tileview_set_tile_by_index(main_screen, 0, 0, LV_ANIM_OFF); ui::menu_layout::setMenuVisible(true); ui::menu_runtime::setScene(ui::menu_runtime::Scene::Menu); set_default_group(menu_g); } void preview_menu_exit() { if(menu_created){ui::menu_runtime::setScene(ui::menu_runtime::Scene::App);lv_obj_add_flag(main_screen,LV_OBJ_FLAG_HIDDEN);} } bool ui_is_interruption_app_active(){return false;} bool ui_is_overlay_active(){return false;} AppScreen* ui_get_active_app(){return active_app;} void ui_switch_to_app(AppScreen* app,lv_obj_t* parent){active_app=app;const int page=page_for(app->stable_id());if(page>=0)native_open_page(page);else app->enter(parent);} void ui_clear_active_app(){active_app=nullptr;} void ui_exit_active_app(lv_obj_t* parent){if(active_app)active_app->exit(parent);active_app=nullptr;} void menu_show(){native_open_page(10);} void preview_power_enter() { preview_menu_enter(); for(size_t i=0;istable_id(),"shutdown")==0){app->enter(nullptr==main_screen?lv_screen_active():main_screen);return;}} } static lv_obj_t* cancel_button(lv_obj_t* obj) { if(lv_obj_check_type(obj,&lv_label_class)&&std::strcmp(lv_label_get_text(obj),"Cancel")==0&&lv_obj_check_type(lv_obj_get_parent(obj),&lv_button_class))return lv_obj_get_parent(obj); for(uint32_t i=0;i