From 45a91e089625b3049efe2b761c65efa178899630 Mon Sep 17 00:00:00 2001 From: Rashad Sookram Date: Fri, 28 Jan 2022 12:29:28 -0500 Subject: [PATCH] Update context menu with tweaks from design. --- .../conversation/ConversationContextMenu.kt | 6 + .../conversation/ConversationFragment.java | 1 + .../conversation/ConversationItem.java | 18 ++- .../conversation/ConversationItemSelection.kt | 22 +-- .../ConversationReactionOverlay.java | 150 ++++++++++-------- .../conversation/SelectedConversationModel.kt | 7 +- .../colors/RecyclerViewColorizer.kt | 14 +- app/src/main/res/anim/delay_grow_fade_in.xml | 23 +++ app/src/main/res/anim/shrink_fade_out.xml | 30 ++++ .../animator/reactions_scrubber_reveal.xml | 2 + app/src/main/res/values/animations.xml | 5 + app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/dimens.xml | 2 - app/src/main/res/values/integers.xml | 4 +- app/src/main/res/values/light_colors.xml | 4 +- 15 files changed, 191 insertions(+), 98 deletions(-) create mode 100644 app/src/main/res/anim/delay_grow_fade_in.xml create mode 100644 app/src/main/res/anim/shrink_fade_out.xml diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationContextMenu.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationContextMenu.kt index 62ff7003db..eaad5e149a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationContextMenu.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationContextMenu.kt @@ -4,6 +4,7 @@ import android.content.Context import android.os.Build import android.view.Gravity import android.view.LayoutInflater +import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.widget.PopupWindow @@ -30,6 +31,7 @@ class ConversationContextMenu(private val anchor: View, items: List) init { setBackgroundDrawable(ContextCompat.getDrawable(context, R.drawable.signal_context_menu_background)) + animationStyle = R.style.ConversationContextMenuAnimation isFocusable = false isOutsideTouchable = true @@ -38,6 +40,10 @@ class ConversationContextMenu(private val anchor: View, items: List) elevation = 20f } + setTouchInterceptor { _, event -> + event.action == MotionEvent.ACTION_OUTSIDE + } + contextMenuList.setItems(items) contentView.measure( diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java index 6e842f3665..69ddc068e3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -1466,6 +1466,7 @@ public class ConversationFragment extends LoggingFragment implements Multiselect itemView.getX(), itemView.getY() + list.getTranslationY(), bodyBubble.getX(), + bodyBubble.getY(), bodyBubble.getWidth(), audioUri, messageRecord.isOutgoing()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java index e9cb491f7d..a1b06c2b23 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -363,13 +363,17 @@ public final class ConversationItem extends RelativeLayout implements BindableCo @Override public boolean dispatchTouchEvent(MotionEvent ev) { - if (ev.getAction() == MotionEvent.ACTION_DOWN) { - getHandler().postDelayed(shrinkBubble, SHRINK_BUBBLE_DELAY_MILLIS); - } else { - getHandler().removeCallbacks(shrinkBubble); - bodyBubble.animate() - .scaleX(1.0f) - .scaleY(1.0f); + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + getHandler().postDelayed(shrinkBubble, SHRINK_BUBBLE_DELAY_MILLIS); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + getHandler().removeCallbacks(shrinkBubble); + bodyBubble.animate() + .scaleX(1.0f) + .scaleY(1.0f); + break; } return super.dispatchTouchEvent(ev); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItemSelection.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItemSelection.kt index c31a6d40a2..1de18c5ef0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItemSelection.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItemSelection.kt @@ -1,7 +1,6 @@ package org.thoughtcrime.securesms.conversation import android.graphics.Bitmap -import android.graphics.Canvas import android.graphics.Path import android.view.View import androidx.core.graphics.applyCanvas @@ -51,7 +50,8 @@ object ConversationItemSelection { val path = Path() - val yTranslation = -conversationItem.y + val xTranslation = -conversationItem.x - conversationItem.bodyBubble.x + val yTranslation = -conversationItem.y - conversationItem.bodyBubble.y val mp4Projection = conversationItem.getGiphyMp4PlayableProjection(list) var scaledVideoBitmap = videoBitmap @@ -63,29 +63,30 @@ object ConversationItemSelection { true ) + mp4Projection.translateX(xTranslation) mp4Projection.translateY(yTranslation) mp4Projection.applyToPath(path) } projections.use { it.forEach { p -> + p.translateX(xTranslation) p.translateY(yTranslation) p.applyToPath(path) } } - val distanceToBubbleBottom = conversationItem.bodyBubble.height + conversationItem.bodyBubble.y.toInt() - return createBitmap(conversationItem.width, distanceToBubbleBottom).applyCanvas { + return createBitmap(conversationItem.bodyBubble.width, conversationItem.bodyBubble.height).applyCanvas { if (drawConversationItem) { - draw(conversationItem) + conversationItem.bodyBubble.draw(this) } withClip(path) { - withTranslation(y = yTranslation) { + withTranslation(x = xTranslation, y = yTranslation) { list.draw(this) if (scaledVideoBitmap != null) { - drawBitmap(scaledVideoBitmap, mp4Projection.x, mp4Projection.y - yTranslation, null) + drawBitmap(scaledVideoBitmap, mp4Projection.x - xTranslation, mp4Projection.y - yTranslation, null) } } } @@ -96,11 +97,4 @@ object ConversationItemSelection { conversationItem.bodyBubble.scaleY = originalScale } } - - private fun Canvas.draw(conversationItem: ConversationItem) { - val bodyBubble = conversationItem.bodyBubble - withTranslation(bodyBubble.x, bodyBubble.y) { - bodyBubble.draw(this@draw) - } - } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationReactionOverlay.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationReactionOverlay.java index 740e0f20a0..bc2dd26f15 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationReactionOverlay.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationReactionOverlay.java @@ -53,8 +53,7 @@ import kotlin.Unit; public final class ConversationReactionOverlay extends RelativeLayout { - private static final Interpolator INTERPOLATOR = new DecelerateInterpolator(); - private static final long TRANSITION_Y_DURATION = 150; + private static final Interpolator INTERPOLATOR = new DecelerateInterpolator(); private final Rect emojiViewGlobalRect = new Rect(); private final Rect emojiStripViewBounds = new Rect(); @@ -89,10 +88,7 @@ public final class ConversationReactionOverlay extends RelativeLayout { private ConversationContextMenu contextMenu; private float touchDownDeadZoneSize; - private float distanceFromTouchDownPointToTopOfScrubberDeadZone; private float distanceFromTouchDownPointToBottomOfScrubberDeadZone; - private int scrubberDistanceFromTouchDown; - private int scrubberHeight; private int scrubberWidth; private int selectedVerticalTranslation; private int scrubberHorizontalMargin; @@ -137,15 +133,12 @@ public final class ConversationReactionOverlay extends RelativeLayout { customEmojiIndex = emojiViews.length - 1; - 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); - touchDownDeadZoneSize = getResources().getDimensionPixelSize(R.dimen.conversation_reaction_touch_deadzone_size); - scrubberDistanceFromTouchDown = getResources().getDimensionPixelOffset(R.dimen.conversation_reaction_scrubber_distance); - scrubberHeight = getResources().getDimensionPixelOffset(R.dimen.conversation_reaction_scrubber_height); - scrubberWidth = getResources().getDimensionPixelOffset(R.dimen.reaction_scrubber_width); - selectedVerticalTranslation = getResources().getDimensionPixelOffset(R.dimen.conversation_reaction_scrub_vertical_translation); - scrubberHorizontalMargin = getResources().getDimensionPixelOffset(R.dimen.conversation_reaction_scrub_horizontal_margin); + touchDownDeadZoneSize = getResources().getDimensionPixelSize(R.dimen.conversation_reaction_touch_deadzone_size); + scrubberWidth = getResources().getDimensionPixelOffset(R.dimen.reaction_scrubber_width); + selectedVerticalTranslation = getResources().getDimensionPixelOffset(R.dimen.conversation_reaction_scrub_vertical_translation); + scrubberHorizontalMargin = getResources().getDimensionPixelOffset(R.dimen.conversation_reaction_scrub_horizontal_margin); animationEmojiStartDelayFactor = getResources().getInteger(R.integer.reaction_scrubber_emoji_reveal_duration_start_delay_factor); @@ -180,7 +173,7 @@ public final class ConversationReactionOverlay extends RelativeLayout { } ViewGroup.LayoutParams layoutParams = inputShade.getLayoutParams(); - layoutParams.height = activity.findViewById(R.id.bottom_panel).getHeight(); + layoutParams.height = getInputPanelHeight(activity); inputShade.setLayoutParams(layoutParams); toolbarShade.setVisibility(VISIBLE); @@ -191,12 +184,8 @@ public final class ConversationReactionOverlay extends RelativeLayout { conversationItem.setLayoutParams(new LayoutParams(conversationItemSnapshot.getWidth(), conversationItemSnapshot.getHeight())); conversationItem.setBackground(new BitmapDrawable(getResources(), conversationItemSnapshot)); - float initialX = selectedConversationModel.getBitmapX(); boolean isMessageOnLeft = selectedConversationModel.isOutgoing() ^ ViewUtil.isLtr(this); - conversationItem.setX(initialX); - conversationItem.setY(selectedConversationModel.getBitmapY() - statusBarHeight); - conversationItem.setScaleX(ConversationItem.LONG_PRESS_SCALE_FACTOR); conversationItem.setScaleY(ConversationItem.LONG_PRESS_SCALE_FACTOR); @@ -208,58 +197,70 @@ public final class ConversationReactionOverlay extends RelativeLayout { }); } + private int getInputPanelHeight(@NonNull Activity activity) { + View bottomPanel = activity.findViewById(R.id.bottom_panel); + View emojiDrawer = activity.findViewById(R.id.emoji_drawer); + + return bottomPanel.getHeight() + (emojiDrawer != null && emojiDrawer.getVisibility() == VISIBLE ? emojiDrawer.getHeight() : 0); + } + private void showAfterLayout(@NonNull Activity activity, @NonNull ConversationMessage conversationMessage, @NonNull PointF lastSeenDownPoint, boolean isMessageOnLeft) { contextMenu = new ConversationContextMenu(dropdownAnchor, getMenuActionItems(conversationMessage)); + conversationItem.setX(selectedConversationModel.getBubbleX()); + conversationItem.setY(selectedConversationModel.getItemY() + selectedConversationModel.getBubbleY() - statusBarHeight); + Bitmap conversationItemSnapshot = selectedConversationModel.getBitmap(); boolean isWideLayout = contextMenu.getMaxWidth() + scrubberWidth < getWidth(); int bubbleWidth = selectedConversationModel.getBubbleWidth(); - float endX = selectedConversationModel.getBitmapX(); + float endX = selectedConversationModel.getBubbleX(); float endY = conversationItem.getY(); float endApparentTop = endY; float endScale = 1f; - float menuPadding = DimensionUnit.DP.toPixels(12f); - int reactionBarHeight = backgroundView.getHeight(); + float menuPadding = DimensionUnit.DP.toPixels(12f); + float reactionBarTopPadding = DimensionUnit.DP.toPixels(32f); + int reactionBarHeight = backgroundView.getHeight(); float reactionBarBackgroundY; if (isWideLayout) { - boolean everythingFitsVertically = scrubberHeight + conversationItemSnapshot.getHeight() < getHeight(); + boolean everythingFitsVertically = reactionBarHeight + menuPadding + reactionBarTopPadding + conversationItemSnapshot.getHeight() < getHeight(); if (everythingFitsVertically) { - boolean reactionBarFitsAboveItem = conversationItem.getY() > scrubberHeight; + boolean reactionBarFitsAboveItem = conversationItem.getY() > reactionBarHeight + menuPadding + reactionBarTopPadding; if (reactionBarFitsAboveItem) { reactionBarBackgroundY = conversationItem.getY() - menuPadding - reactionBarHeight; } else { - endY = reactionBarHeight + menuPadding; - reactionBarBackgroundY = 0f; + endY = reactionBarHeight + menuPadding + reactionBarTopPadding; + reactionBarBackgroundY = reactionBarTopPadding; } } else { - float spaceAvailableForItem = getHeight() - reactionBarHeight - menuPadding; + float spaceAvailableForItem = getHeight() - reactionBarHeight - menuPadding * 2; endScale = spaceAvailableForItem / conversationItem.getHeight(); - endY = reactionBarHeight + menuPadding - Util.halfOffsetFromScale(conversationItemSnapshot.getHeight(), endScale); - reactionBarBackgroundY = 0f; + endX += Util.halfOffsetFromScale(conversationItemSnapshot.getWidth(), endScale) * (isMessageOnLeft ? -1 : 1); + endY = reactionBarHeight + menuPadding + reactionBarTopPadding - Util.halfOffsetFromScale(conversationItemSnapshot.getHeight(), endScale); + reactionBarBackgroundY = reactionBarTopPadding; } } else { - boolean everythingFitsVertically = contextMenu.getMaxHeight() + conversationItemSnapshot.getHeight() + menuPadding + reactionBarHeight < getHeight(); + boolean everythingFitsVertically = contextMenu.getMaxHeight() + conversationItemSnapshot.getHeight() + menuPadding + reactionBarHeight + reactionBarTopPadding < getHeight(); if (everythingFitsVertically) { - float itemBottom = selectedConversationModel.getBitmapY() + conversationItemSnapshot.getHeight(); - boolean menuFitsBelowItem = itemBottom + menuPadding + contextMenu.getMaxHeight() <= getHeight(); + float bubbleBottom = selectedConversationModel.getItemY() + selectedConversationModel.getBubbleY() + conversationItemSnapshot.getHeight(); + boolean menuFitsBelowItem = bubbleBottom + menuPadding + contextMenu.getMaxHeight() <= getHeight() + statusBarHeight; if (menuFitsBelowItem) { reactionBarBackgroundY = conversationItem.getY() - menuPadding - reactionBarHeight; - if (reactionBarBackgroundY < 0) { - endY = backgroundView.getHeight(); - reactionBarBackgroundY = 0f; + if (reactionBarBackgroundY < reactionBarTopPadding) { + endY = backgroundView.getHeight() + menuPadding; + reactionBarBackgroundY = reactionBarTopPadding; } } else { endY = getHeight() - contextMenu.getMaxHeight() - menuPadding - conversationItemSnapshot.getHeight(); @@ -267,30 +268,44 @@ public final class ConversationReactionOverlay extends RelativeLayout { } endApparentTop = endY; - } else if (reactionBarHeight + contextMenu.getMaxHeight() + menuPadding < getHeight()) { - float spaceAvailableForItem = (float) getHeight() - contextMenu.getMaxHeight() - menuPadding - reactionBarHeight; + } else if (reactionBarHeight + contextMenu.getMaxHeight() + menuPadding * 2 < getHeight()) { + float spaceAvailableForItem = (float) getHeight() - contextMenu.getMaxHeight() - menuPadding * 2 - reactionBarHeight - reactionBarTopPadding; endScale = spaceAvailableForItem / conversationItemSnapshot.getHeight(); - endY = reactionBarHeight - Util.halfOffsetFromScale(conversationItemSnapshot.getHeight(), endScale); - reactionBarBackgroundY = 0f; - endApparentTop = reactionBarHeight; + endX += Util.halfOffsetFromScale(conversationItemSnapshot.getWidth(), endScale) * (isMessageOnLeft ? -1 : 1); + endY = reactionBarHeight - Util.halfOffsetFromScale(conversationItemSnapshot.getHeight(), endScale) + menuPadding + reactionBarTopPadding; + reactionBarBackgroundY = reactionBarTopPadding; + endApparentTop = reactionBarHeight + menuPadding + reactionBarTopPadding; } else { contextMenu.setHeight(contextMenu.getMaxHeight() / 2); int menuHeight = contextMenu.getHeight(); - boolean fitsVertically = menuHeight + conversationItem.getHeight() + menuPadding + reactionBarHeight < getHeight(); + boolean fitsVertically = menuHeight + conversationItem.getHeight() + menuPadding * 2 + reactionBarHeight + reactionBarTopPadding < getHeight(); if (fitsVertically) { - endY = getHeight() - menuHeight - menuPadding - conversationItemSnapshot.getHeight(); - reactionBarBackgroundY = endY - reactionBarHeight; + float bubbleBottom = selectedConversationModel.getItemY() + selectedConversationModel.getBubbleY() + conversationItemSnapshot.getHeight(); + boolean menuFitsBelowItem = bubbleBottom + menuPadding + menuHeight <= getHeight() + statusBarHeight; + + if (menuFitsBelowItem) { + reactionBarBackgroundY = conversationItem.getY() - menuPadding - reactionBarHeight; + + if (reactionBarBackgroundY < reactionBarTopPadding) { + endY = reactionBarTopPadding + reactionBarHeight + menuPadding; + reactionBarBackgroundY = reactionBarTopPadding; + } + } else { + endY = getHeight() - menuHeight - menuPadding - conversationItemSnapshot.getHeight(); + reactionBarBackgroundY = endY - reactionBarHeight - menuPadding; + } endApparentTop = endY; } else { - float spaceAvailableForItem = (float) getHeight() - menuHeight - menuPadding - reactionBarHeight; + float spaceAvailableForItem = (float) getHeight() - menuHeight - menuPadding * 2 - reactionBarHeight - reactionBarTopPadding; endScale = spaceAvailableForItem / conversationItemSnapshot.getHeight(); - endY = reactionBarHeight - Util.halfOffsetFromScale(conversationItemSnapshot.getHeight(), endScale); - reactionBarBackgroundY = 0f; - endApparentTop = reactionBarHeight; + endX += Util.halfOffsetFromScale(conversationItemSnapshot.getWidth(), endScale) * (isMessageOnLeft ? -1 : 1); + endY = reactionBarHeight - Util.halfOffsetFromScale(conversationItemSnapshot.getHeight(), endScale) + menuPadding + reactionBarTopPadding; + reactionBarBackgroundY = reactionBarTopPadding; + endApparentTop = reactionBarHeight + menuPadding + reactionBarTopPadding; } } } @@ -331,21 +346,21 @@ public final class ConversationReactionOverlay extends RelativeLayout { float offsetX = isMessageOnLeft ? scrubberRight + menuPadding : scrubberX - contextMenu.getMaxWidth() - menuPadding; contextMenu.show((int) offsetX, (int) Math.min(backgroundView.getY(), getHeight() - contextMenu.getMaxHeight())); } else { - float contentX = selectedConversationModel.getContentX(); - float offsetX = isMessageOnLeft ? contentX : - contextMenu.getMaxWidth() + contentX + bubbleWidth; + float contentX = selectedConversationModel.getBubbleX(); + float offsetX = isMessageOnLeft ? contentX : -contextMenu.getMaxWidth() + contentX + bubbleWidth; float menuTop = endApparentTop + (conversationItemSnapshot.getHeight() * endScale); contextMenu.show((int) offsetX, (int) (menuTop + menuPadding)); } - conversationItem.animate() - .x(endX) - .scaleX(endScale) - .scaleY(endScale); + int revealDuration = getContext().getResources().getInteger(R.integer.reaction_scrubber_reveal_duration); conversationItem.animate() + .x(endX) .y(endY) - .setDuration(TRANSITION_Y_DURATION); + .scaleX(endScale) + .scaleY(endScale) + .setDuration(revealDuration); } @RequiresApi(api = 21) @@ -375,7 +390,7 @@ public final class ConversationReactionOverlay extends RelativeLayout { private void hideInternal(@Nullable OnHideListener onHideListener) { overlayState = OverlayState.HIDDEN; - int duration = getContext().getResources().getInteger(R.integer.reaction_scrubber_reveal_duration); + int duration = getContext().getResources().getInteger(R.integer.reaction_scrubber_hide_duration); List hides = new ArrayList<>(hideAnimators); @@ -395,16 +410,16 @@ public final class ConversationReactionOverlay extends RelativeLayout { ObjectAnimator itemXAnim = new ObjectAnimator(); itemXAnim.setProperty(View.X); - itemXAnim.setFloatValues(selectedConversationModel.getBitmapX()); + itemXAnim.setFloatValues(selectedConversationModel.getBubbleX()); itemXAnim.setTarget(conversationItem); itemXAnim.setDuration(duration); hides.add(itemXAnim); ObjectAnimator itemYAnim = new ObjectAnimator(); itemYAnim.setProperty(View.Y); - itemYAnim.setFloatValues(selectedConversationModel.getBitmapY() - statusBarHeight); + itemYAnim.setFloatValues(selectedConversationModel.getItemY() + selectedConversationModel.getBubbleY() - statusBarHeight); itemYAnim.setTarget(conversationItem); - itemYAnim.setDuration(TRANSITION_Y_DURATION); + itemYAnim.setDuration(duration); hides.add(itemYAnim); hideAnimatorSet.playTogether(hides); @@ -720,29 +735,28 @@ public final class ConversationReactionOverlay extends RelativeLayout { private void initAnimators() { - int duration = getContext().getResources().getInteger(R.integer.reaction_scrubber_reveal_duration); + int revealDuration = getContext().getResources().getInteger(R.integer.reaction_scrubber_reveal_duration); + int revealOffset = getContext().getResources().getInteger(R.integer.reaction_scrubber_reveal_offset); List reveals = Stream.of(emojiViews) .mapIndexed((idx, v) -> { Animator anim = AnimatorInflaterCompat.loadAnimator(getContext(), R.animator.reactions_scrubber_reveal); anim.setTarget(v); - anim.setStartDelay(idx * animationEmojiStartDelayFactor); + anim.setStartDelay(revealOffset + idx * animationEmojiStartDelayFactor); return anim; }) .toList(); - Animator overlayRevealAnim = AnimatorInflaterCompat.loadAnimator(getContext(), android.R.animator.fade_in); - overlayRevealAnim.setDuration(duration); - reveals.add(overlayRevealAnim); - Animator backgroundRevealAnim = AnimatorInflaterCompat.loadAnimator(getContext(), android.R.animator.fade_in); backgroundRevealAnim.setTarget(backgroundView); - backgroundRevealAnim.setDuration(duration); + backgroundRevealAnim.setDuration(revealDuration); + backgroundRevealAnim.setStartDelay(revealOffset); reveals.add(backgroundRevealAnim); Animator selectedRevealAnim = AnimatorInflaterCompat.loadAnimator(getContext(), android.R.animator.fade_in); selectedRevealAnim.setTarget(selectedView); - selectedRevealAnim.setDuration(duration); + backgroundRevealAnim.setDuration(revealDuration); + backgroundRevealAnim.setStartDelay(revealOffset); reveals.add(selectedRevealAnim); revealAnimatorSet.setInterpolator(INTERPOLATOR); @@ -757,18 +771,20 @@ public final class ConversationReactionOverlay extends RelativeLayout { }) .toList(); + int hideDuration = getContext().getResources().getInteger(R.integer.reaction_scrubber_hide_duration); + Animator overlayHideAnim = AnimatorInflaterCompat.loadAnimator(getContext(), android.R.animator.fade_out); - overlayHideAnim.setDuration(duration); + overlayHideAnim.setDuration(hideDuration); hideAnimators.add(overlayHideAnim); Animator backgroundHideAnim = AnimatorInflaterCompat.loadAnimator(getContext(), android.R.animator.fade_out); backgroundHideAnim.setTarget(backgroundView); - backgroundHideAnim.setDuration(duration); + backgroundHideAnim.setDuration(hideDuration); hideAnimators.add(backgroundHideAnim); Animator selectedHideAnim = AnimatorInflaterCompat.loadAnimator(getContext(), android.R.animator.fade_out); selectedHideAnim.setTarget(selectedView); - selectedHideAnim.setDuration(duration); + selectedHideAnim.setDuration(hideDuration); hideAnimators.add(selectedHideAnim); hideAnimatorSet = newHideAnimatorSet(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/SelectedConversationModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/SelectedConversationModel.kt index 6d51777eb0..0369f1185b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/SelectedConversationModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/SelectedConversationModel.kt @@ -9,9 +9,10 @@ import android.net.Uri */ data class SelectedConversationModel( val bitmap: Bitmap, - val bitmapX: Float, - val bitmapY: Float, - val contentX: Float, + val itemX: Float, + val itemY: Float, + val bubbleX: Float, + val bubbleY: Float, val bubbleWidth: Int, val audioUri: Uri? = null, val isOutgoing: Boolean, diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer.kt index 910a20a36d..abcf840178 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/colors/RecyclerViewColorizer.kt @@ -118,13 +118,16 @@ class RecyclerViewColorizer(private val recyclerView: RecyclerView) { colorPaint.xfermode = noLayerXfermode } + val firstColor: Int + val lastColor: Int if (chatColors.isGradient()) { val mask = chatColors.chatBubbleMask as RotatableGradientDrawable mask.setXfermode(colorPaint.xfermode) mask.setBounds(0, 0, parent.width, parent.height) mask.draw(canvas) - outOfBoundsPaint.color = chatColors.getColors().last() + firstColor = chatColors.getColors().first() + lastColor = chatColors.getColors().last() } else { colorPaint.color = chatColors.asSingleColor() canvas.drawRect( @@ -135,9 +138,16 @@ class RecyclerViewColorizer(private val recyclerView: RecyclerView) { colorPaint ) - outOfBoundsPaint.color = chatColors.asSingleColor() + firstColor = chatColors.asSingleColor() + lastColor = chatColors.asSingleColor() } + outOfBoundsPaint.color = firstColor + canvas.drawRect( + 0f, -parent.height.toFloat(), parent.width.toFloat(), 0f, outOfBoundsPaint + ) + + outOfBoundsPaint.color = lastColor canvas.drawRect( 0f, parent.height.toFloat(), parent.width.toFloat(), parent.height * 2f, outOfBoundsPaint ) diff --git a/app/src/main/res/anim/delay_grow_fade_in.xml b/app/src/main/res/anim/delay_grow_fade_in.xml new file mode 100644 index 0000000000..d98c6d9e12 --- /dev/null +++ b/app/src/main/res/anim/delay_grow_fade_in.xml @@ -0,0 +1,23 @@ + + + + + + + diff --git a/app/src/main/res/anim/shrink_fade_out.xml b/app/src/main/res/anim/shrink_fade_out.xml new file mode 100644 index 0000000000..c5de08754c --- /dev/null +++ b/app/src/main/res/anim/shrink_fade_out.xml @@ -0,0 +1,30 @@ + + + + + + + diff --git a/app/src/main/res/animator/reactions_scrubber_reveal.xml b/app/src/main/res/animator/reactions_scrubber_reveal.xml index 1b753fdaea..a5b78a3b85 100644 --- a/app/src/main/res/animator/reactions_scrubber_reveal.xml +++ b/app/src/main/res/animator/reactions_scrubber_reveal.xml @@ -2,6 +2,7 @@ @anim/fade_in @anim/fade_out + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 04b1c57b67..cae7602a62 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -12,6 +12,7 @@ #33000000 #40000000 #66000000 + #80000000 #99000000 #CC000000 #e6000000 diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index f3c707d0de..3ae7f9a9cf 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -149,9 +149,7 @@ @dimen/selection_item_header_height 136dp - 25dp 40dp - 136dp 30dp 25dp 16dp diff --git a/app/src/main/res/values/integers.xml b/app/src/main/res/values/integers.xml index 4afdbd1c33..3414bc7e9e 100644 --- a/app/src/main/res/values/integers.xml +++ b/app/src/main/res/values/integers.xml @@ -1,6 +1,8 @@ - 400 + 200 + 100 + 150 380 10 \ No newline at end of file diff --git a/app/src/main/res/values/light_colors.xml b/app/src/main/res/values/light_colors.xml index abd1b7fba8..4699c24d0f 100644 --- a/app/src/main/res/values/light_colors.xml +++ b/app/src/main/res/values/light_colors.xml @@ -126,8 +126,8 @@ @color/core_grey_60 @color/core_grey_75 - @color/transparent_black_40 - #999999 + @color/transparent_black_50 + #808080 @color/core_grey_02