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 f0099e4..5f25aa0 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..4804456 100644 --- a/apps/menus/playlist_menu.c +++ b/apps/menus/playlist_menu.c @@ -39,6 +39,46 @@ #include "playlist_viewer.h" #include "talk.h" #include "playlist_catalog.h" +#include "sprintf.h" + +#include "debug.h" + +extern struct playlist_info current_playlist; + +/* + funge_playlist_name + + Ensure the name of the playlist: + + a) Ends in m3u8 (as we encode as UTF8) + b) Contains a proper path + c) Failing that is the default path +*/ + +static void funge_playlist_name(char *str, int maxlen) +{ + int len = strlen(str); + + /* Make sure playlist always ends in m3u8 */ + if (len > 4 && !strcasecmp(&str[len-4], ".m3u")) + strcat(str, "8"); + + /* 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)); + } + } +} + int save_playlist_screen(struct playlist_info* playlist) { @@ -48,22 +88,24 @@ int save_playlist_screen(struct playlist_info* playlist) playlist_get_name(playlist, temp, sizeof(temp)); len = strlen(temp); - if (len > 4 && !strcasecmp(&temp[len-4], ".m3u")) - strcat(temp, "8"); - - if (len <= 5 || strcasecmp(&temp[len-5], ".m3u8")) - strcpy(temp, DEFAULT_DYNAMIC_PLAYLIST_NAME); + DEBUGF("save_playlist_screen: name %s\n", temp); + funge_playlist_name(temp, MAX_PATH); + if (!kbd_input(temp, sizeof(temp))) { playlist_save(playlist, temp); /* reload in case playlist was saved to cwd */ reload_directory(); + + /* can exit menu now */ + return 1; } return 0; } + 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), @@ -84,3 +126,110 @@ MAKE_MENU(playlist_options, ID2P(LANG_PLAYLISTS), NULL, Icon_Playlist, &create_playlist_item, &view_playlist, &save_playlist, &catalog); + +/* + * 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 + * + */ + +/* Returns "Save current as " */ +static char* pmsc_get_current_playlist(int selected_item, void * data, char *buffer) +{ + char temp[MAX_PATH],*t; + t = playlist_get_name(NULL, temp, MAX_PATH); + funge_playlist_name(t, MAX_PATH); + snprintf(buffer, MAX_PATH, str(LANG_SAVE_CURRENT_PLAYLIST_AS), t); + return buffer; +} + +/* Just save the playlist and exit */ +int save_playlist_now(struct playlist_info* playlist) +{ + char temp[MAX_PATH+1]; + int len; + + playlist_get_name(playlist, temp, sizeof(temp)); + funge_playlist_name(temp, MAX_PATH); + len = strlen(temp); + + DEBUGF("save_playlist_now: name %s\n", temp); + + playlist_save(playlist, temp); + /* reload in case playlist was saved to cwd */ + reload_directory(); + + return 1; +} + + + + +/* Define the menu */ +MENUITEM_RETURNVALUE(pmsc_continue, + ID2P(LANG_DONT_SAVE_CURRENT_PLAYLIST), /* Continue */ + 0, /* Returns 0 */ + NULL, Icon_NOICON); + +MENUITEM_FUNCTION_DYNTEXT(pmsc_save_playlist_as, + MENU_FUNC_USEPARAM|MENU_FUNC_CHECK_RETVAL, /* Parameter passed */ + (int(*)(void*))save_playlist_now, /* func */ + (void*)¤t_playlist, /* param */ + pmsc_get_current_playlist, /* txt callback */ + NULL, /* voice callback */ + ¤t_playlist, /* callback data */ + 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); + +MAKE_MENU(maybe_save_menu, ID2P(LANG_SAVE_CURRENT_PLAYLIST_Q), NULL, + Icon_Playlist, + &pmsc_save_playlist_as, &pmsc_save_playlist, &pmsc_continue); + +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 11cdee1..82b570d 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -232,6 +232,7 @@ char *create_datetime_filename(char *buffer, const char *path, } #endif /* CONFIG_RTC */ +#if 0 /* 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) @@ -249,6 +250,7 @@ bool warn_on_pl_erase(void) else return true; } +#endif /* 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 diff --git a/apps/playlist.c b/apps/playlist.c index 95e1b82..a6751bc 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); @@ -3467,6 +3467,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;