package com.marverenic.music.dialog;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import com.marverenic.music.JockeyApplication;
import com.marverenic.music.R;
import com.marverenic.music.data.store.PlaylistStore;
import com.marverenic.music.model.AutoPlaylist;
import com.marverenic.music.model.Playlist;
import com.marverenic.music.model.Song;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
import timber.log.Timber;
public class AppendPlaylistDialogFragment extends DialogFragment {
private static final String TAG_MAKE_PLAYLIST = "CreateNewPlaylistDialog";
private static final String TAG_DUPLICATE_CONFIRM = "PlaylistDuplicateConfirmationDialog";
private static final String KEY_TITLE = "AppendPlaylistDialogFragment.Title";
private static final String KEY_SONG = "AppendPlaylistDialogFragment.Song";
private static final String KEY_SONGS = "AppendPlaylistDialogFragment.Songs";
private static final String KEY_SNACKBAR_VIEW = "AppendPlaylistDialogFragment.Snackbar";
@Inject PlaylistStore mPlaylistStore;
private Dialog mDialog;
private String mTitle;
private Playlist[] mChoices;
private String[] mChoiceNames;
private Song mSong;
private List<Song> mSongs;
private boolean mSingle;
@IdRes private int mSnackbarView;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
JockeyApplication.getComponent(this).inject(this);
mTitle = getArguments().getString(KEY_TITLE);
mSnackbarView = getArguments().getInt(KEY_SNACKBAR_VIEW);
if (getArguments().containsKey(KEY_SONG)) {
mSong = getArguments().getParcelable(KEY_SONG);
mSingle = true;
} else if (getArguments().containsKey(KEY_SONGS)) {
mSongs = getArguments().getParcelableArrayList(KEY_SONGS);
mSingle = false;
}
mPlaylistStore.getPlaylists()
.take(1)
.subscribe(playlists -> {
List<Playlist> choices = new ArrayList<>(playlists.size());
List<String> choiceNames = new ArrayList<>(playlists.size());
choiceNames.add(getString(R.string.action_make_new_playlist));
for (Playlist playlist : playlists) {
if (!(playlist instanceof AutoPlaylist)) {
choices.add(playlist);
choiceNames.add(playlist.getPlaylistName());
}
}
mChoices = new Playlist[choices.size()];
mChoiceNames = new String[choiceNames.size()];
choices.toArray(mChoices);
choiceNames.toArray(mChoiceNames);
showDialog();
}, throwable -> {
Timber.e(throwable, "Failed to get playlists");
});
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
if (mDialog == null) {
return super.onCreateDialog(savedInstanceState);
} else {
return mDialog;
}
}
private void showDialog() {
if (getDialog() != null) {
getDialog().hide();
}
mDialog = new AlertDialog.Builder(getContext())
.setTitle(mTitle)
.setItems(mChoiceNames, (dialog, which) -> {onPlaylistSelected(which);})
.setNegativeButton(R.string.action_cancel, null)
.setOnDismissListener(dialog -> getDialog().dismiss())
.show();
}
private void onPlaylistSelected(int which) {
if (which == 0) {
new CreatePlaylistDialogFragment.Builder(getFragmentManager())
.setSongs((mSingle) ? Collections.singletonList(mSong) : mSongs)
.showSnackbarIn(mSnackbarView)
.show(TAG_MAKE_PLAYLIST);
} else {
addToPlaylist(mChoices[which - 1]);
}
}
private void addToPlaylist(Playlist playlist) {
mPlaylistStore.getSongs(playlist)
.take(1)
.subscribe(
oldEntries -> {
updatePlaylist(playlist, oldEntries);
},
throwable -> {
Timber.e(throwable, "Failed to get old entries");
});
}
private void updatePlaylist(Playlist playlist, List<Song> oldEntries) {
if (areContentsDisjoint(oldEntries)) {
if (mSingle) {
mPlaylistStore.addToPlaylist(playlist, mSong);
} else {
mPlaylistStore.addToPlaylist(playlist, mSongs);
}
showSnackbar(playlist, oldEntries);
} else {
showPlaylistDuplicateDisambiguationDialog(playlist);
}
}
private boolean areContentsDisjoint(List<Song> playlistEntries) {
if (mSingle) {
return !playlistEntries.contains(mSong);
} else {
return Collections.disjoint(playlistEntries, mSongs);
}
}
private void showPlaylistDuplicateDisambiguationDialog(Playlist playlist) {
if (mSingle) {
new PlaylistCollisionDialogFragment.Builder(getFragmentManager())
.setPlaylist(playlist)
.setSongs(mSong)
.showSnackbarIn(mSnackbarView)
.show(TAG_DUPLICATE_CONFIRM);
} else {
new PlaylistCollisionDialogFragment.Builder(getFragmentManager())
.setPlaylist(playlist)
.setSongs(mSongs)
.showSnackbarIn(mSnackbarView)
.show(TAG_DUPLICATE_CONFIRM);
}
}
private void showSnackbar(Playlist editedPlaylist, List<Song> previousSongs) {
String message;
if (mSingle) {
message = getString(R.string.message_added_song, mSong, editedPlaylist);
} else {
message = getString(R.string.confirm_add_songs, mSongs.size(), editedPlaylist);
}
showSnackbar(message, editedPlaylist, previousSongs);
}
private void showSnackbar(String message, Playlist editedPlaylist, List<Song> previousSongs) {
View container = getActivity().findViewById(mSnackbarView);
if (container != null) {
Snackbar.make(container, message, Snackbar.LENGTH_LONG)
.setAction(R.string.action_undo, view -> {
mPlaylistStore.editPlaylist(editedPlaylist, previousSongs);
})
.show();
}
}
public static class Builder {
private Bundle mArgs;
private FragmentManager mFragmentManager;
private Context mContext;
public Builder(AppCompatActivity activity) {
this(activity, activity.getSupportFragmentManager());
}
public Builder(Context context, FragmentManager fragmentManager) {
mContext = context;
mFragmentManager = fragmentManager;
mArgs = new Bundle();
}
public Builder setTitle(String title) {
mArgs.putString(KEY_TITLE, title);
return this;
}
public Builder setSongs(Song song) {
if (!song.isInLibrary()) {
throw new IllegalArgumentException("Cannot add a remote song to a local playlist");
}
mArgs.putParcelable(KEY_SONG, song);
mArgs.remove(KEY_SONGS);
if (!mArgs.containsKey(KEY_TITLE)) {
String name = song.getSongName();
String title = mContext.getString(R.string.header_add_song_name_to_playlist, name);
setTitle(title);
}
return this;
}
public Builder setSongs(List<Song> songs) {
mArgs.putParcelableArrayList(KEY_SONGS, copyLocalSongs(songs));
mArgs.remove(KEY_SONG);
return this;
}
public Builder setSongs(List<Song> songs, String name) {
mArgs.putParcelableArrayList(KEY_SONGS, copyLocalSongs(songs));
mArgs.remove(KEY_SONG);
String title = mContext.getString(R.string.header_add_song_name_to_playlist, name);
setTitle(title);
return this;
}
private ArrayList<Song> copyLocalSongs(List<Song> from) {
ArrayList<Song> copy = new ArrayList<>();
for (Song song : from) {
if (song.isInLibrary()) copy.add(song);
}
return copy;
}
public Builder showSnackbarIn(@IdRes int snackbarContainerId) {
mArgs.putInt(KEY_SNACKBAR_VIEW, snackbarContainerId);
return this;
}
public void show(String tag) {
AppendPlaylistDialogFragment dialogFragment = new AppendPlaylistDialogFragment();
dialogFragment.setArguments(mArgs);
dialogFragment.show(mFragmentManager, tag);
}
}
}