فهرست منبع

Merge pull request #20 from acegoal07/dev

Dev
acegoal07 1 سال پیش
والد
کامیت
e8c40d8823

+ 11 - 2
README.md

@@ -14,7 +14,6 @@ This app was design, built and tested using the <a href="https://github.com/Flip
 ## Supported Firmwares
 ## Supported Firmwares
 As i know these firmwares are supported and working if you know any more please let me know
 As i know these firmwares are supported and working if you know any more please let me know
 - <a href="https://github.com/Flipper-XFW/Xtreme-Firmware">Xtreme</a>
 - <a href="https://github.com/Flipper-XFW/Xtreme-Firmware">Xtreme</a>
-- <a href="https://github.com/Next-Flip/Momentum-Firmware">Momentum</a>
 - <a href="https://github.com/RogueMaster/flipperzero-firmware-wPlugins">RogueMaster</a>
 - <a href="https://github.com/RogueMaster/flipperzero-firmware-wPlugins">RogueMaster</a>
 ## Settings:
 ## Settings:
 - Emulate time (How long the NFC card will be emulated for)
 - Emulate time (How long the NFC card will be emulated for)
@@ -22,5 +21,15 @@ As i know these firmwares are supported and working if you know any more please
 - LED indicator (Whether or not the LED's will be on)
 - LED indicator (Whether or not the LED's will be on)
 - Reset settings (Puts all the settings back to the defaults)
 - Reset settings (Puts all the settings back to the defaults)
 ## Playlist editor:
 ## Playlist editor:
+- Create PLaylist (Creates a new playlist with the given name)
 - Delete playlist (Deletes the selected playlist)
 - Delete playlist (Deletes the selected playlist)
-- Rename playlist (Renames the selected playlist the new name provided)
+- Rename playlist (Renames the selected playlist to the new name provided)
+- View playlist content (Allows you to view the contents of the playlist)
+- Add NFC Item (Adds the selected nfc item to the currently selected 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

+ 1 - 4
application.fam

@@ -8,14 +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="1.6",
+    fap_version="1.7",
     fap_icon="assets/icon.png",
     fap_icon="assets/icon.png",
     fap_private_libs=[
     fap_private_libs=[
         Lib(
         Lib(
             name="worker",
             name="worker",
         ),
         ),
-        Lib(
-            name="led",
-        ),
     ],
     ],
 )
 )

+ 0 - 42
lib/led/nfc_playlist_led.c

@@ -1,42 +0,0 @@
-#include "nfc_playlist_led.h"
-
-NotificationMessage blink_message_normal = {
-   .type = NotificationMessageTypeLedBlinkStart,
-   .data.led_blink.color = LightBlue | LightGreen,
-   .data.led_blink.on_time = 10,
-   .data.led_blink.period = 100
-};
-const NotificationSequence blink_sequence_normal = {
-   &blink_message_normal,
-   &message_do_not_reset,
-   NULL
-};
-
-NotificationMessage blink_message_error = {
-   .type = NotificationMessageTypeLedBlinkStart,
-   .data.led_blink.color = LightRed,
-   .data.led_blink.on_time = 10,
-   .data.led_blink.period = 100
-};
-
-const NotificationSequence blink_sequence_error = {
-   &blink_message_error,
-   &message_do_not_reset,
-   NULL
-};
-
-void start_blink(NfcPlaylist* nfc_playlist, int state) {
-   if (nfc_playlist->settings.emulate_led_indicator) {
-      if (state == NfcPlaylistLedState_Normal) {
-         notification_message_block(nfc_playlist->notification, &blink_sequence_normal);
-      } else if (state == NfcPlaylistLedState_Error) {
-         notification_message_block(nfc_playlist->notification, &blink_sequence_error);
-      }
-   }
-}
-
-void stop_blink(NfcPlaylist* nfc_playlist) {
-   if (nfc_playlist->settings.emulate_led_indicator) {
-      notification_message_block(nfc_playlist->notification, &sequence_blink_stop);
-   }
-}

+ 0 - 11
lib/led/nfc_playlist_led.h

@@ -1,11 +0,0 @@
-#pragma once
-#include <../../nfc_playlist.h>
-#include <notification/notification_messages.h>
-
-typedef enum NfcPlaylistLedState {
-   NfcPlaylistLedState_Normal,
-   NfcPlaylistLedState_Error
-} NfcPlaylistLedState;
-
-void start_blink(NfcPlaylist* nfc_playlist, int state);
-void stop_blink(NfcPlaylist* nfc_playlist);

+ 61 - 59
nfc_playlist.c

@@ -1,42 +1,4 @@
 #include "nfc_playlist.h"
 #include "nfc_playlist.h"
-#include "nfc_playlist_i.h"
-
-static void (*const nfc_playlist_scene_on_enter_handlers[])(void*) = {
-   nfc_playlist_main_menu_scene_on_enter,
-   nfc_playlist_settings_scene_on_enter,
-   nfc_playlist_emulation_scene_on_enter,
-   nfc_playlist_file_select_scene_on_enter,
-   nfc_playlist_file_edit_scene_on_enter,
-   nfc_playlist_file_rename_scene_on_enter,
-   nfc_playlist_confirm_delete_scene_on_enter
-};
-
-static bool (*const nfc_playlist_scene_on_event_handlers[])(void*, SceneManagerEvent) = {
-   nfc_playlist_main_menu_scene_on_event,
-   nfc_playlist_settings_scene_on_event,
-   nfc_playlist_emulation_scene_on_event,
-   nfc_playlist_file_select_scene_on_event,
-   nfc_playlist_file_edit_scene_on_event,
-   nfc_playlist_file_rename_scene_on_event,
-   nfc_playlist_confirm_delete_scene_on_event
-};
-
-static void (*const nfc_playlist_scene_on_exit_handlers[])(void*) = {
-   nfc_playlist_main_menu_scene_on_exit,
-   nfc_playlist_settings_scene_on_exit,
-   nfc_playlist_emulation_scene_on_exit,
-   nfc_playlist_file_select_scene_on_exit,
-   nfc_playlist_file_edit_scene_on_exit,
-   nfc_playlist_file_rename_scene_on_exit,
-   nfc_playlist_confirm_delete_scene_on_exit
-};
-
-static const SceneManagerHandlers nfc_playlist_scene_manager_handlers = {
-   .on_enter_handlers = nfc_playlist_scene_on_enter_handlers,
-   .on_event_handlers = nfc_playlist_scene_on_event_handlers,
-   .on_exit_handlers = nfc_playlist_scene_on_exit_handlers,
-   .scene_num = NfcPlaylistScene_count
-};
 
 
 static bool nfc_playlist_custom_callback(void* context, uint32_t custom_event) {
 static bool nfc_playlist_custom_callback(void* context, uint32_t custom_event) {
    furi_assert(context);
    furi_assert(context);
@@ -53,40 +15,40 @@ static bool nfc_playlist_back_event_callback(void* context) {
 static NfcPlaylist* nfc_playlist_alloc() {
 static NfcPlaylist* nfc_playlist_alloc() {
    NfcPlaylist* nfc_playlist = malloc(sizeof(NfcPlaylist));
    NfcPlaylist* nfc_playlist = malloc(sizeof(NfcPlaylist));
    furi_assert(nfc_playlist);
    furi_assert(nfc_playlist);
-   nfc_playlist->scene_manager = scene_manager_alloc(&nfc_playlist_scene_manager_handlers, nfc_playlist);
+   nfc_playlist->scene_manager = scene_manager_alloc(&nfc_playlist_scene_handlers, nfc_playlist);
    nfc_playlist->view_dispatcher = view_dispatcher_alloc();
    nfc_playlist->view_dispatcher = view_dispatcher_alloc();
    view_dispatcher_enable_queue(nfc_playlist->view_dispatcher);
    view_dispatcher_enable_queue(nfc_playlist->view_dispatcher);
    nfc_playlist->variable_item_list = variable_item_list_alloc();
    nfc_playlist->variable_item_list = variable_item_list_alloc();
    nfc_playlist->submenu = submenu_alloc();
    nfc_playlist->submenu = submenu_alloc();
    nfc_playlist->widget= widget_alloc();
    nfc_playlist->widget= widget_alloc();
 
 
-   nfc_playlist->settings.base_file_path = furi_string_alloc_set_str("/ext/apps_data/nfc_playlist/");
-   nfc_playlist->settings.file_path = nfc_playlist->settings.base_file_path;
-   nfc_playlist->settings.file_selected = false;
-   nfc_playlist->settings.file_selected_check = false;
+   nfc_playlist->settings.file_path = furi_string_alloc();
+   nfc_playlist->file_browser_output = furi_string_alloc();
+   nfc_playlist->settings.playlist_selected = false;
    nfc_playlist->settings.emulate_timeout = default_emulate_timeout;
    nfc_playlist->settings.emulate_timeout = default_emulate_timeout;
    nfc_playlist->settings.emulate_delay = default_emulate_delay;
    nfc_playlist->settings.emulate_delay = default_emulate_delay;
    nfc_playlist->settings.emulate_led_indicator = default_emulate_led_indicator;
    nfc_playlist->settings.emulate_led_indicator = default_emulate_led_indicator;
 
 
    nfc_playlist->notification = furi_record_open(RECORD_NOTIFICATION);
    nfc_playlist->notification = furi_record_open(RECORD_NOTIFICATION);
-   nfc_playlist->file_browser = file_browser_alloc(nfc_playlist->settings.file_path);
+   nfc_playlist->file_browser = file_browser_alloc(nfc_playlist->file_browser_output);
+
    nfc_playlist->text_input = text_input_alloc();
    nfc_playlist->text_input = text_input_alloc();
    nfc_playlist->popup = popup_alloc();
    nfc_playlist->popup = popup_alloc();
 
 
    view_dispatcher_set_event_callback_context(nfc_playlist->view_dispatcher, nfc_playlist);
    view_dispatcher_set_event_callback_context(nfc_playlist->view_dispatcher, nfc_playlist);
    view_dispatcher_set_custom_event_callback(nfc_playlist->view_dispatcher, nfc_playlist_custom_callback);
    view_dispatcher_set_custom_event_callback(nfc_playlist->view_dispatcher, nfc_playlist_custom_callback);
    view_dispatcher_set_navigation_event_callback(nfc_playlist->view_dispatcher, nfc_playlist_back_event_callback);
    view_dispatcher_set_navigation_event_callback(nfc_playlist->view_dispatcher, nfc_playlist_back_event_callback);
-   view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Menu, submenu_get_view(nfc_playlist->submenu));
-   view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Settings, variable_item_list_get_view(nfc_playlist->variable_item_list));
+
+   view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Submenu, submenu_get_view(nfc_playlist->submenu));
    view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Popup, popup_get_view(nfc_playlist->popup));
    view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Popup, popup_get_view(nfc_playlist->popup));
-   view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileSelect, file_browser_get_view(nfc_playlist->file_browser));
-   view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileEdit, submenu_get_view(nfc_playlist->submenu));
-   view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileRename, text_input_get_view(nfc_playlist->text_input));
-   view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_ConfirmDelete, widget_get_view(nfc_playlist->widget));
+   view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Widget, widget_get_view(nfc_playlist->widget));
+   view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_VariableItemList, variable_item_list_get_view(nfc_playlist->variable_item_list));
+   view_dispatcher_add_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileBrowser, file_browser_get_view(nfc_playlist->file_browser));
+   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, "/ext/apps_data/nfc_playlist")) {
-      storage_common_mkdir(storage, "/ext/apps_data/nfc_playlist");
+   if (!storage_common_exists(storage, PLAYLIST_DIR)) {
+      storage_common_mkdir(storage, PLAYLIST_DIR);
    }
    }
    furi_record_close(RECORD_STORAGE);
    furi_record_close(RECORD_STORAGE);
 
 
