From 18d62e5d568cfab6377d558525896025468714ff Mon Sep 17 00:00:00 2001 From: 18401019693 Date: Sat, 20 Aug 2022 15:33:41 +0800 Subject: [PATCH] =?UTF-8?q?=E7=9B=B4=E6=92=AD=E9=97=B4=E7=9A=84=E6=BB=9A?= =?UTF-8?q?=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/views/weight/MyDrawerLayout.java | 31 + .../views/weight/VerticalViewPager.java | 2836 +++++++++++++++++ config.gradle | 2 +- .../yunbao/live/activity/LiveActivity.java | 8 +- .../live/activity/LiveAudienceActivity.java | 1036 ++---- .../live/adapter/VerticalPagerAdapter.java | 63 + .../yunbao/live/dialog/BlowkissDialog.java | 4 +- .../live/dialog/LiveMoreDialogFragment.java | 14 +- .../com/yunbao/live/dialog/NewUserDialog.java | 13 +- .../presenter/LiveLinkMicPkPresenter.java | 16 +- .../presenter/LiveRyLinkMicPkPresenter.java | 107 +- .../com/yunbao/live/socket/SocketClient.java | 2 +- .../yunbao/live/socket/SocketRyClient.java | 10 +- .../live/views/LiveActivityLifeCallback.java | 63 + .../live/views/LiveAddImpressViewHolder.java | 8 +- .../live/views/LiveContributeViewHolder.java | 4 +- .../live/views/LiveMedalRankViewHolder.java | 4 +- .../yunbao/live/views/LivePlayListener.java | 27 + .../live/views/LivePlayRyViewHolder.java | 48 +- .../yunbao/live/views/LiveRoomViewHolder.java | 19 +- .../yunbao/live/views/LiveWebViewHolder.java | 4 +- .../live/views/PortraitLiveManager.java | 1286 ++++++++ .../live/views/TurnTableWebViewHolder.java | 4 +- .../live/views/WishlistWebViewHolder.java | 4 +- live/src/main/res/drawable/img_loading_01.png | Bin 0 -> 1898 bytes live/src/main/res/drawable/img_loading_02.png | Bin 0 -> 1902 bytes live/src/main/res/drawable/img_loading_03.png | Bin 0 -> 1892 bytes .../main/res/drawable/loading_animation.xml | 14 + .../res/layout/activity_live_audience.xml | 10 +- .../main/res/layout/activity_live_detail.xml | 13 + .../res/layout/layout_portrait_live_item.xml | 20 + .../yunbao/main/activity/MainActivity.java | 8 +- 32 files changed, 4663 insertions(+), 1015 deletions(-) create mode 100644 common/src/main/java/com/yunbao/common/views/weight/MyDrawerLayout.java create mode 100644 common/src/main/java/com/yunbao/common/views/weight/VerticalViewPager.java create mode 100644 live/src/main/java/com/yunbao/live/adapter/VerticalPagerAdapter.java create mode 100644 live/src/main/java/com/yunbao/live/views/LiveActivityLifeCallback.java create mode 100644 live/src/main/java/com/yunbao/live/views/LivePlayListener.java create mode 100644 live/src/main/java/com/yunbao/live/views/PortraitLiveManager.java create mode 100644 live/src/main/res/drawable/img_loading_01.png create mode 100644 live/src/main/res/drawable/img_loading_02.png create mode 100644 live/src/main/res/drawable/img_loading_03.png create mode 100644 live/src/main/res/drawable/loading_animation.xml create mode 100644 live/src/main/res/layout/activity_live_detail.xml create mode 100644 live/src/main/res/layout/layout_portrait_live_item.xml diff --git a/common/src/main/java/com/yunbao/common/views/weight/MyDrawerLayout.java b/common/src/main/java/com/yunbao/common/views/weight/MyDrawerLayout.java new file mode 100644 index 000000000..876d2ebfb --- /dev/null +++ b/common/src/main/java/com/yunbao/common/views/weight/MyDrawerLayout.java @@ -0,0 +1,31 @@ +package com.yunbao.common.views.weight; + +import android.content.Context; +import android.util.AttributeSet; + +import androidx.drawerlayout.widget.DrawerLayout; + +//解决直播间冲突 +public class MyDrawerLayout extends DrawerLayout { + public MyDrawerLayout(Context context) { + super(context); + } + + public MyDrawerLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public MyDrawerLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + widthMeasureSpec = MeasureSpec.makeMeasureSpec( + MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY); + heightMeasureSpec = MeasureSpec.makeMeasureSpec( + MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/yunbao/common/views/weight/VerticalViewPager.java b/common/src/main/java/com/yunbao/common/views/weight/VerticalViewPager.java new file mode 100644 index 000000000..d09c17b4d --- /dev/null +++ b/common/src/main/java/com/yunbao/common/views/weight/VerticalViewPager.java @@ -0,0 +1,2836 @@ +package com.yunbao.common.views.weight; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.database.DataSetObserver; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.SystemClock; +import android.util.AttributeSet; +import android.util.Log; +import android.view.FocusFinder; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.SoundEffectConstants; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.view.accessibility.AccessibilityEvent; +import android.view.animation.Interpolator; +import android.widget.Scroller; + +import androidx.core.os.ParcelableCompat; +import androidx.core.os.ParcelableCompatCreatorCallbacks; +import androidx.core.view.AccessibilityDelegateCompat; +import androidx.core.view.MotionEventCompat; +import androidx.core.view.VelocityTrackerCompat; +import androidx.core.view.ViewCompat; +import androidx.core.view.ViewConfigurationCompat; +import androidx.core.view.accessibility.AccessibilityEventCompat; +import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; +import androidx.core.view.accessibility.AccessibilityRecordCompat; +import androidx.core.widget.EdgeEffectCompat; +import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +public class VerticalViewPager extends ViewGroup { + + private static final String TAG = "ViewPager"; + private static final boolean DEBUG = false; + + private static final boolean USE_CACHE = false; + + private static final int DEFAULT_OFFSCREEN_PAGES = 1; + private static final int MAX_SETTLE_DURATION = 600; // ms + private static final int MIN_DISTANCE_FOR_FLING = 25; // dips + + private static final int DEFAULT_GUTTER_SIZE = 16; // dips + + private static final int MIN_FLING_VELOCITY = 400; // dips + + private static final int[] LAYOUT_ATTRS = new int[]{ + android.R.attr.layout_gravity + }; + + public void setEnableScroll(boolean enableScroll) { + this.mEnableScroll = enableScroll; + } + + + private boolean mEnableScroll = true; + + /** + * Used to track what the expected number of items in the adapter should be. + * If the app changes this when we don't expect it, we'll throw a big obnoxious exception. + */ + private int mExpectedAdapterCount; + + static class ItemInfo { + Object object; + int position; + boolean scrolling; + float heightFactor; + float offset; + } + + private static final Comparator COMPARATOR = new Comparator() { + @Override + public int compare(ItemInfo lhs, ItemInfo rhs) { + return lhs.position - rhs.position; + } + }; + + private static final Interpolator sInterpolator = new Interpolator() { + public float getInterpolation(float t) { + t -= 1.0f; + return t * t * t * t * t + 1.0f; + } + }; + + private final ArrayList mItems = new ArrayList(); + private final ItemInfo mTempItem = new ItemInfo(); + + private final Rect mTempRect = new Rect(); + + private PagerAdapter mAdapter; + private int mCurItem; // Index of currently displayed page. + private int mRestoredCurItem = -1; + private Parcelable mRestoredAdapterState = null; + private ClassLoader mRestoredClassLoader = null; + private Scroller mScroller; + private PagerObserver mObserver; + + private int mPageMargin; + private Drawable mMarginDrawable; + private int mLeftPageBounds; + private int mRightPageBounds; + + // Offsets of the first and last items, if known. + // Set during population, used to determine if we are at the beginning + // or end of the pager data set during touch scrolling. + private float mFirstOffset = -Float.MAX_VALUE; + private float mLastOffset = Float.MAX_VALUE; + + private int mChildWidthMeasureSpec; + private int mChildHeightMeasureSpec; + private boolean mInLayout; + + private boolean mScrollingCacheEnabled; + + private boolean mPopulatePending; + private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES; + + private boolean mIsBeingDragged; + private boolean mIsUnableToDrag; + private boolean mIgnoreGutter; + private int mDefaultGutterSize; + private int mGutterSize; + private int mTouchSlop; + /** + * Position of the last motion event. + */ + private float mLastMotionX; + private float mLastMotionY; + private float mInitialMotionX; + private float mInitialMotionY; + /** + * ID of the active pointer. This is used to retain consistency during + * drags/flings if multiple pointers are used. + */ + private int mActivePointerId = INVALID_POINTER; + /** + * Sentinel value for no current active pointer. + * Used by {@link #mActivePointerId}. + */ + private static final int INVALID_POINTER = -1; + + /** + * Determines speed during touch scrolling + */ + private VelocityTracker mVelocityTracker; + private int mMinimumVelocity; + private int mMaximumVelocity; + private int mFlingDistance; + private int mCloseEnough; + + // If the pager is at least this close to its final position, complete the scroll + // on touch down and let the user interact with the content inside instead of + // "catching" the flinging pager. + private static final int CLOSE_ENOUGH = 2; // dp + + private boolean mFakeDragging; + private long mFakeDragBeginTime; + + private EdgeEffectCompat mTopEdge; + private EdgeEffectCompat mBottomEdge; + + private boolean mFirstLayout = true; + private boolean mNeedCalculatePageOffsets = false; + private boolean mCalledSuper; + private int mDecorChildCount; + + private ViewPager.OnPageChangeListener mOnPageChangeListener; + private ViewPager.OnPageChangeListener mInternalPageChangeListener; + private OnAdapterChangeListener mAdapterChangeListener; + private ViewPager.PageTransformer mPageTransformer; + private Method mSetChildrenDrawingOrderEnabled; + + private static final int DRAW_ORDER_DEFAULT = 0; + private static final int DRAW_ORDER_FORWARD = 1; + private static final int DRAW_ORDER_REVERSE = 2; + private int mDrawingOrder; + private ArrayList mDrawingOrderedChildren; + private static final ViewPositionComparator sPositionComparator = new ViewPositionComparator(); + + /** + * Indicates that the pager is in an idle, settled state. The current page + * is fully in view and no animation is in progress. + */ + public static final int SCROLL_STATE_IDLE = 0; + + /** + * Indicates that the pager is currently being dragged by the user. + */ + public static final int SCROLL_STATE_DRAGGING = 1; + + /** + * Indicates that the pager is in the process of settling to a final position. + */ + public static final int SCROLL_STATE_SETTLING = 2; + + private final Runnable mEndScrollRunnable = new Runnable() { + public void run() { + setScrollState(SCROLL_STATE_IDLE); + populate(); + } + }; + + private int mScrollState = SCROLL_STATE_IDLE; + + /** + * Used internally to monitor when adapters are switched. + */ + interface OnAdapterChangeListener { + public void onAdapterChanged(PagerAdapter oldAdapter, PagerAdapter newAdapter); + } + + /** + * Used internally to tag special types of child views that should be added as + * pager decorations by default. + */ + interface Decor { + } + + public VerticalViewPager(Context context) { + super(context); + initViewPager(); + } + + public VerticalViewPager(Context context, AttributeSet attrs) { + super(context, attrs); + initViewPager(); + } + + void initViewPager() { + setWillNotDraw(false); + setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); + setFocusable(true); + final Context context = getContext(); + mScroller = new Scroller(context, sInterpolator); + final ViewConfiguration configuration = ViewConfiguration.get(context); + final float density = context.getResources().getDisplayMetrics().density; + + mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); + mMinimumVelocity = (int) (MIN_FLING_VELOCITY * density); + mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); + mTopEdge = new EdgeEffectCompat(context); + mBottomEdge = new EdgeEffectCompat(context); + + mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density); + mCloseEnough = (int) (CLOSE_ENOUGH * density); + mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density); + + ViewCompat.setAccessibilityDelegate(this, new MyAccessibilityDelegate()); + + if (ViewCompat.getImportantForAccessibility(this) + == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { + ViewCompat.setImportantForAccessibility(this, + ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); + } + } + + @Override + protected void onDetachedFromWindow() { + removeCallbacks(mEndScrollRunnable); + super.onDetachedFromWindow(); + } + + private void setScrollState(int newState) { + if (mScrollState == newState) { + return; + } + + mScrollState = newState; + if (mPageTransformer != null) { + // PageTransformers can do complex things that benefit from hardware layers. + enableLayers(newState != SCROLL_STATE_IDLE); + } + if (mOnPageChangeListener != null) { + mOnPageChangeListener.onPageScrollStateChanged(newState); + } + } + + /** + * Set a PagerAdapter that will supply views for this pager as needed. + * + * @param adapter Adapter to use + */ + public void setAdapter(PagerAdapter adapter) { + if (mAdapter != null) { + mAdapter.unregisterDataSetObserver(mObserver); + mAdapter.startUpdate(this); + for (int i = 0; i < mItems.size(); i++) { + final ItemInfo ii = mItems.get(i); + mAdapter.destroyItem(this, ii.position, ii.object); + } + mAdapter.finishUpdate(this); + mItems.clear(); + removeNonDecorViews(); + mCurItem = 0; + scrollTo(0, 0); + } + + final PagerAdapter oldAdapter = mAdapter; + mAdapter = adapter; + mExpectedAdapterCount = 0; + + if (mAdapter != null) { + if (mObserver == null) { + mObserver = new PagerObserver(); + } + mAdapter.registerDataSetObserver(mObserver); + mPopulatePending = false; + final boolean wasFirstLayout = mFirstLayout; + mFirstLayout = true; + mExpectedAdapterCount = mAdapter.getCount(); + if (mRestoredCurItem >= 0) { + mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); + setCurrentItemInternal(mRestoredCurItem, false, true); + mRestoredCurItem = -1; + mRestoredAdapterState = null; + mRestoredClassLoader = null; + } else if (!wasFirstLayout) { + populate(); + } else { + requestLayout(); + } + } + + if (mAdapterChangeListener != null && oldAdapter != adapter) { + mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter); + } + } + + private void removeNonDecorViews() { + for (int i = 0; i < getChildCount(); i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (!lp.isDecor) { + removeViewAt(i); + i--; + } + } + } + + /** + * Retrieve the current adapter supplying pages. + * + * @return The currently registered PagerAdapter + */ + public PagerAdapter getAdapter() { + return mAdapter; + } + + void setOnAdapterChangeListener(OnAdapterChangeListener listener) { + mAdapterChangeListener = listener; + } + +// private int getClientWidth() { +// return getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); +// } + + private int getClientHeight() { + return getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); + } + + + /** + * Set the currently selected page. If the ViewPager has already been through its first + * layout with its current adapter there will be a smooth animated transition between + * the current item and the specified item. + * + * @param item Item index to select + */ + public void setCurrentItem(int item) { + mPopulatePending = false; + setCurrentItemInternal(item, !mFirstLayout, false); + } + + /** + * Set the currently selected page. + * + * @param item Item index to select + * @param smoothScroll True to smoothly scroll to the new item, false to transition immediately + */ + public void setCurrentItem(int item, boolean smoothScroll) { + mPopulatePending = false; + setCurrentItemInternal(item, smoothScroll, false); + } + + public int getCurrentItem() { + return mCurItem; + } + + void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) { + setCurrentItemInternal(item, smoothScroll, always, 0); + } + + void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) { + if (mAdapter == null || mAdapter.getCount() <= 0) { + setScrollingCacheEnabled(false); + return; + } + if (!always && mCurItem == item && mItems.size() != 0) { + setScrollingCacheEnabled(false); + return; + } + + if (item < 0) { + item = 0; + } else if (item >= mAdapter.getCount()) { + item = mAdapter.getCount() - 1; + } + final int pageLimit = mOffscreenPageLimit; + if (item > (mCurItem + pageLimit) || item < (mCurItem - pageLimit)) { + // We are doing a jump by more than one page. To avoid + // glitches, we want to keep all current pages in the view + // until the scroll ends. + for (int i = 0; i < mItems.size(); i++) { + mItems.get(i).scrolling = true; + } + } + final boolean dispatchSelected = mCurItem != item; + + if (mFirstLayout) { + // We don't have any idea how big we are yet and shouldn't have any pages either. + // Just set things up and let the pending layout handle things. + mCurItem = item; + if (dispatchSelected && mOnPageChangeListener != null) { + mOnPageChangeListener.onPageSelected(item); + } + if (dispatchSelected && mInternalPageChangeListener != null) { + mInternalPageChangeListener.onPageSelected(item); + } + requestLayout(); + } else { + populate(item); + scrollToItem(item, smoothScroll, velocity, dispatchSelected); + } + } + + private void scrollToItem(int item, boolean smoothScroll, int velocity, + boolean dispatchSelected) { + final ItemInfo curInfo = infoForPosition(item); + int destY = 0; + if (curInfo != null) { + final int height = getClientHeight(); + destY = (int) (height * Math.max(mFirstOffset, + Math.min(curInfo.offset, mLastOffset))); + } + if (smoothScroll) { + smoothScrollTo(0, destY, velocity); + if (dispatchSelected && mOnPageChangeListener != null) { + mOnPageChangeListener.onPageSelected(item); + } + if (dispatchSelected && mInternalPageChangeListener != null) { + mInternalPageChangeListener.onPageSelected(item); + } + } else { + if (dispatchSelected && mOnPageChangeListener != null) { + mOnPageChangeListener.onPageSelected(item); + } + if (dispatchSelected && mInternalPageChangeListener != null) { + mInternalPageChangeListener.onPageSelected(item); + } + completeScroll(false); + scrollTo(0, destY); + pageScrolled(destY); + } + } + + /** + * Set a listener that will be invoked whenever the page changes or is incrementally + * scrolled. See {@link ViewPager.OnPageChangeListener}. + * + * @param listener Listener to set + */ + public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { + mOnPageChangeListener = listener; + } + + /** + * Set a {@link ViewPager.PageTransformer} that will be called for each attached page whenever + * the scroll position is changed. This allows the application to apply custom property + * transformations to each page, overriding the default sliding look and feel. + *

+ *

Note: Prior to Android 3.0 the property animation APIs did not exist. + * As a result, setting a PageTransformer prior to Android 3.0 (API 11) will have no effect.

+ * + * @param reverseDrawingOrder true if the supplied PageTransformer requires page views + * to be drawn from last to first instead of first to last. + * @param transformer PageTransformer that will modify each page's animation properties + */ + public void setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer) { + if (Build.VERSION.SDK_INT >= 11) { + final boolean hasTransformer = transformer != null; + final boolean needsPopulate = hasTransformer != (mPageTransformer != null); + mPageTransformer = transformer; + setChildrenDrawingOrderEnabledCompat(hasTransformer); + if (hasTransformer) { + mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD; + } else { + mDrawingOrder = DRAW_ORDER_DEFAULT; + } + if (needsPopulate) populate(); + } + } + + void setChildrenDrawingOrderEnabledCompat(boolean enable) { + if (Build.VERSION.SDK_INT >= 7) { + if (mSetChildrenDrawingOrderEnabled == null) { + try { + mSetChildrenDrawingOrderEnabled = ViewGroup.class.getDeclaredMethod( + "setChildrenDrawingOrderEnabled", new Class[]{Boolean.TYPE}); + } catch (NoSuchMethodException e) { + Log.e(TAG, "Can't find setChildrenDrawingOrderEnabled", e); + } + } + try { + mSetChildrenDrawingOrderEnabled.invoke(this, enable); + } catch (Exception e) { + Log.e(TAG, "Error changing children drawing order", e); + } + } + } + + @Override + protected int getChildDrawingOrder(int childCount, int i) { + final int index = mDrawingOrder == DRAW_ORDER_REVERSE ? childCount - 1 - i : i; + final int result = ((LayoutParams) mDrawingOrderedChildren.get(index).getLayoutParams()).childIndex; + return result; + } + + /** + * Set a separate OnPageChangeListener for internal use by the support library. + * + * @param listener Listener to set + * @return The old listener that was set, if any. + */ + ViewPager.OnPageChangeListener setInternalPageChangeListener(ViewPager.OnPageChangeListener listener) { + ViewPager.OnPageChangeListener oldListener = mInternalPageChangeListener; + mInternalPageChangeListener = listener; + return oldListener; + } + + /** + * Returns the number of pages that will be retained to either side of the + * current page in the view hierarchy in an idle state. Defaults to 1. + * + * @return How many pages will be kept offscreen on either side + * @see #setOffscreenPageLimit(int) + */ + public int getOffscreenPageLimit() { + return mOffscreenPageLimit; + } + + /** + * Set the number of pages that should be retained to either side of the + * current page in the view hierarchy in an idle state. Pages beyond this + * limit will be recreated from the adapter when needed. + *

+ *

This is offered as an optimization. If you know in advance the number + * of pages you will need to support or have lazy-loading mechanisms in place + * on your pages, tweaking this setting can have benefits in perceived smoothness + * of paging animations and interaction. If you have a small number of pages (3-4) + * that you can keep active all at once, less time will be spent in layout for + * newly created view subtrees as the user pages back and forth.

+ *

+ *

You should keep this limit low, especially if your pages have complex layouts. + * This setting defaults to 1.

