Adding playlists in the home screen and a ripple animation.

This commit is contained in:
Tristan Roux
2019-04-11 23:30:57 +02:00
parent 6771dfa5e1
commit 91015fc4c7
18 changed files with 838 additions and 1046 deletions

View File

@@ -357,7 +357,7 @@
<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\HomeChannelAdapter.cs" />
<Compile Include="Resources\Portable Class\HomeListAdapter.cs" />
<Compile Include="Resources\Portable Class\HomeHolder.cs" />
<Compile Include="Resources\Portable Class\HomeMultipleSong.cs" />
<Compile Include="Resources\Portable Class\ItemTouchCallback.cs" />
@@ -885,6 +885,9 @@
<ItemGroup>
<AndroidResource Include="Resources\drawable\SplashArt.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\HomePlaylist.xml" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Import Project="..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.25.4.0.2\build\MonoAndroid70\Xamarin.Android.Support.Animated.Vector.Drawable.targets" Condition="Exists('..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.25.4.0.2\build\MonoAndroid70\Xamarin.Android.Support.Animated.Vector.Drawable.targets')" />
<Import Project="..\packages\Xamarin.Android.Support.v7.Preference.25.4.0.2\build\MonoAndroid70\Xamarin.Android.Support.v7.Preference.targets" Condition="Exists('..\packages\Xamarin.Android.Support.v7.Preference.25.4.0.2\build\MonoAndroid70\Xamarin.Android.Support.v7.Preference.targets')" />

View File

@@ -15,7 +15,7 @@ public class CollapsingToolbar : CollapsingToolbarLayout
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (PlaylistTracks.instance != null)
if (PlaylistTracks.instance != null && PlaylistTracks.instance.useHeader)
heightMeasureSpec = widthMeasureSpec;

View File

