mirror of
https://github.com/zoriya/Opus.git
synced 2025-12-06 06:26:15 +00:00
Totally reworking the get playlist part of the app. It's now cleaner.
Reseting the player loadbar when switching to a song witch is not available anymore.
This commit is contained in:
@@ -964,7 +964,7 @@ namespace Opus
|
|||||||
|
|
||||||
public void NotStreamable(string title)
|
public void NotStreamable(string title)
|
||||||
{
|
{
|
||||||
Snackbar snackBar = Snackbar.Make(FindViewById(Resource.Id.snackBar), title + Resource.String.not_streamable, Snackbar.LengthLong);
|
Snackbar snackBar = Snackbar.Make(FindViewById(Resource.Id.snackBar), title + GetString(Resource.String.not_streamable), Snackbar.LengthLong);
|
||||||
snackBar.View.FindViewById<TextView>(Resource.Id.snackbar_text).SetTextColor(Color.White);
|
snackBar.View.FindViewById<TextView>(Resource.Id.snackbar_text).SetTextColor(Color.White);
|
||||||
snackBar.Show();
|
snackBar.Show();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,12 +56,12 @@ namespace Opus.Resources.Portable_Class
|
|||||||
if (adapter != null)
|
if (adapter != null)
|
||||||
ListView.SetAdapter(adapter);
|
ListView.SetAdapter(adapter);
|
||||||
else
|
else
|
||||||
PopulateSongs();
|
PopulateView();
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
#pragma warning restore CS4014
|
#pragma warning restore CS4014
|
||||||
|
|
||||||
private /*async Task */ void PopulateSongs()
|
private /*async Task */ void PopulateView()
|
||||||
{
|
{
|
||||||
if (!populating)
|
if (!populating)
|
||||||
{
|
{
|
||||||
@@ -398,7 +398,7 @@ namespace Opus.Resources.Portable_Class
|
|||||||
|
|
||||||
public async Task Refresh()
|
public async Task Refresh()
|
||||||
{
|
{
|
||||||
/*await*/ PopulateSongs();
|
/*await*/ PopulateView();
|
||||||
await Task.Delay(0); //WE DONT NEED TO TALK ABOUT THIS
|
await Task.Delay(0); //WE DONT NEED TO TALK ABOUT THIS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -554,6 +554,9 @@ namespace Opus.Resources.Portable_Class
|
|||||||
if (MainActivity.instance != null)
|
if (MainActivity.instance != null)
|
||||||
MainActivity.instance.FindViewById<ProgressBar>(Resource.Id.ytProgress).Visibility = ViewStates.Gone;
|
MainActivity.instance.FindViewById<ProgressBar>(Resource.Id.ytProgress).Visibility = ViewStates.Gone;
|
||||||
song.IsParsed = false;
|
song.IsParsed = false;
|
||||||
|
|
||||||
|
if (startPlaybackWhenPosible)
|
||||||
|
Player.instance?.Ready();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
catch(YoutubeExplode.Exceptions.VideoUnplayableException ex)
|
catch(YoutubeExplode.Exceptions.VideoUnplayableException ex)
|
||||||
@@ -566,6 +569,9 @@ namespace Opus.Resources.Portable_Class
|
|||||||
song.IsParsed = false;
|
song.IsParsed = false;
|
||||||
if (position != -1)
|
if (position != -1)
|
||||||
RemoveFromQueue(position); //Remove the song from the queue since it can't be played.
|
RemoveFromQueue(position); //Remove the song from the queue since it can't be played.
|
||||||
|
|
||||||
|
if(startPlaybackWhenPosible)
|
||||||
|
Player.instance?.Ready();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
catch(YoutubeExplode.Exceptions.VideoUnavailableException)
|
catch(YoutubeExplode.Exceptions.VideoUnavailableException)
|
||||||
@@ -577,6 +583,9 @@ namespace Opus.Resources.Portable_Class
|
|||||||
song.IsParsed = false;
|
song.IsParsed = false;
|
||||||
if (position != -1)
|
if (position != -1)
|
||||||
RemoveFromQueue(position); //Remove the song from the queue since it can't be played.
|
RemoveFromQueue(position); //Remove the song from the queue since it can't be played.
|
||||||
|
|
||||||
|
if (startPlaybackWhenPosible)
|
||||||
|
Player.instance?.Ready();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return song;
|
return song;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ using System.Collections.Generic;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using static Android.Provider.MediaStore.Audio;
|
using static Android.Provider.MediaStore.Audio;
|
||||||
using CursorLoader = Android.Support.V4.Content.CursorLoader;
|
using CursorLoader = Android.Support.V4.Content.CursorLoader;
|
||||||
|
using Application = Android.App.Application;
|
||||||
|
|
||||||
namespace Opus.Resources.Portable_Class
|
namespace Opus.Resources.Portable_Class
|
||||||
{
|
{
|
||||||
@@ -64,70 +65,34 @@ namespace Opus.Resources.Portable_Class
|
|||||||
{
|
{
|
||||||
populating = true;
|
populating = true;
|
||||||
|
|
||||||
//Synced playlists
|
|
||||||
List<PlaylistItem> SyncedPlaylists = new List<PlaylistItem>();
|
|
||||||
await Task.Run(() =>
|
|
||||||
{
|
|
||||||
SQLiteConnection db = new SQLiteConnection(System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "SyncedPlaylists.sqlite"));
|
|
||||||
db.CreateTable<PlaylistItem>();
|
|
||||||
|
|
||||||
SyncedPlaylists = db.Table<PlaylistItem>().ToList();
|
|
||||||
});
|
|
||||||
|
|
||||||
//Initialisation
|
//Initialisation
|
||||||
LocalPlaylists.Clear();
|
LocalPlaylists.Clear();
|
||||||
YoutubePlaylists.Clear();
|
YoutubePlaylists.Clear();
|
||||||
LocalPlaylists.Add(new PlaylistItem("Header", -1));
|
LocalPlaylists.Add(new PlaylistItem("Header", -1));
|
||||||
YoutubePlaylists.Add(new PlaylistItem("Header", null));
|
YoutubePlaylists.Add(new PlaylistItem("Header", null));
|
||||||
PlaylistItem Loading = new PlaylistItem("Loading", null);
|
PlaylistItem Loading = new PlaylistItem("Loading", null);
|
||||||
|
|
||||||
|
//Get all local playlist and display an error message if we have an error.
|
||||||
|
(List<PlaylistItem> locPlaylists, string error) = await GetLocalPlaylists();
|
||||||
|
|
||||||
if (await MainActivity.instance.GetReadPermission())
|
if (instance == null)
|
||||||
{
|
return;
|
||||||
//Local playlists
|
|
||||||
Android.Net.Uri uri = Playlists.ExternalContentUri;
|
|
||||||
CursorLoader loader = new CursorLoader(Android.App.Application.Context, uri, null, null, null, null);
|
|
||||||
ICursor cursor = (ICursor)loader.LoadInBackground();
|
|
||||||
|
|
||||||
if (cursor != null && cursor.MoveToFirst())
|
if (locPlaylists == null) //an error has occured
|
||||||
{
|
LocalPlaylists.Add(new PlaylistItem("EMPTY", -1) { Owner = error });
|
||||||
int nameID = cursor.GetColumnIndex(Playlists.InterfaceConsts.Name);
|
|
||||||
int listID = cursor.GetColumnIndex(Playlists.InterfaceConsts.Id);
|
|
||||||
do
|
|
||||||
{
|
|
||||||
string name = cursor.GetString(nameID);
|
|
||||||
long id = cursor.GetLong(listID);
|
|
||||||
|
|
||||||
PlaylistItem ytPlaylist = SyncedPlaylists.Find(x => x.LocalID == id);
|
|
||||||
if (ytPlaylist == null)
|
|
||||||
{
|
|
||||||
Android.Net.Uri musicUri = Playlists.Members.GetContentUri("external", id);
|
|
||||||
CursorLoader cursorLoader = new CursorLoader(Android.App.Application.Context, musicUri, null, null, null, null);
|
|
||||||
ICursor musicCursor = (ICursor)cursorLoader.LoadInBackground();
|
|
||||||
|
|
||||||
LocalPlaylists.Add(new PlaylistItem(name, id, musicCursor.Count));
|
//Handle synced playlist from the local playlist array we had before.
|
||||||
}
|
(List<PlaylistItem> loc, List<PlaylistItem> SyncedPlaylists) = await ProcessSyncedPlaylists(locPlaylists);
|
||||||
else
|
|
||||||
{
|
|
||||||
if (ytPlaylist.YoutubeID == null)
|
|
||||||
ytPlaylist.SyncState = SyncState.Loading;
|
|
||||||
else
|
|
||||||
ytPlaylist.SyncState = SyncState.True;
|
|
||||||
|
|
||||||
YoutubePlaylists.Add(ytPlaylist);
|
if (instance == null)
|
||||||
}
|
return;
|
||||||
}
|
|
||||||
while (cursor.MoveToNext());
|
|
||||||
cursor.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LocalPlaylists.Count == 1)
|
LocalPlaylists.AddRange(loc);
|
||||||
LocalPlaylists.Add(new PlaylistItem("EMPTY", -1) { Owner = Resources.GetString(Resource.String.local_playlist_empty) });
|
YoutubePlaylists.AddRange(SyncedPlaylists);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LocalPlaylists.Add(new PlaylistItem("EMPTY", -1) { Owner = Resources.GetString(Resource.String.no_permission) });
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
//Display this for now, we'll load non synced youtube playlist in the background.
|
||||||
YoutubePlaylists.Add(Loading);
|
YoutubePlaylists.Add(Loading);
|
||||||
adapter = new PlaylistAdapter(LocalPlaylists, YoutubePlaylists);
|
adapter = new PlaylistAdapter(LocalPlaylists, YoutubePlaylists);
|
||||||
ListView.SetAdapter(adapter);
|
ListView.SetAdapter(adapter);
|
||||||
@@ -135,220 +100,324 @@ namespace Opus.Resources.Portable_Class
|
|||||||
adapter.ItemLongCLick += ListView_ItemLongClick;
|
adapter.ItemLongCLick += ListView_ItemLongClick;
|
||||||
ListView.SetItemAnimator(new DefaultItemAnimator());
|
ListView.SetItemAnimator(new DefaultItemAnimator());
|
||||||
|
|
||||||
//Youtube playlists
|
//Youtube owned playlists
|
||||||
if (!await MainActivity.instance.WaitForYoutube())
|
(List<PlaylistItem> yt, string err) = await GetOwnedYoutubePlaylists(SyncedPlaylists);
|
||||||
|
|
||||||
|
if (instance == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (yt == null)
|
||||||
{
|
{
|
||||||
YoutubePlaylists.Remove(Loading);
|
YoutubePlaylists.Remove(Loading);
|
||||||
adapter.NotifyItemRemoved(LocalPlaylists.Count + YoutubePlaylists.Count);
|
adapter.NotifyItemRemoved(LocalPlaylists.Count + YoutubePlaylists.Count);
|
||||||
|
YoutubePlaylists.Add(new PlaylistItem("Error", null)); //Should use the "err" var here
|
||||||
for (int i = 1; i < YoutubePlaylists.Count; i++)
|
|
||||||
{
|
|
||||||
YoutubePlaylists[i].SyncState = SyncState.Error;
|
|
||||||
PlaylistHolder holder = (PlaylistHolder)ListView.GetChildViewHolder(ListView.GetChildAt(LocalPlaylists.Count + i));
|
|
||||||
holder.sync.SetImageResource(Resource.Drawable.SyncError);
|
|
||||||
holder.sync.Visibility = ViewStates.Visible;
|
|
||||||
holder.SyncLoading.Visibility = ViewStates.Gone;
|
|
||||||
if (MainActivity.Theme == 1)
|
|
||||||
holder.sync.SetColorFilter(Color.White);
|
|
||||||
}
|
|
||||||
|
|
||||||
YoutubePlaylists.Add(new PlaylistItem("Error", null));
|
|
||||||
adapter.NotifyItemInserted(LocalPlaylists.Count + YoutubePlaylists.Count);
|
adapter.NotifyItemInserted(LocalPlaylists.Count + YoutubePlaylists.Count);
|
||||||
populating = false;
|
populating = false;
|
||||||
|
SyncError();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int YtCount = YoutubePlaylists.Count;
|
else
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
YouTubeService youtube = YoutubeEngine.youtubeService;
|
int startPos = YoutubePlaylists.Count - 1;
|
||||||
|
YoutubePlaylists.InsertRange(startPos, yt);
|
||||||
PlaylistsResource.ListRequest request = youtube.Playlists.List("snippet,contentDetails");
|
adapter.NotifyItemRangeInserted(LocalPlaylists.Count + startPos, yt.Count);
|
||||||
request.Mine = true;
|
|
||||||
request.MaxResults = 25;
|
|
||||||
PlaylistListResponse response = await request.ExecuteAsync();
|
|
||||||
|
|
||||||
if (instance == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (int i = 0; i < response.Items.Count; i++)
|
|
||||||
{
|
|
||||||
Google.Apis.YouTube.v3.Data.Playlist playlist = response.Items[i];
|
|
||||||
PlaylistItem item = new PlaylistItem(playlist.Snippet.Title, playlist.Id, playlist, (int)playlist.ContentDetails.ItemCount)
|
|
||||||
{
|
|
||||||
Owner = playlist.Snippet.ChannelTitle,
|
|
||||||
ImageURL = playlist.Snippet.Thumbnails.High.Url,
|
|
||||||
HasWritePermission = true
|
|
||||||
};
|
|
||||||
|
|
||||||
PlaylistItem syncedItem = SyncedPlaylists.Find(x => x.YoutubeID == item.YoutubeID);
|
|
||||||
if (SyncedPlaylists.Find(x => x.YoutubeID == item.YoutubeID) != null)
|
|
||||||
{
|
|
||||||
int position = YoutubePlaylists.FindIndex(x => x.Name == item.Name);
|
|
||||||
YoutubePlaylists[position].Snippet = item.Snippet;
|
|
||||||
YoutubePlaylists[position].Count = item.Count;
|
|
||||||
SyncedPlaylists.RemoveAll(x => x.YoutubeID == item.YoutubeID);
|
|
||||||
}
|
|
||||||
else if (SyncedPlaylists.Find(x => x.Name == item.Name) != null)
|
|
||||||
{
|
|
||||||
item.LocalID = SyncedPlaylists.Find(x => x.Name == item.Name).LocalID;
|
|
||||||
int position = YoutubePlaylists.FindIndex(x => x.Name == item.Name);
|
|
||||||
YoutubePlaylists[position] = item;
|
|
||||||
YoutubePlaylists[position].SyncState = SyncState.True;
|
|
||||||
|
|
||||||
PlaylistHolder holder = (PlaylistHolder)ListView.GetChildViewHolder(ListView.GetChildAt(LocalPlaylists.Count + position));
|
|
||||||
holder.Owner.Text = item.Owner;
|
|
||||||
Picasso.With(Android.App.Application.Context).Load(item.ImageURL).Placeholder(Resource.Color.background_material_dark).Resize(400, 400).CenterCrop().Into(holder.AlbumArt);
|
|
||||||
holder.edit.Visibility = ViewStates.Visible;
|
|
||||||
if (MainActivity.Theme == 1)
|
|
||||||
holder.edit.SetColorFilter(Color.White);
|
|
||||||
holder.sync.SetImageResource(Resource.Drawable.Sync);
|
|
||||||
holder.sync.Visibility = ViewStates.Visible;
|
|
||||||
holder.SyncLoading.Visibility = ViewStates.Gone;
|
|
||||||
if (MainActivity.Theme == 1)
|
|
||||||
holder.sync.SetColorFilter(Color.White);
|
|
||||||
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
SQLiteConnection db = new SQLiteConnection(System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "SyncedPlaylists.sqlite"));
|
|
||||||
db.CreateTable<PlaylistItem>();
|
|
||||||
db.InsertOrReplace(item);
|
|
||||||
});
|
|
||||||
SyncedPlaylists.RemoveAll(x => x.LocalID == item.LocalID);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
YoutubePlaylists.Add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(YtCount != YoutubePlaylists.Count)
|
|
||||||
{
|
|
||||||
YoutubePlaylists.Remove(Loading);
|
|
||||||
YoutubePlaylists.Add(Loading);
|
|
||||||
adapter.NotifyItemMoved(LocalPlaylists.Count + YoutubePlaylists.IndexOf(Loading), LocalPlaylists.Count + YoutubePlaylists.Count);
|
|
||||||
}
|
|
||||||
adapter.NotifyItemRangeInserted(LocalPlaylists.Count + YoutubePlaylists.Count + 1 - YtCount, YoutubePlaylists.Count - YtCount);
|
|
||||||
YtCount = YoutubePlaylists.Count;
|
|
||||||
|
|
||||||
//Saved playlists
|
|
||||||
ChannelSectionsResource.ListRequest forkedRequest = youtube.ChannelSections.List("snippet,contentDetails");
|
|
||||||
forkedRequest.Mine = true;
|
|
||||||
ChannelSectionListResponse forkedResponse = await forkedRequest.ExecuteAsync();
|
|
||||||
if (instance == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (ChannelSection section in forkedResponse.Items)
|
|
||||||
{
|
|
||||||
if (section.Snippet.Title == "Saved Playlists")
|
|
||||||
{
|
|
||||||
for (int i = 0; i < section.ContentDetails.Playlists.Count; i++)
|
|
||||||
{
|
|
||||||
PlaylistsResource.ListRequest plRequest = youtube.Playlists.List("snippet, contentDetails");
|
|
||||||
plRequest.Id = section.ContentDetails.Playlists[i];
|
|
||||||
PlaylistListResponse plResponse = await plRequest.ExecuteAsync();
|
|
||||||
|
|
||||||
if (instance == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Google.Apis.YouTube.v3.Data.Playlist playlist = plResponse.Items[i];
|
|
||||||
playlist.Kind = "youtube#saved";
|
|
||||||
PlaylistItem item = new PlaylistItem(playlist.Snippet.Title, playlist.Id, playlist, (int)playlist.ContentDetails.ItemCount)
|
|
||||||
{
|
|
||||||
Owner = playlist.Snippet.ChannelTitle,
|
|
||||||
ImageURL = playlist.Snippet.Thumbnails.High.Url,
|
|
||||||
HasWritePermission = false
|
|
||||||
};
|
|
||||||
|
|
||||||
if (SyncedPlaylists.Find(x => x.YoutubeID == item.YoutubeID) != null)
|
|
||||||
{
|
|
||||||
int position = YoutubePlaylists.FindIndex(x => x.Name == item.Name);
|
|
||||||
YoutubePlaylists[position].Snippet = item.Snippet;
|
|
||||||
YoutubePlaylists[position].Count = item.Count;
|
|
||||||
YoutubePlaylists[position].SyncState = SyncState.True;
|
|
||||||
SyncedPlaylists.RemoveAll(x => x.YoutubeID == item.YoutubeID);
|
|
||||||
}
|
|
||||||
else if (SyncedPlaylists.Find(x => x.Name == item.Name) != null)
|
|
||||||
{
|
|
||||||
item.LocalID = SyncedPlaylists.Find(x => x.Name == item.Name).LocalID;
|
|
||||||
int position = YoutubePlaylists.FindIndex(x => x.Name == item.Name);
|
|
||||||
YoutubePlaylists[position] = item;
|
|
||||||
YoutubePlaylists[position].SyncState = SyncState.True;
|
|
||||||
|
|
||||||
PlaylistHolder holder = (PlaylistHolder)ListView.GetChildViewHolder(ListView.GetChildAt(LocalPlaylists.Count + position));
|
|
||||||
holder.Owner.Text = item.Owner;
|
|
||||||
Picasso.With(Android.App.Application.Context).Load(item.ImageURL).Placeholder(Resource.Color.background_material_dark).Resize(400, 400).CenterCrop().Into(holder.AlbumArt);
|
|
||||||
holder.edit.Visibility = ViewStates.Gone;
|
|
||||||
holder.sync.SetImageResource(Resource.Drawable.Sync);
|
|
||||||
holder.sync.Visibility = ViewStates.Visible;
|
|
||||||
holder.SyncLoading.Visibility = ViewStates.Gone;
|
|
||||||
if (MainActivity.Theme == 1)
|
|
||||||
holder.sync.SetColorFilter(Color.White);
|
|
||||||
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
SQLiteConnection db = new SQLiteConnection(System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "SyncedPlaylists.sqlite"));
|
|
||||||
db.CreateTable<PlaylistItem>();
|
|
||||||
db.InsertOrReplace(item);
|
|
||||||
});
|
|
||||||
SyncedPlaylists.RemoveAll(x => x.LocalID == item.LocalID);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
YoutubePlaylists.Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
YoutubePlaylists.Remove(Loading);
|
|
||||||
adapter.NotifyItemRemoved(LocalPlaylists.Count + YtCount);
|
|
||||||
|
|
||||||
if (YoutubePlaylists.Count == 1)
|
|
||||||
{
|
|
||||||
YoutubePlaylists.Add(new PlaylistItem("EMPTY", null) { Owner = Resources.GetString(Resource.String.youtube_playlist_empty) });
|
|
||||||
}
|
|
||||||
adapter.NotifyItemRangeInserted(LocalPlaylists.Count + YoutubePlaylists.Count + 1 - YtCount, YoutubePlaylists.Count - YtCount);
|
|
||||||
adapter.forkSaved = true;
|
|
||||||
|
|
||||||
if (SyncedPlaylists.Count > 0)
|
|
||||||
{
|
|
||||||
List<PlaylistItem> BadSync = SyncedPlaylists.FindAll(x => x.SyncState == SyncState.Loading);
|
|
||||||
LocalPlaylists.AddRange(BadSync);
|
|
||||||
|
|
||||||
for (int i = 0; i < SyncedPlaylists.Count; i++)
|
|
||||||
SyncedPlaylists[i].SyncState = SyncState.Error;
|
|
||||||
|
|
||||||
if(BadSync.Count > 0)
|
|
||||||
{
|
|
||||||
if (LocalPlaylists[1].Name == "EMPTY")
|
|
||||||
{
|
|
||||||
LocalPlaylists.RemoveAt(1);
|
|
||||||
adapter.NotifyItemRemoved(1);
|
|
||||||
}
|
|
||||||
adapter.NotifyItemRangeInserted(LocalPlaylists.Count - SyncedPlaylists.Count, BadSync.Count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (System.Net.Http.HttpRequestException)
|
|
||||||
|
//Youtube saved playlists
|
||||||
|
(yt, error) = await GetSavedYoutubePlaylists(SyncedPlaylists);
|
||||||
|
|
||||||
|
if (instance == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (yt == null)
|
||||||
{
|
{
|
||||||
YoutubePlaylists.Remove(Loading);
|
YoutubePlaylists.Remove(Loading);
|
||||||
adapter.NotifyItemRemoved(LocalPlaylists.Count + YoutubePlaylists.Count);
|
adapter.NotifyItemRemoved(LocalPlaylists.Count + YoutubePlaylists.Count);
|
||||||
|
YoutubePlaylists.Add(new PlaylistItem("Error", null)); //Should use the "error" var here
|
||||||
for (int i = 1; i < YoutubePlaylists.Count; i++)
|
|
||||||
{
|
|
||||||
YoutubePlaylists[i].SyncState = SyncState.Error;
|
|
||||||
PlaylistHolder holder = (PlaylistHolder)ListView.GetChildViewHolder(ListView.GetChildAt(LocalPlaylists.Count + i));
|
|
||||||
holder.sync.SetImageResource(Resource.Drawable.SyncError);
|
|
||||||
holder.sync.Visibility = ViewStates.Visible;
|
|
||||||
holder.SyncLoading.Visibility = ViewStates.Gone;
|
|
||||||
if (MainActivity.Theme == 1)
|
|
||||||
holder.sync.SetColorFilter(Color.White);
|
|
||||||
}
|
|
||||||
|
|
||||||
YoutubePlaylists.Add(new PlaylistItem("Error", null));
|
|
||||||
adapter.NotifyItemInserted(LocalPlaylists.Count + YoutubePlaylists.Count);
|
adapter.NotifyItemInserted(LocalPlaylists.Count + YoutubePlaylists.Count);
|
||||||
|
populating = false;
|
||||||
|
SyncError();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
YoutubePlaylists.Remove(Loading);
|
||||||
|
int loadPos = LocalPlaylists.Count + YoutubePlaylists.Count;
|
||||||
|
YoutubePlaylists.AddRange(yt);
|
||||||
|
adapter.NotifyItemChanged(loadPos);
|
||||||
|
adapter.NotifyItemRangeInserted(loadPos + 1, yt.Count - 1);
|
||||||
|
adapter.forkSaved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SyncedPlaylists.Count > 0)
|
||||||
|
{
|
||||||
|
List<PlaylistItem> BadSync = SyncedPlaylists.FindAll(x => x.SyncState == SyncState.Loading);
|
||||||
|
for (int i = 0; i < SyncedPlaylists.Count; i++)
|
||||||
|
SyncedPlaylists[i].SyncState = SyncState.Error;
|
||||||
|
|
||||||
|
LocalPlaylists.AddRange(BadSync);
|
||||||
|
|
||||||
|
if (BadSync.Count > 0)
|
||||||
|
{
|
||||||
|
if (LocalPlaylists[1].Name == "EMPTY")
|
||||||
|
{
|
||||||
|
LocalPlaylists.RemoveAt(1);
|
||||||
|
adapter.NotifyItemRemoved(1);
|
||||||
|
}
|
||||||
|
adapter.NotifyItemRangeInserted(LocalPlaylists.Count - SyncedPlaylists.Count, BadSync.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
populating = false;
|
populating = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SyncError()
|
||||||
|
{
|
||||||
|
for (int i = 1; i < YoutubePlaylists.Count; i++)
|
||||||
|
{
|
||||||
|
if(YoutubePlaylists[i].SyncState == SyncState.Loading)
|
||||||
|
{
|
||||||
|
YoutubePlaylists[i].SyncState = SyncState.Error;
|
||||||
|
PlaylistHolder holder = (PlaylistHolder)ListView.GetChildViewHolder(ListView.GetChildAt(LocalPlaylists.Count + i));
|
||||||
|
holder.sync.SetImageResource(Resource.Drawable.SyncError);
|
||||||
|
holder.sync.Visibility = ViewStates.Visible;
|
||||||
|
holder.SyncLoading.Visibility = ViewStates.Gone;
|
||||||
|
if (MainActivity.Theme == 1)
|
||||||
|
holder.sync.SetColorFilter(Color.White);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This method will return all playlists available on the local storage in the array "playlists".
|
||||||
|
* If there is an error, the Task will return an error message to display to the user. */
|
||||||
|
public static async Task<(List<PlaylistItem>, string)> GetLocalPlaylists()
|
||||||
|
{
|
||||||
|
if (!await MainActivity.instance.GetReadPermission())
|
||||||
|
return (null, Application.Context.GetString(Resource.String.no_permission));
|
||||||
|
|
||||||
|
List<PlaylistItem> playlists = new List<PlaylistItem>();
|
||||||
|
|
||||||
|
Android.Net.Uri uri = Playlists.ExternalContentUri;
|
||||||
|
CursorLoader loader = new CursorLoader(Application.Context, uri, null, null, null, null);
|
||||||
|
ICursor cursor = (ICursor)loader.LoadInBackground();
|
||||||
|
|
||||||
|
if (cursor != null && cursor.MoveToFirst())
|
||||||
|
{
|
||||||
|
int nameID = cursor.GetColumnIndex(Playlists.InterfaceConsts.Name);
|
||||||
|
int listID = cursor.GetColumnIndex(Playlists.InterfaceConsts.Id);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
string name = cursor.GetString(nameID);
|
||||||
|
long id = cursor.GetLong(listID);
|
||||||
|
|
||||||
|
Android.Net.Uri musicUri = Playlists.Members.GetContentUri("external", id);
|
||||||
|
CursorLoader cursorLoader = new CursorLoader(Application.Context, musicUri, null, null, null, null);
|
||||||
|
ICursor musicCursor = (ICursor)cursorLoader.LoadInBackground();
|
||||||
|
|
||||||
|
playlists.Add(new PlaylistItem(name, id, musicCursor.Count));
|
||||||
|
}
|
||||||
|
while (cursor.MoveToNext());
|
||||||
|
cursor.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playlists.Count == 1)
|
||||||
|
return (null, Application.Context.GetString(Resource.String.local_playlist_empty));
|
||||||
|
else
|
||||||
|
return (playlists, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This method will proceed the local playlists and remove synced one from the imput.
|
||||||
|
* It will return as first ouput an array containing the true local playlist and as second output the synced youtube playlists.
|
||||||
|
* The outputed youtube playlists will already have the right sync state set (loading, synced...) */
|
||||||
|
public static async Task<(List<PlaylistItem>, List<PlaylistItem>)> ProcessSyncedPlaylists(List<PlaylistItem> localPlaylists)
|
||||||
|
{
|
||||||
|
List<PlaylistItem> syncedPlaylists = new List<PlaylistItem>();
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
|
SQLiteConnection db = new SQLiteConnection(System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "SyncedPlaylists.sqlite"));
|
||||||
|
db.CreateTable<PlaylistItem>();
|
||||||
|
|
||||||
|
syncedPlaylists = db.Table<PlaylistItem>().ToList();
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (PlaylistItem synced in syncedPlaylists)
|
||||||
|
{
|
||||||
|
PlaylistItem local = localPlaylists?.Find(x => x.LocalID == synced.LocalID);
|
||||||
|
if (local != null)
|
||||||
|
{
|
||||||
|
localPlaylists.Remove(local); //This playlist is a synced one, we don't want to display it in the "local" collumn but in the youtube one.
|
||||||
|
|
||||||
|
//Set sync state of the playlist (SyncState can't be false since we take the playlist in the synced database)
|
||||||
|
if (synced.YoutubeID == null)
|
||||||
|
synced.SyncState = SyncState.Loading;
|
||||||
|
else
|
||||||
|
synced.SyncState = SyncState.True;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//If local is null, we had an error loading local playlists or another thing (can be read permission denied for example)
|
||||||
|
synced.SyncState = SyncState.Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (localPlaylists, syncedPlaylists);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This method return all youtube playlists owned by the user and process synced playlist if you give an array of know youtube synced playlists
|
||||||
|
* The YoutubePlaylists array should contains the synced playlist availables. Warning, this will return your initial array (proceded if there is synced playlist) + owned playlists
|
||||||
|
* The second outputed var (the string) is the error message that should be displayed to the user (the list will be null if there is an error)*/
|
||||||
|
public static async Task<(List<PlaylistItem>, string)> GetOwnedYoutubePlaylists(List<PlaylistItem> SyncedPlaylists)
|
||||||
|
{
|
||||||
|
if (!await MainActivity.instance.WaitForYoutube())
|
||||||
|
return (null, "Error"); //Should have a better error handling
|
||||||
|
|
||||||
|
List<PlaylistItem> YoutubePlaylists = new List<PlaylistItem>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
YouTubeService youtube = YoutubeEngine.youtubeService;
|
||||||
|
|
||||||
|
PlaylistsResource.ListRequest request = youtube.Playlists.List("snippet,contentDetails");
|
||||||
|
request.Mine = true;
|
||||||
|
request.MaxResults = 25;
|
||||||
|
PlaylistListResponse response = await request.ExecuteAsync();
|
||||||
|
|
||||||
|
for (int i = 0; i < response.Items.Count; i++)
|
||||||
|
{
|
||||||
|
Google.Apis.YouTube.v3.Data.Playlist playlist = response.Items[i];
|
||||||
|
PlaylistItem item = new PlaylistItem(playlist.Snippet.Title, playlist.Id, playlist, (int)playlist.ContentDetails.ItemCount)
|
||||||
|
{
|
||||||
|
Owner = playlist.Snippet.ChannelTitle,
|
||||||
|
ImageURL = playlist.Snippet.Thumbnails.High.Url,
|
||||||
|
HasWritePermission = true
|
||||||
|
};
|
||||||
|
|
||||||
|
AddItemWithSyncCheck(item, SyncedPlaylists, YoutubePlaylists);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (YoutubePlaylists, null);
|
||||||
|
}
|
||||||
|
catch (System.Net.Http.HttpRequestException)
|
||||||
|
{
|
||||||
|
return (null, "Error"); //Should handle precise error here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This method return all youtube playlists saved by the user and process synced playlist if you give an array of know youtube synced playlists
|
||||||
|
* The YoutubePlaylists array should contains the synced playlist availables. Warning, this will return your initial array (proceded if there is synced playlist) + saved playlists
|
||||||
|
* The second outputed var (the string) is the error message that should be displayed to the user (the list will be null if there is an error)*/
|
||||||
|
public static async Task<(List<PlaylistItem>, string)> GetSavedYoutubePlaylists(List<PlaylistItem> SyncedPlaylists)
|
||||||
|
{
|
||||||
|
if (!await MainActivity.instance.WaitForYoutube())
|
||||||
|
return (null, "Error"); //Should have a better error handling
|
||||||
|
|
||||||
|
List<PlaylistItem> YoutubePlaylists = new List<PlaylistItem>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
YouTubeService youtube = YoutubeEngine.youtubeService;
|
||||||
|
|
||||||
|
ChannelSectionsResource.ListRequest forkedRequest = youtube.ChannelSections.List("snippet,contentDetails");
|
||||||
|
forkedRequest.Mine = true;
|
||||||
|
ChannelSectionListResponse forkedResponse = await forkedRequest.ExecuteAsync();
|
||||||
|
|
||||||
|
foreach (ChannelSection section in forkedResponse.Items)
|
||||||
|
{
|
||||||
|
if (section.Snippet.Title == "Saved Playlists")
|
||||||
|
{
|
||||||
|
for (int i = 0; i < section.ContentDetails.Playlists.Count; i++)
|
||||||
|
{
|
||||||
|
PlaylistsResource.ListRequest plRequest = youtube.Playlists.List("snippet, contentDetails");
|
||||||
|
plRequest.Id = section.ContentDetails.Playlists[i];
|
||||||
|
PlaylistListResponse plResponse = await plRequest.ExecuteAsync();
|
||||||
|
|
||||||
|
Google.Apis.YouTube.v3.Data.Playlist playlist = plResponse.Items[i];
|
||||||
|
playlist.Kind = "youtube#saved";
|
||||||
|
PlaylistItem item = new PlaylistItem(playlist.Snippet.Title, playlist.Id, playlist, (int)playlist.ContentDetails.ItemCount)
|
||||||
|
{
|
||||||
|
Owner = playlist.Snippet.ChannelTitle,
|
||||||
|
ImageURL = playlist.Snippet.Thumbnails.High.Url,
|
||||||
|
HasWritePermission = false
|
||||||
|
};
|
||||||
|
|
||||||
|
AddItemWithSyncCheck(item, SyncedPlaylists, YoutubePlaylists);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (YoutubePlaylists, null);
|
||||||
|
}
|
||||||
|
catch (System.Net.Http.HttpRequestException)
|
||||||
|
{
|
||||||
|
return (null, "Error"); //Should handle precise error here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//All change are made here because PlaylistItem and List are classes witch mean that they will be updated automatically on the others methods
|
||||||
|
public static void AddItemWithSyncCheck(PlaylistItem item, List<PlaylistItem> SyncedPlaylists, List<PlaylistItem> YoutubePlaylists)
|
||||||
|
{
|
||||||
|
PlaylistItem syncedItem = SyncedPlaylists?.Find(x => x.YoutubeID == item.YoutubeID);
|
||||||
|
if (syncedItem != null)
|
||||||
|
{
|
||||||
|
syncedItem.Snippet = item.Snippet;
|
||||||
|
syncedItem.Count = item.Count;
|
||||||
|
}
|
||||||
|
else if (SyncedPlaylists?.Find(x => x.Name == item.Name) != null)
|
||||||
|
{
|
||||||
|
/*We couldn't find a match of a synced playlist with the exact youtube id but we found a synced playlist with the exact same name as this one (item).
|
||||||
|
* We bind them and complete the database for future calls. */
|
||||||
|
syncedItem = SyncedPlaylists.Find(x => x.Name == item.Name);
|
||||||
|
int syncIndex = SyncedPlaylists.IndexOf(syncedItem);
|
||||||
|
item.LocalID = syncedItem.LocalID;
|
||||||
|
item.SyncState = SyncState.True;
|
||||||
|
|
||||||
|
SyncedPlaylists[syncIndex] = item;
|
||||||
|
|
||||||
|
if(instance != null)
|
||||||
|
MainActivity.instance.RunOnUiThread(() => { instance.YoutubeItemSynced(item, syncIndex); });
|
||||||
|
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
SQLiteConnection db = new SQLiteConnection(System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "SyncedPlaylists.sqlite"));
|
||||||
|
db.CreateTable<PlaylistItem>();
|
||||||
|
db.InsertOrReplace(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
YoutubePlaylists.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
//We give the item and the index since the public "YoutubePlaylists" array is not updated yet.
|
||||||
|
private void YoutubeItemSynced(PlaylistItem item, int syncedPlaylistIndex)
|
||||||
|
{
|
||||||
|
/*The display order is
|
||||||
|
* - Local Header
|
||||||
|
* - Local Playlists
|
||||||
|
* - Youtube Header
|
||||||
|
* - Synced Playlists
|
||||||
|
* Since local header and local playlists are both contained in the "LocalPlaylists" array, to get the position of the syncedPlaylist,
|
||||||
|
* we need to sum the LocalPlaylists count (this sum get the position of the youtube header) and then we add the syncedPlaylistIndex.
|
||||||
|
* We need to add one for the youtube header (witch is not in the syncedplaylists array)*/
|
||||||
|
PlaylistHolder holder = (PlaylistHolder)ListView.FindViewHolderForAdapterPosition(LocalPlaylists.Count + syncedPlaylistIndex + 1);
|
||||||
|
holder.Owner.Text = item.Owner;
|
||||||
|
Picasso.With(Application.Context).Load(item.ImageURL).Placeholder(Resource.Color.background_material_dark).Resize(400, 400).CenterCrop().Into(holder.AlbumArt);
|
||||||
|
|
||||||
|
if(item.HasWritePermission)
|
||||||
|
{
|
||||||
|
holder.edit.Visibility = ViewStates.Visible;
|
||||||
|
if (MainActivity.Theme == 1)
|
||||||
|
holder.edit.SetColorFilter(Color.White);
|
||||||
|
}
|
||||||
|
|
||||||
|
holder.sync.SetImageResource(Resource.Drawable.Sync);
|
||||||
|
holder.sync.Visibility = ViewStates.Visible;
|
||||||
|
holder.SyncLoading.Visibility = ViewStates.Gone;
|
||||||
|
if (MainActivity.Theme == 1)
|
||||||
|
holder.sync.SetColorFilter(Color.White);
|
||||||
|
}
|
||||||
|
|
||||||
public static Fragment NewInstance()
|
public static Fragment NewInstance()
|
||||||
{
|
{
|
||||||
if(instance == null)
|
if(instance == null)
|
||||||
|
|||||||
Reference in New Issue
Block a user