Improve showing context menu with keyboard open.

fork-5.53.8
Rashad Sookram 2022-02-03 17:06:17 -05:00 zatwierdzone przez GitHub
rodzic f0414922be
commit 24a875c73a
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
17 zmienionych plików z 248 dodań i 97 usunięć

Wyświetl plik

@ -1308,25 +1308,26 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
public interface ConversationFragmentListener extends VoiceNoteMediaControllerOwner {
void setThreadId(long threadId);
void handleReplyMessage(ConversationMessage conversationMessage);
void onMessageActionToolbarOpened();
void onBottomActionBarVisibilityChanged(int visibility);
void onForwardClicked();
void onMessageRequest(@NonNull MessageRequestViewModel viewModel);
void handleReaction(@NonNull ConversationMessage conversationMessage,
@NonNull ConversationReactionOverlay.OnActionSelectedListener onActionSelectedListener,
@NonNull SelectedConversationModel selectedConversationModel,
@NonNull ConversationReactionOverlay.OnHideListener onHideListener);
void onCursorChanged();
void onMessageWithErrorClicked(@NonNull MessageRecord messageRecord);
void onVoiceNotePause(@NonNull Uri uri);
void onVoiceNotePlay(@NonNull Uri uri, long messageId, double progress);
void onVoiceNoteResume(@NonNull Uri uri, long messageId);
void onVoiceNoteSeekTo(@NonNull Uri uri, double progress);
void onVoiceNotePlaybackSpeedChanged(@NonNull Uri uri, float speed);
void onRegisterVoiceNoteCallbacks(@NonNull Observer<VoiceNotePlaybackState> onPlaybackStartObserver);
void onUnregisterVoiceNoteCallbacks(@NonNull Observer<VoiceNotePlaybackState> onPlaybackStartObserver);
boolean isKeyboardOpen();
void setThreadId(long threadId);
void handleReplyMessage(ConversationMessage conversationMessage);
void onMessageActionToolbarOpened();
void onBottomActionBarVisibilityChanged(int visibility);
void onForwardClicked();
void onMessageRequest(@NonNull MessageRequestViewModel viewModel);
void handleReaction(@NonNull ConversationMessage conversationMessage,
@NonNull ConversationReactionOverlay.OnActionSelectedListener onActionSelectedListener,
@NonNull SelectedConversationModel selectedConversationModel,
@NonNull ConversationReactionOverlay.OnHideListener onHideListener);
void onCursorChanged();
void onMessageWithErrorClicked(@NonNull MessageRecord messageRecord);
void onVoiceNotePause(@NonNull Uri uri);
void onVoiceNotePlay(@NonNull Uri uri, long messageId, double progress);
void onVoiceNoteResume(@NonNull Uri uri, long messageId);
void onVoiceNoteSeekTo(@NonNull Uri uri, double progress);
void onVoiceNotePlaybackSpeedChanged(@NonNull Uri uri, float speed);
void onRegisterVoiceNoteCallbacks(@NonNull Observer<VoiceNotePlaybackState> onPlaybackStartObserver);
void onUnregisterVoiceNoteCallbacks(@NonNull Observer<VoiceNotePlaybackState> onPlaybackStartObserver);
}
private class ConversationScrollListener extends OnScrollListener {
@ -1460,6 +1461,8 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
ConversationItem conversationItem = (ConversationItem) itemView;
Bitmap bitmap = ConversationItemSelection.snapshotView(conversationItem, list, messageRecord, videoBitmap);
View focusedView = listener.isKeyboardOpen() ? conversationItem.getRootView().findFocus() : null;
final ConversationItemBodyBubble bodyBubble = conversationItem.bodyBubble;
SelectedConversationModel selectedConversationModel = new SelectedConversationModel(bitmap,
itemView.getX(),
@ -1468,28 +1471,41 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
bodyBubble.getY(),
bodyBubble.getWidth(),
audioUri,
messageRecord.isOutgoing());
messageRecord.isOutgoing(),
focusedView);
bodyBubble.setVisibility(View.INVISIBLE);
listener.handleReaction(item.getConversationMessage(), new ReactionsToolbarListener(item.getConversationMessage()), selectedConversationModel, () -> {
reactionsShade.setVisibility(View.GONE);
list.setLayoutFrozen(false);
ViewUtil.hideKeyboard(requireContext(), conversationItem);
if (selectedConversationModel.getAudioUri() != null) {
listener.onVoiceNoteResume(selectedConversationModel.getAudioUri(), messageRecord.getId());
}
listener.handleReaction(item.getConversationMessage(),
new ReactionsToolbarListener(item.getConversationMessage()),
selectedConversationModel,
new ConversationReactionOverlay.OnHideListener() {
@Override public void startHide() {
multiselectItemDecoration.hideShade(list);
}
WindowUtil.setLightStatusBarFromTheme(requireActivity());
clearFocusedItem();
@Override public void onHide() {
reactionsShade.setVisibility(View.GONE);
list.setLayoutFrozen(false);
if (mp4Holder != null) {
mp4Holder.show();
mp4Holder.resume();
}
if (selectedConversationModel.getAudioUri() != null) {
listener.onVoiceNoteResume(selectedConversationModel.getAudioUri(), messageRecord.getId());
}
bodyBubble.setVisibility(View.VISIBLE);
});
WindowUtil.setLightStatusBarFromTheme(requireActivity());
WindowUtil.setLightNavigationBarFromTheme(requireActivity());
clearFocusedItem();
if (mp4Holder != null) {
mp4Holder.show();
mp4Holder.resume();
}
bodyBubble.setVisibility(View.VISIBLE);
}
});
}
} else {
clearFocusedItem();

Wyświetl plik

@ -3,10 +3,12 @@ package org.thoughtcrime.securesms.conversation
import android.graphics.Bitmap
import android.graphics.Path
import android.view.View
import android.view.ViewGroup
import androidx.core.graphics.applyCanvas
import androidx.core.graphics.createBitmap
import androidx.core.graphics.withClip
import androidx.core.graphics.withTranslation
import androidx.core.view.children
import androidx.recyclerview.widget.RecyclerView
import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.util.hasNoBubble
@ -76,6 +78,8 @@ object ConversationItemSelection {
}
}
conversationItem.destroyAllDrawingCaches()
return createBitmap(conversationItem.bodyBubble.width, conversationItem.bodyBubble.height).applyCanvas {
if (drawConversationItem) {
conversationItem.bodyBubble.draw(this)
@ -98,3 +102,13 @@ object ConversationItemSelection {
}
}
}
private fun ViewGroup.destroyAllDrawingCaches() {
children.forEach {
it.destroyDrawingCache()
if (it is ViewGroup) {
it.destroyAllDrawingCaches()
}
}
}

