diff --git a/images/left_8x15.png b/images/left_8x15.png new file mode 100644 index 0000000..4b26682 Binary files /dev/null and b/images/left_8x15.png differ diff --git a/images/right_8x15.png b/images/right_8x15.png new file mode 100644 index 0000000..5d470a1 Binary files /dev/null and b/images/right_8x15.png differ diff --git a/voyah_pass.c b/voyah_pass.c index edf247c..e3cc985 100644 --- a/voyah_pass.c +++ b/voyah_pass.c @@ -24,7 +24,24 @@ bool voyah_pass_read_tz(VoyahPassTZ* tz) { const size_t tz_size = sizeof(VoyahPassTZ); bool result = storage_file_open(file, VOYAH_PASS_TZ_FILE, FSAM_READ, FSOM_OPEN_EXISTING); - result = result || storage_file_read(file, tz, tz_size) == tz_size; + result = result && storage_file_read(file, tz, tz_size) == tz_size; + + storage_file_close(file); + storage_file_free(file); + furi_record_close(RECORD_STORAGE); + + return result; +} + +bool voyah_pass_write_tz(VoyahPassTZ* tz) { + furi_check(tz); + + Storage* storage = furi_record_open(RECORD_STORAGE); + File* file = storage_file_alloc(storage); + const size_t tz_size = sizeof(VoyahPassTZ); + + bool result = storage_file_open(file, VOYAH_PASS_TZ_FILE, FSAM_WRITE, FSOM_CREATE_ALWAYS); + result = result && storage_file_write(file, tz, tz_size) == tz_size; storage_file_close(file); storage_file_free(file); @@ -39,7 +56,7 @@ void voyah_pass_set_tz_button(Canvas* canvas, const VoyahPassTZ* tz) { if(tz == NULL) { elements_button_right(canvas, "Set TZ"); } else { - FuriString* tz_str = furi_string_alloc_printf("%+02d:%02d", tz->hours, tz->minutes); + FuriString* tz_str = furi_string_alloc_printf("%+03d:%02d", tz->hours, tz->minutes); elements_button_right(canvas, furi_string_get_cstr(tz_str)); furi_string_free(tz_str); } @@ -87,23 +104,127 @@ void voyah_pass_print_password(Canvas* canvas, int32_t x, int32_t y, const Voyah furi_string_free(password); } +void voyah_pass_draw_dialog(Canvas* canvas, const VoyahPassTZ* tz, VoyahPassApp* app) { + const int8_t hours = tz == NULL ? 0 : tz->hours; + const uint8_t minutes = tz == NULL ? 0 : tz->minutes; + + elements_text_box( + canvas, + 0, + 0, + canvas_width(canvas), + canvas_height(canvas), + AlignCenter, + AlignTop, + "Set your timezone", + false); + + FuriString* str_hours = furi_string_alloc_printf("%+03d", hours); + FuriString* str_minutes = furi_string_alloc_printf("%02d", minutes); + + canvas_set_font(canvas, FontBigNumbers); + canvas_set_color(canvas, ColorXOR); + + FuriString* str = furi_string_alloc_set(str_hours); + furi_string_cat_str(str, ":"); + furi_string_cat(str, str_minutes); + + const size_t w_str = canvas_string_width(canvas, furi_string_get_cstr(str)); + const size_t font_h = canvas_current_font_height(canvas); + const int32_t x = (canvas_width(canvas) - w_str) / 2; + const int32_t y = canvas_height(canvas) / 2 + 4; + const uint16_t padding = 3; + uint16_t h_width; + int32_t x_box; + + if(app->sel_pos == 1) { + x_box = x + canvas_string_width(canvas, furi_string_get_cstr(str_hours)) + + canvas_glyph_width(canvas, ':') + 1; + h_width = canvas_string_width(canvas, furi_string_get_cstr(str_minutes)); + } else { + h_width = canvas_string_width(canvas, furi_string_get_cstr(str_hours)); + x_box = x; + } + + canvas_draw_box( + canvas, x_box - padding, y - font_h, h_width + padding * 2, font_h + padding * 2); + + canvas_draw_str(canvas, x, y, furi_string_get_cstr(str)); + + furi_string_free(str_minutes); + furi_string_free(str_hours); + furi_string_free(str); + + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontSecondary); + + const int32_t icon_padding = 10; + const int32_t x_right = x + w_str + icon_padding; + const int32_t x_left = x - icon_get_width(&I_left_8x15) - icon_padding; + + canvas_draw_icon(canvas, x_right, y - icon_get_height(&I_right_8x15) + 1, &I_right_8x15); + canvas_draw_icon(canvas, x_left, y - icon_get_height(&I_left_8x15) + 1, &I_left_8x15); + + elements_button_center(canvas, "Set"); +} + +void voyah_pass_init_tz(VoyahPassApp* app) { + if(app->tz == NULL) { + app->tz = malloc(sizeof(VoyahPassTZ)); + } +} + +void voyah_pass_up_pressed(VoyahPassApp* app) { + furi_check(app->tz); + + switch(app->sel_pos) { + case 0: + if(++app->tz->hours > VOYAH_PASS_MAX_TZ) app->tz->hours = VOYAH_PASS_MAX_TZ; + break; + + default: + app->tz->minutes = app->tz->minutes == 60 - 15 ? 00 : app->tz->minutes + 15; + break; + } +} + +void voyah_pass_down_pressed(VoyahPassApp* app) { + furi_check(app->tz); + + switch(app->sel_pos) { + case 0: + if(--app->tz->hours < VOYAH_PASS_MIN_TZ) app->tz->hours = VOYAH_PASS_MIN_TZ; + break; + + default: + app->tz->minutes = app->tz->minutes == 0 ? 60 - 15 : app->tz->minutes - 15; + break; + } +} + void voyah_pass_render_callback(Canvas* canvas, void* ctx) { + furi_check(ctx); + canvas_set_color(canvas, ColorBlack); canvas_clear(canvas); + canvas_set_font(canvas, FontSecondary); + const VoyahPassTZ* tz = ((VoyahPassApp*)ctx)->tz; - const uint16_t y = (canvas_height(canvas) - icon_get_height(&I_logo_38x54)) / 2; - canvas_draw_icon(canvas, 0, y, &I_logo_38x54); + if(((VoyahPassApp*)ctx)->state == DialogState) { + voyah_pass_draw_dialog(canvas, tz, (VoyahPassApp*)ctx); + } else { + const uint16_t y = (canvas_height(canvas) - icon_get_height(&I_logo_38x54)) / 2; + canvas_draw_icon(canvas, 0, y, &I_logo_38x54); - const size_t font_height = canvas_current_font_height(canvas); + const size_t font_height = canvas_current_font_height(canvas); - const uint16_t x = icon_get_width(&I_logo_38x54) + 5; + const uint16_t x = icon_get_width(&I_logo_38x54) + 5; - voyah_pass_set_tz_button(canvas, tz); - canvas_draw_str( - canvas, x, y + font_height, tz == NULL ? "Today's passwords:" : "Today's password:"); - voyah_pass_print_password(canvas, x, y + font_height * 2.5, tz); + canvas_draw_str( + canvas, x, y + font_height, tz == NULL ? "Today's passwords:" : "Today's password:"); + voyah_pass_print_password(canvas, x, y + font_height * 2.5, tz); - if(((VoyahPassApp*)ctx)->state == DialogState) { + voyah_pass_set_tz_button(canvas, tz); } } @@ -114,6 +235,15 @@ static void voyah_pass_input_callback(InputEvent* input_event, void* ctx) { VoyahPassApp* voyah_pass_app_alloc() { VoyahPassApp* app = malloc(sizeof(VoyahPassApp)); + app->state = InitialState; + app->sel_pos = 0; + + voyah_pass_init_tz(app); + if(!voyah_pass_read_tz(app->tz)) { + free(app->tz); + app->tz = NULL; + } + app->view_port = view_port_alloc(); view_port_draw_callback_set(app->view_port, voyah_pass_render_callback, app); app->gui = furi_record_open(RECORD_GUI); @@ -122,14 +252,6 @@ VoyahPassApp* voyah_pass_app_alloc() { app->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); view_port_input_callback_set(app->view_port, voyah_pass_input_callback, app->event_queue); - app->state = InitialState; - - app->tz = malloc(sizeof(VoyahPassTZ)); - if(!voyah_pass_read_tz(app->tz)) { - free(app->tz); - app->tz = NULL; - } - return app; } @@ -154,25 +276,61 @@ int32_t voyah_pass_main(void* p) { furi_message_queue_get(app->event_queue, &event, FuriWaitForever) == FuriStatusOk); if(event.type == InputTypeShort) { - switch(event.key) { - case InputKeyBack: - if(app->state == InitialState) { - return 0; - } else { + if(app->state == DialogState) { + switch(event.key) { + case InputKeyRight: + case InputKeyLeft: + app->sel_pos = 1 - app->sel_pos; + break; + + case InputKeyBack: app->state = InitialState; + if(app->tz_backup == NULL) { + free(app->tz); + app->tz = NULL; + } else { + memcpy(app->tz, app->tz_backup, sizeof(VoyahPassTZ)); + free(app->tz_backup); + } + break; + + case InputKeyUp: + voyah_pass_up_pressed(app); + break; + + case InputKeyDown: + voyah_pass_down_pressed(app); + break; + + case InputKeyOk: + app->state = InitialState; + voyah_pass_write_tz(app->tz); + break; + + default: + break; } - break; + } else { + switch(event.key) { + case InputKeyBack: + return 0; + break; - case InputKeyRight: - if(app->state == InitialState) { + case InputKeyRight: app->state = DialogState; + if(app->tz == NULL) { + app->tz_backup = NULL; + } else { + app->tz_backup = malloc(sizeof(VoyahPassTZ)); + memcpy(app->tz_backup, app->tz, sizeof(VoyahPassTZ)); + } + voyah_pass_init_tz(app); + break; + + default: + break; } - break; - - default: - break; } - view_port_update(app->view_port); } } diff --git a/voyah_pass.h b/voyah_pass.h index 5d986d2..95498a9 100644 --- a/voyah_pass.h +++ b/voyah_pass.h @@ -5,15 +5,18 @@ #include #include #include -#include #include #define VOYAH_PASS_TZ_FILE APP_DATA_PATH("tz.bin") +#define VOYAH_PASS_MAX_TZ 14 +#define VOYAH_PASS_MIN_TZ -12 -#if defined __has_include && __has_include("voyah_pass_icons.h") +#if __has_include("voyah_pass_icons.h") #include "voyah_pass_icons.h" #else extern const Icon I_logo_38x54; +extern const Icon I_right_8x15; +extern const Icon I_left_8x15; #endif #define DESTRUCT(func) __attribute__((__cleanup__(func))) __auto_type @@ -32,6 +35,7 @@ typedef struct { Gui* gui; ViewPort* view_port; FuriMessageQueue* event_queue; - VoyahPassTZ* tz; + VoyahPassTZ *tz, *tz_backup; VoyahPassState state; + uint8_t sel_pos; } VoyahPassApp;