Ver Fonte

Merge pull request #9 from leedave/feature/ir_ind_timer

Feature/ir ind timer
David Lee há 1 ano atrás
pai
commit
47aea2c6e0

+ 1 - 1
README.md

@@ -4,7 +4,7 @@
 - Infrared working
 - Infrared working
 - SubGhz working
 - SubGhz working
 - Pause working
 - Pause working
-- IR Timing features in development
+- IR Timing features working
 
 
 ## What this is?
 ## What this is?
 This app combines commands used in IR and SubGhz into playlists that can be run with one click
 This app combines commands used in IR and SubGhz into playlists that can be run with one click

+ 1 - 1
application.fam

@@ -6,7 +6,7 @@ App(
     stack_size=3 * 1024,
     stack_size=3 * 1024,
     fap_icon="icons/xremote_10px.png",
     fap_icon="icons/xremote_10px.png",
     fap_icon_assets="icons",
     fap_icon_assets="icons",
-    fap_version="2.0",
+    fap_version="2.1",
     fap_category="Infrared",
     fap_category="Infrared",
     fap_author="Leedave",
     fap_author="Leedave",
     fap_description="One-Click, sends multiple commands",
     fap_description="One-Click, sends multiple commands",

+ 3 - 0
docs/changelog.md

@@ -1,3 +1,6 @@
+## v2.1
+- Added ability to individually set IR Signal time
+
 ## v2.0
 ## v2.0
 - SubGhz Functionality added
 - SubGhz Functionality added
 - Slight change in Storage format to enalbe individual IR timings later (feature request)
 - Slight change in Storage format to enalbe individual IR timings later (feature request)

+ 390 - 0
helpers/gui/int_input.c

@@ -0,0 +1,390 @@
+#include "int_input.h"
+
+#include <gui/elements.h>
+#include <furi.h>
+#include <assets_icons.h>
+
+/** IntInput type */
+struct IntInput {
+    View* view;
+};
+
+typedef struct {
+    const char text;
+    const uint8_t x;
+    const uint8_t y;
+} IntInputKey;
+
+typedef struct {
+    const char* header;
+    char* text_buffer;
+    size_t text_buffer_size;
+    bool clear_default_text;
+
+    IntInputCallback callback;
+    void* callback_context;
+
+    int8_t selected_row;
+    uint8_t selected_column;
+} IntInputModel;
+
+static const uint8_t keyboard_origin_x = 7;
+static const uint8_t keyboard_origin_y = 31;
+static const uint8_t keyboard_row_count = 2;
+static const uint8_t enter_symbol = '\r';
+static const uint8_t backspace_symbol = '\b';
+
+static const IntInputKey keyboard_keys_row_1[] = {
+    {'0', 0, 12},
+    {'1', 11, 12},
+    {'2', 22, 12},
+    {'3', 33, 12},
+    {'4', 44, 12},
+    {backspace_symbol, 103, 4},
+};
+
+static const IntInputKey keyboard_keys_row_2[] = {
+    {'5', 0, 26},
+    {'6', 11, 26},
+    {'7', 22, 26},
+    {'8', 33, 26},
+    {'9', 44, 26},
+    {enter_symbol, 95, 17},
+};
+
+/** Get row size
+ *
+ * @param      row_index  Index of row
+ *
+ * @return     uint8_t Row size
+ */
+static uint8_t int_input_get_row_size(uint8_t row_index) {
+    uint8_t row_size = 0;
+
+    switch(row_index + 1) {
+    case 1:
+        row_size = COUNT_OF(keyboard_keys_row_1);
+        break;
+    case 2:
+        row_size = COUNT_OF(keyboard_keys_row_2);
+        break;
+    default:
+        furi_crash();
+    }
+
+    return row_size;
+}
+
+/** Get row pointer
+ *
+ * @param      row_index  Index of row
+ *
+ * @return     const IntInputKey* Row pointer
+ */
+static const IntInputKey* int_input_get_row(uint8_t row_index) {
+    const IntInputKey* row = NULL;
+
+    switch(row_index + 1) {
+    case 1:
+        row = keyboard_keys_row_1;
+        break;
+    case 2:
+        row = keyboard_keys_row_2;
+        break;
+    default:
+        furi_crash();
+    }
+
+    return row;
+}
+
+/** Draw input box (common view)
+ *
+ * @param      canvas  The canvas
+ * @param      model   The model
+ */
+static void int_input_draw_input(Canvas* canvas, IntInputModel* model) {
+    const uint8_t text_x = 8;
+    const uint8_t text_y = 25;
+
+    elements_slightly_rounded_frame(canvas, 6, 14, 116, 15);
+
+    const char* text = model->text_buffer;
+    canvas_draw_str(canvas, text_x, text_y, text);
+}
+
+static void int_input_backspace_cb(IntInputModel* model) {
+    uint8_t text_length = model->clear_default_text ? 1 : strlen(model->text_buffer);
+    if(text_length > 0) {
+        model->text_buffer[text_length - 1] = 0;
+    }
+}
+
+/** Handle up button
+ *
+ * @param      model  The model
+ */
+static void int_input_handle_up(IntInputModel* model) {
+    if(model->selected_row > 0) {
+        model->selected_row--;
+    }
+}
+
+/** Handle down button
+ *
+ * @param      model  The model
+ */
+static void int_input_handle_down(IntInputModel* model) {
+    if(model->selected_row < keyboard_row_count - 1) {
+        model->selected_row += 1;
+    }
+}
+
+/** Handle left button
+ *
+ * @param      model  The model
+ */
+static void int_input_handle_left(IntInputModel* model) {
+    if(model->selected_column > 0) {
+        model->selected_column--;
+    } else {
+        model->selected_column = int_input_get_row_size(model->selected_row) - 1;
+    }
+}
+
+/** Handle right button
+ *
+ * @param      model  The model
+ */
+static void int_input_handle_right(IntInputModel* model) {
+    if(model->selected_column < int_input_get_row_size(model->selected_row) - 1) {
+        model->selected_column++;
+    } else {
+        model->selected_column = 0;
+    }
+}
+
+/** Handle OK button
+ *
+ * @param      model  The model
+ */
+static void int_input_handle_ok(IntInputModel* model) {
+    char selected = int_input_get_row(model->selected_row)[model->selected_column].text;
+    size_t text_length = strlen(model->text_buffer);
+    if(selected == enter_symbol) {
+        model->callback(model->callback_context);
+    } else if(selected == backspace_symbol) {
+        int_input_backspace_cb(model);
+    } else {
+        if(model->clear_default_text) {
+            text_length = 0;
+        }
+        if(text_length < (model->text_buffer_size - 1)) {
+            model->text_buffer[text_length] = selected;
+            model->text_buffer[text_length + 1] = 0;
+        }
+    }
+    model->clear_default_text = false;
+}
+
+/** Draw callback
+ *
+ * @param      canvas  The canvas
+ * @param      _model  The model
+ */
+static void int_input_view_draw_callback(Canvas* canvas, void* _model) {
+    IntInputModel* model = _model;
+    uint8_t text_length = model->text_buffer ? strlen(model->text_buffer) : 0;
+    UNUSED(text_length);
+
+    canvas_clear(canvas);
+    canvas_set_color(canvas, ColorBlack);
+
+    int_input_draw_input(canvas, model);
+
+    canvas_set_font(canvas, FontSecondary);
+    canvas_draw_str(canvas, 2, 9, model->header);
+    canvas_set_font(canvas, FontKeyboard);
+    // Draw keyboard
+    for(uint8_t row = 0; row < keyboard_row_count; row++) {
+        const uint8_t column_count = int_input_get_row_size(row);
+        const IntInputKey* keys = int_input_get_row(row);
+
+        for(size_t column = 0; column < column_count; column++) {
+            if(keys[column].text == enter_symbol) {
+                canvas_set_color(canvas, ColorBlack);
+                if(model->selected_row == row && model->selected_column == column) {
+                    canvas_draw_icon(
+                        canvas,
+                        keyboard_origin_x + keys[column].x,
+                        keyboard_origin_y + keys[column].y,
+                        &I_KeySaveSelected_24x11);
+                } else {
+                    canvas_draw_icon(
+                        canvas,
+                        keyboard_origin_x + keys[column].x,
+                        keyboard_origin_y + keys[column].y,
+                        &I_KeySave_24x11);
+                }
+            } else if(keys[column].text == backspace_symbol) {
+                canvas_set_color(canvas, ColorBlack);
+                if(model->selected_row == row && model->selected_column == column) {
+                    canvas_draw_icon(
+                        canvas,
+                        keyboard_origin_x + keys[column].x,
+                        keyboard_origin_y + keys[column].y,
+                        &I_KeyBackspaceSelected_16x9);
+                } else {
+                    canvas_draw_icon(
+                        canvas,
+                        keyboard_origin_x + keys[column].x,
+                        keyboard_origin_y + keys[column].y,
+                        &I_KeyBackspace_16x9);
+                }
+            } else {
+                if(model->selected_row == row && model->selected_column == column) {
+                    canvas_set_color(canvas, ColorBlack);
+                    canvas_draw_box(
+                        canvas,
+                        keyboard_origin_x + keys[column].x - 3,
+                        keyboard_origin_y + keys[column].y - 10,
+                        11,
+                        13);
+                    canvas_set_color(canvas, ColorWhite);
+                } else if(model->selected_row == -1 && row == 0 && model->selected_column == column) {
+                    canvas_set_color(canvas, ColorBlack);
+                    canvas_draw_frame(
+                        canvas,
+                        keyboard_origin_x + keys[column].x - 3,
+                        keyboard_origin_y + keys[column].y - 10,
+                        11,
+                        13);
+                } else {
+                    canvas_set_color(canvas, ColorBlack);
+                }
+
+                canvas_draw_glyph(
+                    canvas,
+                    keyboard_origin_x + keys[column].x,
+                    keyboard_origin_y + keys[column].y,
+                    keys[column].text);
+            }
+        }
+    }
+}
+
+/** Input callback
+ *
+ * @param      event    The event
+ * @param      context  The context
+ *
+ * @return     true
+ * @return     false
+ */
+static bool int_input_view_input_callback(InputEvent* event, void* context) {
+    IntInput* int_input = context;
+    furi_assert(int_input);
+
+    bool consumed = false;
+
+    // Fetch the model
+    IntInputModel* model = view_get_model(int_input->view);
+
+    if(event->type == InputTypeShort || event->type == InputTypeLong ||
+       event->type == InputTypeRepeat) {
+        consumed = true;
+        switch(event->key) {
+        case InputKeyLeft:
+            int_input_handle_left(model);
+            break;
+        case InputKeyRight:
+            int_input_handle_right(model);
+            break;
+        case InputKeyUp:
+            int_input_handle_up(model);
+            break;
+        case InputKeyDown:
+            int_input_handle_down(model);
+            break;
+        case InputKeyOk:
+            int_input_handle_ok(model);
+            break;
+        default:
+            consumed = false;
+            break;
+        }
+    }
+
+    // commit view
+    view_commit_model(int_input->view, consumed);
+
+    return consumed;
+}
+
+void int_input_reset(IntInput* int_input) {
+    FURI_LOG_D("INT_INPUT", "Resetting Model");
+    furi_assert(int_input);
+    with_view_model(
+        int_input->view,
+        IntInputModel * model,
+        {
+            model->header = "";
+            model->selected_row = 0;
+            model->selected_column = 0;
+            model->clear_default_text = false;
+            model->text_buffer = "";
+            model->text_buffer_size = 0;
+            model->callback = NULL;
+            model->callback_context = NULL;
+        },
+        true);
+}
+
+IntInput* int_input_alloc() {
+    IntInput* int_input = malloc(sizeof(IntInput));
+    int_input->view = view_alloc();
+    view_set_context(int_input->view, int_input);
+    view_allocate_model(int_input->view, ViewModelTypeLocking, sizeof(IntInputModel));
+    view_set_draw_callback(int_input->view, int_input_view_draw_callback);
+    view_set_input_callback(int_input->view, int_input_view_input_callback);
+
+    int_input_reset(int_input);
+
+    return int_input;
+}
+
+void int_input_free(IntInput* int_input) {
+    furi_assert(int_input);
+    view_free(int_input->view);
+    free(int_input);
+}
+
+View* int_input_get_view(IntInput* int_input) {
+    furi_assert(int_input);
+    return int_input->view;
+}
+
+void int_input_set_result_callback(
+    IntInput* int_input,
+    IntInputCallback callback,
+    void* callback_context,
+    char* text_buffer,
+    size_t text_buffer_size,
+    bool clear_default_text) {
+    with_view_model(
+        int_input->view,
+        IntInputModel * model,
+        {
+            model->callback = callback;
+            model->callback_context = callback_context;
+            model->text_buffer = text_buffer;
+            model->text_buffer_size = text_buffer_size;
+            model->clear_default_text = clear_default_text;
+        },
+        true);
+}
+
+void int_input_set_header_text(IntInput* int_input, const char* text) {
+    with_view_model(
+        int_input->view, IntInputModel * model, { model->header = text; }, true);
+}

+ 71 - 0
helpers/gui/int_input.h

@@ -0,0 +1,71 @@
+/**
+ * @file int_input.h
+ * GUI: Integer string keyboard view module API
+ */
+
+#pragma once
+
+#include <gui/view.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Int input anonymous structure  */
+typedef struct IntInput IntInput;
+
+/** callback that is executed on save button press */
+typedef void (*IntInputCallback)(void* context);
+
+/** callback that is executed when byte buffer is changed */
+typedef void (*IntChangedCallback)(void* context);
+
+/** Allocate and initialize Int input. This Int input is used to enter Ints.
+ *
+ * @return     IntInput instance pointer
+ */
+IntInput* int_input_alloc();
+
+/** Deinitialize and free byte input
+ *
+ * @param      int_input  Int input instance
+ */
+void int_input_free(IntInput* int_input);
+
+/** Get byte input view
+ *
+ * @param      int_input  byte input instance
+ *
+ * @return     View instance that can be used for embedding
+ */
+View* int_input_get_view(IntInput* int_input);
+
+/** Set byte input result callback
+ *
+ * @param      int_input          byte input instance
+ * @param      input_callback     input callback fn
+ * @param      changed_callback   changed callback fn
+ * @param      callback_context   callback context
+ * @param      text_buffer        buffer to use
+ * @param      text_buffer_size   buffer length
+ * @param      clear_default_text clear previous entry
+ */
+
+void int_input_set_result_callback(
+    IntInput* int_input,
+    IntInputCallback input_callback,
+    void* callback_context,
+    char* text_buffer,
+    size_t text_buffer_size,
+    bool clear_default_text);
+
+/** Set byte input header text
+ *
+ * @param      int_input  byte input instance
+ * @param      text        text to be shown
+ */
+void int_input_set_header_text(IntInput* int_input, const char* text);
+
+#ifdef __cplusplus
+}
+#endif

