diff --git a/apps/filetree.c b/apps/filetree.c
index fc5e4d3..6b96d10 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -105,11 +105,12 @@ bool ft_play_playlist(char* pathname, char* dirname, char* filename)
splash(0, ID2P(LANG_WAIT));
- /* about to create a new current playlist...
- allow user to cancel the operation */
- if (!warn_on_pl_erase())
- return false;
-
+ /* maybe save the current playlist */
+ if (!playlist_maybe_save_current())
+ {
+ return false;
+ }
+
if (playlist_create(dirname, filename) != -1)
{
if (global_settings.playlist_shuffle)
@@ -407,11 +408,13 @@ int ft_enter(struct tree_context* c)
splash(0, ID2P(LANG_WAIT));
- /* about to create a new current playlist...
- allow user to cancel the operation */
- if (!warn_on_pl_erase())
- break;
-
+ /* about to create a new current
+ * playlist... allow user to
+ * cancel the operation
+ */
+ if (!playlist_maybe_save_current())
+ break;
+
if (global_settings.party_mode && audio_status())
{
playlist_insert_track(NULL, buf,
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 603e43d..6bdae38 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -6816,6 +6816,62 @@
+ id: LANG_SAVE_CURRENT_PLAYLIST_Q
+ desc: In the potentially save playlist menu
+ user:
+
+ *: "Save Current Playlist?"
+
+
+ *: "Save Current Playlist?"
+
+
+ *: "Save Current Playlist?"
+
+
+
+ id: LANG_SAVE_CURRENT_PLAYLIST_AS
+ desc: In the potentially save playlist menu
+ user:
+
+ *: "as '%s'"
+
+
+ *: "as '%s'"
+
+
+ *: "Save Current Playlist as '%s'"
+
+
+
+ id: LANG_SAVE_CURRENT_PLAYLIST_AS_PROMPT
+ desc: In the potentially save playlist menu
+ user:
+
+ *: "as ..."
+
+
+ *: "as ..."
+
+
+ *: "as ..."
+
+
+
+ id: LANG_DONT_SAVE_CURRENT_PLAYLIST
+ desc: In the potentially save playlist menu
+ user:
+
+ *: "No (Changes will be lost)"
+
+
+ *: "No (Changes will be lost)"
+
+
+ *: "No (Changes will be lost)"
+
+
+
id: LANG_PLAYLIST_SAVE_COUNT
desc: splash number of tracks saved
user:
@@ -6873,21 +6929,21 @@
id: LANG_WARN_ERASEDYNPLAYLIST_MENU
- desc: in playlist options menu, option to warn when erasing dynamic playlist
+ desc: in playlist options menu, option to warn when erasing modified playlists
user:
- *: "Warn When Erasing Dynamic Playlist"
+ *: "Warn When Erasing Modified Playlist"
- *: "Warn When Erasing Dynamic Playlist"
+ *: "Warn When Erasing Modified Playlist"
- *: "Warn When Erasing Dynamic Playlist"
+ *: "Warn When Erasing Modified Playlist"
- id: LANG_WARN_ERASEDYNPLAYLIST_PROMPT
- desc: prompt shown when about to erase a modified dynamic playlist
+ id: LANG_WARN_SAVE_PLAYLIST_PROMPT
+ desc: prompt shown when about to erase a modified playlist
user:
*: "Erase dynamic playlist?"
@@ -6900,6 +6956,20 @@
+ id: LANG_WARN_ERASEDYNPLAYLIST_CONTINUE
+ desc: option to select if we are happy to continue and erase current playlist
+ user:
+
+ *: "Continue"
+
+
+ *: "Continue"
+
+
+ *: "Continue"
+
+
+
id: LANG_SHUTDOWN
desc: in main menu
user:
diff --git a/apps/menus/playlist_menu.c b/apps/menus/playlist_menu.c
index 6345df9..4b1e5bf 100644
--- a/apps/menus/playlist_menu.c
+++ b/apps/menus/playlist_menu.c
@@ -39,31 +39,90 @@
#include "playlist_viewer.h"
#include "talk.h"
#include "playlist_catalog.h"
+#include "sprintf.h"
-int save_playlist_screen(struct playlist_info* playlist)
+#include "debug.h"
+
+extern struct playlist_info current_playlist;
+
+/*
+ playlist_menu_getname
+
+ Fetch the current playlist name and then ensure:
+
+ a) Ends in m3u8 (as we encode as UTF8)
+ b) Contains a proper path
+ c) Failing that is the default path
+*/
+
+static void playlist_menu_getname(struct playlist_info* playlist, char *str, int maxlen)
{
- char temp[MAX_PATH+1];
int len;
- playlist_get_name(playlist, temp, sizeof(temp));
- len = strlen(temp);
+ /*
+ Fetch the playlist name, if playlist is NULL it will
+ fetch the current playing playlist name
+ */
+ playlist_get_name(playlist, str, maxlen);
+ len = strlen(str);
- if (len > 4 && !strcasecmp(&temp[len-4], ".m3u"))
- strcat(temp, "8");
+ /* Make sure playlist always ends in m3u8 */
+ if (len > 4 && !strcasecmp(&str[len-4], ".m3u"))
+ strcat(str, "8");
- if (len <= 5 || strcasecmp(&temp[len-5], ".m3u8"))
- strcpy(temp, DEFAULT_DYNAMIC_PLAYLIST_NAME);
+ /* If the playlist is shorter than the extension then it's
+ * probably a dud filename so replace it with the default
+ * filename
+ */
+ if (len<=5)
+ {
+ /* directory config is of the format: "dir: /path/to/dir" */
+ if (global_settings.playlist_catalog_dir[0])
+ {
+ snprintf(str, maxlen, "%s%s", global_settings.playlist_catalog_dir, DEFAULT_DYNAMIC_PLAYLIST_NAME);
+ } else {
+ strncpy(str, DEFAULT_DYNAMIC_PLAYLIST_NAME, sizeof(DEFAULT_DYNAMIC_PLAYLIST_NAME));
+ }
+ }
+}
+
+/*
+ save_playlist_screen
- if (!kbd_input(temp, sizeof(temp)))
+ Called when we want to save the current playlist. If the current
+ playlist is already named then sets the starting string as that.
+
+ Returns 0 if we didn't anything, 1 once the playlist is saved
+*/
+
+int save_playlist_screen(struct playlist_info* playlist)
+{
+ char temp[MAX_PATH+1];
+
+ playlist_menu_getname(playlist, temp, MAX_PATH);
+
+ if (!kbd_input(temp, MAX_PATH))
{
playlist_save(playlist, temp);
/* reload in case playlist was saved to cwd */
reload_directory();
+
+ /* can exit menu now */
+ return 1;
}
return 0;
}
+
+/*
+ Main Menu -> Playlists ->
+ + Create Playlist
+ + View Current Playlist
+ + Save Current Playlist
+ + View Catalog
+*/
+
MENUITEM_FUNCTION(create_playlist_item, 0, ID2P(LANG_CREATE_PLAYLIST),
(int(*)(void))create_playlist, NULL, NULL, Icon_NOICON);
MENUITEM_FUNCTION(view_playlist, 0, ID2P(LANG_VIEW_DYNAMIC_PLAYLIST),
@@ -74,13 +133,124 @@ MENUITEM_FUNCTION(save_playlist, MENU_FUNC_USEPARAM, ID2P(LANG_SAVE_DYNAMIC_PLAY
MENUITEM_FUNCTION(catalog, 0, ID2P(LANG_CATALOG_VIEW),
(int(*)(void))catalog_view_playlists,
NULL, NULL, Icon_NOICON);
+MAKE_MENU(playlist_options, ID2P(LANG_PLAYLISTS), NULL,
+ Icon_Playlist,
+ &create_playlist_item, &view_playlist, &save_playlist, &catalog);
+
+/*
+ Settings -> General Settings -> Playlists ->
+ + Recursively Insert Directories
+ + Warn When Erasing Modified Playlist
+*/
+
MENUITEM_SETTING(recursive_dir_insert, &global_settings.recursive_dir_insert, NULL);
MENUITEM_SETTING(warn_on_erase, &global_settings.warnon_erase_dynplaylist, NULL);
MAKE_MENU(playlist_settings, ID2P(LANG_PLAYLISTS), NULL,
Icon_Playlist,
&recursive_dir_insert, &warn_on_erase);
-MAKE_MENU(playlist_options, ID2P(LANG_PLAYLISTS), NULL,
- Icon_Playlist,
- &create_playlist_item, &view_playlist, &save_playlist, &catalog);
+/* Returns "Save current as " */
+static char* save_playlist_as_string(int selected_item, void * data, char *buffer)
+{
+ char temp[MAX_PATH];
+
+ playlist_menu_getname(NULL, temp, MAX_PATH);
+ snprintf(buffer, MAX_PATH, str(LANG_SAVE_CURRENT_PLAYLIST_AS), temp);
+ return buffer;
+}
+
+/* Just save the playlist and exit */
+int save_playlist_now(struct playlist_info* playlist)
+{
+ char temp[MAX_PATH];
+
+ playlist_menu_getname(NULL, temp, MAX_PATH);
+ playlist_save(playlist, temp);
+ /* reload in case playlist was saved to cwd */
+ reload_directory();
+ return 1;
+}
+
+/*
+ Menu:
+
+ (Potential playlist erasing action) ->
+ "Save current playlist?
+ + as "current name"
+ + as ....
+ + No (Changes will be lost)
+*/
+
+MENUITEM_FUNCTION_DYNTEXT(pmsc_save_playlist_as,
+ MENU_FUNC_CHECK_RETVAL,
+ (int(*)(void*))save_playlist_now, /* func */
+ NULL,
+ save_playlist_as_string,
+ NULL, /* voice callback */
+ NULL,
+ NULL, Icon_NOICON);
+
+MENUITEM_FUNCTION(pmsc_save_playlist,
+ MENU_FUNC_USEPARAM|MENU_FUNC_CHECK_RETVAL,
+ ID2P(LANG_SAVE_CURRENT_PLAYLIST_AS_PROMPT),
+ (int(*)(void*))save_playlist_screen,
+ ¤t_playlist,
+ NULL, Icon_NOICON);
+
+MENUITEM_RETURNVALUE(pmsc_continue,
+ ID2P(LANG_DONT_SAVE_CURRENT_PLAYLIST), /* Continue */
+ 0, /* Returns 0 */
+ NULL, Icon_NOICON);
+
+MAKE_MENU(maybe_save_menu, ID2P(LANG_SAVE_CURRENT_PLAYLIST_Q), NULL,
+ Icon_Playlist,
+ &pmsc_save_playlist_as, &pmsc_save_playlist, &pmsc_continue);
+
+/*
+ * Potentially save current dynamic playlist.
+ *
+ * Originally we used to warn if the dynamic playlist was going to get
+ * over-written. Now we offer multiple options for quick save
+ *
+ * "Save current playlist?
+ * - as "current name"
+ * - as ....
+ * - No (Changes will be lost)
+ *
+ * If the user aborts the menu (e.g. going "back") we return false up
+ * the chain and abort whatever action we were about to do
+ *
+ */
+bool playlist_maybe_save_current(void)
+{
+ bool r=true;
+
+ DEBUGF("playlist_maybe_save_current: c:%s pm:%s mod:%s\n",
+ global_settings.warnon_erase_dynplaylist?"true":"false",
+ global_settings.party_mode?"true":"false",
+ playlist_modified(NULL)?"true":"false");
+
+ /* We only care if the playlist has been modified */
+ if (global_settings.warnon_erase_dynplaylist &&
+ !global_settings.party_mode &&
+ playlist_modified(NULL))
+ {
+ int menu_selection = 0;
+ int menu_r;
+ menu_r = do_menu(&maybe_save_menu, &menu_selection, NULL, false);
+
+
+ DEBUGF("playlist_maybe_save_current: menu_selection=%d menu_r=%d\n",
+ menu_selection, menu_r);
+
+ /* Did we abort? */
+ if (menu_r == GO_TO_PREVIOUS) {
+ r = false;
+ }
+ }
+
+ DEBUGF("playlist_maybe_save_current: %s\n", r?"true":"false");
+ return r;
+}
+
diff --git a/apps/misc.c b/apps/misc.c
index 1410d47..3644736 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -238,24 +238,6 @@ char *create_datetime_filename(char *buffer, const char *path,
}
#endif /* CONFIG_RTC */
-/* Ask the user if they really want to erase the current dynamic playlist
- * returns true if the playlist should be replaced */
-bool warn_on_pl_erase(void)
-{
- if (global_settings.warnon_erase_dynplaylist &&
- !global_settings.party_mode &&
- playlist_modified(NULL))
- {
- static const char *lines[] =
- {ID2P(LANG_WARN_ERASEDYNPLAYLIST_PROMPT)};
- static const struct text_message message={lines, 1};
-
- return (gui_syncyesno_run(&message, NULL, NULL) == YESNO_YES);
- }
- else
- return true;
-}
-
/* Read (up to) a line of text from fd into buffer and return number of bytes
* read (which may be larger than the number of bytes stored in buffer). If
* an error occurs, -1 is returned (and buffer contains whatever could be
diff --git a/apps/playlist.c b/apps/playlist.c
index 38f6851..70d8b11 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -143,7 +143,7 @@ struct directory_search_context {
int count;
};
-static struct playlist_info current_playlist;
+struct playlist_info current_playlist;
static char now_playing[MAX_PATH+1];
static void empty_playlist(struct playlist_info* playlist, bool resume);
@@ -3468,6 +3468,7 @@ int playlist_save(struct playlist_info* playlist, char *filename)
return result;
}
+
/*
* Search specified directory for tracks and notify via callback. May be
* called recursively.
diff --git a/apps/playlist.h b/apps/playlist.h
index df3bd62..8fe85fb 100644
--- a/apps/playlist.h
+++ b/apps/playlist.h
@@ -165,6 +165,7 @@ char *playlist_get_name(const struct playlist_info* playlist, char *buf,
int playlist_get_track_info(struct playlist_info* playlist, int index,
struct playlist_track_info* info);
int playlist_save(struct playlist_info* playlist, char *filename);
+bool playlist_maybe_save_current(void);
int playlist_directory_tracksearch(const char* dirname, bool recurse,
int (*callback)(char*, void*),
void* context);
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 7777a9f..99e9762 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -1495,10 +1495,10 @@ int tagtree_enter(struct tree_context* c)
break;
}
c->dirlevel--;
- /* about to create a new current playlist...
- allow user to cancel the operation */
- if (!warn_on_pl_erase())
- break;
+
+ /* maybe save the current playlist */
+ if (!playlist_maybe_save_current())
+ break;
if (tagtree_play_folder(c) >= 0)
rc = 2;