package info.justaway.adapter;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v4.content.ContextCompat;
import android.support.v4.util.LongSparseArray;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.ArrayList;
import butterknife.Bind;
import butterknife.ButterKnife;
import de.greenrobot.event.EventBus;
import info.justaway.BuildConfig;
import info.justaway.ProfileActivity;
import info.justaway.R;
import info.justaway.event.AlertDialogEvent;
import info.justaway.model.AccessTokenManager;
import info.justaway.model.FavRetweetManager;
import info.justaway.model.Row;
import info.justaway.model.UserIconManager;
import info.justaway.settings.BasicSettings;
import info.justaway.settings.MuteSettings;
import info.justaway.util.ActionUtil;
import info.justaway.util.ImageUtil;
import info.justaway.util.MessageUtil;
import info.justaway.util.StatusUtil;
import info.justaway.util.ThemeUtil;
import info.justaway.util.TimeUtil;
import twitter4j.DirectMessage;
import twitter4j.Status;
import twitter4j.User;
public class TwitterAdapter extends ArrayAdapter<Row> {
static class ViewHolder {
@Bind(R.id.action_container) ViewGroup mActionContainer;
@Bind(R.id.action_icon) TextView mActionIcon;
@Bind(R.id.action_by_display_name) TextView mActionByDisplayName;
@Bind(R.id.action_by_screen_name) TextView mActionByScreenName;
@Bind(R.id.icon) ImageView mIcon;
@Bind(R.id.display_name) TextView mDisplayName;
@Bind(R.id.screen_name) TextView mScreenName;
@Bind(R.id.lock) TextView mLock;
@Bind(R.id.datetime_relative) TextView mDatetimeRelative;
@Bind(R.id.status) TextView mStatus;
@Bind(R.id.quoted_display_name) TextView mQuotedDisplayName;
@Bind(R.id.quoted_screen_name) TextView mQuotedScreenName;
@Bind(R.id.quoted_status) TextView mQuotedStatus;
@Bind(R.id.quoted_tweet) RelativeLayout mQuotedTweet;
@Bind(R.id.quoted_images_container_wrapper) ViewGroup mQuotedImagesContainerWrapper;
@Bind(R.id.quoted_images_container) ViewGroup mQuotedImagesContainer;
@Bind(R.id.quoted_play) TextView mQuotedPlay;
@Bind(R.id.images_container_wrapper) ViewGroup mImagesContainerWrapper;
@Bind(R.id.images_container) ViewGroup mImagesContainer;
@Bind(R.id.play) TextView mPlay;
@Bind(R.id.menu_and_via_container) ViewGroup mMenuAndViaContainer;
@Bind(R.id.do_reply) TextView mDoReply;
@Bind(R.id.do_retweet) TextView mDoRetweet;
@Bind(R.id.retweet_count) TextView mRetweetCount;
@Bind(R.id.do_fav) TextView mDoFav;
@Bind(R.id.fav_count) TextView mFavCount;
@Bind(R.id.via) TextView mVia;
@Bind(R.id.datetime) TextView mDatetime;
@Bind(R.id.retweet_container) View mRetweetContainer;
@Bind(R.id.retweet_icon) ImageView mRetweetIcon;
@Bind(R.id.retweet_by) TextView mRetweetBy;
public ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
private Context mContext;
private LayoutInflater mInflater;
private int mLayout;
private int mColorBlue = 0;
private static final int LIMIT = 100;
private int mLimit = LIMIT;
private final LongSparseArray<Boolean> mIdMap = new LongSparseArray<>();
public TwitterAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mContext = context;
mLayout = textViewResourceId;
}
public Context getContext() {
return mContext;
}
public void extensionAdd(Row row) {
if (MuteSettings.isMute(row)) {
return;
}
if (exists(row)) {
return;
}
super.add(row);
if (row.isStatus()) {
mIdMap.put(row.getStatus().getId(), true);
}
filter(row);
mLimit++;
}
@Override
public void add(Row row) {
if (MuteSettings.isMute(row)) {
return;
}
if (exists(row)) {
return;
}
super.add(row);
if (row.isStatus()) {
mIdMap.put(row.getStatus().getId(), true);
}
filter(row);
limitation();
}
@Override
public void insert(Row row, int index) {
if (MuteSettings.isMute(row)) {
return;
}
if (exists(row)) {
return;
}
super.insert(row, index);
if (row.isStatus()) {
mIdMap.put(row.getStatus().getId(), true);
}
filter(row);
limitation();
}
@Override
public void remove(Row row) {
super.remove(row);
if (row.isStatus()) {
mIdMap.remove(row.getStatus().getId());
}
}
public boolean exists(Row row) {
return row.isStatus() && mIdMap.get(row.getStatus().getId(), false);
}
private void filter(Row row) {
Status status = row.getStatus();
if (status != null && status.isRetweeted()) {
Status retweet = status.getRetweetedStatus();
if (retweet != null && status.getUser().getId() == AccessTokenManager.getUserId()) {
FavRetweetManager.setRtId(retweet.getId(), status.getId());
}
}
}
@SuppressWarnings("unused")
public void replaceStatus(Status status) {
for (int i = 0; i < getCount(); i++) {
Row row = getItem(i);
if (!row.isDirectMessage() && row.getStatus().getId() == status.getId()) {
row.setStatus(status);
notifyDataSetChanged();
break;
}
}
}
public ArrayList<Integer> removeStatus(long statusId) {
int position = 0;
ArrayList<Integer> positions = new ArrayList<>();
ArrayList<Row> rows = new ArrayList<>();
for (int i = 0; i < getCount(); i++) {
Row row = getItem(i);
if (row.isDirectMessage()) {
continue;
}
twitter4j.Status status = row.getStatus();
twitter4j.Status retweet = status.getRetweetedStatus();
if (row.getStatus().getId() == statusId || (retweet != null && retweet.getId() == statusId)) {
rows.add(row);
positions.add(position);
}
position++;
}
for (Row row : rows) {
remove(row);
}
return positions;
}
public void removeDirectMessage(long directMessageId) {
for (int i = 0; i < getCount(); i++) {
Row row = getItem(i);
if (row.isDirectMessage() && row.getMessage().getId() == directMessageId) {
remove(row);
break;
}
}
}
public void limitation() {
int size = getCount();
if (size > mLimit) {
int count = size - mLimit;
for (int i = 0; i < count; i++) {
super.remove(getItem(size - i - 1));
}
}
}
@Override
public void clear() {
super.clear();
mIdMap.clear();
mLimit = LIMIT;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
// ビューを受け取る
View view = convertView;
if (view == null) {
// 受け取ったビューがnullなら新しくビューを生成
view = mInflater.inflate(this.mLayout, null);
if (view == null) {
return null;
}
holder = new ViewHolder(view);
holder.mStatus.setTag(12);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
Integer fontSize = BasicSettings.getFontSize();
if (!fontSize.equals(holder.mStatus.getTag())) {
holder.mStatus.setTag(fontSize);
holder.mStatus.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
holder.mDisplayName.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
holder.mScreenName.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize - 2);
holder.mDatetimeRelative.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize - 2);
}
// 表示すべきデータの取得
Row row = getItem(position);
if (row.isDirectMessage()) {
DirectMessage message = row.getMessage();
if (message == null) {
return view;
}
renderMessage(holder, message);
} else {
Status status = row.getStatus();
if (status == null) {
return view;
}
Status retweet = status.getRetweetedStatus();
if (row.isFavorite()) {
renderStatus(holder, status, null, row.getSource());
} else if (retweet == null) {
renderStatus(holder, status, null, null);
} else {
renderStatus(holder, retweet, status, null);
}
}
return view;
}
@SuppressLint("SetTextI18n")
private void renderMessage(ViewHolder holder, final DirectMessage message) {
long userId = AccessTokenManager.getUserId();
holder.mDoRetweet.setVisibility(View.GONE);
holder.mDoFav.setVisibility(View.GONE);
holder.mRetweetCount.setVisibility(View.GONE);
holder.mFavCount.setVisibility(View.GONE);
holder.mMenuAndViaContainer.setVisibility(View.VISIBLE);
if (message.getSender().getId() == userId) {
holder.mDoReply.setVisibility(View.GONE);
} else {
holder.mDoReply.setVisibility(View.VISIBLE);
holder.mDoReply.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ActionUtil.doReplyDirectMessage(message, mContext);
}
});
}
holder.mDisplayName.setText(message.getSender().getName());
holder.mScreenName.setText("@"
+ message.getSender().getScreenName());
holder.mStatus.setText("D " + message.getRecipientScreenName()
+ " " + message.getText());
holder.mDatetime
.setText(TimeUtil.getAbsoluteTime(message.getCreatedAt()));
holder.mDatetimeRelative.setText(TimeUtil.getRelativeTime(message.getCreatedAt()));
holder.mVia.setVisibility(View.GONE);
holder.mQuotedTweet.setVisibility(View.GONE);
holder.mRetweetContainer.setVisibility(View.GONE);
holder.mImagesContainer.setVisibility(View.GONE);
holder.mImagesContainerWrapper.setVisibility(View.GONE);
UserIconManager.displayUserIcon(message.getSender(), holder.mIcon);
holder.mIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), ProfileActivity.class);
intent.putExtra("screenName", message.getSender().getScreenName());
mContext.startActivity(intent);
}
});
holder.mActionContainer.setVisibility(View.GONE);
holder.mLock.setVisibility(View.INVISIBLE);
}
@SuppressLint("SetTextI18n")
private void renderStatus(final ViewHolder holder, final Status status, Status retweet,
User favorite) {
long userId = AccessTokenManager.getUserId();
if (status.getFavoriteCount() > 0) {
holder.mFavCount.setText(String.valueOf(status.getFavoriteCount()));
holder.mFavCount.setVisibility(View.VISIBLE);
} else {
holder.mFavCount.setText("0");
holder.mFavCount.setVisibility(View.INVISIBLE);
}
if (status.getRetweetCount() > 0) {
holder.mRetweetCount.setText(String.valueOf(status.getRetweetCount()));
holder.mRetweetCount.setVisibility(View.VISIBLE);
} else {
holder.mRetweetCount.setText("0");
holder.mRetweetCount.setVisibility(View.INVISIBLE);
}
holder.mDoReply.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ActionUtil.doReplyAll(status, mContext);
}
});
holder.mDoRetweet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (status.getUser().isProtected()) {
MessageUtil.showToast(R.string.toast_protected_tweet_can_not_share);
return;
}
Long id = FavRetweetManager.getRtId(status);
if (id != null) {
if (id == 0) {
MessageUtil.showToast(R.string.toast_destroy_retweet_progress);
} else {
DialogFragment dialog = new DestroyRetweetDialogFragment();
Bundle args = new Bundle(1);
args.putSerializable("status", status);
dialog.setArguments(args);
EventBus.getDefault().post(new AlertDialogEvent(dialog));
}
} else {
DialogFragment dialog = new RetweetDialogFragment();
Bundle args = new Bundle(1);
args.putSerializable("status", status);
dialog.setArguments(args);
EventBus.getDefault().post(new AlertDialogEvent(dialog));
}
}
});
holder.mDoFav.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (holder.mDoFav.getTag().equals("is_fav")) {
holder.mDoFav.setTag("no_fav");
holder.mDoFav.setTextColor(Color.parseColor("#666666"));
ActionUtil.doDestroyFavorite(status.getId());
} else {
holder.mDoFav.setTag("is_fav");
holder.mDoFav.setTextColor(ContextCompat.getColor(mContext, R.color.holo_orange_light));
ActionUtil.doFavorite(status.getId());
}
}
});
if (FavRetweetManager.getRtId(status) != null) {
holder.mDoRetweet.setTextColor(ContextCompat.getColor(mContext, R.color.holo_green_light));
} else {
holder.mDoRetweet.setTextColor(Color.parseColor("#666666"));
}
if (FavRetweetManager.isFav(status)) {
holder.mDoFav.setTag("is_fav");
holder.mDoFav.setTextColor(ContextCompat.getColor(mContext, R.color.holo_orange_light));
} else {
holder.mDoFav.setTag("no_fav");
holder.mDoFav.setTextColor(Color.parseColor("#666666"));
}
holder.mDisplayName.setText(status.getUser().getName());
holder.mScreenName.setText("@" + status.getUser().getScreenName());
holder.mDatetimeRelative.setText(TimeUtil.getRelativeTime(status.getCreatedAt()));
holder.mDatetime.setText(TimeUtil.getAbsoluteTime(status.getCreatedAt()));
String via = StatusUtil.getClientName(status.getSource());
holder.mVia.setText("via " + via);
holder.mVia.setVisibility(View.VISIBLE);
/**
* デバッグモードの時だけ Justaway for Android をハイライト
*/
if (BuildConfig.DEBUG) {
if (via.equals("Justaway for Android")) {
if (mColorBlue == 0) {
mColorBlue = ThemeUtil.getThemeTextColor(R.attr.holo_blue);
}
holder.mVia.setTextColor(mColorBlue);
} else {
holder.mVia.setTextColor(Color.parseColor("#666666"));
}
}
// favの場合
if (favorite != null) {
holder.mActionIcon.setText(R.string.fontello_star);
holder.mActionIcon.setTextColor(ContextCompat.getColor(mContext, R.color.holo_orange_light));
holder.mActionByDisplayName.setText(favorite.getName());
holder.mActionByScreenName.setText("@" + favorite.getScreenName());
holder.mRetweetContainer.setVisibility(View.GONE);
holder.mMenuAndViaContainer.setVisibility(View.VISIBLE);
holder.mActionContainer.setVisibility(View.VISIBLE);
}
// RTの場合
else if (retweet != null) {
// 自分のツイート
if (userId == status.getUser().getId()) {
holder.mActionIcon.setText(R.string.fontello_retweet);
holder.mActionIcon.setTextColor(ContextCompat.getColor(mContext, R.color.holo_green_light));
holder.mActionByDisplayName.setText(retweet.getUser().getName());
holder.mActionByScreenName.setText("@" + retweet.getUser().getScreenName());
holder.mRetweetContainer.setVisibility(View.GONE);
holder.mMenuAndViaContainer.setVisibility(View.VISIBLE);
holder.mActionContainer.setVisibility(View.VISIBLE);
} else {
if (BasicSettings.getUserIconSize().equals("none")) {
holder.mRetweetIcon.setVisibility(View.GONE);
} else {
holder.mRetweetIcon.setVisibility(View.VISIBLE);
ImageUtil.displayRoundedImage(retweet.getUser().getProfileImageURL(), holder.mRetweetIcon);
}
holder.mRetweetBy.setText("RT by " + retweet.getUser().getName() + " @" + retweet.getUser().getScreenName());
holder.mActionContainer.setVisibility(View.GONE);
holder.mMenuAndViaContainer.setVisibility(View.VISIBLE);
holder.mRetweetContainer.setVisibility(View.VISIBLE);
}
} else {
// 自分へのリプ
if (StatusUtil.isMentionForMe(status)) {
holder.mActionIcon.setText(R.string.fontello_at);
holder.mActionIcon.setTextColor(ContextCompat.getColor(mContext, R.color.holo_red_light));
holder.mActionByDisplayName.setText(status.getUser().getName());
holder.mActionByScreenName.setText("@" + status.getUser().getScreenName());
holder.mActionContainer.setVisibility(View.VISIBLE);
holder.mRetweetContainer.setVisibility(View.GONE);
} else {
holder.mActionContainer.setVisibility(View.GONE);
holder.mRetweetContainer.setVisibility(View.GONE);
}
holder.mMenuAndViaContainer.setVisibility(View.VISIBLE);
}
if (status.getUser().isProtected()) {
holder.mLock.setVisibility(View.VISIBLE);
} else {
holder.mLock.setVisibility(View.INVISIBLE);
}
UserIconManager.displayUserIcon(status.getUser(), holder.mIcon);
holder.mIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(v.getContext(), ProfileActivity.class);
intent.putExtra("screenName", status.getUser().getScreenName());
mContext.startActivity(intent);
}
});
// RTの場合はRT元
String statusString = StatusUtil.getExpandedText(status);
holder.mStatus.setText(StatusUtil.generateUnderline(statusString));
// 引用ツイート
Status quotedStatus = status.getQuotedStatus();
if (quotedStatus != null) {
holder.mQuotedDisplayName.setText(quotedStatus.getUser().getName());
holder.mQuotedScreenName.setText(quotedStatus.getUser().getScreenName());
holder.mQuotedStatus.setText(quotedStatus.getText());
// プレビュー表示On
if (BasicSettings.getDisplayThumbnailOn()) {
ImageUtil.displayThumbnailImages(mContext, holder.mQuotedImagesContainer, holder.mImagesContainerWrapper, holder.mQuotedPlay, quotedStatus);
} else {
holder.mQuotedImagesContainer.setVisibility(View.GONE);
holder.mQuotedImagesContainerWrapper.setVisibility(View.GONE);
}
holder.mQuotedTweet.setVisibility(View.VISIBLE);
} else {
holder.mQuotedTweet.setVisibility(View.GONE);
}
// プレビュー表示On
if (BasicSettings.getDisplayThumbnailOn()) {
ImageUtil.displayThumbnailImages(mContext, holder.mImagesContainer, holder.mImagesContainerWrapper, holder.mPlay, status);
} else {
holder.mImagesContainer.setVisibility(View.GONE);
holder.mImagesContainerWrapper.setVisibility(View.GONE);
}
}
public static final class RetweetDialogFragment extends DialogFragment {
@SuppressWarnings("ConstantConditions")
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Status status = (Status) getArguments().getSerializable("status");
if (status == null) {
return null;
}
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.confirm_retweet);
builder.setMessage(status.getText());
builder.setNeutralButton(getString(R.string.button_quote),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActionUtil.doQuote(status, getActivity());
dismiss();
}
}
);
builder.setPositiveButton(getString(R.string.button_retweet),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActionUtil.doRetweet(status.getId());
dismiss();
}
}
);
builder.setNegativeButton(getString(R.string.button_cancel),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dismiss();
}
}
);
return builder.create();
}
}
public static final class DestroyRetweetDialogFragment extends DialogFragment {
@SuppressWarnings("ConstantConditions")
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Status status = (Status) getArguments().getSerializable("status");
if (status == null) {
return null;
}
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.confirm_destroy_retweet);
builder.setMessage(status.getText());
builder.setPositiveButton(getString(R.string.button_destroy_retweet),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActionUtil.doDestroyRetweet(status);
dismiss();
}
}
);
builder.setNegativeButton(getString(R.string.button_cancel),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dismiss();
}
}
);
return builder.create();
}
}
}