mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-14 00:37:21 +00:00
implement byte input, add missing args in text input
TODO: add missing filebrowser dialog
This commit is contained in:
parent
8233534d6a
commit
004d8382d3
5 changed files with 190 additions and 2 deletions
|
@ -66,6 +66,14 @@ App(
|
|||
sources=["modules/js_gui/text_input.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_gui__byte_input",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="js_view_byte_input_ep",
|
||||
requires=["js_app", "js_gui", "js_event_loop"],
|
||||
sources=["modules/js_gui/byte_input.c"],
|
||||
)
|
||||
|
||||
App(
|
||||
appid="js_gui__text_box",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
|
|
130
applications/system/js_app/modules/js_gui/byte_input.c
Normal file
130
applications/system/js_app/modules/js_gui/byte_input.c
Normal file
|
@ -0,0 +1,130 @@
|
|||
#include "../../js_modules.h" // IWYU pragma: keep
|
||||
#include "js_gui.h"
|
||||
#include "../js_event_loop/js_event_loop.h"
|
||||
#include <gui/modules/byte_input.h>
|
||||
|
||||
#define DEFAULT_BUF_SZ 4
|
||||
|
||||
typedef struct {
|
||||
uint8_t* buffer;
|
||||
size_t buffer_size;
|
||||
FuriString* header;
|
||||
FuriSemaphore* input_semaphore;
|
||||
JsEventLoopContract contract;
|
||||
} JsByteKbContext;
|
||||
|
||||
static mjs_val_t
|
||||
input_transformer(struct mjs* mjs, FuriSemaphore* semaphore, JsByteKbContext* context) {
|
||||
furi_check(furi_semaphore_acquire(semaphore, 0) == FuriStatusOk);
|
||||
return mjs_mk_array_buf(mjs, (char*)context->buffer, context->buffer_size);
|
||||
}
|
||||
|
||||
static void input_callback(JsByteKbContext* context) {
|
||||
furi_semaphore_release(context->input_semaphore);
|
||||
}
|
||||
|
||||
static bool header_assign(
|
||||
struct mjs* mjs,
|
||||
ByteInput* input,
|
||||
JsViewPropValue value,
|
||||
JsByteKbContext* context) {
|
||||
UNUSED(mjs);
|
||||
furi_string_set(context->header, value.string);
|
||||
byte_input_set_header_text(input, furi_string_get_cstr(context->header));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
len_assign(struct mjs* mjs, ByteInput* input, JsViewPropValue value, JsByteKbContext* context) {
|
||||
UNUSED(mjs);
|
||||
UNUSED(input);
|
||||
context->buffer_size = (size_t)(value.number);
|
||||
context->buffer = realloc(context->buffer, context->buffer_size); //-V701
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool default_data_assign(
|
||||
struct mjs* mjs,
|
||||
ByteInput* input,
|
||||
JsViewPropValue value,
|
||||
JsByteKbContext* context) {
|
||||
UNUSED(mjs);
|
||||
|
||||
if(mjs_is_data_view(value.array)) {
|
||||
value.array = mjs_dataview_get_buf(mjs, value.array);
|
||||
}
|
||||
size_t default_data_len = 0;
|
||||
char* default_data = mjs_array_buf_get_ptr(mjs, value.array, &default_data_len);
|
||||
memcpy(
|
||||
context->buffer,
|
||||
(uint8_t*)default_data,
|
||||
MIN((size_t)context->buffer_size, default_data_len));
|
||||
|
||||
byte_input_set_result_callback(
|
||||
input,
|
||||
(ByteInputCallback)input_callback,
|
||||
NULL,
|
||||
context,
|
||||
context->buffer,
|
||||
context->buffer_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
static JsByteKbContext* ctx_make(struct mjs* mjs, ByteInput* input, mjs_val_t view_obj) {
|
||||
UNUSED(input);
|
||||
JsByteKbContext* context = malloc(sizeof(JsByteKbContext));
|
||||
*context = (JsByteKbContext){
|
||||
.buffer_size = DEFAULT_BUF_SZ,
|
||||
.buffer = malloc(DEFAULT_BUF_SZ),
|
||||
.header = furi_string_alloc(),
|
||||
.input_semaphore = furi_semaphore_alloc(1, 0),
|
||||
};
|
||||
context->contract = (JsEventLoopContract){
|
||||
.magic = JsForeignMagic_JsEventLoopContract,
|
||||
.object_type = JsEventLoopObjectTypeSemaphore,
|
||||
.object = context->input_semaphore,
|
||||
.non_timer =
|
||||
{
|
||||
.event = FuriEventLoopEventIn,
|
||||
.transformer = (JsEventLoopTransformer)input_transformer,
|
||||
.transformer_context = context,
|
||||
},
|
||||
};
|
||||
UNUSED(mjs);
|
||||
UNUSED(view_obj);
|
||||
mjs_set(mjs, view_obj, "input", ~0, mjs_mk_foreign(mjs, &context->contract));
|
||||
return context;
|
||||
}
|
||||
|
||||
static void ctx_destroy(ByteInput* input, JsByteKbContext* context, FuriEventLoop* loop) {
|
||||
UNUSED(input);
|
||||
furi_event_loop_maybe_unsubscribe(loop, context->input_semaphore);
|
||||
furi_semaphore_free(context->input_semaphore);
|
||||
furi_string_free(context->header);
|
||||
free(context->buffer);
|
||||
free(context);
|
||||
}
|
||||
|
||||
static const JsViewDescriptor view_descriptor = {
|
||||
.alloc = (JsViewAlloc)byte_input_alloc,
|
||||
.free = (JsViewFree)byte_input_free,
|
||||
.get_view = (JsViewGetView)byte_input_get_view,
|
||||
.custom_make = (JsViewCustomMake)ctx_make,
|
||||
.custom_destroy = (JsViewCustomDestroy)ctx_destroy,
|
||||
.prop_cnt = 3,
|
||||
.props = {
|
||||
(JsViewPropDescriptor){
|
||||
.name = "header",
|
||||
.type = JsViewPropTypeString,
|
||||
.assign = (JsViewPropAssign)header_assign},
|
||||
(JsViewPropDescriptor){
|
||||
.name = "length",
|
||||
.type = JsViewPropTypeNumber,
|
||||
.assign = (JsViewPropAssign)len_assign},
|
||||
(JsViewPropDescriptor){
|
||||
.name = "defaultData",
|
||||
.type = JsViewPropTypeTypedArr,
|
||||
.assign = (JsViewPropAssign)default_data_assign},
|
||||
}};
|
||||
|
||||
JS_GUI_VIEW_DEF(byte_input, &view_descriptor);
|
|
@ -215,6 +215,20 @@ static bool
|
|||
}
|
||||
c_value = (JsViewPropValue){.array = value};
|
||||
} break;
|
||||
case JsViewPropTypeTypedArr: {
|
||||
if(!mjs_is_typed_array(value)) {
|
||||
expected_type = "typed_array";
|
||||
break;
|
||||
}
|
||||
c_value = (JsViewPropValue){.array = value};
|
||||
} break;
|
||||
case JsViewPropTypeBool: {
|
||||
if(!mjs_is_boolean(value)) {
|
||||
expected_type = "bool";
|
||||
break;
|
||||
}
|
||||
c_value = (JsViewPropValue){.boolean = mjs_get_bool(mjs, value)};
|
||||
} break;
|
||||
}
|
||||
|
||||
if(expected_type) {
|
||||
|
|
|
@ -9,12 +9,15 @@ typedef enum {
|
|||
JsViewPropTypeString,
|
||||
JsViewPropTypeNumber,
|
||||
JsViewPropTypeArr,
|
||||
JsViewPropTypeTypedArr,
|
||||
JsViewPropTypeBool,
|
||||
} JsViewPropType;
|
||||
|
||||
typedef union {
|
||||
const char* string;
|
||||
int32_t number;
|
||||
mjs_val_t array;
|
||||
bool boolean;
|
||||
} JsViewPropValue;
|
||||
|
||||
/**
|
||||
|
|
|
@ -48,15 +48,40 @@ static bool max_len_assign(
|
|||
JsViewPropValue value,
|
||||
JsKbdContext* context) {
|
||||
UNUSED(mjs);
|
||||
UNUSED(input);
|
||||
context->buffer_size = (size_t)(value.number + 1);
|
||||
context->buffer = realloc(context->buffer, context->buffer_size); //-V701
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool default_text_assign(
|
||||
struct mjs* mjs,
|
||||
TextInput* input,
|
||||
JsViewPropValue value,
|
||||
JsKbdContext* context) {
|
||||
UNUSED(mjs);
|
||||
UNUSED(input);
|
||||
|
||||
if(value.string) {
|
||||
strlcpy(context->buffer, value.string, context->buffer_size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool default_text_clear_assign(
|
||||
struct mjs* mjs,
|
||||
TextInput* input,
|
||||
JsViewPropValue value,
|
||||
JsKbdContext* context) {
|
||||
UNUSED(mjs);
|
||||
|
||||
text_input_set_result_callback(
|
||||
input,
|
||||
(TextInputCallback)input_callback,
|
||||
context,
|
||||
context->buffer,
|
||||
context->buffer_size,
|
||||
true);
|
||||
value.boolean);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -101,7 +126,7 @@ static const JsViewDescriptor view_descriptor = {
|
|||
.get_view = (JsViewGetView)text_input_get_view,
|
||||
.custom_make = (JsViewCustomMake)ctx_make,
|
||||
.custom_destroy = (JsViewCustomDestroy)ctx_destroy,
|
||||
.prop_cnt = 3,
|
||||
.prop_cnt = 5,
|
||||
.props = {
|
||||
(JsViewPropDescriptor){
|
||||
.name = "header",
|
||||
|
@ -115,6 +140,14 @@ static const JsViewDescriptor view_descriptor = {
|
|||
.name = "maxLength",
|
||||
.type = JsViewPropTypeNumber,
|
||||
.assign = (JsViewPropAssign)max_len_assign},
|
||||
(JsViewPropDescriptor){
|
||||
.name = "defaultText",
|
||||
.type = JsViewPropTypeString,
|
||||
.assign = (JsViewPropAssign)default_text_assign},
|
||||
(JsViewPropDescriptor){
|
||||
.name = "defaultTextClear",
|
||||
.type = JsViewPropTypeBool,
|
||||
.assign = (JsViewPropAssign)default_text_clear_assign},
|
||||
}};
|
||||
|
||||
JS_GUI_VIEW_DEF(text_input, &view_descriptor);
|
||||
|
|
Loading…
Reference in a new issue