mirror of
https://github.com/zoriya/Opus.git
synced 2026-06-03 06:25:31 +00:00
Start reworking add to playlits, now working prety well with local playlists.
This commit is contained in:
@@ -259,6 +259,7 @@
|
||||
<Compile Include="Resources\Portable Class\AccountPreference.cs" />
|
||||
<Compile Include="Resources\Portable Class\AccountTarget.cs" />
|
||||
<Compile Include="Resources\Portable Class\Adapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\AddToPlaylistAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\AudioStopper.cs" />
|
||||
<Compile Include="Resources\Portable Class\Browse.cs" />
|
||||
<Compile Include="Resources\Portable Class\ChannelAdapter.cs" />
|
||||
@@ -734,6 +735,12 @@
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\Filter.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\layout\AddToPlaylistItem.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\drawable\PublicIcon.xml" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
<Import Project="..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.25.4.0.2\build\MonoAndroid70\Xamarin.Android.Support.Animated.Vector.Drawable.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.25.4.0.2\build\MonoAndroid70\Xamarin.Android.Support.Animated.Vector.Drawable.targets')" />
|
||||
<Import Project="..\packages\Xamarin.Android.Support.v7.Preference.25.4.0.2\build\MonoAndroid70\Xamarin.Android.Support.v7.Preference.targets" Condition="Exists('..\packages\Xamarin.Android.Support.v7.Preference.25.4.0.2\build\MonoAndroid70\Xamarin.Android.Support.v7.Preference.targets')" />
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
using Android.App;
|
||||
using Android.Graphics;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
public class AddToPlaylistAdapter : RecyclerView.Adapter
|
||||
{
|
||||
private List<PlaylistItem> LocalPlaylists = new List<PlaylistItem>();
|
||||
private List<PlaylistItem> YoutubePlaylists = new List<PlaylistItem>();
|
||||
public event EventHandler<int> ItemClick;
|
||||
|
||||
public AddToPlaylistAdapter(List<PlaylistItem> LocalPlaylists, List<PlaylistItem> YoutubePlaylists)
|
||||
{
|
||||
this.LocalPlaylists = LocalPlaylists;
|
||||
this.YoutubePlaylists = YoutubePlaylists;
|
||||
}
|
||||
|
||||
public override int ItemCount => LocalPlaylists.Count + YoutubePlaylists.Count;
|
||||
|
||||
public override void OnBindViewHolder(RecyclerView.ViewHolder viewHolder, int position)
|
||||
{
|
||||
if (position >= LocalPlaylists.Count && YoutubePlaylists[position - LocalPlaylists.Count].Name == "Loading" && YoutubePlaylists[position - LocalPlaylists.Count].YoutubeID == null)
|
||||
return;
|
||||
|
||||
AddToPlaylistHolder holder = (AddToPlaylistHolder)viewHolder;
|
||||
holder.Title.Text = LocalPlaylists[position].Name;
|
||||
|
||||
if((LocalPlaylists.Count > position && LocalPlaylists[position].SongContained) || (position > LocalPlaylists.Count && YoutubePlaylists[position - LocalPlaylists.Count].SongContained))
|
||||
holder.Added.Checked = true;
|
||||
else
|
||||
holder.Added.Checked = false;
|
||||
|
||||
|
||||
if ((LocalPlaylists.Count > position && LocalPlaylists[position].SyncState == SyncState.True) || (position > LocalPlaylists.Count && YoutubePlaylists[position - LocalPlaylists.Count].SyncState == SyncState.True))
|
||||
{
|
||||
holder.Status.Visibility = ViewStates.Visible;
|
||||
holder.Status.SetImageResource(Resource.Drawable.Sync);
|
||||
}
|
||||
else if(position >= LocalPlaylists.Count)
|
||||
{
|
||||
holder.Status.Visibility = ViewStates.Visible;
|
||||
holder.Status.SetImageResource(Resource.Drawable.PublicIcon);
|
||||
}
|
||||
else
|
||||
{
|
||||
holder.Status.Visibility = ViewStates.Gone;
|
||||
}
|
||||
|
||||
if (MainActivity.Theme == 1)
|
||||
{
|
||||
holder.Status.SetColorFilter(Color.White);
|
||||
holder.Title.SetTextColor(Color.White);
|
||||
}
|
||||
}
|
||||
|
||||
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
|
||||
{
|
||||
if (viewType == 0)
|
||||
{
|
||||
View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.AddToPlaylistItem, parent, false);
|
||||
return new AddToPlaylistHolder(itemView, OnClick);
|
||||
}
|
||||
else
|
||||
{
|
||||
View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.smallLoading, parent, false);
|
||||
return new UslessHolder(itemView);
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetItemViewType(int position)
|
||||
{
|
||||
if (position == LocalPlaylists.Count + YoutubePlaylists.Count - 1 && YoutubePlaylists[position - LocalPlaylists.Count].Name == "Loading")
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OnClick(int position)
|
||||
{
|
||||
ItemClick?.Invoke(this, position);
|
||||
}
|
||||
}
|
||||
|
||||
public class AddToPlaylistHolder : RecyclerView.ViewHolder
|
||||
{
|
||||
public TextView Title;
|
||||
public CheckBox Added;
|
||||
public ImageView Status;
|
||||
|
||||
public AddToPlaylistHolder(View itemView, Action<int> listener) : base(itemView)
|
||||
{
|
||||
Title = itemView.FindViewById<TextView>(Resource.Id.title);
|
||||
Added = itemView.FindViewById<CheckBox>(Resource.Id.added);
|
||||
Status = itemView.FindViewById<ImageView>(Resource.Id.status);
|
||||
|
||||
itemView.Click += (sender, e) => listener(AdapterPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,10 @@ using Android.Database;
|
||||
using Android.Net;
|
||||
using Android.OS;
|
||||
using Android.Provider;
|
||||
using Android.Support.Design.Widget;
|
||||
using Android.Support.V4.App;
|
||||
using Android.Support.V7.App;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using MusicApp.Resources.values;
|
||||
@@ -81,7 +83,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
musicList = new List<Song>();
|
||||
|
||||
Android.Net.Uri musicUri = MediaStore.Audio.Media.ExternalContentUri;
|
||||
Uri musicUri = MediaStore.Audio.Media.ExternalContentUri;
|
||||
|
||||
CursorLoader cursorLoader = new CursorLoader(Android.App.Application.Context, musicUri, null, null, null, null);
|
||||
ICursor musicCursor = (ICursor)cursorLoader.LoadInBackground();
|
||||
@@ -327,12 +329,30 @@ namespace MusicApp.Resources.Portable_Class
|
||||
context.StartService(intent);
|
||||
}
|
||||
|
||||
public static bool SongIsContained(long audioID, long playlistID)
|
||||
{
|
||||
Uri uri = MediaStore.Audio.Playlists.Members.GetContentUri("external", playlistID);
|
||||
CursorLoader loader = new CursorLoader(Android.App.Application.Context, uri, null, null, null, null);
|
||||
ICursor cursor = (ICursor)loader.LoadInBackground();
|
||||
|
||||
if (cursor != null && cursor.MoveToFirst())
|
||||
{
|
||||
int idColumn = cursor.GetColumnIndex(MediaStore.Audio.Playlists.Members.AudioId);
|
||||
do
|
||||
{
|
||||
long id = cursor.GetLong(idColumn);
|
||||
if (id == audioID)
|
||||
return true;
|
||||
}
|
||||
while (cursor.MoveToNext());
|
||||
cursor.Close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void GetPlaylist(Song item)
|
||||
{
|
||||
List<string> playList = new List<string>();
|
||||
List<long> playListId = new List<long>();
|
||||
playList.Add("Create a playlist");
|
||||
playListId.Add(0);
|
||||
List<PlaylistItem> LocalPlaylists = new List<PlaylistItem>();
|
||||
|
||||
Uri uri = MediaStore.Audio.Playlists.ExternalContentUri;
|
||||
CursorLoader loader = new CursorLoader(Android.App.Application.Context, uri, null, null, null, null);
|
||||
@@ -341,24 +361,64 @@ namespace MusicApp.Resources.Portable_Class
|
||||
if (cursor != null && cursor.MoveToFirst())
|
||||
{
|
||||
int nameID = cursor.GetColumnIndex(MediaStore.Audio.Playlists.InterfaceConsts.Name);
|
||||
int pathID = cursor.GetColumnIndex(MediaStore.Audio.Playlists.InterfaceConsts.Data);
|
||||
int playlistID = cursor.GetColumnIndex(MediaStore.Audio.Playlists.InterfaceConsts.Id);
|
||||
do
|
||||
{
|
||||
string name = cursor.GetString(nameID);
|
||||
long id = cursor.GetLong(playlistID);
|
||||
playList.Add(name);
|
||||
playListId.Add(id);
|
||||
PlaylistItem playlist = new PlaylistItem(name, id)
|
||||
{
|
||||
SongContained = SongIsContained(item.Id, id)
|
||||
};
|
||||
LocalPlaylists.Add(playlist);
|
||||
}
|
||||
while (cursor.MoveToNext());
|
||||
cursor.Close();
|
||||
}
|
||||
List<PlaylistItem> YoutubePlaylists = new List<PlaylistItem>
|
||||
{
|
||||
new PlaylistItem("Loading", null)
|
||||
};
|
||||
|
||||
View Layout = inflater.Inflate(Resource.Layout.RecyclerFragment, null);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(act, MainActivity.dialogTheme);
|
||||
builder.SetTitle("Add to a playlist");
|
||||
builder.SetItems(playList.ToArray(), (senderAlert, args) =>
|
||||
builder.SetView(Layout);
|
||||
RecyclerView ListView = Layout.FindViewById<RecyclerView>(Resource.Id.recycler);
|
||||
ListView.SetPadding(0, MainActivity.instance.DpToPx(5), 0, 0);
|
||||
ListView.SetLayoutManager(new LinearLayoutManager(MainActivity.instance));
|
||||
AddToPlaylistAdapter adapter = new AddToPlaylistAdapter(LocalPlaylists, YoutubePlaylists);
|
||||
ListView.SetAdapter(adapter);
|
||||
adapter.ItemClick += async (sender, position) =>
|
||||
{
|
||||
AddToPlaylist(item, playList[args.Which], playListId[args.Which]);
|
||||
});
|
||||
AddToPlaylistHolder holder = (AddToPlaylistHolder)ListView.GetChildViewHolder(ListView.GetChildAt(position));
|
||||
bool add = !holder.Added.Checked;
|
||||
holder.Added.Checked = add;
|
||||
|
||||
bool Local = position < LocalPlaylists.Count;
|
||||
PlaylistItem playlist = Local ? LocalPlaylists[position] : YoutubePlaylists[position - LocalPlaylists.Count];
|
||||
if (add)
|
||||
{
|
||||
if (Local)
|
||||
AddToPlaylist(item, playlist.Name, playlist.LocalID);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (playlist.SyncState == SyncState.True && playlist.YoutubeID != null && playlist.LocalID != 0)
|
||||
{
|
||||
if (item.TrackID == null)
|
||||
item = await PlaylistTracks.CompleteItem(item, playlist.YoutubeID);
|
||||
}
|
||||
SnackbarCallback callback = new SnackbarCallback(item, playlist.LocalID);
|
||||
|
||||
Snackbar snackBar = Snackbar.Make(MainActivity.instance.FindViewById(Resource.Id.snackBar), (item.Title.Length > 20 ? item.Title.Substring(0, 17) + "..." : item.Title) + " has been removed from the playlist.", Snackbar.LengthLong)
|
||||
.SetAction("Undo", (v) => { callback.canceled = true; });
|
||||
snackBar.AddCallback(callback);
|
||||
snackBar.View.FindViewById<TextView>(Resource.Id.snackbar_text).SetTextColor(Android.Graphics.Color.White);
|
||||
snackBar.Show();
|
||||
}
|
||||
};
|
||||
builder.Show();
|
||||
}
|
||||
|
||||
|
||||
@@ -299,7 +299,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
base.OnStop();
|
||||
}
|
||||
|
||||
private async Task<Song> CompleteItem(Song song)
|
||||
public static async Task<Song> CompleteItem(Song song, string YoutubeID)
|
||||
{
|
||||
if (song.youtubeID == null)
|
||||
song = Browse.CompleteItem(song);
|
||||
@@ -484,14 +484,15 @@ namespace MusicApp.Resources.Portable_Class
|
||||
int titleID = musicCursor.GetColumnIndex(Media.InterfaceConsts.Title);
|
||||
int artistID = musicCursor.GetColumnIndex(Media.InterfaceConsts.Artist);
|
||||
int albumID = musicCursor.GetColumnIndex(Media.InterfaceConsts.Album);
|
||||
int thisID = musicCursor.GetColumnIndex(Media.InterfaceConsts.Id);
|
||||
int albumArtID = musicCursor.GetColumnIndex(Albums.InterfaceConsts.AlbumId);
|
||||
int thisID = musicCursor.GetColumnIndex(Playlists.Members.AudioId);
|
||||
int pathID = musicCursor.GetColumnIndex(Media.InterfaceConsts.Data);
|
||||
do
|
||||
{
|
||||
string Artist = musicCursor.GetString(artistID);
|
||||
string Title = musicCursor.GetString(titleID);
|
||||
string Album = musicCursor.GetString(albumID);
|
||||
long AlbumArt = musicCursor.GetLong(musicCursor.GetColumnIndex(Albums.InterfaceConsts.AlbumId));
|
||||
long AlbumArt = musicCursor.GetLong(albumArtID);
|
||||
long id = musicCursor.GetLong(thisID);
|
||||
string path = musicCursor.GetString(pathID);
|
||||
|
||||
@@ -697,7 +698,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
builder.SetTitle("Pick an action");
|
||||
if (hasWriteAcess && YoutubeID != "")
|
||||
{
|
||||
builder.SetItems(action.ToArray(), async (senderAlert, args) =>
|
||||
builder.SetItems(action.ToArray(), (senderAlert, args) =>
|
||||
{
|
||||
switch (args.Which)
|
||||
{
|
||||
@@ -720,20 +721,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if(Synced && LocalID != 0)
|
||||
{
|
||||
RemoveFromPlaylist(item);
|
||||
if (item.TrackID == null)
|
||||
item = await CompleteItem(item);
|
||||
YoutubeEngine.RemoveFromPlaylist(item.TrackID);
|
||||
}
|
||||
else if (LocalID != 0)
|
||||
RemoveFromPlaylist(item);
|
||||
else if(YoutubeID != null)
|
||||
{
|
||||
YoutubeEngine.RemoveFromPlaylist(item.TrackID);
|
||||
RemoveFromYtPlaylist(item, item.TrackID);
|
||||
}
|
||||
DeleteDialog(position);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
@@ -910,9 +898,9 @@ namespace MusicApp.Resources.Portable_Class
|
||||
if(Synced && YoutubeID != null && LocalID != 0)
|
||||
{
|
||||
if (song.TrackID == null)
|
||||
song = await CompleteItem(song);
|
||||
song = await CompleteItem(song, YoutubeID);
|
||||
}
|
||||
SnackbarCallback callback = new SnackbarCallback(position, song, LocalID);
|
||||
SnackbarCallback callback = new SnackbarCallback(song, LocalID);
|
||||
|
||||
Snackbar snackBar = Snackbar.Make(MainActivity.instance.FindViewById(Resource.Id.snackBar), (song.Title.Length > 20 ? song.Title.Substring(0, 17) + "..." : song.Title) + " has been removed from the playlist.", Snackbar.LengthLong)
|
||||
.SetAction("Undo", (v) =>
|
||||
@@ -926,7 +914,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
adapter.Insert(position, song);
|
||||
tracks.Insert(position, song);
|
||||
}
|
||||
if (LocalID != 0)
|
||||
else if (LocalID != 0)
|
||||
{
|
||||
adapter.Insert(position, song);
|
||||
tracks.Insert(position, song);
|
||||
|
||||
@@ -8,14 +8,12 @@ namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
public class SnackbarCallback : BaseTransientBottomBar.BaseCallback
|
||||
{
|
||||
private int position;
|
||||
private Song song;
|
||||
private long playlistId;
|
||||
public bool canceled = false;
|
||||
|
||||
public SnackbarCallback(int position, Song song, long playlistId)
|
||||
public SnackbarCallback(Song song, long playlistId)
|
||||
{
|
||||
this.position = position;
|
||||
this.song = song;
|
||||
this.playlistId = playlistId;
|
||||
}
|
||||
@@ -33,7 +31,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
ContentResolver resolver = MainActivity.instance.ContentResolver;
|
||||
Uri uri = MediaStore.Audio.Playlists.Members.GetContentUri("external", playlistId);
|
||||
resolver.Delete(uri, MediaStore.Audio.Playlists.Members.Id + "=?", new string[] { song.Id.ToString() });
|
||||
resolver.Delete(uri, MediaStore.Audio.Playlists.Members.AudioId + "=?", new string[] { song.Id.ToString() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+522
-513
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M0 0h24v24H0z" />
|
||||
<path
|
||||
android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"
|
||||
android:fillColor="#000000" />
|
||||
</vector>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="3dp" >
|
||||
<CheckBox
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="5dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:id="@+id/added" />
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/title"
|
||||
android:textSize="14dip"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@id/added"
|
||||
android:layout_toLeftOf="@+id/status" />
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@null"
|
||||
android:id="@+id/status"
|
||||
android:paddingRight="5dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentRight="true" />
|
||||
</RelativeLayout>
|
||||
@@ -16,6 +16,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
public string ImageURL { get; set; }
|
||||
public bool HasWritePermission { get; set; }
|
||||
public SyncState SyncState = SyncState.False;
|
||||
public bool SongContained; //For AddToPlaylist dialog
|
||||
|
||||
public PlaylistItem() { }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user