#include #include #include #include #include #include #include "loader.h" #include "loader_menu.h" #define TAG "LoaderMenu" struct LoaderMenu { FuriThread* thread; void (*closed_cb)(void*); void* context; }; static int32_t loader_menu_thread(void* p); LoaderMenu* loader_menu_alloc(void (*closed_cb)(void*), void* context) { LoaderMenu* loader_menu = malloc(sizeof(LoaderMenu)); loader_menu->closed_cb = closed_cb; loader_menu->context = context; loader_menu->thread = furi_thread_alloc_ex(TAG, 1024, loader_menu_thread, loader_menu); furi_thread_start(loader_menu->thread); return loader_menu; } void loader_menu_free(LoaderMenu* loader_menu) { furi_assert(loader_menu); furi_thread_join(loader_menu->thread); furi_thread_free(loader_menu->thread); free(loader_menu); } typedef enum { LoaderMenuViewPrimary, LoaderMenuViewSettings, } LoaderMenuView; typedef struct { Gui* gui; ViewDispatcher* view_dispatcher; Menu* primary_menu; Submenu* settings_menu; } LoaderMenuApp; static void loader_menu_start(const char* name) { Loader* loader = furi_record_open(RECORD_LOADER); loader_start_with_gui_error(loader, name, NULL); furi_record_close(RECORD_LOADER); } static void loader_menu_apps_callback(void* context, uint32_t index) { UNUSED(context); const char* name = FLIPPER_APPS[index].name; loader_menu_start(name); } static void loader_menu_external_apps_callback(void* context, uint32_t index) { UNUSED(context); const char* path = FLIPPER_EXTERNAL_APPS[index].name; loader_menu_start(path); } static void loader_menu_applications_callback(void* context, uint32_t index) { UNUSED(index); UNUSED(context); const char* name = LOADER_APPLICATIONS_NAME; loader_menu_start(name); } static void loader_menu_settings_menu_callback(void* context, uint32_t index) { UNUSED(context); const char* name = FLIPPER_SETTINGS_APPS[index].name; loader_menu_start(name); } static void loader_menu_switch_to_settings(void* context, uint32_t index) { UNUSED(index); LoaderMenuApp* app = context; view_dispatcher_switch_to_view(app->view_dispatcher, LoaderMenuViewSettings); } static uint32_t loader_menu_switch_to_primary(void* context) { UNUSED(context); return LoaderMenuViewPrimary; } static uint32_t loader_menu_exit(void* context) { UNUSED(context); return VIEW_NONE; } static void loader_menu_build_menu(LoaderMenuApp* app, LoaderMenu* menu) { size_t i = 0; menu_add_item( app->primary_menu, LOADER_APPLICATIONS_NAME, &A_Plugins_14, i++, loader_menu_applications_callback, (void*)menu); for(i = 0; i < FLIPPER_APPS_COUNT; i++) { menu_add_item( app->primary_menu, FLIPPER_APPS[i].name, FLIPPER_APPS[i].icon, i, loader_menu_apps_callback, (void*)menu); } for(i = 0; i < FLIPPER_EXTERNAL_APPS_COUNT; i++) { menu_add_item( app->primary_menu, FLIPPER_EXTERNAL_APPS[i].name, FLIPPER_EXTERNAL_APPS[i].icon, i, loader_menu_external_apps_callback, (void*)menu); } menu_add_item( app->primary_menu, "Settings", &A_Settings_14, i++, loader_menu_switch_to_settings, app); }; static void loader_menu_build_submenu(LoaderMenuApp* app, LoaderMenu* loader_menu) { for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { submenu_add_item( app->settings_menu, FLIPPER_SETTINGS_APPS[i].name, i, loader_menu_settings_menu_callback, loader_menu); } } static LoaderMenuApp* loader_menu_app_alloc(LoaderMenu* loader_menu) { LoaderMenuApp* app = malloc(sizeof(LoaderMenuApp)); app->gui = furi_record_open(RECORD_GUI); app->view_dispatcher = view_dispatcher_alloc(); app->primary_menu = menu_alloc(); app->settings_menu = submenu_alloc(); loader_menu_build_menu(app, loader_menu); loader_menu_build_submenu(app, loader_menu); // Primary menu View* primary_view = menu_get_view(app->primary_menu); view_set_context(primary_view, app->primary_menu); view_set_previous_callback(primary_view, loader_menu_exit); view_dispatcher_add_view(app->view_dispatcher, LoaderMenuViewPrimary, primary_view); // Settings menu View* settings_view = submenu_get_view(app->settings_menu); view_set_context(settings_view, app->settings_menu); view_set_previous_callback(settings_view, loader_menu_switch_to_primary); view_dispatcher_add_view(app->view_dispatcher, LoaderMenuViewSettings, settings_view); view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_switch_to_view(app->view_dispatcher, LoaderMenuViewPrimary); return app; } static void loader_menu_app_free(LoaderMenuApp* app) { view_dispatcher_remove_view(app->view_dispatcher, LoaderMenuViewPrimary); view_dispatcher_remove_view(app->view_dispatcher, LoaderMenuViewSettings); view_dispatcher_free(app->view_dispatcher); menu_free(app->primary_menu); submenu_free(app->settings_menu); furi_record_close(RECORD_GUI); free(app); } static int32_t loader_menu_thread(void* p) { LoaderMenu* loader_menu = p; furi_assert(loader_menu); LoaderMenuApp* app = loader_menu_app_alloc(loader_menu); view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); view_dispatcher_run(app->view_dispatcher); if(loader_menu->closed_cb) { loader_menu->closed_cb(loader_menu->context); } loader_menu_app_free(app); return 0; }