mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-20 04:54:45 -07:00
Infrared: Add option to "Load from Library File" for Universal Remotes (#255)
* init * comments * remove trash * remove code that mistakenly added from merging conflicts * remove code that mistakenly added from merging conflicts * format * remove header that added during debugging * ecit name * Revert some whitespace changes to avoid future conflicts * get_button_count() * Use same index values * Use common functions where possible * Unroll long if into guard check * Fix furi check failed due to inflated button index * Show "assets" folders * Load DB file only once and show loading animation * Add bool for auto_detect_buttons * Show error when tryingto load remote file as universal library * Remove unnecessary includes * Fix inputs * more_devices -> from_file * Consistency * Remember last selected library file * Update changelog --------- Co-authored-by: Willy-JL <49810075+Willy-JL@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
925481ffd0
commit
2f22fad58b
@@ -34,7 +34,8 @@ static void infrared_scene_universal_common_hide_popup(InfraredApp* infrared) {
|
||||
|
||||
static int32_t infrared_scene_universal_common_task_callback(void* context) {
|
||||
InfraredApp* infrared = context;
|
||||
const InfraredErrorCode error = infrared_brute_force_calculate_messages(infrared->brute_force);
|
||||
const InfraredErrorCode error =
|
||||
infrared_brute_force_calculate_messages(infrared->brute_force, false);
|
||||
view_dispatcher_send_custom_event(
|
||||
infrared->view_dispatcher,
|
||||
infrared_custom_event_pack(InfraredCustomEventTypeTaskFinished, 0));
|
||||
|
||||
@@ -24,6 +24,7 @@ ADD_SCENE(infrared, universal_fan, UniversalFan)
|
||||
ADD_SCENE(infrared, universal_bluray, UniversalBluray)
|
||||
ADD_SCENE(infrared, universal_monitor, UniversalMonitor)
|
||||
ADD_SCENE(infrared, universal_digital_sign, UniversalDigitalSign)
|
||||
ADD_SCENE(infrared, universal_from_file, UniversalFromFile)
|
||||
ADD_SCENE(infrared, gpio_settings, GpioSettings)
|
||||
ADD_SCENE(infrared, debug, Debug)
|
||||
ADD_SCENE(infrared, error_databases, ErrorDatabases)
|
||||
|
||||
@@ -85,6 +85,10 @@ bool infrared_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
const uint32_t submenu_index = event.event;
|
||||
scene_manager_set_scene_state(scene_manager, InfraredSceneStart, submenu_index);
|
||||
if(submenu_index == SubmenuIndexUniversalRemotes) {
|
||||
// Set file_path only once here so repeated usages of
|
||||
// "Load from Library File" have file browser focused on
|
||||
// last selected file, feels more intuitive
|
||||
furi_string_set(infrared->file_path, INFRARED_APP_FOLDER);
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneUniversal);
|
||||
} else if(
|
||||
submenu_index == SubmenuIndexLearnNewRemote ||
|
||||
|
||||
@@ -10,6 +10,7 @@ typedef enum {
|
||||
SubmenuIndexUniversalBluray,
|
||||
SubmenuIndexUniversalMonitor,
|
||||
SubmenuIndexUniversalDigitalSign,
|
||||
SubmenuIndexUniversalFromFile,
|
||||
} SubmenuIndex;
|
||||
|
||||
static void infrared_scene_universal_submenu_callback(void* context, uint32_t index) {
|
||||
@@ -84,6 +85,13 @@ void infrared_scene_universal_on_enter(void* context) {
|
||||
infrared_scene_universal_submenu_callback,
|
||||
context);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Load from Library File",
|
||||
SubmenuIndexUniversalFromFile,
|
||||
infrared_scene_universal_submenu_callback,
|
||||
context);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(infrared->scene_manager, InfraredSceneUniversal));
|
||||
|
||||
@@ -123,6 +131,9 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) {
|
||||
} else if(event.event == SubmenuIndexUniversalDigitalSign) {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneUniversalDigitalSign);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexUniversalFromFile) {
|
||||
scene_manager_next_scene(scene_manager, InfraredSceneUniversalFromFile);
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(scene_manager, InfraredSceneUniversal, event.event);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
#include "../infrared_app_i.h"
|
||||
|
||||
#include "common/infrared_scene_universal_common.h"
|
||||
|
||||
static void
|
||||
infrared_scene_universal_from_file_item_callback(void* context, int32_t index, InputType type) {
|
||||
if(type == InputTypeRelease) {
|
||||
InfraredApp* infrared = context;
|
||||
uint32_t event = infrared_custom_event_pack(InfraredCustomEventTypeButtonSelected, index);
|
||||
view_dispatcher_send_custom_event(infrared->view_dispatcher, event);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t infrared_scene_universal_from_file_task_callback(void* context) {
|
||||
InfraredApp* infrared = context;
|
||||
ButtonMenu* button_menu = infrared->button_menu;
|
||||
InfraredBruteForce* brute_force = infrared->brute_force;
|
||||
const InfraredErrorCode error =
|
||||
infrared_brute_force_calculate_messages(infrared->brute_force, true);
|
||||
|
||||
if(!INFRARED_ERROR_PRESENT(error)) {
|
||||
// add btns
|
||||
for(size_t i = 0; i < infrared_brute_force_get_button_count(brute_force); ++i) {
|
||||
const char* button_name = infrared_brute_force_get_button_name(brute_force, i);
|
||||
button_menu_add_item(
|
||||
button_menu,
|
||||
button_name,
|
||||
i,
|
||||
infrared_scene_universal_from_file_item_callback,
|
||||
ButtonMenuItemTypeCommon,
|
||||
infrared);
|
||||
}
|
||||
}
|
||||
|
||||
view_dispatcher_send_custom_event(
|
||||
infrared->view_dispatcher,
|
||||
infrared_custom_event_pack(InfraredCustomEventTypeTaskFinished, 0));
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void infrared_scene_universal_from_file_on_enter(void* context) {
|
||||
InfraredApp* infrared = context;
|
||||
ButtonMenu* button_menu = infrared->button_menu;
|
||||
InfraredBruteForce* brute_force = infrared->brute_force;
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(&browser_options, INFRARED_APP_EXTENSION, &I_ir_10px);
|
||||
browser_options.base_path = INFRARED_APP_FOLDER;
|
||||
browser_options.skip_assets = false;
|
||||
if(!dialog_file_browser_show(
|
||||
infrared->dialogs, infrared->file_path, infrared->file_path, &browser_options)) {
|
||||
scene_manager_previous_scene(infrared->scene_manager);
|
||||
return;
|
||||
}
|
||||
|
||||
infrared_brute_force_set_db_filename(brute_force, furi_string_get_cstr(infrared->file_path));
|
||||
|
||||
// File name in header
|
||||
// Using c-string functions on FuriString is a bad idea but file_path is not modified
|
||||
// for the lifetime of this scene so it should be fine
|
||||
const char* file_name = strrchr(furi_string_get_cstr(infrared->file_path), '/');
|
||||
if(file_name) {
|
||||
file_name++; // skip dir seperator
|
||||
} else {
|
||||
file_name = furi_string_get_cstr(infrared->file_path); // fallback
|
||||
}
|
||||
button_menu_set_header(button_menu, file_name);
|
||||
|
||||
// Can't use infrared_scene_universal_common_on_enter() since we use ButtonMenu not ButtonPanel
|
||||
view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical);
|
||||
view_stack_add_view(infrared->view_stack, button_menu_get_view(infrared->button_menu));
|
||||
|
||||
// Load universal remote data in background
|
||||
infrared_blocking_task_start(infrared, infrared_scene_universal_from_file_task_callback);
|
||||
}
|
||||
|
||||
bool infrared_scene_universal_from_file_on_event(void* context, SceneManagerEvent event) {
|
||||
InfraredApp* infrared = context;
|
||||
SceneManager* scene_manager = infrared->scene_manager;
|
||||
InfraredBruteForce* brute_force = infrared->brute_force;
|
||||
|
||||
// Only override InfraredCustomEventTypeTaskFinished on error condition
|
||||
if(!infrared_brute_force_is_started(brute_force) &&
|
||||
event.type == SceneManagerEventTypeCustom) {
|
||||
uint16_t event_type;
|
||||
int16_t event_value;
|
||||
infrared_custom_event_unpack(event.event, &event_type, &event_value);
|
||||
if(event_type == InfraredCustomEventTypeTaskFinished) {
|
||||
const InfraredErrorCode task_error = infrared_blocking_task_finalize(infrared);
|
||||
|
||||
if(INFRARED_ERROR_PRESENT(task_error)) {
|
||||
bool wrong_file_type =
|
||||
INFRARED_ERROR_CHECK(task_error, InfraredErrorCodeWrongFileType);
|
||||
const char* format = wrong_file_type ?
|
||||
"Remote file\n\"%s\" can't be openned as a library" :
|
||||
"Failed to load\n\"%s\"";
|
||||
|
||||
infrared_show_error_message(
|
||||
infrared, format, furi_string_get_cstr(infrared->file_path));
|
||||
scene_manager_previous_scene(scene_manager);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use common function for all other functionality
|
||||
return infrared_scene_universal_common_on_event(context, event);
|
||||
}
|
||||
|
||||
void infrared_scene_universal_from_file_on_exit(void* context) {
|
||||
// Can't use infrared_scene_universal_common_on_exit() since we use ButtonMenu not ButtonPanel
|
||||
InfraredApp* infrared = context;
|
||||
ButtonMenu* button_menu = infrared->button_menu;
|
||||
view_stack_remove_view(infrared->view_stack, button_menu_get_view(button_menu));
|
||||
infrared_brute_force_reset(infrared->brute_force);
|
||||
button_menu_reset(button_menu);
|
||||
}
|
||||
Reference in New Issue
Block a user