BIN
icons/KeyBackspaceSelected_16x9.png


BIN
icons/KeyBackspace_16x9.png


BIN
icons/KeySaveSelected_24x11.png


BIN
icons/KeySave_24x11.png


+ 5 - 0
models/cross/xremote_cross_remote.c

@@ -144,6 +144,11 @@ void xremote_cross_remote_rename_item(CrossRemote* remote, size_t index, const c
     xremote_cross_remote_item_set_name(item, name);
     xremote_cross_remote_item_set_name(item, name);
 }
 }
 
 
+int16_t xremote_cross_remote_get_item_type(CrossRemote* remote, size_t index) {
+    CrossRemoteItem* item = xremote_cross_remote_get_item(remote, index);
+    return xremote_cross_remote_item_get_type(item);
+}
+
 static void xremote_cross_remote_set_name(CrossRemote* remote, const char* name) {
 static void xremote_cross_remote_set_name(CrossRemote* remote, const char* name) {
     furi_string_set(remote->name, name);
     furi_string_set(remote->name, name);
 }
 }

+ 1 - 0
models/cross/xremote_cross_remote.h

@@ -23,6 +23,7 @@ void xremote_cross_remote_remove_item(CrossRemote* remote, size_t index);
 void xremote_cross_remote_rename_item(CrossRemote* remote, size_t index, const char* name);
 void xremote_cross_remote_rename_item(CrossRemote* remote, size_t index, const char* name);
 size_t xremote_cross_remote_get_item_count(CrossRemote* remote);
 size_t xremote_cross_remote_get_item_count(CrossRemote* remote);
 CrossRemoteItem* xremote_cross_remote_get_item(CrossRemote* remote, size_t index);
 CrossRemoteItem* xremote_cross_remote_get_item(CrossRemote* remote, size_t index);