@@ -96,13 +58,12 @@ static NfcPlaylist* nfc_playlist_alloc() {
 static void nfc_playlist_free(NfcPlaylist* nfc_playlist) {
 static void nfc_playlist_free(NfcPlaylist* nfc_playlist) {
    furi_assert(nfc_playlist);
    furi_assert(nfc_playlist);
 
 
-   view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Menu);
-   view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Settings);
+   view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Submenu);
    view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Popup);
    view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Popup);
-   view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileSelect);
-   view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileEdit);
-   view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileRename);
-   view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_ConfirmDelete);
+   view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Widget);
+   view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_VariableItemList);
+   view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileBrowser);
+   view_dispatcher_remove_view(nfc_playlist->view_dispatcher, NfcPlaylistView_TextInput);
 
 
    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);
@@ -115,8 +76,8 @@ static void nfc_playlist_free(NfcPlaylist* nfc_playlist) {
    text_input_free(nfc_playlist->text_input);
    text_input_free(nfc_playlist->text_input);
    popup_free(nfc_playlist->popup);
    popup_free(nfc_playlist->popup);
 
 
-   furi_string_free(nfc_playlist->settings.base_file_path);
    furi_string_free(nfc_playlist->settings.file_path);
    furi_string_free(nfc_playlist->settings.file_path);
+   furi_string_free(nfc_playlist->file_browser_output);
    free(nfc_playlist);
    free(nfc_playlist);
 }
 }
 
 
@@ -144,4 +105,45 @@ int32_t nfc_playlist_main(void* p) {
    nfc_playlist_free(nfc_playlist);
    nfc_playlist_free(nfc_playlist);
 
 
    return 0;
    return 0;
+}
+
+NotificationMessage blink_message_normal = {
+   .type = NotificationMessageTypeLedBlinkStart,
+   .data.led_blink.color = LightBlue | LightGreen,
+   .data.led_blink.on_time = 10,
+   .data.led_blink.period = 100
+};
+const NotificationSequence blink_sequence_normal = {
+   &blink_message_normal,
+   &message_do_not_reset,
+   NULL
+};
+
+NotificationMessage blink_message_error = {
+   .type = NotificationMessageTypeLedBlinkStart,
+   .data.led_blink.color = LightRed,
+   .data.led_blink.on_time = 10,
+   .data.led_blink.period = 100
+};
+
+const NotificationSequence blink_sequence_error = {
+   &blink_message_error,
+   &message_do_not_reset,
+   NULL
+};
+
+void start_blink(NfcPlaylist* nfc_playlist, int state) {
+   if (nfc_playlist->settings.emulate_led_indicator) {
+      if (state == NfcPlaylistLedState_Normal) {
+         notification_message_block(nfc_playlist->notification, &blink_sequence_normal);
+      } else if (state == NfcPlaylistLedState_Error) {
+         notification_message_block(nfc_playlist->notification, &blink_sequence_error);
+      }
+   }
+}
+
+void stop_blink(NfcPlaylist* nfc_playlist) {
+   if (nfc_playlist->settings.emulate_led_indicator) {
+      notification_message_block(nfc_playlist->notification, &sequence_blink_stop);
+   }
 }
 }

+ 38 - 28
nfc_playlist.h

@@ -1,9 +1,12 @@
 #pragma once
 #pragma once
 #include <furi.h>
 #include <furi.h>
 #include <furi_hal.h>
 #include <furi_hal.h>
+
 #include <string.h>
 #include <string.h>
-#include <gui/gui.h>
+
 #include <assets_icons.h>
 #include <assets_icons.h>
+
+#include <gui/gui.h>
 #include <gui/view_dispatcher.h>
 #include <gui/view_dispatcher.h>
 #include <gui/scene_manager.h>
 #include <gui/scene_manager.h>
 #include <gui/modules/popup.h>
 #include <gui/modules/popup.h>
@@ -13,35 +16,30 @@
 #include <gui/modules/text_input.h>
 #include <gui/modules/text_input.h>
 #include <gui/modules/widget.h>
 #include <gui/modules/widget.h>
 #include <gui/modules/widget_elements/widget_element.h>
 #include <gui/modules/widget_elements/widget_element.h>
+
 #include <notification/notification_messages.h>
 #include <notification/notification_messages.h>
