implement byte input, add missing args in text input

TODO: add missing filebrowser dialog
This commit is contained in:
MX 2024-10-16 00:52:50 +03:00
parent 8233534d6a
commit 004d8382d3
No known key found for this signature in database
GPG key ID: 7CCC66B7DBDD1C83
5 changed files with 190 additions and 2 deletions

View file

@ -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,

View 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);

View file

@ -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) {

View file

@ -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;
/**

View file

@ -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);