Add an 'All' tab to reaction details.

This commit is contained in:
Greyson Parrelli 2020-02-02 00:15:59 -05:00
parent 279dcb1428
commit 835ef02872
8 changed files with 84 additions and 41 deletions

View file

@ -7,8 +7,11 @@ import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.emoji.EmojiTextView; import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
import org.thoughtcrime.securesms.util.ThemeUtil; import org.thoughtcrime.securesms.util.ThemeUtil;
@ -19,6 +22,7 @@ import java.util.List;
final class ReactionEmojiCountAdapter extends RecyclerView.Adapter<ReactionEmojiCountAdapter.ViewHolder> { final class ReactionEmojiCountAdapter extends RecyclerView.Adapter<ReactionEmojiCountAdapter.ViewHolder> {
private List<EmojiCount> emojiCountList = Collections.emptyList(); private List<EmojiCount> emojiCountList = Collections.emptyList();
private int totalCount = 0;
private int selectedPosition = -1; private int selectedPosition = -1;
private final OnEmojiCountSelectedListener onEmojiCountSelectedListener; private final OnEmojiCountSelectedListener onEmojiCountSelectedListener;
@ -28,9 +32,10 @@ final class ReactionEmojiCountAdapter extends RecyclerView.Adapter<ReactionEmoji
} }
void updateData(@NonNull List<EmojiCount> newEmojiCount) { void updateData(@NonNull List<EmojiCount> newEmojiCount) {
if (selectedPosition != -1) { if (selectedPosition != -1 && selectedPosition != 0) {
EmojiCount oldSelection = emojiCountList.get(selectedPosition); int emojiPosition = selectedPosition - 1;
int newPosition = -1; EmojiCount oldSelection = emojiCountList.get(emojiPosition);
int newPosition = -1;
for (int i = 0; i < newEmojiCount.size(); i++) { for (int i = 0; i < newEmojiCount.size(); i++) {
if (newEmojiCount.get(i).getEmoji().equals(oldSelection.getEmoji())) { if (newEmojiCount.get(i).getEmoji().equals(oldSelection.getEmoji())) {
@ -41,17 +46,19 @@ final class ReactionEmojiCountAdapter extends RecyclerView.Adapter<ReactionEmoji
if (newPosition == -1 && !newEmojiCount.isEmpty()) { if (newPosition == -1 && !newEmojiCount.isEmpty()) {
selectedPosition = 0; selectedPosition = 0;
onEmojiCountSelectedListener.onSelected(newEmojiCount.get(0)); onEmojiCountSelectedListener.onSelected(null);
} else { } else {
selectedPosition = newPosition; selectedPosition = newPosition + 1;
} }
} else if (!newEmojiCount.isEmpty()) { } else if (!newEmojiCount.isEmpty()) {
selectedPosition = 0; selectedPosition = 0;
onEmojiCountSelectedListener.onSelected(newEmojiCount.get(0)); onEmojiCountSelectedListener.onSelected(null);
} }
this.emojiCountList = newEmojiCount; this.emojiCountList = newEmojiCount;
this.totalCount = Stream.of(emojiCountList).reduce(0, (sum, e) -> sum + e.getCount());
notifyDataSetChanged(); notifyDataSetChanged();
} }
@ -59,7 +66,7 @@ final class ReactionEmojiCountAdapter extends RecyclerView.Adapter<ReactionEmoji
public @NonNull ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public @NonNull ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.reactions_bottom_sheet_dialog_fragment_emoji_item, parent, false), position -> { return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.reactions_bottom_sheet_dialog_fragment_emoji_item, parent, false), position -> {
if (position != -1 && position != selectedPosition) { if (position != -1 && position != selectedPosition) {
onEmojiCountSelectedListener.onSelected(emojiCountList.get(position)); onEmojiCountSelectedListener.onSelected(position == 0 ? null : emojiCountList.get(position - 1).getEmoji());
int oldPosition = selectedPosition; int oldPosition = selectedPosition;
selectedPosition = position; selectedPosition = position;
@ -72,33 +79,44 @@ final class ReactionEmojiCountAdapter extends RecyclerView.Adapter<ReactionEmoji
@Override @Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) { public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.bind(emojiCountList.get(position), selectedPosition); if (position == 0) {
holder.bind(null, totalCount, selectedPosition == position);
} else {
EmojiCount item = emojiCountList.get(position - 1);
holder.bind(item.getEmoji(), item.getCount(), selectedPosition == position);
}
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
return emojiCountList.size(); return 1 + emojiCountList.size();
} }
static final class ViewHolder extends RecyclerView.ViewHolder { static final class ViewHolder extends RecyclerView.ViewHolder {
private final Drawable selected; private final Drawable selectedBackground;
private final EmojiTextView emojiView; private final EmojiTextView emojiView;
private final TextView countView; private final TextView countView;
public ViewHolder(@NonNull View itemView, @NonNull OnViewHolderClickListener onClickListener) { ViewHolder(@NonNull View itemView, @NonNull OnViewHolderClickListener onClickListener) {
super(itemView); super(itemView);
emojiView = itemView.findViewById(R.id.reactions_bottom_view_emoji_item_emoji); emojiView = itemView.findViewById(R.id.reactions_bottom_view_emoji_item_emoji);
countView = itemView.findViewById(R.id.reactions_bottom_view_emoji_item_text); countView = itemView.findViewById(R.id.reactions_bottom_view_emoji_item_text );
selected = ThemeUtil.getThemedDrawable(itemView.getContext(), R.attr.reactions_bottom_dialog_fragment_emoji_selected); selectedBackground = ThemeUtil.getThemedDrawable(itemView.getContext(), R.attr.reactions_bottom_dialog_fragment_emoji_selected);
itemView.setOnClickListener(v -> onClickListener.onClick(getAdapterPosition())); itemView.setOnClickListener(v -> onClickListener.onClick(getAdapterPosition()));
} }
void bind(@NonNull EmojiCount emojiCount, int selectedPosition) { void bind(@Nullable String emoji, int count, boolean selected) {
emojiView.setText(emojiCount.getEmoji()); if (emoji != null) {
countView.setText(String.valueOf(emojiCount.getCount())); emojiView.setVisibility(View.VISIBLE);
itemView.setBackground(getAdapterPosition() == selectedPosition ? selected : null); emojiView.setText(emoji);
countView.setText(String.valueOf(count));
} else {
emojiView.setVisibility(View.GONE);
countView.setText(itemView.getContext().getString(R.string.ReactionsBottomSheetDialogFragment_all, count));
}
itemView.setBackground(selected ? selectedBackground : null);
} }
} }
@ -107,7 +125,6 @@ final class ReactionEmojiCountAdapter extends RecyclerView.Adapter<ReactionEmoji
} }
interface OnEmojiCountSelectedListener { interface OnEmojiCountSelectedListener {
void onSelected(@NonNull EmojiCount emojiCount); void onSelected(@Nullable String emoji);
} }
} }

