diff --git a/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_mainmenu.c b/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_mainmenu.c index 4a5b5779d..6855bef01 100644 --- a/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_mainmenu.c +++ b/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_mainmenu.c @@ -24,7 +24,7 @@ static void xtreme_app_scene_interface_mainmenu_app_changed(VariableItem* item) XtremeApp* app = variable_item_get_context(item); app->mainmenu_app_index = variable_item_get_current_value_index(item); variable_item_set_current_value_text( - item, *CharList_get(app->mainmenu_app_names, app->mainmenu_app_index)); + item, *CharList_get(app->mainmenu_app_labels, app->mainmenu_app_index)); } void xtreme_app_scene_interface_mainmenu_on_enter(void* context) { @@ -42,14 +42,14 @@ void xtreme_app_scene_interface_mainmenu_on_enter(void* context) { item = variable_item_list_add( var_item_list, "App", - CharList_size(app->mainmenu_app_names), + CharList_size(app->mainmenu_app_labels), xtreme_app_scene_interface_mainmenu_app_changed, app); app->mainmenu_app_index = 0; variable_item_set_current_value_index(item, app->mainmenu_app_index); - if(CharList_size(app->mainmenu_app_names)) { + if(CharList_size(app->mainmenu_app_labels)) { variable_item_set_current_value_text( - item, *CharList_get(app->mainmenu_app_names, app->mainmenu_app_index)); + item, *CharList_get(app->mainmenu_app_labels, app->mainmenu_app_index)); } else { variable_item_set_current_value_text(item, "None"); } @@ -78,12 +78,12 @@ bool xtreme_app_scene_interface_mainmenu_on_event(void* context, SceneManagerEve consumed = true; switch(event.event) { case VarItemListIndexRemoveApp: - if(!CharList_size(app->mainmenu_app_names)) break; - if(!CharList_size(app->mainmenu_app_paths)) break; + if(!CharList_size(app->mainmenu_app_labels)) break; + if(!CharList_size(app->mainmenu_app_exes)) break; CharList_remove_v( - app->mainmenu_app_names, app->mainmenu_app_index, app->mainmenu_app_index + 1); + app->mainmenu_app_labels, app->mainmenu_app_index, app->mainmenu_app_index + 1); CharList_remove_v( - app->mainmenu_app_paths, app->mainmenu_app_index, app->mainmenu_app_index + 1); + app->mainmenu_app_exes, app->mainmenu_app_index, app->mainmenu_app_index + 1); app->save_mainmenu_apps = true; app->require_reboot = true; scene_manager_previous_scene(app->scene_manager); diff --git a/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_mainmenu_add.c b/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_mainmenu_add.c index dd9336022..3333be089 100644 --- a/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_mainmenu_add.c +++ b/applications/main/xtreme_app/scenes/xtreme_app_scene_interface_mainmenu_add.c @@ -30,11 +30,11 @@ void xtreme_app_scene_interface_mainmenu_add_on_enter(void* context) { }; if(dialog_file_browser_show(app->dialogs, string, string, &browser_options)) { - CharList_push_back(app->mainmenu_app_paths, strdup(furi_string_get_cstr(string))); + CharList_push_back(app->mainmenu_app_exes, strdup(furi_string_get_cstr(string))); Storage* storage = furi_record_open(RECORD_STORAGE); flipper_application_load_name_and_icon(string, storage, NULL, string); furi_record_close(RECORD_STORAGE); - CharList_push_back(app->mainmenu_app_names, strdup(furi_string_get_cstr(string))); + CharList_push_back(app->mainmenu_app_labels, strdup(furi_string_get_cstr(string))); app->save_mainmenu_apps = true; app->require_reboot = true; } diff --git a/applications/main/xtreme_app/xtreme_app.c b/applications/main/xtreme_app/xtreme_app.c index 3e6b50a5b..b5a930ed8 100644 --- a/applications/main/xtreme_app/xtreme_app.c +++ b/applications/main/xtreme_app/xtreme_app.c @@ -16,11 +16,12 @@ bool xtreme_app_apply(XtremeApp* app) { if(app->save_mainmenu_apps) { Stream* stream = file_stream_alloc(storage); - if(file_stream_open(stream, XTREME_APPS_PATH, FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)) { + if(file_stream_open(stream, XTREME_MENU_PATH, FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)) { + stream_write_format(stream, "MenuAppList Version %u\n", 0); CharList_it_t it; - CharList_it(it, app->mainmenu_app_paths); - for(size_t i = 0; i < CharList_size(app->mainmenu_app_paths); i++) { - stream_write_format(stream, "%s\n", *CharList_get(app->mainmenu_app_paths, i)); + CharList_it(it, app->mainmenu_app_exes); + for(size_t i = 0; i < CharList_size(app->mainmenu_app_exes); i++) { + stream_write_format(stream, "%s\n", *CharList_get(app->mainmenu_app_exes, i)); } } file_stream_close(stream); @@ -227,17 +228,18 @@ XtremeApp* xtreme_app_alloc() { free(name); storage_file_free(folder); - CharList_init(app->mainmenu_app_names); - CharList_init(app->mainmenu_app_paths); + CharList_init(app->mainmenu_app_labels); + CharList_init(app->mainmenu_app_exes); Stream* stream = file_stream_alloc(storage); FuriString* line = furi_string_alloc(); - if(file_stream_open(stream, XTREME_APPS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + if(file_stream_open(stream, XTREME_MENU_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + stream_read_line(stream, line); while(stream_read_line(stream, line)) { furi_string_replace_all(line, "\r", ""); furi_string_replace_all(line, "\n", ""); - CharList_push_back(app->mainmenu_app_paths, strdup(furi_string_get_cstr(line))); + CharList_push_back(app->mainmenu_app_exes, strdup(furi_string_get_cstr(line))); flipper_application_load_name_and_icon(line, storage, NULL, line); - CharList_push_back(app->mainmenu_app_names, strdup(furi_string_get_cstr(line))); + CharList_push_back(app->mainmenu_app_labels, strdup(furi_string_get_cstr(line))); } } furi_string_free(line); @@ -314,14 +316,14 @@ void xtreme_app_free(XtremeApp* app) { } CharList_clear(app->asset_pack_names); - for(CharList_it(it, app->mainmenu_app_names); !CharList_end_p(it); CharList_next(it)) { + for(CharList_it(it, app->mainmenu_app_labels); !CharList_end_p(it); CharList_next(it)) { free(*CharList_cref(it)); } - CharList_clear(app->mainmenu_app_names); - for(CharList_it(it, app->mainmenu_app_paths); !CharList_end_p(it); CharList_next(it)) { + CharList_clear(app->mainmenu_app_labels); + for(CharList_it(it, app->mainmenu_app_exes); !CharList_end_p(it); CharList_next(it)) { free(*CharList_cref(it)); } - CharList_clear(app->mainmenu_app_paths); + CharList_clear(app->mainmenu_app_exes); FrequencyList_clear(app->subghz_static_freqs); FrequencyList_clear(app->subghz_hopper_freqs); diff --git a/applications/main/xtreme_app/xtreme_app.h b/applications/main/xtreme_app/xtreme_app.h index 4089eb820..cce1d1b85 100644 --- a/applications/main/xtreme_app/xtreme_app.h +++ b/applications/main/xtreme_app/xtreme_app.h @@ -42,8 +42,8 @@ typedef struct { CharList_t asset_pack_names; uint8_t asset_pack_index; - CharList_t mainmenu_app_names; - CharList_t mainmenu_app_paths; + CharList_t mainmenu_app_labels; + CharList_t mainmenu_app_exes; uint8_t mainmenu_app_index; bool subghz_use_defaults; FrequencyList_t subghz_static_freqs; diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index 6a7e7bb1d..e0b7305dd 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -134,9 +134,9 @@ FuriPubSub* loader_get_pubsub(Loader* loader) { return loader->pubsub; } -ExtMainAppList_t* loader_get_ext_main_apps(Loader* loader) { +MenuAppList_t* loader_get_menu_apps(Loader* loader) { furi_assert(loader); - return &loader->ext_main_apps; + return &loader->menu_apps; } // callbacks @@ -195,6 +195,31 @@ bool loader_menu_load_fap_meta( return true; } +static void loader_make_menu_file(Storage* storage) { + Stream* new = file_stream_alloc(storage); + if(!storage_file_exists(storage, XTREME_MENU_PATH)) { + if(file_stream_open(new, XTREME_MENU_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS)) { + stream_write_format(new, "MenuAppList Version %u\n", 0); + for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { + stream_write_format(new, "%s\n", FLIPPER_APPS[i].name); + } + for(size_t i = 0; i < FLIPPER_EXTERNAL_APPS_COUNT - 1; i++) { + stream_write_format(new, "%s\n", FLIPPER_EXTERNAL_APPS[i].name); + } + Stream* old = file_stream_alloc(storage); + if(file_stream_open(old, XTREME_MENU_OLD_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { + stream_copy(old, new, stream_size(old)); + } + file_stream_close(old); + stream_free(old); + storage_common_remove(storage, XTREME_MENU_OLD_PATH); + } + file_stream_close(new); + } + file_stream_close(new); + stream_free(new); +} + static Loader* loader_alloc() { Loader* loader = malloc(sizeof(Loader)); loader->pubsub = furi_pubsub_alloc(); @@ -205,33 +230,76 @@ static Loader* loader_alloc() { loader->app.thread = NULL; loader->app.insomniac = false; loader->app.fap = NULL; - ExtMainAppList_init(loader->ext_main_apps); + MenuAppList_init(loader->menu_apps); - if(furi_hal_is_normal_boot()) { - Storage* storage = furi_record_open(RECORD_STORAGE); - FuriString* path = furi_string_alloc(); - FuriString* name = furi_string_alloc(); - Stream* stream = file_stream_alloc(storage); - if(file_stream_open(stream, XTREME_APPS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { - while(stream_read_line(stream, path)) { - furi_string_replace_all(path, "\r", ""); - furi_string_replace_all(path, "\n", ""); - const Icon* icon; - if(!loader_menu_load_fap_meta(storage, path, name, &icon)) continue; - ExtMainAppList_push_back( - loader->ext_main_apps, - (ExtMainApp){ - .name = strdup(furi_string_get_cstr(name)), - .path = strdup(furi_string_get_cstr(path)), - .icon = icon}); + if(!furi_hal_is_normal_boot()) return loader; + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* stream = file_stream_alloc(storage); + FuriString* line = furi_string_alloc(); + FuriString* name = furi_string_alloc(); + do { + + if(!file_stream_open(stream, XTREME_MENU_PATH, FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) { + file_stream_close(stream); + loader_make_menu_file(storage); + if(!file_stream_open(stream, XTREME_MENU_PATH, FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) + break; + } + + uint32_t version; + if(!stream_read_line(stream, line) || + sscanf(furi_string_get_cstr(line), "MenuAppList Version %lu", &version) != 1 || + version > 0) { + file_stream_close(stream); + storage_common_remove(storage, XTREME_MENU_PATH); + loader_make_menu_file(storage); + if(!file_stream_open(stream, XTREME_MENU_PATH, FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) + break; + if(!stream_read_line(stream, line) || + sscanf(furi_string_get_cstr(line), "MenuAppList Version %lu", &version) != 1 || + version > 0) + break; + } + + while(stream_read_line(stream, line)) { + furi_string_replace_all(line, "\r", ""); + furi_string_replace_all(line, "\n", ""); + const char* label = NULL; + const Icon* icon = NULL; + const char* exe = NULL; + if(storage_file_exists(storage, furi_string_get_cstr(line))) { + if(loader_menu_load_fap_meta(storage, line, name, &icon)) { + label = strdup(furi_string_get_cstr(name)); + exe = strdup(furi_string_get_cstr(line)); + } + } else { + for(size_t i = 0; !exe && i < FLIPPER_APPS_COUNT; i++) { + if(!strcmp(furi_string_get_cstr(line), FLIPPER_APPS[i].name)) { + label = FLIPPER_APPS[i].name; + icon = FLIPPER_APPS[i].icon; + exe = FLIPPER_APPS[i].name; + } + } + for(size_t i = 0; !exe && i < FLIPPER_EXTERNAL_APPS_COUNT; i++) { + if(!strcmp(furi_string_get_cstr(line), FLIPPER_EXTERNAL_APPS[i].name)) { + label = FLIPPER_EXTERNAL_APPS[i].name; + icon = FLIPPER_EXTERNAL_APPS[i].icon; + exe = FLIPPER_EXTERNAL_APPS[i].name; + } + } + } + if(label && exe && icon) { + MenuAppList_push_back( + loader->menu_apps, (MenuApp){.label = label, .icon = icon, .exe = exe}); } } - file_stream_close(stream); - stream_free(stream); - furi_string_free(name); - furi_string_free(path); - furi_record_close(RECORD_STORAGE); - } + + } while(false); + furi_string_free(name); + furi_string_free(line); + file_stream_close(stream); + stream_free(stream); + furi_record_close(RECORD_STORAGE); return loader; } diff --git a/applications/services/loader/loader_extmainapp.h b/applications/services/loader/loader_extmainapp.h deleted file mode 100644 index 4eeb263c7..000000000 --- a/applications/services/loader/loader_extmainapp.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include -#include - -typedef struct { - const char* name; - const char* path; - const Icon* icon; -} ExtMainApp; - -LIST_DEF(ExtMainAppList, ExtMainApp, M_POD_OPLIST) - -ExtMainAppList_t* loader_get_ext_main_apps(Loader* loader); diff --git a/applications/services/loader/loader_i.h b/applications/services/loader/loader_i.h index 5ed0441ba..c33e6d101 100644 --- a/applications/services/loader/loader_i.h +++ b/applications/services/loader/loader_i.h @@ -4,7 +4,7 @@ #include #include "loader.h" #include "loader_menu.h" -#include "loader_extmainapp.h" +#include "loader_menuapp.h" #include "loader_applications.h" typedef struct { @@ -20,7 +20,7 @@ struct Loader { LoaderMenu* loader_menu; LoaderApplications* loader_applications; LoaderAppData app; - ExtMainAppList_t ext_main_apps; + MenuAppList_t menu_apps; }; typedef enum { diff --git a/applications/services/loader/loader_menu.c b/applications/services/loader/loader_menu.c index d6b0bde09..ac88f7916 100644 --- a/applications/services/loader/loader_menu.c +++ b/applications/services/loader/loader_menu.c @@ -7,7 +7,7 @@ #include "loader.h" #include "loader_menu.h" -#include "loader_extmainapp.h" +#include "loader_menuapp.h" #define TAG "LoaderMenu" @@ -56,23 +56,9 @@ static void loader_menu_start(const char* name) { furi_record_close(RECORD_LOADER); } -static void loader_menu_apps_callback(void* context, uint32_t index) { +static void loader_menu_callback(void* context, uint32_t index) { UNUSED(context); - const char* name_or_path = (const char*)index; - loader_menu_start(name_or_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); + loader_menu_start((const char*)index); } static void loader_menu_switch_to_settings(void* context, uint32_t index) { @@ -96,43 +82,30 @@ static void loader_menu_build_menu(LoaderMenuApp* app, LoaderMenu* menu) { app->primary_menu, LOADER_APPLICATIONS_NAME, &A_Plugins_14, - 0, - loader_menu_applications_callback, + (uint32_t)LOADER_APPLICATIONS_NAME, + loader_menu_callback, (void*)menu); - for(size_t i = 0; i < FLIPPER_EXTERNAL_APPS_COUNT; i++) { - menu_add_item( - app->primary_menu, - FLIPPER_EXTERNAL_APPS[i].name, - FLIPPER_EXTERNAL_APPS[i].icon, - (uint32_t)FLIPPER_EXTERNAL_APPS[i].name, - loader_menu_apps_callback, - (void*)menu); - } - for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { - menu_add_item( - app->primary_menu, - FLIPPER_APPS[i].name, - FLIPPER_APPS[i].icon, - (uint32_t)FLIPPER_APPS[i].name, - loader_menu_apps_callback, - (void*)menu); - } - menu_add_item( - app->primary_menu, "Settings", &A_Settings_14, 0, loader_menu_switch_to_settings, app); Loader* loader = furi_record_open(RECORD_LOADER); - ExtMainAppList_t* ext_main_apps = loader_get_ext_main_apps(loader); - for(size_t i = 0; i < ExtMainAppList_size(*ext_main_apps); i++) { - const ExtMainApp* ext_main_app = ExtMainAppList_get(*ext_main_apps, i); + MenuAppList_t* menu_apps = loader_get_menu_apps(loader); + for(size_t i = 0; i < MenuAppList_size(*menu_apps); i++) { + const MenuApp* menu_app = MenuAppList_get(*menu_apps, i); menu_add_item( app->primary_menu, - ext_main_app->name, - ext_main_app->icon, - (uint32_t)ext_main_app->path, - loader_menu_apps_callback, + menu_app->label, + menu_app->icon, + (uint32_t)menu_app->exe, + loader_menu_callback, (void*)menu); } furi_record_close(RECORD_LOADER); + + const FlipperExternalApplication* last = + &FLIPPER_EXTERNAL_APPS[FLIPPER_EXTERNAL_APPS_COUNT - 1]; + menu_add_item( + app->primary_menu, last->name, last->icon, (uint32_t)last->path, loader_menu_callback, app); + menu_add_item( + app->primary_menu, "Settings", &A_Settings_14, 0, loader_menu_switch_to_settings, app); }; static void loader_menu_build_submenu(LoaderMenuApp* app, LoaderMenu* loader_menu) { @@ -140,8 +113,8 @@ static void loader_menu_build_submenu(LoaderMenuApp* app, LoaderMenu* loader_men submenu_add_item( app->settings_menu, FLIPPER_SETTINGS_APPS[i].name, - i, - loader_menu_settings_menu_callback, + (uint32_t)FLIPPER_SETTINGS_APPS[i].name, + loader_menu_callback, loader_menu); } } diff --git a/applications/services/loader/loader_menuapp.h b/applications/services/loader/loader_menuapp.h new file mode 100644 index 000000000..a2e0da4a5 --- /dev/null +++ b/applications/services/loader/loader_menuapp.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +typedef struct { + const char* label; + const Icon* icon; + const char* exe; +} MenuApp; + +LIST_DEF(MenuAppList, MenuApp, M_POD_OPLIST) + +MenuAppList_t* loader_get_menu_apps(Loader* loader); diff --git a/lib/xtreme/xtreme.h b/lib/xtreme/xtreme.h index cfef8173a..29a76bc52 100644 --- a/lib/xtreme/xtreme.h +++ b/lib/xtreme/xtreme.h @@ -9,7 +9,8 @@ extern "C" { #define XTREME_SETTINGS_PATH CFG_PATH("xtreme_settings.txt") #define XTREME_ASSETS_PATH EXT_PATH("dolphin_custom") -#define XTREME_APPS_PATH CFG_PATH("xtreme_apps.txt") +#define XTREME_MENU_OLD_PATH CFG_PATH("xtreme_apps.txt") +#define XTREME_MENU_PATH CFG_PATH("xtreme_menu.txt") #define XTREME_ASSETS_PACK_NAME_LEN 32 typedef enum {