From c0852ea8c3a8000006fdaa2606a2343dd00af1a8 Mon Sep 17 00:00:00 2001 From: Anonymus Raccoon <32224410+AnonymusRaccoon@users.noreply.github.com> Date: Wed, 12 Jun 2019 22:49:07 +0200 Subject: [PATCH] Allowing user to reorder songs in playlists. --- Opus/Code/Api/LocalManager.cs | 7 ++- Opus/Code/Api/PlaylistManager.cs | 61 ++++++++++++++++++-- Opus/Code/Others/ItemTouchCallback.cs | 6 +- Opus/Code/UI/Adapter/BaseCursor.cs | 2 +- Opus/Code/UI/Adapter/PlaylistTrackAdapter.cs | 43 ++++++++++++-- Opus/Code/UI/Fragments/PlaylistTracks.cs | 15 +---- 6 files changed, 105 insertions(+), 29 deletions(-) diff --git a/Opus/Code/Api/LocalManager.cs b/Opus/Code/Api/LocalManager.cs index fc22393..303d873 100644 --- a/Opus/Code/Api/LocalManager.cs +++ b/Opus/Code/Api/LocalManager.cs @@ -369,16 +369,19 @@ namespace Opus.Api { if(await MainActivity.instance.GetWritePermission()) { + int playlistCount = await PlaylistManager.GetPlaylistCount(LocalID); + ContentResolver resolver = MainActivity.instance.ContentResolver; List values = new List(); - foreach (Song item in items) + for (int i = 0; i < items.Length; i++) { + Song item = items[i]; if (item != null && item.LocalID != 0 && item.LocalID != -1) { ContentValues value = new ContentValues(); value.Put(MediaStore.Audio.Playlists.Members.AudioId, item.LocalID); - value.Put(MediaStore.Audio.Playlists.Members.PlayOrder, 0); + value.Put(MediaStore.Audio.Playlists.Members.PlayOrder, playlistCount + i + 1); values.Add(value); } } diff --git a/Opus/Code/Api/PlaylistManager.cs b/Opus/Code/Api/PlaylistManager.cs index 4487308..c664f66 100644 --- a/Opus/Code/Api/PlaylistManager.cs +++ b/Opus/Code/Api/PlaylistManager.cs @@ -354,7 +354,6 @@ namespace Opus.Api { if (item.YoutubeID == null) { - Toast.MakeText(MainActivity.instance, Resource.String.playlist_add_song_not_found, ToastLength.Long).Show(); playlists.Remove(Loading); adapter.NotifyItemRemoved(playlists.Count); return; @@ -363,7 +362,7 @@ namespace Opus.Api if (YoutubeManager.IsUsingAPI || !await MainActivity.instance.WaitForYoutube()) { - Toast.MakeText(MainActivity.instance, Resource.String.youtube_loading_error, ToastLength.Long).Show(); + //Toast.MakeText(MainActivity.instance, Resource.String.youtube_loading_error, ToastLength.Long).Show(); playlists.Remove(Loading); adapter.NotifyItemRemoved(playlists.Count); return; @@ -832,9 +831,6 @@ namespace Opus.Api /// public async static Task> GetTracksFromLocalPlaylist(long LocalID) { - if (Looper.MyLooper() == null) - Looper.Prepare(); - List songs = new List(); Uri musicUri = Playlists.Members.GetContentUri("external", LocalID); await Task.Run(() => @@ -842,7 +838,7 @@ namespace Opus.Api if (Looper.MyLooper() == null) Looper.Prepare(); - CursorLoader cursorLoader = new CursorLoader(Application.Context, musicUri, null, null, null, null); + CursorLoader cursorLoader = new CursorLoader(Application.Context, musicUri, null, null, null, MediaStore.Audio.Playlists.Members.PlayOrder); ICursor musicCursor = (ICursor)cursorLoader.LoadInBackground(); if (musicCursor != null && musicCursor.MoveToFirst()) @@ -971,6 +967,27 @@ namespace Opus.Api resolver.Delete(uri, Playlists.Members.Id + "=?", new string[] { song.LocalID.ToString() }); //}); } + + /// + /// This method will give you the current number of songs in the playlist. + /// + /// + /// + public async static Task GetPlaylistCount(long LocalID) + { + int count = 0; + await Task.Run(() => + { + if (Looper.MyLooper() == null) + Looper.Prepare(); + + Uri musicUri = Playlists.Members.GetContentUri("external", LocalID); + CursorLoader cursorLoader = new CursorLoader(Application.Context, musicUri, null, null, null, null); + ICursor cursor = (ICursor)cursorLoader.LoadInBackground(); + count = cursor.Count; + }); + return count; + } #endregion #region YoutubePlaylists @@ -1163,5 +1180,37 @@ namespace Opus.Api snackBar.Show(); } #endregion + + #region Reorder + /// + /// Set the slot of a song in a playlist. Work with local one, youtube one and synced one. + /// + /// + /// + /// + public static void Reorder(PlaylistItem playlist, int fromPosition, int newPosition) + { + if (playlist.LocalID != 0) + Reorder(playlist.LocalID, fromPosition, newPosition); + + //if (playlist.YoutubeID != null) + // Reorder(playlist.YoutubeID, song, newPosition); + } + + /// + /// Set the slot of a song in a local playlist + /// + /// + /// + /// + public async static void Reorder(long PlaylistLocalID, int fromPosition, int newPosition) + { + if (!await MainActivity.instance.GetWritePermission()) + return; + + bool success = Playlists.Members.MoveItem(MainActivity.instance.ContentResolver, PlaylistLocalID, fromPosition, newPosition); + Console.WriteLine("&Reorder success: " + success); + } + #endregion } } \ No newline at end of file diff --git a/Opus/Code/Others/ItemTouchCallback.cs b/Opus/Code/Others/ItemTouchCallback.cs index e8e09a3..42a47b4 100644 --- a/Opus/Code/Others/ItemTouchCallback.cs +++ b/Opus/Code/Others/ItemTouchCallback.cs @@ -10,8 +10,9 @@ namespace Opus.Others { public class ItemTouchCallback : ItemTouchHelper.Callback { - private IItemTouchAdapter adapter; + private readonly IItemTouchAdapter adapter; private readonly bool alwaysAllowSwap; + private readonly Drawable drawable; private int from = -1; private int to = -1; @@ -36,9 +37,6 @@ namespace Opus.Others } } - private Drawable drawable; - - public ItemTouchCallback(IItemTouchAdapter adapter, bool alwaysAllowSwap) { this.adapter = adapter; diff --git a/Opus/Code/UI/Adapter/BaseCursor.cs b/Opus/Code/UI/Adapter/BaseCursor.cs index 4da4a9d..81bf6cc 100644 --- a/Opus/Code/UI/Adapter/BaseCursor.cs +++ b/Opus/Code/UI/Adapter/BaseCursor.cs @@ -44,7 +44,7 @@ namespace Opus.Adapter } } - public T GetItem(int position) + public virtual T GetItem(int position) { cursor.MoveToPosition(position - ItemBefore); return Convert(cursor); diff --git a/Opus/Code/UI/Adapter/PlaylistTrackAdapter.cs b/Opus/Code/UI/Adapter/PlaylistTrackAdapter.cs index cf227de..299d0bf 100644 --- a/Opus/Code/UI/Adapter/PlaylistTrackAdapter.cs +++ b/Opus/Code/UI/Adapter/PlaylistTrackAdapter.cs @@ -125,11 +125,31 @@ namespace Opus.Adapter else holder.Live.Visibility = ViewStates.Gone; + if(PlaylistTracks.instance.isInEditMode) + { + holder.more.Visibility = ViewStates.Gone; + holder.reorder.Visibility = ViewStates.Visible; + } + else + { + holder.more.Visibility = ViewStates.Visible; + holder.reorder.Visibility = ViewStates.Gone; + } + if (!holder.more.HasOnClickListeners) { holder.more.Click += (sender, e) => { - PlaylistTracks.instance.More(tracks == null ? GetItem(holder.AdapterPosition) : tracks[holder.AdapterPosition], holder.AdapterPosition); + PlaylistTracks.instance.More(GetItem(holder.AdapterPosition), holder.AdapterPosition); + }; + } + + if (!holder.reorder.HasOnClickListeners) + { + holder.reorder.Touch += (sender, e) => + { + PlaylistTracks.instance.itemTouchHelper.StartDrag(viewHolder); + MainActivity.instance.contentRefresh.Enabled = false; }; } @@ -138,12 +158,21 @@ namespace Opus.Adapter if (MainActivity.Theme == 1) { holder.more.SetColorFilter(Color.White); + holder.reorder.SetColorFilter(Color.White); holder.Title.SetTextColor(Color.White); holder.Artist.SetTextColor(Color.White); holder.Artist.Alpha = 0.7f; } } + public override Song GetItem(int position) + { + if (tracks == null) + return base.GetItem(position); + else + return tracks[position]; + } + public override void OnClick(int position) { if (tracks != null && position >= ItemBefore) @@ -215,13 +244,19 @@ namespace Opus.Adapter } - public void ItemMoved(int fromPosition, int toPosition) { } + public void ItemMoved(int fromPosition, int toPosition) + { + NotifyItemMoved(fromPosition, toPosition); + } - public void ItemMoveEnded(int fromPosition, int toPosition) { } + public void ItemMoveEnded(int fromPosition, int toPosition) + { + PlaylistManager.Reorder(PlaylistTracks.instance.item, fromPosition, toPosition); + } public void ItemDismissed(int position) { - PlaylistTracks.instance.RemoveFromPlaylist(tracks == null ? GetItem(position) : tracks[position], position); + PlaylistTracks.instance.RemoveFromPlaylist(GetItem(position), position); } } } \ No newline at end of file diff --git a/Opus/Code/UI/Fragments/PlaylistTracks.cs b/Opus/Code/UI/Fragments/PlaylistTracks.cs index c019c3a..2d671d0 100644 --- a/Opus/Code/UI/Fragments/PlaylistTracks.cs +++ b/Opus/Code/UI/Fragments/PlaylistTracks.cs @@ -31,13 +31,14 @@ namespace Opus.Fragments public TextView EmptyView; public RecyclerView ListView; public PlaylistTrackAdapter adapter; - private Android.Support.V7.Widget.Helper.ItemTouchHelper itemTouchHelper; + public Android.Support.V7.Widget.Helper.ItemTouchHelper itemTouchHelper; private string query; private string nextPageToken = null; public bool fullyLoadded = true; public bool lastVisible = false; public bool useHeader = true; + public bool isInEditMode = true; private bool isForked; private bool loading = false; @@ -341,7 +342,7 @@ namespace Opus.Fragments else selection = null; - return new CursorLoader(Android.App.Application.Context, musicUri, null, selection, null, null); + return new CursorLoader(Android.App.Application.Context, musicUri, null, selection, null, Playlists.Members.PlayOrder); } public void OnLoadFinished(Android.Support.V4.Content.Loader loader, Object data) @@ -364,16 +365,6 @@ namespace Opus.Fragments adapter.SwapCursor(null, false); } - string SongToName(Song song) - { - return song.Title; - } - - string SongToYtID(Song song) - { - return song.YoutubeID; - } - public async void OnRefresh(object sender, System.EventArgs e) { await PopulateList();