Alexander Kopachov 2 лет назад
Родитель
Сommit
1b4673e012

+ 4 - 1
application.fam

@@ -15,7 +15,7 @@ App(
     ],
     stack_size=2 * 1024,
     order=20,
-    fap_version="2.23",
+    fap_version="2.3",
     fap_author="Alexander Kopachov (@akopachov)",
     fap_description="Software-based TOTP authenticator for Flipper Zero device",
     fap_weburl="https://github.com/akopachov/flipper-zero_authenticator",
@@ -38,5 +38,8 @@ App(
         Lib(
             name="roll_value",
         ),
+        Lib(
+            name="fonts",
+        ),
     ],
 )

+ 0 - 19
features_config.h

@@ -34,22 +34,3 @@
 #ifndef TOTP_TARGET_FIRMWARE
 #define TOTP_TARGET_FIRMWARE TOTP_FIRMWARE_OFFICIAL_STABLE
 #endif
-
-// List of available font for TOTP code
-#define TOTP_FONT_MODENINE (1)
-#define TOTP_FONT_REDHATMONO (2)
-#define TOTP_FONT_BEDSTEAD (3)
-#define TOTP_FONT_ZECTOR (4)
-#define TOTP_FONT_712SERIF (5)
-#define TOTP_FONT_GRAPH35PIX (6)
-#define TOTP_FONT_KARMAFUTURE (7)
-#define TOTP_FONT_FUNCLIMBING (8)
-#define TOTP_FONT_DPCOMIC (9)
-#define TOTP_FONT_PIXELFLAG (10)
-
-// End of list
-
-// Active font for TOTP codes
-#ifndef TOTP_FONT
-#define TOTP_FONT TOTP_FONT_MODENINE
-#endif

+ 1 - 0
ui/fonts/712serif/712serif.c → lib/fonts/712serif/712serif.c

