diff --git a/.gitignore b/.gitignore index 81a8981f739..dd6a4750db6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ dist/* .vscode .clang-format +.clangd .editorconfig .env .ufbt diff --git a/quac.h b/quac.h index 2aa2f538287..1371214322a 100644 --- a/quac.h +++ b/quac.h @@ -16,7 +16,7 @@ #include "views/action_menu.h" #include "item.h" -#define QUAC_NAME "Quac!" +#define QUAC_NAME "Quac!" #define QUAC_VERSION "v0.6.3" #define QUAC_ABOUT \ "Quick Action remote control\n" QUAC_VERSION "\n" \ @@ -25,9 +25,12 @@ // Location of our actions and folders #define QUAC_SETTINGS_FILENAME ".quac.conf" -#define QUAC_SETTINGS_PATH APP_DATA_PATH(QUAC_SETTINGS_FILENAME) +#define QUAC_SETTINGS_PATH APP_DATA_PATH(QUAC_SETTINGS_FILENAME) -typedef enum { QUAC_APP_PORTRAIT, QUAC_APP_LANDSCAPE } QuacAppLayout; +typedef enum { + QUAC_APP_PORTRAIT, + QUAC_APP_LANDSCAPE +} QuacAppLayout; typedef struct App { SceneManager* scene_manager; @@ -49,6 +52,7 @@ typedef struct App { FuriString* temp_str; // used for renames/etc char temp_cstr[MAX_NAME_LEN]; // used for renames/etc + uint32_t temp_u32; struct { QuacAppLayout layout; // Defaults to Portrait @@ -65,4 +69,4 @@ typedef struct App { } App; App* app_alloc(); -void app_free(App* app); \ No newline at end of file +void app_free(App* app); diff --git a/scenes/scene_action_ir_list.c b/scenes/scene_action_ir_list.c index d8380ace677..4313f5e604e 100644 --- a/scenes/scene_action_ir_list.c +++ b/scenes/scene_action_ir_list.c @@ -27,10 +27,14 @@ void scene_action_ir_list_on_enter(void* context) { // Our selected IR File is app->temp_str submenu_set_header(menu, "Select IR Command"); + uint32_t index = 0; + + // Add an entry for IMPORT ALL + submenu_add_item(menu, "* IMPORT ALL *", index++, scene_action_ir_list_callback, app); + // read the IR file and load the names of all of the commands FuriString* name = furi_string_alloc(); - uint32_t index = 0; FlipperFormat* fff_data_file = flipper_format_file_alloc(app->storage); if(flipper_format_file_open_existing(fff_data_file, furi_string_get_cstr(app->temp_str))) { while(flipper_format_read_string(fff_data_file, "name", name)) { @@ -40,8 +44,11 @@ void scene_action_ir_list_on_enter(void* context) { } } - if(index == 0) { - FURI_LOG_E(TAG, "Failed to get commands from %s", furi_string_get_cstr(app->temp_str)); + // Number of IR Commands in file + app->temp_u32 = index - 1; + if(app->temp_u32 == 0) { + FURI_LOG_E(TAG, "Failed to get ANY commands from %s", furi_string_get_cstr(app->temp_str)); + submenu_change_item_label(menu, 0, "No IR cmds!"); } flipper_format_file_close(fff_data_file); @@ -66,42 +73,63 @@ bool scene_action_ir_list_on_event(void* context, SceneManagerEvent event) { FuriString* file_name = furi_string_alloc(); // new IR file name do { - if(!flipper_format_file_open_existing( - fff_data_file, furi_string_get_cstr(app->temp_str))) { - FURI_LOG_E(TAG, "Failed to open %s", furi_string_get_cstr(app->temp_str)); - break; + uint32_t num_imported = 0; + uint32_t start = index - 1; + uint32_t end = index; + if(index == 0) { + start = 0; + end = app->temp_u32; // Number of IR Commands in file } - if(!infrared_utils_read_signal_at_index(fff_data_file, index, signal, name)) { - FURI_LOG_E(TAG, "Failed to read signal at %lu", index); - break; + for(uint32_t ir_index = start; ir_index < end; ir_index++) { + if(!flipper_format_file_open_existing( + fff_data_file, furi_string_get_cstr(app->temp_str))) { + FURI_LOG_E(TAG, "Failed to open %s", furi_string_get_cstr(app->temp_str)); + break; + } + + if(!infrared_utils_read_signal_at_index(fff_data_file, ir_index, signal, name)) { + FURI_LOG_E(TAG, "Failed to read signal at %lu", index); + break; + } + FURI_LOG_I(TAG, "Read IR signal: %s", furi_string_get_cstr(name)); + flipper_format_file_close(fff_data_file); + + // generate the new path, based on current item's dir and new command name + if(app->selected_item != EMPTY_ACTION_INDEX) { + Item* item = ItemArray_get(app->items_view->items, app->selected_item); + path_extract_dirname(furi_string_get_cstr(item->path), file_name); + } else { + furi_string_set(file_name, app->items_view->path); + } + furi_string_cat_printf(file_name, "/%s.ir", furi_string_get_cstr(name)); + + FURI_LOG_I(TAG, "Writing new IR file: %s", furi_string_get_cstr(file_name)); + if(!flipper_format_file_open_new(fff_data_file, furi_string_get_cstr(file_name))) { + FURI_LOG_E( + TAG, "Error creating new file: %s", furi_string_get_cstr(file_name)); + break; + } + if(!infrared_utils_write_signal(fff_data_file, signal, name)) { + FURI_LOG_E(TAG, "Failed to write signal!"); + break; + } + flipper_format_file_close(fff_data_file); + FURI_LOG_I(TAG, "Imported %s", furi_string_get_cstr(name)); + num_imported++; } - FURI_LOG_I(TAG, "Read IR signal: %s", furi_string_get_cstr(name)); - flipper_format_file_close(fff_data_file); - // generate the new path, based on current item's dir and new command name - if(app->selected_item != EMPTY_ACTION_INDEX) { - Item* item = ItemArray_get(app->items_view->items, app->selected_item); - path_extract_dirname(furi_string_get_cstr(item->path), file_name); + if(num_imported == (end - start)) { + // Import successful! + notification_message(app->notifications, &sequence_success); } else { - furi_string_set(file_name, app->items_view->path); + FURI_LOG_E( + TAG, + "Error importing IR command(s) from %s", + furi_string_get_cstr(app->temp_str)); + notification_message(app->notifications, &sequence_error); } - furi_string_cat_printf(file_name, "/%s.ir", furi_string_get_cstr(name)); - - FURI_LOG_I(TAG, "Writing new IR file: %s", furi_string_get_cstr(file_name)); - if(!flipper_format_file_open_new(fff_data_file, furi_string_get_cstr(file_name))) { - FURI_LOG_E(TAG, "Error creating new file: %s", furi_string_get_cstr(file_name)); - break; - } - if(!infrared_utils_write_signal(fff_data_file, signal, name)) { - FURI_LOG_E(TAG, "Failed to write signal!"); - break; - } - - // Import successful! // Leave the user on this scene, in case they want to import // more commands from this IR file - notification_message(app->notifications, &sequence_success); - } while(false); // cleanup