NekoX/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarPopupWindow.java

542 lines
19 KiB
Java
Raw Normal View History

/*
2019-01-23 18:03:33 +01:00
* This is the source code of Telegram for Android v. 5.x.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
2019-01-23 18:03:33 +01:00
* Copyright Nikolai Kudashov, 2013-2018.
*/
2014-11-13 21:10:14 +01:00
package org.telegram.ui.ActionBar;
2015-06-29 19:12:11 +02:00
import android.animation.Animator;
2019-08-22 01:53:26 +02:00
import android.animation.AnimatorListenerAdapter;
2015-06-29 19:12:11 +02:00
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
2015-06-29 19:12:11 +02:00
import android.graphics.Canvas;
2019-12-31 14:08:08 +01:00
import android.graphics.Color;
2017-03-31 01:58:05 +02:00
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
2015-06-29 19:12:11 +02:00
import android.graphics.drawable.Drawable;
import android.os.Build;
2019-12-31 14:08:08 +01:00
2019-05-14 14:08:05 +02:00
import androidx.annotation.Keep;
import android.view.KeyEvent;
import android.view.View;
2015-07-22 20:56:37 +02:00
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
2019-08-22 01:53:26 +02:00
import android.view.WindowManager;
2015-06-29 19:12:11 +02:00
import android.view.animation.DecelerateInterpolator;
2015-07-22 20:56:37 +02:00
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
2015-07-22 20:56:37 +02:00
import android.widget.ScrollView;
2015-09-24 22:52:02 +02:00
import org.telegram.messenger.AndroidUtilities;
2014-11-21 11:59:05 +01:00
import org.telegram.messenger.FileLog;
2015-06-29 19:12:11 +02:00
import org.telegram.messenger.R;
2015-07-22 20:56:37 +02:00
import org.telegram.ui.Components.LayoutHelper;
2014-11-21 11:59:05 +01:00
import java.lang.reflect.Field;
2019-05-14 14:08:05 +02:00
import java.lang.reflect.Method;
2019-08-22 01:53:26 +02:00
import java.util.ArrayList;
2015-06-29 19:12:11 +02:00
import java.util.HashMap;
public class ActionBarPopupWindow extends PopupWindow {
2019-05-14 14:08:05 +02:00
private static Method layoutInScreenMethod;
private static final Field superListenerField;
2016-10-11 13:57:01 +02:00
private static final boolean allowAnimation = Build.VERSION.SDK_INT >= 18;
2015-06-29 19:12:11 +02:00
private static DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator();
private AnimatorSet windowAnimatorSet;
2016-10-11 13:57:01 +02:00
private boolean animationEnabled = allowAnimation;
2019-05-14 14:08:05 +02:00
private int dismissAnimationDuration = 150;
static {
Field f = null;
try {
f = PopupWindow.class.getDeclaredField("mOnScrollChangedListener");
f.setAccessible(true);
} catch (NoSuchFieldException e) {
/* ignored */
}
superListenerField = f;
}
2018-08-27 10:33:11 +02:00
private static final ViewTreeObserver.OnScrollChangedListener NOP = () -> {
/* do nothing */
};
private ViewTreeObserver.OnScrollChangedListener mSuperScrollListener;
private ViewTreeObserver mViewTreeObserver;
public interface OnDispatchKeyEventListener {
void onDispatchKeyEvent(KeyEvent keyEvent);
}
2015-07-22 20:56:37 +02:00
public static class ActionBarPopupWindowLayout extends FrameLayout {
private OnDispatchKeyEventListener mOnDispatchKeyEventListener;
2015-06-29 19:12:11 +02:00
private float backScaleX = 1;
private float backScaleY = 1;
private int backAlpha = 255;
private int lastStartedChild = 0;
private boolean showedFromBotton;
2016-10-11 13:57:01 +02:00
private boolean animationEnabled = allowAnimation;
2019-08-22 01:53:26 +02:00
private ArrayList<AnimatorSet> itemAnimators;
2015-06-29 19:12:11 +02:00
private HashMap<View, Integer> positions = new HashMap<>();
2015-07-22 20:56:37 +02:00
private ScrollView scrollView;
2017-03-31 01:58:05 +02:00
protected LinearLayout linearLayout;
2015-07-22 20:56:37 +02:00
2019-12-31 14:08:08 +01:00
private int backgroundColor = Color.WHITE;
2017-07-08 18:32:04 +02:00
protected Drawable backgroundDrawable;
public ActionBarPopupWindowLayout(Context context) {
super(context);
2015-06-29 19:12:11 +02:00
2019-05-14 14:08:05 +02:00
backgroundDrawable = getResources().getDrawable(R.drawable.popup_fixed_alert2).mutate();
2019-12-31 14:08:08 +01:00
setBackgroundColor(Theme.getColor(Theme.key_actionBarDefaultSubmenuBackground));
2015-07-22 20:56:37 +02:00
setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8), AndroidUtilities.dp(8));
setWillNotDraw(false);
2015-11-26 22:04:02 +01:00
try {
scrollView = new ScrollView(context);
scrollView.setVerticalScrollBarEnabled(false);
addView(scrollView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT));
} catch (Throwable e) {
2017-03-31 01:58:05 +02:00
FileLog.e(e);
2015-11-26 22:04:02 +01:00
}
2015-07-22 20:56:37 +02:00
linearLayout = new LinearLayout(context);
linearLayout.setOrientation(LinearLayout.VERTICAL);
2015-11-26 22:04:02 +01:00
if (scrollView != null) {
scrollView.addView(linearLayout, new ScrollView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
} else {
addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT));
}
2015-06-29 19:12:11 +02:00
}
public void setShowedFromBotton(boolean value) {
showedFromBotton = value;
}
public void setDispatchKeyEventListener(OnDispatchKeyEventListener listener) {
mOnDispatchKeyEventListener = listener;
}
2019-12-31 14:08:08 +01:00
public int getBackgroundColor() {
return backgroundColor;
}
public void setBackgroundColor(int color) {
if (backgroundColor != color) {
backgroundDrawable.setColorFilter(new PorterDuffColorFilter(backgroundColor = color, PorterDuff.Mode.MULTIPLY));
}
}
2018-07-30 04:07:02 +02:00
@Keep
2015-06-29 19:12:11 +02:00
public void setBackAlpha(int value) {
backAlpha = value;
}
2018-07-30 04:07:02 +02:00
@Keep
2015-06-29 19:12:11 +02:00
public int getBackAlpha() {
return backAlpha;
}
2018-07-30 04:07:02 +02:00
@Keep
2015-06-29 19:12:11 +02:00
public void setBackScaleX(float value) {
backScaleX = value;
invalidate();
}
2018-07-30 04:07:02 +02:00
@Keep
2015-06-29 19:12:11 +02:00
public void setBackScaleY(float value) {
backScaleY = value;
if (animationEnabled) {
int height = getMeasuredHeight() - AndroidUtilities.dp(16);
if (showedFromBotton) {
for (int a = lastStartedChild; a >= 0; a--) {
2015-07-22 20:56:37 +02:00
View child = getItemAt(a);
2015-06-29 19:12:11 +02:00
if (child.getVisibility() != VISIBLE) {
continue;
}
2015-08-13 11:23:31 +02:00
Integer position = positions.get(child);
if (position != null && height - (position * AndroidUtilities.dp(48) + AndroidUtilities.dp(32)) > value * height) {
2015-06-29 19:12:11 +02:00
break;
}
lastStartedChild = a - 1;
startChildAnimation(child);
}
} else {
2019-08-22 01:53:26 +02:00
int count = getItemsCount();
2015-06-29 19:12:11 +02:00
for (int a = lastStartedChild; a < count; a++) {
2015-07-22 20:56:37 +02:00
View child = getItemAt(a);
2015-06-29 19:12:11 +02:00
if (child.getVisibility() != VISIBLE) {
continue;
}
2015-08-13 11:23:31 +02:00
Integer position = positions.get(child);
if (position != null && (position + 1) * AndroidUtilities.dp(48) - AndroidUtilities.dp(24) > value * height) {
2015-06-29 19:12:11 +02:00
break;
}
lastStartedChild = a + 1;
startChildAnimation(child);
}
}
}
invalidate();
}
2017-07-08 18:32:04 +02:00
public void setBackgroundDrawable(Drawable drawable) {
2019-12-31 14:08:08 +01:00
backgroundColor = Color.WHITE;
2017-07-08 18:32:04 +02:00
backgroundDrawable = drawable;
}
2015-06-29 19:12:11 +02:00
private void startChildAnimation(View child) {
if (animationEnabled) {
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(
2019-08-22 01:53:26 +02:00
ObjectAnimator.ofFloat(child, View.ALPHA, 0.0f, 1.0f),
ObjectAnimator.ofFloat(child, View.TRANSLATION_Y, AndroidUtilities.dp(showedFromBotton ? 6 : -6), 0));
2015-06-29 19:12:11 +02:00
animatorSet.setDuration(180);
2019-08-22 01:53:26 +02:00
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
itemAnimators.remove(animatorSet);
}
});
2015-06-29 19:12:11 +02:00
animatorSet.setInterpolator(decelerateInterpolator);
animatorSet.start();
2019-08-22 01:53:26 +02:00
if (itemAnimators == null) {
itemAnimators = new ArrayList<>();
}
itemAnimators.add(animatorSet);
2015-06-29 19:12:11 +02:00
}
}
2016-10-11 13:57:01 +02:00
public void setAnimationEnabled(boolean value) {
animationEnabled = value;
}
2015-07-22 20:56:37 +02:00
@Override
public void addView(View child) {
linearLayout.addView(child);
}
public void addView(View child, LinearLayout.LayoutParams layoutParams) {
linearLayout.addView(child, layoutParams);
}
2016-10-11 13:57:01 +02:00
public void removeInnerViews() {
linearLayout.removeAllViews();
}
2015-06-29 19:12:11 +02:00
public float getBackScaleX() {
return backScaleX;
}
public float getBackScaleY() {
return backScaleY;
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (mOnDispatchKeyEventListener != null) {
mOnDispatchKeyEventListener.onDispatchKeyEvent(event);
}
return super.dispatchKeyEvent(event);
}
2015-06-29 19:12:11 +02:00
@Override
protected void onDraw(Canvas canvas) {
if (backgroundDrawable != null) {
backgroundDrawable.setAlpha(backAlpha);
if (showedFromBotton) {
2019-12-31 14:08:08 +01:00
final int height = getMeasuredHeight();
backgroundDrawable.setBounds(0, (int) (height * (1.0f - backScaleY)), (int) (getMeasuredWidth() * backScaleX), height);
2015-06-29 19:12:11 +02:00
} else {
backgroundDrawable.setBounds(0, 0, (int) (getMeasuredWidth() * backScaleX), (int) (getMeasuredHeight() * backScaleY));
}
backgroundDrawable.draw(canvas);
}
}
2015-07-22 20:56:37 +02:00
2019-08-22 01:53:26 +02:00
public Drawable getBackgroundDrawable() {
return backgroundDrawable;
}
2015-07-22 20:56:37 +02:00
public int getItemsCount() {
return linearLayout.getChildCount();
}
public View getItemAt(int index) {
return linearLayout.getChildAt(index);
}
public void scrollToTop() {
2015-11-26 22:04:02 +01:00
if (scrollView != null) {
scrollView.scrollTo(0, 0);
}
2015-07-22 20:56:37 +02:00
}
2020-07-26 10:03:38 +02:00
public void setupRadialSelectors(int color) {
int count = linearLayout.getChildCount();
for (int a = 0; a < count; a++) {
View child = linearLayout.getChildAt(a);
child.setBackground(Theme.createRadSelectorDrawable(color, a == 0 ? 6 : 0, a == count - 1 ? 6 : 0));
}
}
}
public ActionBarPopupWindow() {
super();
init();
}
public ActionBarPopupWindow(Context context) {
super(context);
init();
}
public ActionBarPopupWindow(int width, int height) {
super(width, height);
init();
}
public ActionBarPopupWindow(View contentView) {
super(contentView);
init();
}
public ActionBarPopupWindow(View contentView, int width, int height, boolean focusable) {
super(contentView, width, height, focusable);
init();
}
public ActionBarPopupWindow(View contentView, int width, int height) {
super(contentView, width, height);
init();
}
2016-10-11 13:57:01 +02:00
public void setAnimationEnabled(boolean value) {
animationEnabled = value;
}
2019-05-14 14:08:05 +02:00
@SuppressWarnings("PrivateAPI")
public void setLayoutInScreen(boolean value) {
try {
if (layoutInScreenMethod == null) {
layoutInScreenMethod = PopupWindow.class.getDeclaredMethod("setLayoutInScreenEnabled", boolean.class);
layoutInScreenMethod.setAccessible(true);
}
layoutInScreenMethod.invoke(this, true);
} catch (Exception e) {
FileLog.e(e);
}
}
private void init() {
if (superListenerField != null) {
try {
mSuperScrollListener = (ViewTreeObserver.OnScrollChangedListener) superListenerField.get(this);
superListenerField.set(this, NOP);
} catch (Exception e) {
mSuperScrollListener = null;
}
}
}
2019-05-14 14:08:05 +02:00
public void setDismissAnimationDuration(int value) {
dismissAnimationDuration = value;
}
private void unregisterListener() {
if (mSuperScrollListener != null && mViewTreeObserver != null) {
if (mViewTreeObserver.isAlive()) {
mViewTreeObserver.removeOnScrollChangedListener(mSuperScrollListener);
}
mViewTreeObserver = null;
}
}
private void registerListener(View anchor) {
if (mSuperScrollListener != null) {
ViewTreeObserver vto = (anchor.getWindowToken() != null) ? anchor.getViewTreeObserver() : null;
if (vto != mViewTreeObserver) {
if (mViewTreeObserver != null && mViewTreeObserver.isAlive()) {
mViewTreeObserver.removeOnScrollChangedListener(mSuperScrollListener);
}
if ((mViewTreeObserver = vto) != null) {
vto.addOnScrollChangedListener(mSuperScrollListener);
}
}
}
}
2019-08-22 01:53:26 +02:00
public void dimBehind() {
View container = getContentView().getRootView();
Context context = getContentView().getContext();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams p = (WindowManager.LayoutParams) container.getLayoutParams();
p.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
p.dimAmount = 0.2f;
wm.updateViewLayout(container, p);
}
@Override
public void showAsDropDown(View anchor, int xoff, int yoff) {
2014-11-21 11:59:05 +01:00
try {
super.showAsDropDown(anchor, xoff, yoff);
registerListener(anchor);
} catch (Exception e) {
2017-03-31 01:58:05 +02:00
FileLog.e(e);
2014-11-21 11:59:05 +01:00
}
}
2015-06-29 19:12:11 +02:00
public void startAnimation() {
if (animationEnabled) {
if (windowAnimatorSet != null) {
return;
}
ActionBarPopupWindowLayout content = (ActionBarPopupWindowLayout) getContentView();
content.setTranslationY(0);
content.setAlpha(1.0f);
content.setPivotX(content.getMeasuredWidth());
content.setPivotY(0);
2015-07-22 20:56:37 +02:00
int count = content.getItemsCount();
2015-06-29 19:12:11 +02:00
content.positions.clear();
int visibleCount = 0;
for (int a = 0; a < count; a++) {
2015-07-22 20:56:37 +02:00
View child = content.getItemAt(a);
2019-08-22 01:53:26 +02:00
child.setAlpha(0.0f);
2015-06-29 19:12:11 +02:00
if (child.getVisibility() != View.VISIBLE) {
continue;
}
content.positions.put(child, visibleCount);
visibleCount++;
}
if (content.showedFromBotton) {
content.lastStartedChild = count - 1;
} else {
content.lastStartedChild = 0;
}
windowAnimatorSet = new AnimatorSet();
windowAnimatorSet.playTogether(
ObjectAnimator.ofFloat(content, "backScaleY", 0.0f, 1.0f),
ObjectAnimator.ofInt(content, "backAlpha", 0, 255));
windowAnimatorSet.setDuration(150 + 16 * visibleCount);
windowAnimatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
windowAnimatorSet = null;
2019-08-22 01:53:26 +02:00
ActionBarPopupWindowLayout content = (ActionBarPopupWindowLayout) getContentView();
int count = content.getItemsCount();
for (int a = 0; a < count; a++) {
View child = content.getItemAt(a);
child.setAlpha(1.0f);
}
2015-06-29 19:12:11 +02:00
}
@Override
public void onAnimationCancel(Animator animation) {
onAnimationEnd(animation);
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
windowAnimatorSet.start();
}
}
@Override
public void update(View anchor, int xoff, int yoff, int width, int height) {
super.update(anchor, xoff, yoff, width, height);
registerListener(anchor);
}
@Override
public void update(View anchor, int width, int height) {
super.update(anchor, width, height);
registerListener(anchor);
}
@Override
public void showAtLocation(View parent, int gravity, int x, int y) {
super.showAtLocation(parent, gravity, x, y);
unregisterListener();
}
@Override
public void dismiss() {
2015-06-29 19:12:11 +02:00
dismiss(true);
}
public void dismiss(boolean animated) {
2015-11-26 22:04:02 +01:00
setFocusable(false);
2015-06-29 19:12:11 +02:00
if (animationEnabled && animated) {
if (windowAnimatorSet != null) {
windowAnimatorSet.cancel();
}
ActionBarPopupWindowLayout content = (ActionBarPopupWindowLayout) getContentView();
2019-12-31 14:08:08 +01:00
if (content.itemAnimators != null && !content.itemAnimators.isEmpty()) {
2019-08-22 01:53:26 +02:00
for (int a = 0, N = content.itemAnimators.size(); a < N; a++) {
2019-12-31 14:08:08 +01:00
AnimatorSet animatorSet = content.itemAnimators.get(a);
animatorSet.removeAllListeners();
animatorSet.cancel();
2019-08-22 01:53:26 +02:00
}
content.itemAnimators.clear();
}
2015-06-29 19:12:11 +02:00
windowAnimatorSet = new AnimatorSet();
windowAnimatorSet.playTogether(
2019-08-22 01:53:26 +02:00
ObjectAnimator.ofFloat(content, View.TRANSLATION_Y, AndroidUtilities.dp(content.showedFromBotton ? 5 : -5)),
ObjectAnimator.ofFloat(content, View.ALPHA, 0.0f));
2019-05-14 14:08:05 +02:00
windowAnimatorSet.setDuration(dismissAnimationDuration);
2015-06-29 19:12:11 +02:00
windowAnimatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
windowAnimatorSet = null;
setFocusable(false);
try {
ActionBarPopupWindow.super.dismiss();
2019-08-22 01:53:26 +02:00
} catch (Exception ignore) {
2015-06-29 19:12:11 +02:00
}
unregisterListener();
}
@Override
public void onAnimationCancel(Animator animation) {
onAnimationEnd(animation);
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
windowAnimatorSet.start();
} else {
try {
super.dismiss();
2019-08-22 01:53:26 +02:00
} catch (Exception ignore) {
2015-06-29 19:12:11 +02:00
}
unregisterListener();
2015-02-26 15:36:15 +01:00
}
}
}