+int16_t xremote_cross_remote_get_item_type(CrossRemote* remote, size_t index);
 
 
 bool xremote_cross_remote_save_new(CrossRemote* remote, const char* name);
 bool xremote_cross_remote_save_new(CrossRemote* remote, const char* name);
 bool xremote_cross_remote_delete(CrossRemote* remote);
 bool xremote_cross_remote_delete(CrossRemote* remote);

+ 4 - 0
models/cross/xremote_cross_remote_item.c

@@ -224,6 +224,10 @@ void xremote_cross_remote_item_set_sg_signal(CrossRemoteItem* item, SubGhzRemote
     item->sg_signal = subghz;
     item->sg_signal = subghz;
 }
 }
 
 
+int16_t xremote_cross_remote_item_get_type(CrossRemoteItem* item) {
+    return item->type;
+}
+
 const char* xremote_cross_remote_item_get_name(CrossRemoteItem* item) {
 const char* xremote_cross_remote_item_get_name(CrossRemoteItem* item) {
     return furi_string_get_cstr(item->name);
     return furi_string_get_cstr(item->name);
 }
 }

+ 1 - 0
models/cross/xremote_cross_remote_item.h

@@ -15,6 +15,7 @@ void xremote_cross_remote_item_set_filename(CrossRemoteItem* item, const char* f
 const char* xremote_cross_remote_item_get_filename(CrossRemoteItem* item);
 const char* xremote_cross_remote_item_get_filename(CrossRemoteItem* item);
 
 
 void xremote_cross_remote_item_set_type(CrossRemoteItem* item, int type);
 void xremote_cross_remote_item_set_type(CrossRemoteItem* item, int type);
+int16_t xremote_cross_remote_item_get_type(CrossRemoteItem* item);
 void xremote_cross_remote_item_set_time(CrossRemoteItem* item, uint32_t time);
 void xremote_cross_remote_item_set_time(CrossRemoteItem* item, uint32_t time);
 uint32_t xremote_cross_remote_item_get_time(CrossRemoteItem* item);
 uint32_t xremote_cross_remote_item_get_time(CrossRemoteItem* item);
 
 

+ 2 - 1
scenes/xremote_scene_config.h

@@ -14,4 +14,5 @@ ADD_SCENE(xremote, ir_remote, IrRemote)
 ADD_SCENE(xremote, save_remote, SaveRemote)
 ADD_SCENE(xremote, save_remote, SaveRemote)
 ADD_SCENE(xremote, save_remote_item, SaveRemoteItem)
 ADD_SCENE(xremote, save_remote_item, SaveRemoteItem)
 ADD_SCENE(xremote, transmit, Transmit)
 ADD_SCENE(xremote, transmit, Transmit)
-ADD_SCENE(xremote, pause_set, PauseSet)
+ADD_SCENE(xremote, pause_set, PauseSet)
+ADD_SCENE(xremote, ir_timer, IrTimer)

+ 10 - 0
scenes/xremote_scene_edit_item.c

@@ -3,6 +3,7 @@
 
 
 enum SubmenuIndexEdit {
 enum SubmenuIndexEdit {
     SubmenuIndexRename = 10,
     SubmenuIndexRename = 10,
+    SubmenuIndexTiming,
     SubmenuIndexDelete,
     SubmenuIndexDelete,
 };
 };
 
 
@@ -15,6 +16,12 @@ void xremote_scene_edit_item_on_enter(void* context) {
     XRemote* app = context;
     XRemote* app = context;
     submenu_add_item(
     submenu_add_item(
         app->editmenu, "Rename", SubmenuIndexRename, xremote_scene_edit_item_submenu_callback, app);
         app->editmenu, "Rename", SubmenuIndexRename, xremote_scene_edit_item_submenu_callback, app);
+    
+    if(xremote_cross_remote_get_item_type(app->cross_remote, app->edit_item) == XRemoteRemoteItemTypeInfrared) {
+        submenu_add_item(
+        app->editmenu, "Set Timing", SubmenuIndexTiming, xremote_scene_edit_item_submenu_callback, app);
+    }
+
     submenu_add_item(
     submenu_add_item(
         app->editmenu, "Delete", SubmenuIndexDelete, xremote_scene_edit_item_submenu_callback, app);
         app->editmenu, "Delete", SubmenuIndexDelete, xremote_scene_edit_item_submenu_callback, app);
 
 
@@ -37,6 +44,9 @@ bool xremote_scene_edit_item_on_event(void* context, SceneManagerEvent event) {
             scene_manager_next_scene(app->scene_manager, XRemoteSceneSaveRemoteItem);
             scene_manager_next_scene(app->scene_manager, XRemoteSceneSaveRemoteItem);
             //scene_manager_next_scene(app->scene_manager, XRemoteSceneWip);
             //scene_manager_next_scene(app->scene_manager, XRemoteSceneWip);
             return 0;
             return 0;
+        } else if(event.event == SubmenuIndexTiming) {
+            scene_manager_next_scene(app->scene_manager, XRemoteSceneIrTimer);
+            return 0;
         }
         }
         scene_manager_next_scene(app->scene_manager, XRemoteSceneCreate);
         scene_manager_next_scene(app->scene_manager, XRemoteSceneCreate);
     }
     }

