From 6c0de2da96926117fac6169821a33f93fe61ced9 Mon Sep 17 00:00:00 2001 From: Sandro Kalatozishvili Date: Sun, 17 Mar 2024 05:10:07 +0400 Subject: [PATCH] Implemented alternative names functionality (#9) * Started implementation of alternative names * Implemented alternative names functionality * Update README.md * Update README.md --- .flipcorg/gallery/screen7.png | Bin 1817 -> 6208 bytes README.md | 44 ++++++++++++++++- deploy.sh | 60 +++++++++++++++++------ infrared/infrared_remote.c | 11 +++-- infrared/infrared_remote_button.c | 8 +++- infrared/infrared_remote_button.h | 5 +- screens/settings_menu.png | Bin 6123 -> 6482 bytes views/xremote_common_view.c | 74 ++++++++++++++++++++++++++-- xremote.c | 1 + xremote.h | 6 +-- xremote_app.c | 77 ++++++++++++++++++++++++++---- xremote_app.h | 12 ++++- xremote_settings.c | 26 ++++++++++ 13 files changed, 284 insertions(+), 40 deletions(-) diff --git a/.flipcorg/gallery/screen7.png b/.flipcorg/gallery/screen7.png index 6b13856a08a30e958f2436f0a72cfee4d4b593ac..d95d71c707f74436875918668f473f02136b3408 100644 GIT binary patch literal 6208 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 #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 c2f7a75352376775ed14ffa7850aea5bf0030ff9..9c4ed5c836d4b41821aaa078a47a8a358d633954 100644 GIT binary patch delta 2691 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 C4P+Vs delta 2455 zcmb`Hc{r4N8^?cRnTRY&DQhIr!82xtnUM)8Ns@i2>|2X{DeKIrXc;1h;*@mi*wPT8 zX&skk)Jfx2h+$H>vW(?mY%jw*)8L%zegA!*f1d04UH9+%eDC}I+;_VX$1rmjtT9Vl zmk2v`A%oSon`d#)OYZ3N5S-K0OleJJysXnoN2N<>IehePB(%BI zGUaC#sF|3i)An86@=NTv>M_;U<(-Y$dV9zSd27*uw2hnWkGdM7R6YHBgVWDQEz}iX zo`N6la_@XAaV!M@*rlvFRpK9xdYWSz-!kvxYOY_ybn0!nZ&{+~5d+bMZIK3# z?$lw51{Hn&{bu_$TXUwkDu$2=?~Z!D{nD|XRovPzxJR$F#p7-re-bQ7nj zNR?Pz9G$OU=|5i=7;%Q!ZnsgJyu6LIth7Poh53uqtS^k(K0IuRNzY-=ba~K6b%tB1 zTg^mLYsuF+)S^+?EmL}n(#2`ht{v>>QC{oHUJ4`k=d(@(sTa$d=RQC31#C#8 zTV1W{GGm*yu~=_{a6BIPb1Cv2`Ct_R0GSh~oe9wdyQ4V2uFYONdnl<(|uaFAot1H!8?$nzZ`bY61X%Vq<0De4%Ho z&w=_8k`q6E?YT-PLzAG+u}CEE*mXS*lfjt8dJUCom;N@;9LtE~{d;mu3M@^!D1g6) zA4>u?w&?uw^qYzW6|;6f(66*BAAovb?i7`=(`dIi{iIg1dl>_eyn#6cOKfSbXAm?%hr@vjI&G?ajxG>}+5Ci$lBpT<_jGF;B0R14fa&h-_W&goY@ zeiw3ZWzOa6V$ukrwt@CwT_5G2;nR7cegbFb-I4SzB#0lZN}907GS)0fJW$ z(NXZ^Pxp`}+C)hYExd!4*s;`G9))GebbOFn%Y{@p7pnd&C~@nN-qsk(zbYc}YaU6pw;|6e5gNH1>SsY(4ZBYWVC)_`=GUyk~B75|6lK2BwW?C;#KT?`|r}~i! zOK}!kB^$riREvq?GOAE?0Hu9%7Jr_XYxlA5^7l=3ly7UC-xN=;5=6zGBKRn z&J19V-zTUxzu244YWHDZcTTUkDHp3D&PQ@iy-ndbxy*iw+Y)6t=OsELgoFqODM!k4 zo__m0l>I|lZxs2Vv_bVz+~v~6!gau$$K#}P7>BBvvMu=UUq2XAMp;*a^tk8FyCzUW zo8m6Fd~sW%D9$>mih_mAPB8(<`JTzPcx)c8S!GY`^2i!mVz1Ekc9OjgdqKEjj5HVs z^G6eZy4}tHGM#~cLV!#eSv$d06uwmv1?%+-BJ7p)E@qQ(aM1qszNBDUP^EstW(uPF zrTQXAg^Bp_Hq@0F{gy}sqZM0ZH~ zGDSa&S&(Gtj8CnOQhQJrlhcA8`H(~~Qo5bsE2a3En_nnQV3YchGGn3)-j`Al6jE~7 z)M_@08-IM?lFa1q)7-N7E2F(W%-X;_^cT7ATr7N>2pOhQA-lS0hHGwW&TLRjwTMrS z+N9`As4E`Km&;3dWSm%*L2lnBGQEku^XV!H3~G+pClgcontext && 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; }