mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-11 06:09:08 -07:00
[FL-3893] JS modules (#3841)
* feat: backport js_gpio from unleashed * feat: backport js_keyboard, TextInputModel::minimum_length from unleashed * fix: api version inconsistency * style: js_gpio * build: fix submodule ._ . * refactor: js_gpio * docs: type declarations for gpio * feat: gpio interrupts * fix: js_gpio freeing, resetting and minor stylistic changes * style: js_gpio * style: mlib array, fixme's * feat: js_gpio adc * feat: js_event_loop * docs: js_event_loop * feat: js_event_loop subscription cancellation * feat: js_event_loop + js_gpio integration * fix: js_event_loop memory leak * feat: stop event loop on back button * test: js: basic, math, event_loop * feat: js_event_loop queue * feat: js linkage to previously loaded plugins * build: fix ci errors * feat: js module ordered teardown * feat: js_gui_defer_free * feat: basic hourglass view * style: JS ASS (Argument Schema for Scripts) * fix: js_event_loop mem leaks and lifetime problems * fix: crashing test and pvs false positives * feat: mjs custom obj destructors, gui submenu view * refactor: yank js_gui_defer_free (yuck) * refactor: maybe_unsubscribe * empty_screen, docs, typing fix-ups * docs: navigation event & demo * feat: submenu setHeader * feat: text_input * feat: text_box * docs: text_box availability * ci: silence irrelevant pvs low priority warning * style: use furistring * style: _get_at -> _safe_get * fix: built-in module name assignment * feat: js_dialog; refactor, optimize: js_gui * docs: js_gui * ci: silence pvs warning: Memory allocation is infallible * style: fix storage spelling * feat: foreign pointer signature checks * feat: js_storage * docs: js_storage * fix: my unit test was breaking other tests ;_; * ci: fix ci? * Make doxygen happy * docs: flipper, math, notification, global * style: review suggestions * style: review fixups * fix: badusb demo script * docs: badusb * ci: add nofl * ci: make linter happy * Bump api version Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
@@ -18,6 +18,7 @@ typedef struct {
|
||||
const char* header;
|
||||
char* text_buffer;
|
||||
size_t text_buffer_size;
|
||||
size_t minimum_length;
|
||||
bool clear_default_text;
|
||||
|
||||
TextInputCallback callback;
|
||||
@@ -321,7 +322,7 @@ static void text_input_handle_ok(TextInput* text_input, TextInputModel* model, b
|
||||
model->text_buffer, model->validator_text, model->validator_callback_context))) {
|
||||
model->validator_message_visible = true;
|
||||
furi_timer_start(text_input->timer, furi_kernel_get_tick_frequency() * 4);
|
||||
} else if(model->callback != 0 && text_length > 0) {
|
||||
} else if(model->callback != 0 && text_length >= model->minimum_length) {
|
||||
model->callback(model->callback_context);
|
||||
}
|
||||
} else if(selected == BACKSPACE_KEY) {
|
||||
@@ -487,6 +488,7 @@ void text_input_reset(TextInput* text_input) {
|
||||
model->header = "";
|
||||
model->selected_row = 0;
|
||||
model->selected_column = 0;
|
||||
model->minimum_length = 1;
|
||||
model->clear_default_text = false;
|
||||
model->text_buffer = NULL;
|
||||
model->text_buffer_size = 0;
|
||||
@@ -531,6 +533,14 @@ void text_input_set_result_callback(
|
||||
true);
|
||||
}
|
||||
|
||||
void text_input_set_minimum_length(TextInput* text_input, size_t minimum_length) {
|
||||
with_view_model(
|
||||
text_input->view,
|
||||
TextInputModel * model,
|
||||
{ model->minimum_length = minimum_length; },
|
||||
true);
|
||||
}
|
||||
|
||||
void text_input_set_validator(
|
||||
TextInput* text_input,
|
||||
TextInputValidatorCallback callback,
|
||||
|
||||
@@ -65,6 +65,13 @@ void text_input_set_result_callback(
|
||||
size_t text_buffer_size,
|
||||
bool clear_default_text);
|
||||
|
||||
/**
|
||||
* @brief Sets the minimum length of a TextInput
|
||||
* @param [in] text_input TextInput
|
||||
* @param [in] minimum_length Minimum input length
|
||||
*/
|
||||
void text_input_set_minimum_length(TextInput* text_input, size_t minimum_length);
|
||||
|
||||
void text_input_set_validator(
|
||||
TextInput* text_input,
|
||||
TextInputValidatorCallback callback,
|
||||
|
||||
@@ -5,6 +5,12 @@
|
||||
#define VIEW_DISPATCHER_QUEUE_LEN (16U)
|
||||
|
||||
ViewDispatcher* view_dispatcher_alloc(void) {
|
||||
ViewDispatcher* dispatcher = view_dispatcher_alloc_ex(furi_event_loop_alloc());
|
||||
dispatcher->is_event_loop_owned = true;
|
||||
return dispatcher;
|
||||
}
|
||||
|
||||
ViewDispatcher* view_dispatcher_alloc_ex(FuriEventLoop* loop) {
|
||||
ViewDispatcher* view_dispatcher = malloc(sizeof(ViewDispatcher));
|
||||
|
||||
view_dispatcher->view_port = view_port_alloc();
|
||||
@@ -16,7 +22,7 @@ ViewDispatcher* view_dispatcher_alloc(void) {
|
||||
|
||||
ViewDict_init(view_dispatcher->views);
|
||||
|
||||
view_dispatcher->event_loop = furi_event_loop_alloc();
|
||||
view_dispatcher->event_loop = loop;
|
||||
|
||||
view_dispatcher->input_queue =
|
||||
furi_message_queue_alloc(VIEW_DISPATCHER_QUEUE_LEN, sizeof(InputEvent));
|
||||
@@ -57,7 +63,7 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher) {
|
||||
furi_message_queue_free(view_dispatcher->input_queue);
|
||||
furi_message_queue_free(view_dispatcher->event_queue);
|
||||
|
||||
furi_event_loop_free(view_dispatcher->event_loop);
|
||||
if(view_dispatcher->is_event_loop_owned) furi_event_loop_free(view_dispatcher->event_loop);
|
||||
// Free dispatcher
|
||||
free(view_dispatcher);
|
||||
}
|
||||
@@ -85,6 +91,7 @@ void view_dispatcher_set_tick_event_callback(
|
||||
ViewDispatcherTickEventCallback callback,
|
||||
uint32_t tick_period) {
|
||||
furi_check(view_dispatcher);
|
||||
furi_check(view_dispatcher->is_event_loop_owned);
|
||||
view_dispatcher->tick_event_callback = callback;
|
||||
view_dispatcher->tick_period = tick_period;
|
||||
}
|
||||
@@ -106,11 +113,12 @@ void view_dispatcher_run(ViewDispatcher* view_dispatcher) {
|
||||
uint32_t tick_period = view_dispatcher->tick_period == 0 ? FuriWaitForever :
|
||||
view_dispatcher->tick_period;
|
||||
|
||||
furi_event_loop_tick_set(
|
||||
view_dispatcher->event_loop,
|
||||
tick_period,
|
||||
view_dispatcher_handle_tick_event,
|
||||
view_dispatcher);
|
||||
if(view_dispatcher->is_event_loop_owned)
|
||||
furi_event_loop_tick_set(
|
||||
view_dispatcher->event_loop,
|
||||
tick_period,
|
||||
view_dispatcher_handle_tick_event,
|
||||
view_dispatcher);
|
||||
|
||||
furi_event_loop_run(view_dispatcher->event_loop);
|
||||
|
||||
|
||||
@@ -47,6 +47,15 @@ typedef void (*ViewDispatcherTickEventCallback)(void* context);
|
||||
*/
|
||||
ViewDispatcher* view_dispatcher_alloc(void);
|
||||
|
||||
/** Allocate ViewDispatcher instance with an externally owned event loop. If
|
||||
* this constructor is used instead of `view_dispatcher_alloc`, the burden of
|
||||
* freeing the event loop is placed on the caller.
|
||||
*
|
||||
* @param loop pointer to FuriEventLoop instance
|
||||
* @return pointer to ViewDispatcher instance
|
||||
*/
|
||||
ViewDispatcher* view_dispatcher_alloc_ex(FuriEventLoop* loop);
|
||||
|
||||
/** Free ViewDispatcher instance
|
||||
*
|
||||
* @warning All added views MUST be removed using view_dispatcher_remove_view()
|
||||
@@ -97,6 +106,10 @@ void view_dispatcher_set_navigation_event_callback(
|
||||
|
||||
/** Set tick event handler
|
||||
*
|
||||
* @warning Requires the event loop to be owned by the view dispatcher, i.e.
|
||||
* it should have been instantiated with `view_dispatcher_alloc`, not
|
||||
* `view_dispatcher_alloc_ex`.
|
||||
*
|
||||
* @param view_dispatcher ViewDispatcher instance
|
||||
* @param callback ViewDispatcherTickEventCallback
|
||||
* @param tick_period callback call period
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
DICT_DEF2(ViewDict, uint32_t, M_DEFAULT_OPLIST, View*, M_PTR_OPLIST) // NOLINT
|
||||
|
||||
struct ViewDispatcher {
|
||||
bool is_event_loop_owned;
|
||||
FuriEventLoop* event_loop;
|
||||
FuriMessageQueue* input_queue;
|
||||
FuriMessageQueue* event_queue;
|
||||
|
||||
@@ -377,7 +377,7 @@ void storage_common_resolve_path_and_ensure_app_directory(Storage* storage, Furi
|
||||
* @param storage pointer to a storage API instance.
|
||||
* @param source pointer to a zero-terminated string containing the source path.
|
||||
* @param dest pointer to a zero-terminated string containing the destination path.
|
||||
* @return FSE_OK if the migration was successfull completed, any other error code on failure.
|
||||
* @return FSE_OK if the migration was successfully completed, any other error code on failure.
|
||||
*/
|
||||
FS_Error storage_common_migrate(Storage* storage, const char* source, const char* dest);
|
||||
|
||||
@@ -425,7 +425,7 @@ bool storage_common_is_subdir(Storage* storage, const char* parent, const char*
|
||||
/******************* Error Functions *******************/
|
||||
|
||||
/**
|
||||
* @brief Get the textual description of a numeric error identifer.
|
||||
* @brief Get the textual description of a numeric error identifier.
|
||||
*
|
||||
* @param error_id numeric identifier of the error in question.
|
||||
* @return pointer to a statically allocated zero-terminated string containing the respective error text.
|
||||
|
||||
Reference in New Issue
Block a user