Skip to content

Instantly share code, notes, and snippets.

@gavilanch
Created September 24, 2017 00:25
Show Gist options
  • Save gavilanch/aa2863e805cea50aac2f954ddce00ec9 to your computer and use it in GitHub Desktop.
Save gavilanch/aa2863e805cea50aac2f954ddce00ec9 to your computer and use it in GitHub Desktop.
// NewsListRow.axml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/newsListRow_RelativeLayout"
android:background="@color/listitemunselected">
<TextView
android:text="Small Text"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/newsImage"
android:layout_alignParentLeft="true"
android:textStyle="bold"
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:id="@+id/newsTitle" />
<ImageView
android:src="@android:drawable/ic_menu_gallery"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:id="@+id/newsImage" />
</RelativeLayout>
// Colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="listitemselected">#78909c</color>
<color name="listitemunselected">#303030</color>
</resources>
// ISelectedChecker
internal interface ISelectedChecker
{
bool IsItemSelected(int id);
}
// BasesNewsListFragment.cs
public class BaseNewsListFragment : Fragment, ISelectedChecker
{
protected ListView _newsListView;
protected List<News> _news;
protected List<News> _selectedNews;
private NewsListAdapter _newsListAdapter;
public BaseNewsListFragment()
{
_news = new List<News>();
_selectedNews = new List<News>();
}
public override void OnCreate(Bundle savedInstanceState)
{
_selectedNews.Clear();
base.OnCreate(savedInstanceState);
SetHasOptionsMenu(true);
}
protected void SetupFragment()
{
SetupViews();
SetupEvents();
SetupAdapter();
}
protected void SetupAdapter()
{
_newsListAdapter = new NewsListAdapter(Activity, _news, this);
_newsListView.Adapter = _newsListAdapter;
}
protected void SetupViews()
{
_newsListView = View.FindViewById<ListView>(Resource.Id.newsListView);
}
protected void SetupEvents()
{
_newsListView.ItemClick += NewsListView_ItemClick;
_newsListView.ItemLongClick += _newsListView_ItemLongClick;
}
private void _newsListView_ItemLongClick(object sender, AdapterView.ItemLongClickEventArgs e)
{
int id = (int)e.Id;
View view = e.View;
RelativeLayout rl = view.FindViewById<RelativeLayout>(Resource.Id.newsListRow_RelativeLayout);
if (_selectedNews.Select(x => x.Id).Contains(id))
{
// deselect element
var colorForUnselected = Resources.GetString(Resource.Color.listitemunselected);
rl.SetBackgroundColor(Android.Graphics.Color.ParseColor(colorForUnselected));
_selectedNews.Remove(_newsListAdapter[e.Position]);
}
else
{
// select element
var colorForSelected = Resources.GetString(Resource.Color.listitemselected);
rl.SetBackgroundColor(Android.Graphics.Color.ParseColor(colorForSelected));
_selectedNews.Add(_newsListAdapter[e.Position]);
}
// Forces android to execute OnCreateOptionsMenu
Activity.InvalidateOptionsMenu();
}
private void NewsListView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
var intent = new Intent(Activity, typeof(MainActivity));
var id = (int)e.Id;
intent.PutExtra(MainActivity.KEY_ID, id);
StartActivity(intent);
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.Inflate(Resource.Layout.NewsListFragment, container, false);
}
protected void UnselectElements()
{
int count = _newsListView.ChildCount;
for (int i = 0; i < count; i++)
{
View row = _newsListView.GetChildAt(i);
var rl = row.FindViewById<RelativeLayout>(Resource.Id.newsListRow_RelativeLayout);
var color = Resources.GetString(Resource.Color.listitemunselected);
rl.SetBackgroundColor(Android.Graphics.Color.ParseColor(color));
}
}
public bool IsItemSelected(int id)
{
return _selectedNews.Select(x => x.Id).Contains(id);
}
}
// AllNewsListFragment
public class AllNewsListFragment : BaseNewsListFragment
{
private NewsService _newsService;
public AllNewsListFragment()
{
_newsService = new NewsService();
}
public override void OnActivityCreated(Bundle savedInstanceState)
{
base.OnActivityCreated(savedInstanceState);
if (!_news.Any())
{
_news = _newsService.GetNews();
}
SetupFragment();
}
public override void OnCreateOptionsMenu(IMenu menu, MenuInflater inflater)
{
if (_selectedNews.Count > 0)
{
inflater.Inflate(Resource.Menu.newsActionMenu, menu);
}
base.OnCreateOptionsMenu(menu, inflater);
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
switch (item.ItemId)
{
case Resource.Id.action_read_later:
SaveSelectedNews(_selectedNews);
return true;
default:
return base.OnOptionsItemSelected(item);
}
}
private void SaveSelectedNews(List<News> selectedNews)
{
try
{
var newsLocalService = new NewsLocalService();
foreach (var news in selectedNews)
{
newsLocalService.Save(news);
}
Toast.MakeText(Activity, $"{selectedNews.Count} news saved", ToastLength.Short).Show();
selectedNews.Clear();
Activity.InvalidateOptionsMenu();
UnselectElements();
}
catch (Exception ex)
{
Toast.MakeText(Activity, ex.Message, ToastLength.Short).Show();
}
}
}
// SavedNewsListFragment
public class SavedNewsListFragment : BaseNewsListFragment
{
private NewsLocalService _newsLocalService;
public SavedNewsListFragment()
{
_newsLocalService = new NewsLocalService();
}
public override void OnActivityCreated(Bundle savedInstanceState)
{
base.OnActivityCreated(savedInstanceState);
FillNews();
SetupFragment();
}
private void FillNews()
{
_news = _newsLocalService.GetAllSavedForReadLater();
}
public override void OnCreateOptionsMenu(IMenu menu, MenuInflater inflater)
{
if (_selectedNews.Count > 0)
{
inflater.Inflate(Resource.Menu.savedNewsActionMenu, menu);
}
base.OnCreateOptionsMenu(menu, inflater);
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
switch (item.ItemId)
{
case Resource.Id.delete_saved_news:
DeleteSelectedNews(_selectedNews);
return true;
default:
return base.OnOptionsItemSelected(item);
}
}
private void DeleteSelectedNews(List<News> selectedNews)
{
try
{
foreach (var news in selectedNews)
{
_newsLocalService.Delete(news.Id);
}
Toast.MakeText(Activity, $"{selectedNews.Count} news deleted", ToastLength.Short).Show();
selectedNews.Clear();
FillNews();
SetupAdapter();
Activity.InvalidateOptionsMenu();
}
catch (Exception ex)
{
Toast.MakeText(Activity, ex.Message, ToastLength.Long).Show();
}
}
}
// NewsListAdapter
class NewsListAdapter : BaseAdapter<News>
{
private Activity _context;
private List<News> _news;
private ISelectedChecker _selectedChecker;
public NewsListAdapter(Activity context, List<News> news, ISelectedChecker selectedChecker)
{
_context = context;
_news = news;
_selectedChecker = selectedChecker;
}
public override News this[int position] => _news[position];
public override int Count => _news.Count;
public override long GetItemId(int position)
{
return this[position].Id;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = this[position];
if (convertView == null)
{
convertView = _context.LayoutInflater.Inflate(Resource.Layout.NewsListRow, null);
}
else
{
var id = (int)GetItemId(position);
RelativeLayout rl = convertView.FindViewById<RelativeLayout>(Resource.Id.newsListRow_RelativeLayout);
if (_selectedChecker.IsItemSelected(id))
{
var colorForSelected = _context.Resources.GetString(Resource.Color.listitemselected);
rl.SetBackgroundColor(Android.Graphics.Color.ParseColor(colorForSelected));
}
else
{
var colorForUnselected = _context.Resources.GetString(Resource.Color.listitemunselected);
rl.SetBackgroundColor(Android.Graphics.Color.ParseColor(colorForUnselected));
}
}
convertView.FindViewById<TextView>(Resource.Id.newsTitle).Text = item.Title;
var newsImage = convertView.FindViewById<ImageView>(Resource.Id.newsImage);
var imageURL = string.Concat(ValuesService.ImagesBaseURL, item.ImageName);
Picasso.With(_context)
.Load(imageURL)
.Placeholder(_context.GetDrawable(Resource.Drawable.Icon))
.Into(newsImage);
return convertView;
}
}
// savedNewsActionMenu
<?xml version="1.0" encoding="utf-8" ?>
<!--For all properties see: http://developer.android.com/guide/topics/resources/menu-resource.html-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/delete_saved_news"
android:showAsAction="always"
android:icon="@android:drawable/ic_delete" />
</menu>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment