diff --git a/.idea/misc.xml b/.idea/misc.xml
index 15571fbc..708be2f4 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -22,10 +22,11 @@
+
-
+
@@ -34,6 +35,7 @@
+
diff --git a/app/src/main/java/com/cappielloantonio/play/adapter/PlaylistAdapter.java b/app/src/main/java/com/cappielloantonio/play/adapter/PlaylistAdapter.java
index e3bcff1c..40b8ef1f 100644
--- a/app/src/main/java/com/cappielloantonio/play/adapter/PlaylistAdapter.java
+++ b/app/src/main/java/com/cappielloantonio/play/adapter/PlaylistAdapter.java
@@ -17,6 +17,7 @@ import com.cappielloantonio.play.R;
import com.cappielloantonio.play.glide.CustomGlideRequest;
import com.cappielloantonio.play.model.Playlist;
import com.cappielloantonio.play.ui.activity.MainActivity;
+import com.cappielloantonio.play.ui.fragment.dialog.PlaylistEditorDialog;
import com.cappielloantonio.play.util.MusicUtil;
import java.util.ArrayList;
@@ -70,7 +71,7 @@ public class PlaylistAdapter extends RecyclerView.Adapter {
+ private static final String TAG = "PlaylistDialogSongHorizontalAdapter";
+
+ private List songs;
+ private LayoutInflater mInflater;
+ private MainActivity mainActivity;
+ private Context context;
+ private FragmentManager fragmentManager;
+
+ public PlaylistDialogSongHorizontalAdapter(MainActivity mainActivity, Context context, FragmentManager fragmentManager) {
+ this.mainActivity = mainActivity;
+ this.context = context;
+ this.fragmentManager = fragmentManager;
+ this.mInflater = LayoutInflater.from(context);
+ this.songs = new ArrayList<>();
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View view = mInflater.inflate(R.layout.item_horizontal_playlist_dialog_track, parent, false);
+ return new ViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder holder, int position) {
+ Song song = songs.get(position);
+
+ holder.songTitle.setText(MusicUtil.getReadableString(song.getTitle()));
+ holder.songArtist.setText(MusicUtil.getReadableString(song.getArtistName()));
+ holder.songDuration.setText(MusicUtil.getReadableDurationString(song.getDuration(), false));
+
+ CustomGlideRequest.Builder
+ .from(context, song.getPrimary(), CustomGlideRequest.SONG_PIC, null)
+ .build()
+ .transform(new RoundedCorners(CustomGlideRequest.CORNER_RADIUS))
+ .into(holder.cover);
+ }
+
+ @Override
+ public int getItemCount() {
+ return songs.size();
+ }
+
+ public List getItems() {
+ return this.songs;
+ }
+
+ public void setItems(List songs) {
+ this.songs = songs;
+ notifyDataSetChanged();
+ }
+
+ public Song getItem(int id) {
+ return songs.get(id);
+ }
+
+ public class ViewHolder extends RecyclerView.ViewHolder {
+ TextView songTitle;
+ TextView songArtist;
+ TextView songDuration;
+ ImageView cover;
+
+ ViewHolder(View itemView) {
+ super(itemView);
+
+ songTitle = itemView.findViewById(R.id.playlist_dialog_song_title_text_view);
+ songArtist = itemView.findViewById(R.id.playlist_dialog_album_artist_text_view);
+ songDuration = itemView.findViewById(R.id.playlist_dialog_song_duration_text_view);
+ cover = itemView.findViewById(R.id.playlist_dialog_song_cover_image_view);
+
+ songTitle.setSelected(true);
+ }
+ }
+}
diff --git a/app/src/main/java/com/cappielloantonio/play/repository/PlaylistRepository.java b/app/src/main/java/com/cappielloantonio/play/repository/PlaylistRepository.java
index 15c41c55..789bb4fb 100644
--- a/app/src/main/java/com/cappielloantonio/play/repository/PlaylistRepository.java
+++ b/app/src/main/java/com/cappielloantonio/play/repository/PlaylistRepository.java
@@ -78,10 +78,10 @@ public class PlaylistRepository {
return listLivePlaylistSongs;
}
- public void addSongToPlaylist(String playlistId, String songId) {
+ public void addSongToPlaylist(String playlistId, ArrayList songsId) {
App.getSubsonicClientInstance(application, false)
.getPlaylistClient()
- .updatePlaylist(playlistId, null, true, songId, null)
+ .updatePlaylist(playlistId, null, true, songsId, null)
.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
@@ -97,10 +97,48 @@ public class PlaylistRepository {
});
}
- public void createPlaylist(String name, String songId) {
+ public void createPlaylist(String playlistId, String name, ArrayList songsId) {
App.getSubsonicClientInstance(application, false)
.getPlaylistClient()
- .createPlaylist(null, name, songId)
+ .createPlaylist(playlistId, name, songsId)
+ .enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (response.body().getStatus().getValue().equals(ResponseStatus.OK)) {
+
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+
+ }
+ });
+ }
+
+ public void updatePlaylist(String playlistId, String name, boolean isPublic, ArrayList songIdToAdd, ArrayList songIndexToRemove) {
+ App.getSubsonicClientInstance(application, false)
+ .getPlaylistClient()
+ .updatePlaylist(playlistId, name, isPublic, songIdToAdd, songIndexToRemove)
+ .enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (response.body().getStatus().getValue().equals(ResponseStatus.OK)) {
+
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+
+ }
+ });
+ }
+
+ public void deletePlaylist(String playlistId) {
+ App.getSubsonicClientInstance(application, false)
+ .getPlaylistClient()
+ .deletePlaylist(playlistId)
.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
diff --git a/app/src/main/java/com/cappielloantonio/play/subsonic/api/playlist/PlaylistClient.java b/app/src/main/java/com/cappielloantonio/play/subsonic/api/playlist/PlaylistClient.java
index e879d662..ea33b535 100644
--- a/app/src/main/java/com/cappielloantonio/play/subsonic/api/playlist/PlaylistClient.java
+++ b/app/src/main/java/com/cappielloantonio/play/subsonic/api/playlist/PlaylistClient.java
@@ -6,6 +6,8 @@ import com.cappielloantonio.play.subsonic.Subsonic;
import com.cappielloantonio.play.subsonic.models.SubsonicResponse;
import com.tickaroo.tikxml.retrofit.TikXmlConverterFactory;
+import java.util.ArrayList;
+
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
@@ -40,12 +42,12 @@ public class PlaylistClient {
return playlistService.getPlaylist(subsonic.getParams(), id);
}
- public Call createPlaylist(String playlistId, String name, String songId) {
+ public Call createPlaylist(String playlistId, String name, ArrayList songsId) {
Log.d(TAG, "createPlaylist()");
- return playlistService.createPlaylist(subsonic.getParams(), playlistId, name, songId);
+ return playlistService.createPlaylist(subsonic.getParams(), playlistId, name, songsId);
}
- public Call updatePlaylist(String playlistId, String name, boolean isPublic, String songIdToAdd, String songIndexToRemove) {
+ public Call updatePlaylist(String playlistId, String name, boolean isPublic, ArrayList songIdToAdd, ArrayList songIndexToRemove) {
Log.d(TAG, "updatePlaylist()");
return playlistService.updatePlaylist(subsonic.getParams(), playlistId, name, isPublic, songIdToAdd, songIndexToRemove);
}
diff --git a/app/src/main/java/com/cappielloantonio/play/subsonic/api/playlist/PlaylistService.java b/app/src/main/java/com/cappielloantonio/play/subsonic/api/playlist/PlaylistService.java
index 5f27e908..e90846ae 100644
--- a/app/src/main/java/com/cappielloantonio/play/subsonic/api/playlist/PlaylistService.java
+++ b/app/src/main/java/com/cappielloantonio/play/subsonic/api/playlist/PlaylistService.java
@@ -2,6 +2,7 @@ package com.cappielloantonio.play.subsonic.api.playlist;
import com.cappielloantonio.play.subsonic.models.SubsonicResponse;
+import java.util.ArrayList;
import java.util.Map;
import retrofit2.Call;
@@ -17,10 +18,10 @@ public interface PlaylistService {
Call getPlaylist(@QueryMap Map params, @Query("id") String id);
@GET("createPlaylist")
- Call createPlaylist(@QueryMap Map params, @Query("playlistId") String playlistId, @Query("name") String name, @Query("songId") String songId);
+ Call createPlaylist(@QueryMap Map params, @Query("playlistId") String playlistId, @Query("name") String name, @Query("songId") ArrayList songsId);
@GET("updatePlaylist")
- Call updatePlaylist(@QueryMap Map params, @Query("playlistId") String playlistId, @Query("name") String name, @Query("public") boolean isPublic, @Query("songIdToAdd") String songIdToAdd, @Query("songIndexToRemove") String songIndexToRemove);
+ Call updatePlaylist(@QueryMap Map params, @Query("playlistId") String playlistId, @Query("name") String name, @Query("public") boolean isPublic, @Query("songIdToAdd") ArrayList songIdToAdd, @Query("songIndexToRemove") ArrayList songIndexToRemove);
@GET("deletePlaylist")
Call deletePlaylist(@QueryMap Map params, @Query("id") String id);
diff --git a/app/src/main/java/com/cappielloantonio/play/ui/fragment/dialog/PlaylistEditorDialog.java b/app/src/main/java/com/cappielloantonio/play/ui/fragment/dialog/PlaylistEditorDialog.java
index 6c8a776d..709107c6 100644
--- a/app/src/main/java/com/cappielloantonio/play/ui/fragment/dialog/PlaylistEditorDialog.java
+++ b/app/src/main/java/com/cappielloantonio/play/ui/fragment/dialog/PlaylistEditorDialog.java
@@ -7,14 +7,21 @@ import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
+import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment;
import androidx.lifecycle.ViewModelProvider;
+import androidx.recyclerview.widget.ItemTouchHelper;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
import com.cappielloantonio.play.R;
+import com.cappielloantonio.play.adapter.PlaylistDialogSongHorizontalAdapter;
import com.cappielloantonio.play.databinding.DialogPlaylistEditorBinding;
import com.cappielloantonio.play.ui.activity.MainActivity;
+import com.cappielloantonio.play.util.MusicUtil;
import com.cappielloantonio.play.viewmodel.PlaylistEditorViewModel;
+import java.util.Collections;
import java.util.Objects;
public class PlaylistEditorDialog extends DialogFragment {
@@ -26,6 +33,7 @@ public class PlaylistEditorDialog extends DialogFragment {
private PlaylistEditorViewModel playlistEditorViewModel;
private String playlistName;
+ private PlaylistDialogSongHorizontalAdapter playlistDialogSongHorizontalAdapter;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
@@ -41,6 +49,7 @@ public class PlaylistEditorDialog extends DialogFragment {
.setTitle("Create playlist")
.setPositiveButton("Save", (dialog, id) -> {
})
+ .setNeutralButton("Delete", (dialog, id) -> dialog.cancel())
.setNegativeButton("Cancel", (dialog, id) -> dialog.cancel());
return builder.create();
@@ -50,15 +59,28 @@ public class PlaylistEditorDialog extends DialogFragment {
public void onStart() {
super.onStart();
- setSongInfo();
+ setParameterInfo();
setButtonAction();
+ initSongsView();
}
- private void setSongInfo() {
+ private void setParameterInfo() {
if (getArguments() != null) {
- playlistEditorViewModel.setSongToAdd(getArguments().getParcelable("song_object"));
+ if (getArguments().getParcelable("song_object") != null) {
+ playlistEditorViewModel.setSongToAdd(getArguments().getParcelable("song_object"));
+ playlistEditorViewModel.setPlaylistToEdit(null);
+ }
+ else if (getArguments().getParcelable("playlist_object") != null) {
+ playlistEditorViewModel.setSongToAdd(null);
+ playlistEditorViewModel.setPlaylistToEdit(getArguments().getParcelable("playlist_object"));
+
+ if (playlistEditorViewModel.getPlaylistToEdit() != null) {
+ bind.playlistNameTextView.setText(MusicUtil.getReadableString(playlistEditorViewModel.getPlaylistToEdit().getName()));
+ }
+ }
} else {
playlistEditorViewModel.setSongToAdd(null);
+ playlistEditorViewModel.setPlaylistToEdit(null);
}
}
@@ -69,10 +91,74 @@ public class PlaylistEditorDialog extends DialogFragment {
((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
if (validateInput()) {
- playlistEditorViewModel.createPlaylist(playlistName);
+ if (playlistEditorViewModel.getSongToAdd() != null) {
+ playlistEditorViewModel.createPlaylist(playlistName);
+ } else if (playlistEditorViewModel.getPlaylistToEdit() != null) {
+ playlistEditorViewModel.updatePlaylist(playlistName);
+ }
+
Objects.requireNonNull(getDialog()).dismiss();
}
});
+
+ ((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> {
+ playlistEditorViewModel.deletePlaylist();
+ Objects.requireNonNull(getDialog()).dismiss();
+ });
+ }
+
+ private void initSongsView() {
+ bind.playlistSongRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
+ bind.playlistSongRecyclerView.setHasFixedSize(true);
+
+ playlistDialogSongHorizontalAdapter = new PlaylistDialogSongHorizontalAdapter(activity, requireContext(), getChildFragmentManager());
+ bind.playlistSongRecyclerView.setAdapter(playlistDialogSongHorizontalAdapter);
+
+ playlistEditorViewModel.getPlaylistSongLiveList().observe(requireActivity(), songs -> {
+ playlistDialogSongHorizontalAdapter.setItems(songs);
+ });
+
+ new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT) {
+ int originalPosition = -1;
+ int fromPosition = -1;
+ int toPosition = -1;
+
+ @Override
+ public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
+ if (originalPosition == -1)
+ originalPosition = viewHolder.getBindingAdapterPosition();
+
+ fromPosition = viewHolder.getBindingAdapterPosition();
+ toPosition = target.getBindingAdapterPosition();
+
+ Collections.swap(playlistDialogSongHorizontalAdapter.getItems(), fromPosition, toPosition);
+ recyclerView.getAdapter().notifyItemMoved(fromPosition, toPosition);
+
+ return false;
+ }
+
+ @Override
+ public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
+ super.clearView(recyclerView, viewHolder);
+
+ /*
+ * Qui vado a riscivere tutta la table Queue, quando teoricamente potrei solo swappare l'ordine degli elementi interessati
+ * Nel caso la coda contenesse parecchi brani, potrebbero verificarsi rallentamenti pesanti
+ */
+ playlistEditorViewModel.orderPlaylistSongLiveListAfterSwap(playlistDialogSongHorizontalAdapter.getItems());
+
+ originalPosition = -1;
+ fromPosition = -1;
+ toPosition = -1;
+ }
+
+ @Override
+ public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
+ playlistEditorViewModel.removeFromPlaylistSongLiveList(playlistDialogSongHorizontalAdapter.getItem(viewHolder.getBindingAdapterPosition()));
+ bind.playlistSongRecyclerView.getAdapter().notifyItemRemoved(viewHolder.getBindingAdapterPosition());
+ }
+ }
+ ).attachToRecyclerView(bind.playlistSongRecyclerView);
}
private boolean validateInput() {
diff --git a/app/src/main/java/com/cappielloantonio/play/viewmodel/PlaylistCatalogueViewModel.java b/app/src/main/java/com/cappielloantonio/play/viewmodel/PlaylistCatalogueViewModel.java
index a8583853..2d39d5ba 100644
--- a/app/src/main/java/com/cappielloantonio/play/viewmodel/PlaylistCatalogueViewModel.java
+++ b/app/src/main/java/com/cappielloantonio/play/viewmodel/PlaylistCatalogueViewModel.java
@@ -31,12 +31,9 @@ public class PlaylistCatalogueViewModel extends AndroidViewModel {
super(application);
playlistRepository = new PlaylistRepository(application);
-
- playlists = playlistRepository.getPlaylists(false, -1);
}
public LiveData> getPlaylistList() {
- return playlists;
+ return playlistRepository.getPlaylists(false, -1);
}
-
}
diff --git a/app/src/main/java/com/cappielloantonio/play/viewmodel/PlaylistChooserViewModel.java b/app/src/main/java/com/cappielloantonio/play/viewmodel/PlaylistChooserViewModel.java
index 6372d400..eaeb3574 100644
--- a/app/src/main/java/com/cappielloantonio/play/viewmodel/PlaylistChooserViewModel.java
+++ b/app/src/main/java/com/cappielloantonio/play/viewmodel/PlaylistChooserViewModel.java
@@ -11,6 +11,8 @@ import com.cappielloantonio.play.model.Playlist;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.repository.PlaylistRepository;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
public class PlaylistChooserViewModel extends AndroidViewModel {
@@ -32,7 +34,7 @@ public class PlaylistChooserViewModel extends AndroidViewModel {
}
public void addSongToPlaylist(String playlistId) {
- playlistRepository.addSongToPlaylist(playlistId, toAdd.getId());
+ playlistRepository.addSongToPlaylist(playlistId, new ArrayList(Collections.singletonList(toAdd.getId())));
}
public void setSongToAdd(Song song) {
diff --git a/app/src/main/java/com/cappielloantonio/play/viewmodel/PlaylistEditorViewModel.java b/app/src/main/java/com/cappielloantonio/play/viewmodel/PlaylistEditorViewModel.java
index 5a8f8314..6dd2bad7 100644
--- a/app/src/main/java/com/cappielloantonio/play/viewmodel/PlaylistEditorViewModel.java
+++ b/app/src/main/java/com/cappielloantonio/play/viewmodel/PlaylistEditorViewModel.java
@@ -1,38 +1,97 @@
package com.cappielloantonio.play.viewmodel;
import android.app.Application;
+import android.util.Log;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
-import com.cappielloantonio.play.model.Server;
+import com.cappielloantonio.play.model.Playlist;
import com.cappielloantonio.play.model.Song;
import com.cappielloantonio.play.repository.PlaylistRepository;
-import com.cappielloantonio.play.repository.ServerRepository;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import java.util.Objects;
public class PlaylistEditorViewModel extends AndroidViewModel {
+ private static final String TAG = "PlaylistEditorViewModel";
+
private PlaylistRepository playlistRepository;
private Song toAdd;
+ private Playlist toEdit;
+
+ private MutableLiveData> songLiveList = new MutableLiveData<>();
public PlaylistEditorViewModel(@NonNull Application application) {
super(application);
playlistRepository = new PlaylistRepository(application);
+
+ Log.d(TAG, "PlaylistEditorViewModel()");
}
public void createPlaylist(String name) {
- playlistRepository.createPlaylist(name, toAdd.getId());
+ playlistRepository.createPlaylist(null, name, new ArrayList(Collections.singletonList(toAdd.getId())));
}
- public void updatePlaylist(String playlistId) {
+ public void updatePlaylist(String name) {
+ playlistRepository.deletePlaylist(toEdit.getId());
+ playlistRepository.createPlaylist(toEdit.getId(), name, getPlaylistSongIds());
+ }
+ public void deletePlaylist() {
+ if (toEdit != null) playlistRepository.deletePlaylist(toEdit.getId());
+ }
+
+ public Song getSongToAdd() {
+ return toAdd;
}
public void setSongToAdd(Song song) {
- toAdd = song;
+ this.toAdd = song;
+ }
+
+ public Playlist getPlaylistToEdit() {
+ return toEdit;
+ }
+
+ public void setPlaylistToEdit(Playlist playlist) {
+ this.toEdit = playlist;
+
+ if (playlist != null) {
+ this.songLiveList = playlistRepository.getPlaylistSongs(toEdit.getId());
+ } else {
+ this.songLiveList = new MutableLiveData<>();
+ }
+ }
+
+ public LiveData> getPlaylistSongLiveList() {
+ return songLiveList;
+ }
+
+ public void removeFromPlaylistSongLiveList(Song song) {
+ List songs = songLiveList.getValue();
+ Objects.requireNonNull(songs).remove(song);
+ songLiveList.postValue(songs);
+ }
+
+ public void orderPlaylistSongLiveListAfterSwap(List songs) {
+ songLiveList.postValue(songs);
+ }
+
+ private ArrayList getPlaylistSongIds() {
+ List songs = songLiveList.getValue();
+ ArrayList ids = new ArrayList<>();
+
+ for (Song song : songs) {
+ ids.add(song.getId());
+ }
+
+ return ids;
}
}
diff --git a/app/src/main/res/layout/dialog_playlist_editor.xml b/app/src/main/res/layout/dialog_playlist_editor.xml
index 14257d53..fda7d389 100644
--- a/app/src/main/res/layout/dialog_playlist_editor.xml
+++ b/app/src/main/res/layout/dialog_playlist_editor.xml
@@ -25,6 +25,15 @@
android:hint="Playlist Name"
android:inputType="textNoSuggestions"
android:textCursorDrawable="@null" />
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_horizontal_playlist_dialog_track.xml b/app/src/main/res/layout/item_horizontal_playlist_dialog_track.xml
new file mode 100644
index 00000000..3e6b6384
--- /dev/null
+++ b/app/src/main/res/layout/item_horizontal_playlist_dialog_track.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file