View file

@ -11,6 +11,7 @@ import androidx.recyclerview.widget.RecyclerView;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.AvatarImageView; import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.reactions.ReactionsLoader.Reaction;
import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.AvatarUtil; import org.thoughtcrime.securesms.util.AvatarUtil;
@ -19,9 +20,9 @@ import java.util.List;
final class ReactionRecipientsAdapter extends RecyclerView.Adapter<ReactionRecipientsAdapter.ViewHolder> { final class ReactionRecipientsAdapter extends RecyclerView.Adapter<ReactionRecipientsAdapter.ViewHolder> {
private List<Recipient> data = Collections.emptyList(); private List<Reaction> data = Collections.emptyList();
public void updateData(List<Recipient> newData) { public void updateData(List<Reaction> newData) {
data = newData; data = newData;
notifyDataSetChanged(); notifyDataSetChanged();
} }
@ -48,21 +49,24 @@ final class ReactionRecipientsAdapter extends RecyclerView.Adapter<ReactionRecip
private final AvatarImageView avatar; private final AvatarImageView avatar;
private final TextView recipient; private final TextView recipient;
private final TextView emoji;
public ViewHolder(@NonNull View itemView) { public ViewHolder(@NonNull View itemView) {
super(itemView); super(itemView);
avatar = itemView.findViewById(R.id.reactions_bottom_view_recipient_avatar); avatar = itemView.findViewById(R.id.reactions_bottom_view_recipient_avatar);
recipient = itemView.findViewById(R.id.reactions_bottom_view_recipient_name); recipient = itemView.findViewById(R.id.reactions_bottom_view_recipient_name);
emoji = itemView.findViewById(R.id.reactions_bottom_view_recipient_emoji);
} }
void bind(Recipient recipient) { void bind(@NonNull Reaction reaction) {
this.recipient.setText(recipient.getDisplayName(itemView.getContext())); this.recipient.setText(reaction.getSender().getDisplayName(itemView.getContext()));
this.emoji.setText(reaction.getEmoji());
if (recipient.equals(Recipient.self())) { if (reaction.getSender().equals(Recipient.self())) {
AvatarUtil.loadIconIntoImageView(recipient, avatar); AvatarUtil.loadIconIntoImageView(reaction.getSender(), avatar);
} else { } else {
this.avatar.setAvatar(GlideApp.with(avatar), recipient, false); this.avatar.setAvatar(GlideApp.with(avatar), reaction.getSender(), false);
} }
} }
} }

View file

@ -88,7 +88,7 @@ public final class ReactionsBottomSheetDialogFragment extends BottomSheetDialogF
} }
private void setUpEmojiRecyclerView() { private void setUpEmojiRecyclerView() {
emojiCountAdapter = new ReactionEmojiCountAdapter((emojiCount -> viewModel.setFilterEmoji(emojiCount.getEmoji()))); emojiCountAdapter = new ReactionEmojiCountAdapter((emoji -> viewModel.setFilterEmoji(emoji)));
emojiRecyclerView.setAdapter(emojiCountAdapter); emojiRecyclerView.setAdapter(emojiCountAdapter);
} }

