mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-12-18 16:53:45 +00:00
494 lines
No EOL
16 KiB
C
494 lines
No EOL
16 KiB
C
#include "../barcode_app.h"
|
|
#include "create_view.h"
|
|
#include <math.h>
|
|
|
|
#define LINE_HEIGHT 16
|
|
#define TEXT_PADDING 4
|
|
#define TOTAL_MENU_ITEMS 5
|
|
|
|
typedef enum {
|
|
TypeMenuItem,
|
|
FileNameMenuItem,
|
|
BarcodeDataMenuItem,
|
|
SaveMenuButton,
|
|
DeleteMenuButton
|
|
} MenuItems;
|
|
|
|
/**
|
|
* Took this function from blackjack
|
|
* @author @teeebor
|
|
*/
|
|
void draw_menu_item(
|
|
Canvas* const canvas,
|
|
const char* text,
|
|
const char* value,
|
|
int y,
|
|
bool left_caret,
|
|
bool right_caret,
|
|
bool selected) {
|
|
UNUSED(selected);
|
|
if(y < 0 || y >= 64) {
|
|
return;
|
|
}
|
|
|
|
if(selected) {
|
|
canvas_set_color(canvas, ColorBlack);
|
|
canvas_draw_box(canvas, 0, y, 123, LINE_HEIGHT);
|
|
canvas_set_color(canvas, ColorWhite);
|
|
}
|
|
|
|
canvas_draw_str_aligned(canvas, 4, y + TEXT_PADDING, AlignLeft, AlignTop, text);
|
|
if(left_caret) {
|
|
canvas_draw_str_aligned(canvas, 60, y + TEXT_PADDING, AlignLeft, AlignTop, "<");
|
|
}
|
|
|
|
canvas_draw_str_aligned(canvas, 90, y + TEXT_PADDING, AlignCenter, AlignTop, value);
|
|
if(right_caret) {
|
|
canvas_draw_str_aligned(canvas, 120, y + TEXT_PADDING, AlignRight, AlignTop, ">");
|
|
}
|
|
|
|
canvas_set_color(canvas, ColorBlack);
|
|
}
|
|
|
|
void draw_button(Canvas* const canvas, const char* text, int y, bool selected) {
|
|
if(selected) {
|
|
canvas_set_color(canvas, ColorBlack);
|
|
canvas_draw_box(canvas, 0, y, 123, LINE_HEIGHT);
|
|
canvas_set_color(canvas, ColorWhite);
|
|
}
|
|
|
|
canvas_draw_str_aligned(canvas, 64, y + TEXT_PADDING, AlignCenter, AlignTop, text);
|
|
|
|
canvas_set_color(canvas, ColorBlack);
|
|
}
|
|
|
|
static void app_draw_callback(Canvas* canvas, void* ctx) {
|
|
furi_assert(ctx);
|
|
|
|
CreateViewModel* create_view_model = ctx;
|
|
|
|
BarcodeTypeObj* type_obj = create_view_model->barcode_type;
|
|
if(create_view_model->barcode_type == NULL) {
|
|
return;
|
|
}
|
|
BarcodeType selected_type = type_obj->type;
|
|
|
|
int selected_menu_item = create_view_model->selected_menu_item;
|
|
|
|
int total_menu_items = create_view_model->mode == EditMode ? TOTAL_MENU_ITEMS :
|
|
TOTAL_MENU_ITEMS - 1;
|
|
|
|
int startY = 0;
|
|
|
|
//the menu items index that is/would be in view
|
|
//int current_last_menu_item = selected_menu_item + 3;
|
|
if(selected_menu_item > 1) {
|
|
int offset = 2;
|
|
if(selected_menu_item + offset > total_menu_items) {
|
|
offset = 3;
|
|
}
|
|
startY -= (LINE_HEIGHT * (selected_menu_item - offset));
|
|
}
|
|
|
|
//ensure that the scroll height is atleast 1
|
|
int scrollHeight = ceil(64.0 / total_menu_items);
|
|
int scrollPos = scrollHeight * selected_menu_item;
|
|
|
|
canvas_set_color(canvas, ColorBlack);
|
|
//draw the scroll bar box
|
|
canvas_draw_box(canvas, 125, scrollPos, 3, scrollHeight);
|
|
//draw the scroll bar track
|
|
canvas_draw_box(canvas, 126, 0, 1, 64);
|
|
|
|
draw_menu_item(
|
|
canvas,
|
|
"Type",
|
|
type_obj->name,
|
|
TypeMenuItem * LINE_HEIGHT + startY,
|
|
selected_type > 0,
|
|
selected_type < NUMBER_OF_BARCODE_TYPES - 2,
|
|
selected_menu_item == TypeMenuItem);
|
|
|
|
draw_menu_item(
|
|
canvas,
|
|
"Name",
|
|
furi_string_empty(create_view_model->file_name) ?
|
|
"--" :
|
|
furi_string_get_cstr(create_view_model->file_name),
|
|
FileNameMenuItem * LINE_HEIGHT + startY,
|
|
false,
|
|
false,
|
|
selected_menu_item == FileNameMenuItem);
|
|
|
|
draw_menu_item(
|
|
canvas,
|
|
"Data",
|
|
furi_string_empty(create_view_model->barcode_data) ?
|
|
"--" :
|
|
furi_string_get_cstr(create_view_model->barcode_data),
|
|
BarcodeDataMenuItem * LINE_HEIGHT + startY,
|
|
false,
|
|
false,
|
|
selected_menu_item == BarcodeDataMenuItem);
|
|
|
|
draw_button(
|
|
canvas,
|
|
"Save",
|
|
SaveMenuButton * LINE_HEIGHT + startY,
|
|
selected_menu_item == SaveMenuButton);
|
|
|
|
if(create_view_model->mode == EditMode) {
|
|
draw_button(
|
|
canvas,
|
|
"Delete",
|
|
DeleteMenuButton * LINE_HEIGHT + startY,
|
|
selected_menu_item == DeleteMenuButton);
|
|
}
|
|
}
|
|
|
|
void text_input_callback(void* ctx) {
|
|
CreateView* create_view_object = ctx;
|
|
|
|
with_view_model(
|
|
create_view_object->view,
|
|
CreateViewModel * model,
|
|
{
|
|
if(create_view_object->setter == FileNameSetter) {
|
|
furi_string_set_str(model->file_name, create_view_object->input);
|
|
}
|
|
if(create_view_object->setter == BarcodeDataSetter) {
|
|
furi_string_set_str(model->barcode_data, create_view_object->input);
|
|
}
|
|
},
|
|
true);
|
|
|
|
view_dispatcher_switch_to_view(
|
|
create_view_object->barcode_app->view_dispatcher, CreateBarcodeView);
|
|
}
|
|
|
|
static bool app_input_callback(InputEvent* input_event, void* ctx) {
|
|
furi_assert(ctx);
|
|
|
|
if(input_event->key == InputKeyBack) {
|
|
return false;
|
|
}
|
|
|
|
CreateView* create_view_object = ctx;
|
|
|
|
//get the currently selected menu item from the model
|
|
int selected_menu_item = 0;
|
|
BarcodeTypeObj* barcode_type = NULL;
|
|
FuriString* file_name;
|
|
FuriString* barcode_data;
|
|
CreateMode mode;
|
|
|
|
with_view_model(
|
|
create_view_object->view,
|
|
CreateViewModel * model,
|
|
{
|
|
selected_menu_item = model->selected_menu_item;
|
|
barcode_type = model->barcode_type;
|
|
file_name = model->file_name;
|
|
barcode_data = model->barcode_data;
|
|
mode = model->mode;
|
|
},
|
|
true);
|
|
|
|
int total_menu_items = mode == EditMode ? TOTAL_MENU_ITEMS : TOTAL_MENU_ITEMS - 1;
|
|
|
|
if(input_event->type == InputTypePress) {
|
|
if(input_event->key == InputKeyUp && selected_menu_item > 0) {
|
|
selected_menu_item--;
|
|
} else if(input_event->key == InputKeyDown && selected_menu_item < total_menu_items - 1) {
|
|
selected_menu_item++;
|
|
} else if(input_event->key == InputKeyLeft) {
|
|
if(selected_menu_item == TypeMenuItem && barcode_type != NULL) { //Select Barcode Type
|
|
if(barcode_type->type > 0) {
|
|
barcode_type = barcode_type_objs[barcode_type->type - 1];
|
|
}
|
|
}
|
|
} else if(input_event->key == InputKeyRight) {
|
|
if(selected_menu_item == TypeMenuItem && barcode_type != NULL) { //Select Barcode Type
|
|
if(barcode_type->type < NUMBER_OF_BARCODE_TYPES - 2) {
|
|
barcode_type = barcode_type_objs[barcode_type->type + 1];
|
|
}
|
|
}
|
|
} else if(input_event->key == InputKeyOk) {
|
|
if(selected_menu_item == FileNameMenuItem && barcode_type != NULL) {
|
|
create_view_object->setter = FileNameSetter;
|
|
|
|
snprintf(
|
|
create_view_object->input,
|
|
sizeof(create_view_object->input),
|
|
"%s",
|
|
furi_string_get_cstr(file_name));
|
|
|
|
text_input_set_result_callback(
|
|
create_view_object->barcode_app->text_input,
|
|
text_input_callback,
|
|
create_view_object,
|
|
create_view_object->input,
|
|
TEXT_BUFFER_SIZE - BARCODE_EXTENSION_LENGTH, //remove the barcode length
|
|
//clear default text
|
|
false);
|
|
text_input_set_header_text(
|
|
create_view_object->barcode_app->text_input, "File Name");
|
|
|
|
view_dispatcher_switch_to_view(
|
|
create_view_object->barcode_app->view_dispatcher, TextInputView);
|
|
}
|
|
if(selected_menu_item == BarcodeDataMenuItem && barcode_type != NULL) {
|
|
create_view_object->setter = BarcodeDataSetter;
|
|
|
|
snprintf(
|
|
create_view_object->input,
|
|
sizeof(create_view_object->input),
|
|
"%s",
|
|
furi_string_get_cstr(barcode_data));
|
|
|
|
text_input_set_result_callback(
|
|
create_view_object->barcode_app->text_input,
|
|
text_input_callback,
|
|
create_view_object,
|
|
create_view_object->input,
|
|
TEXT_BUFFER_SIZE,
|
|
//clear default text
|
|
false);
|
|
text_input_set_header_text(
|
|
create_view_object->barcode_app->text_input, "Barcode Data");
|
|
|
|
view_dispatcher_switch_to_view(
|
|
create_view_object->barcode_app->view_dispatcher, TextInputView);
|
|
}
|
|
if(selected_menu_item == SaveMenuButton && barcode_type != NULL) {
|
|
save_barcode(create_view_object);
|
|
}
|
|
if(selected_menu_item == DeleteMenuButton && barcode_type != NULL) {
|
|
if(mode == EditMode) {
|
|
remove_barcode(create_view_object);
|
|
} else if(mode == NewMode) {
|
|
view_dispatcher_switch_to_view(
|
|
create_view_object->barcode_app->view_dispatcher, MainMenuView);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//change the currently selected menu item
|
|
with_view_model(
|
|
create_view_object->view,
|
|
CreateViewModel * model,
|
|
{
|
|
model->selected_menu_item = selected_menu_item;
|
|
model->barcode_type = barcode_type;
|
|
},
|
|
true);
|
|
|
|
return true;
|
|
}
|
|
|
|
CreateView* create_view_allocate(BarcodeApp* barcode_app) {
|
|
furi_assert(barcode_app);
|
|
|
|
CreateView* create_view_object = malloc(sizeof(CreateView));
|
|
|
|
create_view_object->view = view_alloc();
|
|
create_view_object->barcode_app = barcode_app;
|
|
|
|
view_set_context(create_view_object->view, create_view_object);
|
|
view_allocate_model(create_view_object->view, ViewModelTypeLocking, sizeof(CreateViewModel));
|
|
view_set_draw_callback(create_view_object->view, app_draw_callback);
|
|
view_set_input_callback(create_view_object->view, app_input_callback);
|
|
|
|
return create_view_object;
|
|
}
|
|
|
|
void create_view_free_model(CreateView* create_view_object) {
|
|
with_view_model(
|
|
create_view_object->view,
|
|
CreateViewModel * model,
|
|
{
|
|
if(model->file_path != NULL) {
|
|
furi_string_free(model->file_path);
|
|
}
|
|
if(model->file_name != NULL) {
|
|
furi_string_free(model->file_name);
|
|
}
|
|
if(model->barcode_data != NULL) {
|
|
furi_string_free(model->barcode_data);
|
|
}
|
|
},
|
|
true);
|
|
}
|
|
|
|
void remove_barcode(CreateView* create_view_object) {
|
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
|
|
|
bool success = false;
|
|
|
|
with_view_model(
|
|
create_view_object->view,
|
|
CreateViewModel * model,
|
|
{
|
|
FURI_LOG_I(TAG, "Attempting to remove file");
|
|
if(model->file_path != NULL) {
|
|
FURI_LOG_I(TAG, "Removing File: %s", furi_string_get_cstr(model->file_path));
|
|
if(storage_simply_remove(storage, furi_string_get_cstr(model->file_path))) {
|
|
FURI_LOG_I(
|
|
TAG,
|
|
"File: \"%s\" was successfully removed",
|
|
furi_string_get_cstr(model->file_path));
|
|
success = true;
|
|
} else {
|
|
FURI_LOG_E(TAG, "Unable to remove file!");
|
|
success = false;
|
|
}
|
|
} else {
|
|
FURI_LOG_E(TAG, "Could not remove barcode file");
|
|
success = false;
|
|
}
|
|
},
|
|
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);
|
|
}
|
|
|
|
void save_barcode(CreateView* create_view_object) {
|
|
BarcodeTypeObj* barcode_type = NULL;
|
|
FuriString* file_path; //this may be empty
|
|
FuriString* file_name;
|
|
FuriString* barcode_data;
|
|
CreateMode mode;
|
|
|
|
with_view_model(
|
|
create_view_object->view,
|
|
CreateViewModel * model,
|
|
{
|
|
file_path = model->file_path;
|
|
file_name = model->file_name;
|
|
barcode_data = model->barcode_data;
|
|
barcode_type = model->barcode_type;
|
|
mode = model->mode;
|
|
},
|
|
true);
|
|
|
|
if(file_name == NULL || furi_string_empty(file_name)) {
|
|
FURI_LOG_E(TAG, "File Name cannot be empty");
|
|
return;
|
|
}
|
|
if(barcode_data == NULL || furi_string_empty(barcode_data)) {
|
|
FURI_LOG_E(TAG, "Barcode Data cannot be empty");
|
|
return;
|
|
}
|
|
if(barcode_type == NULL) {
|
|
FURI_LOG_E(TAG, "Type not defined");
|
|
return;
|
|
}
|
|
|
|
bool success = false;
|
|
|
|
FuriString* full_file_path = furi_string_alloc_set(DEFAULT_USER_BARCODES);
|
|
furi_string_push_back(full_file_path, '/');
|
|
furi_string_cat(full_file_path, file_name);
|
|
furi_string_cat_str(full_file_path, BARCODE_EXTENSION);
|
|
|
|
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");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|
|
|
|
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));
|
|
|
|
success = true;
|
|
} else {
|
|
FURI_LOG_E(TAG, "Save error");
|
|
success = false;
|
|
}
|
|
furi_string_free(full_file_path);
|
|
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);
|
|
}
|
|
|
|
void create_view_free(CreateView* create_view_object) {
|
|
furi_assert(create_view_object);
|
|
|
|
create_view_free_model(create_view_object);
|
|
view_free(create_view_object->view);
|
|
free(create_view_object);
|
|
}
|
|
|
|
View* create_get_view(CreateView* create_view_object) {
|
|
furi_assert(create_view_object);
|
|
return create_view_object->view;
|
|
} |