mirror of
https://github.com/zoriya/Opus.git
synced 2025-12-06 06:26:15 +00:00
creating the player
This commit is contained in:
@@ -11,6 +11,7 @@ using Android.Widget;
|
||||
using Android.Content;
|
||||
|
||||
using SearchView = Android.Support.V7.Widget.SearchView;
|
||||
using static Android.App.ActivityManager;
|
||||
|
||||
namespace MusicApp
|
||||
{
|
||||
@@ -183,7 +184,14 @@ namespace MusicApp
|
||||
case Resource.Id.musicLayout:
|
||||
HideTabs();
|
||||
HideSearch();
|
||||
if (MusicPlayer.isRunning)
|
||||
{
|
||||
fragment = Player.NewInstance();
|
||||
break;
|
||||
}
|
||||
if(fragment == null)
|
||||
fragment = Queue.NewInstance();
|
||||
|
||||
break;
|
||||
|
||||
case Resource.Id.browseLayout:
|
||||
|
||||
@@ -136,6 +136,9 @@
|
||||
<Reference Include="YoutubeExplode, Version=3.2.5.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\YoutubeExplode.3.2.5\lib\netstandard1.1\YoutubeExplode.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="YoutubeExtractor, Version=0.10.11.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\YoutubeExtractor.0.10.11\lib\portable-net45+win8+wpa81+wp8\YoutubeExtractor.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="YoutubeSearch, Version=0.1.1.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\YoutubeSearch.dll.1.1\lib\YoutubeSearch.dll</HintPath>
|
||||
</Reference>
|
||||
@@ -154,6 +157,7 @@
|
||||
<Compile Include="Resources\Portable Class\FolderBrowse.cs" />
|
||||
<Compile Include="Resources\Portable Class\FolderTracks.cs" />
|
||||
<Compile Include="Resources\Portable Class\MusicPlayer.cs" />
|
||||
<Compile Include="Resources\Portable Class\Player.cs" />
|
||||
<Compile Include="Resources\Portable Class\Playlist.cs" />
|
||||
<Compile Include="Resources\Portable Class\PlaylistTracks.cs" />
|
||||
<Compile Include="Resources\Portable Class\Preferences.cs" />
|
||||
@@ -332,6 +336,12 @@
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\layout\PreferenceToolbar.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\anim\SlideInUp.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\anim\SlideOutUp.xml" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -2,18 +2,15 @@
|
||||
using Android.OS;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Android.Support.V7.App;
|
||||
using Android.Support.V4.App;
|
||||
using System.Collections.Generic;
|
||||
using Android.Provider;
|
||||
using Android.Database;
|
||||
using Android.Content.PM;
|
||||
using Android.Support.Design.Widget;
|
||||
using Android;
|
||||
using Android.Net;
|
||||
using YoutubeSearch;
|
||||
using MusicApp.Resources.values;
|
||||
using Android.Support.V7.Preferences;
|
||||
using YoutubeExtractor;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
@@ -88,10 +85,30 @@ namespace MusicApp.Resources.Portable_Class
|
||||
ListAdapter = new Adapter(Android.App.Application.Context, Resource.Layout.SongList, list);
|
||||
}
|
||||
|
||||
private void ListView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
|
||||
private /*async*/ void ListView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
|
||||
{
|
||||
Toast.MakeText(Android.App.Application.Context, "Play: comming soon", ToastLength.Short).Show();
|
||||
//await Task.Run(() =>
|
||||
//{
|
||||
Toast.MakeText(Android.App.Application.Context, "Playing : " + list[e.Position].GetPath(), ToastLength.Short).Show();
|
||||
IEnumerable<VideoInfo> videoInfos = DownloadUrlResolver.GetDownloadUrls(list[e.Position].GetPath(), false);
|
||||
//VideoInfo video = videoInfos.Where(info => info.VideoType == VideoType.Mp4 && info.Resolution == 0).OrderByDescending(info => info.AudioBitrate).First();
|
||||
VideoInfo video = videoInfos.Where(info => info.AudioBitrate > 0 && info.AdaptiveType == AdaptiveType.Audio).OrderByDescending(info => info.AudioBitrate).First();
|
||||
|
||||
if (video.RequiresDecryption)
|
||||
{
|
||||
DownloadUrlResolver.DecryptDownloadUrl(video);
|
||||
}
|
||||
|
||||
System.Console.WriteLine(video.DownloadUrl);
|
||||
|
||||
Song song = list[e.Position];
|
||||
|
||||
Intent intent = new Intent(Android.App.Application.Context, typeof(MusicPlayer));
|
||||
intent.SetAction("YTPlay");
|
||||
intent.PutExtra("file", video.DownloadUrl);
|
||||
intent.PutStringArrayListExtra("song", new string[] { song.GetName(), song.GetArtist(), song.GetAlbum() });
|
||||
Activity.StartService(intent);
|
||||
//});
|
||||
}
|
||||
|
||||
private void ListView_ItemLongClick(object sender, AdapterView.ItemLongClickEventArgs e)
|
||||
|
||||
@@ -16,6 +16,7 @@ using Square.Picasso;
|
||||
|
||||
using Uri = Android.Net.Uri;
|
||||
using FileNotFoundException = System.IO.FileNotFoundException;
|
||||
using Android.Widget;
|
||||
|
||||
namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
@@ -27,6 +28,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
public MediaSessionCompat mediaSession;
|
||||
public AudioManager audioManager;
|
||||
public NotificationManager notificationManager;
|
||||
public static bool isRunning = false;
|
||||
public static string title;
|
||||
|
||||
private Notification notification;
|
||||
@@ -84,6 +86,15 @@ namespace MusicApp.Resources.Portable_Class
|
||||
if (player.IsPlaying)
|
||||
Pause();
|
||||
break;
|
||||
case "YTPlay":
|
||||
string[] song = intent.GetStringArrayListExtra("song").ToArray();
|
||||
Console.WriteLine(song.Length);
|
||||
Console.WriteLine(song[0]);
|
||||
Console.WriteLine(song[1]);
|
||||
Console.WriteLine(song[2]);
|
||||
|
||||
PlayFromYT(file, song[0], song[1], song[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (intent.Action != null)
|
||||
@@ -120,6 +131,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
|
||||
public async void Play(string filePath)
|
||||
{
|
||||
isRunning = true;
|
||||
if (player == null)
|
||||
InitializeService();
|
||||
|
||||
@@ -161,6 +173,52 @@ namespace MusicApp.Resources.Portable_Class
|
||||
}
|
||||
}
|
||||
|
||||
public async void PlayFromYT(string url, string title, string artist, string imageURL)
|
||||
{
|
||||
isRunning = true;
|
||||
if (player == null)
|
||||
InitializeService();
|
||||
|
||||
if (mediaSession != null)
|
||||
{
|
||||
player.Reset();
|
||||
InitializePlayer();
|
||||
await player.SetDataSourceAsync(Application.Context, Uri.Parse(url));
|
||||
player.PrepareAsync();
|
||||
CreateNotification(title, artist, 0, imageURL);
|
||||
|
||||
queue.Clear();
|
||||
Song item = new Song(title, artist, imageURL, -1, 1, url);
|
||||
queue.Add(item);
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
mediaSession = new MediaSessionCompat(Application.Context, "MusicApp");
|
||||
mediaSession.SetFlags(MediaSessionCompat.FlagHandlesMediaButtons | MediaSessionCompat.FlagHandlesTransportControls);
|
||||
PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder().SetActions(PlaybackStateCompat.ActionPlay | PlaybackStateCompat.ActionPause);
|
||||
mediaSession.SetPlaybackState(builder.Build());
|
||||
|
||||
await player.SetDataSourceAsync(Application.Context, Uri.Parse(url));
|
||||
var audioFocus = audioManager.RequestAudioFocus(this, Stream.Music, AudioFocus.Gain);
|
||||
if (audioFocus != AudioFocusRequest.Granted)
|
||||
{
|
||||
Console.WriteLine("Can't Get Audio Focus");
|
||||
return;
|
||||
}
|
||||
player.PrepareAsync();
|
||||
CreateNotification(title, artist, 0, imageURL);
|
||||
|
||||
queue.Clear();
|
||||
Song item = new Song(title, artist, imageURL, -1, 1, url);
|
||||
queue.Add(item);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
public async void RandomPlay(List<string> filePath)
|
||||
{
|
||||
Random r = new Random();
|
||||
@@ -215,7 +273,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
player.Reset();
|
||||
InitializePlayer();
|
||||
await player.SetDataSourceAsync(Application.Context, Android.Net.Uri.Parse(filePath));
|
||||
await player.SetDataSourceAsync(Application.Context, Uri.Parse(filePath));
|
||||
player.PrepareAsync();
|
||||
GetTrackSong(filePath, out Song song);
|
||||
CreateNotification(song.GetName(), song.GetArtist(), song.GetAlbumArt());
|
||||
@@ -281,13 +339,15 @@ namespace MusicApp.Resources.Portable_Class
|
||||
song = new Song(Title, Artist, Album, AlbumArt, id, path);
|
||||
}
|
||||
|
||||
async void CreateNotification(string title, string artist, long albumArt)
|
||||
async void CreateNotification(string title, string artist, long albumArt = 0, string imageURI = "")
|
||||
{
|
||||
MusicPlayer.title = title;
|
||||
Bitmap icon = null;
|
||||
|
||||
if (albumArt != 0)
|
||||
{
|
||||
Uri songCover = Uri.Parse("content://media/external/audio/albumart");
|
||||
Uri iconURI = ContentUris.WithAppendedId(songCover, albumArt);
|
||||
Bitmap icon = null;
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
@@ -300,6 +360,14 @@ namespace MusicApp.Resources.Portable_Class
|
||||
icon = Picasso.With(Application.Context).Load(Resource.Drawable.MusicIcon).Get();
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
icon = Picasso.With(Application.Context).Load(imageURI).Get();
|
||||
});
|
||||
}
|
||||
|
||||
Intent tmpPreviusIntent = new Intent(Application.Context, typeof(MusicPlayer));
|
||||
tmpPreviusIntent.SetAction("Previus");
|
||||
@@ -344,6 +412,11 @@ namespace MusicApp.Resources.Portable_Class
|
||||
|
||||
player.Pause();
|
||||
StopForeground(false);
|
||||
|
||||
if(Player.instance != null)
|
||||
{
|
||||
Player.instance.playerView.FindViewById<ImageButton>(Resource.Id.playButton).SetImageResource(Resource.Drawable.ic_play_arrow_black_24dp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,11 +432,17 @@ namespace MusicApp.Resources.Portable_Class
|
||||
|
||||
player.Start();
|
||||
StartForeground(notificationID, notification);
|
||||
|
||||
if (Player.instance != null)
|
||||
{
|
||||
Player.instance.playerView.FindViewById<ImageButton>(Resource.Id.playButton).SetImageResource(Resource.Drawable.ic_pause_black_24dp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
isRunning = false;
|
||||
if(player != null)
|
||||
{
|
||||
if (player.IsPlaying)
|
||||
@@ -409,6 +488,8 @@ namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
isRunning = false;
|
||||
|
||||
if (player != null)
|
||||
player.Release();
|
||||
}
|
||||
|
||||
151
MusicApp/Resources/Portable Class/Player.cs
Normal file
151
MusicApp/Resources/Portable Class/Player.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using MusicApp.Resources.values;
|
||||
using Android.Support.V4.App;
|
||||
using System;
|
||||
using Square.Picasso;
|
||||
using Android.Graphics;
|
||||
using Android.Support.Design.Widget;
|
||||
using MusicApp.Resources.Fragments;
|
||||
using Android.Transitions;
|
||||
using Android.Animation;
|
||||
using Android.App.Job;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using Android.Support.V7.App;
|
||||
|
||||
namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
public class Player : Fragment
|
||||
{
|
||||
public static Player instance;
|
||||
public View playerView;
|
||||
|
||||
private View view;
|
||||
private ImageView imgView;
|
||||
private CancellationTokenSource cancelToken;
|
||||
private int[] timers = new int[] { 0, 1, 10, 30, 60, 120 };
|
||||
private string[] items = new string[] { "Off", "1 minute", "10 minutes", "30 minutes", "1 hour", "2 hours" };
|
||||
private int checkedItem = 0;
|
||||
|
||||
|
||||
public override void OnActivityCreated(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnActivityCreated(savedInstanceState);
|
||||
}
|
||||
|
||||
public override void OnDestroy()
|
||||
{
|
||||
MainActivity.instance.ToolBar.Visibility = ViewStates.Visible;
|
||||
base.OnDestroy();
|
||||
instance = null;
|
||||
}
|
||||
|
||||
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
var useless = base.OnCreateView(inflater, container, savedInstanceState);
|
||||
playerView = LayoutInflater.Inflate(Resource.Layout.player, null);
|
||||
CreatePlayer();
|
||||
return playerView;
|
||||
}
|
||||
|
||||
public static Fragment NewInstance()
|
||||
{
|
||||
instance = new Player { Arguments = new Bundle() };
|
||||
return instance;
|
||||
}
|
||||
|
||||
void CreatePlayer()
|
||||
{
|
||||
MainActivity.instance.ToolBar.Visibility = ViewStates.Gone;
|
||||
MainActivity.instance.FindViewById<BottomNavigationView>(Resource.Id.bottomView).Visibility = ViewStates.Gone;
|
||||
TextView title = playerView.FindViewById<TextView>(Resource.Id.playerTitle);
|
||||
TextView artist = playerView.FindViewById<TextView>(Resource.Id.playerArtist);
|
||||
imgView = playerView.FindViewById<ImageView>(Resource.Id.playerAlbum);
|
||||
playerView.FindViewById<ImageButton>(Resource.Id.playerSleep).Click += SleepButton_Click;
|
||||
playerView.FindViewById<ImageButton>(Resource.Id.lastButton).Click += Last_Click;
|
||||
playerView.FindViewById<ImageButton>(Resource.Id.playButton).Click += Play_Click;
|
||||
playerView.FindViewById<ImageButton>(Resource.Id.nextButton).Click += Next_Click;
|
||||
playerView.FindViewById<FloatingActionButton>(Resource.Id.downFAB).Click += Fab_Click;
|
||||
|
||||
|
||||
Song current = MusicPlayer.queue[MusicPlayer.CurentID()];
|
||||
|
||||
title.Text = current.GetName();
|
||||
artist.Text = current.GetArtist();
|
||||
title.Selected = true;
|
||||
title.SetMarqueeRepeatLimit(3);
|
||||
artist.Selected = true;
|
||||
artist.SetMarqueeRepeatLimit(3);
|
||||
|
||||
var songCover = Android.Net.Uri.Parse("content://media/external/audio/albumart");
|
||||
var songAlbumArtUri = ContentUris.WithAppendedId(songCover, current.GetAlbumArt());
|
||||
|
||||
Picasso.With(Android.App.Application.Context).Load(songAlbumArtUri).Placeholder(Resource.Drawable.MusicIcon).Into(imgView);
|
||||
}
|
||||
|
||||
private void Fab_Click(object sender, EventArgs e)
|
||||
{
|
||||
Activity.SupportFragmentManager.BeginTransaction()./*SetCustomAnimations(Resource.Animation.SlideInUp, Resource.Animation.SlideOutUp)/*/Replace(Resource.Id.contentView, Queue.NewInstance()).Commit();
|
||||
}
|
||||
|
||||
private void Last_Click(object sender, EventArgs e)
|
||||
{
|
||||
Intent intent = new Intent(Android.App.Application.Context, typeof(MusicPlayer));
|
||||
intent.SetAction("Previus");
|
||||
Activity.StartService(intent);
|
||||
}
|
||||
|
||||
private void Play_Click(object sender, EventArgs e)
|
||||
{
|
||||
Intent intent = new Intent(Android.App.Application.Context, typeof(MusicPlayer));
|
||||
intent.SetAction("Pause");
|
||||
Activity.StartService(intent);
|
||||
}
|
||||
|
||||
private void Next_Click(object sender, EventArgs e)
|
||||
{
|
||||
Intent intent = new Intent(Android.App.Application.Context, typeof(MusicPlayer));
|
||||
intent.SetAction("Next");
|
||||
Activity.StartService(intent);
|
||||
}
|
||||
|
||||
private void SleepButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(Activity, Resource.Style.AppCompatAlertDialogStyle);
|
||||
builder.SetTitle("Sleep in :");
|
||||
builder.SetSingleChoiceItems(items, checkedItem, ((senders, eventargs) => { checkedItem = eventargs.Which; }));
|
||||
builder.SetPositiveButton("Ok", ((senders, args) => { Sleep(timers[checkedItem]); }));
|
||||
builder.SetNegativeButton("Cancel", ((senders, args) => { }));
|
||||
builder.Show();
|
||||
}
|
||||
|
||||
async void Sleep(int time)
|
||||
{
|
||||
cancelToken?.Cancel();
|
||||
|
||||
if (time == 0)
|
||||
return;
|
||||
|
||||
using (cancelToken = new CancellationTokenSource())
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
Thread.Sleep(time * 60 * 1000);
|
||||
Intent intent = new Intent(Android.App.Application.Context, typeof(MusicPlayer));
|
||||
intent.SetAction("Stop");
|
||||
Activity.StartService(intent);
|
||||
});
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
Console.WriteLine("Sleep Timer Canceled");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,23 +18,37 @@ using Android.Support.V7.App;
|
||||
|
||||
namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
public class Queue: ListFragment
|
||||
public class Queue: ListFragment/*, ViewTreeObserver.IOnPreDrawListener*/
|
||||
{
|
||||
public static Queue instance;
|
||||
public Adapter adapter;
|
||||
public View emptyView;
|
||||
|
||||
private View view;
|
||||
private ImageView imgView;
|
||||
private View playerView;
|
||||
private View controllerView;
|
||||
private bool isEmpty = false;
|
||||
private CancellationTokenSource cancelToken;
|
||||
private int[] timers = new int[] { 0, 1, 10, 30, 60, 120 };
|
||||
private string[] items = new string[] { "Off", "1 minute", "10 minutes", "30 minutes", "1 hour", "2 hours" };
|
||||
private int checkedItem = 0;
|
||||
//private float yFraction = 0;
|
||||
|
||||
|
||||
//public void SetYFraction(float fraction)
|
||||
//{
|
||||
// yFraction = fraction;
|
||||
|
||||
// float translationY = View.Height * fraction;
|
||||
// View.TranslationY = translationY;
|
||||
//}
|
||||
|
||||
//public bool OnPreDraw()
|
||||
//{
|
||||
// if(View.Height == 0)
|
||||
// SetYFraction(yFraction);
|
||||
// return true;
|
||||
//}
|
||||
|
||||
//public float GetYFraction()
|
||||
//{
|
||||
// return yFraction;
|
||||
//}
|
||||
|
||||
public override void OnActivityCreated(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnActivityCreated(savedInstanceState);
|
||||
@@ -48,6 +62,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
public override void OnDestroy()
|
||||
{
|
||||
MainActivity.instance.ToolBar.Visibility = ViewStates.Visible;
|
||||
MainActivity.instance.FindViewById<BottomNavigationView>(Resource.Id.bottomView).Visibility = ViewStates.Visible;
|
||||
if (isEmpty)
|
||||
{
|
||||
ViewGroup rootView = Activity.FindViewById<ViewGroup>(Android.Resource.Id.Content);
|
||||
@@ -61,6 +76,7 @@ namespace MusicApp.Resources.Portable_Class
|
||||
{
|
||||
View view = base.OnCreateView(inflater, container, savedInstanceState);
|
||||
this.view = view;
|
||||
view.SetPadding(0, 100, 0, 100);
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -85,166 +101,6 @@ namespace MusicApp.Resources.Portable_Class
|
||||
isEmpty = true;
|
||||
Activity.AddContentView(emptyView, View.LayoutParameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainActivity.instance.ToolBar.Visibility = ViewStates.Gone;
|
||||
playerView = LayoutInflater.Inflate(Resource.Layout.player, null);
|
||||
TextView title = playerView.FindViewById<TextView>(Resource.Id.playerTitle);
|
||||
TextView artist = playerView.FindViewById<TextView>(Resource.Id.playerArtist);
|
||||
imgView = playerView.FindViewById<ImageView>(Resource.Id.playerAlbum);
|
||||
ImageButton sleepButton = playerView.FindViewById<ImageButton>(Resource.Id.playerSleep);
|
||||
sleepButton.Click += SleepButton_Click;
|
||||
|
||||
|
||||
Song current = MusicPlayer.queue[MusicPlayer.CurentID()];
|
||||
|
||||
title.Text = current.GetName();
|
||||
artist.Text = current.GetArtist();
|
||||
title.Selected = true;
|
||||
title.SetMarqueeRepeatLimit(3);
|
||||
artist.Selected = true;
|
||||
artist.SetMarqueeRepeatLimit(3);
|
||||
|
||||
var songCover = Android.Net.Uri.Parse("content://media/external/audio/albumart");
|
||||
var songAlbumArtUri = ContentUris.WithAppendedId(songCover, current.GetAlbumArt());
|
||||
|
||||
Picasso.With(Android.App.Application.Context).Load(songAlbumArtUri).Placeholder(Resource.Drawable.MusicIcon).Into(imgView);
|
||||
|
||||
ListView.AddHeaderView(playerView);
|
||||
|
||||
FloatingActionButton fab = playerView.FindViewById<FloatingActionButton>(Resource.Id.playFAB);
|
||||
fab.Click += Fab_Click;
|
||||
}
|
||||
}
|
||||
|
||||
private void SleepButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(Activity, Resource.Style.AppCompatAlertDialogStyle);
|
||||
builder.SetTitle("Sleep in :");
|
||||
builder.SetSingleChoiceItems(items, checkedItem, ((senders, eventargs) => { checkedItem = eventargs.Which; } ));
|
||||
builder.SetPositiveButton("Ok", ((senders, args) => { Sleep(timers[checkedItem]); } ));
|
||||
builder.SetNegativeButton("Cancel", ((senders, args) => { }));
|
||||
builder.Show();
|
||||
}
|
||||
|
||||
async void Sleep(int time)
|
||||
{
|
||||
cancelToken?.Cancel();
|
||||
|
||||
if (time == 0)
|
||||
return;
|
||||
|
||||
using (cancelToken = new CancellationTokenSource())
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
Thread.Sleep(time * 60 * 1000);
|
||||
Intent intent = new Intent(Android.App.Application.Context, typeof(MusicPlayer));
|
||||
intent.SetAction("Stop");
|
||||
Activity.StartService(intent);
|
||||
});
|
||||
}
|
||||
catch(TaskCanceledException)
|
||||
{
|
||||
Console.WriteLine("Sleep Timer Canceled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Fab_Click(object sender, EventArgs e)
|
||||
{
|
||||
playerView.FindViewById(Resource.Id.playerTitle).Visibility = ViewStates.Gone;
|
||||
playerView.FindViewById(Resource.Id.playerArtist).Visibility = ViewStates.Gone;
|
||||
FloatingActionButton fab = playerView.FindViewById<FloatingActionButton>(Resource.Id.playFAB);
|
||||
|
||||
LinearLayout layout = playerView.FindViewById<LinearLayout>(Resource.Id.infoPanel);
|
||||
layout.SetPadding(0, 15, 0, 0);
|
||||
|
||||
controllerView = LayoutInflater.Inflate(Resource.Layout.playerControl, layout, true);
|
||||
layout.SetBackgroundColor(new Color(76, 181, 174));
|
||||
|
||||
controllerView.Visibility = ViewStates.Gone;
|
||||
int centerX = controllerView.Top;
|
||||
int centerY = controllerView.Left;
|
||||
float endRadius = (float)Math.Sqrt(controllerView.Width * controllerView.Width + controllerView.Height + controllerView.Height) * 2;
|
||||
|
||||
Animator animator = ViewAnimationUtils.CreateCircularReveal(controllerView, centerX, centerY, 0, endRadius);
|
||||
animator.SetDuration(750);
|
||||
|
||||
controllerView.Visibility = ViewStates.Visible;
|
||||
animator.Start();
|
||||
|
||||
fab.Hide();
|
||||
|
||||
controllerView.FindViewById<ImageButton>(Resource.Id.controllerLast).Click += Last_Click;
|
||||
controllerView.FindViewById<ImageButton>(Resource.Id.controllerPlay).Click += Play_Click;
|
||||
controllerView.FindViewById<ImageButton>(Resource.Id.controllerNext).Click += Next_Click;
|
||||
|
||||
TextView text = controllerView.FindViewById<TextView>(Resource.Id.controllerTitle);
|
||||
string Title = playerView.FindViewById<TextView>(Resource.Id.playerTitle).Text;
|
||||
string Artist = playerView.FindViewById<TextView>(Resource.Id.playerArtist).Text;
|
||||
|
||||
text.Text = Title + " - " + Artist;
|
||||
}
|
||||
|
||||
private void CloseFab()
|
||||
{
|
||||
FloatingActionButton fab = playerView.FindViewById<FloatingActionButton>(Resource.Id.playFAB);
|
||||
|
||||
LinearLayout layout = playerView.FindViewById<LinearLayout>(Resource.Id.infoPanel);
|
||||
layout.SetBackgroundColor(new Color(43, 85, 104));
|
||||
|
||||
int centerX = layout.Top;
|
||||
int centerY = layout.Left;
|
||||
float endRadius = (float)Math.Sqrt(layout.Width * layout.Width + layout.Height + layout.Height) * 2;
|
||||
|
||||
Animator animator = ViewAnimationUtils.CreateCircularReveal(controllerView, centerX, centerY, endRadius, 0);
|
||||
animator.SetDuration(750);
|
||||
animator.AnimationEnd += Animator_AnimationEnd;
|
||||
animator.Start();
|
||||
|
||||
LinearLayout controller = playerView.FindViewById<LinearLayout>(Resource.Id.playerControl);
|
||||
controller.Visibility = ViewStates.Invisible;
|
||||
|
||||
}
|
||||
|
||||
private void Animator_AnimationEnd(object sender, EventArgs e)
|
||||
{
|
||||
FloatingActionButton fab = playerView.FindViewById<FloatingActionButton>(Resource.Id.playFAB);
|
||||
fab.Show();
|
||||
playerView.FindViewById(Resource.Id.playerTitle).Visibility = ViewStates.Visible;
|
||||
playerView.FindViewById(Resource.Id.playerArtist).Visibility = ViewStates.Visible;
|
||||
|
||||
LinearLayout layout = playerView.FindViewById<LinearLayout>(Resource.Id.infoPanel);
|
||||
layout.SetPadding(0, 15, 0, 20);
|
||||
LinearLayout controller = playerView.FindViewById<LinearLayout>(Resource.Id.playerControl);
|
||||
layout.RemoveView(controller);
|
||||
}
|
||||
|
||||
private void Last_Click(object sender, EventArgs e)
|
||||
{
|
||||
Intent intent = new Intent(Android.App.Application.Context, typeof(MusicPlayer));
|
||||
intent.SetAction("Previus");
|
||||
Activity.StartService(intent);
|
||||
CloseFab();
|
||||
}
|
||||
|
||||
private void Play_Click(object sender, EventArgs e)
|
||||
{
|
||||
Intent intent = new Intent(Android.App.Application.Context, typeof(MusicPlayer));
|
||||
intent.SetAction("Pause");
|
||||
Activity.StartService(intent);
|
||||
CloseFab();
|
||||
}
|
||||
|
||||
private void Next_Click(object sender, EventArgs e)
|
||||
{
|
||||
Intent intent = new Intent(Android.App.Application.Context, typeof(MusicPlayer));
|
||||
intent.SetAction("Next");
|
||||
Activity.StartService(intent);
|
||||
CloseFab();
|
||||
}
|
||||
|
||||
private void ListView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
|
||||
|
||||
123
MusicApp/Resources/Resource.Designer.cs
generated
123
MusicApp/Resources/Resource.Designer.cs
generated
@@ -81,6 +81,12 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f04000f
|
||||
public const int design_snackbar_out = 2130968591;
|
||||
|
||||
// aapt resource value: 0x7f040010
|
||||
public const int SlideInUp = 2130968592;
|
||||
|
||||
// aapt resource value: 0x7f040011
|
||||
public const int SlideOutUp = 2130968593;
|
||||
|
||||
static Animation()
|
||||
{
|
||||
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
|
||||
@@ -2452,8 +2458,8 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f07001e
|
||||
public const int add = 2131165214;
|
||||
|
||||
// aapt resource value: 0x7f0700b7
|
||||
public const int albumArt = 2131165367;
|
||||
// aapt resource value: 0x7f0700ba
|
||||
public const int albumArt = 2131165370;
|
||||
|
||||
// aapt resource value: 0x7f070058
|
||||
public const int alertTitle = 2131165272;
|
||||
@@ -2464,8 +2470,8 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f070023
|
||||
public const int always = 2131165219;
|
||||
|
||||
// aapt resource value: 0x7f0700b8
|
||||
public const int artist = 2131165368;
|
||||
// aapt resource value: 0x7f0700bb
|
||||
public const int artist = 2131165371;
|
||||
|
||||
// aapt resource value: 0x7f07002f
|
||||
public const int auto = 2131165231;
|
||||
@@ -2479,8 +2485,8 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f07008c
|
||||
public const int bottomView = 2131165324;
|
||||
|
||||
// aapt resource value: 0x7f0700bd
|
||||
public const int browseLayout = 2131165373;
|
||||
// aapt resource value: 0x7f0700c0
|
||||
public const int browseLayout = 2131165376;
|
||||
|
||||
// aapt resource value: 0x7f070073
|
||||
public const int browseList = 2131165299;
|
||||
@@ -2524,17 +2530,17 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f07008b
|
||||
public const int contentView = 2131165323;
|
||||
|
||||
// aapt resource value: 0x7f0700ac
|
||||
public const int controllerLast = 2131165356;
|
||||
|
||||
// aapt resource value: 0x7f0700ae
|
||||
public const int controllerNext = 2131165358;
|
||||
|
||||
// aapt resource value: 0x7f0700ad
|
||||
public const int controllerPlay = 2131165357;
|
||||
|
||||
// aapt resource value: 0x7f0700af
|
||||
public const int controllerTitle = 2131165359;
|
||||
public const int controllerLast = 2131165359;
|
||||
|
||||
// aapt resource value: 0x7f0700b1
|
||||
public const int controllerNext = 2131165361;
|
||||
|
||||
// aapt resource value: 0x7f0700b0
|
||||
public const int controllerPlay = 2131165360;
|
||||
|
||||
// aapt resource value: 0x7f0700b2
|
||||
public const int controllerTitle = 2131165362;
|
||||
|
||||
// aapt resource value: 0x7f070078
|
||||
public const int coordinator = 2131165304;
|
||||
@@ -2569,8 +2575,11 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f070012
|
||||
public const int disableHome = 2131165202;
|
||||
|
||||
// aapt resource value: 0x7f0700be
|
||||
public const int downloadLayout = 2131165374;
|
||||
// aapt resource value: 0x7f0700ad
|
||||
public const int downFAB = 2131165357;
|
||||
|
||||
// aapt resource value: 0x7f0700c1
|
||||
public const int downloadLayout = 2131165377;
|
||||
|
||||
// aapt resource value: 0x7f070066
|
||||
public const int edit_query = 2131165286;
|
||||
@@ -2629,8 +2638,8 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f070049
|
||||
public const int icon = 2131165257;
|
||||
|
||||
// aapt resource value: 0x7f0700b0
|
||||
public const int icon_frame = 2131165360;
|
||||
// aapt resource value: 0x7f0700b3
|
||||
public const int icon_frame = 2131165363;
|
||||
|
||||
// aapt resource value: 0x7f07009f
|
||||
public const int icon_group = 2131165343;
|
||||
@@ -2644,8 +2653,8 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f07009b
|
||||
public const int info = 2131165339;
|
||||
|
||||
// aapt resource value: 0x7f0700a7
|
||||
public const int infoPanel = 2131165351;
|
||||
// aapt resource value: 0x7f0700aa
|
||||
public const int infoPanel = 2131165354;
|
||||
|
||||
// aapt resource value: 0x7f070000
|
||||
public const int item_touch_helper_previous_elevation = 2131165184;
|
||||
@@ -2653,20 +2662,23 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f070076
|
||||
public const int largeLabel = 2131165302;
|
||||
|
||||
// aapt resource value: 0x7f0700a7
|
||||
public const int lastButton = 2131165351;
|
||||
|
||||
// aapt resource value: 0x7f070034
|
||||
public const int left = 2131165236;
|
||||
|
||||
// aapt resource value: 0x7f0700a0
|
||||
public const int line1 = 2131165344;
|
||||
|
||||
// aapt resource value: 0x7f0700b9
|
||||
public const int line2 = 2131165369;
|
||||
// aapt resource value: 0x7f0700bc
|
||||
public const int line2 = 2131165372;
|
||||
|
||||
// aapt resource value: 0x7f0700a2
|
||||
public const int line3 = 2131165346;
|
||||
|
||||
// aapt resource value: 0x7f0700b2
|
||||
public const int list = 2131165362;
|
||||
// aapt resource value: 0x7f0700b5
|
||||
public const int list = 2131165365;
|
||||
|
||||
// aapt resource value: 0x7f07000f
|
||||
public const int listMode = 2131165199;
|
||||
@@ -2674,8 +2686,8 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f070048
|
||||
public const int list_item = 2131165256;
|
||||
|
||||
// aapt resource value: 0x7f0700bb
|
||||
public const int masked = 2131165371;
|
||||
// aapt resource value: 0x7f0700be
|
||||
public const int masked = 2131165374;
|
||||
|
||||
// aapt resource value: 0x7f070094
|
||||
public const int media_actions = 2131165332;
|
||||
@@ -2689,8 +2701,8 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f070019
|
||||
public const int multiply = 2131165209;
|
||||
|
||||
// aapt resource value: 0x7f0700bc
|
||||
public const int musicLayout = 2131165372;
|
||||
// aapt resource value: 0x7f0700bf
|
||||
public const int musicLayout = 2131165375;
|
||||
|
||||
// aapt resource value: 0x7f07007d
|
||||
public const int navigation_header_container = 2131165309;
|
||||
@@ -2698,6 +2710,9 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f070026
|
||||
public const int never = 2131165222;
|
||||
|
||||
// aapt resource value: 0x7f0700a9
|
||||
public const int nextButton = 2131165353;
|
||||
|
||||
// aapt resource value: 0x7f07008d
|
||||
public const int noPlaylist = 2131165325;
|
||||
|
||||
@@ -2728,26 +2743,26 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f070038
|
||||
public const int pin = 2131165240;
|
||||
|
||||
// aapt resource value: 0x7f0700aa
|
||||
public const int playFAB = 2131165354;
|
||||
// aapt resource value: 0x7f0700a8
|
||||
public const int playButton = 2131165352;
|
||||
|
||||
// aapt resource value: 0x7f0700a5
|
||||
public const int playerAlbum = 2131165349;
|
||||
|
||||
// aapt resource value: 0x7f0700a9
|
||||
public const int playerArtist = 2131165353;
|
||||
// aapt resource value: 0x7f0700ac
|
||||
public const int playerArtist = 2131165356;
|
||||
|
||||
// aapt resource value: 0x7f0700ab
|
||||
public const int playerControl = 2131165355;
|
||||
// aapt resource value: 0x7f0700ae
|
||||
public const int playerControl = 2131165358;
|
||||
|
||||
// aapt resource value: 0x7f0700a6
|
||||
public const int playerSleep = 2131165350;
|
||||
|
||||
// aapt resource value: 0x7f0700a8
|
||||
public const int playerTitle = 2131165352;
|
||||
// aapt resource value: 0x7f0700ab
|
||||
public const int playerTitle = 2131165355;
|
||||
|
||||
// aapt resource value: 0x7f0700bf
|
||||
public const int playlistLayout = 2131165375;
|
||||
// aapt resource value: 0x7f0700c2
|
||||
public const int playlistLayout = 2131165378;
|
||||
|
||||
// aapt resource value: 0x7f070074
|
||||
public const int playlistName = 2131165300;
|
||||
@@ -2788,8 +2803,8 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f070040
|
||||
public const int scrollable = 2131165248;
|
||||
|
||||
// aapt resource value: 0x7f0700b6
|
||||
public const int search = 2131165366;
|
||||
// aapt resource value: 0x7f0700b9
|
||||
public const int search = 2131165369;
|
||||
|
||||
// aapt resource value: 0x7f070068
|
||||
public const int search_badge = 2131165288;
|
||||
@@ -2821,17 +2836,17 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f070071
|
||||
public const int search_voice_btn = 2131165297;
|
||||
|
||||
// aapt resource value: 0x7f0700b3
|
||||
public const int seekbar = 2131165363;
|
||||
// aapt resource value: 0x7f0700b6
|
||||
public const int seekbar = 2131165366;
|
||||
|
||||
// aapt resource value: 0x7f0700b4
|
||||
public const int seekbar_value = 2131165364;
|
||||
// aapt resource value: 0x7f0700b7
|
||||
public const int seekbar_value = 2131165367;
|
||||
|
||||
// aapt resource value: 0x7f070072
|
||||
public const int select_dialog_listview = 2131165298;
|
||||
|
||||
// aapt resource value: 0x7f0700c0
|
||||
public const int settings = 2131165376;
|
||||
// aapt resource value: 0x7f0700c3
|
||||
public const int settings = 2131165379;
|
||||
|
||||
// aapt resource value: 0x7f07005c
|
||||
public const int shortcut = 2131165276;
|
||||
@@ -2860,8 +2875,8 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f07004c
|
||||
public const int spacer = 2131165260;
|
||||
|
||||
// aapt resource value: 0x7f0700b1
|
||||
public const int spinner = 2131165361;
|
||||
// aapt resource value: 0x7f0700b4
|
||||
public const int spinner = 2131165364;
|
||||
|
||||
// aapt resource value: 0x7f070008
|
||||
public const int split_action_bar = 2131165192;
|
||||
@@ -2887,8 +2902,8 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f07006f
|
||||
public const int submit_area = 2131165295;
|
||||
|
||||
// aapt resource value: 0x7f0700b5
|
||||
public const int switchWidget = 2131165365;
|
||||
// aapt resource value: 0x7f0700b8
|
||||
public const int switchWidget = 2131165368;
|
||||
|
||||
// aapt resource value: 0x7f070011
|
||||
public const int tabMode = 2131165201;
|
||||
@@ -2959,8 +2974,8 @@ namespace MusicApp
|
||||
// aapt resource value: 0x7f07000e
|
||||
public const int view_offset_helper = 2131165198;
|
||||
|
||||
// aapt resource value: 0x7f0700ba
|
||||
public const int visible = 2131165370;
|
||||
// aapt resource value: 0x7f0700bd
|
||||
public const int visible = 2131165373;
|
||||
|
||||
// aapt resource value: 0x7f070027
|
||||
public const int withText = 2131165223;
|
||||
|
||||
8
MusicApp/Resources/anim/SlideInUp.xml
Normal file
8
MusicApp/Resources/anim/SlideInUp.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set>
|
||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fromXDelta="-100%"
|
||||
android:toXDelta="0"
|
||||
android:interpolator="@android:anim/decelerate_interpolator"
|
||||
android:duration="500"/>
|
||||
</set>
|
||||
9
MusicApp/Resources/anim/SlideOutUp.xml
Normal file
9
MusicApp/Resources/anim/SlideOutUp.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set>
|
||||
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:propertyName="x"
|
||||
android:valueType="floatType"
|
||||
android:valueFrom="-1280"
|
||||
android:valueTo="0"
|
||||
android:duration="500"/>
|
||||
</set>
|
||||
@@ -16,6 +16,7 @@
|
||||
<ImageView
|
||||
android:id="@+id/playerAlbum"
|
||||
android:layout_width="fill_parent"
|
||||
android:background="@null"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="fitCenter"
|
||||
android:adjustViewBounds="true" />
|
||||
@@ -24,9 +25,39 @@
|
||||
android:background="@drawable/ic_timer_white_24dp"
|
||||
android:layout_width="35dp"
|
||||
android:layout_height="35dp"
|
||||
android:layout_gravity="top|right"
|
||||
android:paddingTop="80dp"
|
||||
android:paddingRight="40dp"/>
|
||||
android:layout_gravity="top|center"
|
||||
android:paddingTop="280dp" />
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
<ImageButton
|
||||
android:id="@+id/lastButton"
|
||||
android:background="@null"
|
||||
android:tint="#ffffff"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:src="@drawable/ic_skip_previous_black_24dp"/>
|
||||
<ImageButton
|
||||
android:id="@+id/playButton"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginLeft="50dp"
|
||||
android:background="@null"
|
||||
android:layout_marginRight="50dp"
|
||||
android:layout_gravity="center"
|
||||
android:tint="#ffffff"
|
||||
android:src="@drawable/ic_pause_black_24dp"/>
|
||||
<ImageButton
|
||||
android:id="@+id/nextButton"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:background="@null"
|
||||
android:tint="#ffffff"
|
||||
android:src="@drawable/ic_skip_next_black_24dp"/>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
@@ -53,7 +84,7 @@
|
||||
android:textColor="#FFFFFF"
|
||||
android:alpha=".92"
|
||||
android:textStyle="bold"
|
||||
android:paddingLeft="65dp"
|
||||
android:paddingLeft="60dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentStart="true"/>
|
||||
<TextView
|
||||
@@ -69,22 +100,21 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:paddingLeft="65dp"
|
||||
android:paddingLeft="60dp"
|
||||
android:alpha=".92"
|
||||
android:textSize="20sp"
|
||||
android:textColor="#FFFFFF"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/playFAB"
|
||||
android:id="@+id/downFAB"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_anchor="@id/playerAlbum"
|
||||
app:layout_anchorGravity="bottom|right|end"
|
||||
android:transitionName="playButton"
|
||||
app:layout_anchor="@id/infoPanel"
|
||||
app:layout_anchorGravity="bottom|center"
|
||||
android:layout_margin="10dip"
|
||||
app:elevation="12dp"
|
||||
app:borderWidth="0dp"
|
||||
app:backgroundTint="#4cb5ae"
|
||||
android:src="@drawable/ic_pause_black_24dp" />
|
||||
android:src="@drawable/ic_expand_more_black_24dp" />
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
@@ -73,5 +73,6 @@
|
||||
<package id="Xamarin.Android.Support.v7.RecyclerView" version="25.4.0.2" targetFramework="monoandroid70" />
|
||||
<package id="Xamarin.Android.Support.Vector.Drawable" version="25.4.0.2" targetFramework="monoandroid70" />
|
||||
<package id="YoutubeExplode" version="3.2.5" targetFramework="monoandroid70" />
|
||||
<package id="YoutubeExtractor" version="0.10.11" targetFramework="monoandroid70" />
|
||||
<package id="YoutubeSearch.dll" version="1.1" targetFramework="monoandroid70" />
|
||||
</packages>
|
||||
Reference in New Issue
Block a user