MX 1 год назад
Родитель
Сommit
783fd93617

+ 1 - 6
README.md

@@ -29,10 +29,5 @@ As i know these firmwares are supported and working if you know any more please
 - Add NFC Item (Adds the selected nfc item to the currently selected playlist)
 - Add NFC Item (Adds the selected nfc item to the currently selected playlist)
 - Remove NFC Item (Opens a menu allowing you to select a line to remove from the playlist)
 - Remove NFC Item (Opens a menu allowing you to select a line to remove from the playlist)
 - View playlist content (Allows you to view the contents of the playlist)
 - View playlist content (Allows you to view the contents of the playlist)
-## Development plans/ideas:
-Things i would like to add:
-- Ability to remove cards from the playlist
 
 
-These features are not guaranteed to be added but are being looked at as features to add
-
-Any feedback is welcome and would be very much appreciated
+Any feedback is welcome and would be very much appreciated

+ 2 - 2
application.fam

@@ -8,12 +8,12 @@ App(
     fap_category="NFC",
     fap_category="NFC",
     fap_author="@acegoal07",
     fap_author="@acegoal07",
     fap_weburl="https://github.com/acegoal07/FlipperZero_NFC_Playlist/tree/main",
     fap_weburl="https://github.com/acegoal07/FlipperZero_NFC_Playlist/tree/main",
-    fap_version="2.1",
+    fap_version="2.2",
     fap_icon_assets="assets",
     fap_icon_assets="assets",
     fap_icon="icon.png",
     fap_icon="icon.png",
     fap_private_libs=[
     fap_private_libs=[
         Lib(
         Lib(
-            name="worker",
+            name="emulation_worker",
         ),
         ),
     ],
     ],
 )
 )

+ 84 - 0
lib/emulation_worker/nfc_playlist_emulation_worker.c

@@ -0,0 +1,84 @@
+#include "nfc_playlist_emulation_worker.h"
+
+NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker_alloc() {
+    NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker =
+        malloc(sizeof(NfcPlaylistEmulationWorker));
+    nfc_playlist_emulation_worker->thread = furi_thread_alloc_ex(
+        "NfcPlaylistEmulationWorker",
+        4096,
+        nfc_playlist_emulation_worker_task,
+        nfc_playlist_emulation_worker);
+    nfc_playlist_emulation_worker->state = NfcPlaylistEmulationWorkerState_Stopped;
+    nfc_playlist_emulation_worker->nfc = nfc_alloc();
+    nfc_playlist_emulation_worker->nfc_device = nfc_device_alloc();
+    return nfc_playlist_emulation_worker;
+}
+
+void nfc_playlist_emulation_worker_free(NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker) {
+    furi_assert(nfc_playlist_emulation_worker);
+    furi_thread_free(nfc_playlist_emulation_worker->thread);
+    nfc_free(nfc_playlist_emulation_worker->nfc);
+    nfc_device_free(nfc_playlist_emulation_worker->nfc_device);
+    free(nfc_playlist_emulation_worker);
+}
+
+void nfc_playlist_emulation_worker_stop(NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker) {
+    furi_assert(nfc_playlist_emulation_worker);
+    if(nfc_playlist_emulation_worker->state != NfcPlaylistEmulationWorkerState_Stopped) {
+        nfc_playlist_emulation_worker->state = NfcPlaylistEmulationWorkerState_Stopped;
+        furi_thread_join(nfc_playlist_emulation_worker->thread);
+    }
+}
+
+void nfc_playlist_emulation_worker_start(
+    NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker) {
+    furi_assert(nfc_playlist_emulation_worker);
+    nfc_playlist_emulation_worker->state = NfcPlaylistEmulationWorkerState_Emulating;
+    furi_thread_start(nfc_playlist_emulation_worker->thread);
+}
+
+int32_t nfc_playlist_emulation_worker_task(void* context) {
+    NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker = context;
+
+    if(nfc_playlist_emulation_worker->state == NfcPlaylistEmulationWorkerState_Emulating) {
+        nfc_playlist_emulation_worker->nfc_listener = nfc_listener_alloc(
+            nfc_playlist_emulation_worker->nfc,
+            nfc_playlist_emulation_worker->nfc_protocol,
+            nfc_device_get_data(
+                nfc_playlist_emulation_worker->nfc_device,
+                nfc_playlist_emulation_worker->nfc_protocol));
+        nfc_listener_start(nfc_playlist_emulation_worker->nfc_listener, NULL, NULL);
+
+        while(nfc_playlist_emulation_worker->state == NfcPlaylistEmulationWorkerState_Emulating) {
+            furi_delay_ms(50);
+        }
+
+        nfc_listener_stop(nfc_playlist_emulation_worker->nfc_listener);
+        nfc_listener_free(nfc_playlist_emulation_worker->nfc_listener);
+    }
+
+    nfc_playlist_emulation_worker->state = NfcPlaylistEmulationWorkerState_Stopped;
+
+    return 0;
+}
+
+bool nfc_playlist_emulation_worker_is_emulating(
+    NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker) {
+    furi_assert(nfc_playlist_emulation_worker);
+    return nfc_playlist_emulation_worker->state == NfcPlaylistEmulationWorkerState_Emulating;
+}
+
+void nfc_playlist_emulation_worker_set_nfc_data(
+    NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker,
+    char* file_path) {
+    furi_assert(nfc_playlist_emulation_worker);
+    nfc_device_load(nfc_playlist_emulation_worker->nfc_device, file_path);
+    nfc_playlist_emulation_worker->nfc_protocol =
+        nfc_device_get_protocol(nfc_playlist_emulation_worker->nfc_device);
+}
+
+void nfc_playlist_emulation_worker_clear_nfc_data(
+    NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker) {
+    furi_assert(nfc_playlist_emulation_worker);
+    nfc_device_clear(nfc_playlist_emulation_worker->nfc_device);
+}

+ 35 - 0
lib/emulation_worker/nfc_playlist_emulation_worker.h

@@ -0,0 +1,35 @@
+#pragma once
+#include <furi.h>
+#include <furi_hal.h>
+#include <nfc/nfc.h>
+#include <nfc/nfc_device.h>
+#include <nfc/nfc_listener.h>
+
+typedef enum NfcPlaylistEmulationWorkerState {
+    NfcPlaylistEmulationWorkerState_Emulating,
+    NfcPlaylistEmulationWorkerState_Stopped
+} NfcPlaylistEmulationWorkerState;
+
+typedef struct NfcPlaylistEmulationWorker {
+    FuriThread* thread;
+    NfcPlaylistEmulationWorkerState state;
+    NfcListener* nfc_listener;
+    NfcDevice* nfc_device;
+    NfcProtocol nfc_protocol;
+    Nfc* nfc;
+} NfcPlaylistEmulationWorker;
+
+NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker_alloc();
+void nfc_playlist_emulation_worker_free(NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker);
+void nfc_playlist_emulation_worker_stop(NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker);
+void nfc_playlist_emulation_worker_start(NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker);
+
+int32_t nfc_playlist_emulation_worker_task(void* context);
+
+bool nfc_playlist_emulation_worker_is_emulating(
+    NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker);
+void nfc_playlist_emulation_worker_set_nfc_data(
+    NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker,
+    char* file_path);
+void nfc_playlist_emulation_worker_clear_nfc_data(
+    NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker);

