Skip to content

Commit

Permalink
Implement ability to react with any emoji behind a flag.
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-signal committed May 14, 2020
1 parent 40b5339 commit d94fc4b
Show file tree
Hide file tree
Showing 53 changed files with 761 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ public int getCount() {

@Override
public @NonNull Object instantiateItem(@NonNull ViewGroup container, int position) {
EmojiPageView page = new EmojiPageView(context, emojiSelectionListener, variationSelectorListener);
EmojiPageView page = new EmojiPageView(context, emojiSelectionListener, variationSelectorListener, true);
page.setModel(pages.get(position));
container.addView(page);
return page;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public class EmojiPageView extends FrameLayout implements VariationSelectorListe

public EmojiPageView(@NonNull Context context,
@NonNull EmojiEventListener emojiSelectionListener,
@NonNull VariationSelectorListener variationSelectorListener)
@NonNull VariationSelectorListener variationSelectorListener,
boolean allowVariations)
{
super(context);
final View view = LayoutInflater.from(getContext()).inflate(R.layout.emoji_grid_layout, this, true);
Expand All @@ -40,7 +41,8 @@ public EmojiPageView(@NonNull Context context,
adapter = new EmojiPageViewGridAdapter(EmojiProvider.getInstance(context),
popup,
emojiSelectionListener,
this);
this,
allowVariations);

recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
Expand Down Expand Up @@ -83,6 +85,10 @@ public void onVariationSelectorStateChanged(boolean open) {
}
}

public void setRecyclerNestedScrollingEnabled(boolean enabled) {
recyclerView.setNestedScrollingEnabled(enabled);
}

private static class ScrollDisabler implements RecyclerView.OnItemTouchListener {
@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView, @NonNull MotionEvent motionEvent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,20 @@ public class EmojiPageViewGridAdapter extends RecyclerView.Adapter<EmojiPageView
private final EmojiVariationSelectorPopup popup;
private final VariationSelectorListener variationSelectorListener;
private final EmojiEventListener emojiEventListener;
private final boolean allowVariations;

public EmojiPageViewGridAdapter(@NonNull EmojiProvider emojiProvider,
@NonNull EmojiVariationSelectorPopup popup,
@NonNull EmojiEventListener emojiEventListener,
@NonNull VariationSelectorListener variationSelectorListener)
@NonNull VariationSelectorListener variationSelectorListener,
boolean allowVariations)
{
this.emojiList = new ArrayList<>();
this.emojiProvider = emojiProvider;
this.popup = popup;
this.emojiEventListener = emojiEventListener;
this.variationSelectorListener = variationSelectorListener;
this.allowVariations = allowVariations;

popup.setOnDismissListener(this);
}
Expand Down Expand Up @@ -65,7 +68,7 @@ public void onBindViewHolder(@NonNull EmojiViewHolder viewHolder, int i) {
emojiEventListener.onEmojiSelected(emoji.getValue());
});

