cogs-mykey-public/scenes/cogs_mikai_scene_set_credit.c

194 lines
7.0 KiB
C

#include "../cogs_mikai.h"
#include <furi_hal_rtc.h>
enum {
SetCreditSceneEventInput,
};
static bool cogs_mikai_scene_set_credit_validator(const char* text, FuriString* error, void* context) {
UNUSED(context);
if(strlen(text) == 0) {
return true;
}
bool has_decimal = false;
for(size_t i = 0; text[i] != '\0'; i++) {
if(text[i] == '.' || text[i] == ',') {
if(has_decimal) {
furi_string_set(error, "Only one decimal point");
return false;
}
has_decimal = true;
} else if(text[i] < '0' || text[i] > '9') {
furi_string_set(error, "Only numbers and '.'");
return false;
}
}
return true;
}
static bool parse_euros_to_cents(const char* text, uint16_t* cents) {
if(!text || !cents) return false;
uint32_t integer_part = 0;
uint32_t decimal_part = 0;
uint32_t decimal_digits = 0;
bool in_decimal = false;
for(size_t i = 0; text[i] != '\0'; i++) {
if(text[i] == '.' || text[i] == ',') {
in_decimal = true;
} else if(text[i] >= '0' && text[i] <= '9') {
if(in_decimal) {
if(decimal_digits < 2) {
decimal_part = decimal_part * 10 + (text[i] - '0');
decimal_digits++;
}
} else {
integer_part = integer_part * 10 + (text[i] - '0');
}
}
}
if(decimal_digits == 1) {
decimal_part *= 10;
}
uint32_t total_cents = integer_part * 100 + decimal_part;
if(total_cents > 99999) return false; // Max 999.99 EUR
*cents = (uint16_t)total_cents;
return true;
}
static void cogs_mikai_scene_set_credit_text_input_callback(void* context) {
COGSMyKaiApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, SetCreditSceneEventInput);
}
static void cogs_mikai_scene_set_credit_popup_callback(void* context) {
COGSMyKaiApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, 0);
}
void cogs_mikai_scene_set_credit_on_enter(void* context) {
COGSMyKaiApp* app = context;
if(!app->mykey.is_loaded) {
Popup* popup = app->popup;
popup_set_header(popup, "Error", 64, 10, AlignCenter, AlignTop);
popup_set_text(popup, "No card loaded\nRead a card first", 64, 25, AlignCenter, AlignTop);
popup_set_callback(popup, cogs_mikai_scene_set_credit_popup_callback);
popup_set_context(popup, app);
popup_set_timeout(popup, 2000);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(app->view_dispatcher, COGSMyKaiViewPopup);
return;
}
TextInput* text_input = app->text_input;
snprintf(app->text_buffer, sizeof(app->text_buffer), "10.00");
text_input_set_header_text(text_input, "Set Credit (EUR)");
text_input_set_validator(text_input, cogs_mikai_scene_set_credit_validator, NULL);
text_input_set_result_callback(
text_input,
cogs_mikai_scene_set_credit_text_input_callback,
app,
app->text_buffer,
sizeof(app->text_buffer),
false);
view_dispatcher_switch_to_view(app->view_dispatcher, COGSMyKaiViewTextInput);
}
bool cogs_mikai_scene_set_credit_on_event(void* context, SceneManagerEvent event) {
COGSMyKaiApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SetCreditSceneEventInput) {
if(app->text_buffer[0] == '\0') {
FURI_LOG_W(TAG, "Ignoring empty text_buffer (already processed)");
consumed = true;
return consumed;
}
FURI_LOG_I(TAG, "Set credit input: '%s'", app->text_buffer);
uint16_t cents = 0;
bool parse_ok = parse_euros_to_cents(app->text_buffer, &cents);
FURI_LOG_I(TAG, "Parse result: %d, cents: %d", parse_ok, cents);
if(parse_ok) {
FURI_LOG_I(TAG, "Valid amount: %d cents", cents);
DateTime datetime;
furi_hal_rtc_get_datetime(&datetime);
bool success = mykey_set_cents(
&app->mykey,
cents,
datetime.day,
datetime.month,
datetime.year - 2000);
if(success) {
app->mykey.current_credit = mykey_get_current_credit(&app->mykey);
text_input_reset(app->text_input);
memset(app->text_buffer, 0, sizeof(app->text_buffer));
Popup* popup = app->popup;
popup_set_header(popup, "Credit Set!", 64, 10, AlignCenter, AlignTop);
popup_set_text(popup, "Saved in memory\nUse 'Write to Card'", 64, 25, AlignCenter, AlignTop);
popup_set_callback(popup, cogs_mikai_scene_set_credit_popup_callback);
popup_set_context(popup, app);
popup_set_timeout(popup, 2000);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(app->view_dispatcher, COGSMyKaiViewPopup);
notification_message(app->notifications, &sequence_success);
} else {
Popup* popup = app->popup;
popup_set_header(popup, "Error", 64, 10, AlignCenter, AlignTop);
popup_set_text(popup, "Failed to set credit", 64, 25, AlignCenter, AlignTop);
popup_set_callback(popup, cogs_mikai_scene_set_credit_popup_callback);
popup_set_context(popup, app);
popup_set_timeout(popup, 2000);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(app->view_dispatcher, COGSMyKaiViewPopup);
notification_message(app->notifications, &sequence_error);
}
} else {
FURI_LOG_E(TAG, "Invalid amount: parse_ok=%d, cents=%d",
parse_ok, cents);
Popup* popup = app->popup;
popup_set_header(popup, "Error", 64, 10, AlignCenter, AlignTop);
popup_set_text(
popup,
"Invalid amount\nEnter 0.00-999.99",
64,
25,
AlignCenter,
AlignTop);
popup_set_callback(popup, cogs_mikai_scene_set_credit_popup_callback);
popup_set_context(popup, app);
popup_set_timeout(popup, 2000);
popup_enable_timeout(popup);
view_dispatcher_switch_to_view(app->view_dispatcher, COGSMyKaiViewPopup);
}
consumed = true;
} else {
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, COGSMyKaiSceneStart);
consumed = true;
}
}
return consumed;
}
void cogs_mikai_scene_set_credit_on_exit(void* context) {
COGSMyKaiApp* app = context;
text_input_reset(app->text_input);
popup_reset(app->popup);
}