+ 0 - 73
lib/worker/nfc_playlist_worker.c

@@ -1,73 +0,0 @@
-#include "nfc_playlist_worker.h"
-
-NfcPlaylistWorker* nfc_playlist_worker_alloc() {
-   NfcPlaylistWorker* nfc_playlist_worker = malloc(sizeof(NfcPlaylistWorker));
-   nfc_playlist_worker->thread = furi_thread_alloc_ex("NfcPlaylistWorker", 8192, nfc_playlist_worker_task, nfc_playlist_worker);
-   nfc_playlist_worker->state = NfcPlaylistWorkerState_Stopped;
-   nfc_playlist_worker->nfc = nfc_alloc();
-   nfc_playlist_worker->nfc_device = nfc_device_alloc();
-   return nfc_playlist_worker;
-}
-
-void nfc_playlist_worker_free(NfcPlaylistWorker* nfc_playlist_worker) {
-   furi_assert(nfc_playlist_worker);
-   furi_thread_free(nfc_playlist_worker->thread);
-   nfc_free(nfc_playlist_worker->nfc);
-   nfc_device_free(nfc_playlist_worker->nfc_device);
-   free(nfc_playlist_worker);
-}
-
-void nfc_playlist_worker_stop(NfcPlaylistWorker* nfc_playlist_worker) {
-   furi_assert(nfc_playlist_worker);
-   if (nfc_playlist_worker->state != NfcPlaylistWorkerState_Stopped) {
-      nfc_playlist_worker->state = NfcPlaylistWorkerState_Stopped;
-      furi_thread_join(nfc_playlist_worker->thread);
-   }
-}
-
-void nfc_playlist_worker_start(NfcPlaylistWorker* nfc_playlist_worker) {
-   furi_assert(nfc_playlist_worker);
-   nfc_playlist_worker->state = NfcPlaylistWorkerState_Emulating;
-   furi_thread_start(nfc_playlist_worker->thread);
-}
-
-int32_t nfc_playlist_worker_task(void* context) {
-   NfcPlaylistWorker* nfc_playlist_worker = context;
-
-   if (nfc_playlist_worker->state == NfcPlaylistWorkerState_Emulating) {
-
-      nfc_playlist_worker->nfc_listener =
-         nfc_listener_alloc(nfc_playlist_worker->nfc,
-            nfc_playlist_worker->nfc_protocol,
-            nfc_device_get_data(nfc_playlist_worker->nfc_device, nfc_playlist_worker->nfc_protocol)
-         );
-      nfc_listener_start(nfc_playlist_worker->nfc_listener, NULL, NULL);
-
-      while(nfc_playlist_worker->state == NfcPlaylistWorkerState_Emulating) {
-         furi_delay_ms(50);
-      }
-
-      nfc_listener_stop(nfc_playlist_worker->nfc_listener);
-      nfc_listener_free(nfc_playlist_worker->nfc_listener);
-   }
-
-   nfc_playlist_worker->state = NfcPlaylistWorkerState_Stopped;
-
-   return 0;
-}
-
-bool nfc_playlist_worker_is_emulating(NfcPlaylistWorker* nfc_playlist_worker) {
-   furi_assert(nfc_playlist_worker);
-   return nfc_playlist_worker->state == NfcPlaylistWorkerState_Emulating;
-}
-
-void nfc_playlist_worker_set_nfc_data(NfcPlaylistWorker* nfc_playlist_worker, char* file_path) {
-   furi_assert(nfc_playlist_worker);
-   nfc_device_load(nfc_playlist_worker->nfc_device, file_path);
-   nfc_playlist_worker->nfc_protocol = nfc_device_get_protocol(nfc_playlist_worker->nfc_device);
-}
-
-void nfc_playlist_worker_clear_nfc_data(NfcPlaylistWorker* nfc_playlist_worker) {
-   furi_assert(nfc_playlist_worker);
-   nfc_device_clear(nfc_playlist_worker->nfc_device);
-}

+ 0 - 31
lib/worker/nfc_playlist_worker.h

@@ -1,31 +0,0 @@
-#pragma once
-#include <furi.h>
-#include <furi_hal.h>
-#include <nfc/nfc.h>
-#include <nfc/nfc_device.h>
-#include <nfc/nfc_listener.h>
-
-typedef enum NfcPlaylistWorkerState {
-   NfcPlaylistWorkerState_Emulating,
-   NfcPlaylistWorkerState_Stopped
-} NfcPlaylistWorkerState;
-
-typedef struct NfcPlaylistWorker {
-   FuriThread* thread;
-   NfcPlaylistWorkerState state;
-   NfcListener* nfc_listener;
-   NfcDevice* nfc_device;
-   NfcProtocol nfc_protocol;
-   Nfc* nfc;
-} NfcPlaylistWorker;
-
-NfcPlaylistWorker* nfc_playlist_worker_alloc();
-void nfc_playlist_worker_free(NfcPlaylistWorker* nfc_playlist_worker);
-void nfc_playlist_worker_stop(NfcPlaylistWorker* nfc_playlist_worker);
-void nfc_playlist_worker_start(NfcPlaylistWorker* nfc_playlist_worker);
-
-int32_t nfc_playlist_worker_task(void* context);
-
-bool nfc_playlist_worker_is_emulating(NfcPlaylistWorker* nfc_playlist_worker);
-void nfc_playlist_worker_set_nfc_data(NfcPlaylistWorker* nfc_playlist_worker, char* file_path);
-void nfc_playlist_worker_clear_nfc_data(NfcPlaylistWorker* nfc_playlist_worker);

+ 4 - 5
nfc_playlist.c

@@ -66,9 +66,8 @@ static NfcPlaylist* nfc_playlist_alloc() {
         text_input_get_view(nfc_playlist->text_input));
         text_input_get_view(nfc_playlist->text_input));
 
 
     Storage* storage = furi_record_open(RECORD_STORAGE);
     Storage* storage = furi_record_open(RECORD_STORAGE);
-    if(!storage_common_exists(storage, PLAYLIST_DIR)) {
-        storage_common_mkdir(storage, PLAYLIST_DIR);
-    }
+    storage_simply_mkdir(storage, PLAYLIST_DIR);
+
     furi_record_close(RECORD_STORAGE);
     furi_record_close(RECORD_STORAGE);
 
 
     return nfc_playlist;
     return nfc_playlist;
