mirror of https://github.com/NekoX-Dev/NekoX.git
369 lines
12 KiB
Java
369 lines
12 KiB
Java
/*
|
|
* 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).
|
|
*
|
|
* Copyright Nikolai Kudashov, 2013-2018.
|
|
*/
|
|
|
|
package org.telegram.ui.Components;
|
|
|
|
import android.content.Context;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Color;
|
|
import android.graphics.Paint;
|
|
import android.graphics.Paint.Style;
|
|
import android.graphics.drawable.Drawable;
|
|
import androidx.viewpager.widget.ViewPager;
|
|
import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
|
|
|
|
import android.graphics.drawable.RippleDrawable;
|
|
import android.os.Build;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
|
|
import android.widget.FrameLayout;
|
|
import android.widget.HorizontalScrollView;
|
|
import android.widget.ImageView;
|
|
import android.widget.LinearLayout;
|
|
|
|
import org.telegram.messenger.AndroidUtilities;
|
|
import org.telegram.ui.ActionBar.Theme;
|
|
|
|
public class PagerSlidingTabStrip extends HorizontalScrollView {
|
|
|
|
public interface IconTabProvider {
|
|
Drawable getPageIconDrawable(int position);
|
|
void customOnDraw(Canvas canvas, int position);
|
|
boolean canScrollToTab(int position);
|
|
}
|
|
|
|
private LinearLayout.LayoutParams defaultTabLayoutParams;
|
|
|
|
private final PageListener pageListener = new PageListener();
|
|
public OnPageChangeListener delegatePageListener;
|
|
|
|
private LinearLayout tabsContainer;
|
|
private ViewPager pager;
|
|
|
|
private int tabCount;
|
|
|
|
private int currentPosition = 0;
|
|
private float currentPositionOffset = 0f;
|
|
|
|
private Paint rectPaint;
|
|
|
|
private int indicatorColor = 0xff666666;
|
|
private int underlineColor = 0x1a000000;
|
|
|
|
private boolean shouldExpand = false;
|
|
|
|
private int scrollOffset = AndroidUtilities.dp(52);
|
|
private int indicatorHeight = AndroidUtilities.dp(8);
|
|
private int underlineHeight = AndroidUtilities.dp(2);
|
|
private int dividerPadding = AndroidUtilities.dp(12);
|
|
private int tabPadding = AndroidUtilities.dp(24);
|
|
|
|
private Theme.ResourcesProvider resourcesProvider;
|
|
private int lastScrollX = 0;
|
|
|
|
public PagerSlidingTabStrip(Context context, Theme.ResourcesProvider resourcesProvider) {
|
|
super(context);
|
|
this.resourcesProvider = resourcesProvider;
|
|
|
|
setFillViewport(true);
|
|
setWillNotDraw(false);
|
|
|
|
tabsContainer = new LinearLayout(context);
|
|
tabsContainer.setOrientation(LinearLayout.HORIZONTAL);
|
|
tabsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
|
|
addView(tabsContainer);
|
|
|
|
rectPaint = new Paint();
|
|
rectPaint.setAntiAlias(true);
|
|
rectPaint.setStyle(Style.FILL);
|
|
|
|
defaultTabLayoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutHelper.MATCH_PARENT);
|
|
}
|
|
|
|
public void setViewPager(ViewPager pager) {
|
|
this.pager = pager;
|
|
if (pager.getAdapter() == null) {
|
|
throw new IllegalStateException("ViewPager does not have adapter instance.");
|
|
}
|
|
pager.setOnPageChangeListener(pageListener);
|
|
notifyDataSetChanged();
|
|
}
|
|
|
|
public void setOnPageChangeListener(OnPageChangeListener listener) {
|
|
this.delegatePageListener = listener;
|
|
}
|
|
|
|
public void notifyDataSetChanged() {
|
|
tabsContainer.removeAllViews();
|
|
tabCount = pager.getAdapter().getCount();
|
|
for (int i = 0; i < tabCount; i++) {
|
|
if (pager.getAdapter() instanceof IconTabProvider) {
|
|
addIconTab(i, ((IconTabProvider) pager.getAdapter()).getPageIconDrawable(i), pager.getAdapter().getPageTitle(i));
|
|
}
|
|
}
|
|
updateTabStyles();
|
|
getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
|
|
@Override
|
|
public void onGlobalLayout() {
|
|
getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
|
currentPosition = pager.getCurrentItem();
|
|
scrollToChild(currentPosition, 0);
|
|
}
|
|
});
|
|
}
|
|
|
|
public View getTab(int position) {
|
|
if (position < 0 || position >= tabsContainer.getChildCount()) {
|
|
return null;
|
|
}
|
|
return tabsContainer.getChildAt(position);
|
|
}
|
|
|
|
private void addIconTab(final int position, Drawable drawable, CharSequence contentDescription) {
|
|
ImageView tab = new ImageView(getContext()) {
|
|
@Override
|
|
protected void onDraw(Canvas canvas) {
|
|
super.onDraw(canvas);
|
|
if (pager.getAdapter() instanceof IconTabProvider) {
|
|
((IconTabProvider) pager.getAdapter()).customOnDraw(canvas, position);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setSelected(boolean selected) {
|
|
super.setSelected(selected);
|
|
Drawable background = getBackground();
|
|
if (Build.VERSION.SDK_INT >= 21 && background != null) {
|
|
int color = getThemedColor(selected ? Theme.key_chat_emojiPanelIconSelected : Theme.key_chat_emojiBottomPanelIcon);
|
|
Theme.setSelectorDrawableColor(background, Color.argb(30, Color.red(color), Color.green(color), Color.blue(color)), true);
|
|
}
|
|
}
|
|
};
|
|
tab.setFocusable(true);
|
|
if (Build.VERSION.SDK_INT >= 21) {
|
|
RippleDrawable rippleDrawable = (RippleDrawable) Theme.createSelectorDrawable(getThemedColor(Theme.key_chat_emojiBottomPanelIcon));
|
|
Theme.setRippleDrawableForceSoftware(rippleDrawable);
|
|
tab.setBackground(rippleDrawable);
|
|
}
|
|
tab.setImageDrawable(drawable);
|
|
tab.setScaleType(ImageView.ScaleType.CENTER);
|
|
tab.setOnClickListener(v -> {
|
|
if (pager.getAdapter() instanceof IconTabProvider) {
|
|
if (!((IconTabProvider) pager.getAdapter()).canScrollToTab(position)) {
|
|
return;
|
|
}
|
|
}
|
|
pager.setCurrentItem(position, false);
|
|
});
|
|
tabsContainer.addView(tab);
|
|
tab.setSelected(position == currentPosition);
|
|
tab.setContentDescription(contentDescription);
|
|
}
|
|
|
|
private void updateTabStyles() {
|
|
for (int i = 0; i < tabCount; i++) {
|
|
View v = tabsContainer.getChildAt(i);
|
|
v.setLayoutParams(defaultTabLayoutParams);
|
|
if (shouldExpand) {
|
|
v.setPadding(0, 0, 0, 0);
|
|
v.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1.0F));
|
|
} else {
|
|
v.setPadding(tabPadding, 0, tabPadding, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
if (!shouldExpand || MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) {
|
|
return;
|
|
}
|
|
int myWidth = getMeasuredWidth();
|
|
tabsContainer.measure(MeasureSpec.EXACTLY | myWidth, heightMeasureSpec);
|
|
}
|
|
|
|
private void scrollToChild(int position, int offset) {
|
|
if (tabCount == 0) {
|
|
return;
|
|
}
|
|
int newScrollX = tabsContainer.getChildAt(position).getLeft() + offset;
|
|
if (position > 0 || offset > 0) {
|
|
newScrollX -= scrollOffset;
|
|
}
|
|
if (newScrollX != lastScrollX) {
|
|
lastScrollX = newScrollX;
|
|
scrollTo(newScrollX, 0);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onDraw(Canvas canvas) {
|
|
super.onDraw(canvas);
|
|
|
|
if (isInEditMode() || tabCount == 0) {
|
|
return;
|
|
}
|
|
|
|
final int height = getHeight();
|
|
|
|
if (underlineHeight != 0) {
|
|
rectPaint.setColor(underlineColor);
|
|
canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint);
|
|
}
|
|
|
|
View currentTab = tabsContainer.getChildAt(currentPosition);
|
|
float lineLeft = currentTab.getLeft();
|
|
float lineRight = currentTab.getRight();
|
|
|
|
if (currentPositionOffset > 0f && currentPosition < tabCount - 1) {
|
|
View nextTab = tabsContainer.getChildAt(currentPosition + 1);
|
|
final float nextTabLeft = nextTab.getLeft();
|
|
final float nextTabRight = nextTab.getRight();
|
|
|
|
lineLeft = (currentPositionOffset * nextTabLeft + (1f - currentPositionOffset) * lineLeft);
|
|
lineRight = (currentPositionOffset * nextTabRight + (1f - currentPositionOffset) * lineRight);
|
|
}
|
|
|
|
if (indicatorHeight != 0) {
|
|
rectPaint.setColor(indicatorColor);
|
|
canvas.drawRect(lineLeft, height - indicatorHeight, lineRight, height, rectPaint);
|
|
}
|
|
}
|
|
|
|
private class PageListener implements OnPageChangeListener {
|
|
|
|
@Override
|
|
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
|
currentPosition = position;
|
|
currentPositionOffset = positionOffset;
|
|
scrollToChild(position, (int) (positionOffset * tabsContainer.getChildAt(position).getWidth()));
|
|
invalidate();
|
|
if (delegatePageListener != null) {
|
|
delegatePageListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onPageScrollStateChanged(int state) {
|
|
if (state == ViewPager.SCROLL_STATE_IDLE) {
|
|
scrollToChild(pager.getCurrentItem(), 0);
|
|
}
|
|
if (delegatePageListener != null) {
|
|
delegatePageListener.onPageScrollStateChanged(state);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onPageSelected(int position) {
|
|
if (delegatePageListener != null) {
|
|
delegatePageListener.onPageSelected(position);
|
|
}
|
|
for (int a = 0; a < tabsContainer.getChildCount(); a++) {
|
|
tabsContainer.getChildAt(a).setSelected(a == position);
|
|
}
|
|
}
|
|
}
|
|
|
|
private int getThemedColor(String key) {
|
|
Integer color = resourcesProvider != null ? resourcesProvider.getColor(key) : null;
|
|
return color != null ? color : Theme.getColor(key);
|
|
}
|
|
|
|
public void onSizeChanged(int paramInt1, int paramInt2, int paramInt3, int paramInt4) {
|
|
if (!shouldExpand) {
|
|
post(PagerSlidingTabStrip.this::notifyDataSetChanged);
|
|
}
|
|
}
|
|
|
|
public void setIndicatorColor(int indicatorColor) {
|
|
this.indicatorColor = indicatorColor;
|
|
invalidate();
|
|
}
|
|
|
|
public void setIndicatorColorResource(int resId) {
|
|
this.indicatorColor = getResources().getColor(resId);
|
|
invalidate();
|
|
}
|
|
|
|
public int getIndicatorColor() {
|
|
return this.indicatorColor;
|
|
}
|
|
|
|
public void setIndicatorHeight(int indicatorLineHeightPx) {
|
|
this.indicatorHeight = indicatorLineHeightPx;
|
|
invalidate();
|
|
}
|
|
|
|
public int getIndicatorHeight() {
|
|
return indicatorHeight;
|
|
}
|
|
|
|
public void setUnderlineColor(int underlineColor) {
|
|
this.underlineColor = underlineColor;
|
|
invalidate();
|
|
}
|
|
|
|
public void setUnderlineColorResource(int resId) {
|
|
this.underlineColor = getResources().getColor(resId);
|
|
invalidate();
|
|
}
|
|
|
|
public int getUnderlineColor() {
|
|
return underlineColor;
|
|
}
|
|
|
|
public void setUnderlineHeight(int underlineHeightPx) {
|
|
this.underlineHeight = underlineHeightPx;
|
|
invalidate();
|
|
}
|
|
|
|
public int getUnderlineHeight() {
|
|
return underlineHeight;
|
|
}
|
|
|
|
public void setDividerPadding(int dividerPaddingPx) {
|
|
this.dividerPadding = dividerPaddingPx;
|
|
invalidate();
|
|
}
|
|
|
|
public int getDividerPadding() {
|
|
return dividerPadding;
|
|
}
|
|
|
|
public void setScrollOffset(int scrollOffsetPx) {
|
|
this.scrollOffset = scrollOffsetPx;
|
|
invalidate();
|
|
}
|
|
|
|
public int getScrollOffset() {
|
|
return scrollOffset;
|
|
}
|
|
|
|
public void setShouldExpand(boolean shouldExpand) {
|
|
this.shouldExpand = shouldExpand;
|
|
tabsContainer.setLayoutParams(new FrameLayout.LayoutParams(-1, -1));
|
|
updateTabStyles();
|
|
requestLayout();
|
|
}
|
|
|
|
public boolean getShouldExpand() {
|
|
return shouldExpand;
|
|
}
|
|
|
|
public void setTabPaddingLeftRight(int paddingPx) {
|
|
this.tabPadding = paddingPx;
|
|
updateTabStyles();
|
|
}
|
|
|
|
public int getTabPaddingLeftRight() {
|
|
return tabPadding;
|
|
}
|
|
}
|