Alexander Kopachov 3 лет назад
Родитель
Сommit
805adfe2fb

+ 3 - 0
cli/cli.c

@@ -10,6 +10,7 @@
 #include "commands/help/help.h"
 #include "commands/help/help.h"
 #include "commands/move/move.h"
 #include "commands/move/move.h"
 #include "commands/pin/pin.h"
 #include "commands/pin/pin.h"
+#include "commands/notification/notification.h"
 
 
 static void totp_cli_print_unknown_command(const FuriString* unknown_command) {
 static void totp_cli_print_unknown_command(const FuriString* unknown_command) {
     TOTP_CLI_PRINTF(
     TOTP_CLI_PRINTF(
@@ -52,6 +53,8 @@ static void totp_cli_handler(Cli* cli, FuriString* args, void* context) {
         totp_cli_command_move_handle(plugin_state, args, cli);
         totp_cli_command_move_handle(plugin_state, args, cli);
     } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_PIN) == 0) {
     } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_PIN) == 0) {
         totp_cli_command_pin_handle(plugin_state, args, cli);
         totp_cli_command_pin_handle(plugin_state, args, cli);
+    } else if(furi_string_cmp_str(cmd, TOTP_CLI_COMMAND_NOTIFICATION) == 0) {
+        totp_cli_command_notification_handle(plugin_state, args, cli);
     } else {
     } else {
         totp_cli_print_unknown_command(cmd);
         totp_cli_print_unknown_command(cmd);
     }
     }

+ 1 - 0
cli/cli_helpers.h

@@ -6,6 +6,7 @@
 #define TOTP_CLI_COMMAND_NAME "totp"
 #define TOTP_CLI_COMMAND_NAME "totp"
 
 
 #define DOCOPT_ARGUMENT(arg) "<" arg ">"
 #define DOCOPT_ARGUMENT(arg) "<" arg ">"
+#define DOCOPT_MULTIPLE(arg) arg "..."
 #define DOCOPT_OPTIONAL(param) "[" param "]"
 #define DOCOPT_OPTIONAL(param) "[" param "]"
 #define DOCOPT_REQUIRED(param) "(" param ")"
 #define DOCOPT_REQUIRED(param) "(" param ")"
 #define DOCOPT_OPTION(option, value) option " " value
 #define DOCOPT_OPTION(option, value) option " " value

+ 4 - 16
cli/commands/add/add.c

@@ -4,6 +4,7 @@
 #include "../../../lib/list/list.h"
 #include "../../../lib/list/list.h"
 #include "../../../types/token_info.h"
 #include "../../../types/token_info.h"
 #include "../../../services/config/config.h"
 #include "../../../services/config/config.h"
+#include "../../../services/convert/convert.h"
 #include "../../cli_helpers.h"
 #include "../../cli_helpers.h"
 #include "../../../ui/scene_director.h"
 #include "../../../ui/scene_director.h"
 
 
@@ -14,21 +15,6 @@
 #define TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX "-d"
 #define TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX "-d"
 #define TOTP_CLI_COMMAND_ADD_ARG_UNSECURE_PREFIX "-u"
 #define TOTP_CLI_COMMAND_ADD_ARG_UNSECURE_PREFIX "-u"
 
 
-static bool token_info_set_digits_from_str(TokenInfo* token_info, const FuriString* str) {
-    switch(furi_string_get_char(str, 0)) {
-    case '6':
-        token_info->digits = TOTP_6_DIGITS;
-        return true;
-    case '8':
-        token_info->digits = TOTP_8_DIGITS;
-        return true;
-    default:
-        break;
-    }
-
-    return false;
-}
-
 static bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str) {
 static bool token_info_set_algo_from_str(TokenInfo* token_info, const FuriString* str) {
     if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME) == 0) {
     if(furi_string_cmpi_str(str, TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME) == 0) {
         token_info->algo = SHA1;
         token_info->algo = SHA1;
@@ -73,6 +59,7 @@ void totp_cli_command_add_docopt_options() {
         DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ADD_ARG_ALGO)) "      Token hashing algorithm.\r\n");
         DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_ADD_ARG_ALGO)) "      Token hashing algorithm.\r\n");
     TOTP_CLI_PRINTF(
     TOTP_CLI_PRINTF(
         "                 Could be one of: sha1, sha256, sha512 " DOCOPT_DEFAULT("sha1") "\r\n");
         "                 Could be one of: sha1, sha256, sha512 " DOCOPT_DEFAULT("sha1") "\r\n");
