From 5cfc773b7b32586a64141737c0abcce5d307f07a Mon Sep 17 00:00:00 2001 From: Georgii Surkov Date: Tue, 12 Mar 2024 15:09:35 +0300 Subject: [PATCH 1/6] FL-3496: do not hardcode universal library names in CLI --- applications/main/infrared/infrared_cli.c | 49 ++++++++++++++++++++--- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/applications/main/infrared/infrared_cli.c b/applications/main/infrared/infrared_cli.c index c960ffa28..9829e59e9 100644 --- a/applications/main/infrared/infrared_cli.c +++ b/applications/main/infrared/infrared_cli.c @@ -10,8 +10,10 @@ #include "infrared_signal.h" #include "infrared_brute_force.h" -#define INFRARED_CLI_BUF_SIZE 10 -#define INFRARED_ASSETS_FOLDER "infrared/assets" +#define INFRARED_CLI_BUF_SIZE (10U) +#define INFRARED_CLI_FILE_NAME_SIZE (256U) +#define INFRARED_FILE_EXTENSION ".ir" +#define INFRARED_ASSETS_FOLDER EXT_PATH("infrared/assets") #define INFRARED_BRUTE_FORCE_DUMMY_INDEX 0 DICT_DEF2(dict_signals, FuriString*, FURI_STRING_OPLIST, int, M_DEFAULT_OPLIST) @@ -66,6 +68,37 @@ static void signal_received_callback(void* context, InfraredWorkerSignal* receiv } } +static void infrared_cli_print_universal_remotes(void) { + Storage* storage = furi_record_open(RECORD_STORAGE); + File* dir = storage_file_alloc(storage); + + do { + if(!storage_dir_open(dir, INFRARED_ASSETS_FOLDER)) break; + + FileInfo file_info; + char file_name[INFRARED_CLI_FILE_NAME_SIZE]; + + while(storage_dir_read(dir, &file_info, file_name, sizeof(file_name))) { + if(file_info.flags & FSF_DIRECTORY) { + continue; + } + + char* file_ext = strstr(file_name, INFRARED_FILE_EXTENSION); + if((file_ext == NULL) || (strcmp(file_ext, INFRARED_FILE_EXTENSION) != 0)) { + continue; + } + + *file_ext = '\0'; + printf("%s ", file_name); + } + + printf("\r\n"); + } while(false); + + storage_file_free(dir); + furi_record_close(RECORD_STORAGE); +} + static void infrared_cli_print_usage(void) { printf("Usage:\r\n"); printf("\tir rx [raw]\r\n"); @@ -85,8 +118,9 @@ static void infrared_cli_print_usage(void) { printf("\tir decode []\r\n"); printf("\tir universal \r\n"); printf("\tir universal list \r\n"); - // TODO FL-3496: Do not hardcode universal remote names - printf("\tAvailable universal remotes: tv audio ac projector\r\n"); + printf("\tAvailable universal remotes: "); + + infrared_cli_print_universal_remotes(); } static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args) { @@ -365,7 +399,10 @@ static void infrared_cli_list_remote_signals(FuriString* remote_name) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); FuriString* remote_path = furi_string_alloc_printf( - "%s/%s.ir", EXT_PATH(INFRARED_ASSETS_FOLDER), furi_string_get_cstr(remote_name)); + "%s/%s%s", + INFRARED_ASSETS_FOLDER, + furi_string_get_cstr(remote_name), + INFRARED_FILE_EXTENSION); do { if(!flipper_format_buffered_file_open_existing(ff, furi_string_get_cstr(remote_path))) { @@ -413,7 +450,7 @@ static void infrared_cli_brute_force_signals(Cli* cli, FuriString* remote_name, FuriString* signal_name) { InfraredBruteForce* brute_force = infrared_brute_force_alloc(); FuriString* remote_path = furi_string_alloc_printf( - "%s/%s.ir", EXT_PATH(INFRARED_ASSETS_FOLDER), furi_string_get_cstr(remote_name)); + "%s/%s.ir", INFRARED_ASSETS_FOLDER, furi_string_get_cstr(remote_name)); infrared_brute_force_set_db_filename(brute_force, furi_string_get_cstr(remote_path)); infrared_brute_force_add_record( From b27066b508316574df3027d6522e9e61cfd9b150 Mon Sep 17 00:00:00 2001 From: Georgii Surkov Date: Tue, 12 Mar 2024 16:14:21 +0300 Subject: [PATCH 2/6] FL-3523: remove TODO, no changes necessary --- applications/main/infrared/infrared_cli.c | 1 - 1 file changed, 1 deletion(-) diff --git a/applications/main/infrared/infrared_cli.c b/applications/main/infrared/infrared_cli.c index 9829e59e9..8ac3e65b6 100644 --- a/applications/main/infrared/infrared_cli.c +++ b/applications/main/infrared/infrared_cli.c @@ -245,7 +245,6 @@ static bool infrared_cli_decode_raw_signal( size_t i; for(i = 0; i < raw_signal->timings_size; ++i) { - // TODO FL-3523: Any infrared_check_decoder_ready() magic? const InfraredMessage* message = infrared_decode(decoder, level, raw_signal->timings[i]); if(message) { From 3f7a070397ead88d3472a81264439ffed350ef9c Mon Sep 17 00:00:00 2001 From: Georgii Surkov Date: Tue, 12 Mar 2024 16:18:48 +0300 Subject: [PATCH 3/6] FL-3767: remove TODO, no changes necessary --- applications/services/rpc/rpc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 53b139dd4..1594da0b1 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -190,8 +190,6 @@ bool rpc_pb_stream_read(pb_istream_t* istream, pb_byte_t* buf, size_t count) { furi_assert(session); furi_assert(istream->bytes_left); - /* TODO FL-3768 this function may be called after - marking the worker for termination */ if(session->terminate) { return false; } From 98c328f93f88f4ae350bd2385ee5e40bc46dff02 Mon Sep 17 00:00:00 2001 From: Georgii Surkov Date: Tue, 12 Mar 2024 19:45:22 +0300 Subject: [PATCH 4/6] FL-3790: fix laggy TextInput by not adding it into a ViewStack --- applications/main/infrared/infrared_app.c | 12 ++++++++---- applications/main/infrared/infrared_app_i.h | 1 + .../common/infrared_scene_universal_common.c | 3 ++- .../infrared/scenes/infrared_scene_edit_delete.c | 7 ++----- .../infrared/scenes/infrared_scene_edit_move.c | 8 +++----- .../infrared/scenes/infrared_scene_edit_rename.c | 15 +++++---------- .../infrared/scenes/infrared_scene_remote_list.c | 3 --- .../main/infrared/scenes/infrared_scene_rpc.c | 7 ++----- 8 files changed, 23 insertions(+), 33 deletions(-) diff --git a/applications/main/infrared/infrared_app.c b/applications/main/infrared/infrared_app.c index 50534c660..4c89272de 100644 --- a/applications/main/infrared/infrared_app.c +++ b/applications/main/infrared/infrared_app.c @@ -189,6 +189,10 @@ static InfraredApp* infrared_alloc() { view_dispatcher_add_view( view_dispatcher, InfraredViewMove, infrared_move_view_get_view(infrared->move_view)); + infrared->loading = loading_alloc(); + view_dispatcher_add_view( + view_dispatcher, InfraredViewLoading, loading_get_view(infrared->loading)); + if(app_state->is_debug_enabled) { infrared->debug_view = infrared_debug_view_alloc(); view_dispatcher_add_view( @@ -198,7 +202,6 @@ static InfraredApp* infrared_alloc() { } infrared->button_panel = button_panel_alloc(); - infrared->loading = loading_alloc(); infrared->progress = infrared_progress_view_alloc(); return infrared; @@ -240,13 +243,15 @@ static void infrared_free(InfraredApp* infrared) { view_dispatcher_remove_view(view_dispatcher, InfraredViewMove); infrared_move_view_free(infrared->move_view); + view_dispatcher_remove_view(view_dispatcher, InfraredViewLoading); + loading_free(infrared->loading); + if(app_state->is_debug_enabled) { view_dispatcher_remove_view(view_dispatcher, InfraredViewDebugView); infrared_debug_view_free(infrared->debug_view); } button_panel_free(infrared->button_panel); - loading_free(infrared->loading); infrared_progress_view_free(infrared->progress); view_dispatcher_free(view_dispatcher); @@ -385,14 +390,13 @@ void infrared_tx_stop(InfraredApp* infrared) { } void infrared_blocking_task_start(InfraredApp* infrared, FuriThreadCallback callback) { - view_stack_add_view(infrared->view_stack, loading_get_view(infrared->loading)); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewLoading); furi_thread_set_callback(infrared->task_thread, callback); furi_thread_start(infrared->task_thread); } bool infrared_blocking_task_finalize(InfraredApp* infrared) { furi_thread_join(infrared->task_thread); - view_stack_remove_view(infrared->view_stack, loading_get_view(infrared->loading)); return furi_thread_get_return_code(infrared->task_thread); } diff --git a/applications/main/infrared/infrared_app_i.h b/applications/main/infrared/infrared_app_i.h index bccd58608..2c8047343 100644 --- a/applications/main/infrared/infrared_app_i.h +++ b/applications/main/infrared/infrared_app_i.h @@ -141,6 +141,7 @@ typedef enum { InfraredViewStack, InfraredViewDebugView, InfraredViewMove, + InfraredViewLoading, } InfraredView; /** diff --git a/applications/main/infrared/scenes/common/infrared_scene_universal_common.c b/applications/main/infrared/scenes/common/infrared_scene_universal_common.c index 9fc48bd46..9bdcdc4a8 100644 --- a/applications/main/infrared/scenes/common/infrared_scene_universal_common.c +++ b/applications/main/infrared/scenes/common/infrared_scene_universal_common.c @@ -46,7 +46,6 @@ void infrared_scene_universal_common_on_enter(void* context) { InfraredApp* infrared = context; view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); view_stack_add_view(infrared->view_stack, button_panel_get_view(infrared->button_panel)); - view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); // Load universal remote data in background infrared_blocking_task_start(infrared, infrared_scene_universal_common_task_callback); @@ -98,6 +97,8 @@ bool infrared_scene_universal_common_on_event(void* context, SceneManagerEvent e if(!task_success) { scene_manager_next_scene(infrared->scene_manager, InfraredSceneErrorDatabases); + } else { + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); } } consumed = true; diff --git a/applications/main/infrared/scenes/infrared_scene_edit_delete.c b/applications/main/infrared/scenes/infrared_scene_edit_delete.c index 8dc4ab6f9..90a2633d3 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_delete.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_delete.c @@ -91,10 +91,7 @@ void infrared_scene_edit_delete_on_enter(void* context) { dialog_ex_set_result_callback(dialog_ex, infrared_scene_edit_delete_dialog_result_callback); dialog_ex_set_context(dialog_ex, context); - view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationHorizontal); - view_stack_add_view(infrared->view_stack, dialog_ex_get_view(infrared->dialog_ex)); - - view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx); } bool infrared_scene_edit_delete_on_event(void* context, SceneManagerEvent event) { @@ -136,5 +133,5 @@ bool infrared_scene_edit_delete_on_event(void* context, SceneManagerEvent event) void infrared_scene_edit_delete_on_exit(void* context) { InfraredApp* infrared = context; - view_stack_remove_view(infrared->view_stack, dialog_ex_get_view(infrared->dialog_ex)); + dialog_ex_reset(infrared->dialog_ex); } diff --git a/applications/main/infrared/scenes/infrared_scene_edit_move.c b/applications/main/infrared/scenes/infrared_scene_edit_move.c index 500f3d791..fcac1fc15 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_move.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_move.c @@ -38,10 +38,7 @@ void infrared_scene_edit_move_on_enter(void* context) { infrared_move_view_set_callback( infrared->move_view, infrared_scene_edit_move_button_callback, infrared); - view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationHorizontal); - view_stack_add_view(infrared->view_stack, infrared_move_view_get_view(infrared->move_view)); - - view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewMove); } bool infrared_scene_edit_move_on_event(void* context, SceneManagerEvent event) { @@ -62,6 +59,8 @@ bool infrared_scene_edit_move_on_event(void* context, SceneManagerEvent event) { infrared_show_error_message(infrared, "Failed to move\n\"%s\"", signal_name); scene_manager_search_and_switch_to_previous_scene( infrared->scene_manager, InfraredSceneRemoteList); + } else { + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewMove); } } consumed = true; @@ -72,6 +71,5 @@ bool infrared_scene_edit_move_on_event(void* context, SceneManagerEvent event) { void infrared_scene_edit_move_on_exit(void* context) { InfraredApp* infrared = context; - view_stack_remove_view(infrared->view_stack, infrared_move_view_get_view(infrared->move_view)); infrared_move_view_reset(infrared->move_view); } diff --git a/applications/main/infrared/scenes/infrared_scene_edit_rename.c b/applications/main/infrared/scenes/infrared_scene_edit_rename.c index 2763c2777..a546ad6e5 100644 --- a/applications/main/infrared/scenes/infrared_scene_edit_rename.c +++ b/applications/main/infrared/scenes/infrared_scene_edit_rename.c @@ -75,10 +75,7 @@ void infrared_scene_edit_rename_on_enter(void* context) { enter_name_length, false); - view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationHorizontal); - view_stack_add_view(infrared->view_stack, text_input_get_view(infrared->text_input)); - - view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewTextInput); } bool infrared_scene_edit_rename_on_event(void* context, SceneManagerEvent event) { @@ -117,12 +114,10 @@ void infrared_scene_edit_rename_on_exit(void* context) { InfraredApp* infrared = context; TextInput* text_input = infrared->text_input; - view_stack_remove_view(infrared->view_stack, text_input_get_view(text_input)); - - void* validator_context = text_input_get_validator_callback_context(text_input); - text_input_set_validator(text_input, NULL, NULL); - + ValidatorIsFile* validator_context = text_input_get_validator_callback_context(text_input); if(validator_context) { - validator_is_file_free((ValidatorIsFile*)validator_context); + validator_is_file_free(validator_context); } + + text_input_reset(text_input); } diff --git a/applications/main/infrared/scenes/infrared_scene_remote_list.c b/applications/main/infrared/scenes/infrared_scene_remote_list.c index 744409a7a..9c880ac2f 100644 --- a/applications/main/infrared/scenes/infrared_scene_remote_list.c +++ b/applications/main/infrared/scenes/infrared_scene_remote_list.c @@ -18,9 +18,6 @@ static void infrared_scene_remote_list_select_and_load(InfraredApp* infrared) { infrared->dialogs, infrared->file_path, infrared->file_path, &browser_options); if(file_selected) { - view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical); - view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); - // Load the remote in a separate thread infrared_blocking_task_start(infrared, infrared_scene_remote_list_task_callback); diff --git a/applications/main/infrared/scenes/infrared_scene_rpc.c b/applications/main/infrared/scenes/infrared_scene_rpc.c index 03a2bff01..4c263a117 100644 --- a/applications/main/infrared/scenes/infrared_scene_rpc.c +++ b/applications/main/infrared/scenes/infrared_scene_rpc.c @@ -30,11 +30,8 @@ void infrared_scene_rpc_on_enter(void* context) { popup_set_context(popup, context); popup_set_callback(popup, infrared_popup_closed_callback); - view_stack_add_view(infrared->view_stack, popup_get_view(infrared->popup)); - view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack); - + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); scene_manager_set_scene_state(infrared->scene_manager, InfraredSceneRpc, InfraredRpcStateIdle); - notification_message(infrared->notifications, &sequence_display_backlight_on); } @@ -69,6 +66,7 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) { popup_set_text( infrared->popup, infrared->text_store[0], 89, 44, AlignCenter, AlignTop); + view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup); rpc_system_app_confirm(infrared->rpc_ctx, task_success); @@ -135,6 +133,5 @@ void infrared_scene_rpc_on_exit(void* context) { infrared_tx_stop(infrared); } - view_stack_remove_view(infrared->view_stack, popup_get_view(infrared->popup)); popup_reset(infrared->popup); } From 75432346de09bd926ba2881ca8cfb7a84ffbd58f Mon Sep 17 00:00:00 2001 From: Georgii Surkov Date: Tue, 12 Mar 2024 19:54:45 +0300 Subject: [PATCH 5/6] Improve documentation --- applications/services/gui/view_dispatcher.h | 4 +++- applications/services/gui/view_holder.h | 6 ++++++ applications/services/gui/view_stack.h | 4 +++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/applications/services/gui/view_dispatcher.h b/applications/services/gui/view_dispatcher.h index 67a3fc40b..bec15f6e3 100644 --- a/applications/services/gui/view_dispatcher.h +++ b/applications/services/gui/view_dispatcher.h @@ -1,6 +1,8 @@ /** * @file view_dispatcher.h - * GUI: ViewDispatcher API + * @brief GUI: ViewDispatcher API + * + * @warning Views added to a ViewDispatcher MUST NOT be in a ViewStack at the same time. */ #pragma once diff --git a/applications/services/gui/view_holder.h b/applications/services/gui/view_holder.h index 8e7db3b85..0bd29652c 100644 --- a/applications/services/gui/view_holder.h +++ b/applications/services/gui/view_holder.h @@ -1,3 +1,9 @@ +/** + * @file view_holder.h + * @brief GUI: ViewHolder API + * + * @warning View added to a ViewHolder MUST NOT be in a ViewStack at the same time. + */ #pragma once #include diff --git a/applications/services/gui/view_stack.h b/applications/services/gui/view_stack.h index ed17f682f..7387038b0 100644 --- a/applications/services/gui/view_stack.h +++ b/applications/services/gui/view_stack.h @@ -1,11 +1,13 @@ /** * @file view_stack.h - * GUI: ViewStack API + * @brief GUI: ViewStack API * * ViewStack accumulates several Views in one stack. * Draw callbacks are called sequenctially starting from * first added. Input callbacks are called in reverse order. * Consumed input is not passed on underlying layers. + * + * @warning Views added to a ViewStack MUST NOT be in a ViewDispatcher or a ViewHolder at the same time. */ #pragma once From 2aa85347ee22f0298aafeb880e55a95beb0e4fab Mon Sep 17 00:00:00 2001 From: Georgii Surkov Date: Wed, 13 Mar 2024 12:28:08 +0300 Subject: [PATCH 6/6] Fix logical error in documentation --- applications/main/infrared/infrared_app_i.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/applications/main/infrared/infrared_app_i.h b/applications/main/infrared/infrared_app_i.h index 2c8047343..1c074323a 100644 --- a/applications/main/infrared/infrared_app_i.h +++ b/applications/main/infrared/infrared_app_i.h @@ -214,8 +214,8 @@ void infrared_tx_stop(InfraredApp* infrared); /** * @brief Start a blocking task in a separate thread. * - * If a ViewStack is currently on screen, a busy "Hourglass" animation - * will be shown and no input will be accepted until completion. + * Before starting a blocking task, the current view will be replaced + * with a busy animation. All subsequent user input will be ignored. * * @param[in,out] infrared pointer to the application instance. * @param[in] callback pointer to the function to be run in the thread. @@ -223,10 +223,11 @@ void infrared_tx_stop(InfraredApp* infrared); void infrared_blocking_task_start(InfraredApp* infrared, FuriThreadCallback callback); /** - * @brief Wait for a blocking task to finish and receive the result. + * @brief Wait for a blocking task to finish and get the result. * - * Upon the completion of a blocking task, the busy animation will be hidden - * and input will be accepted again. + * The busy animation shown during the infrared_blocking_task_start() call + * will NOT be hidden and WILL remain on screen. If another view is needed + * (e.g. to display the results), the caller code MUST set it explicitly. * * @param[in,out] infrared pointer to the application instance. * @return true if the blocking task finished successfully, false otherwise.