mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-22 22:57:29 +00:00
Allow removing like/reaction
This commit is contained in:
parent
255c3c84b4
commit
6a163454f4
@ -389,7 +389,9 @@ public final class DirectItemsAdapter extends RecyclerView.Adapter<RecyclerView.
|
|||||||
|
|
||||||
void onStoryClick(DirectItemStoryShare storyShare);
|
void onStoryClick(DirectItemStoryShare storyShare);
|
||||||
|
|
||||||
void onReaction(final DirectItem item, Emoji emoji);
|
void onReaction(DirectItem item, Emoji emoji);
|
||||||
|
|
||||||
|
void onReactionClick(DirectItem item, int position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface DirectItemInternalLongClickListener {
|
public interface DirectItemInternalLongClickListener {
|
||||||
|
@ -10,7 +10,7 @@ import androidx.recyclerview.widget.ListAdapter;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import awais.instagrabber.adapters.viewholder.DirectInboxItemViewHolder;
|
import awais.instagrabber.adapters.viewholder.directmessages.DirectInboxItemViewHolder;
|
||||||
import awais.instagrabber.databinding.LayoutDmInboxItemBinding;
|
import awais.instagrabber.databinding.LayoutDmInboxItemBinding;
|
||||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
package awais.instagrabber.adapters;
|
||||||
|
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.recyclerview.widget.DiffUtil;
|
||||||
|
import androidx.recyclerview.widget.ListAdapter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import awais.instagrabber.adapters.viewholder.directmessages.DirectReactionViewHolder;
|
||||||
|
import awais.instagrabber.databinding.LayoutDmUserItemBinding;
|
||||||
|
import awais.instagrabber.repositories.responses.User;
|
||||||
|
import awais.instagrabber.repositories.responses.directmessages.DirectItemEmojiReaction;
|
||||||
|
|
||||||
|
public final class DirectReactionsAdapter extends ListAdapter<DirectItemEmojiReaction, DirectReactionViewHolder> {
|
||||||
|
|
||||||
|
private static final DiffUtil.ItemCallback<DirectItemEmojiReaction> DIFF_CALLBACK = new DiffUtil.ItemCallback<DirectItemEmojiReaction>() {
|
||||||
|
@Override
|
||||||
|
public boolean areItemsTheSame(@NonNull final DirectItemEmojiReaction oldItem, @NonNull final DirectItemEmojiReaction newItem) {
|
||||||
|
return oldItem.getSenderId() == newItem.getSenderId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areContentsTheSame(@NonNull final DirectItemEmojiReaction oldItem, @NonNull final DirectItemEmojiReaction newItem) {
|
||||||
|
return oldItem.getEmoji().equals(newItem.getEmoji());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final long viewerId;
|
||||||
|
private final List<User> users;
|
||||||
|
private final String itemId;
|
||||||
|
private final OnReactionClickListener onReactionClickListener;
|
||||||
|
|
||||||
|
public DirectReactionsAdapter(final long viewerId,
|
||||||
|
final List<User> users,
|
||||||
|
final String itemId,
|
||||||
|
final OnReactionClickListener onReactionClickListener) {
|
||||||
|
super(DIFF_CALLBACK);
|
||||||
|
this.viewerId = viewerId;
|
||||||
|
this.users = users;
|
||||||
|
this.itemId = itemId;
|
||||||
|
this.onReactionClickListener = onReactionClickListener;
|
||||||
|
setHasStableIds(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public DirectReactionViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||||
|
final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
|
||||||
|
final LayoutDmUserItemBinding binding = LayoutDmUserItemBinding.inflate(layoutInflater, parent, false);
|
||||||
|
return new DirectReactionViewHolder(binding, viewerId, itemId, onReactionClickListener);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull final DirectReactionViewHolder holder, final int position) {
|
||||||
|
final DirectItemEmojiReaction reaction = getItem(position);
|
||||||
|
if (reaction == null) return;
|
||||||
|
holder.bind(reaction, getUser(reaction.getSenderId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(final int position) {
|
||||||
|
return getItem(position).getSenderId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private User getUser(final long pk) {
|
||||||
|
return users.stream()
|
||||||
|
.filter(user -> user.getPk() == pk)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnReactionClickListener {
|
||||||
|
void onReactionClick(String itemId, DirectItemEmojiReaction reaction);
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,7 @@ import com.google.common.collect.ImmutableList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
import awais.instagrabber.adapters.viewholder.DirectUserViewHolder;
|
import awais.instagrabber.adapters.viewholder.directmessages.DirectUserViewHolder;
|
||||||
import awais.instagrabber.databinding.ItemFavSectionHeaderBinding;
|
import awais.instagrabber.databinding.ItemFavSectionHeaderBinding;
|
||||||
import awais.instagrabber.databinding.LayoutDmUserItemBinding;
|
import awais.instagrabber.databinding.LayoutDmUserItemBinding;
|
||||||
import awais.instagrabber.repositories.responses.User;
|
import awais.instagrabber.repositories.responses.User;
|
||||||
|
@ -12,7 +12,7 @@ import java.util.List;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import awais.instagrabber.adapters.DirectUsersAdapter.OnDirectUserClickListener;
|
import awais.instagrabber.adapters.DirectUsersAdapter.OnDirectUserClickListener;
|
||||||
import awais.instagrabber.adapters.viewholder.DirectUserViewHolder;
|
import awais.instagrabber.adapters.viewholder.directmessages.DirectUserViewHolder;
|
||||||
import awais.instagrabber.databinding.LayoutDmUserItemBinding;
|
import awais.instagrabber.databinding.LayoutDmUserItemBinding;
|
||||||
import awais.instagrabber.repositories.responses.User;
|
import awais.instagrabber.repositories.responses.User;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package awais.instagrabber.adapters.viewholder;
|
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||||
|
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
import android.view.View;
|
import android.view.View;
|
@ -24,7 +24,6 @@ import androidx.transition.TransitionManager;
|
|||||||
import com.google.android.material.transition.MaterialFade;
|
import com.google.android.material.transition.MaterialFade;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import awais.instagrabber.R;
|
import awais.instagrabber.R;
|
||||||
@ -109,7 +108,7 @@ public abstract class DirectItemViewHolder extends RecyclerView.ViewHolder {
|
|||||||
public void bind(final int position, final DirectItem item) {
|
public void bind(final int position, final DirectItem item) {
|
||||||
this.item = item;
|
this.item = item;
|
||||||
final MessageDirection messageDirection = isSelf(item) ? MessageDirection.OUTGOING : MessageDirection.INCOMING;
|
final MessageDirection messageDirection = isSelf(item) ? MessageDirection.OUTGOING : MessageDirection.INCOMING;
|
||||||
itemView.post(() -> bindBase(item, messageDirection));
|
itemView.post(() -> bindBase(item, messageDirection, position));
|
||||||
itemView.post(() -> bindItem(item, messageDirection));
|
itemView.post(() -> bindItem(item, messageDirection));
|
||||||
itemView.post(() -> setupLongClickListener(position));
|
itemView.post(() -> setupLongClickListener(position));
|
||||||
// bindBase(item, messageDirection);
|
// bindBase(item, messageDirection);
|
||||||
@ -117,7 +116,7 @@ public abstract class DirectItemViewHolder extends RecyclerView.ViewHolder {
|
|||||||
// setupLongClickListener(position);
|
// setupLongClickListener(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void bindBase(final DirectItem item, final MessageDirection messageDirection) {
|
private void bindBase(final DirectItem item, final MessageDirection messageDirection, final int position) {
|
||||||
final FrameLayout.LayoutParams containerLayoutParams = (FrameLayout.LayoutParams) binding.container.getLayoutParams();
|
final FrameLayout.LayoutParams containerLayoutParams = (FrameLayout.LayoutParams) binding.container.getLayoutParams();
|
||||||
final DirectItemType itemType = item.getItemType();
|
final DirectItemType itemType = item.getItemType();
|
||||||
setMessageDirectionGravity(messageDirection, containerLayoutParams);
|
setMessageDirectionGravity(messageDirection, containerLayoutParams);
|
||||||
@ -134,7 +133,7 @@ public abstract class DirectItemViewHolder extends RecyclerView.ViewHolder {
|
|||||||
binding.messageInfo.setPadding(0, 0, messageInfoPaddingSmall, dmRadiusSmall);
|
binding.messageInfo.setPadding(0, 0, messageInfoPaddingSmall, dmRadiusSmall);
|
||||||
}
|
}
|
||||||
setupReply(item, messageDirection);
|
setupReply(item, messageDirection);
|
||||||
setReactions(item);
|
setReactions(item, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setBackground(final MessageDirection messageDirection) {
|
private void setBackground(final MessageDirection messageDirection) {
|
||||||
@ -334,7 +333,7 @@ public abstract class DirectItemViewHolder extends RecyclerView.ViewHolder {
|
|||||||
replyInfoLayoutParams.endToStart = isIncoming ? ConstraintLayout.LayoutParams.UNSET : quoteLineId;
|
replyInfoLayoutParams.endToStart = isIncoming ? ConstraintLayout.LayoutParams.UNSET : quoteLineId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setReactions(final DirectItem item) {
|
private void setReactions(final DirectItem item, final int position) {
|
||||||
binding.getRoot().post(() -> {
|
binding.getRoot().post(() -> {
|
||||||
MaterialFade materialFade = new MaterialFade();
|
MaterialFade materialFade = new MaterialFade();
|
||||||
materialFade.addTarget(binding.emojis);
|
materialFade.addTarget(binding.emojis);
|
||||||
@ -343,17 +342,27 @@ public abstract class DirectItemViewHolder extends RecyclerView.ViewHolder {
|
|||||||
final List<DirectItemEmojiReaction> emojis = reactions != null ? reactions.getEmojis() : null;
|
final List<DirectItemEmojiReaction> emojis = reactions != null ? reactions.getEmojis() : null;
|
||||||
if (emojis == null || emojis.isEmpty()) {
|
if (emojis == null || emojis.isEmpty()) {
|
||||||
binding.container.setPadding(messageInfoPaddingSmall, messageInfoPaddingSmall, messageInfoPaddingSmall, messageInfoPaddingSmall);
|
binding.container.setPadding(messageInfoPaddingSmall, messageInfoPaddingSmall, messageInfoPaddingSmall, messageInfoPaddingSmall);
|
||||||
binding.emojis.setVisibility(View.GONE);
|
binding.reactionsWrapper.setVisibility(View.GONE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
binding.emojis.setVisibility(View.VISIBLE);
|
binding.reactionsWrapper.setVisibility(View.VISIBLE);
|
||||||
binding.emojis.setTranslationY(getReactionsTranslationY());
|
binding.reactionsWrapper.setTranslationY(getReactionsTranslationY());
|
||||||
binding.container.setPadding(messageInfoPaddingSmall, messageInfoPaddingSmall, messageInfoPaddingSmall, reactionAdjustMargin);
|
binding.container.setPadding(messageInfoPaddingSmall, messageInfoPaddingSmall, messageInfoPaddingSmall, reactionAdjustMargin);
|
||||||
final String emojisJoined = emojis.stream()
|
binding.emojis.setEmojis(emojis.stream()
|
||||||
.map(DirectItemEmojiReaction::getEmoji)
|
.map(DirectItemEmojiReaction::getEmoji)
|
||||||
.collect(Collectors.joining());
|
.collect(Collectors.toList()));
|
||||||
final String text = String.format(Locale.ENGLISH, "%s %d", emojisJoined, emojis.size());
|
// binding.emojis.setEmojis(ImmutableList.of("😣",
|
||||||
binding.emojis.setText(text);
|
// "😖",
|
||||||
|
// "😫",
|
||||||
|
// "😩",
|
||||||
|
// "🥺",
|
||||||
|
// "😢",
|
||||||
|
// "😭",
|
||||||
|
// "😤",
|
||||||
|
// "😠",
|
||||||
|
// "😡",
|
||||||
|
// "🤬"));
|
||||||
|
binding.emojis.setOnClickListener(v -> callback.onReactionClick(item, position));
|
||||||
// final List<DirectUser> reactedUsers = emojis.stream()
|
// final List<DirectUser> reactedUsers = emojis.stream()
|
||||||
// .map(DirectItemEmojiReaction::getSenderId)
|
// .map(DirectItemEmojiReaction::getSenderId)
|
||||||
// .distinct()
|
// .distinct()
|
||||||
|
@ -0,0 +1,71 @@
|
|||||||
|
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import awais.instagrabber.R;
|
||||||
|
import awais.instagrabber.adapters.DirectReactionsAdapter.OnReactionClickListener;
|
||||||
|
import awais.instagrabber.customviews.emoji.Emoji;
|
||||||
|
import awais.instagrabber.databinding.LayoutDmUserItemBinding;
|
||||||
|
import awais.instagrabber.repositories.responses.User;
|
||||||
|
import awais.instagrabber.repositories.responses.directmessages.DirectItemEmojiReaction;
|
||||||
|
import awais.instagrabber.utils.emoji.EmojiParser;
|
||||||
|
|
||||||
|
public class DirectReactionViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
private final LayoutDmUserItemBinding binding;
|
||||||
|
private final long viewerId;
|
||||||
|
private final String itemId;
|
||||||
|
private final OnReactionClickListener onReactionClickListener;
|
||||||
|
private final EmojiParser emojiParser;
|
||||||
|
|
||||||
|
public DirectReactionViewHolder(final LayoutDmUserItemBinding binding,
|
||||||
|
final long viewerId,
|
||||||
|
final String itemId,
|
||||||
|
final OnReactionClickListener onReactionClickListener) {
|
||||||
|
super(binding.getRoot());
|
||||||
|
this.binding = binding;
|
||||||
|
this.viewerId = viewerId;
|
||||||
|
this.itemId = itemId;
|
||||||
|
this.onReactionClickListener = onReactionClickListener;
|
||||||
|
binding.info.setVisibility(View.GONE);
|
||||||
|
binding.secondaryImage.setVisibility(View.VISIBLE);
|
||||||
|
emojiParser = EmojiParser.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bind(final DirectItemEmojiReaction reaction,
|
||||||
|
@Nullable final User user) {
|
||||||
|
itemView.setOnClickListener(v -> {
|
||||||
|
if (onReactionClickListener == null) return;
|
||||||
|
onReactionClickListener.onReactionClick(itemId, reaction);
|
||||||
|
});
|
||||||
|
setUser(user);
|
||||||
|
setReaction(reaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setReaction(final DirectItemEmojiReaction reaction) {
|
||||||
|
final Emoji emoji = emojiParser.getEmoji(reaction.getEmoji());
|
||||||
|
if (emoji == null) {
|
||||||
|
binding.secondaryImage.setImageDrawable(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
binding.secondaryImage.setImageDrawable(emoji.getDrawable());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setUser(final User user) {
|
||||||
|
if (user == null) {
|
||||||
|
binding.fullName.setText("");
|
||||||
|
binding.username.setText("");
|
||||||
|
binding.profilePic.setImageURI((String) null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
binding.fullName.setText(user.getFullName());
|
||||||
|
if (user.getPk() == viewerId) {
|
||||||
|
binding.username.setText(R.string.tap_to_remove);
|
||||||
|
} else {
|
||||||
|
binding.username.setText(user.getUsername());
|
||||||
|
}
|
||||||
|
binding.profilePic.setImageURI(user.getProfilePicUrl());
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package awais.instagrabber.adapters.viewholder;
|
package awais.instagrabber.adapters.viewholder.directmessages;
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
@ -0,0 +1,82 @@
|
|||||||
|
package awais.instagrabber.customviews;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
import android.text.SpannableStringBuilder;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.emoji.widget.EmojiAppCompatTextView;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ReactionEmojiTextView extends EmojiAppCompatTextView {
|
||||||
|
private static final String TAG = ReactionEmojiTextView.class.getSimpleName();
|
||||||
|
|
||||||
|
private final SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
|
||||||
|
|
||||||
|
private String count = "";
|
||||||
|
private SpannableString ellipsisSpannable;
|
||||||
|
private String distinctEmojis;
|
||||||
|
|
||||||
|
public ReactionEmojiTextView(final Context context) {
|
||||||
|
super(context);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReactionEmojiTextView(final Context context, final AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReactionEmojiTextView(final Context context, final AttributeSet attrs, final int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
ellipsisSpannable = new SpannableString(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
|
public void setEmojis(@NonNull final List<String> emojis) {
|
||||||
|
count = String.valueOf(emojis.size());
|
||||||
|
distinctEmojis = emojis.stream()
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.joining());
|
||||||
|
ellipsisSpannable = new SpannableString(count);
|
||||||
|
setText(distinctEmojis + (emojis.size() > 1 ? count : ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
final CharSequence text = getText();
|
||||||
|
if (text == null) return;
|
||||||
|
final int measuredWidth = getMeasuredWidth();
|
||||||
|
float availableTextWidth = measuredWidth - getCompoundPaddingLeft() - getCompoundPaddingRight();
|
||||||
|
CharSequence ellipsizedText = TextUtils.ellipsize(text, getPaint(), availableTextWidth, getEllipsize());
|
||||||
|
if (!ellipsizedText.toString().equals(text.toString())) {
|
||||||
|
// If the ellipsizedText is different than the original text, this means that it didn't fit and got indeed ellipsized.
|
||||||
|
// Calculate the new availableTextWidth by taking into consideration the size of the custom ellipsis, too.
|
||||||
|
availableTextWidth = (availableTextWidth - getPaint().measureText(count));
|
||||||
|
ellipsizedText = TextUtils.ellipsize(text, getPaint(), availableTextWidth, getEllipsize());
|
||||||
|
final int defaultEllipsisStart = ellipsizedText.toString().indexOf(getDefaultEllipsis());
|
||||||
|
final int defaultEllipsisEnd = defaultEllipsisStart + 1;
|
||||||
|
spannableStringBuilder.clear();
|
||||||
|
// Update the text with the ellipsized version and replace the default ellipsis with the custom one.
|
||||||
|
final SpannableStringBuilder replace = spannableStringBuilder.append(ellipsizedText)
|
||||||
|
.replace(defaultEllipsisStart, defaultEllipsisEnd, ellipsisSpannable);
|
||||||
|
setText(replace);
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private char getDefaultEllipsis() {
|
||||||
|
return '…';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,121 @@
|
|||||||
|
package awais.instagrabber.dialogs;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import awais.instagrabber.R;
|
||||||
|
import awais.instagrabber.adapters.DirectReactionsAdapter;
|
||||||
|
import awais.instagrabber.adapters.DirectReactionsAdapter.OnReactionClickListener;
|
||||||
|
import awais.instagrabber.repositories.responses.User;
|
||||||
|
import awais.instagrabber.repositories.responses.directmessages.DirectItemReactions;
|
||||||
|
import awais.instagrabber.utils.TextUtils;
|
||||||
|
|
||||||
|
public class DirectItemReactionDialogFragment extends BottomSheetDialogFragment {
|
||||||
|
|
||||||
|
private static final String ARG_VIEWER_ID = "viewerId";
|
||||||
|
private static final String ARG_ITEM_ID = "itemId";
|
||||||
|
private static final String ARG_USERS = "users";
|
||||||
|
private static final String ARG_REACTIONS = "reactions";
|
||||||
|
|
||||||
|
private RecyclerView recyclerView;
|
||||||
|
private OnReactionClickListener onReactionClickListener;
|
||||||
|
|
||||||
|
public static DirectItemReactionDialogFragment newInstance(final long viewerId,
|
||||||
|
@NonNull final ArrayList<User> users,
|
||||||
|
@NonNull final String itemId,
|
||||||
|
@NonNull final DirectItemReactions reactions) {
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putLong(ARG_VIEWER_ID, viewerId);
|
||||||
|
args.putSerializable(ARG_USERS, users);
|
||||||
|
args.putString(ARG_ITEM_ID, itemId);
|
||||||
|
args.putSerializable(ARG_REACTIONS, reactions);
|
||||||
|
DirectItemReactionDialogFragment fragment = new DirectItemReactionDialogFragment();
|
||||||
|
fragment.setArguments(args);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DirectItemReactionDialogFragment() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setStyle(DialogFragment.STYLE_NORMAL, R.style.ThemeOverlay_Rounded_BottomSheetDialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) {
|
||||||
|
final Context context = getContext();
|
||||||
|
if (context == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
recyclerView = new RecyclerView(context);
|
||||||
|
return recyclerView;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(@NonNull final Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
try {
|
||||||
|
onReactionClickListener = (OnReactionClickListener) getParentFragment();
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
throw new ClassCastException("Calling fragment must implement DirectReactionsAdapter.OnReactionClickListener interface");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
final Dialog dialog = getDialog();
|
||||||
|
if (dialog == null) return;
|
||||||
|
final BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialog;
|
||||||
|
final View bottomSheetInternal = bottomSheetDialog.findViewById(com.google.android.material.R.id.design_bottom_sheet);
|
||||||
|
if (bottomSheetInternal == null) return;
|
||||||
|
bottomSheetInternal.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
bottomSheetInternal.requestLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
final Context context = getContext();
|
||||||
|
if (context == null) return;
|
||||||
|
final Bundle arguments = getArguments();
|
||||||
|
if (arguments == null) return;
|
||||||
|
final long viewerId = arguments.getLong(ARG_VIEWER_ID);
|
||||||
|
final Serializable usersSerializable = arguments.getSerializable(ARG_USERS);
|
||||||
|
if (!(usersSerializable instanceof ArrayList)) return;
|
||||||
|
//noinspection unchecked
|
||||||
|
final List<User> users = (ArrayList<User>) usersSerializable;
|
||||||
|
final Serializable reactionsSerializable = arguments.getSerializable(ARG_REACTIONS);
|
||||||
|
if (!(reactionsSerializable instanceof DirectItemReactions)) return;
|
||||||
|
final DirectItemReactions reactions = (DirectItemReactions) reactionsSerializable;
|
||||||
|
final String itemId = arguments.getString(ARG_ITEM_ID);
|
||||||
|
if (TextUtils.isEmpty(itemId)) return;
|
||||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(context));
|
||||||
|
final DirectReactionsAdapter adapter = new DirectReactionsAdapter(viewerId, users, itemId, onReactionClickListener);
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
adapter.submitList(reactions.getEmojis());
|
||||||
|
}
|
||||||
|
}
|
@ -50,6 +50,7 @@ import com.google.android.material.snackbar.Snackbar;
|
|||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@ -60,6 +61,7 @@ import awais.instagrabber.adapters.DirectItemsAdapter;
|
|||||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemCallback;
|
||||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemLongClickListener;
|
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemLongClickListener;
|
||||||
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemOrHeader;
|
import awais.instagrabber.adapters.DirectItemsAdapter.DirectItemOrHeader;
|
||||||
|
import awais.instagrabber.adapters.DirectReactionsAdapter;
|
||||||
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemViewHolder;
|
import awais.instagrabber.adapters.viewholder.directmessages.DirectItemViewHolder;
|
||||||
import awais.instagrabber.animations.CubicBezierInterpolator;
|
import awais.instagrabber.animations.CubicBezierInterpolator;
|
||||||
import awais.instagrabber.customviews.RecordView;
|
import awais.instagrabber.customviews.RecordView;
|
||||||
@ -70,6 +72,7 @@ import awais.instagrabber.customviews.helpers.HeightProvider;
|
|||||||
import awais.instagrabber.customviews.helpers.RecyclerLazyLoaderAtEdge;
|
import awais.instagrabber.customviews.helpers.RecyclerLazyLoaderAtEdge;
|
||||||
import awais.instagrabber.customviews.helpers.TextWatcherAdapter;
|
import awais.instagrabber.customviews.helpers.TextWatcherAdapter;
|
||||||
import awais.instagrabber.databinding.FragmentDirectMessagesThreadBinding;
|
import awais.instagrabber.databinding.FragmentDirectMessagesThreadBinding;
|
||||||
|
import awais.instagrabber.dialogs.DirectItemReactionDialogFragment;
|
||||||
import awais.instagrabber.dialogs.MediaPickerBottomDialogFragment;
|
import awais.instagrabber.dialogs.MediaPickerBottomDialogFragment;
|
||||||
import awais.instagrabber.fragments.PostViewV2Fragment;
|
import awais.instagrabber.fragments.PostViewV2Fragment;
|
||||||
import awais.instagrabber.models.Resource;
|
import awais.instagrabber.models.Resource;
|
||||||
@ -77,6 +80,7 @@ import awais.instagrabber.repositories.requests.StoryViewerOptions;
|
|||||||
import awais.instagrabber.repositories.responses.Media;
|
import awais.instagrabber.repositories.responses.Media;
|
||||||
import awais.instagrabber.repositories.responses.User;
|
import awais.instagrabber.repositories.responses.User;
|
||||||
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
import awais.instagrabber.repositories.responses.directmessages.DirectItem;
|
||||||
|
import awais.instagrabber.repositories.responses.directmessages.DirectItemEmojiReaction;
|
||||||
import awais.instagrabber.repositories.responses.directmessages.DirectItemStoryShare;
|
import awais.instagrabber.repositories.responses.directmessages.DirectItemStoryShare;
|
||||||
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
import awais.instagrabber.repositories.responses.directmessages.DirectThread;
|
||||||
import awais.instagrabber.utils.AppExecutors;
|
import awais.instagrabber.utils.AppExecutors;
|
||||||
@ -90,7 +94,7 @@ import awais.instagrabber.viewmodels.DirectThreadViewModel;
|
|||||||
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
|
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
|
||||||
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
|
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
|
||||||
|
|
||||||
public class DirectMessageThreadFragment extends Fragment {
|
public class DirectMessageThreadFragment extends Fragment implements DirectReactionsAdapter.OnReactionClickListener {
|
||||||
private static final String TAG = DirectMessageThreadFragment.class.getSimpleName();
|
private static final String TAG = DirectMessageThreadFragment.class.getSimpleName();
|
||||||
private static final int STORAGE_PERM_REQUEST_CODE = 8020;
|
private static final int STORAGE_PERM_REQUEST_CODE = 8020;
|
||||||
private static final int AUDIO_RECORD_PERM_REQUEST_CODE = 1000;
|
private static final int AUDIO_RECORD_PERM_REQUEST_CODE = 1000;
|
||||||
@ -145,9 +149,7 @@ public class DirectMessageThreadFragment extends Fragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMentionClick(final String mention) {
|
public void onMentionClick(final String mention) {
|
||||||
final Bundle bundle = new Bundle();
|
navigateToUser(mention);
|
||||||
bundle.putString("username", "@" + mention);
|
|
||||||
NavHostFragment.findNavController(DirectMessageThreadFragment.this).navigate(R.id.action_global_profileFragment, bundle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -215,10 +217,17 @@ public class DirectMessageThreadFragment extends Fragment {
|
|||||||
resourceLiveData.observe(getViewLifecycleOwner(), directItemResource -> handleSentMessage(resourceLiveData));
|
resourceLiveData.observe(getViewLifecycleOwner(), directItemResource -> handleSentMessage(resourceLiveData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReactionClick(final DirectItem item, final int position) {
|
||||||
|
showReactionsDialog(item);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final DirectItemLongClickListener directItemLongClickListener = position -> {
|
private final DirectItemLongClickListener directItemLongClickListener = position -> {
|
||||||
// viewModel.setSelectedPosition(position);
|
// viewModel.setSelectedPosition(position);
|
||||||
};
|
};
|
||||||
|
private DirectItemReactionDialogFragment reactionDialogFragment;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
@ -1132,6 +1141,50 @@ public class DirectMessageThreadFragment extends Fragment {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showReactionsDialog(final DirectItem item) {
|
||||||
|
final LiveData<List<User>> users = viewModel.getUsers();
|
||||||
|
final LiveData<List<User>> leftUsers = viewModel.getLeftUsers();
|
||||||
|
final ArrayList<User> allUsers = new ArrayList<>();
|
||||||
|
allUsers.add(viewModel.getCurrentUser());
|
||||||
|
if (users != null && users.getValue() != null) {
|
||||||
|
allUsers.addAll(users.getValue());
|
||||||
|
}
|
||||||
|
if (leftUsers != null && leftUsers.getValue() != null) {
|
||||||
|
allUsers.addAll(leftUsers.getValue());
|
||||||
|
}
|
||||||
|
reactionDialogFragment = DirectItemReactionDialogFragment
|
||||||
|
.newInstance(viewModel.getViewerId(),
|
||||||
|
allUsers,
|
||||||
|
item.getItemId(),
|
||||||
|
item.getReactions());
|
||||||
|
reactionDialogFragment.show(getChildFragmentManager(), "reactions_dialog");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReactionClick(final String itemId, final DirectItemEmojiReaction reaction) {
|
||||||
|
if (reactionDialogFragment != null) {
|
||||||
|
reactionDialogFragment.dismiss();
|
||||||
|
}
|
||||||
|
if (reaction == null) return;
|
||||||
|
if (reaction.getSenderId() == viewModel.getViewerId()) {
|
||||||
|
final LiveData<Resource<DirectItem>> resourceLiveData = viewModel.sendDeleteReaction(itemId);
|
||||||
|
if (resourceLiveData != null) {
|
||||||
|
resourceLiveData.observe(getViewLifecycleOwner(), directItemResource -> handleSentMessage(resourceLiveData));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// navigate to user
|
||||||
|
final User user = viewModel.getUser(reaction.getSenderId());
|
||||||
|
if (user == null) return;
|
||||||
|
navigateToUser(user.getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void navigateToUser(@NonNull final String username) {
|
||||||
|
final Bundle bundle = new Bundle();
|
||||||
|
bundle.putString("username", "@" + username);
|
||||||
|
NavHostFragment.findNavController(DirectMessageThreadFragment.this).navigate(R.id.action_global_profileFragment, bundle);
|
||||||
|
}
|
||||||
|
|
||||||
public static class ItemsAdapterDataMerger extends MediatorLiveData<Pair<User, DirectThread>> {
|
public static class ItemsAdapterDataMerger extends MediatorLiveData<Pair<User, DirectThread>> {
|
||||||
private User user;
|
private User user;
|
||||||
private DirectThread thread;
|
private DirectThread thread;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package awais.instagrabber.repositories.responses.directmessages;
|
package awais.instagrabber.repositories.responses.directmessages;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class DirectItemEmojiReaction {
|
public class DirectItemEmojiReaction implements Serializable {
|
||||||
private final long senderId;
|
private final long senderId;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private final String emoji;
|
private final String emoji;
|
||||||
|
@ -2,10 +2,11 @@ package awais.instagrabber.repositories.responses.directmessages;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class DirectItemReactions implements Cloneable {
|
public class DirectItemReactions implements Cloneable, Serializable {
|
||||||
private List<DirectItemEmojiReaction> emojis;
|
private List<DirectItemEmojiReaction> emojis;
|
||||||
private List<DirectItemEmojiReaction> likes;
|
private List<DirectItemEmojiReaction> likes;
|
||||||
|
|
||||||
|
@ -270,6 +270,13 @@ public final class EmojiParser {
|
|||||||
return ALL_EMOJIS;
|
return ALL_EMOJIS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Emoji getEmoji(final String emoji) {
|
||||||
|
if (emoji == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return ALL_EMOJIS.get(emoji);
|
||||||
|
}
|
||||||
|
|
||||||
// public String getMinorCategory(String emoji) {
|
// public String getMinorCategory(String emoji) {
|
||||||
// String minorCat = emojiToMinorCategory.get(emoji);
|
// String minorCat = emojiToMinorCategory.get(emoji);
|
||||||
// if (minorCat == null) {
|
// if (minorCat == null) {
|
||||||
|
@ -77,6 +77,7 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
private final MutableLiveData<String> threadTitle = new MutableLiveData<>("");
|
private final MutableLiveData<String> threadTitle = new MutableLiveData<>("");
|
||||||
private final MutableLiveData<Boolean> fetching = new MutableLiveData<>(false);
|
private final MutableLiveData<Boolean> fetching = new MutableLiveData<>(false);
|
||||||
private final MutableLiveData<List<User>> users = new MutableLiveData<>(new ArrayList<>());
|
private final MutableLiveData<List<User>> users = new MutableLiveData<>(new ArrayList<>());
|
||||||
|
private final MutableLiveData<List<User>> leftUsers = new MutableLiveData<>(new ArrayList<>());
|
||||||
|
|
||||||
private final DirectMessagesService service;
|
private final DirectMessagesService service;
|
||||||
private final ContentResolver contentResolver;
|
private final ContentResolver contentResolver;
|
||||||
@ -92,18 +93,19 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
private User currentUser;
|
private User currentUser;
|
||||||
private Call<DirectThreadFeedResponse> chatsRequest;
|
private Call<DirectThreadFeedResponse> chatsRequest;
|
||||||
private VoiceRecorder voiceRecorder;
|
private VoiceRecorder voiceRecorder;
|
||||||
|
private final long viewerId;
|
||||||
|
|
||||||
public DirectThreadViewModel(@NonNull final Application application) {
|
public DirectThreadViewModel(@NonNull final Application application) {
|
||||||
super(application);
|
super(application);
|
||||||
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
final String cookie = settingsHelper.getString(Constants.COOKIE);
|
||||||
final long userId = CookieUtils.getUserIdFromCookie(cookie);
|
viewerId = CookieUtils.getUserIdFromCookie(cookie);
|
||||||
final String deviceUuid = settingsHelper.getString(Constants.DEVICE_UUID);
|
final String deviceUuid = settingsHelper.getString(Constants.DEVICE_UUID);
|
||||||
csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
csrfToken = CookieUtils.getCsrfTokenFromCookie(cookie);
|
||||||
if (TextUtils.isEmpty(csrfToken) || userId <= 0 || TextUtils.isEmpty(deviceUuid)) {
|
if (TextUtils.isEmpty(csrfToken) || viewerId <= 0 || TextUtils.isEmpty(deviceUuid)) {
|
||||||
throw new IllegalArgumentException("User is not logged in!");
|
throw new IllegalArgumentException("User is not logged in!");
|
||||||
}
|
}
|
||||||
service = DirectMessagesService.getInstance(csrfToken, userId, deviceUuid);
|
service = DirectMessagesService.getInstance(csrfToken, viewerId, deviceUuid);
|
||||||
mediaService = MediaService.getInstance(deviceUuid, csrfToken, userId);
|
mediaService = MediaService.getInstance(deviceUuid, csrfToken, viewerId);
|
||||||
contentResolver = application.getContentResolver();
|
contentResolver = application.getContentResolver();
|
||||||
recordingsDir = DirectoryUtils.getOutputMediaDirectory(application, "Recordings");
|
recordingsDir = DirectoryUtils.getOutputMediaDirectory(application, "Recordings");
|
||||||
this.application = application;
|
this.application = application;
|
||||||
@ -138,6 +140,10 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getViewerId() {
|
||||||
|
return viewerId;
|
||||||
|
}
|
||||||
|
|
||||||
public void setItems(final List<DirectItem> items) {
|
public void setItems(final List<DirectItem> items) {
|
||||||
this.items.postValue(items);
|
this.items.postValue(items);
|
||||||
}
|
}
|
||||||
@ -219,13 +225,53 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
"none"
|
"none"
|
||||||
);
|
);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
temp.add(reaction);
|
temp.add(0, reaction);
|
||||||
} else if (shouldReplaceIfAlreadyReacted) {
|
} else if (shouldReplaceIfAlreadyReacted) {
|
||||||
temp.set(index, reaction);
|
temp.add(0, reaction);
|
||||||
|
temp.remove(index);
|
||||||
}
|
}
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void removeReaction(final DirectItem item) {
|
||||||
|
try {
|
||||||
|
final DirectItem itemClone = (DirectItem) item.clone();
|
||||||
|
final DirectItemReactions reactions = itemClone.getReactions();
|
||||||
|
final DirectItemReactions reactionsClone = (DirectItemReactions) reactions.clone();
|
||||||
|
final List<DirectItemEmojiReaction> likes = reactionsClone.getLikes();
|
||||||
|
if (likes != null) {
|
||||||
|
final List<DirectItemEmojiReaction> updatedLikes = likes.stream()
|
||||||
|
.filter(like -> like.getSenderId() != viewerId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
reactionsClone.setLikes(updatedLikes);
|
||||||
|
}
|
||||||
|
final List<DirectItemEmojiReaction> emojis = reactionsClone.getEmojis();
|
||||||
|
if (emojis != null) {
|
||||||
|
final List<DirectItemEmojiReaction> updatedEmojis = emojis.stream()
|
||||||
|
.filter(emoji -> emoji.getSenderId() != viewerId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
reactionsClone.setEmojis(updatedEmojis);
|
||||||
|
}
|
||||||
|
itemClone.setReactions(reactionsClone);
|
||||||
|
List<DirectItem> list = this.items.getValue();
|
||||||
|
list = list == null ? new LinkedList<>() : new LinkedList<>(list);
|
||||||
|
int index = -1;
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
final DirectItem directItem = list.get(i);
|
||||||
|
if (directItem.getItemId().equals(item.getItemId())) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index >= 0) {
|
||||||
|
list.set(index, itemClone);
|
||||||
|
}
|
||||||
|
this.items.postValue(list);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "removeReaction: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void updateItemSent(final String clientContext, final long timestamp) {
|
private void updateItemSent(final String clientContext, final long timestamp) {
|
||||||
if (clientContext == null) return;
|
if (clientContext == null) return;
|
||||||
List<DirectItem> list = this.items.getValue();
|
List<DirectItem> list = this.items.getValue();
|
||||||
@ -259,6 +305,10 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LiveData<List<User>> getLeftUsers() {
|
||||||
|
return leftUsers;
|
||||||
|
}
|
||||||
|
|
||||||
public void fetchChats() {
|
public void fetchChats() {
|
||||||
final Boolean isFetching = fetching.getValue();
|
final Boolean isFetching = fetching.getValue();
|
||||||
if ((isFetching != null && isFetching) || !hasOlder) return;
|
if ((isFetching != null && isFetching) || !hasOlder) return;
|
||||||
@ -319,9 +369,8 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
threadTitle.postValue(thread.getThreadTitle());
|
threadTitle.postValue(thread.getThreadTitle());
|
||||||
cursor = thread.getOldestCursor();
|
cursor = thread.getOldestCursor();
|
||||||
hasOlder = thread.hasOlder();
|
hasOlder = thread.hasOlder();
|
||||||
if (users.getValue() == null || users.getValue().isEmpty()) {
|
|
||||||
users.postValue(thread.getUsers());
|
users.postValue(thread.getUsers());
|
||||||
}
|
leftUsers.postValue(thread.getLeftUsers());
|
||||||
fetching.postValue(false);
|
fetching.postValue(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -637,6 +686,33 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
}
|
}
|
||||||
final Call<DirectThreadBroadcastResponse> request = service.broadcastReaction(
|
final Call<DirectThreadBroadcastResponse> request = service.broadcastReaction(
|
||||||
clientContext, threadIdOrUserIds, item.getItemId(), emojiUnicode, false);
|
clientContext, threadIdOrUserIds, item.getItemId(), emojiUnicode, false);
|
||||||
|
handleBroadcastReactionRequest(data, item, request);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveData<Resource<DirectItem>> sendDeleteReaction(final String itemId) {
|
||||||
|
final MutableLiveData<Resource<DirectItem>> data = new MutableLiveData<>();
|
||||||
|
final DirectItem item = getItem(itemId);
|
||||||
|
if (item == null) {
|
||||||
|
data.postValue(Resource.error("Invalid item", null));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
final DirectItemReactions reactions = item.getReactions();
|
||||||
|
if (reactions == null) {
|
||||||
|
// already removed?
|
||||||
|
data.postValue(Resource.success(item));
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
removeReaction(item);
|
||||||
|
final String clientContext = UUID.randomUUID().toString();
|
||||||
|
final Call<DirectThreadBroadcastResponse> request = service.broadcastReaction(clientContext, threadIdOrUserIds, item.getItemId(), null, true);
|
||||||
|
handleBroadcastReactionRequest(data, item, request);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleBroadcastReactionRequest(final MutableLiveData<Resource<DirectItem>> data,
|
||||||
|
final DirectItem item,
|
||||||
|
@NonNull final Call<DirectThreadBroadcastResponse> request) {
|
||||||
request.enqueue(new Callback<DirectThreadBroadcastResponse>() {
|
request.enqueue(new Callback<DirectThreadBroadcastResponse>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(@NonNull final Call<DirectThreadBroadcastResponse> call,
|
public void onResponse(@NonNull final Call<DirectThreadBroadcastResponse> call,
|
||||||
@ -662,13 +738,51 @@ public class DirectThreadViewModel extends AndroidViewModel {
|
|||||||
Log.e(TAG, "enqueueRequest: onFailure: ", t);
|
Log.e(TAG, "enqueueRequest: onFailure: ", t);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return data;
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private DirectItem getItem(final String itemId) {
|
||||||
|
if (itemId == null) return null;
|
||||||
|
final List<DirectItem> items = this.items.getValue();
|
||||||
|
if (items == null) return null;
|
||||||
|
return items.stream()
|
||||||
|
.filter(directItem -> directItem.getItemId().equals(itemId))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public User getCurrentUser() {
|
||||||
|
return currentUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentUser(final User currentUser) {
|
public void setCurrentUser(final User currentUser) {
|
||||||
this.currentUser = currentUser;
|
this.currentUser = currentUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public User getUser(final long userId) {
|
||||||
|
final LiveData<List<User>> users = getUsers();
|
||||||
|
User match = null;
|
||||||
|
if (users != null && users.getValue() != null) {
|
||||||
|
final List<User> userList = users.getValue();
|
||||||
|
match = userList.stream()
|
||||||
|
.filter(user -> user.getPk() == userId)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
if (match == null) {
|
||||||
|
final LiveData<List<User>> leftUsers = getLeftUsers();
|
||||||
|
if (leftUsers != null && leftUsers.getValue() != null) {
|
||||||
|
final List<User> userList = leftUsers.getValue();
|
||||||
|
match = userList.stream()
|
||||||
|
.filter(user -> user.getPk() == userId)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
private void enqueueRequest(@NonNull final Call<DirectThreadBroadcastResponse> request,
|
private void enqueueRequest(@NonNull final Call<DirectThreadBroadcastResponse> request,
|
||||||
@NonNull final MutableLiveData<Resource<DirectItem>> data,
|
@NonNull final MutableLiveData<Resource<DirectItem>> data,
|
||||||
@NonNull final DirectItem directItem) {
|
@NonNull final DirectItem directItem) {
|
||||||
|
@ -173,28 +173,34 @@
|
|||||||
|
|
||||||
</awais.instagrabber.customviews.ChatMessageLayout>
|
</awais.instagrabber.customviews.ChatMessageLayout>
|
||||||
|
|
||||||
<androidx.emoji.widget.EmojiAppCompatTextView
|
<FrameLayout
|
||||||
android:id="@+id/emojis"
|
android:id="@+id/reactions_wrapper"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="4dp"
|
android:layout_marginStart="4dp"
|
||||||
android:layout_marginBottom="4dp"
|
android:layout_marginBottom="4dp"
|
||||||
android:background="@drawable/bg_rounded_corner"
|
android:paddingBottom="2dp"
|
||||||
android:elevation="1dp"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:padding="4dp"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
|
||||||
android:textSize="18sp"
|
|
||||||
android:translationY="@dimen/dm_reaction_translation_y_type_1"
|
android:translationY="@dimen/dm_reaction_translation_y_type_1"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0"
|
|
||||||
app:layout_constraintStart_toStartOf="@id/chat_message_layout"
|
app:layout_constraintStart_toStartOf="@id/chat_message_layout"
|
||||||
app:layout_constraintTop_toBottomOf="parent"
|
app:layout_constraintTop_toBottomOf="parent"
|
||||||
app:layout_constraintWidth_max="wrap"
|
tools:visibility="visible">
|
||||||
tools:text="😀"
|
|
||||||
tools:visibility="visible" />
|
<awais.instagrabber.customviews.ReactionEmojiTextView
|
||||||
|
android:id="@+id/emojis"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_rounded_corner"
|
||||||
|
android:elevation="1dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:padding="4dp"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textColor="?android:textColorPrimary"
|
||||||
|
android:textSize="18sp"
|
||||||
|
tools:text="😀😀😀😀😀😀😀" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
<!--<FrameLayout-->
|
<!--<FrameLayout-->
|
||||||
<!-- android:id="@+id/reactions"-->
|
<!-- android:id="@+id/reactions"-->
|
||||||
|
@ -78,12 +78,26 @@
|
|||||||
android:duplicateParentState="true"
|
android:duplicateParentState="true"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/profile_pic"
|
app:layout_constraintBottom_toBottomOf="@id/profile_pic"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toStartOf="@id/secondary_image"
|
||||||
app:layout_constraintStart_toEndOf="@id/info"
|
app:layout_constraintStart_toEndOf="@id/info"
|
||||||
app:layout_constraintTop_toTopOf="@id/profile_pic"
|
app:layout_constraintTop_toTopOf="@id/profile_pic"
|
||||||
app:srcCompat="@drawable/ic_circle_check"
|
app:srcCompat="@drawable/ic_circle_check"
|
||||||
app:tint="@color/ic_circle_check_tint"
|
app:tint="@color/ic_circle_check_tint"
|
||||||
tools:visibility="visible" />
|
tools:visibility="gone" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/secondary_image"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/profile_pic"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/select"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/profile_pic"
|
||||||
|
tools:srcCompat="@mipmap/ic_launcher"
|
||||||
|
tools:visibility="gone" />
|
||||||
|
|
||||||
<include
|
<include
|
||||||
layout="@layout/item_pref_divider"
|
layout="@layout/item_pref_divider"
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
<dimen name="dm_message_item_margin">80dp</dimen>
|
<dimen name="dm_message_item_margin">80dp</dimen>
|
||||||
<dimen name="dm_message_item_avatar_size">48dp</dimen>
|
<dimen name="dm_message_item_avatar_size">48dp</dimen>
|
||||||
<dimen name="dm_message_info_padding_small">4dp</dimen>
|
<dimen name="dm_message_info_padding_small">4dp</dimen>
|
||||||
<dimen name="dm_reaction_adjust_margin">22dp</dimen>
|
<dimen name="dm_reaction_adjust_margin">24dp</dimen>
|
||||||
<dimen name="dm_reaction_translation_y_type_1">6dp</dimen>
|
<dimen name="dm_reaction_translation_y_type_1">6dp</dimen>
|
||||||
<dimen name="dm_reaction_translation_y_type_2">-12dp</dimen>
|
<dimen name="dm_reaction_translation_y_type_2">-12dp</dimen>
|
||||||
|
|
||||||
|
@ -397,4 +397,5 @@
|
|||||||
<string name="edit_unsuccessful">Edit was unsuccessful</string>
|
<string name="edit_unsuccessful">Edit was unsuccessful</string>
|
||||||
<string name="message">Message</string>
|
<string name="message">Message</string>
|
||||||
<string name="reply">Reply</string>
|
<string name="reply">Reply</string>
|
||||||
|
<string name="tap_to_remove">Tap to remove</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user