+ * + * @param limit How many pages will be kept offscreen in an idle state. + */ + public void setOffscreenPageLimit(int limit) { + if (limit < DEFAULT_OFFSCREEN_PAGES) { + Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " + + DEFAULT_OFFSCREEN_PAGES); + limit = DEFAULT_OFFSCREEN_PAGES; + } + if (limit != mOffscreenPageLimit) { + mOffscreenPageLimit = limit; + populate(); + } + } + + /** + * Set the margin between pages. + * + * @param marginPixels Distance between adjacent pages in pixels + * @see #getPageMargin() + * @see #setPageMarginDrawable(Drawable) + * @see #setPageMarginDrawable(int) + */ + public void setPageMargin(int marginPixels) { + final int oldMargin = mPageMargin; + mPageMargin = marginPixels; + + final int height = getHeight(); + recomputeScrollPosition(height, height, marginPixels, oldMargin); + + requestLayout(); + } + + /** + * Return the margin between pages. + * + * @return The size of the margin in pixels + */ + public int getPageMargin() { + return mPageMargin; + } + + /** + * Set a drawable that will be used to fill the margin between pages. + * + * @param d Drawable to display between pages + */ + public void setPageMarginDrawable(Drawable d) { + mMarginDrawable = d; + if (d != null) refreshDrawableState(); + setWillNotDraw(d == null); + invalidate(); + } + + /** + * Set a drawable that will be used to fill the margin between pages. + * + * @param resId Resource ID of a drawable to display between pages + */ + public void setPageMarginDrawable(int resId) { + setPageMarginDrawable(getContext().getResources().getDrawable(resId)); + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return super.verifyDrawable(who) || who == mMarginDrawable; + } + + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + final Drawable d = mMarginDrawable; + if (d != null && d.isStateful()) { + d.setState(getDrawableState()); + } + } + + // We want the duration of the page snap animation to be influenced by the distance that + // the screen has to travel, however, we don't want this duration to be effected in a + // purely linear fashion. Instead, we use this method to moderate the effect that the distance + // of travel has on the overall snap duration. + float distanceInfluenceForSnapDuration(float f) { + f -= 0.5f; // center the values about 0. + f *= 0.3f * Math.PI / 2.0f; + return (float) Math.sin(f); + } + + /** + * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. + * + * @param x the number of pixels to scroll by on the X axis + * @param y the number of pixels to scroll by on the Y axis + */ + void smoothScrollTo(int x, int y) { + smoothScrollTo(x, y, 0); + } + + /** + * Like {@link View#scrollBy}, but scroll smoothly instead of immediately. + * + * @param x the number of pixels to scroll by on the X axis + * @param y the number of pixels to scroll by on the Y axis + * @param velocity the velocity associated with a fling, if applicable. (0 otherwise) + */ + void smoothScrollTo(int x, int y, int velocity) { + if (getChildCount() == 0) { + // Nothing to do. + setScrollingCacheEnabled(false); + return; + } + int sx = getScrollX(); + int sy = getScrollY(); + int dx = x - sx; + int dy = y - sy; + if (dx == 0 && dy == 0) { + completeScroll(false); + populate(); + setScrollState(SCROLL_STATE_IDLE); + return; + } + + setScrollingCacheEnabled(true); + setScrollState(SCROLL_STATE_SETTLING); + + final int height = getClientHeight(); + final int halfHeight = height / 2; + final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / height); + final float distance = halfHeight + halfHeight * + distanceInfluenceForSnapDuration(distanceRatio); + + int duration = 0; + velocity = Math.abs(velocity); + if (velocity > 0) { + duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); + } else { + final float pageHeight = height * mAdapter.getPageWidth(mCurItem); + final float pageDelta = (float) Math.abs(dx) / (pageHeight + mPageMargin); + duration = (int) ((pageDelta + 1) * 100); + } + duration = Math.min(duration, MAX_SETTLE_DURATION); + + mScroller.startScroll(sx, sy, dx, dy, duration); + ViewCompat.postInvalidateOnAnimation(this); + } + + ItemInfo addNewItem(int position, int index) { + ItemInfo ii = new ItemInfo(); + ii.position = position; + ii.object = mAdapter.instantiateItem(this, position); + ii.heightFactor = mAdapter.getPageWidth(position); + if (index < 0 || index >= mItems.size()) { + mItems.add(ii); + } else { + mItems.add(index, ii); + } + return ii; + } + + void dataSetChanged() { + // This method only gets called if our observer is attached, so mAdapter is non-null. + + final int adapterCount = mAdapter.getCount(); + mExpectedAdapterCount = adapterCount; + boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1 && + mItems.size() < adapterCount; + int newCurrItem = mCurItem; + + boolean isUpdating = false; + for (int i = 0; i < mItems.size(); i++) { + final ItemInfo ii = mItems.get(i); + final int newPos = mAdapter.getItemPosition(ii.object); + + if (newPos == PagerAdapter.POSITION_UNCHANGED) { + continue; + } + + if (newPos == PagerAdapter.POSITION_NONE) { + mItems.remove(i); + i--; + + if (!isUpdating) { + mAdapter.startUpdate(this); + isUpdating = true; + } + + mAdapter.destroyItem(this, ii.position, ii.object); + needPopulate = true; + + if (mCurItem == ii.position) { + // Keep the current item in the valid range + newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1)); + needPopulate = true; + } + continue; + } + + if (ii.position != newPos) { + if (ii.position == mCurItem) { + // Our current item changed position. Follow it. + newCurrItem = newPos; + } + + ii.position = newPos; + needPopulate = true; + } + } + + if (isUpdating) { + mAdapter.finishUpdate(this); + } + + Collections.sort(mItems, COMPARATOR); + + if (needPopulate) { + // Reset our known page widths; populate will recompute them. + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (!lp.isDecor) { + lp.heightFactor = 0.f; + } + } + + setCurrentItemInternal(newCurrItem, false, true); + requestLayout(); + } + } + + void populate() { + populate(mCurItem); + } + + void populate(int newCurrentItem) { + ItemInfo oldCurInfo = null; + int focusDirection = View.FOCUS_FORWARD; + if (mCurItem != newCurrentItem) { + focusDirection = mCurItem < newCurrentItem ? View.FOCUS_DOWN : View.FOCUS_UP; + oldCurInfo = infoForPosition(mCurItem); + mCurItem = newCurrentItem; + } + + if (mAdapter == null) { + sortChildDrawingOrder(); + return; + } + + // Bail now if we are waiting to populate. This is to hold off + // on creating views from the time the user releases their finger to + // fling to a new position until we have finished the scroll to + // that position, avoiding glitches from happening at that point. + if (mPopulatePending) { + if (DEBUG) Log.i(TAG, "populate is pending, skipping for now..."); + sortChildDrawingOrder(); + return; + } + + // Also, don't populate until we are attached to a window. This is to + // avoid trying to populate before we have restored our view hierarchy + // state and conflicting with what is restored. + if (getWindowToken() == null) { + return; + } + + mAdapter.startUpdate(this); + + final int pageLimit = mOffscreenPageLimit; + final int startPos = Math.max(0, mCurItem - pageLimit); + final int N = mAdapter.getCount(); + final int endPos = Math.min(N - 1, mCurItem + pageLimit); + + if (N != mExpectedAdapterCount) { + String resName; + try { + resName = getResources().getResourceName(getId()); + } catch (Resources.NotFoundException e) { + resName = Integer.toHexString(getId()); + } + throw new IllegalStateException("The application's PagerAdapter changed the adapter's" + + " contents without calling PagerAdapter#notifyDataSetChanged!" + + " Expected adapter item count: " + mExpectedAdapterCount + ", found: " + N + + " Pager id: " + resName + + " Pager class: " + getClass() + + " Problematic adapter: " + mAdapter.getClass()); + } + + // Locate the currently focused item or add it if needed. + int curIndex = -1; + ItemInfo curItem = null; + for (curIndex = 0; curIndex < mItems.size(); curIndex++) { + final ItemInfo ii = mItems.get(curIndex); + if (ii.position >= mCurItem) { + if (ii.position == mCurItem) curItem = ii; + break; + } + } + + if (curItem == null && N > 0) { + curItem = addNewItem(mCurItem, curIndex); + } + + // Fill 3x the available width or up to the number of offscreen + // pages requested to either side, whichever is larger. + // If we have no current item we have no work to do. + if (curItem != null) { + float extraHeightTop = 0.f; + int itemIndex = curIndex - 1; + ItemInfo ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; + final int clientHeight = getClientHeight(); + final float topHeightNeeded = clientHeight <= 0 ? 0 : + 2.f - curItem.heightFactor + (float) getPaddingLeft() / (float) clientHeight; + for (int pos = mCurItem - 1; pos >= 0; pos--) { + if (extraHeightTop >= topHeightNeeded && pos < startPos) { + if (ii == null) { + break; + } + if (pos == ii.position && !ii.scrolling) { + mItems.remove(itemIndex); + mAdapter.destroyItem(this, pos, ii.object); + if (DEBUG) { + Log.i(TAG, "populate() - destroyItem() with pos: " + pos + + " view: " + ((View) ii.object)); + } + itemIndex--; + curIndex--; + ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; + } + } else if (ii != null && pos == ii.position) { + extraHeightTop += ii.heightFactor; + itemIndex--; + ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; + } else { + ii = addNewItem(pos, itemIndex + 1); + extraHeightTop += ii.heightFactor; + curIndex++; + ii = itemIndex >= 0 ? mItems.get(itemIndex) : null; + } + } + + float extraHeightBottom = curItem.heightFactor; + itemIndex = curIndex + 1; + if (extraHeightBottom < 2.f) { + ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; + final float bottomHeightNeeded = clientHeight <= 0 ? 0 : + (float) getPaddingRight() / (float) clientHeight + 2.f; + for (int pos = mCurItem + 1; pos < N; pos++) { + if (extraHeightBottom >= bottomHeightNeeded && pos > endPos) { + if (ii == null) { + break; + } + if (pos == ii.position && !ii.scrolling) { + mItems.remove(itemIndex); + mAdapter.destroyItem(this, pos, ii.object); + if (DEBUG) { + Log.i(TAG, "populate() - destroyItem() with pos: " + pos + + " view: " + ((View) ii.object)); + } + ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; + } + } else if (ii != null && pos == ii.position) { + extraHeightBottom += ii.heightFactor; + itemIndex++; + ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; + } else { + ii = addNewItem(pos, itemIndex); + itemIndex++; + extraHeightBottom += ii.heightFactor; + ii = itemIndex < mItems.size() ? mItems.get(itemIndex) : null; + } + } + } + + calculatePageOffsets(curItem, curIndex, oldCurInfo); + } + + if (DEBUG) { + Log.i(TAG, "Current page list:"); + for (int i = 0; i < mItems.size(); i++) { + Log.i(TAG, "#" + i + ": page " + mItems.get(i).position); + } + } + + mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null); + + mAdapter.finishUpdate(this); + + // Check width measurement of current pages and drawing sort order. + // Update LayoutParams as needed. + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + lp.childIndex = i; + if (!lp.isDecor && lp.heightFactor == 0.f) { + // 0 means requery the adapter for this, it doesn't have a valid width. + final ItemInfo ii = infoForChild(child); + if (ii != null) { + lp.heightFactor = ii.heightFactor; + lp.position = ii.position; + } + } + } + sortChildDrawingOrder(); + + if (hasFocus()) { + View currentFocused = findFocus(); + ItemInfo ii = currentFocused != null ? infoForAnyChild(currentFocused) : null; + if (ii == null || ii.position != mCurItem) { + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + ii = infoForChild(child); + if (ii != null && ii.position == mCurItem) { + if (child.requestFocus(focusDirection)) { + break; + } + } + } + } + } + } + + private void sortChildDrawingOrder() { + if (mDrawingOrder != DRAW_ORDER_DEFAULT) { + if (mDrawingOrderedChildren == null) { + mDrawingOrderedChildren = new ArrayList(); + } else { + mDrawingOrderedChildren.clear(); + } + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + mDrawingOrderedChildren.add(child); + } + Collections.sort(mDrawingOrderedChildren, sPositionComparator); + } + } + + private void calculatePageOffsets(ItemInfo curItem, int curIndex, ItemInfo oldCurInfo) { + final int N = mAdapter.getCount(); + final int height = getClientHeight(); + final float marginOffset = height > 0 ? (float) mPageMargin / height : 0; + // Fix up offsets for later layout. + if (oldCurInfo != null) { + final int oldCurPosition = oldCurInfo.position; + // Base offsets off of oldCurInfo. + if (oldCurPosition < curItem.position) { + int itemIndex = 0; + ItemInfo ii = null; + float offset = oldCurInfo.offset + oldCurInfo.heightFactor + marginOffset; + for (int pos = oldCurPosition + 1; + pos <= curItem.position && itemIndex < mItems.size(); pos++) { + ii = mItems.get(itemIndex); + while (pos > ii.position && itemIndex < mItems.size() - 1) { + itemIndex++; + ii = mItems.get(itemIndex); + } + while (pos < ii.position) { + // We don't have an item populated for this, + // ask the adapter for an offset. + offset += mAdapter.getPageWidth(pos) + marginOffset; + pos++; + } + ii.offset = offset; + offset += ii.heightFactor + marginOffset; + } + } else if (oldCurPosition > curItem.position) { + int itemIndex = mItems.size() - 1; + ItemInfo ii = null; + float offset = oldCurInfo.offset; + for (int pos = oldCurPosition - 1; + pos >= curItem.position && itemIndex >= 0; pos--) { + ii = mItems.get(itemIndex); + while (pos < ii.position && itemIndex > 0) { + itemIndex--; + ii = mItems.get(itemIndex); + } + while (pos > ii.position) { + // We don't have an item populated for this, + // ask the adapter for an offset. + offset -= mAdapter.getPageWidth(pos) + marginOffset; + pos--; + } + offset -= ii.heightFactor + marginOffset; + ii.offset = offset; + } + } + } + + // Base all offsets off of curItem. + final int itemCount = mItems.size(); + float offset = curItem.offset; + int pos = curItem.position - 1; + mFirstOffset = curItem.position == 0 ? curItem.offset : -Float.MAX_VALUE; + mLastOffset = curItem.position == N - 1 ? + curItem.offset + curItem.heightFactor - 1 : Float.MAX_VALUE; + // Previous pages + for (int i = curIndex - 1; i >= 0; i--, pos--) { + final ItemInfo ii = mItems.get(i); + while (pos > ii.position) { + offset -= mAdapter.getPageWidth(pos--) + marginOffset; + } + offset -= ii.heightFactor + marginOffset; + ii.offset = offset; + if (ii.position == 0) mFirstOffset = offset; + } + offset = curItem.offset + curItem.heightFactor + marginOffset; + pos = curItem.position + 1; + // Next pages + for (int i = curIndex + 1; i < itemCount; i++, pos++) { + final ItemInfo ii = mItems.get(i); + while (pos < ii.position) { + offset += mAdapter.getPageWidth(pos++) + marginOffset; + } + if (ii.position == N - 1) { + mLastOffset = offset + ii.heightFactor - 1; + } + ii.offset = offset; + offset += ii.heightFactor + marginOffset; + } + + mNeedCalculatePageOffsets = false; + } + + /** + * This is the persistent state that is saved by ViewPager. Only needed + * if you are creating a sublass of ViewPager that must save its own + * state, in which case it should implement a subclass of this which + * contains that state. + */ + public static class SavedState extends View.BaseSavedState { + int position; + Parcelable adapterState; + ClassLoader loader; + + public SavedState(Parcelable superState) { + super(superState); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeInt(position); + out.writeParcelable(adapterState, flags); + } + + @Override + public String toString() { + return "FragmentPager.SavedState{" + + Integer.toHexString(System.identityHashCode(this)) + + " position=" + position + "}"; + } + + public static final Creator CREATOR + = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks() { + @Override + public SavedState createFromParcel(Parcel in, ClassLoader loader) { + return new SavedState(in, loader); + } + + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }); + + SavedState(Parcel in, ClassLoader loader) { + super(in); + if (loader == null) { + loader = getClass().getClassLoader(); + } + position = in.readInt(); + adapterState = in.readParcelable(loader); + this.loader = loader; + } + } + + @Override + public Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + SavedState ss = new SavedState(superState); + ss.position = mCurItem; + if (mAdapter != null) { + ss.adapterState = mAdapter.saveState(); + } + return ss; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + if (!(state instanceof SavedState)) { + super.onRestoreInstanceState(state); + return; + } + + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + + if (mAdapter != null) { + mAdapter.restoreState(ss.adapterState, ss.loader); + setCurrentItemInternal(ss.position, false, true); + } else { + mRestoredCurItem = ss.position; + mRestoredAdapterState = ss.adapterState; + mRestoredClassLoader = ss.loader; + } + } + + @Override + public void addView(View child, int index, ViewGroup.LayoutParams params) { + if (!checkLayoutParams(params)) { + params = generateLayoutParams(params); + } + final LayoutParams lp = (LayoutParams) params; + lp.isDecor |= child instanceof Decor; + if (mInLayout) { + if (lp != null && lp.isDecor) { + throw new IllegalStateException("Cannot add pager decor view during layout"); + } + lp.needsMeasure = true; + addViewInLayout(child, index, params); + } else { + super.addView(child, index, params); + } + + if (USE_CACHE) { + if (child.getVisibility() != GONE) { + child.setDrawingCacheEnabled(mScrollingCacheEnabled); + } else { + child.setDrawingCacheEnabled(false); + } + } + } + + @Override + public void removeView(View view) { + if (mInLayout) { + removeViewInLayout(view); + } else { + super.removeView(view); + } + } + + ItemInfo infoForChild(View child) { + for (int i = 0; i < mItems.size(); i++) { + ItemInfo ii = mItems.get(i); + if (mAdapter.isViewFromObject(child, ii.object)) { + return ii; + } + } + return null; + } + + ItemInfo infoForAnyChild(View child) { + ViewParent parent; + while ((parent = child.getParent()) != this) { + if (parent == null || !(parent instanceof View)) { + return null; + } + child = (View) parent; + } + return infoForChild(child); + } + + ItemInfo infoForPosition(int position) { + for (int i = 0; i < mItems.size(); i++) { + ItemInfo ii = mItems.get(i); + if (ii.position == position) { + return ii; + } + } + return null; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mFirstLayout = true; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // For simple implementation, our internal size is always 0. + // We depend on the container to specify the layout size of + // our view. We can't really know what it is since we will be + // adding and removing different arbitrary views and do not + // want the layout to change as this happens. + setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), + getDefaultSize(0, heightMeasureSpec)); + + final int measuredHeight = getMeasuredHeight(); + final int maxGutterSize = measuredHeight / 10; + mGutterSize = Math.min(maxGutterSize, mDefaultGutterSize); + + // Children are just made to fill our space. + int childWidthSize = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); + int childHeightSize = measuredHeight - getPaddingTop() - getPaddingBottom(); + + /* + * Make sure all children have been properly measured. Decor views first. + * Right now we cheat and make this less complicated by assuming decor + * views won't intersect. We will pin to edges based on gravity. + */ + int size = getChildCount(); + for (int i = 0; i < size; ++i) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (lp != null && lp.isDecor) { + final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; + final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; + int widthMode = MeasureSpec.AT_MOST; + int heightMode = MeasureSpec.AT_MOST; + boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM; + boolean consumeHorizontal = hgrav == Gravity.LEFT || hgrav == Gravity.RIGHT; + + if (consumeVertical) { + widthMode = MeasureSpec.EXACTLY; + } else if (consumeHorizontal) { + heightMode = MeasureSpec.EXACTLY; + } + + int widthSize = childWidthSize; + int heightSize = childHeightSize; + if (lp.width != LayoutParams.WRAP_CONTENT) { + widthMode = MeasureSpec.EXACTLY; + if (lp.width != LayoutParams.FILL_PARENT) { + widthSize = lp.width; + } + } + if (lp.height != LayoutParams.WRAP_CONTENT) { + heightMode = MeasureSpec.EXACTLY; + if (lp.height != LayoutParams.FILL_PARENT) { + heightSize = lp.height; + } + } + final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, widthMode); + final int heightSpec = MeasureSpec.makeMeasureSpec(heightSize, heightMode); + child.measure(widthSpec, heightSpec); + + if (consumeVertical) { + childHeightSize -= child.getMeasuredHeight(); + } else if (consumeHorizontal) { + childWidthSize -= child.getMeasuredWidth(); + } + } + } + } + + mChildWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY); + mChildHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeightSize, MeasureSpec.EXACTLY); + + // Make sure we have created all fragments that we need to have shown. + mInLayout = true; + populate(); + mInLayout = false; + + // Page views next. + size = getChildCount(); + for (int i = 0; i < size; ++i) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + if (DEBUG) Log.v(TAG, "Measuring #" + i + " " + child + + ": " + mChildWidthMeasureSpec); + + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (lp == null || !lp.isDecor) { + final int heightSpec = MeasureSpec.makeMeasureSpec( + (int) (childHeightSize * lp.heightFactor), MeasureSpec.EXACTLY); + child.measure(mChildWidthMeasureSpec, heightSpec); + } + } + } + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + // Make sure scroll position is set correctly. + if (h != oldh) { + recomputeScrollPosition(h, oldh, mPageMargin, mPageMargin); + } + } + + private void recomputeScrollPosition(int height, int oldHeight, int margin, int oldMargin) { + if (oldHeight > 0 && !mItems.isEmpty()) { + final int heightWithMargin = height - getPaddingTop() - getPaddingBottom() + margin; + final int oldHeightWithMargin = oldHeight - getPaddingTop() - getPaddingBottom() + + oldMargin; + final int ypos = getScrollY(); + final float pageOffset = (float) ypos / oldHeightWithMargin; + final int newOffsetPixels = (int) (pageOffset * heightWithMargin); + + scrollTo(getScrollX(), newOffsetPixels); + if (!mScroller.isFinished()) { + // We now return to your regularly scheduled scroll, already in progress. + final int newDuration = mScroller.getDuration() - mScroller.timePassed(); + ItemInfo targetInfo = infoForPosition(mCurItem); + mScroller.startScroll(0, newOffsetPixels, + 0, (int) (targetInfo.offset * height), newDuration); + } + } else { + final ItemInfo ii = infoForPosition(mCurItem); + final float scrollOffset = ii != null ? Math.min(ii.offset, mLastOffset) : 0; + final int scrollPos = (int) (scrollOffset * + (height - getPaddingTop() - getPaddingBottom())); + if (scrollPos != getScrollY()) { + completeScroll(false); + scrollTo(getScrollX(), scrollPos); + } + } + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + final int count = getChildCount(); + int width = r - l; + int height = b - t; + int paddingLeft = getPaddingLeft(); + int paddingTop = getPaddingTop(); + int paddingRight = getPaddingRight(); + int paddingBottom = getPaddingBottom(); + final int scrollY = getScrollY(); + + int decorCount = 0; + + // First pass - decor views. We need to do this in two passes so that + // we have the proper offsets for non-decor views later. + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + int childLeft = 0; + int childTop = 0; + if (lp.isDecor) { + final int hgrav = lp.gravity & Gravity.HORIZONTAL_GRAVITY_MASK; + final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; + switch (hgrav) { + default: + childLeft = paddingLeft; + break; + case Gravity.LEFT: + childLeft = paddingLeft; + paddingLeft += child.getMeasuredWidth(); + break; + case Gravity.CENTER_HORIZONTAL: + childLeft = Math.max((width - child.getMeasuredWidth()) / 2, + paddingLeft); + break; + case Gravity.RIGHT: + childLeft = width - paddingRight - child.getMeasuredWidth(); + paddingRight += child.getMeasuredWidth(); + break; + } + switch (vgrav) { + default: + childTop = paddingTop; + break; + case Gravity.TOP: + childTop = paddingTop; + paddingTop += child.getMeasuredHeight(); + break; + case Gravity.CENTER_VERTICAL: + childTop = Math.max((height - child.getMeasuredHeight()) / 2, + paddingTop); + break; + case Gravity.BOTTOM: + childTop = height - paddingBottom - child.getMeasuredHeight(); + paddingBottom += child.getMeasuredHeight(); + break; + } + childTop += scrollY; + child.layout(childLeft, childTop, + childLeft + child.getMeasuredWidth(), + childTop + child.getMeasuredHeight()); + decorCount++; + } + } + } + + final int childHeight = height - paddingTop - paddingBottom; + // Page views. Do this once we have the right padding offsets from above. + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + ItemInfo ii; + if (!lp.isDecor && (ii = infoForChild(child)) != null) { + int toff = (int) (childHeight * ii.offset); + int childLeft = paddingLeft; + int childTop = paddingTop + toff; + if (lp.needsMeasure) { + // This was added during layout and needs measurement. + // Do it now that we know what we're working with. + lp.needsMeasure = false; + final int widthSpec = MeasureSpec.makeMeasureSpec( + (int) (width - paddingLeft - paddingRight), + MeasureSpec.EXACTLY); + final int heightSpec = MeasureSpec.makeMeasureSpec( + (int) (childHeight * lp.heightFactor), + MeasureSpec.EXACTLY); + child.measure(widthSpec, heightSpec); + } + if (DEBUG) Log.v(TAG, "Positioning #" + i + " " + child + " f=" + ii.object + + ":" + childLeft + "," + childTop + " " + child.getMeasuredWidth() + + "x" + child.getMeasuredHeight()); + child.layout(childLeft, childTop, + childLeft + child.getMeasuredWidth(), + childTop + child.getMeasuredHeight()); + } + } + } + mLeftPageBounds = paddingLeft; + mRightPageBounds = width - paddingRight; + mDecorChildCount = decorCount; + + if (mFirstLayout) { + scrollToItem(mCurItem, false, 0, false); + } + mFirstLayout = false; + } + + @Override + public void computeScroll() { + if (!mScroller.isFinished() && mScroller.computeScrollOffset()) { + int oldX = getScrollX(); + int oldY = getScrollY(); + int x = mScroller.getCurrX(); + int y = mScroller.getCurrY(); + + if (oldX != x || oldY != y) { + scrollTo(x, y); + if (!pageScrolled(y)) { + mScroller.abortAnimation(); + scrollTo(x, 0); + } + } + + // Keep on drawing until the animation has finished. + ViewCompat.postInvalidateOnAnimation(this); + return; + } + + // Done with scroll, clean up state. + completeScroll(true); + } + + private boolean pageScrolled(int ypos) { + if (mItems.size() == 0) { + mCalledSuper = false; + onPageScrolled(0, 0, 0); + if (!mCalledSuper) { + throw new IllegalStateException( + "onPageScrolled did not call superclass implementation"); + } + return false; + } + final ItemInfo ii = infoForCurrentScrollPosition(); + final int height = getClientHeight(); + final int heightWithMargin = height + mPageMargin; + final float marginOffset = (float) mPageMargin / height; + final int currentPage = ii.position; + final float pageOffset = (((float) ypos / height) - ii.offset) / + (ii.heightFactor + marginOffset); + final int offsetPixels = (int) (pageOffset * heightWithMargin); + + mCalledSuper = false; + onPageScrolled(currentPage, pageOffset, offsetPixels); + if (!mCalledSuper) { + throw new IllegalStateException( + "onPageScrolled did not call superclass implementation"); + } + return true; + } + + /** + * This method will be invoked when the current page is scrolled, either as part + * of a programmatically initiated smooth scroll or a user initiated touch scroll. + * If you override this method you must call through to the superclass implementation + * (e.g. super.onPageScrolled(position, offset, offsetPixels)) before onPageScrolled + * returns. + * + * @param position Position index of the first page currently being displayed. + * Page position+1 will be visible if positionOffset is nonzero. + * @param offset Value from [0, 1) indicating the offset from the page at position. + * @param offsetPixels Value in pixels indicating the offset from position. + */ + protected void onPageScrolled(int position, float offset, int offsetPixels) { + // Offset any decor views if needed - keep them on-screen at all times. + if (mDecorChildCount > 0) { + final int scrollY = getScrollY(); + int paddingTop = getPaddingTop(); + int paddingBottom = getPaddingBottom(); + final int height = getHeight(); + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (!lp.isDecor) continue; + + final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK; + int childTop = 0; + switch (vgrav) { + default: + childTop = paddingTop; + break; + case Gravity.TOP: + childTop = paddingTop; + paddingTop += child.getHeight(); + break; + case Gravity.CENTER_VERTICAL: + childTop = Math.max((height - child.getMeasuredHeight()) / 2, + paddingTop); + break; + case Gravity.BOTTOM: + childTop = height - paddingBottom - child.getMeasuredHeight(); + paddingBottom += child.getMeasuredHeight(); + break; + } + childTop += scrollY; + + final int childOffset = childTop - child.getTop(); + if (childOffset != 0) { + child.offsetTopAndBottom(childOffset); + } + } + } + + if (mOnPageChangeListener != null) { + mOnPageChangeListener.onPageScrolled(position, offset, offsetPixels); + } + if (mInternalPageChangeListener != null) { + mInternalPageChangeListener.onPageScrolled(position, offset, offsetPixels); + } + + if (mPageTransformer != null) { + final int scrollY = getScrollY(); + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + if (lp.isDecor) continue; + + final float transformPos = (float) (child.getTop() - scrollY) / getClientHeight(); + mPageTransformer.transformPage(child, transformPos); + } + } + + mCalledSuper = true; + } + + private void completeScroll(boolean postEvents) { + boolean needPopulate = mScrollState == SCROLL_STATE_SETTLING; + if (needPopulate) { + // Done with scroll, no longer want to cache view drawing. + setScrollingCacheEnabled(false); + mScroller.abortAnimation(); + int oldX = getScrollX(); + int oldY = getScrollY(); + int x = mScroller.getCurrX(); + int y = mScroller.getCurrY(); + if (oldX != x || oldY != y) { + scrollTo(x, y); + } + } + mPopulatePending = false; + for (int i = 0; i < mItems.size(); i++) { + ItemInfo ii = mItems.get(i); + if (ii.scrolling) { + needPopulate = true; + ii.scrolling = false; + } + } + if (needPopulate) { + if (postEvents) { + ViewCompat.postOnAnimation(this, mEndScrollRunnable); + } else { + mEndScrollRunnable.run(); + } + } + } + + private boolean isGutterDrag(float y, float dy) { + return (y < mGutterSize && dy > 0) || (y > getHeight() - mGutterSize && dy < 0); + } + + @SuppressLint("WrongConstant") + private void enableLayers(boolean enable) { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final int layerType = enable ? + ViewCompat.LAYER_TYPE_HARDWARE : ViewCompat.LAYER_TYPE_NONE; + ViewCompat.setLayerType(getChildAt(i), layerType, null); + } + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + if (!mEnableScroll) { + return false; + } + /* + * This method JUST determines whether we want to intercept the motion. + * If we return true, onMotionEvent will be called and we do the actual + * scrolling there. + */ + + final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; + + // Always take care of the touch gesture being complete. + if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { + // Release the drag. + if (DEBUG) Log.v(TAG, "Intercept done!"); + mIsBeingDragged = false; + mIsUnableToDrag = false; + mActivePointerId = INVALID_POINTER; + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + return false; + } + + // Nothing more to do here if we have decided whether or not we + // are dragging. + if (action != MotionEvent.ACTION_DOWN) { + if (mIsBeingDragged) { + if (DEBUG) Log.v(TAG, "Intercept returning true!"); + return true; + } + if (mIsUnableToDrag) { + if (DEBUG) Log.v(TAG, "Intercept returning false!"); + return false; + } + } + + switch (action) { + case MotionEvent.ACTION_MOVE: { + /* + * mIsBeingDragged == false, otherwise the shortcut would have caught it. Check + * whether the user has moved far enough from his original down touch. + */ + + /* + * Locally do absolute value. mLastMotionY is set to the y value + * of the down event. + */ + final int activePointerId = mActivePointerId; + if (activePointerId == INVALID_POINTER) { + // If we don't have a valid id, the touch down wasn't on content. + break; + } + + final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId); + final float y = MotionEventCompat.getY(ev, pointerIndex); + final float dy = y - mLastMotionY; + final float yDiff = Math.abs(dy); + final float x = MotionEventCompat.getX(ev, pointerIndex); + final float xDiff = Math.abs(x - mInitialMotionX); + if (DEBUG) Log.i(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); + + if (dy != 0 && !isGutterDrag(mLastMotionY, dy) && + canScroll(this, false, (int) dy, (int) x, (int) y)) { + // Nested view has scrollable area under this point. Let it be handled there. + mLastMotionX = x; + mLastMotionY = y; + mIsUnableToDrag = true; + return false; + } + if (yDiff > mTouchSlop && yDiff * 0.5f > xDiff) { + if (DEBUG) Log.v(TAG, "Starting drag!"); + mIsBeingDragged = true; + requestParentDisallowInterceptTouchEvent(true); + setScrollState(SCROLL_STATE_DRAGGING); + mLastMotionY = dy > 0 ? mInitialMotionY + mTouchSlop : + mInitialMotionY - mTouchSlop; + mLastMotionX = x; + setScrollingCacheEnabled(true); + } else if (xDiff > mTouchSlop) { + // The finger has moved enough in the vertical + // direction to be counted as a drag... abort + // any attempt to drag horizontally, to work correctly + // with children that have scrolling containers. + if (DEBUG) Log.v(TAG, "Starting unable to drag!"); + mIsUnableToDrag = true; + } + if (mIsBeingDragged) { + // Scroll to follow the motion event + if (performDrag(y)) { + ViewCompat.postInvalidateOnAnimation(this); + } + } + break; + } + + case MotionEvent.ACTION_DOWN: { + /* + * Remember location of down touch. + * ACTION_DOWN always refers to pointer index 0. + */ + mLastMotionX = mInitialMotionX = ev.getX(); + mLastMotionY = mInitialMotionY = ev.getY(); + mActivePointerId = MotionEventCompat.getPointerId(ev, 0); + mIsUnableToDrag = false; + + mScroller.computeScrollOffset(); + if (mScrollState == SCROLL_STATE_SETTLING && + Math.abs(mScroller.getFinalY() - mScroller.getCurrY()) > mCloseEnough) { + // Let the user 'catch' the pager as it animates. + mScroller.abortAnimation(); + mPopulatePending = false; + populate(); + mIsBeingDragged = true; + requestParentDisallowInterceptTouchEvent(true); + setScrollState(SCROLL_STATE_DRAGGING); + } else { + completeScroll(false); + mIsBeingDragged = false; + } + + if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY + + " mIsBeingDragged=" + mIsBeingDragged + + "mIsUnableToDrag=" + mIsUnableToDrag); + break; + } + + case MotionEventCompat.ACTION_POINTER_UP: + onSecondaryPointerUp(ev); + break; + } + + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(ev); + + /* + * The only time we want to intercept motion events is if we are in the + * drag mode. + */ + return mIsBeingDragged; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + + if (!mEnableScroll) { + return false; + } + + if (mFakeDragging) { + // A fake drag is in progress already, ignore this real one + // but still eat the touch events. + // (It is likely that the user is multi-touching the screen.) + return true; + } + + if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) { + // Don't handle edge touches immediately -- they may actually belong to one of our + // descendants. + return false; + } + + if (mAdapter == null || mAdapter.getCount() == 0) { + // Nothing to present or scroll; nothing to touch. + return false; + } + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(ev); + + final int action = ev.getAction(); + boolean needsInvalidate = false; + + switch (action & MotionEventCompat.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: { + mScroller.abortAnimation(); + mPopulatePending = false; + populate(); + + // Remember where the motion event started + mLastMotionX = mInitialMotionX = ev.getX(); + mLastMotionY = mInitialMotionY = ev.getY(); + mActivePointerId = MotionEventCompat.getPointerId(ev, 0); + break; + } + case MotionEvent.ACTION_MOVE: + + final View child = getCurrentView(); + int[] location = new int[2]; + child.getLocationOnScreen(location); + + + if (!mIsBeingDragged) { + final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); + final float y = MotionEventCompat.getY(ev, pointerIndex); + final float dy = y - mLastMotionY; + final float yDiff = Math.abs(y - mLastMotionY); + final float x = MotionEventCompat.getX(ev, pointerIndex); + final float xDiff = Math.abs(x - mLastMotionX); + if (DEBUG) + Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); + + if (yDiff > mTouchSlop && yDiff > xDiff) { + if (DEBUG) Log.v(TAG, "Starting drag!"); + mIsBeingDragged = true; + requestParentDisallowInterceptTouchEvent(true); + mLastMotionY = y - mInitialMotionY > 0 ? mInitialMotionY + mTouchSlop : + mInitialMotionY - mTouchSlop; + mLastMotionX = x; + setScrollState(SCROLL_STATE_DRAGGING); + setScrollingCacheEnabled(true); + + // Disallow Parent Intercept, just in case + ViewParent parent = getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(true); + } + } + } + // Not else! Note that mIsBeingDragged can be set above. + if (mIsBeingDragged) { + // Scroll to follow the motion event + final int activePointerIndex = MotionEventCompat.findPointerIndex( + ev, mActivePointerId); + final float y = MotionEventCompat.getY(ev, activePointerIndex); + needsInvalidate |= performDrag(y); + } + break; + case MotionEvent.ACTION_UP: + if (mIsBeingDragged) { + final VelocityTracker velocityTracker = mVelocityTracker; + velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); + int initialVelocity = (int) VelocityTrackerCompat.getYVelocity( + velocityTracker, mActivePointerId); + mPopulatePending = true; + final int height = getClientHeight(); + final int scrollY = getScrollY(); + final ItemInfo ii = infoForCurrentScrollPosition(); + final int currentPage = ii.position; + final float pageOffset = (((float) scrollY / height) - ii.offset) / ii.heightFactor; + final int activePointerIndex = + MotionEventCompat.findPointerIndex(ev, mActivePointerId); + final float y = MotionEventCompat.getY(ev, activePointerIndex); + final int totalDelta = (int) (y - mInitialMotionY); + int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, + totalDelta); + + setCurrentItemInternal(nextPage, true, true, initialVelocity); + mActivePointerId = INVALID_POINTER; + endDrag(); + needsInvalidate = mTopEdge.onRelease() | mBottomEdge.onRelease(); + } + break; + case MotionEvent.ACTION_CANCEL: + if (mIsBeingDragged) { + scrollToItem(mCurItem, true, 0, false); + mActivePointerId = INVALID_POINTER; + endDrag(); + needsInvalidate = mTopEdge.onRelease() | mBottomEdge.onRelease(); + } + break; + case MotionEventCompat.ACTION_POINTER_DOWN: { + final int index = MotionEventCompat.getActionIndex(ev); + final float y = MotionEventCompat.getY(ev, index); + mLastMotionY = y; + mActivePointerId = MotionEventCompat.getPointerId(ev, index); + break; + } + case MotionEventCompat.ACTION_POINTER_UP: + onSecondaryPointerUp(ev); + mLastMotionY = MotionEventCompat.getY(ev, + MotionEventCompat.findPointerIndex(ev, mActivePointerId)); + break; + } + if (needsInvalidate) { + ViewCompat.postInvalidateOnAnimation(this); + } + return true; + } + + private void requestParentDisallowInterceptTouchEvent(boolean disallowIntercept) { + final ViewParent parent = getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(disallowIntercept); + } + } + + private boolean performDrag(float y) { + boolean needsInvalidate = false; + + final float deltaY = mLastMotionY - y; + mLastMotionY = y; + + float oldScrollY = getScrollY(); + float scrollY = oldScrollY + deltaY; + final int height = getClientHeight(); + + float topBound = height * mFirstOffset; + float bottomBound = height * mLastOffset; + boolean topAbsolute = true; + boolean bottomAbsolute = true; + + final ItemInfo firstItem = mItems.get(0); + final ItemInfo lastItem = mItems.get(mItems.size() - 1); + if (firstItem.position != 0) { + topAbsolute = false; + topBound = firstItem.offset * height; + } + if (lastItem.position != mAdapter.getCount() - 1) { + bottomAbsolute = false; + bottomBound = lastItem.offset * height; + } + + if (scrollY < topBound) { + if (topAbsolute) { + float over = topBound - scrollY; + needsInvalidate = mTopEdge.onPull(Math.abs(over) / height); + } + scrollY = topBound; + } else if (scrollY > bottomBound) { + if (bottomAbsolute) { + float over = scrollY - bottomBound; + needsInvalidate = mBottomEdge.onPull(Math.abs(over) / height); + } + scrollY = bottomBound; + } + // Don't lose the rounded component + mLastMotionX += scrollY - (int) scrollY; + scrollTo(getScrollX(), (int) scrollY); + pageScrolled((int) scrollY); + + return needsInvalidate; + } + + /** + * @return Info about the page at the current scroll position. + * This can be synthetic for a missing middle page; the 'object' field can be null. + */ + private ItemInfo infoForCurrentScrollPosition() { + final int height = getClientHeight(); + final float scrollOffset = height > 0 ? (float) getScrollY() / height : 0; + final float marginOffset = height > 0 ? (float) mPageMargin / height : 0; + int lastPos = -1; + float lastOffset = 0.f; + float lastHeight = 0.f; + boolean first = true; + + ItemInfo lastItem = null; + for (int i = 0; i < mItems.size(); i++) { + ItemInfo ii = mItems.get(i); + float offset; + if (!first && ii.position != lastPos + 1) { + // Create a synthetic item for a missing page. + ii = mTempItem; + ii.offset = lastOffset + lastHeight + marginOffset; + ii.position = lastPos + 1; + ii.heightFactor = mAdapter.getPageWidth(ii.position); + i--; + } + offset = ii.offset; + + final float topBound = offset; + final float bottomBound = offset + ii.heightFactor + marginOffset; + if (first || scrollOffset >= topBound) { + if (scrollOffset < bottomBound || i == mItems.size() - 1) { + return ii; + } + } else { + return lastItem; + } + first = false; + lastPos = ii.position; + lastOffset = offset; + lastHeight = ii.heightFactor; + lastItem = ii; + } + + return lastItem; + } + + private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaY) { + int targetPage; + if (Math.abs(deltaY) > mFlingDistance && Math.abs(velocity) > mMinimumVelocity) { + targetPage = velocity > 0 ? currentPage : currentPage + 1; + } else { + final float truncator = currentPage >= mCurItem ? 0.4f : 0.6f; + targetPage = (int) (currentPage + pageOffset + truncator); + } + + if (mItems.size() > 0) { + final ItemInfo firstItem = mItems.get(0); + final ItemInfo lastItem = mItems.get(mItems.size() - 1); + + // Only let the user target pages we have items for + targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position)); + } + + return targetPage; + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + boolean needsInvalidate = false; + + final int overScrollMode = ViewCompat.getOverScrollMode(this); + if (overScrollMode == ViewCompat.OVER_SCROLL_ALWAYS || + (overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS && + mAdapter != null && mAdapter.getCount() > 1)) { + if (!mTopEdge.isFinished()) { + final int restoreCount = canvas.save(); + final int height = getHeight(); + final int width = getWidth() - getPaddingLeft() - getPaddingRight(); + + canvas.translate(getPaddingLeft(), mFirstOffset * height); + mTopEdge.setSize(width, height); + needsInvalidate |= mTopEdge.draw(canvas); + canvas.restoreToCount(restoreCount); + } + if (!mBottomEdge.isFinished()) { + final int restoreCount = canvas.save(); + final int height = getHeight(); + final int width = getWidth() - getPaddingLeft() - getPaddingRight(); + + canvas.rotate(180); + canvas.translate(-width - getPaddingLeft(), -(mLastOffset + 1) * height); + mBottomEdge.setSize(width, height); + needsInvalidate |= mBottomEdge.draw(canvas); + canvas.restoreToCount(restoreCount); + } + } else { + mTopEdge.finish(); + mBottomEdge.finish(); + } + + if (needsInvalidate) { + // Keep animating + ViewCompat.postInvalidateOnAnimation(this); + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + // Draw the margin drawable between pages if needed. + if (mPageMargin > 0 && mMarginDrawable != null && mItems.size() > 0 && mAdapter != null) { + final int scrollY = getScrollY(); + final int height = getHeight(); + + final float marginOffset = (float) mPageMargin / height; + int itemIndex = 0; + ItemInfo ii = mItems.get(0); + float offset = ii.offset; + final int itemCount = mItems.size(); + final int firstPos = ii.position; + final int lastPos = mItems.get(itemCount - 1).position; + for (int pos = firstPos; pos < lastPos; pos++) { + while (pos > ii.position && itemIndex < itemCount) { + ii = mItems.get(++itemIndex); + } + + float drawAt; + if (pos == ii.position) { + drawAt = (ii.offset + ii.heightFactor) * height; + offset = ii.offset + ii.heightFactor + marginOffset; + } else { + float heightFactor = mAdapter.getPageWidth(pos); + drawAt = (offset + heightFactor) * height; + offset += heightFactor + marginOffset; + } + + if (drawAt + mPageMargin > scrollY) { + mMarginDrawable.setBounds(mLeftPageBounds, (int) drawAt, + mRightPageBounds, (int) (drawAt + mPageMargin + 0.5f)); + mMarginDrawable.draw(canvas); + } + + if (drawAt > scrollY + height) { + break; // No more visible, no sense in continuing + } + } + } + } + + /** + * Start a fake drag of the pager. + *

+ *

A fake drag can be useful if you want to synchronize the motion of the ViewPager + * with the touch scrolling of another view, while still letting the ViewPager + * control the snapping motion and fling behavior. (e.g. parallax-scrolling tabs.) + * Call {@link #fakeDragBy(float)} to simulate the actual drag motion. Call + * {@link #endFakeDrag()} to complete the fake drag and fling as necessary. + *

+ *

During a fake drag the ViewPager will ignore all touch events. If a real drag + * is already in progress, this method will return false. + * + * @return true if the fake drag began successfully, false if it could not be started. + * @see #fakeDragBy(float) + * @see #endFakeDrag() + */ + public boolean beginFakeDrag() { + if (mIsBeingDragged) { + return false; + } + mFakeDragging = true; + setScrollState(SCROLL_STATE_DRAGGING); + mInitialMotionY = mLastMotionY = 0; + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } else { + mVelocityTracker.clear(); + } + final long time = SystemClock.uptimeMillis(); + final MotionEvent ev = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 0); + mVelocityTracker.addMovement(ev); + ev.recycle(); + mFakeDragBeginTime = time; + return true; + } + + /** + * End a fake drag of the pager. + * + * @see #beginFakeDrag() + * @see #fakeDragBy(float) + */ + public void endFakeDrag() { + if (!mFakeDragging) { + throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); + } + + final VelocityTracker velocityTracker = mVelocityTracker; + velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); + int initialVelocity = (int) VelocityTrackerCompat.getYVelocity( + velocityTracker, mActivePointerId); + mPopulatePending = true; + final int height = getClientHeight(); + final int scrollY = getScrollY(); + final ItemInfo ii = infoForCurrentScrollPosition(); + final int currentPage = ii.position; + final float pageOffset = (((float) scrollY / height) - ii.offset) / ii.heightFactor; + final int totalDelta = (int) (mLastMotionY - mInitialMotionY); + int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity, + totalDelta); + setCurrentItemInternal(nextPage, true, true, initialVelocity); + endDrag(); + + mFakeDragging = false; + } + + /** + * Fake drag by an offset in pixels. You must have called {@link #beginFakeDrag()} first. + * + * @param yOffset Offset in pixels to drag by. + * @see #beginFakeDrag() + * @see #endFakeDrag() + */ + public void fakeDragBy(float yOffset) { + if (!mFakeDragging) { + throw new IllegalStateException("No fake drag in progress. Call beginFakeDrag first."); + } + + mLastMotionY += yOffset; + + float oldScrollY = getScrollY(); + float scrollY = oldScrollY - yOffset; + final int height = getClientHeight(); + + float topBound = height * mFirstOffset; + float bottomBound = height * mLastOffset; + + final ItemInfo firstItem = mItems.get(0); + final ItemInfo lastItem = mItems.get(mItems.size() - 1); + if (firstItem.position != 0) { + topBound = firstItem.offset * height; + } + if (lastItem.position != mAdapter.getCount() - 1) { + bottomBound = lastItem.offset * height; + } + + if (scrollY < topBound) { + scrollY = topBound; + } else if (scrollY > bottomBound) { + scrollY = bottomBound; + } + // Don't lose the rounded component + mLastMotionY += scrollY - (int) scrollY; + scrollTo(getScrollX(), (int) scrollY); + pageScrolled((int) scrollY); + + // Synthesize an event for the VelocityTracker. + final long time = SystemClock.uptimeMillis(); + final MotionEvent ev = MotionEvent.obtain(mFakeDragBeginTime, time, MotionEvent.ACTION_MOVE, + 0, mLastMotionY, 0); + mVelocityTracker.addMovement(ev); + ev.recycle(); + } + + /** + * Returns true if a fake drag is in progress. + * + * @return true if currently in a fake drag, false otherwise. + * @see #beginFakeDrag() + * @see #fakeDragBy(float) + * @see #endFakeDrag() + */ + public boolean isFakeDragging() { + return mFakeDragging; + } + + private void onSecondaryPointerUp(MotionEvent ev) { + final int pointerIndex = MotionEventCompat.getActionIndex(ev); + final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); + if (pointerId == mActivePointerId) { + // This was our active pointer going up. Choose a new + // active pointer and adjust accordingly. + final int newPointerIndex = pointerIndex == 0 ? 1 : 0; + mLastMotionY = MotionEventCompat.getY(ev, newPointerIndex); + mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); + if (mVelocityTracker != null) { + mVelocityTracker.clear(); + } + } + } + + private void endDrag() { + mIsBeingDragged = false; + mIsUnableToDrag = false; + + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } + + private void setScrollingCacheEnabled(boolean enabled) { + if (mScrollingCacheEnabled != enabled) { + mScrollingCacheEnabled = enabled; + if (USE_CACHE) { + final int size = getChildCount(); + for (int i = 0; i < size; ++i) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE) { + child.setDrawingCacheEnabled(enabled); + } + } + } + } + } + + public boolean internalCanScrollVertically(int direction) { + if (mAdapter == null) { + return false; + } + + final int height = getClientHeight(); + final int scrollY = getScrollY(); + if (direction < 0) { + return (scrollY > (int) (height * mFirstOffset)); + } else if (direction > 0) { + return (scrollY < (int) (height * mLastOffset)); + } else { + return false; + } + } + + /** + * Tests scrollability within child views of v given a delta of dx. + * + * @param v View to test for horizontal scrollability + * @param checkV Whether the view v passed should itself be checked for scrollability (true), + * or just its children (false). + * @param dy Delta scrolled in pixels + * @param x X coordinate of the active touch point + * @param y Y coordinate of the active touch point + * @return true if child views of v can be scrolled by delta of dx. + */ + protected boolean canScroll(View v, boolean checkV, int dy, int x, int y) { + if (v instanceof ViewGroup) { + final ViewGroup group = (ViewGroup) v; + final int scrollX = v.getScrollX(); + final int scrollY = v.getScrollY(); + final int count = group.getChildCount(); + // Count backwards - let topmost views consume scroll distance first. + for (int i = count - 1; i >= 0; i--) { + // TODO: Add versioned support here for transformed views. + // This will not work for transformed views in Honeycomb+ + final View child = group.getChildAt(i); + if (y + scrollY >= child.getTop() && y + scrollY < child.getBottom() && + x + scrollX >= child.getLeft() && x + scrollX < child.getRight() && + canScroll(child, true, dy, x + scrollX - child.getLeft(), + y + scrollY - child.getTop())) { + return true; + } + } + } + + return checkV && ViewCompat.canScrollVertically(v, -dy); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + // Let the focused view and/or our descendants get the key first + return super.dispatchKeyEvent(event) || executeKeyEvent(event); + } + + /** + * You can call this function yourself to have the scroll view perform + * scrolling from a key event, just as if the event had been dispatched to + * it by the view hierarchy. + * + * @param event The key event to execute. + * @return Return true if the event was handled, else false. + */ + public boolean executeKeyEvent(KeyEvent event) { + boolean handled = false; + if (event.getAction() == KeyEvent.ACTION_DOWN) { + switch (event.getKeyCode()) { + case KeyEvent.KEYCODE_DPAD_LEFT: + handled = arrowScroll(FOCUS_LEFT); + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + handled = arrowScroll(FOCUS_RIGHT); + break; + case KeyEvent.KEYCODE_TAB: + if (Build.VERSION.SDK_INT >= 11) { + // The focus finder had a bug handling FOCUS_FORWARD and FOCUS_BACKWARD + // before Android 3.0. Ignore the tab key on those devices. + if (event.hasNoModifiers()) { + handled = arrowScroll(FOCUS_FORWARD); + } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) { + handled = arrowScroll(FOCUS_BACKWARD); + } + } + break; + } + } + return handled; + } + + public boolean arrowScroll(int direction) { + View currentFocused = findFocus(); + if (currentFocused == this) { + currentFocused = null; + } else if (currentFocused != null) { + boolean isChild = false; + for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup; + parent = parent.getParent()) { + if (parent == this) { + isChild = true; + break; + } + } + if (!isChild) { + // This would cause the focus search down below to fail in fun ways. + final StringBuilder sb = new StringBuilder(); + sb.append(currentFocused.getClass().getSimpleName()); + for (ViewParent parent = currentFocused.getParent(); parent instanceof ViewGroup; + parent = parent.getParent()) { + sb.append(" => ").append(parent.getClass().getSimpleName()); + } + Log.e(TAG, "arrowScroll tried to find focus based on non-child " + + "current focused view " + sb.toString()); + currentFocused = null; + } + } + + boolean handled = false; + + View nextFocused = FocusFinder.getInstance().findNextFocus(this, currentFocused, + direction); + if (nextFocused != null && nextFocused != currentFocused) { + if (direction == View.FOCUS_UP) { + // If there is nothing to the left, or this is causing us to + // jump to the right, then what we really want to do is page left. + final int nextTop = getChildRectInPagerCoordinates(mTempRect, nextFocused).top; + final int currTop = getChildRectInPagerCoordinates(mTempRect, currentFocused).top; + if (currentFocused != null && nextTop >= currTop) { + handled = pageUp(); + } else { + handled = nextFocused.requestFocus(); + } + } else if (direction == View.FOCUS_DOWN) { + // If there is nothing to the right, or this is causing us to + // jump to the left, then what we really want to do is page right. + final int nextDown = getChildRectInPagerCoordinates(mTempRect, nextFocused).bottom; + final int currDown = getChildRectInPagerCoordinates(mTempRect, currentFocused).bottom; + if (currentFocused != null && nextDown <= currDown) { + handled = pageDown(); + } else { + handled = nextFocused.requestFocus(); + } + } + } else if (direction == FOCUS_UP || direction == FOCUS_BACKWARD) { + // Trying to move left and nothing there; try to page. + handled = pageUp(); + } else if (direction == FOCUS_DOWN || direction == FOCUS_FORWARD) { + // Trying to move right and nothing there; try to page. + handled = pageDown(); + } + if (handled) { + playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); + } + return handled; + } + + private Rect getChildRectInPagerCoordinates(Rect outRect, View child) { + if (outRect == null) { + outRect = new Rect(); + } + if (child == null) { + outRect.set(0, 0, 0, 0); + return outRect; + } + outRect.left = child.getLeft(); + outRect.right = child.getRight(); + outRect.top = child.getTop(); + outRect.bottom = child.getBottom(); + + ViewParent parent = child.getParent(); + while (parent instanceof ViewGroup && parent != this) { + final ViewGroup group = (ViewGroup) parent; + outRect.left += group.getLeft(); + outRect.right += group.getRight(); + outRect.top += group.getTop(); + outRect.bottom += group.getBottom(); + + parent = group.getParent(); + } + return outRect; + } + + boolean pageUp() { + if (mCurItem > 0) { + setCurrentItem(mCurItem - 1, true); + return true; + } + return false; + } + + boolean pageDown() { + if (mAdapter != null && mCurItem < (mAdapter.getCount() - 1)) { + setCurrentItem(mCurItem + 1, true); + return true; + } + return false; + } + + /** + * We only want the current page that is being shown to be focusable. + */ + @Override + public void addFocusables(ArrayList views, int direction, int focusableMode) { + final int focusableCount = views.size(); + + final int descendantFocusability = getDescendantFocusability(); + + if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) { + for (int i = 0; i < getChildCount(); i++) { + final View child = getChildAt(i); + if (child.getVisibility() == VISIBLE) { + ItemInfo ii = infoForChild(child); + if (ii != null && ii.position == mCurItem) { + child.addFocusables(views, direction, focusableMode); + } + } + } + } + + // we add ourselves (if focusable) in all cases except for when we are + // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is + // to avoid the focus search finding layouts when a more precise search + // among the focusable children would be more interesting. + if ( + descendantFocusability != FOCUS_AFTER_DESCENDANTS || + // No focusable descendants + (focusableCount == views.size())) { + // Note that we can't call the superclass here, because it will + // add all views in. So we need to do the same thing View does. + if (!isFocusable()) { + return; + } + if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE && + isInTouchMode() && !isFocusableInTouchMode()) { + return; + } + if (views != null) { + views.add(this); + } + } + } + + /** + * We only want the current page that is being shown to be touchable. + */ + @Override + public void addTouchables(ArrayList views) { + // Note that we don't call super.addTouchables(), which means that + // we don't call View.addTouchables(). This is okay because a ViewPager + // is itself not touchable. + for (int i = 0; i < getChildCount(); i++) { + final View child = getChildAt(i); + if (child.getVisibility() == VISIBLE) { + ItemInfo ii = infoForChild(child); + if (ii != null && ii.position == mCurItem) { + child.addTouchables(views); + } + } + } + } + + /** + * We only want the current page that is being shown to be focusable. + */ + @Override + protected boolean onRequestFocusInDescendants(int direction, + Rect previouslyFocusedRect) { + int index; + int increment; + int end; + int count = getChildCount(); + if ((direction & FOCUS_FORWARD) != 0) { + index = 0; + increment = 1; + end = count; + } else { + index = count - 1; + increment = -1; + end = -1; + } + for (int i = index; i != end; i += increment) { + View child = getChildAt(i); + if (child.getVisibility() == VISIBLE) { + ItemInfo ii = infoForChild(child); + if (ii != null && ii.position == mCurItem) { + if (child.requestFocus(direction, previouslyFocusedRect)) { + return true; + } + } + } + } + return false; + } + + @SuppressLint("WrongConstant") + @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + // Dispatch scroll events from this ViewPager. + if (event.getEventType() == AccessibilityEventCompat.TYPE_VIEW_SCROLLED) { + return super.dispatchPopulateAccessibilityEvent(event); + } + + // Dispatch all other accessibility events from the current page. + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + if (child.getVisibility() == VISIBLE) { + final ItemInfo ii = infoForChild(child); + if (ii != null && ii.position == mCurItem && + child.dispatchPopulateAccessibilityEvent(event)) { + return true; + } + } + } + + return false; + } + + @Override + protected ViewGroup.LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(); + } + + @Override + protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return generateDefaultLayoutParams(); + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams && super.checkLayoutParams(p); + } + + @Override + public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { + return new LayoutParams(getContext(), attrs); + } + + class MyAccessibilityDelegate extends AccessibilityDelegateCompat { + + @Override + public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(host, event); + event.setClassName(ViewPager.class.getName()); + final AccessibilityRecordCompat recordCompat = AccessibilityRecordCompat.obtain(); + recordCompat.setScrollable(canScroll()); + if (event.getEventType() == AccessibilityEventCompat.TYPE_VIEW_SCROLLED + && mAdapter != null) { + recordCompat.setItemCount(mAdapter.getCount()); + recordCompat.setFromIndex(mCurItem); + recordCompat.setToIndex(mCurItem); + } + } + + @Override + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { + super.onInitializeAccessibilityNodeInfo(host, info); + info.setClassName(ViewPager.class.getName()); + info.setScrollable(canScroll()); + if (internalCanScrollVertically(1)) { + info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD); + } + if (internalCanScrollVertically(-1)) { + info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD); + } + } + + @Override + public boolean performAccessibilityAction(View host, int action, Bundle args) { + if (super.performAccessibilityAction(host, action, args)) { + return true; + } + switch (action) { + case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: { + if (internalCanScrollVertically(1)) { + setCurrentItem(mCurItem + 1); + return true; + } + } + return false; + case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: { + if (internalCanScrollVertically(-1)) { + setCurrentItem(mCurItem - 1); + return true; + } + } + return false; + } + return false; + } + + private boolean canScroll() { + return (mAdapter != null) && (mAdapter.getCount() > 1); + } + } + + private class PagerObserver extends DataSetObserver { + @Override + public void onChanged() { + dataSetChanged(); + } + + @Override + public void onInvalidated() { + dataSetChanged(); + } + } + + /** + * Layout parameters that should be supplied for views added to a + * ViewPager. + */ + public static class LayoutParams extends ViewGroup.LayoutParams { + /** + * true if this view is a decoration on the pager itself and not + * a view supplied by the adapter. + */ + public boolean isDecor; + + /** + * Gravity setting for use on decor views only: + * Where to position the view page within the overall ViewPager + * container; constants are defined in {@link Gravity}. + */ + public int gravity; + + /** + * Width as a 0-1 multiplier of the measured pager width + */ + float heightFactor = 0.f; + + /** + * true if this view was added during layout and needs to be measured + * before being positioned. + */ + boolean needsMeasure; + + /** + * Adapter position this view is for if !isDecor + */ + int position; + + /** + * Current child index within the ViewPager that this view occupies + */ + int childIndex; + + public LayoutParams() { + super(FILL_PARENT, FILL_PARENT); + } + + public LayoutParams(Context context, AttributeSet attrs) { + super(context, attrs); + + final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS); + gravity = a.getInteger(0, Gravity.TOP); + a.recycle(); + } + } + + static class ViewPositionComparator implements Comparator { + @Override + public int compare(View lhs, View rhs) { + final LayoutParams llp = (LayoutParams) lhs.getLayoutParams(); + final LayoutParams rlp = (LayoutParams) rhs.getLayoutParams(); + if (llp.isDecor != rlp.isDecor) { + return llp.isDecor ? 1 : -1; + } + return llp.position - rlp.position; + } + } + + public View getCurrentView() { + try { + final int currentItem = this.getCurrentItem(); + for (int i = 0; i < this.getChildCount(); i++) { + final View child = this.getChildAt(i); + final VerticalViewPager.LayoutParams layoutParams = (VerticalViewPager.LayoutParams) child.getLayoutParams(); + + Field f = layoutParams.getClass().getDeclaredField("position"); //NoSuchFieldException + f.setAccessible(true); + int position = (Integer) f.get(layoutParams); //IllegalAccessException + + if (!layoutParams.isDecor && currentItem == position) { + return child; + } + } + } catch (NoSuchFieldException e) { + Log.e(TAG, e.toString()); + } catch (IllegalArgumentException e) { + Log.e(TAG, e.toString()); + } catch (IllegalAccessException e) { + Log.e(TAG, e.toString()); + } + return null; + } +} \ No newline at end of file diff --git a/config.gradle b/config.gradle index d733c9c09..7d7250467 100644 --- a/config.gradle +++ b/config.gradle @@ -9,7 +9,7 @@ ext { ] manifestPlaceholders = [ //正式 - + serverHost : "https://napi.yaoulive.com", //測試 // serverHost : "https://ceshi.yaoulive.com", diff --git a/live/src/main/java/com/yunbao/live/activity/LiveActivity.java b/live/src/main/java/com/yunbao/live/activity/LiveActivity.java index 27de3c796..1781132e7 100644 --- a/live/src/main/java/com/yunbao/live/activity/LiveActivity.java +++ b/live/src/main/java/com/yunbao/live/activity/LiveActivity.java @@ -1109,9 +1109,7 @@ public abstract class LiveActivity extends AbsActivity implements SocketMessageL mLiveContributeViewHolder.addToParent(); } mLiveContributeViewHolder.show(); - if (CommonAppConfig.LIVE_ROOM_SCROLL && !mIsAnchor) { - ((LiveAudienceActivity) this).setScrollFrozen(true); - } + } /** @@ -1124,9 +1122,7 @@ public abstract class LiveActivity extends AbsActivity implements SocketMessageL mLiveMedalRankViewHolder.addToParent(); } mLiveMedalRankViewHolder.show(); - if (CommonAppConfig.LIVE_ROOM_SCROLL && !mIsAnchor) { - ((LiveAudienceActivity) this).setScrollFrozen(true); - } + } diff --git a/live/src/main/java/com/yunbao/live/activity/LiveAudienceActivity.java b/live/src/main/java/com/yunbao/live/activity/LiveAudienceActivity.java index 347c24a3f..c80613bcb 100644 --- a/live/src/main/java/com/yunbao/live/activity/LiveAudienceActivity.java +++ b/live/src/main/java/com/yunbao/live/activity/LiveAudienceActivity.java @@ -3,7 +3,6 @@ package com.yunbao.live.activity; import android.app.Dialog; import android.content.Context; import android.content.Intent; -import android.graphics.Outline; import android.media.AudioManager; import android.os.Bundle; import android.os.CountDownTimer; @@ -11,62 +10,36 @@ import android.os.Handler; import android.os.Looper; import android.text.TextUtils; import android.util.Log; -import android.view.Display; -import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.ViewOutlineProvider; -import android.view.ViewParent; -import android.widget.FrameLayout; import android.widget.ImageView; import androidx.annotation.IdRes; -import androidx.annotation.NonNull; -import androidx.core.view.GravityCompat; -import androidx.drawerlayout.widget.DrawerLayout; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; -import com.adjust.sdk.Adjust; -import com.adjust.sdk.AdjustEvent; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.blankj.utilcode.util.GsonUtils; -import com.ms.banner.Banner; -import com.opensource.svgaplayer.SVGAImageView; -import com.tencent.imsdk.v2.V2TIMCallback; -import com.tencent.imsdk.v2.V2TIMManager; import com.yunbao.common.CommonAppConfig; -import com.yunbao.common.CommonAppContext; import com.yunbao.common.Constants; import com.yunbao.common.HtmlConfig; -import com.yunbao.common.activity.WebViewActivity; import com.yunbao.common.bean.AnchorRecommendItemModel; import com.yunbao.common.bean.AnchorRecommendModel; import com.yunbao.common.bean.IMLoginModel; -import com.yunbao.common.bean.SlideInfoModel; import com.yunbao.common.bean.UserBean; -import com.yunbao.common.custom.CommonRefreshView; -import com.yunbao.common.custom.ItemDecoration; -import com.yunbao.common.custom.MyViewPager; import com.yunbao.common.dialog.EffectsSettingsDialog; import com.yunbao.common.dialog.LiveChargeDialogFragment; import com.yunbao.common.dialog.LiveTotalDialog; import com.yunbao.common.event.LiveAudienceEvent; -import com.yunbao.common.glide.ImgLoader; import com.yunbao.common.http.CommonHttpConsts; import com.yunbao.common.http.CommonHttpUtil; import com.yunbao.common.http.HttpCallback; import com.yunbao.common.http.HttpClient; import com.yunbao.common.http.main.MainNetManager; -import com.yunbao.common.interfaces.OnItemClickListener; import com.yunbao.common.manager.IMLoginManager; import com.yunbao.common.pay.PayCallback; import com.yunbao.common.pay.PayPresenter; import com.yunbao.common.utils.Bus; -import com.yunbao.common.utils.DeviceUtils; import com.yunbao.common.utils.DialogUitl; import com.yunbao.common.utils.L; import com.yunbao.common.utils.ProcessResultUtil; @@ -74,51 +47,33 @@ import com.yunbao.common.utils.RandomUtil; import com.yunbao.common.utils.RouteUtil; import com.yunbao.common.utils.ToastUtil; import com.yunbao.common.utils.WordUtil; -import com.yunbao.common.views.SlideInBannerViewHolder; +import com.yunbao.common.views.weight.VerticalViewPager; import com.yunbao.live.R; -import com.yunbao.live.adapter.LiveRoomScrollAdapter; -import com.yunbao.live.adapter.SidebarAdapter; +import com.yunbao.live.adapter.VerticalPagerAdapter; import com.yunbao.live.bean.LiveBean; -import com.yunbao.live.bean.LiveGuardInfo; -import com.yunbao.live.bean.LivePKUserListBean; -import com.yunbao.live.bean.LiveUserGiftBean; -import com.yunbao.live.bean.WishlistModel; -import com.yunbao.live.dialog.BlowkissDialog; import com.yunbao.live.dialog.LiveFansFragment; import com.yunbao.live.dialog.LiveGiftDialogFragment; import com.yunbao.live.dialog.LiveGuardDialogFragment; import com.yunbao.live.dialog.LiveHDDialogFragment; import com.yunbao.live.dialog.LiveMicUserDialogFragment; import com.yunbao.live.dialog.LiveWishListDialogFragment4Audience; -import com.yunbao.live.dialog.NewUserDialog; import com.yunbao.live.event.LinkMicTxAccEvent; import com.yunbao.live.event.LiveRoomChangeEvent; import com.yunbao.live.http.LiveHttpConsts; import com.yunbao.live.http.LiveHttpUtil; -import com.yunbao.live.presenter.LiveLinkMicAnchorPresenter; -import com.yunbao.live.presenter.LiveLinkMicPkPresenter; -import com.yunbao.live.presenter.LiveLinkMicPresenter; import com.yunbao.live.presenter.LiveRoomCheckLivePresenter; -import com.yunbao.live.presenter.LiveRyLinkMicPkPresenter; import com.yunbao.live.socket.SocketChatUtil; -import com.yunbao.live.socket.SocketClient; import com.yunbao.live.socket.SocketRyChatUtil; -import com.yunbao.live.socket.SocketRyClient; import com.yunbao.live.socket.SocketSendBean; import com.yunbao.live.utils.LiveImDeletUtil; -import com.yunbao.live.utils.LiveStorge; -import com.yunbao.live.views.LiveAudienceViewHolder; -import com.yunbao.live.views.LiveEndViewHolder; -import com.yunbao.live.views.LivePlayKsyViewHolder; -import com.yunbao.live.views.LivePlayRyViewHolder; -import com.yunbao.live.views.LivePlayTxViewHolder; import com.yunbao.live.views.LiveRoomPlayViewHolder; -import com.yunbao.live.views.LiveRoomViewHolder; +import com.yunbao.live.views.PortraitLiveManager; -import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import cn.rongcloud.rtc.api.RCRTCEngine; @@ -126,20 +81,11 @@ import cn.rongcloud.rtc.api.callback.IRCRTCResultCallback; import cn.rongcloud.rtc.api.callback.IRCRTCSwitchRoleCallback; import cn.rongcloud.rtc.base.RTCErrorCode; import io.rong.imlib.IRongCallback; -import io.rong.imlib.IRongCoreCallback; -import io.rong.imlib.IRongCoreEnum; import io.rong.imlib.RongIMClient; -import io.rong.imlib.chatroom.base.RongChatRoomClient; import io.rong.imlib.model.Conversation; import io.rong.message.TextMessage; -import pl.droidsonroids.gif.GifImageView; -import static com.yunbao.common.CommonAppContext.logger; -import static com.yunbao.common.CommonAppContext.mFirebaseAnalytics; -import static com.yunbao.live.presenter.LiveLinkMicPresenter.mBannerList2; -import static com.yunbao.live.views.LivePlayKsyViewHolder.setViewUP; import static com.yunbao.live.views.LivePlayRyViewHolder.Micing; -import static com.yunbao.live.views.LiveRoomViewHolder.isStayRoomfive; /** * Created by cxf on 2018/10/10. @@ -150,665 +96,219 @@ public class LiveAudienceActivity extends LiveActivity { private static final String TAG = "LiveAudienceActivity"; public static String anyway; - public static JSONObject pkInfo; + public JSONObject pkInfo; public static LiveAudienceActivity liveAudienceActivity; - private Banner mBanner; - public CommonRefreshView sidebarList; - private SidebarAdapter sidebarAdapter; - private ImageView sidebarBack; - private DrawerLayout drawerLayout; - public static void forward(Context context, LiveBean liveBean, int liveType, int liveTypeVal, String key, int position, int liveSdk) { - Intent intent = new Intent(context, LiveAudienceActivity.class); - intent.putExtra(Constants.LIVE_BEAN, liveBean); - intent.putExtra(Constants.LIVE_TYPE, liveType); - intent.putExtra(Constants.LIVE_TYPE_VAL, liveTypeVal); - intent.putExtra(Constants.LIVE_KEY, key); - intent.putExtra(Constants.LIVE_POSITION, position); - intent.putExtra(Constants.LIVE_SDK, liveSdk); - intent.putExtra(Constants.LIVE_SDK, liveSdk); - intent.putExtra("landscape", liveBean.getLandscape()); - intent.putExtra("isry", liveBean.getIs_rong()); - context.startActivity(intent); - } + // 竖直滑动 ViewPager + private VerticalViewPager verticalViewPager; + // ViewPager 的 Adapter + private VerticalPagerAdapter mPagerAdapter; + //直播间滑动数据列表 + private List itemModelList = new ArrayList<>(); - private String mKey; - private int mPosition; - private RecyclerView mRecyclerView; - private LiveRoomScrollAdapter mRoomScrollAdapter; - private View mMainContentView; - public static MyViewPager mViewPager; - private ViewGroup mSecondPage;//默认显示第二页 - private FrameLayout mContainerWrap; - public static LiveRoomPlayViewHolder mLivePlayViewHolder; - private LiveAudienceViewHolder mLiveAudienceViewHolder; - private boolean mEnd; private boolean mCoinNotEnough;//余额不足 private LiveRoomCheckLivePresenter mCheckLivePresenter; private boolean mLighted; private PayPresenter mPayPresenter; - public static ImageView btnSmallScreen; + public ImageView btnSmallScreen; public static String is_fans; public static int fansNum; - public static int backIndex = 0;//0=未判断,1=已判断 + public static ProcessResultUtil mProcessResultUtil; private LiveImDeletUtil liveImDeletUtil; public static int isattention; - private ImageView liveBack; - private LiveBean liveBean; + + private LiveBean mLiveBean; + //当前直播间下标 + private int mCurrentItem, mCurrentPage; + private static PortraitLiveManager manager; + private int mLastPosition = -1; + + private ViewGroup mViewGroup; + @Override public T findViewById(@IdRes int id) { - if (CommonAppConfig.LIVE_ROOM_SCROLL) { - if (mMainContentView != null) { - return mMainContentView.findViewById(id); - } - } + return super.findViewById(id); } @Override protected int getLayoutId() { - if (CommonAppConfig.LIVE_ROOM_SCROLL) { - return R.layout.activity_live_audience_2; - } - return R.layout.activity_live_audience; - } - - public void setScrollFrozen(boolean frozen) { - if (mRecyclerView != null) { - mRecyclerView.setLayoutFrozen(frozen); - } + return R.layout.activity_live_detail; } @Override protected void main() { Bus.getOn(this); - - liveImDeletUtil = new LiveImDeletUtil(); - if (getIntent().getIntExtra("isry", 0) == 1) { - isRy = true; - } else { - isRy = false; - } - liveAudienceActivity = this; - setVolumeControlStream(AudioManager.STREAM_MUSIC); - if (CommonAppConfig.LIVE_ROOM_SCROLL) { - mRecyclerView = super.findViewById(R.id.recyclerView); - mRecyclerView.setHasFixedSize(true); - mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false)); - mMainContentView = LayoutInflater.from(mContext).inflate(R.layout.activity_live_audience, null, false); - } super.main(); + liveAudienceActivity = this; + liveImDeletUtil = new LiveImDeletUtil(); + mProcessResultUtil = new ProcessResultUtil(this); Intent intent = getIntent(); mLiveSDK = intent.getIntExtra(Constants.LIVE_SDK, Constants.LIVE_SDK_KSY); L.e(TAG, "直播sdk----->" + (mLiveSDK == Constants.LIVE_SDK_KSY ? "金山云" : "腾讯云")); - mProcessResultUtil = new ProcessResultUtil(this); - if (isRy == false) { - mLivePlayViewHolder = new LivePlayKsyViewHolder(mContext, (ViewGroup) findViewById(R.id.play_container), getIntent().getIntExtra("landscape", 0)); - } else { - mLivePlayViewHolder = new LivePlayRyViewHolder(mContext, (ViewGroup) findViewById(R.id.play_container), getIntent().getIntExtra("landscape", 0)); - } - mLivePlayViewHolder.addToParent(); - mLivePlayViewHolder.subscribeActivityLifeCycle(); - mViewPager = (MyViewPager) findViewById(R.id.viewPager); - mSecondPage = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.view_audience_page, mViewPager, false); - mContainerWrap = mSecondPage.findViewById(R.id.container_wrap); - mContainer = mSecondPage.findViewById(R.id.container); - btnSmallScreen = findViewById(R.id.btn_small_screen); - btnSmallScreen.setOnClickListener(v -> { - mViewPager.setCurrentItem(1); - btnSmallScreen.setVisibility(View.GONE); - ((LiveAudienceActivity) mContext).mLivePlayViewHolder.smallScreen(); - }); - mContainer.removeAllViews(); - mLiveRoomViewHolder = new LiveRoomViewHolder(false, 1, mContext, mContainer, (GifImageView) mSecondPage.findViewById(R.id.gift_gif), (SVGAImageView) mSecondPage.findViewById(R.id.gift_svga), mContainerWrap, getWindowManager()); - mLiveRoomViewHolder.addToParent(); - mLiveRoomViewHolder.subscribeActivityLifeCycle(); - mLiveAudienceViewHolder = new LiveAudienceViewHolder(mContext, mContainer); - mLiveAudienceViewHolder.addToParent(); - mLiveAudienceViewHolder.subscribeActivityLifeCycle(); - mLiveBottomViewHolder = mLiveAudienceViewHolder; - mViewPager.setAdapter(new PagerAdapter() { - - @Override - public int getCount() { - return 2; - } - - @Override - public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { - return view == object; - } - - @NonNull - @Override - public Object instantiateItem(@NonNull ViewGroup container, int position) { - if (position == 0) { - View view = new View(mContext); - view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - container.addView(view); - return view; - } else { - container.addView(mSecondPage); - return mSecondPage; - } - } - - @Override - public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { - } - }); - mViewPager.setCurrentItem(1); - mLiveLinkMicPresenter = new LiveLinkMicPresenter(mContext, mLivePlayViewHolder, false, mLiveSDK, mLiveAudienceViewHolder.getContentView()); - mLiveLinkMicAnchorPresenter = new LiveLinkMicAnchorPresenter(mContext, mLivePlayViewHolder, false, mLiveSDK, null); - if (isRy == false) { - mLiveLinkMicPkPresenter = new LiveLinkMicPkPresenter(mContext, mLivePlayViewHolder, false, null); - } else { - mLiveRyLinkMicPkPresenter = new LiveRyLinkMicPkPresenter(mContext, mLivePlayViewHolder, false, null); - } - if (CommonAppConfig.LIVE_ROOM_SCROLL) { - mKey = intent.getStringExtra(Constants.LIVE_KEY); - mPosition = intent.getIntExtra(Constants.LIVE_POSITION, 0); - List list = LiveStorge.getInstance().get(mKey); - mRoomScrollAdapter = new LiveRoomScrollAdapter(mContext, list, mPosition); - mRoomScrollAdapter.setActionListener(new LiveRoomScrollAdapter.ActionListener() { - @Override - public void onPageSelected(LiveBean liveBean, ViewGroup container, boolean first) { - L.e(TAG, "onPageSelected----->" + liveBean); - if (mMainContentView != null && container != null) { - ViewParent parent = mMainContentView.getParent(); - if (parent != null) { - ViewGroup viewGroup = (ViewGroup) parent; - if (viewGroup != container) { - viewGroup.removeView(mMainContentView); - container.addView(mMainContentView); - } - } else { - container.addView(mMainContentView); - } - } - if (!first) { - checkLive(liveBean); - } - } - - @Override - public void onPageOutWindow(String liveUid) { - L.e(TAG, "onPageOutWindow----->" + liveUid); - if (TextUtils.isEmpty(mLiveUid) || mLiveUid.equals(liveUid)) { - LiveHttpUtil.cancel(LiveHttpConsts.CHECK_LIVE); - LiveHttpUtil.cancel(LiveHttpConsts.ENTER_ROOM); - LiveHttpUtil.cancel(LiveHttpConsts.ROOM_CHARGE); - clearRoomData(); - } - } - }); - mRecyclerView.setAdapter(mRoomScrollAdapter); - } mLiveType = intent.getIntExtra(Constants.LIVE_TYPE, Constants.LIVE_TYPE_NORMAL); mLiveTypeVal = intent.getIntExtra(Constants.LIVE_TYPE_VAL, 0); - liveBean = intent.getParcelableExtra(Constants.LIVE_BEAN); - setLiveRoomData(liveBean); - enterRoom(); - //直播页面背景 - liveBack = findViewById(R.id.live_back); - ImgLoader.displayBlurLive(mContext, liveBean.getAvatar(), liveBack); + mLiveBean = intent.getParcelableExtra(Constants.LIVE_BEAN); + setVolumeControlStream(AudioManager.STREAM_MUSIC); + manager = new PortraitLiveManager(this, intent); + initView(); + initData(); + } + /** + * 初始化界面 + */ + private void initView() { + // 竖直滑动 ViewPager + verticalViewPager = findViewById(R.id.view_pager); - //侧边栏 - drawerLayout = findViewById(R.id.drawer_layout); - FrameLayout leftDrawer = findViewById(R.id.left_drawer); - DrawerLayout.LayoutParams layoutParams = (DrawerLayout.LayoutParams) leftDrawer.getLayoutParams(); - layoutParams.width = DeviceUtils.getScreenWidth(this) / 3 * 2; - leftDrawer.setLayoutParams(layoutParams); - sidebarList = (CommonRefreshView) findViewById(R.id.sidebarList); - sidebarBack = findViewById(R.id.sidebar_back); - ImgLoader.displayBlurLive(mContext, liveBean.getAvatar(), sidebarBack); - //禁止滑动打开侧边栏 - drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); - sidebarList.setEmptyLayoutId(R.layout.view_no_data_live); - GridLayoutManager gridLayoutManager = new GridLayoutManager(mContext, 2, GridLayoutManager.VERTICAL, false); - sidebarList.setLayoutManager(gridLayoutManager); - sidebarList.setLoadMoreEnable(false); - ItemDecoration decoration = new ItemDecoration(mContext, 0x00000000, 6, 0); - decoration.setOnlySetItemOffsetsButNoDraw(true); - sidebarList.setItemDecoration(decoration); - Display mDisplay = getWindowManager().getDefaultDisplay(); - sidebarAdapter = new SidebarAdapter(mContext, mDisplay.getHeight()); - sidebarAdapter.setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AnchorRecommendItemModel bean, int position) { - gotoLive(bean.getUid()); - } - }); - sidebarAdapter.setHasStableIds(true); - sidebarList.setRecyclerViewAdapter(sidebarAdapter); + } - sidebarList.setDataHelperNew(new CommonRefreshView.DataHelperNew() { - @Override - public void loadData(int p) { + public void setBackIndex(int backIndex) { + manager.setBackIndex(backIndex); + } - } + public static LiveRoomPlayViewHolder getmLivePlayViewHolder() { + return manager.getmLivePlayViewHolder(); + } - @Override - public void refresh() { - //推荐位 - MainNetManager.get(mContext) - .anchorRecommend("10", new com.yunbao.common.http.base.HttpCallback() { - @Override - public void onSuccess(AnchorRecommendModel data) { - if (isFinishing()) return; + public static void setCurrentItem(int index) { + manager.mViewPager.setCurrentItem(index); + } - sidebarAdapter.addData(data.getList()); - sidebarList.onFinish(); - } - - @Override - public void onError(String error) { - } - }); - - - } - }); - sidebarList.initData(); - mBanner = findViewById(R.id.banner); - mBanner.setOutlineProvider(new ViewOutlineProvider() { - @Override - public void getOutline(View view, Outline outline) { - outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), 10); - } - }); - mBanner.setClipToOutline(true); - - //侧边栏 + /** + * 初始化数据 + */ + private void initData() { + //直播间列表 MainNetManager.get(mContext) - .getHot(1, new com.yunbao.common.http.base.HttpCallback>() { + .anchorRecommend("30", new com.yunbao.common.http.base.HttpCallback() { @Override - public void onSuccess(List data) { - runOnUiThread(() -> onBanner(data)); - + public void onSuccess(AnchorRecommendModel data) { + itemModelList = data.getList(); + //查询直播间状态 + int index = -1; + for (int i = 0; i < itemModelList.size(); i++) { + AnchorRecommendItemModel model = itemModelList.get(i); + if (TextUtils.equals(mLiveBean.getUid(), model.getUid())) { + index = i; + } + } + if (index > -1) { + Collections.swap(itemModelList, index, 0); + } else { + String json = GsonUtils.toJson(mLiveBean); + AnchorRecommendItemModel model = GsonUtils.fromJson(json, AnchorRecommendItemModel.class); + itemModelList.add(0, model); + } + mPagerAdapter = new VerticalPagerAdapter(itemModelList, mContext); + verticalViewPager.setAdapter(mPagerAdapter); } @Override public void onError(String error) { - + ToastUtil.show(error); } }); - //心愿单 - LiveHttpUtil.getWishList(mLiveUid, new HttpCallback() { + + + verticalViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override - public void onSuccess(int code, String msg, String[] info) { - if (info.length > 0) { - String json = info[0]; - WishlistModel model = GsonUtils.fromJson(json, WishlistModel.class); - mLiveRoomViewHolder.initWishList(model.getWishlist()); - } + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + mCurrentItem = position; + Log.e(TAG, "mCurrentItem:" + mCurrentItem); } @Override - public void onFinish() { + public void onPageSelected(int position) { + super.onPageSelected(position); + mCurrentPage = position; } }); + verticalViewPager.setPageTransformer(false, new ViewPager.PageTransformer() { + @Override + public void transformPage(View page, float position) { + if (itemModelList.size() == 0) { + return; + } + ViewGroup viewGroup = (ViewGroup) page; + Log.e(TAG, "position:" + mCurrentItem); + if ((position < 0 && viewGroup.getId() != mCurrentItem)) { + // room_container 为视频播放的根布局 id + View rootView = viewGroup.findViewById(R.id.drawer_layout); + if (rootView != null && rootView.getParent() != null && rootView.getParent() instanceof ViewGroup) { + ((ViewGroup) (rootView.getParent())).removeView(rootView); + manager.onRemove(); + } + } + + // 满足此种条件,表明需要加载直播视频,以及聊天室了 + if (viewGroup.getId() == mCurrentItem && (position == 0)&& mCurrentItem != mLastPosition) { + + loadData(viewGroup,mCurrentItem); + } + } + + + }); } - //定时器 - public static CountDownTimer countDownTimer = null; - private int timeIndex = 1; + private void loadData(ViewGroup viewGroup, int currentItem) { + mViewGroup = viewGroup; + AnchorRecommendItemModel data = itemModelList.get(mCurrentPage); - public void setTime() { - backIndex = 0; - L.e(TAG, "alert_end_time----->" + CommonAppConfig.getInstance().alert_end_time); - countDownTimer = new CountDownTimer(CommonAppConfig.getInstance().alert_end_time * 1000, 1000) { - @Override - public void onTick(long millisUntilFinished) { + //获取直播间状态 + LiveHttpUtil.getLiveInfo(data.getUid(), liveInfo); + mLastPosition = currentItem; - if (IMLoginManager.get(mContext).isisNewUserOne() == true && timeIndex == 10) { - NewUserDialog fragment1 = new NewUserDialog(); - fragment1.show(((LiveActivity) mContext).getSupportFragmentManager(), "NewUserDialog"); - } - - if (timeIndex == CommonAppConfig.getInstance().alert_time) { - if (mLiveRoomViewHolder.isAttention == 0) { - BlowkissDialog fragment1 = new BlowkissDialog(); - fragment1.show(((LiveActivity) mContext).getSupportFragmentManager(), "BlowkissDialog"); - } - } - timeIndex++; - if (mLiveRoomViewHolder != null && timeIndex < CommonAppConfig.getInstance().alert_end_time) { - mLiveRoomViewHolder.isStayRoom(false); - } - L.e(TAG, "timeIndex----->" + timeIndex); - } - - /** - *倒计时结束后调用的 - */ - @Override - public void onFinish() { - if (timeIndex >= CommonAppConfig.getInstance().alert_end_time) { - if (mLiveRoomViewHolder != null) { - mLiveRoomViewHolder.isStayRoom(true); - } - } - } - }; - countDownTimer.start(); } - String avat; - - private void setLiveRoomData(LiveBean liveBean) { - mLiveBean = liveBean; - mLiveUid = liveBean.getUid(); - mStream = liveBean.getStream(); - mAncherName = liveBean.getUserNiceName(); - - mLivePlayViewHolder.setCover(liveBean.getThumb()); - mLivePlayViewHolder.play(liveBean.getPull()); - avat = liveBean.getAvatar(); - mLiveRoomViewHolder.setAvatar(liveBean.getAvatar()); - mLiveRoomViewHolder.setAnchorLevel(liveBean.getLevelAnchor()); - mLiveRoomViewHolder.setName(liveBean.getUserNiceName()); - mLiveRoomViewHolder.setRoomNum(liveBean.getLiangNameTip()); - mLiveRoomViewHolder.setTitle(liveBean.getTitle()); - if (isRy == false) { - mLiveLinkMicPkPresenter.setLiveUid(mLiveUid, ""); - } else { - mLiveRyLinkMicPkPresenter.setLiveUid(mLiveUid, ""); - } - mLiveLinkMicPresenter.setLiveUid(mLiveUid); - } - - private void clearRoomData() { - if (mSocketClient != null) { - mSocketClient.disConnect(); - mSocketClient = null; - } - if (mSocketRyClient != null) { - mSocketRyClient.disConnect(); - mSocketRyClient = null; - - } - if (mLivePlayViewHolder != null) { - mLivePlayViewHolder.stopPlay(); - } - - if (mLivePlayViewHolder != null) { - mLivePlayViewHolder.stopPlay(); - } - - if (mLiveRoomViewHolder != null) { - mLiveRoomViewHolder.clearData(); - } - if (mLiveEndViewHolder != null) { - mLiveEndViewHolder.removeFromParent(); - } - if (mLiveLinkMicPresenter != null) { - mLiveLinkMicPresenter.clearData(); - } - if (mLiveLinkMicAnchorPresenter != null) { - mLiveLinkMicAnchorPresenter.clearData(); - } - if (mLiveLinkMicPkPresenter != null) { - mLiveLinkMicPkPresenter.clearData(); - } - if (mLiveRyLinkMicPkPresenter != null) { - mLiveRyLinkMicPkPresenter.clearData(); - } - } - - private void checkLive(LiveBean bean) { - if (mCheckLivePresenter == null) { - mCheckLivePresenter = new LiveRoomCheckLivePresenter(mContext, new LiveRoomCheckLivePresenter.ActionListener() { - @Override - public void onLiveRoomChanged(LiveBean liveBean, int liveType, int liveTypeVal, int liveSdk) { - if (liveBean == null) { + /** + * 获取直播间状态 + */ + private HttpCallback liveInfo = new HttpCallback() { + @Override + public void onSuccess(int code, String msg, String[] info) { + if (code == 0 && info.length > 0) { + LiveBean liveBean = JSON.parseObject(info[0], LiveBean.class); + LiveRoomCheckLivePresenter mCheckLivePresenter = new LiveRoomCheckLivePresenter(mContext, (liveBean1, liveType, liveTypeVal, liveSdk) -> { + //主播正在直播 + if (liveBean1 == null) { return; } - setLiveRoomData(liveBean); + mLiveSDK = liveSdk; mLiveType = liveType; mLiveTypeVal = liveTypeVal; - if (mRoomScrollAdapter != null) { - mRoomScrollAdapter.hideCover(); + mLiveBean = liveBean1; + mStream = liveBean.getStream(); + mAncherName = liveBean.getUserNiceName(); + //加载当前页面数据 + View rootView = manager.getRootView(); + if (rootView.getParent() != null && rootView.getParent() instanceof ViewGroup) { + ((ViewGroup) (rootView.getParent())).removeView(rootView); + manager.onRemove(); } - enterRoom(); - } - }); - } - mCheckLivePresenter.checkLive(bean); - } + mViewGroup.addView(manager.getRootView()); + manager.onAdd(liveBean, liveType, liveTypeVal, liveSdk); + }); + + mCheckLivePresenter.checkLive(liveBean); + } else { + //直播间未直播 - private void enterRoom() { - //进入直播间IM - if (isRy == false) { - mSocketClient = new SocketClient(mLiveUid, LiveAudienceActivity.this); - if (mLiveLinkMicPresenter != null) { - mLiveLinkMicPresenter.setSocketClient(mSocketClient); - } - } else { - mSocketRyClient = new SocketRyClient(mLiveUid, LiveAudienceActivity.this); - if (mLiveLinkMicPresenter != null) { - mLiveLinkMicPresenter.setSocketClient(mSocketClient); } } - timeIndex = 0; - LiveHttpUtil.enterRoom(mLiveUid, mStream, new HttpCallback() { - @Override - public void onSuccess(int code, String msg, String[] info) { - if (code == 0 && info.length > 0) { - JSONObject obj = JSON.parseObject(info[0]); - mDanmuPrice = obj.getString("barrage_fee"); - mSocketUserType = obj.getIntValue("usertype"); - mChatLevel = obj.getIntValue("speak_limit"); - mDanMuLevel = obj.getIntValue("barrage_limit"); + }; - EventBus.getDefault().post("close_login"); - EventBus.getDefault().post("oneUesrOver"); - //进入直播间 - AdjustEvent adjustEvent1 = new AdjustEvent("hiepcu"); - Adjust.trackEvent(adjustEvent1); - mFirebaseAnalytics.logEvent("FS_enterroom", null); - logger.logEvent("FB_enterroom"); + private void clearRoomData() { - //观看1分钟 - if (obj.getIntValue("see_time") >= 60) { - AdjustEvent good_user = new AdjustEvent("7zxuxz"); - Adjust.trackEvent(good_user); - CommonHttpUtil.setAdvertisingChannels("7zxuxz", new HttpCallback() { - @Override - public void onSuccess(int code, String msg, String[] info) { - if (code == 0) { - mFirebaseAnalytics.logEvent("FS_enter_app_1min", null); - logger.logEvent("FB_enter_app_1min", null); - } - } - }); - } - if (obj.getIntValue("see_time") >= 600 && obj.getIntValue("un_charge") == 1) { - AdjustEvent good_user = new AdjustEvent("val8lv"); - Adjust.trackEvent(good_user); - CommonHttpUtil.setAdvertisingChannels("val8lv", new HttpCallback() { - @Override - public void onSuccess(int code, String msg, String[] info) { - if (code == 0) { - mFirebaseAnalytics.logEvent("FS_good_user", null); - logger.logEvent("FB_good_user", null); - } - } - }); - - //有效用户 - } else if (obj.getIntValue("see_time") >= 600) { - AdjustEvent valid_user = new AdjustEvent("xuf8ep"); - Adjust.trackEvent(valid_user); - CommonHttpUtil.setAdvertisingChannels("xuf8ep", new HttpCallback() { - @Override - public void onSuccess(int code, String msg, String[] info) { - if (code == 0) { - mFirebaseAnalytics.logEvent("FS_Valid_user", null); - logger.logEvent("FB_Valid_user", null); - } - } - }); - } - //连接socket - LiveHttpUtil.enterBackRoom(mLiveUid, mStream, new HttpCallback() { - @Override - public void onSuccess(int code, String msg, String[] info) { - - } - }); - if (mLiveRoomViewHolder != null) { - LivePlayKsyViewHolder.setLandscape(obj.getIntValue("landscape")); - - mLiveRoomViewHolder.setLiveInfo(mLiveUid, mStream, obj.getIntValue("userlist_time") * 4000); - mLiveRoomViewHolder.setVotes(obj.getString("votestotal")); - //真爱排行 数量 - mLiveRoomViewHolder.setMedaRankNum(obj.getString("medalRankNum")); - isattention = obj.getIntValue("isattention"); - if (isattention == 0) { - if (countDownTimer != null) { - countDownTimer.cancel(); - timeIndex = 0; - countDownTimer = null; - setTime(); - } else { - setTime(); - } - } else { - if (countDownTimer != null) { - countDownTimer.cancel(); - countDownTimer = null; - } - } - mLiveAudienceViewHolder.setLiveInfo(mLiveUid, mStream, avat, isattention); - mLiveRoomViewHolder.setAttention(isattention); - if (obj.containsKey("lminfo")) { - JSONObject mic_data = obj.getJSONObject("lminfo"); - if (mic_data.containsKey("userlist")) { - mLiveRoomViewHolder.updataMicList(mic_data.getJSONArray("userlist")); - } - } - List list = JSON.parseArray(obj.getString("userlists"), LiveUserGiftBean.class); - mLiveRoomViewHolder.setUserList(list); - mLiveRoomViewHolder.startRefreshUserList(); - if (mLiveType == Constants.LIVE_TYPE_TIME) {//计时收费 - mLiveRoomViewHolder.startRequestTimeCharge(); - } - } - - if (obj.getString("isleave").equals("1")) { - if (LivePlayKsyViewHolder.leave != null) { - LivePlayKsyViewHolder.leave.setVisibility(View.VISIBLE); - } - } - //判断是否有连麦,要显示连麦窗口 - String linkMicUid = obj.getString("linkmic_uid"); - String linkMicPull = obj.getString("linkmic_pull"); - if (!TextUtils.isEmpty(linkMicUid) && !"0".equals(linkMicUid) && !TextUtils.isEmpty(linkMicPull)) { - if (mLiveSDK != Constants.LIVE_SDK_TX && mLiveLinkMicPresenter != null) { - mLiveLinkMicPresenter.onLinkMicPlay(linkMicUid, linkMicPull); - } - } - //判断是否有主播连麦 - pkInfo = JSON.parseObject(obj.getString("pkinfo")); - if (pkInfo != null && pkInfo.getIntValue("drpk_status") != 1) { - String pkUid = pkInfo.getString("pkuid"); - anyway = "1"; - if (!TextUtils.isEmpty(pkUid) && !"0".equals(pkUid) && anyway.equals("0")) { - if (mLiveSDK != Constants.LIVE_SDK_TX) { - String pkPull = pkInfo.getString("pkpull"); - if (!TextUtils.isEmpty(pkPull) && mLiveLinkMicAnchorPresenter != null) { - mLiveLinkMicAnchorPresenter.onLinkMicAnchorPlayUrl(pkUid, pkPull); - } - } else { - if (mLivePlayViewHolder instanceof LivePlayTxViewHolder) { - ((LivePlayTxViewHolder) mLivePlayViewHolder).setAnchorLinkMic(true, 0); - } - } - } - - if (obj.getString("isconnection") != null && obj.getString("isconnection").equals("1")) { - if (isRy == false) { - setViewUP(); - } else { - LivePlayRyViewHolder.setViewUP(1); - } - } - if (pkInfo.getIntValue("ifpk") == 1 && pkInfo.getString("end_pk_time").equals("0")) {//pk开始了 - if (isRy == false) { - setViewUP(); - } else { - LivePlayRyViewHolder.setViewUP(2); - } - //pk排名数据 - LivePKUserListBean livePKUserListBean = JSON.parseObject(pkInfo.getString("pk_top_users"), LivePKUserListBean.class); - if (mLiveRoomViewHolder != null) { - mLiveRoomViewHolder.setOtherInfo(pkInfo.getString("pkuid"), pkInfo.getString("pkuimg"), pkInfo.getString("pkuname")); - } - if (mLiveLinkMicPkPresenter != null) { - mLiveLinkMicPkPresenter.onEnterRoomPkStart(pkUid, pkInfo.getLongValue("pk_gift_liveuid"), pkInfo.getLongValue("pk_gift_pkuid"), pkInfo.getIntValue("pk_time"), livePKUserListBean); - } else { - mLiveRyLinkMicPkPresenter.onEnterRoomPkStart(pkUid, pkInfo.getLongValue("pk_gift_liveuid"), pkInfo.getLongValue("pk_gift_pkuid"), pkInfo.getIntValue("pk_time"), livePKUserListBean); - } - } else if (!pkInfo.getString("end_pk_time").equals("0")) { - if (isRy == false) { - setViewUP(); - } else { - LivePlayRyViewHolder.setViewUP(3); - } - //pk排名数据 - LivePKUserListBean livePKUserListBean = JSON.parseObject(pkInfo.getString("pk_top_users"), LivePKUserListBean.class); - if (mLiveLinkMicPkPresenter != null) { - mLiveLinkMicPkPresenter.onEnterRoomCFStart(pkUid, pkInfo.getLongValue("pk_gift_liveuid"), pkInfo.getLongValue("pk_gift_pkuid"), pkInfo.getIntValue("end_pk_time"), livePKUserListBean); - } else { - mLiveRyLinkMicPkPresenter.onEnterRoomCFStart(pkUid, pkInfo.getLongValue("pk_gift_liveuid"), pkInfo.getLongValue("pk_gift_pkuid"), pkInfo.getIntValue("end_pk_time"), livePKUserListBean); - - } - } - //多人PK - } else if (pkInfo != null && pkInfo.getIntValue("drpk_status") == 1) { - if (isRy == false) { - setViewUP(); - } else { - LivePlayRyViewHolder.setViewUP(4); - } - mLiveRoomViewHolder.UpPkBar(pkInfo.getJSONArray("userlist"), mLiveUid, pkInfo.getIntValue("drpk_time")); - } - - //守护相关 - mLiveGuardInfo = new LiveGuardInfo(); - int guardNum = obj.getIntValue("guard_nums"); - fansNum = obj.getIntValue("count_fans"); - is_fans = obj.getString("is_fans") + ""; - mLiveGuardInfo.setGuardNum(guardNum); - JSONObject guardObj = obj.getJSONObject("guard"); - if (guardObj != null) { - mLiveGuardInfo.setMyGuardType(guardObj.getIntValue("type")); - mLiveGuardInfo.setMyGuardEndTime(guardObj.getString("endtime")); - } - if (mLiveRoomViewHolder != null) { - mLiveRoomViewHolder.setGuardNum(guardNum); - mLiveRoomViewHolder.setFansNum(fansNum); - //红包相关 - mLiveRoomViewHolder.setRedPackBtnVisible(obj.getIntValue("isred") == 1); - } - //奖池等级 - int giftPrizePoolLevel = obj.getIntValue("jackpot_level"); - if (giftPrizePoolLevel >= 0) { - if (mLiveRoomViewHolder != null) { - mLiveRoomViewHolder.showPrizePoolLevel(String.valueOf(giftPrizePoolLevel)); - } - } - } - } - }); } + /** * 打开礼物窗口 */ @@ -869,31 +369,7 @@ public class LiveAudienceActivity extends LiveActivity { * 结束观看 */ public void endPlay() { - CommonAppContext.Ingroup = 0; - mLiveAudienceViewHolder.handler.removeCallbacks(mLiveAudienceViewHolder.runnable); - mLiveAudienceViewHolder.handler1.removeCallbacks(mLiveAudienceViewHolder.runnable1); - if (mEnd) { - return; - } - mEnd = true; - //断开socket - if (isRy == false) { - if (mSocketClient != null) { - mSocketClient.disConnect(); - } - mSocketClient = null; - } else { - if (mSocketRyClient != null) { - mSocketRyClient.disConnect(); - } - mSocketRyClient = null; - } - - //结束播放 - if (mLivePlayViewHolder != null) { - mLivePlayViewHolder.release(); - } - mLivePlayViewHolder = null; + manager.endPlay(); release(); } @@ -908,14 +384,6 @@ public class LiveAudienceActivity extends LiveActivity { LiveHttpUtil.cancel(LiveHttpConsts.ROOM_CHARGE); CommonHttpUtil.cancel(CommonHttpConsts.GET_BALANCE); super.release(); - if (mRoomScrollAdapter != null) { - mRoomScrollAdapter.setActionListener(null); - } - mRoomScrollAdapter = null; - if (mLiveAudienceViewHolder != null) { - mLiveAudienceViewHolder.countDownTimerTrickery = null; - mLiveAudienceViewHolder = null; - } } @@ -925,26 +393,7 @@ public class LiveAudienceActivity extends LiveActivity { @Override public void onLiveEnd() { super.onLiveEnd(); - if (!CommonAppConfig.LIVE_ROOM_SCROLL) { - if (mViewPager != null) { - if (mViewPager.getCurrentItem() != 1) { - mViewPager.setCurrentItem(1, false); - } - mViewPager.setCanScroll(false); - } - endPlay(); - } else { - if (mLivePlayViewHolder != null) { - mLivePlayViewHolder.stopPlay2(); - } - } - if (mLiveEndViewHolder == null) { - mLiveEndViewHolder = new LiveEndViewHolder(mContext, mSecondPage, mLiveBean.getUid()); - mLiveEndViewHolder.subscribeActivityLifeCycle(); - mLiveEndViewHolder.addToParent(); - } - mLiveBean.setIsattention(isattention + ""); - mLiveEndViewHolder.showData(mLiveBean, mStream); + manager.onLiveEnd(); } @@ -986,9 +435,7 @@ public class LiveAudienceActivity extends LiveActivity { @Override public void prankTurntable(String msgtype, int time, JSONObject jsonObject) { - if (mLiveAudienceViewHolder != null) { - mLiveAudienceViewHolder.closeAndOpenTrickery(msgtype, time, jsonObject); - } + manager.prankTurntable(msgtype, time, jsonObject); } @Override @@ -1105,81 +552,14 @@ public class LiveAudienceActivity extends LiveActivity { } public void end() { - IMLoginManager.get(this).setisNewUserOne(false); - if (!mEnd && !canBackPressed()) { - return; - } - if (countDownTimer != null) { - countDownTimer.cancel(); - countDownTimer = null; - timeIndex = 0; - } - if (backIndex == 0) { - if (LiveRoomViewHolder.isAttention == 0) { - if (isStayRoomfive) { - LiveRoomViewHolder.showFollowDialog(LiveRoomViewHolder.mNameText, LiveRoomViewHolder.mAvatarUrl, mContext); - } else { - backIndex = 1; - ((LiveAudienceActivity) mContext).onBackPressed(); - } - } else { - backIndex = 1; - ((LiveAudienceActivity) mContext).onBackPressed(); - } - } else { - exitLiveRoom(); - } - mBannerList2.clear(); + manager.end(); } /** * 退出直播间 */ public void exitLiveRoom() { - RongChatRoomClient.getInstance().quitChatRoom("g" + mLiveUid, new IRongCoreCallback.OperationCallback() { - @Override - public void onSuccess() { - Log.i("tx", "退出成功"); - //连接socket - LiveHttpUtil.qBackRoom(mLiveUid, mStream, new HttpCallback() { - @Override - public void onSuccess(int code, String msg, String[] info) { - - } - }); - } - - @Override - public void onError(IRongCoreEnum.CoreErrorCode coreErrorCode) { - - } - }); - - try { - V2TIMManager.getInstance().quitGroup("g" + mLiveUid, new V2TIMCallback() { - @Override - public void onSuccess() { - - Log.i("tx", "退出成功" + mLiveUid); - //连接socket - LiveHttpUtil.qBackRoom(mLiveUid, mStream, new HttpCallback() { - @Override - public void onSuccess(int code, String msg, String[] info) { - - } - }); - } - - @Override - public void onError(int code, String desc) { - Log.i("tx", "退出失败"); - } - }); - endPlay(); - super.onBackPressed(); - } catch (Exception e) { - e.printStackTrace(); - } + manager.exitLiveRoom(); } @@ -1220,20 +600,19 @@ public class LiveAudienceActivity extends LiveActivity { * 暂停播放 */ public void pausePlay() { - if (mLivePlayViewHolder != null) { - mLivePlayViewHolder.pausePlay(); - } + manager.pausePlay(); } /** * 恢复播放 */ public void resumePlay() { - if (mLivePlayViewHolder != null) { - mLivePlayViewHolder.resumePlay(); - } + manager.resumePlay(); } + public CountDownTimer getCountDownTimer() { + return manager.getCountDownTimer(); + } /** * 充值成功 @@ -1284,9 +663,7 @@ public class LiveAudienceActivity extends LiveActivity { */ @Subscribe(threadMode = ThreadMode.MAIN) public void onLinkMicTxAccEvent(LinkMicTxAccEvent e) { - if (mLivePlayViewHolder != null && mLivePlayViewHolder instanceof LivePlayTxViewHolder) { - ((LivePlayTxViewHolder) mLivePlayViewHolder).onLinkMicTxAccEvent(e.isLinkMic()); - } + manager.onLinkMicTxAccEvent(e); } /** @@ -1295,9 +672,7 @@ public class LiveAudienceActivity extends LiveActivity { * @param linkMic true开始连麦 false断开连麦 */ public void onLinkMicTxAnchor(boolean linkMic) { - if (mLivePlayViewHolder != null && mLivePlayViewHolder instanceof LivePlayTxViewHolder) { - ((LivePlayTxViewHolder) mLivePlayViewHolder).setAnchorLinkMic(linkMic, 5000); - } + manager.onLinkMicTxAnchor(linkMic); } @@ -1338,11 +713,10 @@ public class LiveAudienceActivity extends LiveActivity { LiveHttpUtil.cancel(LiveHttpConsts.ENTER_ROOM); LiveHttpUtil.cancel(LiveHttpConsts.ROOM_CHARGE); clearRoomData(); - - setLiveRoomData(liveBean); mLiveType = e.getLiveType(); mLiveTypeVal = e.getLiveTypeVal(); - enterRoom(); + manager.onAdd(liveBean, mLiveType, mLiveTypeVal, mLiveSDK); + } } @@ -1352,64 +726,6 @@ public class LiveAudienceActivity extends LiveActivity { } - /** - * 侧滑轮播 - */ - public void onBanner(List data) { - if (data == null || data.size() == 0 || mBanner == null) { - return; - } - - if (mBanner.isStart()) { - mBanner.update(data); - } else { - mBanner.setAutoPlay(true) - .setPages(data, new SlideInBannerViewHolder()) - .setDelayTime(3000) - .setOnBannerClickListener((datas, p) -> { - if (p >= 0 && p < data.size()) { - SlideInfoModel bean = data.get(p); - if (bean != null) { - String link = bean.getSlideUrl(); - if (link.contains("http")) { - WebViewActivity.forward(mContext, link, true); - } else { - gotoLive(link); - } - } - } - }).start(); - } - - } - - /** - * 前往直播间 - */ - private void gotoLive(final String liveId) { - LiveHttpUtil.getLiveInfo(liveId, new HttpCallback() { - @Override - public void onSuccess(int code, String msg, String[] info) { - if (code == 0 && info.length > 0) { - LiveBean liveBean = JSON.parseObject(info[0], LiveBean.class); - if (mCheckLivePresenter == null) { - mCheckLivePresenter = new LiveRoomCheckLivePresenter(mContext, (liveBean1, liveType, liveTypeVal, liveSdk) -> { - if (liveBean1 == null) { - return; - } - LiveAudienceActivity.forward(mContext, liveBean1, liveType, liveTypeVal, "", 0, liveSdk); - finish(); - }); - } - mCheckLivePresenter.checkLive(liveBean); - - } else { - RouteUtil.forwardUserHome(mContext, liveId, 0); - finish(); - } - } - }); - } /** * 跳转页面或者弹窗展示 @@ -1423,7 +739,7 @@ public class LiveAudienceActivity extends LiveActivity { switch (event.getType()) { case SIDEBAR: //从右边打开侧边栏 - drawerLayout.openDrawer(GravityCompat.END); + manager.openDrawer(); break; case BOTTOM_COLLECTION: LiveTotalDialog liveTotalDialog = new LiveTotalDialog(); @@ -1441,8 +757,7 @@ public class LiveAudienceActivity extends LiveActivity { liveGiftDialogFragment.show(((LiveAudienceActivity) mContext).getSupportFragmentManager(), "LiveGiftDialogFragment"); break; case CURRENT_ACTIVITY: - - bundle.putString("url", event.getModel().activityUrl(mContext, liveBean.getUid())); + bundle.putString("url", event.getModel().activityUrl(mContext, mLiveBean.getUid())); int show = TextUtils.isEmpty(event.getModel().getShowType()) ? 0 : Integer.parseInt(event.getModel().getShowType()); bundle.putInt("show_type", show); LiveHDDialogFragment liveHDDialogFragment = new LiveHDDialogFragment(); @@ -1529,4 +844,27 @@ public class LiveAudienceActivity extends LiveActivity { } + @Override + public boolean canBackPressed() { + return super.canBackPressed(); + } + + /** + * 跳转当前页面 + */ + public static void forward(Context context, LiveBean liveBean, int liveType, int liveTypeVal, String key, int position, int liveSdk) { + Intent intent = new Intent(context, LiveAudienceActivity.class); + intent.putExtra(Constants.LIVE_BEAN, liveBean); + intent.putExtra(Constants.LIVE_TYPE, liveType); + intent.putExtra(Constants.LIVE_TYPE_VAL, liveTypeVal); + intent.putExtra(Constants.LIVE_KEY, key); + intent.putExtra(Constants.LIVE_POSITION, position); + intent.putExtra(Constants.LIVE_SDK, liveSdk); + intent.putExtra(Constants.LIVE_SDK, liveSdk); + intent.putExtra("landscape", liveBean.getLandscape()); + intent.putExtra("isry", liveBean.getIs_rong()); + context.startActivity(intent); + } + + } diff --git a/live/src/main/java/com/yunbao/live/adapter/VerticalPagerAdapter.java b/live/src/main/java/com/yunbao/live/adapter/VerticalPagerAdapter.java new file mode 100644 index 000000000..419c9041c --- /dev/null +++ b/live/src/main/java/com/yunbao/live/adapter/VerticalPagerAdapter.java @@ -0,0 +1,63 @@ +package com.yunbao.live.adapter; + +import android.app.Activity; +import android.graphics.drawable.AnimationDrawable; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.yunbao.common.bean.AnchorRecommendItemModel; +import com.yunbao.common.glide.ImgLoader; +import com.yunbao.live.R; + +import java.util.ArrayList; +import java.util.List; + +public class VerticalPagerAdapter extends androidx.viewpager.widget.PagerAdapter { + List liveBeans = new ArrayList<>(); + private Activity mContext; + private int mPosition; + + + + public VerticalPagerAdapter(List liveBeans, Activity mContext) { + this.liveBeans = liveBeans; + this.mContext = mContext; + } + + @Override + + public int getCount() { + return liveBeans.size(); + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + Log.e("LiveAudienceActivity", "VerticalPagerAdapter:" + position); + View view = LayoutInflater.from(container.getContext()).inflate(R.layout.layout_portrait_live_item, null); + // 背景 + AnchorRecommendItemModel liveItemBean = liveBeans.get(position); + ImageView ivBg = view.findViewById(R.id.iv_bg); + ImgLoader.displayBlurLive(mContext, liveItemBean.getAvatar(), ivBg); + // 加载动画 + ImageView ivLoading = view.findViewById(R.id.iv_loading); + AnimationDrawable frameAnimation = (AnimationDrawable) ivLoading.getBackground(); + frameAnimation.start(); + + view.setId(position); + container.addView(view); + return view; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView(container.findViewById(position)); + } +} diff --git a/live/src/main/java/com/yunbao/live/dialog/BlowkissDialog.java b/live/src/main/java/com/yunbao/live/dialog/BlowkissDialog.java index f14469221..a09f7d58e 100644 --- a/live/src/main/java/com/yunbao/live/dialog/BlowkissDialog.java +++ b/live/src/main/java/com/yunbao/live/dialog/BlowkissDialog.java @@ -18,11 +18,11 @@ import com.yunbao.common.http.HttpCallback; import com.yunbao.common.utils.ToastUtil; import com.yunbao.live.R; import com.yunbao.live.activity.LiveActivity; +import com.yunbao.live.activity.LiveAudienceActivity; import com.yunbao.live.http.LiveHttpUtil; import java.lang.reflect.Field; -import static com.yunbao.live.activity.LiveAudienceActivity.countDownTimer; import static com.yunbao.live.views.LiveRoomViewHolder.follow; import static com.yunbao.live.views.LiveRoomViewHolder.mLiveUid; @@ -142,7 +142,7 @@ public class BlowkissDialog extends AbsDialogFragment { ToastUtil.show(msg); } }); - countDownTimer.cancel(); + ((LiveAudienceActivity) mContext).getCountDownTimer().cancel(); dismiss(); } }); diff --git a/live/src/main/java/com/yunbao/live/dialog/LiveMoreDialogFragment.java b/live/src/main/java/com/yunbao/live/dialog/LiveMoreDialogFragment.java index f39eaeb7b..fe59af87a 100644 --- a/live/src/main/java/com/yunbao/live/dialog/LiveMoreDialogFragment.java +++ b/live/src/main/java/com/yunbao/live/dialog/LiveMoreDialogFragment.java @@ -23,7 +23,7 @@ import static com.yunbao.live.activity.LiveActivity.mLiveUid; */ public class LiveMoreDialogFragment extends AbsDialogFragment { - private LinearLayout btn_more,btn_full_screen,btn_jb; + private LinearLayout btn_more, btn_full_screen, btn_jb; private ActionListener mActionListener; @Override @@ -55,18 +55,18 @@ public class LiveMoreDialogFragment extends AbsDialogFragment { public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); btn_more = (LinearLayout) mRootView.findViewById(R.id.btn_more); - btn_full_screen = (LinearLayout)mRootView.findViewById(R.id.btn_full_screen); - btn_jb = (LinearLayout)mRootView.findViewById(R.id.btn_jb); + btn_full_screen = (LinearLayout) mRootView.findViewById(R.id.btn_full_screen); + btn_jb = (LinearLayout) mRootView.findViewById(R.id.btn_jb); btn_more.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dismiss(); - if(LivePlayRyViewHolder.landscape != 1){ + if (LivePlayRyViewHolder.landscape != 1) { - }else if (((LiveAudienceActivity) mContext).pkInfo != null&&((LiveAudienceActivity) mContext).pkInfo.getIntValue("ifpk")==0 && ((LiveAudienceActivity) mContext).anyway.equals("1") && LiveRoomViewHolder.d_pk_view.getVisibility()!=View.VISIBLE) { + } else if (((LiveAudienceActivity) mContext).pkInfo != null && ((LiveAudienceActivity) mContext).pkInfo.getIntValue("ifpk") == 0 && ((LiveAudienceActivity) mContext).anyway.equals("1") && LiveRoomViewHolder.d_pk_view.getVisibility() != View.VISIBLE) { ((LiveAudienceActivity) mContext).btnSmallScreen.setVisibility(View.VISIBLE); - ((LiveAudienceActivity) mContext).mViewPager.setCurrentItem(0); - ((LiveAudienceActivity) mContext).mLivePlayViewHolder.fullScreen(); + LiveAudienceActivity.setCurrentItem(0); + LiveAudienceActivity.getmLivePlayViewHolder().fullScreen(); } else { Toast.makeText(mContext, "当前模式不能全屏", Toast.LENGTH_SHORT).show(); } diff --git a/live/src/main/java/com/yunbao/live/dialog/NewUserDialog.java b/live/src/main/java/com/yunbao/live/dialog/NewUserDialog.java index 41f11a2e5..68eb14007 100644 --- a/live/src/main/java/com/yunbao/live/dialog/NewUserDialog.java +++ b/live/src/main/java/com/yunbao/live/dialog/NewUserDialog.java @@ -5,8 +5,6 @@ import android.view.Gravity; import android.view.View; import android.view.Window; import android.view.WindowManager; -import android.widget.ImageView; -import android.widget.RelativeLayout; import android.widget.TextView; import androidx.annotation.Nullable; @@ -24,18 +22,14 @@ import com.yunbao.common.dialog.AbsDialogFragment; import com.yunbao.common.http.CommonHttpUtil; import com.yunbao.common.http.HttpCallback; import com.yunbao.common.manager.IMLoginManager; -import com.yunbao.common.utils.ToastUtil; import com.yunbao.live.R; -import com.yunbao.live.activity.LiveActivity; +import com.yunbao.live.activity.LiveAudienceActivity; import com.yunbao.live.http.LiveHttpUtil; import org.greenrobot.eventbus.EventBus; import java.lang.reflect.Field; -import static com.yunbao.live.activity.LiveAudienceActivity.countDownTimer; -import static com.yunbao.live.views.LiveRoomViewHolder.follow; -import static com.yunbao.live.views.LiveRoomViewHolder.mLiveUid; public class NewUserDialog extends AbsDialogFragment { int gif = 0; @@ -108,7 +102,8 @@ public class NewUserDialog extends AbsDialogFragment { JSONObject obj = old_obj.getJSONObject("reward_all"); gold.setText(obj.getString("gold")); exp.setText(obj.getString("experience")); - }}); + } + }); TextView btn_confirm = (TextView) mRootView.findViewById(R.id.btn_confirm); @@ -129,7 +124,7 @@ public class NewUserDialog extends AbsDialogFragment { EventBus.getDefault().post("showBanner"); EventBus.getDefault().post("svga_new_user_gif"); IMLoginManager.get(mContext).setNewUserGif(true); - countDownTimer.cancel(); + ((LiveAudienceActivity) mContext).getCountDownTimer().cancel(); dismiss(); } }); diff --git a/live/src/main/java/com/yunbao/live/presenter/LiveLinkMicPkPresenter.java b/live/src/main/java/com/yunbao/live/presenter/LiveLinkMicPkPresenter.java index 96f3f1ff5..efec10260 100644 --- a/live/src/main/java/com/yunbao/live/presenter/LiveLinkMicPkPresenter.java +++ b/live/src/main/java/com/yunbao/live/presenter/LiveLinkMicPkPresenter.java @@ -387,7 +387,7 @@ public class LiveLinkMicPkPresenter implements View.OnClickListener { } //接受PK回调 - private void pkAccept(){ + private void pkAccept() { mTRTCCloud1 = LivePushTxViewHolder.mTRTCCloud.createSubCloud(); mTRTCParams1 = new TRTCCloudDef.TRTCParams(); mTRTCParams1.sdkAppId = GenerateTestUserSig.SDKAPPID; @@ -406,7 +406,7 @@ public class LiveLinkMicPkPresenter implements View.OnClickListener { /** * 主播与主播PK 主播收到其他主播发过来的PK申请的回调 */ - public void onLinkMicPkApply(UserBean u, String stream,int forwhat) { + public void onLinkMicPkApply(UserBean u, String stream, int forwhat) { mApplyUid = u.getId(); mApplyUrl = u.getAvatar(); if (mApplyUrl == null) { @@ -416,11 +416,11 @@ public class LiveLinkMicPkPresenter implements View.OnClickListener { if (mApplyNmae == null) { mApplyNmae = ""; } - if(forwhat == 1) { + if (forwhat == 1) { if (mIsApplyDialogShow == false) { showApplyDialog(u); } - }else{ + } else { pkAccept(); } } @@ -1002,8 +1002,8 @@ public class LiveLinkMicPkPresenter implements View.OnClickListener { mLiveLinkMicPkViewHolder = new LiveLinkMicPkViewHolder(mContext, mPkContainer); mLiveLinkMicPkViewHolder.addToParent(); mLiveLinkMicPkViewHolder.setIsAnchor(mIsAnchor); - if (LiveAudienceActivity.mLivePlayViewHolder != null) { - LiveAudienceActivity.mLivePlayViewHolder.setPkview(); + if (LiveAudienceActivity.getmLivePlayViewHolder() != null) { + LiveAudienceActivity.getmLivePlayViewHolder().setPkview(); } } @@ -1081,8 +1081,8 @@ public class LiveLinkMicPkPresenter implements View.OnClickListener { public void run() { try { Thread.sleep(4000); - if (LiveAudienceActivity.mLivePlayViewHolder != null) { - LiveAudienceActivity.mLivePlayViewHolder.setPkEndview(); + if ( LiveAudienceActivity.getmLivePlayViewHolder() != null) { + LiveAudienceActivity.getmLivePlayViewHolder().setPkEndview(); } } catch (InterruptedException e) { e.printStackTrace(); diff --git a/live/src/main/java/com/yunbao/live/presenter/LiveRyLinkMicPkPresenter.java b/live/src/main/java/com/yunbao/live/presenter/LiveRyLinkMicPkPresenter.java index bc849625b..9ab9ed94e 100644 --- a/live/src/main/java/com/yunbao/live/presenter/LiveRyLinkMicPkPresenter.java +++ b/live/src/main/java/com/yunbao/live/presenter/LiveRyLinkMicPkPresenter.java @@ -32,8 +32,8 @@ import com.yunbao.common.utils.StringUtil; import com.yunbao.common.utils.ToastUtil; import com.yunbao.common.utils.WordUtil; import com.yunbao.live.R; -import com.yunbao.live.activity.LiveRyAnchorActivity; import com.yunbao.live.activity.LiveAudienceActivity; +import com.yunbao.live.activity.LiveRyAnchorActivity; import com.yunbao.live.bean.LivePKUserListBean; import com.yunbao.live.custom.ProgressTextView; import com.yunbao.live.interfaces.ILiveLinkMicViewHolder; @@ -53,7 +53,6 @@ import cn.rongcloud.rtc.api.RCRTCRemoteUser; import cn.rongcloud.rtc.api.callback.IRCRTCOtherRoomEventsListener; import cn.rongcloud.rtc.api.callback.IRCRTCResultCallback; import cn.rongcloud.rtc.api.callback.IRCRTCResultDataCallback; -import cn.rongcloud.rtc.api.stream.RCRTCAudioInputStream; import cn.rongcloud.rtc.api.stream.RCRTCInputStream; import cn.rongcloud.rtc.api.stream.RCRTCVideoInputStream; import cn.rongcloud.rtc.api.stream.RCRTCVideoStreamConfig; @@ -74,10 +73,10 @@ import static com.yunbao.common.Constants.SOCKET_LIVE_DRPK; import static com.yunbao.live.activity.LiveRyAnchorActivity.isDRPK; import static com.yunbao.live.views.AbsRyLivePushViewHolder.mPreView; import static com.yunbao.live.views.AbsRyLivePushViewHolder.mPreView1; -import static com.yunbao.live.views.LivePushRyViewHolder.rcrtcLiveInfo; -import static com.yunbao.live.views.LivePushRyViewHolder.rtcRoom; import static com.yunbao.live.views.LivePushRyViewHolder.contexts; import static com.yunbao.live.views.LivePushRyViewHolder.dr_pk_view; +import static com.yunbao.live.views.LivePushRyViewHolder.rcrtcLiveInfo; +import static com.yunbao.live.views.LivePushRyViewHolder.rtcRoom; //import cn.rongcloud.rtc.jni.video.RCRect; @@ -170,7 +169,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { @Override public void onLeaveRoom(RCRTCOtherRoom room, int reasonCode) { - Log.d("RYM_DG","Other onLeaveRoom: room = " + room.getRoomId()); + Log.d("RYM_DG", "Other onLeaveRoom: room = " + room.getRoomId()); } }; @@ -218,7 +217,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { } public void setLiveUid(String liveUid, String url) { - Log.e("liveUid",liveUid); + Log.e("liveUid", liveUid); mLiveUid = liveUid; mUrl = url; } @@ -334,7 +333,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { String pkUid = datas.getString("pkuid"); Log.i("seed", seed_msg.mResult.toString()); - Log.e("ry1",datas.getString("win_uid")+"VVVVVV"+ datas.getString("pkuid")); + Log.e("ry1", datas.getString("win_uid") + "VVVVVV" + datas.getString("pkuid")); HttpClient.getInstance().post("Tx.sendmsgzs2", "Tx.sendmsgzs2") .params("GroupId", "g" + pkUid) @@ -499,7 +498,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { rtcRoom.getLocalUser().subscribeStreams(inputStreamList1, new IRCRTCResultCallback() { @Override public void onSuccess() { - Log.i("ry","订阅资源成功"); + Log.i("ry", "订阅资源成功"); if (rtcRoom != null) { RCRTCMixConfig config = new RCRTCMixConfig(); @@ -529,7 +528,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { rcrtcLiveInfo.setMixConfig(config, new IRCRTCResultCallback() { @Override public void onSuccess() { - Log.e("ry", "混成功"+u.getId()); + Log.e("ry", "混成功" + u.getId()); } @Override @@ -543,7 +542,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { @Override public void onFailed(RTCErrorCode rtcErrorCode) { - Log.i("ry","订阅资源失败: " + rtcErrorCode.getReason()); + Log.i("ry", "订阅资源失败: " + rtcErrorCode.getReason()); } }); } @@ -552,7 +551,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { @Override public void onFailed(RTCErrorCode rtcErrorCode) { - Log.i("ry","加入其他房间失败 :" + rtcErrorCode.getReason()); + Log.i("ry", "加入其他房间失败 :" + rtcErrorCode.getReason()); } }); @@ -561,16 +560,16 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { /** * 主播与主播PK 主播收到其他主播发过来的PK申请的回调 */ - public void onLinkMicPkApply(UserBean u, String stream,int by) { - Log.e("ry", u.getUserNiceName()+"单人收到"+u.getAvatar()); + public void onLinkMicPkApply(UserBean u, String stream, int by) { + Log.e("ry", u.getUserNiceName() + "单人收到" + u.getAvatar()); mApplyUid = u.getId(); mApplyUrl = u.getAvatar(); mApplyNmae = u.getUserNiceName(); - if(by != 1) { + if (by != 1) { if (mIsApplyDialogShow == false) { showApplyDialog(u); } - }else{ + } else { isPK(); } } @@ -600,7 +599,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { for (int i = 0; i < rcrtcOtherRoom.getRemoteUsers().size(); i++) { //遍历远端用户发布的资源列表 for (RCRTCInputStream stream : rcrtcOtherRoom.getRemoteUsers().get(i).getStreams()) { - Log.e("ry",stream.getMediaType()+"类型"); + Log.e("ry", stream.getMediaType() + "类型"); if (stream.getMediaType() == RCRTCMediaType.VIDEO) { //如果远端用户发布的是视频流,创建显示视图RCRTCVideoView,并添加到布局中显示 RCRTCVideoView remoteView = new RCRTCVideoView(contexts); @@ -659,12 +658,12 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { rtcRoom.getLocalUser().subscribeStreams(inputStreamList, new IRCRTCResultCallback() { @Override public void onSuccess() { - Log.i("ry","订阅资源成功"); + Log.i("ry", "订阅资源成功"); } @Override public void onFailed(RTCErrorCode rtcErrorCode) { - Log.i("ry","订阅资源失败: " + rtcErrorCode.getReason()); + Log.i("ry", "订阅资源失败: " + rtcErrorCode.getReason()); } }); } @@ -673,7 +672,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { @Override public void onFailed(RTCErrorCode rtcErrorCode) { - Log.i("ry","11111加入其他房间失败 :" + rtcErrorCode.getReason()); + Log.i("ry", "11111加入其他房间失败 :" + rtcErrorCode.getReason()); } }); LivePushRyViewHolder.btn_close.setVisibility(View.VISIBLE); @@ -721,7 +720,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { } - private void isPK(){ + private void isPK() { ScreenDimenUtil util = ScreenDimenUtil.getInstance(); int mScreenWdith = util.getScreenWdith(); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, mScreenWdith * 720 / 960); @@ -738,7 +737,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { msg1.put("pkhead", CommonAppConfig.getInstance().getUserBean().getAvatarThumb()); msg1.put("pkname", CommonAppConfig.getInstance().getUserBean().getUserNiceName()); - rtcRoom.getLocalUser().responseJoinOtherRoom(mApplyUid, mApplyUid, true, true,msg1.toString(), new IRCRTCResultCallback() { + rtcRoom.getLocalUser().responseJoinOtherRoom(mApplyUid, mApplyUid, true, true, msg1.toString(), new IRCRTCResultCallback() { @Override public void onSuccess() { RCRTCEngine.getInstance().joinOtherRoom(mApplyUid, new IRCRTCResultDataCallback() { @@ -770,7 +769,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { rtcRoom.getLocalUser().subscribeStreams(inputStreamList, new IRCRTCResultCallback() { @Override public void onSuccess() { - Log.i("ry","订阅资源成功"); + Log.i("ry", "订阅资源成功"); List streams = new ArrayList<>(); streams.add(RCRTCEngine.getInstance().getDefaultVideoStream()); if (rtcRoom != null) { @@ -815,7 +814,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { @Override public void onFailed(RTCErrorCode rtcErrorCode) { - Log.i("ry","订阅资源失败: " + rtcErrorCode); + Log.i("ry", "订阅资源失败: " + rtcErrorCode); } }); } @@ -825,7 +824,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { @Override public void onFailed(RTCErrorCode rtcErrorCode) { Log.e("ry", mApplyUid + "加入其他房间失败 :" + rtcErrorCode); - Log.i("ry",mApplyUid + "加入其他房间失败 :" + rtcErrorCode); + Log.i("ry", mApplyUid + "加入其他房间失败 :" + rtcErrorCode); } }); @@ -834,7 +833,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { LiveRyAnchorActivity.isDRPK = 1; LivePushRyViewHolder.btn_close.setVisibility(View.VISIBLE); SocketRyLinkMicPkUtil.linkMicPkAccept(mSocketRyClient, mApplyUid, mApplyUrl, mApplyNmae); - onLinkMicPkStart(mApplyUid,2); + onLinkMicPkStart(mApplyUid, 2); } }); } @@ -848,14 +847,14 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { } //与用户连麦 - public void setUserMic(String liveid){ + public void setUserMic(String liveid) { JSONObject msg1 = new JSONObject(); msg1.put("uid", CommonAppConfig.getInstance().getUid()); msg1.put("pkuid", CommonAppConfig.getInstance().getUid()); msg1.put("pkhead", CommonAppConfig.getInstance().getUserBean().getAvatarThumb()); msg1.put("pkname", CommonAppConfig.getInstance().getUserBean().getUserNiceName()); - rtcRoom.getLocalUser().responseJoinOtherRoom(liveid, liveid, true, true,msg1.toString(), new IRCRTCResultCallback() { + rtcRoom.getLocalUser().responseJoinOtherRoom(liveid, liveid, true, true, msg1.toString(), new IRCRTCResultCallback() { @Override public void onSuccess() { RCRTCEngine.getInstance().joinOtherRoom(liveid, new IRCRTCResultDataCallback() { @@ -865,11 +864,11 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { ToastUtil.show("接受成功"); new Handler(Looper.getMainLooper()).post(new Runnable() { public void run() { - Log.e("ry",liveid+"来了!!!!"+ rcrtcOtherRoom.getRemoteUsers().size()); + Log.e("ry", liveid + "来了!!!!" + rcrtcOtherRoom.getRemoteUsers().size()); for (int i = 0; i < rcrtcOtherRoom.getRemoteUsers().size(); i++) { //遍历远端用户发布的资源列表 for (RCRTCInputStream stream : rcrtcOtherRoom.getRemoteUsers().get(i).getStreams()) { - Log.e("ry",stream.getMediaType()+"rcrtcOtherRoom成功 :"+rcrtcOtherRoom.getRemoteUsers().size()); + Log.e("ry", stream.getMediaType() + "rcrtcOtherRoom成功 :" + rcrtcOtherRoom.getRemoteUsers().size()); if (stream.getMediaType() == RCRTCMediaType.AUDIO) { //音频只需要订阅 inputStreamList.add(stream); @@ -888,7 +887,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { @Override public void onFailed(RTCErrorCode rtcErrorCode) { - Log.e("ry","订阅资源失败: " + rtcErrorCode); + Log.e("ry", "订阅资源失败: " + rtcErrorCode); } }); } @@ -898,7 +897,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { @Override public void onFailed(RTCErrorCode rtcErrorCode) { Log.e("ry", liveid + "加入其他房间失败 :" + rtcErrorCode); - Log.i("ry",liveid + "加入其他房间失败 :" + rtcErrorCode); + Log.i("ry", liveid + "加入其他房间失败 :" + rtcErrorCode); } }); @@ -1051,7 +1050,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { * 退出多人PK */ public static void leaveDRRoom() { - Log.e("ry", "退出多人OKKK"+inputStreamList.size()); + Log.e("ry", "退出多人OKKK" + inputStreamList.size()); isDRPK = 0; for (int i = 0; i < inputStreamList.size(); i++) { //退出副房间 @@ -1212,7 +1211,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { //添加水印 // RCRTCRect rect = new RCRTCRect(0.5f, 0.5f, 0.2f); // RCRTCEngine.getInstance().getDefaultVideoStream().setWatermark(fromText(50, mNameText), rect); - dRjoinOtherRoom(u.getId(),1); + dRjoinOtherRoom(u.getId(), 1); for (int i = 0; i < users.size(); i++) { JSONObject user = users.getJSONObject(i); @@ -1357,8 +1356,8 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { //多人PK接受申请画 加入副房间 - public void dRjoinOtherRoom(String uid,int i) { - Log.e("ry",uid+"洒洒"+i+"VVVV"+i); + public void dRjoinOtherRoom(String uid, int i) { + Log.e("ry", uid + "洒洒" + i + "VVVV" + i); mApplyUid = uid; RCRTCEngine.getInstance().joinOtherRoom(mApplyUid, new IRCRTCResultDataCallback() { @Override @@ -1378,14 +1377,14 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { dr_pk_view.setVisibility(View.VISIBLE); } - Log.e("ry","多人接受成功"+mApplyUid); + Log.e("ry", "多人接受成功" + mApplyUid); ToastUtil.show("接受成功"); //遍历远端用户列表 for (int i = 0; i < rcrtcOtherRoom.getRemoteUsers().size(); i++) { - Log.e("ry", rcrtcOtherRoom.getRemoteUsers().get(i).getUserId()+"收到rcrtcOtherRoom"+rcrtcOtherRoom.getRemoteUsers().size()); + Log.e("ry", rcrtcOtherRoom.getRemoteUsers().get(i).getUserId() + "收到rcrtcOtherRoom" + rcrtcOtherRoom.getRemoteUsers().size()); //遍历远端用户发布的资源列表 for (RCRTCInputStream stream : rcrtcOtherRoom.getRemoteUsers().get(i).getStreams()) { - Log.e("ry", i+"收到" + stream.getMediaType() + "实打实打算"+rcrtcOtherRoom.getRemoteUsers().get(i).getUserId()); + Log.e("ry", i + "收到" + stream.getMediaType() + "实打实打算" + rcrtcOtherRoom.getRemoteUsers().get(i).getUserId()); if (stream.getMediaType() == RCRTCMediaType.VIDEO) { if (inputStreamList.size() == 0) { //如果远端用户发布的是视频流,创建显示视图RCRTCVideoView,并添加到布局中显示 @@ -1429,12 +1428,12 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { rtcRoom.getLocalUser().subscribeStreams(inputStreamList1, new IRCRTCResultCallback() { @Override public void onSuccess() { - Log.i("ry","订阅资源成功"); + Log.i("ry", "订阅资源成功"); } @Override public void onFailed(RTCErrorCode rtcErrorCode) { - Log.i("ry","订阅资源失败: " + rtcErrorCode.getReason()); + Log.i("ry", "订阅资源失败: " + rtcErrorCode.getReason()); } }); //2. 合流画布设置 @@ -1458,7 +1457,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { @Override public void onFailed(RTCErrorCode rtcErrorCode) { Log.e("ry", mApplyUid + "加入其他房间失败 :" + rtcErrorCode); - Log.i("ry",mApplyUid + "加入其他房间失败 :" + rtcErrorCode); + Log.i("ry", mApplyUid + "加入其他房间失败 :" + rtcErrorCode); } }); } @@ -1488,7 +1487,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { for (int i = 0; i < rcrtcOtherRoom.getRemoteUsers().size(); i++) { //遍历远端用户发布的资源列表 for (RCRTCInputStream stream : rcrtcOtherRoom.getRemoteUsers().get(i).getStreams()) { - Log.e("ry111",stream.getMediaType()+""); + Log.e("ry111", stream.getMediaType() + ""); if (stream.getMediaType() == RCRTCMediaType.VIDEO) { if (inputStreamList.size() == 0) { //如果远端用户发布的是视频流,创建显示视图RCRTCVideoView,并添加到布局中显示 @@ -1536,12 +1535,12 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { rtcRoom.getLocalUser().subscribeStreams(inputStreamList1, new IRCRTCResultCallback() { @Override public void onSuccess() { - Log.i("ry","订阅资源成功"); + Log.i("ry", "订阅资源成功"); } @Override public void onFailed(RTCErrorCode rtcErrorCode) { - Log.i("ry","订阅资源失败: " + rtcErrorCode.getReason()); + Log.i("ry", "订阅资源失败: " + rtcErrorCode.getReason()); } }); @@ -1549,7 +1548,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { rcrtcLiveInfo.setMixConfig(create_Custom_MixConfig(false, inputStreamList), new IRCRTCResultCallback() { @Override public void onSuccess() { - Log.e("ry", inputStreamList.size()+"混成功"+u); + Log.e("ry", inputStreamList.size() + "混成功" + u); } @Override @@ -1567,7 +1566,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { @Override public void onFailed(RTCErrorCode rtcErrorCode) { - Log.i("ry","加入其他房间失败 :" + rtcErrorCode.getReason()); + Log.i("ry", "加入其他房间失败 :" + rtcErrorCode.getReason()); } }); @@ -1775,8 +1774,8 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { /** * 主播与主播PK 所有人收到PK开始的回调 */ - public void onLinkMicPkStart(String pkUid,int i) { - Log.d("tag", i+"mPkTimeCount2"); + public void onLinkMicPkStart(String pkUid, int i) { + Log.d("tag", i + "mPkTimeCount2"); mIsPk = true; hideSendPkWait(); mIsPkEnd = false; @@ -1788,8 +1787,8 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { mLiveLinkMicPkViewHolder = new LiveLinkMicPkViewHolder(mContext, mPkContainer); mLiveLinkMicPkViewHolder.addToParent(); mLiveLinkMicPkViewHolder.setIsAnchor(mIsAnchor); - if (LiveAudienceActivity.mLivePlayViewHolder != null) { - LiveAudienceActivity.mLivePlayViewHolder.setPkview(); + if (LiveAudienceActivity.getmLivePlayViewHolder() != null) { + LiveAudienceActivity.getmLivePlayViewHolder().setPkview(); } } @@ -1840,7 +1839,7 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { }, 3000); } } else { - Log.e("ry1",winUid+"result"); + Log.e("ry1", winUid + "result"); if (winUid.equals(mLiveUid)) { mLiveLinkMicPkViewHolder.end(1); } else { @@ -1903,9 +1902,9 @@ public class LiveRyLinkMicPkPresenter implements View.OnClickListener { public void run() { // try { // Thread.sleep(4000); - if (LiveAudienceActivity.mLivePlayViewHolder != null) { - LiveAudienceActivity.mLivePlayViewHolder.setPkEndview(); - } + if ( LiveAudienceActivity.getmLivePlayViewHolder() != null) { + LiveAudienceActivity.getmLivePlayViewHolder().setPkEndview(); + } // } catch (InterruptedException e) { // e.printStackTrace(); // } diff --git a/live/src/main/java/com/yunbao/live/socket/SocketClient.java b/live/src/main/java/com/yunbao/live/socket/SocketClient.java index a5b49714b..e0c13751c 100644 --- a/live/src/main/java/com/yunbao/live/socket/SocketClient.java +++ b/live/src/main/java/com/yunbao/live/socket/SocketClient.java @@ -171,7 +171,7 @@ public class SocketClient { LiveRoomViewHolder.d_pk_view.setVisibility(View.GONE); //創建了多人房間 } else if (action3 == 9) { - LiveAudienceActivity.mLivePlayViewHolder.setPkview(); + LiveAudienceActivity.getmLivePlayViewHolder().setPkview(); } break; case Constants.SOCKET_ALL_SERVER_NOTIFY://全服通知 diff --git a/live/src/main/java/com/yunbao/live/socket/SocketRyClient.java b/live/src/main/java/com/yunbao/live/socket/SocketRyClient.java index 7a1cb9514..a8128dc89 100644 --- a/live/src/main/java/com/yunbao/live/socket/SocketRyClient.java +++ b/live/src/main/java/com/yunbao/live/socket/SocketRyClient.java @@ -242,7 +242,7 @@ public class SocketRyClient { } LiveRoomViewHolder.UpPkBar(map.getJSONArray("userlist"), mLiveUid, map.getIntValue("drpk_time")); if (LiveRyAnchorActivity.mLivePushViewHolder == null) { - LiveAudienceActivity.mLivePlayViewHolder.setPkview(); + LiveAudienceActivity.getmLivePlayViewHolder().setPkview(); } } else if (action3 == 5) { @@ -256,17 +256,17 @@ public class SocketRyClient { leaveDRRoom(); isDRPK = 0; } else { - LiveAudienceActivity.mLivePlayViewHolder.setPkEndview(); + LiveAudienceActivity.getmLivePlayViewHolder().setPkEndview(); } //創建了多人房間 } else if (action3 == 3) { - if (LiveAudienceActivity.mLivePlayViewHolder != null) { - LiveAudienceActivity.mLivePlayViewHolder.setPkview(); + if ( LiveAudienceActivity.getmLivePlayViewHolder() != null) { + LiveAudienceActivity.getmLivePlayViewHolder().setPkview(); } isDRPK = 1; } else if (action3 == 10) { if (!map.getString("uid").equals(CommonAppConfig.getInstance().getUid())) { - LiveAudienceActivity.mLivePlayViewHolder.setPkview(); + LiveAudienceActivity.getmLivePlayViewHolder().setPkview(); } } diff --git a/live/src/main/java/com/yunbao/live/views/LiveActivityLifeCallback.java b/live/src/main/java/com/yunbao/live/views/LiveActivityLifeCallback.java new file mode 100644 index 000000000..e7a9faf16 --- /dev/null +++ b/live/src/main/java/com/yunbao/live/views/LiveActivityLifeCallback.java @@ -0,0 +1,63 @@ +package com.yunbao.live.views; + +import android.content.Intent; +import android.content.res.Configuration; + +/** + * 该类的方法对应 Activity 的方法 + */ +public interface LiveActivityLifeCallback { + + /** + * Activity 的 onStart + */ + void onStart(); + + + /** + * Activity 的 onResume + */ + void onResume(); + + /** + * Activity 的 onPause + */ + void onPause(); + + /** + * Activity 的 onStop + */ + void onStop(); + + /** + * Activity 的 onDestroy + */ + void onDestroy(); + + /** + * Activity 的 onRestart + */ + void onRestart(); + + + /** + * Activity 的 onConfigurationChanged + */ + void onConfigurationChanged(Configuration newConfig); + + /** + * Activity 的 onActivityResult + */ + void onActivityResult(int requestCode, int resultCode, Intent data); + + /** + * Activity 的 onNewIntent + */ + void onNewIntent(Intent intent); + + /** + * Activity 的 onBackPressed + */ + void onBackPressed(); + +} diff --git a/live/src/main/java/com/yunbao/live/views/LiveAddImpressViewHolder.java b/live/src/main/java/com/yunbao/live/views/LiveAddImpressViewHolder.java index a0e56b49c..c890a3c5b 100644 --- a/live/src/main/java/com/yunbao/live/views/LiveAddImpressViewHolder.java +++ b/live/src/main/java/com/yunbao/live/views/LiveAddImpressViewHolder.java @@ -116,9 +116,7 @@ public class LiveAddImpressViewHolder extends AbsLivePageViewHolder { mLinkedList.clear(); mGroup.removeAllViews(); removeFromParent(); - if (CommonAppConfig.LIVE_ROOM_SCROLL && mContext != null && mContext instanceof LiveAudienceActivity) { - ((LiveAudienceActivity) mContext).setScrollFrozen(false); - } + } private void initData() { @@ -151,9 +149,7 @@ public class LiveAddImpressViewHolder extends AbsLivePageViewHolder { line++; mGroup.addView(linearLayout); } - if (CommonAppConfig.LIVE_ROOM_SCROLL && mContext != null && mContext instanceof LiveAudienceActivity) { - ((LiveAudienceActivity) mContext).setScrollFrozen(true); - } + } } }); diff --git a/live/src/main/java/com/yunbao/live/views/LiveContributeViewHolder.java b/live/src/main/java/com/yunbao/live/views/LiveContributeViewHolder.java index 98a704cc3..f79ddf200 100644 --- a/live/src/main/java/com/yunbao/live/views/LiveContributeViewHolder.java +++ b/live/src/main/java/com/yunbao/live/views/LiveContributeViewHolder.java @@ -109,8 +109,6 @@ public class LiveContributeViewHolder extends AbsLivePageViewHolder implements V @Override public void onHide() { - if (CommonAppConfig.LIVE_ROOM_SCROLL && mContext != null && mContext instanceof LiveAudienceActivity) { - ((LiveAudienceActivity) mContext).setScrollFrozen(false); - } + } } diff --git a/live/src/main/java/com/yunbao/live/views/LiveMedalRankViewHolder.java b/live/src/main/java/com/yunbao/live/views/LiveMedalRankViewHolder.java index 69ea046e1..1d8c2c1e1 100644 --- a/live/src/main/java/com/yunbao/live/views/LiveMedalRankViewHolder.java +++ b/live/src/main/java/com/yunbao/live/views/LiveMedalRankViewHolder.java @@ -108,8 +108,6 @@ public class LiveMedalRankViewHolder extends AbsLivePageViewHolder implements Vi @Override public void onHide() { - if (CommonAppConfig.LIVE_ROOM_SCROLL && mContext != null && mContext instanceof LiveAudienceActivity) { - ((LiveAudienceActivity) mContext).setScrollFrozen(false); - } + } } diff --git a/live/src/main/java/com/yunbao/live/views/LivePlayListener.java b/live/src/main/java/com/yunbao/live/views/LivePlayListener.java new file mode 100644 index 000000000..9f0668b68 --- /dev/null +++ b/live/src/main/java/com/yunbao/live/views/LivePlayListener.java @@ -0,0 +1,27 @@ +package com.yunbao.live.views; + +import android.view.ViewGroup; + +import com.yunbao.live.bean.LiveBean; + + +public interface LivePlayListener extends LiveActivityLifeCallback { + + /** + * 用户滑动显示该页面 + * + * @param data 房间信息 + */ + void onAdd(LiveBean data, int liveType, int liveTypeVal, int liveSdk); + + /** + * 用户滑动移除该页面 + */ + void onRemove(); + + /** + * @return 页面的根布局 View + */ + ViewGroup getRootView(); + +} diff --git a/live/src/main/java/com/yunbao/live/views/LivePlayRyViewHolder.java b/live/src/main/java/com/yunbao/live/views/LivePlayRyViewHolder.java index a5f11df1b..0ca597137 100644 --- a/live/src/main/java/com/yunbao/live/views/LivePlayRyViewHolder.java +++ b/live/src/main/java/com/yunbao/live/views/LivePlayRyViewHolder.java @@ -1,6 +1,5 @@ package com.yunbao.live.views; -import android.Manifest; import android.app.Dialog; import android.content.Context; import android.media.AudioManager; @@ -14,17 +13,12 @@ import android.view.ViewGroup; import android.view.ViewParent; import android.widget.FrameLayout; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.RelativeLayout; -import com.alibaba.fastjson.JSONArray; -import com.alibaba.fastjson.JSONObject; import com.tencent.live2.V2TXLiveDef; import com.tencent.live2.V2TXLivePlayer; import com.tencent.live2.impl.V2TXLivePlayerImpl; import com.tencent.rtmp.ui.TXCloudVideoView; -import com.yunbao.common.CommonAppConfig; -import com.yunbao.common.bean.UserBean; import com.yunbao.common.glide.ImgLoader; import com.yunbao.common.http.HttpCallback; import com.yunbao.common.http.HttpClient; @@ -36,8 +30,6 @@ import com.yunbao.common.utils.ToastUtil; import com.yunbao.common.utils.WordUtil; import com.yunbao.live.R; import com.yunbao.live.activity.LiveActivity; -import com.yunbao.live.activity.LiveAudienceActivity; -import com.yunbao.live.presenter.LiveRyLinkMicPkPresenter; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -47,8 +39,6 @@ import java.util.ArrayList; import java.util.List; import cn.rongcloud.rtc.api.RCRTCEngine; -import cn.rongcloud.rtc.api.RCRTCMixConfig; -import cn.rongcloud.rtc.api.RCRTCOtherRoom; import cn.rongcloud.rtc.api.RCRTCRemoteUser; import cn.rongcloud.rtc.api.RCRTCRoom; import cn.rongcloud.rtc.api.RCRTCRoomConfig; @@ -57,7 +47,6 @@ import cn.rongcloud.rtc.api.callback.IRCRTCResultDataCallback; import cn.rongcloud.rtc.api.callback.IRCRTCRoomEventsListener; import cn.rongcloud.rtc.api.callback.IRCRTCSwitchRoleCallback; import cn.rongcloud.rtc.api.callback.IRCRTCSwitchRoleDataCallback; -import cn.rongcloud.rtc.api.stream.RCRTCCDNInputStream; import cn.rongcloud.rtc.api.stream.RCRTCInputStream; import cn.rongcloud.rtc.api.stream.RCRTCLiveInfo; import cn.rongcloud.rtc.api.stream.RCRTCOutputStream; @@ -69,20 +58,9 @@ import cn.rongcloud.rtc.base.RCRTCMediaType; import cn.rongcloud.rtc.base.RCRTCParamsType; import cn.rongcloud.rtc.base.RCRTCRoomType; import cn.rongcloud.rtc.base.RTCErrorCode; -import cn.rongcloud.rtc.core.RendererCommon; -import cn.rongcloud.rtc.plugin.player.IPlayerPrepareListener; import static cn.rongcloud.rtc.core.RendererCommon.ScalingType.SCALE_ASPECT_FILL; import static com.lzy.okgo.utils.HttpUtils.runOnUiThread; -import static com.yunbao.common.Constants.SOCKET_LIVE_DRPK; -import static com.yunbao.live.activity.LiveActivity.mLiveRyLinkMicPkPresenter; -import static com.yunbao.live.activity.LiveRyAnchorActivity.mLivePushViewHolder; -import static com.yunbao.live.presenter.LiveRyLinkMicPkPresenter.leaveDRRoom; -import static com.yunbao.live.views.AbsRyLivePushViewHolder.mPreView; -import static com.yunbao.live.views.LivePushRyViewHolder.contexts; -import static com.yunbao.live.views.LivePushRyViewHolder.dr_pk_view; -import static com.yunbao.live.views.LivePushRyViewHolder.rcrtcLiveInfo; -import static com.yunbao.live.views.LivePushRyViewHolder.rtcRoom; public class LivePlayRyViewHolder extends LiveRoomPlayViewHolder { @@ -118,6 +96,7 @@ public class LivePlayRyViewHolder extends LiveRoomPlayViewHolder { public static int Micing = 0; RCRTCRoom rcrtcRoom; String purl; + public LivePlayRyViewHolder(Context context, ViewGroup parentView, int landscapes) { super(context, parentView); contexts = context; @@ -223,7 +202,9 @@ public class LivePlayRyViewHolder extends LiveRoomPlayViewHolder { public void release() { mEnd = true; mStarted = false; - mPlayer.stopPlay(); + if (mPlayer != null) { + mPlayer.stopPlay(); + } L.e(TAG, "release------->"); } @@ -440,7 +421,7 @@ public class LivePlayRyViewHolder extends LiveRoomPlayViewHolder { UsertoRY(); } }); - }else if("inviteMic".equals(str)){ + } else if ("inviteMic".equals(str)) { DialogUitl.showSimpleDialog(mContext, "主播邀請您進行語音連麥", new DialogUitl.SimpleCallback() { @Override public void onConfirmClick(Dialog dialog, String content) { @@ -448,8 +429,8 @@ public class LivePlayRyViewHolder extends LiveRoomPlayViewHolder { } }); - }else if("endMic".equals(str)){ - if(rcrtcRoom!=null){ + } else if ("endMic".equals(str)) { + if (rcrtcRoom != null) { // 开始切换为观众身份 RCRTCEngine.getInstance().getRoom().getLocalUser().switchToAudience(new IRCRTCSwitchRoleCallback() { @@ -464,18 +445,18 @@ public class LivePlayRyViewHolder extends LiveRoomPlayViewHolder { @Override public void onSuccess() { - Log.e("ry", "下麦成功"); + Log.e("ry", "下麦成功"); // 该用户切换为观众成功,可以以观众身份进行音视频 //退出rtc播放 RCRTCEngine.getInstance().leaveRoom(new IRCRTCResultCallback() { @Override public void onSuccess() { - Log.e("ry", "退出多人房间成功"); + Log.e("ry", "退出多人房间成功"); new Handler(Looper.getMainLooper()).post(new Runnable() { public void run() { mPlayer.startPlay(purl); - Log.e("ry",mPlayer.isPlaying()+"purl"+purl); - if(mPlayer.isPlaying()!=1){ + Log.e("ry", mPlayer.isPlaying() + "purl" + purl); + if (mPlayer.isPlaying() != 1) { mPlayer.startPlay(purl); } ry_view.removeAllViews(); @@ -483,7 +464,8 @@ public class LivePlayRyViewHolder extends LiveRoomPlayViewHolder { rcrtcRoom = null; Micing = 0; ToastUtil.show("已成功退出語音連麥"); - }}); + } + }); } @Override @@ -501,7 +483,7 @@ public class LivePlayRyViewHolder extends LiveRoomPlayViewHolder { */ @Override public void onFailed(RTCErrorCode errorCode) { - Log.e("ry", "下麦失败"+errorCode); + Log.e("ry", "下麦失败" + errorCode); } }); @@ -564,7 +546,7 @@ public class LivePlayRyViewHolder extends LiveRoomPlayViewHolder { // new Handler().postDelayed(new Runnable() { // @Override // public void run() { - toMic(); + toMic(); // } // }, 3000); diff --git a/live/src/main/java/com/yunbao/live/views/LiveRoomViewHolder.java b/live/src/main/java/com/yunbao/live/views/LiveRoomViewHolder.java index 94986da77..d285f4f9d 100644 --- a/live/src/main/java/com/yunbao/live/views/LiveRoomViewHolder.java +++ b/live/src/main/java/com/yunbao/live/views/LiveRoomViewHolder.java @@ -104,7 +104,6 @@ import pl.droidsonroids.gif.GifImageView; import static com.yunbao.common.CommonAppContext.logger; import static com.yunbao.common.CommonAppContext.mFirebaseAnalytics; -import static com.yunbao.live.activity.LiveAudienceActivity.countDownTimer; /** * Created by cxf on 2018/10/9. @@ -1200,8 +1199,8 @@ public class LiveRoomViewHolder extends AbsViewHolder implements View.OnClickLis } else if (i == R.id.btn_follow) { follow(); - if (countDownTimer != null) { - countDownTimer.cancel(); + if (((LiveAudienceActivity) mContext).getCountDownTimer() != null) { + ((LiveAudienceActivity) mContext).getCountDownTimer().cancel(); } } else if (i == R.id.view_medal) { //点击粉丝勋章, 弹窗 开通粉丝勋章 @@ -1255,8 +1254,8 @@ public class LiveRoomViewHolder extends AbsViewHolder implements View.OnClickLis if (TextUtils.isEmpty(mLiveUid)) { return; } - if (countDownTimer != null) { - countDownTimer.cancel(); + if (((LiveAudienceActivity) Contexts).getCountDownTimer() != null) { + ((LiveAudienceActivity) Contexts).getCountDownTimer().cancel(); } CommonHttpUtil.setAttention(mLiveUid, new CommonCallback() { @Override @@ -1292,7 +1291,7 @@ public class LiveRoomViewHolder extends AbsViewHolder implements View.OnClickLis dialog.findViewById(R.id.btn_confirm).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - LiveAudienceActivity.backIndex = 1; + ((LiveAudienceActivity) context).setBackIndex(1); ((LiveAudienceActivity) context).onBackPressed(); follow(); } @@ -1300,7 +1299,7 @@ public class LiveRoomViewHolder extends AbsViewHolder implements View.OnClickLis dialog.findViewById(R.id.btn_cancel).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - LiveAudienceActivity.backIndex = 1; + ((LiveAudienceActivity) context).setBackIndex(1); ((LiveAudienceActivity) context).onBackPressed(); } }); @@ -1318,15 +1317,15 @@ public class LiveRoomViewHolder extends AbsViewHolder implements View.OnClickLis if (isStayRoomfive) { showFollowDialog(mNameText, mAvatarUrl, mContext); } else { - LiveAudienceActivity.backIndex = 1; + ((LiveAudienceActivity) mContext).setBackIndex(1); ((LiveAudienceActivity) mContext).onBackPressed(); } } else { - LiveAudienceActivity.backIndex = 1; + ((LiveAudienceActivity) mContext).setBackIndex(1); ((LiveAudienceActivity) mContext).onBackPressed(); } } else { - LiveAudienceActivity.backIndex = 1; + ((LiveAudienceActivity) mContext).setBackIndex(1); ((LiveAnchorActivity) mContext).onBackPressed(); } } else { diff --git a/live/src/main/java/com/yunbao/live/views/LiveWebViewHolder.java b/live/src/main/java/com/yunbao/live/views/LiveWebViewHolder.java index d69053c6c..e72902886 100644 --- a/live/src/main/java/com/yunbao/live/views/LiveWebViewHolder.java +++ b/live/src/main/java/com/yunbao/live/views/LiveWebViewHolder.java @@ -112,8 +112,6 @@ public class LiveWebViewHolder extends AbsLivePageViewHolder implements View.OnC @Override public void onHide() { - if (CommonAppConfig.LIVE_ROOM_SCROLL && mContext != null && mContext instanceof LiveAudienceActivity) { - ((LiveAudienceActivity) mContext).setScrollFrozen(false); - } + } } diff --git a/live/src/main/java/com/yunbao/live/views/PortraitLiveManager.java b/live/src/main/java/com/yunbao/live/views/PortraitLiveManager.java new file mode 100644 index 000000000..922cb9649 --- /dev/null +++ b/live/src/main/java/com/yunbao/live/views/PortraitLiveManager.java @@ -0,0 +1,1286 @@ +package com.yunbao.live.views; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.Outline; +import android.os.CountDownTimer; +import android.text.TextUtils; +import android.util.Log; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewOutlineProvider; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import androidx.annotation.NonNull; +import androidx.core.view.GravityCompat; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.viewpager.widget.PagerAdapter; + +import com.adjust.sdk.Adjust; +import com.adjust.sdk.AdjustEvent; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.blankj.utilcode.util.GsonUtils; +import com.ms.banner.Banner; +import com.tencent.imsdk.v2.V2TIMCallback; +import com.tencent.imsdk.v2.V2TIMManager; +import com.yunbao.common.CommonAppConfig; +import com.yunbao.common.CommonAppContext; +import com.yunbao.common.Constants; +import com.yunbao.common.activity.WebViewActivity; +import com.yunbao.common.bean.AnchorRecommendModel; +import com.yunbao.common.bean.SlideInfoModel; +import com.yunbao.common.bean.UserBean; +import com.yunbao.common.custom.CommonRefreshView; +import com.yunbao.common.custom.ItemDecoration; +import com.yunbao.common.custom.MyViewPager; +import com.yunbao.common.glide.ImgLoader; +import com.yunbao.common.http.CommonHttpUtil; +import com.yunbao.common.http.HttpCallback; +import com.yunbao.common.http.main.MainNetManager; +import com.yunbao.common.manager.IMLoginManager; +import com.yunbao.common.utils.DeviceUtils; +import com.yunbao.common.utils.RouteUtil; +import com.yunbao.common.views.SlideInBannerViewHolder; +import com.yunbao.live.R; +import com.yunbao.live.activity.LiveActivity; +import com.yunbao.live.activity.LiveAudienceActivity; +import com.yunbao.live.adapter.SidebarAdapter; +import com.yunbao.live.bean.LiveBean; +import com.yunbao.live.bean.LiveBuyGuardMsgBean; +import com.yunbao.live.bean.LiveChatBean; +import com.yunbao.live.bean.LiveDanMuBean; +import com.yunbao.live.bean.LiveEnterRoomBean; +import com.yunbao.live.bean.LiveGiftPrizePoolWinBean; +import com.yunbao.live.bean.LiveGuardInfo; +import com.yunbao.live.bean.LiveLuckGiftWinBean; +import com.yunbao.live.bean.LivePKUserListBean; +import com.yunbao.live.bean.LiveReceiveGiftBean; +import com.yunbao.live.bean.LiveUserGiftBean; +import com.yunbao.live.bean.WishlistModel; +import com.yunbao.live.dialog.BlowkissDialog; +import com.yunbao.live.dialog.NewUserDialog; +import com.yunbao.live.event.LinkMicTxAccEvent; +import com.yunbao.live.http.LiveHttpUtil; +import com.yunbao.live.presenter.LiveLinkMicAnchorPresenter; +import com.yunbao.live.presenter.LiveLinkMicPkPresenter; +import com.yunbao.live.presenter.LiveLinkMicPresenter; +import com.yunbao.live.presenter.LiveRoomCheckLivePresenter; +import com.yunbao.live.presenter.LiveRyLinkMicPkPresenter; +import com.yunbao.live.socket.SocketClient; +import com.yunbao.live.socket.SocketMessageListener; +import com.yunbao.live.socket.SocketRyClient; + +import org.greenrobot.eventbus.EventBus; + +import java.util.List; + +import io.rong.imlib.IRongCoreCallback; +import io.rong.imlib.IRongCoreEnum; +import io.rong.imlib.chatroom.base.RongChatRoomClient; + +import static com.yunbao.common.CommonAppContext.logger; +import static com.yunbao.common.CommonAppContext.mFirebaseAnalytics; +import static com.yunbao.live.presenter.LiveLinkMicPresenter.mBannerList2; +import static com.yunbao.live.views.LivePlayKsyViewHolder.setViewUP; +import static com.yunbao.live.views.LiveRoomViewHolder.isStayRoomfive; + +/** + * 竖屏直播间UI逻辑 + */ +public class PortraitLiveManager implements LivePlayListener, SocketMessageListener { + private Activity mContext; + private DrawerLayout mRootContainer; + //直播间插件父布局 + private FrameLayout playContainer; + //直播间纯净模式的切换 + public MyViewPager mViewPager; + //纯净页面,默认显示第二页 + private ViewGroup mSecondPage; + private FrameLayout mContainerWrap; + private ViewGroup mContainer; + private ImageView btnSmallScreen; + private Intent mIntent; + //直播间背景 + private ImageView liveBack; + //侧边栏轮播 + private Banner mBanner; + //侧边栏刷新列表 + public CommonRefreshView sidebarList; + //侧边栏适配器 + private SidebarAdapter sidebarAdapter; + //侧边栏背景 + private ImageView sidebarBack; + //侧滑布局 + private DrawerLayout drawerLayout; + //直播间拆分布局 + private LiveRoomPlayViewHolder mLivePlayViewHolder; + //头部布局 + private LiveRoomViewHolder mLiveRoomViewHolder; + //底部布局 + private LiveAudienceViewHolder mLiveAudienceViewHolder; + //观众与主播连麦逻辑 + private LiveLinkMicPresenter mLiveLinkMicPresenter; + private LiveBean mLiveBean; + //sdk类型 0金山 1腾讯 + private int mLiveSDK; + //主播与主播连麦逻辑 + private LiveLinkMicAnchorPresenter mLiveLinkMicAnchorPresenter; + //主播与主播PK逻辑 + private LiveLinkMicPkPresenter mLiveLinkMicPkPresenter; + //主播与主播PK逻辑 + private LiveRyLinkMicPkPresenter mLiveRyLinkMicPkPresenter; + //直播间的类型 普通 密码 门票 计时等 + private int mLiveType; + //收费价格,计时收费每次扣费的值 + private int mLiveTypeVal; + //直播结束页面 + private LiveEndViewHolder mLiveEndViewHolder; + private SocketRyClient mSocketRyClient; + private SocketClient mSocketClient; + private String mDanmuPrice;//弹幕价格 + private int mSocketUserType;//socket用户类型 30 普通用户 40 管理员 50 主播 60超管 + private int mChatLevel;//发言等级限制 + private int mDanMuLevel;//弹幕等级限制 + private int isattention; + private int backIndex = 0;//0=未判断,1=已判断 + private JSONObject pkInfo; + private LiveGuardInfo mLiveGuardInfo; + private int fansNum; + private String is_fans; + private String anyway; + private boolean mEnd; + + public PortraitLiveManager(Activity context, Intent intent) { + this.mContext = context; + this.mIntent = intent; + ininView(); + } + + /** + * 初始化布局 + */ + private void ininView() { + // 直播间根布局 + mRootContainer = (DrawerLayout) LayoutInflater.from(mContext).inflate(R.layout.activity_live_audience, null); + + + playContainer = mRootContainer.findViewById(R.id.play_container); + + mViewPager = mRootContainer.findViewById(R.id.viewPager); + btnSmallScreen = mRootContainer.findViewById(R.id.btn_small_screen); + mSecondPage = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.view_audience_page, mViewPager, false); + mContainerWrap = mSecondPage.findViewById(R.id.container_wrap); + mContainer = mSecondPage.findViewById(R.id.container); + btnSmallScreen.setOnClickListener(v -> { + mViewPager.setCurrentItem(1); + btnSmallScreen.setVisibility(View.GONE); + if (mContext instanceof LiveAudienceActivity) { + this.mLivePlayViewHolder.smallScreen(); + } + }); + mContainer.removeAllViews(); + mViewPager.setAdapter(pagerAdapter); + mViewPager.setCurrentItem(1); + + //直播页面背景 + liveBack = mRootContainer.findViewById(R.id.live_back); + //侧边栏 + drawerLayout = mRootContainer.findViewById(R.id.drawer_layout); + FrameLayout leftDrawer = mRootContainer.findViewById(R.id.left_drawer); + DrawerLayout.LayoutParams layoutParams = (DrawerLayout.LayoutParams) leftDrawer.getLayoutParams(); + layoutParams.width = DeviceUtils.getScreenWidth(mContext) / 3 * 2; + leftDrawer.setLayoutParams(layoutParams); + sidebarList = mRootContainer.findViewById(R.id.sidebarList); + sidebarBack = mRootContainer.findViewById(R.id.sidebar_back); + + //禁止滑动打开侧边栏 + drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); + sidebarList.setEmptyLayoutId(R.layout.view_no_data_live); + GridLayoutManager gridLayoutManager = new GridLayoutManager(mContext, 2, GridLayoutManager.VERTICAL, false); + sidebarList.setLayoutManager(gridLayoutManager); + sidebarList.setLoadMoreEnable(false); + ItemDecoration decoration = new ItemDecoration(mContext, 0x00000000, 6, 0); + decoration.setOnlySetItemOffsetsButNoDraw(true); + sidebarList.setItemDecoration(decoration); + Display mDisplay = mContext.getWindowManager().getDefaultDisplay(); + sidebarAdapter = new SidebarAdapter(mContext, mDisplay.getHeight()); + //侧边栏轮播 + mBanner = mRootContainer.findViewById(R.id.banner); + sidebarAdapter.setOnItemClickListener((bean, position) -> gotoLive(bean.getUid())); + sidebarAdapter.setHasStableIds(true); + sidebarList.setRecyclerViewAdapter(sidebarAdapter); + + } + + @Override + public void onAdd(LiveBean data, int liveType, int liveTypeVal, int liveSdk) { + mLiveBean = data; + mLiveSDK = liveSdk; + mLiveType = liveType; + mLiveTypeVal = liveTypeVal; + + if (mIntent.getIntExtra("isry", 0) == 1) { + mLivePlayViewHolder = new LivePlayRyViewHolder(mContext, playContainer, mIntent.getIntExtra("landscape", 0)); + } else { + mLivePlayViewHolder = new LivePlayKsyViewHolder(mContext, playContainer, mIntent.getIntExtra("landscape", 0)); + } + mLivePlayViewHolder.addToParent(); + mLivePlayViewHolder.subscribeActivityLifeCycle(); + mLiveRoomViewHolder = new LiveRoomViewHolder(false, 1, mContext, mContainer, mSecondPage.findViewById(R.id.gift_gif), mSecondPage.findViewById(R.id.gift_svga), mContainerWrap, mContext.getWindowManager()); + + mLiveRoomViewHolder.subscribeActivityLifeCycle(); + mLiveAudienceViewHolder = new LiveAudienceViewHolder(mContext, mContainer); + mLiveAudienceViewHolder.addToParent(); + mLiveRoomViewHolder.addToParent(); + mLiveAudienceViewHolder.subscribeActivityLifeCycle(); + mLiveLinkMicPresenter = new LiveLinkMicPresenter(mContext, mLivePlayViewHolder, false, mLiveSDK, mLiveAudienceViewHolder.getContentView()); + mLiveLinkMicAnchorPresenter = new LiveLinkMicAnchorPresenter(mContext, mLivePlayViewHolder, false, mLiveSDK, null); + if (!(mIntent.getIntExtra("isry", 0) == 1)) { + mLiveLinkMicPkPresenter = new LiveLinkMicPkPresenter(mContext, mLivePlayViewHolder, false, null); + } else { + mLiveRyLinkMicPkPresenter = new LiveRyLinkMicPkPresenter(mContext, mLivePlayViewHolder, false, null); + } + + //直播间背景 + ImgLoader.displayBlurLive(mContext, mLiveBean.getAvatar(), liveBack); + //侧边栏背景 + ImgLoader.displayBlurLive(mContext, mLiveBean.getAvatar(), sidebarBack); + + + sidebarList.setDataHelperNew(new CommonRefreshView.DataHelperNew() { + @Override + public void loadData(int p) { + + } + + @Override + public void refresh() { + //推荐位 + MainNetManager.get(mContext) + .anchorRecommend("10", new com.yunbao.common.http.base.HttpCallback() { + @Override + public void onSuccess(AnchorRecommendModel data) { + if (mContext.isFinishing()) return; + sidebarAdapter.addData(data.getList()); + sidebarList.onFinish(); + } + + @Override + public void onError(String error) { + } + }); + } + }); + sidebarList.initData(); + mBanner.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), 10); + } + }); + mBanner.setClipToOutline(true); + + //侧边栏 + MainNetManager.get(mContext) + .getHot(1, new com.yunbao.common.http.base.HttpCallback>() { + @Override + public void onSuccess(List data) { + mContext.runOnUiThread(() -> onBanner(data)); + + } + + @Override + public void onError(String error) { + + } + }); + mLivePlayViewHolder.setCover(data.getThumb()); + mLivePlayViewHolder.play(data.getPull()); + mLiveRoomViewHolder.setAvatar(data.getAvatar()); + mLiveRoomViewHolder.setAnchorLevel(data.getLevelAnchor()); + mLiveRoomViewHolder.setName(data.getUserNiceName()); + mLiveRoomViewHolder.setRoomNum(data.getLiangNameTip()); + mLiveRoomViewHolder.setTitle(data.getTitle()); + if (!(mIntent.getIntExtra("isry", 0) == 1)) { + mLiveLinkMicPkPresenter.setLiveUid(data.getUid(), ""); + } else { + mLiveRyLinkMicPkPresenter.setLiveUid(data.getUid(), ""); + } + mLiveLinkMicPresenter.setLiveUid(data.getUid()); + //心愿单 + LiveHttpUtil.getWishList(mLiveBean.getUid(), new HttpCallback() { + @Override + public void onSuccess(int code, String msg, String[] info) { + if (info.length > 0) { + String json = info[0]; + WishlistModel model = GsonUtils.fromJson(json, WishlistModel.class); + mLiveRoomViewHolder.initWishList(model.getWishlist()); + } + } + + @Override + public void onFinish() { + + enterRoom(); + } + }); + } + + @Override + public void onRemove() { + if (mSocketClient != null) { + + mSocketClient.disConnect(); + mSocketClient = null; + + } + if (mSocketRyClient != null) { + mSocketRyClient.disConnect(); + mSocketRyClient = null; + } + if (mLivePlayViewHolder != null) { + + mLivePlayViewHolder.stopPlay(); + } + + if (mLiveRoomViewHolder != null) { + mLiveRoomViewHolder.removeFromParent(); + mLiveRoomViewHolder.clearData(); + mLiveRoomViewHolder = null; + } + if (mLiveEndViewHolder != null) { + + mLiveEndViewHolder.removeFromParent(); + mLiveEndViewHolder = null; + } + if (mLiveLinkMicPresenter != null) { + mLiveLinkMicPresenter.clearData(); + } + if (mLiveLinkMicAnchorPresenter != null) { + mLiveLinkMicAnchorPresenter.clearData(); + } + if (mLiveLinkMicPkPresenter != null) { + mLiveLinkMicPkPresenter.clearData(); + } + if (mLiveRyLinkMicPkPresenter != null) { + mLiveRyLinkMicPkPresenter.clearData(); + } + if (mLiveAudienceViewHolder != null) { + mLiveAudienceViewHolder.removeFromParent(); + mLiveAudienceViewHolder.countDownTimerTrickery = null; + mLiveAudienceViewHolder = null; + } + } + + @Override + public ViewGroup getRootView() { + return mRootContainer; + } + + @Override + public void onStart() { + + } + + @Override + public void onResume() { + + } + + @Override + public void onPause() { + + } + + @Override + public void onStop() { + + } + + @Override + public void onDestroy() { + + } + + @Override + public void onRestart() { + + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + + } + + @Override + public void onNewIntent(Intent intent) { + + } + + @Override + public void onBackPressed() { + + } + + @Override + public void onConnect(boolean successConn) { + + } + + @Override + public void onDisConnect() { + + } + + @Override + public void onChat(LiveChatBean bean, int index) { + + } + + @Override + public void onLight() { + + } + + @Override + public void onEnterRoom(LiveEnterRoomBean bean) { + + } + + @Override + public void onLeaveRoom(UserBean bean) { + + } + + @Override + public void onSendGift(LiveReceiveGiftBean bean) { + + } + + @Override + public void onBuyZuoji(LiveReceiveGiftBean bean) { + + } + + @Override + public void onBuyLiangName(LiveReceiveGiftBean bean) { + + } + + @Override + public void onBuyVip(LiveReceiveGiftBean bean) { + + } + + @Override + public void onSys(LiveReceiveGiftBean bean) { + + } + + @Override + public void onSendGiftPk(long leftGift, long rightGift, LivePKUserListBean bean) { + + } + + @Override + public void onSendDanMu(LiveDanMuBean bean) { + + } + + @Override + public void onLiveEnd() { + if (!CommonAppConfig.LIVE_ROOM_SCROLL) { + if (mViewPager != null) { + if (mViewPager.getCurrentItem() != 1) { + mViewPager.setCurrentItem(1, false); + } + mViewPager.setCanScroll(false); + } + endPlay(); + } else { + if (mLivePlayViewHolder != null) { + mLivePlayViewHolder.stopPlay2(); + } + } + if (mLiveEndViewHolder == null) { + mLiveEndViewHolder = new LiveEndViewHolder(mContext, mSecondPage, mLiveBean.getUid()); + mLiveEndViewHolder.subscribeActivityLifeCycle(); + mLiveEndViewHolder.addToParent(); + } + mLiveBean.setIsattention(isattention + ""); + mLiveEndViewHolder.showData(mLiveBean, mLiveBean.getStream()); + } + + @Override + public void onAnchorInvalid() { + + } + + @Override + public void onSuperCloseLive() { + + } + + @Override + public void onKick(String touid) { + + } + + @Override + public void onShutUp(String touid, String content) { + + } + + @Override + public void onSetAdmin(String toUid, int isAdmin) { + + } + + @Override + public void onChangeTimeCharge(int typeVal) { + + } + + @Override + public void onUpdateVotes(String uid, String addVotes, int first) { + + } + + @Override + public void addFakeFans(List list) { + + } + + @Override + public void onBuyGuard(LiveBuyGuardMsgBean bean) { + + } + + @Override + public void onBuyNobility(LiveBuyGuardMsgBean bean) { + + } + + @Override + public void onRedPack(LiveChatBean liveChatBean) { + + } + + @Override + public void onAudienceApplyLinkMic(UserBean u) { + + } + + @Override + public void onAnchorAcceptLinkMic() { + + } + + @Override + public void onAnchorRefuseLinkMic() { + + } + + @Override + public void onAudienceSendLinkMicUrl(String uid, String uname, String playUrl) { + + } + + @Override + public void onAnchorCloseLinkMic(String touid, String uname) { + + } + + @Override + public void onAudienceCloseLinkMic(String uid, String uname) { + + } + + @Override + public void onAnchorNotResponse() { + + } + + @Override + public void onAnchorBusy() { + + } + + @Override + public void onAudienceLinkMicExitRoom(String touid) { + + } + + @Override + public void onLinkMicAnchorApply(UserBean u, String stream) { + + } + + @Override + public void onLinkMicAnchorPlayUrl(String pkUid, String playUrl) { + + } + + @Override + public void onLinkMicAnchorClose() { + + } + + @Override + public void onLinkMicAnchorRefuse() { + + } + + @Override + public void onLinkMicAnchorBusy() { + + } + + @Override + public void onLinkMicAnchorNotResponse() { + + } + + @Override + public void onlinkMicPlayGaming() { + + } + + @Override + public void onLinkMicPkApply(UserBean u, String stream, int forwhat) { + + } + + @Override + public void onLinkDRMicPkApply(UserBean u) { + + } + + @Override + public void onLinkDRMicPkApplyOk(UserBean u) { + + } + + @Override + public void onLinkMicPkStart(String pkUid, String pkhead, String pkname) { + + } + + @Override + public void onLinkMicPkClose(int i) { + + } + + @Override + public void onLinkMicPkRefuse() { + + } + + @Override + public void onLinkMicPkBusy() { + + } + + @Override + public void onLinkMicPkNotResponse() { + + } + + @Override + public void onLinkMicPkEnd(String winUid) { + + } + + @Override + public void onLuckGiftWin(LiveLuckGiftWinBean bean) { + + } + + @Override + public void onPrizePoolWin(LiveGiftPrizePoolWinBean bean) { + + } + + @Override + public void onPrizePoolUp(String level) { + + } + + @Override + public void onGameZjh(JSONObject obj) { + + } + + @Override + public void onGameHd(JSONObject obj) { + + } + + @Override + public void onGameZp(JSONObject obj) { + + } + + @Override + public void onGameNz(JSONObject obj) { + + } + + @Override + public void onGameEbb(JSONObject obj) { + + } + + @Override + public void onLinkMicToPk(String uid, String pkhead, String pkname) { + + } + + @Override + public void onUpUserList(JSONObject obj) { + + } + + @Override + public void prankTurntable(String msgtype, int time, JSONObject jsonObject) { + if (mLiveAudienceViewHolder != null) { + mLiveAudienceViewHolder.closeAndOpenTrickery(msgtype, time, jsonObject); + } + } + + private PagerAdapter pagerAdapter = new PagerAdapter() { + @Override + public int getCount() { + return 2; + } + + @Override + public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { + return view == object; + } + + @NonNull + @Override + public Object instantiateItem(@NonNull ViewGroup container, int position) { + if (position == 0) { + View view = new View(mContext); + view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + container.addView(view); + return view; + } else { + container.addView(mSecondPage); + return mSecondPage; + } + } + + @Override + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + } + }; + + + private void enterRoom() { + //进入直播间IM + if (!(mIntent.getIntExtra("isry", 0) == 1)) { + mSocketClient = new SocketClient(mLiveBean.getUid(), this); + if (mLiveLinkMicPresenter != null) { + mLiveLinkMicPresenter.setSocketClient(mSocketClient); + } + } else { + mSocketRyClient = new SocketRyClient(mLiveBean.getUid(), this); + if (mLiveLinkMicPresenter != null) { + mLiveLinkMicPresenter.setSocketClient(mSocketClient); + } + } + timeIndex = 0; + LiveHttpUtil.enterRoom(mLiveBean.getUid(), mLiveBean.getStream(), new HttpCallback() { + @Override + public void onSuccess(int code, String msg, String[] info) { + if (code == 0 && info.length > 0) { + JSONObject obj = JSON.parseObject(info[0]); + mDanmuPrice = obj.getString("barrage_fee"); + mSocketUserType = obj.getIntValue("usertype"); + mChatLevel = obj.getIntValue("speak_limit"); + mDanMuLevel = obj.getIntValue("barrage_limit"); + + EventBus.getDefault().post("close_login"); + EventBus.getDefault().post("oneUesrOver"); + + //进入直播间 + AdjustEvent adjustEvent1 = new AdjustEvent("hiepcu"); + Adjust.trackEvent(adjustEvent1); + mFirebaseAnalytics.logEvent("FS_enterroom", null); + logger.logEvent("FB_enterroom"); + + //观看1分钟 + if (obj.getIntValue("see_time") >= 60) { + AdjustEvent good_user = new AdjustEvent("7zxuxz"); + Adjust.trackEvent(good_user); + CommonHttpUtil.setAdvertisingChannels("7zxuxz", new HttpCallback() { + @Override + public void onSuccess(int code, String msg, String[] info) { + if (code == 0) { + mFirebaseAnalytics.logEvent("FS_enter_app_1min", null); + logger.logEvent("FB_enter_app_1min", null); + } + } + }); + } + if (obj.getIntValue("see_time") >= 600 && obj.getIntValue("un_charge") == 1) { + AdjustEvent good_user = new AdjustEvent("val8lv"); + Adjust.trackEvent(good_user); + CommonHttpUtil.setAdvertisingChannels("val8lv", new HttpCallback() { + @Override + public void onSuccess(int code, String msg, String[] info) { + if (code == 0) { + mFirebaseAnalytics.logEvent("FS_good_user", null); + logger.logEvent("FB_good_user", null); + } + } + }); + + //有效用户 + } else if (obj.getIntValue("see_time") >= 600) { + AdjustEvent valid_user = new AdjustEvent("xuf8ep"); + Adjust.trackEvent(valid_user); + CommonHttpUtil.setAdvertisingChannels("xuf8ep", new HttpCallback() { + @Override + public void onSuccess(int code, String msg, String[] info) { + if (code == 0) { + mFirebaseAnalytics.logEvent("FS_Valid_user", null); + logger.logEvent("FB_Valid_user", null); + } + } + }); + } + //连接socket + LiveHttpUtil.enterBackRoom(mLiveBean.getUid(), mLiveBean.getStream(), new HttpCallback() { + @Override + public void onSuccess(int code, String msg, String[] info) { + //链接上socket以后隐藏Loading加载直播间内容 + } + }); + if (mLiveRoomViewHolder != null) { + LivePlayKsyViewHolder.setLandscape(obj.getIntValue("landscape")); + + mLiveRoomViewHolder.setLiveInfo(mLiveBean.getUid(), mLiveBean.getStream(), obj.getIntValue("userlist_time") * 4000); + mLiveRoomViewHolder.setVotes(obj.getString("votestotal")); + //真爱排行 数量 + mLiveRoomViewHolder.setMedaRankNum(obj.getString("medalRankNum")); + isattention = obj.getIntValue("isattention"); + if (isattention == 0) { + if (countDownTimer != null) { + countDownTimer.cancel(); + timeIndex = 0; + countDownTimer = null; + setTime(); + } else { + setTime(); + } + } else { + if (countDownTimer != null) { + countDownTimer.cancel(); + countDownTimer = null; + } + } + mLiveAudienceViewHolder.setLiveInfo(mLiveBean.getUid(), mLiveBean.getStream(), mLiveBean.getAvatar(), isattention); + mLiveRoomViewHolder.setAttention(isattention); + if (obj.containsKey("lminfo")) { + JSONObject mic_data = obj.getJSONObject("lminfo"); + if (mic_data.containsKey("userlist")) { + mLiveRoomViewHolder.updataMicList(mic_data.getJSONArray("userlist")); + } + } + List list = JSON.parseArray(obj.getString("userlists"), LiveUserGiftBean.class); + mLiveRoomViewHolder.setUserList(list); + mLiveRoomViewHolder.startRefreshUserList(); + if (mLiveType == Constants.LIVE_TYPE_TIME) {//计时收费 + mLiveRoomViewHolder.startRequestTimeCharge(); + } + } + + if (obj.getString("isleave").equals("1")) { + if (LivePlayKsyViewHolder.leave != null) { + LivePlayKsyViewHolder.leave.setVisibility(View.VISIBLE); + } + } + //判断是否有连麦,要显示连麦窗口 + String linkMicUid = obj.getString("linkmic_uid"); + String linkMicPull = obj.getString("linkmic_pull"); + if (!TextUtils.isEmpty(linkMicUid) && !"0".equals(linkMicUid) && !TextUtils.isEmpty(linkMicPull)) { + if (mLiveSDK != Constants.LIVE_SDK_TX && mLiveLinkMicPresenter != null) { + mLiveLinkMicPresenter.onLinkMicPlay(linkMicUid, linkMicPull); + } + } + //判断是否有主播连麦 + pkInfo = JSON.parseObject(obj.getString("pkinfo")); + if (pkInfo != null && pkInfo.getIntValue("drpk_status") != 1) { + String pkUid = pkInfo.getString("pkuid"); + anyway = "1"; + if (!TextUtils.isEmpty(pkUid) && !"0".equals(pkUid) && anyway.equals("0")) { + if (mLiveSDK != Constants.LIVE_SDK_TX) { + String pkPull = pkInfo.getString("pkpull"); + if (!TextUtils.isEmpty(pkPull) && mLiveLinkMicAnchorPresenter != null) { + mLiveLinkMicAnchorPresenter.onLinkMicAnchorPlayUrl(pkUid, pkPull); + } + } else { + if (mLivePlayViewHolder instanceof LivePlayTxViewHolder) { + ((LivePlayTxViewHolder) mLivePlayViewHolder).setAnchorLinkMic(true, 0); + } + } + } + + if (obj.getString("isconnection") != null && obj.getString("isconnection").equals("1")) { + if (!(mIntent.getIntExtra("isry", 0) == 1)) { + setViewUP(); + } else { + LivePlayRyViewHolder.setViewUP(1); + } + } + if (pkInfo.getIntValue("ifpk") == 1 && pkInfo.getString("end_pk_time").equals("0")) {//pk开始了 + if (!(mIntent.getIntExtra("isry", 0) == 1)) { + setViewUP(); + } else { + LivePlayRyViewHolder.setViewUP(2); + } + //pk排名数据 + LivePKUserListBean livePKUserListBean = JSON.parseObject(pkInfo.getString("pk_top_users"), LivePKUserListBean.class); + if (mLiveRoomViewHolder != null) { + mLiveRoomViewHolder.setOtherInfo(pkInfo.getString("pkuid"), pkInfo.getString("pkuimg"), pkInfo.getString("pkuname")); + } + if (mLiveLinkMicPkPresenter != null) { + mLiveLinkMicPkPresenter.onEnterRoomPkStart(pkUid, pkInfo.getLongValue("pk_gift_liveuid"), pkInfo.getLongValue("pk_gift_pkuid"), pkInfo.getIntValue("pk_time"), livePKUserListBean); + } else { + mLiveRyLinkMicPkPresenter.onEnterRoomPkStart(pkUid, pkInfo.getLongValue("pk_gift_liveuid"), pkInfo.getLongValue("pk_gift_pkuid"), pkInfo.getIntValue("pk_time"), livePKUserListBean); + } + } else if (!pkInfo.getString("end_pk_time").equals("0")) { + if (!(mIntent.getIntExtra("isry", 0) == 1)) { + setViewUP(); + } else { + LivePlayRyViewHolder.setViewUP(3); + } + //pk排名数据 + LivePKUserListBean livePKUserListBean = JSON.parseObject(pkInfo.getString("pk_top_users"), LivePKUserListBean.class); + if (mLiveLinkMicPkPresenter != null) { + mLiveLinkMicPkPresenter.onEnterRoomCFStart(pkUid, pkInfo.getLongValue("pk_gift_liveuid"), pkInfo.getLongValue("pk_gift_pkuid"), pkInfo.getIntValue("end_pk_time"), livePKUserListBean); + } else { + mLiveRyLinkMicPkPresenter.onEnterRoomCFStart(pkUid, pkInfo.getLongValue("pk_gift_liveuid"), pkInfo.getLongValue("pk_gift_pkuid"), pkInfo.getIntValue("end_pk_time"), livePKUserListBean); + + } + } + //多人PK + } else if (pkInfo != null && pkInfo.getIntValue("drpk_status") == 1) { + if (!(mIntent.getIntExtra("isry", 0) == 1)) { + setViewUP(); + } else { + LivePlayRyViewHolder.setViewUP(4); + } + mLiveRoomViewHolder.UpPkBar(pkInfo.getJSONArray("userlist"), mLiveBean.getUid(), pkInfo.getIntValue("drpk_time")); + } + + //守护相关 + mLiveGuardInfo = new LiveGuardInfo(); + int guardNum = obj.getIntValue("guard_nums"); + fansNum = obj.getIntValue("count_fans"); + is_fans = obj.getString("is_fans") + ""; + mLiveGuardInfo.setGuardNum(guardNum); + JSONObject guardObj = obj.getJSONObject("guard"); + if (guardObj != null) { + mLiveGuardInfo.setMyGuardType(guardObj.getIntValue("type")); + mLiveGuardInfo.setMyGuardEndTime(guardObj.getString("endtime")); + } + if (mLiveRoomViewHolder != null) { + mLiveRoomViewHolder.setGuardNum(guardNum); + mLiveRoomViewHolder.setFansNum(fansNum); + //红包相关 + mLiveRoomViewHolder.setRedPackBtnVisible(obj.getIntValue("isred") == 1); + } + //奖池等级 + int giftPrizePoolLevel = obj.getIntValue("jackpot_level"); + if (giftPrizePoolLevel >= 0) { + if (mLiveRoomViewHolder != null) { + mLiveRoomViewHolder.showPrizePoolLevel(String.valueOf(giftPrizePoolLevel)); + } + } + } + } + }); + } + + //定时器 + public CountDownTimer countDownTimer = null; + private int timeIndex = 1; + + public PortraitLiveManager setBackIndex(int backIndex) { + this.backIndex = backIndex; + return this; + } + + public CountDownTimer getCountDownTimer() { + return countDownTimer; + } + + public void setTime() { + backIndex = 0; + countDownTimer = new CountDownTimer(CommonAppConfig.getInstance().alert_end_time * 1000, 1000) { + @Override + public void onTick(long millisUntilFinished) { + + if (IMLoginManager.get(mContext).isisNewUserOne() == true && timeIndex == 10) { + NewUserDialog fragment1 = new NewUserDialog(); + fragment1.show(((LiveActivity) mContext).getSupportFragmentManager(), "NewUserDialog"); + } + + if (timeIndex == CommonAppConfig.getInstance().alert_time) { + if (mLiveRoomViewHolder.isAttention == 0) { + BlowkissDialog fragment1 = new BlowkissDialog(); + fragment1.show(((LiveActivity) mContext).getSupportFragmentManager(), "BlowkissDialog"); + } + } + timeIndex++; + if (mLiveRoomViewHolder != null && timeIndex < CommonAppConfig.getInstance().alert_end_time) { + mLiveRoomViewHolder.isStayRoom(false); + } + } + + /** + *倒计时结束后调用的 + */ + @Override + public void onFinish() { + if (timeIndex >= CommonAppConfig.getInstance().alert_end_time) { + if (mLiveRoomViewHolder != null) { + mLiveRoomViewHolder.isStayRoom(true); + } + } + } + }; + countDownTimer.start(); + } + + /** + * 侧滑轮播 + */ + public void onBanner(List data) { + if (data == null || data.size() == 0 || mBanner == null) { + return; + } + + if (mBanner.isStart()) { + mBanner.update(data); + } else { + mBanner.setAutoPlay(true) + .setPages(data, new SlideInBannerViewHolder()) + .setDelayTime(3000) + .setOnBannerClickListener((datas, p) -> { + if (p >= 0 && p < data.size()) { + SlideInfoModel bean = data.get(p); + if (bean != null) { + String link = bean.getSlideUrl(); + if (link.contains("http")) { + WebViewActivity.forward(mContext, link, true); + } else { + gotoLive(link); + } + } + } + }).start(); + } + + } + + /** + * 前往直播间 + */ + private void gotoLive(final String liveId) { + LiveHttpUtil.getLiveInfo(liveId, new HttpCallback() { + @Override + public void onSuccess(int code, String msg, String[] info) { + if (code == 0 && info.length > 0) { + LiveBean liveBean = JSON.parseObject(info[0], LiveBean.class); + LiveRoomCheckLivePresenter mCheckLivePresenter = new LiveRoomCheckLivePresenter(mContext, (liveBean1, liveType, liveTypeVal, liveSdk) -> { + if (liveBean1 == null) { + return; + } + LiveAudienceActivity.forward(mContext, liveBean1, liveType, liveTypeVal, "", 0, liveSdk); + mContext.finish(); + }); + mCheckLivePresenter.checkLive(liveBean); + + } else { + RouteUtil.forwardUserHome(mContext, liveId, 0); + mContext.finish(); + } + } + }); + } + + /** + * 暂停播放 + */ + public void pausePlay() { + if (mLivePlayViewHolder != null) { + mLivePlayViewHolder.pausePlay(); + } + } + + public LiveRoomPlayViewHolder getmLivePlayViewHolder() { + return mLivePlayViewHolder; + } + + /** + * 恢复播放 + */ + public void resumePlay() { + if (mLivePlayViewHolder != null) { + mLivePlayViewHolder.resumePlay(); + } + } + + /** + * 结束观看 + */ + public void endPlay() { + CommonAppContext.Ingroup = 0; + mLiveAudienceViewHolder.handler.removeCallbacks(mLiveAudienceViewHolder.runnable); + mLiveAudienceViewHolder.handler1.removeCallbacks(mLiveAudienceViewHolder.runnable1); + if (mEnd) { + return; + } + mEnd = true; + //断开socket + if (!(mIntent.getIntExtra("isry", 0) == 1)) { + if (mSocketClient != null) { + mSocketClient.disConnect(); + } + mSocketClient = null; + } else { + if (mSocketRyClient != null) { + mSocketRyClient.disConnect(); + } + mSocketRyClient = null; + } + + //结束播放 + if (mLivePlayViewHolder != null) { + mLivePlayViewHolder.release(); + } + mLivePlayViewHolder = null; + onRemove(); + } + + public void end() { + boolean canBackPressed = true; + if (mContext instanceof LiveAudienceActivity) { + canBackPressed = ((LiveAudienceActivity) mContext).canBackPressed(); + } + IMLoginManager.get(mContext).setisNewUserOne(false); + if (!mEnd && !canBackPressed) { + return; + } + if (countDownTimer != null) { + countDownTimer.cancel(); + countDownTimer = null; + timeIndex = 0; + } + if (backIndex == 0) { + if (LiveRoomViewHolder.isAttention == 0) { + if (isStayRoomfive) { + LiveRoomViewHolder.showFollowDialog(LiveRoomViewHolder.mNameText, LiveRoomViewHolder.mAvatarUrl, mContext); + } else { + backIndex = 1; + ((LiveAudienceActivity) mContext).onBackPressed(); + } + } else { + backIndex = 1; + ((LiveAudienceActivity) mContext).onBackPressed(); + } + } else { + exitLiveRoom(); + } + mBannerList2.clear(); + } + + /** + * 退出直播间 + */ + public void exitLiveRoom() { + RongChatRoomClient.getInstance().quitChatRoom("g" + mLiveBean.getUid(), new IRongCoreCallback.OperationCallback() { + @Override + public void onSuccess() { + Log.i("tx", "退出成功"); + //连接socket + LiveHttpUtil.qBackRoom(mLiveBean.getUid(), mLiveBean.getStream(), new HttpCallback() { + @Override + public void onSuccess(int code, String msg, String[] info) { + + } + }); + } + + @Override + public void onError(IRongCoreEnum.CoreErrorCode coreErrorCode) { + + } + }); + + try { + V2TIMManager.getInstance().quitGroup("g" + mLiveBean.getUid(), new V2TIMCallback() { + @Override + public void onSuccess() { + + Log.i("tx", "退出成功" + mLiveBean.getUid()); + //连接socket + LiveHttpUtil.qBackRoom(mLiveBean.getUid(), mLiveBean.getStream(), new HttpCallback() { + @Override + public void onSuccess(int code, String msg, String[] info) { + + } + }); + } + + @Override + public void onError(int code, String desc) { + Log.i("tx", "退出失败"); + } + }); + endPlay(); + mContext.finish(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void openDrawer() { + drawerLayout.openDrawer(GravityCompat.END); + } + + public void onLinkMicTxAccEvent(LinkMicTxAccEvent e) { + if (mLivePlayViewHolder != null && mLivePlayViewHolder instanceof LivePlayTxViewHolder) { + ((LivePlayTxViewHolder) mLivePlayViewHolder).onLinkMicTxAccEvent(e.isLinkMic()); + } + } + + /** + * 腾讯sdk时候主播连麦回调 + * + * @param linkMic true开始连麦 false断开连麦 + */ + public void onLinkMicTxAnchor(boolean linkMic) { + if (mLivePlayViewHolder != null && mLivePlayViewHolder instanceof LivePlayTxViewHolder) { + ((LivePlayTxViewHolder) mLivePlayViewHolder).setAnchorLinkMic(linkMic, 5000); + } + } + +} diff --git a/live/src/main/java/com/yunbao/live/views/TurnTableWebViewHolder.java b/live/src/main/java/com/yunbao/live/views/TurnTableWebViewHolder.java index ed93b2a47..b9cc8907e 100644 --- a/live/src/main/java/com/yunbao/live/views/TurnTableWebViewHolder.java +++ b/live/src/main/java/com/yunbao/live/views/TurnTableWebViewHolder.java @@ -138,8 +138,6 @@ public class TurnTableWebViewHolder extends AbsLivePageViewHolder implements Vie @Override public void onHide() { - if (CommonAppConfig.LIVE_ROOM_SCROLL && mContext != null && mContext instanceof LiveAudienceActivity) { - ((LiveAudienceActivity) mContext).setScrollFrozen(false); - } + } } diff --git a/live/src/main/java/com/yunbao/live/views/WishlistWebViewHolder.java b/live/src/main/java/com/yunbao/live/views/WishlistWebViewHolder.java index 4a25d31a8..03bc7eb98 100644 --- a/live/src/main/java/com/yunbao/live/views/WishlistWebViewHolder.java +++ b/live/src/main/java/com/yunbao/live/views/WishlistWebViewHolder.java @@ -177,8 +177,6 @@ public class WishlistWebViewHolder extends AbsLivePageViewHolder implements View @Override public void onHide() { - if (CommonAppConfig.LIVE_ROOM_SCROLL && mContext != null && mContext instanceof LiveAudienceActivity) { - ((LiveAudienceActivity) mContext).setScrollFrozen(false); - } + } } diff --git a/live/src/main/res/drawable/img_loading_01.png b/live/src/main/res/drawable/img_loading_01.png new file mode 100644 index 0000000000000000000000000000000000000000..fa3a470f65c263ccb53c4851cfe2d062d2b42164 GIT binary patch literal 1898 zcmaJ?eOME99G@TzCm1L*c~P$!MCx|8fty>*8ry*Rcs?)?rYSPE1CDvSxg9b|g+W9h zC?Ns@ihzj)Dijil7J@>AF9?bz1Pco>Fin(vx0{OfM|96~_j`FhpU?N@_xU}S5wtSE zf#yo1P$&+vK#80j^T~Ifoh|u2KX@aY99#&gf(XH*i3Ft{p@`IY6avUFWeg%mlXDGdm7%Icjf$^kyuS?aH3~=p3?Y<&5!;|O2#i9;3ta&@w`_w9;01)x z2pKPvQouog7}q1f5*C-KV*79a9-qbLLVS+TVt@m&c_73C+1^ZuEr7TJZ$9wqVUW@E z>S%#n;{PfZxe_vB2|_0T!GweaR)RMR*T;ZtKA#Ul9FW6dk_e_@vzAaAnOehw2?Ysa zQ0Y+}f#O=gqNt3*;|U>y%=BdmnC`W#*6^xLWWzwCQU|hGkfo#vAPoOM6vJMl4TK!| zC*S`RHiT~0A)p*F;PHADd2rDSETMD)u^v$pxIPreH%xRfC>AGhLoBWX#9~X=mI7Yk zs8)?97~XxsfnkA6Yao8Cinp(M^cjUyozJi?Rjiq`9!Alj^Yolv>wQ`a3 zTu0DJj5&D3^-_ap%_=SGy!1v+b5%ycddFiupwmd&`k>-_^zHM3vWu0TzL&;Db)WP^ zsAPvj``#NZ3n>3hml!?nuJjnmfU3N!e=^+czg~4YuGw~nRa^2E6WeTKMjvgkZm=t{ z`OfA%C5eV#w}Y1ZQb%p}?Z2=od8En1Y_;*i^{4lzh))A|=0G2mt}-!WwVr+k={!*5}d=9-nq% zP~Rvu=b47?F1fYy=ajyfE7jH-=^E1)Q;$77-Sks&P~<`p=4n5AJJ~9v{p5qlv8>$< z4kwP*g!~oQazJ?b)8_Gjz!qn7d;NOlV`bNa7R7Lb%wcbFsE?|oAyM?P)=0NkllVRXswy4voH>d*HV`kyQ; zIg{l!UgIykbhoT_(7t(Nt7%7EW?0W5Ix>m}hSYuKe>kV~X23iZH($F}&CTBg`}9Dm zccAMZl-_cLGj_Qb#a4INHy6yIKC(}ZoSW~{P8$3SjH>Fci zY=68sYis{aM|j$f=NJAcs~vLr_=XEL@vzuu^*b|NM}(<&sI8`msLm%pULByNd%7-a z14>lx!)Y@v=3O1^%xhh9*()3z1fi@%*6{$#<|wO_j4|FTO_==FR>#hvM0zxJJ- z?eqINTL08GS2%jFslxN98*~a^y({)wa<^_DBV$MGZr=Xy5jePN`I_uHmle#pR{&qu z*+YG&cFDt1SB4b^f1Bzww##;JZr1sp>0ROF5%r(buGY)w?-?=+PNzUsQ8DZO%>5MO z9a&X`_s`Ev{3W%w@L)Y`ov)$O>pnbC4~u0NGiycI_9U0-Epx)U)oY#4*?BJ_92HV; zsoMq~Z^Scf_=oH#8h<9 z(`TMl04MX|vMtVU2lUbVKe->AGd6g8XUZ0*=eH|>wlmv~JB;5-j~xrn8L+aa+zS~( UJH8pCTK;}A=}O5FzsQuo0VNy$9{>OV literal 0 HcmV?d00001 diff --git a/live/src/main/res/drawable/img_loading_02.png b/live/src/main/res/drawable/img_loading_02.png new file mode 100644 index 0000000000000000000000000000000000000000..15afbedc703ac78a43a799c8d335fac84f9e117a GIT binary patch literal 1902 zcmaJ?X;2eq7!K035`-!OBN1^4ilR+62N1FnB?m`@AcY8cR1=bgL`ZhK*_eb*5fEvy zN`V#+>Oq0hP;C_~rKl8-8lx32P>@tjDXlspFkT&0up1TIAEi69`@Qcs&-1*;_kOb_ zNr|x@6e@*8B6&#S#L2|Ejd%klze#-0_uWb(7C$^X9Zx|raiao*Ndgs;0Rs}PA`4E2 z6)N-lXW&Q@$u(FbOUKit36K)eG89e>!=yzCHi;Cu#Dpr8*)R@dz*!m{pEh))od#%B zd|FzVlqp3;uv!zBi@_Cz-XgkUfb#t5e?S)puz%VV&@nLKvrI{=%>;(|;r$l}nMEQlEnad^P1 zhekxhRGCn+IObI>!sFA_IF3RfXfzrbMh*kPvOpG(#{-#ckj^!xbjFP9HR` zAcplyOoQSYLR^SLGLy(;DE+(lF9MP*06cCA=U5fzb zr)hL5#HbH>!I4TKiB69zbV^tv=F+o@|>K`s|LauWhv?vi-3}c%0uqp;aw7`q9AO&Nhy^lJ@4#w%Vv4}~ zI=|YBxttj#a~%Jsq-0s})Mq63qgAF6@;+K#i4QnRt}N=NsA7_-_o|XJ#*PsaE?=ufbMN`EWGc=K2z^L-4=N=(hNn8)#vXLW%l5P znfu(Yoj%n4w%T`t@Vk#xWk?e*_rtNgozjta=8U#|>>nNQXyoaTZM)5Uz*++zXfO3! zYc2QnE|0S6zAg7`)%MXH=Y&^t7U4Q+;m1Q7U?* z({|Ul>XQV6hdI!({*W!CrF9p7?d?waf@b5L7W8p&*bd5%9Uu8VHp(_OAKNqa;s91u`n)2|^K_Ls1@mg* zq4}a)|DJfY)L8Sgq7VYOuBdSEp}?jA_S|RJAKSD z{ClII?d$y^WN3beUsvsx%kLSkAIzD*&SynD^>ar{hT3Z`{Wek@R8pd@e7D=#ot?68NjXPc&?WXUJQxUM$P*+@!6pJWsi>dz6CwY8z1oC9Xb zF4weErH7V@uXT9`V)EI8g4W?cb%NghL&4eRCTed7W*_D%FV*L=9JXf4`qbMNI%#=l z-J~22nQ*3BHfL_;_6T%W_btFDH&ap@nyiSIyu4Pn9aq%^zh9&$LKdw z%#3tHtzZ1Wkf`;9HT&=x>d@B#Q4#S2poq7-C%bfYL2Xy|@QRGJkNB3n5Zg3M-A`ra zykpNtlFK4wYbclRK>e2Oh3D8t;f=L_#S0Qoj)CNnDTbro{VgO{5Q ML??>B6Uqz!2D~}-A^-pY literal 0 HcmV?d00001 diff --git a/live/src/main/res/drawable/img_loading_03.png b/live/src/main/res/drawable/img_loading_03.png new file mode 100644 index 0000000000000000000000000000000000000000..0ac1379f03c10e07f8861fcee99824debbaadc00 GIT binary patch literal 1892 zcmaJ?X;c$e6pn=eMntK?VNsigU4fYp0!fY_SwMme5)w8A4j~yxgvrFo2th=n5_jCS zh#-iHq98?)gDVjitRi(mMWGduB5GV}>((N6qM-dzI_J#1d*AuK?=J7YGpnPcW{#ye zQAi}xSYfyzhFG@~?-VNw;@j5qD4tjx@z4ZZjHcr`QVb?>K6JM)&ul2C{wW0U+DY-<#?O(gOi75TG-BKspBu;4s+Kp@&99 z!{q6l7(v)jEW!(-DR5lP0f3yG9N!#yjB)Fz@~fL5vo=)Rz-q+uWg{XY~zzMwUD z4E#0U{}k3pa@8;p18dL)n2b2MbQe=7HHVMEQXIu3D4I3g#b^bJqZ$ROrt|Lj6=WM>%pX{1Nqrxbl&6 z5sb(Mh-3iM;r{Eehqs6cGMQgSmvFueKdd4q9wSCu;eDl*xH0WQ0av2EXH2>pCFV}t z)v&6N84F%3H#8qyy?WXNt6<%}ENCE?EV3;-zh*{0d0PQO{?1S-h<8m^Bqm&#DA*dl zC!zXL2Ln4U%FD~kXiHKx_0B!kddKk$`;RRecS-FXy_rBK?3tfB4vZ+vH&c<~b#6WD zUk36FEV_l!BKvv}MvT4YmVIjG?1pmq8_ zN0+*ybKfPB?RB|+rDeJao}-LM9jY9!DKZUf#(7LE&TwK0^Rt(2Fsw9K?>G$0O3f;l zu1p^6uQg;C+{&ymK)o@&*16kzvE@MTmcbMkjcd|izCQAOM^#<3Vf31q6cS%y^X_Ih zj2_TCc3L}}zH9+(aM(C+G`eU!UzCZuqm&w64} z{KV_!=9Xt|qiPeb+BM{VUt^FgyBF!q%Cod9ig=#9!rF+2Ev+&?mizOR-PL&qMfy@F zx3OZKN9SVwv$va8cr{W^RsHzEd2d}yg6Lj+)y0C}ikIaH9d4I1BImf545s_{w_dUf zamuXLKP|`}@8Y9!ozobluuMiuPMkVl-_!4XefFHDLc8Bzn)jQ#v>s*kJ{W!N@n(lK zBareuYF<0PM&%zDBd$LZR^$3Gq=gweEwg*;NbQzg@bDsAv4l`wA zL920~&7Zq?yPO3nk3ux=1JVaAW`zqkM2k}b zd%ZUIuZqhxi#lfqi4KL$=`xr%#X?&=U22_stK9Z;Sstwiy3Ve8AGbUzu}E}$dDRWE z6J8mfIosm#<{q~?YU{y{yV0jy(>mQ_jni!lkNCtI8a_&l9q6xhNrw)E)Q2NGR~&ga z8%f$}TalHz1YH~UVELV*Jq;I{*6CyYkJg`kgB?|+>DPB%0`evuzg@7yj)RTS-SSTy z*V#&$tGB60JUg}Tz)9$vu8N>-Wt6zOBNvfxQwuA$4%wGqO%3&GAs>oMwQnY05BJC} z7EAVdzUJW(M#$1WxXZSX;=KQ{_-TFFiD^mOJ31|sf+-kp;Dc!6+q92_8EvdQlY0Nm w+7ItN!y}Brlp8X3@1>bs`&FG+od( + + + + + + + \ No newline at end of file diff --git a/live/src/main/res/layout/activity_live_audience.xml b/live/src/main/res/layout/activity_live_audience.xml index bf8340dfe..7dd19fd7d 100644 --- a/live/src/main/res/layout/activity_live_audience.xml +++ b/live/src/main/res/layout/activity_live_audience.xml @@ -1,10 +1,11 @@ - + @@ -79,9 +80,8 @@ android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="8dp" - android:paddingEnd="8dp" - android:paddingTop="56dp" - > + android:paddingTop="56dp" + android:paddingEnd="8dp"> - \ No newline at end of file + \ No newline at end of file diff --git a/live/src/main/res/layout/activity_live_detail.xml b/live/src/main/res/layout/activity_live_detail.xml new file mode 100644 index 000000000..4eedf5c79 --- /dev/null +++ b/live/src/main/res/layout/activity_live_detail.xml @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/live/src/main/res/layout/layout_portrait_live_item.xml b/live/src/main/res/layout/layout_portrait_live_item.xml new file mode 100644 index 000000000..a1f63e882 --- /dev/null +++ b/live/src/main/res/layout/layout_portrait_live_item.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/main/src/main/java/com/yunbao/main/activity/MainActivity.java b/main/src/main/java/com/yunbao/main/activity/MainActivity.java index fb048fbc9..8e397bc6c 100644 --- a/main/src/main/java/com/yunbao/main/activity/MainActivity.java +++ b/main/src/main/java/com/yunbao/main/activity/MainActivity.java @@ -126,9 +126,10 @@ import cn.rongcloud.rtc.api.RCRTCEngine; import io.reactivex.Observer; import io.reactivex.disposables.Disposable; import io.rong.imlib.RongIMClient; +import kotlin.Unit; import static com.yunbao.common.CommonAppContext.isReady; -import kotlin.*; + @Route(path = RouteUtil.PATH_MAIN) public class MainActivity extends AbsActivity implements MainAppBarLayoutListener { @@ -273,7 +274,7 @@ public class MainActivity extends AbsActivity implements MainAppBarLayoutListene Display mDisplay = getWindowManager().getDefaultDisplay(); Height = mDisplay.getHeight(); // IMLib 初始化 - RongIMClient.init(this, RongcloudIMManager.RONG_IM_KEY,true); + RongIMClient.init(this, RongcloudIMManager.RONG_IM_KEY, true); // RTCLib 初始化 RCRTCConfig.Builder config = RCRTCConfig.Builder.create(); RCRTCEngine.getInstance().init(MainActivity.this, config.build()); @@ -673,7 +674,6 @@ public class MainActivity extends AbsActivity implements MainAppBarLayoutListene public void onSuccess(int code, String msg, String[] info) { if (info.length > 0) { - Log.e("MainActivity", info[0]); JSONObject obj = JSON.parseObject(info[0]); if (code == 0) { Bundle bundle = new Bundle(); @@ -683,7 +683,7 @@ public class MainActivity extends AbsActivity implements MainAppBarLayoutListene fragment.setArguments(bundle); fragment.show(getSupportFragmentManager(), "SigninDialog"); } - if (obj.containsKey("msg_zdy_send") && obj.containsKey("msg_zdy_send_text")) { + if (obj != null && obj.containsKey("msg_zdy_send") && obj.containsKey("msg_zdy_send_text")) { Log.e("MainActivity333", info[0]); NoviceInstructorManager.get(mContext).getNetNoviceInstructor(info[0]); }