-#include <nfc_playlist_worker.h>
 
 
-typedef enum {
-   NfcPlaylistView_Menu,
-   NfcPlaylistView_Settings,
-   NfcPlaylistView_Popup,
-   NfcPlaylistView_FileSelect,
-   NfcPlaylistView_FileEdit,
-   NfcPlaylistView_FileRename,
-   NfcPlaylistView_ConfirmDelete
-} NfcPlayScenesView;
+#include <storage/storage.h>
+
+#include <toolbox/stream/stream.h>
+#include <toolbox/stream/file_stream.h>
+
+#include "lib/worker/nfc_playlist_worker.h"
+
+#include "scenes/nfc_playlist_scene.h"
 
 
 typedef enum {
 typedef enum {
-   NfcPlaylistScene_MainMenu,
-   NfcPlaylistScene_Settings,
-   NfcPlaylistScene_EmulatingPopup,
-   NfcPlaylistScene_FileSelect,
-   NfcPlaylistScene_FileEdit,
-   NfcPlaylistScene_FileRename,
-   NfcPlaylistScene_ConfirmDelete,
-   NfcPlaylistScene_count
-} NfcPlaylistScene;
+   NfcPlaylistView_Submenu,
+   NfcPlaylistView_Popup,
+   NfcPlaylistView_Widget,
+   NfcPlaylistView_VariableItemList,
+   NfcPlaylistView_FileBrowser,
+   NfcPlaylistView_TextInput
+} NfcPlaylistView;
 
 
 typedef struct {
 typedef struct {
-   FuriString* base_file_path;
    FuriString* file_path;
    FuriString* file_path;
-   bool file_selected;
-   bool file_selected_check;
+   bool playlist_selected;
    uint8_t emulate_timeout;
    uint8_t emulate_timeout;
    uint8_t emulate_delay;
    uint8_t emulate_delay;
    bool emulate_led_indicator;
    bool emulate_led_indicator;
@@ -50,21 +48,33 @@ typedef struct {
 typedef struct {
 typedef struct {
    SceneManager* scene_manager;
    SceneManager* scene_manager;
    ViewDispatcher* view_dispatcher;
    ViewDispatcher* view_dispatcher;
-   VariableItemList* variable_item_list;
-   FileBrowser* file_browser;
-   TextInput* text_input;
    Submenu* submenu;
    Submenu* submenu;
    Popup* popup;
    Popup* popup;
    Widget* widget;
    Widget* widget;
+   VariableItemList* variable_item_list;
+   FileBrowser* file_browser;
+   FuriString* file_browser_output;
+   TextInput* text_input;
+   char* text_input_output;
    NotificationApp* notification;
    NotificationApp* notification;
    FuriThread* thread;
    FuriThread* thread;
    NfcPlaylistWorker* nfc_playlist_worker;
    NfcPlaylistWorker* nfc_playlist_worker;
    NfcPlaylistSettings settings;
    NfcPlaylistSettings settings;
-   char* playlist_name;
 } NfcPlaylist;
 } NfcPlaylist;
 
 
 static const int options_emulate_timeout[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
 static const int options_emulate_timeout[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
 static const int default_emulate_timeout = 4;
 static const int default_emulate_timeout = 4;
 static const int options_emulate_delay[] = {0, 1, 2, 3, 4, 5, 6};
 static const int options_emulate_delay[] = {0, 1, 2, 3, 4, 5, 6};
 static const int default_emulate_delay = 0;
 static const int default_emulate_delay = 0;
-static const bool default_emulate_led_indicator = true;
+static const bool default_emulate_led_indicator = true;
+
+#define PLAYLIST_LOCATION "/ext/apps_data/nfc_playlist/"
+#define PLAYLIST_DIR "/ext/apps_data/nfc_playlist"
+
+typedef enum NfcPlaylistLedState {
+   NfcPlaylistLedState_Normal,
+   NfcPlaylistLedState_Error
+} NfcPlaylistLedState;
+
+void start_blink(NfcPlaylist* nfc_playlist, int state);
+void stop_blink(NfcPlaylist* nfc_playlist);

+ 0 - 8
nfc_playlist_i.h

@@ -1,8 +0,0 @@
-#pragma once
-#include "scences/main_menu.h"
-#include "scences/settings.h"
-#include "scences/emulation.h"
-#include "scences/file_select.h"
-#include "scences/file_edit.h"
-#include "scences/file_rename.h"
-#include "scences/confirm_delete.h"

+ 0 - 10
scences/confirm_delete.h

@@ -1,10 +0,0 @@
-#pragma once
-#include <furi.h>
-#include <gui/view_dispatcher.h>
-#include <gui/scene_manager.h>
-#include <gui/modules/widget.h>
-#include <storage/storage.h>
-
-void nfc_playlist_confirm_delete_scene_on_enter(void* context);
-bool nfc_playlist_confirm_delete_scene_on_event(void* context, SceneManagerEvent event);
-void nfc_playlist_confirm_delete_scene_on_exit(void* context);

+ 0 - 20
scences/emulation.h

@@ -1,20 +0,0 @@
-#pragma once
-#include <furi.h>
-#include <storage/storage.h>
-#include <toolbox/stream/stream.h>
-#include <toolbox/stream/file_stream.h>
-#include <lib/worker/nfc_playlist_worker.h>
-#include <lib/led/nfc_playlist_led.h>
-#include <gui/view_dispatcher.h>
-#include <gui/scene_manager.h>
-#include <gui/modules/popup.h>
-
-void nfc_playlist_emulation_scene_on_enter(void* context);
-bool nfc_playlist_emulation_scene_on_event(void* context, SceneManagerEvent event);
-void nfc_playlist_emulation_scene_on_exit(void* context);
-
-typedef enum NfcPlaylistEmulationState {
-   NfcPlaylistEmulationState_Emulating,
-   NfcPlaylistEmulationState_Stopped,
-   NfcPlaylistEmulationState_Canceled
-} NfcPlaylistEmulationState;

+ 0 - 58
scences/file_edit.c

@@ -1,58 +0,0 @@
-#include "nfc_playlist.h"
-#include "scences/file_edit.h"
-
-void nfc_playlist_file_edit_menu_callback(void* context, uint32_t index) {
-   NfcPlaylist* nfc_playlist = context;
-   scene_manager_handle_custom_event(nfc_playlist->scene_manager, index);
-}
-
-void nfc_playlist_file_edit_scene_on_enter(void* context) {
-   NfcPlaylist* nfc_playlist = context;
-
-   submenu_set_header(nfc_playlist->submenu, "Edit Playlist");
-
-   submenu_add_lockable_item(
-      nfc_playlist->submenu,
-      "Delete Playlist",
-      NfcPlaylistMenuSelection_DeletePlaylist,
-      nfc_playlist_file_edit_menu_callback,
-      nfc_playlist,
-      !nfc_playlist->settings.file_selected_check,
-      "No\nplaylist\nselected");
-
-   submenu_add_lockable_item(
-      nfc_playlist->submenu,
-      "Rename Playlist",
-      NfcPlaylistMenuSelection_RenamePlaylist,
-      nfc_playlist_file_edit_menu_callback,
-      nfc_playlist,
-      !nfc_playlist->settings.file_selected_check,
-      "No\nplaylist\nselected");
-
-   view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileEdit);
-}
-
-bool nfc_playlist_file_edit_scene_on_event(void* context, SceneManagerEvent event) {
-   NfcPlaylist* nfc_playlist = context;
-   bool consumed = false;
-   if(event.type == SceneManagerEventTypeCustom) {
-      switch(event.event) {
-         case NfcPlaylistMenuSelection_DeletePlaylist:
-            scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_ConfirmDelete);
-            consumed = true;
-            break;
-         case NfcPlaylistMenuSelection_RenamePlaylist:
-            scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_FileRename);
-            consumed = true;
-            break;
-         default:
-            break;
-      }
-   }
-   return consumed;
-}
-
-void nfc_playlist_file_edit_scene_on_exit(void* context) {
-   NfcPlaylist* nfc_playlist = context;
-   submenu_reset(nfc_playlist->submenu);
-}

+ 0 - 14
scences/file_edit.h

@@ -1,14 +0,0 @@
-#pragma once
-#include <furi.h>
-#include <gui/view_dispatcher.h>
-#include <gui/scene_manager.h>
-#include <gui/modules/submenu.h>
-
-void nfc_playlist_file_edit_scene_on_enter(void* context);
-bool nfc_playlist_file_edit_scene_on_event(void* context, SceneManagerEvent event);
-void nfc_playlist_file_edit_scene_on_exit(void* context);
-
-typedef enum {
-   NfcPlaylistMenuSelection_DeletePlaylist,
-   NfcPlaylistMenuSelection_RenamePlaylist
-} NfcPlaylistFileEditMenuSelection;

+ 0 - 10
scences/file_rename.h

@@ -1,10 +0,0 @@
-#pragma once
-#include <furi.h>
-#include <gui/view_dispatcher.h>
-#include <gui/scene_manager.h>
-#include <gui/modules/text_input.h>
-#include <storage/storage.h>
-
-void nfc_playlist_file_rename_scene_on_enter(void* context);
-bool nfc_playlist_file_rename_scene_on_event(void* context, SceneManagerEvent event);
-void nfc_playlist_file_rename_scene_on_exit(void* context);

+ 0 - 34
scences/file_select.c

@@ -1,34 +0,0 @@
-#include "nfc_playlist.h"
-#include "scences/file_select.h"
-
-void nfc_playlist_file_select_menu_callback(void* context) {
-   NfcPlaylist* nfc_playlist = context;
-   nfc_playlist->settings.file_selected_check = true;
-   scene_manager_previous_scene(nfc_playlist->scene_manager);
-}
-
-void nfc_playlist_file_select_scene_on_enter(void* context) {
-   NfcPlaylist* nfc_playlist = context;
-   file_browser_configure(
-      nfc_playlist->file_browser,
-      ".txt",
-      furi_string_get_cstr(nfc_playlist->settings.base_file_path),
-      true,
-      true,
-      &I_sub1_10px,
-      true);
-   view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileSelect);
-   file_browser_set_callback(nfc_playlist->file_browser, nfc_playlist_file_select_menu_callback, nfc_playlist);
-   file_browser_start(nfc_playlist->file_browser, nfc_playlist->settings.base_file_path);
-}
-
-bool nfc_playlist_file_select_scene_on_event(void* context, SceneManagerEvent event) {
-   UNUSED(event);
-   UNUSED(context);
-   return false;
-}
-
-void nfc_playlist_file_select_scene_on_exit(void* context) {
-   NfcPlaylist* nfc_playlist = context;
-   file_browser_stop(nfc_playlist->file_browser);
-}

+ 0 - 9
scences/file_select.h

@@ -1,9 +0,0 @@
-#pragma once
-#include <furi.h>
-#include <gui/view_dispatcher.h>
-#include <gui/scene_manager.h>
-#include <gui/modules/file_browser.h>
-
-void nfc_playlist_file_select_scene_on_enter(void* context);
-bool nfc_playlist_file_select_scene_on_event(void* context, SceneManagerEvent event);
-void nfc_playlist_file_select_scene_on_exit(void* context);

+ 0 - 23
scences/main_menu.h

@@ -1,23 +0,0 @@
-#pragma once
-#include <furi.h>
-#include <gui/view_dispatcher.h>
-#include <gui/scene_manager.h>
-#include <gui/modules/submenu.h>
-
-void nfc_playlist_main_menu_scene_on_enter(void* context);
-bool nfc_playlist_main_menu_scene_on_event(void* context, SceneManagerEvent event);
-void nfc_playlist_main_menu_scene_on_exit(void* context);
-
-typedef enum {
-   NfcPlaylistEvent_ShowEmulatingPopup,
-   NfcPlaylistEvent_ShowFileSelect,
-   NfcPlaylistEvent_ShowFileEdit,
-   NfcPlaylistEvent_ShowSettings
-} NfcPlaylistMainMenuEvent;
-
-typedef enum {
-   NfcPlaylistMenuSelection_Start,
-   NfcPlaylistMenuSelection_FileSelect,
-   NfcPlaylistMenuSelection_FileEdit,
-   NfcPlaylistMenuSelection_Settings
-} NfcPlaylistMainMenuMenuSelection;

+ 0 - 16
scences/settings.h

@@ -1,16 +0,0 @@
-#pragma once
-#include <furi.h>
-#include <gui/view_dispatcher.h>
-#include <gui/scene_manager.h>
-#include <gui/modules/variable_item_list.h>
-
-void nfc_playlist_settings_scene_on_enter(void* context);
-bool nfc_playlist_settings_scene_on_event(void* context, SceneManagerEvent event);
-void nfc_playlist_settings_scene_on_exit(void* context);
-
-typedef enum {
-   NfcPlaylistSettings_Timeout,
-   NfcPlaylistSettings_Delay,
-   NfcPlaylistSettings_LedIndicator,
-   NfcPlaylistSettings_Reset
-} NfcPlaylistSettingsMenuSelection;

+ 30 - 0
scenes/nfc_playlist_scene.c

@@ -0,0 +1,30 @@
+#include "nfc_playlist_scene.h"
+
+// Generate scene on_enter handlers definition
+#define ADD_SCENE(prefix, name, id) prefix##_##name##_scene_on_enter,
+void (*const nfc_playlist_on_enter_handlers[])(void*) = {
+#include "nfc_playlist_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Generate scene on_event handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_##name##_scene_on_event,
+bool (*const nfc_playlist_on_event_handlers[])(void* context, SceneManagerEvent event) = {
+#include "nfc_playlist_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Generate scene on_exit handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_##name##_scene_on_exit,
+void (*const nfc_playlist_on_exit_handlers[])(void* context) = {
+#include "nfc_playlist_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Initialize scene handlers configuration structure
+const SceneManagerHandlers nfc_playlist_scene_handlers = {
+   .on_enter_handlers = nfc_playlist_on_enter_handlers,
+   .on_event_handlers = nfc_playlist_on_event_handlers,
+   .on_exit_handlers = nfc_playlist_on_exit_handlers,
+   .scene_num = NfcPlaylistScene_Count,
+};

+ 29 - 0
scenes/nfc_playlist_scene.h

@@ -0,0 +1,29 @@
+#pragma once
+
+#include <gui/scene_manager.h>
+
+// Generate scene id and total number
+#define ADD_SCENE(prefix, name, id) NfcPlaylistScene_##id,
+typedef enum {
+#include "nfc_playlist_scene_config.h"
+   NfcPlaylistScene_Count
+} NfcPlaylistScene;
+#undef ADD_SCENE
+
+extern const SceneManagerHandlers nfc_playlist_scene_handlers;
+
+// Generate scene on_enter handlers declaration
+#define ADD_SCENE(prefix, name, id) void prefix##_##name##_scene_on_enter(void*);
+#include "nfc_playlist_scene_config.h"
+#undef ADD_SCENE
+
+// Generate scene on_event handlers declaration
+#define ADD_SCENE(prefix, name, id) \
+   bool prefix##_##name##_scene_on_event(void* context, SceneManagerEvent event);
+#include "nfc_playlist_scene_config.h"
+#undef ADD_SCENE
+
+// Generate scene on_exit handlers declaration
+#define ADD_SCENE(prefix, name, id) void prefix##_##name##_scene_on_exit(void* context);
+#include "nfc_playlist_scene_config.h"
+#undef ADD_SCENE

+ 10 - 0
scenes/nfc_playlist_scene_config.h

@@ -0,0 +1,10 @@
+ADD_SCENE(nfc_playlist, confirm_delete, ConfirmDelete)
+ADD_SCENE(nfc_playlist, emulation, Emulation)
+ADD_SCENE(nfc_playlist, file_edit, FileEdit)
+ADD_SCENE(nfc_playlist, file_rename, FileRename)
+ADD_SCENE(nfc_playlist, main_menu, MainMenu)
+ADD_SCENE(nfc_playlist, name_new_file, NameNewFile)
+ADD_SCENE(nfc_playlist, nfc_select, NfcSelect)
+ADD_SCENE(nfc_playlist, playlist_select, PlaylistSelect)
+ADD_SCENE(nfc_playlist, settings, Settings)
+ADD_SCENE(nfc_playlist, view_playlist_content, ViewPlaylistContent)

+ 4 - 6
scences/confirm_delete.c → scenes/nfc_playlist_scene_confirm_delete.c

@@ -1,5 +1,4 @@
-#include "nfc_playlist.h"
-#include "scences/confirm_delete.h"
+#include "../nfc_playlist.h"
 
 
 void nfc_playlist_confirm_delete_menu_callback(GuiButtonType result, InputType type, void* context) {
 void nfc_playlist_confirm_delete_menu_callback(GuiButtonType result, InputType type, void* context) {
    NfcPlaylist* nfc_playlist = context;
    NfcPlaylist* nfc_playlist = context;
@@ -22,7 +21,7 @@ void nfc_playlist_confirm_delete_scene_on_enter(void* context) {
 
 
    furi_string_free(temp_str);
    furi_string_free(temp_str);
 
 
-   view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_ConfirmDelete);
+   view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Widget);
 }
 }
 
 
 bool nfc_playlist_confirm_delete_scene_on_event(void* context, SceneManagerEvent event) {
 bool nfc_playlist_confirm_delete_scene_on_event(void* context, SceneManagerEvent event) {
@@ -33,9 +32,8 @@ bool nfc_playlist_confirm_delete_scene_on_event(void* context, SceneManagerEvent
          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.file_path));
             storage_simply_remove(storage, furi_string_get_cstr(nfc_playlist->settings.file_path));
-            nfc_playlist->settings.file_selected = false;
-            nfc_playlist->settings.file_selected_check = false;
-            nfc_playlist->settings.file_path = nfc_playlist->settings.base_file_path;
+            nfc_playlist->settings.playlist_selected = false;
+            furi_string_reset(nfc_playlist->settings.file_path);
             furi_record_close(RECORD_STORAGE);
             furi_record_close(RECORD_STORAGE);
             consumed = true;
             consumed = true;
             break;
             break;

+ 19 - 10
scences/emulation.c → scenes/nfc_playlist_scene_emulation.c

@@ -1,5 +1,10 @@
-#include "nfc_playlist.h"
-#include "scences/emulation.h"
+#include "../nfc_playlist.h"
+
+typedef enum NfcPlaylistEmulationState {
+   NfcPlaylistEmulationState_Emulating,
+   NfcPlaylistEmulationState_Stopped,
+   NfcPlaylistEmulationState_Canceled
+} NfcPlaylistEmulationState;
 
 
 NfcPlaylistEmulationState EmulationState = NfcPlaylistEmulationState_Stopped;
 NfcPlaylistEmulationState EmulationState = NfcPlaylistEmulationState_Stopped;
 
 
@@ -8,17 +13,20 @@ int32_t nfc_playlist_emulation_task(void* context) {
 
 
    Storage* storage = furi_record_open(RECORD_STORAGE);
    Storage* storage = furi_record_open(RECORD_STORAGE);
    Stream* stream = file_stream_alloc(storage);
    Stream* stream = file_stream_alloc(storage);
-   FuriString* line = furi_string_alloc();
-   FuriString* tmp_header_str = furi_string_alloc();
-   FuriString* tmp_counter_str = furi_string_alloc();
 
 
    popup_reset(nfc_playlist->popup);
    popup_reset(nfc_playlist->popup);
    popup_set_context(nfc_playlist->popup, nfc_playlist);
    popup_set_context(nfc_playlist->popup, nfc_playlist);
+   
    view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Popup);
    view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Popup);
 
 
-   if (file_stream_open(stream, furi_string_get_cstr(nfc_playlist->settings.file_path), FSAM_READ, FSOM_OPEN_EXISTING) && nfc_playlist->settings.file_selected_check) {
+   if (file_stream_open(stream, furi_string_get_cstr(nfc_playlist->settings.file_path), FSAM_READ, FSOM_OPEN_EXISTING)) {
       EmulationState = NfcPlaylistEmulationState_Emulating;
       EmulationState = NfcPlaylistEmulationState_Emulating;
       int file_position = 0;
       int file_position = 0;
+
+      FuriString* line = furi_string_alloc();
+      FuriString* tmp_header_str = furi_string_alloc();
+      FuriString* tmp_counter_str = furi_string_alloc();
+
       while(stream_read_line(stream, line) && EmulationState == NfcPlaylistEmulationState_Emulating) {
       while(stream_read_line(stream, line) && EmulationState == NfcPlaylistEmulationState_Emulating) {
 
 
          char* file_path = (char*)furi_string_get_cstr(line);
          char* file_path = (char*)furi_string_get_cstr(line);
@@ -80,21 +88,22 @@ int32_t nfc_playlist_emulation_task(void* context) {
             nfc_playlist_worker_stop(nfc_playlist->nfc_playlist_worker);
             nfc_playlist_worker_stop(nfc_playlist->nfc_playlist_worker);
             nfc_playlist_worker_clear_nfc_data(nfc_playlist->nfc_playlist_worker);
             nfc_playlist_worker_clear_nfc_data(nfc_playlist->nfc_playlist_worker);
          }
          }
-         free(file_path);
       }
       }
       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);
       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);
+
       EmulationState = NfcPlaylistEmulationState_Stopped;
       EmulationState = NfcPlaylistEmulationState_Stopped;
+      furi_string_free(line);
+      furi_string_free(tmp_header_str);
+      furi_string_free(tmp_counter_str);
+
    } 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);
    }
    }
 
 
