From 13cb0934a5ba59cd352a6400a17dcde31155d399 Mon Sep 17 00:00:00 2001 From: Tristan Roux Date: Sat, 20 Apr 2019 01:31:16 +0200 Subject: [PATCH] Starting to rework code oraganizing structure. Making browse use content loader and load only what it need. --- Opus/Code/Adapter/BaseCursor.cs | 77 ++++++++ Opus/Code/Adapter/BrowseAdapter.cs | 115 ++++++++++++ Opus/Code/DataStructure/Song.cs | 138 ++++++++++++++ .../DataStructure}/UslessHolder.cs | 2 +- .../Fragments}/Browse.cs | 175 +++++++---------- Opus/{ => Code}/MainActivity.cs | 2 + Opus/Opus.csproj | 15 +- .../Portable Class/AddToPlaylistAdapter.cs | 1 + .../Resources/Portable Class/BrowseAdapter.cs | 109 ----------- .../Portable Class/CastQueueManager.cs | 1 + .../Portable Class/CurrentItemDecoration.cs | 7 +- Opus/Resources/Portable Class/Downloader.cs | 1 + Opus/Resources/Portable Class/EditMetaData.cs | 1 + Opus/Resources/Portable Class/FolderBrowse.cs | 2 + Opus/Resources/Portable Class/FolderTracks.cs | 177 +++++++++--------- Opus/Resources/Portable Class/Home.cs | 1 + Opus/Resources/Portable Class/HomeAdapter.cs | 1 + .../Portable Class/HomeListAdapter.cs | 7 +- Opus/Resources/Portable Class/HomeSection.cs | 1 + Opus/Resources/Portable Class/LineAdapter.cs | 10 +- Opus/Resources/Portable Class/MusicPlayer.cs | 2 + .../Resources/Portable Class/PagerFragment.cs | 1 + Opus/Resources/Portable Class/Player.cs | 6 +- Opus/Resources/Portable Class/Playlist.cs | 2 + .../Portable Class/PlaylistAdapter.cs | 1 + Opus/Resources/Portable Class/PlaylistItem.cs | 3 +- .../Portable Class/PlaylistTrackAdapter.cs | 5 +- .../Portable Class/PlaylistTracks.cs | 2 + Opus/Resources/Portable Class/Queue.cs | 4 +- Opus/Resources/Portable Class/QueueAdapter.cs | 7 +- .../Portable Class/RecyclerHolder.cs | 41 ---- .../Portable Class/SnackbarCallback.cs | 1 + Opus/Resources/Portable Class/Song.cs | 74 -------- .../Resources/Portable Class/YoutubeEngine.cs | 2 + Opus/Resources/Portable Class/YtAdapter.cs | 5 +- Opus/Resources/Portable Class/YtFile.cs | 3 +- 36 files changed, 558 insertions(+), 444 deletions(-) create mode 100644 Opus/Code/Adapter/BaseCursor.cs create mode 100644 Opus/Code/Adapter/BrowseAdapter.cs create mode 100644 Opus/Code/DataStructure/Song.cs rename Opus/{Resources/Portable Class => Code/DataStructure}/UslessHolder.cs (90%) rename Opus/{Resources/Portable Class => Code/Fragments}/Browse.cs (88%) rename Opus/{ => Code}/MainActivity.cs (99%) delete mode 100644 Opus/Resources/Portable Class/BrowseAdapter.cs delete mode 100644 Opus/Resources/Portable Class/RecyclerHolder.cs delete mode 100644 Opus/Resources/Portable Class/Song.cs diff --git a/Opus/Code/Adapter/BaseCursor.cs b/Opus/Code/Adapter/BaseCursor.cs new file mode 100644 index 0000000..e1b3b06 --- /dev/null +++ b/Opus/Code/Adapter/BaseCursor.cs @@ -0,0 +1,77 @@ +using Android.Database; +using Android.Support.V7.Widget; +using Android.Views; + +namespace Opus.Adapter +{ + public abstract class BaseCursor : RecyclerView.Adapter + { + public ICursor cursor; + /// + /// This is the number of items (for example headers) there is before the list represented by the cursor. + /// + public abstract int ItemBefore { get; } + public int BaseCount { get { return cursor != null ? cursor.Count : 0; } } + public override int ItemCount => BaseCount + ItemBefore; + + public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position) + { + if (cursor.MoveToPosition(position - ItemBefore)) + OnBindViewHolder(holder, Convert(cursor)); + } + public abstract void OnBindViewHolder(RecyclerView.ViewHolder viewHolder, T item); + + public void SwapCursor(ICursor newCursor) + { + if (newCursor == cursor) + return; + + if (newCursor != null) + { + MainActivity.instance.FindViewById(Resource.Id.loading).Visibility = ViewStates.Gone; + cursor = newCursor; + NotifyDataSetChanged(); + } + else + { + NotifyItemRangeRemoved(0, ItemCount); + cursor = null; + MainActivity.instance.FindViewById(Resource.Id.loading).Visibility = ViewStates.Visible; + } + } + + public T GetItem(int position) + { + cursor.MoveToPosition(position - ItemBefore); + return Convert(cursor); + } + + public void OnClick(int position) + { + if (position >= ItemBefore) + { + cursor.MoveToPosition(position - ItemBefore); + Clicked(Convert(cursor)); + } + else + HeaderClicked(position); + } + public abstract void Clicked(T item); + public virtual void HeaderClicked(int position) { } + + public void OnLongClick(int position) + { + if (position >= ItemBefore) + { + cursor.MoveToPosition(position - ItemBefore); + LongClicked(Convert(cursor)); + } + else + HeaderLongClicked(position); + } + public abstract void LongClicked(T item); + public virtual void HeaderLongClicked(int position) { } + + public abstract T Convert(ICursor cursor); + } +} \ No newline at end of file diff --git a/Opus/Code/Adapter/BrowseAdapter.cs b/Opus/Code/Adapter/BrowseAdapter.cs new file mode 100644 index 0000000..624ebfc --- /dev/null +++ b/Opus/Code/Adapter/BrowseAdapter.cs @@ -0,0 +1,115 @@ +using Android.App; +using Android.Content; +using Android.Database; +using Android.Graphics; +using Android.Support.V7.Widget; +using Android.Views; +using Opus.DataStructure; +using Opus.Fragments; +using Square.Picasso; + +namespace Opus.Adapter +{ + public class BrowseAdapter : BaseCursor + { + public bool displayShuffle; + public override int ItemBefore => (displayShuffle && BaseCount != 0) ? 1 : 0; + + + public BrowseAdapter() + { + cursor = null; + displayShuffle = true; + } + + public BrowseAdapter(ICursor cursor, bool displayShuffle) + { + this.cursor = cursor; + this.displayShuffle = displayShuffle; + } + + public override void OnBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) + { + if (position == 0 && displayShuffle) + { + if (MainActivity.Theme == 1) + ((CardView)viewHolder.ItemView).SetCardBackgroundColor(Color.ParseColor("#212121")); + else + ((CardView)viewHolder.ItemView).SetCardBackgroundColor(Color.White); + } + else + base.OnBindViewHolder(viewHolder, position); + } + + public override void OnBindViewHolder(RecyclerView.ViewHolder viewHolder, Song song) + { + SongHolder holder = (SongHolder)viewHolder; + + if (MainActivity.Theme == 1) + { + holder.more.SetColorFilter(Color.White); + holder.Title.SetTextColor(Color.White); + holder.Artist.SetTextColor(Color.White); + holder.Artist.Alpha = 0.7f; + } + + holder.Title.Text = song.Title; + holder.Artist.Text = song.Artist; + + var songCover = Android.Net.Uri.Parse("content://media/external/audio/albumart"); + var songAlbumArtUri = ContentUris.WithAppendedId(songCover, song.AlbumArt); + Picasso.With(Application.Context).Load(songAlbumArtUri).Placeholder(Resource.Color.background_material_dark).Resize(400, 400).CenterCrop().Into(holder.AlbumArt); + + if (!holder.more.HasOnClickListeners) + { + holder.more.Click += (sender, e) => + { + Browse.instance?.More(GetItem(holder.AdapterPosition)); + }; + } + } + + public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType) + { + if (viewType == 0) + { + View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.ShuffleButton, parent, false); + return new UslessHolder(itemView, OnClick); + } + else + { + View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.SongList, parent, false); + return new SongHolder(itemView, OnClick, OnLongClick); + } + } + + public override int GetItemViewType(int position) + { + if (position == 0 && displayShuffle) + return 0; + else + return 1; + } + + public override void HeaderClicked(int position) + { + MainActivity.instance.ShuffleAll(); + } + + public override void Clicked(Song song) + { + song = Browse.CompleteItem(song); + Browse.Play(song); + } + + public override void LongClicked(Song song) + { + Browse.instance?.More(song); + } + + public override Song Convert(ICursor cursor) + { + return Song.FromCursor(cursor); + } + } +} \ No newline at end of file diff --git a/Opus/Code/DataStructure/Song.cs b/Opus/Code/DataStructure/Song.cs new file mode 100644 index 0000000..ab200d0 --- /dev/null +++ b/Opus/Code/DataStructure/Song.cs @@ -0,0 +1,138 @@ +using Android.Database; +using Android.Gms.Cast; +using Android.Provider; +using Android.Support.V7.Widget; +using Android.Views; +using Android.Widget; +using Newtonsoft.Json; +using SQLite; +using System; + +namespace Opus.DataStructure +{ + [Serializable] + public class Song + { + [PrimaryKey, Unique] + public int Index { get; set; } + + public string Title { get; set; } + public string Artist { get; set; } + public string Album { get; set; } + public long AlbumArt { get; set; } + public string YoutubeID { get; set; } + public long Id { get; set; } + public string Path { get; set; } + public bool? IsParsed { get; set; } + public bool IsYt { get; set; } + public DateTimeOffset? ExpireDate { get; set;} + public bool IsLiveStream = false; + public string TrackID; + + public Song() { } + + public Song(string title, string artist, string album, string youtubeID, long albumArt, long id, string path, bool isYT = false, bool isParsed = true) + { + Title = title; + Artist = artist; + Album = album; + YoutubeID = youtubeID; + AlbumArt = albumArt; + Id = id; + Path = path; + IsYt = isYT; + IsParsed = isParsed; + } + + public override string ToString() + { + return Title + " Artist: " + Artist + " Album: " + Album + " youtubeID: " + YoutubeID + " AlbumArt: " + AlbumArt + " Id: " + Id + " Path: " + Path + " isYT: " + IsYt + " isParsed: " + IsParsed; + } + + public static Song FromCursor(ICursor cursor) + { + int titleID = cursor.GetColumnIndex(MediaStore.Audio.Media.InterfaceConsts.Title); + int artistID = cursor.GetColumnIndex(MediaStore.Audio.Media.InterfaceConsts.Artist); + int albumID = cursor.GetColumnIndex(MediaStore.Audio.Media.InterfaceConsts.Album); + int thisID = cursor.GetColumnIndex(MediaStore.Audio.Media.InterfaceConsts.Id); + int pathID = cursor.GetColumnIndex(MediaStore.Audio.Media.InterfaceConsts.Data); + + string Artist = cursor.GetString(artistID); + string Title = cursor.GetString(titleID); + string Album = cursor.GetString(albumID); + long AlbumArt = cursor.GetLong(cursor.GetColumnIndex(MediaStore.Audio.Albums.InterfaceConsts.AlbumId)); + long id = cursor.GetLong(thisID); + string path = cursor.GetString(pathID); + + if (Title == null) + Title = "Unknown Title"; + if (Artist == null) + Artist = "Unknow Artist"; + if (Album == null) + Album = "Unknow Album"; + + return new Song(Title, Artist, Album, null, AlbumArt, id, path); + } + + + public static explicit operator Song(string v) + { + if (v == null) + return null; + + string Name = v.Substring(0, v.IndexOf(" Artist: ")); + string Artist = v.Substring(v.IndexOf(" Artist: ") + 9, v.IndexOf(" Album: ") - Name.Length - 8); + string Album = v.Substring(v.IndexOf(" Album: ") + 8, v.IndexOf(" youtubeID: ") - v.IndexOf(" Album: ") - 8); + string youtubeID = v.Substring(v.IndexOf(" youtubeID: ") + 12, v.IndexOf(" AlbumArt: ") - v.IndexOf(" youtubeID: ") - 12); + long AlbumArt = long.Parse(v.Substring(v.IndexOf(" AlbumArt: ") + 11, v.IndexOf(" Id: ") - v.IndexOf(" AlbumArt: ") - 11)); + long id = long.Parse(v.Substring(v.IndexOf(" Id: ") + 5, v.IndexOf(" Path: ") - v.IndexOf(" Id: ") - 5)); + string path = v.Substring(v.IndexOf(" Path: ") + 7, v.IndexOf(" isYT: ") - v.IndexOf(" Path: ") - 7); + bool isYT = bool.Parse(v.Substring(v.IndexOf(" isYT: ") + 7, v.IndexOf(" isParsed: ") - v.IndexOf(" isYT: ") - 7)); + bool isParsed = bool.Parse(v.Substring(v.IndexOf(" isParsed: ") + 11)); + + Song song = new Song(Name, Artist, Album, youtubeID, AlbumArt, id, path, isYT, isParsed); + return song; + } + + public static explicit operator Song(MediaQueueItem v) + { + if (v == null) + return null; + + return JsonConvert.DeserializeObject(v.Media.CustomData.ToString()); + } + } + + public class SongHolder : RecyclerView.ViewHolder + { + public ImageView reorder; + public TextView Title; + public TextView Artist; + public TextView Live; + public ImageView AlbumArt; + public ImageView youtubeIcon; + public ImageView more; + public TextView status; + public Button action; + public View RightButtons; + public View TextLayout; + + public SongHolder(View itemView, Action listener, Action longListener) : base(itemView) + { + reorder = itemView.FindViewById(Resource.Id.reorder); + Title = itemView.FindViewById(Resource.Id.title); + Artist = itemView.FindViewById(Resource.Id.artist); + Live = itemView.FindViewById(Resource.Id.isLive); + AlbumArt = itemView.FindViewById(Resource.Id.albumArt); + youtubeIcon = itemView.FindViewById(Resource.Id.youtubeIcon); + more = itemView.FindViewById(Resource.Id.moreButton); + RightButtons = itemView.FindViewById(Resource.Id.rightButtons); + TextLayout = itemView.FindViewById(Resource.Id.textLayout); + status = itemView.FindViewById(Resource.Id.status); + action = itemView.FindViewById