[FL-2212] File validators and archive fixes #972

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
Nikolay Minaylov 2022-01-29 12:39:10 +03:00 committed by GitHub
parent 84410c83b5
commit 6264ee8c3b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 194 additions and 52 deletions

View file

@ -25,4 +25,5 @@ struct ArchiveApp {
ArchiveBrowserView* browser;
TextInput* text_input;
char text_store[MAX_NAME_LEN];
char file_extension[MAX_EXT_LEN + 1];
};

View file

@ -272,7 +272,6 @@ void archive_enter_dir(ArchiveBrowserView* browser, string_t name) {
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
model->last_idx = model->idx;
model->last_offset = model->list_offset;
model->idx = 0;
model->depth = CLAMP(model->depth + 1, MAX_DEPTH, 0);
return false;

View file

@ -31,6 +31,40 @@ uint16_t archive_favorites_count(void* context) {
return lines;
}
static bool archive_favourites_rescan() {
string_t buffer;
string_init(buffer);
FileWorker* file_worker = file_worker_alloc(true);
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
if(result) {
while(1) {
if(!file_worker_read_until(file_worker, buffer, '\n')) {
break;
}
if(!string_size(buffer)) {
break;
}
bool file_exists = false;
file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists);
if(file_exists) {
archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer));
}
}
}
string_clear(buffer);
file_worker_close(file_worker);
file_worker_remove(file_worker, ARCHIVE_FAV_PATH);
file_worker_rename(file_worker, ARCHIVE_FAV_TEMP_PATH, ARCHIVE_FAV_PATH);
file_worker_free(file_worker);
return result;
}
bool archive_favorites_read(void* context) {
furi_assert(context);
@ -41,6 +75,8 @@ bool archive_favorites_read(void* context) {
FileInfo file_info;
string_init(buffer);
bool need_refresh = false;
bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING);
if(result) {
@ -52,13 +88,24 @@ bool archive_favorites_read(void* context) {
break;
}
archive_add_item(browser, &file_info, string_get_cstr(buffer));
bool file_exists = false;
file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists);
if(file_exists)
archive_add_item(browser, &file_info, string_get_cstr(buffer));
else
need_refresh = true;
string_reset(buffer);
}
}
string_clear(buffer);
file_worker_close(file_worker);
file_worker_free(file_worker);
if(need_refresh) {
archive_favourites_rescan();
}
return result;
}

View file

@ -30,6 +30,14 @@ void archive_trim_file_path(char* name, bool ext) {
}
}
void archive_get_file_extension(char* name, char* ext) {
char* dot = strrchr(name, '.');
if(dot == NULL)
*ext = '\0';
else
strncpy(ext, dot, MAX_EXT_LEN);
}
void set_file_type(ArchiveFile_t* file, FileInfo* file_info) {
furi_assert(file);
furi_assert(file_info);

View file

@ -50,6 +50,7 @@ ARRAY_DEF(
bool filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name);
void set_file_type(ArchiveFile_t* file, FileInfo* file_info);
void archive_trim_file_path(char* name, bool ext);
void archive_get_file_extension(char* name, char* ext);
bool archive_get_filenames(void* context, const char* path);
bool archive_dir_empty(void* context, const char* path);
bool archive_read_dir(void* context, const char* path);

View file

@ -18,6 +18,7 @@ void archive_scene_rename_on_enter(void* context) {
ArchiveFile_t* current = archive_get_current_file(archive->browser);
strlcpy(archive->text_store, string_get_cstr(current->name), MAX_NAME_LEN);
archive_get_file_extension(archive->text_store, archive->file_extension);
archive_trim_file_path(archive->text_store, true);
text_input_set_header_text(text_input, "Rename:");
@ -30,6 +31,10 @@ void archive_scene_rename_on_enter(void* context) {
MAX_TEXT_INPUT_LEN,
false);
ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(archive_get_path(archive->browser), archive->file_extension);
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput);
}
@ -74,6 +79,11 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) {
void archive_scene_rename_on_exit(void* context) {
ArchiveApp* archive = (ArchiveApp*)context;
// Clear view
void* validator_context = text_input_get_validator_callback_context(archive->text_input);
text_input_set_validator(archive->text_input, NULL, NULL);
validator_is_file_free(validator_context);
text_input_reset(archive->text_input);
}

View file

@ -11,6 +11,7 @@
#define MAX_LEN_PX 110
#define MAX_NAME_LEN 255
#define MAX_EXT_LEN 6
#define FRAME_HEIGHT 12
#define MENU_ITEMS 4
#define MAX_DEPTH 32

View file

@ -18,6 +18,9 @@ void desktop_scene_lock_menu_on_enter(void* context) {
desktop_lock_menu_set_callback(desktop->lock_menu, desktop_scene_lock_menu_callback, desktop);
desktop_lock_menu_pin_set(desktop->lock_menu, desktop->settings.pincode.length > 0);
uint8_t idx = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLockMenu);
desktop_lock_menu_set_idx(desktop->lock_menu, idx);
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewLockMenu);
}
@ -30,6 +33,7 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) {
case DesktopLockMenuEventLock:
scene_manager_set_scene_state(
desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateLockedNoPin);
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
consumed = true;
break;
@ -39,12 +43,14 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) {
desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateLockedWithPin);
scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain);
} else {
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 1);
scene_manager_next_scene(desktop->scene_manager, DesktopScenePinSetup);
}
consumed = true;
break;
case DesktopLockMenuEventExit:
scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0);
scene_manager_search_and_switch_to_previous_scene(
desktop->scene_manager, DesktopSceneMain);
consumed = true;
@ -57,6 +63,4 @@ bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) {
}
void desktop_scene_lock_menu_on_exit(void* context) {
Desktop* desktop = (Desktop*)context;
desktop_lock_menu_reset_idx(desktop->lock_menu);
}