-   furi_string_free(line);
-   furi_string_free(tmp_header_str);
-   furi_string_free(tmp_counter_str);
    file_stream_close(stream);
    file_stream_close(stream);
    furi_record_close(RECORD_STORAGE);
    furi_record_close(RECORD_STORAGE);
    stream_free(stream);
    stream_free(stream);

+ 102 - 0
scenes/nfc_playlist_scene_file_edit.c

@@ -0,0 +1,102 @@
+#include "../nfc_playlist.h"
+
+typedef enum {
+   NfcPlaylistMenuSelection_CreatePlaylist,
+   NfcPlaylistMenuSelection_DeletePlaylist,
+   NfcPlaylistMenuSelection_RenamePlaylist,
+   NfcPlaylistMenuSelection_ViewPlaylistContent,
+   NfcPlaylistMenuSelection_AddNfcItem
+} NfcPlaylistFileEditMenuSelection;
+
+void nfc_playlist_file_edit_menu_callback(void* context, uint32_t index) {
+   NfcPlaylist* nfc_playlist = context;
+   scene_manager_handle_custom_event(nfc_playlist->scene_manager, index);
+}
+
+void nfc_playlist_file_edit_scene_on_enter(void* context) {
+   NfcPlaylist* nfc_playlist = context;
+
+   submenu_set_header(nfc_playlist->submenu, "Edit Playlist");
+
+   submenu_add_item(
+      nfc_playlist->submenu,
+      "Create Playlist",
+      NfcPlaylistMenuSelection_CreatePlaylist,
+      nfc_playlist_file_edit_menu_callback,
+      nfc_playlist);
+
+   submenu_add_lockable_item(
+      nfc_playlist->submenu,
+      "Delete Playlist",
+      NfcPlaylistMenuSelection_DeletePlaylist,
+      nfc_playlist_file_edit_menu_callback,
+      nfc_playlist,
+      furi_string_empty(nfc_playlist->settings.file_path),
+      "No\nplaylist\nselected");
+
+   submenu_add_lockable_item(
+      nfc_playlist->submenu,
+      "Rename Playlist",
+      NfcPlaylistMenuSelection_RenamePlaylist,
+      nfc_playlist_file_edit_menu_callback,
+      nfc_playlist,
+      furi_string_empty(nfc_playlist->settings.file_path),
+      "No\nplaylist\nselected");
+
+   submenu_add_lockable_item(
+      nfc_playlist->submenu,
+      "View Playlist Content",
+      NfcPlaylistMenuSelection_ViewPlaylistContent,
+      nfc_playlist_file_edit_menu_callback,
+      nfc_playlist,
+      furi_string_empty(nfc_playlist->settings.file_path),
+      "No\nplaylist\nselected");
+
+   submenu_add_lockable_item(
+      nfc_playlist->submenu,
+      "Add NFC Item",
+      NfcPlaylistMenuSelection_AddNfcItem,
+      nfc_playlist_file_edit_menu_callback,
+      nfc_playlist,
+      furi_string_empty(nfc_playlist->settings.file_path),
+      "No\nplaylist\nselected");
+
+   view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Submenu);
+}
+
+bool nfc_playlist_file_edit_scene_on_event(void* context, SceneManagerEvent event) {
+   NfcPlaylist* nfc_playlist = context;
+   bool consumed = false;
+   if(event.type == SceneManagerEventTypeCustom) {
+      switch(event.event) {
+         case NfcPlaylistMenuSelection_CreatePlaylist:
+            scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_NameNewFile);
+            consumed = true;
+            break;
+         case NfcPlaylistMenuSelection_DeletePlaylist:
+            scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_ConfirmDelete);
+            consumed = true;
+            break;
+         case NfcPlaylistMenuSelection_RenamePlaylist:
+            scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_FileRename);
+            consumed = true;
+            break;
+         case NfcPlaylistMenuSelection_ViewPlaylistContent:
+            scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_ViewPlaylistContent);
+            consumed = true;
+            break;
+         case NfcPlaylistMenuSelection_AddNfcItem:
+            scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_NfcSelect);
+            consumed = true;
+            break;
+         default:
+            break;
+      }
+   }
+   return consumed;
+}
+
+void nfc_playlist_file_edit_scene_on_exit(void* context) {
+   NfcPlaylist* nfc_playlist = context;
+   submenu_reset(nfc_playlist->submenu);
+}