if (emoji.getVariations().size() > 1) {
if (allowVariations && emoji.getVariations().size() > 1) {
viewHolder.itemView.setOnLongClickListener(v -> {
popup.dismiss();
popup.setVariations(emoji.getVariations());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

Expand Down Expand Up @@ -36,6 +37,10 @@ public final class EmojiUtil {

private EmojiUtil() {}

public static List<EmojiPageModel> getDisplayPages() {
return EmojiPages.DISPLAY_PAGES;
}

/**
* This will return all ways we know of expressing a singular emoji. This is to aid in search,
* where some platforms may send an emoji we've locally marked as 'obsolete'.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@
import org.thoughtcrime.securesms.profiles.GroupShareProfileView;
import org.thoughtcrime.securesms.profiles.edit.EditProfileActivity;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.reactions.any.ReactWithAnyEmojiBottomSheetDialogFragment;
import org.thoughtcrime.securesms.recipients.LiveRecipient;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientExporter;
Expand Down Expand Up @@ -269,7 +270,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
ComposeText.CursorPositionChangedListener,
ConversationSearchBottomBar.EventListener,
StickerKeyboardProvider.StickerEventListener,
AttachmentKeyboard.Callback
AttachmentKeyboard.Callback,
ConversationReactionOverlay.OnReactionSelectedListener,
ReactWithAnyEmojiBottomSheetDialogFragment.Callback
{

private static final int SHORTCUT_ICON_SIZE = Build.VERSION.SDK_INT >= 26 ? ViewUtil.dpToPx(72) : ViewUtil.dpToPx(48 + 16 * 2);
Expand Down Expand Up @@ -1714,7 +1717,7 @@ private void initializeViews() {

inlineAttachmentButton.setOnClickListener(v -> handleAddAttachment());

reactionOverlay.setOnReactionSelectedListener(this::onReactionSelected);
reactionOverlay.setOnReactionSelectedListener(this);
}

protected void initializeActionBar() {
Expand Down Expand Up @@ -1831,10 +1834,12 @@ private void showStickerIntroductionTooltip() {
.show(TooltipPopup.POSITION_ABOVE);
}


private void onReactionSelected(MessageRecord messageRecord, String emoji) {
@Override
public void onReactionSelected(MessageRecord messageRecord, String emoji) {
final Context context = getApplicationContext();

reactionOverlay.hide();

SignalExecutors.BOUNDED.execute(() -> {
ReactionRecord oldRecord = Stream.of(messageRecord.getReactions())
.filter(record -> record.getAuthor().equals(Recipient.self().getId()))
Expand All @@ -1849,6 +1854,35 @@ private void onReactionSelected(MessageRecord messageRecord, String emoji) {
});
}

@Override
public void onCustomReactionSelected(@NonNull MessageRecord messageRecord, boolean hasAddedCustomEmoji) {
ReactionRecord oldRecord = Stream.of(messageRecord.getReactions())
.filter(record -> record.getAuthor().equals(Recipient.self().getId()))
.findFirst()
.orElse(null);

if (oldRecord != null && hasAddedCustomEmoji) {
final Context context = getApplicationContext();

reactionOverlay.hide();

SignalExecutors.BOUNDED.execute(() -> MessageSender.sendReactionRemoval(context,
messageRecord.getId(),
messageRecord.isMms(),
oldRecord));
} else {
reactionOverlay.hideAllButMask();

ReactWithAnyEmojiBottomSheetDialogFragment.createForMessageRecord(messageRecord)
.show(getSupportFragmentManager(), "BOTTOM");
}
}

@Override
public void onReactWithAnyEmojiDialogDismissed() {
reactionOverlay.hideMask();
}

@Override
public void onSearchMoveUpPressed() {
searchViewModel.onMoveUp();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.Toolbar;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
Expand All @@ -30,14 +31,17 @@
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.animation.AnimationCompleteListener;
import org.thoughtcrime.securesms.components.MaskView;
import org.thoughtcrime.securesms.components.emoji.EmojiImageView;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.ReactionRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

public final class ConversationReactionOverlay extends RelativeLayout {
Expand All @@ -60,12 +64,13 @@ public final class ConversationReactionOverlay extends RelativeLayout {
private boolean downIsOurs;
private boolean isToolbarTouch;
private int selected = -1;
private int customEmojiIndex;
private int originalStatusBarColor;

private View backgroundView;
private ConstraintLayout foregroundView;
private View selectedView;
private View[] emojiViews;
private EmojiImageView[] emojiViews;
private MaskView maskView;
private Toolbar toolbar;

Expand All @@ -85,8 +90,10 @@ public final class ConversationReactionOverlay extends RelativeLayout {
private Toolbar.OnMenuItemClickListener onToolbarItemClickedListener;
private OnHideListener onHideListener;

private AnimatorSet revealAnimatorSet = new AnimatorSet();
private AnimatorSet hideAnimatorSet = new AnimatorSet();
private AnimatorSet revealAnimatorSet = new AnimatorSet();
private AnimatorSet hideAnimatorSet = new AnimatorSet();
private AnimatorSet hideAllButMaskAnimatorSet = new AnimatorSet();
private AnimatorSet hideMaskAnimatorSet = new AnimatorSet();

public ConversationReactionOverlay(@NonNull Context context) {
super(context);
Expand All @@ -111,7 +118,10 @@ protected void onFinishInflate() {

emojiViews = Stream.of(ReactionEmoji.values())
.map(e -> findViewById(e.viewId))
.toArray(View[]::new);
.toArray(EmojiImageView[]::new);

customEmojiIndex = FeatureFlags.reactWithAnyEmoji() ? ReactionEmoji.values().length - 1
: ReactionEmoji.values().length;

distanceFromTouchDownPointToTopOfScrubberDeadZone = getResources().getDimensionPixelSize(R.dimen.conversation_reaction_scrub_deadzone_distance_from_touch_top);
distanceFromTouchDownPointToBottomOfScrubberDeadZone = getResources().getDimensionPixelSize(R.dimen.conversation_reaction_scrub_deadzone_distance_from_touch_bottom);
Expand Down Expand Up @@ -144,7 +154,7 @@ public void show(@NonNull Activity activity, @NonNull View maskTarget, @NonNull
selected = -1;

setupToolbarMenuItems();
setupSelectedEmojiBackground();
setupSelectedEmoji();

if (Build.VERSION.SDK_INT >= 21) {
View statusBarBackground = activity.findViewById(android.R.id.statusBarBackground);
Expand Down Expand Up @@ -188,6 +198,22 @@ public void show(@NonNull Activity activity, @NonNull View maskTarget, @NonNull

public void hide() {
maskView.setTarget(null);
hideInternal(hideAnimatorSet, onHideListener);
}

public void hideAllButMask() {
hideInternal(hideAllButMaskAnimatorSet, null);
}

public void hideMask() {
hideMaskAnimatorSet.start();

if (onHideListener != null) {
onHideListener.onHide();
}
}

private void hideInternal(@NonNull AnimatorSet hideAnimatorSet, @Nullable OnHideListener onHideListener) {
overlayState = OverlayState.HIDDEN;

revealAnimatorSet.end();
Expand Down Expand Up @@ -316,20 +342,30 @@ public boolean applyTouchEvent(@NonNull MotionEvent motionEvent) {
}
}

private void setupSelectedEmojiBackground() {
private void setupSelectedEmoji() {
final String oldEmoji = getOldEmoji(messageRecord);

if (oldEmoji == null) {
selectedView.setVisibility(View.GONE);
}

boolean foundSelected = false;

for (int i = 0; i < emojiViews.length; i++) {
final View view = emojiViews[i];
final EmojiImageView view = emojiViews[i];

view.setScaleX(1.0f);
view.setScaleY(1.0f);
view.setTranslationY(0);

if (ReactionEmoji.values()[i].emoji.equals(oldEmoji)) {
boolean isAtCustomIndex = i == customEmojiIndex;
boolean isNotAtCustomIndexAndOldEmojiMatches = !isAtCustomIndex && ReactionEmoji.values()[i].emoji.equals(oldEmoji);
boolean isAtCustomIndexAndOldEmojiExists = isAtCustomIndex && oldEmoji != null;

if (!foundSelected &&
(isNotAtCustomIndexAndOldEmojiMatches || isAtCustomIndexAndOldEmojiExists))
{
foundSelected = true;
selectedView.setVisibility(View.VISIBLE);

ConstraintSet constraintSet = new ConstraintSet();
Expand All @@ -339,6 +375,18 @@ private void setupSelectedEmojiBackground() {
constraintSet.connect(selectedView.getId(), ConstraintSet.LEFT, view.getId(), ConstraintSet.LEFT);
constraintSet.connect(selectedView.getId(), ConstraintSet.RIGHT, view.getId(), ConstraintSet.RIGHT);
constraintSet.applyTo(foregroundView);

if (isAtCustomIndex) {
view.setImageEmoji(oldEmoji);
view.setTag(oldEmoji);
} else {
view.setImageEmoji(ReactionEmoji.values()[i].emoji);
}
} else if (isAtCustomIndex) {
view.setImageDrawable(AppCompatResources.getDrawable(getContext(), R.drawable.ic_any_emoji_32));
view.setTag(null);
} else {
view.setImageEmoji(ReactionEmoji.values()[i].emoji);
}
}
}
Expand Down Expand Up @@ -396,9 +444,14 @@ private void shrinkView(@NonNull View view) {
}

private void handleUpEvent() {
hide();
if (selected != -1 && onReactionSelectedListener != null) {
onReactionSelectedListener.onReactionSelected(messageRecord, ReactionEmoji.values()[selected].emoji);
if (selected == customEmojiIndex) {
onReactionSelectedListener.onCustomReactionSelected(messageRecord, emojiViews[selected].getTag() != null);
} else {
onReactionSelectedListener.onReactionSelected(messageRecord, ReactionEmoji.values()[selected].emoji);
}
} else {
hide();
}
}

Expand Down Expand Up @@ -494,7 +547,6 @@ private void initAnimators() {
Animator overlayHideAnim = AnimatorInflaterCompat.loadAnimator(getContext(), android.R.animator.fade_out);
overlayHideAnim.setTarget(maskView);
overlayHideAnim.setDuration(duration);
hides.add(overlayHideAnim);

Animator backgroundHideAnim = AnimatorInflaterCompat.loadAnimator(getContext(), android.R.animator.fade_out);
backgroundHideAnim.setTarget(backgroundView);
Expand All @@ -511,15 +563,26 @@ private void initAnimators() {
toolbarHideAnim.setDuration(duration);
hides.add(toolbarHideAnim);

hideAnimatorSet.addListener(new AnimationCompleteListener() {
AnimationCompleteListener hideListener = new AnimationCompleteListener() {
@Override
public void onAnimationEnd(Animator animation) {
setVisibility(View.GONE);
}
});
};

List<Animator> hideAllAnimators = new LinkedList<>(hides);
hideAllAnimators.add(overlayHideAnim);

hideAnimatorSet.addListener(hideListener);
hideAnimatorSet.setInterpolator(INTERPOLATOR);
hideAnimatorSet.playTogether(hides);
hideAnimatorSet.playTogether(hideAllAnimators);

hideAllButMaskAnimatorSet.setInterpolator(INTERPOLATOR);
hideAllButMaskAnimatorSet.playTogether(hides);

hideMaskAnimatorSet.addListener(hideListener);
hideMaskAnimatorSet.setInterpolator(INTERPOLATOR);
hideMaskAnimatorSet.playTogether(overlayHideAnim);
}

public interface OnHideListener {
Expand All @@ -528,6 +591,7 @@ public interface OnHideListener {

public interface OnReactionSelectedListener {
void onReactionSelected(@NonNull MessageRecord messageRecord, String emoji);
void onCustomReactionSelected(@NonNull MessageRecord messageRecord, boolean hasAddedCustomEmoji);
}

private static class Boundary {
Expand Down

0 comments on commit d94fc4b

Please sign in to comment.