View file

@ -9,9 +9,6 @@ import androidx.lifecycle.ViewModelProvider;
import com.annimon.stream.Stream; import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -26,12 +23,12 @@ public class ReactionsViewModel extends ViewModel {
this.repository = repository; this.repository = repository;
} }
public @NonNull LiveData<List<Recipient>> getRecipients() { public @NonNull LiveData<List<Reaction>> getRecipients() {
return Transformations.switchMap(filterEmoji, return Transformations.switchMap(filterEmoji,
emoji -> Transformations.map(repository.getReactions(), emoji -> Transformations.map(repository.getReactions(),
reactions -> Stream.of(reactions) reactions -> Stream.of(reactions)
.filter(reaction -> reaction.getEmoji().equals(emoji)) .filter(reaction -> emoji == null || reaction.getEmoji().equals(emoji))
.map(Reaction::getSender).toList())); .toList()));
} }
public @NonNull LiveData<List<EmojiCount>> getEmojiCounts() { public @NonNull LiveData<List<EmojiCount>> getEmojiCounts() {

View file

@ -5,7 +5,7 @@
android:layout_height="36dp" android:layout_height="36dp"
android:layout_marginStart="6dp" android:layout_marginStart="6dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginEnd="6dp" android:layout_marginEnd="4dp"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
android:gravity="center" android:gravity="center"
android:orientation="horizontal"> android:orientation="horizontal">
@ -14,6 +14,7 @@
android:id="@+id/reactions_bottom_view_emoji_item_emoji" android:id="@+id/reactions_bottom_view_emoji_item_emoji"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="2dp"
android:gravity="center" android:gravity="center"
android:includeFontPadding="false" android:includeFontPadding="false"
android:textSize="22dp" android:textSize="22dp"
@ -25,12 +26,14 @@
android:id="@+id/reactions_bottom_view_emoji_item_text" android:id="@+id/reactions_bottom_view_emoji_item_text"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="4dp" android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:gravity="center" android:gravity="center"
android:includeFontPadding="true" android:includeFontPadding="true"
android:textColor="?title_text_color_primary" android:textColor="?title_text_color_primary"
android:textSize="14dp" android:textSize="14dp"
android:textStyle="bold" android:textStyle="bold"
android:textAllCaps="true"
tools:ignore="SpUsage" tools:ignore="SpUsage"
tools:text="24" /> tools:text="24" />
</LinearLayout> </LinearLayout>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -24,9 +25,25 @@
android:textColor="?title_text_color_primary" android:textColor="?title_text_color_primary"
android:textSize="17sp" android:textSize="17sp"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/reactions_bottom_view_recipient_avatar"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/reactions_bottom_view_recipient_emoji"
app:layout_constraintStart_toEndOf="@id/reactions_bottom_view_recipient_avatar"
app:layout_constraintHorizontal_bias="0.0"
tools:text="@tools:sample/full_names" /> tools:text="@tools:sample/full_names" />
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/reactions_bottom_view_recipient_emoji"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:gravity="center"
android:textSize="22dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:ignore="SpUsage" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -15,7 +15,8 @@
android:id="@+id/reactions_pill_emoji" android:id="@+id/reactions_pill_emoji"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textSize="16dp"/> android:textSize="16dp"
tools:ignore="SpUsage" />
<Space <Space
android:id="@+id/reactions_pill_spacer" android:id="@+id/reactions_pill_spacer"
@ -30,6 +31,7 @@
android:textSize="14dp" android:textSize="14dp"
android:fontFamily="sans-serif-medium" android:fontFamily="sans-serif-medium"
android:textColor="?reactions_pill_text_color" android:textColor="?reactions_pill_text_color"
tools:text="23" /> tools:text="23"
tools:ignore="SpUsage" />
</LinearLayout> </LinearLayout>

View file

@ -667,6 +667,9 @@
<string name="RatingManager_later">Later</string> <string name="RatingManager_later">Later</string>
<string name="RatingManager_whoops_the_play_store_app_does_not_appear_to_be_installed">Whoops, the Play Store app does not appear to be installed on your device.</string> <string name="RatingManager_whoops_the_play_store_app_does_not_appear_to_be_installed">Whoops, the Play Store app does not appear to be installed on your device.</string>
<!-- ReactionsBottomSheetDialogFragment -->
<string name="ReactionsBottomSheetDialogFragment_all">All %1$d</string>
<!-- ReactionsConversationView --> <!-- ReactionsConversationView -->
<string name="ReactionsConversationView_plus">+%1$d</string> <string name="ReactionsConversationView_plus">+%1$d</string>