Skip to content

Commit

Permalink
Added a text input that only accepts full numbers (int) (flipperdevic…
Browse files Browse the repository at this point in the history
…es#3350)

* Added a text input that only accepts full numbers (int)
* Added to Gui sdk_headers and api_symbols in f7 and f18
* Fixed _Bool declarations in symbols csv
* renamed int_input to number_input
* Changed name & added example fap
* Added a text input that only accepts full numbers (int)
* Added to Gui sdk_headers and api_symbols in f7 and f18
* Changed name & added example fap
* update for clearing views
* GUI: Fix array out of bounds in menu exit (flipperdevices#3604)
* GUI: Fix array out of bounds in menu exit
* Gui: fix incorrect empty menu handling
* Gui: add missing item check in menu ok handling
* Gui: remove dead code from menu module
* nfc app: add legacy keys for plantain cards (flipperdevices#3602)
* refactoring test app, part 1
* Refactor test app, part 2
* Minor updates while travelling
* Switched from const char to FuriString. Using Temp module copy for development to spare compile time
* Option to limit number output with min and max values
* Preparations for option to change number sign from + to -
* Preparations for option to change number sign from + to -
* Preparing for testing
* counter automatic API version change
* added trailing comma in application.fam ... because the lint check wants it¿
* removed unused callback NumberChangedCallback
* change uint8_t to size_t in number_input_backspace_cb
* Removal of unused view_stack in demo app
* copied module to app folder for faster development (remove later)
* Replaced all uint8_t with size_t... removed unused logic for selected_row < 0
* Optimize use of canvas_set_color
* Remove alloc/free of furistring that actually is a pointer
* Dynamic Header text with min/max in Example
* Removed the need of useSign in Model
* Number_input Removed sign from model, started transfer from text to int32_t
* number_input FuriString in input_show_number
* number_input FuriString in input_show_number
* limiting inputs for min/max values
* limiting inputs for min/max values
* number_input change save button on invalid numbers
* input_number update demo app to allow change of min/max
* number input fine tuning
* number_input, Remove temp development folder
* number_input, fbt format
* Bump CSV Files
* Clear input if value is zero
* number_input: handle null on header text
* number_input: change keyboard values to char
* number input: Remove static on char for header text, change numbers to INT32_MIN/INT32_MAX
* number_input: removal of dead code
* number_input: fix for crash if number_input not opened before free
* number_input: added icon for example app
* number_input: Replaced view for show_number with DialogEx
* Number_input: FBT Format
* number_input: bump csv versions
* number_input: allow negative input if max_value is 0
* Number_input: linting / format
* Removed dead code, fbt format
* Examples: cleanup number input code
* Examples: moar code cleanup in number input, simplify as much as possible, highlight incorrect input handling
* Gui: correctly handle INT_MAX and INT_MIN
* Gui: fix memory leak in number input module

Co-authored-by: David Lee <[email protected]>
Co-authored-by: Aleksandr Kutuzov <[email protected]>
Co-authored-by: WillyJL <[email protected]>
Co-authored-by: gornekich <[email protected]>
  • Loading branch information
5 people authored and ofabel committed Sep 26, 2024
1 parent da35608 commit 0b5b04c
Show file tree
Hide file tree
Showing 23 changed files with 907 additions and 2 deletions.
7 changes: 7 additions & 0 deletions applications/examples/example_number_input/ReadMe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Number Input

Simple keyboard that limits user inputs to a full number (integer). Useful to enforce correct entries without the need of intense validations after a user input.

Definition of min/max values is required. Numbers are of type int32_t. If negative numbers are allowed withing min - max, an additional button is displayed to switch the sign between + and -.

It is also possible to define a header text, shown in this example app with the 3 different input options.
10 changes: 10 additions & 0 deletions applications/examples/example_number_input/application.fam
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
App(
appid="example_number_input",
name="Example: Number Input",
apptype=FlipperAppType.EXTERNAL,
entry_point="example_number_input",
requires=["gui"],
stack_size=1 * 1024,
fap_icon="example_number_input_10px.png",
fap_category="Examples",
)
79 changes: 79 additions & 0 deletions applications/examples/example_number_input/example_number_input.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include "example_number_input.h"

bool example_number_input_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
ExampleNumberInput* app = context;
return scene_manager_handle_custom_event(app->scene_manager, event);
}

static bool example_number_input_back_event_callback(void* context) {
furi_assert(context);
ExampleNumberInput* app = context;
return scene_manager_handle_back_event(app->scene_manager);
}

static ExampleNumberInput* example_number_input_alloc() {
ExampleNumberInput* app = malloc(sizeof(ExampleNumberInput));
app->gui = furi_record_open(RECORD_GUI);

app->view_dispatcher = view_dispatcher_alloc();

app->scene_manager = scene_manager_alloc(&example_number_input_scene_handlers, app);
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_custom_event_callback(
app->view_dispatcher, example_number_input_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
app->view_dispatcher, example_number_input_back_event_callback);

app->number_input = number_input_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
ExampleNumberInputViewIdNumberInput,
number_input_get_view(app->number_input));

app->dialog_ex = dialog_ex_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
ExampleNumberInputViewIdShowNumber,
dialog_ex_get_view(app->dialog_ex));

app->current_number = 5;
app->min_value = INT32_MIN;
app->max_value = INT32_MAX;

return app;
}

