From 4cf000f27010c904db2e76d7afa78373bfa4aefa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Thu, 24 Jun 2021 00:46:52 +0300 Subject: [PATCH] [FL-1465] Archive application bug fixes. Gui: update TextInput API. (#530) * Update MLib to latest master. * Archive: update string_t usage, add unsafe usage TODO, change model type to blocking and fix invalid usage. * Gui: update text_input API and it's usage. * fix blocking model issues * fix unsafe string_t usage Co-authored-by: Igor Baranov Co-authored-by: its your bedtime <23366927+itsyourbedtime@users.noreply.github.com> --- applications/archive/archive.c | 313 ++++++++++-------- applications/archive/archive_i.h | 6 +- applications/archive/archive_views.c | 21 +- applications/archive/archive_views.h | 4 +- applications/gui-test/gui-test.c | 2 +- applications/gui/modules/text_input.c | 32 +- applications/gui/modules/text_input.h | 10 +- .../ibutton/scene/ibutton-scene-save-name.cpp | 2 +- .../ibutton/scene/ibutton-scene-save-name.h | 2 +- applications/irda/irda-app.cpp | 2 +- applications/irda/irda-app.hpp | 2 +- lib/mlib | 2 +- 12 files changed, 220 insertions(+), 178 deletions(-) diff --git a/applications/archive/archive.c b/applications/archive/archive.c index 93d8d11f..07d6cbfa 100644 --- a/applications/archive/archive.c +++ b/applications/archive/archive.c @@ -5,30 +5,29 @@ static bool archive_get_filenames(ArchiveApp* archive); static void update_offset(ArchiveApp* archive) { furi_assert(archive); - ArchiveViewModel* model = view_get_model(archive->view_archive_main); - size_t array_size = files_array_size(model->files); - uint16_t bounds = array_size > 3 ? 2 : array_size; - - if(model->list_offset < model->idx - bounds) { - model->list_offset = CLAMP(model->list_offset + 1, array_size - (bounds + 2), 0); - } else if(model->list_offset > model->idx - bounds) { - model->list_offset = CLAMP(model->idx - 1, array_size - (bounds), 0); - } - - view_commit_model(archive->view_archive_main, true); + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + size_t array_size = files_array_size(model->files); + uint16_t bounds = array_size > 3 ? 2 : array_size; + if(model->list_offset < model->idx - bounds) { + model->list_offset = CLAMP(model->list_offset + 1, array_size - (bounds + 2), 0); + } else if(model->list_offset > model->idx - bounds) { + model->list_offset = CLAMP(model->idx - 1, array_size - (bounds), 0); + } + return true; + }); } static void archive_update_last_idx(ArchiveApp* archive) { furi_assert(archive); - ArchiveViewModel* model = view_get_model(archive->view_archive_main); - - archive->browser.last_idx[archive->browser.depth] = - CLAMP(model->idx, files_array_size(model->files) - 1, 0); - model->idx = 0; - view_commit_model(archive->view_archive_main, true); - - model = NULL; + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + archive->browser.last_idx[archive->browser.depth] = + CLAMP(model->idx, files_array_size(model->files) - 1, 0); + model->idx = 0; + return true; + }); } static void archive_switch_dir(ArchiveApp* archive, const char* path) { @@ -42,13 +41,12 @@ static void archive_switch_dir(ArchiveApp* archive, const char* path) { static void archive_switch_tab(ArchiveApp* archive) { furi_assert(archive); - ArchiveViewModel* model = view_get_model(archive->view_archive_main); - - model->tab_idx = archive->browser.tab_id; - model->idx = 0; - view_commit_model(archive->view_archive_main, true); - - model = NULL; + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + model->tab_idx = archive->browser.tab_id; + model->idx = 0; + return true; + }); archive->browser.depth = 0; archive_switch_dir(archive, tab_default_paths[archive->browser.tab_id]); @@ -59,23 +57,23 @@ static void archive_switch_tab(ArchiveApp* archive) { static void archive_leave_dir(ArchiveApp* archive) { furi_assert(archive); - char* path_ptr = stringi_get_cstr(archive->browser.path); - char* last_char = strrchr(path_ptr, '/'); - if(last_char) path_ptr[last_char - path_ptr] = '\0'; + size_t last_char = + string_search_rchar(archive->browser.path, '/', string_size(archive->browser.path)); + if(last_char) { + string_right(archive->browser.path, last_char); + } archive->browser.depth = CLAMP(archive->browser.depth - 1, MAX_DEPTH, 0); - ArchiveViewModel* model = view_get_model(archive->view_archive_main); - model->idx = archive->browser.last_idx[archive->browser.depth]; - view_commit_model(archive->view_archive_main, true); + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + model->idx = archive->browser.last_idx[archive->browser.depth]; + return true; + }); archive_switch_dir(archive, string_get_cstr(archive->browser.path)); update_offset(archive); - - model = NULL; - path_ptr = NULL; - last_char = NULL; } static void archive_enter_dir(ArchiveApp* archive, string_t name) { @@ -93,7 +91,7 @@ static void archive_enter_dir(ArchiveApp* archive, string_t name) { update_offset(archive); } -static bool filter_by_extension(ArchiveApp* archive, FileInfo* file_info, char* name) { +static bool filter_by_extension(ArchiveApp* archive, FileInfo* file_info, const char* name) { furi_assert(archive); furi_assert(file_info); furi_assert(name); @@ -134,54 +132,62 @@ static bool archive_get_filenames(ArchiveApp* archive) { ArchiveFile_t item; FileInfo file_info; File directory; - string_t name; + char name[MAX_NAME_LEN]; bool result; - string_init_printf(name, "%0*d\n", MAX_NAME_LEN, 0); result = dir_api->open(&directory, string_get_cstr(archive->browser.path)); - ArchiveViewModel* model = view_get_model(archive->view_archive_main); - files_array_clear(model->files); + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + files_array_clean(model->files); + return true; + }); if(!result) { dir_api->close(&directory); - string_clear(name); return false; } while(1) { - char* name_ptr = stringi_get_cstr(name); - result = dir_api->read(&directory, &file_info, name_ptr, MAX_NAME_LEN); + result = dir_api->read(&directory, &file_info, name, MAX_NAME_LEN); - if(directory.error_id == FSE_NOT_EXIST || name_ptr[0] == 0) { - view_commit_model(archive->view_archive_main, true); + if(directory.error_id == FSE_NOT_EXIST || name[0] == 0) { break; } if(result) { - if(directory.error_id == FSE_OK) { - if(filter_by_extension(archive, &file_info, name_ptr)) { + uint16_t files_cnt; + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + files_cnt = files_array_size(model->files); + + return true; + }); + + if(files_cnt > MAX_FILES) { + break; + } else if(directory.error_id == FSE_OK) { + if(filter_by_extension(archive, &file_info, name)) { ArchiveFile_t_init(&item); string_init_set(item.name, name); set_file_type(&item, &file_info); - files_array_push_back(model->files, item); + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + files_array_push_back(model->files, item); + return true; + }); + ArchiveFile_t_clear(&item); } } else { dir_api->close(&directory); - string_clear(name); - view_commit_model(archive->view_archive_main, true); return false; } } } - view_commit_model(archive->view_archive_main, true); - model = NULL; - dir_api->close(&directory); - string_clear(name); return true; } @@ -219,9 +225,8 @@ static void archive_add_to_favourites(ArchiveApp* archive) { string_clear(buffer_dst); } -static void archive_text_input_callback(void* context, char* text) { +static void archive_text_input_callback(void* context) { furi_assert(context); - furi_assert(text); ArchiveApp* archive = (ArchiveApp*)context; FS_Common_Api* common_api = &archive->fs_api->common; @@ -236,17 +241,20 @@ static void archive_text_input_callback(void* context, char* text) { string_cat(buffer_dst, "/"); string_cat(buffer_src, archive->browser.name); - string_cat_str(buffer_dst, text); + string_cat_str(buffer_dst, archive->browser.text_input_buffer); // append extension - ArchiveViewModel* model = view_get_model(archive->view_archive_main); - ArchiveFile_t* file = - files_array_get(model->files, CLAMP(model->idx, files_array_size(model->files) - 1, 0)); - string_cat(buffer_src, known_ext[file->type]); - string_cat(buffer_dst, known_ext[file->type]); - model = NULL; - file = NULL; + ArchiveFile_t* file; + + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + file = files_array_get( + model->files, CLAMP(model->idx, files_array_size(model->files) - 1, 0)); + return true; + }); + + string_cat(buffer_dst, known_ext[file->type]); common_api->rename(string_get_cstr(buffer_src), string_get_cstr(buffer_dst)); view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewMain); @@ -256,22 +264,25 @@ static void archive_text_input_callback(void* context, char* text) { archive_get_filenames(archive); } + static void archive_enter_text_input(ArchiveApp* archive) { furi_assert(archive); + *archive->browser.text_input_buffer = '\0'; - string_set(archive->browser.text_input_buffer, archive->browser.name); + strlcpy( + archive->browser.text_input_buffer, + string_get_cstr(archive->browser.name), + string_size(archive->browser.name)); archive_trim_file_ext(archive->browser.text_input_buffer); - char* text_input_buffer_ptr = stringi_get_cstr(archive->browser.text_input_buffer); - text_input_set_header_text(archive->text_input, "Rename:"); text_input_set_result_callback( archive->text_input, archive_text_input_callback, archive, - text_input_buffer_ptr, + archive->browser.text_input_buffer, MAX_NAME_LEN); view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput); @@ -282,10 +293,12 @@ static void archive_show_file_menu(ArchiveApp* archive) { archive->browser.menu = true; - ArchiveViewModel* model = view_get_model(archive->view_archive_main); - model->menu = true; - model->menu_idx = 0; - view_commit_model(archive->view_archive_main, true); + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + model->menu = true; + model->menu_idx = 0; + return true; + }); } static void archive_close_file_menu(ArchiveApp* archive) { @@ -293,10 +306,12 @@ static void archive_close_file_menu(ArchiveApp* archive) { archive->browser.menu = false; - ArchiveViewModel* model = view_get_model(archive->view_archive_main); - model->menu = false; - model->menu_idx = 0; - view_commit_model(archive->view_archive_main, true); + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + model->menu = false; + model->menu_idx = 0; + return true; + }); } static void archive_open_app(ArchiveApp* archive, const char* app_name, const char* args) { @@ -324,18 +339,27 @@ static void archive_delete_file(ArchiveApp* archive, string_t name) { update_offset(archive); - ArchiveViewModel* model = view_get_model(archive->view_archive_main); - model->idx = CLAMP(model->idx, files_array_size(model->files) - 1, 0); - view_commit_model(archive->view_archive_main, true); + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + model->idx = CLAMP(model->idx, files_array_size(model->files) - 1, 0); + return true; + }); } static void archive_file_menu_callback(ArchiveApp* archive) { furi_assert(archive); - ArchiveViewModel* model = view_get_model(archive->view_archive_main); - ArchiveFile_t* selected = files_array_get(model->files, model->idx); + ArchiveFile_t* selected; + uint8_t idx = 0; - switch(model->menu_idx) { + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + selected = files_array_get(model->files, model->idx); + idx = model->menu_idx; + return true; + }); + + switch(idx) { case 0: if((selected->type != ArchiveFileTypeFolder && selected->type != ArchiveFileTypeUnknown)) { string_t full_path; @@ -369,8 +393,6 @@ static void archive_file_menu_callback(ArchiveApp* archive) { archive_close_file_menu(archive); break; } - - model = NULL; selected = NULL; } @@ -378,19 +400,25 @@ static void menu_input_handler(ArchiveApp* archive, InputEvent* event) { furi_assert(archive); furi_assert(archive); - ArchiveViewModel* model = view_get_model(archive->view_archive_main); if(event->type == InputTypeShort) { - if(event->key == InputKeyUp) { - model->menu_idx = CLAMP(model->menu_idx - 1, MENU_ITEMS - 1, 0); - } else if(event->key == InputKeyDown) { - model->menu_idx = CLAMP(model->menu_idx + 1, MENU_ITEMS - 1, 0); - } else if(event->key == InputKeyOk) { + if(event->key == InputKeyUp || event->key == InputKeyDown) { + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + if(event->key == InputKeyUp) { + model->menu_idx = CLAMP(model->menu_idx - 1, MENU_ITEMS - 1, 0); + } else if(event->key == InputKeyDown) { + model->menu_idx = CLAMP(model->menu_idx + 1, MENU_ITEMS - 1, 0); + } + return true; + }); + } + + if(event->key == InputKeyOk) { archive_file_menu_callback(archive); } else if(event->key == InputKeyBack) { archive_close_file_menu(archive); } } - view_commit_model(archive->view_archive_main, true); } /* main controls */ @@ -400,7 +428,6 @@ static bool archive_view_input(InputEvent* event, void* context) { furi_assert(context); ArchiveApp* archive = context; - ArchiveViewModel* model = view_get_model(archive->view_archive_main); bool in_menu = archive->browser.menu; if(in_menu) { @@ -429,72 +456,77 @@ static bool archive_view_input(InputEvent* event, void* context) { return true; } } - - size_t num_elements = files_array_size(model->files) - 1; - if((event->type == InputTypeShort || event->type == InputTypeRepeat)) { - if(event->key == InputKeyUp) { - model->idx = CLAMP(model->idx - 1, num_elements, 0); - update_offset(archive); - return true; - } else if(event->key == InputKeyDown) { - model->idx = CLAMP(model->idx + 1, num_elements, 0); - update_offset(archive); - return true; - } + if(event->key == InputKeyUp || event->key == InputKeyDown) { + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + size_t num_elements = files_array_size(model->files) - 1; + if((event->type == InputTypeShort || event->type == InputTypeRepeat)) { + if(event->key == InputKeyUp) { + model->idx = CLAMP(model->idx - 1, num_elements, 0); + } else if(event->key == InputKeyDown) { + model->idx = CLAMP(model->idx + 1, num_elements, 0); + } + } + return true; + }); + update_offset(archive); } if(event->key == InputKeyOk) { - if(files_array_size(model->files) > 0) { - ArchiveFile_t* selected = files_array_get(model->files, model->idx); - string_set(archive->browser.name, selected->name); - model = NULL; + ArchiveFile_t* selected; + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + if(files_array_size(model->files) > 0) { + selected = files_array_get(model->files, model->idx); + } - if(selected->type == ArchiveFileTypeFolder) { - if(event->type == InputTypeShort) { - archive_enter_dir(archive, archive->browser.name); - } else if(event->type == InputTypeLong) { - archive_show_file_menu(archive); - } - } else { - if(event->type == InputTypeShort) { - archive_show_file_menu(archive); - } + return true; + }); + + string_set(archive->browser.name, selected->name); + if(selected->type == ArchiveFileTypeFolder) { + if(event->type == InputTypeShort) { + archive_enter_dir(archive, archive->browser.name); + } else if(event->type == InputTypeLong) { + archive_show_file_menu(archive); + } + } else { + if(event->type == InputTypeShort) { + archive_show_file_menu(archive); } } } + update_offset(archive); + return true; } void archive_free(ArchiveApp* archive) { furi_assert(archive); - ArchiveViewModel* model = view_get_model(archive->view_archive_main); - files_array_clear(model->files); - model = NULL; + view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewMain); + view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewTextInput); + view_dispatcher_free(archive->view_dispatcher); + + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + files_array_clear(model->files); + return false; + }); + + view_free(archive->view_archive_main); string_clear(archive->browser.name); string_clear(archive->browser.path); - string_clear(archive->browser.text_input_buffer); text_input_free(archive->text_input); furi_record_close("sdcard"); archive->fs_api = NULL; - - view_free(archive->view_archive_main); - - view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewMain); - - view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewTextInput); - - view_dispatcher_free(archive->view_dispatcher); - furi_record_close("gui"); archive->gui = NULL; - furi_thread_free(archive->app_thread); - furi_check(osMessageQueueDelete(archive->event_queue) == osOK); free(archive); @@ -503,10 +535,9 @@ void archive_free(ArchiveApp* archive) { ArchiveApp* archive_alloc() { ArchiveApp* archive = furi_alloc(sizeof(ArchiveApp)); - archive->event_queue = osMessageQueueNew(2, sizeof(AppEvent), NULL); + archive->event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL); archive->app_thread = furi_thread_alloc(); archive->gui = furi_record_open("gui"); - archive->view_dispatcher = view_dispatcher_alloc(); archive->fs_api = furi_record_open("sdcard"); archive->text_input = text_input_alloc(); archive->view_archive_main = view_alloc(); @@ -514,13 +545,21 @@ ArchiveApp* archive_alloc() { furi_check(archive->event_queue); view_allocate_model( - archive->view_archive_main, ViewModelTypeLockFree, sizeof(ArchiveViewModel)); + archive->view_archive_main, ViewModelTypeLocking, sizeof(ArchiveViewModel)); + with_view_model( + archive->view_archive_main, (ArchiveViewModel * model) { + files_array_init(model->files); + return false; + }); + view_set_context(archive->view_archive_main, archive); view_set_draw_callback(archive->view_archive_main, archive_view_render); view_set_input_callback(archive->view_archive_main, archive_view_input); view_set_previous_callback( text_input_get_view(archive->text_input), archive_previous_callback); + // View Dispatcher + archive->view_dispatcher = view_dispatcher_alloc(); view_dispatcher_add_view( archive->view_dispatcher, ArchiveViewMain, archive->view_archive_main); view_dispatcher_add_view( diff --git a/applications/archive/archive_i.h b/applications/archive/archive_i.h index 97428232..e91ddb5a 100644 --- a/applications/archive/archive_i.h +++ b/applications/archive/archive_i.h @@ -15,7 +15,7 @@ #include "applications.h" #define MAX_DEPTH 32 -#define MAX_NAME_LEN 255 +#define MAX_FILES 100 //temp typedef enum { ArchiveViewMain, @@ -47,7 +47,7 @@ static const char* known_ext[] = { [ArchiveFileTypeNFC] = ".nfc", [ArchiveFileTypeSubOne] = ".sub1", [ArchiveFileTypeLFRFID] = ".rfid", - [ArchiveFileTypeIrda] = ".irda", + [ArchiveFileTypeIrda] = ".ir", }; static const char* tab_default_paths[] = { @@ -94,7 +94,7 @@ typedef struct { ArchiveTabEnum tab_id; string_t name; string_t path; - string_t text_input_buffer; + char text_input_buffer[MAX_NAME_LEN]; uint8_t depth; uint16_t last_idx[MAX_DEPTH]; diff --git a/applications/archive/archive_views.c b/applications/archive/archive_views.c index 56e31971..7845698e 100644 --- a/applications/archive/archive_views.c +++ b/applications/archive/archive_views.c @@ -1,7 +1,7 @@ #include "archive_views.h" static const char* ArchiveTabNames[] = - {"Favourites", "iButton", "NFC", "SubOne", "Rfid", "Infared", "Browser"}; + {"Favourites", "iButton", "NFC", "SubOne", "Rfid", "Infrared", "Browser"}; static const IconName ArchiveItemIcons[] = { [ArchiveFileTypeIButton] = I_ibutt_10px, @@ -47,14 +47,13 @@ static void render_item_menu(Canvas* canvas, ArchiveViewModel* model) { canvas_draw_icon_name(canvas, 64, 20 + model->menu_idx * 11, I_ButtonRight_4x7); } -void archive_trim_file_ext(string_t name) { - size_t str_len = string_size(name); - char* buff_ptr = stringi_get_cstr(name); - char* end = buff_ptr + str_len; - while(end > buff_ptr && *end != '.' && *end != '\\' && *end != '/') { +void archive_trim_file_ext(char* name) { + size_t str_len = strlen(name); + char* end = name + str_len; + while(end > name && *end != '.' && *end != '\\' && *end != '/') { --end; } - if((end > buff_ptr && *end == '.') && (*(end - 1) != '\\' && *(end - 1) != '/')) { + if((end > name && *end == '.') && (*(end - 1) != '\\' && *(end - 1) != '/')) { *end = '\0'; } } @@ -80,15 +79,17 @@ static void draw_list(Canvas* canvas, ArchiveViewModel* model) { bool scrollbar = array_size > 4; string_t str_buff; + char cstr_buff[MAX_NAME_LEN]; string_init(str_buff); for(size_t i = 0; i < MIN(MENU_ITEMS, array_size); ++i) { size_t idx = CLAMP(i + model->list_offset, array_size, 0); ArchiveFile_t* file = files_array_get(model->files, CLAMP(idx, array_size - 1, 0)); - string_set(str_buff, file->name); + strlcpy(cstr_buff, string_get_cstr(file->name), string_size(file->name)); + if(is_known_app(file->type)) archive_trim_file_ext(cstr_buff); + string_set_str(str_buff, cstr_buff); - if(is_known_app(file->type)) archive_trim_file_ext(str_buff); elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX); if(model->idx == idx) { @@ -98,7 +99,7 @@ static void draw_list(Canvas* canvas, ArchiveViewModel* model) { } canvas_draw_icon_name(canvas, 2, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file->type]); - canvas_draw_str(canvas, 15, 24 + i * FRAME_HEIGHT, stringi_get_cstr(str_buff)); + canvas_draw_str(canvas, 15, 24 + i * FRAME_HEIGHT, string_get_cstr(str_buff)); string_clean(str_buff); } diff --git a/applications/archive/archive_views.h b/applications/archive/archive_views.h index c2055200..eabd0be0 100644 --- a/applications/archive/archive_views.h +++ b/applications/archive/archive_views.h @@ -7,6 +7,8 @@ #include #define MAX_LEN_PX 98 +#define MAX_NAME_LEN 255 + #define FRAME_HEIGHT 12 #define MENU_ITEMS 4 @@ -63,4 +65,4 @@ typedef struct { } ArchiveViewModel; void archive_view_render(Canvas* canvas, void* model); -void archive_trim_file_ext(string_t name); \ No newline at end of file +void archive_trim_file_ext(char* name); \ No newline at end of file diff --git a/applications/gui-test/gui-test.c b/applications/gui-test/gui-test.c index 5ca2cd7f..1886041a 100644 --- a/applications/gui-test/gui-test.c +++ b/applications/gui-test/gui-test.c @@ -118,7 +118,7 @@ static void dialog_ex_callback(DialogExResult result, void* context) { next_view(context); } -static void text_input_callback(void* context, char* text) { +static void text_input_callback(void* context) { next_view(context); } diff --git a/applications/gui/modules/text_input.c b/applications/gui/modules/text_input.c index 4900afbb..8a1b3db2 100644 --- a/applications/gui/modules/text_input.c +++ b/applications/gui/modules/text_input.c @@ -14,8 +14,8 @@ typedef struct { typedef struct { const char* header; - char* text; - uint8_t max_text_length; + char* text_buffer; + size_t text_buffer_size; TextInputCallback callback; void* callback_context; @@ -128,19 +128,19 @@ static const char char_to_uppercase(const char letter) { } static void text_input_backspace_cb(TextInputModel* model) { - uint8_t text_length = strlen(model->text); + uint8_t text_length = strlen(model->text_buffer); if(text_length > 0) { - model->text[text_length - 1] = 0; + model->text_buffer[text_length - 1] = 0; } } static void text_input_view_draw_callback(Canvas* canvas, void* _model) { TextInputModel* model = _model; - uint8_t text_length = strlen(model->text); + uint8_t text_length = strlen(model->text_buffer); uint8_t needed_string_width = canvas_width(canvas) - 8; uint8_t start_pos = 4; - char* text = model->text; + const char* text = model->text_buffer; canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); @@ -286,20 +286,20 @@ static void text_input_handle_ok(TextInput* text_input) { with_view_model( text_input->view, (TextInputModel * model) { char selected = get_selected_char(model); - uint8_t text_length = strlen(model->text); + uint8_t text_length = strlen(model->text_buffer); if(selected == ENTER_KEY) { if(model->callback != 0 && text_length > 0) { - model->callback(model->callback_context, model->text); + model->callback(model->callback_context); } } else if(selected == BACKSPACE_KEY) { text_input_backspace_cb(model); - } else if(text_length < model->max_text_length) { + } else if(text_length < (model->text_buffer_size - 1)) { if(text_length == 0 && char_is_lowercase(selected)) { selected = char_to_uppercase(selected); } - model->text[text_length] = selected; - model->text[text_length + 1] = 0; + model->text_buffer[text_length] = selected; + model->text_buffer[text_length + 1] = 0; } return true; }); @@ -361,7 +361,7 @@ TextInput* text_input_alloc() { with_view_model( text_input->view, (TextInputModel * model) { - model->max_text_length = 0; + model->text_buffer_size = 0; model->header = ""; model->selected_row = 0; model->selected_column = 0; @@ -386,14 +386,14 @@ void text_input_set_result_callback( TextInput* text_input, TextInputCallback callback, void* callback_context, - char* text, - uint8_t max_text_length) { + char* text_buffer, + size_t text_buffer_size) { with_view_model( text_input->view, (TextInputModel * model) { model->callback = callback; model->callback_context = callback_context; - model->text = text; - model->max_text_length = max_text_length; + model->text_buffer = text_buffer; + model->text_buffer_size = text_buffer_size; return true; }); } diff --git a/applications/gui/modules/text_input.h b/applications/gui/modules/text_input.h index 8e5d8405..51f5e3e2 100644 --- a/applications/gui/modules/text_input.h +++ b/applications/gui/modules/text_input.h @@ -7,7 +7,7 @@ extern "C" { /* Text input anonymous structure */ typedef struct TextInput TextInput; -typedef void (*TextInputCallback)(void* context, char* text); +typedef void (*TextInputCallback)(void* context); /** * @brief Allocate and initialize text input @@ -37,15 +37,15 @@ View* text_input_get_view(TextInput* text_input); * @param text_input - Text input instance * @param callback - callback fn * @param callback_context - callback context - * @param text - text buffer to use - * @param max_text_length - text buffer length + * @param text_buffer - pointer to YOUR text buffer, that we going to modify + * @param text_buffer_size - YOUR text buffer size in bytes. Max string length will be text_buffer_size - 1. */ void text_input_set_result_callback( TextInput* text_input, TextInputCallback callback, void* callback_context, - char* text, - uint8_t max_text_length); + char* text_buffer, + size_t text_buffer_size); /** * @brief Set text input header text diff --git a/applications/ibutton/scene/ibutton-scene-save-name.cpp b/applications/ibutton/scene/ibutton-scene-save-name.cpp index 04230332..75676a80 100644 --- a/applications/ibutton/scene/ibutton-scene-save-name.cpp +++ b/applications/ibutton/scene/ibutton-scene-save-name.cpp @@ -51,7 +51,7 @@ void iButtonSceneSaveName::on_exit(iButtonApp* app) { text_input_set_result_callback(text_input, NULL, NULL, NULL, 0); } -void iButtonSceneSaveName::text_input_callback(void* context, char* text) { +void iButtonSceneSaveName::text_input_callback(void* context) { iButtonApp* app = static_cast(context); iButtonEvent event; diff --git a/applications/ibutton/scene/ibutton-scene-save-name.h b/applications/ibutton/scene/ibutton-scene-save-name.h index 811b0f65..1d7126e9 100644 --- a/applications/ibutton/scene/ibutton-scene-save-name.h +++ b/applications/ibutton/scene/ibutton-scene-save-name.h @@ -8,5 +8,5 @@ public: void on_exit(iButtonApp* app) final; private: - void text_input_callback(void* context, char* text); + void text_input_callback(void* context); }; \ No newline at end of file diff --git a/applications/irda/irda-app.cpp b/applications/irda/irda-app.cpp index 95b9a137..c3cb52a8 100644 --- a/applications/irda/irda-app.cpp +++ b/applications/irda/irda-app.cpp @@ -126,7 +126,7 @@ uint8_t IrdaApp::get_text_store_size() { return text_store_size; } -void IrdaApp::text_input_callback(void* context, char* text) { +void IrdaApp::text_input_callback(void* context) { IrdaApp* app = static_cast(context); IrdaAppEvent event; event.type = IrdaAppEvent::Type::TextEditDone; diff --git a/applications/irda/irda-app.hpp b/applications/irda/irda-app.hpp index 16ba3f49..96edc653 100644 --- a/applications/irda/irda-app.hpp +++ b/applications/irda/irda-app.hpp @@ -82,7 +82,7 @@ public: void notify_click(); void notify_click_and_blink(); - static void text_input_callback(void* context, char* text); + static void text_input_callback(void* context); static void popup_callback(void* context); IrdaApp() { diff --git a/lib/mlib b/lib/mlib index a03b2e80..3c83e408 160000 --- a/lib/mlib +++ b/lib/mlib @@ -1 +1 @@ -Subproject commit a03b2e80c646a7db208a73362a764aa1ac7246fe +Subproject commit 3c83e4088ccb6d5513c08a7c6475b3cbdba76796