+ 7 - 7
scences/file_rename.c → scenes/nfc_playlist_scene_file_rename.c

@@ -1,5 +1,4 @@
-#include "nfc_playlist.h"
-#include "scences/file_rename.h"
+#include "../nfc_playlist.h"
 
 
 void nfc_playlist_file_rename_menu_callback(void* context) {
 void nfc_playlist_file_rename_menu_callback(void* context) {
    NfcPlaylist* nfc_playlist = context;
    NfcPlaylist* nfc_playlist = context;
@@ -13,7 +12,7 @@ void nfc_playlist_file_rename_menu_callback(void* context) {
    furi_string_printf(tmp_old_file_path, "%s", old_file_path);
    furi_string_printf(tmp_old_file_path, "%s", old_file_path);
    furi_string_replace(tmp_old_file_path, old_file_name, "");
    furi_string_replace(tmp_old_file_path, old_file_name, "");
 
 
-   furi_string_printf(tmp_new_file_path, "%s%s.txt", furi_string_get_cstr(tmp_old_file_path), nfc_playlist->playlist_name);
+   furi_string_printf(tmp_new_file_path, "%s%s.txt", furi_string_get_cstr(tmp_old_file_path), nfc_playlist->text_input_output);
 
 
    if(!storage_file_exists(storage, furi_string_get_cstr(tmp_new_file_path))) {
    if(!storage_file_exists(storage, furi_string_get_cstr(tmp_new_file_path))) {
       storage_common_rename_safe(storage, furi_string_get_cstr(nfc_playlist->settings.file_path), furi_string_get_cstr(tmp_new_file_path));
       storage_common_rename_safe(storage, furi_string_get_cstr(nfc_playlist->settings.file_path), furi_string_get_cstr(tmp_new_file_path));
@@ -28,11 +27,12 @@ void nfc_playlist_file_rename_menu_callback(void* context) {
 
 
 void nfc_playlist_file_rename_scene_on_enter(void* context) {
 void nfc_playlist_file_rename_scene_on_enter(void* context) {
    NfcPlaylist* nfc_playlist = context;
    NfcPlaylist* nfc_playlist = context;
-   nfc_playlist->playlist_name = (char*)malloc(50);
+   nfc_playlist->text_input_output = (char*)malloc(50);
    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_file_rename_menu_callback, nfc_playlist, nfc_playlist->playlist_name, 50, true);
-   view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileRename);   
+   text_input_set_result_callback(nfc_playlist->text_input, nfc_playlist_file_rename_menu_callback, nfc_playlist, nfc_playlist->text_input_output, 50, true);
+   
+   view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_TextInput);
 }
 }
 
 
 bool nfc_playlist_file_rename_scene_on_event(void* context, SceneManagerEvent event) {
 bool nfc_playlist_file_rename_scene_on_event(void* context, SceneManagerEvent event) {
@@ -44,5 +44,5 @@ bool nfc_playlist_file_rename_scene_on_event(void* context, SceneManagerEvent ev
 void nfc_playlist_file_rename_scene_on_exit(void* context) {
 void nfc_playlist_file_rename_scene_on_exit(void* context) {
    NfcPlaylist* nfc_playlist = context;
    NfcPlaylist* nfc_playlist = context;
    text_input_reset(nfc_playlist->text_input);
    text_input_reset(nfc_playlist->text_input);
-   free(nfc_playlist->playlist_name);
+   free(nfc_playlist->text_input_output);
 }
 }

+ 30 - 13
scences/main_menu.c → scenes/nfc_playlist_scene_main_menu.c

@@ -1,5 +1,18 @@
-#include "nfc_playlist.h"
-#include "scences/main_menu.h"
+#include "../nfc_playlist.h"
+
+typedef enum {
+   NfcPlaylistEvent_ShowEmulation,
+   NfcPlaylistEvent_ShowPlaylistSelect,
+   NfcPlaylistEvent_ShowFileEdit,
+   NfcPlaylistEvent_ShowSettings
+} NfcPlaylistMainMenuEvent;
+
+typedef enum {
+   NfcPlaylistMenuSelection_Start,
+   NfcPlaylistMenuSelection_PlaylistSelect,
+   NfcPlaylistMenuSelection_FileEdit,
+   NfcPlaylistMenuSelection_Settings
+} NfcPlaylistMainMenuMenuSelection;
 
 
 void nfc_playlist_main_menu_menu_callback(void* context, uint32_t index) {
 void nfc_playlist_main_menu_menu_callback(void* context, uint32_t index) {
    NfcPlaylist* nfc_playlist = context;
    NfcPlaylist* nfc_playlist = context;
@@ -8,13 +21,16 @@ void nfc_playlist_main_menu_menu_callback(void* context, uint32_t index) {
 
 
 void nfc_playlist_main_menu_scene_on_enter(void* context) {
 void nfc_playlist_main_menu_scene_on_enter(void* context) {
    NfcPlaylist* nfc_playlist = context;
    NfcPlaylist* nfc_playlist = context;
-   if (!nfc_playlist->settings.file_selected) {
-      nfc_playlist->settings.file_selected = true;
-      scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_FileSelect);
+   if (!nfc_playlist->settings.playlist_selected) {
+      nfc_playlist->settings.playlist_selected = true;
+      scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_PlaylistSelect);
       return;
       return;
    }
    }
 
 
-   submenu_set_header(nfc_playlist->submenu, "NFC Playlist");
+   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);
 
 
    submenu_add_lockable_item(
    submenu_add_lockable_item(
       nfc_playlist->submenu,
       nfc_playlist->submenu,
@@ -22,13 +38,13 @@ void nfc_playlist_main_menu_scene_on_enter(void* context) {
       NfcPlaylistMenuSelection_Start,
       NfcPlaylistMenuSelection_Start,
       nfc_playlist_main_menu_menu_callback,
       nfc_playlist_main_menu_menu_callback,
       nfc_playlist,
       nfc_playlist,
-      !nfc_playlist->settings.file_selected_check,
+      furi_string_empty(nfc_playlist->settings.file_path),
       "No\nplaylist\nselected");
       "No\nplaylist\nselected");
 
 
    submenu_add_item(
    submenu_add_item(
       nfc_playlist->submenu,
       nfc_playlist->submenu,
       "Select playlist",
       "Select playlist",
-      NfcPlaylistMenuSelection_FileSelect,
+      NfcPlaylistMenuSelection_PlaylistSelect,
       nfc_playlist_main_menu_menu_callback,
       nfc_playlist_main_menu_menu_callback,
       nfc_playlist);
       nfc_playlist);
 
 
@@ -45,7 +61,8 @@ void nfc_playlist_main_menu_scene_on_enter(void* context) {
       NfcPlaylistMenuSelection_Settings,
       NfcPlaylistMenuSelection_Settings,
       nfc_playlist_main_menu_menu_callback,
       nfc_playlist_main_menu_menu_callback,
       nfc_playlist);
       nfc_playlist);
-   view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Menu);
+      
+   view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Submenu);
 }
 }
 
 
 bool nfc_playlist_main_menu_scene_on_event(void* context, SceneManagerEvent event) {
 bool nfc_playlist_main_menu_scene_on_event(void* context, SceneManagerEvent event) {
@@ -53,12 +70,12 @@ 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_ShowEmulatingPopup:
-            scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_EmulatingPopup);
+         case NfcPlaylistEvent_ShowEmulation:
+            scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_Emulation);
             consumed = true;
             consumed = true;
             break;
             break;
-         case NfcPlaylistEvent_ShowFileSelect:
-            scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_FileSelect);
+         case NfcPlaylistEvent_ShowPlaylistSelect:
+            scene_manager_next_scene(nfc_playlist->scene_manager, NfcPlaylistScene_PlaylistSelect);
             consumed = true;
             consumed = true;
             break;
             break;
          case NfcPlaylistEvent_ShowFileEdit:
          case NfcPlaylistEvent_ShowFileEdit:

+ 42 - 0
scenes/nfc_playlist_scene_name_new_file.c

@@ -0,0 +1,42 @@
+#include "../nfc_playlist.h"
+
+void nfc_playlist_name_new_file_menu_callback(void* 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);
+
+   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.file_path, file_name);
+   }
+   
+   storage_file_free(file);
+   furi_string_free(file_name);
+   furi_record_close(RECORD_STORAGE);
+   scene_manager_previous_scene(nfc_playlist->scene_manager);
+}
+
+void nfc_playlist_name_new_file_scene_on_enter(void* context) {
+   NfcPlaylist* nfc_playlist = context;
+   nfc_playlist->text_input_output = (char*)malloc(50);
+   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_result_callback(nfc_playlist->text_input, nfc_playlist_name_new_file_menu_callback, nfc_playlist, nfc_playlist->text_input_output, 50, true);
+   
+   view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_TextInput);
+}
+
+bool nfc_playlist_name_new_file_scene_on_event(void* context, SceneManagerEvent event) {
+   UNUSED(context);
+   UNUSED(event);
+   return false;
+}
+
+void nfc_playlist_name_new_file_scene_on_exit(void* context) {
+   NfcPlaylist* nfc_playlist = context;
+   text_input_reset(nfc_playlist->text_input);
+   free(nfc_playlist->text_input_output);
+}