+ 58 - 0
scenes/xremote_scene_ir_timer.c

@@ -0,0 +1,58 @@
+#include "../xremote.h"
+#include "../models/cross/xremote_cross_remote.h"
+
+void xremote_scene_ir_timer_callback(void* context) {
+    XRemote* app = context;
+    view_dispatcher_send_custom_event(app->view_dispatcher, XRemoteCustomEventTextInput);
+}
+
+void xremote_scene_ir_timer_on_enter(void* context) {
+    furi_assert(context);
+    XRemote* app = context;
+    IntInput* int_input = app->int_input;
+    size_t enter_name_length = 5;
+    char* str = "Transmit in ms (0 - 9999)";
+    const char* constStr = str;
+    CrossRemoteItem* item = xremote_cross_remote_get_item(app->cross_remote, app->edit_item);
+    int_input_set_header_text(int_input, constStr);
+    snprintf(app->text_store[1], 5, "%lu", item->time);
+
+    int_input_set_result_callback(
+        int_input,
+        xremote_scene_ir_timer_callback,
+        context,
+        app->text_store[1],
+        enter_name_length,
+        false);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, XRemoteViewIdIntInput);
+}
+
+bool xremote_scene_ir_timer_on_event(void* context, SceneManagerEvent event) {
+    XRemote* app = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeBack) {
+        scene_manager_previous_scene(app->scene_manager);
+        return true;
+    } else if(event.type == SceneManagerEventTypeCustom) {
+        CrossRemoteItem* item = xremote_cross_remote_get_item(app->cross_remote, app->edit_item);
+        xremote_cross_remote_item_set_time(item, atoi(app->text_store[1]));
+        if (item->time > 9999) {
+            item->time = 9999;
+        }
+        //app->first_station = atoi(app->text_store[0]);
+        /*if(app->first_station > app->max_station) {
+            app->first_station = app->max_station;
+            snprintf(app->text_store[0], 5, "%lu", app->first_station);
+        }*/
+        scene_manager_previous_scene(app->scene_manager);
+        return true;
+    }
+    return consumed;
+}
+
+void xremote_scene_ir_timer_on_exit(void* context) {
+    XRemote* app = context;
+    UNUSED(app);
+}

