[FL-2045] SubGhz: new protocol (GSN , Beninca/Allmatic, Elmes) and validator (#958)
* SubGhz: add new method of obtaining a manufactory code subghz_protocol_keeloq_common_magic_xor_type1_learning * TextInput: checking for a lock on a file with the same name * TextInput: fix checking for a lock on a file with the same name * Assets: rename and recompile * TextInput: added picture and timer to turn off blob * TextInput: Fix graphics * TextInput: fix validator * Validators: Add validator is file * TextInput: fix callback validator_is_file_alloc * SubGhz: add propocol GNS (dimamic), Beninca/Alcatic, Elmes * SubGhz: fix function description * Gui: correct timer routine on deallocation * Format sources Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
struct TextInput {
|
||||
View* view;
|
||||
osTimerId_t timer;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -23,6 +24,11 @@ typedef struct {
|
||||
|
||||
uint8_t selected_row;
|
||||
uint8_t selected_column;
|
||||
|
||||
TextInputValidatorCallback validator_callback;
|
||||
void* validator_callback_context;
|
||||
string_t validator_text;
|
||||
bool valadator_message_visible;
|
||||
} TextInputModel;
|
||||
|
||||
static const uint8_t keyboard_origin_x = 1;
|
||||
@@ -236,6 +242,17 @@ static void text_input_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if(model->valadator_message_visible) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
canvas_draw_box(canvas, 8, 10, 110, 48);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_draw_icon(canvas, 10, 14, &I_WarningDolphin_45x42);
|
||||
canvas_draw_rframe(canvas, 8, 8, 112, 50, 3);
|
||||
canvas_draw_rframe(canvas, 9, 9, 110, 48, 2);
|
||||
elements_multiline_text(canvas, 62, 20, string_get_cstr(model->validator_text));
|
||||
canvas_set_font(canvas, FontKeyboard);
|
||||
}
|
||||
}
|
||||
|
||||
static void text_input_handle_up(TextInput* text_input) {
|
||||
@@ -295,7 +312,13 @@ static void text_input_handle_ok(TextInput* text_input) {
|
||||
uint8_t text_length = strlen(model->text_buffer);
|
||||
|
||||
if(selected == ENTER_KEY) {
|
||||
if(model->callback != 0 && text_length > 0) {
|
||||
if(model->validator_callback && (!model->validator_callback(
|
||||
model->text_buffer,
|
||||
model->validator_text,
|
||||
model->validator_callback_context))) {
|
||||
model->valadator_message_visible = true;
|
||||
osTimerStart(text_input->timer, osKernelGetTickFreq() * 4);
|
||||
} else if(model->callback != 0 && text_length > 0) {
|
||||
model->callback(model->callback_context);
|
||||
}
|
||||
} else if(selected == BACKSPACE_KEY) {
|
||||
@@ -321,6 +344,16 @@ static bool text_input_view_input_callback(InputEvent* event, void* context) {
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
|
||||
with_view_model(
|
||||
text_input->view, (TextInputModel * model) {
|
||||
if(model->valadator_message_visible) {
|
||||
if(event->key == InputKeyBack) {
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
model->valadator_message_visible = false;
|
||||
return false;
|
||||
});
|
||||
switch(event->key) {
|
||||
case InputKeyUp:
|
||||
text_input_handle_up(text_input);
|
||||
@@ -351,7 +384,11 @@ static bool text_input_view_input_callback(InputEvent* event, void* context) {
|
||||
event->key == InputKeyBack) {
|
||||
with_view_model(
|
||||
text_input->view, (TextInputModel * model) {
|
||||
text_input_backspace_cb(model);
|
||||
if(model->valadator_message_visible) {
|
||||
model->valadator_message_visible = false;
|
||||
} else {
|
||||
text_input_backspace_cb(model);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -361,6 +398,17 @@ static bool text_input_view_input_callback(InputEvent* event, void* context) {
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void text_input_timer_callback(void* context) {
|
||||
furi_assert(context);
|
||||
TextInput* text_input = context;
|
||||
|
||||
with_view_model(
|
||||
text_input->view, (TextInputModel * model) {
|
||||
model->valadator_message_visible = false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
TextInput* text_input_alloc() {
|
||||
TextInput* text_input = furi_alloc(sizeof(TextInput));
|
||||
text_input->view = view_alloc();
|
||||
@@ -369,6 +417,14 @@ TextInput* text_input_alloc() {
|
||||
view_set_draw_callback(text_input->view, text_input_view_draw_callback);
|
||||
view_set_input_callback(text_input->view, text_input_view_input_callback);
|
||||
|
||||
text_input->timer = osTimerNew(text_input_timer_callback, osTimerOnce, text_input, NULL);
|
||||
|
||||
with_view_model(
|
||||
text_input->view, (TextInputModel * model) {
|
||||
string_init(model->validator_text);
|
||||
return false;
|
||||
});
|
||||
|
||||
text_input_clean(text_input);
|
||||
|
||||
return text_input;
|
||||
@@ -376,7 +432,21 @@ TextInput* text_input_alloc() {
|
||||
|
||||
void text_input_free(TextInput* text_input) {
|
||||
furi_assert(text_input);
|
||||
with_view_model(
|
||||
text_input->view, (TextInputModel * model) {
|
||||
string_clear(model->validator_text);
|
||||
return false;
|
||||
});
|
||||
|
||||
// Send stop command
|
||||
osTimerStop(text_input->timer);
|
||||
// Wait till timer stop
|
||||
while(osTimerIsRunning(text_input->timer)) osDelay(1);
|
||||
// Release allocated memory
|
||||
osTimerDelete(text_input->timer);
|
||||
|
||||
view_free(text_input->view);
|
||||
|
||||
free(text_input);
|
||||
}
|
||||
|
||||
@@ -393,6 +463,10 @@ void text_input_clean(TextInput* text_input) {
|
||||
model->text_buffer_size = 0;
|
||||
model->callback = NULL;
|
||||
model->callback_context = NULL;
|
||||
model->validator_callback = NULL;
|
||||
model->validator_callback_context = NULL;
|
||||
string_reset(model->validator_text);
|
||||
model->valadator_message_visible = false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@@ -425,10 +499,42 @@ void text_input_set_result_callback(
|
||||
});
|
||||
}
|
||||
|
||||
void text_input_set_validator(
|
||||
TextInput* text_input,
|
||||
TextInputValidatorCallback callback,
|
||||
void* callback_context) {
|
||||
with_view_model(
|
||||
text_input->view, (TextInputModel * model) {
|
||||
model->validator_callback = callback;
|
||||
model->validator_callback_context = callback_context;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
TextInputValidatorCallback text_input_get_validator_callback(TextInput* text_input) {
|
||||
TextInputValidatorCallback validator_callback = NULL;
|
||||
with_view_model(
|
||||
text_input->view, (TextInputModel * model) {
|
||||
validator_callback = model->validator_callback;
|
||||
return false;
|
||||
});
|
||||
return validator_callback;
|
||||
}
|
||||
|
||||
void* text_input_get_validator_callback_context(TextInput* text_input) {
|
||||
void* validator_callback_context = NULL;
|
||||
with_view_model(
|
||||
text_input->view, (TextInputModel * model) {
|
||||
validator_callback_context = model->validator_callback_context;
|
||||
return false;
|
||||
});
|
||||
return validator_callback_context;
|
||||
}
|
||||
|
||||
void text_input_set_header_text(TextInput* text_input, const char* text) {
|
||||
with_view_model(
|
||||
text_input->view, (TextInputModel * model) {
|
||||
model->header = text;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -6,6 +6,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "validators.h"
|
||||
#include <m-string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -14,6 +16,7 @@ extern "C" {
|
||||
/** Text input anonymous structure */
|
||||
typedef struct TextInput TextInput;
|
||||
typedef void (*TextInputCallback)(void* context);
|
||||
typedef bool (*TextInputValidatorCallback)(const char* text, string_t error, void* context);
|
||||
|
||||
/** Allocate and initialize text input
|
||||
*
|
||||
@@ -63,6 +66,15 @@ void text_input_set_result_callback(
|
||||
size_t text_buffer_size,
|
||||
bool clear_default_text);
|
||||
|
||||
void text_input_set_validator(
|
||||
TextInput* text_input,
|
||||
TextInputValidatorCallback callback,
|
||||
void* callback_context);
|
||||
|
||||
TextInputValidatorCallback text_input_get_validator_callback(TextInput* text_input);
|
||||
|
||||
void* text_input_get_validator_callback_context(TextInput* text_input);
|
||||
|
||||
/** Set text input header text
|
||||
*
|
||||
* @param text_input TextInput instance
|
||||
|
42
applications/gui/modules/validators.c
Normal file
42
applications/gui/modules/validators.c
Normal file
@@ -0,0 +1,42 @@
|
||||
#include <furi.h>
|
||||
#include "validators.h"
|
||||
#include "applications/storage/storage.h"
|
||||
|
||||
struct ValidatorIsFile {
|
||||
const char* app_path_folder;
|
||||
const char* app_extension;
|
||||
};
|
||||
|
||||
bool validator_is_file_callback(const char* text, string_t error, void* context) {
|
||||
furi_assert(context);
|
||||
ValidatorIsFile* instance = context;
|
||||
bool ret = true;
|
||||
string_t path;
|
||||
string_init_printf(path, "%s/%s%s", instance->app_path_folder, text, instance->app_extension);
|
||||
Storage* storage = furi_record_open("storage");
|
||||
if(storage_common_stat(storage, string_get_cstr(path), NULL) == FSE_OK) {
|
||||
ret = false;
|
||||
string_printf(error, "This name\nexists!\nChoose\nanother one.");
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
string_clear(path);
|
||||
furi_record_close("storage");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ValidatorIsFile*
|
||||
validator_is_file_alloc_init(const char* app_path_folder, const char* app_extension) {
|
||||
ValidatorIsFile* instance = furi_alloc(sizeof(ValidatorIsFile));
|
||||
|
||||
instance->app_path_folder = app_path_folder;
|
||||
instance->app_extension = app_extension;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void validator_is_file_free(ValidatorIsFile* instance) {
|
||||
furi_assert(instance);
|
||||
free(instance);
|
||||
}
|
20
applications/gui/modules/validators.h
Normal file
20
applications/gui/modules/validators.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
// #include <gui/view.h>
|
||||
#include <m-string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
typedef struct ValidatorIsFile ValidatorIsFile;
|
||||
|
||||
ValidatorIsFile*
|
||||
validator_is_file_alloc_init(const char* app_path_folder, const char* app_extension);
|
||||
|
||||
void validator_is_file_free(ValidatorIsFile* instance);
|
||||
|
||||
bool validator_is_file_callback(const char* text, string_t error, void* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -1,10 +1,11 @@
|
||||
#include "../subghz_i.h"
|
||||
#include <lib/toolbox/random_name.h>
|
||||
#include "file_worker.h"
|
||||
#include "../helpers/subghz_custom_event.h"
|
||||
#include <lib/subghz/protocols/subghz_protocol_raw.h>
|
||||
#include <gui/modules/validators.h>
|
||||
|
||||
void subghz_scene_save_name_text_input_callback(void* context) {
|
||||
furi_assert(context);
|
||||
SubGhz* subghz = context;
|
||||
view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneSaveName);
|
||||
}
|
||||
@@ -37,6 +38,11 @@ void subghz_scene_save_name_on_enter(void* context) {
|
||||
subghz->file_name,
|
||||
22, //Max len name
|
||||
dev_name_empty);
|
||||
|
||||
ValidatorIsFile* validator_is_file =
|
||||
validator_is_file_alloc_init(SUBGHZ_APP_PATH_FOLDER, SUBGHZ_APP_EXTENSION);
|
||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
||||
|
||||
view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTextInput);
|
||||
}
|
||||
|
||||
@@ -50,7 +56,9 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
|
||||
if(event.event == SubghzCustomEventSceneSaveName) {
|
||||
if(strcmp(subghz->file_name, "")) {
|
||||
if(strcmp(subghz->file_name_tmp, "")) {
|
||||
subghz_rename_file(subghz);
|
||||
if(!subghz_rename_file(subghz)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
subghz_save_protocol_to_file(subghz, subghz->file_name);
|
||||
}
|
||||
@@ -79,6 +87,10 @@ void subghz_scene_save_name_on_exit(void* context) {
|
||||
SubGhz* subghz = context;
|
||||
|
||||
// Clear view
|
||||
void* validator_context = text_input_get_validator_callback_context(subghz->text_input);
|
||||
text_input_set_validator(subghz->text_input, NULL, NULL);
|
||||
validator_is_file_free(validator_context);
|
||||
|
||||
text_input_clean(subghz->text_input);
|
||||
scene_manager_set_scene_state(
|
||||
subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet);
|
||||
|
@@ -421,7 +421,7 @@ bool subghz_rename_file(SubGhz* subghz) {
|
||||
FS_Error fs_result =
|
||||
storage_common_rename(storage, string_get_cstr(old_path), string_get_cstr(new_path));
|
||||
|
||||
if(fs_result != FSE_OK && fs_result != FSE_EXIST) {
|
||||
if(fs_result != FSE_OK) {
|
||||
dialog_message_show_storage_error(subghz->dialogs, "Cannot rename\n file/directory");
|
||||
ret = false;
|
||||
}
|
||||
|
Reference in New Issue
Block a user