mirror of
https://github.com/zoriya/Opus.git
synced 2025-12-06 06:26:15 +00:00
Cleaning up the code.
This commit is contained in:
230
Opus/Code/Api/LocalManager.cs
Normal file
230
Opus/Code/Api/LocalManager.cs
Normal file
@@ -0,0 +1,230 @@
|
||||
using Android.App;
|
||||
using Android.Database;
|
||||
using Android.Net;
|
||||
using Android.OS;
|
||||
using Android.Provider;
|
||||
using Android.Support.V4.Content;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Fragments;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using TagLib;
|
||||
using ContentResolver = Android.Content.ContentResolver;
|
||||
using ContentValues = Android.Content.ContentValues;
|
||||
using Intent = Android.Content.Intent;
|
||||
|
||||
namespace Opus.Api
|
||||
{
|
||||
public class LocalManager
|
||||
{
|
||||
#region Playback
|
||||
/// <summary>
|
||||
/// Handle playback of a local file using it's path.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
public static void Play(string path)
|
||||
{
|
||||
Intent intent = new Intent(Application.Context, typeof(MusicPlayer));
|
||||
intent.PutExtra("file", path);
|
||||
Application.Context.StartService(intent);
|
||||
|
||||
MainActivity.instance.ShowPlayer();
|
||||
MusicPlayer.UpdateQueueDataBase();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a local item to the queue.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
public static void PlayNext(string path)
|
||||
{
|
||||
Intent intent = new Intent(Application.Context, typeof(MusicPlayer));
|
||||
intent.PutExtra("file", path);
|
||||
intent.SetAction("PlayNext");
|
||||
Application.Context.StartService(intent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a local item at the end of the queue.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
public static void PlayLast(string path)
|
||||
{
|
||||
Intent intent = new Intent(Application.Context, typeof(MusicPlayer));
|
||||
intent.PutExtra("file", path);
|
||||
intent.SetAction("PlayLast");
|
||||
Application.Context.StartService(intent);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Metadata
|
||||
/// <summary>
|
||||
/// Return a song using only it's path (can be normal path or content:// path). This method read metadata in the device database.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <returns></returns>
|
||||
public async static Task<Song> GetSong(string filePath)
|
||||
{
|
||||
string Title = "Unknow";
|
||||
string Artist = "Unknow";
|
||||
long AlbumArt = 0;
|
||||
long id = 0;
|
||||
string path;
|
||||
Uri musicUri = MediaStore.Audio.Media.ExternalContentUri;
|
||||
|
||||
if (filePath.StartsWith("content://"))
|
||||
musicUri = Uri.Parse(filePath);
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
Looper.Prepare();
|
||||
CursorLoader cursorLoader = new CursorLoader(Application.Context, musicUri, null, null, null, null);
|
||||
ICursor musicCursor = (ICursor)cursorLoader.LoadInBackground();
|
||||
if (musicCursor != null && musicCursor.MoveToFirst())
|
||||
{
|
||||
int titleID = musicCursor.GetColumnIndex(MediaStore.Audio.Media.InterfaceConsts.Title);
|
||||
int artistID = musicCursor.GetColumnIndex(MediaStore.Audio.Media.InterfaceConsts.Artist);
|
||||
int thisID = musicCursor.GetColumnIndex(MediaStore.Audio.Media.InterfaceConsts.Id);
|
||||
int pathID = musicCursor.GetColumnIndex(MediaStore.Audio.Media.InterfaceConsts.Data);
|
||||
do
|
||||
{
|
||||
path = musicCursor.GetString(pathID);
|
||||
|
||||
if (path == filePath || filePath.StartsWith("content://"))
|
||||
{
|
||||
Artist = musicCursor.GetString(artistID);
|
||||
Title = musicCursor.GetString(titleID);
|
||||
AlbumArt = musicCursor.GetLong(musicCursor.GetColumnIndex(MediaStore.Audio.Albums.InterfaceConsts.AlbumId));
|
||||
id = musicCursor.GetLong(thisID);
|
||||
|
||||
if (Title == null)
|
||||
Title = "Unknown Title";
|
||||
if (Artist == null)
|
||||
Artist = "Unknow Artist";
|
||||
|
||||
if (filePath.StartsWith("content://"))
|
||||
filePath = path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (musicCursor.MoveToNext());
|
||||
musicCursor.Close();
|
||||
}
|
||||
});
|
||||
return new Song(Title, Artist, null, null, AlbumArt, id, filePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the youtubeID of a local song in the file's metadata and add it to the song object.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public static Song CompleteItem(Song item)
|
||||
{
|
||||
item.YoutubeID = GetYtID(item.Path);
|
||||
return item;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the youtubeID of a local song in the file's metadata using the path of the file.
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetYtID(string path)
|
||||
{
|
||||
Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||
var meta = TagLib.File.Create(new StreamFileAbstraction(path, stream, stream));
|
||||
string ytID = meta.Tag.Comment;
|
||||
stream.Dispose();
|
||||
return ytID;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Open the EditMetadata page for a song.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public static void EditMetadata(Song item)
|
||||
{
|
||||
item = CompleteItem(item);
|
||||
Intent intent = new Intent(Application.Context, typeof(EditMetaData));
|
||||
intent.PutExtra("Song", item.ToString());
|
||||
MainActivity.instance.StartActivity(intent);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PlaylistsImplementation
|
||||
/// <summary>
|
||||
/// Return true if the local song of id audioID is contained in the local playlist with the id of playlistID.
|
||||
/// </summary>
|
||||
/// <param name="audioID"></param>
|
||||
/// <param name="playlistID"></param>
|
||||
/// <returns></returns>
|
||||
public async static Task<bool> SongIsContained(long audioID, long playlistID)
|
||||
{
|
||||
Uri uri = MediaStore.Audio.Playlists.Members.GetContentUri("external", playlistID);
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
CursorLoader loader = new CursorLoader(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;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add an array of local song in a playlist.
|
||||
/// </summary>
|
||||
/// <param name="item">The array of songs you want to add to the playlist. Will only add local file, if you input youtube file in this array, they will be ignored<</param>
|
||||
/// <param name="playList">The name of the playlist</param>
|
||||
/// <param name="LocalID">The id of the local playlist or -1 if you want to add this song to a playlist that will be created after.</param>
|
||||
/// <param name="saveAsSynced">Used only if you want to create a playlist with this method. True if the newly created playlist should be synced on youtube.</param>
|
||||
public async static void AddToPlaylist(Song[] items, string playList, long LocalID, bool saveAsSynced = false)
|
||||
{
|
||||
if (LocalID == -1)
|
||||
{
|
||||
LocalID = await PlaylistManager.GetPlaylistID(playList);
|
||||
if (LocalID == -1)
|
||||
PlaylistManager.CreateLocalPlaylist(playList, items, saveAsSynced);
|
||||
else
|
||||
AddToPlaylist(items, playList, LocalID);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(await MainActivity.instance.GetWritePermission())
|
||||
{
|
||||
ContentResolver resolver = MainActivity.instance.ContentResolver;
|
||||
List<ContentValues> values = new List<ContentValues>();
|
||||
|
||||
foreach (Song item in items)
|
||||
{
|
||||
if (item != null && item.Id != 0 && item.Id != -1)
|
||||
{
|
||||
ContentValues value = new ContentValues();
|
||||
value.Put(MediaStore.Audio.Playlists.Members.AudioId, item.Id);
|
||||
value.Put(MediaStore.Audio.Playlists.Members.PlayOrder, 0);
|
||||
values.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
resolver.BulkInsert(MediaStore.Audio.Playlists.Members.GetContentUri("external", LocalID), values.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
1151
Opus/Code/Api/PlaylistManager.cs
Normal file
1151
Opus/Code/Api/PlaylistManager.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -11,14 +11,15 @@ using Android.Support.V4.App;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.Adapter;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Fragments;
|
||||
using Opus.Resources.values;
|
||||
using Opus.Others;
|
||||
using SQLite;
|
||||
using Square.Picasso;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using TagLib;
|
||||
@@ -29,9 +30,10 @@ using static Android.Provider.MediaStore.Audio;
|
||||
using Bitmap = Android.Graphics.Bitmap;
|
||||
using CursorLoader = Android.Support.V4.Content.CursorLoader;
|
||||
using File = System.IO.File;
|
||||
using Playlist = Opus.Fragments.Playlist;
|
||||
using Stream = System.IO.Stream;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Api.Services
|
||||
{
|
||||
[Service]
|
||||
public class Downloader : Service, MediaScannerConnection.IOnScanCompletedListener
|
||||
@@ -244,16 +246,15 @@ namespace Opus.Resources.Portable_Class
|
||||
public void OnScanCompleted(string path, Uri uri)
|
||||
{
|
||||
Android.Util.Log.Debug("MusisApp", "Scan Completed with path = " + path + " and uri = " + uri.ToString());
|
||||
//long id = long.Parse(uri.ToString().Substring(uri.ToString().IndexOf("audio/media/") + 12, uri.ToString().Length - uri.ToString().IndexOf("audio/media/") - 12));
|
||||
string playlist = path.Substring(downloadPath.Length + 1);
|
||||
|
||||
if (playlist.IndexOf('/') != -1)
|
||||
{
|
||||
playlist = playlist.Substring(0, playlist.IndexOf('/'));
|
||||
Handler handler = new Handler(MainActivity.instance.MainLooper);
|
||||
handler.Post(() =>
|
||||
handler.Post(async () =>
|
||||
{
|
||||
Browse.AddToPlaylist(Browse.GetSong(path), playlist, -1, true);
|
||||
LocalManager.AddToPlaylist(new[] { await LocalManager.GetSong(path) }, playlist, -1, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -261,7 +262,7 @@ namespace Opus.Resources.Portable_Class
|
||||
public async void SyncWithPlaylist(string playlistName, bool keepDeleted)
|
||||
{
|
||||
Playlist.instance?.StartSyncing(playlistName);
|
||||
long LocalID = Browse.GetPlaylistID(playlistName);
|
||||
long LocalID = await PlaylistManager.GetPlaylistID(playlistName);
|
||||
SyncWithPlaylist(LocalID, keepDeleted);
|
||||
|
||||
await Task.Run(() =>
|
||||
@@ -298,7 +299,7 @@ namespace Opus.Resources.Portable_Class
|
||||
long id = musicCursor.GetLong(songID);
|
||||
paths.Add(path);
|
||||
localIDs.Add(id);
|
||||
videoIDs.Add(Browse.GetYtID(path));
|
||||
videoIDs.Add(LocalManager.GetYtID(path));
|
||||
}
|
||||
while (musicCursor.MoveToNext());
|
||||
musicCursor.Close();
|
||||
@@ -428,16 +429,5 @@ namespace Opus.Resources.Portable_Class
|
||||
StartForeground(notificationID, notification.Build());
|
||||
}
|
||||
}
|
||||
|
||||
public enum DownloadState
|
||||
{
|
||||
Initialization,
|
||||
Downloading,
|
||||
MetaData,
|
||||
Completed,
|
||||
Canceled,
|
||||
UpToDate,
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,11 @@ using Com.Google.Android.Exoplayer2.Source.Hls;
|
||||
using Com.Google.Android.Exoplayer2.Trackselection;
|
||||
using Com.Google.Android.Exoplayer2.Upstream;
|
||||
using Com.Google.Android.Exoplayer2.Util;
|
||||
using Opus.Resources.values;
|
||||
using Newtonsoft.Json;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Fragments;
|
||||
using Opus.Others;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using Org.Json;
|
||||
using SQLite;
|
||||
using Square.Picasso;
|
||||
@@ -36,10 +39,8 @@ using CursorLoader = Android.Support.V4.Content.CursorLoader;
|
||||
using MediaInfo = Android.Gms.Cast.MediaInfo;
|
||||
using MediaMetadata = Android.Gms.Cast.MediaMetadata;
|
||||
using Uri = Android.Net.Uri;
|
||||
using Opus.Fragments;
|
||||
using Opus.DataStructure;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Api.Services
|
||||
{
|
||||
[Service]
|
||||
public class MusicPlayer : Service, IPlayerEventListener, AudioManager.IOnAudioFocusChangeListener
|
||||
@@ -247,7 +248,7 @@ namespace Opus.Resources.Portable_Class
|
||||
player.Volume = volume * (volumeDuked ? 0.2f : 1);
|
||||
}
|
||||
|
||||
public void Play(string filePath, string title = null, string artist = null, string youtubeID = null, string thumbnailURI = null, bool isLive = false, DateTimeOffset? expireDate = null)
|
||||
public async void Play(string filePath, string title = null, string artist = null, string youtubeID = null, string thumbnailURI = null, bool isLive = false, DateTimeOffset? expireDate = null)
|
||||
{
|
||||
isRunning = true;
|
||||
if (player == null)
|
||||
@@ -260,7 +261,7 @@ namespace Opus.Resources.Portable_Class
|
||||
|
||||
Song song = null;
|
||||
if (title == null)
|
||||
song = Browse.GetSong(filePath);
|
||||
song = await LocalManager.GetSong(filePath);
|
||||
else
|
||||
{
|
||||
song = new Song(title, artist, thumbnailURI, youtubeID, -1, -1, filePath, true);
|
||||
@@ -687,7 +688,7 @@ namespace Opus.Resources.Portable_Class
|
||||
YoutubeClient client = new YoutubeClient();
|
||||
Video video = await client.GetVideoAsync(youtubeID);
|
||||
|
||||
var ytPlaylistRequest = YoutubeEngine.youtubeService.PlaylistItems.List("snippet, contentDetails");
|
||||
var ytPlaylistRequest = YoutubeSearch.youtubeService.PlaylistItems.List("snippet, contentDetails");
|
||||
ytPlaylistRequest.PlaylistId = video.GetVideoMixPlaylistId();
|
||||
ytPlaylistRequest.MaxResults = 15;
|
||||
|
||||
@@ -774,9 +775,8 @@ namespace Opus.Resources.Portable_Class
|
||||
|
||||
foreach (string filePath in filePaths)
|
||||
{
|
||||
Song song = Browse.GetSong(filePath);
|
||||
Song song = await LocalManager.GetSong(filePath);
|
||||
queue.Add(song);
|
||||
await Task.Delay(10);
|
||||
}
|
||||
|
||||
if (UseCastPlayer)
|
||||
@@ -788,30 +788,6 @@ namespace Opus.Resources.Portable_Class
|
||||
Home.instance?.RefreshQueue();
|
||||
}
|
||||
|
||||
public async void RandomPlay(List<Song> songs, bool clearQueue)
|
||||
{
|
||||
currentID = 0;
|
||||
if (clearQueue)
|
||||
queue.Clear();
|
||||
|
||||
Random r = new Random();
|
||||
songs = songs.OrderBy(x => r.Next()).ToList();
|
||||
if (clearQueue)
|
||||
{
|
||||
Play(songs[0]);
|
||||
songs.RemoveAt(0);
|
||||
}
|
||||
queue.AddRange(songs);
|
||||
|
||||
if (UseCastPlayer)
|
||||
{
|
||||
await RemotePlayer.QueueLoadAsync(queue.ConvertAll(GetQueueItem).ToArray(), 0, 0, null);
|
||||
}
|
||||
|
||||
UpdateQueueDataBase();
|
||||
Home.instance?.RefreshQueue();
|
||||
}
|
||||
|
||||
private void RandomizeQueue()
|
||||
{
|
||||
Random r = new Random();
|
||||
@@ -841,11 +817,11 @@ namespace Opus.Resources.Portable_Class
|
||||
}
|
||||
}
|
||||
|
||||
public void AddToQueue(string filePath, string title = null, string artist = null, string youtubeID = null, string thumbnailURI = null, bool isLive = false)
|
||||
public async void AddToQueue(string filePath, string title = null, string artist = null, string youtubeID = null, string thumbnailURI = null, bool isLive = false)
|
||||
{
|
||||
Song song = null;
|
||||
if(title == null)
|
||||
song = Browse.GetSong(filePath);
|
||||
song = await LocalManager.GetSong(filePath);
|
||||
else
|
||||
song = new Song(title, artist, thumbnailURI, youtubeID, -1, -1, filePath, true);
|
||||
|
||||
@@ -918,6 +894,18 @@ namespace Opus.Resources.Portable_Class
|
||||
UpdateQueueDataBase();
|
||||
}
|
||||
|
||||
public void InsertToQueue(int position, Song[] songs)
|
||||
{
|
||||
queue.InsertRange(position, songs);
|
||||
Home.instance?.NotifyQueueRangeInserted(position, songs.Length);
|
||||
Queue.instance?.NotifyItemRangeInserted(position, songs.Length);
|
||||
|
||||
if (UseCastPlayer)
|
||||
RemotePlayer.QueueInsertItems(GetQueueItems(songs), RemotePlayer.MediaQueue.ItemIdAtIndex(position + 1), null);
|
||||
|
||||
UpdateQueueDataBase();
|
||||
}
|
||||
|
||||
public static void RemoveFromQueue(int position)
|
||||
{
|
||||
if (CurrentID() > position)
|
||||
@@ -963,9 +951,9 @@ namespace Opus.Resources.Portable_Class
|
||||
UpdateQueueDataBase();
|
||||
}
|
||||
|
||||
public void PlayLastInQueue(string filePath)
|
||||
public async void PlayLastInQueue(string filePath)
|
||||
{
|
||||
Song song = Browse.GetSong(filePath);
|
||||
Song song = await LocalManager.GetSong(filePath);
|
||||
|
||||
if (UseCastPlayer)
|
||||
RemotePlayer.QueueAppendItem(GetQueueItem(song), null);
|
||||
@@ -1559,6 +1547,16 @@ namespace Opus.Resources.Portable_Class
|
||||
return new MediaQueueItem.Builder(GetMediaInfo(song)).Build();
|
||||
}
|
||||
|
||||
private static MediaQueueItem[] GetQueueItems(Song[] songs)
|
||||
{
|
||||
MediaQueueItem[] items = new MediaQueueItem[songs.Length];
|
||||
for (int i = 0; i < songs.Length; i++)
|
||||
{
|
||||
items[i] = GetQueueItem(songs[i]);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
private async void StartCasting()
|
||||
{
|
||||
if (UseCastPlayer && (RemotePlayer.MediaQueue == null || RemotePlayer.MediaQueue.ItemCount == 0))
|
||||
43
Opus/Code/Api/SongManager.cs
Normal file
43
Opus/Code/Api/SongManager.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using Opus.DataStructure;
|
||||
|
||||
namespace Opus.Api
|
||||
{
|
||||
public class SongManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Play a song, can be a local one or a youtube one. The class will handle it automatically.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public static void Play(Song item)
|
||||
{
|
||||
if (!item.IsYt)
|
||||
LocalManager.Play(item.Path);
|
||||
else
|
||||
YoutubeManager.Play(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a song to the next slot of the queue. Handle both youtube and local files.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public static void PlayNext(Song item)
|
||||
{
|
||||
if (!item.IsYt)
|
||||
LocalManager.PlayNext(item.Path);
|
||||
else
|
||||
YoutubeManager.PlayNext(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a song to the end of the queue. Handle both youtube and local files.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public static void PlayLast(Song item)
|
||||
{
|
||||
if (!item.IsYt)
|
||||
LocalManager.PlayLast(item.Path);
|
||||
else
|
||||
YoutubeManager.PlayLast(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
431
Opus/Code/Api/YoutubeManager.cs
Normal file
431
Opus/Code/Api/YoutubeManager.cs
Normal file
@@ -0,0 +1,431 @@
|
||||
using Android.Content;
|
||||
using Android.Database;
|
||||
using Android.Graphics;
|
||||
using Android.Provider;
|
||||
using Android.Support.Design.Widget;
|
||||
using Android.Support.V4.Content;
|
||||
using Android.Support.V7.Preferences;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Google.Apis.YouTube.v3;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Fragments;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using TagLib;
|
||||
using YoutubeExplode;
|
||||
using YoutubeExplode.Models;
|
||||
using CursorLoader = Android.Support.V4.Content.CursorLoader;
|
||||
|
||||
namespace Opus.Api
|
||||
{
|
||||
public class YoutubeManager
|
||||
{
|
||||
public static YouTubeService YoutubeService
|
||||
{
|
||||
get
|
||||
{
|
||||
return YoutubeSearch.youtubeService; //Will change that with the rework of the youtubeengine class.
|
||||
}
|
||||
}
|
||||
|
||||
#region Playback
|
||||
/// <summary>
|
||||
/// Handle playback of a youtube song
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public static void Play(Song item)
|
||||
{
|
||||
Intent intent = new Intent(Android.App.Application.Context, typeof(MusicPlayer));
|
||||
intent.SetAction("YoutubePlay");
|
||||
intent.PutExtra("action", "Play");
|
||||
intent.PutExtra("file", item.YoutubeID);
|
||||
intent.PutExtra("title", item.Title);
|
||||
intent.PutExtra("artist", item.Artist);
|
||||
intent.PutExtra("thumbnailURI", item.Path);
|
||||
intent.PutExtra("addToQueue", true);
|
||||
intent.PutExtra("showPlayer", true);
|
||||
Android.App.Application.Context.StartService(intent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a youtube item to the next slot of the queue.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public static void PlayNext(Song item)
|
||||
{
|
||||
Intent intent = new Intent(Android.App.Application.Context, typeof(MusicPlayer));
|
||||
intent.SetAction("YoutubePlay");
|
||||
intent.PutExtra("action", "PlayNext");
|
||||
intent.PutExtra("file", item.YoutubeID);
|
||||
intent.PutExtra("title", item.Title);
|
||||
intent.PutExtra("artist", item.Artist);
|
||||
intent.PutExtra("thumbnailURI", item.Path);
|
||||
Android.App.Application.Context.StartService(intent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a youtube item to the last slot of the queue.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public static void PlayLast(Song item)
|
||||
{
|
||||
Intent intent = new Intent(Android.App.Application.Context, typeof(MusicPlayer));
|
||||
intent.SetAction("YoutubePlay");
|
||||
intent.PutExtra("action", "PlayLast");
|
||||
intent.PutExtra("file", item.YoutubeID);
|
||||
intent.PutExtra("title", item.Title);
|
||||
intent.PutExtra("artist", item.Artist);
|
||||
intent.PutExtra("thumbnailURI", item.Path);
|
||||
Android.App.Application.Context.StartService(intent);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Downloader
|
||||
/// <summary>
|
||||
/// Download every youtube song in the items array and add them to the local playlist that you named in the second var.
|
||||
/// </summary>
|
||||
/// <param name="items"></param>
|
||||
/// <param name="playlist"></param>
|
||||
public static void Download(Song[] items, string playlist)
|
||||
{
|
||||
string[] names = items.ToList().ConvertAll(x => x.Title).ToArray();
|
||||
string[] videoIDs = items.ToList().ConvertAll(x => x.YoutubeID).ToArray();
|
||||
|
||||
DownloadFiles(names, videoIDs, playlist);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download songs using there id and there name (for the queue). Then, they will be added to the playlist that you named.
|
||||
/// </summary>
|
||||
/// <param name="names"></param>
|
||||
/// <param name="videoIDs"></param>
|
||||
/// <param name="playlist"></param>
|
||||
public static async void DownloadFiles(string[] names, string[] videoIDs, string playlist)
|
||||
{
|
||||
ISharedPreferences prefManager = PreferenceManager.GetDefaultSharedPreferences(Android.App.Application.Context);
|
||||
string downloadPath = prefManager.GetString("downloadPath", null);
|
||||
if (downloadPath == null)
|
||||
{
|
||||
Snackbar snackBar = Snackbar.Make(MainActivity.instance.FindViewById(Resource.Id.snackBar), Resource.String.download_path_not_set, Snackbar.LengthLong).SetAction(Resource.String.set_path, (v) =>
|
||||
{
|
||||
Intent pref = new Intent(Android.App.Application.Context, typeof(Preferences));
|
||||
MainActivity.instance.StartActivity(pref);
|
||||
});
|
||||
snackBar.View.FindViewById<TextView>(Resource.Id.snackbar_text).SetTextColor(Color.White);
|
||||
snackBar.Show();
|
||||
|
||||
ISharedPreferencesEditor editor = prefManager.Edit();
|
||||
editor.PutString("downloadPath", Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryMusic).ToString());
|
||||
editor.Commit();
|
||||
|
||||
downloadPath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryMusic).ToString();
|
||||
}
|
||||
|
||||
Context context = Android.App.Application.Context;
|
||||
Intent intent = new Intent(context, typeof(Downloader));
|
||||
context.StartService(intent);
|
||||
|
||||
while (Downloader.instance == null)
|
||||
await Task.Delay(10);
|
||||
|
||||
List<DownloadFile> files = new List<DownloadFile>();
|
||||
for (int i = 0; i < names.Length; i++)
|
||||
{
|
||||
if (videoIDs[i] != null && videoIDs[i] != "")
|
||||
files.Add(new DownloadFile(names[i], videoIDs[i], playlist));
|
||||
}
|
||||
|
||||
Downloader.instance.downloadPath = downloadPath;
|
||||
Downloader.instance.maxDownload = prefManager.GetInt("maxDownload", 4);
|
||||
Downloader.queue.AddRange(files);
|
||||
|
||||
if (playlist != null)
|
||||
Downloader.instance.SyncWithPlaylist(playlist, prefManager.GetBoolean("keepDeleted", true));
|
||||
|
||||
Downloader.instance.StartDownload();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download a playlist or update the local playlist with new songs.
|
||||
/// </summary>
|
||||
/// <param name="playlist">The name of the playlist (local one)</param>
|
||||
/// <param name="playlistID">The youtube id of your playlist</param>
|
||||
/// <param name="showToast">True if you want this method to display that the download has started</param>
|
||||
public static async void DownloadPlaylist(string playlist, string playlistID, bool showToast = true)
|
||||
{
|
||||
if (!await MainActivity.instance.WaitForYoutube())
|
||||
return;
|
||||
|
||||
if (!await MainActivity.instance.GetReadPermission())
|
||||
return;
|
||||
|
||||
if (!await MainActivity.instance.GetWritePermission())
|
||||
return;
|
||||
|
||||
if (showToast)
|
||||
Toast.MakeText(Android.App.Application.Context, Resource.String.syncing, ToastLength.Short).Show();
|
||||
|
||||
List<string> names = new List<string>();
|
||||
List<string> videoIDs = new List<string>();
|
||||
string nextPageToken = "";
|
||||
while (nextPageToken != null)
|
||||
{
|
||||
var ytPlaylistRequest = YoutubeService.PlaylistItems.List("snippet, contentDetails");
|
||||
ytPlaylistRequest.PlaylistId = playlistID;
|
||||
ytPlaylistRequest.MaxResults = 50;
|
||||
ytPlaylistRequest.PageToken = nextPageToken;
|
||||
|
||||
var ytPlaylist = await ytPlaylistRequest.ExecuteAsync();
|
||||
|
||||
foreach (var item in ytPlaylist.Items)
|
||||
{
|
||||
names.Add(item.Snippet.Title);
|
||||
videoIDs.Add(item.ContentDetails.VideoId);
|
||||
}
|
||||
|
||||
nextPageToken = ytPlaylist.NextPageToken;
|
||||
}
|
||||
|
||||
if (names.Count > 0)
|
||||
DownloadFiles(names.ToArray(), videoIDs.ToArray(), playlist);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region PlaylistsImplementation
|
||||
/// <summary>
|
||||
/// Return true if the youtube song of id audioID is contained in the youtube playlist with the id of playlistID.
|
||||
/// </summary>
|
||||
/// <param name="audioID"></param>
|
||||
/// <param name="playlistID"></param>
|
||||
/// <returns></returns>
|
||||
public async static Task<bool> SongIsContained(string audioID, string playlistID)
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = YoutubeService.PlaylistItems.List("snippet, contentDetails");
|
||||
request.PlaylistId = playlistID;
|
||||
request.VideoId = audioID;
|
||||
request.MaxResults = 1;
|
||||
|
||||
var response = await request.ExecuteAsync();
|
||||
if (response.Items.Count > 0)
|
||||
return true;
|
||||
}
|
||||
catch (System.Net.Http.HttpRequestException)
|
||||
{
|
||||
MainActivity.instance.Timout();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Add an array of youtube song to a playlist.
|
||||
/// </summary>
|
||||
/// <param name="items">The array of songs you want to add to the playlist. Will only add youtube file, if you input local file in this array, they will be ignored</param>
|
||||
/// <param name="PlaylistYtID">The id of the youtube playlist</param>
|
||||
public async static void AddToPlaylist(Song[] items, string PlaylistYtID)
|
||||
{
|
||||
Google.Apis.YouTube.v3.Data.PlaylistItem playlistItem = new Google.Apis.YouTube.v3.Data.PlaylistItem();
|
||||
PlaylistItemSnippet snippet = new PlaylistItemSnippet
|
||||
{
|
||||
PlaylistId = PlaylistYtID
|
||||
};
|
||||
|
||||
foreach (Song item in items)
|
||||
{
|
||||
if (item != null && item.IsYt)
|
||||
{
|
||||
try
|
||||
{
|
||||
ResourceId resourceId = new ResourceId
|
||||
{
|
||||
Kind = "youtube#video",
|
||||
VideoId = item.YoutubeID
|
||||
};
|
||||
snippet.ResourceId = resourceId;
|
||||
playlistItem.Snippet = snippet;
|
||||
|
||||
var insertRequest = YoutubeService.PlaylistItems.Insert(playlistItem, "snippet");
|
||||
await insertRequest.ExecuteAsync();
|
||||
}
|
||||
catch (System.Net.Http.HttpRequestException)
|
||||
{
|
||||
MainActivity.instance.Timout();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Mix
|
||||
/// <summary>
|
||||
/// Add a list of related songs to the queue.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public static async void CreateMixFromSong(Song item)
|
||||
{
|
||||
bool AddItemToQueue = true;
|
||||
if (MusicPlayer.queue.Count == 0)
|
||||
{
|
||||
SongManager.Play(item);
|
||||
AddItemToQueue = false;
|
||||
}
|
||||
|
||||
ProgressBar parseProgress = MainActivity.instance.FindViewById<ProgressBar>(Resource.Id.ytProgress);
|
||||
parseProgress.Visibility = ViewStates.Visible;
|
||||
parseProgress.ScaleY = 6;
|
||||
|
||||
if (!await MainActivity.instance.WaitForYoutube())
|
||||
{
|
||||
Snackbar snackBar = Snackbar.Make(MainActivity.instance.FindViewById(Resource.Id.snackBar), Resource.String.youtube_loading_error, Snackbar.LengthLong);
|
||||
snackBar.View.FindViewById<TextView>(Resource.Id.snackbar_text).SetTextColor(Color.White);
|
||||
snackBar.Show();
|
||||
return;
|
||||
}
|
||||
|
||||
List<Song> tracks = new List<Song>();
|
||||
try
|
||||
{
|
||||
YoutubeClient client = new YoutubeClient();
|
||||
var video = await client.GetVideoAsync(item.YoutubeID);
|
||||
|
||||
var ytPlaylistRequest = YoutubeService.PlaylistItems.List("snippet, contentDetails");
|
||||
ytPlaylistRequest.PlaylistId = video.GetVideoMixPlaylistId();
|
||||
ytPlaylistRequest.MaxResults = 25;
|
||||
|
||||
var ytPlaylist = await ytPlaylistRequest.ExecuteAsync();
|
||||
|
||||
foreach (var ytItem in ytPlaylist.Items)
|
||||
{
|
||||
if (ytItem.Snippet.Title != "[Deleted video]" && ytItem.Snippet.Title != "Private video" && ytItem.Snippet.Title != "Deleted video" && !MusicPlayer.queue.Exists(x => x.YoutubeID == ytItem.ContentDetails.VideoId))
|
||||
{
|
||||
Song song = new Song(ytItem.Snippet.Title, ytItem.Snippet.ChannelTitle, ytItem.Snippet.Thumbnails.High.Url, ytItem.ContentDetails.VideoId, -1, -1, ytItem.ContentDetails.VideoId, true, false);
|
||||
tracks.Add(song);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is System.Net.Http.HttpRequestException)
|
||||
MainActivity.instance.Timout();
|
||||
else
|
||||
MainActivity.instance.UnknowError();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Random r = new Random();
|
||||
tracks = tracks.OrderBy(x => r.Next()).ToList();
|
||||
if (AddItemToQueue && !MusicPlayer.queue.Exists(x => x.YoutubeID == item.YoutubeID))
|
||||
tracks.Add(item);
|
||||
|
||||
Intent intent = new Intent(MainActivity.instance, typeof(MusicPlayer));
|
||||
MainActivity.instance.StartService(intent);
|
||||
|
||||
while (MusicPlayer.instance == null)
|
||||
await Task.Delay(100);
|
||||
|
||||
MusicPlayer.instance.AddToQueue(tracks.ToArray());
|
||||
MainActivity.instance.ShowPlayer();
|
||||
Home.instance?.RefreshQueue();
|
||||
Queue.instance?.Refresh();
|
||||
parseProgress.Visibility = ViewStates.Gone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Play songs from the channel of your choice.
|
||||
/// </summary>
|
||||
/// <param name="ChannelID"></param>
|
||||
public async static void MixFromChannel(string ChannelID)
|
||||
{
|
||||
if (!await MainActivity.instance.WaitForYoutube())
|
||||
return;
|
||||
|
||||
List<Song> songs = new List<Song>();
|
||||
try
|
||||
{
|
||||
SearchResource.ListRequest searchRequest = YoutubeService.Search.List("snippet");
|
||||
searchRequest.Fields = "items(id/videoId,snippet/title,snippet/thumbnails/high/url,snippet/channelTitle)";
|
||||
searchRequest.Type = "video";
|
||||
searchRequest.ChannelId = ChannelID;
|
||||
searchRequest.MaxResults = 20;
|
||||
var searchReponse = await searchRequest.ExecuteAsync();
|
||||
|
||||
|
||||
foreach (var video in searchReponse.Items)
|
||||
{
|
||||
Song song = new Song(video.Snippet.Title, video.Snippet.ChannelTitle, video.Snippet.Thumbnails.High.Url, video.Id.VideoId, -1, -1, null, true, false);
|
||||
songs.Add(song);
|
||||
}
|
||||
}
|
||||
catch (System.Net.Http.HttpRequestException)
|
||||
{
|
||||
MainActivity.instance.Timout();
|
||||
}
|
||||
|
||||
Random r = new Random();
|
||||
songs = songs.OrderBy(x => r.Next()).ToList();
|
||||
SongManager.Play(songs[0]);
|
||||
songs.RemoveAt(0);
|
||||
|
||||
while (MusicPlayer.instance == null)
|
||||
await Task.Delay(10);
|
||||
|
||||
MusicPlayer.instance.AddToQueue(songs.ToArray());
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Metadata
|
||||
/// <summary>
|
||||
/// Return the local path of a youtube video (if downloaded). If the video is not downloaded, return null.
|
||||
/// </summary>
|
||||
/// <param name="videoID"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetLocalPathFromYTID(string videoID)
|
||||
{
|
||||
Android.Net.Uri musicUri = MediaStore.Audio.Media.ExternalContentUri;
|
||||
CursorLoader cursorLoader = new CursorLoader(Android.App.Application.Context, musicUri, null, null, null, null);
|
||||
ICursor musicCursor = (ICursor)cursorLoader.LoadInBackground();
|
||||
|
||||
if (musicCursor != null && musicCursor.MoveToFirst())
|
||||
{
|
||||
int pathKey = musicCursor.GetColumnIndex(MediaStore.Audio.Media.InterfaceConsts.Data);
|
||||
do
|
||||
{
|
||||
string path = musicCursor.GetString(pathKey);
|
||||
|
||||
try
|
||||
{
|
||||
Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||
var meta = TagLib.File.Create(new StreamFileAbstraction(path, stream, stream));
|
||||
string ytID = meta.Tag.Comment;
|
||||
stream.Dispose();
|
||||
|
||||
if (ytID == videoID)
|
||||
{
|
||||
musicCursor.Close();
|
||||
return path;
|
||||
}
|
||||
}
|
||||
catch (CorruptFileException)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
while (musicCursor.MoveToNext());
|
||||
musicCursor.Close();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
using Opus.Resources.Portable_Class;
|
||||
|
||||
namespace Opus.Resources.values
|
||||
namespace Opus.DataStructure
|
||||
{
|
||||
[System.Serializable]
|
||||
public class DownloadFile
|
||||
@@ -20,4 +18,15 @@ namespace Opus.Resources.values
|
||||
this.playlist = playlist;
|
||||
}
|
||||
}
|
||||
|
||||
public enum DownloadState
|
||||
{
|
||||
Initialization,
|
||||
Downloading,
|
||||
MetaData,
|
||||
Completed,
|
||||
Canceled,
|
||||
UpToDate,
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
using Opus.DataStructure;
|
||||
using Opus.Resources.values;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using SQLite;
|
||||
using System;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.DataStructure
|
||||
{
|
||||
[Serializable]
|
||||
public class PlaylistItem
|
||||
@@ -55,6 +56,31 @@ namespace Opus.Resources.Portable_Class
|
||||
}
|
||||
}
|
||||
|
||||
public class PlaylistHolder : RecyclerView.ViewHolder
|
||||
{
|
||||
public TextView Title;
|
||||
public TextView Owner;
|
||||
public ImageView AlbumArt;
|
||||
public ImageView edit;
|
||||
public ImageView sync;
|
||||
public ProgressBar SyncLoading;
|
||||
public ImageView more;
|
||||
|
||||
public PlaylistHolder(View itemView, Action<int> listener, Action<int> longListener) : base(itemView)
|
||||
{
|
||||
Title = itemView.FindViewById<TextView>(Resource.Id.title);
|
||||
Owner = itemView.FindViewById<TextView>(Resource.Id.artist);
|
||||
AlbumArt = itemView.FindViewById<ImageView>(Resource.Id.albumArt);
|
||||
edit = itemView.FindViewById<ImageView>(Resource.Id.edit);
|
||||
sync = itemView.FindViewById<ImageView>(Resource.Id.sync);
|
||||
SyncLoading = itemView.FindViewById<ProgressBar>(Resource.Id.syncLoading);
|
||||
more = itemView.FindViewById<ImageView>(Resource.Id.moreButton);
|
||||
|
||||
itemView.Click += (sender, e) => listener(AdapterPosition);
|
||||
itemView.LongClick += (sender, e) => longListener(AdapterPosition);
|
||||
}
|
||||
}
|
||||
|
||||
public enum SyncState
|
||||
{
|
||||
False,
|
||||
@@ -3,7 +3,7 @@ using Android.Views;
|
||||
using Android.Widget;
|
||||
using System;
|
||||
|
||||
namespace Opus.Resources.values
|
||||
namespace Opus.DataStructure
|
||||
{
|
||||
public class TwoLineHolder : RecyclerView.ViewHolder
|
||||
{
|
||||
@@ -1,5 +1,6 @@
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using System;
|
||||
|
||||
namespace Opus.DataStructure
|
||||
@@ -14,4 +15,27 @@ namespace Opus.DataStructure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class EmptyHolder : RecyclerView.ViewHolder
|
||||
{
|
||||
public TextView text;
|
||||
public EmptyHolder(View itemView) : base(itemView)
|
||||
{
|
||||
text = (TextView)itemView;
|
||||
}
|
||||
}
|
||||
|
||||
public class HeaderHolder : RecyclerView.ViewHolder
|
||||
{
|
||||
public TextView headerText;
|
||||
public HeaderHolder(View itemView, Action<int> listener, Action<int> longListener) : base(itemView)
|
||||
{
|
||||
headerText = itemView.FindViewById<TextView>(Android.Resource.Id.Title);
|
||||
if (listener != null)
|
||||
{
|
||||
itemView.Click += (sender, e) => listener(AdapterPosition);
|
||||
itemView.LongClick += (sender, e) => longListener(AdapterPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
24
Opus/Code/DataStructure/YtFile.cs
Normal file
24
Opus/Code/DataStructure/YtFile.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace Opus.DataStructure
|
||||
{
|
||||
[System.Serializable]
|
||||
public class YtFile
|
||||
{
|
||||
public Song song;
|
||||
public PlaylistItem playlist;
|
||||
public YtKind Kind;
|
||||
|
||||
public YtFile(Song song, YtKind kind)
|
||||
{
|
||||
this.song = song;
|
||||
Kind = kind;
|
||||
}
|
||||
|
||||
public YtFile(PlaylistItem playlist, YtKind kind)
|
||||
{
|
||||
this.playlist = playlist;
|
||||
Kind = kind;
|
||||
}
|
||||
}
|
||||
|
||||
public enum YtKind { Null, Video, Playlist, Channel, ChannelPreview, Loading }
|
||||
}
|
||||
@@ -1,760 +0,0 @@
|
||||
using Android;
|
||||
using Android.Content;
|
||||
using Android.Content.PM;
|
||||
using Android.Database;
|
||||
using Android.OS;
|
||||
using Android.Provider;
|
||||
using Android.Support.Design.Widget;
|
||||
using Android.Support.V4.App;
|
||||
using Android.Support.V4.Content;
|
||||
using Android.Support.V7.App;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Google.Apis.YouTube.v3;
|
||||
using Java.Lang;
|
||||
using Opus.Adapter;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using SQLite;
|
||||
using Square.Picasso;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using TagLib;
|
||||
using Color = Android.Graphics.Color;
|
||||
using CursorLoader = Android.Support.V4.Content.CursorLoader;
|
||||
using Uri = Android.Net.Uri;
|
||||
|
||||
namespace Opus.Fragments
|
||||
{
|
||||
public class Browse : Fragment, LoaderManager.ILoaderCallbacks
|
||||
{
|
||||
public static Browse instance;
|
||||
public RecyclerView ListView;
|
||||
public BrowseAdapter adapter;
|
||||
public bool focused = true;
|
||||
|
||||
private TextView EmptyView;
|
||||
|
||||
//public Browse() { }
|
||||
//protected Browse(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) { }
|
||||
|
||||
public override void OnActivityCreated(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnActivityCreated(savedInstanceState);
|
||||
MainActivity.instance.contentRefresh.Refresh += OnRefresh;
|
||||
ListView.NestedScrollingEnabled = true;
|
||||
}
|
||||
|
||||
public override void OnDestroy()
|
||||
{
|
||||
MainActivity.instance.contentRefresh.Refresh -= OnRefresh;
|
||||
base.OnDestroy();
|
||||
instance = null;
|
||||
}
|
||||
|
||||
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
View view = inflater.Inflate(Resource.Layout.CompleteRecycler, container, false);
|
||||
|
||||
//if(MainActivity.Theme == 1)
|
||||
// view.SetBackgroundColor(Color.ParseColor("#424242"));
|
||||
|
||||
view.FindViewById(Resource.Id.loading).Visibility = ViewStates.Visible;
|
||||
EmptyView = view.FindViewById<TextView>(Resource.Id.empty);
|
||||
ListView = view.FindViewById<RecyclerView>(Resource.Id.recycler);
|
||||
ListView.SetLayoutManager(new LinearLayoutManager(Android.App.Application.Context));
|
||||
ListView.SetItemAnimator(new DefaultItemAnimator());
|
||||
adapter = new BrowseAdapter();
|
||||
ListView.SetAdapter(adapter);
|
||||
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
PopulateList();
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
return view;
|
||||
}
|
||||
|
||||
public async Task PopulateList()
|
||||
{
|
||||
if (await MainActivity.instance.GetReadPermission() == false)
|
||||
{
|
||||
MainActivity.instance.FindViewById(Resource.Id.loading).Visibility = ViewStates.Gone;
|
||||
EmptyView.Visibility = ViewStates.Visible;
|
||||
EmptyView.Text = GetString(Resource.String.no_permission);
|
||||
return;
|
||||
}
|
||||
|
||||
LoaderManager.GetInstance(this).InitLoader(0, null, this);
|
||||
|
||||
//if (adapter.ItemCount == 0)
|
||||
//{
|
||||
// EmptyView.Visibility = ViewStates.Visible;
|
||||
// EmptyView.Text = MainActivity.instance.Resources.GetString(Resource.String.no_song);
|
||||
//}
|
||||
}
|
||||
|
||||
public Android.Support.V4.Content.Loader OnCreateLoader(int id, Bundle args)
|
||||
{
|
||||
Uri musicUri = MediaStore.Audio.Media.ExternalContentUri;
|
||||
|
||||
return new CursorLoader(Android.App.Application.Context, musicUri, null, null, null, MediaStore.Audio.Media.InterfaceConsts.Title + " ASC");
|
||||
}
|
||||
|
||||
public void OnLoadFinished(Android.Support.V4.Content.Loader loader, Java.Lang.Object data)
|
||||
{
|
||||
adapter.SwapCursor((ICursor)data);
|
||||
}
|
||||
|
||||
public void OnLoaderReset(Android.Support.V4.Content.Loader loader)
|
||||
{
|
||||
adapter.SwapCursor(null);
|
||||
}
|
||||
|
||||
public static Fragment NewInstance()
|
||||
{
|
||||
if (instance == null)
|
||||
instance = new Browse { Arguments = new Bundle() };
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void OnRefresh(object sender, EventArgs e)
|
||||
{
|
||||
if (!focused)
|
||||
return;
|
||||
Refresh();
|
||||
MainActivity.instance.contentRefresh.Refreshing = false;
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
adapter.NotifyDataSetChanged();
|
||||
}
|
||||
|
||||
//SHOULD CALL THIS METHOD EVERYTIME THE SEARCHBAR TEXT CHANGE
|
||||
public void Search(string search)
|
||||
{
|
||||
LoaderManager.GetInstance(this).RestartLoader(0, null, this);
|
||||
|
||||
//result = new List<Song>();
|
||||
//foreach(Song item in musicList)
|
||||
//{
|
||||
// if(item.Title.ToLower().Contains(search.ToLower()) || item.Artist.ToLower().Contains(search.ToLower()))
|
||||
// {
|
||||
// result.Add(item);
|
||||
// }
|
||||
//}
|
||||
//adapter = new BrowseAdapter(result, result.Count == musicList.Count);
|
||||
//adapter.ItemClick += ListView_ItemClick;
|
||||
//adapter.ItemLongCLick += ListView_ItemLongClick;
|
||||
//Console.WriteLine("&ListView: " + ListView);
|
||||
//ListView.SetAdapter(adapter);
|
||||
}
|
||||
|
||||
public void More(Song item)
|
||||
{
|
||||
item = CompleteItem(item);
|
||||
|
||||
BottomSheetDialog bottomSheet = new BottomSheetDialog(MainActivity.instance);
|
||||
View bottomView = MainActivity.instance.LayoutInflater.Inflate(Resource.Layout.BottomSheet, null);
|
||||
bottomView.FindViewById<TextView>(Resource.Id.bsTitle).Text = item.Title;
|
||||
bottomView.FindViewById<TextView>(Resource.Id.bsArtist).Text = item.Artist;
|
||||
bottomSheet.SetContentView(bottomView);
|
||||
if (item.Album == null)
|
||||
{
|
||||
var songCover = Uri.Parse("content://media/external/audio/albumart");
|
||||
var songAlbumArtUri = ContentUris.WithAppendedId(songCover, item.AlbumArt);
|
||||
|
||||
Picasso.With(MainActivity.instance).Load(songAlbumArtUri).Placeholder(Resource.Drawable.noAlbum).Resize(400, 400).CenterCrop().Into(bottomView.FindViewById<ImageView>(Resource.Id.bsArt));
|
||||
}
|
||||
else
|
||||
{
|
||||
Picasso.With(MainActivity.instance).Load(item.Album).Placeholder(Resource.Drawable.noAlbum).Transform(new RemoveBlackBorder(true)).Into(bottomView.FindViewById<ImageView>(Resource.Id.bsArt));
|
||||
}
|
||||
|
||||
bottomSheet.FindViewById<ListView>(Resource.Id.bsItems).Adapter = new BottomSheetAdapter(MainActivity.instance, Resource.Layout.BottomSheetText, new List<BottomSheetAction>
|
||||
{
|
||||
new BottomSheetAction(Resource.Drawable.Play, MainActivity.instance.Resources.GetString(Resource.String.play), (sender, eventArg) => { Play(item); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistPlay, MainActivity.instance.Resources.GetString(Resource.String.play_next), (sender, eventArg) => { PlayNext(item); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.Queue, MainActivity.instance.Resources.GetString(Resource.String.play_last), (sender, eventArg) => { PlayLast(item); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistAdd, MainActivity.instance.Resources.GetString(Resource.String.add_to_playlist), (sender, eventArg) => { GetPlaylist(item); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.Edit, MainActivity.instance.Resources.GetString(Resource.String.edit_metadata), (sender, eventArg) => { EditMetadata(item); bottomSheet.Dismiss(); })
|
||||
});
|
||||
bottomSheet.Show();
|
||||
}
|
||||
|
||||
public static Song GetSong(string filePath)
|
||||
{
|
||||
string Title = "Unknow";
|
||||
string Artist = "Unknow";
|
||||
long AlbumArt = 0;
|
||||
long id = 0;
|
||||
string path;
|
||||
Uri musicUri = MediaStore.Audio.Media.ExternalContentUri;
|
||||
|
||||
if (filePath.StartsWith("content://"))
|
||||
musicUri = Uri.Parse(filePath);
|
||||
|
||||
CursorLoader cursorLoader = new CursorLoader(Android.App.Application.Context, musicUri, null, null, null, null);
|
||||
ICursor musicCursor = (ICursor)cursorLoader.LoadInBackground();
|
||||
if (musicCursor != null && musicCursor.MoveToFirst())
|
||||
{
|
||||
int titleID = musicCursor.GetColumnIndex(MediaStore.Audio.Media.InterfaceConsts.Title);
|
||||
int artistID = musicCursor.GetColumnIndex(MediaStore.Audio.Media.InterfaceConsts.Artist);
|
||||
int thisID = musicCursor.GetColumnIndex(MediaStore.Audio.Media.InterfaceConsts.Id);
|
||||
int pathID = musicCursor.GetColumnIndex(MediaStore.Audio.Media.InterfaceConsts.Data);
|
||||
do
|
||||
{
|
||||
path = musicCursor.GetString(pathID);
|
||||
|
||||
if (path == filePath || filePath.StartsWith("content://"))
|
||||
{
|
||||
Artist = musicCursor.GetString(artistID);
|
||||
Title = musicCursor.GetString(titleID);
|
||||
AlbumArt = musicCursor.GetLong(musicCursor.GetColumnIndex(MediaStore.Audio.Albums.InterfaceConsts.AlbumId));
|
||||
id = musicCursor.GetLong(thisID);
|
||||
|
||||
if (Title == null)
|
||||
Title = "Unknown Title";
|
||||
if (Artist == null)
|
||||
Artist = "Unknow Artist";
|
||||
|
||||
if (filePath.StartsWith("content://"))
|
||||
filePath = path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (musicCursor.MoveToNext());
|
||||
musicCursor.Close();
|
||||
}
|
||||
return new Song(Title, Artist, null, null, AlbumArt, id, filePath);
|
||||
}
|
||||
|
||||
public static Song CompleteItem(Song item)
|
||||
{
|
||||
item.YoutubeID = GetYtID(item.Path);
|
||||
return item;
|
||||
}
|
||||
|
||||
public static string GetYtID(string path)
|
||||
{
|
||||
Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||
var meta = TagLib.File.Create(new StreamFileAbstraction(path, stream, stream));
|
||||
string ytID = meta.Tag.Comment;
|
||||
stream.Dispose();
|
||||
return ytID;
|
||||
}
|
||||
|
||||
public static void Play(Song item)
|
||||
{
|
||||
Context context = Android.App.Application.Context;
|
||||
Intent intent = new Intent(context, typeof(MusicPlayer));
|
||||
intent.PutExtra("file", item.Path);
|
||||
context.StartService(intent);
|
||||
|
||||
MainActivity.instance.ShowPlayer();
|
||||
MusicPlayer.UpdateQueueDataBase();
|
||||
}
|
||||
|
||||
public static void PlayNext(Song item)
|
||||
{
|
||||
Context context = Android.App.Application.Context;
|
||||
Intent intent = new Intent(context, typeof(MusicPlayer));
|
||||
intent.PutExtra("file", item.Path);
|
||||
intent.SetAction("PlayNext");
|
||||
context.StartService(intent);
|
||||
}
|
||||
|
||||
public static void PlayLast(Song item)
|
||||
{
|
||||
Context context = Android.App.Application.Context;
|
||||
Intent intent = new Intent(context, typeof(MusicPlayer));
|
||||
intent.PutExtra("file", item.Path);
|
||||
intent.SetAction("PlayLast");
|
||||
context.StartService(intent);
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
private async static Task<bool> SongIsContained(string audioID, string playlistID)
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = YoutubeEngine.youtubeService.PlaylistItems.List("snippet, contentDetails");
|
||||
request.PlaylistId = playlistID;
|
||||
request.VideoId = audioID;
|
||||
request.MaxResults = 1;
|
||||
|
||||
var response = await request.ExecuteAsync();
|
||||
if (response.Items.Count > 0)
|
||||
return true;
|
||||
}
|
||||
catch (System.Net.Http.HttpRequestException)
|
||||
{
|
||||
MainActivity.instance.Timout();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static async void GetPlaylist(Song item)
|
||||
{
|
||||
List<PlaylistItem> SyncedPlaylists = new List<PlaylistItem>();
|
||||
await Task.Run(() =>
|
||||
{
|
||||
SQLiteConnection db = new SQLiteConnection(Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "SyncedPlaylists.sqlite"));
|
||||
db.CreateTable<PlaylistItem>();
|
||||
|
||||
SyncedPlaylists = db.Table<PlaylistItem>().ToList();
|
||||
});
|
||||
|
||||
List<PlaylistItem> Playlists = new List<PlaylistItem>();
|
||||
|
||||
Uri uri = MediaStore.Audio.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())
|
||||
{
|
||||
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);
|
||||
PlaylistItem playlist = new PlaylistItem(name, id)
|
||||
{
|
||||
SongContained = SongIsContained(item.Id, id)
|
||||
};
|
||||
PlaylistItem synced = SyncedPlaylists.Find(x => x.LocalID == id);
|
||||
if (synced != null)
|
||||
{
|
||||
if (synced.YoutubeID == null)
|
||||
playlist.SyncState = SyncState.Loading;
|
||||
else
|
||||
{
|
||||
playlist.SyncState = SyncState.True;
|
||||
playlist.YoutubeID = synced.YoutubeID;
|
||||
}
|
||||
}
|
||||
Playlists.Add(playlist);
|
||||
}
|
||||
while (cursor.MoveToNext());
|
||||
cursor.Close();
|
||||
}
|
||||
PlaylistItem Loading = new PlaylistItem("Loading", null);
|
||||
Playlists.Add(Loading);
|
||||
|
||||
View Layout = MainActivity.instance.LayoutInflater.Inflate(Resource.Layout.AddToPlaylistLayout, null);
|
||||
if(MainActivity.Theme == 1)
|
||||
{
|
||||
Layout.FindViewById<ImageView>(Resource.Id.leftIcon).SetColorFilter(Color.White);
|
||||
Layout.FindViewById<View>(Resource.Id.divider).SetBackgroundColor(Color.White);
|
||||
}
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.instance, MainActivity.dialogTheme);
|
||||
builder.SetTitle(Resource.String.save_playlist);
|
||||
builder.SetView(Layout);
|
||||
RecyclerView ListView = Layout.FindViewById<RecyclerView>(Resource.Id.recycler);
|
||||
ListView.SetLayoutManager(new LinearLayoutManager(MainActivity.instance));
|
||||
AddToPlaylistAdapter adapter = new AddToPlaylistAdapter(Playlists);
|
||||
ListView.SetAdapter(adapter);
|
||||
adapter.ItemClick += async (sender, position) =>
|
||||
{
|
||||
AddToPlaylistHolder holder = (AddToPlaylistHolder)ListView.GetChildViewHolder(ListView.GetChildAt(position));
|
||||
bool add = !holder.Added.Checked;
|
||||
holder.Added.Checked = add;
|
||||
|
||||
PlaylistItem playlist = Playlists[position];
|
||||
if (add)
|
||||
{
|
||||
if (playlist.LocalID != 0)
|
||||
{
|
||||
if (item.Id == 0 || item.Id == -1)
|
||||
YoutubeEngine.Download(item.Title, item.YoutubeID, playlist.Name);
|
||||
else
|
||||
AddToPlaylist(item, playlist.Name, playlist.LocalID);
|
||||
}
|
||||
if (playlist.YoutubeID != null)
|
||||
YoutubeEngine.AddToPlaylist(item, playlist.YoutubeID);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (playlist.SyncState == SyncState.True && playlist.YoutubeID != null && playlist.LocalID != 0)
|
||||
{
|
||||
if (item.TrackID == null)
|
||||
item = await PlaylistTracks.CompleteItem(item, playlist.YoutubeID);
|
||||
}
|
||||
|
||||
if (item.TrackID != null)
|
||||
{
|
||||
YoutubeEngine.RemoveFromPlaylist(item.TrackID);
|
||||
}
|
||||
if (playlist.LocalID != 0)
|
||||
{
|
||||
ContentResolver resolver = MainActivity.instance.ContentResolver;
|
||||
Uri plUri = MediaStore.Audio.Playlists.Members.GetContentUri("external", playlist.LocalID);
|
||||
resolver.Delete(plUri, MediaStore.Audio.Playlists.Members.AudioId + "=?", new string[] { item.Id.ToString() });
|
||||
}
|
||||
}
|
||||
};
|
||||
builder.SetPositiveButton(Resource.String.ok, (sender, e) => { });
|
||||
AlertDialog dialog = builder.Create();
|
||||
Layout.FindViewById<LinearLayout>(Resource.Id.CreatePlaylist).Click += (sender, e) => { dialog.Dismiss(); CreatePlalistDialog(item); };
|
||||
dialog.Show();
|
||||
|
||||
|
||||
if(item.YoutubeID == null)
|
||||
{
|
||||
item = CompleteItem(item);
|
||||
if (item.YoutubeID == null)
|
||||
{
|
||||
Toast.MakeText(MainActivity.instance, Resource.String.playlist_add_song_not_found, ToastLength.Long).Show();
|
||||
Playlists.Remove(Loading);
|
||||
adapter.NotifyItemRemoved(Playlists.Count);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!await MainActivity.instance.WaitForYoutube())
|
||||
{
|
||||
Toast.MakeText(MainActivity.instance, Resource.String.youtube_loading_error, ToastLength.Long).Show();
|
||||
Playlists.Remove(Loading);
|
||||
adapter.NotifyItemRemoved(Playlists.Count);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
PlaylistsResource.ListRequest request = YoutubeEngine.youtubeService.Playlists.List("snippet");
|
||||
request.Mine = true;
|
||||
request.MaxResults = 50;
|
||||
var response = await request.ExecuteAsync();
|
||||
|
||||
foreach(var playlist in response.Items)
|
||||
{
|
||||
if (SyncedPlaylists.Find(x => x.Name == playlist.Snippet.Title) != null)
|
||||
{
|
||||
int position = Playlists.FindIndex(x => x.Name == playlist.Snippet.Title && x.SyncState == SyncState.Loading);
|
||||
if(position != -1)
|
||||
{
|
||||
Playlists[position].SyncState = SyncState.True;
|
||||
Playlists[position].YoutubeID = playlist.Id;
|
||||
|
||||
AddToPlaylistHolder holder = (AddToPlaylistHolder)ListView.GetChildViewHolder(ListView.GetChildAt(position));
|
||||
holder.SyncLoading.Visibility = ViewStates.Gone;
|
||||
holder.Status.Visibility = ViewStates.Visible;
|
||||
holder.Status.SetImageResource(Resource.Drawable.Sync);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PlaylistItem YtPlaylist = new PlaylistItem(playlist.Snippet.Title, playlist.Id)
|
||||
{
|
||||
SongContained = await SongIsContained(item.YoutubeID, playlist.Id)
|
||||
};
|
||||
Playlists.Insert(Playlists.Count - 1, YtPlaylist);
|
||||
adapter.NotifyItemInserted(Playlists.Count - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Net.Http.HttpRequestException)
|
||||
{
|
||||
MainActivity.instance.Timout();
|
||||
}
|
||||
|
||||
Playlists.Remove(Loading);
|
||||
adapter.NotifyItemRemoved(Playlists.Count);
|
||||
}
|
||||
|
||||
public async static Task CheckWritePermission()
|
||||
{
|
||||
const string permission = Manifest.Permission.WriteExternalStorage;
|
||||
if (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(MainActivity.instance, permission) != (int)Permission.Granted)
|
||||
{
|
||||
string[] permissions = new string[] { permission };
|
||||
MainActivity.instance.RequestPermissions(permissions, 2659);
|
||||
|
||||
await Task.Delay(1000);
|
||||
while (Android.Support.V4.Content.ContextCompat.CheckSelfPermission(MainActivity.instance, permission) != (int)Permission.Granted)
|
||||
await Task.Delay(500);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public async static void AddToPlaylist(Song item, string playList, long LocalID, bool saveAsSynced = false)
|
||||
{
|
||||
if(LocalID == -1)
|
||||
{
|
||||
LocalID = GetPlaylistID(playList);
|
||||
if (LocalID == -1)
|
||||
CreatePlaylist(playList, item, saveAsSynced);
|
||||
else
|
||||
AddToPlaylist(item, playList, LocalID);
|
||||
}
|
||||
else
|
||||
{
|
||||
await CheckWritePermission();
|
||||
|
||||
ContentResolver resolver = MainActivity.instance.ContentResolver;
|
||||
ContentValues value = new ContentValues();
|
||||
value.Put(MediaStore.Audio.Playlists.Members.AudioId, item.Id);
|
||||
value.Put(MediaStore.Audio.Playlists.Members.PlayOrder, 0);
|
||||
resolver.Insert(MediaStore.Audio.Playlists.Members.GetContentUri("external", LocalID), value);
|
||||
}
|
||||
}
|
||||
|
||||
public async static void AddToPlaylist(Song[] items, string playList, long LocalID, bool saveAsSynced = false)
|
||||
{
|
||||
if (LocalID == -1)
|
||||
{
|
||||
LocalID = GetPlaylistID(playList);
|
||||
if (LocalID == -1)
|
||||
CreatePlaylist(playList, items, saveAsSynced);
|
||||
else
|
||||
AddToPlaylist(items, playList, LocalID);
|
||||
}
|
||||
else
|
||||
{
|
||||
await CheckWritePermission();
|
||||
|
||||
ContentResolver resolver = MainActivity.instance.ContentResolver;
|
||||
List<ContentValues> values = new List<ContentValues>();
|
||||
|
||||
foreach (Song item in items)
|
||||
{
|
||||
if(item != null && item.Id != 0 && item.Id != -1)
|
||||
{
|
||||
ContentValues value = new ContentValues();
|
||||
value.Put(MediaStore.Audio.Playlists.Members.AudioId, item.Id);
|
||||
value.Put(MediaStore.Audio.Playlists.Members.PlayOrder, 0);
|
||||
values.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
resolver.BulkInsert(MediaStore.Audio.Playlists.Members.GetContentUri("external", LocalID), values.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public static void CreatePlalistDialog(Song item)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.instance, MainActivity.dialogTheme);
|
||||
builder.SetTitle(Resource.String.new_playlist);
|
||||
View view = MainActivity.instance.LayoutInflater.Inflate(Resource.Layout.CreatePlaylistDialog, null);
|
||||
builder.SetView(view);
|
||||
PlaylistLocationAdapter adapter = new PlaylistLocationAdapter(MainActivity.instance, Android.Resource.Layout.SimpleSpinnerItem, new string[] { MainActivity.instance.GetString(Resource.String.create_local), MainActivity.instance.GetString(Resource.String.create_youtube), MainActivity.instance.GetString(Resource.String.create_synced) })
|
||||
{
|
||||
YoutubeWorkflow = item.YoutubeID != null
|
||||
};
|
||||
adapter.SetDropDownViewResource(Android.Resource.Layout.SimpleSpinnerDropDownItem);
|
||||
view.FindViewById<Spinner>(Resource.Id.playlistLocation).Adapter = adapter;
|
||||
builder.SetNegativeButton(Resource.String.cancel, (senderAlert, args) => { });
|
||||
builder.SetPositiveButton(Resource.String.ok, (senderAlert, args) =>
|
||||
{
|
||||
switch (view.FindViewById<Spinner>(Resource.Id.playlistLocation).SelectedItemPosition)
|
||||
{
|
||||
case 0:
|
||||
CreatePlaylist(view.FindViewById<EditText>(Resource.Id.playlistName).Text, item);
|
||||
break;
|
||||
case 1:
|
||||
YoutubeEngine.CreatePlaylist(view.FindViewById<EditText>(Resource.Id.playlistName).Text, item);
|
||||
break;
|
||||
case 2:
|
||||
CreatePlaylist(view.FindViewById<EditText>(Resource.Id.playlistName).Text, item, true);
|
||||
YoutubeEngine.CreatePlaylist(view.FindViewById<EditText>(Resource.Id.playlistName).Text, item);
|
||||
break;
|
||||
}
|
||||
});
|
||||
builder.Show();
|
||||
}
|
||||
|
||||
public static void CreatePlalistDialog(Song[] songs)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.instance, MainActivity.dialogTheme);
|
||||
builder.SetTitle(Resource.String.new_playlist);
|
||||
View view = MainActivity.instance.LayoutInflater.Inflate(Resource.Layout.CreatePlaylistDialog, null);
|
||||
builder.SetView(view);
|
||||
PlaylistLocationAdapter adapter = new PlaylistLocationAdapter(MainActivity.instance, Android.Resource.Layout.SimpleSpinnerItem, new string[] { MainActivity.instance.GetString(Resource.String.create_local), MainActivity.instance.GetString(Resource.String.create_youtube), MainActivity.instance.GetString(Resource.String.create_synced) })
|
||||
{
|
||||
YoutubeWorkflow = true
|
||||
};
|
||||
adapter.SetDropDownViewResource(Android.Resource.Layout.SimpleSpinnerDropDownItem);
|
||||
view.FindViewById<Spinner>(Resource.Id.playlistLocation).Adapter = adapter;
|
||||
builder.SetNegativeButton(Resource.String.cancel, (senderAlert, args) => { });
|
||||
builder.SetPositiveButton(Resource.String.ok, (senderAlert, args) =>
|
||||
{
|
||||
switch (view.FindViewById<Spinner>(Resource.Id.playlistLocation).SelectedItemPosition)
|
||||
{
|
||||
case 0:
|
||||
CreatePlaylist(view.FindViewById<EditText>(Resource.Id.playlistName).Text, songs);
|
||||
break;
|
||||
case 1:
|
||||
YoutubeEngine.CreatePlaylist(view.FindViewById<EditText>(Resource.Id.playlistName).Text, songs);
|
||||
break;
|
||||
case 2:
|
||||
CreatePlaylist(view.FindViewById<EditText>(Resource.Id.playlistName).Text, songs, true);
|
||||
YoutubeEngine.CreatePlaylist(view.FindViewById<EditText>(Resource.Id.playlistName).Text, songs);
|
||||
break;
|
||||
}
|
||||
});
|
||||
builder.Show();
|
||||
}
|
||||
|
||||
public async static void CreatePlaylist(string name, Song item, bool syncedPlaylist = false)
|
||||
{
|
||||
await CheckWritePermission();
|
||||
|
||||
ContentResolver resolver = MainActivity.instance.ContentResolver;
|
||||
Uri uri = MediaStore.Audio.Playlists.ExternalContentUri;
|
||||
ContentValues value = new ContentValues();
|
||||
value.Put(MediaStore.Audio.Playlists.InterfaceConsts.Name, name);
|
||||
resolver.Insert(uri, value);
|
||||
|
||||
long playlistID = 0;
|
||||
|
||||
CursorLoader loader = new CursorLoader(Android.App.Application.Context, uri, null, null, null, null);
|
||||
ICursor cursor = (ICursor)loader.LoadInBackground();
|
||||
|
||||
if (cursor != null && cursor.MoveToFirst())
|
||||
{
|
||||
int nameID = cursor.GetColumnIndex(MediaStore.Audio.Playlists.InterfaceConsts.Name);
|
||||
int getplaylistID = cursor.GetColumnIndex(MediaStore.Audio.Playlists.InterfaceConsts.Id);
|
||||
do
|
||||
{
|
||||
string playlistName = cursor.GetString(nameID);
|
||||
long id = cursor.GetLong(getplaylistID);
|
||||
|
||||
if (playlistName == name)
|
||||
playlistID = id;
|
||||
}
|
||||
while (cursor.MoveToNext());
|
||||
cursor.Close();
|
||||
}
|
||||
|
||||
if(item != null)
|
||||
{
|
||||
if (item.Id == 0 || item.Id == -1)
|
||||
YoutubeEngine.Download(item.Title, item.YoutubeID, name);
|
||||
else
|
||||
AddToPlaylist(item, name, playlistID);
|
||||
}
|
||||
|
||||
if (syncedPlaylist)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
SQLiteConnection db = new SQLiteConnection(Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "SyncedPlaylists.sqlite"));
|
||||
db.CreateTable<PlaylistItem>();
|
||||
db.InsertOrReplace(new PlaylistItem(name, playlistID, null));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async static void CreatePlaylist(string name, Song[] items, bool syncedPlaylist = false)
|
||||
{
|
||||
await CheckWritePermission();
|
||||
|
||||
ContentResolver resolver = MainActivity.instance.ContentResolver;
|
||||
Uri uri = MediaStore.Audio.Playlists.ExternalContentUri;
|
||||
ContentValues value = new ContentValues();
|
||||
value.Put(MediaStore.Audio.Playlists.InterfaceConsts.Name, name);
|
||||
resolver.Insert(uri, value);
|
||||
|
||||
long playlistID = 0;
|
||||
|
||||
CursorLoader loader = new CursorLoader(Android.App.Application.Context, uri, null, null, null, null);
|
||||
ICursor cursor = (ICursor)loader.LoadInBackground();
|
||||
|
||||
if (cursor != null && cursor.MoveToFirst())
|
||||
{
|
||||
int nameID = cursor.GetColumnIndex(MediaStore.Audio.Playlists.InterfaceConsts.Name);
|
||||
int getplaylistID = cursor.GetColumnIndex(MediaStore.Audio.Playlists.InterfaceConsts.Id);
|
||||
do
|
||||
{
|
||||
string playlistName = cursor.GetString(nameID);
|
||||
long id = cursor.GetLong(getplaylistID);
|
||||
|
||||
if (playlistName == name)
|
||||
playlistID = id;
|
||||
}
|
||||
while (cursor.MoveToNext());
|
||||
cursor.Close();
|
||||
}
|
||||
|
||||
if (items != null && items.Length > 0)
|
||||
{
|
||||
AddToPlaylist(items, name, playlistID); //Will only add files already downloaded
|
||||
YoutubeEngine.DownloadFiles(items, name); //Will download missing files and add them
|
||||
}
|
||||
|
||||
if (syncedPlaylist)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
SQLiteConnection db = new SQLiteConnection(Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "SyncedPlaylists.sqlite"));
|
||||
db.CreateTable<PlaylistItem>();
|
||||
db.InsertOrReplace(new PlaylistItem(name, playlistID, null));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static long GetPlaylistID(string playlistName)
|
||||
{
|
||||
Uri uri = MediaStore.Audio.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())
|
||||
{
|
||||
int nameID = cursor.GetColumnIndex(MediaStore.Audio.Playlists.InterfaceConsts.Name);
|
||||
int plID = cursor.GetColumnIndex(MediaStore.Audio.Playlists.InterfaceConsts.Id);
|
||||
do
|
||||
{
|
||||
string name = cursor.GetString(nameID);
|
||||
|
||||
if (name != playlistName)
|
||||
continue;
|
||||
|
||||
return cursor.GetLong(plID);
|
||||
}
|
||||
while (cursor.MoveToNext());
|
||||
cursor.Close();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static void EditMetadata(Song item)
|
||||
{
|
||||
item = CompleteItem(item);
|
||||
Intent intent = new Intent(Android.App.Application.Context, typeof(EditMetaData));
|
||||
intent.PutExtra("Song", item.ToString());
|
||||
MainActivity.instance.StartActivity(intent);
|
||||
}
|
||||
|
||||
public override void OnViewStateRestored(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnViewStateRestored(savedInstanceState);
|
||||
instance.ListView = View.FindViewById<RecyclerView>(Resource.Id.recycler);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,12 @@ using Google.Apis.Auth.OAuth2;
|
||||
using Google.Apis.Services;
|
||||
using Google.Apis.YouTube.v3;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Opus.Api;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Fragments;
|
||||
using Opus.Others;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using Opus.Resources.values;
|
||||
using SQLite;
|
||||
using Square.Picasso;
|
||||
using System;
|
||||
@@ -41,13 +45,11 @@ using YoutubeExplode;
|
||||
using CursorLoader = Android.Support.V4.Content.CursorLoader;
|
||||
using Environment = Android.OS.Environment;
|
||||
using Fragment = Android.Support.V4.App.Fragment;
|
||||
using Playlist = Opus.Resources.Portable_Class.Playlist;
|
||||
using Playlist = Opus.Fragments.Playlist;
|
||||
using Request = Square.OkHttp.Request;
|
||||
using SearchView = Android.Support.V7.Widget.SearchView;
|
||||
using Toolbar = Android.Support.V7.Widget.Toolbar;
|
||||
using TransportType = Android.Net.TransportType;
|
||||
using Opus.Fragments;
|
||||
using Opus.DataStructure;
|
||||
|
||||
namespace Opus
|
||||
{
|
||||
@@ -345,7 +347,7 @@ namespace Opus
|
||||
|
||||
JToken json = JObject.Parse(response);
|
||||
GoogleCredential credential = GoogleCredential.FromAccessToken((string)json.SelectToken("access_token"));
|
||||
YoutubeEngine.youtubeService = new YouTubeService(new BaseClientService.Initializer()
|
||||
YoutubeSearch.youtubeService = new YouTubeService(new BaseClientService.Initializer()
|
||||
{
|
||||
HttpClientInitializer = credential,
|
||||
ApplicationName = "Opus"
|
||||
@@ -411,7 +413,7 @@ namespace Opus
|
||||
|
||||
JToken json = JObject.Parse(response);
|
||||
GoogleCredential credential = GoogleCredential.FromAccessToken((string)json.SelectToken("access_token"));
|
||||
YoutubeEngine.youtubeService = new YouTubeService(new BaseClientService.Initializer()
|
||||
YoutubeSearch.youtubeService = new YouTubeService(new BaseClientService.Initializer()
|
||||
{
|
||||
HttpClientInitializer = credential,
|
||||
ApplicationName = "Opus"
|
||||
@@ -444,14 +446,14 @@ namespace Opus
|
||||
|
||||
public async Task<bool> WaitForYoutube()
|
||||
{
|
||||
if(YoutubeEngine.youtubeService == null)
|
||||
if(YoutubeSearch.youtubeService == null)
|
||||
{
|
||||
if(!waitingForYoutube)
|
||||
Login(true);
|
||||
|
||||
waitingForYoutube = true;
|
||||
|
||||
while (YoutubeEngine.youtubeService == null)
|
||||
while (YoutubeSearch.youtubeService == null)
|
||||
{
|
||||
if (waitingForYoutube == false)
|
||||
return false;
|
||||
@@ -522,7 +524,7 @@ namespace Opus
|
||||
SupportFragmentManager.PopBackStack();
|
||||
//SupportFragmentManager.BeginTransaction().Remove(PlaylistTracks.instance).Commit();
|
||||
}
|
||||
else if (YoutubeEngine.instances != null)
|
||||
else if (YoutubeSearch.instances != null)
|
||||
{
|
||||
var searchView = menu.FindItem(Resource.Id.search).ActionView.JavaCast<SearchView>();
|
||||
menu.FindItem(Resource.Id.search).CollapseActionView();
|
||||
@@ -530,7 +532,7 @@ namespace Opus
|
||||
searchView.Iconified = true;
|
||||
searchView.SetQuery("", false);
|
||||
SupportActionBar.SetDisplayHomeAsUpEnabled(false);
|
||||
YoutubeEngine.instances = null;
|
||||
YoutubeSearch.instances = null;
|
||||
}
|
||||
//else if (FolderTracks.instance != null)
|
||||
//{
|
||||
@@ -552,7 +554,7 @@ namespace Opus
|
||||
public bool OnMenuItemActionCollapse(IMenuItem item) //Youtube search collapse
|
||||
{
|
||||
Console.WriteLine("&Youtube Search Collapse");
|
||||
if (YoutubeEngine.instances == null || SearchableActivity.IgnoreMyself)
|
||||
if (YoutubeSearch.instances == null || SearchableActivity.IgnoreMyself)
|
||||
return true;
|
||||
|
||||
Console.WriteLine("&Youtube instnace != null");
|
||||
@@ -632,7 +634,7 @@ namespace Opus
|
||||
{
|
||||
contentRefresh.Refreshing = false;
|
||||
|
||||
if (YoutubeEngine.instances != null)
|
||||
if (YoutubeSearch.instances != null)
|
||||
{
|
||||
var searchView = menu.FindItem(Resource.Id.search).ActionView.JavaCast<SearchView>();
|
||||
menu.FindItem(Resource.Id.search).CollapseActionView();
|
||||
@@ -912,7 +914,9 @@ namespace Opus
|
||||
while (MusicPlayer.instance == null)
|
||||
await Task.Delay(10);
|
||||
|
||||
MusicPlayer.instance.RandomPlay(songs, true);
|
||||
Random r = new Random();
|
||||
songs = songs.OrderBy(x => r.Next()).ToList();
|
||||
MusicPlayer.instance.AddToQueue(songs.ToArray());
|
||||
|
||||
ShowSmallPlayer();
|
||||
ShowPlayer();
|
||||
@@ -1039,7 +1043,7 @@ namespace Opus
|
||||
{
|
||||
if (item.YoutubeID != null)
|
||||
{
|
||||
YoutubeEngine.DownloadPlaylist(item.Name, item.YoutubeID, false);
|
||||
YoutubeManager.DownloadPlaylist(item.Name, item.YoutubeID, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1214,7 +1218,7 @@ namespace Opus
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
YoutubeEngine.instances = null;
|
||||
YoutubeSearch.instances = null;
|
||||
|
||||
if (MusicPlayer.instance != null && !MusicPlayer.isRunning && Preferences.instance == null && EditMetaData.instance == null)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Media;
|
||||
using Opus.Api.Services;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Others
|
||||
{
|
||||
[IntentFilter(new[] { AudioManager.ActionAudioBecomingNoisy })]
|
||||
public class AudioStopper : BroadcastReceiver
|
||||
@@ -1,8 +1,9 @@
|
||||
using Android.Gms.Cast.Framework.Media;
|
||||
using Android.Widget;
|
||||
using Opus.Api.Services;
|
||||
using System;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Others
|
||||
{
|
||||
public class CastCallback : RemoteMediaClient.Callback
|
||||
{
|
||||
@@ -1,8 +1,9 @@
|
||||
using Android.Gms.Cast.Framework.Media;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Resources.values;
|
||||
using Opus.Fragments;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Others
|
||||
{
|
||||
public class CastQueueManager : MediaQueue.Callback
|
||||
{
|
||||
@@ -2,11 +2,11 @@
|
||||
using Square.Picasso;
|
||||
using System;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Others
|
||||
{
|
||||
public class CircleTransformation : Java.Lang.Object, ITransformation
|
||||
{
|
||||
private bool UseBorder = false;
|
||||
private readonly bool UseBorder = false;
|
||||
public string Key => "Circle-" + UseBorder;
|
||||
|
||||
public CircleTransformation() { }
|
||||
@@ -2,8 +2,12 @@
|
||||
using Android.Graphics.Drawables;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Support.V7.Widget.Helper;
|
||||
using Opus.Adapter;
|
||||
using Opus.Api.Services;
|
||||
using Opus.Fragments;
|
||||
using Opus.Resources.Portable_Class;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Others
|
||||
{
|
||||
public class ItemTouchCallback : ItemTouchHelper.Callback
|
||||
{
|
||||
@@ -20,7 +24,7 @@ namespace Opus.Resources.Portable_Class
|
||||
if (alwaysAllowSwap)
|
||||
return true;
|
||||
|
||||
if (PlaylistTracks.instance != null && (!PlaylistTracks.instance.hasWriteAcess || ((PlaylistTrackAdapter)adapter)?.IsEmpty == true))
|
||||
if (PlaylistTracks.instance != null && (!PlaylistTracks.instance.item.HasWritePermission || ((PlaylistTrackAdapter)adapter)?.IsEmpty == true))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using Android.Graphics;
|
||||
using Square.Picasso;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Others
|
||||
{
|
||||
public class RemoveBlackBorder : Java.Lang.Object, ITransformation
|
||||
{
|
||||
40
Opus/Code/Others/RemoveTrackFromPlaylistCallback.cs
Normal file
40
Opus/Code/Others/RemoveTrackFromPlaylistCallback.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Android.Support.Design.Widget;
|
||||
using Opus.Api;
|
||||
using Opus.DataStructure;
|
||||
|
||||
namespace Opus.Others
|
||||
{
|
||||
public class RemoveTrackFromPlaylistCallback : BaseTransientBottomBar.BaseCallback
|
||||
{
|
||||
private Song song;
|
||||
private readonly long LocalPlaylistID;
|
||||
public bool canceled = false;
|
||||
|
||||
public RemoveTrackFromPlaylistCallback(Song song, long LocalPlaylistID)
|
||||
{
|
||||
this.song = song;
|
||||
this.LocalPlaylistID = LocalPlaylistID;
|
||||
}
|
||||
|
||||
public override void OnDismissed(Java.Lang.Object transientBottomBar, int @event)
|
||||
{
|
||||
base.OnDismissed(transientBottomBar, @event);
|
||||
if(!canceled)
|
||||
{
|
||||
if (song.TrackID != null)
|
||||
{
|
||||
PlaylistManager.RemoveFromYoutubePlaylist(song.TrackID);
|
||||
}
|
||||
if (LocalPlaylistID != 0)
|
||||
{
|
||||
PlaylistManager.RemoveFromLocalPlaylist(song, LocalPlaylistID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnShown(Java.Lang.Object transientBottomBar)
|
||||
{
|
||||
base.OnShown(transientBottomBar);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ using Opus.DataStructure;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Adapter
|
||||
{
|
||||
public class AddToPlaylistAdapter : RecyclerView.Adapter
|
||||
{
|
||||
@@ -2,13 +2,12 @@
|
||||
using Android.Content.Res;
|
||||
using Android.Graphics;
|
||||
using Android.Graphics.Drawables;
|
||||
using Android.Support.V4.Content;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Adapter
|
||||
{
|
||||
public class BottomSheetAction
|
||||
{
|
||||
@@ -4,6 +4,7 @@ using Android.Database;
|
||||
using Android.Graphics;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Opus.Api;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Fragments;
|
||||
using Square.Picasso;
|
||||
@@ -58,7 +59,7 @@ namespace Opus.Adapter
|
||||
|
||||
var songCover = Android.Net.Uri.Parse("content://media/external/audio/albumart");
|
||||
var songAlbumArtUri = ContentUris.WithAppendedId(songCover, song.AlbumArt);
|
||||
Picasso.With(Application.Context).Load(songAlbumArtUri).Placeholder(Resource.Color.background_material_dark).Resize(400, 400).CenterCrop().Into(holder.AlbumArt);
|
||||
Picasso.With(Application.Context).Load(songAlbumArtUri).Placeholder(Resource.Color.placeholder).Resize(400, 400).CenterCrop().Into(holder.AlbumArt);
|
||||
|
||||
if (!holder.more.HasOnClickListeners)
|
||||
{
|
||||
@@ -98,8 +99,8 @@ namespace Opus.Adapter
|
||||
|
||||
public override void Clicked(Song song)
|
||||
{
|
||||
song = Browse.CompleteItem(song);
|
||||
Browse.Play(song);
|
||||
song = LocalManager.CompleteItem(song);
|
||||
SongManager.Play(song);
|
||||
}
|
||||
|
||||
public override void LongClicked(Song song)
|
||||
@@ -2,8 +2,11 @@
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Fragments;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Adapter
|
||||
{
|
||||
public class DownloadQueueAdapter : RecyclerView.Adapter
|
||||
{
|
||||
@@ -1,20 +1,13 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Android.Content;
|
||||
using Android.Content.Res;
|
||||
using Android.Graphics;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.Fragments;
|
||||
using Opus.Resources.values;
|
||||
using Android.Graphics;
|
||||
using Android.Content.Res;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Adapter
|
||||
{
|
||||
public class FolderAdapter : ArrayAdapter
|
||||
{
|
||||
@@ -1,17 +1,17 @@
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Android.Graphics;
|
||||
using Android.Graphics.Drawables;
|
||||
using Android.Support.Design.Widget;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Util;
|
||||
using Android.Views;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Fragments;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using Opus.Resources.values;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static Android.Content.Res.Resources;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Adapter
|
||||
{
|
||||
public class HomeAdapter : RecyclerView.Adapter
|
||||
{
|
||||
@@ -84,7 +84,7 @@ namespace Opus.Resources.Portable_Class
|
||||
position = holder.AdapterPosition;
|
||||
MainActivity.instance.contentRefresh.Refresh -= Home.instance.OnRefresh;
|
||||
Home.instance = null;
|
||||
MainActivity.instance.SupportFragmentManager.BeginTransaction().Replace(Resource.Id.contentView, PlaylistTracks.NewInstance(items[position].contentValue, items[position].SectionTitle)).AddToBackStack(null).Commit();
|
||||
//MainActivity.instance.SupportFragmentManager.BeginTransaction().Replace(Resource.Id.contentView, PlaylistTracks.NewInstance(items[position].contentValue, items[position].SectionTitle)).AddToBackStack(null).Commit();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Content.Res;
|
||||
using Android.Graphics;
|
||||
using Android.Support.V7.Preferences;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.Api;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Resources.values;
|
||||
using Opus.Fragments;
|
||||
using Opus.Others;
|
||||
using Square.Picasso;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Adapter
|
||||
{
|
||||
public class HomeListAdapter : RecyclerView.Adapter
|
||||
{
|
||||
@@ -59,8 +57,8 @@ namespace Opus.Resources.Portable_Class
|
||||
if(!holder.RightButtons.FindViewById<ImageButton>(Resource.Id.play).HasOnClickListeners)
|
||||
{
|
||||
//Only support local playlists for now.
|
||||
holder.RightButtons.FindViewById<ImageButton>(Resource.Id.play).Click += (sender, e) => { Playlist.PlayInOrder(playlists[position].LocalID); };
|
||||
holder.RightButtons.FindViewById<ImageButton>(Resource.Id.shuffle).Click += (sender, e) => { Playlist.RandomPlay(playlists[position].LocalID, MainActivity.instance); };
|
||||
holder.RightButtons.FindViewById<ImageButton>(Resource.Id.play).Click += (sender, e) => { PlaylistManager.PlayInOrder(playlists[position]); };
|
||||
holder.RightButtons.FindViewById<ImageButton>(Resource.Id.shuffle).Click += (sender, e) => { PlaylistManager.Shuffle(playlists[position]); };
|
||||
}
|
||||
|
||||
if(MainActivity.Theme == 1)
|
||||
@@ -100,14 +98,7 @@ namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
MainActivity.instance.contentRefresh.Refresh -= Home.instance.OnRefresh;
|
||||
Home.instance = null;
|
||||
PlaylistItem playlist = playlists[position];
|
||||
|
||||
if (playlist.SyncState == SyncState.True || playlist.SyncState == SyncState.Loading)
|
||||
MainActivity.instance.SupportFragmentManager.BeginTransaction().Replace(Resource.Id.contentView, PlaylistTracks.NewInstance(playlist.YoutubeID, playlist.LocalID, playlist.Name, playlist.HasWritePermission, true, playlist.Owner, playlist.Count, playlist.ImageURL)).AddToBackStack("Playlist Track").Commit();
|
||||
else if (playlist.LocalID != 0 && playlist.LocalID != -1)
|
||||
MainActivity.instance.SupportFragmentManager.BeginTransaction().Replace(Resource.Id.contentView, PlaylistTracks.NewInstance(playlist.LocalID, playlist.Name)).AddToBackStack("Playlist Track").Commit();
|
||||
else
|
||||
MainActivity.instance.SupportFragmentManager.BeginTransaction().Replace(Resource.Id.contentView, PlaylistTracks.NewInstance(playlist.YoutubeID, playlist.Name, playlist.HasWritePermission, true, playlist.Owner, playlist.Count, playlist.ImageURL)).AddToBackStack("Playlist Track").Commit();
|
||||
MainActivity.instance.SupportFragmentManager.BeginTransaction().Replace(Resource.Id.contentView, PlaylistTracks.NewInstance(playlists[position], false)).AddToBackStack("Playlist Track").Commit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Gms.Cast.Framework.Media;
|
||||
using Android.Graphics;
|
||||
using Android.Net;
|
||||
using Android.Support.Design.Widget;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.Api;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Fragments;
|
||||
using Opus.Resources.values;
|
||||
using Opus.Others;
|
||||
using Square.Picasso;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Adapter
|
||||
{
|
||||
public class LineAdapter : RecyclerView.Adapter
|
||||
{
|
||||
@@ -153,7 +151,7 @@ namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
if (UseQueue)
|
||||
{
|
||||
if(MusicPlayer.instance != null)
|
||||
if (MusicPlayer.instance != null)
|
||||
MusicPlayer.instance.SwitchQueue(position);
|
||||
else
|
||||
{
|
||||
@@ -163,10 +161,8 @@ namespace Opus.Resources.Portable_Class
|
||||
MainActivity.instance.StartService(intent);
|
||||
}
|
||||
}
|
||||
else if (!songList[position].IsYt)
|
||||
Browse.Play(songList[position]);
|
||||
else
|
||||
YoutubeEngine.Play(songList[position].YoutubeID, songList[position].Title, songList[position].Artist, songList[position].Album);
|
||||
SongManager.Play(songList[position]);
|
||||
}
|
||||
|
||||
void OnLongClick(int position)
|
||||
@@ -196,7 +192,7 @@ namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
new BottomSheetAction(Resource.Drawable.Play, MainActivity.instance.Resources.GetString(Resource.String.play), (sender, eventArg) => { OnClick(position); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.Close, MainActivity.instance.Resources.GetString(Resource.String.remove_from_queue), (sender, eventArg) => { MusicPlayer.RemoveFromQueue(position); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistAdd, MainActivity.instance.Resources.GetString(Resource.String.add_to_playlist), (sender, eventArg) => { Browse.GetPlaylist(item); bottomSheet.Dismiss(); })
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistAdd, MainActivity.instance.Resources.GetString(Resource.String.add_to_playlist), (sender, eventArg) => { PlaylistManager.AddSongToPlaylistDialog(item); bottomSheet.Dismiss(); })
|
||||
};
|
||||
|
||||
if (item.IsYt)
|
||||
@@ -205,12 +201,12 @@ namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
new BottomSheetAction(Resource.Drawable.PlayCircle, MainActivity.instance.Resources.GetString(Resource.String.create_mix_from_song), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeEngine.CreateMix(item);
|
||||
YoutubeManager.CreateMixFromSong(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.Download, MainActivity.instance.Resources.GetString(Resource.String.download), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeEngine.Download(item.Title, item.YoutubeID);
|
||||
YoutubeManager.Download(new[] { item }, null);
|
||||
bottomSheet.Dismiss();
|
||||
})
|
||||
});
|
||||
@@ -219,7 +215,7 @@ namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
actions.Add(new BottomSheetAction(Resource.Drawable.Edit, MainActivity.instance.Resources.GetString(Resource.String.edit_metadata), (sender, eventArg) =>
|
||||
{
|
||||
Browse.EditMetadata(item);
|
||||
LocalManager.EditMetadata(item);
|
||||
bottomSheet.Dismiss();
|
||||
}));
|
||||
}
|
||||
@@ -250,36 +246,31 @@ namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
new BottomSheetAction(Resource.Drawable.Play, MainActivity.instance.Resources.GetString(Resource.String.play), (sender, eventArg) =>
|
||||
{
|
||||
if (!item.IsYt)
|
||||
Browse.Play(item);
|
||||
else
|
||||
YoutubeEngine.Play(item.YoutubeID, item.Title, item.Artist, item.Album);
|
||||
SongManager.Play(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistPlay, MainActivity.instance.Resources.GetString(Resource.String.play_next), (sender, eventArg) =>
|
||||
{
|
||||
if (!item.IsYt)
|
||||
Browse.PlayNext(item);
|
||||
else
|
||||
YoutubeEngine.PlayNext(item.YoutubeID, item.Title, item.Artist, item.Album);
|
||||
SongManager.PlayNext(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.Queue, MainActivity.instance.Resources.GetString(Resource.String.play_last), (sender, eventArg) =>
|
||||
{
|
||||
if (!item.IsYt)
|
||||
Browse.PlayLast(item);
|
||||
else
|
||||
YoutubeEngine.PlayLast(item.YoutubeID, item.Title, item.Artist, item.Album);
|
||||
SongManager.PlayLast(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistAdd, MainActivity.instance.Resources.GetString(Resource.String.add_to_playlist), (sender, eventArg) => { Browse.GetPlaylist(item); bottomSheet.Dismiss(); })
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistAdd, MainActivity.instance.Resources.GetString(Resource.String.add_to_playlist), (sender, eventArg) =>
|
||||
{
|
||||
PlaylistManager.AddSongToPlaylistDialog(item);
|
||||
bottomSheet.Dismiss();
|
||||
})
|
||||
};
|
||||
|
||||
if (!item.IsYt)
|
||||
{
|
||||
actions.Add(new BottomSheetAction(Resource.Drawable.Edit, MainActivity.instance.Resources.GetString(Resource.String.edit_metadata), (sender, eventArg) =>
|
||||
{
|
||||
Browse.EditMetadata(item);
|
||||
LocalManager.EditMetadata(item);
|
||||
bottomSheet.Dismiss();
|
||||
}));
|
||||
}
|
||||
@@ -289,12 +280,12 @@ namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
new BottomSheetAction(Resource.Drawable.PlayCircle, MainActivity.instance.Resources.GetString(Resource.String.create_mix_from_song), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeEngine.CreateMix(item);
|
||||
YoutubeManager.CreateMixFromSong(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.Download, MainActivity.instance.Resources.GetString(Resource.String.download), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeEngine.Download(item.Title, item.YoutubeID);
|
||||
YoutubeManager.Download(new[] { item }, null);
|
||||
bottomSheet.Dismiss();
|
||||
})
|
||||
});
|
||||
@@ -1,17 +1,18 @@
|
||||
using Android.App;
|
||||
using Android.Content.Res;
|
||||
using Android.Graphics;
|
||||
using Android.Graphics.Drawables;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Resources.values;
|
||||
using Opus.Fragments;
|
||||
using Opus.Others;
|
||||
using Square.Picasso;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Adapter
|
||||
{
|
||||
public class PlaylistAdapter : RecyclerView.Adapter
|
||||
{
|
||||
@@ -5,7 +5,7 @@ using Android.Widget;
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Adapter
|
||||
{
|
||||
public class PlaylistLocationAdapter : ArrayAdapter
|
||||
{
|
||||
@@ -8,14 +8,16 @@ using Android.Text;
|
||||
using Android.Text.Style;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Resources.values;
|
||||
using Opus.Others;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using Square.Picasso;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using PopupMenu = Android.Support.V7.Widget.PopupMenu;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Adapter
|
||||
{
|
||||
public class QueueAdapter : RecyclerView.Adapter, IItemTouchAdapter
|
||||
{
|
||||
@@ -1,13 +1,12 @@
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Java.Lang;
|
||||
using Opus.Fragments;
|
||||
using Opus.Resources.values;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Adapter
|
||||
{
|
||||
public class SuggestionAdapter : ArrayAdapter
|
||||
{
|
||||
@@ -1,19 +1,18 @@
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Android.Support.V7.App;
|
||||
using Android.Support.V7.Preferences;
|
||||
using Android.Graphics;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.Api;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Fragments;
|
||||
using Opus.Others;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using Opus.Resources.values;
|
||||
using Square.Picasso;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Adapter
|
||||
{
|
||||
public class YtAdapter : RecyclerView.Adapter
|
||||
{
|
||||
@@ -31,11 +30,10 @@ namespace Opus.Resources.Portable_Class
|
||||
|
||||
public override void OnBindViewHolder(RecyclerView.ViewHolder viewHolder, int position)
|
||||
{
|
||||
Song song = items[position].item;
|
||||
|
||||
if(items[position].Kind == YtKind.Video)
|
||||
{
|
||||
SongHolder holder = (SongHolder)viewHolder;
|
||||
Song song = items[position].song;
|
||||
|
||||
holder.Title.Text = song.Title;
|
||||
holder.Artist.Text = song.Artist;
|
||||
@@ -50,7 +48,7 @@ namespace Opus.Resources.Portable_Class
|
||||
holder.more.Click += (sender, e) =>
|
||||
{
|
||||
int tagPosition = (int)((ImageView)sender).Tag;
|
||||
YoutubeEngine.instances[0].More(items[tagPosition].item);
|
||||
YoutubeSearch.instances[0].More(items[tagPosition].song);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -87,11 +85,12 @@ namespace Opus.Resources.Portable_Class
|
||||
else if (items[position].Kind == YtKind.Playlist)
|
||||
{
|
||||
PlaylistHolder holder = (PlaylistHolder)viewHolder;
|
||||
PlaylistItem playlist = items[position].playlist;
|
||||
|
||||
holder.Title.Text = song.Title;
|
||||
holder.Owner.Text = song.Artist;
|
||||
holder.Title.Text = playlist.Name;
|
||||
holder.Owner.Text = playlist.Owner;
|
||||
|
||||
var songAlbumArtUri = Android.Net.Uri.Parse(song.Album);
|
||||
var songAlbumArtUri = Android.Net.Uri.Parse(playlist.ImageURL);
|
||||
Picasso.With(Android.App.Application.Context).Load(songAlbumArtUri).Placeholder(Resource.Color.background_material_dark).Transform(new RemoveBlackBorder(true)).Into(holder.AlbumArt);
|
||||
|
||||
holder.more.Tag = position;
|
||||
@@ -100,7 +99,7 @@ namespace Opus.Resources.Portable_Class
|
||||
holder.more.Click += (sender, e) =>
|
||||
{
|
||||
int tagPosition = (int)((ImageView)sender).Tag;
|
||||
YoutubeEngine.instances[0].PlaylistMore(items[tagPosition].item);
|
||||
YoutubeSearch.instances[0].PlaylistMore(items[tagPosition].playlist);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -115,6 +114,7 @@ namespace Opus.Resources.Portable_Class
|
||||
else if(items[position].Kind == YtKind.Channel)
|
||||
{
|
||||
RecyclerChannelHolder holder = (RecyclerChannelHolder)viewHolder;
|
||||
Song song = items[position].song; // SHOULD USE A CHANNEL STRUCTURE
|
||||
|
||||
holder.Title.Text = song.Title;
|
||||
Picasso.With(Android.App.Application.Context).Load(song.Album).Placeholder(Resource.Color.background_material_dark).Transform(new CircleTransformation(false)).Into(holder.AlbumArt);
|
||||
@@ -123,7 +123,7 @@ namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
holder.action.Click += (sender, e) =>
|
||||
{
|
||||
YoutubeEngine.instances[0].MixFromChannel(song.YoutubeID);
|
||||
YoutubeManager.MixFromChannel(song.YoutubeID);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -135,15 +135,16 @@ namespace Opus.Resources.Portable_Class
|
||||
else if(items[position].Kind == YtKind.ChannelPreview)
|
||||
{
|
||||
ChannelPreviewHolder holder = (ChannelPreviewHolder)viewHolder;
|
||||
Song song = items[position].song;
|
||||
|
||||
holder.Name.Text = song.Title;
|
||||
Picasso.With(Android.App.Application.Context).Load(song.Album).Placeholder(Resource.Color.background_material_dark).Transform(new CircleTransformation(true)).Into(holder.Logo);
|
||||
|
||||
List<YtFile> files = items.FindAll(x => x.item.Artist == song.Title && x.Kind == YtKind.Video);
|
||||
List<YtFile> files = items.FindAll(x => x.song.Artist == song.Title && x.Kind == YtKind.Video);
|
||||
if(files.Count > 0)
|
||||
Picasso.With(Android.App.Application.Context).Load(files[0].item.Album).Transform(new RemoveBlackBorder()).Into(holder.MixOne);
|
||||
Picasso.With(Android.App.Application.Context).Load(files[0].song.Album).Transform(new RemoveBlackBorder()).Into(holder.MixOne);
|
||||
if (files.Count > 1)
|
||||
Picasso.With(Android.App.Application.Context).Load(files[1].item.Album).Transform(new RemoveBlackBorder()).Into(holder.MixTwo);
|
||||
Picasso.With(Android.App.Application.Context).Load(files[1].song.Album).Transform(new RemoveBlackBorder()).Into(holder.MixTwo);
|
||||
|
||||
holder.MixOne.ViewTreeObserver.Draw += (sender, e) =>
|
||||
{
|
||||
@@ -154,7 +155,7 @@ namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
holder.MixHolder.Click += (sender, e) =>
|
||||
{
|
||||
YoutubeEngine.instances?[0]?.MixFromChannel(song.YoutubeID);
|
||||
YoutubeManager.MixFromChannel(song.YoutubeID);
|
||||
};
|
||||
}
|
||||
|
||||
180
Opus/Code/UI/Fragments/Browse.cs
Normal file
180
Opus/Code/UI/Fragments/Browse.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
using Android.Content;
|
||||
using Android.Database;
|
||||
using Android.OS;
|
||||
using Android.Provider;
|
||||
using Android.Support.Design.Widget;
|
||||
using Android.Support.V4.App;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.Adapter;
|
||||
using Opus.Api;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Others;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using Square.Picasso;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using CursorLoader = Android.Support.V4.Content.CursorLoader;
|
||||
using Uri = Android.Net.Uri;
|
||||
|
||||
namespace Opus.Fragments
|
||||
{
|
||||
public class Browse : Fragment, LoaderManager.ILoaderCallbacks
|
||||
{
|
||||
public static Browse instance;
|
||||
public RecyclerView ListView;
|
||||
public BrowseAdapter adapter;
|
||||
public bool focused = true;
|
||||
|
||||
private string query = null;
|
||||
private TextView EmptyView;
|
||||
|
||||
public override void OnActivityCreated(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnActivityCreated(savedInstanceState);
|
||||
MainActivity.instance.contentRefresh.Refresh += OnRefresh;
|
||||
ListView.NestedScrollingEnabled = true;
|
||||
}
|
||||
|
||||
public override void OnDestroy()
|
||||
{
|
||||
MainActivity.instance.contentRefresh.Refresh -= OnRefresh;
|
||||
base.OnDestroy();
|
||||
instance = null;
|
||||
}
|
||||
|
||||
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
View view = inflater.Inflate(Resource.Layout.CompleteRecycler, container, false);
|
||||
view.FindViewById(Resource.Id.loading).Visibility = ViewStates.Visible;
|
||||
EmptyView = view.FindViewById<TextView>(Resource.Id.empty);
|
||||
ListView = view.FindViewById<RecyclerView>(Resource.Id.recycler);
|
||||
ListView.SetLayoutManager(new LinearLayoutManager(Android.App.Application.Context));
|
||||
ListView.SetItemAnimator(new DefaultItemAnimator());
|
||||
adapter = new BrowseAdapter();
|
||||
ListView.SetAdapter(adapter);
|
||||
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
PopulateList();
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
return view;
|
||||
}
|
||||
|
||||
public async Task PopulateList()
|
||||
{
|
||||
if (await MainActivity.instance.GetReadPermission() == false)
|
||||
{
|
||||
MainActivity.instance.FindViewById(Resource.Id.loading).Visibility = ViewStates.Gone;
|
||||
EmptyView.Visibility = ViewStates.Visible;
|
||||
EmptyView.Text = GetString(Resource.String.no_permission);
|
||||
return;
|
||||
}
|
||||
|
||||
LoaderManager.GetInstance(this).InitLoader(0, null, this);
|
||||
|
||||
//if (adapter.ItemCount == 0)
|
||||
//{
|
||||
// EmptyView.Visibility = ViewStates.Visible;
|
||||
// EmptyView.Text = MainActivity.instance.Resources.GetString(Resource.String.no_song);
|
||||
//}
|
||||
}
|
||||
|
||||
public Android.Support.V4.Content.Loader OnCreateLoader(int id, Bundle args)
|
||||
{
|
||||
Uri musicUri = MediaStore.Audio.Media.ExternalContentUri;
|
||||
string selection;
|
||||
if (query != null)
|
||||
{
|
||||
selection = MediaStore.Audio.Media.InterfaceConsts.Title + " LIKE '%" + query + "%' OR " + MediaStore.Audio.Media.InterfaceConsts.Artist + " LIKE '%" + query + "%'";
|
||||
adapter.displayShuffle = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
selection = null;
|
||||
adapter.displayShuffle = true;
|
||||
}
|
||||
|
||||
return new CursorLoader(Android.App.Application.Context, musicUri, null, selection, null, MediaStore.Audio.Media.InterfaceConsts.Title + " ASC");
|
||||
}
|
||||
|
||||
public void OnLoadFinished(Android.Support.V4.Content.Loader loader, Java.Lang.Object data)
|
||||
{
|
||||
adapter.SwapCursor((ICursor)data);
|
||||
}
|
||||
|
||||
public void OnLoaderReset(Android.Support.V4.Content.Loader loader)
|
||||
{
|
||||
adapter.SwapCursor(null);
|
||||
}
|
||||
|
||||
public static Fragment NewInstance()
|
||||
{
|
||||
if (instance == null)
|
||||
instance = new Browse { Arguments = new Bundle() };
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void OnRefresh(object sender, EventArgs e)
|
||||
{
|
||||
if (!focused)
|
||||
return;
|
||||
Refresh();
|
||||
MainActivity.instance.contentRefresh.Refreshing = false;
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
adapter.NotifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void Search(string search)
|
||||
{
|
||||
if (search == "")
|
||||
query = null;
|
||||
else
|
||||
query = search;
|
||||
|
||||
LoaderManager.GetInstance(this).RestartLoader(0, null, this);
|
||||
}
|
||||
|
||||
public void More(Song item)
|
||||
{
|
||||
item = LocalManager.CompleteItem(item);
|
||||
|
||||
BottomSheetDialog bottomSheet = new BottomSheetDialog(MainActivity.instance);
|
||||
View bottomView = MainActivity.instance.LayoutInflater.Inflate(Resource.Layout.BottomSheet, null);
|
||||
bottomView.FindViewById<TextView>(Resource.Id.bsTitle).Text = item.Title;
|
||||
bottomView.FindViewById<TextView>(Resource.Id.bsArtist).Text = item.Artist;
|
||||
bottomSheet.SetContentView(bottomView);
|
||||
if (item.Album == null)
|
||||
{
|
||||
var songCover = Uri.Parse("content://media/external/audio/albumart");
|
||||
var songAlbumArtUri = ContentUris.WithAppendedId(songCover, item.AlbumArt);
|
||||
|
||||
Picasso.With(MainActivity.instance).Load(songAlbumArtUri).Placeholder(Resource.Drawable.noAlbum).Resize(400, 400).CenterCrop().Into(bottomView.FindViewById<ImageView>(Resource.Id.bsArt));
|
||||
}
|
||||
else
|
||||
{
|
||||
Picasso.With(MainActivity.instance).Load(item.Album).Placeholder(Resource.Drawable.noAlbum).Transform(new RemoveBlackBorder(true)).Into(bottomView.FindViewById<ImageView>(Resource.Id.bsArt));
|
||||
}
|
||||
|
||||
bottomSheet.FindViewById<ListView>(Resource.Id.bsItems).Adapter = new BottomSheetAdapter(MainActivity.instance, Resource.Layout.BottomSheetText, new List<BottomSheetAction>
|
||||
{
|
||||
new BottomSheetAction(Resource.Drawable.Play, MainActivity.instance.Resources.GetString(Resource.String.play), (sender, eventArg) => { SongManager.Play(item); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistPlay, MainActivity.instance.Resources.GetString(Resource.String.play_next), (sender, eventArg) => { SongManager.PlayNext(item); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.Queue, MainActivity.instance.Resources.GetString(Resource.String.play_last), (sender, eventArg) => { SongManager.PlayLast(item); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistAdd, MainActivity.instance.Resources.GetString(Resource.String.add_to_playlist), (sender, eventArg) => { PlaylistManager.AddSongToPlaylistDialog(item); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.Edit, MainActivity.instance.Resources.GetString(Resource.String.edit_metadata), (sender, eventArg) => { LocalManager.EditMetadata(item); bottomSheet.Dismiss(); })
|
||||
});
|
||||
bottomSheet.Show();
|
||||
}
|
||||
|
||||
public override void OnViewStateRestored(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnViewStateRestored(savedInstanceState);
|
||||
instance.ListView = View.FindViewById<RecyclerView>(Resource.Id.recycler);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,13 @@ using Android.Support.V4.App;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Java.IO;
|
||||
using Opus.Adapter;
|
||||
using Opus.Resources.values;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Fragments
|
||||
{
|
||||
[Register("Opus/DownloadFragment")]
|
||||
public class DownloadFragment : ListFragment
|
||||
@@ -4,8 +4,12 @@ using Android.OS;
|
||||
using Android.Support.V7.App;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Opus.Adapter;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Resources.Portable_Class;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Fragments
|
||||
{
|
||||
[Activity(Label = "DownloadQueue", Theme = "@style/Theme")]
|
||||
public class DownloadQueue : AppCompatActivity, PopupMenu.IOnMenuItemClickListener
|
||||
@@ -4,7 +4,6 @@ using Android.Content;
|
||||
using Android.Content.PM;
|
||||
using Android.Graphics;
|
||||
using Android.OS;
|
||||
using Android.Preferences;
|
||||
using Android.Provider;
|
||||
using Android.Runtime;
|
||||
using Android.Support.Design.Widget;
|
||||
@@ -13,17 +12,16 @@ using Android.Util;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Resources.values;
|
||||
using Opus.Others;
|
||||
using Square.Picasso;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using TagLib;
|
||||
using YoutubeExplode;
|
||||
using YoutubeExplode.Models;
|
||||
using Picture = TagLib.Picture;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Fragments
|
||||
{
|
||||
[Activity(Label = "EditMetaData", Theme = "@style/Theme", WindowSoftInputMode = SoftInput.AdjustResize|SoftInput.StateHidden)]
|
||||
public class EditMetaData : AppCompatActivity
|
||||
@@ -1,15 +1,14 @@
|
||||
using Android.Content;
|
||||
using Android.Database;
|
||||
using Android.Net;
|
||||
using Android.Database;
|
||||
using Android.OS;
|
||||
using Android.Provider;
|
||||
using Android.Support.V4.App;
|
||||
using Android.Support.V7.Preferences;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Support.V7.Widget.Helper;
|
||||
using Android.Views;
|
||||
using Google.Apis.YouTube.v3;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using Opus.Adapter;
|
||||
using Opus.Api;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Resources.values;
|
||||
using System;
|
||||
@@ -17,8 +16,9 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CursorLoader = Android.Support.V4.Content.CursorLoader;
|
||||
using PlaylistItem = Opus.DataStructure.PlaylistItem;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Fragments
|
||||
{
|
||||
public class Home : Fragment
|
||||
{
|
||||
@@ -129,10 +129,10 @@ namespace Opus.Resources.Portable_Class
|
||||
adapter.ItemClick += ListView_ItemClick;
|
||||
ListView.SetItemAnimator(new DefaultItemAnimator());
|
||||
|
||||
(List<PlaylistItem> playlists, string error) = await Playlist.GetLocalPlaylists(false);
|
||||
(List<PlaylistItem> playlists, string error) = await PlaylistManager.GetLocalPlaylists(false);
|
||||
if(playlists != null)
|
||||
{
|
||||
(List<PlaylistItem> pl, List<PlaylistItem> sp) = await Playlist.ProcessSyncedPlaylists(playlists);
|
||||
(List<PlaylistItem> pl, List<PlaylistItem> sp) = await PlaylistManager.ProcessSyncedPlaylists(playlists);
|
||||
sp.AddRange(pl);
|
||||
adapterItems.Add(new HomeSection(GetString(Resource.String.playlists), SectionType.PlaylistList, sp));
|
||||
adapter.NotifyItemInserted(adapterItems.Count - 1);
|
||||
@@ -190,6 +190,12 @@ namespace Opus.Resources.Portable_Class
|
||||
QueueAdapter?.NotifyItemInserted(position);
|
||||
}
|
||||
|
||||
public void NotifyQueueRangeInserted(int position, int count)
|
||||
{
|
||||
if (adapterItems.Count > 0)
|
||||
QueueAdapter?.NotifyItemRangeInserted(position, count);
|
||||
}
|
||||
|
||||
public void NotifyQueueChanged(int position, Java.Lang.Object payload)
|
||||
{
|
||||
if (adapterItems.Count > 0)
|
||||
459
Opus/Code/UI/Fragments/Playlist.cs
Normal file
459
Opus/Code/UI/Fragments/Playlist.cs
Normal file
@@ -0,0 +1,459 @@
|
||||
using Android.Content.Res;
|
||||
using Android.Graphics;
|
||||
using Android.OS;
|
||||
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 Opus.Adapter;
|
||||
using Opus.Api;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Others;
|
||||
using Square.Picasso;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Application = Android.App.Application;
|
||||
using PlaylistItem = Opus.DataStructure.PlaylistItem;
|
||||
|
||||
namespace Opus.Fragments
|
||||
{
|
||||
public class Playlist : Fragment
|
||||
{
|
||||
public static Playlist instance;
|
||||
public RecyclerView ListView;
|
||||
private PlaylistAdapter adapter;
|
||||
private bool populating = false;
|
||||
|
||||
private List<PlaylistItem> LocalPlaylists = new List<PlaylistItem>();
|
||||
private List<PlaylistItem> YoutubePlaylists = new List<PlaylistItem>();
|
||||
|
||||
|
||||
public override void OnActivityCreated(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnActivityCreated(savedInstanceState);
|
||||
MainActivity.instance.contentRefresh.Refresh += OnRefresh;
|
||||
}
|
||||
|
||||
public override void OnDestroy()
|
||||
{
|
||||
MainActivity.instance.contentRefresh.Refresh -= OnRefresh;
|
||||
base.OnDestroy();
|
||||
instance = null;
|
||||
}
|
||||
|
||||
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
View view = inflater.Inflate(Resource.Layout.RecyclerFragment, container, false);
|
||||
ListView = view.FindViewById<RecyclerView>(Resource.Id.recycler);
|
||||
ListView.SetLayoutManager(new LinearLayoutManager(Application.Context));
|
||||
instance = this;
|
||||
|
||||
#pragma warning disable CS4014
|
||||
populating = false;
|
||||
PopulateView();
|
||||
return view;
|
||||
}
|
||||
|
||||
public async Task PopulateView()
|
||||
{
|
||||
System.Console.WriteLine("&Populating - " + populating);
|
||||
if (!populating)
|
||||
{
|
||||
populating = true;
|
||||
|
||||
//Initialisation
|
||||
LocalPlaylists.Clear();
|
||||
YoutubePlaylists.Clear();
|
||||
LocalPlaylists.Add(new PlaylistItem("Header", -1));
|
||||
YoutubePlaylists.Add(new PlaylistItem("Header", null));
|
||||
PlaylistItem Loading = new PlaylistItem("Loading", null);
|
||||
|
||||
//Get all local playlist and display an error message if we have an error.
|
||||
System.Console.WriteLine("&Getting local playlists");
|
||||
(List<PlaylistItem> locPlaylists, string error) = await PlaylistManager.GetLocalPlaylists();
|
||||
System.Console.WriteLine("&Local playlist got");
|
||||
if (instance == null)
|
||||
return;
|
||||
|
||||
if (locPlaylists == null) //an error has occured
|
||||
LocalPlaylists.Add(new PlaylistItem("EMPTY", -1) { Owner = error });
|
||||
|
||||
System.Console.WriteLine("&LocalPlaylist got");
|
||||
//Handle synced playlist from the local playlist array we had before.
|
||||
(List<PlaylistItem> loc, List<PlaylistItem> SyncedPlaylists) = await PlaylistManager.ProcessSyncedPlaylists(locPlaylists);
|
||||
|
||||
if (instance == null)
|
||||
return;
|
||||
|
||||
LocalPlaylists.AddRange(loc);
|
||||
YoutubePlaylists.AddRange(SyncedPlaylists);
|
||||
|
||||
System.Console.WriteLine("&Synced got");
|
||||
//Display this for now, we'll load non synced youtube playlist in the background.
|
||||
YoutubePlaylists.Add(Loading);
|
||||
adapter = new PlaylistAdapter(LocalPlaylists, YoutubePlaylists);
|
||||
ListView.SetAdapter(adapter);
|
||||
adapter.ItemClick += ListView_ItemClick;
|
||||
adapter.ItemLongCLick += ListView_ItemLongClick;
|
||||
ListView.SetItemAnimator(new DefaultItemAnimator());
|
||||
System.Console.WriteLine("&ListView created");
|
||||
|
||||
//Youtube owned playlists
|
||||
(List<PlaylistItem> yt, string err) = await PlaylistManager.GetOwnedYoutubePlaylists(SyncedPlaylists, YoutubeItemSynced);
|
||||
|
||||
if (instance == null)
|
||||
return;
|
||||
|
||||
if (yt == null)
|
||||
{
|
||||
YoutubePlaylists.Remove(Loading);
|
||||
adapter.NotifyItemRemoved(LocalPlaylists.Count + YoutubePlaylists.Count);
|
||||
YoutubePlaylists.Add(new PlaylistItem("Error", null)); //Should use the "err" var here
|
||||
adapter.NotifyItemInserted(LocalPlaylists.Count + YoutubePlaylists.Count);
|
||||
populating = false;
|
||||
SyncError();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
int startPos = YoutubePlaylists.Count - 1;
|
||||
YoutubePlaylists.InsertRange(startPos, yt);
|
||||
adapter.NotifyItemRangeInserted(LocalPlaylists.Count + startPos, yt.Count);
|
||||
}
|
||||
|
||||
//Youtube saved playlists
|
||||
(yt, error) = await PlaylistManager.GetSavedYoutubePlaylists(SyncedPlaylists, YoutubeItemSynced);
|
||||
|
||||
if (instance == null)
|
||||
return;
|
||||
|
||||
if (yt == null)
|
||||
{
|
||||
YoutubePlaylists.Remove(Loading);
|
||||
adapter.NotifyItemRemoved(LocalPlaylists.Count + YoutubePlaylists.Count);
|
||||
YoutubePlaylists.Add(new PlaylistItem("Error", null)); //Should use the "error" var here
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public async void StartSyncing(string playlistName)
|
||||
{
|
||||
int LocalIndex = LocalPlaylists.FindIndex(x => x.Name == playlistName);
|
||||
if (LocalIndex != -1)
|
||||
{
|
||||
LocalPlaylists.RemoveAt(LocalIndex);
|
||||
adapter.NotifyItemRemoved(LocalIndex);
|
||||
if (LocalPlaylists.Count == 1)
|
||||
{
|
||||
LocalPlaylists.Add(new PlaylistItem("EMPTY", -1) { Owner = Resources.GetString(Resource.String.local_playlist_empty) });
|
||||
adapter.NotifyItemInserted(1);
|
||||
}
|
||||
await Task.Delay(500);
|
||||
}
|
||||
|
||||
int YoutubeIndex = YoutubePlaylists.FindIndex(x => x.Name == playlistName);
|
||||
YoutubePlaylists[YoutubeIndex].SyncState = SyncState.Loading;
|
||||
PlaylistHolder holder = (PlaylistHolder)ListView.GetChildViewHolder(ListView.GetChildAt(LocalPlaylists.Count + YoutubeIndex));
|
||||
holder.sync.Visibility = ViewStates.Gone;
|
||||
holder.SyncLoading.Visibility = ViewStates.Visible;
|
||||
if (MainActivity.Theme == 1)
|
||||
holder.SyncLoading.IndeterminateTintList = ColorStateList.ValueOf(Color.White);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//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()
|
||||
{
|
||||
if(instance == null)
|
||||
instance = new Playlist { Arguments = new Bundle() };
|
||||
return instance;
|
||||
}
|
||||
|
||||
private async void OnRefresh(object sender, System.EventArgs e)
|
||||
{
|
||||
await Refresh();
|
||||
MainActivity.instance.contentRefresh.Refreshing = false;
|
||||
}
|
||||
|
||||
public async Task Refresh()
|
||||
{
|
||||
await PopulateView();
|
||||
}
|
||||
|
||||
private void ListView_ItemClick(object sender, int Position)
|
||||
{
|
||||
if(Position == LocalPlaylists.Count + YoutubePlaylists.Count)
|
||||
{
|
||||
View view = LayoutInflater.Inflate(Resource.Layout.SaveAPlaylist, null);
|
||||
AlertDialog dialog = new AlertDialog.Builder(Activity, MainActivity.dialogTheme)
|
||||
.SetTitle(Resource.String.add_playlist_msg)
|
||||
.SetView(view)
|
||||
.SetNegativeButton(Resource.String.cancel, (s, eventArgs) => { })
|
||||
.SetPositiveButton(Resource.String.add, /*async*/ (s, eventArgs) =>
|
||||
{
|
||||
string url = view.FindViewById<EditText>(Resource.Id.playlistURL).Text;
|
||||
string shrinkedURL = url.Substring(url.IndexOf('=') + 1);
|
||||
string playlistID = shrinkedURL;
|
||||
if (shrinkedURL.Contains("&"))
|
||||
{
|
||||
playlistID = shrinkedURL.Substring(0, shrinkedURL.IndexOf("&"));
|
||||
}
|
||||
/*await*/ PlaylistManager.ForkPlaylist(playlistID);
|
||||
|
||||
if (YoutubePlaylists.Count == 3 && YoutubePlaylists[1].Name == "EMPTY")
|
||||
{
|
||||
YoutubePlaylists.RemoveAt(1);
|
||||
adapter.NotifyItemChanged(LocalPlaylists.Count + YoutubePlaylists.Count - 1);
|
||||
}
|
||||
else
|
||||
adapter.NotifyItemInserted(LocalPlaylists.Count + YoutubePlaylists.Count);
|
||||
})
|
||||
.Show();
|
||||
return;
|
||||
}
|
||||
|
||||
bool local = Position <= LocalPlaylists.Count;
|
||||
PlaylistItem playlist = local ?
|
||||
LocalPlaylists[Position] :
|
||||
YoutubePlaylists[Position - LocalPlaylists.Count];
|
||||
|
||||
if(playlist.SyncState == SyncState.Error && local)
|
||||
{
|
||||
//Handle sync errors
|
||||
}
|
||||
|
||||
instance = null;
|
||||
MainActivity.instance.contentRefresh.Refresh -= OnRefresh;
|
||||
MainActivity.instance.contentRefresh.Refresh -= OnRefresh;
|
||||
|
||||
MainActivity.instance.SupportFragmentManager.BeginTransaction().Replace(Resource.Id.contentView, PlaylistTracks.NewInstance(playlist, false)).AddToBackStack("Playlist Track").Commit();
|
||||
}
|
||||
|
||||
private void ListView_ItemLongClick(object sender, int position)
|
||||
{
|
||||
More(position);
|
||||
}
|
||||
|
||||
public void More(int Position)
|
||||
{
|
||||
bool local = Position <= LocalPlaylists.Count;
|
||||
PlaylistItem item = local ?
|
||||
LocalPlaylists[Position] :
|
||||
YoutubePlaylists[Position - LocalPlaylists.Count];
|
||||
|
||||
BottomSheetDialog bottomSheet = new BottomSheetDialog(MainActivity.instance);
|
||||
View bottomView = LayoutInflater.Inflate(Resource.Layout.BottomSheet, null);
|
||||
bottomView.FindViewById<TextView>(Resource.Id.bsTitle).Text = item.Name;
|
||||
if (!local || item.SyncState != SyncState.False)
|
||||
{
|
||||
bottomView.FindViewById<TextView>(Resource.Id.bsArtist).Text = item.Owner;
|
||||
Picasso.With(MainActivity.instance).Load(item.ImageURL).Placeholder(Resource.Color.background_material_dark).Transform(new RemoveBlackBorder(true)).Into(bottomView.FindViewById<ImageView>(Resource.Id.bsArt));
|
||||
}
|
||||
else
|
||||
{
|
||||
bottomView.FindViewById<TextView>(Resource.Id.bsArtist).Text = item.Count + " element" + (item.Count == 1 ? "" : "s");
|
||||
bottomView.FindViewById<ImageView>(Resource.Id.bsArt).Visibility = ViewStates.Gone;
|
||||
}
|
||||
bottomSheet.SetContentView(bottomView);
|
||||
|
||||
List<BottomSheetAction> actions = new List<BottomSheetAction>
|
||||
{
|
||||
new BottomSheetAction(Resource.Drawable.Play, Resources.GetString(Resource.String.play_in_order), (sender, eventArg) =>
|
||||
{
|
||||
PlaylistManager.PlayInOrder(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.Shuffle, Resources.GetString(Resource.String.random_play), (sender, eventArg) =>
|
||||
{
|
||||
PlaylistManager.Shuffle(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.Queue, Resources.GetString(Resource.String.add_to_queue), (sender, eventArg) =>
|
||||
{
|
||||
PlaylistManager.AddToQueue(item);
|
||||
bottomSheet.Dismiss();
|
||||
})
|
||||
};
|
||||
|
||||
if (local || item.HasWritePermission)
|
||||
{
|
||||
actions.AddRange(new BottomSheetAction[]{ new BottomSheetAction(Resource.Drawable.Edit, Resources.GetString(Resource.String.rename), (sender, eventArg) =>
|
||||
{
|
||||
PlaylistManager.Rename(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.Delete, Resources.GetString(Resource.String.delete), (sender, eventArg) =>
|
||||
{
|
||||
PlaylistManager.Delete(item, null);
|
||||
bottomSheet.Dismiss();
|
||||
})});
|
||||
}
|
||||
|
||||
if(item.SyncState == SyncState.True)
|
||||
{
|
||||
actions.AddRange(new BottomSheetAction[]{ new BottomSheetAction(Resource.Drawable.Sync, Resources.GetString(Resource.String.sync_now), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeManager.DownloadPlaylist(item.Name, item.YoutubeID);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.SyncDisabled, Resources.GetString(Resource.String.stop_sync), (sender, eventArg) =>
|
||||
{
|
||||
PlaylistManager.StopSyncingDialog(item, () =>
|
||||
{
|
||||
YoutubePlaylists[Position - LocalPlaylists.Count].LocalID = 0;
|
||||
YoutubePlaylists[Position - LocalPlaylists.Count].SyncState = SyncState.False;
|
||||
PlaylistHolder holder = (PlaylistHolder)ListView.GetChildViewHolder(ListView.GetChildAt(Position));
|
||||
holder.sync.Visibility = ViewStates.Gone;
|
||||
holder.SyncLoading.Visibility = ViewStates.Gone;
|
||||
|
||||
PlaylistItem LocalPlaylist = new PlaylistItem(YoutubePlaylists[Position - LocalPlaylists.Count].Name, item.LocalID, YoutubePlaylists[Position - LocalPlaylists.Count].Count);
|
||||
if (LocalPlaylists.Count == 2 && LocalPlaylists[1].Name == "EMPTY")
|
||||
{
|
||||
LocalPlaylists.RemoveAt(1);
|
||||
adapter.NotifyItemRemoved(1);
|
||||
}
|
||||
|
||||
LocalPlaylists.Add(LocalPlaylist);
|
||||
adapter.NotifyItemInserted(LocalPlaylists.Count);
|
||||
});
|
||||
bottomSheet.Dismiss();
|
||||
})});
|
||||
}
|
||||
else if (!local )
|
||||
{
|
||||
actions.Add(new BottomSheetAction(Resource.Drawable.Sync, Resources.GetString(Resource.String.sync), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeManager.DownloadPlaylist(item.Name, item.YoutubeID);
|
||||
bottomSheet.Dismiss();
|
||||
}));
|
||||
|
||||
if(!item.HasWritePermission)
|
||||
{
|
||||
actions.Add(new BottomSheetAction(Resource.Drawable.Delete, Resources.GetString(Resource.String.unfork), (sender, eventArg) =>
|
||||
{
|
||||
PlaylistManager.Unfork(Position, item.YoutubeID);
|
||||
bottomSheet.Dismiss();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
bottomSheet.FindViewById<ListView>(Resource.Id.bsItems).Adapter = new BottomSheetAdapter(MainActivity.instance, Resource.Layout.BottomSheetText, actions);
|
||||
bottomSheet.Show();
|
||||
}
|
||||
|
||||
public void CheckForSync()
|
||||
{
|
||||
for (int i = 1; i < YoutubePlaylists.Count; i++)
|
||||
{
|
||||
if (YoutubePlaylists[i].SyncState != SyncState.False && Downloader.queue.Find(x => x.playlist == YoutubePlaylists[i].Name && (x.State == DownloadState.Downloading || x.State == DownloadState.Initialization || x.State == DownloadState.MetaData || x.State == DownloadState.None)) == null)
|
||||
{
|
||||
YoutubePlaylists[i].SyncState = SyncState.True;
|
||||
PlaylistHolder holder = (PlaylistHolder)ListView.GetChildViewHolder(ListView.GetChildAt(LocalPlaylists.Count + i));
|
||||
holder.SyncLoading.Visibility = ViewStates.Gone;
|
||||
holder.sync.SetImageResource(Resource.Drawable.Sync);
|
||||
holder.sync.Visibility = ViewStates.Visible;
|
||||
if (MainActivity.Theme == 1)
|
||||
holder.sync.SetColorFilter(Color.White);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void SyncCanceled()
|
||||
{
|
||||
for (int i = 0; i < YoutubePlaylists.Count; i++)
|
||||
{
|
||||
if(YoutubePlaylists[i].SyncState == SyncState.Loading)
|
||||
{
|
||||
YoutubePlaylists[i].SyncState = SyncState.True;
|
||||
adapter.NotifyItemChanged(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnResume()
|
||||
{
|
||||
base.OnResume();
|
||||
instance = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,47 +2,38 @@
|
||||
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.Views;
|
||||
using Android.Widget;
|
||||
using Google.Apis.YouTube.v3;
|
||||
using Google.Apis.YouTube.v3.Data;
|
||||
using Opus.Adapter;
|
||||
using Opus.Api;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Fragments;
|
||||
using Opus.Resources.values;
|
||||
using SQLite;
|
||||
using Opus.Others;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using Square.Picasso;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using static Android.Provider.MediaStore.Audio;
|
||||
using CursorLoader = Android.Support.V4.Content.CursorLoader;
|
||||
using PlaylistItem = Opus.DataStructure.PlaylistItem;
|
||||
using PopupMenu = Android.Support.V7.Widget.PopupMenu;
|
||||
using RecyclerView = Android.Support.V7.Widget.RecyclerView;
|
||||
using Toolbar = Android.Support.V7.Widget.Toolbar;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Fragments
|
||||
{
|
||||
public class PlaylistTracks : Fragment, PopupMenu.IOnMenuItemClickListener, AppBarLayout.IOnOffsetChangedListener
|
||||
{
|
||||
public static PlaylistTracks instance;
|
||||
public string playlistName;
|
||||
public PlaylistItem item;
|
||||
public RecyclerView ListView;
|
||||
public PlaylistTrackAdapter adapter;
|
||||
private Android.Support.V7.Widget.Helper.ItemTouchHelper itemTouchHelper;
|
||||
public List<Song> result = null;
|
||||
private bool Synced = false;
|
||||
public long LocalID;
|
||||
public string YoutubeID;
|
||||
private string author;
|
||||
private int count;
|
||||
private Uri thumnailURI;
|
||||
public bool hasWriteAcess;
|
||||
private bool forked;
|
||||
private string nextPageToken = null;
|
||||
public bool fullyLoadded = true;
|
||||
public bool forked;
|
||||
public bool lastVisible = false;
|
||||
public bool useHeader = true;
|
||||
public bool navigating = false;
|
||||
@@ -60,7 +51,7 @@ namespace Opus.Resources.Portable_Class
|
||||
MainActivity.instance.SupportActionBar.SetDisplayHomeAsUpEnabled(true);
|
||||
MainActivity.instance.SupportActionBar.SetDisplayShowTitleEnabled(true);
|
||||
MainActivity.instance.FindViewById(Resource.Id.toolbarLogo).Visibility = ViewStates.Gone;
|
||||
MainActivity.instance.SupportActionBar.Title = playlistName;
|
||||
MainActivity.instance.SupportActionBar.Title = item.Name;
|
||||
}
|
||||
|
||||
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
@@ -92,27 +83,27 @@ namespace Opus.Resources.Portable_Class
|
||||
Activity.FindViewById<RelativeLayout>(Resource.Id.playlistHeader).Visibility = ViewStates.Visible;
|
||||
((AppBarLayout.LayoutParams)Activity.FindViewById<CollapsingToolbarLayout>(Resource.Id.collapsingToolbar).LayoutParameters).ScrollFlags = AppBarLayout.LayoutParams.ScrollFlagScroll | AppBarLayout.LayoutParams.ScrollFlagExitUntilCollapsed;
|
||||
Activity.FindViewById<AppBarLayout>(Resource.Id.appbar).AddOnOffsetChangedListener(this);
|
||||
Activity.FindViewById<TextView>(Resource.Id.headerTitle).Text = playlistName;
|
||||
Activity.FindViewById<TextView>(Resource.Id.headerTitle).Text = item.Name;
|
||||
|
||||
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerPlay).HasOnClickListeners)
|
||||
Activity.FindViewById<ImageButton>(Resource.Id.headerPlay).Click += (sender, e0) => { PlayInOrder(0); };
|
||||
Activity.FindViewById<ImageButton>(Resource.Id.headerPlay).Click += (sender, e0) => { PlaylistManager.PlayInOrder(item); };
|
||||
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerShuffle).HasOnClickListeners)
|
||||
Activity.FindViewById<ImageButton>(Resource.Id.headerShuffle).Click += (sender, e0) => { RandomPlay(); };
|
||||
Activity.FindViewById<ImageButton>(Resource.Id.headerShuffle).Click += (sender, e0) => { PlaylistManager.Shuffle(item); };
|
||||
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerMore).HasOnClickListeners)
|
||||
Activity.FindViewById<ImageButton>(Resource.Id.headerMore).Click += PlaylistMore;
|
||||
|
||||
if (LocalID != 0 && thumnailURI == null)
|
||||
if (item.LocalID != 0 && item.ImageURL == null)
|
||||
{
|
||||
Activity.FindViewById<TextView>(Resource.Id.headerAuthor).Text = MainActivity.account == null ? "by me" : "by " + MainActivity.account.DisplayName;
|
||||
}
|
||||
else if (YoutubeID != null && YoutubeID != "")
|
||||
else if (item.YoutubeID != null && item.YoutubeID != "")
|
||||
{
|
||||
Activity.FindViewById<TextView>(Resource.Id.headerAuthor).Text = author;
|
||||
Activity.FindViewById<TextView>(Resource.Id.headerNumber).Text = count.ToString() + " " + GetString(Resource.String.songs);
|
||||
if (count == -1)
|
||||
Activity.FindViewById<TextView>(Resource.Id.headerAuthor).Text = item.Owner;
|
||||
Activity.FindViewById<TextView>(Resource.Id.headerNumber).Text = item.Count.ToString() + " " + GetString(Resource.String.songs);
|
||||
if (item.Count == -1)
|
||||
Activity.FindViewById<TextView>(Resource.Id.headerNumber).Text = "NaN" + " " + GetString(Resource.String.songs);
|
||||
|
||||
Picasso.With(Android.App.Application.Context).Load(thumnailURI).Placeholder(Resource.Drawable.noAlbum).Transform(new RemoveBlackBorder(true)).Into(Activity.FindViewById<ImageView>(Resource.Id.headerArt));
|
||||
Picasso.With(Android.App.Application.Context).Load(item.ImageURL).Placeholder(Resource.Drawable.noAlbum).Transform(new RemoveBlackBorder(true)).Into(Activity.FindViewById<ImageView>(Resource.Id.headerArt));
|
||||
}
|
||||
Activity.FindViewById(Resource.Id.collapsingToolbar).RequestLayout();
|
||||
}
|
||||
@@ -136,19 +127,19 @@ namespace Opus.Resources.Portable_Class
|
||||
Activity.FindViewById<AppBarLayout>(Resource.Id.appbar).RemoveOnOffsetChangedListener(this);
|
||||
|
||||
|
||||
if (YoutubeEngine.instances != null)
|
||||
if (YoutubeSearch.instances != null)
|
||||
{
|
||||
MainActivity.instance.FindViewById<TabLayout>(Resource.Id.tabs).Visibility = ViewStates.Visible;
|
||||
Android.Support.V7.Widget.SearchView searchView = (Android.Support.V7.Widget.SearchView)MainActivity.instance.menu.FindItem(Resource.Id.search).ActionView;
|
||||
searchView.Focusable = false;
|
||||
MainActivity.instance.menu.FindItem(Resource.Id.search).ExpandActionView();
|
||||
searchView.SetQuery(YoutubeEngine.instances[0].Query, false);
|
||||
searchView.SetQuery(YoutubeSearch.instances[0].Query, false);
|
||||
searchView.ClearFocus();
|
||||
|
||||
int selectedTab = 0;
|
||||
for (int i = 0; i < YoutubeEngine.instances.Length; i++)
|
||||
for (int i = 0; i < YoutubeSearch.instances.Length; i++)
|
||||
{
|
||||
if (YoutubeEngine.instances[i].IsFocused)
|
||||
if (YoutubeSearch.instances[i].IsFocused)
|
||||
selectedTab = i;
|
||||
}
|
||||
}
|
||||
@@ -159,234 +150,57 @@ namespace Opus.Resources.Portable_Class
|
||||
|
||||
|
||||
//Header more click
|
||||
public bool OnMenuItemClick(IMenuItem item)
|
||||
public bool OnMenuItemClick(IMenuItem menuItem)
|
||||
{
|
||||
switch (item.ItemId)
|
||||
switch (menuItem.ItemId)
|
||||
{
|
||||
case Resource.Id.download:
|
||||
YoutubeEngine.DownloadPlaylist(playlistName, YoutubeID);
|
||||
YoutubeManager.DownloadPlaylist(item.Name, item.YoutubeID);
|
||||
break;
|
||||
|
||||
case Resource.Id.fork:
|
||||
#pragma warning disable CS4014
|
||||
YoutubeEngine.ForkPlaylist(YoutubeID);
|
||||
PlaylistManager.ForkPlaylist(item.YoutubeID);
|
||||
break;
|
||||
|
||||
case Resource.Id.addToQueue:
|
||||
if (LocalID != 0)
|
||||
Playlist.AddToQueue(LocalID);
|
||||
else if (YoutubeID != null)
|
||||
Playlist.AddToQueue(YoutubeID);
|
||||
else
|
||||
AddToQueue();
|
||||
PlaylistManager.AddToQueue(item);
|
||||
break;
|
||||
|
||||
case Resource.Id.rename:
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(Activity, MainActivity.dialogTheme);
|
||||
builder.SetTitle(Resource.String.rename_playlist);
|
||||
View view = LayoutInflater.Inflate(Resource.Layout.CreatePlaylistDialog, null);
|
||||
builder.SetView(view);
|
||||
builder.SetNegativeButton(Resource.String.cancel, (senderAlert, args) => { });
|
||||
builder.SetPositiveButton(Resource.String.rename, (senderAlert, args) =>
|
||||
PlaylistManager.Rename(item, (newName) =>
|
||||
{
|
||||
Rename(view.FindViewById<EditText>(Resource.Id.playlistName).Text);
|
||||
MainActivity.instance.FindViewById<TextView>(Resource.Id.headerTitle).Text = newName;
|
||||
});
|
||||
builder.Show();
|
||||
break;
|
||||
|
||||
case Resource.Id.sync:
|
||||
StopSyncing();
|
||||
PlaylistManager.StopSyncingDialog(item, () => { /*SHOULD RECREATE CURSOR LOADER HERE*/ });
|
||||
break;
|
||||
|
||||
case Resource.Id.delete:
|
||||
Delete();
|
||||
PlaylistManager.Delete(item, () =>
|
||||
{
|
||||
MainActivity.instance.SupportFragmentManager.PopBackStack();
|
||||
});
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async void AddToQueue()
|
||||
{
|
||||
List<Song> songs = tracks;
|
||||
if (MusicPlayer.instance == null || MusicPlayer.queue == null || MusicPlayer.queue?.Count == 0)
|
||||
{
|
||||
Song first = songs[0];
|
||||
if (!first.IsYt)
|
||||
{
|
||||
Browse.Play(first);
|
||||
}
|
||||
else
|
||||
YoutubeEngine.Play(first.YoutubeID, first.Title, first.Artist, first.Album);
|
||||
|
||||
songs.RemoveAt(0);
|
||||
}
|
||||
|
||||
while (MusicPlayer.instance == null)
|
||||
await Task.Delay(10);
|
||||
|
||||
songs.Reverse();
|
||||
foreach (Song song in songs)
|
||||
MusicPlayer.instance.AddToQueue(song);
|
||||
}
|
||||
|
||||
async void Rename(string newName)
|
||||
{
|
||||
if(YoutubeID != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Google.Apis.YouTube.v3.Data.Playlist playlist = new Google.Apis.YouTube.v3.Data.Playlist
|
||||
{
|
||||
Snippet = new PlaylistSnippet()
|
||||
};
|
||||
playlist.Snippet.Title = newName;
|
||||
playlist.Id = YoutubeID;
|
||||
|
||||
await YoutubeEngine.youtubeService.Playlists.Update(playlist, "snippet").ExecuteAsync();
|
||||
}
|
||||
catch (System.Net.Http.HttpRequestException)
|
||||
{
|
||||
MainActivity.instance.Timout();
|
||||
}
|
||||
}
|
||||
if(LocalID != 0)
|
||||
{
|
||||
ContentValues value = new ContentValues();
|
||||
value.Put(Playlists.InterfaceConsts.Name, newName);
|
||||
Activity.ContentResolver.Update(Playlists.ExternalContentUri, value, Playlists.InterfaceConsts.Id + "=?", new string[] { LocalID.ToString() });
|
||||
}
|
||||
|
||||
playlistName = newName;
|
||||
Activity.FindViewById<TextView>(Resource.Id.headerTitle).Text = playlistName;
|
||||
}
|
||||
|
||||
void StopSyncing()
|
||||
{
|
||||
AlertDialog dialog = new AlertDialog.Builder(MainActivity.instance, MainActivity.dialogTheme)
|
||||
.SetTitle(Resource.String.stop_syncing)
|
||||
.SetPositiveButton(Resource.String.yes, async (sender, e) =>
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
SQLiteConnection db = new SQLiteConnection(System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "SyncedPlaylists.sqlite"));
|
||||
db.CreateTable<PlaylistItem>();
|
||||
|
||||
db.Delete(db.Table<PlaylistItem>().ToList().Find(x => x.LocalID == LocalID));
|
||||
});
|
||||
MainActivity.instance.SupportFragmentManager.PopBackStack();
|
||||
})
|
||||
.SetNegativeButton(Resource.String.no, (sender, e) => { })
|
||||
.Create();
|
||||
dialog.Show();
|
||||
}
|
||||
|
||||
void Delete()
|
||||
{
|
||||
AlertDialog dialog = new AlertDialog.Builder(MainActivity.instance, MainActivity.dialogTheme)
|
||||
.SetTitle(MainActivity.instance.GetString(Resource.String.delete_playlist, playlistName))
|
||||
.SetPositiveButton(Resource.String.yes, async (sender, e) =>
|
||||
{
|
||||
if (YoutubeID != null)
|
||||
{
|
||||
if (hasWriteAcess)
|
||||
{
|
||||
try
|
||||
{
|
||||
PlaylistsResource.DeleteRequest deleteRequest = YoutubeEngine.youtubeService.Playlists.Delete(YoutubeID);
|
||||
await deleteRequest.ExecuteAsync();
|
||||
}
|
||||
catch (System.Net.Http.HttpRequestException)
|
||||
{
|
||||
MainActivity.instance.Timout();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ChannelSectionsResource.ListRequest forkedRequest = YoutubeEngine.youtubeService.ChannelSections.List("snippet,contentDetails");
|
||||
forkedRequest.Mine = true;
|
||||
ChannelSectionListResponse forkedResponse = await forkedRequest.ExecuteAsync();
|
||||
|
||||
foreach (ChannelSection section in forkedResponse.Items)
|
||||
{
|
||||
if (section.Snippet.Title == "Saved Playlists")
|
||||
{
|
||||
section.ContentDetails.Playlists.Remove(YoutubeID);
|
||||
ChannelSectionsResource.UpdateRequest request = YoutubeEngine.youtubeService.ChannelSections.Update(section, "snippet,contentDetails");
|
||||
ChannelSection response = await request.ExecuteAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Net.Http.HttpRequestException)
|
||||
{
|
||||
MainActivity.instance.Timout();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(LocalID != 0)
|
||||
{
|
||||
ContentResolver resolver = Activity.ContentResolver;
|
||||
Uri uri = Playlists.ExternalContentUri;
|
||||
resolver.Delete(Playlists.ExternalContentUri, Playlists.InterfaceConsts.Id + "=?", new string[] { LocalID.ToString() });
|
||||
}
|
||||
MainActivity.instance.SupportFragmentManager.PopBackStack();
|
||||
})
|
||||
.SetNegativeButton(Resource.String.no, (sender, e) => { })
|
||||
.Create();
|
||||
dialog.Show();
|
||||
}
|
||||
|
||||
public static async Task<Song> CompleteItem(Song song, string YoutubeID)
|
||||
{
|
||||
if (song.YoutubeID == null)
|
||||
song = Browse.CompleteItem(song);
|
||||
|
||||
song.TrackID = null;
|
||||
if (await MainActivity.instance.WaitForYoutube())
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = YoutubeEngine.youtubeService.PlaylistItems.List("snippet");
|
||||
request.PlaylistId = YoutubeID;
|
||||
request.VideoId = song.YoutubeID;
|
||||
request.MaxResults = 1;
|
||||
|
||||
var result = await request.ExecuteAsync();
|
||||
song.TrackID = result.Items[0].Id;
|
||||
}
|
||||
catch (System.Net.Http.HttpRequestException)
|
||||
{
|
||||
MainActivity.instance.Timout();
|
||||
}
|
||||
}
|
||||
else
|
||||
MainActivity.instance.Timout();
|
||||
|
||||
return song;
|
||||
}
|
||||
|
||||
void RandomPlay()
|
||||
{
|
||||
if (instance.LocalID != 0)
|
||||
Playlist.RandomPlay(instance.LocalID, MainActivity.instance);
|
||||
else
|
||||
YoutubeEngine.RandomPlay(instance.YoutubeID);
|
||||
}
|
||||
|
||||
void PlaylistMore(object sender, System.EventArgs eventArgs)
|
||||
{
|
||||
PopupMenu menu = new PopupMenu(MainActivity.instance, MainActivity.instance.FindViewById<ImageButton>(Resource.Id.headerMore));
|
||||
if (LocalID == 0 && hasWriteAcess)
|
||||
if (item.LocalID == 0 && item.HasWritePermission)
|
||||
menu.Inflate(Resource.Menu.ytplaylist_header_more);
|
||||
else if (LocalID == 0 && forked)
|
||||
else if (item.LocalID == 0 && forked)
|
||||
menu.Inflate(Resource.Menu.ytplaylistnowrite_header_more);
|
||||
else if (LocalID == 0)
|
||||
else if (item.LocalID == 0)
|
||||
menu.Inflate(Resource.Menu.ytplaylist_nowrite_nofork_header_more);
|
||||
else
|
||||
menu.Inflate(Resource.Menu.playlist_header_more);
|
||||
|
||||
if (Synced)
|
||||
if (item.SyncState == SyncState.True)
|
||||
{
|
||||
menu.Menu.GetItem(0).SetTitle("Sync Now");
|
||||
menu.Menu.Add(Menu.None, Resource.Id.sync, menu.Menu.Size() - 3, "Stop Syncing");
|
||||
@@ -395,70 +209,35 @@ namespace Opus.Resources.Portable_Class
|
||||
menu.Show();
|
||||
}
|
||||
|
||||
public static Fragment NewInstance(List<Song> songs, string playlistName)
|
||||
{
|
||||
instance = new PlaylistTracks { Arguments = new Bundle() };
|
||||
instance.tracks = songs;
|
||||
instance.playlistName = playlistName;
|
||||
instance.useHeader = false;
|
||||
instance.fullyLoadded = true;
|
||||
instance.hasWriteAcess = false;
|
||||
return instance;
|
||||
}
|
||||
//public static Fragment NewInstance(List<Song> songs, string playlistName)
|
||||
//{
|
||||
// instance = new PlaylistTracks { Arguments = new Bundle() };
|
||||
// instance.tracks = songs;
|
||||
// instance.playlistName = playlistName;
|
||||
// instance.useHeader = false;
|
||||
// instance.fullyLoadded = true;
|
||||
// instance.hasWriteAcess = false;
|
||||
// return instance;
|
||||
//}
|
||||
|
||||
public static Fragment NewInstance(long playlistId, string playlistName)
|
||||
public static Fragment NewInstance(PlaylistItem item, bool forked)
|
||||
{
|
||||
instance = new PlaylistTracks { Arguments = new Bundle() };
|
||||
instance.LocalID = playlistId;
|
||||
instance.playlistName = playlistName;
|
||||
instance.fullyLoadded = true;
|
||||
instance.hasWriteAcess = true;
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static Fragment NewInstance(string ytID, long LocalID, string playlistName, bool hasWriteAcess, bool forked, string author, int count, string thumbnailURI)
|
||||
{
|
||||
instance = new PlaylistTracks { Arguments = new Bundle() };
|
||||
instance.YoutubeID = ytID;
|
||||
instance.LocalID = LocalID;
|
||||
instance.hasWriteAcess = hasWriteAcess;
|
||||
instance.item = item;
|
||||
instance.forked = forked;
|
||||
instance.playlistName = playlistName;
|
||||
instance.author = author;
|
||||
instance.count = count;
|
||||
if(thumbnailURI != null)
|
||||
instance.thumnailURI = Uri.Parse(thumbnailURI);
|
||||
if (LocalID != 0 && LocalID != -1)
|
||||
instance.fullyLoadded = true;
|
||||
else
|
||||
instance.fullyLoadded = false;
|
||||
instance.Synced = true;
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static Fragment NewInstance(string ytID, string playlistName, bool hasWriteAcess, bool forked, string author, int count, string thumbnailURI)
|
||||
{
|
||||
instance = new PlaylistTracks { Arguments = new Bundle() };
|
||||
instance.Synced = false;
|
||||
instance.YoutubeID = ytID;
|
||||
instance.hasWriteAcess = hasWriteAcess;
|
||||
instance.forked = forked;
|
||||
instance.playlistName = playlistName;
|
||||
instance.author = author;
|
||||
instance.count = count;
|
||||
instance.thumnailURI = thumbnailURI == null ? null : Uri.Parse(thumbnailURI);
|
||||
instance.fullyLoadded = false;
|
||||
instance.useHeader = true;
|
||||
instance.fullyLoadded = item.LocalID != 0 && item.LocalID != -1;
|
||||
return instance;
|
||||
}
|
||||
|
||||
async Task PopulateList()
|
||||
{
|
||||
if (LocalID == 0 && YoutubeID == "" && tracks.Count == 0)
|
||||
if (item.LocalID == 0 && item.YoutubeID == "" && tracks.Count == 0)
|
||||
return;
|
||||
|
||||
if (LocalID != 0)
|
||||
if (item.LocalID != 0)
|
||||
{
|
||||
Uri musicUri = Playlists.Members.GetContentUri("external", LocalID);
|
||||
Uri musicUri = Playlists.Members.GetContentUri("external", item.LocalID);
|
||||
|
||||
CursorLoader cursorLoader = new CursorLoader(Android.App.Application.Context, musicUri, null, null, null, null);
|
||||
ICursor musicCursor = (ICursor)cursorLoader.LoadInBackground();
|
||||
@@ -490,8 +269,8 @@ namespace Opus.Resources.Portable_Class
|
||||
Album = "Unknow Album";
|
||||
|
||||
Song song = new Song(Title, Artist, Album, null, AlbumArt, id, path);
|
||||
if (Synced)
|
||||
song = Browse.CompleteItem(song);
|
||||
if (item.SyncState == SyncState.True)
|
||||
song = LocalManager.CompleteItem(song);
|
||||
|
||||
tracks.Add(song);
|
||||
}
|
||||
@@ -512,16 +291,16 @@ namespace Opus.Resources.Portable_Class
|
||||
var songCover = Uri.Parse("content://media/external/audio/albumart");
|
||||
var songAlbumArtUri = ContentUris.WithAppendedId(songCover, tracks[0].AlbumArt);
|
||||
|
||||
if(thumnailURI == null)
|
||||
if(item.ImageURL == null)
|
||||
Picasso.With(Android.App.Application.Context).Load(songAlbumArtUri).Placeholder(Resource.Drawable.noAlbum).Resize(1080, 1080).CenterCrop().Into(Activity.FindViewById<ImageView>(Resource.Id.headerArt));
|
||||
}
|
||||
else if (YoutubeID != null)
|
||||
else if (item.YoutubeID != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
tracks = new List<Song>();
|
||||
var ytPlaylistRequest = YoutubeEngine.youtubeService.PlaylistItems.List("snippet, contentDetails");
|
||||
ytPlaylistRequest.PlaylistId = YoutubeID;
|
||||
var ytPlaylistRequest = YoutubeSearch.youtubeService.PlaylistItems.List("snippet, contentDetails");
|
||||
ytPlaylistRequest.PlaylistId = item.YoutubeID;
|
||||
ytPlaylistRequest.MaxResults = 50;
|
||||
|
||||
var ytPlaylist = await ytPlaylistRequest.ExecuteAsync();
|
||||
@@ -589,8 +368,8 @@ namespace Opus.Resources.Portable_Class
|
||||
loading = true;
|
||||
try
|
||||
{
|
||||
var ytPlaylistRequest = YoutubeEngine.youtubeService.PlaylistItems.List("snippet, contentDetails");
|
||||
ytPlaylistRequest.PlaylistId = YoutubeID;
|
||||
var ytPlaylistRequest = YoutubeSearch.youtubeService.PlaylistItems.List("snippet, contentDetails");
|
||||
ytPlaylistRequest.PlaylistId = item.YoutubeID;
|
||||
ytPlaylistRequest.MaxResults = 50;
|
||||
ytPlaylistRequest.PageToken = nextPageToken;
|
||||
|
||||
@@ -650,7 +429,7 @@ namespace Opus.Resources.Portable_Class
|
||||
if (!useHeader)
|
||||
Position--;
|
||||
|
||||
PlayInOrder(Position);
|
||||
PlaylistManager.PlayInOrder(item, Position);
|
||||
}
|
||||
|
||||
private void ListView_ItemLongClick(object sender, int Position)
|
||||
@@ -686,31 +465,33 @@ namespace Opus.Resources.Portable_Class
|
||||
|
||||
List<BottomSheetAction> actions = new List<BottomSheetAction>
|
||||
{
|
||||
new BottomSheetAction(Resource.Drawable.Play, Resources.GetString(Resource.String.play), (sender, eventArg) => { PlayInOrder(position); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.Play, Resources.GetString(Resource.String.play), (sender, eventArg) =>
|
||||
{
|
||||
PlaylistManager.PlayInOrder(this.item, position);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistPlay, Resources.GetString(Resource.String.play_next), (sender, eventArg) =>
|
||||
{
|
||||
if (!item.IsYt)
|
||||
Browse.PlayNext(item);
|
||||
else
|
||||
YoutubeEngine.PlayNext(item.YoutubeID, item.Title, item.Artist, item.Album);
|
||||
SongManager.PlayNext(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.Queue, Resources.GetString(Resource.String.play_last), (sender, eventArg) =>
|
||||
{
|
||||
if (!item.IsYt)
|
||||
Browse.PlayLast(item);
|
||||
else
|
||||
YoutubeEngine.PlayLast(item.YoutubeID, item.Title, item.Artist, item.Album);
|
||||
SongManager.PlayLast(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistAdd, Resources.GetString(Resource.String.add_to_playlist), (sender, eventArg) => { Browse.GetPlaylist(item); bottomSheet.Dismiss(); })
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistAdd, Resources.GetString(Resource.String.add_to_playlist), (sender, eventArg) =>
|
||||
{
|
||||
PlaylistManager.AddSongToPlaylistDialog(item);
|
||||
bottomSheet.Dismiss();
|
||||
})
|
||||
};
|
||||
|
||||
if (hasWriteAcess && YoutubeID != "")
|
||||
if (this.item.HasWritePermission)
|
||||
{
|
||||
actions.Add(new BottomSheetAction(Resource.Drawable.Close, Resources.GetString(Resource.String.remove_track_from_playlist), (sender, eventArg) =>
|
||||
{
|
||||
DeleteDialog(position);
|
||||
RemoveFromPlaylist(item, position);
|
||||
bottomSheet.Dismiss();
|
||||
}));
|
||||
}
|
||||
@@ -719,10 +500,7 @@ namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
actions.Add(new BottomSheetAction(Resource.Drawable.Edit, Resources.GetString(Resource.String.edit_metadata), (sender, eventArg) =>
|
||||
{
|
||||
if (item.IsYt)
|
||||
YoutubeEngine.Download(item.Title, item.YoutubeID);
|
||||
else
|
||||
Browse.EditMetadata(item);
|
||||
LocalManager.EditMetadata(item);
|
||||
bottomSheet.Dismiss();
|
||||
}));
|
||||
}
|
||||
@@ -732,15 +510,12 @@ namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
new BottomSheetAction(Resource.Drawable.PlayCircle, Resources.GetString(Resource.String.create_mix_from_song), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeEngine.CreateMix(item);
|
||||
YoutubeManager.CreateMixFromSong(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.Download, Resources.GetString(Resource.String.download), (sender, eventArg) =>
|
||||
{
|
||||
if (item.IsYt)
|
||||
YoutubeEngine.Download(item.Title, item.YoutubeID);
|
||||
else
|
||||
Browse.EditMetadata(item);
|
||||
YoutubeManager.Download(new[] { item }, null);
|
||||
bottomSheet.Dismiss();
|
||||
})
|
||||
});
|
||||
@@ -750,66 +525,18 @@ namespace Opus.Resources.Portable_Class
|
||||
bottomSheet.Show();
|
||||
}
|
||||
|
||||
public async void PlayInOrder(int fromPosition)
|
||||
public void RemoveFromPlaylist(Song item, int position)
|
||||
{
|
||||
if (instance.tracks.Count <= fromPosition)
|
||||
return;
|
||||
|
||||
if (instance.YoutubeID != null && !instance.Synced)
|
||||
PlaylistManager.RemoveTrackFromPlaylistDialog(this.item, item, () =>
|
||||
{
|
||||
if (instance.result != null && instance.result.Count > fromPosition)
|
||||
YoutubeEngine.Play(instance.result[fromPosition].YoutubeID, instance.result[fromPosition].Title, instance.result[fromPosition].Artist, instance.result[fromPosition].Album);
|
||||
else
|
||||
YoutubeEngine.Play(instance.tracks[fromPosition].YoutubeID, instance.tracks[fromPosition].Title, instance.tracks[fromPosition].Artist, instance.tracks[fromPosition].Album);
|
||||
|
||||
while (instance.nextPageToken != null)
|
||||
await instance.LoadMore();
|
||||
}
|
||||
|
||||
List<Song> songs = instance.tracks.GetRange(fromPosition, instance.tracks.Count - fromPosition);
|
||||
if (result != null && result.Count > fromPosition)
|
||||
songs = instance.result.GetRange(fromPosition, instance.result.Count - fromPosition);
|
||||
|
||||
if (!songs[0].IsYt)
|
||||
adapter.NotifyItemRemoved(position);
|
||||
}, () =>
|
||||
{
|
||||
Browse.Play(songs[0]);
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
|
||||
songs.RemoveAt(0);
|
||||
MusicPlayer.queue.AddRange(songs);
|
||||
|
||||
List<Song> preSongs = instance.tracks.GetRange(0, fromPosition);
|
||||
if (result != null && result.Count > fromPosition)
|
||||
preSongs = instance.result.GetRange(0, fromPosition);
|
||||
|
||||
MusicPlayer.queue.InsertRange(0, preSongs);
|
||||
MusicPlayer.currentID = preSongs.Count;
|
||||
MusicPlayer.SaveQueueSlot();
|
||||
Queue.instance?.Refresh();
|
||||
|
||||
while (MusicPlayer.instance == null)
|
||||
await Task.Delay(10);
|
||||
|
||||
MusicPlayer.UpdateQueueDataBase();
|
||||
Home.instance?.RefreshQueue();
|
||||
}
|
||||
|
||||
private void RemoveFromYtPlaylist(Song item, string ytTrackID)
|
||||
{
|
||||
adapter.Remove(item);
|
||||
tracks.Remove(item);
|
||||
result?.Remove(item);
|
||||
}
|
||||
|
||||
void RemoveFromPlaylist(Song item)
|
||||
{
|
||||
ContentResolver resolver = Activity.ContentResolver;
|
||||
Uri uri = MediaStore.Audio.Playlists.Members.GetContentUri("external", LocalID);
|
||||
resolver.Delete(uri, MediaStore.Audio.Playlists.Members.Id + "=?", new string[] { item.Id.ToString() });
|
||||
adapter.Remove(item);
|
||||
tracks.Remove(item);
|
||||
result?.Remove(item);
|
||||
adapter.NotifyItemChanged(position);
|
||||
}, () =>
|
||||
{
|
||||
adapter.NotifyItemInserted(position);
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnResume()
|
||||
@@ -820,9 +547,9 @@ namespace Opus.Resources.Portable_Class
|
||||
if(useHeader)
|
||||
{
|
||||
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerPlay).HasOnClickListeners)
|
||||
Activity.FindViewById<ImageButton>(Resource.Id.headerPlay).Click += (sender, e0) => { instance.PlayInOrder(0); };
|
||||
Activity.FindViewById<ImageButton>(Resource.Id.headerPlay).Click += (sender, e0) => { PlaylistManager.PlayInOrder(item); };
|
||||
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerShuffle).HasOnClickListeners)
|
||||
Activity.FindViewById<ImageButton>(Resource.Id.headerShuffle).Click += (sender, e0) => { RandomPlay(); };
|
||||
Activity.FindViewById<ImageButton>(Resource.Id.headerShuffle).Click += (sender, e0) => { PlaylistManager.Shuffle(item); };
|
||||
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerMore).HasOnClickListeners)
|
||||
Activity.FindViewById<ImageButton>(Resource.Id.headerMore).Click += PlaylistMore;
|
||||
}
|
||||
@@ -844,65 +571,5 @@ namespace Opus.Resources.Portable_Class
|
||||
MainActivity.instance.SupportActionBar.SetDisplayShowTitleEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteDialog(int position)
|
||||
{
|
||||
if (!useHeader)
|
||||
position--;
|
||||
|
||||
Song song = tracks[position];
|
||||
if (result != null && result.Count > position)
|
||||
song = result[position];
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(MainActivity.instance, MainActivity.dialogTheme)
|
||||
.SetTitle(MainActivity.instance.GetString(Resource.String.remove_from_playlist, song.Title))
|
||||
.SetPositiveButton(Resource.String.yes, async (sender, e) =>
|
||||
{
|
||||
if(Synced && YoutubeID != null && LocalID != 0)
|
||||
{
|
||||
if (song.TrackID == null)
|
||||
song = await CompleteItem(song, YoutubeID);
|
||||
}
|
||||
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) + GetString(Resource.String.removed_from_playlist), Snackbar.LengthLong)
|
||||
.SetAction(GetString(Resource.String.undo), (v) =>
|
||||
{
|
||||
callback.canceled = true;
|
||||
if (YoutubeID != null)
|
||||
{
|
||||
if (result != null && result.Count >= position)
|
||||
result?.Insert(position, song);
|
||||
|
||||
adapter.Insert(position, song);
|
||||
tracks.Insert(position, song);
|
||||
}
|
||||
else if (LocalID != 0)
|
||||
{
|
||||
adapter.Insert(position, song);
|
||||
tracks.Insert(position, song);
|
||||
if (result != null && result.Count >= position)
|
||||
result?.Insert(position, song);
|
||||
}
|
||||
});
|
||||
snackBar.AddCallback(callback);
|
||||
snackBar.View.FindViewById<TextView>(Resource.Id.snackbar_text).SetTextColor(Android.Graphics.Color.White);
|
||||
snackBar.Show();
|
||||
|
||||
if(YoutubeID != null)
|
||||
{
|
||||
RemoveFromYtPlaylist(song, song.TrackID);
|
||||
}
|
||||
else
|
||||
{
|
||||
adapter.Remove(song);
|
||||
tracks.Remove(song);
|
||||
result?.Remove(song);
|
||||
}
|
||||
})
|
||||
.SetNegativeButton(Resource.String.no, (sender, e) => { adapter.NotifyItemChanged(position); })
|
||||
.Create();
|
||||
dialog.Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,16 +14,16 @@ using Android.Support.V7.App;
|
||||
using Android.Support.V7.Preferences;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using System.Collections.Generic;
|
||||
using Opus.Api.Services;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using AlertDialog = Android.Support.V7.App.AlertDialog;
|
||||
using Preference = Android.Support.V7.Preferences.Preference;
|
||||
using PreferenceManager = Android.Support.V7.Preferences.PreferenceManager;
|
||||
using Toolbar = Android.Support.V7.Widget.Toolbar;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Fragments
|
||||
{
|
||||
[Activity(Label = "Settings", Theme = "@style/Theme")]
|
||||
public class Preferences : AppCompatActivity
|
||||
@@ -12,10 +12,13 @@ using Android.Text.Style;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus;
|
||||
using Opus.Adapter;
|
||||
using Opus.Api;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Fragments;
|
||||
using Opus.Others;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using Opus.Resources.values;
|
||||
using Opus.Views;
|
||||
using Square.Picasso;
|
||||
using System.Collections.Generic;
|
||||
using Fragment = Android.Support.V4.App.Fragment;
|
||||
@@ -64,14 +67,6 @@ public class Queue : Fragment, RecyclerView.IOnItemTouchListener, PopupMenu.IOnM
|
||||
|
||||
private void Scroll(object sender, View.ScrollChangeEventArgs e) { }
|
||||
|
||||
//protected override void OnStop()
|
||||
//{
|
||||
// Home.instance?.RefreshQueue();
|
||||
// MusicPlayer.ParseNextSong();
|
||||
// base.OnStop();
|
||||
// instance = null;
|
||||
//}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
adapter.NotifyDataSetChanged();
|
||||
@@ -83,6 +78,12 @@ public class Queue : Fragment, RecyclerView.IOnItemTouchListener, PopupMenu.IOnM
|
||||
adapter.NotifyItemInserted(position);
|
||||
}
|
||||
|
||||
public void NotifyItemRangeInserted(int position, int count)
|
||||
{
|
||||
position++;
|
||||
adapter.NotifyItemRangeInserted(position, count);
|
||||
}
|
||||
|
||||
public void NotifyItemChanged(int position)
|
||||
{
|
||||
position++;
|
||||
@@ -134,34 +135,6 @@ public class Queue : Fragment, RecyclerView.IOnItemTouchListener, PopupMenu.IOnM
|
||||
adapter.NotifyItemChanged(MusicPlayer.queue.Count + 1);
|
||||
}
|
||||
|
||||
//public override bool OnCreateOptionsMenu(IMenu menu)
|
||||
//{
|
||||
// MenuInflater.Inflate(Resource.Menu.QueueItems, menu);
|
||||
// this.menu = menu;
|
||||
// menu.FindItem(Resource.Id.shuffle).Icon.SetColorFilter(Color.White, PorterDuff.Mode.Multiply);
|
||||
// if (MusicPlayer.repeat)
|
||||
// menu.FindItem(Resource.Id.repeat).Icon.SetColorFilter(Color.Argb(255, 21, 183, 237), PorterDuff.Mode.Multiply);
|
||||
|
||||
// return base.OnCreateOptionsMenu(menu);
|
||||
//}
|
||||
|
||||
//public override bool OnOptionsItemSelected(IMenuItem item)
|
||||
//{
|
||||
// if (item.ItemId == Android.Resource.Id.Home)
|
||||
// {
|
||||
// Finish();
|
||||
// }
|
||||
// else if(item.ItemId == Resource.Id.shuffle)
|
||||
// {
|
||||
// ShuffleQueue();
|
||||
// }
|
||||
// else if(item.ItemId == Resource.Id.repeat)
|
||||
// {
|
||||
// Repeat(item);
|
||||
// }
|
||||
// return base.OnOptionsItemSelected(item);
|
||||
//}
|
||||
|
||||
private void ListView_ItemClick(object sender, int Position)
|
||||
{
|
||||
Song item = MusicPlayer.queue[Position];
|
||||
@@ -213,7 +186,7 @@ public class Queue : Fragment, RecyclerView.IOnItemTouchListener, PopupMenu.IOnM
|
||||
{
|
||||
new BottomSheetAction(Resource.Drawable.Play, Resources.GetString(Resource.String.play), (sender, eventArg) => { ListView_ItemClick(null, position); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.Close, Resources.GetString(Resource.String.remove_from_queue), (sender, eventArg) => { MusicPlayer.RemoveFromQueue(position); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistAdd, Resources.GetString(Resource.String.add_to_playlist), (sender, eventArg) => { Browse.GetPlaylist(item); bottomSheet.Dismiss(); })
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistAdd, Resources.GetString(Resource.String.add_to_playlist), (sender, eventArg) => { PlaylistManager.AddSongToPlaylistDialog(item); bottomSheet.Dismiss(); })
|
||||
};
|
||||
|
||||
if (item.IsYt)
|
||||
@@ -222,12 +195,12 @@ public class Queue : Fragment, RecyclerView.IOnItemTouchListener, PopupMenu.IOnM
|
||||
{
|
||||
new BottomSheetAction(Resource.Drawable.PlayCircle, Resources.GetString(Resource.String.create_mix_from_song), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeEngine.CreateMix(item);
|
||||
YoutubeManager.CreateMixFromSong(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.Download, Resources.GetString(Resource.String.download), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeEngine.Download(item.Title, item.YoutubeID);
|
||||
YoutubeManager.Download(new[] { item }, null);
|
||||
bottomSheet.Dismiss();
|
||||
})
|
||||
});
|
||||
@@ -236,7 +209,7 @@ public class Queue : Fragment, RecyclerView.IOnItemTouchListener, PopupMenu.IOnM
|
||||
{
|
||||
actions.Add(new BottomSheetAction(Resource.Drawable.Edit, Resources.GetString(Resource.String.edit_metadata), (sender, eventArg) =>
|
||||
{
|
||||
Browse.EditMetadata(item);
|
||||
LocalManager.EditMetadata(item);
|
||||
bottomSheet.Dismiss();
|
||||
}));
|
||||
}
|
||||
@@ -322,6 +295,6 @@ public class Queue : Fragment, RecyclerView.IOnItemTouchListener, PopupMenu.IOnM
|
||||
|
||||
public void SaveQueueToPlaylist()
|
||||
{
|
||||
Browse.CreatePlalistDialog(MusicPlayer.queue.ToArray());
|
||||
PlaylistManager.CreatePlalistDialog(MusicPlayer.queue.ToArray());
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,10 @@ using Android.Runtime;
|
||||
using Android.Support.V7.App;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.Resources.values;
|
||||
using Newtonsoft.Json;
|
||||
using Opus.Adapter;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using Opus.Resources.values;
|
||||
using SQLite;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -15,7 +17,7 @@ using AlertDialog = Android.Support.V7.App.AlertDialog;
|
||||
using SearchView = Android.Support.V7.Widget.SearchView;
|
||||
using Toolbar = Android.Support.V7.Widget.Toolbar;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Fragments
|
||||
{
|
||||
[Activity(Label = "SearchableActivity", Theme = "@style/Theme")]
|
||||
public class SearchableActivity : AppCompatActivity, IMenuItemOnActionExpandListener
|
||||
@@ -187,7 +189,7 @@ namespace Opus.Resources.Portable_Class
|
||||
protected override void OnStop()
|
||||
{
|
||||
base.OnStop();
|
||||
if ((SearchQuery == null || SearchQuery == "") && YoutubeEngine.instances == null)
|
||||
if ((SearchQuery == null || SearchQuery == "") && YoutubeSearch.instances == null)
|
||||
MainActivity.instance.CancelSearch();
|
||||
}
|
||||
|
||||
491
Opus/Code/UI/Fragments/YoutubeSearch.cs
Normal file
491
Opus/Code/UI/Fragments/YoutubeSearch.cs
Normal file
@@ -0,0 +1,491 @@
|
||||
using Android.Graphics;
|
||||
using Android.OS;
|
||||
using Android.Support.Design.Widget;
|
||||
using Android.Support.V4.App;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Google.Apis.YouTube.v3;
|
||||
using Opus.Adapter;
|
||||
using Opus.Api;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Others;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using Square.Picasso;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using SearchView = Android.Support.V7.Widget.SearchView;
|
||||
|
||||
namespace Opus.Fragments
|
||||
{
|
||||
public class YoutubeSearch : Fragment
|
||||
{
|
||||
public static YoutubeSearch[] instances;
|
||||
public static YouTubeService youtubeService;
|
||||
public string Query;
|
||||
private string nextPageToken = null;
|
||||
public string querryType;
|
||||
|
||||
public bool IsFocused = false;
|
||||
public RecyclerView ListView;
|
||||
public List<YtFile> result;
|
||||
|
||||
private YtAdapter adapter;
|
||||
public TextView EmptyView;
|
||||
public ProgressBar LoadingView;
|
||||
private bool searching;
|
||||
|
||||
|
||||
public YoutubeSearch(string Query, string querryType)
|
||||
{
|
||||
this.Query = Query;
|
||||
this.querryType = querryType;
|
||||
}
|
||||
|
||||
public override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreate(savedInstanceState);
|
||||
MainActivity.instance.contentRefresh.Refresh += OnRefresh;
|
||||
}
|
||||
|
||||
private async void OnRefresh(object sender, EventArgs e)
|
||||
{
|
||||
if (IsFocused)
|
||||
{
|
||||
await Search(Query, querryType, false);
|
||||
MainActivity.instance.contentRefresh.Refreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnScroll(object sender, View.ScrollChangeEventArgs e)
|
||||
{
|
||||
if (((LinearLayoutManager)ListView.GetLayoutManager()).FindLastVisibleItemPosition() == result.Count - 1)
|
||||
LoadMore();
|
||||
}
|
||||
|
||||
async void LoadMore()
|
||||
{
|
||||
if(nextPageToken != null && !searching)
|
||||
{
|
||||
try
|
||||
{
|
||||
searching = true;
|
||||
SearchResource.ListRequest searchResult = youtubeService.Search.List("snippet");
|
||||
searchResult.Q = Query.Replace(" ", "+-");
|
||||
searchResult.PageToken = nextPageToken;
|
||||
searchResult.TopicId = "/m/04rlf";
|
||||
switch (querryType)
|
||||
{
|
||||
case "All":
|
||||
searchResult.Type = "video,channel,playlist";
|
||||
searchResult.EventType = null;
|
||||
break;
|
||||
case "Tracks":
|
||||
searchResult.Type = "video";
|
||||
searchResult.EventType = null;
|
||||
break;
|
||||
case "Playlists":
|
||||
searchResult.Type = "playlist";
|
||||
searchResult.EventType = null;
|
||||
break;
|
||||
case "Lives":
|
||||
searchResult.Type = "video";
|
||||
searchResult.EventType = SearchResource.ListRequest.EventTypeEnum.Live;
|
||||
break;
|
||||
case "Channels":
|
||||
searchResult.Type = "channel";
|
||||
searchResult.EventType = null;
|
||||
break;
|
||||
default:
|
||||
searchResult.Type = "video";
|
||||
searchResult.EventType = null;
|
||||
break;
|
||||
}
|
||||
searchResult.MaxResults = 50;
|
||||
|
||||
var searchReponse = await searchResult.ExecuteAsync();
|
||||
nextPageToken = searchReponse.NextPageToken;
|
||||
|
||||
int loadPos = result.Count - 1;
|
||||
result.RemoveAt(loadPos);
|
||||
adapter.NotifyItemRemoved(loadPos);
|
||||
|
||||
foreach (var video in searchReponse.Items)
|
||||
{
|
||||
Song videoInfo = new Song(video.Snippet.Title, video.Snippet.ChannelTitle, video.Snippet.Thumbnails.High.Url, null, -1, -1, null, true, false);
|
||||
YtKind kind = YtKind.Null;
|
||||
|
||||
if (video.Snippet.LiveBroadcastContent == "live")
|
||||
videoInfo.IsLiveStream = true;
|
||||
|
||||
switch (video.Id.Kind)
|
||||
{
|
||||
case "youtube#video":
|
||||
kind = YtKind.Video;
|
||||
videoInfo.YoutubeID = video.Id.VideoId;
|
||||
break;
|
||||
case "youtube#playlist":
|
||||
kind = YtKind.Playlist;
|
||||
videoInfo.YoutubeID = video.Id.PlaylistId;
|
||||
break;
|
||||
case "youtube#channel":
|
||||
kind = YtKind.Channel;
|
||||
videoInfo.YoutubeID = video.Id.ChannelId;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("&Kind = " + video.Id.Kind);
|
||||
break;
|
||||
}
|
||||
result.Add(new YtFile(videoInfo, kind));
|
||||
}
|
||||
|
||||
if (nextPageToken != null)
|
||||
result.Add(new YtFile(new Song(), YtKind.Loading));
|
||||
|
||||
adapter.NotifyItemRangeInserted(loadPos, result.Count - loadPos);
|
||||
searching = false;
|
||||
}
|
||||
catch (System.Net.Http.HttpRequestException)
|
||||
{
|
||||
MainActivity.instance.Timout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnFocus() { }
|
||||
public void OnUnfocus() { }
|
||||
|
||||
public static Fragment[] NewInstances(string searchQuery)
|
||||
{
|
||||
instances = new YoutubeSearch[]
|
||||
{
|
||||
new YoutubeSearch(searchQuery, "All"),
|
||||
new YoutubeSearch(searchQuery, "Tracks"),
|
||||
new YoutubeSearch(searchQuery, "Playlists"),
|
||||
new YoutubeSearch(searchQuery, "Lives"),
|
||||
new YoutubeSearch(searchQuery, "Channels")
|
||||
};
|
||||
return instances;
|
||||
}
|
||||
|
||||
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
View view = inflater.Inflate(Resource.Layout.CompleteRecycler, container, false);
|
||||
EmptyView = view.FindViewById<TextView>(Resource.Id.empty);
|
||||
LoadingView = view.FindViewById<ProgressBar>(Resource.Id.loading);
|
||||
ListView = view.FindViewById<RecyclerView>(Resource.Id.recycler);
|
||||
ListView.SetLayoutManager(new LinearLayoutManager(Android.App.Application.Context));
|
||||
ListView.SetItemAnimator(new DefaultItemAnimator());
|
||||
ListView.ScrollChange += OnScroll;
|
||||
|
||||
if (savedInstanceState != null)
|
||||
Query = savedInstanceState.GetString("Query");
|
||||
|
||||
#pragma warning disable CS4014
|
||||
Search(Query, querryType, true);
|
||||
return view;
|
||||
}
|
||||
|
||||
public async Task Search(string search, string querryType, bool loadingBar)
|
||||
{
|
||||
SearchableActivity.IgnoreMyself = true;
|
||||
IMenuItem searchItem = MainActivity.instance.menu.FindItem(Resource.Id.search);
|
||||
searchItem.ExpandActionView();
|
||||
SearchView searchView = (SearchView)searchItem.ActionView;
|
||||
searchView.SetQuery(search, false);
|
||||
searchView.ClearFocus();
|
||||
searchView.Focusable = false;
|
||||
|
||||
if (search == null || search == "")
|
||||
return;
|
||||
|
||||
searching = true;
|
||||
Query = search;
|
||||
|
||||
if (loadingBar)
|
||||
{
|
||||
adapter = null;
|
||||
ListView.SetAdapter(null);
|
||||
EmptyView.Visibility = ViewStates.Gone;
|
||||
LoadingView.Visibility = ViewStates.Visible;
|
||||
}
|
||||
|
||||
SearchableActivity.IgnoreMyself = false;
|
||||
|
||||
if (!await MainActivity.instance.WaitForYoutube())
|
||||
{
|
||||
ListView.SetAdapter(null);
|
||||
EmptyView.Text = MainActivity.instance.GetString(Resource.String.youtube_loading_error);
|
||||
EmptyView.SetTextColor(Color.Red);
|
||||
EmptyView.Visibility = ViewStates.Visible;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
SearchResource.ListRequest searchResult = youtubeService.Search.List("snippet");
|
||||
searchResult.Q = search.Replace(" ", "+-");
|
||||
searchResult.TopicId = "/m/04rlf";
|
||||
switch (querryType)
|
||||
{
|
||||
case "All":
|
||||
searchResult.Type = "video,channel,playlist";
|
||||
searchResult.EventType = null;
|
||||
break;
|
||||
case "Tracks":
|
||||
searchResult.Type = "video";
|
||||
searchResult.EventType = null;
|
||||
break;
|
||||
case "Playlists":
|
||||
searchResult.Type = "playlist";
|
||||
searchResult.EventType = null;
|
||||
break;
|
||||
case "Lives":
|
||||
searchResult.Type = "video";
|
||||
searchResult.EventType = SearchResource.ListRequest.EventTypeEnum.Live;
|
||||
break;
|
||||
case "Channels":
|
||||
searchResult.Type = "channel";
|
||||
searchResult.EventType = null;
|
||||
break;
|
||||
default:
|
||||
searchResult.Type = "video";
|
||||
searchResult.EventType = null;
|
||||
break;
|
||||
}
|
||||
searchResult.MaxResults = 50;
|
||||
|
||||
var searchReponse = await searchResult.ExecuteAsync();
|
||||
nextPageToken = searchReponse.NextPageToken;
|
||||
result = new List<YtFile>();
|
||||
|
||||
foreach (var video in searchReponse.Items)
|
||||
{
|
||||
Song videoInfo = new Song(HttpUtility.HtmlDecode(video.Snippet.Title), HttpUtility.HtmlDecode(video.Snippet.ChannelTitle), video.Snippet.Thumbnails.High.Url, null, -1, -1, video.Snippet.ChannelId, true, false);
|
||||
YtKind kind = YtKind.Null;
|
||||
|
||||
if (video.Snippet.LiveBroadcastContent == "live")
|
||||
videoInfo.IsLiveStream = true;
|
||||
|
||||
switch (video.Id.Kind)
|
||||
{
|
||||
case "youtube#video":
|
||||
kind = YtKind.Video;
|
||||
videoInfo.YoutubeID = video.Id.VideoId;
|
||||
break;
|
||||
case "youtube#playlist":
|
||||
kind = YtKind.Playlist;
|
||||
videoInfo.YoutubeID = video.Id.PlaylistId;
|
||||
break;
|
||||
case "youtube#channel":
|
||||
kind = YtKind.Channel;
|
||||
videoInfo.YoutubeID = video.Id.ChannelId;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("&Kind = " + video.Id.Kind);
|
||||
break;
|
||||
}
|
||||
result.Add(new YtFile(videoInfo, kind));
|
||||
}
|
||||
|
||||
LoadingView.Visibility = ViewStates.Gone;
|
||||
if (nextPageToken != null)
|
||||
result.Add(new YtFile(new Song(), YtKind.Loading));
|
||||
|
||||
if(result.Count > 0 && result[0].Kind == YtKind.Channel && result.Count(x => x.song.Artist == result[0].song.Title && x.Kind == YtKind.Video) > 0)
|
||||
{
|
||||
YtFile channelPreview = new YtFile(result[0].song, YtKind.ChannelPreview);
|
||||
result.Insert(0, channelPreview);
|
||||
}
|
||||
else if (result.Count > 0 && querryType == "All" || querryType == "Channels")
|
||||
{
|
||||
IEnumerable<string> artist = result.GetRange(0, (result.Count > 20 ? 20 : result.Count)).GroupBy(x => x.song.Artist).Where(x => x.Count() > 5).Select(x => x.Key);
|
||||
if (artist.Count() == 1)
|
||||
{
|
||||
Song channel = null;
|
||||
if (result.Find(x => x.Kind == YtKind.Channel && x.song.Title == artist.First()) != null)
|
||||
channel = result.Find(x => x.song.Title == artist.First() && x.Kind == YtKind.Channel).song;
|
||||
//else
|
||||
//{
|
||||
// string channelID = result.Find(x => x.item.Artist == artist.First()).item.Path;
|
||||
// ChannelsResource.ListRequest request = youtubeService.Channels.List("snippet");
|
||||
// request.Id = channelID;
|
||||
// ChannelListResponse response = await request.ExecuteAsync();
|
||||
// channel = new Song(response.Items[0].Snippet.Title, null, response.Items[0].Snippet.Thumbnails.High.Url, channelID, -1, -1, null);
|
||||
//}
|
||||
|
||||
if (channel != null)
|
||||
{
|
||||
YtFile channelPreview = new YtFile(channel, YtKind.ChannelPreview);
|
||||
result.Insert(0, channelPreview);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adapter = new YtAdapter(result);
|
||||
adapter.ItemClick += ListView_ItemClick;
|
||||
adapter.ItemLongCLick += ListView_ItemLongClick;
|
||||
ListView.SetAdapter(adapter);
|
||||
searching = false;
|
||||
|
||||
if (result.Count == 0)
|
||||
{
|
||||
EmptyView.Visibility = ViewStates.Visible;
|
||||
switch (querryType)
|
||||
{
|
||||
case "All":
|
||||
EmptyView.Text = GetString(Resource.String.no_result) + " " + search;
|
||||
break;
|
||||
case "Tracks":
|
||||
EmptyView.Text = GetString(Resource.String.no_track) + " " + search;
|
||||
break;
|
||||
case "Playlists":
|
||||
EmptyView.Text = GetString(Resource.String.no_playlist) + " " + search;
|
||||
break;
|
||||
case "Lives":
|
||||
EmptyView.Text = GetString(Resource.String.no_lives) + " " + search;
|
||||
break;
|
||||
case "Channels":
|
||||
EmptyView.Text = GetString(Resource.String.no_channel) + " " + search;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
EmptyView.Visibility = ViewStates.Gone;
|
||||
}
|
||||
catch (System.Net.Http.HttpRequestException)
|
||||
{
|
||||
MainActivity.instance.Timout();
|
||||
EmptyView.Text = GetString(Resource.String.timout);
|
||||
EmptyView.Visibility = ViewStates.Visible;
|
||||
}
|
||||
}
|
||||
|
||||
private void ListView_ItemClick(object sender, int position)
|
||||
{
|
||||
switch (result[position].Kind)
|
||||
{
|
||||
case YtKind.Video:
|
||||
YoutubeManager.Play(result[position].song);
|
||||
break;
|
||||
case YtKind.Playlist:
|
||||
SearchableActivity.IgnoreMyself = true;
|
||||
MainActivity.instance.menu.FindItem(Resource.Id.search).CollapseActionView();
|
||||
MainActivity.instance.FindViewById<TabLayout>(Resource.Id.tabs).Visibility = ViewStates.Gone;
|
||||
MainActivity.instance.SupportFragmentManager.BeginTransaction().Replace(Resource.Id.contentView, PlaylistTracks.NewInstance(result[position].playlist, false)).AddToBackStack("Playlist Track").Commit();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ListView_ItemLongClick(object sender, int position)
|
||||
{
|
||||
if(result[position].Kind == YtKind.Video)
|
||||
{
|
||||
Song item = result[position].song;
|
||||
More(item);
|
||||
}
|
||||
else if(result[position].Kind == YtKind.Playlist)
|
||||
{
|
||||
PlaylistItem item = result[position].playlist;
|
||||
PlaylistMore(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void More(Song item)
|
||||
{
|
||||
BottomSheetDialog bottomSheet = new BottomSheetDialog(MainActivity.instance);
|
||||
View bottomView = MainActivity.instance.LayoutInflater.Inflate(Resource.Layout.BottomSheet, null);
|
||||
bottomView.FindViewById<TextView>(Resource.Id.bsTitle).Text = item.Title;
|
||||
bottomView.FindViewById<TextView>(Resource.Id.bsArtist).Text = item.Artist;
|
||||
Picasso.With(MainActivity.instance).Load(item.Album).Placeholder(Resource.Drawable.noAlbum).Transform(new RemoveBlackBorder(true)).Into(bottomView.FindViewById<ImageView>(Resource.Id.bsArt));
|
||||
bottomSheet.SetContentView(bottomView);
|
||||
|
||||
bottomSheet.FindViewById<ListView>(Resource.Id.bsItems).Adapter = new BottomSheetAdapter(MainActivity.instance, Resource.Layout.BottomSheetText, new List<BottomSheetAction>
|
||||
{
|
||||
new BottomSheetAction(Resource.Drawable.Play, Resources.GetString(Resource.String.play), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeManager.Play(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistPlay, Resources.GetString(Resource.String.play_next), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeManager.PlayNext(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.Queue, Resources.GetString(Resource.String.play_last), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeManager.PlayLast(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.PlayCircle, Resources.GetString(Resource.String.create_mix_from_song), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeManager.CreateMixFromSong(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistAdd, Resources.GetString(Resource.String.add_to_playlist), (sender, eventArg) => { PlaylistManager.AddSongToPlaylistDialog(item); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.Download, Resources.GetString(Resource.String.download), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeManager.Download(new[] { item }, null);
|
||||
bottomSheet.Dismiss();
|
||||
})
|
||||
});
|
||||
bottomSheet.Show();
|
||||
}
|
||||
|
||||
public void PlaylistMore(PlaylistItem item)
|
||||
{
|
||||
BottomSheetDialog bottomSheet = new BottomSheetDialog(MainActivity.instance);
|
||||
View bottomView = MainActivity.instance.LayoutInflater.Inflate(Resource.Layout.BottomSheet, null);
|
||||
bottomView.FindViewById<TextView>(Resource.Id.bsTitle).Text = item.Name;
|
||||
bottomView.FindViewById<TextView>(Resource.Id.bsArtist).Text = item.Owner;
|
||||
Picasso.With(MainActivity.instance).Load(item.ImageURL).Placeholder(Resource.Color.background_material_dark).Transform(new RemoveBlackBorder(true)).Into(bottomView.FindViewById<ImageView>(Resource.Id.bsArt));
|
||||
bottomSheet.SetContentView(bottomView);
|
||||
|
||||
List<BottomSheetAction> actions = new List<BottomSheetAction>
|
||||
{
|
||||
new BottomSheetAction(Resource.Drawable.Play, MainActivity.instance.Resources.GetString(Resource.String.play_in_order), (sender, eventArg) =>
|
||||
{
|
||||
PlaylistManager.PlayInOrder(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.Shuffle, MainActivity.instance.Resources.GetString(Resource.String.random_play), (sender, eventArg) =>
|
||||
{
|
||||
PlaylistManager.Shuffle(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.Queue, MainActivity.instance.Resources.GetString(Resource.String.add_to_queue), (sender, eventArg) =>
|
||||
{
|
||||
PlaylistManager.AddToQueue(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.LibraryAdd, MainActivity.instance.Resources.GetString(Resource.String.add_to_library), (sender, eventArg) =>
|
||||
{
|
||||
PlaylistManager.ForkPlaylist(item.YoutubeID);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.Download, MainActivity.instance.Resources.GetString(Resource.String.download), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeManager.DownloadPlaylist(item.Name, item.YoutubeID);
|
||||
bottomSheet.Dismiss();
|
||||
})
|
||||
};
|
||||
|
||||
bottomSheet.FindViewById<ListView>(Resource.Id.bsItems).Adapter = new BottomSheetAdapter(MainActivity.instance, Resource.Layout.BottomSheetText, actions);
|
||||
bottomSheet.Show();
|
||||
}
|
||||
|
||||
public override void OnSaveInstanceState(Bundle outState)
|
||||
{
|
||||
outState.PutString("Query", Query);
|
||||
base.OnSaveInstanceState(outState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ using Android.Views;
|
||||
using Android.Widget;
|
||||
using Google.Apis.YouTube.v3;
|
||||
using Opus;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using Opus.Fragments;
|
||||
using Opus.Others;
|
||||
using Square.Picasso;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
@@ -96,7 +97,7 @@ public class AccountPreference : Preference, IResultCallback
|
||||
private async void LogOut()
|
||||
{
|
||||
MainActivity.account = null;
|
||||
YoutubeEngine.youtubeService = null;
|
||||
YoutubeSearch.youtubeService = null;
|
||||
|
||||
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DefaultSignIn)
|
||||
.RequestIdToken(Preferences.instance.GetString(Resource.String.clientID))
|
||||
@@ -2,7 +2,7 @@
|
||||
using Android.Runtime;
|
||||
using Android.Support.Design.Widget;
|
||||
using Android.Util;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using Opus.Fragments;
|
||||
using System;
|
||||
|
||||
[Register("Opus/CollapsingToolbarLayout")]
|
||||
@@ -5,11 +5,13 @@ using Android.Support.V7.Widget;
|
||||
using Android.Text;
|
||||
using Android.Text.Style;
|
||||
using Android.Views;
|
||||
using Opus.Adapter;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Resources.values;
|
||||
using Opus.Others;
|
||||
using Square.Picasso;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Views
|
||||
{
|
||||
public class CurrentItemDecoration : RecyclerView.ItemDecoration
|
||||
{
|
||||
@@ -16,10 +16,12 @@ using Android.Text.Style;
|
||||
using Android.Util;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.Adapter;
|
||||
using Opus.Api;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Fragments;
|
||||
using Opus.Others;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using Opus.Resources.values;
|
||||
using Square.Picasso;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -407,7 +409,7 @@ namespace Opus
|
||||
List<BottomSheetAction> actions = new List<BottomSheetAction>
|
||||
{
|
||||
new BottomSheetAction(Resource.Drawable.Timer, Resources.GetString(Resource.String.timer), (sender, eventArg) => { SleepDialog(); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistAdd, Resources.GetString(Resource.String.add_to_playlist), (sender, eventArg) => { Browse.GetPlaylist(item); bottomSheet.Dismiss(); })
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistAdd, Resources.GetString(Resource.String.add_to_playlist), (sender, eventArg) => { PlaylistManager.AddSongToPlaylistDialog(item); bottomSheet.Dismiss(); })
|
||||
};
|
||||
|
||||
if (item.IsYt)
|
||||
@@ -416,12 +418,12 @@ namespace Opus
|
||||
{
|
||||
new BottomSheetAction(Resource.Drawable.PlayCircle, Resources.GetString(Resource.String.create_mix_from_song), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeEngine.CreateMix(item);
|
||||
YoutubeManager.CreateMixFromSong(item);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.Download, Resources.GetString(Resource.String.download), (sender, eventArg) =>
|
||||
{
|
||||
YoutubeEngine.Download(item.Title, item.YoutubeID);
|
||||
YoutubeManager.Download(new[]{ item }, null);
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.OpenInBrowser, Resources.GetString(Resource.String.open_youtube), (sender, eventArg) =>
|
||||
@@ -436,7 +438,7 @@ namespace Opus
|
||||
{
|
||||
actions.Add(new BottomSheetAction(Resource.Drawable.Edit, Resources.GetString(Resource.String.edit_metadata), (sender, eventArg) =>
|
||||
{
|
||||
Browse.EditMetadata(item);
|
||||
LocalManager.EditMetadata(item);
|
||||
bottomSheet.Dismiss();
|
||||
}));
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using Android.Runtime;
|
||||
using Android.Support.V7.Preferences;
|
||||
using Android.Util;
|
||||
using Opus;
|
||||
using Opus.Api.Services;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using Org.Adw.Library.Widgets.Discreteseekbar;
|
||||
using System;
|
||||
100
Opus/Opus.csproj
100
Opus/Opus.csproj
@@ -106,8 +106,8 @@
|
||||
<Reference Include="Google.Apis.Core, Version=1.38.2.0, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Google.Apis.Core.1.38.2\lib\netstandard2.0\Google.Apis.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Google.Apis.YouTube.v3, Version=1.38.0.1488, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Google.Apis.YouTube.v3.1.38.0.1488\lib\netstandard2.0\Google.Apis.YouTube.v3.dll</HintPath>
|
||||
<Reference Include="Google.Apis.YouTube.v3, Version=1.38.2.1488, Culture=neutral, PublicKeyToken=4b01fa6e34db77ab, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Google.Apis.YouTube.v3.1.38.2.1488\lib\netstandard2.0\Google.Apis.YouTube.v3.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Java.Interop" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
@@ -322,75 +322,77 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Code\Adapter\BaseCursor.cs" />
|
||||
<Compile Include="Code\UI\Adapter\BaseCursor.cs" />
|
||||
<Compile Include="Code\Api\LocalManager.cs" />
|
||||
<Compile Include="Code\Api\PlaylistManager.cs" />
|
||||
<Compile Include="Code\Api\SongManager.cs" />
|
||||
<Compile Include="Code\Api\YoutubeManager.cs" />
|
||||
<Compile Include="GlobalSuppressions.cs" />
|
||||
<Compile Include="Code\MainActivity.cs" />
|
||||
<Compile Include="Resources\Portable Class\AccountPreference.cs" />
|
||||
<Compile Include="Code\UI\Views\AccountPreference.cs" />
|
||||
<Compile Include="Resources\Portable Class\AccountTarget.cs" />
|
||||
<Compile Include="Code\Adapter\BrowseAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\AddToPlaylistAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\AudioStopper.cs" />
|
||||
<Compile Include="Resources\Portable Class\BottomSheetAdapter.cs" />
|
||||
<Compile Include="Code\Fragments\Browse.cs" />
|
||||
<Compile Include="Resources\Portable Class\CastCallback.cs" />
|
||||
<Compile Include="Code\UI\Adapter\BrowseAdapter.cs" />
|
||||
<Compile Include="Code\UI\Adapter\AddToPlaylistAdapter.cs" />
|
||||
<Compile Include="Code\Others\AudioStopper.cs" />
|
||||
<Compile Include="Code\UI\Adapter\BottomSheetAdapter.cs" />
|
||||
<Compile Include="Code\UI\Fragments\Browse.cs" />
|
||||
<Compile Include="Code\Others\CastCallback.cs" />
|
||||
<Compile Include="Resources\Portable Class\CastProvider.cs" />
|
||||
<Compile Include="Resources\Portable Class\CastQueueManager.cs" />
|
||||
<Compile Include="Code\Others\CastQueueManager.cs" />
|
||||
<Compile Include="Resources\Portable Class\ChannelPreviewHolder.cs" />
|
||||
<Compile Include="Resources\Portable Class\CircleTransformation.cs" />
|
||||
<Compile Include="Resources\Portable Class\CollapsingToolbar.cs" />
|
||||
<Compile Include="Resources\Portable Class\CurrentItemDecoration.cs" />
|
||||
<Compile Include="Resources\Portable Class\DownloadQueue.cs" />
|
||||
<Compile Include="Resources\Portable Class\DownloadQueueAdapter.cs" />
|
||||
<Compile Include="Code\Others\CircleTransformation.cs" />
|
||||
<Compile Include="Code\UI\Views\CollapsingToolbar.cs" />
|
||||
<Compile Include="Code\UI\Views\CurrentItemDecoration.cs" />
|
||||
<Compile Include="Code\UI\Fragments\DownloadQueue.cs" />
|
||||
<Compile Include="Code\UI\Adapter\DownloadQueueAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\FixedLinearLayoutManager.cs" />
|
||||
<Compile Include="Resources\Portable Class\FixedNestedScrollView.cs" />
|
||||
<Compile Include="Resources\Portable Class\PlayerBehavior.cs" />
|
||||
<Compile Include="Resources\Portable Class\PlaylistHolder.cs" />
|
||||
<Compile Include="Resources\Portable Class\PlaylistLocationAdapter.cs" />
|
||||
<Compile Include="Code\UI\Adapter\PlaylistLocationAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\PlaylistTrackAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\RemoveBlackBorder.cs" />
|
||||
<Compile Include="Resources\Portable Class\SearchableActivity.cs" />
|
||||
<Compile Include="Resources\Portable Class\Downloader.cs" />
|
||||
<Compile Include="Resources\Portable Class\DownloadFragment.cs" />
|
||||
<Compile Include="Resources\Portable Class\EditMetaData.cs" />
|
||||
<Compile Include="Resources\Portable Class\FolderAdapter.cs" />
|
||||
<Compile Include="Code\Others\RemoveBlackBorder.cs" />
|
||||
<Compile Include="Code\UI\Fragments\SearchableActivity.cs" />
|
||||
<Compile Include="Code\Api\Services\Downloader.cs" />
|
||||
<Compile Include="Code\UI\Fragments\DownloadFragment.cs" />
|
||||
<Compile Include="Code\UI\Fragments\EditMetaData.cs" />
|
||||
<Compile Include="Code\UI\Adapter\FolderAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\FolderBrowse.cs" />
|
||||
<Compile Include="Resources\Portable Class\FolderTracks.cs" />
|
||||
<Compile Include="Resources\Portable Class\HeadphonesActions.cs" />
|
||||
<Compile Include="Resources\Portable Class\Home.cs" />
|
||||
<Compile Include="Resources\Portable Class\HomeAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\HomeListAdapter.cs" />
|
||||
<Compile Include="Code\UI\Fragments\Home.cs" />
|
||||
<Compile Include="Code\UI\Adapter\HomeAdapter.cs" />
|
||||
<Compile Include="Code\UI\Adapter\HomeListAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\HomeHolder.cs" />
|
||||
<Compile Include="Resources\Portable Class\HomeMultipleSong.cs" />
|
||||
<Compile Include="Resources\Portable Class\ItemTouchCallback.cs" />
|
||||
<Compile Include="Resources\Portable Class\LineAdapter.cs" />
|
||||
<Compile Include="Code\Others\ItemTouchCallback.cs" />
|
||||
<Compile Include="Code\UI\Adapter\LineAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\LineSongHolder.cs" />
|
||||
<Compile Include="Resources\Portable Class\MusicPlayer.cs" />
|
||||
<Compile Include="Code\Api\Services\MusicPlayer.cs" />
|
||||
<Compile Include="Resources\Portable Class\PagerFragment.cs" />
|
||||
<Compile Include="Resources\Portable Class\PercentTransform.cs" />
|
||||
<Compile Include="Resources\Portable Class\Player.cs" />
|
||||
<Compile Include="Resources\Portable Class\Playlist.cs" />
|
||||
<Compile Include="Resources\Portable Class\PlaylistAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\PlaylistTracks.cs" />
|
||||
<Compile Include="Resources\Portable Class\Preferences.cs" />
|
||||
<Compile Include="Resources\Portable Class\Queue.cs" />
|
||||
<Compile Include="Code\UI\Views\Player.cs" />
|
||||
<Compile Include="Code\UI\Fragments\Playlist.cs" />
|
||||
<Compile Include="Code\UI\Adapter\PlaylistAdapter.cs" />
|
||||
<Compile Include="Code\UI\Fragments\PlaylistTracks.cs" />
|
||||
<Compile Include="Code\UI\Fragments\Preferences.cs" />
|
||||
<Compile Include="Code\UI\Fragments\Queue.cs" />
|
||||
<Compile Include="Resources\Portable Class\QueueHolder.cs" />
|
||||
<Compile Include="Resources\Portable Class\QueueAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\SeekbarPreference.cs" />
|
||||
<Compile Include="Code\UI\Adapter\QueueAdapter.cs" />
|
||||
<Compile Include="Code\UI\Views\SeekbarPreference.cs" />
|
||||
<Compile Include="Resources\Portable Class\Sleeper.cs" />
|
||||
<Compile Include="Resources\Portable Class\SnackbarCallback.cs" />
|
||||
<Compile Include="Resources\Portable Class\SuggestionAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\PlaylistItem.cs" />
|
||||
<Compile Include="Code\Others\RemoveTrackFromPlaylistCallback.cs" />
|
||||
<Compile Include="Code\UI\Adapter\SuggestionAdapter.cs" />
|
||||
<Compile Include="Code\DataStructure\PlaylistItem.cs" />
|
||||
<Compile Include="Resources\Portable Class\TwoLineAdapter.cs" />
|
||||
<Compile Include="Code\DataStructure\UslessHolder.cs" />
|
||||
<Compile Include="Resources\Portable Class\ViewPagerAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\YoutubeEngine.cs" />
|
||||
<Compile Include="Resources\Portable Class\YtAdapter.cs" />
|
||||
<Compile Include="Resources\Portable Class\YtFile.cs" />
|
||||
<Compile Include="Code\UI\Fragments\YoutubeSearch.cs" />
|
||||
<Compile Include="Code\UI\Adapter\YtAdapter.cs" />
|
||||
<Compile Include="Code\DataStructure\YtFile.cs" />
|
||||
<Compile Include="Resources\Resource.Designer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Resources\Portable Class\ChannelHolder.cs" />
|
||||
<Compile Include="Resources\Portable Class\DownloadFile.cs" />
|
||||
<Compile Include="Resources\Portable Class\EmptyCategoryHolder.cs" />
|
||||
<Compile Include="Code\DataStructure\DownloadFile.cs" />
|
||||
<Compile Include="Resources\Portable Class\Folder.cs" />
|
||||
<Compile Include="Resources\Portable Class\FolderHolder.cs" />
|
||||
<Compile Include="Resources\Portable Class\Holder.cs" />
|
||||
@@ -400,7 +402,7 @@
|
||||
<Compile Include="Resources\Portable Class\PaddingChange.cs" />
|
||||
<Compile Include="Code\DataStructure\Song.cs" />
|
||||
<Compile Include="Resources\Portable Class\Suggestion.cs" />
|
||||
<Compile Include="Resources\Portable Class\TwoLineHolder.cs" />
|
||||
<Compile Include="Code\DataStructure\TwoLineHolder.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
@@ -897,9 +899,7 @@
|
||||
<SubType>Designer</SubType>
|
||||
</AndroidResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Code\API\" />
|
||||
</ItemGroup>
|
||||
<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')" />
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
|
||||
namespace Opus.Resources.values
|
||||
{
|
||||
public class EmptyHolder : RecyclerView.ViewHolder
|
||||
{
|
||||
public TextView text;
|
||||
public EmptyHolder(View itemView) : base(itemView)
|
||||
{
|
||||
text = (TextView)itemView;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,9 @@ using Android.Support.V7.App;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.Adapter;
|
||||
using Opus.Api;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Fragments;
|
||||
using Opus.Resources.values;
|
||||
@@ -224,7 +227,7 @@ namespace Opus.Resources.Portable_Class
|
||||
musicCursor.Close();
|
||||
|
||||
songs.Reverse();
|
||||
Browse.Play(songs[0]);
|
||||
SongManager.Play(songs[0]);
|
||||
|
||||
while (MusicPlayer.instance == null)
|
||||
await Task.Delay(10);
|
||||
@@ -278,7 +281,7 @@ namespace Opus.Resources.Portable_Class
|
||||
|
||||
else
|
||||
{
|
||||
await Browse.CheckWritePermission();
|
||||
await MainActivity.instance.GetWritePermission();
|
||||
|
||||
List<ContentValues> values = new List<ContentValues>();
|
||||
ContentResolver resolver = MainActivity.instance.ContentResolver;
|
||||
@@ -334,7 +337,7 @@ namespace Opus.Resources.Portable_Class
|
||||
|
||||
public async void CreatePlaylist(string name, string path)
|
||||
{
|
||||
await Browse.CheckWritePermission();
|
||||
await MainActivity.instance.GetWritePermission();
|
||||
|
||||
ContentResolver resolver = MainActivity.instance.ContentResolver;
|
||||
Uri uri = MediaStore.Audio.Playlists.ExternalContentUri;
|
||||
|
||||
@@ -7,8 +7,11 @@ using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.Adapter;
|
||||
using Opus.Api;
|
||||
using Opus.Api.Services;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Fragments;
|
||||
using Opus.Others;
|
||||
using Square.Picasso;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
@@ -190,7 +193,7 @@ namespace Opus.Resources.Portable_Class
|
||||
}
|
||||
queue.Reverse();
|
||||
|
||||
Browse.Play(item);
|
||||
SongManager.Play(item);
|
||||
|
||||
while(MusicPlayer.instance == null)
|
||||
await Task.Delay(10);
|
||||
@@ -240,7 +243,7 @@ namespace Opus.Resources.Portable_Class
|
||||
}
|
||||
queue.Reverse();
|
||||
|
||||
Browse.Play(item);
|
||||
SongManager.Play(item);
|
||||
|
||||
while (MusicPlayer.instance == null)
|
||||
await Task.Delay(10);
|
||||
@@ -250,10 +253,10 @@ namespace Opus.Resources.Portable_Class
|
||||
|
||||
bottomSheet.Dismiss();
|
||||
}),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistPlay, Resources.GetString(Resource.String.play_next), (sender, eventArg) => { Browse.PlayNext(item); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.Queue, Resources.GetString(Resource.String.play_last), (sender, eventArg) => { Browse.PlayLast(item); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistAdd, Resources.GetString(Resource.String.add_to_playlist), (sender, eventArg) => { Browse.GetPlaylist(item); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.Edit, Resources.GetString(Resource.String.edit_metadata), (sender, eventArg) => { Browse.EditMetadata(item); bottomSheet.Dismiss(); })
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistPlay, Resources.GetString(Resource.String.play_next), (sender, eventArg) => { SongManager.PlayNext(item); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.Queue, Resources.GetString(Resource.String.play_last), (sender, eventArg) => { SongManager.PlayLast(item); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.PlaylistAdd, Resources.GetString(Resource.String.add_to_playlist), (sender, eventArg) => { PlaylistManager.AddSongToPlaylistDialog(item); bottomSheet.Dismiss(); }),
|
||||
new BottomSheetAction(Resource.Drawable.Edit, Resources.GetString(Resource.String.edit_metadata), (sender, eventArg) => { LocalManager.EditMetadata(item); bottomSheet.Dismiss(); })
|
||||
});
|
||||
bottomSheet.Show();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.Support.V4.Media.Session;
|
||||
using Opus.Api.Services;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
|
||||
@@ -5,21 +5,6 @@ using System;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
public class HeaderHolder : RecyclerView.ViewHolder
|
||||
{
|
||||
public TextView headerText;
|
||||
|
||||
public HeaderHolder(View itemView, Action<int> listener, Action<int> longListener) : base(itemView)
|
||||
{
|
||||
headerText = itemView.FindViewById<TextView>(Android.Resource.Id.Title);
|
||||
if(listener != null)
|
||||
{
|
||||
itemView.Click += (sender, e) => listener(AdapterPosition);
|
||||
itemView.LongClick += (sender, e) => longListener(AdapterPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class HomeHolder : RecyclerView.ViewHolder
|
||||
{
|
||||
public LinearLayout textLayout;
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace Opus.Resources.Portable_Class
|
||||
tabs.AddTab(tabs.NewTab().SetText(Resources.GetString(Resource.String.channels)));
|
||||
|
||||
ViewPagerAdapter adapter = new ViewPagerAdapter(ChildFragmentManager);
|
||||
Fragment[] fragment = YoutubeEngine.NewInstances(query);
|
||||
Fragment[] fragment = YoutubeSearch.NewInstances(query);
|
||||
adapter.AddFragment(fragment[0], Resources.GetString(Resource.String.all));
|
||||
adapter.AddFragment(fragment[1], Resources.GetString(Resource.String.songs));
|
||||
adapter.AddFragment(fragment[2], Resources.GetString(Resource.String.playlists));
|
||||
@@ -100,8 +100,8 @@ namespace Opus.Resources.Portable_Class
|
||||
tabs.TabMode = TabLayout.ModeScrollable;
|
||||
tabs.SetScrollPosition(pos, 0f, true);
|
||||
|
||||
YoutubeEngine.instances[pos].IsFocused = true;
|
||||
YoutubeEngine.instances[pos].OnFocus();
|
||||
YoutubeSearch.instances[pos].IsFocused = true;
|
||||
YoutubeSearch.instances[pos].OnFocus();
|
||||
}
|
||||
return view;
|
||||
}
|
||||
@@ -115,9 +115,9 @@ namespace Opus.Resources.Portable_Class
|
||||
else
|
||||
FolderBrowse.instance.ListView.SmoothScrollToPosition(0);
|
||||
}
|
||||
if (YoutubeEngine.instances != null)
|
||||
if (YoutubeSearch.instances != null)
|
||||
{
|
||||
foreach (YoutubeEngine instance in YoutubeEngine.instances)
|
||||
foreach (YoutubeSearch instance in YoutubeSearch.instances)
|
||||
{
|
||||
if (instance.IsFocused)
|
||||
{
|
||||
@@ -157,16 +157,16 @@ namespace Opus.Resources.Portable_Class
|
||||
MainActivity.instance.HideSearch();
|
||||
}
|
||||
}
|
||||
else if (YoutubeEngine.instances != null)
|
||||
else if (YoutubeSearch.instances != null)
|
||||
{
|
||||
foreach (YoutubeEngine instance in YoutubeEngine.instances)
|
||||
foreach (YoutubeSearch instance in YoutubeSearch.instances)
|
||||
{
|
||||
if (instance.IsFocused)
|
||||
instance.OnUnfocus();
|
||||
instance.IsFocused = false;
|
||||
}
|
||||
YoutubeEngine.instances[position].IsFocused = true;
|
||||
YoutubeEngine.instances[position].OnFocus();
|
||||
YoutubeSearch.instances[position].IsFocused = true;
|
||||
YoutubeSearch.instances[position].OnFocus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ namespace Opus.Resources.Portable_Class
|
||||
base.OnDestroyView();
|
||||
Browse.instance = null;
|
||||
FolderBrowse.instance = null;
|
||||
YoutubeEngine.instances = null;
|
||||
YoutubeSearch.instances = null;
|
||||
|
||||
adapter?.Dispose();
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,33 +0,0 @@
|
||||
using Android.Graphics;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using System;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
public class PlaylistHolder : RecyclerView.ViewHolder
|
||||
{
|
||||
public TextView Title;
|
||||
public TextView Owner;
|
||||
public ImageView AlbumArt;
|
||||
public ImageView edit;
|
||||
public ImageView sync;
|
||||
public ProgressBar SyncLoading;
|
||||
public ImageView more;
|
||||
|
||||
public PlaylistHolder(View itemView, Action<int> listener, Action<int> longListener) : base(itemView)
|
||||
{
|
||||
Title = itemView.FindViewById<TextView>(Resource.Id.title);
|
||||
Owner = itemView.FindViewById<TextView>(Resource.Id.artist);
|
||||
AlbumArt = itemView.FindViewById<ImageView>(Resource.Id.albumArt);
|
||||
edit = itemView.FindViewById<ImageView>(Resource.Id.edit);
|
||||
sync = itemView.FindViewById<ImageView>(Resource.Id.sync);
|
||||
SyncLoading = itemView.FindViewById<ProgressBar>(Resource.Id.syncLoading);
|
||||
more = itemView.FindViewById<ImageView>(Resource.Id.moreButton);
|
||||
|
||||
itemView.Click += (sender, e) => listener(AdapterPosition);
|
||||
itemView.LongClick += (sender, e) => longListener(AdapterPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,15 @@ using Android.Graphics;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.Api;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Resources.values;
|
||||
using Opus.Fragments;
|
||||
using Opus.Others;
|
||||
using Square.Picasso;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Adapter
|
||||
{
|
||||
public class PlaylistTrackAdapter : RecyclerView.Adapter, IItemTouchAdapter
|
||||
{
|
||||
@@ -28,26 +29,6 @@ namespace Opus.Resources.Portable_Class
|
||||
this.songList = songList;
|
||||
}
|
||||
|
||||
public void AddToList(List<Song> songList)
|
||||
{
|
||||
int positionStart = this.songList.Count;
|
||||
this.songList.AddRange(songList);
|
||||
NotifyItemRangeInserted(positionStart, songList.Count);
|
||||
}
|
||||
|
||||
public void Insert(int position, Song item)
|
||||
{
|
||||
songList.Add(item);
|
||||
NotifyItemInserted(position);
|
||||
}
|
||||
|
||||
public void Remove(Song song)
|
||||
{
|
||||
int position = songList.IndexOf(song);
|
||||
songList.Remove(song);
|
||||
NotifyItemRemoved(position);
|
||||
}
|
||||
|
||||
public override int ItemCount
|
||||
{
|
||||
get
|
||||
@@ -80,29 +61,10 @@ namespace Opus.Resources.Portable_Class
|
||||
header.FindViewById<TextView>(Resource.Id.headerNumber).Text = songList.Count + " " + (songList.Count < 2 ? MainActivity.instance.GetString(Resource.String.element) : MainActivity.instance.GetString(Resource.String.elements));
|
||||
if (!header.FindViewById<ImageButton>(Resource.Id.headerPlay).HasOnClickListeners)
|
||||
{
|
||||
header.FindViewById<ImageButton>(Resource.Id.headerPlay).Click += (sender, e0) => { PlaylistTracks.instance.PlayInOrder(0); };
|
||||
header.FindViewById<ImageButton>(Resource.Id.headerPlay).Click += (sender, e0) => { PlaylistManager.PlayInOrder(PlaylistTracks.instance.item); };
|
||||
header.FindViewById<ImageButton>(Resource.Id.headerShuffle).Click += (sender, e0) =>
|
||||
{
|
||||
if (PlaylistTracks.instance.tracks[0].IsYt)
|
||||
{
|
||||
Random r = new Random();
|
||||
Song[] songs = PlaylistTracks.instance.tracks.OrderBy(x => r.Next()).ToArray();
|
||||
YoutubeEngine.PlayFiles(songs);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<string> tracksPath = new List<string>();
|
||||
foreach (Song song in PlaylistTracks.instance.tracks)
|
||||
tracksPath.Add(song.Path);
|
||||
|
||||
Intent intent = new Intent(MainActivity.instance, typeof(MusicPlayer));
|
||||
intent.PutStringArrayListExtra("files", tracksPath);
|
||||
intent.SetAction("RandomPlay");
|
||||
MainActivity.instance.StartService(intent);
|
||||
|
||||
MainActivity.instance.ShowSmallPlayer();
|
||||
MainActivity.instance.ShowPlayer();
|
||||
}
|
||||
PlaylistManager.Shuffle(PlaylistTracks.instance.item);
|
||||
};
|
||||
header.FindViewById<ImageButton>(Resource.Id.headerMore).Click += (sender, e0) =>
|
||||
{
|
||||
@@ -221,7 +183,7 @@ namespace Opus.Resources.Portable_Class
|
||||
|
||||
public void ItemDismissed(int position)
|
||||
{
|
||||
PlaylistTracks.instance.DeleteDialog(position);
|
||||
PlaylistTracks.instance.RemoveFromPlaylist(songList[position], position);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Support.V4.App;
|
||||
using Opus.Api.Services;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
using Android.Content;
|
||||
using Android.Net;
|
||||
using Android.Provider;
|
||||
using Android.Support.Design.Widget;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Resources.values;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
public class SnackbarCallback : BaseTransientBottomBar.BaseCallback
|
||||
{
|
||||
private Song song;
|
||||
private long playlistId;
|
||||
public bool canceled = false;
|
||||
|
||||
public SnackbarCallback(Song song, long playlistId)
|
||||
{
|
||||
this.song = song;
|
||||
this.playlistId = playlistId;
|
||||
}
|
||||
|
||||
public override void OnDismissed(Java.Lang.Object transientBottomBar, int @event)
|
||||
{
|
||||
base.OnDismissed(transientBottomBar, @event);
|
||||
if(!canceled)
|
||||
{
|
||||
if (song.TrackID != null)
|
||||
{
|
||||
YoutubeEngine.RemoveFromPlaylist(song.TrackID);
|
||||
}
|
||||
if (playlistId != 0)
|
||||
{
|
||||
ContentResolver resolver = MainActivity.instance.ContentResolver;
|
||||
Uri uri = MediaStore.Audio.Playlists.Members.GetContentUri("external", playlistId);
|
||||
resolver.Delete(uri, MediaStore.Audio.Playlists.Members.AudioId + "=?", new string[] { song.Id.ToString() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnShown(Java.Lang.Object transientBottomBar)
|
||||
{
|
||||
base.OnShown(transientBottomBar);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Android.Graphics;
|
||||
using Android.Support.V7.Widget;
|
||||
using Android.Views;
|
||||
using Android.Widget;
|
||||
using Opus.Resources.values;
|
||||
using Opus.DataStructure;
|
||||
using Opus.Resources.Portable_Class;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
namespace Opus.Adapter
|
||||
{
|
||||
public class TwoLineAdapter : RecyclerView.Adapter
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +0,0 @@
|
||||
using Opus.DataStructure;
|
||||
using Opus.Resources.values;
|
||||
|
||||
namespace Opus.Resources.Portable_Class
|
||||
{
|
||||
[System.Serializable]
|
||||
public class YtFile
|
||||
{
|
||||
public Song item;
|
||||
public YtKind Kind;
|
||||
|
||||
public YtFile(Song item, YtKind kind)
|
||||
{
|
||||
this.item = item;
|
||||
Kind = kind;
|
||||
}
|
||||
}
|
||||
|
||||
public enum YtKind { Null, Video, Playlist, Channel, ChannelPreview, Loading }
|
||||
}
|
||||
153
Opus/Resources/Resource.Designer.cs
generated
153
Opus/Resources/Resource.Designer.cs
generated
@@ -2117,44 +2117,44 @@ namespace Opus
|
||||
public partial class Color
|
||||
{
|
||||
|
||||
// aapt resource value: 0x7f090072
|
||||
public const int abc_background_cache_hint_selector_material_dark = 2131296370;
|
||||
|
||||
// aapt resource value: 0x7f090073
|
||||
public const int abc_background_cache_hint_selector_material_light = 2131296371;
|
||||
public const int abc_background_cache_hint_selector_material_dark = 2131296371;
|
||||
|
||||
// aapt resource value: 0x7f090074
|
||||
public const int abc_btn_colored_borderless_text_material = 2131296372;
|
||||
public const int abc_background_cache_hint_selector_material_light = 2131296372;
|
||||
|
||||
// aapt resource value: 0x7f090075
|
||||
public const int abc_btn_colored_text_material = 2131296373;
|
||||
public const int abc_btn_colored_borderless_text_material = 2131296373;
|
||||
|
||||
// aapt resource value: 0x7f090076
|
||||
public const int abc_color_highlight_material = 2131296374;
|
||||
public const int abc_btn_colored_text_material = 2131296374;
|
||||
|
||||
// aapt resource value: 0x7f090077
|
||||
public const int abc_hint_foreground_material_dark = 2131296375;
|
||||
public const int abc_color_highlight_material = 2131296375;
|
||||
|
||||
// aapt resource value: 0x7f090078
|
||||
public const int abc_hint_foreground_material_light = 2131296376;
|
||||
public const int abc_hint_foreground_material_dark = 2131296376;
|
||||
|
||||
// aapt resource value: 0x7f090079
|
||||
public const int abc_hint_foreground_material_light = 2131296377;
|
||||
|
||||
// aapt resource value: 0x7f090018
|
||||
public const int abc_input_method_navigation_guard = 2131296280;
|
||||
|
||||
// aapt resource value: 0x7f090079
|
||||
public const int abc_primary_text_disable_only_material_dark = 2131296377;
|
||||
|
||||
// aapt resource value: 0x7f09007a
|
||||
public const int abc_primary_text_disable_only_material_light = 2131296378;
|
||||
public const int abc_primary_text_disable_only_material_dark = 2131296378;
|
||||
|
||||
// aapt resource value: 0x7f09007b
|
||||
public const int abc_primary_text_material_dark = 2131296379;
|
||||
public const int abc_primary_text_disable_only_material_light = 2131296379;
|
||||
|
||||
// aapt resource value: 0x7f09007c
|
||||
public const int abc_primary_text_material_light = 2131296380;
|
||||
public const int abc_primary_text_material_dark = 2131296380;
|
||||
|
||||
// aapt resource value: 0x7f09007d
|
||||
public const int abc_search_url_text = 2131296381;
|
||||
public const int abc_primary_text_material_light = 2131296381;
|
||||
|
||||
// aapt resource value: 0x7f09007e
|
||||
public const int abc_search_url_text = 2131296382;
|
||||
|
||||
// aapt resource value: 0x7f090019
|
||||
public const int abc_search_url_text_normal = 2131296281;
|
||||
@@ -2165,29 +2165,29 @@ namespace Opus
|
||||
// aapt resource value: 0x7f09001b
|
||||
public const int abc_search_url_text_selected = 2131296283;
|
||||
|
||||
// aapt resource value: 0x7f09007e
|
||||
public const int abc_secondary_text_material_dark = 2131296382;
|
||||
|
||||
// aapt resource value: 0x7f09007f
|
||||
public const int abc_secondary_text_material_light = 2131296383;
|
||||
public const int abc_secondary_text_material_dark = 2131296383;
|
||||
|
||||
// aapt resource value: 0x7f090080
|
||||
public const int abc_tint_btn_checkable = 2131296384;
|
||||
public const int abc_secondary_text_material_light = 2131296384;
|
||||
|
||||
// aapt resource value: 0x7f090081
|
||||
public const int abc_tint_default = 2131296385;
|
||||
public const int abc_tint_btn_checkable = 2131296385;
|
||||
|
||||
// aapt resource value: 0x7f090082
|
||||
public const int abc_tint_edittext = 2131296386;
|
||||
public const int abc_tint_default = 2131296386;
|
||||
|
||||
// aapt resource value: 0x7f090083
|
||||
public const int abc_tint_seek_thumb = 2131296387;
|
||||
public const int abc_tint_edittext = 2131296387;
|
||||
|
||||
// aapt resource value: 0x7f090084
|
||||
public const int abc_tint_spinner = 2131296388;
|
||||
public const int abc_tint_seek_thumb = 2131296388;
|
||||
|
||||
// aapt resource value: 0x7f090085
|
||||
public const int abc_tint_switch_track = 2131296389;
|
||||
public const int abc_tint_spinner = 2131296389;
|
||||
|
||||
// aapt resource value: 0x7f090086
|
||||
public const int abc_tint_switch_track = 2131296390;
|
||||
|
||||
// aapt resource value: 0x7f09001c
|
||||
public const int accent_material_dark = 2131296284;
|
||||
@@ -2276,11 +2276,11 @@ namespace Opus
|
||||
// aapt resource value: 0x7f09000a
|
||||
public const int cast_libraries_material_featurehighlight_text_header_color = 2131296266;
|
||||
|
||||
// aapt resource value: 0x7f090086
|
||||
public const int color_tint = 2131296390;
|
||||
|
||||
// aapt resource value: 0x7f090087
|
||||
public const int common_google_signin_btn_text_dark = 2131296391;
|
||||
public const int color_tint = 2131296391;
|
||||
|
||||
// aapt resource value: 0x7f090088
|
||||
public const int common_google_signin_btn_text_dark = 2131296392;
|
||||
|
||||
// aapt resource value: 0x7f09000b
|
||||
public const int common_google_signin_btn_text_dark_default = 2131296267;
|
||||
@@ -2294,8 +2294,8 @@ namespace Opus
|
||||
// aapt resource value: 0x7f09000e
|
||||
public const int common_google_signin_btn_text_dark_pressed = 2131296270;
|
||||
|
||||
// aapt resource value: 0x7f090088
|
||||
public const int common_google_signin_btn_text_light = 2131296392;
|
||||
// aapt resource value: 0x7f090089
|
||||
public const int common_google_signin_btn_text_light = 2131296393;
|
||||
|
||||
// aapt resource value: 0x7f09000f
|
||||
public const int common_google_signin_btn_text_light_default = 2131296271;
|
||||
@@ -2309,8 +2309,8 @@ namespace Opus
|
||||
// aapt resource value: 0x7f090012
|
||||
public const int common_google_signin_btn_text_light_pressed = 2131296274;
|
||||
|
||||
// aapt resource value: 0x7f090089
|
||||
public const int common_google_signin_btn_tint = 2131296393;
|
||||
// aapt resource value: 0x7f09008a
|
||||
public const int common_google_signin_btn_tint = 2131296394;
|
||||
|
||||
// aapt resource value: 0x7f090055
|
||||
public const int design_bottom_navigation_shadow_color = 2131296341;
|
||||
@@ -2321,8 +2321,8 @@ namespace Opus
|
||||
// aapt resource value: 0x7f090057
|
||||
public const int design_default_color_primary_dark = 2131296343;
|
||||
|
||||
// aapt resource value: 0x7f09008a
|
||||
public const int design_error = 2131296394;
|
||||
// aapt resource value: 0x7f09008b
|
||||
public const int design_error = 2131296395;
|
||||
|
||||
// aapt resource value: 0x7f090058
|
||||
public const int design_fab_shadow_end_color = 2131296344;
|
||||
@@ -2348,8 +2348,8 @@ namespace Opus
|
||||
// aapt resource value: 0x7f09005f
|
||||
public const int design_snackbar_background_color = 2131296351;
|
||||
|
||||
// aapt resource value: 0x7f09008b
|
||||
public const int design_tint_password_toggle = 2131296395;
|
||||
// aapt resource value: 0x7f09008c
|
||||
public const int design_tint_password_toggle = 2131296396;
|
||||
|
||||
// aapt resource value: 0x7f09002a
|
||||
public const int dim_foreground_disabled_material_dark = 2131296298;
|
||||
@@ -2369,14 +2369,14 @@ namespace Opus
|
||||
// aapt resource value: 0x7f09006d
|
||||
public const int dsb_progress_color = 2131296365;
|
||||
|
||||
// aapt resource value: 0x7f09008c
|
||||
public const int dsb_progress_color_list = 2131296396;
|
||||
// aapt resource value: 0x7f09008d
|
||||
public const int dsb_progress_color_list = 2131296397;
|
||||
|
||||
// aapt resource value: 0x7f09006e
|
||||
public const int dsb_ripple_color_focused = 2131296366;
|
||||
|
||||
// aapt resource value: 0x7f09008d
|
||||
public const int dsb_ripple_color_list = 2131296397;
|
||||
// aapt resource value: 0x7f09008e
|
||||
public const int dsb_ripple_color_list = 2131296398;
|
||||
|
||||
// aapt resource value: 0x7f09006f
|
||||
public const int dsb_ripple_color_pressed = 2131296367;
|
||||
@@ -2384,8 +2384,8 @@ namespace Opus
|
||||
// aapt resource value: 0x7f090070
|
||||
public const int dsb_track_color = 2131296368;
|
||||
|
||||
// aapt resource value: 0x7f09008e
|
||||
public const int dsb_track_color_list = 2131296398;
|
||||
// aapt resource value: 0x7f09008f
|
||||
public const int dsb_track_color_list = 2131296399;
|
||||
|
||||
// aapt resource value: 0x7f09002e
|
||||
public const int error_color_material_dark = 2131296302;
|
||||
@@ -2447,71 +2447,71 @@ namespace Opus
|
||||
// aapt resource value: 0x7f09003f
|
||||
public const int material_grey_900 = 2131296319;
|
||||
|
||||
// aapt resource value: 0x7f09008f
|
||||
public const int mtrl_bottom_nav_colored_item_tint = 2131296399;
|
||||
|
||||
// aapt resource value: 0x7f090090
|
||||
public const int mtrl_bottom_nav_item_tint = 2131296400;
|
||||
public const int mtrl_bottom_nav_colored_item_tint = 2131296400;
|
||||
|
||||
// aapt resource value: 0x7f090091
|
||||
public const int mtrl_bottom_nav_item_tint = 2131296401;
|
||||
|
||||
// aapt resource value: 0x7f090060
|
||||
public const int mtrl_btn_bg_color_disabled = 2131296352;
|
||||
|
||||
// aapt resource value: 0x7f090091
|
||||
public const int mtrl_btn_bg_color_selector = 2131296401;
|
||||
|
||||
// aapt resource value: 0x7f090092
|
||||
public const int mtrl_btn_ripple_color = 2131296402;
|
||||
public const int mtrl_btn_bg_color_selector = 2131296402;
|
||||
|
||||
// aapt resource value: 0x7f090093
|
||||
public const int mtrl_btn_stroke_color_selector = 2131296403;
|
||||
public const int mtrl_btn_ripple_color = 2131296403;
|
||||
|
||||
// aapt resource value: 0x7f090094
|
||||
public const int mtrl_btn_text_btn_ripple_color = 2131296404;
|
||||
public const int mtrl_btn_stroke_color_selector = 2131296404;
|
||||
|
||||
// aapt resource value: 0x7f090095
|
||||
public const int mtrl_btn_text_btn_ripple_color = 2131296405;
|
||||
|
||||
// aapt resource value: 0x7f090061
|
||||
public const int mtrl_btn_text_color_disabled = 2131296353;
|
||||
|
||||
// aapt resource value: 0x7f090095
|
||||
public const int mtrl_btn_text_color_selector = 2131296405;
|
||||
// aapt resource value: 0x7f090096
|
||||
public const int mtrl_btn_text_color_selector = 2131296406;
|
||||
|
||||
// aapt resource value: 0x7f090062
|
||||
public const int mtrl_btn_transparent_bg_color = 2131296354;
|
||||
|
||||
// aapt resource value: 0x7f090096
|
||||
public const int mtrl_chip_background_color = 2131296406;
|
||||
|
||||
// aapt resource value: 0x7f090097
|
||||
public const int mtrl_chip_close_icon_tint = 2131296407;
|
||||
public const int mtrl_chip_background_color = 2131296407;
|
||||
|
||||
// aapt resource value: 0x7f090098
|
||||
public const int mtrl_chip_ripple_color = 2131296408;
|
||||
public const int mtrl_chip_close_icon_tint = 2131296408;
|
||||
|
||||
// aapt resource value: 0x7f090099
|
||||
public const int mtrl_chip_text_color = 2131296409;
|
||||
public const int mtrl_chip_ripple_color = 2131296409;
|
||||
|
||||
// aapt resource value: 0x7f09009a
|
||||
public const int mtrl_fab_ripple_color = 2131296410;
|
||||
public const int mtrl_chip_text_color = 2131296410;
|
||||
|
||||
// aapt resource value: 0x7f09009b
|
||||
public const int mtrl_fab_ripple_color = 2131296411;
|
||||
|
||||
// aapt resource value: 0x7f090063
|
||||
public const int mtrl_scrim_color = 2131296355;
|
||||
|
||||
// aapt resource value: 0x7f09009b
|
||||
public const int mtrl_tabs_colored_ripple_color = 2131296411;
|
||||
|
||||
// aapt resource value: 0x7f09009c
|
||||
public const int mtrl_tabs_icon_color_selector = 2131296412;
|
||||
public const int mtrl_tabs_colored_ripple_color = 2131296412;
|
||||
|
||||
// aapt resource value: 0x7f09009d
|
||||
public const int mtrl_tabs_icon_color_selector_colored = 2131296413;
|
||||
public const int mtrl_tabs_icon_color_selector = 2131296413;
|
||||
|
||||
// aapt resource value: 0x7f09009e
|
||||
public const int mtrl_tabs_legacy_text_color_selector = 2131296414;
|
||||
public const int mtrl_tabs_icon_color_selector_colored = 2131296414;
|
||||
|
||||
// aapt resource value: 0x7f09009f
|
||||
public const int mtrl_tabs_ripple_color = 2131296415;
|
||||
public const int mtrl_tabs_legacy_text_color_selector = 2131296415;
|
||||
|
||||
// aapt resource value: 0x7f0900a0
|
||||
public const int mtrl_text_btn_text_color_selector = 2131296416;
|
||||
public const int mtrl_tabs_ripple_color = 2131296416;
|
||||
|
||||
// aapt resource value: 0x7f0900a1
|
||||
public const int mtrl_text_btn_text_color_selector = 2131296417;
|
||||
|
||||
// aapt resource value: 0x7f090064
|
||||
public const int mtrl_textinput_default_box_stroke_color = 2131296356;
|
||||
@@ -2534,6 +2534,9 @@ namespace Opus
|
||||
// aapt resource value: 0x7f090054
|
||||
public const int notification_material_background_media_default_color = 2131296340;
|
||||
|
||||
// aapt resource value: 0x7f090072
|
||||
public const int placeholder = 2131296370;
|
||||
|
||||
// aapt resource value: 0x7f090013
|
||||
public const int preference_fallback_accent_color = 2131296275;
|
||||
|
||||
@@ -2588,11 +2591,11 @@ namespace Opus
|
||||
// aapt resource value: 0x7f09004f
|
||||
public const int switch_thumb_disabled_material_light = 2131296335;
|
||||
|
||||
// aapt resource value: 0x7f0900a1
|
||||
public const int switch_thumb_material_dark = 2131296417;
|
||||
|
||||
// aapt resource value: 0x7f0900a2
|
||||
public const int switch_thumb_material_light = 2131296418;
|
||||
public const int switch_thumb_material_dark = 2131296418;
|
||||
|
||||
// aapt resource value: 0x7f0900a3
|
||||
public const int switch_thumb_material_light = 2131296419;
|
||||
|
||||
// aapt resource value: 0x7f090050
|
||||
public const int switch_thumb_normal_material_dark = 2131296336;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<resources>
|
||||
<color name="splashColor">#212121</color>
|
||||
<color name="placeholder">#212121</color>
|
||||
</resources>
|
||||
@@ -4,7 +4,7 @@
|
||||
<package id="Google.Apis" version="1.38.2" targetFramework="monoandroid90" />
|
||||
<package id="Google.Apis.Auth" version="1.38.2" targetFramework="monoandroid90" />
|
||||
<package id="Google.Apis.Core" version="1.38.2" targetFramework="monoandroid90" />
|
||||
<package id="Google.Apis.YouTube.v3" version="1.38.0.1488" targetFramework="monoandroid90" />
|
||||
<package id="Google.Apis.YouTube.v3" version="1.38.2.1488" targetFramework="monoandroid90" />
|
||||
<package id="Karamunting.Android.AnderWeb.DiscreteSeekBar" version="1.0.1.1" targetFramework="monoandroid81" />
|
||||
<package id="Microsoft.CSharp" version="4.5.0" targetFramework="monoandroid81" />
|
||||
<package id="Microsoft.NETCore.Platforms" version="2.2.0" targetFramework="monoandroid81" />
|
||||
|
||||
Reference in New Issue
Block a user