diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/RotatableGradientDrawable.java b/app/src/main/java/org/thoughtcrime/securesms/components/RotatableGradientDrawable.java index 9d3c87bb3..b5160e4fe 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/RotatableGradientDrawable.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/RotatableGradientDrawable.java @@ -16,7 +16,6 @@ import androidx.annotation.Nullable; import java.util.Arrays; -import kotlin.jvm.functions.Function1; import kotlin.jvm.functions.Function2; /** @@ -121,7 +120,11 @@ public final class RotatableGradientDrawable extends Drawable { public void draw(Canvas canvas) { int save = canvas.save(); canvas.rotate(degrees, getBounds().width() / 2f, getBounds().height() / 2f); - canvas.drawRect(fillRect, fillPaint); + + int height = fillRect.height(); + int width = fillRect.width(); + canvas.drawRect(fillRect.left - width, fillRect.top - height, fillRect.right + width, fillRect.bottom + height, fillPaint); + canvas.restoreToCount(save); } 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 0238f09ef..673cc820b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -908,7 +908,7 @@ public class ConversationFragment extends LoggingFragment implements Multiselect } lastSeenDecoration = new LastSeenHeader(getListAdapter(), lastSeen); - list.addItemDecoration(lastSeenDecoration); + list.addItemDecoration(lastSeenDecoration, 0); } private void handleCopyMessage(final Set multiselectParts) { 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 f252ac54a..f71e20e10 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationReactionOverlay.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationReactionOverlay.java @@ -101,9 +101,8 @@ public final class ConversationReactionOverlay extends FrameLayout { private OnActionSelectedListener onActionSelectedListener; private OnHideListener onHideListener; - private AnimatorSet revealAnimatorSet = new AnimatorSet(); - private AnimatorSet hideAnimatorSet = new AnimatorSet(); - private List hideAnimators; + private AnimatorSet revealAnimatorSet = new AnimatorSet(); + private AnimatorSet hideAnimatorSet = new AnimatorSet(); public ConversationReactionOverlay(@NonNull Context context) { super(context); @@ -325,7 +324,6 @@ public final class ConversationReactionOverlay extends FrameLayout { reactionBarBackgroundY = Math.max(reactionBarBackgroundY, -statusBarHeight); hideAnimatorSet.end(); - hideAnimatorSet = newHideAnimatorSet(); setVisibility(View.VISIBLE); float scrubberX; @@ -421,72 +419,11 @@ public final class ConversationReactionOverlay extends FrameLayout { private void hideInternal(@Nullable OnHideListener onHideListener) { overlayState = OverlayState.HIDDEN; - int duration = getContext().getResources().getInteger(R.integer.reaction_scrubber_hide_duration); - - List hides = new ArrayList<>(hideAnimators); - - ObjectAnimator itemScaleXAnim = new ObjectAnimator(); - itemScaleXAnim.setProperty(View.SCALE_X); - itemScaleXAnim.setFloatValues(1f); - itemScaleXAnim.setTarget(conversationItem); - itemScaleXAnim.setDuration(duration); - hides.add(itemScaleXAnim); - - ObjectAnimator itemScaleYAnim = new ObjectAnimator(); - itemScaleYAnim.setProperty(View.SCALE_Y); - itemScaleYAnim.setFloatValues(1f); - itemScaleYAnim.setTarget(conversationItem); - itemScaleYAnim.setDuration(duration); - hides.add(itemScaleYAnim); - - ObjectAnimator itemXAnim = new ObjectAnimator(); - itemXAnim.setProperty(View.X); - itemXAnim.setFloatValues(selectedConversationModel.getBubbleX()); - itemXAnim.setTarget(conversationItem); - itemXAnim.setDuration(duration); - hides.add(itemXAnim); - - ObjectAnimator itemYAnim = new ObjectAnimator(); - itemYAnim.setProperty(View.Y); - itemYAnim.setFloatValues(selectedConversationModel.getItemY() + selectedConversationModel.getBubbleY() - statusBarHeight); - itemYAnim.setTarget(conversationItem); - itemYAnim.setDuration(duration); - hides.add(itemYAnim); - - ObjectAnimator toolbarShadeAnim = new ObjectAnimator(); - toolbarShadeAnim.setProperty(View.ALPHA); - toolbarShadeAnim.setFloatValues(0f); - toolbarShadeAnim.setTarget(toolbarShade); - toolbarShadeAnim.setDuration(duration); - hides.add(toolbarShadeAnim); - - ObjectAnimator inputShadeAnim = new ObjectAnimator(); - inputShadeAnim.setProperty(View.ALPHA); - inputShadeAnim.setFloatValues(0f); - inputShadeAnim.setTarget(inputShade); - inputShadeAnim.setDuration(duration); - hides.add(inputShadeAnim); - - if (Build.VERSION.SDK_INT >= 21 && activity != null) { - ValueAnimator statusBarAnim = ValueAnimator.ofArgb(activity.getWindow().getStatusBarColor(), originalStatusBarColor); - statusBarAnim.setDuration(duration); - statusBarAnim.addUpdateListener(animation -> { - WindowUtil.setStatusBarColor(activity.getWindow(), (int) animation.getAnimatedValue()); - }); - hides.add(statusBarAnim); - - ValueAnimator navigationBarAnim = ValueAnimator.ofArgb(activity.getWindow().getStatusBarColor(), originalNavigationBarColor); - navigationBarAnim.setDuration(duration); - navigationBarAnim.addUpdateListener(animation -> { - WindowUtil.setNavigationBarColor(activity.getWindow(), (int) animation.getAnimatedValue()); - }); - hides.add(navigationBarAnim); - } - - hideAnimatorSet.playTogether(hides); + AnimatorSet animatorSet = newHideAnimatorSet(); + hideAnimatorSet = animatorSet; revealAnimatorSet.end(); - hideAnimatorSet.start(); + animatorSet.start(); if (onHideListener != null) { onHideListener.startHide(); @@ -496,9 +433,9 @@ public final class ConversationReactionOverlay extends FrameLayout { ViewUtil.focusAndShowKeyboard(selectedConversationModel.getFocusedView()); } - hideAnimatorSet.addListener(new AnimationCompleteListener() { + animatorSet.addListener(new AnimationCompleteListener() { @Override public void onAnimationEnd(Animator animation) { - hideAnimatorSet.removeListener(this); + animatorSet.removeListener(this); toolbarShade.setVisibility(INVISIBLE); inputShade.setVisibility(INVISIBLE); @@ -839,32 +776,6 @@ public final class ConversationReactionOverlay extends FrameLayout { revealAnimatorSet.setInterpolator(INTERPOLATOR); revealAnimatorSet.playTogether(reveals); - - hideAnimators = Stream.of(emojiViews) - .mapIndexed((idx, v) -> { - Animator anim = AnimatorInflaterCompat.loadAnimator(getContext(), R.animator.reactions_scrubber_hide); - anim.setTarget(v); - return anim; - }) - .toList(); - - int hideDuration = getContext().getResources().getInteger(R.integer.reaction_scrubber_hide_duration); - - Animator overlayHideAnim = AnimatorInflaterCompat.loadAnimator(getContext(), android.R.animator.fade_out); - overlayHideAnim.setDuration(hideDuration); - hideAnimators.add(overlayHideAnim); - - Animator backgroundHideAnim = AnimatorInflaterCompat.loadAnimator(getContext(), android.R.animator.fade_out); - backgroundHideAnim.setTarget(backgroundView); - backgroundHideAnim.setDuration(hideDuration); - hideAnimators.add(backgroundHideAnim); - - Animator selectedHideAnim = AnimatorInflaterCompat.loadAnimator(getContext(), android.R.animator.fade_out); - selectedHideAnim.setTarget(selectedView); - selectedHideAnim.setDuration(hideDuration); - hideAnimators.add(selectedHideAnim); - - hideAnimatorSet = newHideAnimatorSet(); } private @NonNull AnimatorSet newHideAnimatorSet() { @@ -878,9 +789,97 @@ public final class ConversationReactionOverlay extends FrameLayout { }); set.setInterpolator(INTERPOLATOR); + set.playTogether(newHideAnimators()); + return set; } + private @NonNull List newHideAnimators() { + int duration = getContext().getResources().getInteger(R.integer.reaction_scrubber_hide_duration); + + List animators = new ArrayList<>(Stream.of(emojiViews) + .mapIndexed((idx, v) -> { + Animator anim = AnimatorInflaterCompat.loadAnimator(getContext(), R.animator.reactions_scrubber_hide); + anim.setTarget(v); + return anim; + }) + .toList()); + + Animator overlayHideAnim = AnimatorInflaterCompat.loadAnimator(getContext(), android.R.animator.fade_out); + overlayHideAnim.setDuration(duration); + animators.add(overlayHideAnim); + + Animator backgroundHideAnim = AnimatorInflaterCompat.loadAnimator(getContext(), android.R.animator.fade_out); + backgroundHideAnim.setTarget(backgroundView); + backgroundHideAnim.setDuration(duration); + animators.add(backgroundHideAnim); + + Animator selectedHideAnim = AnimatorInflaterCompat.loadAnimator(getContext(), android.R.animator.fade_out); + selectedHideAnim.setTarget(selectedView); + selectedHideAnim.setDuration(duration); + animators.add(selectedHideAnim); + + ObjectAnimator itemScaleXAnim = new ObjectAnimator(); + itemScaleXAnim.setProperty(View.SCALE_X); + itemScaleXAnim.setFloatValues(1f); + itemScaleXAnim.setTarget(conversationItem); + itemScaleXAnim.setDuration(duration); + animators.add(itemScaleXAnim); + + ObjectAnimator itemScaleYAnim = new ObjectAnimator(); + itemScaleYAnim.setProperty(View.SCALE_Y); + itemScaleYAnim.setFloatValues(1f); + itemScaleYAnim.setTarget(conversationItem); + itemScaleYAnim.setDuration(duration); + animators.add(itemScaleYAnim); + + ObjectAnimator itemXAnim = new ObjectAnimator(); + itemXAnim.setProperty(View.X); + itemXAnim.setFloatValues(selectedConversationModel.getBubbleX()); + itemXAnim.setTarget(conversationItem); + itemXAnim.setDuration(duration); + animators.add(itemXAnim); + + ObjectAnimator itemYAnim = new ObjectAnimator(); + itemYAnim.setProperty(View.Y); + itemYAnim.setFloatValues(selectedConversationModel.getItemY() + selectedConversationModel.getBubbleY() - statusBarHeight); + itemYAnim.setTarget(conversationItem); + itemYAnim.setDuration(duration); + animators.add(itemYAnim); + + ObjectAnimator toolbarShadeAnim = new ObjectAnimator(); + toolbarShadeAnim.setProperty(View.ALPHA); + toolbarShadeAnim.setFloatValues(0f); + toolbarShadeAnim.setTarget(toolbarShade); + toolbarShadeAnim.setDuration(duration); + animators.add(toolbarShadeAnim); + + ObjectAnimator inputShadeAnim = new ObjectAnimator(); + inputShadeAnim.setProperty(View.ALPHA); + inputShadeAnim.setFloatValues(0f); + inputShadeAnim.setTarget(inputShade); + inputShadeAnim.setDuration(duration); + animators.add(inputShadeAnim); + + if (Build.VERSION.SDK_INT >= 21 && activity != null) { + ValueAnimator statusBarAnim = ValueAnimator.ofArgb(activity.getWindow().getStatusBarColor(), originalStatusBarColor); + statusBarAnim.setDuration(duration); + statusBarAnim.addUpdateListener(animation -> { + WindowUtil.setStatusBarColor(activity.getWindow(), (int) animation.getAnimatedValue()); + }); + animators.add(statusBarAnim); + + ValueAnimator navigationBarAnim = ValueAnimator.ofArgb(activity.getWindow().getStatusBarColor(), originalNavigationBarColor); + navigationBarAnim.setDuration(duration); + navigationBarAnim.addUpdateListener(animation -> { + WindowUtil.setNavigationBarColor(activity.getWindow(), (int) animation.getAnimatedValue()); + }); + animators.add(navigationBarAnim); + } + + return animators; + } + public interface OnHideListener { void startHide(); void onHide(); 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 abcf84017..c505ad749 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,16 +118,11 @@ 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) - - firstColor = chatColors.getColors().first() - lastColor = chatColors.getColors().last() } else { colorPaint.color = chatColors.asSingleColor() canvas.drawRect( @@ -138,19 +133,17 @@ class RecyclerViewColorizer(private val recyclerView: RecyclerView) { colorPaint ) - firstColor = chatColors.asSingleColor() - lastColor = chatColors.asSingleColor() + val color = chatColors.asSingleColor() + + outOfBoundsPaint.color = color + canvas.drawRect( + 0f, -parent.height.toFloat(), parent.width.toFloat(), 0f, outOfBoundsPaint + ) + + canvas.drawRect( + 0f, parent.height.toFloat(), parent.width.toFloat(), parent.height * 2f, outOfBoundsPaint + ) } - - 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 - ) } }