View file

@ -4,6 +4,8 @@
#include "../desktop_i.h"
#include "desktop_lock_menu.h"
#define LOCK_MENU_ITEMS_NB 3
void desktop_lock_menu_set_callback(
DesktopLockMenuView* lock_menu,
DesktopLockMenuViewCallback callback,
@ -22,10 +24,11 @@ void desktop_lock_menu_pin_set(DesktopLockMenuView* lock_menu, bool pin_is_set)
});
}
void desktop_lock_menu_reset_idx(DesktopLockMenuView* lock_menu) {
void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx) {
furi_assert(idx < LOCK_MENU_ITEMS_NB);
with_view_model(
lock_menu->view, (DesktopLockMenuViewModel * model) {
model->idx = 0;
model->idx = idx;
return true;
});
}
@ -51,7 +54,7 @@ static void lock_menu_callback(void* context, uint8_t index) {
}
void desktop_lock_menu_render(Canvas* canvas, void* model) {
const char* Lockmenu_Items[3] = {"Lock", "Lock with PIN", "DUMB mode"};
const char* Lockmenu_Items[LOCK_MENU_ITEMS_NB] = {"Lock", "Lock with PIN", "DUMB mode"};
DesktopLockMenuViewModel* m = model;
canvas_clear(canvas);
@ -60,14 +63,15 @@ void desktop_lock_menu_render(Canvas* canvas, void* model) {
canvas_draw_icon(canvas, 116, 0 + STATUS_BAR_Y_SHIFT, &I_DoorRight_70x55);
canvas_set_font(canvas, FontSecondary);
for(uint8_t i = 0; i < 3; ++i) {
for(uint8_t i = 0; i < LOCK_MENU_ITEMS_NB; ++i) {
const char* str = Lockmenu_Items[i];
if(i == 1 && !m->pin_set) str = "Set PIN";
if(m->hint_timeout && m->idx == 2 && m->idx == i) str = "Not implemented";
canvas_draw_str_aligned(
canvas, 64, 9 + (i * 17) + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter, str);
if(str != NULL)
canvas_draw_str_aligned(
canvas, 64, 9 + (i * 17) + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter, str);
if(m->idx == i) elements_frame(canvas, 15, 1 + (i * 17) + STATUS_BAR_Y_SHIFT, 98, 15);
}
@ -90,9 +94,9 @@ bool desktop_lock_menu_input(InputEvent* event, void* context) {
lock_menu->view, (DesktopLockMenuViewModel * model) {
model->hint_timeout = 0; // clear hint timeout
if(event->key == InputKeyUp) {
model->idx = CLAMP(model->idx - 1, 2, 0);
model->idx = CLAMP(model->idx - 1, LOCK_MENU_ITEMS_NB - 1, 0);
} else if(event->key == InputKeyDown) {
model->idx = CLAMP(model->idx + 1, 2, 0);
model->idx = CLAMP(model->idx + 1, LOCK_MENU_ITEMS_NB - 1, 0);
}
idx = model->idx;
return true;

View file

@ -28,6 +28,6 @@ void desktop_lock_menu_set_callback(
View* desktop_lock_menu_get_view(DesktopLockMenuView* lock_menu);
void desktop_lock_menu_pin_set(DesktopLockMenuView* lock_menu, bool pin_is_set);
void desktop_lock_menu_reset_idx(DesktopLockMenuView* lock_menu);
void desktop_lock_menu_set_idx(DesktopLockMenuView* lock_menu, uint8_t idx);
DesktopLockMenuView* desktop_lock_menu_alloc();
void desktop_lock_menu_free(DesktopLockMenuView* lock_menu);

View file

@ -64,6 +64,10 @@ public:
SceneAddValue,
};
static const char* app_folder;
static const char* app_extension;
static const char* app_filetype;
iButtonAppViewManager* get_view_manager();
void switch_to_next_scene(Scene index);
void search_and_switch_to_previous_scene(std::initializer_list<Scene> scenes_list);
@ -137,10 +141,6 @@ private:
static const uint8_t text_store_size = 128;
char text_store[text_store_size + 1];
static const char* app_folder;
static const char* app_extension;
static const char* app_filetype;
bool load_key_data(string_t key_path);
void make_app_folder();
};

View file

@ -25,6 +25,10 @@ void iButtonSceneSaveName::on_enter(iButtonApp* app) {
text_input_set_result_callback(
text_input, callback, app, app->get_text_store(), IBUTTON_KEY_NAME_SIZE, key_name_empty);
ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(app->app_folder, app->app_extension);
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewTextInput);
}
@ -48,6 +52,11 @@ bool iButtonSceneSaveName::on_event(iButtonApp* app, iButtonEvent* event) {
void iButtonSceneSaveName::on_exit(iButtonApp* app) {
TextInput* text_input = app->get_view_manager()->get_text_input();
void* validator_context = text_input_get_validator_callback_context(text_input);
text_input_set_validator(text_input, NULL, NULL);
validator_is_file_free((ValidatorIsFile*)validator_context);
text_input_reset(text_input);
}

View file

@ -20,6 +20,10 @@ void IrdaAppSceneEditRename::on_enter(IrdaApp* app) {
strncpy(app->get_text_store(0), remote_name.c_str(), app->get_text_store_size());
enter_name_length = IrdaAppRemoteManager::max_remote_name_length;
text_input_set_header_text(text_input, "Name the remote");
ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(app->irda_directory, app->irda_extension);
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
}
text_input_set_result_callback(
@ -59,4 +63,10 @@ bool IrdaAppSceneEditRename::on_event(IrdaApp* app, IrdaAppEvent* event) {
}
void IrdaAppSceneEditRename::on_exit(IrdaApp* app) {
TextInput* text_input = app->get_view_manager()->get_text_input();
void* validator_context = text_input_get_validator_callback_context(text_input);
text_input_set_validator(text_input, NULL, NULL);
if(validator_context != NULL) validator_is_file_free((ValidatorIsFile*)validator_context);
}

View file

@ -35,9 +35,9 @@ void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool need_restore) {
string_printf(string_header, "Delete %s?", key.get_name());
line_1->set_text(
string_get_cstr(string_header), 64, 19, AlignCenter, AlignBottom, FontPrimary);
string_get_cstr(string_header), 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary);
line_2->set_text(
string_get_cstr(string_data), 64, 29, AlignCenter, AlignBottom, FontSecondary);
string_get_cstr(string_data), 64, 29, 0, AlignCenter, AlignBottom, FontSecondary);
switch(key.get_type()) {
case LfrfidKeyType::KeyEM4100:
@ -52,12 +52,13 @@ void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool need_restore) {
break;
}
line_3->set_text(
string_get_cstr(string_decrypted), 64, 39, AlignCenter, AlignBottom, FontSecondary);
string_get_cstr(string_decrypted), 64, 39, 0, AlignCenter, AlignBottom, FontSecondary);
line_4->set_text(
lfrfid_key_get_type_string(key.get_type()),
64,
49,
0,
AlignCenter,
AlignBottom,
FontSecondary);

View file

@ -36,9 +36,9 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool need_restore) {
switch(app->worker.key.get_type()) {
case LfrfidKeyType::KeyEM4100:
line_1_text->set_text("HEX:", 65, 23, AlignRight, AlignBottom, FontSecondary);
line_2_text->set_text("Mod:", 65, 35, AlignRight, AlignBottom, FontSecondary);
line_3_text->set_text("ID:", 65, 47, AlignRight, AlignBottom, FontSecondary);
line_1_text->set_text("HEX:", 65, 23, 0, AlignRight, AlignBottom, FontSecondary);
line_2_text->set_text("Mod:", 65, 35, 0, AlignRight, AlignBottom, FontSecondary);
line_3_text->set_text("ID:", 65, 47, 0, AlignRight, AlignBottom, FontSecondary);
for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) {
string_cat_printf(string[0], "%02X", data[i]);
@ -48,17 +48,17 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool need_restore) {
string_printf(string[2], "%03u,%05u", data[2], (uint16_t)((data[3] << 8) | (data[4])));
line_1_value->set_text(
string_get_cstr(string[0]), 68, 23, AlignLeft, AlignBottom, FontSecondary);
string_get_cstr(string[0]), 68, 23, 0, AlignLeft, AlignBottom, FontSecondary);
line_2_value->set_text(
string_get_cstr(string[1]), 68, 35, AlignLeft, AlignBottom, FontSecondary);
string_get_cstr(string[1]), 68, 35, 0, AlignLeft, AlignBottom, FontSecondary);
line_3_value->set_text(
string_get_cstr(string[2]), 68, 47, AlignLeft, AlignBottom, FontSecondary);
string_get_cstr(string[2]), 68, 47, 0, AlignLeft, AlignBottom, FontSecondary);
break;
case LfrfidKeyType::KeyH10301:
case LfrfidKeyType::KeyI40134:
line_1_text->set_text("HEX:", 65, 23, AlignRight, AlignBottom, FontSecondary);
line_2_text->set_text("FC:", 65, 35, AlignRight, AlignBottom, FontSecondary);
line_3_text->set_text("Card:", 65, 47, AlignRight, AlignBottom, FontSecondary);
line_1_text->set_text("HEX:", 65, 23, 0, AlignRight, AlignBottom, FontSecondary);
line_2_text->set_text("FC:", 65, 35, 0, AlignRight, AlignBottom, FontSecondary);
line_3_text->set_text("Card:", 65, 47, 0, AlignRight, AlignBottom, FontSecondary);
for(uint8_t i = 0; i < app->worker.key.get_type_data_count(); i++) {
string_cat_printf(string[0], "%02X", data[i]);
@ -68,11 +68,11 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool need_restore) {
string_printf(string[2], "%u", (uint16_t)((data[1] << 8) | (data[2])));
line_1_value->set_text(
string_get_cstr(string[0]), 68, 23, AlignLeft, AlignBottom, FontSecondary);
string_get_cstr(string[0]), 68, 23, 0, AlignLeft, AlignBottom, FontSecondary);
line_2_value->set_text(
string_get_cstr(string[1]), 68, 35, AlignLeft, AlignBottom, FontSecondary);
string_get_cstr(string[1]), 68, 35, 0, AlignLeft, AlignBottom, FontSecondary);
line_3_value->set_text(
string_get_cstr(string[2]), 68, 47, AlignLeft, AlignBottom, FontSecondary);
string_get_cstr(string[2]), 68, 47, 0, AlignLeft, AlignBottom, FontSecondary);
break;
}

