From a5436e71cbc86ff8d4974c9dca057252317f6a62 Mon Sep 17 00:00:00 2001 From: ESurge Date: Sun, 4 Jun 2023 21:22:34 -0700 Subject: [PATCH 1/4] Consolidated SubGHz Remote Configurator and SubGHz Remote Refactored to be one app --- .../helpers/subrem_custom_event.h | 34 +- .../helpers/subrem_types.h | 4 + .../helpers/txrx/subghz_txrx.c | 563 ++++++++++++++++++ .../helpers/txrx/subghz_txrx_i.h | 29 + .../icons/DolphinNice_96x59.png | Bin 0 -> 2459 bytes .../icons/remote_scene/ButtonDown_7x4.png | Bin 0 -> 102 bytes .../icons/remote_scene/ButtonLeft_4x7.png | Bin 0 -> 1415 bytes .../icons/remote_scene/ButtonRight_4x7.png | Bin 0 -> 1839 bytes .../icons/remote_scene/ButtonUp_7x4.png | Bin 0 -> 102 bytes .../icons/remote_scene/Ok_btn_9x9.png | Bin 0 -> 3605 bytes .../icons/remote_scene/Pin_arrow_up_7x9.png | Bin 0 -> 3603 bytes .../icons/remote_scene/Pin_cell_13x13.png | Bin 0 -> 3593 bytes .../icons/remote_scene/Pin_star_7x7.png | Bin 0 -> 3600 bytes .../icons/remote_scene/back_10px.png | Bin 0 -> 154 bytes .../icons/sub1_10px.png | Bin 0 -> 299 bytes .../icons/subrem_10px.png | Bin 0 -> 5000 bytes .../scenes/subrem_scene_config.h | 6 + .../scenes/subrem_scene_edit_label.c | 133 +++++ .../scenes/subrem_scene_edit_menu.c | 123 ++++ .../scenes/subrem_scene_edit_preview.c | 74 +++ .../scenes/subrem_scene_edit_submenu.c | 54 ++ .../scenes/subrem_scene_enter_new_name.c | 70 +++ .../scenes/subrem_scene_open_map_file.c | 106 +++- .../scenes/subrem_scene_open_sub_file.c | 118 ++++ .../scenes/subrem_scene_start.c | 11 + .../subghz_remote_app.c | 41 +- .../subghz_remote_app_i.c | 52 +- .../subghz_remote_app_i.h | 15 + .../views/edit_menu.c | 290 +++++++++ .../views/edit_menu.h | 29 + 30 files changed, 1724 insertions(+), 28 deletions(-) create mode 100644 applications/external/subghz_remote_refactored/helpers/txrx/subghz_txrx.c create mode 100644 applications/external/subghz_remote_refactored/helpers/txrx/subghz_txrx_i.h create mode 100644 applications/external/subghz_remote_refactored/icons/DolphinNice_96x59.png create mode 100644 applications/external/subghz_remote_refactored/icons/remote_scene/ButtonDown_7x4.png create mode 100644 applications/external/subghz_remote_refactored/icons/remote_scene/ButtonLeft_4x7.png create mode 100644 applications/external/subghz_remote_refactored/icons/remote_scene/ButtonRight_4x7.png create mode 100644 applications/external/subghz_remote_refactored/icons/remote_scene/ButtonUp_7x4.png create mode 100644 applications/external/subghz_remote_refactored/icons/remote_scene/Ok_btn_9x9.png create mode 100644 applications/external/subghz_remote_refactored/icons/remote_scene/Pin_arrow_up_7x9.png create mode 100644 applications/external/subghz_remote_refactored/icons/remote_scene/Pin_cell_13x13.png create mode 100644 applications/external/subghz_remote_refactored/icons/remote_scene/Pin_star_7x7.png create mode 100644 applications/external/subghz_remote_refactored/icons/remote_scene/back_10px.png create mode 100644 applications/external/subghz_remote_refactored/icons/sub1_10px.png create mode 100644 applications/external/subghz_remote_refactored/icons/subrem_10px.png create mode 100644 applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_label.c create mode 100644 applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_menu.c create mode 100644 applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_preview.c create mode 100644 applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_submenu.c create mode 100644 applications/external/subghz_remote_refactored/scenes/subrem_scene_enter_new_name.c create mode 100644 applications/external/subghz_remote_refactored/scenes/subrem_scene_open_sub_file.c create mode 100644 applications/external/subghz_remote_refactored/views/edit_menu.c create mode 100644 applications/external/subghz_remote_refactored/views/edit_menu.h diff --git a/applications/external/subghz_remote_refactored/helpers/subrem_custom_event.h b/applications/external/subghz_remote_refactored/helpers/subrem_custom_event.h index 8d93ab1fda9..0e5276f1ffa 100644 --- a/applications/external/subghz_remote_refactored/helpers/subrem_custom_event.h +++ b/applications/external/subghz_remote_refactored/helpers/subrem_custom_event.h @@ -1,13 +1,28 @@ #pragma once +typedef enum { + SubRemEditMenuStateUP = 0, + SubRemEditMenuStateDOWN, + SubRemEditMenuStateLEFT, + SubRemEditMenuStateRIGHT, + SubRemEditMenuStateOK, +} SubRemEditMenuState; + typedef enum { // StartSubmenuIndex - SubmenuIndexSubRemOpenMapFile = 0, + SubmenuIndexSubRemOpenMapFile, + SubmenuIndexSubRemRunMapFile, + SubmenuIndexSubRemEditMapFile, + SubmenuIndexSubRemNewMapFile, #if FURI_DEBUG SubmenuIndexSubRemRemoteView, #endif // SubmenuIndexSubRemAbout, + // EditSubmenuIndex + EditSubmenuIndexEditLabel, + EditSubmenuIndexEditFile, + // SubRemCustomEvent SubRemCustomEventViewRemoteStartUP = 100, SubRemCustomEventViewRemoteStartDOWN, @@ -17,4 +32,21 @@ typedef enum { SubRemCustomEventViewRemoteBack, SubRemCustomEventViewRemoteStop, SubRemCustomEventViewRemoteForcedStop, + + SubRemCustomEventViewEditMenuBack, + SubRemCustomEventViewEditMenuUP, + SubRemCustomEventViewEditMenuDOWN, + SubRemCustomEventViewEditMenuEdit, + SubRemCustomEventViewEditMenuSave, + + SubRemCustomEventSceneEditsubmenu, + SubRemCustomEventSceneEditLabelInputDone, + SubRemCustomEventSceneEditLabelWidgetAcces, + SubRemCustomEventSceneEditLabelWidgetBack, + + SubRemCustomEventSceneEditOpenSubErrorPopup, + + SubRemCustomEventSceneEditPreviewSaved, + + SubRemCustomEventSceneNewName, } SubRemCustomEvent; \ No newline at end of file diff --git a/applications/external/subghz_remote_refactored/helpers/subrem_types.h b/applications/external/subghz_remote_refactored/helpers/subrem_types.h index b392de17e05..b43f8499d84 100644 --- a/applications/external/subghz_remote_refactored/helpers/subrem_types.h +++ b/applications/external/subghz_remote_refactored/helpers/subrem_types.h @@ -18,7 +18,11 @@ typedef enum { typedef enum { SubRemViewIDSubmenu, + SubRemViewIDWidget, + SubRemViewIDPopup, + SubRemViewIDTextInput, SubRemViewIDRemote, + SubRemViewIDEditMenu, } SubRemViewID; typedef enum { diff --git a/applications/external/subghz_remote_refactored/helpers/txrx/subghz_txrx.c b/applications/external/subghz_remote_refactored/helpers/txrx/subghz_txrx.c new file mode 100644 index 00000000000..c1f519ba0d4 --- /dev/null +++ b/applications/external/subghz_remote_refactored/helpers/txrx/subghz_txrx.c @@ -0,0 +1,563 @@ +#include "subghz_txrx_i.h" +#include + +#define TAG "SubGhz" + +SubGhzTxRx* subghz_txrx_alloc() { + SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx)); + instance->setting = subghz_setting_alloc(); + subghz_setting_load(instance->setting, EXT_PATH("subghz/assets/setting_user")); + + instance->preset = malloc(sizeof(SubGhzRadioPreset)); + instance->preset->name = furi_string_alloc(); + subghz_txrx_set_preset( + instance, "AM650", subghz_setting_get_default_frequency(instance->setting), NULL, 0); + + instance->txrx_state = SubGhzTxRxStateSleep; + + subghz_txrx_hopper_set_state(instance, SubGhzHopperStateOFF); + subghz_txrx_speaker_set_state(instance, SubGhzSpeakerStateDisable); + subghz_txrx_set_debug_pin_state(instance, false); + + instance->worker = subghz_worker_alloc(); + instance->fff_data = flipper_format_string_alloc(); + + instance->environment = subghz_environment_alloc(); + instance->is_database_loaded = subghz_environment_load_keystore( + instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes")); + subghz_environment_load_keystore( + instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user")); + subghz_environment_set_came_atomo_rainbow_table_file_name( + instance->environment, EXT_PATH("subghz/assets/came_atomo")); + subghz_environment_set_alutech_at_4n_rainbow_table_file_name( + instance->environment, EXT_PATH("subghz/assets/alutech_at_4n")); + subghz_environment_set_nice_flor_s_rainbow_table_file_name( + instance->environment, EXT_PATH("subghz/assets/nice_flor_s")); + subghz_environment_set_protocol_registry( + instance->environment, (void*)&subghz_protocol_registry); + instance->receiver = subghz_receiver_alloc_init(instance->environment); + + subghz_worker_set_overrun_callback( + instance->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset); + subghz_worker_set_pair_callback( + instance->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode); + subghz_worker_set_context(instance->worker, instance->receiver); + + return instance; +} + +void subghz_txrx_free(SubGhzTxRx* instance) { + furi_assert(instance); + + subghz_worker_free(instance->worker); + subghz_receiver_free(instance->receiver); + subghz_environment_free(instance->environment); + flipper_format_free(instance->fff_data); + furi_string_free(instance->preset->name); + subghz_setting_free(instance->setting); + free(instance->preset); + free(instance); +} + +bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->is_database_loaded; +} + +void subghz_txrx_set_preset( + SubGhzTxRx* instance, + const char* preset_name, + uint32_t frequency, + uint8_t* preset_data, + size_t preset_data_size) { + furi_assert(instance); + furi_string_set(instance->preset->name, preset_name); + SubGhzRadioPreset* preset = instance->preset; + preset->frequency = frequency; + preset->data = preset_data; + preset->data_size = preset_data_size; +} + +const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset) { + UNUSED(instance); + const char* preset_name = ""; + if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) { + preset_name = "AM270"; + } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) { + preset_name = "AM650"; + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) { + preset_name = "FM238"; + } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) { + preset_name = "FM476"; + } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) { + preset_name = "CUSTOM"; + } else { + FURI_LOG_E(TAG, "Unknown preset"); + } + return preset_name; +} + +SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance) { + furi_assert(instance); + return *instance->preset; +} + +void subghz_txrx_get_frequency_and_modulation( + SubGhzTxRx* instance, + FuriString* frequency, + FuriString* modulation, + bool long_name) { + furi_assert(instance); + SubGhzRadioPreset* preset = instance->preset; + if(frequency != NULL) { + furi_string_printf( + frequency, + "%03ld.%02ld", + preset->frequency / 1000000 % 1000, + preset->frequency / 10000 % 100); + } + if(modulation != NULL) { + if(long_name) { + furi_string_printf(modulation, "%s", furi_string_get_cstr(preset->name)); + } else { + furi_string_printf(modulation, "%.2s", furi_string_get_cstr(preset->name)); + } + } +} + +static void subghz_txrx_begin(SubGhzTxRx* instance, uint8_t* preset_data) { + furi_assert(instance); + furi_hal_subghz_reset(); + furi_hal_subghz_idle(); + furi_hal_subghz_load_custom_preset(preset_data); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); + instance->txrx_state = SubGhzTxRxStateIDLE; +} + +static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) { + furi_assert(instance); + if(!furi_hal_subghz_is_frequency_valid(frequency)) { + furi_crash("SubGhz: Incorrect RX frequency."); + } + furi_assert( + instance->txrx_state != SubGhzTxRxStateRx && instance->txrx_state != SubGhzTxRxStateSleep); + + furi_hal_subghz_idle(); + uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_gpio_init(furi_hal_subghz.cc1101_g0_pin, GpioModeInput, GpioPullNo, GpioSpeedLow); + furi_hal_subghz_flush_rx(); + subghz_txrx_speaker_on(instance); + furi_hal_subghz_rx(); + + furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, instance->worker); + subghz_worker_start(instance->worker); + instance->txrx_state = SubGhzTxRxStateRx; + return value; +} + +static void subghz_txrx_idle(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); + furi_hal_subghz_idle(); + subghz_txrx_speaker_off(instance); + instance->txrx_state = SubGhzTxRxStateIDLE; +} + +static void subghz_txrx_rx_end(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state == SubGhzTxRxStateRx); + + if(subghz_worker_is_running(instance->worker)) { + subghz_worker_stop(instance->worker); + furi_hal_subghz_stop_async_rx(); + } + furi_hal_subghz_idle(); + subghz_txrx_speaker_off(instance); + instance->txrx_state = SubGhzTxRxStateIDLE; +} + +void subghz_txrx_sleep(SubGhzTxRx* instance) { + furi_assert(instance); + furi_hal_subghz_sleep(); + instance->txrx_state = SubGhzTxRxStateSleep; +} + +static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) { + furi_assert(instance); + if(!furi_hal_subghz_is_frequency_valid(frequency)) { + furi_crash("SubGhz: Incorrect TX frequency."); + } + furi_assert(instance->txrx_state != SubGhzTxRxStateSleep); + furi_hal_subghz_idle(); + furi_hal_subghz_set_frequency_and_path(frequency); + furi_hal_gpio_write(furi_hal_subghz.cc1101_g0_pin, false); + furi_hal_gpio_init( + furi_hal_subghz.cc1101_g0_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow); + bool ret = furi_hal_subghz_tx(); + if(ret) { + subghz_txrx_speaker_on(instance); + instance->txrx_state = SubGhzTxRxStateTx; + } + + return ret; +} + +SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format) { + furi_assert(instance); + furi_assert(flipper_format); + + subghz_txrx_stop(instance); + + SubGhzTxRxStartTxState ret = SubGhzTxRxStartTxStateErrorParserOthers; + FuriString* temp_str = furi_string_alloc(); + uint32_t repeat = 200; + do { + if(!flipper_format_rewind(flipper_format)) { + FURI_LOG_E(TAG, "Rewind error"); + break; + } + if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) { + FURI_LOG_E(TAG, "Missing Protocol"); + break; + } + if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) { + FURI_LOG_E(TAG, "Unable Repeat"); + break; + } + ret = SubGhzTxRxStartTxStateOk; + + SubGhzRadioPreset* preset = instance->preset; + instance->transmitter = + subghz_transmitter_alloc_init(instance->environment, furi_string_get_cstr(temp_str)); + + if(instance->transmitter) { + if(subghz_transmitter_deserialize(instance->transmitter, flipper_format) == + SubGhzProtocolStatusOk) { + if(strcmp(furi_string_get_cstr(preset->name), "") != 0) { + subghz_txrx_begin( + instance, + subghz_setting_get_preset_data_by_name( + instance->setting, furi_string_get_cstr(preset->name))); + if(preset->frequency) { + if(!subghz_txrx_tx(instance, preset->frequency)) { + FURI_LOG_E(TAG, "Only Rx"); + ret = SubGhzTxRxStartTxStateErrorOnlyRx; + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + + } else { + FURI_LOG_E( + TAG, "Unknown name preset \" %s \"", furi_string_get_cstr(preset->name)); + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + + if(ret == SubGhzTxRxStartTxStateOk) { + //Start TX + furi_hal_subghz_start_async_tx( + subghz_transmitter_yield, instance->transmitter); + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + } else { + ret = SubGhzTxRxStartTxStateErrorParserOthers; + } + if(ret != SubGhzTxRxStartTxStateOk) { + subghz_transmitter_free(instance->transmitter); + if(instance->txrx_state != SubGhzTxRxStateIDLE) { + subghz_txrx_idle(instance); + } + } + + } while(false); + furi_string_free(temp_str); + return ret; +} + +void subghz_txrx_rx_start(SubGhzTxRx* instance) { + furi_assert(instance); + subghz_txrx_stop(instance); + subghz_txrx_begin( + instance, + subghz_setting_get_preset_data_by_name( + subghz_txrx_get_setting(instance), furi_string_get_cstr(instance->preset->name))); + subghz_txrx_rx(instance, instance->preset->frequency); +} + +void subghz_txrx_set_need_save_callback( + SubGhzTxRx* instance, + SubGhzTxRxNeedSaveCallback callback, + void* context) { + furi_assert(instance); + instance->need_save_callback = callback; + instance->need_save_context = context; +} + +static void subghz_txrx_tx_stop(SubGhzTxRx* instance) { + furi_assert(instance); + furi_assert(instance->txrx_state == SubGhzTxRxStateTx); + //Stop TX + furi_hal_subghz_stop_async_tx(); + subghz_transmitter_stop(instance->transmitter); + subghz_transmitter_free(instance->transmitter); + + //if protocol dynamic then we save the last upload + if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) { + if(instance->need_save_callback) { + instance->need_save_callback(instance->need_save_context); + } + } + subghz_txrx_idle(instance); + subghz_txrx_speaker_off(instance); + //Todo: Show message + // notification_message(notifications, &sequence_reset_red); +} + +FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->fff_data; +} + +SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->setting; +} + +void subghz_txrx_stop(SubGhzTxRx* instance) { + furi_assert(instance); + + switch(instance->txrx_state) { + case SubGhzTxRxStateTx: + subghz_txrx_tx_stop(instance); + subghz_txrx_speaker_unmute(instance); + break; + case SubGhzTxRxStateRx: + subghz_txrx_rx_end(instance); + subghz_txrx_speaker_mute(instance); + break; + + default: + break; + } +} + +void subghz_txrx_hopper_update(SubGhzTxRx* instance) { + furi_assert(instance); + + switch(instance->hopper_state) { + case SubGhzHopperStateOFF: + case SubGhzHopperStatePause: + return; + case SubGhzHopperStateRSSITimeOut: + if(instance->hopper_timeout != 0) { + instance->hopper_timeout--; + return; + } + break; + default: + break; + } + float rssi = -127.0f; + if(instance->hopper_state != SubGhzHopperStateRSSITimeOut) { + // See RSSI Calculation timings in CC1101 17.3 RSSI + rssi = furi_hal_subghz_get_rssi(); + + // Stay if RSSI is high enough + if(rssi > -90.0f) { + instance->hopper_timeout = 10; + instance->hopper_state = SubGhzHopperStateRSSITimeOut; + return; + } + } else { + instance->hopper_state = SubGhzHopperStateRunning; + } + // Select next frequency + if(instance->hopper_idx_frequency < + subghz_setting_get_hopper_frequency_count(instance->setting) - 1) { + instance->hopper_idx_frequency++; + } else { + instance->hopper_idx_frequency = 0; + } + + if(instance->txrx_state == SubGhzTxRxStateRx) { + subghz_txrx_rx_end(instance); + }; + if(instance->txrx_state == SubGhzTxRxStateIDLE) { + subghz_receiver_reset(instance->receiver); + instance->preset->frequency = + subghz_setting_get_hopper_frequency(instance->setting, instance->hopper_idx_frequency); + subghz_txrx_rx(instance, instance->preset->frequency); + } +} + +SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->hopper_state; +} + +void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state) { + furi_assert(instance); + instance->hopper_state = state; +} + +void subghz_txrx_hopper_unpause(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->hopper_state == SubGhzHopperStatePause) { + instance->hopper_state = SubGhzHopperStateRunning; + } +} + +void subghz_txrx_hopper_pause(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->hopper_state == SubGhzHopperStateRunning) { + instance->hopper_state = SubGhzHopperStatePause; + } +} + +void subghz_txrx_speaker_on(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton); + } + + if(instance->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_acquire(30)) { + if(!instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + } + } else { + instance->speaker_state = SubGhzSpeakerStateDisable; + } + } +} + +void subghz_txrx_speaker_off(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } + if(instance->speaker_state != SubGhzSpeakerStateDisable) { + if(furi_hal_speaker_is_mine()) { + if(!instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } + furi_hal_speaker_release(); + if(instance->speaker_state == SubGhzSpeakerStateShutdown) + instance->speaker_state = SubGhzSpeakerStateDisable; + } + } +} + +void subghz_txrx_speaker_mute(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } + if(instance->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_is_mine()) { + if(!instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(NULL); + } + } + } +} + +void subghz_txrx_speaker_unmute(SubGhzTxRx* instance) { + furi_assert(instance); + if(instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_ibutton); + } + if(instance->speaker_state == SubGhzSpeakerStateEnable) { + if(furi_hal_speaker_is_mine()) { + if(!instance->debug_pin_state) { + furi_hal_subghz_set_async_mirror_pin(&gpio_speaker); + } + } + } +} + +void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state) { + furi_assert(instance); + instance->speaker_state = state; +} + +SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->speaker_state; +} + +bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol) { + furi_assert(instance); + furi_assert(name_protocol); + bool res = false; + instance->decoder_result = + subghz_receiver_search_decoder_base_by_name(instance->receiver, name_protocol); + if(instance->decoder_result) { + res = true; + } + return res; +} + +SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->decoder_result; +} + +bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance) { + furi_assert(instance); + return ( + (instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) == + SubGhzProtocolFlag_Save); +} + +bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type) { + furi_assert(instance); + const SubGhzProtocol* protocol = instance->decoder_result->protocol; + if(check_type) { + return ( + ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) && + protocol->encoder->deserialize && protocol->type == SubGhzProtocolTypeStatic); + } + return ( + ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) && + protocol->encoder->deserialize); +} + +void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter) { + furi_assert(instance); + subghz_receiver_set_filter(instance->receiver, filter); +} + +void subghz_txrx_set_rx_calback( + SubGhzTxRx* instance, + SubGhzReceiverCallback callback, + void* context) { + subghz_receiver_set_rx_callback(instance->receiver, callback, context); +} + +void subghz_txrx_set_raw_file_encoder_worker_callback_end( + SubGhzTxRx* instance, + SubGhzProtocolEncoderRAWCallbackEnd callback, + void* context) { + subghz_protocol_raw_file_encoder_worker_set_callback_end( + (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(instance->transmitter), + callback, + context); +} + +void subghz_txrx_set_debug_pin_state(SubGhzTxRx* instance, bool state) { + furi_assert(instance); + instance->debug_pin_state = state; +} + +bool subghz_txrx_get_debug_pin_state(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->debug_pin_state; +} + +SubGhzReceiver* subghz_txrx_get_receiver(SubGhzTxRx* instance) { + furi_assert(instance); + return instance->receiver; +} \ No newline at end of file diff --git a/applications/external/subghz_remote_refactored/helpers/txrx/subghz_txrx_i.h b/applications/external/subghz_remote_refactored/helpers/txrx/subghz_txrx_i.h new file mode 100644 index 00000000000..680d271585b --- /dev/null +++ b/applications/external/subghz_remote_refactored/helpers/txrx/subghz_txrx_i.h @@ -0,0 +1,29 @@ + +#pragma once +#include "subghz_txrx.h" + +struct SubGhzTxRx { + SubGhzWorker* worker; + + SubGhzEnvironment* environment; + SubGhzReceiver* receiver; + SubGhzTransmitter* transmitter; + SubGhzProtocolDecoderBase* decoder_result; + FlipperFormat* fff_data; + + SubGhzRadioPreset* preset; + SubGhzSetting* setting; + + uint8_t hopper_timeout; + uint8_t hopper_idx_frequency; + bool is_database_loaded; + SubGhzHopperState hopper_state; + + SubGhzTxRxState txrx_state; + SubGhzSpeakerState speaker_state; + + SubGhzTxRxNeedSaveCallback need_save_callback; + void* need_save_context; + + bool debug_pin_state; +}; \ No newline at end of file diff --git a/applications/external/subghz_remote_refactored/icons/DolphinNice_96x59.png b/applications/external/subghz_remote_refactored/icons/DolphinNice_96x59.png new file mode 100644 index 0000000000000000000000000000000000000000..a299d3630239b4486e249cc501872bed5996df3b GIT binary patch literal 2459 zcmbVO3s4i+8V(M(gEFORwSrA`4O0uPn|M|5y* zB*aMDxC&7(gP9JN;POOi-9khrC>Z9YJs2U!LnVcQEEC0fDtKo&ILlzb30%M}3J^;~ zv7RzcsilOs4Mq@tD*&R;!LMSk2A~{(`HK9|hQBqEX)3sQr9Je6SZU*F-^fD-p+~Hs; zHLkO%v?>ZoxEv+F#whudr%615FkA0DYR0tMEo}3OOY#xecLWe>xV?u5KtSmC^ z7)Fmj6gjfKstiEV-*Cxbbb+&rRWuI_rBJ)ybs_f1Rn&f2>q3pYwI^|J(hdn{j{0EZIm_F zpIyIWLsRUgOItR-dUbVd|6Zo=_BU_Tj4|{{jxO#=JH4o8er(5{!nZD_j4}MH&zh~9 zVLC~y(0-D6GO0ghZD8BYzP?o{>22~lT6^d@X{SwQ8vrNY-PPIMajIwC)`s14Ep72@ zeq7YOzM`?U{+W)ocXBr`eSOcpk?Rxc=ou5&)fWW|pD};-Z0mvk9}=&`Rb&y<77W~a z(>6YM;6Y5aIU~JKZ}mQZynKHiSTQ#Bczn@&jTiN^?vPJ(jhm7cXLx0oum5P$`TceG zU+wR;OO^)8CVlnM)5p$CO&e94KJt>HccCaHGusmW_b`T6m| z-R6V6Db1pErTot?^d22ojm+2>_)FbD`_+WbDGMx9f@hO27maS2`csiV(D&Fs`PS2& zvrq18du_&zXID(!KIxsU$)iuTYuZ?zmYiP&n&i@Be{IdbS-jA2c0QAlu5NXQv_0K< z3Hvs4eeu6B7yD&CNT~gIkMV&UkRU=V!iQ(+_(O&u^ah$+s{_yn(yBYeD40HeU{xGsIT6W Zfq!wOp!Q_E)I!3HFqj;YoHDIHH2#}J9|(o>FH3<^BV2haYO z-y5_sM4;GPjq%Ck6>60csmUj6EiNa>ORduPH4*)h!w|e3sE@(Z)z4*}Q$iC10Gods AV*mgE literal 0 HcmV?d00001 diff --git a/applications/external/subghz_remote_refactored/icons/remote_scene/ButtonLeft_4x7.png b/applications/external/subghz_remote_refactored/icons/remote_scene/ButtonLeft_4x7.png new file mode 100644 index 0000000000000000000000000000000000000000..0b4655d43247083aa705620e9836ac415b42ca46 GIT binary patch literal 1415 zcmbVM+iKK67*5rq)>aU2M7$VM1Vxif;vTv~W2u`S7ED{V3s&&L*<`XiG|9wd+THd> z5CnY!sdyuJtrvQyAo>KpiLcV|{Tkc)riAbluXfwSZCApL`ztB&p zx6LGKvks4K_4~)qD&oGa-YdJlW)hAKMNJd7<=t?6c^RI1>c$ifyjaM>^|&8!ey zB4!nh9u>5uen6Ve@<H5rru6h<2Ef#GQdQ*CmZOlQi~N!?9H`Rp;C% zU}CB21#?;r`&0|6C0}b-=jODa5|nEJ#ntxQ&{~jpgtwDta4hftr~G=#p@V36e4Zjh zq%J~{y26Jjn=1Nw-l*3%QW5YFE*v4z3gt0$&(*xf2en34c?JpH8+FYldo+Alvg8af-pG4(=!fyUi-Wsg z`g#n9VUcf(DFr{poMSNzw-lz>w+HV+n1ELr&SLA#LHUb0p(xWQ(1*vJ-i+1!`swxZ Z!O7;c$;lT_->m1Ovaz)0yuI`A$q$F8u*d)a literal 0 HcmV?d00001 diff --git a/applications/external/subghz_remote_refactored/icons/remote_scene/ButtonRight_4x7.png b/applications/external/subghz_remote_refactored/icons/remote_scene/ButtonRight_4x7.png new file mode 100644 index 0000000000000000000000000000000000000000..8e1c74c1c0038ea55172f19ac875003fc80c2d06 GIT binary patch literal 1839 zcmcIlO>f*p7#Yw)M6zw!O+@VZ{?d|D~WYi~8rHRY?X-&T}Yen`g$^+EJ;z+|RV zE@PoDvZ9%#+_}3bC_5Cj8jDGq541mi{7F+&KF}W65sr$Xn5H|YrMQ2(J7%Yc%;(zO z57ax000=TsQ+1Ke@+w#iw3au3cGGQWY740k2ijH>P(6tD)S)be>gX6Tj7`<`b>di- zgWp$8Y+?i31~CzF0&E4uRlA=C(Mp~K`{74jEchB|)4DDK!ZVhSwdFyw0YIZ1cDh0S{OvfO-U_~ zvmRF*m9sWDXNH)GOyqS1Skhxbr6}s*7t&@~kFM(NW5}qh?Lu@lJ}HE;FDiLdGO>LO z5pS*%E2grR)l^;|?O5b_?u0me&c1U}%jrk8*%=Wk%i)8yp2P|kuxmKg<=(u_`oQRI_0 zS`-DNysBx=#3&qSkgA@hJP>~D+ZM(s5jI6Owp`?yE=3e`YGUqkVOp#Cp=3wR3O4hX zX6BLsN3UBzV(vI5;|SZHgOb=HD0VFjpTyfFW}GnQuh>2*Q`k>*cAmA#iUT7EXSpo# zkPm5~#I-o^cpgfe#P$=4-Pi*SpT!-@nJgp8L347xe>5EKl`=_ZFc8XGy+_j=_R_7! z@vZZMowS1GJ?Zw)eetks%~G{BTR>T}9|jt0j3Btyb*C3-`C?fwY3EY`q*oYZ39DpM z&uJ;PCZPLs4QO1Jd_|A1PF)azZJ)RZ`^-VMWr6e#XUOA%3eLG_Ch@BDOHzMk*MF0G zCo7xMd?Mg*HMIXw%nNz?%60fZiZPlqb?GqUpXO`F&Yi!okZl(n>P@r1P2i)yk3DgRwbHeNn6e|;J^SK4TM LH~i+q&mR8;k>NTA literal 0 HcmV?d00001 diff --git a/applications/external/subghz_remote_refactored/icons/remote_scene/ButtonUp_7x4.png b/applications/external/subghz_remote_refactored/icons/remote_scene/ButtonUp_7x4.png new file mode 100644 index 0000000000000000000000000000000000000000..1be79328b40a93297a5609756328406565c437c0 GIT binary patch literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)I!3HFqj;YoHDIHH2#}J8d-yTOk1_O>mFaFD) zeWb+ZHz{mGZZ1QpXe09^4tcYT#4oe=UbmGC^A-KE*|F&zP#=S*tDnm{r-UX30HgpM AM*si- literal 0 HcmV?d00001 diff --git a/applications/external/subghz_remote_refactored/icons/remote_scene/Ok_btn_9x9.png b/applications/external/subghz_remote_refactored/icons/remote_scene/Ok_btn_9x9.png new file mode 100644 index 0000000000000000000000000000000000000000..9a1539da2049f12f7b25f96b11a9c40cd8227302 GIT binary patch literal 3605 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 LwKgd=cDwXHDN#*w literal 0 HcmV?d00001 diff --git a/applications/external/subghz_remote_refactored/icons/remote_scene/back_10px.png b/applications/external/subghz_remote_refactored/icons/remote_scene/back_10px.png new file mode 100644 index 0000000000000000000000000000000000000000..f9c615a99e69c0100b03a9ae7b2df903da4ecd66 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2xGmzZ=C-xtZVk{1FcVbv~PUa<$!;&U>c zv7h@-A}f&37T^=&`v3obAT#vPO>_%)r1c48n{Iv*t(u1!X;5977~7Co?ed rv9U?Av01aVRT(gMJdt+jXk=uN>R^g!*w%ImsF1<>&pI=m5)cB{fFDGZlI8yr;B3<$MxhJ?+;A4eL&#) z0Ra}bue?07WhLz78x$BO|L3mq-MMxdP^D^#YeY#(Vo9o1a#1RfVlXl=GSoFN)ipE; zF*LF=Hn1|b&^9ozGB8+QQTzo(LvDUbW?CgwgE3G~h=HkCbE6;07#-3sX@sAxkg$U?hnu$6%_P+PX_Jv(ud zLf1xG|CwUz?7R1Up5OC4zxVgNce*W&4YheW_vK(1mglK+H=%$1JZE+m`hA@F<1zI2 zyA8fptqH{ONK}=TAjGw<2*hDRkufZBKGgVD-U({Lf_l{mhyV1gGrhn5dOvmG&rb;X|2#O* z`;Gdu`y8=lFC6>o;MdlzEhu;(gUPC_z|AEGi;B+`t?Ze5z3-kKC+@xe!rsi0?9s|K zy?-daKNrL9+N8K#jUJb4ydqS`GmmU@)cv;7aPpz%>TUZsFY*}}-;x*iZ59ty6_jpT zvujoMQ}z8jJ+AG;!%Gj}Yq-_gD;(ypTplW&z40q}pQ&N1scCq0d(~q_cR%sbwf8Sv zdVdlA`l;oI1plLZ-jYiT3faL`zr6A#=Lo=7=AJsu{N?^-b1q)%coKW)>T~u}qi^rn z-7>H`clPEJwEVR7TGqAGdqR;5OY#pr*E?^={1s1Y&f(g=vM=|qHywW9AEyugs9|9K z_qUv^T38l3y>(BG-D_BB`RVoV^}JI09`V|mBd`AW<~wBWyCXky1n0|1Nlg+*V)QGN;EdcVFdq|MubW(V_Tn9{lz<&(!Cf?0&8A zl@E$Ck9Ky~46J|Y$whnDXUy8sU3Tos>?t>Un9|+}sNpj`p?cz$4F;W6I^yu1td=)j zwphHBH{ybAO5KJiY~Ik|6F0PrHpy5~o?}l42p|MCfG0x1a7;)zj7eMpo$JG-5l@?` zHXBJXB*PHMf{1m6HIN{}u@W63h2e%VF{(r~MGfORCh)5rn!{*B^Z0mvp@`R;h7ZTa zSU`M`2@oM^6GetXP{HeN+v@{V%k5_5e+8G zkwg*(VF;PVP*i$K$XbuLG3}vK5Kuyqq!%K4ie;ot)zny<8cCZ^NiaQ~ENpU0nj%lI zJjF+!xy>BKy>oC09YBCl_0@MKq5HSOc8#H zHxrPt@G@uPXxUw}=@F^kKtO1=<+RE`fZLx72 zM^h}%PZ&K2qcJ389h0U^tT{O|!J$hHs!^{hL5Gn|PU-6=pgIxrK<@yAog7DH3a%&w z8g!!r!BMD#C>udrd^9VVErOXZqga7TC7!lcqdrv)I*fX4xSm29%!}Gu0vbreA!k;g z%|4nF%vOQs$|!0w97;_$K_%JJIG$`y z0f?!B#blXMGE;<>npEzfp3l7GX_S~MYjF^T&H&=qVRY(yC*C;TeK^CKEcntEB`m4& z*s`e!#M_|0il0b3`57vUflm0by2LgR4nVX&k8KG5wO*Mw+x#3L%ravoDAo)K9*8VK z`z@R#$`oXol=A*h>SY-g(0){rAj zX|i`eX-Qc`CULv;$ClJi>UW`W?b^xP)oq_>=<%(|iFP_&{;^5&uL6OoA}L2u$;}G@ zRN$B(Zj5Yq}83M;=f=r9w8MiVD2l{4`U z0fy0oX&k*FI5pSMi{36|`Ri-l*r@*9d2H`fXk<>LZgmX9OeOkpSK|4KPBfUUdA!xx z?`7r}mf + +typedef enum { + SubRemSceneEditLabelStateTextInput, + SubRemSceneEditLabelStateWidget, +} SubRemSceneEditLabelState; + +void subrem_scene_edit_label_text_input_callback(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event( + app->view_dispatcher, SubRemCustomEventSceneEditLabelInputDone); +} + +void subrem_scene_edit_label_widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + if((result == GuiButtonTypeCenter) && (type == InputTypeShort)) { + view_dispatcher_send_custom_event( + app->view_dispatcher, SubRemCustomEventSceneEditLabelWidgetAcces); + } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { + view_dispatcher_send_custom_event( + app->view_dispatcher, SubRemCustomEventSceneEditLabelWidgetBack); + } +} + +void subrem_scene_edit_label_on_enter(void* context) { + SubGhzRemoteApp* app = context; + + SubRemSubFilePreset* sub_preset = app->map_preset->subs_preset[app->chusen_sub]; + + FuriString* temp_str = furi_string_alloc(); + + if(furi_string_empty(sub_preset->label)) { + if(furi_string_empty(sub_preset->file_path)) { + path_extract_filename(sub_preset->file_path, temp_str, true); + strcpy(app->file_name_tmp, furi_string_get_cstr(temp_str)); + } else { + strcpy(app->file_name_tmp, ""); + } + } else { + strcpy(app->file_name_tmp, furi_string_get_cstr(sub_preset->label)); + } + + TextInput* text_input = app->text_input; + text_input_set_header_text(text_input, "Label name"); + text_input_set_result_callback( + text_input, + subrem_scene_edit_label_text_input_callback, + app, + app->file_name_tmp, + 25, + false); + + text_input_set_minimum_length(app->text_input, 0); + + widget_add_string_element( + app->widget, 63, 12, AlignCenter, AlignCenter, FontPrimary, "Empty Label Name"); + widget_add_string_element( + app->widget, 63, 32, AlignCenter, AlignCenter, FontSecondary, "Continue?"); + + widget_add_button_element( + app->widget, GuiButtonTypeCenter, "Ok", subrem_scene_edit_label_widget_callback, app); + widget_add_button_element( + app->widget, GuiButtonTypeLeft, "Back", subrem_scene_edit_label_widget_callback, app); + + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneEditLabel, SubRemSceneEditLabelStateTextInput); + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDTextInput); + + furi_string_free(temp_str); +} + +bool subrem_scene_edit_label_on_event(void* context, SceneManagerEvent event) { + SubGhzRemoteApp* app = context; + + FuriString* label = app->map_preset->subs_preset[app->chusen_sub]->label; + + if(event.type == SceneManagerEventTypeBack) { + if(scene_manager_get_scene_state(app->scene_manager, SubRemSceneEditLabel) == + SubRemSceneEditLabelStateWidget) { + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneEditLabel, SubRemSceneEditLabelStateTextInput); + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDTextInput); + return true; + } else if( + scene_manager_get_scene_state(app->scene_manager, SubRemSceneEditLabel) == + SubRemSceneEditLabelStateTextInput) { + scene_manager_previous_scene(app->scene_manager); + return true; + } + + scene_manager_previous_scene(app->scene_manager); + return true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubRemCustomEventSceneEditLabelInputDone) { + if(strcmp(app->file_name_tmp, "") == 0) { + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneEditLabel, SubRemSceneEditLabelStateWidget); + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDWidget); + + } else { + furi_string_set(label, app->file_name_tmp); + app->map_not_saved = true; + scene_manager_previous_scene(app->scene_manager); + } + return true; + } else if(event.event == SubRemCustomEventSceneEditLabelWidgetAcces) { + furi_string_set(label, app->file_name_tmp); + app->map_not_saved = true; + scene_manager_previous_scene(app->scene_manager); + + return true; + } else if(event.event == SubRemCustomEventSceneEditLabelWidgetBack) { + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneEditLabel, SubRemSceneEditLabelStateTextInput); + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDTextInput); + + return true; + } + } + return false; +} + +void subrem_scene_edit_label_on_exit(void* context) { + SubGhzRemoteApp* app = context; + + // Clear view + text_input_reset(app->text_input); + widget_reset(app->widget); +} diff --git a/applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_menu.c b/applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_menu.c new file mode 100644 index 00000000000..a8882009a83 --- /dev/null +++ b/applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_menu.c @@ -0,0 +1,123 @@ +#include "../subghz_remote_app_i.h" + +void subrem_scene_edit_menu_callback(SubRemCustomEvent event, void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void subrem_scene_edit_menu_widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + if((result == GuiButtonTypeRight) && (type == InputTypeShort)) { + app->map_not_saved = false; + view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventViewEditMenuBack); + } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDEditMenu); + } +} + +static uint8_t subrem_scene_edit_menu_state_to_index(SubRemEditMenuState event_id) { + uint8_t ret = 0; + + if(event_id == SubRemEditMenuStateUP) { + ret = SubRemSubKeyNameUp; + } else if(event_id == SubRemEditMenuStateDOWN) { + ret = SubRemSubKeyNameDown; + } else if(event_id == SubRemEditMenuStateLEFT) { + ret = SubRemSubKeyNameLeft; + } else if(event_id == SubRemEditMenuStateRIGHT) { + ret = SubRemSubKeyNameRight; + } else if(event_id == SubRemEditMenuStateOK) { + ret = SubRemSubKeyNameOk; + } + + return ret; +} + +static void subrem_scene_edit_menu_update_data(SubGhzRemoteApp* app) { + furi_assert(app); + uint8_t index = subrem_scene_edit_menu_state_to_index( + scene_manager_get_scene_state(app->scene_manager, SubRemSceneEditMenu)); + + subrem_view_edit_menu_add_data_to_show( + app->subrem_edit_menu, + index, + app->map_preset->subs_preset[index]->label, + app->map_preset->subs_preset[index]->file_path, + app->map_preset->subs_preset[index]->load_state); +} + +void subrem_scene_edit_menu_on_enter(void* context) { + SubGhzRemoteApp* app = context; + + subrem_view_edit_menu_set_callback( + app->subrem_edit_menu, subrem_scene_edit_menu_callback, app); + + subrem_scene_edit_menu_update_data(app); + + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDEditMenu); + + Widget* widget = app->widget; + + widget_add_string_element( + widget, 63, 12, AlignCenter, AlignBottom, FontPrimary, "Changes are not saved"); + widget_add_string_element( + widget, 63, 32, AlignCenter, AlignBottom, FontPrimary, "do you want to exit?"); + + widget_add_button_element( + widget, GuiButtonTypeRight, "Yes", subrem_scene_edit_menu_widget_callback, app); + widget_add_button_element( + widget, GuiButtonTypeLeft, "No", subrem_scene_edit_menu_widget_callback, app); +} + +bool subrem_scene_edit_menu_on_event(void* context, SceneManagerEvent event) { + SubGhzRemoteApp* app = context; + + if(event.type == SceneManagerEventTypeBack) { + // Catch widget backEvent + return true; + } + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubRemCustomEventViewEditMenuBack) { + if(app->map_not_saved) { + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDWidget); + } else if(!scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SubRemSceneStart)) { + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + } + + return true; + } else if( + event.event == SubRemCustomEventViewEditMenuUP || + event.event == SubRemCustomEventViewEditMenuDOWN) { + scene_manager_set_scene_state( + app->scene_manager, + SubRemSceneEditMenu, + subrem_view_edit_menu_get_index(app->subrem_edit_menu)); + subrem_scene_edit_menu_update_data(app); + + return true; + } else if(event.event == SubRemCustomEventViewEditMenuEdit) { + app->chusen_sub = subrem_view_edit_menu_get_index(app->subrem_edit_menu); + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneEditSubMenu, EditSubmenuIndexEditLabel); + scene_manager_next_scene(app->scene_manager, SubRemSceneEditSubMenu); + + return true; + } else if(event.event == SubRemCustomEventViewEditMenuSave) { + scene_manager_next_scene(app->scene_manager, SubRemSceneEditPreview); + + return true; + } + } + + return false; +} + +void subrem_scene_edit_menu_on_exit(void* context) { + SubGhzRemoteApp* app = context; + widget_reset(app->widget); +} diff --git a/applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_preview.c b/applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_preview.c new file mode 100644 index 00000000000..98a423202e2 --- /dev/null +++ b/applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_preview.c @@ -0,0 +1,74 @@ +#include "../subghz_remote_app_i.h" +#include "../views/remote.h" + +#define TAG "SubRemScenRemote" + +void subghz_scene_edit_preview_save_popup_callback(void* context) { + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event( + app->view_dispatcher, SubRemCustomEventSceneEditPreviewSaved); +} + +void subrem_scene_edit_preview_callback(SubRemCustomEvent event, void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, event); +} + +void subrem_scene_edit_preview_on_enter(void* context) { + SubGhzRemoteApp* app = context; + + // Setup view + Popup* popup = app->popup; + popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); + popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, app); + popup_set_callback(popup, subghz_scene_edit_preview_save_popup_callback); + popup_enable_timeout(popup); + + subrem_view_remote_update_data_labels(app->subrem_remote_view, app->map_preset->subs_preset); + subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateOFF, 0); + + subrem_view_remote_set_callback( + app->subrem_remote_view, subrem_scene_edit_preview_callback, app); + + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDRemote); +} + +bool subrem_scene_edit_preview_on_event(void* context, SceneManagerEvent event) { + SubGhzRemoteApp* app = context; + + if(event.type == SceneManagerEventTypeBack || + (event.type == SceneManagerEventTypeCustom && + (event.event == SubRemCustomEventViewRemoteStartLEFT || + event.event == SubRemCustomEventViewRemoteForcedStop))) { + scene_manager_previous_scene(app->scene_manager); + return true; + } else if( + event.type == SceneManagerEventTypeCustom && + (event.event == SubRemCustomEventViewRemoteStartRIGHT || + event.event == SubRemCustomEventViewRemoteStartOK)) { + if(subrem_save_map_to_file(app)) { + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDPopup); + app->map_not_saved = false; + return true; + } + // TODO error screen + return true; + } else if( + event.type == SceneManagerEventTypeCustom && + event.event == SubRemCustomEventSceneEditPreviewSaved) { + scene_manager_search_and_switch_to_previous_scene(app->scene_manager, SubRemSceneEditMenu); + } + // } else if(event.type == SceneManagerEventTypeTick) { + // } + return false; +} + +void subrem_scene_edit_preview_on_exit(void* context) { + SubGhzRemoteApp* app = context; + + subrem_view_remote_set_state(app->subrem_remote_view, SubRemViewRemoteStateIdle, 0); + popup_reset(app->popup); +} diff --git a/applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_submenu.c b/applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_submenu.c new file mode 100644 index 00000000000..447beb96d91 --- /dev/null +++ b/applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_submenu.c @@ -0,0 +1,54 @@ +#include "../subghz_remote_app_i.h" +#include "../helpers/subrem_custom_event.h" + +void subrem_scene_edit_submenu_text_input_callback(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventSceneEditsubmenu); +} + +void subrem_scene_edit_submenu_callback(void* context, uint32_t index) { + furi_assert(context); + SubGhzRemoteApp* app = context; + + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void subrem_scene_edit_submenu_on_enter(void* context) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + Submenu* submenu = app->submenu; + submenu_add_item( + submenu, "Edit Label", EditSubmenuIndexEditLabel, subrem_scene_edit_submenu_callback, app); + submenu_add_item( + submenu, "Edit File", EditSubmenuIndexEditFile, subrem_scene_edit_submenu_callback, app); + + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDSubmenu); +} + +bool subrem_scene_edit_submenu_on_event(void* context, SceneManagerEvent event) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == EditSubmenuIndexEditLabel) { + scene_manager_next_scene(app->scene_manager, SubRemSceneEditLabel); + consumed = true; + } else if(event.event == EditSubmenuIndexEditFile) { + scene_manager_next_scene(app->scene_manager, SubRemSceneOpenSubFile); + consumed = true; + } + } + + return consumed; +} + +void subrem_scene_edit_submenu_on_exit(void* context) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + submenu_reset(app->submenu); +} diff --git a/applications/external/subghz_remote_refactored/scenes/subrem_scene_enter_new_name.c b/applications/external/subghz_remote_refactored/scenes/subrem_scene_enter_new_name.c new file mode 100644 index 00000000000..b829723a3aa --- /dev/null +++ b/applications/external/subghz_remote_refactored/scenes/subrem_scene_enter_new_name.c @@ -0,0 +1,70 @@ +#include "../subghz_remote_app_i.h" +#include "../helpers/subrem_custom_event.h" + +#include + +void subrem_scene_enter_new_name_text_input_callback(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, SubRemCustomEventSceneNewName); +} + +void subrem_scene_enter_new_name_on_enter(void* context) { + SubGhzRemoteApp* app = context; + + // Setup view + TextInput* text_input = app->text_input; + + //strncpy(app->file_name_tmp, "subrem_", SUBREM_MAX_LEN_NAME); + text_input_set_header_text(text_input, "Map file Name"); + text_input_set_result_callback( + text_input, + subrem_scene_enter_new_name_text_input_callback, + app, + app->file_name_tmp, + 25, + false); + + ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( + furi_string_get_cstr(app->file_path), SUBREM_APP_EXTENSION, ""); + text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); + + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDTextInput); +} + +bool subrem_scene_enter_new_name_on_event(void* context, SceneManagerEvent event) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SubRemCustomEventSceneNewName) { + if(strcmp(app->file_name_tmp, "") != 0) { + furi_string_set(app->file_path, SUBREM_APP_FOLDER); + furi_string_cat_printf( + app->file_path, "/%s%s", app->file_name_tmp, SUBREM_APP_EXTENSION); + + subrem_map_preset_reset(app->map_preset); + scene_manager_next_scene(app->scene_manager, SubRemSceneEditMenu); + } else { //error + } + consumed = true; + } + } + + return consumed; +} + +void subrem_scene_enter_new_name_on_exit(void* context) { + furi_assert(context); + + SubGhzRemoteApp* app = context; + submenu_reset(app->submenu); + + // Clear validator & view + void* validator_context = text_input_get_validator_callback_context(app->text_input); + text_input_set_validator(app->text_input, NULL, NULL); + validator_is_file_free(validator_context); + text_input_reset(app->text_input); +} diff --git a/applications/external/subghz_remote_refactored/scenes/subrem_scene_open_map_file.c b/applications/external/subghz_remote_refactored/scenes/subrem_scene_open_map_file.c index 1e917580ccd..e8e99989902 100644 --- a/applications/external/subghz_remote_refactored/scenes/subrem_scene_open_map_file.c +++ b/applications/external/subghz_remote_refactored/scenes/subrem_scene_open_map_file.c @@ -1,43 +1,105 @@ #include "../subghz_remote_app_i.h" -void subrem_scene_open_map_file_on_enter(void* context) { +void subrem_scene_open_map_file_submenu_callback(void* context, uint32_t index) { furi_assert(context); SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +void subrem_scene_open_map_file_on_enter(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + FURI_LOG_I("sub", "here1"); SubRemLoadMapState load_state = subrem_load_from_file(app); - if(load_state == SubRemLoadMapStateOK || load_state == SubRemLoadMapStateNotAllOK) { - scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); + FURI_LOG_I("sub", "here2"); + if(load_state == SubRemLoadMapStateBack) { + FURI_LOG_I("sub", "here3"); + if(!scene_manager_previous_scene(app->scene_manager)) { + FURI_LOG_I("sub", "here4"); + scene_manager_stop(app->scene_manager); + view_dispatcher_stop(app->view_dispatcher); + } else { + FURI_LOG_I("sub", "here5"); + scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, SubRemSceneStart); + } + } else if((load_state == SubRemLoadMapStateNotAllOK) || (load_state == SubRemLoadMapStateOK)) { + FURI_LOG_I("sub", "here6"); + Submenu* submenu = app->submenu; + + FURI_LOG_I("sub", "here6a"); + submenu_add_item( + submenu, + "Run Map File", + SubmenuIndexSubRemRunMapFile, + subrem_scene_open_map_file_submenu_callback, + app); + FURI_LOG_I("sub", "here6b"); + submenu_add_item( + submenu, + "Edit Map File", + SubmenuIndexSubRemEditMapFile, + subrem_scene_open_map_file_submenu_callback, + app); + + FURI_LOG_I("sub", "here6c"); + submenu_set_selected_item( + submenu, + scene_manager_get_scene_state(app->scene_manager, SubmenuIndexSubRemOpenMapFile)); + + FURI_LOG_I("sub", "here6d"); + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDSubmenu); + FURI_LOG_I("sub", "here7"); } else { - if(load_state != SubRemLoadMapStateBack) { + FURI_LOG_I("sub", "here8"); #ifdef SUBREM_LIGHT - dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file"); + dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file"); #else - DialogMessage* message = dialog_message_alloc(); + DialogMessage* message = dialog_message_alloc(); + + dialog_message_set_header(message, "Map File Error", 64, 8, AlignCenter, AlignCenter); + dialog_message_set_text(message, "Can't load\nMap file", 64, 32, AlignCenter, AlignCenter); + dialog_message_set_buttons(message, "Back", NULL, NULL); + dialog_message_show(app->dialogs, message); - dialog_message_set_header(message, "Map File Error", 64, 8, AlignCenter, AlignCenter); - dialog_message_set_text( - message, "Can't load\nMap file", 64, 32, AlignCenter, AlignCenter); - dialog_message_set_buttons(message, "Back", NULL, NULL); - dialog_message_show(app->dialogs, message); + dialog_message_free(message); - dialog_message_free(message); + FURI_LOG_I("sub", "here9"); #endif - } - // TODO: Map Preset Reset - if(!scene_manager_previous_scene(app->scene_manager)) { - scene_manager_stop(app->scene_manager); - view_dispatcher_stop(app->view_dispatcher); - } } } bool subrem_scene_open_map_file_on_event(void* context, SceneManagerEvent event) { - UNUSED(context); - UNUSED(event); - return false; + furi_assert(context); + + FURI_LOG_I("sub", "here10"); + SubGhzRemoteApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + FURI_LOG_I("sub", "here11"); + FURI_LOG_I("sub", "event.event: %lu", event.event); + if(event.event == SubmenuIndexSubRemRunMapFile) { + FURI_LOG_I("sub", "here12"); + scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); + consumed = true; + } else if(event.event == SubmenuIndexSubRemEditMapFile) { + FURI_LOG_I("sub", "here13"); + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneEditMenu, SubRemSubKeyNameUp); + scene_manager_next_scene(app->scene_manager, SubRemSceneEditMenu); + consumed = true; + } + } + + return consumed; } void subrem_scene_open_map_file_on_exit(void* context) { - UNUSED(context); + furi_assert(context); + + SubGhzRemoteApp* app = context; + submenu_reset(app->submenu); } diff --git a/applications/external/subghz_remote_refactored/scenes/subrem_scene_open_sub_file.c b/applications/external/subghz_remote_refactored/scenes/subrem_scene_open_sub_file.c new file mode 100644 index 00000000000..eb438cb9289 --- /dev/null +++ b/applications/external/subghz_remote_refactored/scenes/subrem_scene_open_sub_file.c @@ -0,0 +1,118 @@ +#include "../subghz_remote_app_i.h" + +void subrem_scene_open_sub_file_error_popup_callback(void* context) { + SubGhzRemoteApp* app = context; + view_dispatcher_send_custom_event( + app->view_dispatcher, SubRemCustomEventSceneEditOpenSubErrorPopup); +} + +SubRemLoadSubState subrem_scene_open_sub_file_dialog(SubGhzRemoteApp* app) { + furi_assert(app); + + SubRemSubFilePreset* sub = app->map_preset->subs_preset[app->chusen_sub]; + + FuriString* temp_file_path = furi_string_alloc(); + + if(furi_string_empty(sub->file_path)) { + furi_string_set(temp_file_path, SUBGHZ_RAW_FOLDER); + } else { + furi_string_set(temp_file_path, sub->file_path); + } + + SubRemLoadSubState ret = SubRemLoadSubStateNotSet; + + DialogsFileBrowserOptions browser_options; + + dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px); + browser_options.base_path = SUBGHZ_RAW_FOLDER; + + // Input events and views are managed by file_select + if(!dialog_file_browser_show(app->dialogs, temp_file_path, temp_file_path, &browser_options)) { + } else { + // Check sub file + SubRemSubFilePreset* sub_candidate = subrem_sub_file_preset_alloc(); + furi_string_set(sub_candidate->label, sub->label); + furi_string_set(sub_candidate->file_path, temp_file_path); + + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* fff_file = flipper_format_file_alloc(storage); + + if(flipper_format_file_open_existing( + fff_file, furi_string_get_cstr(sub_candidate->file_path))) { + ret = subrem_sub_preset_load(sub_candidate, app->txrx, fff_file); + } + + flipper_format_file_close(fff_file); + flipper_format_free(fff_file); + furi_record_close(RECORD_STORAGE); + + if(ret == SubRemLoadSubStateOK) { + subrem_sub_file_preset_free(app->map_preset->subs_preset[app->chusen_sub]); + app->map_preset->subs_preset[app->chusen_sub] = sub_candidate; + app->map_not_saved = true; + } else { + subrem_sub_file_preset_free(sub_candidate); + } + } + + furi_string_free(temp_file_path); + + return ret; +} + +void subrem_scene_open_sub_file_on_enter(void* context) { + furi_assert(context); + SubGhzRemoteApp* app = context; + + SubRemLoadSubState load_state = subrem_scene_open_sub_file_dialog(app); + + Popup* popup = app->popup; + // popup_set_icon(); + popup_set_header(popup, "ERROR", 63, 16, AlignCenter, AlignBottom); + popup_set_timeout(popup, 1500); + popup_set_context(popup, app); + popup_set_callback(popup, subrem_scene_open_sub_file_error_popup_callback); + popup_enable_timeout(popup); + + if(load_state == SubRemLoadSubStateOK) { + scene_manager_previous_scene(app->scene_manager); + } else if(load_state == SubRemLoadSubStateNotSet) { + scene_manager_previous_scene(app->scene_manager); + } else { + switch(load_state) { + case SubRemLoadSubStateErrorFreq: + + popup_set_text(popup, "Bad frequency", 63, 30, AlignCenter, AlignBottom); + break; + case SubRemLoadSubStateErrorMod: + + popup_set_text(popup, "Bad modulation", 63, 30, AlignCenter, AlignBottom); + break; + case SubRemLoadSubStateErrorProtocol: + + popup_set_text(popup, "Unsupported protocol", 63, 30, AlignCenter, AlignBottom); + break; + + default: + break; + } + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDPopup); + } +} + +bool subrem_scene_open_sub_file_on_event(void* context, SceneManagerEvent event) { + SubGhzRemoteApp* app = context; + + if(event.type == SceneManagerEventTypeCustom && + event.event == SubRemCustomEventSceneEditOpenSubErrorPopup) { + scene_manager_previous_scene(app->scene_manager); + return true; + } + return false; +} + +void subrem_scene_open_sub_file_on_exit(void* context) { + SubGhzRemoteApp* app = context; + + popup_reset(app->popup); +} diff --git a/applications/external/subghz_remote_refactored/scenes/subrem_scene_start.c b/applications/external/subghz_remote_refactored/scenes/subrem_scene_start.c index e780b54ceaa..fef8014db68 100644 --- a/applications/external/subghz_remote_refactored/scenes/subrem_scene_start.c +++ b/applications/external/subghz_remote_refactored/scenes/subrem_scene_start.c @@ -19,6 +19,12 @@ void subrem_scene_start_on_enter(void* context) { SubmenuIndexSubRemOpenMapFile, subrem_scene_start_submenu_callback, app); + submenu_add_item( + submenu, + "New Map File", + SubmenuIndexSubRemNewMapFile, + subrem_scene_start_submenu_callback, + app); #if FURI_DEBUG submenu_add_item( submenu, @@ -54,6 +60,11 @@ bool subrem_scene_start_on_event(void* context, SceneManagerEvent event) { #endif scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile); consumed = true; + } else if(event.event == SubmenuIndexSubRemNewMapFile) { + scene_manager_set_scene_state( + app->scene_manager, SubRemSceneStart, SubmenuIndexSubRemNewMapFile); + scene_manager_next_scene(app->scene_manager, SubRemSceneEnterNewName); + consumed = true; } // } else if(event.event == SubmenuIndexSubRemAbout) { // scene_manager_next_scene(app->scene_manager, SubRemSceneAbout); diff --git a/applications/external/subghz_remote_refactored/subghz_remote_app.c b/applications/external/subghz_remote_refactored/subghz_remote_app.c index 624a602ae99..e026fe4dea2 100644 --- a/applications/external/subghz_remote_refactored/subghz_remote_app.c +++ b/applications/external/subghz_remote_refactored/subghz_remote_app.c @@ -73,6 +73,20 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { // Dialog app->dialogs = furi_record_open(RECORD_DIALOGS); + // TextInput + app->text_input = text_input_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, SubRemViewIDTextInput, text_input_get_view(app->text_input)); + + // Widget + app->widget = widget_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, SubRemViewIDWidget, widget_get_view(app->widget)); + + // Popup + app->popup = popup_alloc(); + view_dispatcher_add_view(app->view_dispatcher, SubRemViewIDPopup, popup_get_view(app->popup)); + // Remote view app->subrem_remote_view = subrem_view_remote_alloc(); view_dispatcher_add_view( @@ -80,6 +94,13 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { SubRemViewIDRemote, subrem_view_remote_get_view(app->subrem_remote_view)); + // Edit Menu view + app->subrem_edit_menu = subrem_view_edit_menu_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, + SubRemViewIDEditMenu, + subrem_view_edit_menu_get_view(app->subrem_edit_menu)); + app->map_preset = malloc(sizeof(SubRemMapPreset)); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { app->map_preset->subs_preset[i] = subrem_sub_file_preset_alloc(); @@ -89,12 +110,14 @@ SubGhzRemoteApp* subghz_remote_app_alloc() { subghz_txrx_set_need_save_callback(app->txrx, subrem_save_active_sub, app); + app->map_not_saved = false; + #ifdef SUBREM_LIGHT scene_manager_next_scene(app->scene_manager, SubRemSceneOpenMapFile); #else scene_manager_next_scene(app->scene_manager, SubRemSceneStart); scene_manager_set_scene_state( - app->scene_manager, SubRemSceneStart, SubmenuIndexSubRemOpenMapFile); + app->scene_manager, SubRemSceneStart, SubmenuIndexSubRemEditMapFile); #endif return app; @@ -117,10 +140,26 @@ void subghz_remote_app_free(SubGhzRemoteApp* app) { // Dialog furi_record_close(RECORD_DIALOGS); + // TextInput + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDTextInput); + text_input_free(app->text_input); + + // Widget + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDWidget); + widget_free(app->widget); + + // Popup + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDPopup); + popup_free(app->popup); + // Remote view view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDRemote); subrem_view_remote_free(app->subrem_remote_view); + // Edit view + view_dispatcher_remove_view(app->view_dispatcher, SubRemViewIDEditMenu); + subrem_view_edit_menu_free(app->subrem_edit_menu); + scene_manager_free(app->scene_manager); view_dispatcher_free(app->view_dispatcher); diff --git a/applications/external/subghz_remote_refactored/subghz_remote_app_i.c b/applications/external/subghz_remote_refactored/subghz_remote_app_i.c index 26659ccb1e6..771c57c69ac 100644 --- a/applications/external/subghz_remote_refactored/subghz_remote_app_i.c +++ b/applications/external/subghz_remote_refactored/subghz_remote_app_i.c @@ -22,7 +22,7 @@ static const char* map_file_labels[SubRemSubKeyNameMaxCount][2] = { [SubRemSubKeyNameOk] = {"OK", "OKLABEL"}, }; -static void subrem_map_preset_reset(SubRemMapPreset* map_preset) { +void subrem_map_preset_reset(SubRemMapPreset* map_preset) { furi_assert(map_preset); for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { @@ -101,7 +101,7 @@ static bool subrem_map_preset_load(SubRemMapPreset* map_preset, FlipperFormat* f ret = true; } if(ret) { - // Preload seccesful + // Preload successful FURI_LOG_I( TAG, "%-5s: %s %s", @@ -145,9 +145,9 @@ SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_p } if(ret == SubRemLoadMapStateOK) { - FURI_LOG_I(TAG, "Load Map File Seccesful"); + FURI_LOG_I(TAG, "Load Map File Successful"); } else if(ret == SubRemLoadMapStateNotAllOK) { - FURI_LOG_I(TAG, "Load Map File Seccesful [Not all files]"); + FURI_LOG_I(TAG, "Load Map File Successful [Not all files]"); } else { FURI_LOG_E(TAG, "Broken Map File"); } @@ -278,3 +278,47 @@ SubRemLoadMapState subrem_load_from_file(SubGhzRemoteApp* app) { return ret; } + +bool subrem_save_map_to_file(SubGhzRemoteApp* app) { + furi_assert(app); + + const char* file_name = furi_string_get_cstr(app->file_path); + bool saved = false; + FlipperFormat* fff_data = flipper_format_string_alloc(); + + SubRemSubFilePreset* sub_preset; + + flipper_format_write_header_cstr( + fff_data, SUBREM_APP_APP_FILE_TYPE, SUBREM_APP_APP_FILE_VERSION); + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + sub_preset = app->map_preset->subs_preset[i]; + if(!furi_string_empty(sub_preset->file_path)) { + flipper_format_write_string(fff_data, map_file_labels[i][0], sub_preset->file_path); + } + } + for(uint8_t i = 0; i < SubRemSubKeyNameMaxCount; i++) { + sub_preset = app->map_preset->subs_preset[i]; + if(!furi_string_empty(sub_preset->file_path)) { + flipper_format_write_string(fff_data, map_file_labels[i][1], sub_preset->label); + } + } + + Storage* storage = furi_record_open(RECORD_STORAGE); + Stream* flipper_format_stream = flipper_format_get_raw_stream(fff_data); + + do { + if(!storage_simply_remove(storage, file_name)) { + break; + } + //ToDo check Write + stream_seek(flipper_format_stream, 0, StreamOffsetFromStart); + stream_save_to_file(flipper_format_stream, storage, file_name, FSOM_CREATE_ALWAYS); + + saved = true; + } while(0); + + furi_record_close(RECORD_STORAGE); + flipper_format_free(fff_data); + + return saved; +} \ No newline at end of file diff --git a/applications/external/subghz_remote_refactored/subghz_remote_app_i.h b/applications/external/subghz_remote_refactored/subghz_remote_app_i.h index 7526114f9ca..311e90778e4 100644 --- a/applications/external/subghz_remote_refactored/subghz_remote_app_i.h +++ b/applications/external/subghz_remote_refactored/subghz_remote_app_i.h @@ -9,6 +9,7 @@ #include #include "views/remote.h" +#include "views/edit_menu.h" #include #include @@ -32,16 +33,24 @@ typedef struct { SceneManager* scene_manager; NotificationApp* notifications; DialogsApp* dialogs; + Widget* widget; + Popup* popup; + TextInput* text_input; Submenu* submenu; + Submenu* open_submenu; FuriString* file_path; + char file_name_tmp[SUBREM_MAX_LEN_NAME]; SubRemViewRemote* subrem_remote_view; + SubRemViewEditMenu* subrem_edit_menu; SubRemMapPreset* map_preset; SubGhzTxRx* txrx; + bool map_not_saved; + uint8_t chusen_sub; } SubGhzRemoteApp; @@ -51,4 +60,10 @@ bool subrem_tx_start_sub(SubGhzRemoteApp* app, SubRemSubFilePreset* sub_preset); bool subrem_tx_stop_sub(SubGhzRemoteApp* app, bool forced); +SubRemLoadMapState subrem_map_file_load(SubGhzRemoteApp* app, const char* file_path); + +void subrem_map_preset_reset(SubRemMapPreset* map_preset); + +bool subrem_save_map_to_file(SubGhzRemoteApp* app); + void subrem_save_active_sub(void* context); \ No newline at end of file diff --git a/applications/external/subghz_remote_refactored/views/edit_menu.c b/applications/external/subghz_remote_refactored/views/edit_menu.c new file mode 100644 index 00000000000..9b88182b51b --- /dev/null +++ b/applications/external/subghz_remote_refactored/views/edit_menu.c @@ -0,0 +1,290 @@ +#include "edit_menu.h" +#include "../subghz_remote_app_i.h" + +#include +#include + +#define subrem_view_edit_menu_MAX_LABEL_LENGTH 12 + +#define FRAME_HEIGHT 12 + +struct SubRemViewEditMenu { + View* view; + SubRemViewEditMenuCallback callback; + void* context; +}; + +typedef struct { + FuriString* label; + FuriString* file_path; + SubRemLoadSubState sub_state; + + uint8_t chusen; +} SubRemViewEditMenuModel; + +void subrem_view_edit_menu_set_callback( + SubRemViewEditMenu* subrem_view_edit_menu, + SubRemViewEditMenuCallback callback, + void* context) { + furi_assert(subrem_view_edit_menu); + + subrem_view_edit_menu->callback = callback; + subrem_view_edit_menu->context = context; +} + +void subrem_view_edit_menu_add_data_to_show( + SubRemViewEditMenu* subrem_view_edit_remote, + uint8_t index, + FuriString* label, + FuriString* path, + SubRemLoadSubState state) { + furi_assert(subrem_view_edit_remote); + + with_view_model( + subrem_view_edit_remote->view, + SubRemViewEditMenuModel * model, + { + model->chusen = index; + if(!furi_string_empty(label)) { + furi_string_set(model->label, label); + } else { + furi_string_set(model->label, "Empty label"); + } + furi_string_set(model->file_path, path); + model->sub_state = state; + }, + true); +} + +uint8_t subrem_view_edit_menu_get_index(SubRemViewEditMenu* subrem_view_edit_remote) { + furi_assert(subrem_view_edit_remote); + uint8_t index; + + with_view_model( + subrem_view_edit_remote->view, + SubRemViewEditMenuModel * model, + { index = model->chusen; }, + true); + return index; +} + +void subrem_view_edit_menu_draw(Canvas* canvas, SubRemViewEditMenuModel* model) { + canvas_clear(canvas); + canvas_set_color(canvas, ColorBlack); + + canvas_clear(canvas); + + // Draw bottom btn + canvas_set_font(canvas, FontSecondary); + elements_button_left(canvas, "Back"); + elements_button_center(canvas, "Edit"); + elements_button_right(canvas, "Save"); + + // Draw top frame + canvas_draw_line(canvas, 1, 0, 125, 0); + canvas_draw_box(canvas, 0, 1, 127, FRAME_HEIGHT - 2); + canvas_draw_line(canvas, 1, FRAME_HEIGHT - 1, 125, FRAME_HEIGHT - 1); + + canvas_set_color(canvas, ColorWhite); + + // Draw btn name + canvas_set_font(canvas, FontPrimary); + switch(model->chusen) { + case SubRemSubKeyNameUp: + canvas_draw_str(canvas, 3, FRAME_HEIGHT - 2, "UP"); + break; + + case SubRemSubKeyNameDown: + canvas_draw_str(canvas, 3, FRAME_HEIGHT - 2, "DOWN"); + break; + + case SubRemSubKeyNameLeft: + canvas_draw_str(canvas, 3, FRAME_HEIGHT - 2, "LEFT"); + break; + + case SubRemSubKeyNameRight: + canvas_draw_str(canvas, 3, FRAME_HEIGHT - 2, "RIGHT"); + break; + + case SubRemSubKeyNameOk: + canvas_draw_str(canvas, 3, FRAME_HEIGHT - 2, "OK"); + break; + + default: + break; + } + + // Draw Label + canvas_set_font(canvas, FontSecondary); + elements_text_box( + canvas, + 38, + 2, + 127 - 38, + FRAME_HEIGHT, + AlignCenter, + AlignBottom, + furi_string_empty(model->label) ? "Empty label" : furi_string_get_cstr(model->label), + true); + + // Draw arrow + canvas_set_color(canvas, ColorBlack); + if(model->chusen != 0) { + canvas_draw_icon(canvas, 119, 13, &I_Pin_arrow_up_7x9); + } + if(model->chusen != 4) { + canvas_draw_icon_ex(canvas, 119, 42, &I_Pin_arrow_up_7x9, IconRotation180); + } + + // Draw file_path + if(model->sub_state == SubRemLoadSubStateOK) { + canvas_set_font(canvas, FontSecondary); + elements_text_box( + canvas, + 1, + FRAME_HEIGHT + 1, + 118, + (63 - FRAME_HEIGHT * 2), + AlignLeft, + AlignTop, + furi_string_get_cstr(model->file_path), + false); + } else if(furi_string_empty(model->file_path)) { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 1, FRAME_HEIGHT * 2 - 2, "Button not set"); + } else { + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 1, FRAME_HEIGHT * 2 - 2, "ERR:"); + canvas_set_font(canvas, FontSecondary); + switch(model->sub_state) { + case SubRemLoadSubStateErrorNoFile: + canvas_draw_str(canvas, 26, FRAME_HEIGHT * 2 - 2, "File not found"); + break; + case SubRemLoadSubStateErrorFreq: + canvas_draw_str(canvas, 26, FRAME_HEIGHT * 2 - 2, "Bad frequency"); + break; + case SubRemLoadSubStateErrorMod: + canvas_draw_str(canvas, 26, FRAME_HEIGHT * 2 - 2, "Bad modulation"); + break; + case SubRemLoadSubStateErrorProtocol: + canvas_draw_str(canvas, 26, FRAME_HEIGHT * 2 - 2, "Unsupported protocol"); + break; + + default: + break; + } + elements_text_box( + canvas, + 1, + FRAME_HEIGHT * 2, + 118, + 30, + AlignLeft, + AlignTop, + furi_string_get_cstr(model->file_path), + false); + } +} + +bool subrem_view_edit_menu_input(InputEvent* event, void* context) { + furi_assert(context); + SubRemViewEditMenu* subrem_view_edit_menu = context; + + if((event->key == InputKeyBack || event->key == InputKeyLeft) && + event->type == InputTypeShort) { + subrem_view_edit_menu->callback( + SubRemCustomEventViewEditMenuBack, subrem_view_edit_menu->context); + return true; + } else if(event->key == InputKeyUp && event->type == InputTypeShort) { + with_view_model( + subrem_view_edit_menu->view, + SubRemViewEditMenuModel * model, + { + if(model->chusen > 0) { + model->chusen -= 1; + }; + }, + true); + subrem_view_edit_menu->callback( + SubRemCustomEventViewEditMenuUP, subrem_view_edit_menu->context); + return true; + } else if(event->key == InputKeyDown && event->type == InputTypeShort) { + with_view_model( + subrem_view_edit_menu->view, + SubRemViewEditMenuModel * model, + { + if(model->chusen < 4) { + model->chusen += 1; + }; + }, + true); + subrem_view_edit_menu->callback( + SubRemCustomEventViewEditMenuDOWN, subrem_view_edit_menu->context); + return true; + } else if(event->key == InputKeyOk && event->type == InputTypeShort) { + subrem_view_edit_menu->callback( + SubRemCustomEventViewEditMenuEdit, subrem_view_edit_menu->context); + return true; + } else if(event->key == InputKeyRight && event->type == InputTypeShort) { + subrem_view_edit_menu->callback( + SubRemCustomEventViewEditMenuSave, subrem_view_edit_menu->context); + return true; + } + + return true; +} + +void subrem_view_edit_menu_enter(void* context) { + furi_assert(context); +} + +void subrem_view_edit_menu_exit(void* context) { + furi_assert(context); +} + +SubRemViewEditMenu* subrem_view_edit_menu_alloc() { + SubRemViewEditMenu* subrem_view_edit_menu = malloc(sizeof(SubRemViewEditMenu)); + + // View allocation and configuration + subrem_view_edit_menu->view = view_alloc(); + view_allocate_model( + subrem_view_edit_menu->view, ViewModelTypeLocking, sizeof(SubRemViewEditMenuModel)); + view_set_context(subrem_view_edit_menu->view, subrem_view_edit_menu); + view_set_draw_callback( + subrem_view_edit_menu->view, (ViewDrawCallback)subrem_view_edit_menu_draw); + view_set_input_callback(subrem_view_edit_menu->view, subrem_view_edit_menu_input); + view_set_enter_callback(subrem_view_edit_menu->view, subrem_view_edit_menu_enter); + view_set_exit_callback(subrem_view_edit_menu->view, subrem_view_edit_menu_exit); + + with_view_model( + subrem_view_edit_menu->view, + SubRemViewEditMenuModel * model, + { + model->label = furi_string_alloc(); // furi_string_alloc_set_str("LABEL"); + model->file_path = furi_string_alloc(); // furi_string_alloc_set_str("FILE_PATH"); + + model->chusen = 0; + }, + true); + return subrem_view_edit_menu; +} + +void subrem_view_edit_menu_free(SubRemViewEditMenu* subghz_edit_menu) { + furi_assert(subghz_edit_menu); + + with_view_model( + subghz_edit_menu->view, + SubRemViewEditMenuModel * model, + { + furi_string_free(model->label); + furi_string_free(model->file_path); + }, + true); + view_free(subghz_edit_menu->view); + free(subghz_edit_menu); +} + +View* subrem_view_edit_menu_get_view(SubRemViewEditMenu* subrem_view_edit_menu) { + furi_assert(subrem_view_edit_menu); + return subrem_view_edit_menu->view; +} \ No newline at end of file diff --git a/applications/external/subghz_remote_refactored/views/edit_menu.h b/applications/external/subghz_remote_refactored/views/edit_menu.h new file mode 100644 index 00000000000..7ceb7fac04e --- /dev/null +++ b/applications/external/subghz_remote_refactored/views/edit_menu.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include "../helpers/subrem_custom_event.h" +#include "../helpers/subrem_presets.h" + +typedef struct SubRemViewEditMenu SubRemViewEditMenu; + +typedef void (*SubRemViewEditMenuCallback)(SubRemCustomEvent event, void* context); + +void subrem_view_edit_menu_set_callback( + SubRemViewEditMenu* subrem_view_edit_menu, + SubRemViewEditMenuCallback callback, + void* context); + +SubRemViewEditMenu* subrem_view_edit_menu_alloc(); + +void subrem_view_edit_menu_free(SubRemViewEditMenu* subrem_view_edit_menu); + +View* subrem_view_edit_menu_get_view(SubRemViewEditMenu* subrem_view_edit_menu); + +void subrem_view_edit_menu_add_data_to_show( + SubRemViewEditMenu* subrem_view_edit_remote, + uint8_t index, + FuriString* label, + FuriString* path, + SubRemLoadSubState state); + +uint8_t subrem_view_edit_menu_get_index(SubRemViewEditMenu* subrem_view_edit_remote); \ No newline at end of file From 1cd9e1a7f048ee3a2f09c383f5563544833aa99b Mon Sep 17 00:00:00 2001 From: ESurge Date: Sun, 4 Jun 2023 21:48:29 -0700 Subject: [PATCH 2/4] Redid fix for External Application as Favorite --- .../scenes/desktop_settings_scene_favorite.c | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c index 7818cfe1a12..80221aa1012 100644 --- a/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c +++ b/applications/settings/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -5,11 +5,8 @@ #include #include -#define EXTERNAL_APPLICATION_NAME ("[External Application]") -#define EXTERNAL_APPLICATION_INDEX (FLIPPER_APPS_COUNT2 + 1) - #define NONE_APPLICATION_NAME ("None (disable)") -#define NONE_APPLICATION_INDEX (FLIPPER_APPS_COUNT2 + 2) +#define NONE_APPLICATION_INDEX (FLIPPER_APPS_COUNT2 + 1) static bool favorite_fap_selector_item_callback( FuriString* file_path, @@ -84,21 +81,13 @@ void desktop_settings_scene_favorite_on_enter(void* context) { if(!curr_favorite_app->is_external && !strcmp(FLIPPER_APPS2[i].name, curr_favorite_app->name_or_path)) { pre_select_item = i; + } else if( + curr_favorite_app->is_external && + (strcmp(FLIPPER_APPS2[i].name, "Applications") == 0)) { + pre_select_item = i; } } - //#ifdef APP_FAP_LOADER - submenu_add_item( - submenu, - EXTERNAL_APPLICATION_NAME, - EXTERNAL_APPLICATION_INDEX, - desktop_settings_scene_favorite_submenu_callback, - app); - if(curr_favorite_app->is_external) { - pre_select_item = EXTERNAL_APPLICATION_INDEX; - } - //#endif - submenu_add_item( submenu, NONE_APPLICATION_NAME, @@ -168,7 +157,7 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e curr_favorite_app->is_external = false; strncpy(curr_favorite_app->name_or_path, "None (disable)", MAX_APP_LENGTH); consumed = true; - } else if(event.event == EXTERNAL_APPLICATION_INDEX) { + } else if(strcmp(FLIPPER_APPS2[event.event].name, "Applications") == 0) { const DialogsFileBrowserOptions browser_options = { .extension = ".fap", .icon = &I_unknown_10px, From 022c0641acd77462d36e3d069c9f291ad4fe53e6 Mon Sep 17 00:00:00 2001 From: ESurge Date: Sun, 4 Jun 2023 22:07:29 -0700 Subject: [PATCH 3/4] Small update to SubGHz Remote Refactored consolidation --- .../scenes/subrem_scene_edit_menu.c | 2 +- .../scenes/subrem_scene_open_map_file.c | 20 +------------------ 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_menu.c b/applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_menu.c index a8882009a83..1fe66d4b398 100644 --- a/applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_menu.c +++ b/applications/external/subghz_remote_refactored/scenes/subrem_scene_edit_menu.c @@ -84,7 +84,7 @@ bool subrem_scene_edit_menu_on_event(void* context, SceneManagerEvent event) { if(app->map_not_saved) { view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDWidget); } else if(!scene_manager_search_and_switch_to_previous_scene( - app->scene_manager, SubRemSceneStart)) { + app->scene_manager, SubRemSceneOpenMapFile)) { scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); } diff --git a/applications/external/subghz_remote_refactored/scenes/subrem_scene_open_map_file.c b/applications/external/subghz_remote_refactored/scenes/subrem_scene_open_map_file.c index e8e99989902..79ba0e08ea5 100644 --- a/applications/external/subghz_remote_refactored/scenes/subrem_scene_open_map_file.c +++ b/applications/external/subghz_remote_refactored/scenes/subrem_scene_open_map_file.c @@ -10,33 +10,26 @@ void subrem_scene_open_map_file_submenu_callback(void* context, uint32_t index) void subrem_scene_open_map_file_on_enter(void* context) { furi_assert(context); SubGhzRemoteApp* app = context; - FURI_LOG_I("sub", "here1"); + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDSubmenu); SubRemLoadMapState load_state = subrem_load_from_file(app); - FURI_LOG_I("sub", "here2"); if(load_state == SubRemLoadMapStateBack) { - FURI_LOG_I("sub", "here3"); if(!scene_manager_previous_scene(app->scene_manager)) { - FURI_LOG_I("sub", "here4"); scene_manager_stop(app->scene_manager); view_dispatcher_stop(app->view_dispatcher); } else { - FURI_LOG_I("sub", "here5"); scene_manager_search_and_switch_to_previous_scene( app->scene_manager, SubRemSceneStart); } } else if((load_state == SubRemLoadMapStateNotAllOK) || (load_state == SubRemLoadMapStateOK)) { - FURI_LOG_I("sub", "here6"); Submenu* submenu = app->submenu; - FURI_LOG_I("sub", "here6a"); submenu_add_item( submenu, "Run Map File", SubmenuIndexSubRemRunMapFile, subrem_scene_open_map_file_submenu_callback, app); - FURI_LOG_I("sub", "here6b"); submenu_add_item( submenu, "Edit Map File", @@ -44,16 +37,12 @@ void subrem_scene_open_map_file_on_enter(void* context) { subrem_scene_open_map_file_submenu_callback, app); - FURI_LOG_I("sub", "here6c"); submenu_set_selected_item( submenu, scene_manager_get_scene_state(app->scene_manager, SubmenuIndexSubRemOpenMapFile)); - FURI_LOG_I("sub", "here6d"); view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDSubmenu); - FURI_LOG_I("sub", "here7"); } else { - FURI_LOG_I("sub", "here8"); #ifdef SUBREM_LIGHT dialog_message_show_storage_error(app->dialogs, "Can't load\nMap file"); #else @@ -65,8 +54,6 @@ void subrem_scene_open_map_file_on_enter(void* context) { dialog_message_show(app->dialogs, message); dialog_message_free(message); - - FURI_LOG_I("sub", "here9"); #endif } } @@ -74,19 +61,14 @@ void subrem_scene_open_map_file_on_enter(void* context) { bool subrem_scene_open_map_file_on_event(void* context, SceneManagerEvent event) { furi_assert(context); - FURI_LOG_I("sub", "here10"); SubGhzRemoteApp* app = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - FURI_LOG_I("sub", "here11"); - FURI_LOG_I("sub", "event.event: %lu", event.event); if(event.event == SubmenuIndexSubRemRunMapFile) { - FURI_LOG_I("sub", "here12"); scene_manager_next_scene(app->scene_manager, SubRemSceneRemote); consumed = true; } else if(event.event == SubmenuIndexSubRemEditMapFile) { - FURI_LOG_I("sub", "here13"); scene_manager_set_scene_state( app->scene_manager, SubRemSceneEditMenu, SubRemSubKeyNameUp); scene_manager_next_scene(app->scene_manager, SubRemSceneEditMenu); From ae4d379c66d6aee9333f805014fc9e1bfc982257 Mon Sep 17 00:00:00 2001 From: ESurge Date: Sun, 4 Jun 2023 22:19:32 -0700 Subject: [PATCH 4/4] Formatting for recent commit --- .../scenes/subrem_scene_open_map_file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/external/subghz_remote_refactored/scenes/subrem_scene_open_map_file.c b/applications/external/subghz_remote_refactored/scenes/subrem_scene_open_map_file.c index 79ba0e08ea5..f047d3a0b1c 100644 --- a/applications/external/subghz_remote_refactored/scenes/subrem_scene_open_map_file.c +++ b/applications/external/subghz_remote_refactored/scenes/subrem_scene_open_map_file.c @@ -10,7 +10,7 @@ void subrem_scene_open_map_file_submenu_callback(void* context, uint32_t index) void subrem_scene_open_map_file_on_enter(void* context) { furi_assert(context); SubGhzRemoteApp* app = context; - view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDSubmenu); + view_dispatcher_switch_to_view(app->view_dispatcher, SubRemViewIDSubmenu); SubRemLoadMapState load_state = subrem_load_from_file(app); if(load_state == SubRemLoadMapStateBack) {