+ 66 - 0
scenes/nfc_playlist_scene_nfc_select.c

@@ -0,0 +1,66 @@
+#include "../nfc_playlist.h"
+
+#define MAX_PLAYLIST_SIZE 1000
+
+void nfc_playlist_nfc_select_menu_callback(void* context) {
+   NfcPlaylist* nfc_playlist = context;
+
+   Storage* storage = furi_record_open(RECORD_STORAGE);
+   File* file = storage_file_alloc(storage);
+   
+   if (storage_file_open(file, furi_string_get_cstr(nfc_playlist->settings.file_path), FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) {
+      uint8_t buffer[MAX_PLAYLIST_SIZE];
+      uint16_t read_count = storage_file_read(file, buffer, MAX_PLAYLIST_SIZE);
+      FuriString* playlist_content = furi_string_alloc();
+
+      for(uint16_t i = 0; i < read_count; i++) {
+         furi_string_push_back(playlist_content, buffer[i]);
+      }
+
+      if (read_count > 0) {
+         furi_string_printf(playlist_content, "\n%s", furi_string_get_cstr(nfc_playlist->file_browser_output));
+      } else {
+         furi_string_printf(playlist_content, "%s", furi_string_get_cstr(nfc_playlist->file_browser_output));
+      }
+
+      storage_file_write(file, furi_string_get_cstr(playlist_content), sizeof(char) * furi_string_utf8_length(playlist_content));
+
+      furi_string_free(playlist_content);
+      storage_file_close(file);
+   }
+
+   storage_file_free(file);
+   furi_record_close(RECORD_STORAGE);
+   furi_string_reset(nfc_playlist->file_browser_output);
+   
+   scene_manager_previous_scene(nfc_playlist->scene_manager);
+}
+
+void nfc_playlist_nfc_select_scene_on_enter(void* context) {
+   NfcPlaylist* nfc_playlist = context;
+   file_browser_configure(
+      nfc_playlist->file_browser,
+      ".nfc",
+      "/ext/nfc/",
+      true,
+      true,
+      &I_Nfc_10px,
+      true);
+   file_browser_set_callback(nfc_playlist->file_browser, nfc_playlist_nfc_select_menu_callback, nfc_playlist);
+   FuriString* tmp_str = furi_string_alloc_set_str("/ext/nfc/");
+   file_browser_start(nfc_playlist->file_browser, tmp_str);
+   furi_string_free(tmp_str);
+   
+   view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileBrowser);
+}
+
+bool nfc_playlist_nfc_select_scene_on_event(void* context, SceneManagerEvent event) {
+   UNUSED(event);
+   UNUSED(context);
+   return false;
+}
+
+void nfc_playlist_nfc_select_scene_on_exit(void* context) {
+   NfcPlaylist* nfc_playlist = context;
+   file_browser_stop(nfc_playlist->file_browser);
+}

