/*
* This file is part of Popcorn Time.
*
* Popcorn Time is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Popcorn Time is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Popcorn Time. If not, see <http://www.gnu.org/licenses/>.
*/
package pct.droid.adapters;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Transformation;
import java.util.ArrayList;
import butterknife.ButterKnife;
import butterknife.Bind;
import hugo.weaving.DebugLog;
import pct.droid.R;
import pct.droid.base.providers.media.models.Media;
import pct.droid.base.utils.AnimUtils;
import pct.droid.base.utils.LocaleUtils;
import pct.droid.base.utils.PixelUtils;
public class MediaGridAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private int mItemWidth, mItemHeight, mMargin, mColumns;
private ArrayList<OverviewItem> mItems = new ArrayList<>();
// private ArrayList<Media> mData = new ArrayList<>();
private MediaGridAdapter.OnItemClickListener mItemClickListener;
final int NORMAL = 0, LOADING = 1;
public MediaGridAdapter(Context context, ArrayList<Media> items, Integer columns) {
mColumns = columns;
int screenWidth = PixelUtils.getScreenWidth(context);
mItemWidth = (screenWidth / columns);
mItemHeight = (int) ((double) mItemWidth / 0.677);
mMargin = PixelUtils.getPixelsFromDp(context, 2);
setItems(items);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
switch (viewType) {
case LOADING:
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.media_griditem_loading, parent, false);
return new MediaGridAdapter.LoadingHolder(v);
case NORMAL:
default:
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.media_griditem, parent, false);
return new MediaGridAdapter.ViewHolder(v);
}
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder viewHolder, int position) {
int double_margin = mMargin * 2;
int top_margin = (position < mColumns) ? mMargin * 2 : mMargin;
GridLayoutManager.LayoutParams layoutParams = (GridLayoutManager.LayoutParams) viewHolder.itemView.getLayoutParams();
layoutParams.height = mItemHeight;
layoutParams.width = mItemWidth;
int mod = LocaleUtils.currentLocaleIsRTL() ? 1 : 0;
if (position % mColumns == mod) {
layoutParams.setMargins(double_margin, top_margin, mMargin, mMargin);
} else if (position % mColumns == mColumns - 1) {
layoutParams.setMargins(mMargin, top_margin, double_margin, mMargin);
} else {
layoutParams.setMargins(mMargin, top_margin, mMargin, mMargin);
}
viewHolder.itemView.setLayoutParams(layoutParams);
if (getItemViewType(position) == NORMAL) {
final ViewHolder videoViewHolder = (ViewHolder) viewHolder;
final OverviewItem overviewItem = getItem(position);
Media item = overviewItem.media;
videoViewHolder.title.setText(item.title);
videoViewHolder.year.setText(item.year);
videoViewHolder.coverImage.setVisibility(View.GONE);
videoViewHolder.title.setVisibility(View.GONE);
videoViewHolder.year.setVisibility(View.GONE);
if (item.image != null && !item.image.equals("")) {
Picasso.with(videoViewHolder.coverImage.getContext()).load(item.image)
.resize(mItemWidth, mItemHeight)
.transform(DrawGradient.INSTANCE)
.into(videoViewHolder.coverImage, new Callback() {
@Override
public void onSuccess() {
overviewItem.isImageError = false;
AnimUtils.fadeIn(videoViewHolder.coverImage);
AnimUtils.fadeIn(videoViewHolder.title);
AnimUtils.fadeIn(videoViewHolder.year);
}
@Override
public void onError() {
overviewItem.isImageError = true;
AnimUtils.fadeIn(videoViewHolder.title);
AnimUtils.fadeIn(videoViewHolder.year);
}
});
}
}
}
@Override
public int getItemCount() {
return mItems.size();
}
@Override
public int getItemViewType(int position) {
if (getItem(position).isLoadingItem) {
return LOADING;
}
return NORMAL;
}
public OverviewItem getItem(int position) {
if (position < 0 || mItems.size() <= position) return null;
return mItems.get(position);
}
public void setOnItemClickListener(MediaGridAdapter.OnItemClickListener listener) {
mItemClickListener = listener;
}
@DebugLog
public void removeLoading() {
if (getItemCount() <= 0) return;
OverviewItem item = mItems.get(getItemCount() - 1);
if (item.isLoadingItem) {
mItems.remove(getItemCount() - 1);
notifyDataSetChanged();
}
}
@DebugLog
public void addLoading() {
OverviewItem item = null;
if (getItemCount() != 0) {
item = mItems.get(getItemCount() - 1);
}
if (getItemCount() == 0 || (item != null && !item.isLoadingItem)) {
mItems.add(new OverviewItem(true));
notifyDataSetChanged();
}
}
@DebugLog
public boolean isLoading() {
if (getItemCount() <= 0) return false;
return getItemViewType(getItemCount() - 1) == LOADING;
}
@DebugLog
public void setItems(ArrayList<Media> items) {
// Clear items
mItems.clear();
// Add new items, if available
if (null != items) {
for (Media item : items) {
mItems.add(new OverviewItem(item));
}
}
notifyDataSetChanged();
}
public void clearItems() {
mItems.clear();
notifyDataSetChanged();
}
public interface OnItemClickListener {
public void onItemClick(View v, Media item, int position);
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
View itemView;
@Bind(R.id.focus_overlay)
View focusOverlay;
@Bind(R.id.cover_image)
ImageView coverImage;
@Bind(R.id.title)
TextView title;
@Bind(R.id.year)
TextView year;
private View.OnFocusChangeListener mOnFocusChangeListener = new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
focusOverlay.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
}
};
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
this.itemView = itemView;
itemView.setOnClickListener(this);
coverImage.setMinimumHeight(mItemHeight);
itemView.setOnFocusChangeListener(mOnFocusChangeListener);
}
public ImageView getCoverImage() {
return coverImage;
}
@Override
public void onClick(View view) {
if (mItemClickListener != null) {
int position = getPosition();
Media item = getItem(position).media;
mItemClickListener.onItemClick(view, item, position);
}
}
}
class LoadingHolder extends RecyclerView.ViewHolder {
View itemView;
public LoadingHolder(View itemView) {
super(itemView);
this.itemView = itemView;
itemView.setMinimumHeight(mItemHeight);
}
}
class OverviewItem {
Media media;
boolean isImageError = true;
boolean isLoadingItem = false;
OverviewItem(Media media) {
this.media = media;
}
OverviewItem(boolean loading) {
this.isLoadingItem = loading;
}
}
private static class DrawGradient implements Transformation {
static Transformation INSTANCE = new DrawGradient();
@Override
public Bitmap transform(Bitmap src) {
// Code borrowed from https://stackoverflow.com/questions/23657811/how-to-mask-bitmap-with-lineargradient-shader-properly
int w = src.getWidth();
int h = src.getHeight();
Bitmap overlay = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(overlay);
canvas.drawBitmap(src, 0, 0, null);
src.recycle();
Paint paint = new Paint();
float gradientHeight = h / 2f;
LinearGradient shader = new LinearGradient(0, h - gradientHeight, 0, h, 0xFFFFFFFF, 0x00FFFFFF, Shader.TileMode.CLAMP);
paint.setShader(shader);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
canvas.drawRect(0, h - gradientHeight, w, h, paint);
return overlay;
}
@Override
public String key() {
return "gradient()";
}
}
}