diff --git a/.flipcorg/gallery/screen7.png b/.flipcorg/gallery/screen7.png index 6b13856..d95d71c 100644 Binary files a/.flipcorg/gallery/screen7.png and b/.flipcorg/gallery/screen7.png differ diff --git a/README.md b/README.md index 7e9d29f..2798e2e 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,46 @@ Button name | Description `Stop` | Stop +## Alternative button names +In addition to the predefined names, `XRemote` uses alternative button names to make it as easy as possible to interact with different types of IR dumps. This means that if a button is not found in the file with the appropriate name, the application will try to find the same button with alternative names. Ensure this feature is enabled in the application settings before you use it. + +Alternate names are case insensitive and defined in the file: +``` +SD Card/apps_data/flipper_xremote/alt_names.cfg +``` + +If this file does not exist, it will be created automatically with default values when the application is launched. You are free to remove, edit or add any values you want to this file. Here is the alt_names.cfg file with default contents: + +``` +Filetype: XRemote Alt-Names +Version: 1 +# +Power: shutdown,off,on,standby +Setup: settings,config,cfg +Input: source,select +Menu: osd,gui +List: guide +Info: display +Mode: aspect,format +Back: return,exit +Ok: enter,select +Up: uparrow +Down: downarrow +Left: leftarrow +Right: rightarrow +Mute: silence,silent,unmute +Vol_up: vol+,volume+,volup,+ +Vol_dn: vol-,volume-,voldown,- +Ch_next: ch+,channel+,chup +Ch_prev: ch-,channel-,chdown +Next: next,skip,ffwd +Prev: prev,back,rewind,rew +Fast_fo: fastfwd,fastforward,ff +Fast_ba: fastback,fastrewind,fb +Play_pa: playpause,play,pause + +``` + ## Installation options 1. Install the latest stable version directly from the official [application catalog](https://lab.flipper.net/apps/flipper_xremote). @@ -73,7 +113,7 @@ Button name | Description - Use deploy script from this repository to build and run the application on the device: ```bash - ./deploy.sh --fw=/path/to/the/firmware + ./deploy.sh -b --fw=/path/to/the/firmware ``` 2. If you don't have the firmware or the Linux please refer to the [official documentation](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/AppsOnSDCard.md) for build instructions. @@ -89,6 +129,7 @@ Button name | Description - [x] Player buttons page - [x] Custom buttons page - [x] Edit custom layout + - [x] Alternative button names - [ ] Add or remove button - [ ] All buttons page - [x] Application settings @@ -98,6 +139,7 @@ Button name | Description - [x] Vertical/horizontal views - [x] IR command repeat count - [x] Exit button behavior + - [x] Enable/disable alt names ## Screens diff --git a/deploy.sh b/deploy.sh index 0f1c47f..79815a7 100755 --- a/deploy.sh +++ b/deploy.sh @@ -9,11 +9,39 @@ XCLR_DIM="\x1B[2m" XCLR_RED="\x1B[31m" XCLR_RESET="\x1B[0m\n" -# Parse firmware path from arguments if present +FBT_CMD="./fbt" +FBT_DBG="DEBUG=0" +FBT_ARGS="COMPACT=1 launch" + +BUILD_PROJECT=0 +LINK_PROJECT=0 +RUN_QFLIPPER=0 +BUILD_DONE=0 + for arg in "$@"; do if [[ $arg == --firmware=* || $arg == --fw=* ]]; then FLIPPER_FIRMWARE="${arg#*=}" fi + + if [[ $arg == "--build" || $arg == "-b" ]]; then + BUILD_PROJECT=1 + fi + + if [[ $arg == "--run" || $arg == "-r" ]]; then + RUN_PROJECT=1 + fi + + if [[ $arg == "--link" || $arg == "-l" ]]; then + LINK_PROJECT=1 + fi + + if [[ $arg == "--debug" || $arg == "-d" ]]; then + FBT_DBG="DEBUG=1" + fi + + if [[ $arg == "--sudo" || $arg == "-s" ]]; then + FBT_CMD="sudo ./fbt" + fi done # Check if FLIPPER_FIRMWARE variable is set @@ -41,21 +69,25 @@ XREMOTE_PROJ_NAME=$(basename "$XREMOTE_PROJ_PATH") FLIPPER_APPSRC="applications_user/$XREMOTE_PROJ_NAME" FLIPPER_USER_APP="$FLIPPER_FIRMWARE/$FLIPPER_APPSRC" -# Unlink existing user application first -[ -s $FLIPPER_USER_APP ] && rm -f $FLIPPER_USER_APP -ln -s $XREMOTE_PROJ_PATH $FLIPPER_FIRMWARE/applications_user +link_project() { + [ -s $FLIPPER_USER_APP ] && rm -f $FLIPPER_USER_APP + ln -s $XREMOTE_PROJ_PATH $FLIPPER_FIRMWARE/applications_user +} -# Build and deploy the project -cd $FLIPPER_FIRMWARE -DEPLOY_DONE=0 -sudo ./fbt COMPACT=1 DEBUG=0 launch APPSRC=$FLIPPER_APPSRC && DEPLOY_DONE=1 +build_project() { + cd $FLIPPER_FIRMWARE + $FBT_CMD $FBT_ARGS $FBT_DBG APPSRC=$FLIPPER_APPSRC && BUILD_DONE=1 +} -# Run qflipper command if asked -for arg in "$@"; do - if [[ $arg == "--run" || $arg == "-r" ]]; then - [ $DEPLOY_DONE -eq 1 ] && sudo qflipper +run_project() { + if [[ $BUILD_PROJECT -eq 0 || $BUILD_DONE -eq 1 ]]; then + qFlipper fi -done +} + +[ $LINK_PROJECT -eq 1 ] && link_project +[ $BUILD_PROJECT -eq 1 ] && build_project +[ $RUN_PROJECT -eq 1 ] && run_project # Return with success -exit 0 \ No newline at end of file +exit 0 diff --git a/infrared/infrared_remote.c b/infrared/infrared_remote.c index d9075cc..12066c1 100644 --- a/infrared/infrared_remote.c +++ b/infrared/infrared_remote.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -89,7 +91,9 @@ InfraredRemoteButton* infrared_remote_get_button(InfraredRemote* remote, size_t bool infrared_remote_find_button_by_name(InfraredRemote* remote, const char* name, size_t* index) { for(size_t i = 0; i < InfraredButtonArray_size(remote->buttons); i++) { InfraredRemoteButton* button = *InfraredButtonArray_get(remote->buttons, i); - if(!strcmp(infrared_remote_button_get_name(button), name)) { + FuriString* firi_name = infrared_remote_button_get_furi_name(button); + + if(button && !furi_string_cmpi_str(firi_name, name)) { *index = i; return true; } @@ -101,9 +105,8 @@ InfraredRemoteButton* infrared_remote_get_button_by_name(InfraredRemote* remote, const char* name) { for(size_t i = 0; i < InfraredButtonArray_size(remote->buttons); i++) { InfraredRemoteButton* button = *InfraredButtonArray_get(remote->buttons, i); - if(!strcmp(infrared_remote_button_get_name(button), name)) { - return button; - } + FuriString* firi_name = infrared_remote_button_get_furi_name(button); + if(button && !furi_string_cmpi_str(firi_name, name)) return button; } return NULL; } diff --git a/infrared/infrared_remote_button.c b/infrared/infrared_remote_button.c index 613761a..80747c4 100644 --- a/infrared/infrared_remote_button.c +++ b/infrared/infrared_remote_button.c @@ -3,7 +3,9 @@ https://github.com/DarkFlippers/unleashed-firmware The original project is licensed under the GNU GPLv3 - No modifications were made to this file. + + Modifications made: + - Added function infrared_remote_button_get_furi_name() */ #include "infrared_remote_button.h" @@ -36,6 +38,10 @@ const char* infrared_remote_button_get_name(InfraredRemoteButton* button) { return furi_string_get_cstr(button->name); } +FuriString* infrared_remote_button_get_furi_name(InfraredRemoteButton* button) { + return button->name; +} + void infrared_remote_button_set_signal(InfraredRemoteButton* button, InfraredSignal* signal) { infrared_signal_set_signal(button->signal, signal); } diff --git a/infrared/infrared_remote_button.h b/infrared/infrared_remote_button.h index e55d28f..158b623 100644 --- a/infrared/infrared_remote_button.h +++ b/infrared/infrared_remote_button.h @@ -3,7 +3,9 @@ https://github.com/DarkFlippers/unleashed-firmware The original project is licensed under the GNU GPLv3 - No modifications were made to this file. + + Modifications made: + - Added function infrared_remote_button_get_furi_name() */ #pragma once @@ -17,6 +19,7 @@ void infrared_remote_button_free(InfraredRemoteButton* button); void infrared_remote_button_set_name(InfraredRemoteButton* button, const char* name); const char* infrared_remote_button_get_name(InfraredRemoteButton* button); +FuriString* infrared_remote_button_get_furi_name(InfraredRemoteButton* button); void infrared_remote_button_set_signal(InfraredRemoteButton* button, InfraredSignal* signal); InfraredSignal* infrared_remote_button_get_signal(InfraredRemoteButton* button); diff --git a/screens/settings_menu.png b/screens/settings_menu.png index c2f7a75..9c4ed5c 100644 Binary files a/screens/settings_menu.png and b/screens/settings_menu.png differ diff --git a/views/xremote_common_view.c b/views/xremote_common_view.c index 670bb1d..37f20d0 100644 --- a/views/xremote_common_view.c +++ b/views/xremote_common_view.c @@ -90,9 +90,7 @@ XRemoteView* void xremote_view_clear_context(XRemoteView* rview) { furi_assert(rview); - if(rview->context && rview->on_clear) rview->on_clear(rview->context); - rview->context = NULL; } @@ -134,16 +132,84 @@ View* xremote_view_get_view(XRemoteView* rview) { return rview->view; } +InfraredRemoteButton* + infrared_remote_get_button_by_alt_name(InfraredRemote* remote, const char* name) { + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); + FuriString* header = furi_string_alloc(); + + FURI_LOG_I(XREMOTE_APP_TAG, "loading alt_names file: \'%s\'", XREMOTE_ALT_NAMES); + + InfraredRemoteButton* button = NULL; + uint32_t version = 0; + + do { + /* Open file and read the header */ + if(!flipper_format_buffered_file_open_existing(ff, XREMOTE_ALT_NAMES)) break; + if(!flipper_format_read_header(ff, header, &version)) break; + if(!furi_string_equal(header, "XRemote Alt-Names") || (version != 1)) break; + + FuriString* value = furi_string_alloc(); + if(!flipper_format_read_string(ff, name, value)) break; + + size_t start = 0; + size_t posit = furi_string_search_str(value, ",", start); + + if(posit == FURI_STRING_FAILURE) { + const char* alt_name_cstr = furi_string_get_cstr(value); + button = infrared_remote_get_button_by_name(remote, alt_name_cstr); + } else { + FuriString* alt_name = furi_string_alloc(); + + while(posit != FURI_STRING_FAILURE) { + furi_string_set_n(alt_name, value, start, posit - start); + const char* alt_name_cstr = furi_string_get_cstr(alt_name); + button = infrared_remote_get_button_by_name(remote, alt_name_cstr); + + furi_string_reset(alt_name); + if(button != NULL) break; + + start = posit + 1; // Move to the next position + posit = furi_string_search_str(value, ",", start); + } + + if(posit == FURI_STRING_FAILURE && button == NULL) { + size_t str_len = furi_string_utf8_length(value); + furi_string_set_n(alt_name, value, start, str_len - start); + const char* alt_name_cstr = furi_string_get_cstr(alt_name); + button = infrared_remote_get_button_by_name(remote, alt_name_cstr); + } + + furi_string_free(alt_name); + } + + } while(false); + + furi_record_close(RECORD_STORAGE); + furi_string_free(header); + flipper_format_free(ff); + + return button; +} + InfraredRemoteButton* xremote_view_get_button_by_name(XRemoteView* rview, const char* name) { xremote_app_assert(rview->context, NULL); + xremote_app_assert(rview->app_ctx, NULL); + + XRemoteAppSettings* settings = rview->app_ctx->app_settings; XRemoteAppButtons* buttons = (XRemoteAppButtons*)rview->context; - return infrared_remote_get_button_by_name(buttons->remote, name); + InfraredRemoteButton* button = infrared_remote_get_button_by_name(buttons->remote, name); + + if(button == NULL && settings->alt_names) + button = infrared_remote_get_button_by_alt_name(buttons->remote, name); + + return button; } bool xremote_view_press_button(XRemoteView* rview, InfraredRemoteButton* button) { xremote_app_assert(button, false); - XRemoteAppSettings* settings = rview->app_ctx->app_settings; + XRemoteAppSettings* settings = rview->app_ctx->app_settings; InfraredSignal* signal = infrared_remote_button_get_signal(button); xremote_app_assert(signal, false); diff --git a/xremote.c b/xremote.c index e6fee34..3b1b860 100644 --- a/xremote.c +++ b/xremote.c @@ -81,6 +81,7 @@ int32_t xremote_main(void* p) { /* Allocate context and main application */ XRemoteAppContext* context = xremote_app_context_alloc(p); XRemoteApp* app = xremote_app_alloc(context); + xremote_app_alt_names_check_and_store(); /* Allocate and build the menu */ xremote_app_submenu_alloc(app, XRemoteViewSubmenu, xremote_exit_callback); diff --git a/xremote.h b/xremote.h index 72fc285..c4316ba 100644 --- a/xremote.h +++ b/xremote.h @@ -8,9 +8,9 @@ #include "xremote_app.h" -#define XREMOTE_VERSION_MAJ 1 -#define XREMOTE_VERSION_MIN 2 -#define XREMOTE_BUILD_NUMBER 0 +#define XREMOTE_VERSION_MAJ 1 +#define XREMOTE_VERSION_MIN 2 +#define XREMOTE_BUILD_NUMBER 2 /* Returns FAP_VERSION + XREMOTE_BUILD_NUMBER */ void xremote_get_version(char* version, size_t length); diff --git a/xremote_app.c b/xremote_app.c index 2f0908e..90e738c 100644 --- a/xremote_app.c +++ b/xremote_app.c @@ -13,7 +13,6 @@ ////////////////////////////////////////////////////////////////////////////// #define XREMOTE_APP_SETTINGS APP_DATA_PATH("xremote.cfg") -#define TAG "XRemoteApp" #define XREMOTE_ORIENTATION_TEXT_HORIZONTAL "Horizontal" #define XREMOTE_ORIENTATION_TEXT_VERTICAL "Vertical" @@ -44,6 +43,10 @@ const char* xremote_app_get_exit_str(XRemoteAppExit exit_behavior) { return exit_behavior == XRemoteAppExitPress ? "Press" : "Hold"; } +const char* xremote_app_get_alt_names_str(uint8_t alt_names_index) { + return alt_names_index ? "On" : "Off"; +} + const char* xremote_app_get_orientation_str(ViewOrientation view_orientation) { return view_orientation == ViewOrientationHorizontal ? "Horizontal" : "Vertical"; } @@ -145,6 +148,49 @@ bool xremote_app_extension_store(XRemoteAppButtons* buttons, FuriString* path) { return success; } +bool xremote_app_alt_names_check_and_store() { + Storage* storage = furi_record_open(RECORD_STORAGE); + FlipperFormat* ff = flipper_format_file_alloc(storage); + bool success = false; + + do { + if(!flipper_format_file_open_new(ff, XREMOTE_ALT_NAMES)) break; + if(!flipper_format_write_header_cstr(ff, "XRemote Alt-Names", 1)) break; + if(!flipper_format_write_comment_cstr(ff, "")) break; + + if(!flipper_format_write_string_cstr(ff, "Power", "shutdown,off,on,standby")) break; + if(!flipper_format_write_string_cstr(ff, "Setup", "settings,config,cfg")) break; + if(!flipper_format_write_string_cstr(ff, "Input", "source,select")) break; + if(!flipper_format_write_string_cstr(ff, "Menu", "osd,gui")) break; + if(!flipper_format_write_string_cstr(ff, "List", "guide")) break; + if(!flipper_format_write_string_cstr(ff, "Info", "display")) break; + if(!flipper_format_write_string_cstr(ff, "Mode", "aspect,format")) break; + if(!flipper_format_write_string_cstr(ff, "Back", "return,exit")) break; + if(!flipper_format_write_string_cstr(ff, "Ok", "enter,select")) break; + if(!flipper_format_write_string_cstr(ff, "Up", "uparrow")) break; + if(!flipper_format_write_string_cstr(ff, "Down", "downarrow")) break; + if(!flipper_format_write_string_cstr(ff, "Left", "leftarrow")) break; + if(!flipper_format_write_string_cstr(ff, "Right", "rightarrow")) break; + if(!flipper_format_write_string_cstr(ff, "Mute", "silence,silent,unmute")) break; + if(!flipper_format_write_string_cstr(ff, "Vol_up", "vol+,volume+,volup,+")) break; + if(!flipper_format_write_string_cstr(ff, "Vol_dn", "vol-,volume-,voldown,-")) break; + if(!flipper_format_write_string_cstr(ff, "Ch_next", "ch+,channel+,chup")) break; + if(!flipper_format_write_string_cstr(ff, "Ch_prev", "ch-,channel-,chdown")) break; + if(!flipper_format_write_string_cstr(ff, "Next", "next,skip,ffwd")) break; + if(!flipper_format_write_string_cstr(ff, "Prev", "prev,back,rewind,rew")) break; + if(!flipper_format_write_string_cstr(ff, "Fast_fo", "fastfwd,fastforward,ff")) break; + if(!flipper_format_write_string_cstr(ff, "Fast_ba", "fastback,fastrewind,fb")) break; + if(!flipper_format_write_string_cstr(ff, "Play_pa", "playpause,play,pause")) break; + + success = true; + } while(false); + + furi_record_close(RECORD_STORAGE); + flipper_format_free(ff); + + return success; +} + void xremote_app_buttons_free(XRemoteAppButtons* buttons) { xremote_app_assert_void(buttons); infrared_remote_free(buttons->remote); @@ -183,7 +229,7 @@ XRemoteAppButtons* xremote_app_buttons_alloc() { XRemoteAppButtons* xremote_app_buttons_load(XRemoteAppContext* app_ctx) { /* Show file selection dialog (returns selected file path with app_ctx->file_path) */ - if(!xremote_app_browser_select_file(app_ctx, XREMOTE_APP_EXTENSION)) return NULL; + if(!xremote_app_context_select_file(app_ctx, XREMOTE_APP_EXTENSION)) return NULL; XRemoteAppButtons* buttons = xremote_app_buttons_alloc(); buttons->app_ctx = app_ctx; @@ -207,6 +253,7 @@ XRemoteAppSettings* xremote_app_settings_alloc() { settings->orientation = ViewOrientationHorizontal; settings->exit_behavior = XRemoteAppExitPress; settings->repeat_count = 2; + settings->alt_names = 0; return settings; } @@ -219,7 +266,7 @@ bool xremote_app_settings_store(XRemoteAppSettings* settings) { Storage* storage = furi_record_open(RECORD_STORAGE); FlipperFormat* ff = flipper_format_file_alloc(storage); - FURI_LOG_I(TAG, "store config file: \'%s\'", XREMOTE_APP_SETTINGS); + FURI_LOG_I(XREMOTE_APP_TAG, "store config file: \'%s\'", XREMOTE_APP_SETTINGS); bool success = false; do { @@ -238,6 +285,9 @@ bool xremote_app_settings_store(XRemoteAppSettings* settings) { value = settings->repeat_count; if(!flipper_format_write_uint32(ff, "repeat", &value, 1)) break; + value = settings->alt_names; + if(!flipper_format_write_uint32(ff, "altNames", &value, 1)) break; + success = true; } while(false); @@ -252,7 +302,7 @@ bool xremote_app_settings_load(XRemoteAppSettings* settings) { FlipperFormat* ff = flipper_format_buffered_file_alloc(storage); FuriString* header = furi_string_alloc(); - FURI_LOG_I(TAG, "load config file: \'%s\'", XREMOTE_APP_SETTINGS); + FURI_LOG_I(XREMOTE_APP_TAG, "load config file: \'%s\'", XREMOTE_APP_SETTINGS); uint32_t version = 0; uint32_t value = 0; bool success = false; @@ -273,6 +323,9 @@ bool xremote_app_settings_load(XRemoteAppSettings* settings) { if(!flipper_format_read_uint32(ff, "repeat", &value, 1)) break; settings->repeat_count = value; + if(!flipper_format_read_uint32(ff, "altNames", &value, 1)) break; + settings->alt_names = value; + success = true; } while(false); @@ -326,24 +379,23 @@ void xremote_app_context_free(XRemoteAppContext* ctx) { free(ctx); } -bool xremote_app_browser_select_file(XRemoteAppContext* app_ctx, const char* extension) { +bool xremote_app_browser_select_file(FuriString** file_path, const char* extension) { DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS); Storage* storage = furi_record_open(RECORD_STORAGE); storage_simply_mkdir(storage, XREMOTE_APP_FOLDER); - if(app_ctx->file_path == NULL) { - app_ctx->file_path = furi_string_alloc(); - furi_string_set(app_ctx->file_path, XREMOTE_APP_FOLDER); + if(*file_path == NULL) { + *file_path = furi_string_alloc(); + furi_string_set(*file_path, XREMOTE_APP_FOLDER); } /* Open file browser (view and dialogs are managed by the browser itself) */ DialogsFileBrowserOptions browser; dialog_file_browser_set_basic_options(&browser, extension, &I_IR_Icon_10x10); browser.base_path = XREMOTE_APP_FOLDER; - FuriString* path = app_ctx->file_path; /* Show file selection dialog (returns selected file path with file_path) */ - bool status = dialog_file_browser_show(dialogs, path, path, &browser); + bool status = dialog_file_browser_show(dialogs, *file_path, *file_path, &browser); /* Cleanup file loading context */ furi_record_close(RECORD_STORAGE); @@ -352,6 +404,11 @@ bool xremote_app_browser_select_file(XRemoteAppContext* app_ctx, const char* ext return status; } +bool xremote_app_context_select_file(XRemoteAppContext* app_ctx, const char* extension) { + if(app_ctx == NULL) return false; + return xremote_app_browser_select_file(&app_ctx->file_path, extension); +} + const char* xremote_app_context_get_exit_str(XRemoteAppContext* app_ctx) { XRemoteAppExit exit_behavior = app_ctx->app_settings->exit_behavior; return exit_behavior == XRemoteAppExitHold ? "Hold to exit" : "Press to exit"; diff --git a/xremote_app.h b/xremote_app.h index 1f0a3ac..51a8aac 100644 --- a/xremote_app.h +++ b/xremote_app.h @@ -32,9 +32,13 @@ // XRemote generic functions and definitions ////////////////////////////////////////////////////////////////////////////// +#define XREMOTE_APP_TEXT_MAX 128 #define XREMOTE_APP_EXTENSION ".ir" +#define XREMOTE_APP_TAG "XRemoteApp" + #define XREMOTE_APP_FOLDER ANY_PATH("infrared") -#define XREMOTE_APP_TEXT_MAX 128 +#define XREMOTE_APP_SETTINGS APP_DATA_PATH("xremote.cfg") +#define XREMOTE_ALT_NAMES APP_DATA_PATH("alt_names.cfg") #define xremote_app_assert_void(cond) \ if(!cond) return @@ -49,6 +53,7 @@ uint32_t xremote_app_get_exit_index(XRemoteAppExit exit_behavior); ViewOrientation xremote_app_get_orientation(uint8_t orientation_index); const char* xremote_app_get_orientation_str(ViewOrientation view_orientation); +const char* xremote_app_get_alt_names_str(uint8_t alt_names_index); uint32_t xremote_app_get_orientation_index(ViewOrientation view_orientation); ////////////////////////////////////////////////////////////////////////////// @@ -59,6 +64,7 @@ typedef struct { ViewOrientation orientation; XRemoteAppExit exit_behavior; uint32_t repeat_count; + uint32_t alt_names; } XRemoteAppSettings; XRemoteAppSettings* xremote_app_settings_alloc(); @@ -87,7 +93,8 @@ const char* xremote_app_context_get_exit_str(XRemoteAppContext* app_ctx); void xremote_app_context_notify_led(XRemoteAppContext* app_ctx); void xremote_app_notification_blink(NotificationApp* notifications); bool xremote_app_send_signal(XRemoteAppContext* app_ctx, InfraredSignal* signal); -bool xremote_app_browser_select_file(XRemoteAppContext* app_ctx, const char* extension); +bool xremote_app_context_select_file(XRemoteAppContext* app_ctx, const char* extension); +bool xremote_app_browser_select_file(FuriString** file_path, const char* extension); ////////////////////////////////////////////////////////////////////////////// // XRemote buttons and custom button pairs @@ -114,6 +121,7 @@ XRemoteAppButtons* xremote_app_buttons_load(XRemoteAppContext* app_ctx); bool xremote_app_extension_store(XRemoteAppButtons* buttons, FuriString* path); bool xremote_app_extension_load(XRemoteAppButtons* buttons, FuriString* path); +bool xremote_app_alt_names_check_and_store(); ////////////////////////////////////////////////////////////////////////////// // XRemote application factory diff --git a/xremote_settings.c b/xremote_settings.c index 3af88a5..2710f7d 100644 --- a/xremote_settings.c +++ b/xremote_settings.c @@ -22,6 +22,9 @@ typedef struct { #define XREMOTE_REPEAT_TEXT "IR Msg Repeat" #define XREMOTE_REPEAT_MAX 128 +#define XREMOTE_ALT_NAMES_TEXT "Alt Names" +#define XREMOTE_ALT_NAMES_MAX 2 + static uint32_t xremote_settings_view_exit_callback(void* context) { UNUSED(context); return XRemoteViewSubmenu; @@ -63,6 +66,17 @@ static void infrared_settings_exit_changed(VariableItem* item) { xremote_app_settings_store(settings); } +static void infrared_settings_alt_names_changed(VariableItem* item) { + XRemoteSettingsContext* ctx = variable_item_get_context(item); + XRemoteAppSettings* settings = ctx->app_ctx->app_settings; + + settings->alt_names = variable_item_get_current_value_index(item); + const char* alt_names_str = xremote_app_get_alt_names_str(settings->alt_names); + + variable_item_set_current_value_text(item, alt_names_str); + xremote_app_settings_store(settings); +} + static XRemoteSettingsContext* xremote_settings_context_alloc(XRemoteAppContext* app_ctx) { XRemoteSettingsContext* context = malloc(sizeof(XRemoteSettingsContext)); XRemoteAppSettings* settings = app_ctx->app_settings; @@ -121,6 +135,18 @@ static XRemoteSettingsContext* xremote_settings_context_alloc(XRemoteAppContext* variable_item_set_current_value_index(item, exit_index); variable_item_set_current_value_text(item, exit_str); + /* Add exit behavior to variable item list */ + item = variable_item_list_add( + context->item_list, + XREMOTE_ALT_NAMES_TEXT, + XREMOTE_ALT_NAMES_MAX, + infrared_settings_alt_names_changed, + context); + + /* Set exit behavior item index and string */ + variable_item_set_current_value_index(item, settings->alt_names); + variable_item_set_current_value_text(item, xremote_app_get_alt_names_str(settings->alt_names)); + return context; }