Search in sources :

Example 36 with Playlist

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));
}
Also used : R(com.simplecity.amp_library.R) Spannable(android.text.Spannable) Completable(io.reactivex.Completable) Uri(android.net.Uri) PlayCountTable(com.simplecity.amp_library.sql.providers.PlayCountTable) AndroidSchedulers(io.reactivex.android.schedulers.AndroidSchedulers) Song(com.simplecity.amp_library.model.Song) Optional(com.annimon.stream.Optional) CheckBox(android.widget.CheckBox) ContentResolver(android.content.ContentResolver) MediaStore(android.provider.MediaStore) View(android.view.View) Schedulers(io.reactivex.schedulers.Schedulers) Log(android.util.Log) Playlist(com.simplecity.amp_library.model.Playlist) SubMenu(android.view.SubMenu) Query(com.simplecity.amp_library.model.Query) List(java.util.List) TextView(android.widget.TextView) ContentValues(android.content.ContentValues) Nullable(android.support.annotation.Nullable) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) SqlUtils(com.simplecity.amp_library.sql.SqlUtils) TextWatcher(android.text.TextWatcher) FileType(com.simplecity.amp_library.interfaces.FileType) Context(android.content.Context) Stream(com.annimon.stream.Stream) Environment(android.os.Environment) Dialog(android.app.Dialog) Intent(android.content.Intent) NonNull(android.support.annotation.NonNull) Single(io.reactivex.Single) Editable(android.text.Editable) ArrayList(java.util.ArrayList) SuppressLint(android.annotation.SuppressLint) SpannableStringBuilder(android.text.SpannableStringBuilder) Toast(android.widget.Toast) BaseFileObject(com.simplecity.amp_library.model.BaseFileObject) Observable(io.reactivex.Observable) UnsafeConsumer(com.simplecity.amp_library.rx.UnsafeConsumer) Cursor(android.database.Cursor) SqlBriteUtils(com.simplecity.amp_library.sql.sqlbrite.SqlBriteUtils) LayoutInflater(android.view.LayoutInflater) StyleSpan(android.text.style.StyleSpan) FileWriter(java.io.FileWriter) ProgressDialog(android.app.ProgressDialog) TextUtils(android.text.TextUtils) DialogAction(com.afollestad.materialdialogs.DialogAction) IOException(java.io.IOException) WorkerThread(android.support.annotation.WorkerThread) File(java.io.File) TimeUnit(java.util.concurrent.TimeUnit) ShuttleApplication(com.simplecity.amp_library.ShuttleApplication) Pair(android.support.v4.util.Pair) Crashlytics(com.crashlytics.android.Crashlytics) Collections(java.util.Collections) EditText(android.widget.EditText) ContentUris(android.content.ContentUris) Song(com.simplecity.amp_library.model.Song) CheckBox(android.widget.CheckBox) ArrayList(java.util.ArrayList) SuppressLint(android.annotation.SuppressLint) TextView(android.widget.TextView) View(android.view.View) TextView(android.widget.TextView) SuppressLint(android.annotation.SuppressLint)

Example 37 with Playlist

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));
}
Also used : R(com.simplecity.amp_library.R) Spannable(android.text.Spannable) Completable(io.reactivex.Completable) Uri(android.net.Uri) PlayCountTable(com.simplecity.amp_library.sql.providers.PlayCountTable) AndroidSchedulers(io.reactivex.android.schedulers.AndroidSchedulers) Song(com.simplecity.amp_library.model.Song) Optional(com.annimon.stream.Optional) CheckBox(android.widget.CheckBox) ContentResolver(android.content.ContentResolver) MediaStore(android.provider.MediaStore) View(android.view.View) Schedulers(io.reactivex.schedulers.Schedulers) Log(android.util.Log) Playlist(com.simplecity.amp_library.model.Playlist) SubMenu(android.view.SubMenu) Query(com.simplecity.amp_library.model.Query) List(java.util.List) TextView(android.widget.TextView) ContentValues(android.content.ContentValues) Nullable(android.support.annotation.Nullable) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) SqlUtils(com.simplecity.amp_library.sql.SqlUtils) TextWatcher(android.text.TextWatcher) FileType(com.simplecity.amp_library.interfaces.FileType) Context(android.content.Context) Stream(com.annimon.stream.Stream) Environment(android.os.Environment) Dialog(android.app.Dialog) Intent(android.content.Intent) NonNull(android.support.annotation.NonNull) Single(io.reactivex.Single) Editable(android.text.Editable) ArrayList(java.util.ArrayList) SuppressLint(android.annotation.SuppressLint) SpannableStringBuilder(android.text.SpannableStringBuilder) Toast(android.widget.Toast) BaseFileObject(com.simplecity.amp_library.model.BaseFileObject) Observable(io.reactivex.Observable) UnsafeConsumer(com.simplecity.amp_library.rx.UnsafeConsumer) Cursor(android.database.Cursor) SqlBriteUtils(com.simplecity.amp_library.sql.sqlbrite.SqlBriteUtils) LayoutInflater(android.view.LayoutInflater) StyleSpan(android.text.style.StyleSpan) FileWriter(java.io.FileWriter) ProgressDialog(android.app.ProgressDialog) TextUtils(android.text.TextUtils) DialogAction(com.afollestad.materialdialogs.DialogAction) IOException(java.io.IOException) WorkerThread(android.support.annotation.WorkerThread) File(java.io.File) TimeUnit(java.util.concurrent.TimeUnit) ShuttleApplication(com.simplecity.amp_library.ShuttleApplication) Pair(android.support.v4.util.Pair) Crashlytics(com.crashlytics.android.Crashlytics) Collections(java.util.Collections) EditText(android.widget.EditText) ContentUris(android.content.ContentUris) Song(com.simplecity.amp_library.model.Song) SpannableStringBuilder(android.text.SpannableStringBuilder) FileWriter(java.io.FileWriter) IOException(java.io.IOException) ProgressDialog(android.app.ProgressDialog) File(java.io.File) SuppressLint(android.annotation.SuppressLint)