Wyświetl plik

@ -3791,6 +3791,11 @@ public class ConversationParentFragment extends Fragment
});
}
@Override
public boolean isKeyboardOpen() {
return container.isKeyboardOpen();
}
@Override
public void setThreadId(long threadId) {
this.threadId = threadId;

Wyświetl plik

@ -3,8 +3,10 @@ package org.thoughtcrime.securesms.conversation;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.PointF;
import android.graphics.Rect;
@ -14,11 +16,10 @@ import android.util.AttributeSet;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.RelativeLayout;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -51,7 +52,7 @@ import java.util.List;
import kotlin.Unit;
public final class ConversationReactionOverlay extends RelativeLayout {
public final class ConversationReactionOverlay extends FrameLayout {
private static final Interpolator INTERPOLATOR = new DecelerateInterpolator();
@ -94,6 +95,7 @@ public final class ConversationReactionOverlay extends RelativeLayout {
private int scrubberHorizontalMargin;
private int animationEmojiStartDelayFactor;
private int statusBarHeight;
private int bottomNavigationBarHeight;
private OnReactionSelectedListener onReactionSelectedListener;
private OnActionSelectedListener onActionSelectedListener;
@ -168,16 +170,24 @@ public final class ConversationReactionOverlay extends RelativeLayout {
if (Build.VERSION.SDK_INT >= 21) {
View statusBarBackground = activity.findViewById(android.R.id.statusBarBackground);
statusBarHeight = statusBarBackground == null ? 0 : statusBarBackground.getHeight();
View navigationBarBackground = activity.findViewById(android.R.id.navigationBarBackground);
bottomNavigationBarHeight = navigationBarBackground == null ? 0 : navigationBarBackground.getHeight();
} else {
statusBarHeight = ViewUtil.getStatusBarHeight(this);
statusBarHeight = ViewUtil.getStatusBarHeight(this);
bottomNavigationBarHeight = ViewUtil.getNavigationBarHeight(this);
}
ViewGroup.LayoutParams layoutParams = inputShade.getLayoutParams();
layoutParams.height = getInputPanelHeight(activity);
inputShade.setLayoutParams(layoutParams);
boolean isLandscape = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
if (isLandscape) {
bottomNavigationBarHeight = 0;
}
toolbarShade.setVisibility(VISIBLE);
toolbarShade.setAlpha(1f);
inputShade.setVisibility(VISIBLE);
inputShade.setAlpha(1f);
Bitmap conversationItemSnapshot = selectedConversationModel.getBitmap();
@ -191,6 +201,11 @@ public final class ConversationReactionOverlay extends RelativeLayout {
setVisibility(View.INVISIBLE);
if (Build.VERSION.SDK_INT >= 21) {
this.activity = activity;
updateSystemUiOnShow(activity);
}
ViewKt.doOnLayout(this, v -> {
showAfterLayout(activity, conversationMessage, lastSeenDownPoint, isMessageOnLeft);
return Unit.INSTANCE;
@ -198,7 +213,7 @@ public final class ConversationReactionOverlay extends RelativeLayout {
}
private int getInputPanelHeight(@NonNull Activity activity) {
View bottomPanel = activity.findViewById(R.id.bottom_panel);
View bottomPanel = activity.findViewById(R.id.conversation_activity_panel_parent);
View emojiDrawer = activity.findViewById(R.id.emoji_drawer);
return bottomPanel.getHeight() + (emojiDrawer != null && emojiDrawer.getVisibility() == VISIBLE ? emojiDrawer.getHeight() : 0);
@ -208,6 +223,11 @@ public final class ConversationReactionOverlay extends RelativeLayout {
@NonNull ConversationMessage conversationMessage,
@NonNull PointF lastSeenDownPoint,
boolean isMessageOnLeft) {
LayoutParams layoutParams = (LayoutParams) inputShade.getLayoutParams();
layoutParams.bottomMargin = bottomNavigationBarHeight;
layoutParams.height = getInputPanelHeight(activity);
inputShade.setLayoutParams(layoutParams);
contextMenu = new ConversationContextMenu(dropdownAnchor, getMenuActionItems(conversationMessage));
conversationItem.setX(selectedConversationModel.getBubbleX());
@ -216,7 +236,8 @@ public final class ConversationReactionOverlay extends RelativeLayout {
Bitmap conversationItemSnapshot = selectedConversationModel.getBitmap();
boolean isWideLayout = contextMenu.getMaxWidth() + scrubberWidth < getWidth();
int bubbleWidth = selectedConversationModel.getBubbleWidth();
int overlayHeight = getHeight() - bottomNavigationBarHeight;
int bubbleWidth = selectedConversationModel.getBubbleWidth();
float endX = selectedConversationModel.getBubbleX();
float endY = conversationItem.getY();
@ -230,7 +251,7 @@ public final class ConversationReactionOverlay extends RelativeLayout {
float reactionBarBackgroundY;
if (isWideLayout) {
boolean everythingFitsVertically = reactionBarHeight + menuPadding + reactionBarTopPadding + conversationItemSnapshot.getHeight() < getHeight();
boolean everythingFitsVertically = reactionBarHeight + menuPadding + reactionBarTopPadding + conversationItemSnapshot.getHeight() < overlayHeight;
if (everythingFitsVertically) {
boolean reactionBarFitsAboveItem = conversationItem.getY() > reactionBarHeight + menuPadding + reactionBarTopPadding;
@ -241,7 +262,7 @@ public final class ConversationReactionOverlay extends RelativeLayout {
reactionBarBackgroundY = reactionBarTopPadding;
}
} else {
float spaceAvailableForItem = getHeight() - reactionBarHeight - menuPadding * 2;
float spaceAvailableForItem = overlayHeight - reactionBarHeight - menuPadding - reactionBarTopPadding;
endScale = spaceAvailableForItem / conversationItem.getHeight();
endX += Util.halfOffsetFromScale(conversationItemSnapshot.getWidth(), endScale) * (isMessageOnLeft ? -1 : 1);
@ -249,27 +270,27 @@ public final class ConversationReactionOverlay extends RelativeLayout {
reactionBarBackgroundY = reactionBarTopPadding;
}
} else {
boolean everythingFitsVertically = contextMenu.getMaxHeight() + conversationItemSnapshot.getHeight() + menuPadding + reactionBarHeight + reactionBarTopPadding < getHeight();
boolean everythingFitsVertically = contextMenu.getMaxHeight() + conversationItemSnapshot.getHeight() + menuPadding + reactionBarHeight + reactionBarTopPadding < overlayHeight;
if (everythingFitsVertically) {
float bubbleBottom = selectedConversationModel.getItemY() + selectedConversationModel.getBubbleY() + conversationItemSnapshot.getHeight();
boolean menuFitsBelowItem = bubbleBottom + menuPadding + contextMenu.getMaxHeight() <= getHeight() + statusBarHeight;
boolean menuFitsBelowItem = bubbleBottom + menuPadding + contextMenu.getMaxHeight() <= overlayHeight + statusBarHeight;
if (menuFitsBelowItem) {
reactionBarBackgroundY = conversationItem.getY() - menuPadding - reactionBarHeight;
if (reactionBarBackgroundY < reactionBarTopPadding) {
endY = backgroundView.getHeight() + menuPadding;
endY = backgroundView.getHeight() + menuPadding + reactionBarTopPadding;
reactionBarBackgroundY = reactionBarTopPadding;
}
} else {
endY = getHeight() - contextMenu.getMaxHeight() - menuPadding - conversationItemSnapshot.getHeight();
endY = overlayHeight - contextMenu.getMaxHeight() - menuPadding - conversationItemSnapshot.getHeight();
reactionBarBackgroundY = endY - menuPadding - reactionBarHeight;
}
endApparentTop = endY;
} else if (reactionBarHeight + contextMenu.getMaxHeight() + menuPadding * 2 < getHeight()) {
float spaceAvailableForItem = (float) getHeight() - contextMenu.getMaxHeight() - menuPadding * 2 - reactionBarHeight - reactionBarTopPadding;
} else if (reactionBarHeight + contextMenu.getMaxHeight() + menuPadding * 2 < overlayHeight) {
float spaceAvailableForItem = (float) overlayHeight - contextMenu.getMaxHeight() - menuPadding * 2 - reactionBarHeight - reactionBarTopPadding;
endScale = spaceAvailableForItem / conversationItemSnapshot.getHeight();
endX += Util.halfOffsetFromScale(conversationItemSnapshot.getWidth(), endScale) * (isMessageOnLeft ? -1 : 1);
@ -280,11 +301,11 @@ public final class ConversationReactionOverlay extends RelativeLayout {
contextMenu.setHeight(contextMenu.getMaxHeight() / 2);
int menuHeight = contextMenu.getHeight();
boolean fitsVertically = menuHeight + conversationItem.getHeight() + menuPadding * 2 + reactionBarHeight + reactionBarTopPadding < getHeight();
boolean fitsVertically = menuHeight + conversationItem.getHeight() + menuPadding * 2 + reactionBarHeight + reactionBarTopPadding < overlayHeight;
if (fitsVertically) {
float bubbleBottom = selectedConversationModel.getItemY() + selectedConversationModel.getBubbleY() + conversationItemSnapshot.getHeight();
boolean menuFitsBelowItem = bubbleBottom + menuPadding + menuHeight <= getHeight() + statusBarHeight;
boolean menuFitsBelowItem = bubbleBottom + menuPadding + menuHeight <= overlayHeight + statusBarHeight;
if (menuFitsBelowItem) {
reactionBarBackgroundY = conversationItem.getY() - menuPadding - reactionBarHeight;
@ -294,12 +315,12 @@ public final class ConversationReactionOverlay extends RelativeLayout {
reactionBarBackgroundY = reactionBarTopPadding;
}
} else {
endY = getHeight() - menuHeight - menuPadding - conversationItemSnapshot.getHeight();
endY = overlayHeight - menuHeight - menuPadding - conversationItemSnapshot.getHeight();
reactionBarBackgroundY = endY - reactionBarHeight - menuPadding;
}
endApparentTop = endY;
} else {
float spaceAvailableForItem = (float) getHeight() - menuHeight - menuPadding * 2 - reactionBarHeight - reactionBarTopPadding;
float spaceAvailableForItem = (float) overlayHeight - menuHeight - menuPadding * 2 - reactionBarHeight - reactionBarTopPadding;
endScale = spaceAvailableForItem / conversationItemSnapshot.getHeight();
endX += Util.halfOffsetFromScale(conversationItemSnapshot.getWidth(), endScale) * (isMessageOnLeft ? -1 : 1);
@ -316,11 +337,6 @@ public final class ConversationReactionOverlay extends RelativeLayout {
hideAnimatorSet = newHideAnimatorSet();
setVisibility(View.VISIBLE);
if (Build.VERSION.SDK_INT >= 21) {
this.activity = activity;
updateSystemUiOnShow(activity);
}
float scrubberX;
if (isMessageOnLeft) {
scrubberX = scrubberHorizontalMargin;
@ -344,7 +360,7 @@ public final class ConversationReactionOverlay extends RelativeLayout {
if (isWideLayout) {
float scrubberRight = scrubberX + scrubberWidth;
float offsetX = isMessageOnLeft ? scrubberRight + menuPadding : scrubberX - contextMenu.getMaxWidth() - menuPadding;
contextMenu.show((int) offsetX, (int) Math.min(backgroundView.getY(), getHeight() - contextMenu.getMaxHeight()));
contextMenu.show((int) offsetX, (int) Math.min(backgroundView.getY(), overlayHeight - contextMenu.getMaxHeight()));
} else {
float contentX = selectedConversationModel.getBubbleX();
float offsetX = isMessageOnLeft ? contentX : -contextMenu.getMaxWidth() + contentX + bubbleWidth;
@ -376,6 +392,7 @@ public final class ConversationReactionOverlay extends RelativeLayout {
if (!ThemeUtil.isDarkTheme(getContext())) {
WindowUtil.clearLightStatusBar(window);
WindowUtil.clearLightNavigationBar(window);
}
}
@ -422,11 +439,49 @@ public final class ConversationReactionOverlay extends RelativeLayout {
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);
revealAnimatorSet.end();
hideAnimatorSet.start();
if (onHideListener != null) {
onHideListener.startHide();
}
if (selectedConversationModel.getFocusedView() != null) {
ViewUtil.focusAndShowKeyboard(selectedConversationModel.getFocusedView());
}
hideAnimatorSet.addListener(new AnimationCompleteListener() {
@Override public void onAnimationEnd(Animator animation) {
hideAnimatorSet.removeListener(this);
@ -435,8 +490,6 @@ public final class ConversationReactionOverlay extends RelativeLayout {
inputShade.setVisibility(INVISIBLE);
if (Build.VERSION.SDK_INT >= 21 && activity != null) {
WindowUtil.setStatusBarColor(activity.getWindow(), originalStatusBarColor);
WindowUtil.setNavigationBarColor(activity.getWindow(), originalNavigationBarColor);
activity = null;
}
@ -729,13 +782,21 @@ public final class ConversationReactionOverlay extends RelativeLayout {
}
private void handleActionItemClicked(@NonNull Action action) {
hideInternal(() -> {
if (onHideListener != null) {
onHideListener.onHide();
hideInternal(new OnHideListener() {
@Override public void startHide() {
if (onHideListener != null) {
onHideListener.startHide();
}
}
if (onActionSelectedListener != null) {
onActionSelectedListener.onActionSelected(action);
@Override public void onHide() {
if (onHideListener != null) {
onHideListener.onHide();
}
if (onActionSelectedListener != null) {
onActionSelectedListener.onActionSelected(action);
}
}
});
}
@ -749,7 +810,7 @@ public final class ConversationReactionOverlay extends RelativeLayout {
.mapIndexed((idx, v) -> {
Animator anim = AnimatorInflaterCompat.loadAnimator(getContext(), R.animator.reactions_scrubber_reveal);
anim.setTarget(v);
anim.setStartDelay(revealOffset + idx * animationEmojiStartDelayFactor);
anim.setStartDelay(idx * animationEmojiStartDelayFactor);
return anim;
})
.toList();
@ -773,7 +834,6 @@ public final class ConversationReactionOverlay extends RelativeLayout {
.mapIndexed((idx, v) -> {
Animator anim = AnimatorInflaterCompat.loadAnimator(getContext(), R.animator.reactions_scrubber_hide);
anim.setTarget(v);
anim.setStartDelay(idx * animationEmojiStartDelayFactor);
return anim;
})
.toList();
@ -812,6 +872,7 @@ public final class ConversationReactionOverlay extends RelativeLayout {
}
public interface OnHideListener {
void startHide();
void onHide();
}

Wyświetl plik

@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.conversation
import android.graphics.Bitmap
import android.net.Uri
import android.view.View
/**
* Contains information on a single selected conversation item. This is used when transitioning
@ -16,4 +17,5 @@ data class SelectedConversationModel(
val bubbleWidth: Int,
val audioUri: Uri? = null,
val isOutgoing: Boolean,
val focusedView: View?,
)

Wyświetl plik

@ -1,5 +1,6 @@
package org.thoughtcrime.securesms.conversation.mutiselect
import android.animation.ArgbEvaluator
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Bitmap
@ -12,6 +13,7 @@ import android.graphics.Region
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.animation.doOnEnd
import androidx.core.content.ContextCompat
import androidx.core.view.children
import androidx.core.view.forEach
@ -54,6 +56,7 @@ class MultiselectItemDecoration(
private val selectedParts: MutableSet<MultiselectPart> = mutableSetOf()
private var enterExitAnimation: ValueAnimator? = null
private var hideShadeAnimation: ValueAnimator? = null
private val multiselectPartAnimatorMap: MutableMap<MultiselectPart, ValueAnimator> = mutableMapOf()
private var checkedBitmap: Bitmap? = null
@ -77,7 +80,10 @@ class MultiselectItemDecoration(
checkedBitmap = null
}
private val shadeColor = ContextCompat.getColor(context, R.color.reactions_screen_shade_color)
private val darkShadeColor = ContextCompat.getColor(context, R.color.reactions_screen_dark_shade_color)
private val lightShadeColor = ContextCompat.getColor(context, R.color.reactions_screen_light_shade_color)
private val argbEvaluator = ArgbEvaluator()
private val unselectedPaint = Paint().apply {
isAntiAlias = true
@ -371,7 +377,7 @@ class MultiselectItemDecoration(
}
canvas.clipPath(path)
canvas.drawColor(shadeColor)
canvas.drawShade()
canvas.restore()
}
}
@ -389,11 +395,39 @@ class MultiselectItemDecoration(
}
canvas.clipPath(path, Region.Op.DIFFERENCE)
canvas.drawColor(shadeColor)
canvas.drawShade()
canvas.restore()
}
}
private fun Canvas.drawShade() {
val progress = hideShadeAnimation?.animatedValue as? Float
if (progress == null) {
drawColor(lightShadeColor)
drawColor(darkShadeColor)
return
}
drawColor(argbEvaluator.evaluate(progress, lightShadeColor, Color.TRANSPARENT) as Int)
drawColor(argbEvaluator.evaluate(progress, darkShadeColor, Color.TRANSPARENT) as Int)
}
fun hideShade(list: RecyclerView) {
hideShadeAnimation = ValueAnimator.ofFloat(0f, 1f).apply {
duration = 150L
addUpdateListener {
invalidateIfAnimatorsAreRunning(list)
}
doOnEnd {
hideShadeAnimation = null
}
start()
}
}
private fun isInitialAnimation(): Boolean {
return (enterExitAnimation?.animatedFraction ?: 0f) < 1f
}
@ -441,7 +475,10 @@ class MultiselectItemDecoration(
}
private fun invalidateIfAnimatorsAreRunning(parent: RecyclerView) {
if (enterExitAnimation?.isRunning == true || multiselectPartAnimatorMap.values.any { it.isRunning }) {
if (enterExitAnimation?.isRunning == true ||
multiselectPartAnimatorMap.values.any { it.isRunning } ||
hideShadeAnimation?.isRunning == true
) {
parent.invalidate()
}
}

Wyświetl plik

@ -341,6 +341,15 @@ public final class ViewUtil {
return result;
}
public static int getNavigationBarHeight(@NonNull View view) {
int result = 0;
int resourceId = view.getResources().getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
result = view.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public static void hideKeyboard(@NonNull Context context, @NonNull View view) {
InputMethodManager inputManager = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputManager.hideSoftInputFromWindow(view.getWindowToken(), 0);

Wyświetl plik

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:duration="@integer/reaction_scrubber_reveal_emoji_duration"
android:duration="@integer/reaction_scrubber_hide_duration"
android:interpolator="@android:anim/decelerate_interpolator"
android:propertyName="translationY"
android:valueTo="@dimen/reaction_scrubber_anim_start_translation_y"
android:valueFrom="@dimen/reaction_scrubber_anim_end_translation_y" />
<objectAnimator
android:duration="@integer/reaction_scrubber_reveal_emoji_duration"
android:duration="@integer/reaction_scrubber_hide_duration"
android:interpolator="@android:anim/decelerate_interpolator"
android:propertyName="alpha"
android:valueTo="0"

Wyświetl plik

@ -261,7 +261,7 @@
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="@+id/status_bar_guideline"
app:layout_constraintBottom_toBottomOf="@+id/navigation_bar_guideline"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/parent_start_guideline"
app:layout_constraintEnd_toEndOf="@+id/parent_end_guideline"
android:inflatedId="@+id/conversation_reaction_scrubber"

Wyświetl plik

@ -27,11 +27,12 @@
android:overScrollMode="ifContentScrolls"
app:layout_constraintTop_toTopOf="parent" />
<View
<FrameLayout
android:id="@+id/reactions_shade"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/reactions_screen_shade_color"
android:background="@color/reactions_screen_light_shade_color"
android:foreground="@color/reactions_screen_dark_shade_color"
android:visibility="gone"
app:layout_constrainedHeight="true"
app:layout_constraintTop_toBottomOf="@android:id/list" />

Wyświetl plik

@ -6,8 +6,8 @@
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="@+id/status_bar_guideline"
app:layout_constraintBottom_toBottomOf="@+id/navigation_bar_guideline"
app:layout_constraintStart_toStartOf="@+id/parent_start_guideline"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/parent_end_guideline"
android:elevation="1000dp"
android:visibility="gone"
@ -17,22 +17,23 @@
android:id="@+id/dropdown_anchor"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_alignParentLeft="true"
android:layout_gravity="left"
tools:ignore="RtlHardcoded" />
<View
<FrameLayout
android:id="@+id/toolbar_shade"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:background="@color/reactions_screen_shade_color"
android:layout_alignParentTop="true" />
android:background="@color/reactions_screen_light_shade_color"
android:foreground="@color/reactions_screen_dark_shade_color" />
<View
<FrameLayout
android:id="@+id/input_shade"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@color/reactions_screen_shade_color"
android:layout_alignParentBottom="true" />
android:layout_gravity="bottom"
android:background="@color/reactions_screen_light_shade_color"
android:foreground="@color/reactions_screen_dark_shade_color" />
<View
android:id="@+id/conversation_item"

Wyświetl plik

@ -58,12 +58,13 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/edit_reactions_fragment_scrubber" />
<View
<FrameLayout
android:id="@+id/edit_reactions_fragment_reaction_mask"
android:layout_width="0dp"
android:layout_height="0dp"
android:alpha="0"
android:background="@color/reactions_screen_shade_color"
android:background="@color/reactions_screen_light_shade_color"
android:foreground="@color/reactions_screen_dark_shade_color"
app:elevation="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"

Wyświetl plik

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<View xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@color/reactions_screen_shade_color"
android:background="@color/reactions_screen_light_shade_color"
android:foreground="@color/reactions_screen_dark_shade_color"
android:fitsSystemWindows="true" />

Wyświetl plik

@ -126,8 +126,9 @@
<color name="reactions_pill_text_color">@color/core_grey_35</color>
<color name="reactions_pill_selected_text_color">@color/core_grey_15</color>
<color name="reactions_screen_shade_color">@color/transparent_black_60</color>
<color name="reactions_status_bar_shade">#070707</color>
<color name="reactions_screen_dark_shade_color">@color/transparent_black_70</color>
<color name="reactions_screen_light_shade_color">#df5e5e5e</color>
<color name="reactions_status_bar_shade">#191919</color>
<color name="recipient_contact_button_color">@color/core_grey_80</color>

Wyświetl plik

@ -14,6 +14,7 @@
<color name="transparent_black_40">#66000000</color>
<color name="transparent_black_50">#80000000</color>
<color name="transparent_black_60">#99000000</color>
<color name="transparent_black_70">#b3000000</color>
<color name="transparent_black_80">#CC000000</color>
<color name="transparent_black_90">#e6000000</color>
@ -26,12 +27,13 @@
<color name="transparent_white_40">#66ffffff</color>
<color name="transparent_white_60">#99ffffff</color>
<color name="transparent_white_80">#ccffffff</color>
<color name="transparent_white_87">#dfffffff</color>
<color name="transparent_white_90">#e6ffffff</color>
<color name="transparent_white_95">#f3ffffff</color>
<color name="conversation_compose_divider">#32000000</color>
<color name="conversation_item_selected_system_ui">@color/core_grey_60</color>
<color name="conversation_item_selected_system_ui">#4d4d4d</color>
<color name="touch_highlight">#400099cc</color>
<color name="device_link_item_background_light">#ffffffff</color>

Wyświetl plik

@ -3,6 +3,5 @@
<integer name="reaction_scrubber_reveal_duration">200</integer>
<integer name="reaction_scrubber_reveal_offset">100</integer>
<integer name="reaction_scrubber_hide_duration">150</integer>
<integer name="reaction_scrubber_reveal_emoji_duration">380</integer>
<integer name="reaction_scrubber_emoji_reveal_duration_start_delay_factor">10</integer>
</resources>

Wyświetl plik

@ -126,8 +126,9 @@
<color name="reactions_pill_text_color">@color/core_grey_60</color>
<color name="reactions_pill_selected_text_color">@color/core_grey_75</color>
<color name="reactions_screen_shade_color">@color/transparent_black_50</color>
<color name="reactions_status_bar_shade">#808080</color>
<color name="reactions_screen_dark_shade_color">@color/transparent_black_70</color>
<color name="reactions_screen_light_shade_color">@color/transparent_white_87</color>
<color name="reactions_status_bar_shade">#4d4d4d</color>
<color name="recipient_contact_button_color">@color/core_grey_02</color>