View file

@ -21,6 +21,10 @@ void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool need_restore) {
app->worker.key.get_name_length(),
key_name_empty);
ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(app->app_folder, app->app_extension);
text_input->set_validator(validator_is_file_callback, validator_is_file);
app->view_controller.switch_to<TextInputVM>();
}
@ -46,6 +50,11 @@ bool LfRfidAppSceneSaveName::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
}
void LfRfidAppSceneSaveName::on_exit(LfRfidApp* app) {
void* validator_context =
app->view_controller.get<TextInputVM>()->get_validator_callback_context();
app->view_controller.get<TextInputVM>()->set_validator(NULL, NULL);
validator_is_file_free((ValidatorIsFile*)validator_context);
app->view_controller.get<TextInputVM>()->clean();
}

View file

@ -28,8 +28,9 @@ void LfRfidAppSceneSavedInfo::on_enter(LfRfidApp* app, bool need_restore) {
string_cat_printf(string_data, "%02X", data[i]);
}
line_1->set_text(key.get_name(), 64, 17, AlignCenter, AlignBottom, FontSecondary);
line_2->set_text(string_get_cstr(string_data), 64, 29, AlignCenter, AlignBottom, FontPrimary);
line_1->set_text(key.get_name(), 64, 17, 128 - 2, AlignCenter, AlignBottom, FontSecondary);
line_2->set_text(
string_get_cstr(string_data), 64, 29, 0, AlignCenter, AlignBottom, FontPrimary);
switch(key.get_type()) {
case LfrfidKeyType::KeyEM4100:
@ -44,12 +45,13 @@ void LfRfidAppSceneSavedInfo::on_enter(LfRfidApp* app, bool need_restore) {
break;
}
line_3->set_text(
string_get_cstr(string_decrypted), 64, 39, AlignCenter, AlignBottom, FontSecondary);
string_get_cstr(string_decrypted), 64, 39, 0, AlignCenter, AlignBottom, FontSecondary);
line_4->set_text(
lfrfid_key_get_type_string(key.get_type()),
64,
49,
0,
AlignCenter,
AlignBottom,
FontSecondary);

