Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions base_pack/barcode_gen/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Changelog

## 1.5

- Fix the first save after a fresh install always failing with "A saving error has occurred": the barcodes folder was only created when the app exited; it is now created on startup and rechecked before every save
- Show the actual save error instead of a generic message: empty name or data, a file with this name already exists, SD card not accessible, rename failure
- Fix renaming a barcode to the name of another saved barcode silently overwriting it - it is now rejected with a clear message
- Fix "File Saved!" being reported when the file could not be fully written (e.g. SD card removed mid-save)
- Save and delete failures now return to the edit form with the entered data intact instead of dropping to the main menu

## 1.4

- Add a custom keyboard (by thevan4): symbols can be entered for barcode data, while characters not allowed in file names stay hidden when naming a file
- Update for a newer firmware API (no functional changes)

## 1.3

- Keep the display backlight on while a barcode is shown
- Version bump for catalog compatibility

## 1.2

- Add an "Error Codes Info" screen to the main menu explaining every error the app can show
- Add an About screen
- Fix CODE-128 barcodes containing `#` producing an "Invalid Characters" error
- Fix the CODE-128 check digit encoding lookup for check digit values below 100

## 1.1

- Initial release in this pack: create, edit and display UPC-A, EAN-8, EAN-13, CODE-39, Codabar, CODE-128 (Set B) and CODE-128C barcodes; saved barcodes are stored in `/apps_data/barcodes`
2 changes: 1 addition & 1 deletion base_pack/barcode_gen/application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ App(
fap_file_assets="barcode_encoding_files",
fap_author="@Kingal1337",
fap_weburl="https://github.com/Kingal1337/flipper-barcode-generator",
fap_version="1.4",
fap_version="1.5",
fap_description="App allows you to display various barcodes on flipper screen",
)
28 changes: 11 additions & 17 deletions base_pack/barcode_gen/barcode_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,19 @@ bool get_file_name_from_path(FuriString* file_path, FuriString* file_name, bool
}