@@ -61,7 +61,7 @@ namespace Opus.Resources.Portable_Class
}
#pragma warning restore CS4014
private /*async Task */ void PopulateView()
private async Task PopulateView()
{
if (!populating)
{
@@ -74,7 +74,7 @@ namespace Opus.Resources.Portable_Class
adapterItems.Add(queue);
}
HomeSection shuffle = new HomeSection(Resources.GetString(Resource.String.shuffle), SectionType.Shuffle, null);
HomeSection shuffle = new HomeSection(Resources.GetString(Resource.String.shuffle), SectionType.Shuffle);
adapterItems.Add(shuffle);
if (MainActivity.instance.HasReadPermission())
@@ -128,247 +128,15 @@ namespace Opus.Resources.Portable_Class
adapter.ItemClick += ListView_ItemClick;
ListView.SetItemAnimator(new DefaultItemAnimator());
//ConnectivityManager connectivityManager = (ConnectivityManager)MainActivity.instance.GetSystemService(Context.ConnectivityService);
//NetworkInfo activeNetworkInfo = connectivityManager.ActiveNetworkInfo;
//if (activeNetworkInfo == null || !activeNetworkInfo.IsConnected)
// return;
(List<PlaylistItem> playlists, string error) = await Playlist.GetLocalPlaylists(false);
if(playlists != null)
{
(List<PlaylistItem> pl, List<PlaylistItem> sp) = await Playlist.ProcessSyncedPlaylists(playlists);
sp.AddRange(pl);
adapterItems.Add(new HomeSection(GetString(Resource.String.playlists), SectionType.PlaylistList, sp));
adapter.NotifyItemInserted(adapterItems.Count - 1);
}
//ISharedPreferences prefManager = PreferenceManager.GetDefaultSharedPreferences(Activity);
//List<string> topics = prefManager.GetStringSet("selectedTopics", new string[] { }).ToList();
//foreach (string topic in topics)
//{
// selectedTopics.Add(topic.Substring(0, topic.IndexOf("/#-#/")));
// selectedTopicsID.Add(topic.Substring(topic.IndexOf("/#-#/") + 5));
//}
//if (!await MainActivity.instance.WaitForYoutube())
// return;
//if (instance == null)
// return;
//if (selectedTopicsID.Count > 0)
//{
// List<HomeItem> Items = new List<HomeItem>();
// foreach (string topic in selectedTopicsID)
// {
// try
// {
// YouTubeService youtube = YoutubeEngine.youtubeService;
// ChannelSectionsResource.ListRequest request = youtube.ChannelSections.List("snippet, contentDetails");
// request.ChannelId = topic;
// ChannelSectionListResponse response = await request.ExecuteAsync();
// foreach (var section in response.Items)
// {
// if (section.Snippet.Type == "channelsectionTypeUndefined")
// continue;
// string title = section.Snippet.Title;
// if (title == null || title == "")
// title = selectedTopics[selectedTopicsID.IndexOf(topic)];
// if (title == "Popular Artists" || title == "Featured channels")
// title = (selectedTopics[selectedTopicsID.IndexOf(topic)].Contains(" Music") ? selectedTopics[selectedTopicsID.IndexOf(topic)].Substring(0, selectedTopics[selectedTopicsID.IndexOf(topic)].IndexOf(" Music")) : selectedTopics[selectedTopicsID.IndexOf(topic)]) + "'s " + title;
// if (title == "Popular Channels")
// continue;
// if (Items.Exists(x => x.SectionTitle == title))
// continue;
// SectionType type = SectionType.None;
// List<string> contentValue = null;
// switch (section.Snippet.Type)
// {
// case "multipleChannels":
// type = SectionType.ChannelList;
// contentValue = section.ContentDetails.Channels.ToList();
// break;
// case "multiplePlaylists":
// contentValue = section.ContentDetails.Playlists.ToList();
// type = SectionType.PlaylistList;
// break;
// case "singlePlaylist":
// contentValue = section.ContentDetails.Playlists.ToList();
// type = SectionType.SinglePlaylist;
// break;
// default:
// contentValue = new List<string>();
// break;
// }
// HomeItem item = new HomeItem(title, type, contentValue);
// Items.Add(item);
// }
// }
// catch (System.Net.Http.HttpRequestException)
// {
// MainActivity.instance.Timout();
// }
// }
// List<HomeItem> playlistList = Items.FindAll(x => x.contentType == SectionType.PlaylistList);
// Items.RemoveAll(x => x.contentType == SectionType.PlaylistList);
// Random r = new Random();
// Items = Items.OrderBy(x => r.Next()).ToList();
// Items.AddRange(playlistList);
// foreach (HomeItem item in Items)
// {
// List<Song> contentValue = new List<Song>();
// switch (item.contentType)
// {
// case SectionType.SinglePlaylist:
// try
// {
// YouTubeService youtube = YoutubeEngine.youtubeService;
// PlaylistItemsResource.ListRequest request = youtube.PlaylistItems.List("snippet, contentDetails");
// request.PlaylistId = item.contentValue[0];
// request.MaxResults = 25;
// request.PageToken = "";
// PlaylistItemListResponse response = await request.ExecuteAsync();
// if (response.Items.Count < 10)
// break;
// foreach (var ytItem in response.Items)
// {
// if (ytItem.Snippet.Title != "[Deleted video]" && ytItem.Snippet.Title != "Private video" && ytItem.Snippet.Title != "Deleted video")
// {
// 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);
// contentValue.Add(song);
// if (instance == null)
// return;
// }
// }
// }
// catch (System.Net.Http.HttpRequestException)
// {
// MainActivity.instance.Timout();
// }
// HomeSection section = new HomeSection(item.SectionTitle, item.contentType, contentValue);
// adapter.AddToList(new List<HomeSection>() { section });
// break;
// case SectionType.ChannelList:
// foreach (string channelID in item.contentValue)
// {
// try
// {
// YouTubeService youtube = YoutubeEngine.youtubeService;
// ChannelsResource.ListRequest req = youtube.Channels.List("snippet");
// req.Id = channelID;
// ChannelListResponse resp = await req.ExecuteAsync();
// foreach (var ytItem in resp.Items)
// {
// Song channel = new Song(ytItem.Snippet.Title.Contains(" - Topic") ? ytItem.Snippet.Title.Substring(0, ytItem.Snippet.Title.IndexOf(" - Topic")) : ytItem.Snippet.Title, null, ytItem.Snippet.Thumbnails.Default__.Url, channelID, -1, -1, null, true);
// contentValue.Add(channel);
// if (instance == null)
// return;
// }
// }
// catch (System.Net.Http.HttpRequestException)
// {
// MainActivity.instance.Timout();
// }
// }
// section = new HomeSection(item.SectionTitle, item.contentType, contentValue);
// adapter.AddToList(new List<HomeSection>() { section });
// break;
// case SectionType.PlaylistList:
// foreach (string playlistID in item.contentValue)
// {
// try
// {
// YouTubeService youtube = YoutubeEngine.youtubeService;
// PlaylistsResource.ListRequest request = youtube.Playlists.List("snippet, contentDetails");
// request.Id = playlistID;
// PlaylistListResponse response = await request.ExecuteAsync();
// foreach (var playlist in response.Items)
// {
// Song song = new Song(playlist.Snippet.Title, playlist.Snippet.ChannelTitle, playlist.Snippet.Thumbnails.Default__.Url, playlist.Id, -1, -1, playlist.Id, true);
// contentValue.Add(song);
// if (instance == null)
// return;
// }
// }
// catch (System.Net.Http.HttpRequestException)
// {
// MainActivity.instance.Timout();
// }
// }
// section = new HomeSection(item.SectionTitle, item.contentType, contentValue);
// List<Song> removedValues = new List<Song>();
// for (int i = 0; i < adapter.ItemCount; i++)
// {
// if (adapter.items[i].contentType == SectionType.ChannelList)
// {
// for (int j = 0; j < adapter.items[i].contentValue.Count; j++)
// {
// if (section.contentValue.Exists(x => x.Title.Contains(adapter.items[i].contentValue[j].Title)))
// {
// adapter.items[i].contentValue[j].Artist = section.contentValue.Find(x => x.Title.Contains(adapter.items[i].contentValue[j].Title)).YoutubeID;
// removedValues.Add(section.contentValue.Find(x => x.Title.Contains(adapter.items[i].contentValue[j].Title)));
// if (j < 4 && adapter.items[i].recycler != null)
// {
// RecyclerHolder holder = (RecyclerHolder)adapter.items[i].recycler.GetChildViewHolder(adapter.items[i].recycler.GetLayoutManager().FindViewByPosition(j));
// holder.action.Text = "Mix";
// }
// }
// }
// }
// }
// //section.contentValue = section.contentValue.Except(removedValues).ToList();
// //if(section.contentValue.Count > 0)
// // adapter.AddToList(new List<HomeSection>() { section });
// break;
// default:
// break;
// }
// }
// r = new Random();
// if (r.Next(0, 100) > 90)
// await AddHomeTopics();
// for (int i = 0; i < adapter.items.Count; i++)
// {
// if (adapter.items[i].contentType == SectionType.ChannelList)
// {
// for (int j = 0; j < adapter.items[i].contentValue.Count; j++)
// {
// if (adapter.items[i].contentValue[j].Artist == null)
// {
// adapter.items[i].contentValue[j].Artist = "Follow";
// if (j < 4 && adapter.items[i].recycler != null)
// {
// RecyclerHolder holder = (RecyclerHolder)adapter.items[i].recycler.GetChildViewHolder(adapter.items[i].recycler.GetLayoutManager().FindViewByPosition(j));
// holder.action.Text = "Follow";
// }
// }
// }
// }
// }
//}
//else
//{
// await AddHomeTopics();
//}
populating = false;
}
}
@@ -379,7 +147,7 @@ namespace Opus.Resources.Portable_Class
{
HomeSection queue = new HomeSection("Queue", SectionType.SinglePlaylist, MusicPlayer.queue);
adapterItems.Insert(0, queue);
adapter?.Insert(0, queue);
adapter?.NotifyItemInserted(0);
}
}
@@ -398,8 +166,7 @@ namespace Opus.Resources.Portable_Class
public async Task Refresh()
{
/*await*/ PopulateView();
await Task.Delay(0); //WE DONT NEED TO TALK ABOUT THIS
await PopulateView();
}
public void LoadMore()