Example 38 with Playlist

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);
}
Also used : EditText(android.widget.EditText) R(com.simplecity.amp_library.R) Spannable(android.text.Spannable) Completable(io.reactivex.Completable) Uri(android.net.Uri) PlayCountTable(com.simplecity.amp_library.sql.providers.PlayCountTable) AndroidSchedulers(io.reactivex.android.schedulers.AndroidSchedulers) Song(com.simplecity.amp_library.model.Song) Optional(com.annimon.stream.Optional) CheckBox(android.widget.CheckBox) ContentResolver(android.content.ContentResolver) MediaStore(android.provider.MediaStore) View(android.view.View) Schedulers(io.reactivex.schedulers.Schedulers) Log(android.util.Log) Playlist(com.simplecity.amp_library.model.Playlist) SubMenu(android.view.SubMenu) Query(com.simplecity.amp_library.model.Query) List(java.util.List) TextView(android.widget.TextView) ContentValues(android.content.ContentValues) Nullable(android.support.annotation.Nullable) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) SqlUtils(com.simplecity.amp_library.sql.SqlUtils) TextWatcher(android.text.TextWatcher) FileType(com.simplecity.amp_library.interfaces.FileType) Context(android.content.Context) Stream(com.annimon.stream.Stream) Environment(android.os.Environment) Dialog(android.app.Dialog) Intent(android.content.Intent) NonNull(android.support.annotation.NonNull) Single(io.reactivex.Single) Editable(android.text.Editable) ArrayList(java.util.ArrayList) SuppressLint(android.annotation.SuppressLint) SpannableStringBuilder(android.text.SpannableStringBuilder) Toast(android.widget.Toast) BaseFileObject(com.simplecity.amp_library.model.BaseFileObject) Observable(io.reactivex.Observable) UnsafeConsumer(com.simplecity.amp_library.rx.UnsafeConsumer) Cursor(android.database.Cursor) SqlBriteUtils(com.simplecity.amp_library.sql.sqlbrite.SqlBriteUtils) LayoutInflater(android.view.LayoutInflater) StyleSpan(android.text.style.StyleSpan) FileWriter(java.io.FileWriter) ProgressDialog(android.app.ProgressDialog) TextUtils(android.text.TextUtils) DialogAction(com.afollestad.materialdialogs.DialogAction) IOException(java.io.IOException) WorkerThread(android.support.annotation.WorkerThread) File(java.io.File) TimeUnit(java.util.concurrent.TimeUnit) ShuttleApplication(com.simplecity.amp_library.ShuttleApplication) Pair(android.support.v4.util.Pair) Crashlytics(com.crashlytics.android.Crashlytics) Collections(java.util.Collections) EditText(android.widget.EditText) ContentUris(android.content.ContentUris) ContentValues(android.content.ContentValues) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) View(android.view.View) TextView(android.widget.TextView) Uri(android.net.Uri) Playlist(com.simplecity.amp_library.model.Playlist) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) Dialog(android.app.Dialog) ProgressDialog(android.app.ProgressDialog) SuppressLint(android.annotation.SuppressLint) TextWatcher(android.text.TextWatcher) Editable(android.text.Editable) SuppressLint(android.annotation.SuppressLint)

Aggregations

Playlist (com.simplecity.amp_library.model.Playlist)38 Intent (android.content.Intent)24 View (android.view.View)21 List (java.util.List)21 R (com.simplecity.amp_library.R)19 Uri (android.net.Uri)18 Context (android.content.Context)17 LayoutInflater (android.view.LayoutInflater)17 Toast (android.widget.Toast)17 Song (com.simplecity.amp_library.model.Song)17 ContentUris (android.content.ContentUris)15 MediaStore (android.provider.MediaStore)15 SubMenu (android.view.SubMenu)15 Stream (com.annimon.stream.Stream)15 ArrayList (java.util.ArrayList)15 TextView (android.widget.TextView)14 NonNull (android.support.annotation.NonNull)13 Query (com.simplecity.amp_library.model.Query)13 TimeUnit (java.util.concurrent.TimeUnit)13 Collections (java.util.Collections)11