View file

@ -9,8 +9,17 @@ StringElement::~StringElement() {
void StringElement::draw(Canvas* canvas) {
if(text) {
string_t line;
string_init(line);
string_set_str(line, text);
canvas_set_font(canvas, font);
elements_multiline_text_aligned(canvas, x, y, horizontal, vertical, text);
if(fit_width != 0) {
elements_string_fit_width(canvas, line, fit_width);
}
elements_multiline_text_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(line));
string_clear(line);
}
}
@ -22,6 +31,7 @@ void StringElement::set_text(
const char* _text,
uint8_t _x,
uint8_t _y,
uint8_t _fit_w,
Align _horizontal,
Align _vertical,
Font _font) {
@ -29,8 +39,9 @@ void StringElement::set_text(
text = _text;
x = _x;
y = _y;
fit_width = _fit_w;
horizontal = _horizontal;
vertical = _vertical;
font = _font;
unlock_model(true);
}
}

View file

@ -12,6 +12,7 @@ public:
const char* text = NULL,
uint8_t x = 0,
uint8_t y = 0,
uint8_t fit_width = 0,
Align horizontal = AlignLeft,
Align vertical = AlignTop,
Font font = FontPrimary);
@ -20,6 +21,7 @@ private:
const char* text = NULL;
uint8_t x = 0;
uint8_t y = 0;
uint8_t fit_width = 0;
Align horizontal = AlignLeft;
Align vertical = AlignTop;
Font font = FontPrimary;