View File

@@ -1,6 +1,7 @@
using Android.Content;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Support.Design.Widget;
using Android.Support.V7.Widget;
using Android.Util;
using Android.Views;
@@ -25,25 +26,6 @@ namespace Opus.Resources.Portable_Class
this.items = items;
}
public void UpdateList(List<HomeSection> items)
{
this.items = items;
NotifyDataSetChanged();
}
public void AddToList(List<HomeSection> items)
{
int positionStart = this.items.Count;
this.items.AddRange(items);
NotifyItemRangeInserted(positionStart, items.Count);
}
public void Insert(int position, HomeSection item)
{
//items.Insert(0, item);
NotifyItemInserted(0);
}
public override int ItemCount { get { return items.Count; } }
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
@@ -58,11 +40,11 @@ namespace Opus.Resources.Portable_Class
View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.HomeChannels, parent, false);
return new LineSongHolder(itemView, OnClick, OnLongClick);
}
//else if(viewType == 2)
//{
// View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.HomePlaylists, parent, false);
// return new LineSongHolder(itemView, OnClick, OnLongClick);
//}
else if (viewType == 2)
{
View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.HomePlaylists, parent, false);
return new LineSongHolder(itemView, OnClick, OnLongClick);
}
else
{
View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.ShuffleButton, parent, false);
@@ -99,9 +81,6 @@ namespace Opus.Resources.Portable_Class
holder.more.Click += (sender, e) =>
{
position = holder.AdapterPosition;
MainActivity.instance.SupportActionBar.SetHomeButtonEnabled(true);
MainActivity.instance.SupportActionBar.SetDisplayHomeAsUpEnabled(true);
MainActivity.instance.SupportActionBar.Title = items[position].SectionTitle;
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();
@@ -118,24 +97,24 @@ namespace Opus.Resources.Portable_Class
holder.title.Text = items[position].SectionTitle;
holder.recycler.SetLayoutManager(new LinearLayoutManager(MainActivity.instance, LinearLayoutManager.Vertical, false));
holder.recycler.SetAdapter(new HomeChannelAdapter(items[position].contentValue.GetRange(0, items[position].contentValue.Count > 4 ? 4 : items[position].contentValue.Count), holder.recycler) { allItems = items[position].contentValue.GetRange(4, items[position].contentValue.Count - 4) });
holder.recycler.SetAdapter(new HomeListAdapter(items[position].contentValue.GetRange(0, items[position].contentValue.Count > 4 ? 4 : items[position].contentValue.Count), holder.recycler) { allItems = items[position].contentValue.GetRange(4, items[position].contentValue.Count - 4) });
((GradientDrawable)holder.more.Background).SetStroke(5, Android.Content.Res.ColorStateList.ValueOf(Color.Argb(255, 21, 183, 237)));
holder.more.SetTextColor(Color.Argb(255, 21, 183, 237));
holder.more.Text = ((HomeChannelAdapter)holder.recycler.GetAdapter()).songList.Count > 4 ? "View Less" : "View More";
holder.more.Text = ((HomeListAdapter)holder.recycler.GetAdapter()).channels.Count > 4 ? "View Less" : "View More";
holder.more.Click += (sender, e) =>
{
HomeChannelAdapter adapter = (HomeChannelAdapter)holder.recycler.GetAdapter();
HomeListAdapter adapter = (HomeListAdapter)holder.recycler.GetAdapter();
if(adapter.ItemCount == 4)
{
adapter.songList.AddRange(items[position].contentValue.GetRange(4, items[position].contentValue.Count - 4));
adapter.channels.AddRange(items[position].contentValue.GetRange(4, items[position].contentValue.Count - 4));
adapter.NotifyItemRangeInserted(4, items[position].contentValue.Count - 4);
holder.more.Text = "View Less";
}
else
{
int count = adapter.songList.Count - 4;
adapter.songList.RemoveRange(4, count);
int count = adapter.channels.Count - 4;
adapter.channels.RemoveRange(4, count);
adapter.NotifyItemRangeRemoved(4, count);
holder.more.Text = "View More";
}
@@ -144,33 +123,35 @@ namespace Opus.Resources.Portable_Class
if (MainActivity.Theme == 1)
holder.ItemView.SetBackgroundColor(Color.Argb(255, 62, 62, 62));
}
//else if (items[position].contentType == SectionType.PlaylistList)
//{
// LineSongHolder holder = (LineSongHolder)viewHolder;
// holder.title.Text = items[position].SectionTitle;
// holder.recycler.SetLayoutManager(new LinearLayoutManager(MainActivity.instance, LinearLayoutManager.Vertical, false));
// holder.recycler.SetAdapter(new HomeChannelAdapter(items[position].contentValue.GetRange(0, items[position].contentValue.Count > 4 ? 4 : items[position].contentValue.Count), holder.recycler));
// if (MainActivity.Theme == 1)
// holder.ItemView.SetBackgroundColor(Color.Argb(255, 62, 62, 62));
//}
else if(items[position].contentType == SectionType.TopicSelector)
else if (items[position].contentType == SectionType.PlaylistList)
{
LineSongHolder holder = (LineSongHolder)viewHolder;
items[position].recycler = holder.recycler;
holder.title.Text = items[position].SectionTitle;
holder.recycler.SetLayoutManager(new LinearLayoutManager(MainActivity.instance, LinearLayoutManager.Vertical, false));
holder.recycler.SetAdapter(new HomeChannelAdapter(items[position].contentValue));
holder.more.Click += (sender, e) =>
{
Intent intent = new Intent(MainActivity.instance, typeof(Preferences));
MainActivity.instance.StartActivity(intent);
};
holder.recycler.SetAdapter(new HomeListAdapter(items[position].playlistContent.GetRange(0, items[position].playlistContent.Count > 4 ? 4 : items[position].playlistContent.Count), holder.recycler));
holder.more.Click += (sender, e) => { MainActivity.instance.FindViewById<BottomNavigationView>(Resource.Id.bottomView).SelectedItemId = Resource.Id.playlistLayout; };
if (MainActivity.Theme == 1)
holder.ItemView.SetBackgroundColor(Color.Argb(255, 62, 62, 62));
}
//else if(items[position].contentType == SectionType.TopicSelector)
//{
// LineSongHolder holder = (LineSongHolder)viewHolder;
// items[position].recycler = holder.recycler;
// holder.title.Text = items[position].SectionTitle;
// holder.recycler.SetLayoutManager(new LinearLayoutManager(MainActivity.instance, LinearLayoutManager.Vertical, false));
// holder.recycler.SetAdapter(new HomeListAdapter(items[position].contentValue));
// holder.more.Click += (sender, e) =>
// {
// Intent intent = new Intent(MainActivity.instance, typeof(Preferences));
// MainActivity.instance.StartActivity(intent);
// };
// if (MainActivity.Theme == 1)
// holder.ItemView.SetBackgroundColor(Color.Argb(255, 62, 62, 62));
//}
else if (items[position].contentType == SectionType.Shuffle)
{
if (MainActivity.Theme == 1)

View File

@@ -1,180 +0,0 @@
using Android.App;
using Android.Content;
using Android.Support.V7.Preferences;
using Android.Support.V7.Widget;
using Android.Views;
using Android.Widget;
using Opus.Resources.values;
using Square.Picasso;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Opus.Resources.Portable_Class
{
public class HomeChannelAdapter : RecyclerView.Adapter
{
public RecyclerView recycler;
public int listPadding = 0;
public List<Song> songList;
public List<Song> allItems;
private bool useTopic = false;
public override int ItemCount => useTopic ? 3 : songList.Count;
public HomeChannelAdapter(List<Song> songList, RecyclerView recycler)
{
this.recycler = recycler;
this.songList = songList;
}
public HomeChannelAdapter(List<Song> songList)
{
this.songList = songList;
useTopic = true;
}
public override void OnBindViewHolder(RecyclerView.ViewHolder viewHolder, int position)
{
RecyclerHolder holder = (RecyclerHolder)viewHolder;
holder.Title.Text = songList[position].Title;
var songAlbumArtUri = Android.Net.Uri.Parse(songList[position].Album);
Picasso.With(Application.Context).Load(songAlbumArtUri).Placeholder(Resource.Color.background_material_dark).Resize(400, 400).CenterCrop().Transform(new CircleTransformation()).Into(holder.AlbumArt);
if (!useTopic)
{
if (songList[position].Artist == "Follow")
{
if(Home.instance.selectedTopicsID.Contains(songList[position].YoutubeID))
holder.action.Text = "Unfollow";
else
holder.action.Text = "Follow";
}
else if (songList[position].Artist != null)
holder.action.Text = "Mix";
if (!holder.action.HasOnClickListeners)
{
holder.action.Click += async (sender, e) =>
{
if(holder.action.Text == "Following")
{
holder.action.Text = "Unfollowed";
ISharedPreferences prefManager = PreferenceManager.GetDefaultSharedPreferences(MainActivity.instance);
List<string> topics = prefManager.GetStringSet("selectedTopics", new string[] { }).ToList();
ISharedPreferencesEditor editor = prefManager.Edit();
topics.Remove(songList[position].Title + "/#-#/" + songList[position].YoutubeID);
editor.PutStringSet("selectedTopics", topics);
editor.Apply();
Home.instance.selectedTopics.Remove(songList[position].Title);
Home.instance.selectedTopicsID.Remove(songList[position].YoutubeID);
await Task.Delay(1000);
holder.action.Text = "Follow";
}
else if (songList[position].Artist == "Follow")
{
ISharedPreferences prefManager = PreferenceManager.GetDefaultSharedPreferences(MainActivity.instance);
List<string> topics = prefManager.GetStringSet("selectedTopics", new string[] { }).ToList();
ISharedPreferencesEditor editor = prefManager.Edit();
topics.Add(songList[position].Title + "/#-#/" + songList[position].YoutubeID);
editor.PutStringSet("selectedTopics", topics);
editor.Apply();
Home.instance.selectedTopics.Add(songList[position].Title);
Home.instance.selectedTopicsID.Add(songList[position].YoutubeID);
holder.action.Text = "Following";
await Task.Delay(1000);
if(holder.action.Text != "Unfollowed")
{
if (allItems.Count > 0 && songList.Count < 5)
{
songList[position] = allItems[allItems.Count - 1];
NotifyItemChanged(position);
allItems.RemoveAt(allItems.Count - 1);
}
else
{
songList.RemoveAt(position);
allItems.RemoveAt(position);
NotifyItemRemoved(position);
}
}
}
else if (songList[position].Artist != null)
Playlist.PlayInOrder(songList[position].Artist);
};
}
}
else
{
holder.action.Text = "Follow";
if (!holder.action.HasOnClickListeners)
{
holder.action.Click += async (sender, e) =>
{
if (holder.action.Text == "Following")
{
holder.action.Text = "Unfollowed";
ISharedPreferences prefManager = PreferenceManager.GetDefaultSharedPreferences(MainActivity.instance);
List<string> topics = prefManager.GetStringSet("selectedTopics", new string[] { }).ToList();
ISharedPreferencesEditor editor = prefManager.Edit();
topics.Remove(songList[position].Title + "/#-#/" + songList[position].YoutubeID);
editor.PutStringSet("selectedTopics", topics);
editor.Apply();
await Task.Delay(1000);
holder.action.Text = "Follow";
}
else
{
ISharedPreferences prefManager = PreferenceManager.GetDefaultSharedPreferences(MainActivity.instance);
List<string> topics = prefManager.GetStringSet("selectedTopics", new string[] { }).ToList();
ISharedPreferencesEditor editor = prefManager.Edit();
topics.Add(songList[position].Title + "/#-#/" + songList[position].YoutubeID);
editor.PutStringSet("selectedTopics", topics);
editor.Apply();
holder.action.Text = "Following";
await Task.Delay(1000);
if (holder.action.Text != "Unfollowed")
{
if (position == 0 || position == 1)
{
if (songList.Count < 4)
return;
songList[position] = songList[songList.Count - 1];
songList.RemoveAt(songList.Count - 1);
}
else
songList.RemoveAt(position);
NotifyItemChanged(position);
}
}
};
}
holder.ItemView.SetPadding(4, 1, 4, 1);
}
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.HomeChannel, parent, false);
return new RecyclerHolder(itemView, OnClick, OnLongClick);
}
void OnClick(int position) { }
void OnLongClick(int position) { }
}
}

View File

@@ -0,0 +1,115 @@
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.Resources.values;
using Square.Picasso;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Opus.Resources.Portable_Class
{
public class HomeListAdapter : RecyclerView.Adapter
{
public RecyclerView recycler;
public int listPadding = 0;
public List<Song> channels;
public List<PlaylistItem> playlists;
public List<Song> allItems;
private readonly bool UseChannel;
public bool expanded = false;
public override int ItemCount => UseChannel ? (expanded ? (channels.Count > 3 ? 3 : channels.Count) : channels.Count) :
expanded ? (playlists.Count > 3 ? 3 : playlists.Count) : playlists.Count;
public HomeListAdapter(List<Song> channels, RecyclerView recycler)
{
this.recycler = recycler;
this.channels = channels;
UseChannel = true;
}
public HomeListAdapter(List<PlaylistItem> playlists, RecyclerView recycler)
{
this.recycler = recycler;
this.playlists = playlists;
UseChannel = false;
}
public override void OnBindViewHolder(RecyclerView.ViewHolder viewHolder, int position)
{
RecyclerHolder holder = (RecyclerHolder)viewHolder;
if(UseChannel)
{
holder.Title.Text = channels[position].Title;
Picasso.With(Application.Context).Load(channels[position].Album).Placeholder(Resource.Color.background_material_dark).Transform(new CircleTransformation()).Into(holder.AlbumArt);
holder.ItemView.SetPadding(4, 1, 4, 1);
}
else
{
holder.Title.Text = playlists[position].Name;
Picasso.With(Application.Context).Load(playlists[position].ImageURL).Placeholder(Resource.Color.background_material_dark).Resize(400, 400).CenterCrop().Into(holder.AlbumArt);
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); };
}
if(MainActivity.Theme == 1)
{
holder.RightButtons.FindViewById<ImageButton>(Resource.Id.play).ImageTintList = ColorStateList.ValueOf(Color.White);
holder.RightButtons.FindViewById<ImageButton>(Resource.Id.shuffle).ImageTintList = ColorStateList.ValueOf(Color.White);
}
else
{
holder.RightButtons.FindViewById<ImageButton>(Resource.Id.play).ImageTintList = ColorStateList.ValueOf(Color.Black);
holder.RightButtons.FindViewById<ImageButton>(Resource.Id.shuffle).ImageTintList = ColorStateList.ValueOf(Color.Black);
}
}
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
if(UseChannel)
{
View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.HomeChannel, parent, false);
return new RecyclerHolder(itemView, OnClick, OnLongClick);
}
else
{
View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.HomePlaylist, parent, false);
return new RecyclerHolder(itemView, OnClick, OnLongClick);
}
}
void OnClick(int position)
{
if(UseChannel)
{
//Open a channel view
}
else
{
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();
}
}
void OnLongClick(int position) { }
}
}

