mirror of https://github.com/KokaKiwi/BarInsta
618 lines
29 KiB
Java
618 lines
29 KiB
Java
package awais.instagrabber.adapters.viewholder.directmessages;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.content.res.ColorStateList;
|
|
import android.content.res.Resources;
|
|
import android.graphics.Point;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.view.Gravity;
|
|
import android.view.View;
|
|
import android.view.ViewConfiguration;
|
|
import android.view.ViewPropertyAnimator;
|
|
import android.view.animation.AccelerateDecelerateInterpolator;
|
|
import android.widget.FrameLayout;
|
|
|
|
import androidx.annotation.CallSuper;
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
|
import androidx.core.widget.ImageViewCompat;
|
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
import androidx.transition.TransitionManager;
|
|
|
|
import com.google.android.material.transition.MaterialFade;
|
|
import com.google.common.collect.ImmutableList;
|
|
|
|
import java.time.format.DateTimeFormatter;
|
|
import java.time.format.FormatStyle;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.stream.Collectors;
|
|
|
|
import awais.instagrabber.R;
|
|
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
|
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemInternalLongClickListener;
|
|
import awais.instagrabber.customviews.DirectItemContextMenu;
|
|
import awais.instagrabber.customviews.DirectItemFrameLayout;
|
|
import awais.instagrabber.customviews.RamboTextViewV2;
|
|
import awais.instagrabber.customviews.helpers.SwipeAndRestoreItemTouchHelperCallback.SwipeableViewHolder;
|
|
import awais.instagrabber.databinding.LayoutDmBaseBinding;
|
|
import awais.instagrabber.models.enums.DirectItemType;
|
|
import awais.instagrabber.models.enums.MediaItemType;
|
|
import awais.instagrabber.repositories.responses.Media;
|
|
import awais.instagrabber.repositories.responses.User;
|
|
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
|
import awais.instagrabber.repositories.responses.directmessages.DirectItemEmojiReaction;
|
|
import awais.instagrabber.repositories.responses.directmessages.DirectItemReactions;
|
|
import awais.instagrabber.repositories.responses.directmessages.DirectItemStoryShare;
|
|
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
|
import awais.instagrabber.utils.DMUtils;
|
|
import awais.instagrabber.utils.DeepLinkParser;
|
|
import awais.instagrabber.utils.ResponseBodyUtils;
|
|
|
|
public abstract class DirectItemViewHolder extends RecyclerView.ViewHolder implements SwipeableViewHolder {
|
|
private static final String TAG = DirectItemViewHolder.class.getSimpleName();
|
|
// private static final List<Integer> THREAD_CHANGING_OPTIONS = ImmutableList.of(R.id.unsend);
|
|
|
|
private final LayoutDmBaseBinding binding;
|
|
private final User currentUser;
|
|
private final DirectThread thread;
|
|
private final int groupMessageWidth;
|
|
private final List<Long> userIds;
|
|
private final DirectItemCallback callback;
|
|
private final int reactionAdjustMargin;
|
|
private final AccelerateDecelerateInterpolator accelerateDecelerateInterpolator = new AccelerateDecelerateInterpolator();
|
|
|
|
protected final int margin;
|
|
protected final int dmRadius;
|
|
protected final int dmRadiusSmall;
|
|
protected final int messageInfoPaddingSmall;
|
|
protected final int mediaImageMaxHeight;
|
|
protected final int windowWidth;
|
|
protected final int mediaImageMaxWidth;
|
|
protected final int reactionTranslationYType1;
|
|
protected final int reactionTranslationYType2;
|
|
|
|
private boolean selected = false;
|
|
private DirectItemInternalLongClickListener longClickListener;
|
|
private DirectItem item;
|
|
private ViewPropertyAnimator shrinkGrowAnimator;
|
|
private MessageDirection messageDirection;
|
|
// private View.OnLayoutChangeListener layoutChangeListener;
|
|
|
|
public DirectItemViewHolder(@NonNull final LayoutDmBaseBinding binding,
|
|
@NonNull final User currentUser,
|
|
@NonNull final DirectThread thread,
|
|
@NonNull final DirectItemCallback callback) {
|
|
super(binding.getRoot());
|
|
this.binding = binding;
|
|
this.currentUser = currentUser;
|
|
this.thread = thread;
|
|
this.callback = callback;
|
|
userIds = thread.getUsers()
|
|
.stream()
|
|
.map(User::getPk)
|
|
.collect(Collectors.toList());
|
|
binding.ivProfilePic.setVisibility(thread.isGroup() ? View.VISIBLE : View.GONE);
|
|
binding.ivProfilePic.setOnClickListener(null);
|
|
final Resources resources = itemView.getResources();
|
|
margin = resources.getDimensionPixelSize(R.dimen.dm_message_item_margin);
|
|
final int avatarSize = resources.getDimensionPixelSize(R.dimen.dm_message_item_avatar_size);
|
|
dmRadius = resources.getDimensionPixelSize(R.dimen.dm_message_card_radius);
|
|
dmRadiusSmall = resources.getDimensionPixelSize(R.dimen.dm_message_card_radius_small);
|
|
messageInfoPaddingSmall = resources.getDimensionPixelSize(R.dimen.dm_message_info_padding_small);
|
|
windowWidth = resources.getDisplayMetrics().widthPixels;
|
|
mediaImageMaxHeight = resources.getDimensionPixelSize(R.dimen.dm_media_img_max_height);
|
|
reactionAdjustMargin = resources.getDimensionPixelSize(R.dimen.dm_reaction_adjust_margin);
|
|
final int groupWidthCorrection = avatarSize + messageInfoPaddingSmall * 3;
|
|
mediaImageMaxWidth = windowWidth - margin - (thread.isGroup() ? groupWidthCorrection : messageInfoPaddingSmall * 2);
|
|
// messageInfoPaddingSmall is used cuz it's also 4dp, 1 avatar margin + 2 paddings = 3
|
|
groupMessageWidth = windowWidth - margin - groupWidthCorrection;
|
|
reactionTranslationYType1 = resources.getDimensionPixelSize(R.dimen.dm_reaction_translation_y_type_1);
|
|
reactionTranslationYType2 = resources.getDimensionPixelSize(R.dimen.dm_reaction_translation_y_type_2);
|
|
}
|
|
|
|
public void bind(final int position, final DirectItem item) {
|
|
if (item == null) return;
|
|
this.item = item;
|
|
messageDirection = isSelf(item) ? MessageDirection.OUTGOING : MessageDirection.INCOMING;
|
|
// Asynchronous binding causes some weird behaviour
|
|
// itemView.post(() -> bindBase(item, messageDirection, position));
|
|
// itemView.post(() -> bindItem(item, messageDirection));
|
|
// itemView.post(() -> setupLongClickListener(position, messageDirection));
|
|
bindBase(item, messageDirection, position);
|
|
bindItem(item, messageDirection);
|
|
setupLongClickListener(position, messageDirection);
|
|
}
|
|
|
|
private void bindBase(@NonNull final DirectItem item, final MessageDirection messageDirection, final int position) {
|
|
final FrameLayout.LayoutParams containerLayoutParams = (FrameLayout.LayoutParams) binding.container.getLayoutParams();
|
|
final DirectItemType itemType = item.getItemType();
|
|
setMessageDirectionGravity(messageDirection, containerLayoutParams);
|
|
setGroupUserDetails(item, messageDirection);
|
|
setBackground(messageDirection);
|
|
setMessageInfo(item, messageDirection);
|
|
switch (itemType) {
|
|
case REEL_SHARE:
|
|
case STORY_SHARE: // i think they could have texts?
|
|
// containerLayoutParams.setMarginStart(0);
|
|
// containerLayoutParams.setMarginEnd(0);
|
|
case TEXT:
|
|
case LINK:
|
|
case UNKNOWN:
|
|
binding.messageInfo.setPadding(0, 0, dmRadius, dmRadiusSmall);
|
|
break;
|
|
default:
|
|
if (showMessageInfo()) {
|
|
binding.messageInfo.setPadding(0, 0, messageInfoPaddingSmall, dmRadiusSmall);
|
|
}
|
|
}
|
|
setupReply(item, messageDirection);
|
|
setReactions(item, position);
|
|
if (item.getRepliedToMessage() == null && item.getShowForwardAttribution()) {
|
|
setForwardInfo(messageDirection);
|
|
}
|
|
}
|
|
|
|
private void setBackground(final MessageDirection messageDirection) {
|
|
if (showBackground()) {
|
|
binding.background.setBackgroundResource(messageDirection == MessageDirection.INCOMING ? R.drawable.bg_speech_bubble_incoming
|
|
: R.drawable.bg_speech_bubble_outgoing);
|
|
return;
|
|
}
|
|
binding.background.setBackgroundResource(0);
|
|
}
|
|
|
|
private void setGroupUserDetails(final DirectItem item, final MessageDirection messageDirection) {
|
|
if (showUserDetailsInGroup()) {
|
|
binding.ivProfilePic.setVisibility(messageDirection == MessageDirection.INCOMING && thread.isGroup() ? View.VISIBLE : View.GONE);
|
|
binding.tvUsername.setVisibility(messageDirection == MessageDirection.INCOMING && thread.isGroup() ? View.VISIBLE : View.GONE);
|
|
if (messageDirection == MessageDirection.INCOMING && thread.isGroup()) {
|
|
final List<User> allUsers = new LinkedList(thread.getUsers());
|
|
allUsers.addAll(thread.getLeftUsers());
|
|
final User user = getUser(item.getUserId(), allUsers);
|
|
if (user != null) {
|
|
binding.tvUsername.setText(user.getUsername());
|
|
binding.ivProfilePic.setImageURI(user.getProfilePicUrl());
|
|
}
|
|
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) binding.chatMessageLayout.getLayoutParams();
|
|
layoutParams.matchConstraintMaxWidth = groupMessageWidth;
|
|
binding.chatMessageLayout.setLayoutParams(layoutParams);
|
|
}
|
|
return;
|
|
}
|
|
binding.ivProfilePic.setVisibility(View.GONE);
|
|
binding.tvUsername.setVisibility(View.GONE);
|
|
}
|
|
|
|
private void setMessageDirectionGravity(final MessageDirection messageDirection,
|
|
final FrameLayout.LayoutParams containerLayoutParams) {
|
|
if (allowMessageDirectionGravity()) {
|
|
containerLayoutParams.setMarginStart(messageDirection == MessageDirection.OUTGOING ? margin : 0);
|
|
containerLayoutParams.setMarginEnd(messageDirection == MessageDirection.INCOMING ? margin : 0);
|
|
containerLayoutParams.gravity = messageDirection == MessageDirection.INCOMING ? Gravity.START : Gravity.END;
|
|
return;
|
|
}
|
|
containerLayoutParams.gravity = Gravity.CENTER;
|
|
}
|
|
|
|
private void setMessageInfo(@NonNull final DirectItem item, final MessageDirection messageDirection) {
|
|
if (showMessageInfo()) {
|
|
binding.messageInfo.setVisibility(View.VISIBLE);
|
|
binding.deliveryStatus.setVisibility(messageDirection == MessageDirection.OUTGOING ? View.VISIBLE : View.GONE);
|
|
if (item.getDate() != null) {
|
|
final DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);
|
|
binding.messageTime.setText(dateFormatter.format(item.getDate()));
|
|
}
|
|
if (messageDirection == MessageDirection.OUTGOING) {
|
|
if (item.isPending()) {
|
|
binding.deliveryStatus.setImageResource(R.drawable.ic_check_24);
|
|
} else {
|
|
final boolean read = DMUtils.isRead(item,
|
|
thread.getLastSeenAt(),
|
|
userIds
|
|
);
|
|
binding.deliveryStatus.setImageResource(R.drawable.ic_check_all_24);
|
|
ImageViewCompat.setImageTintList(
|
|
binding.deliveryStatus,
|
|
ColorStateList.valueOf(itemView.getResources().getColor(read ? R.color.blue_500 : R.color.grey_500))
|
|
);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
binding.messageInfo.setVisibility(View.GONE);
|
|
}
|
|
|
|
private void setupReply(final DirectItem item, final MessageDirection messageDirection) {
|
|
if (item.getRepliedToMessage() != null) {
|
|
final List<User> allUsers = new LinkedList(thread.getUsers());
|
|
allUsers.addAll(thread.getLeftUsers());
|
|
setReply(item, messageDirection, allUsers);
|
|
} else {
|
|
binding.quoteLine.setVisibility(View.GONE);
|
|
binding.replyContainer.setVisibility(View.GONE);
|
|
binding.replyInfo.setVisibility(View.GONE);
|
|
}
|
|
}
|
|
|
|
private void setReply(final DirectItem item,
|
|
final MessageDirection messageDirection,
|
|
final List<User> users) {
|
|
final DirectItem replied = item.getRepliedToMessage();
|
|
final DirectItemType itemType = replied.getItemType();
|
|
final Resources resources = itemView.getResources();
|
|
String text = null;
|
|
String url = null;
|
|
switch (itemType) {
|
|
case TEXT:
|
|
text = replied.getText();
|
|
break;
|
|
case LINK:
|
|
text = replied.getLink().getText();
|
|
break;
|
|
case PLACEHOLDER:
|
|
text = replied.getPlaceholder().getMessage();
|
|
break;
|
|
case MEDIA:
|
|
url = ResponseBodyUtils.getThumbUrl(replied.getMedia());
|
|
break;
|
|
case RAVEN_MEDIA:
|
|
url = ResponseBodyUtils.getThumbUrl(replied.getVisualMedia().getMedia());
|
|
break;
|
|
case VOICE_MEDIA:
|
|
text = resources.getString(R.string.voice_message);
|
|
break;
|
|
case MEDIA_SHARE:
|
|
Media mediaShare = replied.getMediaShare();
|
|
if (mediaShare.getMediaType() == MediaItemType.MEDIA_TYPE_SLIDER) {
|
|
mediaShare = mediaShare.getCarouselMedia().get(0);
|
|
}
|
|
url = ResponseBodyUtils.getThumbUrl(mediaShare);
|
|
break;
|
|
case REEL_SHARE:
|
|
text = replied.getReelShare().getText();
|
|
break;
|
|
// Below types cannot be replied to
|
|
// case LIKE:
|
|
// text = "❤️";
|
|
// break;
|
|
// case PROFILE:
|
|
// text = "@" + replied.getProfile().getUsername();
|
|
// break;
|
|
// case CLIP:
|
|
// url = ResponseBodyUtils.getThumbUrl(replied.getClip().getClip().getImageVersions2());
|
|
// break;
|
|
// case FELIX_SHARE:
|
|
// url = ResponseBodyUtils.getThumbUrl(replied.getFelixShare().getVideo().getImageVersions2());
|
|
// break;
|
|
// case STORY_SHARE:
|
|
// final DirectItemMedia media = replied.getStoryShare().getMedia();
|
|
// if (media == null) break;
|
|
// url = ResponseBodyUtils.getThumbUrl(media.getImageVersions2());
|
|
// break;
|
|
// case LOCATION
|
|
}
|
|
if (text == null && url == null) {
|
|
binding.quoteLine.setVisibility(View.GONE);
|
|
binding.replyContainer.setVisibility(View.GONE);
|
|
binding.replyInfo.setVisibility(View.GONE);
|
|
return;
|
|
}
|
|
setReplyGravity(messageDirection);
|
|
final String info = setReplyInfo(item, replied, users, resources);
|
|
binding.replyInfo.setVisibility(View.VISIBLE);
|
|
binding.replyInfo.setText(info);
|
|
binding.quoteLine.setVisibility(View.VISIBLE);
|
|
binding.replyContainer.setVisibility(View.VISIBLE);
|
|
if (url != null) {
|
|
binding.replyText.setVisibility(View.GONE);
|
|
binding.replyImage.setVisibility(View.VISIBLE);
|
|
binding.replyImage.setImageURI(url);
|
|
return;
|
|
}
|
|
binding.replyImage.setVisibility(View.GONE);
|
|
final Drawable background = binding.replyText.getBackground().mutate();
|
|
background.setTint(replied.getUserId() != currentUser.getPk()
|
|
? resources.getColor(R.color.grey_600)
|
|
: resources.getColor(R.color.deep_purple_400));
|
|
binding.replyText.setBackgroundDrawable(background);
|
|
binding.replyText.setVisibility(View.VISIBLE);
|
|
binding.replyText.setText(text);
|
|
}
|
|
|
|
private String setReplyInfo(final DirectItem item,
|
|
final DirectItem replied,
|
|
final List<User> users,
|
|
final Resources resources) {
|
|
final long repliedToUserId = replied.getUserId();
|
|
if (repliedToUserId == item.getUserId() && item.getUserId() == currentUser.getPk()) {
|
|
// User replied to own message
|
|
return resources.getString(R.string.replied_to_yourself);
|
|
}
|
|
if (repliedToUserId == item.getUserId()) {
|
|
// opposite user replied to their own message
|
|
return resources.getString(R.string.replied_to_themself);
|
|
}
|
|
final User user = getUser(repliedToUserId, users);
|
|
final String repliedToUsername = user != null ? user.getUsername() : "";
|
|
if (item.getUserId() == currentUser.getPk()) {
|
|
return thread.isGroup()
|
|
? resources.getString(R.string.replied_you_group, repliedToUsername)
|
|
: resources.getString(R.string.replied_you);
|
|
}
|
|
if (repliedToUserId == currentUser.getPk()) {
|
|
return resources.getString(R.string.replied_to_you);
|
|
}
|
|
return resources.getString(R.string.replied_group, repliedToUsername);
|
|
}
|
|
|
|
private void setForwardInfo(final MessageDirection direction) {
|
|
binding.replyInfo.setVisibility(View.VISIBLE);
|
|
binding.replyInfo.setText(direction == MessageDirection.OUTGOING ? R.string.forward_outgoing : R.string.forward_incoming);
|
|
}
|
|
|
|
private void setReplyGravity(final MessageDirection messageDirection) {
|
|
final boolean isIncoming = messageDirection == MessageDirection.INCOMING;
|
|
final ConstraintLayout.LayoutParams quoteLineLayoutParams = (ConstraintLayout.LayoutParams) binding.quoteLine.getLayoutParams();
|
|
final ConstraintLayout.LayoutParams replyContainerLayoutParams = (ConstraintLayout.LayoutParams) binding.replyContainer.getLayoutParams();
|
|
final ConstraintLayout.LayoutParams replyInfoLayoutParams = (ConstraintLayout.LayoutParams) binding.replyInfo.getLayoutParams();
|
|
final int profilePicId = binding.ivProfilePic.getId();
|
|
final int replyContainerId = binding.replyContainer.getId();
|
|
final int quoteLineId = binding.quoteLine.getId();
|
|
quoteLineLayoutParams.startToEnd = isIncoming ? profilePicId : replyContainerId;
|
|
quoteLineLayoutParams.endToStart = isIncoming ? replyContainerId : ConstraintLayout.LayoutParams.UNSET;
|
|
quoteLineLayoutParams.endToEnd = isIncoming ? ConstraintLayout.LayoutParams.UNSET : ConstraintLayout.LayoutParams.PARENT_ID;
|
|
replyContainerLayoutParams.startToEnd = isIncoming ? quoteLineId : profilePicId;
|
|
replyContainerLayoutParams.endToEnd = isIncoming ? ConstraintLayout.LayoutParams.PARENT_ID : ConstraintLayout.LayoutParams.UNSET;
|
|
replyContainerLayoutParams.endToStart = isIncoming ? ConstraintLayout.LayoutParams.UNSET : quoteLineId;
|
|
replyInfoLayoutParams.startToEnd = isIncoming ? quoteLineId : ConstraintLayout.LayoutParams.UNSET;
|
|
replyInfoLayoutParams.endToStart = isIncoming ? ConstraintLayout.LayoutParams.UNSET : quoteLineId;
|
|
}
|
|
|
|
private void setReactions(final DirectItem item, final int position) {
|
|
binding.getRoot().post(() -> {
|
|
MaterialFade materialFade = new MaterialFade();
|
|
materialFade.addTarget(binding.emojis);
|
|
TransitionManager.beginDelayedTransition(binding.getRoot(), materialFade);
|
|
final DirectItemReactions reactions = item.getReactions();
|
|
final List<DirectItemEmojiReaction> emojis = reactions != null ? reactions.getEmojis() : null;
|
|
if (emojis == null || emojis.isEmpty()) {
|
|
binding.container.setPadding(messageInfoPaddingSmall, messageInfoPaddingSmall, messageInfoPaddingSmall, 0);
|
|
binding.reactionsWrapper.setVisibility(View.GONE);
|
|
return;
|
|
}
|
|
binding.reactionsWrapper.setVisibility(View.VISIBLE);
|
|
binding.reactionsWrapper.setTranslationY(getReactionsTranslationY());
|
|
binding.container.setPadding(messageInfoPaddingSmall, messageInfoPaddingSmall, messageInfoPaddingSmall, reactionAdjustMargin);
|
|
binding.emojis.setEmojis(emojis.stream()
|
|
.map(DirectItemEmojiReaction::getEmoji)
|
|
.collect(Collectors.toList()));
|
|
// binding.emojis.setEmojis(ImmutableList.of("😣",
|
|
// "😖",
|
|
// "😫",
|
|
// "😩",
|
|
// "🥺",
|
|
// "😢",
|
|
// "😭",
|
|
// "😤",
|
|
// "😠",
|
|
// "😡",
|
|
// "🤬"));
|
|
binding.emojis.setOnClickListener(v -> callback.onReactionClick(item, position));
|
|
// final List<DirectUser> reactedUsers = emojis.stream()
|
|
// .map(DirectItemEmojiReaction::getSenderId)
|
|
// .distinct()
|
|
// .map(userId -> getUser(userId, users))
|
|
// .collect(Collectors.toList());
|
|
// for (final DirectUser user : reactedUsers) {
|
|
// if (user == null) continue;
|
|
// final ProfilePicView profilePicView = new ProfilePicView(itemView.getContext());
|
|
// profilePicView.setSize(ProfilePicView.Size.TINY);
|
|
// profilePicView.setImageURI(user.getProfilePicUrl());
|
|
// binding.reactions.addView(profilePicView);
|
|
// }
|
|
});
|
|
}
|
|
|
|
protected boolean isSelf(final DirectItem directItem) {
|
|
return directItem.getUserId() == currentUser.getPk();
|
|
}
|
|
|
|
public void setItemView(final View view) {
|
|
this.binding.message.addView(view);
|
|
}
|
|
|
|
public abstract void bindItem(final DirectItem directItemModel, final MessageDirection messageDirection);
|
|
|
|
@Nullable
|
|
protected User getUser(final long userId, final List<User> users) {
|
|
if (userId == currentUser.getPk()) {
|
|
return currentUser;
|
|
}
|
|
if (users == null) return null;
|
|
for (final User user : users) {
|
|
if (userId != user.getPk()) continue;
|
|
return user;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
protected boolean allowMessageDirectionGravity() {
|
|
return true;
|
|
}
|
|
|
|
protected boolean showUserDetailsInGroup() {
|
|
return true;
|
|
}
|
|
|
|
protected boolean showBackground() {
|
|
return false;
|
|
}
|
|
|
|
protected boolean showMessageInfo() {
|
|
return true;
|
|
}
|
|
|
|
protected boolean allowLongClick() {
|
|
return true;
|
|
}
|
|
|
|
protected boolean allowReaction() {
|
|
return true;
|
|
}
|
|
|
|
protected boolean canForward() {
|
|
return true;
|
|
}
|
|
|
|
protected List<DirectItemContextMenu.MenuItem> getLongClickOptions() {
|
|
return null;
|
|
}
|
|
|
|
protected int getReactionsTranslationY() {
|
|
return reactionTranslationYType1;
|
|
}
|
|
|
|
@CallSuper
|
|
public void cleanup() {
|
|
// if (layoutChangeListener != null) {
|
|
// binding.container.removeOnLayoutChangeListener(layoutChangeListener);
|
|
// }
|
|
}
|
|
|
|
protected void setupRamboTextListeners(@NonNull final RamboTextViewV2 textView) {
|
|
textView.addOnHashtagListener(autoLinkItem -> callback.onHashtagClick(autoLinkItem.getOriginalText().trim()));
|
|
textView.addOnMentionClickListener(autoLinkItem -> openProfile(autoLinkItem.getOriginalText().trim()));
|
|
textView.addOnEmailClickListener(autoLinkItem -> callback.onEmailClick(autoLinkItem.getOriginalText().trim()));
|
|
textView.addOnURLClickListener(autoLinkItem -> openURL(autoLinkItem.getOriginalText().trim()));
|
|
}
|
|
|
|
protected void openProfile(final String username) {
|
|
callback.onMentionClick(username);
|
|
}
|
|
|
|
protected void openLocation(final long locationId) {
|
|
callback.onLocationClick(locationId);
|
|
}
|
|
|
|
protected void openURL(final String url) {
|
|
callback.onURLClick(url);
|
|
}
|
|
|
|
protected void openMedia(final Media media, final int index) {
|
|
callback.onMediaClick(media, index);
|
|
}
|
|
|
|
protected void openStory(final DirectItemStoryShare storyShare) {
|
|
callback.onStoryClick(storyShare);
|
|
}
|
|
|
|
protected void handleDeepLink(final String deepLinkText) {
|
|
if (deepLinkText == null) return;
|
|
final DeepLinkParser.DeepLink deepLink = DeepLinkParser.parse(deepLinkText);
|
|
if (deepLink == null) return;
|
|
switch (deepLink.getType()) {
|
|
case USER:
|
|
callback.onMentionClick(deepLink.getValue());
|
|
break;
|
|
}
|
|
}
|
|
|
|
@SuppressLint("ClickableViewAccessibility")
|
|
private void setupLongClickListener(final int position, final MessageDirection messageDirection) {
|
|
if (!allowLongClick()) return;
|
|
binding.getRoot().setOnItemLongClickListener(new DirectItemFrameLayout.OnItemLongClickListener() {
|
|
@Override
|
|
public void onLongClickStart(final View view) {
|
|
itemView.post(() -> shrink());
|
|
}
|
|
|
|
@Override
|
|
public void onLongClickCancel(final View view) {
|
|
itemView.post(() -> grow());
|
|
}
|
|
|
|
@Override
|
|
public void onLongClick(final View view, final float x, final float y) {
|
|
// if (longClickListener == null) return false;
|
|
// longClickListener.onLongClick(position, this);
|
|
itemView.post(() -> grow());
|
|
setSelected(true);
|
|
showLongClickOptions(new Point((int) x, (int) y), messageDirection);
|
|
}
|
|
});
|
|
}
|
|
|
|
private void showLongClickOptions(final Point location, final MessageDirection messageDirection) {
|
|
final List<DirectItemContextMenu.MenuItem> longClickOptions = getLongClickOptions();
|
|
final ImmutableList.Builder<DirectItemContextMenu.MenuItem> builder = ImmutableList.builder();
|
|
if (longClickOptions != null) {
|
|
builder.addAll(longClickOptions);
|
|
}
|
|
if (canForward()) {
|
|
builder.add(new DirectItemContextMenu.MenuItem(R.id.forward, R.string.forward));
|
|
}
|
|
if (thread.getInputMode() != 1 && messageDirection == MessageDirection.OUTGOING) {
|
|
builder.add(new DirectItemContextMenu.MenuItem(R.id.unsend, R.string.dms_inbox_unsend));
|
|
}
|
|
final boolean showReactions = thread.getInputMode() != 1 && allowReaction();
|
|
final ImmutableList<DirectItemContextMenu.MenuItem> menuItems = builder.build();
|
|
if (!showReactions && menuItems.isEmpty()) return;
|
|
final DirectItemContextMenu menu = new DirectItemContextMenu(itemView.getContext(), showReactions, menuItems);
|
|
menu.setOnDismissListener(() -> setSelected(false));
|
|
menu.setOnReactionClickListener(emoji -> callback.onReaction(item, emoji));
|
|
menu.setOnOptionSelectListener((itemId, cb) -> callback.onOptionSelect(item, itemId, cb));
|
|
menu.setOnAddReactionListener(() -> {
|
|
menu.dismiss();
|
|
itemView.postDelayed(() -> callback.onAddReactionListener(item), 300);
|
|
});
|
|
menu.show(itemView, location);
|
|
}
|
|
|
|
public void setLongClickListener(final DirectItemInternalLongClickListener longClickListener) {
|
|
this.longClickListener = longClickListener;
|
|
}
|
|
|
|
public void setSelected(final boolean selected) {
|
|
this.selected = selected;
|
|
}
|
|
|
|
private void shrink() {
|
|
if (shrinkGrowAnimator != null) {
|
|
shrinkGrowAnimator.cancel();
|
|
}
|
|
shrinkGrowAnimator = itemView.animate()
|
|
.scaleX(0.8f)
|
|
.scaleY(0.8f)
|
|
.setInterpolator(accelerateDecelerateInterpolator)
|
|
.setDuration(ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout());
|
|
shrinkGrowAnimator.start();
|
|
}
|
|
|
|
private void grow() {
|
|
if (shrinkGrowAnimator != null) {
|
|
shrinkGrowAnimator.cancel();
|
|
}
|
|
shrinkGrowAnimator = itemView.animate()
|
|
.scaleX(1f)
|
|
.scaleY(1f)
|
|
.setInterpolator(accelerateDecelerateInterpolator)
|
|
.setDuration(200)
|
|
.withEndAction(() -> shrinkGrowAnimator = null);
|
|
shrinkGrowAnimator.start();
|
|
}
|
|
|
|
@Override
|
|
public int getSwipeDirection() {
|
|
if (item == null || messageDirection == null) return ItemTouchHelper.ACTION_STATE_IDLE;
|
|
return messageDirection == MessageDirection.OUTGOING ? ItemTouchHelper.START : ItemTouchHelper.END;
|
|
}
|
|
|
|
public enum MessageDirection {
|
|
INCOMING,
|
|
OUTGOING
|
|
}
|
|
}
|