Просмотр исходного кода

Merge pull request #29 from acegoal07/dev

Dev
acegoal07 1 год назад
Родитель
Сommit
29da8eb0cc

+ 3 - 5
README.md

@@ -29,10 +29,8 @@ 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
+## Known issues
+### Renaming/creating playlist
+I know of an issue with these functions that can cause them to lock the viewport if you put in a name that is very long im looking into fixing this and finding a solution
 
 
 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,11 +8,11 @@ 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/icon.png",
     fap_icon="assets/icon.png",
     fap_private_libs=[
     fap_private_libs=[
         Lib(
         Lib(
-            name="worker",
+            name="emulation_worker",
         ),
         ),
     ],
     ],
 )
 )

+ 73 - 0
lib/emulation_worker/nfc_playlist_emulation_worker.c

@@ -0,0 +1,73 @@
+#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);
+}

+ 31 - 0
lib/emulation_worker/nfc_playlist_emulation_worker.h

@@ -0,0 +1,31 @@
+#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

@@ -48,9 +48,8 @@ static NfcPlaylist* nfc_playlist_alloc() {
    view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_TextInput, text_input_get_view(nfc_playlist->text_input));
    view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_TextInput, 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;
@@ -68,11 +67,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

+ 9 - 8
scenes/nfc_playlist_scene_confirm_delete.c

@@ -10,16 +10,16 @@ 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(nfc_playlist->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, furi_string_get_cstr(temp_str), false);
    widget_add_text_box_element(nfc_playlist->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, furi_string_get_cstr(temp_str), false);
    widget_add_button_element(nfc_playlist->widget, GuiButtonTypeLeft, "Cancel", nfc_playlist_confirm_delete_menu_callback, nfc_playlist);
    widget_add_button_element(nfc_playlist->widget, GuiButtonTypeLeft, "Cancel", nfc_playlist_confirm_delete_menu_callback, nfc_playlist);
    widget_add_button_element(nfc_playlist->widget, GuiButtonTypeRight, "Delete", nfc_playlist_confirm_delete_menu_callback, nfc_playlist);
    widget_add_button_element(nfc_playlist->widget, GuiButtonTypeRight, "Delete", nfc_playlist_confirm_delete_menu_callback, 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);
 }
 }
@@ -31,12 +31,13 @@ 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(nfc_playlist->scene_manager, NfcPlaylistScene_MainMenu);
             scene_manager_search_and_switch_to_previous_scene(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);

+ 26 - 16
scenes/nfc_playlist_scene_emulation.c