View File

@@ -1,4 +1,5 @@
using Android.Support.V7.Widget;
using Opus.Resources.Portable_Class;
using System.Collections.Generic;
namespace Opus.Resources.values
@@ -9,14 +10,28 @@ namespace Opus.Resources.values
public string SectionTitle;
public SectionType contentType;
public List<Song> contentValue;
public List<PlaylistItem> playlistContent;
public RecyclerView recycler;
public HomeSection(string sectionTitle, SectionType contentType)
{
SectionTitle = sectionTitle;
this.contentType = contentType;
}
public HomeSection(string sectionTitle, SectionType contentType, List<Song> contentValue)
{
SectionTitle = sectionTitle;
this.contentType = contentType;
this.contentValue = contentValue;
}
public HomeSection(string sectionTitle, SectionType contentType, List<PlaylistItem> playlistContent)
{
SectionTitle = sectionTitle;
this.contentType = contentType;
this.playlistContent = playlistContent;
}
}
public enum SectionType

View File

@@ -191,10 +191,18 @@ namespace Opus.Resources.Portable_Class
/* This method will return all playlists available on the local storage in the array "playlists".
* If there is an error, the Task will return an error message to display to the user. */
public static async Task<(List<PlaylistItem>, string)> GetLocalPlaylists()
public static async Task<(List<PlaylistItem>, string)> GetLocalPlaylists(bool askForPermission = true)
{
if (!await MainActivity.instance.GetReadPermission())
return (null, Application.Context.GetString(Resource.String.no_permission));
if(askForPermission)
{
if (!await MainActivity.instance.GetReadPermission())
return (null, Application.Context.GetString(Resource.String.no_permission));
}
else
{
if (!MainActivity.instance.HasReadPermission())
return (null, Application.Context.GetString(Resource.String.no_permission));
}
List<PlaylistItem> playlists = new List<PlaylistItem>();

View File

@@ -1,4 +1,5 @@
using SQLite;
using Opus.Resources.values;
using SQLite;
using System;
namespace Opus.Resources.Portable_Class
@@ -41,6 +42,16 @@ namespace Opus.Resources.Portable_Class
this.LocalID = LocalID;
this.YoutubeID = YoutubeID;
}
public Song ToSong()
{
return new Song(Name, Owner, ImageURL, YoutubeID, -1, LocalID, null, false, HasWritePermission);
}
public static Song ToSong(PlaylistItem item)
{
return new Song(item.Name, item.Owner, item.ImageURL, item.YoutubeID, -1, item.LocalID, null, false, item.HasWritePermission);
}
}
public enum SyncState

