Ammar Githam
4 years ago
20 changed files with 613 additions and 50 deletions
-
4app/src/main/java/awais/instagrabber/adapters/DirectItemsAdapter.java
-
2app/src/main/java/awais/instagrabber/adapters/DirectMessageInboxAdapter.java
-
81app/src/main/java/awais/instagrabber/adapters/DirectReactionsAdapter.java
-
2app/src/main/java/awais/instagrabber/adapters/DirectUsersAdapter.java
-
2app/src/main/java/awais/instagrabber/adapters/UserSearchResultsAdapter.java
-
2app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectInboxItemViewHolder.java
-
35app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectItemViewHolder.java
-
71app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectReactionViewHolder.java
-
2app/src/main/java/awais/instagrabber/adapters/viewholder/directmessages/DirectUserViewHolder.java
-
82app/src/main/java/awais/instagrabber/customviews/ReactionEmojiTextView.java
-
121app/src/main/java/awais/instagrabber/dialogs/DirectItemReactionDialogFragment.java
-
61app/src/main/java/awais/instagrabber/fragments/directmessages/DirectMessageThreadFragment.java
-
3app/src/main/java/awais/instagrabber/repositories/responses/directmessages/DirectItemEmojiReaction.java
-
3app/src/main/java/awais/instagrabber/repositories/responses/directmessages/DirectItemReactions.java
-
7app/src/main/java/awais/instagrabber/utils/emoji/EmojiParser.java
-
134app/src/main/java/awais/instagrabber/viewmodels/DirectThreadViewModel.java
-
30app/src/main/res/layout/layout_dm_base.xml
-
18app/src/main/res/layout/layout_dm_user_item.xml
-
2app/src/main/res/values/dimens.xml
-
1app/src/main/res/values/strings.xml
@ -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); |
|||
} |
|||
} |
@ -1,4 +1,4 @@ |
|||
package awais.instagrabber.adapters.viewholder; |
|||
package awais.instagrabber.adapters.viewholder.directmessages; |
|||
|
|||
import android.graphics.Typeface; |
|||
import android.view.View; |
@ -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.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()); |
|||
} |
|||
} |
Reference in new issue
xxxxxxxxxx