View file

@ -4,9 +4,6 @@
#include <lib/toolbox/path.h>
#include <lib/flipper_file/flipper_file.h>
static const char* nfc_app_folder = "/any/nfc";
static const char* nfc_app_extension = ".nfc";
static const char* nfc_app_shadow_extension = ".shd";
static const char* nfc_file_header = "Flipper NFC device";
static const uint32_t nfc_file_version = 2;
@ -243,7 +240,7 @@ static bool nfc_device_save_file(
do {
// Create nfc directory if necessary
if(!storage_simply_mkdir(dev->storage, nfc_app_folder)) break;
if(!storage_simply_mkdir(dev->storage, NFC_APP_FOLDER)) break;
// First remove nfc device file if it was saved
string_printf(temp_str, "%s/%s%s", folder, dev_name, extension);
// Open file
@ -281,12 +278,12 @@ static bool nfc_device_save_file(
}
bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_extension);
return nfc_device_save_file(dev, dev_name, NFC_APP_FOLDER, NFC_APP_EXTENSION);
}
bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) {
dev->shadow_file_exist = true;
return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_shadow_extension);
return nfc_device_save_file(dev, dev_name, NFC_APP_FOLDER, NFC_APP_SHADOW_EXTENSION);
}
static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
@ -300,9 +297,9 @@ static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
do {
// Check existance of shadow file
size_t ext_start = string_search_str(path, nfc_app_extension);
size_t ext_start = string_search_str(path, NFC_APP_EXTENSION);
string_set_n(temp_str, path, 0, ext_start);
string_cat_printf(temp_str, "%s", nfc_app_shadow_extension);
string_cat_printf(temp_str, "%s", NFC_APP_SHADOW_EXTENSION);
dev->shadow_file_exist =
storage_common_stat(dev->storage, string_get_cstr(temp_str), NULL) == FSE_OK;
// Open shadow file if it exists. If not - open original
@ -374,15 +371,15 @@ bool nfc_file_select(NfcDevice* dev) {
// Input events and views are managed by file_select
bool res = dialog_file_select_show(
dev->dialogs,
nfc_app_folder,
nfc_app_extension,
NFC_APP_FOLDER,
NFC_APP_EXTENSION,
dev->file_name,
sizeof(dev->file_name),
dev->dev_name);
if(res) {
string_t dev_str;
// Get key file path
string_init_printf(dev_str, "%s/%s%s", nfc_app_folder, dev->file_name, nfc_app_extension);
string_init_printf(dev_str, "%s/%s%s", NFC_APP_FOLDER, dev->file_name, NFC_APP_EXTENSION);
res = nfc_device_load_data(dev, dev_str);
if(res) {
nfc_device_set_name(dev, dev->file_name);
@ -409,12 +406,12 @@ bool nfc_device_delete(NfcDevice* dev) {
do {
// Delete original file
string_init_printf(file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension);
string_init_printf(file_path, "%s/%s%s", NFC_APP_FOLDER, dev->dev_name, NFC_APP_EXTENSION);
if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break;
// Delete shadow file if it exists
if(dev->shadow_file_exist) {
string_printf(
file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension);
file_path, "%s/%s%s", NFC_APP_FOLDER, dev->dev_name, NFC_APP_SHADOW_EXTENSION);
if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break;
}
deleted = true;
@ -437,10 +434,10 @@ bool nfc_device_restore(NfcDevice* dev) {
do {
string_init_printf(
path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension);
path, "%s/%s%s", NFC_APP_FOLDER, dev->dev_name, NFC_APP_SHADOW_EXTENSION);
if(!storage_simply_remove(dev->storage, string_get_cstr(path))) break;
dev->shadow_file_exist = false;
string_printf(path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension);
string_printf(path, "%s/%s%s", NFC_APP_FOLDER, dev->dev_name, NFC_APP_EXTENSION);
if(!nfc_device_load_data(dev, path)) break;
restored = true;
} while(0);

View file

@ -10,6 +10,10 @@
#define NFC_DEV_NAME_MAX_LEN 22
#define NFC_FILE_NAME_MAX_LEN 120
#define NFC_APP_FOLDER "/any/nfc"
#define NFC_APP_EXTENSION ".nfc"
#define NFC_APP_SHADOW_EXTENSION ".shd"
typedef enum {
NfcDeviceNfca,
NfcDeviceNfcb,

View file

@ -1,5 +1,6 @@
#include "../nfc_i.h"
#include <lib/toolbox/random_name.h>
#include <gui/modules/validators.h>
#define SCENE_SAVE_NAME_CUSTOM_EVENT (0UL)
@ -29,6 +30,11 @@ void nfc_scene_save_name_on_enter(void* context) {
nfc->text_store,
NFC_DEV_NAME_MAX_LEN,
dev_name_empty);
ValidatorIsFile* validator_is_file =
validator_is_file_alloc_init(NFC_APP_FOLDER, NFC_APP_EXTENSION);
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextInput);
}
@ -60,5 +66,9 @@ void nfc_scene_save_name_on_exit(void* context) {
Nfc* nfc = (Nfc*)context;
// Clear view
void* validator_context = text_input_get_validator_callback_context(nfc->text_input);
text_input_set_validator(nfc->text_input, NULL, NULL);
validator_is_file_free(validator_context);
text_input_reset(nfc->text_input);
}

View file

@ -29,3 +29,11 @@ void TextInputVM::set_result_callback(
void TextInputVM::set_header_text(const char* text) {
text_input_set_header_text(text_input, text);
}
void TextInputVM::set_validator(TextInputValidatorCallback callback, void* callback_context) {
text_input_set_validator(text_input, callback, callback_context);
}
void* TextInputVM::get_validator_callback_context() {
return text_input_get_validator_callback_context(text_input);
}

View file

@ -32,6 +32,10 @@ public:
*/
void set_header_text(const char* text);
void set_validator(TextInputValidatorCallback callback, void* callback_context);
void* get_validator_callback_context();
private:
TextInput* text_input;
};