+    cli_nl();
     TOTP_CLI_PRINTF("  " DOCOPT_OPTION(
     TOTP_CLI_PRINTF("  " DOCOPT_OPTION(
         TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX,
         TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX,
         DOCOPT_ARGUMENT(
         DOCOPT_ARGUMENT(
@@ -164,7 +151,8 @@ void totp_cli_command_add_handle(PluginState* plugin_state, FuriString* args, Cl
                 TOTP_CLI_PRINTF(
                 TOTP_CLI_PRINTF(
                     "Missed value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX
                     "Missed value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX
                     "\"\r\n");
                     "\"\r\n");
-            } else if(!token_info_set_digits_from_str(token_info, temp_str)) {
+            } else if(!token_info_set_digits_from_int(
+                          token_info, CONVERT_CHAR_TO_DIGIT(furi_string_get_char(temp_str, 0)))) {
                 TOTP_CLI_PRINTF(
                 TOTP_CLI_PRINTF(
                     "\"%s\" is incorrect value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX
                     "\"%s\" is incorrect value for argument \"" TOTP_CLI_COMMAND_ADD_ARG_DIGITS_PREFIX
                     "\"\r\n",
                     "\"\r\n",

+ 4 - 0
cli/commands/help/help.c

@@ -6,6 +6,7 @@
 #include "../timezone/timezone.h"
 #include "../timezone/timezone.h"
 #include "../move/move.h"
 #include "../move/move.h"
 #include "../pin/pin.h"
 #include "../pin/pin.h"
+#include "../notification/notification.h"
 
 
 void totp_cli_command_help_docopt_commands() {
 void totp_cli_command_help_docopt_commands() {
     TOTP_CLI_PRINTF("  " TOTP_CLI_COMMAND_HELP ", " TOTP_CLI_COMMAND_HELP_ALT
     TOTP_CLI_PRINTF("  " TOTP_CLI_COMMAND_HELP ", " TOTP_CLI_COMMAND_HELP_ALT
@@ -27,6 +28,7 @@ void totp_cli_command_help_handle() {
     totp_cli_command_timezone_docopt_usage();
     totp_cli_command_timezone_docopt_usage();
     totp_cli_command_move_docopt_usage();
     totp_cli_command_move_docopt_usage();
     totp_cli_command_pin_docopt_usage();
     totp_cli_command_pin_docopt_usage();
+    totp_cli_command_notification_docopt_usage();
     cli_nl();
     cli_nl();
     TOTP_CLI_PRINTF("Commands:\r\n");
     TOTP_CLI_PRINTF("Commands:\r\n");
     totp_cli_command_help_docopt_commands();
     totp_cli_command_help_docopt_commands();
@@ -36,11 +38,13 @@ void totp_cli_command_help_handle() {
     totp_cli_command_timezone_docopt_commands();
     totp_cli_command_timezone_docopt_commands();
     totp_cli_command_move_docopt_commands();
     totp_cli_command_move_docopt_commands();
     totp_cli_command_pin_docopt_commands();
     totp_cli_command_pin_docopt_commands();
+    totp_cli_command_notification_docopt_commands();
     cli_nl();
     cli_nl();
     TOTP_CLI_PRINTF("Arguments:\r\n");
     TOTP_CLI_PRINTF("Arguments:\r\n");
     totp_cli_command_add_docopt_arguments();
     totp_cli_command_add_docopt_arguments();
     totp_cli_command_delete_docopt_arguments();
     totp_cli_command_delete_docopt_arguments();
     totp_cli_command_timezone_docopt_arguments();
     totp_cli_command_timezone_docopt_arguments();
+    totp_cli_command_notification_docopt_arguments();
     cli_nl();
     cli_nl();
     TOTP_CLI_PRINTF("Options:\r\n");
     TOTP_CLI_PRINTF("Options:\r\n");
     totp_cli_command_add_docopt_options();
     totp_cli_command_add_docopt_options();

+ 1 - 15
cli/commands/list/list.c

@@ -20,19 +20,6 @@ static char* get_algo_as_cstr(TokenHashAlgo algo) {
     return "UNKNOWN";
     return "UNKNOWN";
 }
 }
 
 
-static uint8_t get_digits_as_int(TokenDigitsCount digits) {
-    switch(digits) {
-    case TOTP_6_DIGITS:
-        return 6;
-    case TOTP_8_DIGITS:
-        return 8;
-    default:
-        break;
-    }
-
-    return 6;
-}
-
 void totp_cli_command_list_docopt_commands() {
 void totp_cli_command_list_docopt_commands() {
     TOTP_CLI_PRINTF("  " TOTP_CLI_COMMAND_LIST ", " TOTP_CLI_COMMAND_LIST_ALT
     TOTP_CLI_PRINTF("  " TOTP_CLI_COMMAND_LIST ", " TOTP_CLI_COMMAND_LIST_ALT
                     "         List all available tokens\r\n");
                     "         List all available tokens\r\n");
@@ -59,13 +46,12 @@ void totp_cli_command_list_handle(PluginState* plugin_state, Cli* cli) {
     uint16_t index = 1;
     uint16_t index = 1;
     TOTP_LIST_FOREACH(plugin_state->tokens_list, node, {
     TOTP_LIST_FOREACH(plugin_state->tokens_list, node, {
         TokenInfo* token_info = (TokenInfo*)node->data;
         TokenInfo* token_info = (TokenInfo*)node->data;
-        token_info_get_digits_count(token_info);
         TOTP_CLI_PRINTF(
         TOTP_CLI_PRINTF(
             "| %-3" PRIu16 " | %-27.27s | %-6s | %-6" PRIu8 " |\r\n",
             "| %-3" PRIu16 " | %-27.27s | %-6s | %-6" PRIu8 " |\r\n",
             index,
             index,
             token_info->name,
             token_info->name,
             get_algo_as_cstr(token_info->algo),
             get_algo_as_cstr(token_info->algo),
-            get_digits_as_int(token_info->digits));
+            token_info->digits);
         index++;
         index++;
     });
     });
     TOTP_CLI_PRINTF("+-----+-----------------------------+--------+--------+\r\n");
     TOTP_CLI_PRINTF("+-----+-----------------------------+--------+--------+\r\n");

+ 106 - 0
cli/commands/notification/notification.c

@@ -0,0 +1,106 @@
+#include "notification.h"
+#include <lib/toolbox/args.h>
+#include "../../../services/config/config.h"
+#include "../../../ui/scene_director.h"
+#include "../../cli_helpers.h"
+
+#define TOTP_CLI_COMMAND_NOTIFICATION_ARG_METHOD "method"
+#define TOTP_CLI_COMMAND_NOTIFICATION_METHOD_NONE "none"
+#define TOTP_CLI_COMMAND_NOTIFICATION_METHOD_SOUND "sound"
+#define TOTP_CLI_COMMAND_NOTIFICATION_METHOD_VIBRO "vibro"
+
+void totp_cli_command_notification_docopt_commands() {
+    TOTP_CLI_PRINTF("  " TOTP_CLI_COMMAND_NOTIFICATION
+                    "           Get or set notification method\r\n");
+}
+
+void totp_cli_command_notification_docopt_usage() {
+    TOTP_CLI_PRINTF(
+        "  " TOTP_CLI_COMMAND_NAME " " TOTP_CLI_COMMAND_NOTIFICATION " " DOCOPT_OPTIONAL(
+            DOCOPT_MULTIPLE(DOCOPT_ARGUMENT(TOTP_CLI_COMMAND_NOTIFICATION_ARG_METHOD))) "\r\n");
+}
+
+void totp_cli_command_notification_docopt_arguments() {
+    TOTP_CLI_PRINTF(
+        "  " TOTP_CLI_COMMAND_NOTIFICATION_ARG_METHOD
+        "      Notification method to be set. Must be one of [" TOTP_CLI_COMMAND_NOTIFICATION_METHOD_NONE
+        ", " TOTP_CLI_COMMAND_NOTIFICATION_METHOD_SOUND
+        ", " TOTP_CLI_COMMAND_NOTIFICATION_METHOD_VIBRO "]\r\n");
+}
+
+static void totp_cli_command_notification_print_method(NotificationMethod method) {
+    bool has_previous_method = false;
+    if(method & NotificationMethodSound) {
+        TOTP_CLI_PRINTF("\"" TOTP_CLI_COMMAND_NOTIFICATION_METHOD_SOUND "\"");
+        has_previous_method = true;
+    }
+    if(method & NotificationMethodVibro) {
+        if(has_previous_method) {
+            TOTP_CLI_PRINTF(" and ");
+        }
+
+        TOTP_CLI_PRINTF("\"" TOTP_CLI_COMMAND_NOTIFICATION_METHOD_VIBRO "\"");
+    }
+    if(method == NotificationMethodNone) {
+        TOTP_CLI_PRINTF("\"" TOTP_CLI_COMMAND_NOTIFICATION_METHOD_NONE "\"");
+    }
+}
+
+void totp_cli_command_notification_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
+    if(!totp_cli_ensure_authenticated(plugin_state, cli)) {
+        return;
+    }
+
+    FuriString* temp_str = furi_string_alloc();
+    bool new_method_provided = false;
+    NotificationMethod new_method = NotificationMethodNone;
+    bool args_valid = true;
+    while(args_read_string_and_trim(args, temp_str)) {
+        if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_NOTIFICATION_METHOD_NONE) == 0) {
+            new_method_provided = true;
+            new_method = NotificationMethodNone;
+        } else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_NOTIFICATION_METHOD_SOUND) == 0) {
+            new_method_provided = true;
+            new_method |= NotificationMethodSound;
+        } else if(furi_string_cmpi_str(temp_str, TOTP_CLI_COMMAND_NOTIFICATION_METHOD_VIBRO) == 0) {
+            new_method_provided = true;
+            new_method |= NotificationMethodVibro;
+        } else {
+            args_valid = false;
+            break;
+        }
+    }
+
+    do {
+        if(!args_valid) {
+            TOTP_CLI_PRINT_INVALID_ARGUMENTS();
+            break;
+        }
+
+        if(new_method_provided) {
+            Scene previous_scene = TotpSceneNone;
+            if(plugin_state->current_scene == TotpSceneGenerateToken ||
+               plugin_state->current_scene == TotpSceneAppSettings) {
+                previous_scene = plugin_state->current_scene;
+                totp_scene_director_activate_scene(plugin_state, TotpSceneNone, NULL);
+            }
+
+            plugin_state->notification_method = new_method;
+            totp_config_file_update_notification_method(new_method);
+
+            if(previous_scene != TotpSceneNone) {
+                totp_scene_director_activate_scene(plugin_state, previous_scene, NULL);
+            }
+
+            TOTP_CLI_PRINTF("Notification method is set to ");
+            totp_cli_command_notification_print_method(new_method);
+            cli_nl();
+        } else {
+            TOTP_CLI_PRINTF("Current notification method is ");
+            totp_cli_command_notification_print_method(plugin_state->notification_method);
+            cli_nl();
+        }
+    } while(false);
+
+    furi_string_free(temp_str);
+}

+ 11 - 0
cli/commands/notification/notification.h

@@ -0,0 +1,11 @@
+#pragma once
+
+#include <cli/cli.h>
+#include "../../../types/plugin_state.h"
+
+#define TOTP_CLI_COMMAND_NOTIFICATION "notify"
+
+void totp_cli_command_notification_handle(PluginState* plugin_state, FuriString* args, Cli* cli);
+void totp_cli_command_notification_docopt_commands();
+void totp_cli_command_notification_docopt_usage();
+void totp_cli_command_notification_docopt_arguments();

+ 0 - 2
cli/commands/timezone/timezone.c

@@ -21,8 +21,6 @@ void totp_cli_command_timezone_docopt_usage() {
 void totp_cli_command_timezone_docopt_arguments() {
 void totp_cli_command_timezone_docopt_arguments() {
     TOTP_CLI_PRINTF("  " TOTP_CLI_COMMAND_TIMEZONE_ARG_TIMEZONE
     TOTP_CLI_PRINTF("  " TOTP_CLI_COMMAND_TIMEZONE_ARG_TIMEZONE
                     "    Timezone offset in hours to be set.\r\n");
                     "    Timezone offset in hours to be set.\r\n");
-    TOTP_CLI_PRINTF(
-        "              If not provided then current timezone offset will be printed\r\n");
 }
 }
 
 
 void totp_cli_command_timezone_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {
 void totp_cli_command_timezone_handle(PluginState* plugin_state, FuriString* args, Cli* cli) {

BIN
images/totp_arrow_bottom_10x5.png


+ 4 - 2
lib/roll_value/roll_value.h

@@ -2,7 +2,9 @@
 
 
 #include <stdint.h>
 #include <stdint.h>
 
 
-typedef enum {
+typedef uint8_t TotpRollValueOverflowBehavior;
+
+enum TotpRollValueOverflowBehaviors {
     /**
     /**
      * @brief Do not change value if it reached constraint
      * @brief Do not change value if it reached constraint
      */
      */
@@ -12,7 +14,7 @@ typedef enum {
      * @brief Set value to opposite constraint value if it reached constraint
      * @brief Set value to opposite constraint value if it reached constraint
      */
      */
     RollOverflowBehaviorRoll
     RollOverflowBehaviorRoll
-} TotpRollValueOverflowBehavior;
+};
 
 
 #define TOTP_ROLL_VALUE_FN_HEADER(type, step_type) \
 #define TOTP_ROLL_VALUE_FN_HEADER(type, step_type) \
     void totp_roll_value_##type(                   \
     void totp_roll_value_##type(                   \

+ 53 - 32
services/config/config.c

@@ -10,32 +10,6 @@
 #define CONFIG_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf"
 #define CONFIG_FILE_PATH CONFIG_FILE_DIRECTORY_PATH "/totp.conf"
 #define CONFIG_FILE_BACKUP_PATH CONFIG_FILE_PATH ".backup"
 #define CONFIG_FILE_BACKUP_PATH CONFIG_FILE_PATH ".backup"
 
 
-static uint8_t token_info_get_digits_as_int(const TokenInfo* token_info) {
-    switch(token_info->digits) {
-    case TOTP_6_DIGITS:
-        return 6;
-    case TOTP_8_DIGITS:
-        return 8;
-    default:
-        break;
-    }
-
-    return 6;
-}
-
-static void token_info_set_digits_from_int(TokenInfo* token_info, uint8_t digits) {
-    switch(digits) {
-    case 6:
-        token_info->digits = TOTP_6_DIGITS;
-        break;
-    case 8:
-        token_info->digits = TOTP_8_DIGITS;
-        break;
-    default:
-        break;
-    }
-}
-
 static char* token_info_get_algo_as_cstr(const TokenInfo* token_info) {
 static char* token_info_get_algo_as_cstr(const TokenInfo* token_info) {
     switch(token_info->algo) {
     switch(token_info->algo) {
     case SHA1:
     case SHA1:
@@ -106,6 +80,15 @@ FlipperFormat* totp_open_config_file(Storage* storage) {
             fff_data_file,
             fff_data_file,
             "Timezone offset in hours. Important note: do not put '+' sign for positive values");
             "Timezone offset in hours. Important note: do not put '+' sign for positive values");
         flipper_format_write_float(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &tmp_tz, 1);
         flipper_format_write_float(fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &tmp_tz, 1);
+
+        uint32_t tmp_uint32 = NotificationMethodSound | NotificationMethodVibro;
+        flipper_format_write_comment_cstr(fff_data_file, " ");
+        flipper_format_write_comment_cstr(
+            fff_data_file,
+            "How to notify user when new token is generated or badusb mode is activated (possible values: 0 - do not notify, 1 - sound, 2 - vibro, 3 sound and vibro)");
+        flipper_format_write_uint32(
+            fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1);
+
         FuriString* temp_str = furi_string_alloc();
         FuriString* temp_str = furi_string_alloc();
 
 
         flipper_format_write_comment_cstr(fff_data_file, " ");
         flipper_format_write_comment_cstr(fff_data_file, " ");
@@ -172,8 +155,8 @@ void totp_config_file_save_new_token_i(FlipperFormat* file, const TokenInfo* tok
     }
     }
     flipper_format_write_string_cstr(
     flipper_format_write_string_cstr(
         file, TOTP_CONFIG_KEY_TOKEN_ALGO, token_info_get_algo_as_cstr(token_info));
         file, TOTP_CONFIG_KEY_TOKEN_ALGO, token_info_get_algo_as_cstr(token_info));
-    uint32_t digits_count_as_uint32 = token_info_get_digits_as_int(token_info);
-    flipper_format_write_uint32(file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &digits_count_as_uint32, 1);
+    uint32_t tmp_uint32 = token_info->digits;
+    flipper_format_write_uint32(file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &tmp_uint32, 1);
 }
 }
 
 
 void totp_config_file_save_new_token(const TokenInfo* token_info) {
 void totp_config_file_save_new_token(const TokenInfo* token_info) {
@@ -196,6 +179,32 @@ void totp_config_file_update_timezone_offset(float new_timezone_offset) {
     totp_close_storage();
     totp_close_storage();
 }
 }
 
 
+void totp_config_file_update_notification_method(NotificationMethod new_notification_method) {
+    Storage* cfg_storage = totp_open_storage();
+    FlipperFormat* file = totp_open_config_file(cfg_storage);
+
+    uint32_t tmp_uint32 = new_notification_method;
+    flipper_format_insert_or_update_uint32(
+        file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1);
+
+    totp_close_config_file(file);
+    totp_close_storage();
+}
+
+void totp_config_file_update_user_settings(const PluginState* plugin_state) {
+    Storage* cfg_storage = totp_open_storage();
+    FlipperFormat* file = totp_open_config_file(cfg_storage);
+
+    flipper_format_insert_or_update_float(
+        file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1);
+    uint32_t tmp_uint32 = plugin_state->notification_method;
+    flipper_format_insert_or_update_uint32(
+        file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1);
+
+    totp_close_config_file(file);
+    totp_close_storage();
+}
+
 void totp_full_save_config_file(const PluginState* const plugin_state) {
 void totp_full_save_config_file(const PluginState* const plugin_state) {
     Storage* storage = totp_open_storage();
     Storage* storage = totp_open_storage();
     FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
     FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
@@ -213,6 +222,9 @@ void totp_full_save_config_file(const PluginState* const plugin_state) {
     flipper_format_write_float(
     flipper_format_write_float(
         fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1);
         fff_data_file, TOTP_CONFIG_KEY_TIMEZONE, &plugin_state->timezone_offset, 1);
     flipper_format_write_bool(fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1);
     flipper_format_write_bool(fff_data_file, TOTP_CONFIG_KEY_PINSET, &plugin_state->pin_set, 1);
+    uint32_t tmp_uint32 = plugin_state->notification_method;
+    flipper_format_write_uint32(
+        fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1);
 
 
     TOTP_LIST_FOREACH(plugin_state->tokens_list, node, {
     TOTP_LIST_FOREACH(plugin_state->tokens_list, node, {
         const TokenInfo* token_info = node->data;
         const TokenInfo* token_info = node->data;
@@ -320,6 +332,16 @@ void totp_config_file_load_base(PluginState* const plugin_state) {
         plugin_state->pin_set = true;
         plugin_state->pin_set = true;
     }
     }
 
 
+    flipper_format_rewind(fff_data_file);
+
+    uint32_t tmp_uint32;
+    if(!flipper_format_read_uint32(
+           fff_data_file, TOTP_CONFIG_KEY_NOTIFICATION_METHOD, &tmp_uint32, 1)) {
+        tmp_uint32 = NotificationMethodSound | NotificationMethodVibro;
+    }
+
+    plugin_state->notification_method = tmp_uint32;
+
     furi_string_free(temp_str);
     furi_string_free(temp_str);
     totp_close_config_file(fff_data_file);
     totp_close_config_file(fff_data_file);
     totp_close_storage();
     totp_close_storage();
@@ -408,10 +430,9 @@ TokenLoadingResult totp_config_file_load_tokens(PluginState* const plugin_state)
             tokenInfo->algo = SHA1;
             tokenInfo->algo = SHA1;
         }
         }
 
 
-        if(flipper_format_read_uint32(
-               fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &temp_data32, 1)) {
-            token_info_set_digits_from_int(tokenInfo, temp_data32);
-        } else {
+        if(!flipper_format_read_uint32(
+               fff_data_file, TOTP_CONFIG_KEY_TOKEN_DIGITS, &temp_data32, 1) ||
+           !token_info_set_digits_from_int(tokenInfo, temp_data32)) {
             tokenInfo->digits = TOTP_6_DIGITS;
             tokenInfo->digits = TOTP_6_DIGITS;
         }
         }
 
 

+ 16 - 2
services/config/config.h

@@ -6,10 +6,12 @@
 #include "../../types/token_info.h"
 #include "../../types/token_info.h"
 #include "constants.h"
 #include "constants.h"
 
 
+typedef uint8_t TokenLoadingResult;
+
 /**
 /**
  * @brief Token loading results
  * @brief Token loading results
  */
  */
-typedef enum {
+enum TokenLoadingResults {
     /**
     /**
      * @brief All the tokens loaded successfully 
      * @brief All the tokens loaded successfully 
      */
      */
@@ -24,7 +26,7 @@ typedef enum {
      * @brief Tokens not loaded because of error(s) 
      * @brief Tokens not loaded because of error(s) 
      */
      */
     TokenLoadingResultError
     TokenLoadingResultError
-} TokenLoadingResult;
+};
 
 
 /**
 /**
  * @brief Opens storage record
  * @brief Opens storage record
@@ -80,3 +82,15 @@ void totp_config_file_save_new_token(const TokenInfo* token_info);
  * @param new_timezone_offset new timezone offset to be set
  * @param new_timezone_offset new timezone offset to be set
  */
  */
 void totp_config_file_update_timezone_offset(float new_timezone_offset);
 void totp_config_file_update_timezone_offset(float new_timezone_offset);
+
+/**
+ * @brief Updates notification method in an application config file
+ * @param new_notification_method new notification method to be set
+ */
+void totp_config_file_update_notification_method(NotificationMethod new_notification_method);
+
+/**
+ * @brief Updates application user settings
+ * @param plugin_state application state
+ */
+void totp_config_file_update_user_settings(const PluginState* plugin_state);

+ 1 - 0
services/config/constants.h

@@ -11,6 +11,7 @@
 #define TOTP_CONFIG_KEY_CRYPTO_VERIFY "Crypto"
 #define TOTP_CONFIG_KEY_CRYPTO_VERIFY "Crypto"
 #define TOTP_CONFIG_KEY_BASE_IV "BaseIV"
 #define TOTP_CONFIG_KEY_BASE_IV "BaseIV"
 #define TOTP_CONFIG_KEY_PINSET "PinIsSet"
 #define TOTP_CONFIG_KEY_PINSET "PinIsSet"
+#define TOTP_CONFIG_KEY_NOTIFICATION_METHOD "NotificationMethod"
 
 
 #define TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME "sha1"
 #define TOTP_CONFIG_TOKEN_ALGO_SHA1_NAME "sha1"
 #define TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME "sha256"
 #define TOTP_CONFIG_TOKEN_ALGO_SHA256_NAME "sha256"

+ 4 - 0
services/convert/convert.h

@@ -0,0 +1,4 @@
+#pragma once
+
+#define CONVERT_DIGIT_TO_CHAR(digit) ((digit) + '0')
+#define CONVERT_CHAR_TO_DIGIT(ch) ((ch) - '0')

+ 6 - 6
totp_app.c

@@ -22,7 +22,7 @@
 
 
 static void render_callback(Canvas* const canvas, void* ctx) {
 static void render_callback(Canvas* const canvas, void* ctx) {
     PluginState* plugin_state = acquire_mutex((ValueMutex*)ctx, 25);
     PluginState* plugin_state = acquire_mutex((ValueMutex*)ctx, 25);
-    if(plugin_state != NULL && !plugin_state->changing_scene) {
+    if(plugin_state != NULL) {
         totp_scene_director_render(canvas, plugin_state);
         totp_scene_director_render(canvas, plugin_state);
     }
     }
 
 
@@ -38,8 +38,8 @@ static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queu
 
 
 static bool totp_plugin_state_init(PluginState* const plugin_state) {
 static bool totp_plugin_state_init(PluginState* const plugin_state) {
     plugin_state->gui = furi_record_open(RECORD_GUI);
     plugin_state->gui = furi_record_open(RECORD_GUI);
-    plugin_state->notification = furi_record_open(RECORD_NOTIFICATION);
-    plugin_state->dialogs = furi_record_open(RECORD_DIALOGS);
+    plugin_state->notification_app = furi_record_open(RECORD_NOTIFICATION);
+    plugin_state->dialogs_app = furi_record_open(RECORD_DIALOGS);
 
 
     totp_config_file_load_base(plugin_state);
     totp_config_file_load_base(plugin_state);
 
 
@@ -57,7 +57,8 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) {
             SCREEN_HEIGHT_CENTER,
             SCREEN_HEIGHT_CENTER,
             AlignCenter,
             AlignCenter,
             AlignCenter);
             AlignCenter);
-        DialogMessageButton dialog_result = dialog_message_show(plugin_state->dialogs, message);
+        DialogMessageButton dialog_result =
+            dialog_message_show(plugin_state->dialogs_app, message);
         dialog_message_free(message);
         dialog_message_free(message);
         if(dialog_result == DialogMessageButtonRight) {
         if(dialog_result == DialogMessageButtonRight) {
             totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
             totp_scene_director_activate_scene(plugin_state, TotpSceneAuthentication, NULL);
@@ -84,7 +85,7 @@ static bool totp_plugin_state_init(PluginState* const plugin_state) {
                 SCREEN_HEIGHT_CENTER,
                 SCREEN_HEIGHT_CENTER,
                 AlignCenter,
                 AlignCenter,
                 AlignCenter);
                 AlignCenter);
-            dialog_message_show(plugin_state->dialogs, message);
+            dialog_message_show(plugin_state->dialogs_app, message);
             dialog_message_free(message);
             dialog_message_free(message);
             return false;
             return false;
         }
         }
@@ -150,7 +151,6 @@ int32_t totp_app() {
     bool processing = true;
     bool processing = true;
     uint32_t last_user_interaction_time = furi_get_tick();
     uint32_t last_user_interaction_time = furi_get_tick();
     while(processing) {
     while(processing) {
-        if(plugin_state->changing_scene) continue;
         FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
         FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
 
 
         PluginState* plugin_state_m = acquire_mutex_block(&state_mutex);
         PluginState* plugin_state_m = acquire_mutex_block(&state_mutex);

+ 4 - 2
types/event_type.h

@@ -1,7 +1,9 @@
 #pragma once
 #pragma once
 #include <inttypes.h>
 #include <inttypes.h>
 
 
-typedef enum {
+typedef uint8_t EventType;
+
+enum EventTypes {
     EventTypeTick,
     EventTypeTick,
     EventTypeKey,
     EventTypeKey,
-} EventType;
+};

+ 9 - 0
types/notification_method.h

@@ -0,0 +1,9 @@
+#pragma once
+
+typedef uint8_t NotificationMethod;
+
+enum NotificationMethods {
+    NotificationMethodNone = 0b00,
+    NotificationMethodSound = 0b01,
+    NotificationMethodVibro = 0b10,
+};

+ 8 - 7
types/plugin_state.h

@@ -5,6 +5,7 @@
 #include <dialogs/dialogs.h>
 #include <dialogs/dialogs.h>
 #include "../lib/list/list.h"
 #include "../lib/list/list.h"
 #include "../ui/totp_scenes_enum.h"
 #include "../ui/totp_scenes_enum.h"
+#include "notification_method.h"
 
 
 #define TOTP_IV_SIZE 16
 #define TOTP_IV_SIZE 16
 
 
@@ -22,20 +23,15 @@ typedef struct {
      */
      */
     void* current_scene_state;
     void* current_scene_state;
 
 
-    /**
-     * @brief Whether scene is changing now 
-     */
-    bool changing_scene;
-
     /**
     /**
      * @brief Reference to the firmware notification subsystem
      * @brief Reference to the firmware notification subsystem
      */
      */
-    NotificationApp* notification;
+    NotificationApp* notification_app;
 
 
     /**
     /**
      * @brief Reference to the firmware dialogs subsystem 
      * @brief Reference to the firmware dialogs subsystem 
      */
      */
-    DialogsApp* dialogs;
+    DialogsApp* dialogs_app;
 
 
     /**
     /**
      * @brief Reference to the firmware GUI subsystem
      * @brief Reference to the firmware GUI subsystem
@@ -86,4 +82,9 @@ typedef struct {
      * @brief Basic randomly-generated initialization vector (IV)
      * @brief Basic randomly-generated initialization vector (IV)
      */
      */
     uint8_t base_iv[TOTP_IV_SIZE];
     uint8_t base_iv[TOTP_IV_SIZE];
+
+    /**
+     * @brief Notification method
+     */
+    NotificationMethod notification_method;
 } PluginState;
 } PluginState;

+ 9 - 7
types/token_info.c

@@ -45,15 +45,17 @@ bool token_info_set_secret(
     return result;
     return result;
 }
 }
 
 
-uint8_t token_info_get_digits_count(const TokenInfo* token_info) {
-    switch(token_info->digits) {
-    case TOTP_6_DIGITS:
-        return 6;
-    case TOTP_8_DIGITS:
-        return 8;
+bool token_info_set_digits_from_int(TokenInfo* token_info, uint8_t digits) {
+    switch(digits) {
+    case 6:
+        token_info->digits = TOTP_6_DIGITS;
+        return true;
+    case 8:
+        token_info->digits = TOTP_8_DIGITS;
+        return true;
     default:
     default:
         break;
         break;
     }
     }
 
 
-    return 6;
+    return false;
 }
 }

+ 14 - 10
types/token_info.h

@@ -2,10 +2,13 @@
 
 
 #include <inttypes.h>
 #include <inttypes.h>
 
 
+typedef uint8_t TokenHashAlgo;
+typedef uint8_t TokenDigitsCount;
+
 /**
 /**
  * @brief Hashing algorithm to be used to generate token
  * @brief Hashing algorithm to be used to generate token
  */
  */
-typedef enum {
+enum TokenHashAlgos {
     /**
     /**
      * @brief SHA1 hashing algorithm
      * @brief SHA1 hashing algorithm
      */
      */
@@ -20,22 +23,22 @@ typedef enum {
      * @brief SHA512 hashing algorithm
      * @brief SHA512 hashing algorithm
      */
      */
     SHA512
     SHA512
-} TokenHashAlgo;
+};
 
 
 /**
 /**
  * @brief Token digits count to be generated.
  * @brief Token digits count to be generated.
  */
  */
-typedef enum {
+enum TokenDigitsCounts {
     /**
     /**
      * @brief 6 digits
      * @brief 6 digits
      */
      */
-    TOTP_6_DIGITS,
+    TOTP_6_DIGITS = 6,
 
 
     /**
     /**
      * @brief 8 digits
      * @brief 8 digits
      */
      */
-    TOTP_8_DIGITS
-} TokenDigitsCount;
+    TOTP_8_DIGITS = 8
+};
 
 
 #define TOTP_TOKEN_DIGITS_MAX_COUNT 8
 #define TOTP_TOKEN_DIGITS_MAX_COUNT 8
 
 
@@ -96,8 +99,9 @@ bool token_info_set_secret(
     const uint8_t* iv);
     const uint8_t* iv);
 
 
 /**
 /**
- * @brief Gets token digits count as \c uint8_t type
- * @param token_info instance which's desired digits count should be returned
- * @return Token digits length as \c uint8_t type
+ * @brief Sets token digits count from \c uint8_t value
+ * @param token_info instance whichs token digits count length should be updated
+ * @param digits desired token digits count length
+ * @return \c true if token digits count length has been updated; \c false p
  */
  */
-uint8_t token_info_get_digits_count(const TokenInfo* token_info);
+bool token_info_set_digits_from_int(TokenInfo* token_info, uint8_t digits);

+ 4 - 2
types/user_pin_codes.h

@@ -1,8 +1,10 @@
 #pragma once
 #pragma once
 
 
-typedef enum uint8_t {
+typedef uint8_t TotpUserPinCode;
+
+enum TotpUserPinCodes {
     PinCodeArrowUp = 2,
     PinCodeArrowUp = 2,
     PinCodeArrowRight = 8,
     PinCodeArrowRight = 8,
     PinCodeArrowDown = 11,
     PinCodeArrowDown = 11,
     PinCodeArrowLeft = 5
     PinCodeArrowLeft = 5
-} TotpUserPinCode;
+};

+ 0 - 2
ui/scene_director.c

@@ -10,7 +10,6 @@ void totp_scene_director_activate_scene(
     PluginState* const plugin_state,
     PluginState* const plugin_state,
     Scene scene,
     Scene scene,
     const void* context) {
     const void* context) {
-    plugin_state->changing_scene = true;
     totp_scene_director_deactivate_active_scene(plugin_state);
     totp_scene_director_deactivate_active_scene(plugin_state);
     switch(scene) {
     switch(scene) {
     case TotpSceneGenerateToken:
     case TotpSceneGenerateToken:
@@ -35,7 +34,6 @@ void totp_scene_director_activate_scene(
     }
     }
 
 
     plugin_state->current_scene = scene;
     plugin_state->current_scene = scene;
-    plugin_state->changing_scene = false;
 }
 }
 
 
 void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state) {
 void totp_scene_director_deactivate_active_scene(PluginState* const plugin_state) {

+ 8 - 17
ui/scenes/add_new_token/totp_scene_add_new_token.c

@@ -11,10 +11,9 @@
 #include "../../../types/nullable.h"
 #include "../../../types/nullable.h"
 #include "../generate_token/totp_scene_generate_token.h"
 #include "../generate_token/totp_scene_generate_token.h"
 
 
-#define TOKEN_ALGO_LIST_LENGTH 3
 char* TOKEN_ALGO_LIST[] = {"SHA1", "SHA256", "SHA512"};
 char* TOKEN_ALGO_LIST[] = {"SHA1", "SHA256", "SHA512"};
-#define TOKEN_DIGITS_LIST_LENGTH 2
-char* TOKEN_DIGITS_LIST[] = {"6 digits", "8 digits"};
+char* TOKEN_DIGITS_TEXT_LIST[] = {"6 digits", "8 digits"};
+TokenDigitsCount TOKEN_DIGITS_VALUE_LIST[] = {TOTP_6_DIGITS, TOTP_8_DIGITS};
 
 
 typedef enum {
 typedef enum {
     TokenNameTextBox,
     TokenNameTextBox,
@@ -38,7 +37,7 @@ typedef struct {
     TotpNullable_uint16_t current_token_index;
     TotpNullable_uint16_t current_token_index;
     int16_t screen_y_offset;
     int16_t screen_y_offset;
     TokenHashAlgo algo;
     TokenHashAlgo algo;
-    TokenDigitsCount digits_count;
+    uint8_t digits_count_index;
 } SceneState;
 } SceneState;
 
 
 void totp_scene_add_new_token_init(const PluginState* plugin_state) {
 void totp_scene_add_new_token_init(const PluginState* plugin_state) {
@@ -126,7 +125,7 @@ void totp_scene_add_new_token_render(Canvas* const canvas, PluginState* plugin_s
         0,
         0,
         63 - scene_state->screen_y_offset,
         63 - scene_state->screen_y_offset,
         SCREEN_WIDTH,
         SCREEN_WIDTH,
-        TOKEN_DIGITS_LIST[scene_state->digits_count],
+        TOKEN_DIGITS_TEXT_LIST[scene_state->digits_count_index],
         scene_state->selected_control == TokenLengthSelect);
         scene_state->selected_control == TokenLengthSelect);
     ui_control_button_render(
     ui_control_button_render(
         canvas,
         canvas,
@@ -196,11 +195,7 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState
             totp_roll_value_uint8_t(&scene_state->algo, 1, SHA1, SHA512, RollOverflowBehaviorRoll);
             totp_roll_value_uint8_t(&scene_state->algo, 1, SHA1, SHA512, RollOverflowBehaviorRoll);
         } else if(scene_state->selected_control == TokenLengthSelect) {
         } else if(scene_state->selected_control == TokenLengthSelect) {
             totp_roll_value_uint8_t(
             totp_roll_value_uint8_t(
-                &scene_state->digits_count,
-                1,
-                TOTP_6_DIGITS,
-                TOTP_8_DIGITS,
-                RollOverflowBehaviorRoll);
+                &scene_state->digits_count_index, 1, 0, 1, RollOverflowBehaviorRoll);
         }
         }
         break;
         break;
     case InputKeyLeft:
     case InputKeyLeft:
@@ -209,11 +204,7 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState
                 &scene_state->algo, -1, SHA1, SHA512, RollOverflowBehaviorRoll);
                 &scene_state->algo, -1, SHA1, SHA512, RollOverflowBehaviorRoll);
         } else if(scene_state->selected_control == TokenLengthSelect) {
         } else if(scene_state->selected_control == TokenLengthSelect) {
             totp_roll_value_uint8_t(
             totp_roll_value_uint8_t(
-                &scene_state->digits_count,
-                -1,
-                TOTP_6_DIGITS,
-                TOTP_8_DIGITS,
-                RollOverflowBehaviorRoll);
+                &scene_state->digits_count_index, -1, 0, 1, RollOverflowBehaviorRoll);
         }
         }
         break;
         break;
     case InputKeyOk:
     case InputKeyOk:
@@ -252,7 +243,7 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState
                 strlcpy(
                 strlcpy(
                     tokenInfo->name, scene_state->token_name, scene_state->token_name_length + 1);
                     tokenInfo->name, scene_state->token_name, scene_state->token_name_length + 1);
                 tokenInfo->algo = scene_state->algo;
                 tokenInfo->algo = scene_state->algo;
-                tokenInfo->digits = scene_state->digits_count;
+                tokenInfo->digits = TOKEN_DIGITS_VALUE_LIST[scene_state->digits_count_index];
 
 
                 TOTP_LIST_INIT_OR_ADD(plugin_state->tokens_list, tokenInfo, furi_check);
                 TOTP_LIST_INIT_OR_ADD(plugin_state->tokens_list, tokenInfo, furi_check);
                 plugin_state->tokens_count++;
                 plugin_state->tokens_count++;
@@ -274,7 +265,7 @@ bool totp_scene_add_new_token_handle_event(PluginEvent* const event, PluginState
                     SCREEN_HEIGHT_CENTER,
                     SCREEN_HEIGHT_CENTER,
                     AlignCenter,
                     AlignCenter,
                     AlignCenter);
                     AlignCenter);
-                dialog_message_show(plugin_state->dialogs, message);
+                dialog_message_show(plugin_state->dialogs_app, message);
                 dialog_message_free(message);
                 dialog_message_free(message);
                 scene_state->selected_control = TokenSecretTextBox;
                 scene_state->selected_control = TokenSecretTextBox;
                 update_screen_y_offset(scene_state);
                 update_screen_y_offset(scene_state);

+ 77 - 16
ui/scenes/app_settings/totp_app_settings.c

@@ -1,20 +1,25 @@
 #include "totp_app_settings.h"
 #include "totp_app_settings.h"
 #include <math.h>
 #include <math.h>
+#include <totp_icons.h>
 #include "../../ui_controls.h"
 #include "../../ui_controls.h"
 #include "../../scene_director.h"
 #include "../../scene_director.h"
 #include "../token_menu/totp_scene_token_menu.h"
 #include "../token_menu/totp_scene_token_menu.h"
 #include "../../constants.h"
 #include "../../constants.h"
 #include "../../../services/config/config.h"
 #include "../../../services/config/config.h"
+#include "../../../services/convert/convert.h"
 #include "../../../lib/roll_value/roll_value.h"
 #include "../../../lib/roll_value/roll_value.h"
 #include "../../../types/nullable.h"
 #include "../../../types/nullable.h"
 
 
-#define DIGIT_TO_CHAR(digit) ((digit) + '0')
+char* YES_NO_LIST[] = {"NO", "YES"};
 
 
-typedef enum { HoursInput, MinutesInput, ConfirmButton } Control;
+typedef enum { HoursInput, MinutesInput, Sound, Vibro, ConfirmButton } Control;
 
 
 typedef struct {
 typedef struct {
     int8_t tz_offset_hours;
     int8_t tz_offset_hours;
     uint8_t tz_offset_minutes;
     uint8_t tz_offset_minutes;
+    bool notification_sound;
+    bool notification_vibro;
+    uint8_t y_offset;
     TotpNullable_uint16_t current_token_index;
     TotpNullable_uint16_t current_token_index;
     Control selected_control;
     Control selected_control;
 } SceneState;
 } SceneState;
@@ -39,55 +44,87 @@ void totp_scene_app_settings_activate(
     float off_dec = modff(plugin_state->timezone_offset, &off_int);
     float off_dec = modff(plugin_state->timezone_offset, &off_int);
     scene_state->tz_offset_hours = off_int;
     scene_state->tz_offset_hours = off_int;
     scene_state->tz_offset_minutes = 60.0f * off_dec;
     scene_state->tz_offset_minutes = 60.0f * off_dec;
+    scene_state->notification_sound = plugin_state->notification_method & NotificationMethodSound;
+    scene_state->notification_vibro = plugin_state->notification_method & NotificationMethodVibro;
 }
 }
 
 
 static void two_digit_to_str(int8_t num, char* str) {
 static void two_digit_to_str(int8_t num, char* str) {
     uint8_t index = 0;
     uint8_t index = 0;
     if(num < 0) {
     if(num < 0) {
-        str[0] = '-';
-        index++;
+        str[index++] = '-';
         num = -num;
         num = -num;
     }
     }
 
 
     uint8_t d1 = (num / 10) % 10;
     uint8_t d1 = (num / 10) % 10;
     uint8_t d2 = num % 10;
     uint8_t d2 = num % 10;
-    str[index] = DIGIT_TO_CHAR(d1);
-    str[index + 1] = DIGIT_TO_CHAR(d2);
-    str[index + 2] = '\0';
+    str[index++] = CONVERT_DIGIT_TO_CHAR(d1);
+    str[index++] = CONVERT_DIGIT_TO_CHAR(d2);
+    str[index++] = '\0';
 }
 }
 
 
-void totp_scene_app_settings_render(Canvas* const canvas, PluginState* plugin_state) {
-    const SceneState* scene_state = (SceneState*)plugin_state->current_scene_state;
+void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plugin_state) {
+    const SceneState* scene_state = plugin_state->current_scene_state;
 
 
     canvas_set_font(canvas, FontPrimary);
     canvas_set_font(canvas, FontPrimary);
-    canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, "Timezone offset");
+    canvas_draw_str_aligned(
+        canvas, 0, 0 - scene_state->y_offset, AlignLeft, AlignTop, "Timezone offset");
     canvas_set_font(canvas, FontSecondary);
     canvas_set_font(canvas, FontSecondary);
 
 
     char tmp_str[4];
     char tmp_str[4];
     two_digit_to_str(scene_state->tz_offset_hours, &tmp_str[0]);
     two_digit_to_str(scene_state->tz_offset_hours, &tmp_str[0]);
-    canvas_draw_str_aligned(canvas, 0, 16, AlignLeft, AlignTop, "Hours:");
+    canvas_draw_str_aligned(canvas, 0, 16 - scene_state->y_offset, AlignLeft, AlignTop, "Hours:");
     ui_control_select_render(
     ui_control_select_render(
         canvas,
         canvas,
         36,
         36,
-        10,
+        10 - scene_state->y_offset,
         SCREEN_WIDTH - 36,
         SCREEN_WIDTH - 36,
         &tmp_str[0],
         &tmp_str[0],
         scene_state->selected_control == HoursInput);
         scene_state->selected_control == HoursInput);
 
 
     two_digit_to_str(scene_state->tz_offset_minutes, &tmp_str[0]);
     two_digit_to_str(scene_state->tz_offset_minutes, &tmp_str[0]);
-    canvas_draw_str_aligned(canvas, 0, 34, AlignLeft, AlignTop, "Minutes:");
+    canvas_draw_str_aligned(
+        canvas, 0, 34 - scene_state->y_offset, AlignLeft, AlignTop, "Minutes:");
     ui_control_select_render(
     ui_control_select_render(
         canvas,
         canvas,
         36,
         36,
-        28,
+        28 - scene_state->y_offset,
         SCREEN_WIDTH - 36,
         SCREEN_WIDTH - 36,
         &tmp_str[0],
         &tmp_str[0],
         scene_state->selected_control == MinutesInput);
         scene_state->selected_control == MinutesInput);
 
 
+    canvas_draw_icon(
+        canvas,
+        SCREEN_WIDTH_CENTER - 5,
+        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, "Notifications");
+    canvas_set_font(canvas, FontSecondary);
+
+    canvas_draw_str_aligned(canvas, 0, 80 - scene_state->y_offset, AlignLeft, AlignTop, "Sound:");
+    ui_control_select_render(
+        canvas,
+        36,
+        74 - scene_state->y_offset,
+        SCREEN_WIDTH - 36,
+        YES_NO_LIST[scene_state->notification_sound],
+        scene_state->selected_control == Sound);
+
+    canvas_draw_str_aligned(canvas, 0, 98 - scene_state->y_offset, AlignLeft, AlignTop, "Vibro:");
+    ui_control_select_render(
+        canvas,
+        36,
+        92 - scene_state->y_offset,
+        SCREEN_WIDTH - 36,
+        YES_NO_LIST[scene_state->notification_vibro],
+        scene_state->selected_control == Vibro);
+
     ui_control_button_render(
     ui_control_button_render(
         canvas,
         canvas,
         SCREEN_WIDTH_CENTER - 24,
         SCREEN_WIDTH_CENTER - 24,
-        50,
+        115 - scene_state->y_offset,
         48,
         48,
         13,
         13,
         "Confirm",
         "Confirm",
@@ -114,10 +151,20 @@ bool totp_scene_app_settings_handle_event(
             HoursInput,
             HoursInput,
             ConfirmButton,
             ConfirmButton,
             RollOverflowBehaviorStop);
             RollOverflowBehaviorStop);
+        if(scene_state->selected_control > MinutesInput) {
+            scene_state->y_offset = 64;
+        } else {
+            scene_state->y_offset = 0;
+        }
         break;
         break;
     case InputKeyDown:
     case InputKeyDown:
         totp_roll_value_uint8_t(
         totp_roll_value_uint8_t(
             &scene_state->selected_control, 1, HoursInput, ConfirmButton, RollOverflowBehaviorStop);
             &scene_state->selected_control, 1, HoursInput, ConfirmButton, RollOverflowBehaviorStop);
+        if(scene_state->selected_control > MinutesInput) {
+            scene_state->y_offset = 64;
+        } else {
+            scene_state->y_offset = 0;
+        }
         break;
         break;
     case InputKeyRight:
     case InputKeyRight:
         if(scene_state->selected_control == HoursInput) {
         if(scene_state->selected_control == HoursInput) {
@@ -126,6 +173,10 @@ bool totp_scene_app_settings_handle_event(
         } else if(scene_state->selected_control == MinutesInput) {
         } else if(scene_state->selected_control == MinutesInput) {
             totp_roll_value_uint8_t(
             totp_roll_value_uint8_t(
                 &scene_state->tz_offset_minutes, 15, 0, 45, RollOverflowBehaviorRoll);
                 &scene_state->tz_offset_minutes, 15, 0, 45, RollOverflowBehaviorRoll);
+        } else if(scene_state->selected_control == Sound) {
+            scene_state->notification_sound = !scene_state->notification_sound;
+        } else if(scene_state->selected_control == Vibro) {
+            scene_state->notification_vibro = !scene_state->notification_vibro;
         }
         }
         break;
         break;
     case InputKeyLeft:
     case InputKeyLeft:
@@ -135,13 +186,23 @@ bool totp_scene_app_settings_handle_event(
         } else if(scene_state->selected_control == MinutesInput) {
         } else if(scene_state->selected_control == MinutesInput) {
             totp_roll_value_uint8_t(
             totp_roll_value_uint8_t(
                 &scene_state->tz_offset_minutes, -15, 0, 45, RollOverflowBehaviorRoll);
                 &scene_state->tz_offset_minutes, -15, 0, 45, RollOverflowBehaviorRoll);
+        } else if(scene_state->selected_control == Sound) {
+            scene_state->notification_sound = !scene_state->notification_sound;
+        } else if(scene_state->selected_control == Vibro) {
+            scene_state->notification_vibro = !scene_state->notification_vibro;
         }
         }
         break;
         break;
     case InputKeyOk:
     case InputKeyOk:
         if(scene_state->selected_control == ConfirmButton) {
         if(scene_state->selected_control == ConfirmButton) {
             plugin_state->timezone_offset = (float)scene_state->tz_offset_hours +
             plugin_state->timezone_offset = (float)scene_state->tz_offset_hours +
                                             (float)scene_state->tz_offset_minutes / 60.0f;
                                             (float)scene_state->tz_offset_minutes / 60.0f;
-            totp_config_file_update_timezone_offset(plugin_state->timezone_offset);
+
+            plugin_state->notification_method =
+                (scene_state->notification_sound ? NotificationMethodSound :
+                                                   NotificationMethodNone) |
+                (scene_state->notification_vibro ? NotificationMethodVibro :
+                                                   NotificationMethodNone);
+            totp_config_file_update_user_settings(plugin_state);
 
 
             if(!scene_state->current_token_index.is_null) {
             if(!scene_state->current_token_index.is_null) {
                 TokenMenuSceneContext generate_scene_context = {
                 TokenMenuSceneContext generate_scene_context = {

+ 1 - 1
ui/scenes/app_settings/totp_app_settings.h

@@ -12,7 +12,7 @@ void totp_scene_app_settings_init(const PluginState* plugin_state);
 void totp_scene_app_settings_activate(
 void totp_scene_app_settings_activate(
     PluginState* plugin_state,
     PluginState* plugin_state,
     const AppSettingsSceneContext* context);
     const AppSettingsSceneContext* context);
-void totp_scene_app_settings_render(Canvas* const canvas, PluginState* plugin_state);
+void totp_scene_app_settings_render(Canvas* const canvas, const PluginState* plugin_state);
 bool totp_scene_app_settings_handle_event(
 bool totp_scene_app_settings_handle_event(
     const PluginEvent* const event,
     const PluginEvent* const event,
     PluginState* plugin_state);
     PluginState* plugin_state);

+ 1 - 1
ui/scenes/authenticate/totp_scene_authenticate.c

@@ -139,7 +139,7 @@ bool totp_scene_authenticate_handle_event(
                 AlignCenter,
                 AlignCenter,
                 AlignCenter);
                 AlignCenter);
             dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17);
             dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17);
-            dialog_message_show(plugin_state->dialogs, message);
+            dialog_message_show(plugin_state->dialogs_app, message);
             dialog_message_free(message);
             dialog_message_free(message);
         }
         }
         break;
         break;

+ 113 - 53
ui/scenes/generate_token/totp_scene_generate_token.c

@@ -9,6 +9,7 @@
 #include "../../../services/totp/totp.h"
 #include "../../../services/totp/totp.h"
 #include "../../../services/config/config.h"
 #include "../../../services/config/config.h"
 #include "../../../services/crypto/crypto.h"
 #include "../../../services/crypto/crypto.h"
+#include "../../../services/convert/convert.h"
 #include "../../../lib/polyfills/memset_s.h"
 #include "../../../lib/polyfills/memset_s.h"
 #include "../../../lib/roll_value/roll_value.h"
 #include "../../../lib/roll_value/roll_value.h"
 #include "../../scene_director.h"
 #include "../../scene_director.h"
@@ -16,7 +17,6 @@
 #include "../../../workers/type_code/type_code.h"
 #include "../../../workers/type_code/type_code.h"
 
 
 #define TOKEN_LIFETIME 30
 #define TOKEN_LIFETIME 30
-#define DIGIT_TO_CHAR(digit) ((digit) + '0')
 
 
 typedef struct {
 typedef struct {
     uint16_t current_token_index;
     uint16_t current_token_index;
@@ -25,59 +25,107 @@ typedef struct {
     bool need_token_update;
     bool need_token_update;
     uint32_t last_token_gen_time;
     uint32_t last_token_gen_time;
     TotpTypeCodeWorkerContext* type_code_worker_context;
     TotpTypeCodeWorkerContext* type_code_worker_context;
+    NotificationMessage const** notification_sequence_new_token;
+    NotificationMessage const** notification_sequence_badusb;
 } SceneState;
 } SceneState;
 
 
-static const NotificationSequence notification_sequence_new_token = {
-    &message_display_backlight_on,
-    &message_green_255,
-    &message_vibro_on,
-    &message_note_c5,
-    &message_delay_50,
-    &message_vibro_off,
-    &message_sound_off,
-    NULL,
-};
-
-static const NotificationSequence notification_sequence_badusb = {
-    &message_vibro_on,
-    &message_note_d5,
-    &message_delay_50,
-    &message_note_e4,
-    &message_delay_50,
-    &message_note_f3,
-    &message_delay_50,
-    &message_vibro_off,
-    &message_sound_off,
-    NULL,
-};
-
-static void i_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount len) {
-    uint8_t str_token_length = 0;
-    if(len == TOTP_8_DIGITS) {
-        str[8] = '\0';
-        str_token_length = 8;
-    } else if(len == TOTP_6_DIGITS) {
-        str[6] = '\0';
-        str_token_length = 6;
+static const NotificationSequence*
+    get_notification_sequence_new_token(const PluginState* plugin_state, SceneState* scene_state) {
+    if(scene_state->notification_sequence_new_token == NULL) {
+        uint8_t i = 0;
+        uint8_t length = 4;
+        if(plugin_state->notification_method & NotificationMethodVibro) {
+            length += 2;
+        }
+
+        if(plugin_state->notification_method & NotificationMethodSound) {
+            length += 2;
+        }
+
+        scene_state->notification_sequence_new_token = malloc(sizeof(void*) * length);
+        furi_check(scene_state->notification_sequence_new_token != NULL);
+        scene_state->notification_sequence_new_token[i++] = &message_display_backlight_on;
+        scene_state->notification_sequence_new_token[i++] = &message_green_255;
+        if(plugin_state->notification_method & NotificationMethodVibro) {
+            scene_state->notification_sequence_new_token[i++] = &message_vibro_on;
+        }
+
+        if(plugin_state->notification_method & NotificationMethodSound) {
+            scene_state->notification_sequence_new_token[i++] = &message_note_c5;
+        }
+
+        scene_state->notification_sequence_new_token[i++] = &message_delay_50;
+
+        if(plugin_state->notification_method & NotificationMethodVibro) {
+            scene_state->notification_sequence_new_token[i++] = &message_vibro_off;
+        }
+
+        if(plugin_state->notification_method & NotificationMethodSound) {
+            scene_state->notification_sequence_new_token[i++] = &message_sound_off;
+        }
+
+        scene_state->notification_sequence_new_token[i++] = NULL;
     }
     }
 
 
+    return (NotificationSequence*)scene_state->notification_sequence_new_token;
+}
+
+static const NotificationSequence*
+    get_notification_sequence_badusb(const PluginState* plugin_state, SceneState* scene_state) {
+    if(scene_state->notification_sequence_badusb == NULL) {
+        uint8_t i = 0;
+        uint8_t length = 3;
+        if(plugin_state->notification_method & NotificationMethodVibro) {
+            length += 2;
+        }
+
+        if(plugin_state->notification_method & NotificationMethodSound) {
+            length += 6;
+        }
+
+        scene_state->notification_sequence_badusb = malloc(sizeof(void*) * length);
+        furi_check(scene_state->notification_sequence_badusb != NULL);
+
+        scene_state->notification_sequence_badusb[i++] = &message_blue_255;
+        if(plugin_state->notification_method & NotificationMethodVibro) {
+            scene_state->notification_sequence_badusb[i++] = &message_vibro_on;
+        }
+
+        if(plugin_state->notification_method & NotificationMethodSound) {
+            scene_state->notification_sequence_badusb[i++] = &message_note_d5; //-V525
+            scene_state->notification_sequence_badusb[i++] = &message_delay_50;
+            scene_state->notification_sequence_badusb[i++] = &message_note_e4;
+            scene_state->notification_sequence_badusb[i++] = &message_delay_50;
+            scene_state->notification_sequence_badusb[i++] = &message_note_f3;
+        }
+
+        scene_state->notification_sequence_badusb[i++] = &message_delay_50;
+
+        if(plugin_state->notification_method & NotificationMethodVibro) {
+            scene_state->notification_sequence_badusb[i++] = &message_vibro_off;
+        }
+
+        if(plugin_state->notification_method & NotificationMethodSound) {
+            scene_state->notification_sequence_badusb[i++] = &message_sound_off;
+        }
+
+        scene_state->notification_sequence_badusb[i++] = NULL;
+    }
+
+    return (NotificationSequence*)scene_state->notification_sequence_badusb;
+}
+
+static void int_token_to_str(uint32_t i_token_code, char* str, TokenDigitsCount len) {
     if(i_token_code == OTP_ERROR) {
     if(i_token_code == OTP_ERROR) {
-        memset(&str[0], '-', str_token_length);
+        memset(&str[0], '-', len);
     } else {
     } else {
-        if(len == TOTP_8_DIGITS) {
-            str[7] = DIGIT_TO_CHAR(i_token_code % 10);
-            str[6] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
-            str[5] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
-        } else if(len == TOTP_6_DIGITS) {
-            str[5] = DIGIT_TO_CHAR(i_token_code % 10);
+        for(int i = len - 1; i >= 0; i--) {
+            str[i] = CONVERT_DIGIT_TO_CHAR(i_token_code % 10);
+            i_token_code = i_token_code / 10;
         }
         }
-
-        str[4] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
-        str[3] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
-        str[2] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
-        str[1] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
-        str[0] = DIGIT_TO_CHAR((i_token_code = i_token_code / 10) % 10);
     }
     }
+
+    str[len] = '\0';
 }
 }
 
 
 TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) {
 TOTP_ALGO get_totp_algo_impl(TokenHashAlgo algo) {
@@ -137,7 +185,7 @@ void totp_scene_generate_token_activate(
                     AlignCenter);
                     AlignCenter);
             }
             }
 
 
-            dialog_message_show(plugin_state->dialogs, message);
+            dialog_message_show(plugin_state->dialogs_app, message);
             dialog_message_free(message);
             dialog_message_free(message);
         }
         }
     }
     }
@@ -202,10 +250,10 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
             uint8_t* key = totp_crypto_decrypt(
             uint8_t* key = totp_crypto_decrypt(
                 tokenInfo->token, tokenInfo->token_length, &plugin_state->iv[0], &key_length);
                 tokenInfo->token, tokenInfo->token_length, &plugin_state->iv[0], &key_length);
 
 
-            i_token_to_str(
+            int_token_to_str(
                 totp_at(
                 totp_at(
                     get_totp_algo_impl(tokenInfo->algo),
                     get_totp_algo_impl(tokenInfo->algo),
-                    token_info_get_digits_count(tokenInfo),
+                    tokenInfo->digits,
                     key,
                     key,
                     key_length,
                     key_length,
                     curr_ts,
                     curr_ts,
@@ -218,13 +266,15 @@ void totp_scene_generate_token_render(Canvas* const canvas, PluginState* plugin_
         } else {
         } else {
             furi_mutex_acquire(
             furi_mutex_acquire(
                 scene_state->type_code_worker_context->string_sync, FuriWaitForever);
                 scene_state->type_code_worker_context->string_sync, FuriWaitForever);
-            i_token_to_str(0, scene_state->last_code, tokenInfo->digits);
+            int_token_to_str(0, scene_state->last_code, tokenInfo->digits);
         }
         }
 
 
         furi_mutex_release(scene_state->type_code_worker_context->string_sync);
         furi_mutex_release(scene_state->type_code_worker_context->string_sync);
 
 
         if(is_new_token_time) {
         if(is_new_token_time) {
-            notification_message(plugin_state->notification, &notification_sequence_new_token);
+            notification_message(
+                plugin_state->notification_app,
+                get_notification_sequence_new_token(plugin_state, scene_state));
         }
         }
     }
     }
 
 
@@ -291,8 +341,10 @@ bool totp_scene_generate_token_handle_event(
     if(event->input.type == InputTypeLong && event->input.key == InputKeyDown) {
     if(event->input.type == InputTypeLong && event->input.key == InputKeyDown) {
         scene_state = (SceneState*)plugin_state->current_scene_state;
         scene_state = (SceneState*)plugin_state->current_scene_state;
         totp_type_code_worker_notify(
         totp_type_code_worker_notify(
-            scene_state->type_code_worker_context, TotpTypeCodeWorkerEvtType);
-        notification_message(plugin_state->notification, &notification_sequence_badusb);
+            scene_state->type_code_worker_context, TotpTypeCodeWorkerEventType);
+        notification_message(
+            plugin_state->notification_app,
+            get_notification_sequence_badusb(plugin_state, scene_state));
         return true;
         return true;
     }
     }
 
 
@@ -347,6 +399,14 @@ void totp_scene_generate_token_deactivate(PluginState* plugin_state) {
 
 
     totp_type_code_worker_stop(scene_state->type_code_worker_context);
     totp_type_code_worker_stop(scene_state->type_code_worker_context);
 
 
+    if(scene_state->notification_sequence_new_token != NULL) {
+        free(scene_state->notification_sequence_new_token);
+    }
+
+    if(scene_state->notification_sequence_badusb != NULL) {
+        free(scene_state->notification_sequence_badusb);
+    }
+
     free(scene_state);
     free(scene_state);
     plugin_state->current_scene_state = NULL;
     plugin_state->current_scene_state = NULL;
 }
 }

+ 1 - 1
ui/scenes/token_menu/totp_scene_token_menu.c

@@ -143,7 +143,7 @@ bool totp_scene_token_menu_handle_event(const PluginEvent* const event, PluginSt
                 AlignCenter,
                 AlignCenter,
                 AlignCenter);
                 AlignCenter);
             DialogMessageButton dialog_result =
             DialogMessageButton dialog_result =
-                dialog_message_show(plugin_state->dialogs, message);
+                dialog_message_show(plugin_state->dialogs_app, message);
             dialog_message_free(message);
             dialog_message_free(message);
             if(dialog_result == DialogMessageButtonRight &&
             if(dialog_result == DialogMessageButtonRight &&
                !scene_state->current_token_index.is_null) {
                !scene_state->current_token_index.is_null) {

+ 4 - 2
ui/totp_scenes_enum.h

@@ -1,9 +1,11 @@
 #pragma once
 #pragma once
 
 
+typedef uint8_t Scene;
+
 /**
 /**
  * @brief TOTP application scenes
  * @brief TOTP application scenes
  */
  */
-typedef enum {
+enum Scenes {
     /**
     /**
      * @brief Empty scene which does nothing 
      * @brief Empty scene which does nothing 
      */
      */
@@ -33,4 +35,4 @@ typedef enum {
      * @brief Scene where user can change application settings 
      * @brief Scene where user can change application settings 
      */
      */
     TotpSceneAppSettings
     TotpSceneAppSettings
-} Scene;
+};

+ 8 - 7
workers/type_code/type_code.c

@@ -1,4 +1,5 @@
 #include "type_code.h"
 #include "type_code.h"
+#include "../../services/convert/convert.h"
 
 
 static const uint8_t hid_number_keys[10] = {
 static const uint8_t hid_number_keys[10] = {
     HID_KEYBOARD_0,
     HID_KEYBOARD_0,
@@ -20,7 +21,7 @@ static void totp_type_code_worker_restore_usb_mode(TotpTypeCodeWorkerContext* co
 }
 }
 
 
 static inline bool totp_type_code_worker_stop_requested() {
 static inline bool totp_type_code_worker_stop_requested() {
-    return furi_thread_flags_get() & TotpTypeCodeWorkerEvtStop;
+    return furi_thread_flags_get() & TotpTypeCodeWorkerEventStop;
 }
 }
 
 
 static void totp_type_code_worker_type_code(TotpTypeCodeWorkerContext* context) {
 static void totp_type_code_worker_type_code(TotpTypeCodeWorkerContext* context) {
@@ -38,7 +39,7 @@ static void totp_type_code_worker_type_code(TotpTypeCodeWorkerContext* context)
         furi_delay_ms(500);
         furi_delay_ms(500);
         i = 0;
         i = 0;
         while(i < context->string_length && context->string[i] != 0) {
         while(i < context->string_length && context->string[i] != 0) {
-            uint8_t digit = context->string[i] - '0';
+            uint8_t digit = CONVERT_CHAR_TO_DIGIT(context->string[i]);
             if(digit > 9) break;
             if(digit > 9) break;
             uint8_t hid_kb_key = hid_number_keys[digit];
             uint8_t hid_kb_key = hid_number_keys[digit];
             furi_hal_hid_kb_press(hid_kb_key);
             furi_hal_hid_kb_press(hid_kb_key);
@@ -63,14 +64,14 @@ static int32_t totp_type_code_worker_callback(void* context) {
 
 
     while(true) {
     while(true) {
         uint32_t flags = furi_thread_flags_wait(
         uint32_t flags = furi_thread_flags_wait(
-            TotpTypeCodeWorkerEvtStop | TotpTypeCodeWorkerEvtType,
+            TotpTypeCodeWorkerEventStop | TotpTypeCodeWorkerEventType,
             FuriFlagWaitAny,
             FuriFlagWaitAny,
             FuriWaitForever);
             FuriWaitForever);
         furi_check((flags & FuriFlagError) == 0); //-V562
         furi_check((flags & FuriFlagError) == 0); //-V562
-        if(flags & TotpTypeCodeWorkerEvtStop) break;
+        if(flags & TotpTypeCodeWorkerEventStop) break;
 
 
         TotpTypeCodeWorkerContext* h_context = acquire_mutex_block(&context_mutex);
         TotpTypeCodeWorkerContext* h_context = acquire_mutex_block(&context_mutex);
-        if(flags & TotpTypeCodeWorkerEvtType) {
+        if(flags & TotpTypeCodeWorkerEventType) {
             totp_type_code_worker_type_code(h_context);
             totp_type_code_worker_type_code(h_context);
         }
         }
 
 
@@ -98,7 +99,7 @@ TotpTypeCodeWorkerContext* totp_type_code_worker_start() {
 
 
 void totp_type_code_worker_stop(TotpTypeCodeWorkerContext* context) {
 void totp_type_code_worker_stop(TotpTypeCodeWorkerContext* context) {
     furi_assert(context != NULL);
     furi_assert(context != NULL);
-    furi_thread_flags_set(furi_thread_get_id(context->thread), TotpTypeCodeWorkerEvtStop);
+    furi_thread_flags_set(furi_thread_get_id(context->thread), TotpTypeCodeWorkerEventStop);
     furi_thread_join(context->thread);
     furi_thread_join(context->thread);
     furi_thread_free(context->thread);
     furi_thread_free(context->thread);
     furi_mutex_free(context->string_sync);
     furi_mutex_free(context->string_sync);
@@ -108,7 +109,7 @@ void totp_type_code_worker_stop(TotpTypeCodeWorkerContext* context) {
 
 
 void totp_type_code_worker_notify(
 void totp_type_code_worker_notify(
     TotpTypeCodeWorkerContext* context,
     TotpTypeCodeWorkerContext* context,
-    TotpTypeCodeWorkerEvtFlags event) {
+    TotpTypeCodeWorkerEvent event) {
     furi_assert(context != NULL);
     furi_assert(context != NULL);
     furi_thread_flags_set(furi_thread_get_id(context->thread), event);
     furi_thread_flags_set(furi_thread_get_id(context->thread), event);
 }
 }

+ 8 - 6
workers/type_code/type_code.h

@@ -4,6 +4,8 @@
 #include <furi/furi.h>
 #include <furi/furi.h>
 #include <furi_hal.h>
 #include <furi_hal.h>
 
 
+typedef uint8_t TotpTypeCodeWorkerEvent;
+
 typedef struct {
 typedef struct {
     char* string;
     char* string;
     uint8_t string_length;
     uint8_t string_length;
@@ -12,14 +14,14 @@ typedef struct {
     FuriHalUsbInterface* usb_mode_prev;
     FuriHalUsbInterface* usb_mode_prev;
 } TotpTypeCodeWorkerContext;
 } TotpTypeCodeWorkerContext;
 
 
-typedef enum {
-    TotpTypeCodeWorkerEvtReserved = (1 << 0),
-    TotpTypeCodeWorkerEvtStop = (1 << 1),
-    TotpTypeCodeWorkerEvtType = (1 << 2)
-} TotpTypeCodeWorkerEvtFlags;
+enum TotpTypeCodeWorkerEvents {
+    TotpTypeCodeWorkerEventReserved = (1 << 0),
+    TotpTypeCodeWorkerEventStop = (1 << 1),
+    TotpTypeCodeWorkerEventType = (1 << 2)
+};
 
 
 TotpTypeCodeWorkerContext* totp_type_code_worker_start();
 TotpTypeCodeWorkerContext* totp_type_code_worker_start();
 void totp_type_code_worker_stop(TotpTypeCodeWorkerContext* context);
 void totp_type_code_worker_stop(TotpTypeCodeWorkerContext* context);
 void totp_type_code_worker_notify(
 void totp_type_code_worker_notify(
     TotpTypeCodeWorkerContext* context,
     TotpTypeCodeWorkerContext* context,
-    TotpTypeCodeWorkerEvtFlags event);
+    TotpTypeCodeWorkerEvent event);