@@ -931,6 +931,7 @@ const FONT_CHAR_INFO _712Serif_24ptDescriptors[] = {
 
 /* Font information for 7:12 Serif 24pt */
 const FONT_INFO _712Serif_24ptFontInfo = {
+    "712 Serif",
     14, /*  Character height */
     '-', /*  Start character */
     'Y', /*  End character */

+ 0 - 0
ui/fonts/712serif/712serif.h → lib/fonts/712serif/712serif.h


+ 23 - 0
lib/fonts/available_fonts.c

@@ -0,0 +1,23 @@
+#include "available_fonts.h"
+#include "712serif/712serif.h"
+#include "bedstead/bedstead.h"
+#include "dpcomic/dpcomic.h"
+#include "funclimbing/funclimbing.h"
+#include "graph35pix/graph35pix.h"
+#include "karma_future/karma_future.h"
+#include "mode_nine/mode_nine.h"
+#include "pixelflag/pixelflag.h"
+#include "redhat_mono/redhat_mono.h"
+#include "zector/zector.h"
+
+const FONT_INFO* const available_fonts[AVAILABLE_FONTS_COUNT] = {
+    &modeNine_15ptFontInfo,
+    &_712Serif_24ptFontInfo,
+    &bedstead_17ptFontInfo,
+    &dPComic_18ptFontInfo,
+    &funclimbingDemo_18ptFontInfo,
+    &graph35pix_12ptFontInfo,
+    &karmaFuture_14ptFontInfo,
+    &pixelFlag_18ptFontInfo,
+    &redHatMono_16ptFontInfo,
+    &zector_18ptFontInfo};

+ 7 - 0
lib/fonts/available_fonts.h

@@ -0,0 +1,7 @@
+#pragma once
+
+#include "font_info.h"
+
+#define AVAILABLE_FONTS_COUNT (10)
+
+extern const FONT_INFO* const available_fonts[AVAILABLE_FONTS_COUNT];

+ 1 - 0
ui/fonts/bedstead/bedstead.c → lib/fonts/bedstead/bedstead.c

@@ -1047,6 +1047,7 @@ const FONT_CHAR_INFO bedstead_17ptDescriptors[] = {
 
 /* Font information for Bedstead 17pt */
 const FONT_INFO bedstead_17ptFontInfo = {
+    "Bedstead",
     16, /*  Character height */
     '-', /*  Start character */
     'Y', /*  End character */

+ 0 - 0
ui/fonts/bedstead/bedstead.h → lib/fonts/bedstead/bedstead.h


+ 1 - 0
ui/fonts/dpcomic/dpcomic.c → lib/fonts/dpcomic/dpcomic.c

@@ -1105,6 +1105,7 @@ const FONT_CHAR_INFO dPComic_18ptDescriptors[] = {
 
 /* Font information for DPComic 18pt */
 const FONT_INFO dPComic_18ptFontInfo = {
+    "DP Comic",
     17, /*  Character height */
     '-', /*  Start character */
     'Y', /*  End character */

+ 0 - 0
ui/fonts/dpcomic/dpcomic.h → lib/fonts/dpcomic/dpcomic.h


+ 1 - 1
ui/fonts/font_info.h → lib/fonts/font_info.h

@@ -14,11 +14,11 @@ typedef struct {
 
 // Describes a single font
 typedef struct {
+    const char* name; // Font name
     const uint8_t height; // height, in pages (8 pixels), of the font's characters
     const uint8_t startChar; // the first character in the font (e.g. in charInfo and data)
     const uint8_t endChar; // the last character in the font
     const uint8_t spacePixels; // number of pixels that a space character takes up
     const FONT_CHAR_INFO* charInfo; // pointer to array of char information
     const uint8_t* data; // pointer to generated array of character visual representation
-
 } FONT_INFO;

+ 1 - 0
ui/fonts/funclimbing/funclimbing.c → lib/fonts/funclimbing/funclimbing.c

@@ -1163,6 +1163,7 @@ const FONT_CHAR_INFO funclimbingDemo_18ptDescriptors[] = {
 
 /* Font information for fun climbing (Demo) 18pt */
 const FONT_INFO funclimbingDemo_18ptFontInfo = {
+    "Fun Climbing",
     18, /*  Character height */
     '-', /*  Start character */
     'Y', /*  End character */

+ 0 - 0
ui/fonts/funclimbing/funclimbing.h → lib/fonts/funclimbing/funclimbing.h


+ 1 - 0
ui/fonts/graph35pix/graph35pix.c → lib/fonts/graph35pix/graph35pix.c

@@ -931,6 +931,7 @@ const FONT_CHAR_INFO graph35pix_12ptDescriptors[] = {
 
 /* Font information for Graph 35+ pix 12pt */
 const FONT_INFO graph35pix_12ptFontInfo = {
+    "Graph 35pix",
     14, /*  Character height */
     '-', /*  Start character */
     'Y', /*  End character */

+ 0 - 0
ui/fonts/graph35pix/graph35pix.h → lib/fonts/graph35pix/graph35pix.h


+ 1 - 0
ui/fonts/karma_future/karma_future.c → lib/fonts/karma_future/karma_future.c

@@ -1163,6 +1163,7 @@ const FONT_CHAR_INFO karmaFuture_14ptDescriptors[] = {
 
 /* Font information for Karma Future 14pt */
 const FONT_INFO karmaFuture_14ptFontInfo = {
+    "Karma Future",
     18, /*  Character height */
     '-', /*  Start character */
     'Y', /*  End character */

+ 0 - 0
ui/fonts/karma_future/karma_future.h → lib/fonts/karma_future/karma_future.h


+ 1 - 0
ui/fonts/mode_nine/mode_nine.c → lib/fonts/mode_nine/mode_nine.c

@@ -932,6 +932,7 @@ const FONT_CHAR_INFO modeNine_15ptDescriptors[] = {
 
 /* Font information for ModeNine 15pt */
 const FONT_INFO modeNine_15ptFontInfo = {
+    "Mode Nine",
     14, /*  Character height */
     '-', /*  Start character */
     'Y', /*  End character */

+ 0 - 0
ui/fonts/mode_nine/mode_nine.h → lib/fonts/mode_nine/mode_nine.h


+ 1 - 0
ui/fonts/pixelflag/pixelflag.c → lib/fonts/pixelflag/pixelflag.c

@@ -1105,6 +1105,7 @@ const FONT_CHAR_INFO pixelFlag_18ptDescriptors[] = {
 
 /* Font information for {PixelFlag} 18pt */
 const FONT_INFO pixelFlag_18ptFontInfo = {
+    "Pixel Flag",
     17, /*  Character height */
     '-', /*  Start character */
     'Y', /*  End character */

+ 0 - 0
ui/fonts/pixelflag/pixelflag.h → lib/fonts/pixelflag/pixelflag.h


+ 1 - 0
ui/fonts/redhat_mono/redhat_mono.c → lib/fonts/redhat_mono/redhat_mono.c

@@ -1048,6 +1048,7 @@ const FONT_CHAR_INFO redHatMono_16ptDescriptors[] = {
 
 /* Font information for Red Hat Mono 16pt */
 const FONT_INFO redHatMono_16ptFontInfo = {
+    "RedHat Mono",
     16, /*  Character height */
     '-', /*  Start character */
     'Y', /*  End character */

+ 0 - 0
ui/fonts/redhat_mono/redhat_mono.h → lib/fonts/redhat_mono/redhat_mono.h


+ 1 - 0
ui/fonts/zector/zector.c → lib/fonts/zector/zector.c

@@ -1047,6 +1047,7 @@ const FONT_CHAR_INFO zector_18ptDescriptors[] = {
 
 /* Font information for Zector 18pt */
 const FONT_INFO zector_18ptFontInfo = {
+    "Zector",
     16, /*  Character height */
     '-', /*  Start character */
     'Y', /*  End character */

+ 0 - 0
ui/fonts/zector/zector.h → lib/fonts/zector/zector.h


+ 14 - 0
services/config/config.c

@@ -154,6 +154,9 @@ static bool totp_open_config_file(Storage* storage, FlipperFormat** file) {
         flipper_format_write_uint32(
             fff_data_file, TOTP_CONFIG_KEY_AUTOMATION_METHOD, &tmp_uint32, 1);
 
+        tmp_uint32 = 0;
+        flipper_format_write_uint32(fff_data_file, TOTP_CONFIG_KEY_FONT, &tmp_uint32, 1);
+
         if(!flipper_format_rewind(fff_data_file)) {
             totp_close_config_file(fff_data_file);
             FURI_LOG_E(LOGGING_TAG, "Rewind error");
@@ -257,6 +260,11 @@ bool totp_config_file_update_user_settings(const PluginState* plugin_state) {
             break;
         }
 
+        tmp_uint32 = plugin_state->active_font_index;
+        if(!flipper_format_insert_or_update_uint32(file, TOTP_CONFIG_KEY_FONT, &tmp_uint32, 1)) {
+            break;
+        }
+
         update_result = true;
     } while(false);
 
@@ -405,6 +413,12 @@ bool totp_config_file_load(PluginState* const plugin_state) {
 
         plugin_state->automation_method = tmp_uint32;
 
+        if(!flipper_format_read_uint32(fff_data_file, TOTP_CONFIG_KEY_FONT, &tmp_uint32, 1)) {
+            tmp_uint32 = 0;
+        }
+
+        plugin_state->active_font_index = tmp_uint32;
+
         plugin_state->config_file_context = malloc(sizeof(ConfigFileContext));
         furi_check(plugin_state->config_file_context != NULL);
         plugin_state->config_file_context->storage = storage;

+ 2 - 1
services/config/constants.h

@@ -4,7 +4,7 @@
 
 #define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("authenticator")
 #define CONFIG_FILE_HEADER "Flipper TOTP plugin config file"
-#define CONFIG_FILE_ACTUAL_VERSION (5)
+#define CONFIG_FILE_ACTUAL_VERSION (6)
 
 #define TOTP_CONFIG_KEY_TIMEZONE "Timezone"
 #define TOTP_CONFIG_KEY_TOKEN_NAME "TokenName"
@@ -18,3 +18,4 @@
 #define TOTP_CONFIG_KEY_PINSET "PinIsSet"
 #define TOTP_CONFIG_KEY_NOTIFICATION_METHOD "NotificationMethod"
 #define TOTP_CONFIG_KEY_AUTOMATION_METHOD "AutomationMethod"
+#define TOTP_CONFIG_KEY_FONT "Font"

+ 10 - 0
services/config/migrations/common_migration.c

@@ -58,6 +58,16 @@ bool totp_config_migrate_to_latest(
 
         flipper_format_rewind(fff_backup_data_file);
 
+        if(flipper_format_read_string(fff_backup_data_file, TOTP_CONFIG_KEY_FONT, temp_str)) {
+            flipper_format_write_string(fff_data_file, TOTP_CONFIG_KEY_FONT, temp_str);
+        } else {
+            uint32_t default_font_index = 0;
+            flipper_format_write_uint32(
+                fff_data_file, TOTP_CONFIG_KEY_FONT, &default_font_index, 1);
+        }
+
+        flipper_format_rewind(fff_backup_data_file);
+
         while(true) {
             if(!flipper_format_read_string(
                    fff_backup_data_file, TOTP_CONFIG_KEY_TOKEN_NAME, temp_str)) {

+ 5 - 0
types/plugin_state.h

@@ -105,4 +105,9 @@ typedef struct {
      * @brief IDLE timeout context
      */
     IdleTimeoutContext* idle_timeout_context;
+
+    /**
+     * @brief Font index to be used to draw TOTP token
+     */
+    uint8_t active_font_index;
 } PluginState;

+ 33 - 0
ui/canvas_extensions.c

@@ -0,0 +1,33 @@
+#include "canvas_extensions.h"
+
+void canvas_draw_str_ex(
+    Canvas* canvas,
+    uint8_t x,
+    uint8_t y,
+    const char* text,
+    size_t text_length,
+    const FONT_INFO* const font) {
+    const char* p_ch = text;
+    char ch;
+    size_t i = 0;
+    uint8_t offset_x = x;
+    uint8_t char_width = font->charInfo[0].width;
+    uint8_t offset_x_inc = char_width + font->spacePixels;
+    while(i < text_length && (ch = *p_ch) != 0) {
+        if(ch >= font->startChar && ch <= font->endChar) {
+            uint8_t char_index = ch - font->startChar;
+            canvas_draw_xbm(
+                canvas,
+                offset_x,
+                y,
+                char_width,
+                font->height,
+                &font->data[font->charInfo[char_index].offset]);
+        }
+
+        offset_x += offset_x_inc;
+
+        p_ch++;
+        i++;
+    }
+}

+ 13 - 0
ui/canvas_extensions.h

@@ -0,0 +1,13 @@
+#pragma once
+
+#include <stdint.h>
+#include <gui/gui.h>
+#include <font_info.h>
+
+void canvas_draw_str_ex(
+    Canvas* canvas,
+    uint8_t x,
+    uint8_t y,
+    const char* text,
+    size_t text_length,
+    const FONT_INFO* const font);

+ 0 - 38
ui/fonts/active_font.h

@@ -1,38 +0,0 @@
-#pragma once
-
-#include "../../features_config.h"
-#include "font_info.h"
-
-#if TOTP_FONT == TOTP_FONT_MODENINE
-#include "mode_nine/mode_nine.h"
-#define TOTP_CODE_FONT_INFO modeNine_15ptFontInfo
-#elif TOTP_FONT == TOTP_FONT_REDHATMONO
-#include "redhat_mono/redhat_mono.h"
-#define TOTP_CODE_FONT_INFO redHatMono_16ptFontInfo
-#elif TOTP_FONT == TOTP_FONT_BEDSTEAD
-#include "bedstead/bedstead.h"
-#define TOTP_CODE_FONT_INFO bedstead_17ptFontInfo
-#elif TOTP_FONT == TOTP_FONT_ZECTOR
-#include "zector/zector.h"
-#define TOTP_CODE_FONT_INFO zector_18ptFontInfo
-#elif TOTP_FONT == TOTP_FONT_712SERIF
-#include "712serif/712serif.h"
-#define TOTP_CODE_FONT_INFO _712Serif_24ptFontInfo
-#elif TOTP_FONT == TOTP_FONT_GRAPH35PIX
-#include "graph35pix/graph35pix.h"
-#define TOTP_CODE_FONT_INFO graph35pix_12ptFontInfo
-#elif TOTP_FONT == TOTP_FONT_KARMAFUTURE
-#include "karma_future/karma_future.h"
-#define TOTP_CODE_FONT_INFO karmaFuture_14ptFontInfo
-#elif TOTP_FONT == TOTP_FONT_FUNCLIMBING
-#include "funclimbing/funclimbing.h"
-#define TOTP_CODE_FONT_INFO funclimbingDemo_18ptFontInfo
-#elif TOTP_FONT == TOTP_FONT_DPCOMIC
-#include "dpcomic/dpcomic.h"
-#define TOTP_CODE_FONT_INFO dPComic_18ptFontInfo
-#elif TOTP_FONT == TOTP_FONT_PIXELFLAG
-#include "pixelflag/pixelflag.h"
-#define TOTP_CODE_FONT_INFO pixelFlag_18ptFontInfo
-#else
-#error TOTP Font is not set or unknown
-#endif

+ 87 - 37
ui/scenes/app_settings/totp_app_settings.c

@@ -1,6 +1,8 @@
 #include "totp_app_settings.h"
 #include <math.h>
 #include <totp_icons.h>
+#include <available_fonts.h>
+#include "../../canvas_extensions.h"
 #include "../../ui_controls.h"
 #include "../../common_dialogs.h"
 #include "../../scene_director.h"
@@ -14,17 +16,20 @@
 #include "../../../workers/bt_type_code/bt_type_code.h"
 #endif
 
-char* YES_NO_LIST[] = {"NO", "YES"};
-char* ON_OFF_LIST[] = {"OFF", "ON"};
+static const char* YES_NO_LIST[] = {"NO", "YES"};
+static const char* ON_OFF_LIST[] = {"OFF", "ON"};
+static const char* FONT_TEST_STR = "0123BCD";
+static const uint8_t FONT_TEST_STR_LENGTH = 7;
 
 typedef enum {
     HoursInput,
     MinutesInput,
-    Sound,
-    Vibro,
-    BadUsb,
+    FontSelect,
+    SoundSwitch,
+    VibroSwitch,
+    BadUsbSwitch,
 #ifdef TOTP_BADBT_TYPE_ENABLED
-    BadBt,
+    BadBtSwitch,
 #endif
     ConfirmButton
 } Control;
@@ -40,6 +45,7 @@ typedef struct {
 #endif
     uint8_t y_offset;
     Control selected_control;
+    uint8_t active_font;
 } SceneState;
 
 void totp_scene_app_settings_activate(PluginState* plugin_state) {
@@ -57,6 +63,7 @@ void totp_scene_app_settings_activate(PluginState* plugin_state) {
 #ifdef TOTP_BADBT_TYPE_ENABLED
     scene_state->badbt_enabled = plugin_state->automation_method & AutomationMethodBadBt;
 #endif
+    scene_state->active_font = plugin_state->active_font_index;
 }
 
 static void two_digit_to_str(int8_t num, char* str) {
@@ -109,65 +116,88 @@ void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plu
         SCREEN_HEIGHT - 5 - scene_state->y_offset,
         &I_totp_arrow_bottom_10x5);
 
+    canvas_set_font(canvas, FontPrimary);
+    canvas_draw_str_aligned(canvas, 0, 64 - scene_state->y_offset, AlignLeft, AlignTop, "Font");
+    canvas_set_font(canvas, FontSecondary);
+
+    const FONT_INFO* const font = available_fonts[scene_state->active_font];
+    ui_control_select_render(
+        canvas,
+        0,
+        74 - scene_state->y_offset,
+        SCREEN_WIDTH,
+        font->name,
+        scene_state->selected_control == FontSelect);
+
+    uint8_t font_x_offset =
+        SCREEN_WIDTH_CENTER -
+        (((font->charInfo[0].width + font->spacePixels) * FONT_TEST_STR_LENGTH) >> 1);
+    uint8_t font_y_offset = 108 - scene_state->y_offset - (font->height >> 1);
+    canvas_draw_str_ex(
+        canvas, font_x_offset, font_y_offset, FONT_TEST_STR, FONT_TEST_STR_LENGTH, font);
+
+    canvas_draw_icon(
+        canvas, SCREEN_WIDTH_CENTER - 5, 123 - scene_state->y_offset, &I_totp_arrow_bottom_10x5);
+
     canvas_set_font(canvas, FontPrimary);
     canvas_draw_str_aligned(
-        canvas, 0, 64 - scene_state->y_offset, AlignLeft, AlignTop, "Notifications");
+        canvas, 0, 128 - scene_state->y_offset, AlignLeft, AlignTop, "Notifications");
     canvas_set_font(canvas, FontSecondary);
 
-    canvas_draw_str_aligned(canvas, 0, 81 - scene_state->y_offset, AlignLeft, AlignTop, "Sound:");
+    canvas_draw_str_aligned(canvas, 0, 145 - scene_state->y_offset, AlignLeft, AlignTop, "Sound:");
     ui_control_select_render(
         canvas,
         36,
-        74 - scene_state->y_offset,
+        138 - scene_state->y_offset,
         SCREEN_WIDTH - 36,
         YES_NO_LIST[scene_state->notification_sound],
-        scene_state->selected_control == Sound);
+        scene_state->selected_control == SoundSwitch);
 
-    canvas_draw_str_aligned(canvas, 0, 99 - scene_state->y_offset, AlignLeft, AlignTop, "Vibro:");
+    canvas_draw_str_aligned(canvas, 0, 163 - scene_state->y_offset, AlignLeft, AlignTop, "Vibro:");
     ui_control_select_render(
         canvas,
         36,
-        92 - scene_state->y_offset,
+        156 - scene_state->y_offset,
         SCREEN_WIDTH - 36,
         YES_NO_LIST[scene_state->notification_vibro],
-        scene_state->selected_control == Vibro);
+        scene_state->selected_control == VibroSwitch);
 
     canvas_draw_icon(
-        canvas, SCREEN_WIDTH_CENTER - 5, 123 - scene_state->y_offset, &I_totp_arrow_bottom_10x5);
+        canvas, SCREEN_WIDTH_CENTER - 5, 187 - scene_state->y_offset, &I_totp_arrow_bottom_10x5);
 
     canvas_set_font(canvas, FontPrimary);
     canvas_draw_str_aligned(
-        canvas, 0, 128 - scene_state->y_offset, AlignLeft, AlignTop, "Automation");
+        canvas, 0, 192 - scene_state->y_offset, AlignLeft, AlignTop, "Automation");
     canvas_set_font(canvas, FontSecondary);
 
     canvas_draw_str_aligned(
-        canvas, 0, 145 - scene_state->y_offset, AlignLeft, AlignTop, "BadUSB:");
+        canvas, 0, 209 - scene_state->y_offset, AlignLeft, AlignTop, "BadUSB:");
     ui_control_select_render(
         canvas,
         36,
-        138 - scene_state->y_offset,
+        202 - scene_state->y_offset,
         SCREEN_WIDTH - 36,
         ON_OFF_LIST[scene_state->badusb_enabled],
-        scene_state->selected_control == BadUsb);
+        scene_state->selected_control == BadUsbSwitch);
 
 #ifdef TOTP_BADBT_TYPE_ENABLED
-    canvas_draw_str_aligned(canvas, 0, 163 - scene_state->y_offset, AlignLeft, AlignTop, "BadBT:");
+    canvas_draw_str_aligned(canvas, 0, 227 - scene_state->y_offset, AlignLeft, AlignTop, "BadBT:");
     ui_control_select_render(
         canvas,
         36,
-        156 - scene_state->y_offset,
+        220 - scene_state->y_offset,
         SCREEN_WIDTH - 36,
         ON_OFF_LIST[scene_state->badbt_enabled],
-        scene_state->selected_control == BadBt);
+        scene_state->selected_control == BadBtSwitch);
 #endif
 
     ui_control_button_render(
         canvas,
         SCREEN_WIDTH_CENTER - 24,
 #ifdef TOTP_BADBT_TYPE_ENABLED
-        178 - scene_state->y_offset,
+        242 - scene_state->y_offset,
 #else
-        165 - scene_state->y_offset,
+        229 - scene_state->y_offset,
 #endif
         48,
         13,
@@ -192,10 +222,12 @@ bool totp_scene_app_settings_handle_event(
                 HoursInput,
                 ConfirmButton,
                 RollOverflowBehaviorStop);
-            if(scene_state->selected_control > Vibro) {
-                scene_state->y_offset = 128;
+            if(scene_state->selected_control > VibroSwitch) {
+                scene_state->y_offset = SCREEN_HEIGHT * 3;
+            } else if(scene_state->selected_control > FontSelect) {
+                scene_state->y_offset = SCREEN_HEIGHT * 2;
             } else if(scene_state->selected_control > MinutesInput) {
-                scene_state->y_offset = 64;
+                scene_state->y_offset = SCREEN_HEIGHT;
             } else {
                 scene_state->y_offset = 0;
             }
@@ -207,10 +239,12 @@ bool totp_scene_app_settings_handle_event(
                 HoursInput,
                 ConfirmButton,
                 RollOverflowBehaviorStop);
-            if(scene_state->selected_control > Vibro) {
-                scene_state->y_offset = 128;
+            if(scene_state->selected_control > VibroSwitch) {
+                scene_state->y_offset = SCREEN_HEIGHT * 3;
+            } else if(scene_state->selected_control > FontSelect) {
+                scene_state->y_offset = SCREEN_HEIGHT * 2;
             } else if(scene_state->selected_control > MinutesInput) {
-                scene_state->y_offset = 64;
+                scene_state->y_offset = SCREEN_HEIGHT;
             } else {
                 scene_state->y_offset = 0;
             }
@@ -222,15 +256,22 @@ bool totp_scene_app_settings_handle_event(
             } else if(scene_state->selected_control == MinutesInput) {
                 totp_roll_value_uint8_t(
                     &scene_state->tz_offset_minutes, 15, 0, 45, RollOverflowBehaviorRoll);
-            } else if(scene_state->selected_control == Sound) {
+            } else if(scene_state->selected_control == FontSelect) {
+                totp_roll_value_uint8_t(
+                    &scene_state->active_font,
+                    1,
+                    0,
+                    AVAILABLE_FONTS_COUNT - 1,
+                    RollOverflowBehaviorRoll);
+            } else if(scene_state->selected_control == SoundSwitch) {
                 scene_state->notification_sound = !scene_state->notification_sound;
-            } else if(scene_state->selected_control == Vibro) {
+            } else if(scene_state->selected_control == VibroSwitch) {
                 scene_state->notification_vibro = !scene_state->notification_vibro;
-            } else if(scene_state->selected_control == BadUsb) {
+            } else if(scene_state->selected_control == BadUsbSwitch) {
                 scene_state->badusb_enabled = !scene_state->badusb_enabled;
             }
 #ifdef TOTP_BADBT_TYPE_ENABLED
-            else if(scene_state->selected_control == BadBt) {
+            else if(scene_state->selected_control == BadBtSwitch) {
                 scene_state->badbt_enabled = !scene_state->badbt_enabled;
             }
 #endif
@@ -242,15 +283,22 @@ bool totp_scene_app_settings_handle_event(
             } else if(scene_state->selected_control == MinutesInput) {
                 totp_roll_value_uint8_t(
                     &scene_state->tz_offset_minutes, -15, 0, 45, RollOverflowBehaviorRoll);
-            } else if(scene_state->selected_control == Sound) {
+            } else if(scene_state->selected_control == FontSelect) {
+                totp_roll_value_uint8_t(
+                    &scene_state->active_font,
+                    -1,
+                    0,
+                    AVAILABLE_FONTS_COUNT - 1,
+                    RollOverflowBehaviorRoll);
+            } else if(scene_state->selected_control == SoundSwitch) {
                 scene_state->notification_sound = !scene_state->notification_sound;
-            } else if(scene_state->selected_control == Vibro) {
+            } else if(scene_state->selected_control == VibroSwitch) {
                 scene_state->notification_vibro = !scene_state->notification_vibro;
-            } else if(scene_state->selected_control == BadUsb) {
+            } else if(scene_state->selected_control == BadUsbSwitch) {
                 scene_state->badusb_enabled = !scene_state->badusb_enabled;
             }
 #ifdef TOTP_BADBT_TYPE_ENABLED
-            else if(scene_state->selected_control == BadBt) {
+            else if(scene_state->selected_control == BadBtSwitch) {
                 scene_state->badbt_enabled = !scene_state->badbt_enabled;
             }
 #endif
@@ -281,6 +329,8 @@ bool totp_scene_app_settings_handle_event(
                                                                         AutomationMethodNone;
 #endif
 
+        plugin_state->active_font_index = scene_state->active_font;
+
         if(!totp_config_file_update_user_settings(plugin_state)) {
             totp_dialogs_config_updating_error(plugin_state);
             return false;

+ 16 - 24
ui/scenes/generate_token/totp_scene_generate_token.c

@@ -3,7 +3,9 @@
 #include <notification/notification_messages.h>
 #include <totp_icons.h>
 #include <roll_value.h>
+#include <available_fonts.h>
 #include "totp_scene_generate_token.h"
+#include "../../canvas_extensions.h"
 #include "../../../types/token_info.h"
 #include "../../../types/common.h"
 #include "../../constants.h"
@@ -16,7 +18,6 @@
 #ifdef TOTP_BADBT_TYPE_ENABLED
 #include "../../../workers/bt_type_code/bt_type_code.h"
 #endif
-#include "../../fonts/active_font.h"
 
 #define PROGRESS_BAR_MARGIN (3)
 #define PROGRESS_BAR_HEIGHT (4)
@@ -26,7 +27,6 @@ typedef struct {
     uint8_t progress_bar_width;
     uint8_t code_total_length;
     uint8_t code_offset_x;
-    uint8_t code_offset_x_inc;
     uint8_t code_offset_y;
 } UiPrecalculatedDimensions;
 
@@ -38,6 +38,7 @@ typedef struct {
     FuriMutex* last_code_update_sync;
     TotpGenerateCodeWorkerContext* generate_code_worker_context;
     UiPrecalculatedDimensions ui_precalculated_dimensions;
+    const FONT_INFO* active_font;
 } SceneState;
 
 static const NotificationSequence*
@@ -141,24 +142,14 @@ static void draw_totp_code(Canvas* const canvas, const PluginState* const plugin
     const TokenInfoIteratorContext* iterator_context =
         totp_config_get_token_iterator_context(plugin_state);
     uint8_t code_length = totp_token_info_iterator_get_current_token(iterator_context)->digits;
-    uint8_t offset_x = scene_state->ui_precalculated_dimensions.code_offset_x;
-    uint8_t char_width = TOTP_CODE_FONT_INFO.charInfo[0].width;
-    uint8_t offset_x_inc = scene_state->ui_precalculated_dimensions.code_offset_x_inc;
-    for(uint8_t i = 0; i < code_length; i++) {
-        char ch = scene_state->last_code[i];
-        if(ch >= TOTP_CODE_FONT_INFO.startChar && ch <= TOTP_CODE_FONT_INFO.endChar) {
-            uint8_t char_index = ch - TOTP_CODE_FONT_INFO.startChar;
-            canvas_draw_xbm(
-                canvas,
-                offset_x,
-                scene_state->ui_precalculated_dimensions.code_offset_y,
-                char_width,
-                TOTP_CODE_FONT_INFO.height,
-                &TOTP_CODE_FONT_INFO.data[TOTP_CODE_FONT_INFO.charInfo[char_index].offset]);
-        }
 
-        offset_x += offset_x_inc;
-    }
+    canvas_draw_str_ex(
+        canvas,
+        scene_state->ui_precalculated_dimensions.code_offset_x,
+        scene_state->ui_precalculated_dimensions.code_offset_y,
+        scene_state->last_code,
+        code_length,
+        scene_state->active_font);
 }
 
 static void on_new_token_code_generated(bool time_left, void* context) {
@@ -171,16 +162,15 @@ static void on_new_token_code_generated(bool time_left, void* context) {
 
     SceneState* scene_state = plugin_state->current_scene_state;
     const TokenInfo* current_token = totp_token_info_iterator_get_current_token(iterator_context);
+    const FONT_INFO* const font = scene_state->active_font;
 
-    uint8_t char_width = TOTP_CODE_FONT_INFO.charInfo[0].width;
+    uint8_t char_width = font->charInfo[0].width;
     scene_state->ui_precalculated_dimensions.code_total_length =
-        current_token->digits * (char_width + TOTP_CODE_FONT_INFO.spacePixels);
+        current_token->digits * (char_width + font->spacePixels);
     scene_state->ui_precalculated_dimensions.code_offset_x =
         (SCREEN_WIDTH - scene_state->ui_precalculated_dimensions.code_total_length) >> 1;
-    scene_state->ui_precalculated_dimensions.code_offset_x_inc =
-        char_width + TOTP_CODE_FONT_INFO.spacePixels;
     scene_state->ui_precalculated_dimensions.code_offset_y =
-        SCREEN_HEIGHT_CENTER - (TOTP_CODE_FONT_INFO.height >> 1);
+        SCREEN_HEIGHT_CENTER - (font->height >> 1);
 
     if(time_left) {
         notification_message(
@@ -213,6 +203,8 @@ void totp_scene_generate_token_activate(PluginState* plugin_state) {
             scene_state->last_code, TokenDigitsCountMax + 1, scene_state->last_code_update_sync);
     }
 
+    scene_state->active_font = available_fonts[plugin_state->active_font_index];
+
 #ifdef TOTP_BADBT_TYPE_ENABLED
 
     if(plugin_state->automation_method & AutomationMethodBadBt) {