View File

@@ -61,6 +61,102 @@ namespace Opus.Resources.Portable_Class
MainActivity.instance.SupportActionBar.Title = playlistName;
}
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 Android.Support.V7.Widget.LinearLayoutManager(MainActivity.instance));
ListView.SetAdapter(new PlaylistTrackAdapter(new List<Song>()));
ListView.ScrollChange += ListView_ScrollChange;
#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
if(useHeader)
CreateHeader();
return view;
}
private void ListView_ScrollChange(object sender, View.ScrollChangeEventArgs e)
{
if (((Android.Support.V7.Widget.LinearLayoutManager)ListView?.GetLayoutManager())?.FindLastVisibleItemPosition() == adapter?.ItemCount - 1)
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
LoadMore();
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
}
void CreateHeader()
{
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;
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerPlay).HasOnClickListeners)
Activity.FindViewById<ImageButton>(Resource.Id.headerPlay).Click += (sender, e0) => { PlayInOrder(0); };
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerShuffle).HasOnClickListeners)
Activity.FindViewById<ImageButton>(Resource.Id.headerShuffle).Click += (sender, e0) => { RandomPlay(); };
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerMore).HasOnClickListeners)
Activity.FindViewById<ImageButton>(Resource.Id.headerMore).Click += PlaylistMore;
if (LocalID != 0 && thumnailURI == null)
{
Activity.FindViewById<TextView>(Resource.Id.headerAuthor).Text = MainActivity.account == null ? "by me" : "by " + MainActivity.account.DisplayName;
}
else if (YoutubeID != null && 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.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));
}
Activity.FindViewById(Resource.Id.collapsingToolbar).RequestLayout();
}
public override void OnDestroyView()
{
Activity.FindViewById<ImageButton>(Resource.Id.headerMore).Click -= PlaylistMore;
if (!MainActivity.instance.Paused)
{
Activity.FindViewById<RelativeLayout>(Resource.Id.playlistHeader).Visibility = ViewStates.Gone;
MainActivity.instance.HideSearch();
MainActivity.instance.SupportActionBar.SetHomeButtonEnabled(false);
MainActivity.instance.SupportActionBar.SetDisplayHomeAsUpEnabled(false);
MainActivity.instance.SupportActionBar.SetDisplayShowTitleEnabled(true);
MainActivity.instance.SupportActionBar.SetDisplayShowTitleEnabled(false);
MainActivity.instance.FindViewById(Resource.Id.toolbarLogo).Visibility = ViewStates.Visible;
MainActivity.instance.contentRefresh.Refresh -= OnRefresh;
Activity.FindViewById<AppBarLayout>(Resource.Id.appbar).RemoveOnOffsetChangedListener(this);
if (YoutubeEngine.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.ClearFocus();
int selectedTab = 0;
for (int i = 0; i < YoutubeEngine.instances.Length; i++)
{
if (YoutubeEngine.instances[i].IsFocused)
selectedTab = i;
}
}
instance = null;
}
base.OnDestroyView();
}
//Header more click
public bool OnMenuItemClick(IMenuItem item)
{
switch (item.ItemId)
@@ -239,46 +335,6 @@ namespace Opus.Resources.Portable_Class
dialog.Show();
}
public override void OnDestroyView()
{
Activity.FindViewById<ImageButton>(Resource.Id.headerMore).Click -= PlaylistMore;
if (!MainActivity.instance.Paused)
{
Activity.FindViewById<RelativeLayout>(Resource.Id.playlistHeader).Visibility = ViewStates.Gone;
MainActivity.instance.HideSearch();
MainActivity.instance.SupportActionBar.SetHomeButtonEnabled(false);
MainActivity.instance.SupportActionBar.SetDisplayHomeAsUpEnabled(false);
MainActivity.instance.SupportActionBar.SetDisplayShowTitleEnabled(true);
MainActivity.instance.SupportActionBar.SetDisplayShowTitleEnabled(false);
MainActivity.instance.FindViewById(Resource.Id.toolbarLogo).Visibility = ViewStates.Visible;
MainActivity.instance.contentRefresh.Refresh -= OnRefresh;
Activity.FindViewById<AppBarLayout>(Resource.Id.appbar).RemoveOnOffsetChangedListener(this);
if (YoutubeEngine.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.ClearFocus();
int selectedTab = 0;
for (int i = 0; i < YoutubeEngine.instances.Length; i++)
{
if (YoutubeEngine.instances[i].IsFocused)
selectedTab = i;
}
}
instance = null;
}
base.OnDestroyView();
}
public static async Task<Song> CompleteItem(Song song, string YoutubeID)
{
if (song.YoutubeID == null)
@@ -308,58 +364,6 @@ namespace Opus.Resources.Portable_Class
return song;
}
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 Android.Support.V7.Widget.LinearLayoutManager(MainActivity.instance));
ListView.SetAdapter(new PlaylistTrackAdapter(new List<Song>()));
ListView.ScrollChange += ListView_ScrollChange;
PopulateList();
CreateHeader();
return view;
}
private void ListView_ScrollChange(object sender, View.ScrollChangeEventArgs e)
{
if (((Android.Support.V7.Widget.LinearLayoutManager)ListView?.GetLayoutManager())?.FindLastVisibleItemPosition() == adapter?.ItemCount - 1)
LoadMore();
}
void CreateHeader()
{
if (useHeader)
{
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;
if(!Activity.FindViewById<ImageButton>(Resource.Id.headerPlay).HasOnClickListeners)
Activity.FindViewById<ImageButton>(Resource.Id.headerPlay).Click += (sender, e0) => { PlayInOrder(0); };
if(!Activity.FindViewById<ImageButton>(Resource.Id.headerShuffle).HasOnClickListeners)
Activity.FindViewById<ImageButton>(Resource.Id.headerShuffle).Click += (sender, e0) => { RandomPlay(); };
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerMore).HasOnClickListeners)
Activity.FindViewById<ImageButton>(Resource.Id.headerMore).Click += PlaylistMore;
if (LocalID != 0 && thumnailURI == null)
{
Activity.FindViewById<TextView>(Resource.Id.headerAuthor).Text = MainActivity.account == null ? "by me" : "by " + MainActivity.account.DisplayName;
}
else if (YoutubeID != null && 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.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));
}
Activity.FindViewById(Resource.Id.collapsingToolbar).RequestLayout();
}
}
void RandomPlay()
{
if (instance.LocalID != 0)
@@ -811,12 +815,15 @@ namespace Opus.Resources.Portable_Class
base.OnResume();
instance = this;
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerPlay).HasOnClickListeners)
Activity.FindViewById<ImageButton>(Resource.Id.headerPlay).Click += (sender, e0) => { instance.PlayInOrder(0); };
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerShuffle).HasOnClickListeners)
Activity.FindViewById<ImageButton>(Resource.Id.headerShuffle).Click += (sender, e0) => { RandomPlay(); };
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerMore).HasOnClickListeners)
Activity.FindViewById<ImageButton>(Resource.Id.headerMore).Click += PlaylistMore;
if(useHeader)
{
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerPlay).HasOnClickListeners)
Activity.FindViewById<ImageButton>(Resource.Id.headerPlay).Click += (sender, e0) => { instance.PlayInOrder(0); };
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerShuffle).HasOnClickListeners)
Activity.FindViewById<ImageButton>(Resource.Id.headerShuffle).Click += (sender, e0) => { RandomPlay(); };
if (!Activity.FindViewById<ImageButton>(Resource.Id.headerMore).HasOnClickListeners)
Activity.FindViewById<ImageButton>(Resource.Id.headerMore).Click += PlaylistMore;
}
}
public void OnOffsetChanged(AppBarLayout appBarLayout, int verticalOffset)