+ 37 - 0
scenes/nfc_playlist_scene_playlist_select.c

@@ -0,0 +1,37 @@
+#include "../nfc_playlist.h"
+
+void nfc_playlist_playlist_select_menu_callback(void* context) {
+   NfcPlaylist* nfc_playlist = context;
+   furi_string_swap(nfc_playlist->settings.file_path, nfc_playlist->file_browser_output);
+   furi_string_reset(nfc_playlist->file_browser_output);
+   scene_manager_previous_scene(nfc_playlist->scene_manager);
+}
+
+void nfc_playlist_playlist_select_scene_on_enter(void* context) {
+   NfcPlaylist* nfc_playlist = context;
+   file_browser_configure(
+      nfc_playlist->file_browser,
+      ".txt",
+      PLAYLIST_LOCATION,
+      true,
+      true,
+      &I_Nfc_10px,
+      true);
+   file_browser_set_callback(nfc_playlist->file_browser, nfc_playlist_playlist_select_menu_callback, nfc_playlist);
+   FuriString* tmp_str = furi_string_alloc_set_str(PLAYLIST_LOCATION);
+   file_browser_start(nfc_playlist->file_browser, tmp_str);
+   furi_string_free(tmp_str);
+   
+   view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_FileBrowser);
+}
+
+bool nfc_playlist_playlist_select_scene_on_event(void* context, SceneManagerEvent event) {
+   UNUSED(event);
+   UNUSED(context);
+   return false;
+}
+
+void nfc_playlist_playlist_select_scene_on_exit(void* context) {
+   NfcPlaylist* nfc_playlist = context;
+   file_browser_stop(nfc_playlist->file_browser);
+}

+ 31 - 23
scences/settings.c → scenes/nfc_playlist_scene_settings.c