@@ -27,6 +27,8 @@ 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();
+      FuriString* tmp_file_ext = furi_string_alloc();
 
 
       while(stream_read_line(stream, line) && EmulationState == NfcPlaylistEmulationState_Emulating) {
       while(stream_read_line(stream, line) && EmulationState == NfcPlaylistEmulationState_Emulating) {
 
 
@@ -45,6 +47,7 @@ int32_t nfc_playlist_emulation_task(void* context) {
                popup_set_text(nfc_playlist->popup, furi_string_get_cstr(tmp_counter_str), 64, 50, AlignCenter, AlignTop);
                popup_set_text(nfc_playlist->popup, furi_string_get_cstr(tmp_counter_str), 64, 50, AlignCenter, 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;
@@ -53,16 +56,17 @@ int32_t nfc_playlist_emulation_task(void* context) {
 
 
          if(EmulationState != NfcPlaylistEmulationState_Emulating) {break;}
          if(EmulationState != NfcPlaylistEmulationState_Emulating) {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);
+
          int time_counter_ms = (options_emulate_timeout[nfc_playlist->settings.emulate_timeout]*1000);
          int time_counter_ms = (options_emulate_timeout[nfc_playlist->settings.emulate_timeout]*1000);
 
 
-         if(!strcasestr(file_ext, "nfc")) {
+         if(!furi_string_cmpi_str(tmp_file_ext, "nfc")) {
             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(nfc_playlist->popup, furi_string_get_cstr(tmp_header_str), 64, 10, AlignCenter, AlignTop);
             popup_set_header(nfc_playlist->popup, furi_string_get_cstr(tmp_header_str), 64, 10, AlignCenter, AlignTop);
             start_blink(nfc_playlist, NfcPlaylistLedState_Error);
             start_blink(nfc_playlist, NfcPlaylistLedState_Error);
             while(time_counter_ms > 0 && EmulationState == NfcPlaylistEmulationState_Emulating) {
             while(time_counter_ms > 0 && EmulationState == NfcPlaylistEmulationState_Emulating) {
@@ -76,7 +80,7 @@ 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(nfc_playlist->popup, furi_string_get_cstr(tmp_header_str), 64, 10, AlignCenter, AlignTop);
             popup_set_header(nfc_playlist->popup, furi_string_get_cstr(tmp_header_str), 64, 10, AlignCenter, AlignTop);
             start_blink(nfc_playlist, NfcPlaylistLedState_Error);
             start_blink(nfc_playlist, NfcPlaylistLedState_Error);
             while(time_counter_ms > 0 && EmulationState == NfcPlaylistEmulationState_Emulating) {
             while(time_counter_ms > 0 && EmulationState == NfcPlaylistEmulationState_Emulating) {
@@ -86,23 +90,27 @@ 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(nfc_playlist->popup, furi_string_get_cstr(tmp_header_str), 64, 10, AlignCenter, AlignTop);
             popup_set_header(nfc_playlist->popup, furi_string_get_cstr(tmp_header_str), 64, 10, AlignCenter, 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) && time_counter_ms > 0 && EmulationState == NfcPlaylistEmulationState_Emulating) {
+            while(nfc_playlist_emulation_worker_is_emulating(nfc_playlist->nfc_playlist_emulation_worker) && time_counter_ms > 0 && 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));
                popup_set_text(nfc_playlist->popup, furi_string_get_cstr(tmp_counter_str), 64, 50, AlignCenter, AlignTop);
                popup_set_text(nfc_playlist->popup, furi_string_get_cstr(tmp_counter_str), 64, 50, AlignCenter, AlignTop);
                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);
 
 
@@ -110,6 +118,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(nfc_playlist->popup, "Failed to open playlist", 64, 10, AlignCenter, AlignTop);
       popup_set_header(nfc_playlist->popup, "Failed to open playlist", 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);
@@ -124,16 +134,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("NfcPlaylistEmulationWorker", 8192, nfc_playlist_emulation_task, nfc_playlist);
-   nfc_playlist->nfc_playlist_worker = nfc_playlist_worker_alloc();
+   nfc_playlist->thread = furi_thread_alloc_ex("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;

+ 34 - 13
scenes/nfc_playlist_scene_name_new_playlist.c

@@ -1,32 +1,53 @@
 #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);
+
+   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;
+      }
    }
    }
 
 
-   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(nfc_playlist->text_input, nfc_playlist_name_new_playlist_menu_callback, nfc_playlist, nfc_playlist->text_input_output, 50, true);
+   text_input_set_result_callback(nfc_playlist->text_input, nfc_playlist_name_new_playlist_menu_callback, nfc_playlist, nfc_playlist->text_input_output, MAX_PLAYLIST_NAME_LEN, 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

@@ -17,22 +17,22 @@ void nfc_playlist_nfc_remove_options_change_callback(VariableItem* item) {
 
 
    uint8_t current_option = variable_item_list_get_selected_item_index(nfc_playlist->variable_item_list);
    uint8_t current_option = 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;
 
 
@@ -45,15 +45,17 @@ void nfc_playlist_nfc_remove_scene_on_enter(void* context) {
       nfc_playlist_nfc_remove_options_change_callback,
       nfc_playlist_nfc_remove_options_change_callback,
       nfc_playlist);
       nfc_playlist);
    variable_item_set_current_value_index(Line_selector, nfc_playlist->settings.playlist_length - 1);
    variable_item_set_current_value_index(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(Line_selector, nfc_playlist->settings.playlist_length == 0 ? true : false, "Playlist\nis empty");
    variable_item_set_locked(Line_selector, nfc_playlist->settings.playlist_length == 0 ? true : false, "Playlist\nis empty");
 
 
    variable_item_list_add(nfc_playlist->variable_item_list, "Remove Line", 0, NULL, NULL);
    variable_item_list_add(nfc_playlist->variable_item_list, "Remove Line", 0, NULL, NULL);
    variable_item_set_locked(variable_item_list_get(nfc_playlist->variable_item_list, NfcPlaylistSettings_RemoveLine), nfc_playlist->settings.playlist_length == 0 ? true : false, "Playlist\nis empty");
    variable_item_set_locked(variable_item_list_get(nfc_playlist->variable_item_list, NfcPlaylistSettings_RemoveLine), nfc_playlist->settings.playlist_length == 0 ? true : false, "Playlist\nis empty");
 
 
    variable_item_list_set_enter_callback(nfc_playlist->variable_item_list, nfc_playlist_nfc_remove_menu_callback, nfc_playlist);
    variable_item_list_set_enter_callback(nfc_playlist->variable_item_list, nfc_playlist_nfc_remove_menu_callback, nfc_playlist);
-   furi_string_free(tmp_str);
 
 
    view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_VariableItemList);
    view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_VariableItemList);
 }
 }
@@ -97,14 +99,12 @@ 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(nfc_playlist->variable_item_list, NfcPlaylistSettings_LineSelector);
                VariableItem* Line_selector = variable_item_list_get(nfc_playlist->variable_item_list, NfcPlaylistSettings_LineSelector);
                variable_item_set_values_count(Line_selector, nfc_playlist->settings.playlist_length);
                variable_item_set_values_count(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);

+ 30 - 13
scenes/nfc_playlist_scene_playlist_rename.c

@@ -1,25 +1,42 @@
 #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 = strchr(old_file_path, '/') != NULL ? &strrchr(old_file_path, '/')[1] : old_file_path;
    char const* old_file_name = 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_safe(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) {
@@ -27,16 +44,16 @@ 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 = strchr(tmp_file_path, '/') != NULL ? &strrchr(tmp_file_path, '/')[1] : tmp_file_path;
    char const* tmp_file_name = 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");
    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(nfc_playlist->text_input, nfc_playlist_playlist_rename_menu_callback, nfc_playlist, nfc_playlist->text_input_output, (50 + sizeof(nfc_playlist->text_input_output)), false);
+   text_input_set_result_callback(nfc_playlist->text_input, nfc_playlist_playlist_rename_menu_callback, nfc_playlist, nfc_playlist->text_input_output, MAX_PLAYLIST_NAME_LEN, false);
 
 
    view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_TextInput);
    view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_TextInput);
 }
 }

+ 10 - 7
scenes/nfc_playlist_scene_settings.c

@@ -18,18 +18,22 @@ void nfc_playlist_settings_options_change_callback(VariableItem* item) {
 
 
    uint8_t current_option = variable_item_list_get_selected_item_index(nfc_playlist->variable_item_list);
    uint8_t current_option = 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));
-         break;
-      case NfcPlaylistSettings_Delay:
+         furi_string_free(tmp_str);
+         break;         
+      }
+      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(item, nfc_playlist->settings.emulate_led_indicator ? "ON" : "OFF");
          variable_item_set_current_value_text(item, nfc_playlist->settings.emulate_led_indicator ? "ON" : "OFF");
@@ -41,7 +45,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

@@ -14,7 +14,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);