static void example_number_input_free(ExampleNumberInput* app) {
furi_assert(app);

view_dispatcher_remove_view(app->view_dispatcher, ExampleNumberInputViewIdShowNumber);
dialog_ex_free(app->dialog_ex);

view_dispatcher_remove_view(app->view_dispatcher, ExampleNumberInputViewIdNumberInput);
number_input_free(app->number_input);

scene_manager_free(app->scene_manager);
view_dispatcher_free(app->view_dispatcher);

furi_record_close(RECORD_GUI);
app->gui = NULL;

//Remove whatever is left
free(app);
}

int32_t example_number_input(void* p) {
UNUSED(p);
ExampleNumberInput* app = example_number_input_alloc();

view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);

scene_manager_next_scene(app->scene_manager, ExampleNumberInputSceneShowNumber);

view_dispatcher_run(app->view_dispatcher);

example_number_input_free(app);

return 0;
}
35 changes: 35 additions & 0 deletions applications/examples/example_number_input/example_number_input.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include <furi.h>
#include <furi_hal.h>

#include <gui/gui.h>
#include <gui/elements.h>
#include <gui/scene_manager.h>
#include <gui/modules/dialog_ex.h>
#include <gui/modules/number_input.h>
#include <gui/view.h>
#include <gui/view_dispatcher.h>
#include <input/input.h>

#include "scenes/example_number_input_scene.h"

typedef struct ExampleNumberInputShowNumber ExampleNumberInputShowNumber;

typedef enum {
ExampleNumberInputViewIdShowNumber,
ExampleNumberInputViewIdNumberInput,
} ExampleNumberInputViewId;

typedef struct {
Gui* gui;
SceneManager* scene_manager;
ViewDispatcher* view_dispatcher;

NumberInput* number_input;
DialogEx* dialog_ex;

int32_t current_number;
int32_t min_value;
int32_t max_value;
} ExampleNumberInput;
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "example_number_input_scene.h"

// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const example_number_input_on_enter_handlers[])(void*) = {
#include "example_number_input_scene_config.h"
};
#undef ADD_SCENE

// Generate scene on_event handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
bool (*const example_number_input_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "example_number_input_scene_config.h"
};
#undef ADD_SCENE

// Generate scene on_exit handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
void (*const example_number_input_on_exit_handlers[])(void* context) = {
#include "example_number_input_scene_config.h"
};
#undef ADD_SCENE