@@ -1,5 +1,11 @@
-#include "nfc_playlist.h"
-#include "scences/settings.h"
+#include "../nfc_playlist.h"
+
+typedef enum {
+   NfcPlaylistSettings_Timeout,
+   NfcPlaylistSettings_Delay,
+   NfcPlaylistSettings_LedIndicator,
+   NfcPlaylistSettings_Reset
+} NfcPlaylistSettingsMenuSelection;
 
 
 void nfc_playlist_settings_menu_callback(void* context, uint32_t index) {
 void nfc_playlist_settings_menu_callback(void* context, uint32_t index) {
    NfcPlaylist* nfc_playlist = context;
    NfcPlaylist* nfc_playlist = context;
@@ -11,17 +17,17 @@ 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* temp_str = furi_string_alloc();
+   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(temp_str, "%ds", options_emulate_timeout[nfc_playlist->settings.emulate_timeout]);
-         variable_item_set_current_value_text(item, furi_string_get_cstr(temp_str));
+         furi_string_printf(tmp_str, "%ds", options_emulate_timeout[nfc_playlist->settings.emulate_timeout]);
+         variable_item_set_current_value_text(item, furi_string_get_cstr(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(temp_str, "%ds", options_emulate_delay[nfc_playlist->settings.emulate_delay]);
-         variable_item_set_current_value_text(item, furi_string_get_cstr(temp_str));
+         furi_string_printf(tmp_str, "%ds", options_emulate_delay[nfc_playlist->settings.emulate_delay]);
+         variable_item_set_current_value_text(item, furi_string_get_cstr(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;
@@ -30,12 +36,12 @@ void nfc_playlist_settings_options_change_callback(VariableItem* item) {
       default:
       default:
          break;
          break;
    }
    }
-   furi_string_free(temp_str);
+   furi_string_free(tmp_str);
 }
 }
 
 
 void nfc_playlist_settings_scene_on_enter(void* context) {
 void nfc_playlist_settings_scene_on_enter(void* context) {
    NfcPlaylist* nfc_playlist = context;
    NfcPlaylist* nfc_playlist = context;
-   FuriString* temp_str = furi_string_alloc();
+   FuriString* tmp_str = furi_string_alloc();
 
 
    variable_item_list_set_header(nfc_playlist->variable_item_list, "Settings");
    variable_item_list_set_header(nfc_playlist->variable_item_list, "Settings");
 
 
@@ -46,8 +52,8 @@ void nfc_playlist_settings_scene_on_enter(void* context) {
       nfc_playlist_settings_options_change_callback,
       nfc_playlist_settings_options_change_callback,
       nfc_playlist);
       nfc_playlist);
    variable_item_set_current_value_index(emulation_timeout_settings, nfc_playlist->settings.emulate_timeout);
    variable_item_set_current_value_index(emulation_timeout_settings, nfc_playlist->settings.emulate_timeout);
-   furi_string_printf(temp_str, "%ds", options_emulate_timeout[nfc_playlist->settings.emulate_timeout]);
-   variable_item_set_current_value_text(emulation_timeout_settings, furi_string_get_cstr(temp_str));
+   furi_string_printf(tmp_str, "%ds", options_emulate_timeout[nfc_playlist->settings.emulate_timeout]);
+   variable_item_set_current_value_text(emulation_timeout_settings, furi_string_get_cstr(tmp_str));
 
 
    VariableItem* emulation_delay_settings = variable_item_list_add(
    VariableItem* emulation_delay_settings = variable_item_list_add(
       nfc_playlist->variable_item_list,
       nfc_playlist->variable_item_list,
@@ -56,8 +62,8 @@ void nfc_playlist_settings_scene_on_enter(void* context) {
       nfc_playlist_settings_options_change_callback,
       nfc_playlist_settings_options_change_callback,
       nfc_playlist);
       nfc_playlist);
    variable_item_set_current_value_index(emulation_delay_settings, nfc_playlist->settings.emulate_delay);
    variable_item_set_current_value_index(emulation_delay_settings, nfc_playlist->settings.emulate_delay);
-   furi_string_printf(temp_str, "%ds", options_emulate_delay[nfc_playlist->settings.emulate_delay]);
-   variable_item_set_current_value_text(emulation_delay_settings, furi_string_get_cstr(temp_str));
+   furi_string_printf(tmp_str, "%ds", options_emulate_delay[nfc_playlist->settings.emulate_delay]);
+   variable_item_set_current_value_text(emulation_delay_settings, furi_string_get_cstr(tmp_str));
 
 
    VariableItem* emulation_led_indicator_settings = variable_item_list_add(
    VariableItem* emulation_led_indicator_settings = variable_item_list_add(
       nfc_playlist->variable_item_list,
       nfc_playlist->variable_item_list,
@@ -70,11 +76,13 @@ void nfc_playlist_settings_scene_on_enter(void* context) {
 
 
    variable_item_list_add(nfc_playlist->variable_item_list, "Reset settings", 0, NULL, NULL);
    variable_item_list_add(nfc_playlist->variable_item_list, "Reset settings", 0, NULL, NULL);
 
 
-   variable_item_list_set_enter_callback(nfc_playlist->variable_item_list, nfc_playlist_settings_menu_callback, nfc_playlist);
-
-   furi_string_free(temp_str);
+   VariableItem* credits = variable_item_list_add(nfc_playlist->variable_item_list, "acegoal07", 1, NULL, NULL);
+   variable_item_set_current_value_text(credits, "Credits");
 
 
-   view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Settings);
+   variable_item_list_set_enter_callback(nfc_playlist->variable_item_list, nfc_playlist_settings_menu_callback, nfc_playlist);
+   furi_string_free(tmp_str);
+   
+   view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_VariableItemList);
 }
 }
 
 
 bool nfc_playlist_settings_scene_on_event(void* context, SceneManagerEvent event) {
 bool nfc_playlist_settings_scene_on_event(void* context, SceneManagerEvent event) {
@@ -83,26 +91,26 @@ bool nfc_playlist_settings_scene_on_event(void* context, SceneManagerEvent event
    if (event.type == SceneManagerEventTypeCustom) {
    if (event.type == SceneManagerEventTypeCustom) {
       switch(event.event) {
       switch(event.event) {
          case NfcPlaylistSettings_Reset:
          case NfcPlaylistSettings_Reset:
-            FuriString* temp_str = furi_string_alloc();
+            FuriString* tmp_str = furi_string_alloc();
 
 
             nfc_playlist->settings.emulate_timeout = default_emulate_timeout;
             nfc_playlist->settings.emulate_timeout = default_emulate_timeout;
             VariableItem* emulation_timeout_settings = variable_item_list_get(nfc_playlist->variable_item_list, NfcPlaylistSettings_Timeout);
             VariableItem* emulation_timeout_settings = variable_item_list_get(nfc_playlist->variable_item_list, NfcPlaylistSettings_Timeout);
             variable_item_set_current_value_index(emulation_timeout_settings, nfc_playlist->settings.emulate_timeout);
             variable_item_set_current_value_index(emulation_timeout_settings, nfc_playlist->settings.emulate_timeout);
-            furi_string_printf(temp_str, "%ds", options_emulate_timeout[nfc_playlist->settings.emulate_timeout]);
-            variable_item_set_current_value_text(emulation_timeout_settings, furi_string_get_cstr(temp_str));
+            furi_string_printf(tmp_str, "%ds", options_emulate_timeout[nfc_playlist->settings.emulate_timeout]);
+            variable_item_set_current_value_text(emulation_timeout_settings, furi_string_get_cstr(tmp_str));
 
 
             nfc_playlist->settings.emulate_delay = default_emulate_delay;
             nfc_playlist->settings.emulate_delay = default_emulate_delay;
             VariableItem* emulation_delay_settings = variable_item_list_get(nfc_playlist->variable_item_list, NfcPlaylistSettings_Delay);
             VariableItem* emulation_delay_settings = variable_item_list_get(nfc_playlist->variable_item_list, NfcPlaylistSettings_Delay);
             variable_item_set_current_value_index(emulation_delay_settings, nfc_playlist->settings.emulate_delay);
             variable_item_set_current_value_index(emulation_delay_settings, nfc_playlist->settings.emulate_delay);
-            furi_string_printf(temp_str, "%ds", options_emulate_delay[nfc_playlist->settings.emulate_delay]);
-            variable_item_set_current_value_text(emulation_delay_settings, furi_string_get_cstr(temp_str));
+            furi_string_printf(tmp_str, "%ds", options_emulate_delay[nfc_playlist->settings.emulate_delay]);
+            variable_item_set_current_value_text(emulation_delay_settings, furi_string_get_cstr(tmp_str));
 
 
             nfc_playlist->settings.emulate_led_indicator = default_emulate_led_indicator;
             nfc_playlist->settings.emulate_led_indicator = default_emulate_led_indicator;
             VariableItem* emulation_led_indicator_settings = variable_item_list_get(nfc_playlist->variable_item_list, NfcPlaylistSettings_LedIndicator);
             VariableItem* emulation_led_indicator_settings = variable_item_list_get(nfc_playlist->variable_item_list, NfcPlaylistSettings_LedIndicator);
             variable_item_set_current_value_index(emulation_led_indicator_settings, nfc_playlist->settings.emulate_led_indicator);
             variable_item_set_current_value_index(emulation_led_indicator_settings, nfc_playlist->settings.emulate_led_indicator);
             variable_item_set_current_value_text(emulation_led_indicator_settings, nfc_playlist->settings.emulate_led_indicator ? "ON" : "OFF");
             variable_item_set_current_value_text(emulation_led_indicator_settings, nfc_playlist->settings.emulate_led_indicator ? "ON" : "OFF");
 
 
-            furi_string_free(temp_str);
+            furi_string_free(tmp_str);
             consumed = true;
             consumed = true;
             break;
             break;
          default:
          default:

+ 44 - 0
scenes/nfc_playlist_scene_view_playlist_content.c

@@ -0,0 +1,44 @@
+#include "../nfc_playlist.h"
+
+#define MAX_PLAYLIST_SIZE 1000
+
+void nfc_playlist_view_playlist_content_scene_on_enter(void* context) {
+   NfcPlaylist* nfc_playlist = context;
+
+   Storage* storage = furi_record_open(RECORD_STORAGE);
+   File* file = storage_file_alloc(storage);
+   
+   if (storage_file_open(file, furi_string_get_cstr(nfc_playlist->settings.file_path), FSAM_READ, FSOM_OPEN_EXISTING)) {
+      uint8_t buffer[MAX_PLAYLIST_SIZE];
+      uint16_t read_count = storage_file_read(file, buffer, MAX_PLAYLIST_SIZE);
+      FuriString* playlist_content = furi_string_alloc();
+
+      for(uint16_t i = 0; i < read_count; i++) {
+         furi_string_push_back(playlist_content, buffer[i]);
+      }
+
+      widget_add_text_scroll_element(nfc_playlist->widget, 4, 4, 124, 60, furi_string_get_cstr(playlist_content));
+      widget_add_frame_element(nfc_playlist->widget, 0, 0, 128, 64, 0);
+
+      furi_string_free(playlist_content);
+      storage_file_close(file);
+   } else {
+      widget_add_text_box_element(nfc_playlist->widget, 0, 0, 128, 64, AlignCenter, AlignCenter, "\eFailed to open playlist\n\nPress back\e", false);
+   }
+
+   storage_file_free(file);
+   furi_record_close(RECORD_STORAGE);
+
+   view_dispatcher_switch_to_view(nfc_playlist->view_dispatcher, NfcPlaylistView_Widget);
+}
+
+bool nfc_playlist_view_playlist_content_scene_on_event(void* context, SceneManagerEvent event) {
+   UNUSED(context);
+   UNUSED(event);
+   return false;
+}
+
+void nfc_playlist_view_playlist_content_scene_on_exit(void* context) {
+   NfcPlaylist* nfc_playlist = context;
+   widget_reset(nfc_playlist->widget);
+}