/**
* Creates the barcode folder
* Creates the barcode folder if it does not exist
* @returns true if the folder exists or was created
*/
void init_folder() {
bool init_folder() {
Storage* storage = furi_record_open(RECORD_STORAGE);
FURI_LOG_I(TAG, "Creating barcodes folder");
if(storage_simply_mkdir(storage, DEFAULT_USER_BARCODES)) {
FURI_LOG_I(TAG, "Barcodes folder successfully created!");
} else {
FURI_LOG_I(TAG, "Barcodes folder already exists.");
//simply_mkdir also returns true when the folder already exists,
//false is a real failure, e.g. a missing SD card
bool folder_ready = storage_simply_mkdir(storage, DEFAULT_USER_BARCODES);
if(!folder_ready) {
FURI_LOG_E(TAG, "Could not create the barcodes folder");
}
furi_record_close(RECORD_STORAGE);
return folder_ready;
}

void select_barcode_item(BarcodeApp* app) {
Expand Down Expand Up @@ -180,15 +182,7 @@ void edit_barcode_item(BarcodeApp* app) {
reason = read_raw_data(file_path, raw_type, raw_data);
if(reason != OKCode) {
FURI_LOG_E(TAG, "Could not read data correctly");
with_view_model(
app->message_view->view,
MessageViewModel * model,
{ model->message = get_error_code_message(reason); },
true);

view_dispatcher_switch_to_view(
create_view_object->barcode_app->view_dispatcher, MessageErrorView);

message_view_show(app->message_view, get_error_code_message(reason), MainMenuView);
} else {
BarcodeTypeObj* type_obj = get_type(raw_type);
if(type_obj->type == UNKNOWN) {
Expand Down Expand Up @@ -275,7 +269,6 @@ uint32_t exit_callback(void* context) {
void free_app(BarcodeApp* app) {
FURI_LOG_I(TAG, "Freeing Data");

init_folder();
free_types();

view_dispatcher_remove_view(app->view_dispatcher, TextInputView);
Expand Down Expand Up @@ -320,6 +313,7 @@ int32_t barcode_main(void* p) {
UNUSED(p);
BarcodeApp* app = malloc(sizeof(BarcodeApp));
init_types();
init_folder();
app->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));

// Register view port in GUI
Expand Down
2 changes: 2 additions & 0 deletions base_pack/barcode_gen/barcode_app.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ enum Views {

void submenu_callback(void* context, uint32_t index);

bool init_folder();

uint32_t main_menu_callback(void* context);

uint32_t exit_callback(void* context);
Expand Down
159 changes: 83 additions & 76 deletions base_pack/barcode_gen/views/create_view.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,20 +353,13 @@ void remove_barcode(CreateView* create_view_object) {
true);
furi_record_close(RECORD_STORAGE);

with_view_model(
create_view_object->barcode_app->message_view->view,
MessageViewModel * model,
{
if(success) {
model->message = "File Deleted";
} else {
model->message = "Could not delete file";
}
},
true);

view_dispatcher_switch_to_view(
create_view_object->barcode_app->view_dispatcher, MessageErrorView);
MessageView* message_view = create_view_object->barcode_app->message_view;
if(success) {
message_view_show(message_view, "File Deleted", MainMenuView);
} else {
//stay in the edit view so the user can retry
message_view_show(message_view, "Could not delete file", CreateBarcodeView);
}
}

void save_barcode(CreateView* create_view_object) {
Expand All @@ -388,20 +381,26 @@ void save_barcode(CreateView* create_view_object) {
},
true);

MessageView* message_view = create_view_object->barcode_app->message_view;

if(file_name == NULL || furi_string_empty(file_name)) {
FURI_LOG_E(TAG, "File Name cannot be empty");
message_view_show(message_view, "File name\ncannot be empty", CreateBarcodeView);
return;
}
if(barcode_data == NULL || furi_string_empty(barcode_data)) {
FURI_LOG_E(TAG, "Barcode Data cannot be empty");
message_view_show(message_view, "Barcode data\ncannot be empty", CreateBarcodeView);
return;
}
if(barcode_type == NULL) {
FURI_LOG_E(TAG, "Type not defined");
message_view_show(message_view, "Barcode type\nis not selected", CreateBarcodeView);
return;
}

bool success = false;
//NULL while the save is still going fine
const char* error_message = NULL;

FuriString* full_file_path = furi_string_alloc_set(DEFAULT_USER_BARCODES);
furi_string_push_back(full_file_path, '/');
Expand All @@ -410,76 +409,84 @@ void save_barcode(CreateView* create_view_object) {

Storage* storage = furi_record_open(RECORD_STORAGE);

if(mode == EditMode) {
if(!furi_string_empty(file_path)) {
if(!furi_string_equal(file_path, full_file_path)) {
FS_Error error = storage_common_rename(
storage,
furi_string_get_cstr(file_path),
furi_string_get_cstr(full_file_path));
if(error != FSE_OK) {
FURI_LOG_E(TAG, "Rename error: %s", storage_error_get_desc(error));
} else {
FURI_LOG_I(TAG, "Rename Success");
}
}
}
//ensure the barcodes folder exists before saving,
//it could have been removed while the app was running
if(!init_folder()) {
error_message = "Cannot access\nthe SD card";
}

FlipperFormat* ff = flipper_format_file_alloc(storage);

FURI_LOG_I(TAG, "Saving Barcode to: %s", furi_string_get_cstr(full_file_path));

bool file_opened_status = false;
if(mode == NewMode) {
file_opened_status =
flipper_format_file_open_new(ff, furi_string_get_cstr(full_file_path));
} else if(mode == EditMode) {
file_opened_status =
flipper_format_file_open_always(ff, furi_string_get_cstr(full_file_path));
//overwriting the barcode's own file in edit mode is fine, but saving
//over any other existing file would destroy it, fail with a clear message instead
bool same_file = file_path != NULL && furi_string_equal(file_path, full_file_path);
if(error_message == NULL && !same_file &&
storage_file_exists(storage, furi_string_get_cstr(full_file_path))) {
FURI_LOG_E(TAG, "File \"%s\" already exists", furi_string_get_cstr(full_file_path));
error_message = "A file with this\nname already exists";
}

if(file_opened_status) {
// Filetype: Barcode
// Version: 1

// # Types - UPC-A, EAN-8, EAN-13, CODE-39
// Type: CODE-39
// Data: AB
flipper_format_write_string_cstr(ff, "Filetype", "Barcode");

flipper_format_write_string_cstr(ff, "Version", FILE_VERSION);

flipper_format_write_comment_cstr(
ff, "Types - UPC-A, EAN-8, EAN-13, CODE-39, CODE-128, Codabar");

flipper_format_write_string_cstr(ff, "Type", barcode_type->name);

flipper_format_write_string_cstr(ff, "Data", furi_string_get_cstr(barcode_data));
//in edit mode a changed name moves the old file before saving
if(error_message == NULL && mode == EditMode && !same_file && !furi_string_empty(file_path)) {
FS_Error error = storage_common_rename(
storage, furi_string_get_cstr(file_path), furi_string_get_cstr(full_file_path));
if(error != FSE_OK) {
FURI_LOG_E(TAG, "Rename error: %s", storage_error_get_desc(error));
error_message = "Could not rename\nthe barcode file";
} else {
FURI_LOG_I(TAG, "Rename Success");
//keep the model path in sync so a failed save below
//does not leave it pointing at the old, now removed file
furi_string_set(file_path, full_file_path);
}
}

success = true;
} else {
FURI_LOG_E(TAG, "Save error");
success = false;
FlipperFormat* ff = NULL;
if(error_message == NULL) {
FURI_LOG_I(TAG, "Saving Barcode to: %s", furi_string_get_cstr(full_file_path));
ff = flipper_format_file_alloc(storage);

//open_new fails on existing files as a backstop to the check above
bool file_saved =
mode == NewMode ?
flipper_format_file_open_new(ff, furi_string_get_cstr(full_file_path)) :
flipper_format_file_open_always(ff, furi_string_get_cstr(full_file_path));
if(file_saved) {
// Filetype: Barcode
// Version: 1

// # Types - UPC-A, EAN-8, EAN-13, CODE-39, CODE-128, Codabar
// Type: CODE-39
// Data: AB
file_saved =
flipper_format_write_string_cstr(ff, "Filetype", "Barcode") &&
flipper_format_write_string_cstr(ff, "Version", FILE_VERSION) &&
flipper_format_write_comment_cstr(
ff, "Types - UPC-A, EAN-8, EAN-13, CODE-39, CODE-128, Codabar") &&
flipper_format_write_string_cstr(ff, "Type", barcode_type->name) &&
flipper_format_write_string_cstr(ff, "Data", furi_string_get_cstr(barcode_data));
if(!file_saved) {
//the file may be partially written, e.g. if the SD card was removed mid-save
FURI_LOG_E(TAG, "Could not write the barcode file");
}
} else {
FURI_LOG_E(TAG, "Could not open file %s", furi_string_get_cstr(full_file_path));
}
if(!file_saved) {
error_message = "A saving error\nhas occurred";
}
}

furi_string_free(full_file_path);
flipper_format_free(ff);
if(ff != NULL) {
flipper_format_free(ff);
}
furi_record_close(RECORD_STORAGE);

with_view_model(
create_view_object->barcode_app->message_view->view,
MessageViewModel * model,
{
if(success) {
model->message = "File Saved!";
} else {
model->message = "A saving error has occurred";
}
},
true);

view_dispatcher_switch_to_view(
create_view_object->barcode_app->view_dispatcher, MessageErrorView);
if(error_message == NULL) {
message_view_show(message_view, "File Saved!", MainMenuView);
} else {
//go back to the create view so the entered data is not lost
message_view_show(message_view, error_message, CreateBarcodeView);
}
}

void create_view_free(CreateView* create_view_object) {
Expand Down
44 changes: 35 additions & 9 deletions base_pack/barcode_gen/views/message_view.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ static void app_draw_callback(Canvas* canvas, void* ctx) {

canvas_clear(canvas);
if(message_view_model->message != NULL) {
canvas_draw_str_aligned(
elements_multiline_text_aligned(
canvas, 62, 30, AlignCenter, AlignCenter, message_view_model->message);
}

Expand All @@ -23,15 +23,18 @@ static bool app_input_callback(InputEvent* input_event, void* ctx) {

MessageView* message_view_object = ctx;

if(input_event->key == InputKeyBack) {
bool dismissed = input_event->type == InputTypeShort &&
(input_event->key == InputKeyBack || input_event->key == InputKeyOk);

if(dismissed) {
uint32_t next_view;
with_view_model(
message_view_object->view,
MessageViewModel * model,
{ next_view = model->next_view; },
false);
view_dispatcher_switch_to_view(
message_view_object->barcode_app->view_dispatcher, MainMenuView);
}
if(input_event->type == InputTypeShort) {
if(input_event->key == InputKeyOk) {
view_dispatcher_switch_to_view(
message_view_object->barcode_app->view_dispatcher, MainMenuView);
}
message_view_object->barcode_app->view_dispatcher, next_view);
}

return true;
Expand All @@ -50,9 +53,32 @@ MessageView* message_view_allocate(BarcodeApp* barcode_app) {
view_set_draw_callback(message_view_object->view, app_draw_callback);
view_set_input_callback(message_view_object->view, app_input_callback);

//safe default in case a caller sets a message without a next_view
with_view_model(
message_view_object->view,
MessageViewModel * model,
{ model->next_view = MainMenuView; },
false);

return message_view_object;
}

void message_view_show(MessageView* message_view_object, const char* message, uint32_t next_view) {
furi_assert(message_view_object);

with_view_model(
message_view_object->view,
MessageViewModel * model,
{
model->message = message;
model->next_view = next_view;
},
true);

view_dispatcher_switch_to_view(
message_view_object->barcode_app->view_dispatcher, MessageErrorView);
}

void message_view_free(MessageView* message_view_object) {
furi_assert(message_view_object);

Expand Down
Loading
Loading