@@ -86,11 +85,11 @@ static void nfc_playlist_free(NfcPlaylist* nfc_playlist) {
 
 
     scene_manager_free(nfc_playlist->scene_manager);
     scene_manager_free(nfc_playlist->scene_manager);
     view_dispatcher_free(nfc_playlist->view_dispatcher);
     view_dispatcher_free(nfc_playlist->view_dispatcher);
+    furi_record_close(RECORD_NOTIFICATION);
+
     variable_item_list_free(nfc_playlist->variable_item_list);
     variable_item_list_free(nfc_playlist->variable_item_list);
     submenu_free(nfc_playlist->submenu);
     submenu_free(nfc_playlist->submenu);
     widget_free(nfc_playlist->widget);
     widget_free(nfc_playlist->widget);
-
-    furi_record_close(RECORD_NOTIFICATION);
     file_browser_free(nfc_playlist->file_browser);
     file_browser_free(nfc_playlist->file_browser);
     text_input_free(nfc_playlist->text_input);
     text_input_free(nfc_playlist->text_input);
     popup_free(nfc_playlist->popup);
     popup_free(nfc_playlist->popup);

+ 7 - 6
nfc_playlist.h

@@ -23,11 +23,16 @@
 
 
 #include <toolbox/stream/stream.h>
 #include <toolbox/stream/stream.h>
 #include <toolbox/stream/file_stream.h>
 #include <toolbox/stream/file_stream.h>
+#include <toolbox/path.h>
 
 
-#include "lib/worker/nfc_playlist_worker.h"
+#include "lib/emulation_worker/nfc_playlist_emulation_worker.h"
 
 
 #include "scenes/nfc_playlist_scene.h"
 #include "scenes/nfc_playlist_scene.h"
 
 
+#define PLAYLIST_LOCATION "/ext/apps_data/nfc_playlist/"
+#define PLAYLIST_DIR "/ext/apps_data/nfc_playlist"
+#define MAX_PLAYLIST_NAME_LEN 50
+
 typedef enum {
 typedef enum {
     NfcPlaylistView_Submenu,
     NfcPlaylistView_Submenu,
     NfcPlaylistView_Popup,
     NfcPlaylistView_Popup,
@@ -60,8 +65,7 @@ typedef struct {
     char* text_input_output;
     char* text_input_output;
     NotificationApp* notification;
     NotificationApp* notification;
     FuriThread* thread;
     FuriThread* thread;
-    FuriString* temp_furi_string;
-    NfcPlaylistWorker* nfc_playlist_worker;
+    NfcPlaylistEmulationWorker* nfc_playlist_emulation_worker;
     NfcPlaylistSettings settings;
     NfcPlaylistSettings settings;
 } NfcPlaylist;
 } NfcPlaylist;
 
 
@@ -72,9 +76,6 @@ static const int default_emulate_delay = 0;
 static const bool default_emulate_led_indicator = true;
 static const bool default_emulate_led_indicator = true;
 static const bool default_skip_error = false;
 static const bool default_skip_error = false;
 
 
-#define PLAYLIST_LOCATION "/ext/apps_data/nfc_playlist/"
-#define PLAYLIST_DIR "/ext/apps_data/nfc_playlist"
-
 typedef enum NfcPlaylistLedState {
 typedef enum NfcPlaylistLedState {
     NfcPlaylistLedState_Normal,
     NfcPlaylistLedState_Normal,
     NfcPlaylistLedState_Error
     NfcPlaylistLedState_Error

+ 12 - 12
scenes/nfc_playlist_scene_confirm_delete.c

@@ -10,13 +10,11 @@ void nfc_playlist_confirm_delete_menu_callback(GuiButtonType result, InputType t
 void nfc_playlist_confirm_delete_scene_on_enter(void* context) {
 void nfc_playlist_confirm_delete_scene_on_enter(void* context) {
     NfcPlaylist* nfc_playlist = context;
     NfcPlaylist* nfc_playlist = context;
 
 
-    FuriString* temp_str = furi_string_alloc();
-    char* file_path = (char*)furi_string_get_cstr(nfc_playlist->settings.playlist_path);
-    furi_string_printf(
-        temp_str,
-        "\e#Delete %s?\e#",
-        strchr(file_path, '/') != NULL ? &strrchr(file_path, '/')[1] : file_path);
-    furi_string_replace(temp_str, ".txt", "");
+    FuriString* file_name = furi_string_alloc();
+    path_extract_filename_no_ext(
+        furi_string_get_cstr(nfc_playlist->settings.playlist_path), file_name);
+    FuriString* temp_str =
+        furi_string_alloc_printf("\e#Delete %s?\e#", furi_string_get_cstr(file_name));
 
 
     widget_add_text_box_element(
     widget_add_text_box_element(
         nfc_playlist->widget,
         nfc_playlist->widget,
@@ -42,6 +40,7 @@ void nfc_playlist_confirm_delete_scene_on_enter(void* context) {
         nfc_playlist);
         nfc_playlist);
 
 
     furi_string_free(temp_str);
     furi_string_free(temp_str);
+    furi_string_free(file_name);
 
 
     view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Widget);
     view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Widget);
 }
 }
@@ -53,14 +52,15 @@ bool nfc_playlist_confirm_delete_scene_on_event(void* context, SceneManagerEvent
         switch(event.event) {
         switch(event.event) {
         case GuiButtonTypeRight:
         case GuiButtonTypeRight:
             Storage* storage = furi_record_open(RECORD_STORAGE);
             Storage* storage = furi_record_open(RECORD_STORAGE);
-            storage_simply_remove(
-                storage, furi_string_get_cstr(nfc_playlist->settings.playlist_path));
-            nfc_playlist->settings.playlist_selected = false;
-            furi_string_reset(nfc_playlist->settings.playlist_path);
+            if(storage_simply_remove(
+                   storage, furi_string_get_cstr(nfc_playlist->settings.playlist_path))) {
+                nfc_playlist->settings.playlist_selected = false;
+                furi_string_reset(nfc_playlist->settings.playlist_path);
+            }
             furi_record_close(RECORD_STORAGE);
             furi_record_close(RECORD_STORAGE);
-            consumed = true;
             scene_manager_search_and_switch_to_previous_scene(
             scene_manager_search_and_switch_to_previous_scene(
                 nfc_playlist->scene_manager, NfcPlaylistScene_MainMenu);
                 nfc_playlist->scene_manager, NfcPlaylistScene_MainMenu);
+            consumed = true;
             break;
             break;
         default:
         default:
             scene_manager_previous_scene(nfc_playlist->scene_manager);
             scene_manager_previous_scene(nfc_playlist->scene_manager);

+ 46 - 25
scenes/nfc_playlist_scene_emulation.c

@@ -31,6 +31,10 @@ int32_t nfc_playlist_emulation_task(void* context) {
         FuriString* line = furi_string_alloc();
         FuriString* line = furi_string_alloc();
         FuriString* tmp_header_str = furi_string_alloc();
         FuriString* tmp_header_str = furi_string_alloc();
         FuriString* tmp_counter_str = furi_string_alloc();
         FuriString* tmp_counter_str = furi_string_alloc();
+        FuriString* tmp_file_name = furi_string_alloc();
+        //
+        char tmp_file_ext[6] = {0};
+        //FuriString* tmp_file_ext = furi_string_alloc();
 
 
         while(stream_read_line(stream, line) &&
         while(stream_read_line(stream, line) &&
               EmulationState == NfcPlaylistEmulationState_Emulating) {
               EmulationState == NfcPlaylistEmulationState_Emulating) {
@@ -57,6 +61,7 @@ int32_t nfc_playlist_emulation_task(void* context) {
                         AlignTop);
                         AlignTop);
                     furi_delay_ms(50);
                     furi_delay_ms(50);
                     time_counter_delay_ms -= 50;
                     time_counter_delay_ms -= 50;
+                    furi_string_reset(tmp_counter_str);
                 };
                 };
             } else if(nfc_playlist->settings.emulate_delay > 0) {
             } else if(nfc_playlist->settings.emulate_delay > 0) {
                 skip_delay = false;
                 skip_delay = false;
@@ -67,18 +72,23 @@ int32_t nfc_playlist_emulation_task(void* context) {
                 break;
                 break;
             }
             }
 
 
-            char* file_name = strchr(file_path, '/') != NULL ? &strrchr(file_path, '/')[1] :
-                                                               file_path;
-            char const* file_ext = &strrchr(file_path, '.')[1];
+            path_extract_filename(line, tmp_file_name, false);
+            //path_extract_ext_str(line, tmp_file_ext);
+            // why?
+            path_extract_extension(line, tmp_file_ext, 6);
+
             int time_counter_ms =
             int time_counter_ms =
                 (options_emulate_timeout[nfc_playlist->settings.emulate_timeout] * 1000);
                 (options_emulate_timeout[nfc_playlist->settings.emulate_timeout] * 1000);
-
-            if(!strcasestr(file_ext, "nfc")) {
+            // use strcmp instead furi string to compare file extension
+            if(strcmp(tmp_file_ext, ".nfc") != 0) {
                 if(nfc_playlist->settings.skip_error) {
                 if(nfc_playlist->settings.skip_error) {
                     skip_delay = true;
                     skip_delay = true;
                     continue;
                     continue;
                 }
                 }
-                furi_string_printf(tmp_header_str, "ERROR invalid file:\n%s", file_name);
+                furi_string_printf(
+                    tmp_header_str,
+                    "ERROR invalid file:\n%s",
+                    furi_string_get_cstr(tmp_file_name));
                 popup_set_header(
                 popup_set_header(
                     nfc_playlist->popup,
                     nfc_playlist->popup,
                     furi_string_get_cstr(tmp_header_str),
                     furi_string_get_cstr(tmp_header_str),
@@ -105,7 +115,8 @@ int32_t nfc_playlist_emulation_task(void* context) {
                     skip_delay = true;
                     skip_delay = true;
                     continue;
                     continue;
                 }
                 }
-                furi_string_printf(tmp_header_str, "ERROR not found:\n%s", file_name);
+                furi_string_printf(
+                    tmp_header_str, "ERROR not found:\n%s", furi_string_get_cstr(tmp_file_name));
                 popup_set_header(
                 popup_set_header(
                     nfc_playlist->popup,
                     nfc_playlist->popup,
                     furi_string_get_cstr(tmp_header_str),
                     furi_string_get_cstr(tmp_header_str),
@@ -128,7 +139,8 @@ int32_t nfc_playlist_emulation_task(void* context) {
                     time_counter_ms -= 50;
                     time_counter_ms -= 50;
                 };
                 };
             } else {
             } else {
-                furi_string_printf(tmp_header_str, "Emulating:\n%s", file_name);
+                furi_string_printf(
+                    tmp_header_str, "Emulating:\n%s", furi_string_get_cstr(tmp_file_name));
                 popup_set_header(
                 popup_set_header(
                     nfc_playlist->popup,
                     nfc_playlist->popup,
                     furi_string_get_cstr(tmp_header_str),
                     furi_string_get_cstr(tmp_header_str),
@@ -136,10 +148,12 @@ int32_t nfc_playlist_emulation_task(void* context) {
                     10,
                     10,
                     AlignCenter,
                     AlignCenter,
                     AlignTop);
                     AlignTop);
-                nfc_playlist_worker_set_nfc_data(nfc_playlist->nfc_playlist_worker, file_path);
-                nfc_playlist_worker_start(nfc_playlist->nfc_playlist_worker);
+                nfc_playlist_emulation_worker_set_nfc_data(
+                    nfc_playlist->nfc_playlist_emulation_worker, file_path);
+                nfc_playlist_emulation_worker_start(nfc_playlist->nfc_playlist_emulation_worker);
                 start_blink(nfc_playlist, NfcPlaylistLedState_Normal);
                 start_blink(nfc_playlist, NfcPlaylistLedState_Normal);
-                while(nfc_playlist_worker_is_emulating(nfc_playlist->nfc_playlist_worker) &&
+                while(nfc_playlist_emulation_worker_is_emulating(
+                          nfc_playlist->nfc_playlist_emulation_worker) &&
                       time_counter_ms > 0 &&
                       time_counter_ms > 0 &&
                       EmulationState == NfcPlaylistEmulationState_Emulating) {
                       EmulationState == NfcPlaylistEmulationState_Emulating) {
                     furi_string_printf(tmp_counter_str, "%ds", (time_counter_ms / 1000));
                     furi_string_printf(tmp_counter_str, "%ds", (time_counter_ms / 1000));
@@ -153,19 +167,24 @@ int32_t nfc_playlist_emulation_task(void* context) {
                     furi_delay_ms(50);
                     furi_delay_ms(50);
                     time_counter_ms -= 50;
                     time_counter_ms -= 50;
                 };
                 };
-                nfc_playlist_worker_stop(nfc_playlist->nfc_playlist_worker);
-                nfc_playlist_worker_clear_nfc_data(nfc_playlist->nfc_playlist_worker);
+                nfc_playlist_emulation_worker_stop(nfc_playlist->nfc_playlist_emulation_worker);
+                nfc_playlist_emulation_worker_clear_nfc_data(
+                    nfc_playlist->nfc_playlist_emulation_worker);
             }
             }
         }
         }
         popup_reset(nfc_playlist->popup);
         popup_reset(nfc_playlist->popup);
-        popup_set_header(
-            nfc_playlist->popup,
-            EmulationState == NfcPlaylistEmulationState_Canceled ? "Emulation stopped" :
-                                                                   "Emulation finished",
-            64,
-            10,
-            AlignCenter,
-            AlignTop);
+        if(nfc_playlist->settings.playlist_length == 0) {
+            popup_set_header(nfc_playlist->popup, "Empty playlist", 64, 10, AlignCenter, AlignTop);
+        } else {
+            popup_set_header(
+                nfc_playlist->popup,
+                EmulationState == NfcPlaylistEmulationState_Canceled ? "Emulation stopped" :
+                                                                       "Emulation finished",
+                64,
+                10,
+                AlignCenter,
+                AlignTop);
+        }
         popup_set_text(nfc_playlist->popup, "Press back", 64, 50, AlignCenter, AlignTop);
         popup_set_text(nfc_playlist->popup, "Press back", 64, 50, AlignCenter, AlignTop);
         stop_blink(nfc_playlist);
         stop_blink(nfc_playlist);
 
 
@@ -173,6 +192,8 @@ int32_t nfc_playlist_emulation_task(void* context) {
         furi_string_free(line);
         furi_string_free(line);
         furi_string_free(tmp_header_str);
         furi_string_free(tmp_header_str);
         furi_string_free(tmp_counter_str);
         furi_string_free(tmp_counter_str);
+        furi_string_free(tmp_file_name);
+        //furi_string_free(tmp_file_ext);
     } else {
     } else {
         popup_set_header(
         popup_set_header(
             nfc_playlist->popup, "Failed to open playlist", 64, 10, AlignCenter, AlignTop);
             nfc_playlist->popup, "Failed to open playlist", 64, 10, AlignCenter, AlignTop);
@@ -189,16 +210,16 @@ int32_t nfc_playlist_emulation_task(void* context) {
 void nfc_playlist_emulation_setup(void* context) {
 void nfc_playlist_emulation_setup(void* context) {
     NfcPlaylist* nfc_playlist = context;
     NfcPlaylist* nfc_playlist = context;
     nfc_playlist->thread = furi_thread_alloc_ex(
     nfc_playlist->thread = furi_thread_alloc_ex(
-        "NfcPlaylistEmulationWorker", 8192, nfc_playlist_emulation_task, nfc_playlist);
-    nfc_playlist->nfc_playlist_worker = nfc_playlist_worker_alloc();
+        "NfcPlaylistEmulationWorker", 4096, nfc_playlist_emulation_task, nfc_playlist);
+    nfc_playlist->nfc_playlist_emulation_worker = nfc_playlist_emulation_worker_alloc();
 }
 }
 
 
 void nfc_playlist_emulation_free(NfcPlaylist* nfc_playlist) {
 void nfc_playlist_emulation_free(NfcPlaylist* nfc_playlist) {
     furi_assert(nfc_playlist);
     furi_assert(nfc_playlist);
     furi_thread_free(nfc_playlist->thread);
     furi_thread_free(nfc_playlist->thread);
-    nfc_playlist_worker_free(nfc_playlist->nfc_playlist_worker);
+    nfc_playlist_emulation_worker_free(nfc_playlist->nfc_playlist_emulation_worker);
     nfc_playlist->thread = NULL;
     nfc_playlist->thread = NULL;
-    nfc_playlist->nfc_playlist_worker = NULL;
+    nfc_playlist->nfc_playlist_emulation_worker = NULL;
 }
 }
 
 
 void nfc_playlist_emulation_start(NfcPlaylist* nfc_playlist) {
 void nfc_playlist_emulation_start(NfcPlaylist* nfc_playlist) {

+ 7 - 15
scenes/nfc_playlist_scene_main_menu.c

@@ -1,12 +1,5 @@
 #include "../nfc_playlist.h"
 #include "../nfc_playlist.h"
 
 
-typedef enum {
-    NfcPlaylistEvent_ShowEmulation,
-    NfcPlaylistEvent_ShowPlaylistSelect,
-    NfcPlaylistEvent_ShowFileEdit,
-    NfcPlaylistEvent_ShowSettings
-} NfcPlaylistMainMenuEvent;
-
 typedef enum {
 typedef enum {
     NfcPlaylistMenuSelection_Start,
     NfcPlaylistMenuSelection_Start,
     NfcPlaylistMenuSelection_PlaylistSelect,
     NfcPlaylistMenuSelection_PlaylistSelect,
@@ -27,10 +20,9 @@ void nfc_playlist_main_menu_scene_on_enter(void* context) {
         return;
         return;
     }
     }
 
 
-    FuriString* tmp_str = furi_string_alloc();
-    furi_string_printf(tmp_str, "NFC Playlist v%s", FAP_VERSION);
-    submenu_set_header(nfc_playlist->submenu, furi_string_get_cstr(tmp_str));
-    furi_string_free(tmp_str);
+    FuriString* header = furi_string_alloc_printf("NFC Playlist v%s", FAP_VERSION);
+    submenu_set_header(nfc_playlist->submenu, furi_string_get_cstr(header));
+    furi_string_free(header);
 
 
     submenu_add_lockable_item(
     submenu_add_lockable_item(
         nfc_playlist->submenu,
         nfc_playlist->submenu,
@@ -70,19 +62,19 @@ bool nfc_playlist_main_menu_scene_on_event(void* context, SceneManagerEvent even
     bool consumed = false;
     bool consumed = false;
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         switch(event.event) {
         switch(event.event) {
-        case NfcPlaylistEvent_ShowEmulation:
+        case NfcPlaylistMenuSelection_Start:
             scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_Emulation);
             scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_Emulation);
             consumed = true;
             consumed = true;
             break;
             break;
-        case NfcPlaylistEvent_ShowPlaylistSelect:
+        case NfcPlaylistMenuSelection_PlaylistSelect:
             scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_PlaylistSelect);
             scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_PlaylistSelect);
             consumed = true;
             consumed = true;
             break;
             break;
-        case NfcPlaylistEvent_ShowFileEdit:
+        case NfcPlaylistMenuSelection_FileEdit:
             scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_PlaylistEdit);
             scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_PlaylistEdit);
             consumed = true;
             consumed = true;
             break;
             break;
-        case NfcPlaylistEvent_ShowSettings:
+        case NfcPlaylistMenuSelection_Settings:
             scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_Settings);
             scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_Settings);
             consumed = true;
             consumed = true;
             break;
             break;

+ 38 - 14
scenes/nfc_playlist_scene_name_new_playlist.c

@@ -1,30 +1,54 @@
 #include "../nfc_playlist.h"
 #include "../nfc_playlist.h"
 
 
-void nfc_playlist_name_new_playlist_menu_callback(void* context) {
+int32_t nfc_playlist_name_new_playlist_thread_task(void* context) {
     NfcPlaylist* nfc_playlist = context;
     NfcPlaylist* nfc_playlist = context;
-    Storage* storage = furi_record_open(RECORD_STORAGE);
-    FuriString* file_name = furi_string_alloc();
 
 
-    furi_string_printf(
-        file_name, "/ext/apps_data/nfc_playlist/%s.txt", nfc_playlist->text_input_output);
+    FuriString* file_name = furi_string_alloc_printf(
+        "/ext/apps_data/nfc_playlist/%s.txt", nfc_playlist->text_input_output);
+    char const* file_name_cstr = furi_string_get_cstr(file_name);
 
 
+    Storage* storage = furi_record_open(RECORD_STORAGE);
     File* file = storage_file_alloc(storage);
     File* file = storage_file_alloc(storage);
-    if(storage_file_open(file, furi_string_get_cstr(file_name), FSAM_READ_WRITE, FSOM_CREATE_NEW)) {
-        storage_file_close(file);
-        furi_string_swap(nfc_playlist->settings.playlist_path, file_name);
-    }
 
 
-    nfc_playlist->settings.playlist_length = 0;
+    if(!storage_file_exists(storage, file_name_cstr)) {
+        if(storage_file_open(file, file_name_cstr, FSAM_READ_WRITE, FSOM_CREATE_NEW)) {
+            storage_file_close(file);
+            furi_string_swap(nfc_playlist->settings.playlist_path, file_name);
+            nfc_playlist->settings.playlist_length = 0;
+        }
+    }
 
 
-    storage_file_free(file);
     furi_string_free(file_name);
     furi_string_free(file_name);
+    storage_file_free(file);
     furi_record_close(RECORD_STORAGE);
     furi_record_close(RECORD_STORAGE);
-    scene_manager_previous_scene(nfc_playlist->scene_manager);
+
+    return 0;
+}
+
+void nfc_playlist_name_new_playlist_thread_state_callback(FuriThreadState state, void* context) {
+    NfcPlaylist* nfc_playlist = context;
+    if(state == FuriThreadStateStopped) {
+        furi_thread_yield();
+        nfc_playlist->thread = NULL;
+        scene_manager_search_and_switch_to_previous_scene(
+            nfc_playlist->scene_manager, NfcPlaylistScene_MainMenu);
+    }
+}
+
+void nfc_playlist_name_new_playlist_menu_callback(void* context) {
+    NfcPlaylist* nfc_playlist = context;
+    nfc_playlist->thread = furi_thread_alloc_ex(
+        "NfcPlaylistCreator", 1024, nfc_playlist_name_new_playlist_thread_task, nfc_playlist);
+    furi_thread_set_state_context(nfc_playlist->thread, nfc_playlist);
+    furi_thread_set_state_callback(
+        nfc_playlist->thread, nfc_playlist_name_new_playlist_thread_state_callback);
+    furi_thread_start(nfc_playlist->thread);
 }
 }
 
 
 void nfc_playlist_name_new_playlist_scene_on_enter(void* context) {
 void nfc_playlist_name_new_playlist_scene_on_enter(void* context) {
     NfcPlaylist* nfc_playlist = context;
     NfcPlaylist* nfc_playlist = context;
-    nfc_playlist->text_input_output = (char*)malloc(50);
+
+    nfc_playlist->text_input_output = malloc(MAX_PLAYLIST_NAME_LEN + 1);
     text_input_set_header_text(nfc_playlist->text_input, "Enter file name");
     text_input_set_header_text(nfc_playlist->text_input, "Enter file name");
     text_input_set_minimum_length(nfc_playlist->text_input, 1);
     text_input_set_minimum_length(nfc_playlist->text_input, 1);
     text_input_set_result_callback(
     text_input_set_result_callback(
@@ -32,7 +56,7 @@ void nfc_playlist_name_new_playlist_scene_on_enter(void* context) {
         nfc_playlist_name_new_playlist_menu_callback,
         nfc_playlist_name_new_playlist_menu_callback,
         nfc_playlist,
         nfc_playlist,
         nfc_playlist->text_input_output,
         nfc_playlist->text_input_output,
-        50,
+        MAX_PLAYLIST_NAME_LEN,
         true);
         true);
 
 
     view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_TextInput);
     view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_TextInput);

+ 11 - 11
scenes/nfc_playlist_scene_nfc_remove.c

@@ -18,22 +18,22 @@ void nfc_playlist_nfc_remove_options_change_callback(VariableItem* item) {
     uint8_t current_option =
     uint8_t current_option =
         variable_item_list_get_selected_item_index(nfc_playlist->variable_item_list);
         variable_item_list_get_selected_item_index(nfc_playlist->variable_item_list);
     uint8_t option_value_index = variable_item_get_current_value_index(item);
     uint8_t option_value_index = variable_item_get_current_value_index(item);
-    FuriString* tmp_str = furi_string_alloc();
+
     switch(current_option) {
     switch(current_option) {
-    case NfcPlaylistSettings_LineSelector:
+    case NfcPlaylistSettings_LineSelector: {
         selected_line = option_value_index + 1;
         selected_line = option_value_index + 1;
-        furi_string_printf(tmp_str, "%d", selected_line);
+        FuriString* tmp_str = furi_string_alloc_printf("%d", selected_line);
         variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_str));
         variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_str));
+        furi_string_free(tmp_str);
         break;
         break;
+    }
     default:
     default:
         break;
         break;
     }
     }
-    furi_string_free(tmp_str);
 }
 }
 
 
 void nfc_playlist_nfc_remove_scene_on_enter(void* context) {
 void nfc_playlist_nfc_remove_scene_on_enter(void* context) {
     NfcPlaylist* nfc_playlist = context;
     NfcPlaylist* nfc_playlist = context;
-    FuriString* tmp_str = furi_string_alloc();
 
 
     selected_line = nfc_playlist->settings.playlist_length;
     selected_line = nfc_playlist->settings.playlist_length;
 
 
@@ -47,8 +47,11 @@ void nfc_playlist_nfc_remove_scene_on_enter(void* context) {
         nfc_playlist);
         nfc_playlist);
     variable_item_set_current_value_index(
     variable_item_set_current_value_index(
         Line_selector, nfc_playlist->settings.playlist_length - 1);
         Line_selector, nfc_playlist->settings.playlist_length - 1);
-    furi_string_printf(tmp_str, "%d", selected_line);
+
+    FuriString* tmp_str = furi_string_alloc_printf("%d", selected_line);
     variable_item_set_current_value_text(Line_selector, furi_string_get_cstr(tmp_str));
     variable_item_set_current_value_text(Line_selector, furi_string_get_cstr(tmp_str));
+    furi_string_free(tmp_str);
+
     variable_item_set_locked(
     variable_item_set_locked(
         Line_selector,
         Line_selector,
         nfc_playlist->settings.playlist_length == 0 ? true : false,
         nfc_playlist->settings.playlist_length == 0 ? true : false,
@@ -62,7 +65,6 @@ void nfc_playlist_nfc_remove_scene_on_enter(void* context) {
 
 
     variable_item_list_set_enter_callback(
     variable_item_list_set_enter_callback(
         nfc_playlist->variable_item_list, nfc_playlist_nfc_remove_menu_callback, nfc_playlist);
         nfc_playlist->variable_item_list, nfc_playlist_nfc_remove_menu_callback, nfc_playlist);
-    furi_string_free(tmp_str);
 
 
     view_dispatcher_switch_to_view(
     view_dispatcher_switch_to_view(
         nfc_playlist->view_dispatcher, NfcPlaylistView_VariableItemList);
         nfc_playlist->view_dispatcher, NfcPlaylistView_VariableItemList);
@@ -111,16 +113,14 @@ bool nfc_playlist_nfc_remove_scene_on_event(void* context, SceneManagerEvent eve
             if(selected_line == 0) {
             if(selected_line == 0) {
                 scene_manager_previous_scene(nfc_playlist->scene_manager);
                 scene_manager_previous_scene(nfc_playlist->scene_manager);
             } else {
             } else {
-                FuriString* tmp_str = furi_string_alloc();
-
                 VariableItem* Line_selector = variable_item_list_get(
                 VariableItem* Line_selector = variable_item_list_get(
                     nfc_playlist->variable_item_list, NfcPlaylistSettings_LineSelector);
                     nfc_playlist->variable_item_list, NfcPlaylistSettings_LineSelector);
                 variable_item_set_values_count(
                 variable_item_set_values_count(
                     Line_selector, nfc_playlist->settings.playlist_length);
                     Line_selector, nfc_playlist->settings.playlist_length);
                 variable_item_set_current_value_index(Line_selector, selected_line - 1);
                 variable_item_set_current_value_index(Line_selector, selected_line - 1);
-                furi_string_printf(tmp_str, "%d", selected_line);
-                variable_item_set_current_value_text(Line_selector, furi_string_get_cstr(tmp_str));
 
 
+                FuriString* tmp_str = furi_string_alloc_printf("%d", selected_line);
+                variable_item_set_current_value_text(Line_selector, furi_string_get_cstr(tmp_str));
                 furi_string_free(tmp_str);
                 furi_string_free(tmp_str);
             }
             }
 
 

+ 7 - 5
scenes/nfc_playlist_scene_playlist_edit.c

@@ -19,6 +19,8 @@ void nfc_playlist_playlist_edit_scene_on_enter(void* context) {
 
 
     submenu_set_header(nfc_playlist->submenu, "Edit Playlist");
     submenu_set_header(nfc_playlist->submenu, "Edit Playlist");
 
 
+    bool playlist_path_empty = furi_string_empty(nfc_playlist->settings.playlist_path);
+
     submenu_add_item(
     submenu_add_item(
         nfc_playlist->submenu,
         nfc_playlist->submenu,
         "Create Playlist",
         "Create Playlist",
@@ -32,7 +34,7 @@ void nfc_playlist_playlist_edit_scene_on_enter(void* context) {
         NfcPlaylistMenuSelection_DeletePlaylist,
         NfcPlaylistMenuSelection_DeletePlaylist,
         nfc_playlist_playlist_edit_menu_callback,
         nfc_playlist_playlist_edit_menu_callback,
         nfc_playlist,
         nfc_playlist,
-        furi_string_empty(nfc_playlist->settings.playlist_path),
+        playlist_path_empty,
         "No\nplaylist\nselected");
         "No\nplaylist\nselected");
 
 
     submenu_add_lockable_item(
     submenu_add_lockable_item(
@@ -41,7 +43,7 @@ void nfc_playlist_playlist_edit_scene_on_enter(void* context) {
         NfcPlaylistMenuSelection_RenamePlaylist,
         NfcPlaylistMenuSelection_RenamePlaylist,
         nfc_playlist_playlist_edit_menu_callback,
         nfc_playlist_playlist_edit_menu_callback,
         nfc_playlist,
         nfc_playlist,
-        furi_string_empty(nfc_playlist->settings.playlist_path),
+        playlist_path_empty,
         "No\nplaylist\nselected");
         "No\nplaylist\nselected");
 
 
     submenu_add_lockable_item(
     submenu_add_lockable_item(
@@ -50,7 +52,7 @@ void nfc_playlist_playlist_edit_scene_on_enter(void* context) {
         NfcPlaylistMenuSelection_AddNfcItem,
         NfcPlaylistMenuSelection_AddNfcItem,
         nfc_playlist_playlist_edit_menu_callback,
         nfc_playlist_playlist_edit_menu_callback,
         nfc_playlist,
         nfc_playlist,
-        furi_string_empty(nfc_playlist->settings.playlist_path),
+        playlist_path_empty,
         "No\nplaylist\nselected");
         "No\nplaylist\nselected");
 
 
     submenu_add_lockable_item(
     submenu_add_lockable_item(
@@ -59,7 +61,7 @@ void nfc_playlist_playlist_edit_scene_on_enter(void* context) {
         NfcPlaylistMenuSelection_RemoveNfcItem,
         NfcPlaylistMenuSelection_RemoveNfcItem,
         nfc_playlist_playlist_edit_menu_callback,
         nfc_playlist_playlist_edit_menu_callback,
         nfc_playlist,
         nfc_playlist,
-        furi_string_empty(nfc_playlist->settings.playlist_path),
+        playlist_path_empty,
         "No\nplaylist\nselected");
         "No\nplaylist\nselected");
 
 
     submenu_add_lockable_item(
     submenu_add_lockable_item(
@@ -68,7 +70,7 @@ void nfc_playlist_playlist_edit_scene_on_enter(void* context) {
         NfcPlaylistMenuSelection_ViewPlaylistContent,
         NfcPlaylistMenuSelection_ViewPlaylistContent,
         nfc_playlist_playlist_edit_menu_callback,
         nfc_playlist_playlist_edit_menu_callback,
         nfc_playlist,
         nfc_playlist,
-        furi_string_empty(nfc_playlist->settings.playlist_path),
+        playlist_path_empty,
         "No\nplaylist\nselected");
         "No\nplaylist\nselected");
 
 
     view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Submenu);
     view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Submenu);

+ 34 - 14
scenes/nfc_playlist_scene_playlist_rename.c

@@ -1,27 +1,47 @@
 #include "../nfc_playlist.h"
 #include "../nfc_playlist.h"
 
 
-void nfc_playlist_playlist_rename_menu_callback(void* context) {
+int32_t nfc_playlist_playlist_rename_thread_task(void* context) {
     NfcPlaylist* nfc_playlist = context;
     NfcPlaylist* nfc_playlist = context;
-    Storage* storage = furi_record_open(RECORD_STORAGE);
 
 
-    char const* old_file_path = (char*)furi_string_get_cstr(nfc_playlist->settings.playlist_path);
+    char const* old_file_path = furi_string_get_cstr(nfc_playlist->settings.playlist_path);
     char const* old_file_name =
     char const* old_file_name =
         strchr(old_file_path, '/') != NULL ? &strrchr(old_file_path, '/')[1] : old_file_path;
         strchr(old_file_path, '/') != NULL ? &strrchr(old_file_path, '/')[1] : old_file_path;
-
-    FuriString* new_file_path = furi_string_alloc_set(nfc_playlist->settings.playlist_path);
+    FuriString* new_file_path = furi_string_alloc_set_str(old_file_path);
     furi_string_replace(new_file_path, old_file_name, nfc_playlist->text_input_output);
     furi_string_replace(new_file_path, old_file_name, nfc_playlist->text_input_output);
     furi_string_cat_str(new_file_path, ".txt");
     furi_string_cat_str(new_file_path, ".txt");
 
 
-    if(storage_common_rename(storage, old_file_path, furi_string_get_cstr(new_file_path)) == 0) {
-        furi_string_move(nfc_playlist->settings.playlist_path, new_file_path);
-    } else {
-        furi_string_free(new_file_path);
+    Storage* storage = furi_record_open(RECORD_STORAGE);
+
+    if(!storage_file_exists(storage, furi_string_get_cstr(new_file_path))) {
+        if(storage_common_rename(storage, old_file_path, furi_string_get_cstr(new_file_path)) ==
+           0) {
+            furi_string_move(nfc_playlist->settings.playlist_path, new_file_path);
+        }
     }
     }
 
 
     furi_record_close(RECORD_STORAGE);
     furi_record_close(RECORD_STORAGE);
 
 
-    scene_manager_search_and_switch_to_previous_scene(
-        nfc_playlist->scene_manager, NfcPlaylistScene_MainMenu);
+    return 0;
+}
+
+void nfc_playlist_playlist_rename_thread_state_callback(FuriThreadState state, void* context) {
+    NfcPlaylist* nfc_playlist = context;
+    if(state == FuriThreadStateStopped) {
+        furi_thread_yield();
+        nfc_playlist->thread = NULL;
+        scene_manager_search_and_switch_to_previous_scene(
+            nfc_playlist->scene_manager, NfcPlaylistScene_MainMenu);
+    }
+}
+
+void nfc_playlist_playlist_rename_menu_callback(void* context) {
+    NfcPlaylist* nfc_playlist = context;
+    nfc_playlist->thread = furi_thread_alloc_ex(
+        "NfcPlaylistRenamer", 1024, nfc_playlist_playlist_rename_thread_task, nfc_playlist);
+    furi_thread_set_state_context(nfc_playlist->thread, nfc_playlist);
+    furi_thread_set_state_callback(
+        nfc_playlist->thread, nfc_playlist_playlist_rename_thread_state_callback);
+    furi_thread_start(nfc_playlist->thread);
 }
 }
 
 
 void nfc_playlist_playlist_rename_scene_on_enter(void* context) {
 void nfc_playlist_playlist_rename_scene_on_enter(void* context) {
@@ -30,11 +50,11 @@ void nfc_playlist_playlist_rename_scene_on_enter(void* context) {
     char const* tmp_file_path = furi_string_get_cstr(nfc_playlist->settings.playlist_path);
     char const* tmp_file_path = furi_string_get_cstr(nfc_playlist->settings.playlist_path);
     char const* tmp_file_name =
     char const* tmp_file_name =
         strchr(tmp_file_path, '/') != NULL ? &strrchr(tmp_file_path, '/')[1] : tmp_file_path;
         strchr(tmp_file_path, '/') != NULL ? &strrchr(tmp_file_path, '/')[1] : tmp_file_path;
-
     FuriString* tmp_file_name_furi = furi_string_alloc_set_str(tmp_file_name);
     FuriString* tmp_file_name_furi = furi_string_alloc_set_str(tmp_file_name);
     furi_string_replace(tmp_file_name_furi, ".txt", "");
     furi_string_replace(tmp_file_name_furi, ".txt", "");
 
 
-    nfc_playlist->text_input_output = strdup(furi_string_get_cstr(tmp_file_name_furi));
+    nfc_playlist->text_input_output = malloc(MAX_PLAYLIST_NAME_LEN + 1);
+    strcpy(nfc_playlist->text_input_output, furi_string_get_cstr(tmp_file_name_furi));
     furi_string_free(tmp_file_name_furi);
     furi_string_free(tmp_file_name_furi);
 
 
     text_input_set_header_text(nfc_playlist->text_input, "Enter new file name");
     text_input_set_header_text(nfc_playlist->text_input, "Enter new file name");
@@ -44,7 +64,7 @@ void nfc_playlist_playlist_rename_scene_on_enter(void* context) {
         nfc_playlist_playlist_rename_menu_callback,
         nfc_playlist_playlist_rename_menu_callback,
         nfc_playlist,
         nfc_playlist,
         nfc_playlist->text_input_output,
         nfc_playlist->text_input_output,
-        (50 + sizeof(nfc_playlist->text_input_output)),
+        MAX_PLAYLIST_NAME_LEN,
         false);
         false);
 
 
     view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_TextInput);
     view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_TextInput);

+ 11 - 8
scenes/nfc_playlist_scene_settings.c

@@ -19,20 +19,24 @@ void nfc_playlist_settings_options_change_callback(VariableItem* item) {
     uint8_t current_option =
     uint8_t current_option =
         variable_item_list_get_selected_item_index(nfc_playlist->variable_item_list);
         variable_item_list_get_selected_item_index(nfc_playlist->variable_item_list);
     uint8_t option_value_index = variable_item_get_current_value_index(item);
     uint8_t option_value_index = variable_item_get_current_value_index(item);
-    FuriString* tmp_str = furi_string_alloc();
+
     switch(current_option) {
     switch(current_option) {
-    case NfcPlaylistSettings_Timeout:
+    case NfcPlaylistSettings_Timeout: {
         nfc_playlist->settings.emulate_timeout = option_value_index;
         nfc_playlist->settings.emulate_timeout = option_value_index;
-        furi_string_printf(
-            tmp_str, "%ds", options_emulate_timeout[nfc_playlist->settings.emulate_timeout]);
+        FuriString* tmp_str = furi_string_alloc_printf(
+            "%ds", options_emulate_timeout[nfc_playlist->settings.emulate_timeout]);
         variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_str));
         variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_str));
+        furi_string_free(tmp_str);
         break;
         break;
-    case NfcPlaylistSettings_Delay:
+    }
+    case NfcPlaylistSettings_Delay: {
         nfc_playlist->settings.emulate_delay = option_value_index;
         nfc_playlist->settings.emulate_delay = option_value_index;
-        furi_string_printf(
-            tmp_str, "%ds", options_emulate_delay[nfc_playlist->settings.emulate_delay]);
+        FuriString* tmp_str = furi_string_alloc_printf(
+            "%ds", options_emulate_delay[nfc_playlist->settings.emulate_delay]);
         variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_str));
         variable_item_set_current_value_text(item, furi_string_get_cstr(tmp_str));
+        furi_string_free(tmp_str);
         break;
         break;
+    }
     case NfcPlaylistSettings_LedIndicator:
     case NfcPlaylistSettings_LedIndicator:
         nfc_playlist->settings.emulate_led_indicator = option_value_index;
         nfc_playlist->settings.emulate_led_indicator = option_value_index;
         variable_item_set_current_value_text(
         variable_item_set_current_value_text(
@@ -46,7 +50,6 @@ void nfc_playlist_settings_options_change_callback(VariableItem* item) {
     default:
     default:
         break;
         break;
     }
     }
-    furi_string_free(tmp_str);
 }
 }
 
 
 void nfc_playlist_settings_scene_on_enter(void* context) {
 void nfc_playlist_settings_scene_on_enter(void* context) {

+ 0 - 1
scenes/nfc_playlist_scene_view_playlist_content.c

@@ -18,7 +18,6 @@ void nfc_playlist_view_playlist_content_scene_on_enter(void* context) {
             furi_string_cat_printf(tmp_str, "%s", furi_string_get_cstr(line));
             furi_string_cat_printf(tmp_str, "%s", furi_string_get_cstr(line));
         }
         }
 
 
-        stream_clean(stream);
         furi_string_free(line);
         furi_string_free(line);
         file_stream_close(stream);
         file_stream_close(stream);