+ 7 - 0
xremote.c

@@ -68,6 +68,12 @@ XRemote* xremote_app_alloc() {
     app->subghz = subghz_alloc();
     app->subghz = subghz_alloc();
 
 
     app->text_input = text_input_alloc();
     app->text_input = text_input_alloc();
+
+    // Custom made int keyboard
+    app->int_input = int_input_alloc();
+    view_dispatcher_add_view(
+        app->view_dispatcher, XRemoteViewIdIntInput, int_input_get_view(app->int_input));
+
     view_dispatcher_add_view(
     view_dispatcher_add_view(
         app->view_dispatcher, XRemoteViewIdTextInput, text_input_get_view(app->text_input));
         app->view_dispatcher, XRemoteViewIdTextInput, text_input_get_view(app->text_input));
 
 
@@ -141,6 +147,7 @@ void xremote_app_free(XRemote* app) {
     view_dispatcher_remove_view(app->view_dispatcher, XRemoteViewIdTransmit);
     view_dispatcher_remove_view(app->view_dispatcher, XRemoteViewIdTransmit);
     view_dispatcher_remove_view(app->view_dispatcher, XRemoteViewIdPauseSet);
     view_dispatcher_remove_view(app->view_dispatcher, XRemoteViewIdPauseSet);
     text_input_free(app->text_input);
     text_input_free(app->text_input);
+    int_input_free(app->int_input);
     button_menu_free(app->button_menu_create);
     button_menu_free(app->button_menu_create);
     button_menu_free(app->button_menu_create_add);
     button_menu_free(app->button_menu_create_add);
     button_menu_free(app->button_menu_ir);
     button_menu_free(app->button_menu_ir);

+ 3 - 0
xremote.h

@@ -9,6 +9,7 @@
 #include "models/cross/xremote_cross_remote.h"
 #include "models/cross/xremote_cross_remote.h"
 #include "helpers/subghz/subghz_types.h"
 #include "helpers/subghz/subghz_types.h"
 #include "helpers/subghz/subghz.h"
 #include "helpers/subghz/subghz.h"
+#include "helpers/gui/int_input.h"
 #include "xremote_i.h"
 #include "xremote_i.h"
 
 
 typedef struct SubGhz SubGhz;
 typedef struct SubGhz SubGhz;
@@ -49,6 +50,7 @@ typedef struct {
     bool stop_transmit;
     bool stop_transmit;
     char text_store[XREMOTE_TEXT_STORE_NUM][XREMOTE_TEXT_STORE_SIZE + 1];
     char text_store[XREMOTE_TEXT_STORE_NUM][XREMOTE_TEXT_STORE_SIZE + 1];
     SubGhz* subghz;
     SubGhz* subghz;
+    IntInput* int_input;
 } XRemote;
 } XRemote;
 
 
 typedef enum {
 typedef enum {
@@ -62,6 +64,7 @@ typedef enum {
     XRemoteViewIdIrRemote,
     XRemoteViewIdIrRemote,
     XRemoteViewIdStack,
     XRemoteViewIdStack,
     XRemoteViewIdTextInput,
     XRemoteViewIdTextInput,
+    XRemoteViewIdIntInput,
     XRemoteViewIdTransmit,
     XRemoteViewIdTransmit,
     XRemoteViewIdPauseSet,
     XRemoteViewIdPauseSet,
 } XRemoteViewId;
 } XRemoteViewId;

+ 1 - 1
xremote_i.h

@@ -49,7 +49,7 @@
 #define XREMOTE_APP_EXTENSION ".xr"
 #define XREMOTE_APP_EXTENSION ".xr"
 #define XREMOTE_FILE_TYPE "Cross Remote File"
 #define XREMOTE_FILE_TYPE "Cross Remote File"
 #define XREMOTE_FILE_VERSION 1
 #define XREMOTE_FILE_VERSION 1
-#define XREMOTE_TEXT_STORE_NUM 2
+#define XREMOTE_TEXT_STORE_NUM 3
 #define XREMOTE_TEXT_STORE_SIZE 128
 #define XREMOTE_TEXT_STORE_SIZE 128
 #define XREMOTE_MAX_ITEM_NAME_LENGTH 22
 #define XREMOTE_MAX_ITEM_NAME_LENGTH 22
 #define XREMOTE_MAX_REMOTE_NAME_LENGTH 22
 #define XREMOTE_MAX_REMOTE_NAME_LENGTH 22