package com.buddycloud.card;
import java.text.ParseException;
import java.util.Date;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.text.Html;
import android.text.Spanned;
import android.text.format.DateUtils;
import android.text.method.LinkMovementMethod;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;
import com.buddycloud.FullScreenImageActivity;
import com.buddycloud.MainActivity;
import com.buddycloud.R;
import com.buddycloud.customviews.MeasuredMediaView;
import com.buddycloud.customviews.MeasuredMediaView.MeasureListener;
import com.buddycloud.customviews.TypefacedEditText;
import com.buddycloud.fragments.ChannelStreamFragment;
import com.buddycloud.model.MediaModel;
import com.buddycloud.model.ModelCallback;
import com.buddycloud.model.PostsModel;
import com.buddycloud.model.SubscribedChannelsModel;
import com.buddycloud.preferences.Preferences;
import com.buddycloud.utils.AvatarUtils;
import com.buddycloud.utils.ImageHelper;
import com.buddycloud.utils.InputUtils;
import com.buddycloud.utils.TextUtils;
import com.buddycloud.utils.TimeUtils;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.assist.ImageLoadingListener;
public class PostCard extends AbstractCard {
private static final String MEDIA_URL_SUFIX = "?maxwidth=600";
private static final String MEDIA_URL_SUFIX_FULL = "?maxwidth=1024";
private JSONObject post;
private String channelJid;
private CardListAdapter repliesAdapter = new CardListAdapter();
private Spanned anchoredContent;
private MainActivity activity;
private String role;
private ChannelStreamFragment fragment;
public PostCard(String channelJid, JSONObject post,
ChannelStreamFragment fragment, String role) {
this.channelJid = channelJid;
this.fragment = fragment;
this.activity = (MainActivity) fragment.getActivity();
this.role = role;
setPost(post);
}
public JSONObject getPost() {
return post;
}
public void setPost(JSONObject post) {
this.post = post;
this.anchoredContent = TextUtils.anchor(post.optString("content"));
fillReplyAdapter(this.activity);
}
private void fillReplyAdapter(Context context) {
repliesAdapter.clear();
JSONArray comments = post.optJSONArray("replies");
for (int i = 0; comments != null && i < comments.length(); i++) {
JSONObject comment = comments.optJSONObject(i);
repliesAdapter.addCard(toReplyCard(comment, context));
}
repliesAdapter.sort();
repliesAdapter.notifyDataSetChanged();
}
@Override
public View getContentView(int position, View convertView, ViewGroup viewGroup) {
final String postAuthor = post.optString("author");
String published = post.optString("published");
String mediaStr = post.optString("media");
final String postId = post.optString("id");
JSONArray mediaArray = null;
if (mediaStr != null && mediaStr.length() > 0) {
try {
mediaArray = new JSONArray(mediaStr);
} catch (JSONException e) {}
}
boolean reuse = convertView != null && convertView.getTag() != null;
CardViewHolder holder = null;
if (!reuse) {
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
convertView = inflater.inflate(R.layout.post_entry, viewGroup, false);
holder = fillHolder(convertView);
convertView.setTag(holder);
} else {
holder = (CardViewHolder) convertView.getTag();
}
final Context context = viewGroup.getContext();
String avatarURL = AvatarUtils.avatarURL(viewGroup.getContext(), postAuthor);
ImageView avatarView = holder.getView(R.id.bcProfilePic);
DisplayImageOptions dio = new DisplayImageOptions.Builder()
.cloneFrom(ImageHelper.defaultImageOptions())
.showImageOnFail(R.drawable.ic_avatar)
.showImageOnLoading(R.drawable.ic_avatar)
.preProcessor(ImageHelper.createRoundProcessor(16, false, -1))
.build();
ImageLoader.getInstance().displayImage(avatarURL, avatarView, dio);
avatarView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
if (!channelJid.equals(postAuthor)) {
activity.showChannelFragment(postAuthor);
}
}
});
final TextView postAuthorView = holder.getView(R.id.bcPostAuthor);
if (!TextUtils.isEmpty(postAuthor)) {
postAuthorView.setText(TextUtils.capitalize(postAuthor.trim()));
}
final View postContainer = holder.getView(R.id.postContainer);
final TextView contentTextView = holder.getView(R.id.bcPostContent);
final TextView contentTextViewAlt = holder.getView(R.id.bcPostPending);
final MeasuredMediaView mediaView = holder.getView(R.id.bcImageContent);
mediaView.setImageBitmap(null);
drawNoMediaLayout(contentTextView, contentTextViewAlt, mediaView);
if (mediaArray != null) {
drawMediaLayout(mediaArray, context, contentTextView,
contentTextViewAlt, mediaView);
}
FrameLayout postContentWrapper = holder.getView(R.id.postContentWrapper);
postContentWrapper.forceLayout();
View contextArrowDown = holder.getView(R.id.bcArrowDown);
contextArrowDown.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
PostContextUtils.showPostContextActions(context, channelJid,
postId, role, PostContextUtils.TOPIC_POST);
}
});
TextView publishedView = holder.getView(R.id.bcPostDate);
TextView publishedPendingView = holder.getView(R.id.bcPostPending);
boolean pending = PostsModel.isPending(post);
if (!pending) {
try {
long publishedTime = TimeUtils.fromISOToDate(published).getTime();
publishedView.setText(
DateUtils.getRelativeTimeSpanString(publishedTime,
new Date().getTime(), DateUtils.MINUTE_IN_MILLIS));
publishedPendingView.setVisibility(View.GONE);
contextArrowDown.setVisibility(View.VISIBLE);
} catch (ParseException e) {
e.printStackTrace();
}
} else {
publishedView.setText(Html.fromHtml("⌚"));
publishedPendingView.setVisibility(View.VISIBLE);
contextArrowDown.setVisibility(View.GONE);
}
// REPLIES SECTION
LinearLayout replyListViewSection = holder.getView(R.id.replyListViewSection);
if (repliesAdapter.getCount() > 0) {
replyListViewSection.setVisibility(View.VISIBLE);
ReplySectionUtils.configure(replyListViewSection, repliesAdapter);
}
else {
replyListViewSection.setVisibility(View.GONE);
}
// COMMENT BOX SECTION
View commentBoxFrameView = holder.getView(R.id.commentBoxFrameView);
if (!SubscribedChannelsModel.canPost(role)) {
commentBoxFrameView.setVisibility(View.GONE);
} else {
commentBoxFrameView.setVisibility(View.VISIBLE);
ImageView replyAuthorPicView = holder.getView(R.id.bcReplyAuthorPic);
String replyAuthorURL = AvatarUtils.avatarURL(viewGroup.getContext(),
Preferences.getPreference(context, Preferences.MY_CHANNEL_JID));
ImageLoader.getInstance().displayImage(replyAuthorURL, replyAuthorPicView, dio);
final TypefacedEditText replyTxt = holder.getView(R.id.postNewCommentTxt);
replyTxt.setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
/**
* Android doesn't show "Send" button for multiline edittext. So we've
* override that particular action for all the devices.
*/
if (actionId == EditorInfo.IME_ACTION_SEND ||
actionId == EditorInfo.IME_ACTION_DONE ||
event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
sendReply(context, replyTxt);
return true;
}
return false;
}
});
replyTxt.setOnKeyPreImeListener(new TypefacedEditText.KeyImeChange() {
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
/**
* Check if the "back key" pressed for the keypad to close.
* So we can also show the "+" add post button.
*/
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
fragment.showAddPostTopicBtn();
}
}, 500);
}
return false;
}
});
}
// adjust shadow
adjustShadow(context, postContainer, replyListViewSection);
return convertView;
}
private void adjustShadow(final Context context,
View postContainer,
View replyListViewSection) {
if (getRepliesAdapter() != null && getRepliesAdapter().getCount() > 0) {
setBackground(context, postContainer, R.drawable.post_item_list_shadow);
if(!SubscribedChannelsModel.canPost(role)) {
setBackground(context, replyListViewSection, R.drawable.comment_item_shadow);
} else {
setBackground(context, replyListViewSection, R.drawable.comment_item_list_shadow);
}
}
else if(!SubscribedChannelsModel.canPost(role)) {
setBackground(context, postContainer, R.drawable.post_item_shadow);
}
}
@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
private void setBackground(final Context context, View view, int resId) {
if (view == null) return ;
Drawable drawable = context.getResources().getDrawable(resId);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
view.setBackgroundDrawable(drawable);
} else {
view.setBackground(drawable);
}
}
public CardListAdapter getRepliesAdapter() {
return repliesAdapter;
}
private void drawNoMediaLayout(TextView contentTextView,
TextView contentTextViewAlt, final MeasuredMediaView mediaView) {
mediaView.setVisibility(View.GONE);
contentTextViewAlt.setVisibility(View.GONE);
contentTextView.setVisibility(View.VISIBLE);
contentTextView.setText(anchoredContent);
contentTextView.setMovementMethod(LinkMovementMethod.getInstance());
}
private void drawMediaLayout(final JSONArray mediaArray, final Context context,
final TextView contentTextView, final TextView contentTextViewAlt,
final MeasuredMediaView mediaView) {
contentTextView.setText(TextUtils.anchor(getMediaURL(mediaArray, context)));
mediaView.setMeasureListener(new MeasureListener() {
@Override
public void measure(int widthMeasureSpec, int heightMeasureSpec) {
drawMediaLayout(mediaArray, context, contentTextView,
contentTextViewAlt, mediaView, widthMeasureSpec);
}
});
mediaView.setVisibility(View.VISIBLE);
}
private void drawMediaLayout(final JSONArray mediaArray,
final Context context, final TextView contentTextView,
final TextView contentTextViewAlt,
final MeasuredMediaView mediaView, int widthMeasureSpec) {
final String imageURLLo = getMediaLoURL(mediaArray, context);
DisplayImageOptions dio = new DisplayImageOptions.Builder()
.cloneFrom(ImageHelper.defaultImageOptions())
.preProcessor(ImageHelper.createRoundProcessor(8, true, widthMeasureSpec))
.build();
ImageLoader.getInstance().displayImage(imageURLLo, mediaView, dio, new ImageLoadingListener() {
@Override
public void onLoadingStarted(String arg0, View arg1) {
contentTextViewAlt.setVisibility(View.VISIBLE);
}
@Override
public void onLoadingFailed(String arg0, View arg1, FailReason arg2) {
}
@Override
public void onLoadingComplete(String arg0, View arg1, Bitmap arg2) {
contentTextViewAlt.setVisibility(View.GONE);
contentTextView.setVisibility(View.VISIBLE);
contentTextView.setText(anchoredContent);
contentTextView.setMovementMethod(LinkMovementMethod.getInstance());
final String imageURLHi = getMediaHiURL(mediaArray, context);
mediaView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(context, FullScreenImageActivity.class);
intent.putExtra(FullScreenImageActivity.IMAGE_URL, imageURLLo);
intent.putExtra(FullScreenImageActivity.IMAGE_URL_HIGH_RES, imageURLHi);
activity.startActivityForResult(intent, FullScreenImageActivity.REQUEST_CODE);
}
});
}
@Override
public void onLoadingCancelled(String arg0, View arg1) {
// TODO Auto-generated method stub
}
});
}
private String getMediaLoURL(JSONArray mediaArray, final Context context) {
String userMediaURL = getMediaURL(mediaArray, context);
return userMediaURL + MEDIA_URL_SUFIX;
}
private String getMediaHiURL(JSONArray mediaArray, final Context context) {
String userMediaURL = getMediaURL(mediaArray, context);
return userMediaURL + MEDIA_URL_SUFIX_FULL;
}
private String getMediaURL(JSONArray mediaArray, final Context context) {
String apiAddress = Preferences.getPreference(context, Preferences.API_ADDRESS);
JSONObject mediaJson = mediaArray.optJSONObject(0);
String userMediaURL = apiAddress + "/" + mediaJson.optString("channel") +
MediaModel.ENDPOINT + "/" + mediaJson.optString("id");
return userMediaURL;
}
private void sendReply(final Context context, final EditText replyTxt) {
if (replyTxt == null || TextUtils.isEmpty(replyTxt.getText().toString())) {
Toast.makeText(context, context.getString(R.string.message_post_comment_mandatory),
Toast.LENGTH_LONG).show();
return ;
}
JSONObject replyPost = createReply(replyTxt);
replyTxt.setText("");
PostsModel.getInstance().save(context, replyPost, new ModelCallback<JSONObject>() {
@Override
public void success(JSONObject response) {
Toast.makeText(context, context.getString(R.string.message_reply_created),
Toast.LENGTH_LONG).show();
InputUtils.hideKeyboard(fragment.getActivity());
fragment.fillRemotely(null, null);
}
@Override
public void error(Throwable throwable) {
}
}, channelJid);
}
private JSONObject createReply(EditText postContent) {
JSONObject reply = new JSONObject();
try {
reply.putOpt("content", postContent.getText().toString());
reply.putOpt("replyTo", this.post.optString("id"));
} catch (JSONException e) {
e.printStackTrace();
}
return reply;
}
private CommentCard toReplyCard(JSONObject comment, Context context) {
CommentCard commentCard = new CommentCard(channelJid, comment,
activity, role);
return commentCard;
}
private static CardViewHolder fillHolder(View view) {
return CardViewHolder.create(view,
R.id.postContentWrapper, R.id.postContainer,
R.id.postTitleWrapper, R.id.bcProfilePic,
R.id.bcPostAuthor,
R.id.bcPostDate, R.id.bcTopRightView,
R.id.bcArrowDown, R.id.bcPostPending,
R.id.bcImageContent, R.id.bcPostContent,
R.id.replyListViewSection,
R.id.commentBoxFrameView, R.id.bcReplyAuthorPic,
R.id.postNewCommentTxt);
}
@Override
public int compareTo(Card anotherCard) {
try {
Date otherUpdated = TimeUtils.threadUpdated(anotherCard.getPost());
Date thisUpdated = TimeUtils.threadUpdated(this.getPost());
return otherUpdated.compareTo(thisUpdated);
} catch (ParseException e) {
return 0;
}
}
public void addPendingCard(JSONObject pendingItem) {
repliesAdapter.addCard(toReplyCard(pendingItem, activity));
repliesAdapter.sort();
}
}