File diff suppressed because it is too large Load Diff

View File

@@ -7,10 +7,10 @@
android:padding="4dp" >
<ImageView
android:id="@+id/albumArt"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentLeft="true"
android:paddingLeft="20dp"
android:layout_marginLeft="20dp"
android:gravity="center" />
<Button
android:id="@+id/action"

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:foreground="?android:attr/selectableItemBackground"
android:clickable="true"
android:padding="4dp" >
<ImageView
android:id="@+id/albumArt"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentLeft="true"
android:layout_marginLeft="20dp"
android:gravity="center" />
<LinearLayout
android:id="@+id/rightButtons"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageButton
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_margin="6dp"
android:src="@drawable/play"
android:background="@null"
android:id="@+id/play" />
<ImageButton
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_margin="6dp"
android:src="@drawable/shuffle"
android:background="@null"
android:id="@+id/shuffle" />
</LinearLayout>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16dip"
android:layout_centerVertical="true"
android:paddingLeft="90dp"
android:textStyle="bold"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@id/rightButtons" />
</RelativeLayout >

View File

@@ -3,7 +3,9 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="7dp" >
android:foreground="?android:attr/selectableItemBackground"
android:clickable="true"
android:layout_margin="7dp" >
<ImageView
android:layout_width="150dp"
android:layout_height="150dp"

View File

@@ -4,6 +4,8 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="?android:colorBackground"
android:foreground="?android:attr/selectableItemBackground"
android:clickable="true"
android:padding="8dp" >
<ImageView
android:id="@+id/albumArt"

View File

@@ -9,7 +9,9 @@
android:layout_marginRight="20dp"
android:layout_marginBottom="10dp"
app:cardCornerRadius="16dp"
app:cardElevation="14dp" >
app:cardElevation="14dp"
android:foreground="?android:attr/selectableItemBackground"
android:clickable="true" >
<LinearLayout
android:gravity="center"
android:layout_width="fill_parent"

View File

@@ -2,7 +2,9 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="78dp" >
android:layout_height="78dp"
android:foreground="?android:attr/selectableItemBackground"
android:clickable="true" >
<ImageView
android:id="@+id/albumArt"
android:layout_width="70dp"

View File

@@ -2,7 +2,9 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="wrap_content" >
android:layout_width="wrap_content"
android:foreground="?android:attr/selectableItemBackground"
android:clickable="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"