/*
* Copyright 2013-2015 The GDG Frisbee Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gdg.frisbee.android.chapter;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.text.style.URLSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.plus.Plus;
import com.google.android.gms.plus.PlusOneButton;
import com.squareup.picasso.Picasso;
import org.gdg.frisbee.android.R;
import org.gdg.frisbee.android.api.model.plus.Activity;
import org.gdg.frisbee.android.api.model.plus.Attachment;
import org.gdg.frisbee.android.api.model.plus.Thumbnail;
import org.gdg.frisbee.android.app.App;
import org.gdg.frisbee.android.utils.Utils;
import org.gdg.frisbee.android.widget.ResizableImageView;
import org.joda.time.DateTime;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
private static final int VIEW_TYPE_ARTICLE = 1;
private static final int VIEW_TYPE_VIDEO = 2;
private static final int VIEW_TYPE_PHOTO = 3;
private static final int VIEW_TYPE_ALBUM = 4;
private static final int VIEW_TYPE_EVENT = 5;
private static final int ACTIVITY_REQUEST_CODE_GPLUS_BUTTON = 1;
private final Context context;
private final LayoutInflater inflater;
private ArrayList<Item> activities;
private final GoogleApiClient plusClient;
private final Picasso picasso;
NewsAdapter(Context context, GoogleApiClient plusClient) {
this.context = context;
this.plusClient = plusClient;
inflater = LayoutInflater.from(this.context);
activities = new ArrayList<>();
picasso = App.from(context).getPicasso();
setHasStableIds(true);
}
public void addAll(Collection<Activity> items) {
for (Activity a : items) {
activities.add(new Item(a));
}
notifyDataSetChanged();
}
public void replaceAll(Collection<Activity> items, int start) {
for (Activity a : items) {
if (start < activities.size()) {
if (a.getId().equals(activities.get(start).getActivity().getId())) {
activities.set(start, new Item(a));
} else {
activities.add(start, new Item(a));
start++;
}
} else {
activities.add(new Item(a));
}
start++;
}
notifyDataSetChanged();
}
public void add(Activity item) {
activities.add(new Item(item));
notifyDataSetChanged();
}
public void clear() {
activities.clear();
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return activities.size();
}
private Item getItemInternal(int i) {
return activities.get(i);
}
@Override
public long getItemId(int i) {
return Utils.stringToLong(getItemInternal(i).getActivity().getId());
}
@Override
public int getItemViewType(int position) {
if (position >= 0) {
if (position >= getItemCount()) {
position = position % getItemCount();
}
Item item = getItemInternal(position);
Activity activity = item.getActivity();
if (activity.getObject().getAttachments() == null
|| activity.getObject().getAttachments().isEmpty()) {
return 0;
} else {
Attachment attachment = activity.getObject().getAttachments().get(0);
String objectType = attachment.getObjectType();
switch (objectType) {
case "article":
return VIEW_TYPE_ARTICLE;
case "video":
return VIEW_TYPE_VIDEO;
case "photo":
return VIEW_TYPE_PHOTO;
case "album":
return VIEW_TYPE_ALBUM;
case "event":
return VIEW_TYPE_EVENT;
}
}
}
return 0;
}
public void updatePlusOne(ViewHolder viewHolder) {
if (viewHolder != null) {
if (shouldShowGPlusButton()) {
viewHolder.plusButton.setVisibility(View.VISIBLE);
viewHolder.plusButton.initialize(viewHolder.url, ACTIVITY_REQUEST_CODE_GPLUS_BUTTON);
} else {
viewHolder.plusButton.setVisibility(View.GONE);
}
}
}
private boolean shouldShowGPlusButton() {
return plusClient != null && plusClient.hasConnectedApi(Plus.API);
}
@Override
public NewsAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = inflater.inflate(R.layout.news_item_base, viewGroup, false);
final ViewHolder viewHolder = new ViewHolder(v);
viewHolder.content.setMovementMethod(LinkMovementMethod.getInstance());
viewHolder.shareContent.setMovementMethod(LinkMovementMethod.getInstance());
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int i) {
Item item = getItemInternal(i);
final Activity activity = item.getActivity();
holder.url = activity.getUrl();
updatePlusOne(holder);
if (activity.getPublished() != null) {
holder.timeStamp.setVisibility(View.VISIBLE);
holder.timeStamp.setText(
Utils.toHumanTimePeriod(
context,
activity.getPublished(),
DateTime.now()
)
);
} else {
holder.timeStamp.setVisibility(View.GONE);
}
if (activity.getVerb().equals("share")) {
populateShare(activity, holder);
} else {
holder.shareContainer.setVisibility(View.GONE);
populatePost(activity, holder.content);
}
if (activity.getObject().getAttachments() != null && activity.getObject().getAttachments().size() > 0) {
final Attachment attachment = activity.getObject().getAttachments().get(0);
switch (getItemViewType(i)) {
case VIEW_TYPE_ARTICLE:
// Article
populateArticle(holder, holder.container, attachment);
break;
case VIEW_TYPE_VIDEO:
// Video
populateVideo(holder, holder.container, attachment);
break;
case VIEW_TYPE_PHOTO:
// Photo
populatePhoto(holder, holder.container, attachment);
break;
case VIEW_TYPE_ALBUM:
// Album
populateAlbum(holder, holder.container, attachment);
break;
case VIEW_TYPE_EVENT:
// Event
populateEvent(holder, holder.container, attachment);
break;
}
}
// That item will contain a special property that tells if it was freshly retrieved
// if (!item.isConsumed()) {
// item.setConsumed(true);
// // In which case we magically instantiate our effect and launch it directly on the view
// Animation animation = AnimationUtils.makeInChildBottomAnimation(context);
// view.startAnimation(animation);
// }
}
private View createAttachmentView(ViewHolder mViewHolder, ViewGroup container, int layout, int type) {
View attachmentView;
if (container.getChildCount() == 0) {
attachmentView = inflater.inflate(layout, container, false);
container.addView(attachmentView);
switch (type) {
case 1:
// Article
mViewHolder.articleImage = (ImageView) attachmentView.findViewById(R.id.image);
mViewHolder.title = (TextView) attachmentView.findViewById(R.id.displayName);
mViewHolder.attachmentContent = (TextView) attachmentView.findViewById(R.id.content);
break;
case 2:
// Video
mViewHolder.poster = (ResizableImageView) attachmentView.findViewById(R.id.videoPoster);
break;
case 3:
// Photo
mViewHolder.photo = (ResizableImageView) attachmentView.findViewById(R.id.photo);
break;
case 4:
// Album
mViewHolder.pic1 = (ImageView) attachmentView.findViewById(R.id.pic1);
mViewHolder.pic2 = (ImageView) attachmentView.findViewById(R.id.pic2);
mViewHolder.pic3 = (ImageView) attachmentView.findViewById(R.id.pic3);
break;
case 5:
// Event
mViewHolder.attachmentContent = (TextView) attachmentView.findViewById(R.id.content);
mViewHolder.attachmentTitle = (TextView) attachmentView.findViewById(R.id.title);
mViewHolder.articleImage = (ImageView) attachmentView.findViewById(R.id.image);
break;
}
} else {
attachmentView = container.getChildAt(0);
}
return attachmentView;
}
private void populateArticle(ViewHolder mViewHolder,
ViewGroup container,
final Attachment attachment) {
if (attachment == null) {
return;
}
View attachmentView = createAttachmentView(mViewHolder, container, R.layout.news_item_article, 1);
mViewHolder.title.setText(attachment.getDisplayName());
try {
mViewHolder.attachmentContent.setText(new URL(attachment.getUrl()).getHost());
} catch (MalformedURLException e) {
e.printStackTrace();
}
if (attachment.getImage() == null && attachment.getFullImage() == null) {
mViewHolder.articleImage.setVisibility(View.GONE);
} else {
mViewHolder.articleImage.setImageDrawable(null);
String imageUrl = getAttachmentImageUrl(attachment);
if (imageUrl != null) {
mViewHolder.articleImage.setVisibility(View.VISIBLE);
picasso.load(imageUrl)
.into(mViewHolder.articleImage);
} else {
mViewHolder.articleImage.setVisibility(View.GONE);
}
}
attachmentView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
context.startActivity(Utils.createExternalIntent(context, Uri.parse(attachment.getUrl())));
}
});
}
@Nullable
private static String getAttachmentImageUrl(final Attachment attachment) {
if (attachment.getFullImage() != null) {
return attachment.getFullImage().getUrl();
} else if (attachment.getImage() != null) {
return attachment.getImage().getUrl();
}
return null;
}
private void populateVideo(ViewHolder mViewHolder,
ViewGroup container,
final Attachment attachment) {
if (attachment == null) {
return;
}
View attachmentView = createAttachmentView(mViewHolder, container, R.layout.news_item_video, 2);
// Precalc Image Size
mViewHolder.poster.setDimensions(attachment.getImage().getWidth(), attachment.getImage().getHeight());
mViewHolder.poster.setImageDrawable(null);
picasso.load(attachment.getImage().getUrl())
.into(mViewHolder.poster);
attachmentView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
String videoId = getVideoIdFrom(attachment);
if (videoId != null) {
Intent playVideoIntent = new Intent(context, YoutubeActivity.class);
playVideoIntent.putExtra(YoutubeActivity.EXTRA_VIDEO_ID, videoId);
context.startActivity(playVideoIntent);
} else {
Intent viewUrlIntent = Utils.createExternalIntent(context, Uri.parse(attachment.getUrl()));
if (Utils.canLaunch(context, viewUrlIntent)) {
context.startActivity(viewUrlIntent);
}
}
} catch (UnsupportedEncodingException | MalformedURLException e) {
e.printStackTrace();
}
}
});
}
private static String getVideoIdFrom(final Attachment attachment)
throws UnsupportedEncodingException, MalformedURLException {
return Utils.splitQuery(new URL(attachment.getUrl())).get("v");
}
private void populatePhoto(ViewHolder mViewHolder,
ViewGroup container,
Attachment attachment) {
if (attachment == null) {
return;
}
createAttachmentView(mViewHolder, container, R.layout.news_item_photo, 3);
// Precalc Image Size
if (attachment.getImage() != null
&& attachment.getImage().getUrl() != null
&& attachment.getImage().getWidth() != null) {
mViewHolder.photo.setDimensions(attachment.getImage().getWidth(), attachment.getImage().getHeight());
}
mViewHolder.photo.setImageDrawable(null);
picasso.load(attachment.getImage().getUrl())
.into(mViewHolder.photo);
}
private void populateAlbum(ViewHolder mViewHolder,
ViewGroup container,
Attachment attachment) {
if (attachment == null) {
return;
}
createAttachmentView(mViewHolder, container, R.layout.news_item_album, 4);
List<Thumbnail> thumbnails = attachment.getThumbnails();
picasso.load(thumbnails.get(0).getImage().getUrl())
.into(mViewHolder.pic1);
if (thumbnails.size() > 1) {
picasso.load(thumbnails.get(1).getImage().getUrl())
.into(mViewHolder.pic2);
}
if (thumbnails.size() > 2) {
picasso.load(thumbnails.get(2).getImage().getUrl())
.into(mViewHolder.pic3);
}
}
private void populateEvent(ViewHolder mViewHolder,
ViewGroup container,
final Attachment attachment) {
createAttachmentView(mViewHolder, container, R.layout.news_item_event, 5);
TextView title = mViewHolder.attachmentTitle;
String name = attachment.getDisplayName();
if (TextUtils.isEmpty(name)) {
title.setVisibility(View.GONE);
} else {
title.setText(name);
title.setClickable(true);
View.OnClickListener mClickEvent = new View.OnClickListener() {
@Override
public void onClick(View view) {
openEventInGPlus(attachment.getUrl());
}
};
mViewHolder.articleImage.setOnClickListener(mClickEvent);
title.setOnClickListener(mClickEvent);
}
TextView content = mViewHolder.attachmentContent;
content.setText(attachment.getContent());
}
private void openEventInGPlus(String uri) {
context.startActivity(Utils.createExternalIntent(context, Uri.parse(uri)));
}
private void populatePost(Activity item, TextView content) {
content.setText(fromHtml(item.getObject().getContent()));
}
private void populateShare(Activity item, ViewHolder holder) {
String originallyShared = "";
if (item.getObject().getActor() != null && context != null) {
originallyShared = "<b><a href=\""
+ item.getObject().getActor().getUrl() + "\">"
+ item.getObject().getActor().getDisplayName()
+ "</a></b> " + context.getString(R.string.originally_shared) + "<br/><br/>";
}
if (item.getAnnotation() != null) {
holder.content.setText(fromHtml(item.getAnnotation()));
holder.shareContent.setText(fromHtml(originallyShared + item.getObject().getContent()));
holder.shareContainer.setVisibility(View.VISIBLE);
} else {
holder.shareContainer.setVisibility(View.GONE);
holder.content.setText(fromHtml(originallyShared + item.getObject().getContent()));
}
}
private Spanned fromHtml(String html) {
Spanned spanned = Html.fromHtml(html);
if (spanned instanceof SpannableStringBuilder) {
SpannableStringBuilder ssb = (SpannableStringBuilder) spanned;
URLSpan[] urlspans = ssb.getSpans(0, ssb.length() - 1, URLSpan.class);
for (URLSpan span : urlspans) {
int start = ssb.getSpanStart(span);
int end = ssb.getSpanEnd(span);
final String url = span.getURL();
ssb.removeSpan(span);
ssb.setSpan(new ClickableSpan() {
@Override
public void onClick(View view) {
context.startActivity(Utils.createExternalIntent(context, Uri.parse(url)));
}
}, start, end, 33);
}
}
return spanned;
}
private static class Item {
private Activity mActivity;
private boolean mConsumed = false;
Item(Activity a) {
mActivity = a;
mConsumed = false;
}
public Activity getActivity() {
return mActivity;
}
public void setActivity(Activity mActivity) {
this.mActivity = mActivity;
}
public boolean isConsumed() {
return mConsumed;
}
public void setConsumed(boolean mConsumed) {
this.mConsumed = mConsumed;
}
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView attachmentTitle;
@BindView(R.id.plus_one_button)
PlusOneButton plusButton;
@BindView(R.id.attachmentContainer)
ViewGroup container;
@BindView(R.id.shareContainer)
ViewGroup shareContainer;
@BindView(R.id.timestamp)
TextView timeStamp;
@BindView(R.id.content)
TextView content;
@BindView(R.id.shareContent)
TextView shareContent;
ImageView articleImage;
TextView title;
ResizableImageView poster;
ResizableImageView photo;
TextView attachmentContent;
ImageView pic1;
ImageView pic2;
ImageView pic3;
String url;
ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}