use of com.simplecity.amp_library.model.Playlist in project Shuttle by timusus.
the class PlaylistUtils method addToPlaylist.
/**
* Method addToPlaylist.
*
* @param playlist Playlist
* @param songs List<Song>
* @return boolean true if the playlist addition was successful
*/
@SuppressLint("CheckResult")
public static void addToPlaylist(Context context, Playlist playlist, List<Song> songs, Runnable insertCallback) {
if (playlist == null || songs == null || songs.isEmpty()) {
return;
}
final ArrayList<Song> mutableSongList = new ArrayList<>(songs);
playlist.getSongsObservable().first(Collections.emptyList()).observeOn(AndroidSchedulers.mainThread()).subscribe(existingSongs -> {
if (!SettingsManager.getInstance().ignoreDuplicates()) {
List<Song> duplicates = Stream.of(existingSongs).filter(mutableSongList::contains).distinct().toList();
if (!duplicates.isEmpty()) {
@SuppressLint("InflateParams") View customView = LayoutInflater.from(context).inflate(R.layout.dialog_playlist_duplicates, null);
TextView messageText = customView.findViewById(R.id.textView);
CheckBox applyToAll = customView.findViewById(R.id.applyToAll);
CheckBox alwaysAdd = customView.findViewById(R.id.alwaysAdd);
if (duplicates.size() <= 1) {
applyToAll.setVisibility(View.GONE);
applyToAll.setChecked(false);
}
messageText.setText(getPlaylistRemoveString(context, duplicates.get(0)));
applyToAll.setText(getApplyCheckboxString(context, duplicates.size()));
DialogUtils.getBuilder(context).title(R.string.dialog_title_playlist_duplicates).customView(customView, false).positiveText(R.string.dialog_button_playlist_duplicate_add).autoDismiss(false).onPositive((dialog, which) -> {
// If we've only got one item, or we're applying it to all items
if (duplicates.size() != 1 && !applyToAll.isChecked()) {
// If we're 'adding' this song, we remove it from the 'duplicates' list
duplicates.remove(0);
messageText.setText(getPlaylistRemoveString(context, duplicates.get(0)));
applyToAll.setText(getApplyCheckboxString(context, duplicates.size()));
} else {
// Add all songs to the playlist
insertPlaylistItems(context, playlist, mutableSongList, existingSongs.size(), insertCallback);
SettingsManager.getInstance().setIgnoreDuplicates(alwaysAdd.isChecked());
dialog.dismiss();
}
}).negativeText(R.string.dialog_button_playlist_duplicate_skip).onNegative((dialog, which) -> {
// If we've only got one item, or we're applying it to all items
if (duplicates.size() != 1 && !applyToAll.isChecked()) {
// If we're 'skipping' this song, we remove it from the 'duplicates' list,
// and from the ids to be added
mutableSongList.remove(duplicates.remove(0));
messageText.setText(getPlaylistRemoveString(context, duplicates.get(0)));
applyToAll.setText(getApplyCheckboxString(context, duplicates.size()));
} else {
// Remove duplicates from our set of ids
Stream.of(duplicates).filter(mutableSongList::contains).forEach(mutableSongList::remove);
insertPlaylistItems(context, playlist, mutableSongList, existingSongs.size(), insertCallback);
SettingsManager.getInstance().setIgnoreDuplicates(alwaysAdd.isChecked());
dialog.dismiss();
}
}).show();
} else {
insertPlaylistItems(context, playlist, mutableSongList, existingSongs.size(), insertCallback);
}
} else {
insertPlaylistItems(context, playlist, mutableSongList, existingSongs.size(), insertCallback);
}
}, error -> LogUtils.logException(TAG, "PlaylistUtils: Error determining existing songs", error));
}
use of com.simplecity.amp_library.model.Playlist in project Shuttle by timusus.
the class PlaylistUtils method createM3uPlaylist.
@SuppressLint("CheckResult")
public static void createM3uPlaylist(final Context context, final Playlist playlist) {
ProgressDialog progressDialog = new ProgressDialog(context);
progressDialog.setIndeterminate(true);
progressDialog.setTitle(R.string.saving_playlist);
progressDialog.show();
playlist.getSongsObservable().first(Collections.emptyList()).map(songs -> {
if (!songs.isEmpty()) {
File playlistFile = null;
if (Environment.getExternalStorageDirectory().canWrite()) {
File root = new File(Environment.getExternalStorageDirectory(), "Playlists/Export/");
if (!root.exists()) {
root.mkdirs();
}
File noMedia = new File(root, ".nomedia");
if (!noMedia.exists()) {
try {
noMedia.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
String name = playlist.name.replaceAll("[^a-zA-Z0-9.-]", "_");
playlistFile = new File(root, name + ".m3u");
int i = 0;
while (playlistFile.exists()) {
i++;
playlistFile = new File(root, name + i + ".m3u");
}
try {
FileWriter fileWriter = new FileWriter(playlistFile);
StringBuilder body = new StringBuilder();
body.append("#EXTM3U\n");
for (Song song : songs) {
body.append("#EXTINF:").append(song.duration / 1000).append(",").append(song.name).append(" - ").append(song.artistName).append("\n").append(song.path).append("\n");
}
fileWriter.append(body);
fileWriter.flush();
fileWriter.close();
} catch (IOException e) {
Log.e(TAG, "Failed to write file: " + e);
}
}
return playlistFile;
}
return null;
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(file -> {
progressDialog.dismiss();
if (file != null) {
Toast.makeText(context, String.format(context.getString(R.string.playlist_saved), file.getPath()), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, R.string.playlist_save_failed, Toast.LENGTH_SHORT).show();
}
}, error -> LogUtils.logException(TAG, "Error saving m3u playlist", error));
}
use of com.simplecity.amp_library.model.Playlist in project Shuttle by timusus.
the class PlaylistUtils method createPlaylistDialog.
@SuppressLint("CheckResult")
private static void createPlaylistDialog(final Context context, final OnSavePlaylistListener listener) {
@SuppressLint("InflateParams") View customView = LayoutInflater.from(context).inflate(R.layout.dialog_playlist, null);
final EditText editText = customView.findViewById(R.id.editText);
Observable.fromCallable(() -> makePlaylistName(context)).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(name -> {
editText.setText(name);
if (!TextUtils.isEmpty(name)) {
editText.setSelection(name.length());
}
}, error -> LogUtils.logException(TAG, "PlaylistUtils: Error Setting playlist name", error));
MaterialDialog.Builder builder = DialogUtils.getBuilder(context).customView(customView, false).title(R.string.menu_playlist).positiveText(R.string.create_playlist_create_text).onPositive((materialDialog, dialogAction) -> {
String name = editText.getText().toString();
if (!name.isEmpty()) {
idForPlaylistObservable(context, name).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(id -> {
Uri uri;
if (id >= 0) {
uri = ContentUris.withAppendedId(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, id);
clearPlaylist(id);
} else {
ContentValues values = new ContentValues(1);
values.put(MediaStore.Audio.Playlists.NAME, name);
try {
uri = context.getContentResolver().insert(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, values);
} catch (IllegalArgumentException | NullPointerException e) {
Toast.makeText(context, R.string.dialog_create_playlist_error, Toast.LENGTH_LONG).show();
uri = null;
}
}
if (uri != null) {
listener.onSave(new Playlist(Playlist.Type.USER_CREATED, Long.valueOf(uri.getLastPathSegment()), name, true, false, true, true, true));
}
}, error -> LogUtils.logException(TAG, "PlaylistUtils: Error Saving playlist", error));
}
}).negativeText(R.string.cancel);
final Dialog dialog = builder.build();
dialog.show();
TextWatcher textWatcher = new TextWatcher() {
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// don't care about this one
}
// Fixme:
// It's probably best to just query all playlist names first, and then check against
// that list, rather than requerying for each char change.
public void onTextChanged(CharSequence s, int start, int before, int count) {
String newText = editText.getText().toString();
if (newText.trim().length() == 0) {
((MaterialDialog) dialog).getActionButton(DialogAction.POSITIVE).setEnabled(false);
} else {
((MaterialDialog) dialog).getActionButton(DialogAction.POSITIVE).setEnabled(true);
// check if playlist with current name exists already, and warn the user if so.
idForPlaylistObservable(context, newText).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(id -> {
if (id >= 0) {
((MaterialDialog) dialog).getActionButton(DialogAction.POSITIVE).setText(R.string.create_playlist_overwrite_text);
} else {
((MaterialDialog) dialog).getActionButton(DialogAction.POSITIVE).setText(R.string.create_playlist_create_text);
}
}, error -> LogUtils.logException(TAG, "PlaylistUtils: Error handling text change", error));
}
}
public void afterTextChanged(Editable s) {
// don't care about this one
}
};
editText.addTextChangedListener(textWatcher);
}
Aggregations