// Initialize scene handlers configuration structure
const SceneManagerHandlers example_number_input_scene_handlers = {
.on_enter_handlers = example_number_input_on_enter_handlers,
.on_event_handlers = example_number_input_on_event_handlers,
.on_exit_handlers = example_number_input_on_exit_handlers,
.scene_num = ExampleNumberInputSceneNum,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#pragma once

#include <gui/scene_manager.h>

// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) ExampleNumberInputScene##id,
typedef enum {
#include "example_number_input_scene_config.h"
ExampleNumberInputSceneNum,
} ExampleNumberInputScene;
#undef ADD_SCENE

extern const SceneManagerHandlers example_number_input_scene_handlers;

// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "example_number_input_scene_config.h"
#undef ADD_SCENE

// Generate scene on_event handlers declaration
#define ADD_SCENE(prefix, name, id) \
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
#include "example_number_input_scene_config.h"
#undef ADD_SCENE

// Generate scene on_exit handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
#include "example_number_input_scene_config.h"
#undef ADD_SCENE
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ADD_SCENE(example_number_input, input_number, InputNumber)
ADD_SCENE(example_number_input, show_number, ShowNumber)
ADD_SCENE(example_number_input, input_max, InputMax)
ADD_SCENE(example_number_input, input_min, InputMin)
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include "../example_number_input.h"

void example_number_input_scene_input_max_callback(void* context, int32_t number) {
ExampleNumberInput* app = context;
app->max_value = number;
view_dispatcher_send_custom_event(app->view_dispatcher, 0);
}

void example_number_input_scene_input_max_on_enter(void* context) {
furi_assert(context);
ExampleNumberInput* app = context;
NumberInput* number_input = app->number_input;

number_input_set_header_text(number_input, "Enter the maximum value");
number_input_set_result_callback(
number_input,
example_number_input_scene_input_max_callback,
context,
app->max_value,
app->min_value,
INT32_MAX);

view_dispatcher_switch_to_view(app->view_dispatcher, ExampleNumberInputViewIdNumberInput);
}

bool example_number_input_scene_input_max_on_event(void* context, SceneManagerEvent event) {
ExampleNumberInput* app = context;
bool consumed = false;

if(event.type == SceneManagerEventTypeCustom) {
scene_manager_previous_scene(app->scene_manager);
return true;
}
return consumed;
}

void example_number_input_scene_input_max_on_exit(void* context) {
UNUSED(context);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include "../example_number_input.h"

void example_number_input_scene_input_min_callback(void* context, int32_t number) {
ExampleNumberInput* app = context;
app->min_value = number;
view_dispatcher_send_custom_event(app->view_dispatcher, 0);
}

void example_number_input_scene_input_min_on_enter(void* context) {
furi_assert(context);
ExampleNumberInput* app = context;
NumberInput* number_input = app->number_input;

number_input_set_header_text(number_input, "Enter the minimum value");
number_input_set_result_callback(
number_input,
example_number_input_scene_input_min_callback,
context,
app->min_value,
INT32_MIN,
app->max_value);

view_dispatcher_switch_to_view(app->view_dispatcher, ExampleNumberInputViewIdNumberInput);
}

bool example_number_input_scene_input_min_on_event(void* context, SceneManagerEvent event) {
ExampleNumberInput* app = context;
bool consumed = false;

if(event.type == SceneManagerEventTypeCustom) {
scene_manager_previous_scene(app->scene_manager);
return true;
}
return consumed;
}

void example_number_input_scene_input_min_on_exit(void* context) {
UNUSED(context);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "../example_number_input.h"

void example_number_input_scene_input_number_callback(void* context, int32_t number) {
ExampleNumberInput* app = context;
app->current_number = number;
view_dispatcher_send_custom_event(app->view_dispatcher, 0);
}

void example_number_input_scene_input_number_on_enter(void* context) {
furi_assert(context);
ExampleNumberInput* app = context;
NumberInput* number_input = app->number_input;

char str[50];
snprintf(str, sizeof(str), "Set Number (%ld - %ld)", app->min_value, app->max_value);

number_input_set_header_text(number_input, str);
number_input_set_result_callback(
number_input,
example_number_input_scene_input_number_callback,
context,
app->current_number,
app->min_value,
app->max_value);

view_dispatcher_switch_to_view(app->view_dispatcher, ExampleNumberInputViewIdNumberInput);
}

bool example_number_input_scene_input_number_on_event(void* context, SceneManagerEvent event) {
ExampleNumberInput* app = context;
bool consumed = false;

if(event.type == SceneManagerEventTypeCustom) { //Back button pressed
scene_manager_previous_scene(app->scene_manager);
return true;
}
return consumed;
}

void example_number_input_scene_input_number_on_exit(void* context) {
UNUSED(context);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include "../example_number_input.h"

static void
example_number_input_scene_confirm_dialog_callback(DialogExResult result, void* context) {
ExampleNumberInput* app = context;

view_dispatcher_send_custom_event(app->view_dispatcher, result);
}

static void example_number_input_scene_update_view(void* context) {
ExampleNumberInput* app = context;
DialogEx* dialog_ex = app->dialog_ex;

dialog_ex_set_header(dialog_ex, "The number is", 64, 0, AlignCenter, AlignTop);

static char buffer[12]; //needs static for extended lifetime

snprintf(buffer, sizeof(buffer), "%ld", app->current_number);
dialog_ex_set_text(dialog_ex, buffer, 64, 29, AlignCenter, AlignCenter);

dialog_ex_set_left_button_text(dialog_ex, "Min");
dialog_ex_set_right_button_text(dialog_ex, "Max");
dialog_ex_set_center_button_text(dialog_ex, "Change");

dialog_ex_set_result_callback(dialog_ex, example_number_input_scene_confirm_dialog_callback);
dialog_ex_set_context(dialog_ex, app);
}

void example_number_input_scene_show_number_on_enter(void* context) {
furi_assert(context);
ExampleNumberInput* app = context;

example_number_input_scene_update_view(app);

view_dispatcher_switch_to_view(app->view_dispatcher, ExampleNumberInputViewIdShowNumber);
}

bool example_number_input_scene_show_number_on_event(void* context, SceneManagerEvent event) {
ExampleNumberInput* app = context;
bool consumed = false;

if(event.type == SceneManagerEventTypeCustom) {
switch(event.event) {
case DialogExResultCenter:
scene_manager_next_scene(app->scene_manager, ExampleNumberInputSceneInputNumber);
consumed = true;
break;
case DialogExResultLeft:
scene_manager_next_scene(app->scene_manager, ExampleNumberInputSceneInputMin);
consumed = true;
break;
case DialogExResultRight:
scene_manager_next_scene(app->scene_manager, ExampleNumberInputSceneInputMax);
consumed = true;
break;
default:
break;
}
}

return consumed;
}

void example_number_input_scene_show_number_on_exit(void* context) {
UNUSED(context);
}
1 change: 1 addition & 0 deletions applications/services/gui/application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ App(
"view_holder.h",
"modules/button_menu.h",
"modules/byte_input.h",
"modules/number_input.h",
"modules/popup.h",
"modules/text_input.h",
"modules/widget.h",
Expand Down
Loading

0 comments on commit 0b5b04c

Please sign in to comment.