) : RecyclerView.LayoutManager() {
+ private enum class FlingOrientation{NONE, LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM, BOTTOM_TO_TOP}
+
+ enum class ScrollOrientation{LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM, BOTTOM_TO_TOP}
+
+ private var mVisibleItemCount = visibleCount
+
+ private var mScrollOrientation = scrollOrientation
+
+ private var mScrollOffset: Int
+
+ var isFlinging = false
+
+ private lateinit var mOnScrollListener: OnScrollListener
+ private lateinit var mOnFlingListener: OnFlingListener
+
+ //做动画的组件,支持自定义
+ private var mAnimation: StackAnimation? = null
+ //做布局的组件,支持自定义
+ private var mLayout: StackLayout? = null
+
+ //是否是翻页效果
+ private var mPagerMode = true
+
+ //触发翻页效果的最低 Fling速度
+ private var mPagerFlingVelocity = 0
+
+ //标志当前滚动是否是调用scrollToCenter之后触发的滚动
+ private var mFixScrolling = false
+
+ //fling的方向,用来判断是前翻还是后翻
+ private var mFlingOrientation = FlingOrientation.NONE
+
+ //当前所处item对应的位置
+ private var itemPosition = 0
+
+ //判断item位置是否发生了改变
+ private var isItemPositionChanged = false
+
+ //item 位置发生改变的回调
+ private var itemChangedListener: ItemChangedListener? = null
+
+ interface ItemChangedListener {
+ fun onItemChanged(position: Int)
+ }
+
+ /**
+ * 设置是否为ViewPager 式翻页模式.
+ *
+ * 当设置为 true 的时候,可以配合[StackLayoutManager.setPagerFlingVelocity]设置触发翻页的最小速度.
+ * @param isPagerMode 这个值默认是 false,当设置为 true 的时候,会有 viewPager 翻页效果.
+ */
+ fun setPagerMode(isPagerMode: Boolean) {
+ mPagerMode = isPagerMode
+ }
+
+ /**
+ * @return 当前是否为ViewPager翻页模式.
+ */
+ fun getPagerMode(): Boolean {
+ return mPagerMode
+ }
+
+ /**
+ * 设置触发ViewPager翻页效果的最小速度.
+ *
+ * 该值仅在 [StackLayoutManager.getPagerMode] == true的时候有效.
+ * @param velocity 默认值是2000.
+ */
+ fun setPagerFlingVelocity(@androidx.annotation.IntRange(from = 0, to = Int.MAX_VALUE.toLong()) velocity: Int) {
+ mPagerFlingVelocity = Int.MAX_VALUE.coerceAtMost(0.coerceAtLeast(velocity))
+ }
+
+ /**
+ * @return 当前触发翻页的最小 fling 速度.
+ */
+ fun getPagerFlingVelocity(): Int {
+ return mPagerFlingVelocity
+ }
+
+ /**
+ * 设置recyclerView 静止时候可见的itemView 个数.
+ * @param count 可见 itemView,默认为3
+ */
+ fun setVisibleItemCount(@androidx.annotation.IntRange(from = 1, to = Long.MAX_VALUE)count: Int) {
+ mVisibleItemCount = (itemCount - 1).coerceAtMost(1.coerceAtLeast(count))
+ mAnimation?.setVisibleCount(mVisibleItemCount)
+ }
+
+ /**
+ * 获取recyclerView 静止时候可见的itemView 个数.
+ * @return 静止时候可见的itemView 个数,默认为3.
+ */
+ fun getVisibleItemCount(): Int {
+ return mVisibleItemCount
+ }
+
+ /**
+ * 设置 item 偏移值,即第 i 个 item 相对于 第 i-1个 item 在水平方向的偏移值,默认是40px.
+ * @param offset 每个 item 相对于前一个的偏移值.
+ */
+ fun setItemOffset(offset: Int) {
+ mLayout?.setItemOffset(offset)
+ }
+
+ /**
+ * 获取每个 item 相对于前一个的水平偏移值.
+ * @return 每个 item 相对于前一个的水平偏移值.
+ */
+ fun getItemOffset(): Int {
+ return if (mLayout == null) {
+ 0
+ } else {
+ mLayout!!.getItemOffset()
+ }
+ }
+
+ /**
+ * 设置item 移动动画.
+ * @param animation item 移动动画.
+ */
+ fun setAnimation(animation: StackAnimation) {
+ mAnimation = animation
+ }
+
+ /**
+ * 获取 item 移动动画.
+ * @return item 移动动画.
+ */
+ fun getAnimation(): StackAnimation? {
+ return mAnimation
+ }
+
+ /**
+ * 获取StackLayoutManager 的滚动方向.
+ * @return StackLayoutManager 的滚动方向.
+ */
+ fun getScrollOrientation(): ScrollOrientation {
+ return mScrollOrientation
+ }
+
+ /**
+ * 返回第一个可见 itemView 的位置.
+ * @return 返回第一个可见 itemView 的位置.
+ */
+ fun getFirstVisibleItemPosition(): Int {
+ if (width == 0 || height == 0) {
+ return 0
+ }
+ return when(mScrollOrientation) {
+ ScrollOrientation.RIGHT_TO_LEFT -> floor((mScrollOffset * 1.0 / width)).toInt()
+ ScrollOrientation.LEFT_TO_RIGHT -> itemCount - 1 - ceil((mScrollOffset * 1.0 / width)).toInt()
+ ScrollOrientation.BOTTOM_TO_TOP -> floor((mScrollOffset * 1.0 / height)).toInt()
+ ScrollOrientation.TOP_TO_BOTTOM -> itemCount - 1 - ceil((mScrollOffset * 1.0 / height)).toInt()
+ }
+ }
+
+ /**
+ * 设置 item 位置改变时触发的回调
+ */
+ fun setItemChangedListener(listener: ItemChangedListener) {
+ itemChangedListener = listener
+ }
+
+// constructor(scrollOrientation: ScrollOrientation) : this(scrollOrientation, 3, DefaultAnimation::class.java, DefaultLayout::class.java)
+//
+// constructor(scrollOrientation: ScrollOrientation, visibleCount: Int) : this(scrollOrientation, visibleCount, DefaultAnimation::class.java, DefaultLayout::class.java)
+
+// constructor() : this(ScrollOrientation.RIGHT_TO_LEFT)
+
+ init {
+ mScrollOffset = when(mScrollOrientation) {
+ ScrollOrientation.RIGHT_TO_LEFT, ScrollOrientation.BOTTOM_TO_TOP -> 0
+ else -> Int.MAX_VALUE
+ }
+
+ if (StackAnimation::class.java.isAssignableFrom(animation)) {
+ try {
+ val cla = animation.getDeclaredConstructor(ScrollOrientation::class.java, Int::class.javaPrimitiveType)
+ mAnimation = cla.newInstance(scrollOrientation, visibleCount) as StackAnimation
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ if (StackLayout::class.java.isAssignableFrom(layout)) {
+ try {
+ val cla = layout.getDeclaredConstructor(ScrollOrientation::class.java, Int::class.javaPrimitiveType, Int::class.javaPrimitiveType)
+ mLayout = cla.newInstance(scrollOrientation, visibleCount, 30) as StackLayout
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ }
+
+ override fun generateDefaultLayoutParams(): LayoutParams {
+ return LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT)
+ }
+
+ override fun onAttachedToWindow(view: RecyclerView) {
+ super.onAttachedToWindow(view)
+ mOnFlingListener = object : OnFlingListener() {
+ override fun onFling(velocityX: Int, velocityY: Int): Boolean {
+ if (mPagerMode) {
+ when(mScrollOrientation) {
+ ScrollOrientation.RIGHT_TO_LEFT, ScrollOrientation.LEFT_TO_RIGHT -> {
+ mFlingOrientation = when {
+ velocityX > mPagerFlingVelocity -> FlingOrientation.RIGHT_TO_LEFT
+ velocityX < -mPagerFlingVelocity -> FlingOrientation.LEFT_TO_RIGHT
+ else -> FlingOrientation.NONE
+ }
+ if (mScrollOffset in 1 until width * (itemCount - 1)) { //边界不需要滚动
+ mFixScrolling = true
+ }
+ }
+ else -> {
+ mFlingOrientation = when {
+ velocityY > mPagerFlingVelocity -> FlingOrientation.BOTTOM_TO_TOP
+ velocityY < -mPagerFlingVelocity -> FlingOrientation.TOP_TO_BOTTOM
+ else -> FlingOrientation.NONE
+ }
+ if (mScrollOffset in 1 until width * (itemCount - 1)) { //边界不需要滚动
+ mFixScrolling = true
+ }
+ }
+ }
+ calculateAndScrollToTarget(view)
+ }
+ else {
+ Utils.log("$velocityX $velocityY")
+ }
+ return mPagerMode
+ }
+ }
+ view.onFlingListener = mOnFlingListener
+
+ mOnScrollListener = object : OnScrollListener() {
+ override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
+ if (newState == SCROLL_STATE_IDLE) {
+ isFlinging = false
+ if (!mFixScrolling) {
+ mFixScrolling = true
+ calculateAndScrollToTarget(view)
+ } else {
+ //表示此次 IDLE 是由修正位置结束触发的
+ mFixScrolling = false
+ }
+ } else if (newState == SCROLL_STATE_DRAGGING) {
+ mFixScrolling = false
+ isFlinging = false
+ } else if (newState == SCROLL_STATE_SETTLING) {
+ isFlinging = true
+ }
+ }
+ }
+ view.addOnScrollListener(mOnScrollListener)
+ }
+
+ override fun onDetachedFromWindow(view: RecyclerView?, recycler: RecyclerView.Recycler?) {
+ super.onDetachedFromWindow(view, recycler)
+ if (view?.onFlingListener == mOnFlingListener) {
+ view.onFlingListener = null
+ }
+ view?.removeOnScrollListener(mOnScrollListener)
+ }
+
+ override fun canScrollHorizontally(): Boolean {
+ if (itemCount == 0) {
+ return false
+ }
+ return when (mScrollOrientation) {
+ ScrollOrientation.LEFT_TO_RIGHT, ScrollOrientation.RIGHT_TO_LEFT -> true
+ else -> false
+ }
+ }
+
+ override fun canScrollVertically(): Boolean {
+ if (itemCount == 0) {
+ return false
+ }
+ return when (mScrollOrientation) {
+ ScrollOrientation.TOP_TO_BOTTOM, ScrollOrientation.BOTTOM_TO_TOP -> true
+ else -> false
+ }
+ }
+
+ override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: State) {
+
+ mLayout?.requestLayout()
+
+ removeAndRecycleAllViews(recycler)
+
+ if (itemCount > 0) {
+ mScrollOffset = getValidOffset(mScrollOffset)
+ loadItemView(recycler)
+ }
+ }
+
+ override fun scrollHorizontallyBy(dx: Int, recycler: RecyclerView.Recycler, state: State): Int {
+ return handleScrollBy(dx, recycler)
+ }
+
+ override fun scrollVerticallyBy(dy: Int, recycler: RecyclerView.Recycler, state: State?): Int {
+ return handleScrollBy(dy, recycler)
+ }
+
+ override fun scrollToPosition(position: Int) {
+ if (position < 0 || position >= itemCount) {
+ throw ArrayIndexOutOfBoundsException("$position is out of bound [0..$itemCount-1]")
+ }
+ if (position < 0) {
+ throw ArrayIndexOutOfBoundsException("$position is out of bound [0..$itemCount-1]")
+ }
+ mScrollOffset = getPositionOffset(position)
+ requestLayout()
+ }
+
+ override fun smoothScrollToPosition(recyclerView: RecyclerView, state: State?, position: Int) {
+ if (position < 0 || position >= itemCount) {
+ throw ArrayIndexOutOfBoundsException("$position is out of bound [0..$itemCount-1]")
+ }
+ if (position < 0) {
+ throw ArrayIndexOutOfBoundsException("$position is out of bound [0..$itemCount-1]")
+ }
+ mFixScrolling = true
+ scrollToCenter(position, recyclerView, true)
+ }
+
+ private fun updatePositionRecordAndNotify(position: Int) {
+ if (itemChangedListener == null) {
+ return
+ }
+ if (position != itemPosition) {
+ isItemPositionChanged = true
+ itemPosition = position
+ itemChangedListener?.onItemChanged(itemPosition)
+ } else {
+ isItemPositionChanged = false
+ }
+ }
+
+ private fun handleScrollBy(offset: Int, recycler: RecyclerView.Recycler): Int {
+ //期望值,不得超过最大最小值,所以期望值不一定等于实际值
+ val expectOffset = mScrollOffset + offset
+ //实际值
+ mScrollOffset = getValidOffset(expectOffset)
+
+ //实际偏移,超过最大最小值之后的偏移都应该是0,该值作为返回值,否则在极限位置进行滚动的时候不会出现弹性阴影
+ val exactMove = mScrollOffset - expectOffset + offset
+
+ if (exactMove == 0) {
+ //itemViews 位置都不会改变,直接 return
+ return 0
+ }
+
+ detachAndScrapAttachedViews(recycler)
+
+ loadItemView(recycler)
+
+ return offset
+ }
+
+ private fun loadItemView(recycler: RecyclerView.Recycler) {
+ val firstVisiblePosition = getFirstVisibleItemPosition()
+ val lastVisiblePosition = getLastVisibleItemPosition()
+
+ //位移百分比
+ val movePercent = getFirstVisibleItemMovePercent()
+
+ for (i in lastVisiblePosition downTo firstVisiblePosition) {
+ val view = recycler.getViewForPosition(i)
+ view.layoutParams = view.layoutParams.apply { width = DisplayUtils.getScreenWidth() - 50F.dip2px() }
+ //添加到recycleView 中
+ addView(view)
+ //测量
+ measureChild(view, 0, 0)
+ //布局
+ mLayout?.doLayout(this, mScrollOffset, movePercent, view, i - firstVisiblePosition)
+ //做动画
+ mAnimation?.doAnimation(movePercent, view, i - firstVisiblePosition)
+ }
+
+ //尝试更新当前item的位置并通知外界
+ updatePositionRecordAndNotify(firstVisiblePosition)
+
+ //重用
+ if (firstVisiblePosition - 1 >= 0) {
+ val view = recycler.getViewForPosition(firstVisiblePosition - 1)
+ resetViewAnimateProperty(view)
+ removeAndRecycleView(view, recycler)
+ }
+ if (lastVisiblePosition + 1 < itemCount) {
+ val view = recycler.getViewForPosition(lastVisiblePosition + 1)
+ resetViewAnimateProperty(view)
+ removeAndRecycleView(view, recycler)
+ }
+ }
+
+ private fun resetViewAnimateProperty(view: View) {
+ view.rotationY = 0f
+ view.rotationX = 0f
+ view.scaleX = 1f
+ view.scaleY = 1f
+ view.alpha = 1f
+ }
+
+ private fun calculateAndScrollToTarget(view: RecyclerView) {
+ val targetPosition = calculateCenterPosition(getFirstVisibleItemPosition())
+ scrollToCenter(targetPosition, view, true)
+ }
+
+ private fun scrollToCenter(targetPosition: Int, recyclerView: RecyclerView, animation: Boolean) {
+ val targetOffset = getPositionOffset(targetPosition)
+ when(mScrollOrientation) {
+ ScrollOrientation.LEFT_TO_RIGHT, ScrollOrientation.RIGHT_TO_LEFT -> {
+ if (animation) {
+ recyclerView.smoothScrollBy(targetOffset - mScrollOffset, 0)
+ } else {
+ recyclerView.scrollBy(targetOffset - mScrollOffset, 0)
+ }
+ }
+ else -> {
+ if (animation) {
+ recyclerView.smoothScrollBy(0, targetOffset - mScrollOffset)
+ } else {
+ recyclerView.scrollBy(0, targetOffset - mScrollOffset)
+ }
+ }
+ }
+ }
+
+ private fun getValidOffset(expectOffset: Int): Int {
+ val offset = (width * (itemCount - 1)).coerceAtMost(expectOffset).coerceAtLeast(0)
+ return when(mScrollOrientation) {
+ ScrollOrientation.RIGHT_TO_LEFT, ScrollOrientation.LEFT_TO_RIGHT -> offset
+ else -> (height * (itemCount - 1)).coerceAtMost(expectOffset).coerceAtLeast(0)
+ }
+ }
+
+ private fun getPositionOffset(position: Int): Int {
+ return when(mScrollOrientation) {
+ ScrollOrientation.RIGHT_TO_LEFT -> position * width
+ ScrollOrientation.LEFT_TO_RIGHT -> (itemCount - 1 - position) * width
+ ScrollOrientation.BOTTOM_TO_TOP -> position * height
+ ScrollOrientation.TOP_TO_BOTTOM -> (itemCount - 1 - position) * height
+ }
+ }
+
+ private fun getLastVisibleItemPosition(): Int {
+ val firstVisiblePosition = getFirstVisibleItemPosition()
+ return if (firstVisiblePosition + mVisibleItemCount > itemCount - 1) {
+ itemCount - 1
+ } else {
+ firstVisiblePosition + mVisibleItemCount
+ }
+ }
+
+ private fun getFirstVisibleItemMovePercent(): Float {
+ if (width == 0 || height == 0) {
+ return 0f
+ }
+ return when (mScrollOrientation) {
+ ScrollOrientation.RIGHT_TO_LEFT -> (mScrollOffset % width) * 1.0f / width
+ ScrollOrientation.LEFT_TO_RIGHT -> {
+ val targetPercent = 1 - (mScrollOffset % width) * 1.0f / width
+ return if (targetPercent == 1f) {
+ 0f
+ } else {
+ targetPercent
+ }
+ }
+ ScrollOrientation.BOTTOM_TO_TOP -> (mScrollOffset % height) * 1.0f / height
+ ScrollOrientation.TOP_TO_BOTTOM -> {
+ val targetPercent = 1 - (mScrollOffset % height) * 1.0f / height
+ return if (targetPercent == 1f) {
+ 0f
+ } else {
+ targetPercent
+ }
+ }
+ }
+ }
+
+ private fun calculateCenterPosition(position: Int): Int {
+ //当是 Fling 触发的时候
+ val triggerOrientation = mFlingOrientation
+ mFlingOrientation = FlingOrientation.NONE
+ when(mScrollOrientation) {
+ ScrollOrientation.RIGHT_TO_LEFT -> {
+ if (triggerOrientation == FlingOrientation.RIGHT_TO_LEFT) {
+ return position + 1
+ } else if (triggerOrientation == FlingOrientation.LEFT_TO_RIGHT) {
+ return position
+ }
+ }
+ ScrollOrientation.LEFT_TO_RIGHT -> {
+ if (triggerOrientation == FlingOrientation.LEFT_TO_RIGHT) {
+ return position + 1
+ } else if (triggerOrientation == FlingOrientation.RIGHT_TO_LEFT) {
+ return position
+ }
+ }
+ ScrollOrientation.BOTTOM_TO_TOP -> {
+ if (triggerOrientation == FlingOrientation.BOTTOM_TO_TOP) {
+ return position + 1
+ } else if (triggerOrientation == FlingOrientation.TOP_TO_BOTTOM) {
+ return position
+ }
+ }
+ ScrollOrientation.TOP_TO_BOTTOM -> {
+ if (triggerOrientation == FlingOrientation.TOP_TO_BOTTOM) {
+ return position + 1
+ } else if (triggerOrientation == FlingOrientation.BOTTOM_TO_TOP) {
+ return position
+ }
+ }
+ }
+
+ //当不是 fling 触发的时候
+ val percent = getFirstVisibleItemMovePercent()
+ //向左移动超过50% position(firstVisibleItemPosition)++
+ //否 position不变
+ return if (percent < 0.5) {
+ position
+ } else {
+ position + 1
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/CropImageActivity.java b/app/src/main/java/com/gh/gamecenter/CropImageActivity.java
index 09ca79c334..5df6096cd0 100644
--- a/app/src/main/java/com/gh/gamecenter/CropImageActivity.java
+++ b/app/src/main/java/com/gh/gamecenter/CropImageActivity.java
@@ -8,6 +8,7 @@ import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.TextView;
import com.gh.base.ToolBarActivity;
@@ -20,6 +21,10 @@ import java.io.File;
import java.lang.ref.SoftReference;
import androidx.annotation.NonNull;
+import androidx.core.view.OnApplyWindowInsetsListener;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+
import butterknife.BindView;
public class CropImageActivity extends ToolBarActivity {
@@ -37,11 +42,16 @@ public class CropImageActivity extends ToolBarActivity {
@NonNull
public static Intent getIntent(Context context, String picturePath, float cropRatio, String entrance) {
+ return getIntent(context, picturePath, cropRatio, true, entrance);
+ }
+
+ @NonNull
+ public static Intent getIntent(Context context, String picturePath, float cropRatio, boolean isBlackTheme, String entrance) {
Intent intent = new Intent(context, CropImageActivity.class);
intent.putExtra(EntranceUtils.KEY_PATH, picturePath);
intent.putExtra(EntranceUtils.KEY_ENTRANCE, entrance);
intent.putExtra(EntranceUtils.KEY_IMAGE_CROP_RATIO, cropRatio);
- intent.putExtra(EntranceUtils.KEY_BLACK_THEME, true);
+ intent.putExtra(EntranceUtils.KEY_BLACK_THEME, isBlackTheme);
return intent;
}
@@ -62,12 +72,13 @@ public class CropImageActivity extends ToolBarActivity {
setToolbarMenu(R.menu.menu_positive);
MenuItem menuItem = getMenuItem(R.id.layout_menu_positive);
TextView menuButton = menuItem.getActionView().findViewById(R.id.menu_answer_post);
- menuButton.setTextColor(getResources().getColor(mBlackTheme ? R.color.theme_font : R.color.title));
+ menuButton.setTextColor(getResources().getColor(R.color.theme_font));
float ratio = getIntent().getFloatExtra(EntranceUtils.KEY_IMAGE_CROP_RATIO, 1F);
mCropImageCustom.setCropRatio(ratio);
- DisplayUtils.transparentStatusBar(this);
+ DisplayUtils.setLightStatusBar(this, !mBlackTheme);
+ DisplayUtils.setStatusBarColor(this, R.color.transparent, !mBlackTheme);
}
@Override
diff --git a/app/src/main/java/com/gh/gamecenter/SkipActivity.java b/app/src/main/java/com/gh/gamecenter/SkipActivity.java
index 56148a1080..bb112c004e 100644
--- a/app/src/main/java/com/gh/gamecenter/SkipActivity.java
+++ b/app/src/main/java/com/gh/gamecenter/SkipActivity.java
@@ -36,6 +36,7 @@ import static com.gh.common.util.EntranceUtils.HOST_COMMUNITY_COLUMN_DETAIL;
import static com.gh.common.util.EntranceUtils.HOST_COMMUNITY_QUESTION_LABEL_DETAIL;
import static com.gh.common.util.EntranceUtils.HOST_DOWNLOAD;
import static com.gh.common.util.EntranceUtils.HOST_GAME;
+import static com.gh.common.util.EntranceUtils.HOST_GAME_COLLECTION_DETAIL;
import static com.gh.common.util.EntranceUtils.HOST_LIBAO;
import static com.gh.common.util.EntranceUtils.HOST_QQ;
import static com.gh.common.util.EntranceUtils.HOST_QQ_GROUP;
@@ -390,6 +391,9 @@ public class SkipActivity extends BaseActivity {
position = uri.getQueryParameter("position");
DirectUtils.directToHelpAndFeedback(this, TextUtils.isEmpty(position) ? 0 : Integer.parseInt(position));
break;
+ case HOST_GAME_COLLECTION_DETAIL:
+ DirectUtils.directToGameCollectionDetail(this, path, ENTRANCE_BROWSER);
+ break;
default:
EntranceUtils.jumpActivity(this, new Bundle()); // 跳转至首页
return;
diff --git a/app/src/main/java/com/gh/gamecenter/WeiBoShareActivity.java b/app/src/main/java/com/gh/gamecenter/WeiBoShareActivity.java
index fab00a3394..b78dde982f 100644
--- a/app/src/main/java/com/gh/gamecenter/WeiBoShareActivity.java
+++ b/app/src/main/java/com/gh/gamecenter/WeiBoShareActivity.java
@@ -272,6 +272,13 @@ public class WeiBoShareActivity extends Activity implements WbShareCallback {
ShareUtils.shareEntrance == ShareUtils.ShareEntrance.communityArticle ||
ShareUtils.shareEntrance == ShareUtils.ShareEntrance.video) {
NewLogUtils.logShareResult(true);
+ } else if (ShareUtils.shareEntrance == ShareUtils.ShareEntrance.gameCollection) {
+ NewLogUtils.logViewOrClickGameCollectionDetail(
+ "click_game_collect_detail_favorite_success",
+ ShareUtils.shareEntity.getShareTitle(),
+ ShareUtils.resourceId,
+ "新浪微博"
+ );
}
} else {
IntegralLogHelper.INSTANCE.logInviteResult("成功", "微博");
diff --git a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/GameCollectionItemViewHolder.kt b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/GameCollectionItemViewHolder.kt
new file mode 100644
index 0000000000..24ebf431eb
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/GameCollectionItemViewHolder.kt
@@ -0,0 +1,6 @@
+package com.gh.gamecenter.adapter.viewholder
+
+import com.gh.base.BaseRecyclerViewHolder
+import com.gh.gamecenter.databinding.GameCollectionItemBinding
+
+class GameCollectionItemViewHolder(var binding: GameCollectionItemBinding) : BaseRecyclerViewHolder(binding.root)
diff --git a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/GameHeadViewHolder.kt b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/GameHeadViewHolder.kt
index f80943c444..96fa28c90c 100644
--- a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/GameHeadViewHolder.kt
+++ b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/GameHeadViewHolder.kt
@@ -48,7 +48,8 @@ class GameHeadViewHolder(var binding: GameHeadItemBinding) :
&& subject.data != null
&& subject.data!!.size >= subject.more ?: 0
&& subject.type != "column_collection"
- && subject.type != "gallery_slide") {
+ && subject.type != "gallery_slide"
+ && subject.type != "game_list_collection") {
binding.headMore.visibility = View.GONE
} else if (subject.home == "hide"){
binding.headMore.visibility = View.GONE
diff --git a/app/src/main/java/com/gh/gamecenter/collection/CollectionWrapperFragment.java b/app/src/main/java/com/gh/gamecenter/collection/CollectionWrapperFragment.java
index b0b4fcaae2..2df04ac545 100644
--- a/app/src/main/java/com/gh/gamecenter/collection/CollectionWrapperFragment.java
+++ b/app/src/main/java/com/gh/gamecenter/collection/CollectionWrapperFragment.java
@@ -3,8 +3,10 @@ package com.gh.gamecenter.collection;
import android.os.Bundle;
import com.gh.base.fragment.BaseFragment_TabLayout;
+import com.gh.common.util.EntranceUtils;
import com.gh.common.util.MtaHelper;
import com.gh.gamecenter.R;
+import com.gh.gamecenter.manager.UserManager;
import java.util.List;
@@ -29,27 +31,41 @@ public class CollectionWrapperFragment extends BaseFragment_TabLayout {
return fragment;
}
+ @Override
+ protected int getLayoutId() {
+ return R.layout.fragment_no_padding_tablayout_viewpager;
+ }
+
@Override
protected void initTabTitleList(List tabTitleList) {
tabTitleList.add(getString(R.string.answer));
tabTitleList.add(getString(R.string.collection_article));
+ tabTitleList.add(getString(R.string.video));
+ tabTitleList.add(getString(R.string.game_collection));
tabTitleList.add(getString(R.string.collection_toolkit));
tabTitleList.add(getString(R.string.collection_info));
- tabTitleList.add(getString(R.string.video));
}
@Override
protected void initFragmentList(List fragments) {
fragments.add(new AnswerFragment().with(getArguments()));
fragments.add(new CommunityArticleFragment().with(getArguments()));
- fragments.add(new ToolsFragment().with(getArguments()));
- fragments.add(new ArticleFragment().with(getArguments()));
Bundle arguments = getArguments();
if (arguments != null)
arguments.putString("videoStyle", VideoFragment.VideoStyle.COLLECT.getValue());
fragments.add(new VideoFragment().with(arguments));
+ Bundle gameCollectionArguments = getArguments();
+ if (gameCollectionArguments != null) {
+ gameCollectionArguments.putString(EntranceUtils.KEY_USER_ID, UserManager.getInstance().getUserId());
+ gameCollectionArguments.putString(EntranceUtils.KEY_TYPE, GamesCollectionFragment.TYPE_COLLECT);
+ }
+ fragments.add(new GamesCollectionFragment().with(arguments));
+
+ fragments.add(new ToolsFragment().with(getArguments()));
+ fragments.add(new ArticleFragment().with(getArguments()));
+
}
@Override
diff --git a/app/src/main/java/com/gh/gamecenter/collection/GamesCollectionAdapter.kt b/app/src/main/java/com/gh/gamecenter/collection/GamesCollectionAdapter.kt
new file mode 100644
index 0000000000..6b613f72a7
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/collection/GamesCollectionAdapter.kt
@@ -0,0 +1,268 @@
+package com.gh.gamecenter.collection
+
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.graphics.drawable.ColorDrawable
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import android.widget.PopupWindow
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import androidx.databinding.DataBindingUtil
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.constant.ItemViewType
+import com.gh.common.util.*
+import com.gh.gamecenter.GameDetailActivity
+import com.gh.gamecenter.R
+import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
+import com.gh.gamecenter.adapter.viewholder.GameCollectionItemViewHolder
+import com.gh.gamecenter.baselist.ListAdapter
+import com.gh.gamecenter.collection.GamesCollectionFragment.Companion.TYPE_USER
+import com.gh.gamecenter.entity.GamesCollectionEntity
+import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
+import com.gh.gamecenter.gamecollection.publish.GameCollectionEditActivity
+import com.gh.gamecenter.manager.UserManager
+
+class GamesCollectionAdapter(
+ context: Context,
+ private val mViewModel: GamesCollectionViewModel
+) : ListAdapter(context) {
+
+ override fun getItemCount(): Int {
+ return if (mEntityList == null || mEntityList.isEmpty()) return 0 else mEntityList.size + 1
+ }
+
+ override fun getItemViewType(position: Int): Int {
+ return if (position == itemCount - 1) {
+ ItemViewType.ITEM_FOOTER
+ } else {
+ ItemViewType.ITEM_BODY
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ return when (viewType) {
+ ItemViewType.ITEM_BODY -> GameCollectionItemViewHolder(
+ DataBindingUtil.inflate(
+ mLayoutInflater,
+ R.layout.game_collection_item,
+ parent,
+ false
+ )
+ )
+
+ else -> FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false))
+ }
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ when (holder) {
+ is GameCollectionItemViewHolder -> {
+ val itemEntity = mEntityList[position]
+ holder.binding.run {
+ entity = itemEntity
+ executePendingBindings()
+
+ moreIv.goneIf(itemEntity.user?.id != UserManager.getInstance().userId)
+
+ when (itemEntity.stamp) {
+ "special_choice" -> {
+ tagIv.setBackgroundResource(R.drawable.ic_chosen)
+ }
+ "official" -> {
+ tagIv.setBackgroundResource(R.drawable.ic_official)
+ }
+ }
+
+ when {
+ mViewModel.mIsInsertGameCollection -> {
+ userIcon.visibility = View.VISIBLE
+ userName.visibility = View.VISIBLE
+ timeTv.visibility = View.GONE
+ myselfTag.visibility = View.GONE
+ }
+
+ mViewModel.type == TYPE_USER && itemEntity.display == "self_only" -> {
+ userIcon.visibility = View.GONE
+ userName.visibility = View.GONE
+ timeTv.visibility = View.GONE
+ myselfTag.visibility = View.VISIBLE
+ }
+
+ mViewModel.type == TYPE_USER && itemEntity.display != "self_only"-> {
+ userIcon.visibility = View.GONE
+ userName.visibility = View.GONE
+ timeTv.visibility = View.VISIBLE
+ myselfTag.visibility = View.GONE
+ }
+
+ else -> {
+ userIcon.visibility = View.VISIBLE
+ userName.visibility = View.VISIBLE
+ timeTv.visibility = View.GONE
+ myselfTag.visibility = View.GONE
+ }
+ }
+
+ moreIv.setOnClickListener {
+ showOptionPopupWindow(moreIv, itemEntity)
+ }
+
+ myselfTag.setOnClickListener {
+ DialogHelper.showDialog(mContext, "仅自己可见", "游戏单开启“仅自己可见”后,将不会对其他用户展示,您可以通过关闭仅自己可见或者投稿分享游戏单", "我知道了", "", {
+
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
+ }
+
+ gameOne.setOnClickListener {
+ GameDetailActivity.startGameDetailActivity(mContext, itemEntity.games?.safelyGetInRelease(0)?.id, "")
+ }
+ gameTwo.setOnClickListener {
+ GameDetailActivity.startGameDetailActivity(mContext, itemEntity.games?.safelyGetInRelease(1)?.id, "")
+ }
+ gameThree.setOnClickListener {
+ GameDetailActivity.startGameDetailActivity(mContext, itemEntity.games?.safelyGetInRelease(2)?.id, "")
+ }
+
+ userIcon.setOnClickListener {
+ val path = when (mViewModel.type) {
+ GamesCollectionFragment.TYPE_COLLECT -> "我的收藏-游戏单"
+ GamesCollectionFragment.TYPE_HISTORY -> "浏览记录-游戏单"
+ GamesCollectionFragment.TYPE_USER -> "个人主页-游戏单"
+ else -> ""
+ }
+ DirectUtils.directToHomeActivity(mContext, itemEntity.user?.id, "", path)
+ }
+ userName.setOnClickListener { userIcon.performClick() }
+
+ root.setOnClickListener {
+ if (mViewModel.mIsInsertGameCollection) {
+ val entity = GamesCollectionEntity().apply {
+ id = itemEntity.id
+ title = itemEntity.title
+ intro = itemEntity.intro
+ }
+ val intent = Intent().apply {
+ putExtra(GamesCollectionEntity::class.java.simpleName, entity)
+ }
+ (mContext as AppCompatActivity).setResult(Activity.RESULT_OK, intent)
+ (mContext as AppCompatActivity).finish()
+ } else {
+ NewLogUtils.logEnterGameCollectionDetail(itemEntity.title, itemEntity.id)
+ mContext.startActivity(GameCollectionDetailActivity.getIntent(mContext, itemEntity.id))
+ }
+ }
+
+ commentCountContainer.setOnClickListener {
+ NewLogUtils.logEnterGameCollectionDetail(itemEntity.title, itemEntity.id)
+ mContext.startActivity(
+ GameCollectionDetailActivity.getIntent(
+ mContext,
+ itemEntity.id,
+ isScrollToCommentArea = true
+ )
+ )
+ }
+
+ voteCountContainer.setOnClickListener {
+ debounceActionWithInterval(R.id.vote_count_container, 1000) {
+ mViewModel.postVoteGameCollection(itemEntity.id, !voteIcon.isChecked) {
+ if (!voteIcon.isChecked) {
+ voteCount.setTextColor(R.color.theme_font.toColor())
+ voteIcon.isChecked = true
+ voteIcon.visibility = View.GONE
+ voteAnimation.visibility = View.VISIBLE
+ voteAnimation.setAnimation("lottie/community_vote.json")
+ voteAnimation.playAnimation()
+ voteAnimation.doOnAnimationEnd {
+ voteAnimation.visibility = View.GONE
+ voteIcon.visibility = View.VISIBLE
+ }
+
+ itemEntity.me?.vote = true
+ itemEntity.count?.run {
+ vote++
+ voteCount.text = vote.toString()
+ }
+ } else {
+ voteIcon.isChecked = false
+ itemEntity.me?.vote = false
+ itemEntity.count?.run {
+ vote--
+ if (vote < 0) vote = 0
+ voteCount.setTextColor(R.color.text_999999.toColor())
+ voteCount.text = vote.toString()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ is FooterViewHolder -> holder.initFooterViewHolder(mViewModel, mIsLoading, mIsNetworkError, mIsOver)
+ }
+ }
+
+ private fun showOptionPopupWindow(view: View, entity: GamesCollectionEntity) {
+ val contentList = arrayListOf("编辑", "投稿", "删除")
+
+ val inflater = LayoutInflater.from(mContext)
+ val layout = inflater.inflate(R.layout.layout_popup_container, null)
+ val popupWindow = PopupWindow(
+ layout,
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ )
+ popupWindow.apply {
+ setBackgroundDrawable(ColorDrawable(0))
+ isTouchable = true
+ isFocusable = true
+ isOutsideTouchable = true
+ }
+
+ val container = layout.findViewById(R.id.container)
+ for (text in contentList) {
+ val item = inflater.inflate(R.layout.layout_popup_option_item, container, false)
+ container.addView(item)
+
+ val hitText = item.findViewById(R.id.hint_text)
+ hitText.text = text
+
+ item.setOnClickListener {
+ dealOption(text, entity)
+ popupWindow.dismiss()
+ }
+ }
+ popupWindow.showAutoOrientation(view)
+ }
+
+ private fun dealOption(content: String, entity: GamesCollectionEntity) {
+ when (content) {
+ "编辑" -> {
+ mContext.startActivity(GameCollectionEditActivity.getIntent(mContext, entity))
+ }
+
+ "投稿" -> {
+ if ((entity.count?.game ?: 0) >= 8) {
+ DialogHelper.showDialog(mContext, "温馨提示", "投稿通过后,将自动关闭“仅自己可见”,所有用户都能浏览到游戏单,确定投稿?", "确定", "取消", {
+ mViewModel.publishGameCollection(entity)
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
+ } else {
+ DialogHelper.showDialog(mContext, "温馨提示", "游戏单需要收录至少8个游戏,才可以投稿至游戏单广场哦~", "添加游戏", "我知道了", {
+ mContext.startActivity(GameCollectionEditActivity.getIntent(mContext, entity))
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
+ }
+ }
+
+ "删除" -> {
+ DialogHelper.showDialog(mContext, "温馨提示", "游戏单删除后将无法恢复,是否确认删除", "确定", "取消", {
+ mViewModel.deleteGameCollection(entity)
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/collection/GamesCollectionFragment.kt b/app/src/main/java/com/gh/gamecenter/collection/GamesCollectionFragment.kt
new file mode 100644
index 0000000000..bab8713915
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/collection/GamesCollectionFragment.kt
@@ -0,0 +1,80 @@
+package com.gh.gamecenter.collection
+
+import android.os.Bundle
+import android.view.View
+import androidx.core.content.ContextCompat
+import com.gh.common.util.*
+import com.gh.common.util.EntranceUtils.*
+import com.gh.common.view.SpacingItemDecoration
+import com.gh.gamecenter.R
+import com.gh.gamecenter.baselist.ListFragment
+import com.gh.gamecenter.baselist.LoadType
+import com.gh.gamecenter.entity.GamesCollectionEntity
+
+class GamesCollectionFragment : ListFragment() {
+
+ private var mUserId = ""
+ private var mType = ""
+ private var mIsInsertGameCollection = false
+ private var mAdapter: GamesCollectionAdapter? = null
+
+ override fun provideListViewModel() = viewModelProvider(
+ GamesCollectionViewModel.Factory(mUserId, mType, mIsInsertGameCollection)
+ )
+
+ override fun provideListAdapter() = mAdapter ?: GamesCollectionAdapter(requireContext(), mListViewModel).apply { mAdapter = this }
+
+ override fun getItemDecoration() = SpacingItemDecoration(notDecorateTheFirstItem = mType == TYPE_USER, top = 16F.dip2px())
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ mUserId = arguments?.getString(KEY_USER_ID, "") ?: ""
+ mType = arguments?.getString(KEY_TYPE, "") ?: ""
+ mIsInsertGameCollection = arguments?.getBoolean(KEY_INSERT_GAME_COLLECTION, false) ?: false
+ super.onCreate(savedInstanceState)
+ mListRv?.run {
+ overScrollMode = View.OVER_SCROLL_NEVER
+ if (!mIsInsertGameCollection && mType == TYPE_USER) setBackgroundColor(R.color.white.toColor())
+ }
+
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ mListViewModel.deleteLiveData.observe(viewLifecycleOwner) {
+ val index = mAdapter?.entityList?.indexOf(it) ?: -1
+ mAdapter?.entityList?.removeAt(index)
+ if (mAdapter?.entityList?.isNullOrEmpty() == true) {
+ onLoadEmpty()
+ } else {
+ mAdapter?.notifyItemRemoved(index)
+ }
+
+ toast("删除成功")
+ }
+
+ mListViewModel.publishLiveData.observe(viewLifecycleOwner) {
+ mListViewModel.load(LoadType.REFRESH)
+ }
+ }
+
+ override fun onLoadEmpty() {
+ super.onLoadEmpty()
+ // RecyclerView 被隐藏的话会导致不能 AppBar 不能滑动
+ if (mType == TYPE_USER) mListRv.visibility = View.VISIBLE
+ }
+
+ override fun onLoadError() {
+ super.onLoadError()
+ if (mType == TYPE_USER) {
+ mListRv.visibility = View.VISIBLE
+ mReuseNoConn?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.background))
+ }
+ }
+
+ companion object {
+ const val TYPE_HISTORY = "history"
+ const val TYPE_COLLECT = "collect"
+ const val TYPE_USER = "user"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/collection/GamesCollectionViewModel.kt b/app/src/main/java/com/gh/gamecenter/collection/GamesCollectionViewModel.kt
new file mode 100644
index 0000000000..6a0d9dec1f
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/collection/GamesCollectionViewModel.kt
@@ -0,0 +1,128 @@
+package com.gh.gamecenter.collection
+
+import android.annotation.SuppressLint
+import android.app.Application
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.gh.common.history.HistoryDatabase
+import com.gh.common.util.ErrorHelper
+import com.gh.common.util.ToastUtils
+import com.gh.common.util.observableToMain
+import com.gh.common.util.singleToMain
+import com.gh.gamecenter.baselist.ListViewModel
+import com.gh.gamecenter.collection.GamesCollectionFragment.Companion.TYPE_COLLECT
+import com.gh.gamecenter.collection.GamesCollectionFragment.Companion.TYPE_HISTORY
+import com.gh.gamecenter.entity.GamesCollectionEntity
+import com.gh.gamecenter.retrofit.BiResponse
+import com.gh.gamecenter.retrofit.Response
+import com.gh.gamecenter.retrofit.RetrofitManager
+import com.halo.assistant.HaloApp
+import io.reactivex.Single
+import okhttp3.ResponseBody
+import retrofit2.HttpException
+
+class GamesCollectionViewModel(application: Application, var userId: String, var type: String, val mIsInsertGameCollection: Boolean = false) :
+ ListViewModel(application) {
+
+ private val mApi = RetrofitManager.getInstance(getApplication()).api
+ val deleteLiveData = MutableLiveData()
+ val publishLiveData = MutableLiveData()
+
+ override fun provideDataObservable(page: Int) = null
+
+ override fun provideDataSingle(page: Int): Single> {
+ return when (type) {
+ TYPE_COLLECT -> mApi.getFavoriteGameCollectionList(userId)
+
+ TYPE_HISTORY -> {
+ if (page > 5) {
+ Single.create { it.onSuccess(arrayListOf()) }
+ } else {
+ HistoryDatabase.instance.gamesCollectionDao().getGamesCollectionWithOffset(20, (page - 1) * 20)
+ }
+ }
+
+ else -> {
+ val map = if (mIsInsertGameCollection) {
+ hashMapOf("filter" to "display")
+ } else mapOf()
+ mApi.getUserGameCollectionList(userId, map)
+ }
+ }
+ }
+
+ override fun mergeResultLiveData() {
+ mResultLiveData.addSource(mListLiveData) {
+ mResultLiveData.postValue(it)
+ }
+ }
+
+ fun deleteGameCollection(entity: GamesCollectionEntity) {
+ mApi.deleteGameCollection(entity.id)
+ .compose(observableToMain())
+ .subscribe(object : Response() {
+ override fun onResponse(response: ResponseBody?) {
+ super.onResponse(response)
+ deleteLiveData.postValue(entity)
+ }
+
+ override fun onFailure(e: HttpException?) {
+ super.onFailure(e)
+ ToastUtils.showToast("删除失败")
+ }
+ })
+ }
+
+ fun publishGameCollection(entity: GamesCollectionEntity){
+ mApi.deleteGameCollection(entity.id)
+ .compose(observableToMain())
+ .subscribe(object : Response() {
+ override fun onResponse(response: ResponseBody?) {
+ super.onResponse(response)
+ publishLiveData.postValue(entity)
+ }
+
+ override fun onFailure(e: HttpException?) {
+ super.onFailure(e)
+ ToastUtils.showToast("投稿失败")
+ }
+ })
+ }
+
+ @SuppressLint("CheckResult")
+ fun postVoteGameCollection(gameCollectionId: String, isVote: Boolean, successCallback: (() -> Unit)) {
+ val single = if (isVote) {
+ mApi.voteGameCollection(gameCollectionId)
+ } else {
+ mApi.unVoteGameCollection(gameCollectionId)
+ }
+ single.compose(singleToMain())
+ .subscribe(object : BiResponse() {
+ override fun onSuccess(data: ResponseBody) {
+ ToastUtils.toast(if (isVote) "点赞成功" else "取消点赞")
+ successCallback.invoke()
+ }
+
+ override fun onFailure(exception: Exception) {
+ super.onFailure(exception)
+
+ if (exception is HttpException) {
+ ErrorHelper.handleError(
+ getApplication(),
+ exception.response()?.errorBody()?.string()
+ )
+ }
+ }
+ })
+ }
+
+
+ class Factory(private val mUserId: String, private val mType: String, private val mIsInsertGameCollection: Boolean) :
+ ViewModelProvider.NewInstanceFactory() {
+ override fun create(modelClass: Class): T {
+ return GamesCollectionViewModel(HaloApp.getInstance().application, mUserId, mType, mIsInsertGameCollection) as T
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/entity/GameCollectionDraft.kt b/app/src/main/java/com/gh/gamecenter/entity/GameCollectionDraft.kt
new file mode 100644
index 0000000000..aae0ec76fa
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/entity/GameCollectionDraft.kt
@@ -0,0 +1,45 @@
+package com.gh.gamecenter.entity
+
+import android.os.Parcelable
+import androidx.room.Entity
+import androidx.room.Ignore
+import androidx.room.PrimaryKey
+import androidx.room.TypeConverters
+import com.gh.gamecenter.R
+import com.gh.gamecenter.qa.entity.Count
+import com.gh.gamecenter.qa.entity.TimeEntity
+import com.gh.gamecenter.room.converter.SimpleGameListConverter
+import com.gh.gamecenter.room.converter.TagInfoListConverter
+import com.google.gson.annotations.SerializedName
+import kotlinx.android.parcel.Parcelize
+
+@Entity
+@Parcelize
+class GameCollectionDraft(
+ @Ignore
+ @SerializedName("_id")
+ var id: String = "",
+ @PrimaryKey
+ var primaryKey: String = "", // db key
+ @TypeConverters(TagInfoListConverter::class)
+ var tags: ArrayList? = null,
+ @TypeConverters(SimpleGameListConverter::class)
+ var games: ArrayList? = null,
+ var title: String = "",
+ var intro: String = "",
+ var cover: String = "",
+ var display: String = "",//self_only: 仅自己可见
+) : Parcelable {
+
+ fun convertGameCollectionEntity(): GamesCollectionEntity {
+ val entity = GamesCollectionEntity()
+ entity.id = id
+ entity.tags = tags
+ entity.games = games
+ entity.title = title
+ entity.intro = intro
+ entity.cover = cover
+ entity.display = display
+ return entity
+ }
+}
diff --git a/app/src/main/java/com/gh/gamecenter/entity/GameCollectionTagEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/GameCollectionTagEntity.kt
new file mode 100644
index 0000000000..693dc99b9e
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/entity/GameCollectionTagEntity.kt
@@ -0,0 +1,14 @@
+package com.gh.gamecenter.entity
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.android.parcel.Parcelize
+
+@Parcelize
+data class GameCollectionTagEntity(
+ @SerializedName("_id")
+ val categoryId: String = "",
+ @SerializedName("name")
+ val categoryName: String = "",
+ val tags: List = ArrayList()
+) : Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt
index d9ef421c6f..12f088d9d9 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt
@@ -252,6 +252,13 @@ data class GameEntity(
@SerializedName("bbs_id")
var bbsId: String = "",
+ //游戏单推荐分数
+ @SerializedName("recommend_star")
+ var recommendStar: Int = 5,
+ //游戏单推荐理由
+ @SerializedName("recommend_text")
+ var recommendText: String = "",
+
// 本地字段,使用镜像信息
var useMirrorInfo: Boolean = false,
// 本地字段,曝光用
@@ -549,6 +556,20 @@ data class GameEntity(
&& (useMirrorInfo || RegionSettingHelper.shouldThisGameDisplayMirrorInfo(id)))
}
+ fun toSimpleGame(): SimpleGame {
+ val simpleGame = SimpleGame()
+ simpleGame.id = id
+ simpleGame.mName = mName
+ simpleGame.nameSuffix = nameSuffix
+ simpleGame.mIcon = mIcon
+ simpleGame.mRawIcon = mRawIcon
+ simpleGame.active = active
+ simpleGame.iconSubscript = iconSubscript
+ simpleGame.recommendStar = recommendStar
+ simpleGame.recommendText = recommendText
+ return simpleGame
+ }
+
fun clone(): GameEntity {
val gameEntity = GameEntity()
gameEntity.id = id
@@ -762,12 +783,22 @@ data class SimpleGame(
@SerializedName("name_suffix")
var nameSuffix: String? = null,
@SerializedName("icon")
- private var mIcon: String? = null,
+ var mIcon: String? = null,
@SerializedName("ori_icon")
- private var mRawIcon: String? = null,
+ var mRawIcon: String? = null,
@SerializedName("icon_subscript")
var iconSubscript: String? = null,
- var active: Boolean = false
+ var active: Boolean = false,
+ //游戏单推荐分数
+ @SerializedName("recommend_star")
+ var recommendStar: Int = 5,
+ @SerializedName("mirror_status")
+ var mirrorStatus: String? = "",
+ @SerializedName("mirror_data")
+ var mirrorData: SimpleGame? = null,
+ //游戏单推荐理由
+ @SerializedName("recommend_text")
+ var recommendText: String = "",
) : Parcelable {
@IgnoredOnParcel
@@ -788,6 +819,10 @@ data class SimpleGame(
gameEntity.icon = mIcon
gameEntity.rawIcon = mRawIcon
gameEntity.iconSubscript = iconSubscript
+ gameEntity.mirrorStatus = mirrorStatus
+ gameEntity.mirrorData = mirrorData?.toGameEntity()
+ gameEntity.recommendStar = recommendStar
+ gameEntity.recommendText = recommendText
return gameEntity
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/entity/GamesCollectionDetailEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/GamesCollectionDetailEntity.kt
new file mode 100644
index 0000000000..a9abc1cf49
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/entity/GamesCollectionDetailEntity.kt
@@ -0,0 +1,38 @@
+package com.gh.gamecenter.entity
+
+import android.os.Parcelable
+import com.gh.gamecenter.qa.entity.Count
+import com.gh.gamecenter.qa.entity.TimeEntity
+import com.google.gson.annotations.SerializedName
+import kotlinx.android.parcel.Parcelize
+
+@Parcelize
+class GamesCollectionDetailEntity(
+ @SerializedName("_id")
+ var id: String = "",
+ var tags: ArrayList? = null,
+ var games: ArrayList? = null,
+ var title: String = "",
+ var intro: String = "",
+ var cover: String = "",
+ var video: Video? = null,
+ var display: String = "",//self_only: 仅自己可见
+ var status: String = "",// draft/pending/pass/failed
+ var time: TimeEntity? = null,
+ var stamp: String = "",//special_choice: 精选 official: 官方
+ var count: Count? = null,
+ var user: UserEntity? = null,
+ var me: MeEntity? = null,
+) : Parcelable {
+
+ @Parcelize
+ data class Video(
+ var active: Boolean = false,
+ var format: String = "",
+ var title: String = "",
+ var size: Long = 0,
+ var url: String = "",
+ var poster: String = "",
+ var time: Long = 0
+ ) : Parcelable
+}
diff --git a/app/src/main/java/com/gh/gamecenter/entity/GamesCollectionEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/GamesCollectionEntity.kt
new file mode 100644
index 0000000000..f72c1747e7
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/entity/GamesCollectionEntity.kt
@@ -0,0 +1,52 @@
+package com.gh.gamecenter.entity
+
+import android.os.Parcelable
+import androidx.room.Entity
+import androidx.room.Ignore
+import androidx.room.PrimaryKey
+import androidx.room.TypeConverters
+import com.gh.gamecenter.R
+import com.gh.gamecenter.qa.entity.Count
+import com.gh.gamecenter.qa.entity.TimeEntity
+import com.gh.gamecenter.room.converter.*
+import com.google.gson.annotations.SerializedName
+import kotlinx.android.parcel.Parcelize
+
+@Entity
+@Parcelize
+class GamesCollectionEntity(
+ @PrimaryKey
+ @SerializedName("_id")
+ var id: String = "",
+ @TypeConverters(TagInfoListConverter::class)
+ var tags: ArrayList? = null,
+ @TypeConverters(SimpleGameListConverter::class)
+ var games: ArrayList? = null,
+ var title: String = "",
+ var intro: String = "",
+ var cover: String = "",
+ var display: String = "",//self_only: 仅自己可见
+ var stamp: String = "",//special_choice: 精选 offical: 官方
+ @TypeConverters(CountConverter::class)
+ var count: Count? = null,
+ @TypeConverters(UserConverter::class)
+ var user: User? = null,
+ @TypeConverters(MeConverter::class)
+ var me: MeEntity? = null,
+ var orderTag: Long = 0,
+ @Ignore
+ var time: TimeEntity? = null,
+ @Ignore
+ var status: String = "",// draft/pending/pass/failed
+) : Parcelable {
+
+ fun getStatusLabelRes(): Int {
+ return when {
+ display == "self_only" && status == "draft" -> R.drawable.ic_game_collection_private
+ status == "draft" -> R.drawable.ic_game_collection_draft
+ status == "pending" -> R.drawable.ic_game_collection_pending
+ status == "failed" -> R.drawable.ic_game_collection_fail
+ else -> -1
+ }
+ }
+}
diff --git a/app/src/main/java/com/gh/gamecenter/entity/HomeContent.kt b/app/src/main/java/com/gh/gamecenter/entity/HomeContent.kt
index 9a57462f34..cb7ece6001 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/HomeContent.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/HomeContent.kt
@@ -13,6 +13,8 @@ data class HomeContent(
val linkGame: GameEntity? = null,
@SerializedName("link_column")
val linkColumn: SubjectEntity? = null,
+ @SerializedName("game_list")
+ val linkGameCollection: List? = null,
@SerializedName("link_top_game_comment")
val linkTopGameComment: List? = null,
@SerializedName("display_content")
diff --git a/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt
index e9ac7b7617..a7f9598108 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/MeEntity.kt
@@ -25,8 +25,8 @@ class MeEntity(@SerializedName("is_community_voted")
@SerializedName("is_answer_opposed")
var isAnswerOpposed: Boolean = false, // 是否已经踩过回答
- @SerializedName(value = "is_answer_own", alternate = ["is_community_article_own", "is_question_own", "is_video_own"])
- var isContentOwner: Boolean = false, // 是否是当前内容(回答/社区文章/问题/视频)的拥有者
+ @SerializedName(value = "is_answer_own", alternate = ["is_community_article_own", "is_question_own", "is_video_own", "is_game_list_own"])
+ var isContentOwner: Boolean = false, // 是否是当前内容(回答/社区文章/问题/视频/游戏单)的拥有者
@SerializedName("is_answer_favorite")
var isAnswerFavorite: Boolean = false,
@@ -62,7 +62,7 @@ class MeEntity(@SerializedName("is_community_voted")
var isCommentOwner: Boolean = false, // 是否是当前评论的拥有者
@SyncPage(syncNames = [SyncFieldConstants.ARTICLE_COMMENT_VOTE])
- @SerializedName("is_comment_voted", alternate = ["is_answer_comment_voted", "is_video_comment_voted", "is_community_article_comment_voted", "is_question_comment_voted"])
+ @SerializedName("is_comment_voted", alternate = ["is_answer_comment_voted", "is_video_comment_voted", "is_community_article_comment_voted", "is_question_comment_voted", "is_game_list_voted"])
var isCommentVoted: Boolean = false, // 是否已经点赞过当前评论
@SerializedName("is_version_requested")
@@ -116,7 +116,9 @@ class MeEntity(@SerializedName("is_community_voted")
var questionDraft: QuestionDraftEntity? = null,//问题详情可能返回草稿
@SerializedName("is_follow_bbs")
- var isFollowForum: Boolean = false
+ var isFollowForum: Boolean = false,
+
+ var vote: Boolean = false
) : Parcelable
@Parcelize
diff --git a/app/src/main/java/com/gh/gamecenter/entity/MessageEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/MessageEntity.kt
index e9b4d33af9..d1f03036fb 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/MessageEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/MessageEntity.kt
@@ -24,6 +24,9 @@ class MessageEntity {
var answer: Answer = Answer()
+ @SerializedName("game_list")
+ var gameList: GameList = GameList()
+
var type: String = ""
var read: Boolean = true // true:已读,false:未读
@@ -60,7 +63,7 @@ class MessageEntity {
title = parcel.readString()
thumb = parcel.readString()
communityId = parcel.readString()
- images = parcel.createStringArrayList()?: arrayListOf()
+ images = parcel.createStringArrayList() ?: arrayListOf()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
@@ -102,7 +105,7 @@ class MessageEntity {
constructor(parcel: Parcel) : this() {
id = parcel.readString()
content = parcel.readString()
- images = parcel.createStringArrayList()?: arrayListOf()
+ images = parcel.createStringArrayList() ?: arrayListOf()
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
@@ -170,7 +173,7 @@ class MessageEntity {
@SerializedName("_id")
var id: String? = null
- @SerializedName("top_id")
+ @SerializedName("top_id", alternate = ["parent_id"])
var topId: String? = null
var content: String? = null
@@ -216,4 +219,11 @@ class MessageEntity {
var urlComment: String? = null
}
+ class GameList {
+ @SerializedName("_id")
+ var id: String = ""
+ var cover: String = ""
+ var title: String = ""
+ }
+
}
diff --git a/app/src/main/java/com/gh/gamecenter/entity/ForumShareEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/NormalShareEntity.kt
similarity index 93%
rename from app/src/main/java/com/gh/gamecenter/entity/ForumShareEntity.kt
rename to app/src/main/java/com/gh/gamecenter/entity/NormalShareEntity.kt
index fda128ebcb..0f5f4c4b2b 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/ForumShareEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/NormalShareEntity.kt
@@ -5,7 +5,7 @@ import com.gh.common.util.ShareUtils
import kotlinx.android.parcel.Parcelize
@Parcelize
-data class ForumShareEntity(
+data class NormalShareEntity(
var id: String = "",
var shareUrl: String = "",
var shareIcon: String = "",
diff --git a/app/src/main/java/com/gh/gamecenter/entity/PersonalEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/PersonalEntity.kt
index 95755b0233..bc6cc27ee8 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/PersonalEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/PersonalEntity.kt
@@ -40,6 +40,8 @@ data class PersonalEntity(
@SerializedName("game_comment")
val gameComment: Int = 0,
val video: Int = 0,
+ @SerializedName("game_list")
+ val gameList: Int = 0,
@SerializedName("today_visit")
val todayVisit: Int? = 0) : Parcelable {
diff --git a/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt
index ea5538ddd5..6fa025e7b1 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/SubjectEntity.kt
@@ -30,6 +30,9 @@ data class SubjectEntity(
@SerializedName("common_collection_content")
var commonCollectionList: MutableList? = null,
+ @SerializedName("game_list_collection")
+ var gameListCollection: List? = null,
+
@SerializedName("show_name")
var showName: Boolean = true, // 是否显示“专题名字”,true、false
@SerializedName("show_suffix")
diff --git a/app/src/main/java/com/gh/gamecenter/entity/TagInfoEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/TagInfoEntity.kt
new file mode 100644
index 0000000000..f4c3e67bb0
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/entity/TagInfoEntity.kt
@@ -0,0 +1,12 @@
+package com.gh.gamecenter.entity
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.android.parcel.Parcelize
+
+@Parcelize
+data class TagInfoEntity(
+ @SerializedName("_id")
+ var id: String = "",
+ var name: String = ""
+) : Parcelable
diff --git a/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperFragment.kt b/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperFragment.kt
index 8164293b66..f0ad72c3e2 100644
--- a/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperFragment.kt
@@ -26,6 +26,7 @@ import com.gh.gamecenter.entity.SubjectRecommendEntity
import com.gh.gamecenter.game.GameFragment
import com.gh.gamecenter.game.columncollection.detail.ColumnCollectionDetailFragment
import com.gh.gamecenter.game.commoncollection.detail.CommonCollectionDetailFragment
+import com.gh.gamecenter.gamecollection.square.GameCollectionSquareFragment
import com.gh.gamecenter.home.HomeFragment
import com.gh.gamecenter.servers.GameServersPublishFragment
import com.gh.gamecenter.servers.GameServersTestFragment
@@ -384,7 +385,7 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
private fun generateFragments(tabList: ArrayList): ArrayList {
val fragmentList = arrayListOf()
- for (tab in tabList) {
+ for ((index, tab) in tabList.withIndex()) {
val fragment = when (tab.type) {
"home" -> HomeFragment().with(Bundle())
"top_game_comment" -> AmwayFragment().with(Bundle())
@@ -392,6 +393,11 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
putParcelable(EntranceUtils.KEY_BLOCK_DATA, tab)
})
"server" -> GameServersPublishFragment().with(Bundle())
+ "game_list" -> GameCollectionSquareFragment().with(Bundle().apply {
+ putString(EntranceUtils.KEY_ENTRANCE, "顶部tab")
+ putInt(EntranceUtils.KEY_TAB_INDEX, index)
+ putString(EntranceUtils.KEY_NAME, tab.name)
+ })
"column_test" -> GameServersTestFragment().with(Bundle().apply {
putString(GameServersTestFragment.TEST_COLUMN_ID, tab.link)
})
diff --git a/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt
index fdafb07946..83ae9a52b2 100644
--- a/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt
@@ -49,6 +49,7 @@ import com.gh.gamecenter.game.vertical.GameVerticalAdapter
import com.gh.gamecenter.game.vertical.GameVerticalSlideViewHolder
import com.gh.gamecenter.game.vertical.OnPagerSnapScrollListener
import com.gh.gamecenter.home.BlankDividerViewHolder
+import com.gh.gamecenter.home.gamecollection.HomeGameCollectionViewHolder
import com.gh.gamecenter.servers.GameServersActivity
import com.gh.gamecenter.subject.SubjectActivity
import com.lightgame.adapter.BaseRecyclerAdapter
@@ -102,6 +103,8 @@ class GameFragmentAdapter(
if (itemData.gallerySlide != null) return ItemViewType.GALLERY_SLIDE
if (itemData.blankDivider != null) return ItemViewType.BLANK_DIVIDER
if (itemData.rankCollection != null) return ItemViewType.RANK_COLLECTION
+ if (itemData.gameCollection != null) return ItemViewType.GAME_COLLECTION_ITEM
+
return ItemViewType.LOADING
}
@@ -182,6 +185,9 @@ class GameFragmentAdapter(
ItemViewType.RANK_COLLECTION -> {
RankCollectionViewHolder(RankCollectionListBinding.bind(mLayoutInflater.inflate(R.layout.rank_collection_list, parent, false)))
}
+ ItemViewType.GAME_COLLECTION_ITEM -> {
+ HomeGameCollectionViewHolder(HomeGameCollectionItemBinding.bind(mLayoutInflater.inflate(R.layout.home_game_collection_item, parent, false)))
+ }
else -> GameItemViewHolder(GameItemBinding.bind(mLayoutInflater.inflate(R.layout.game_item, parent, false)))
}
}
@@ -203,6 +209,7 @@ class GameFragmentAdapter(
is BlankDividerViewHolder -> holder.bindView(mItemDataList[position].blankDivider!!)
is CommonCollectionViewHolder -> bindCommonCollection(holder, position)
is RankCollectionViewHolder -> bindRankCollection(holder, position)
+ is HomeGameCollectionViewHolder -> bindGameCollection(holder, position)
}
}
@@ -830,6 +837,9 @@ class GameFragmentAdapter(
blockData?.name ?: ""
)
}
+ "game_list_collection" -> {
+ DirectUtils.directToGameCollectionSquare(mContext, "版块内容列表", column.name ?: "")
+ }
else -> {
if (column.indexRightTopLink != null) {
val link = column.indexRightTopLink!!
@@ -859,6 +869,45 @@ class GameFragmentAdapter(
}
}
+ private fun bindGameCollection(holder: HomeGameCollectionViewHolder, position: Int) {
+ val gameItemData = mItemDataList[position]
+ val gameCollectionItemDataList = gameItemData.gameCollection?: listOf()
+
+ val exposureList = arrayListOf()
+ for (gameCollectionItemData in gameCollectionItemDataList) {
+ runOnIoThread(true) {
+ val gameCollection = gameCollectionItemData.gameCollectionItem
+ val gameCollectionSource = listOf(ExposureSource("游戏单", "${gameCollection?.title} + ${gameCollection?.id}"))
+ val gameExposureList = arrayListOf()
+ gameCollection?.games?.get(0)?.let {
+ gameExposureList.add(ExposureEvent.createEventWithSourceConcat(
+ gameEntity = it.toGameEntity().apply { outerSequence = position; sequence = gameCollectionItemData.gameStartPosition + 1 },
+ basicSource = mBasicExposureSource,
+ source = gameCollectionSource
+ ))
+ }
+ gameCollection?.games?.get(1)?.let {
+ gameExposureList.add(ExposureEvent.createEventWithSourceConcat(
+ gameEntity = it.toGameEntity().apply { outerSequence = position; sequence = gameCollectionItemData.gameStartPosition + 2 },
+ basicSource = mBasicExposureSource,
+ source = gameCollectionSource
+ ))
+ }
+ gameCollection?.games?.get(2)?.let {
+ gameExposureList.add(ExposureEvent.createEventWithSourceConcat(
+ gameEntity = it.toGameEntity().apply { outerSequence = position; sequence = gameCollectionItemData.gameStartPosition + 3 },
+ basicSource = mBasicExposureSource,
+ source = gameCollectionSource
+ ))
+ }
+ gameCollectionItemData.exposureEventList = gameExposureList
+ exposureList.addAll(gameExposureList)
+ }
+ }
+ gameItemData.exposureEventList = exposureList
+ holder.bindGameCollectionList(gameCollectionItemDataList, "版块内容列表")
+ }
+
override fun getItemCount(): Int {
return if (mItemDataList.size > 0) mItemDataList.size + 1 else mItemDataList.size
}
diff --git a/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt b/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt
index 6e7ed1e383..70ff0fd055 100644
--- a/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt
@@ -14,6 +14,7 @@ import com.gh.gamecenter.baselist.LoadStatus
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.game.data.GameItemData
import com.gh.gamecenter.game.data.GameSubjectData
+import com.gh.gamecenter.gamecollection.square.GameCollectionListItemData
import com.gh.gamecenter.home.BlankDividerViewHolder
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.Response
@@ -650,6 +651,23 @@ class GameViewModel(application: Application, var blockData: SubjectRecommendEnt
}
}
+ if (subjectEntity.type == "game_list_collection") {
+ val gameCollectionItem = GameItemData()
+ val itemDataList = arrayListOf().apply {
+ if (!subjectEntity.gameListCollection.isNullOrEmpty()) {
+ var position = 0
+ for (item in subjectEntity.gameListCollection!!) {
+ add(GameCollectionListItemData(gameCollectionItem = item, gameStartPosition = position))
+ position += if (item.count?.game!! > 2) 3 else item.count?.game ?: 0
+ }
+ }
+ }
+ gameCollectionItem.gameCollection = itemDataList
+ appendAdditionalInfoToSubjectGame(subjectEntity, index)
+ mItemDataListCache.add(gameCollectionItem)
+ continue
+ }
+
appendAdditionalInfoToSubjectGame(subjectEntity, index)
}
diff --git a/app/src/main/java/com/gh/gamecenter/game/data/GameItemData.kt b/app/src/main/java/com/gh/gamecenter/game/data/GameItemData.kt
index 26063dc792..7b6bfcfb11 100644
--- a/app/src/main/java/com/gh/gamecenter/game/data/GameItemData.kt
+++ b/app/src/main/java/com/gh/gamecenter/game/data/GameItemData.kt
@@ -5,6 +5,7 @@ import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.LinkEntity
import com.gh.gamecenter.entity.SubjectEntity
import com.gh.gamecenter.entity.SubjectRecommendEntity
+import com.gh.gamecenter.gamecollection.square.GameCollectionListItemData
class GameItemData {
var game: GameEntity? = null
@@ -24,6 +25,8 @@ class GameItemData {
var rankCollection: SubjectEntity? = null
+ var gameCollection: List? = null
+
var blankDivider: Float? = null // 空白的空间补全item
var exposureEvent: ExposureEvent? = null
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/choose/AddGamesActivity.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/AddGamesActivity.kt
new file mode 100644
index 0000000000..09a979b0d0
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/AddGamesActivity.kt
@@ -0,0 +1,19 @@
+package com.gh.gamecenter.gamecollection.choose
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import com.gh.gamecenter.NormalActivity
+
+class AddGamesActivity : NormalActivity() {
+
+ override fun provideNormalIntent(): Intent {
+ return getTargetIntent(this, AddGamesActivity::class.java, AddGamesFragment::class.java)
+ }
+
+ companion object {
+ fun getIntent(context: Context): Intent {
+ return getTargetIntent(context, AddGamesActivity::class.java, AddGamesFragment::class.java)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/choose/AddGamesFragment.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/AddGamesFragment.kt
new file mode 100644
index 0000000000..b994ba2dfa
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/AddGamesFragment.kt
@@ -0,0 +1,19 @@
+package com.gh.gamecenter.gamecollection.choose
+
+import androidx.core.os.bundleOf
+import androidx.fragment.app.Fragment
+import com.gh.base.fragment.BaseLazyTabFragment
+import com.gh.common.util.EntranceUtils
+
+class AddGamesFragment : BaseLazyTabFragment() {
+
+ override fun initFragmentList(fragments: MutableList) {
+ fragments.add(AddSearchGameFragment().apply { bundleOf(EntranceUtils.KEY_NAVIGATION_TITLE to "添加游戏") })
+ fragments.add(AddUserPlayedGameFragment())
+ }
+
+ override fun initTabTitleList(tabTitleList: MutableList) {
+ tabTitleList.add("搜索游戏")
+ tabTitleList.add("玩过游戏")
+ }
+}
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/choose/AddSearchAndPlayedGameAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/AddSearchAndPlayedGameAdapter.kt
new file mode 100644
index 0000000000..3864f12d74
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/AddSearchAndPlayedGameAdapter.kt
@@ -0,0 +1,44 @@
+package com.gh.gamecenter.gamecollection.choose
+
+import android.content.Context
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.util.ToastUtils
+import com.gh.common.util.toColor
+import com.gh.common.util.toDrawable
+import com.gh.gamecenter.R
+import com.gh.gamecenter.game.GameItemViewHolder
+import com.gh.gamecenter.qa.editor.GameAdapter
+
+class AddSearchAndPlayedGameAdapter(context: Context, val mChooseGamesViewModel: ChooseGamesViewModel) : GameAdapter(context) {
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ if (holder is GameItemViewHolder) {
+ val entity = mEntityList[position]
+ val isSelected = mChooseGamesViewModel.chooseGamesLiveData.value?.find { it.id == entity.id } != null
+ holder.binding.game = entity
+ holder.binding.downloadBtn.text = if (isSelected) "删除" else "添加"
+ holder.binding.downloadBtn.background =
+ if (isSelected) R.drawable.bg_shape_f5_radius_999.toDrawable() else R.drawable.download_button_normal_style.toDrawable()
+ holder.binding.downloadBtn.setTextColor(if (isSelected) R.color.text_999999.toColor() else R.color.white.toColor())
+
+ holder.binding.downloadBtn.setOnClickListener {
+ val chooseGameList = mChooseGamesViewModel.chooseGamesLiveData.value ?: arrayListOf()
+ if (isSelected) {
+ chooseGameList.remove(chooseGameList.find { it.id == entity.id })
+ ToastUtils.showToast("游戏已移除")
+ } else {
+ if (chooseGameList.size >= 100) {
+ ToastUtils.showToast("已添加游戏到达上限")
+ return@setOnClickListener
+ }
+ chooseGameList.add(entity)
+ ToastUtils.showToast("游戏已添加")
+ }
+ notifyItemChanged(position)
+ mChooseGamesViewModel.chooseGamesLiveData.postValue(chooseGameList)
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/choose/AddSearchGameFragment.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/AddSearchGameFragment.kt
new file mode 100644
index 0000000000..a1799ffd54
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/AddSearchGameFragment.kt
@@ -0,0 +1,59 @@
+package com.gh.gamecenter.gamecollection.choose
+
+import android.os.Bundle
+import android.view.View
+import androidx.core.widget.doOnTextChanged
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.util.goneIf
+import com.gh.common.util.viewModelProvider
+import com.gh.gamecenter.R
+import com.gh.gamecenter.SuggestionActivity
+import com.gh.gamecenter.databinding.FragmentSearchGameBinding
+import com.gh.gamecenter.qa.editor.GameAdapter
+import com.gh.gamecenter.qa.editor.GameFragment
+import com.gh.gamecenter.suggest.SuggestType
+
+class AddSearchGameFragment : GameFragment() {
+
+ private lateinit var mBinding: FragmentSearchGameBinding
+ private lateinit var mChooseGamesViewModel: ChooseGamesViewModel
+
+ override fun getLayoutId(): Int = 0
+
+ override fun getInflatedLayout(): View {
+ return FragmentSearchGameBinding.inflate(layoutInflater, null, false).apply {
+ mBinding = this
+ }.root
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ mChooseGamesViewModel = viewModelProvider(ChooseGamesViewModel.Factory())
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ setNavigationTitle("添加游戏")
+ noneText.text = "没有找到相关游戏,换个搜索词试试?"
+ searchEt.doOnTextChanged { text, _, _, _ ->
+ mBinding.promptTv.goneIf(!text.isNullOrEmpty())
+ }
+
+ mBinding.applyGameTv.setOnClickListener {
+ SuggestionActivity.startSuggestionActivity(requireContext(), SuggestType.gameCollect, "【游戏单添加游戏】")
+ }
+ }
+
+ override fun getItemDecoration(): RecyclerView.ItemDecoration? {
+ return null
+ }
+
+ override fun provideListAdapter(): GameAdapter? {
+ if (mAdapter == null) {
+ mAdapter = AddSearchAndPlayedGameAdapter(requireContext(), mChooseGamesViewModel)
+ }
+ return mAdapter
+ }
+
+ override fun isAutoShowKeyboard(): Boolean = false
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/choose/AddUserPlayedGameFragment.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/AddUserPlayedGameFragment.kt
new file mode 100644
index 0000000000..c2801c2e23
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/AddUserPlayedGameFragment.kt
@@ -0,0 +1,51 @@
+package com.gh.gamecenter.gamecollection.choose
+
+import android.os.Bundle
+import android.view.View
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.util.EntranceUtils
+import com.gh.common.util.toColor
+import com.gh.common.util.viewModelProvider
+import com.gh.gamecenter.R
+import com.gh.gamecenter.baselist.ListAdapter
+import com.gh.gamecenter.baselist.ListFragment
+import com.gh.gamecenter.entity.GameEntity
+import com.gh.gamecenter.manager.UserManager
+import com.gh.gamecenter.mygame.PlayedGameViewModel
+import com.gh.gamecenter.qa.editor.GameAdapter
+
+class AddUserPlayedGameFragment : ListFragment() {
+
+ private var mAdapter: GameAdapter? = null
+ private lateinit var mViewModel: PlayedGameViewModel
+ private lateinit var mChooseGamesViewModel: ChooseGamesViewModel
+
+ override fun getLayoutId(): Int = R.layout.fragment_add_user_played_game
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ mChooseGamesViewModel = viewModelProvider(ChooseGamesViewModel.Factory())
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ mCachedView.setBackgroundColor(R.color.white.toColor())
+ }
+
+ override fun provideListAdapter(): ListAdapter {
+ return mAdapter ?: AddSearchAndPlayedGameAdapter(requireContext(), mChooseGamesViewModel).apply {
+ mAdapter = this
+ }
+ }
+
+ override fun getItemDecoration(): RecyclerView.ItemDecoration? {
+ return null
+ }
+
+ override fun provideListViewModel(): PlayedGameViewModel {
+ val userId = arguments?.getString(EntranceUtils.KEY_USER_ID)
+ ?: UserManager.getInstance().userId
+ mViewModel = viewModelProvider(PlayedGameViewModel.Factory(userId, true))
+ return mViewModel
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/choose/ChooseGamesActivity.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/ChooseGamesActivity.kt
new file mode 100644
index 0000000000..0769fa62a5
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/ChooseGamesActivity.kt
@@ -0,0 +1,23 @@
+package com.gh.gamecenter.gamecollection.choose
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import com.gh.gamecenter.NormalActivity
+
+class ChooseGamesActivity : NormalActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setNavigationTitle("选择游戏")
+ }
+
+ override fun provideNormalIntent(): Intent {
+ return getTargetIntent(this, ChooseGamesActivity::class.java, ChooseGamesFragment::class.java)
+ }
+
+ companion object {
+ fun getIntent(context: Context): Intent {
+ return getTargetIntent(context, ChooseGamesActivity::class.java, ChooseGamesFragment::class.java)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/choose/ChooseGamesAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/ChooseGamesAdapter.kt
new file mode 100644
index 0000000000..5deb3cccf1
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/ChooseGamesAdapter.kt
@@ -0,0 +1,93 @@
+package com.gh.gamecenter.gamecollection.choose
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.view.MotionEvent
+import android.view.ViewGroup
+import androidx.core.widget.doOnTextChanged
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.base.BaseRecyclerViewHolder
+import com.gh.common.util.PatternUtils
+import com.gh.common.util.TextHelper
+import com.gh.common.util.consume
+import com.gh.common.util.toBinding
+import com.gh.gamecenter.baselist.ListAdapter
+import com.gh.gamecenter.databinding.ItemChooseGamesBinding
+import com.gh.gamecenter.entity.GameEntity
+import com.lightgame.adapter.BaseRecyclerAdapter
+
+class ChooseGamesAdapter(context: Context, val dragListener: ItemDragListener) :
+ ListAdapter(context) {
+
+
+ public override fun setListData(updateData: MutableList?) {
+ super.setListData(updateData)
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ return ChooseGamesViewHolder(parent.toBinding())
+ }
+
+ override fun areItemsTheSame(oldItem: GameEntity?, newItem: GameEntity?): Boolean {
+ return oldItem == newItem
+ }
+
+ override fun areContentsTheSame(oldItem: GameEntity?, newItem: GameEntity?): Boolean {
+ return oldItem?.id == newItem?.id
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ if (holder is ChooseGamesViewHolder) {
+ val gameEntity = mEntityList[position]
+ holder.binding.recommendReasonEt.run {
+ doOnTextChanged { text, start, _, _ ->
+ if(PatternUtils.isHasWrap(text.toString())){
+ setText(PatternUtils.replaceWrap(text.toString()))
+ setSelection(start)
+ return@doOnTextChanged
+ }
+ if (PatternUtils.isHasSpace(text.toString())) {
+ setText(PatternUtils.replaceSpace(text.toString()))
+ setSelection(start)
+ return@doOnTextChanged
+ }
+ }
+ }
+ holder.binding.gameNameTv.text = gameEntity.name
+ holder.binding.gameIcon.displayGameIcon(gameEntity)
+ holder.binding.recommendReasonEt.setText(gameEntity.recommendText)
+ holder.binding.ratingScore.rating = gameEntity.recommendStar.toFloat()
+ holder.binding.recommendReasonEt.filters = arrayOf(TextHelper.getFilter(45, "最多输入45个字"))
+ holder.binding.recommendReasonEt.doOnTextChanged { text, _, _, _ ->
+ gameEntity.recommendText = text.toString()
+ }
+ holder.binding.ratingScore.setOnRatingChangeListener { _, rating ->
+ gameEntity.recommendStar = rating.toInt()
+ }
+ holder.binding.deleteIv.setOnClickListener {
+ dragListener.deleteItem(gameEntity)
+ }
+ holder.binding.dragView.setOnTouchListener { _, event ->
+ consume {
+ if (event.action == MotionEvent.ACTION_DOWN) {
+ dragListener.startDragItem(holder)
+ }
+ }
+ }
+ holder.binding.topView.setOnClickListener {
+ dragListener.setToTop(holder)
+ }
+ }
+ }
+
+ override fun getItemCount(): Int = mEntityList.size
+
+ class ChooseGamesViewHolder(val binding: ItemChooseGamesBinding) : BaseRecyclerViewHolder(binding.root)
+
+ interface ItemDragListener {
+ fun startDragItem(holder: RecyclerView.ViewHolder)
+ fun setToTop(holder: RecyclerView.ViewHolder)
+ fun deleteItem(entity: GameEntity)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/choose/ChooseGamesFragment.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/ChooseGamesFragment.kt
new file mode 100644
index 0000000000..ee4cf9d765
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/ChooseGamesFragment.kt
@@ -0,0 +1,141 @@
+package com.gh.gamecenter.gamecollection.choose
+
+import android.os.Bundle
+import android.view.MenuItem
+import android.view.View
+import androidx.recyclerview.widget.ItemTouchHelper
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.util.DialogHelper
+import com.gh.common.util.goneIf
+import com.gh.common.util.viewModelProvider
+import com.gh.gamecenter.R
+import com.gh.gamecenter.databinding.FragmentChooseGamesBinding
+import com.gh.gamecenter.entity.GameEntity
+import com.gh.gamecenter.normal.NormalFragment
+import java.lang.ref.WeakReference
+import java.util.*
+
+class ChooseGamesFragment : NormalFragment(), ChooseGamesAdapter.ItemDragListener {
+
+ private lateinit var mBinding: FragmentChooseGamesBinding
+ private lateinit var mViewModel: ChooseGamesViewModel
+ private lateinit var mAdapter: ChooseGamesAdapter
+
+ private val mItemTouchCallback = CustomItemTouchHelper(this)
+ private val mItemTouchHelper = ItemTouchHelper(mItemTouchCallback)
+
+ override fun getLayoutId(): Int = 0
+
+ override fun getInflatedLayout(): View {
+ return FragmentChooseGamesBinding.inflate(layoutInflater, null, false).apply {
+ mBinding = this
+ }.root
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ initMenu(R.menu.menu_save)
+ mViewModel = viewModelProvider(ChooseGamesViewModel.Factory())
+ }
+
+ override fun onMenuItemClick(menuItem: MenuItem?) {
+ super.onMenuItemClick(menuItem)
+ menuItem?.run {
+ if (itemId == R.id.layout_menu_save) {
+ requireActivity().finish()
+ }
+ }
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ mViewModel.chooseGamesLiveData.observe(viewLifecycleOwner) {
+ mBinding.addGamesTv.goneIf(it.isNotEmpty())
+ mBinding.gamesRv.goneIf(it.isEmpty())
+ mAdapter.setListData(it)
+ mBinding.gameCountTv.text = "已收录${it.size}款游戏"
+ }
+ mBinding.gamesRv.apply {
+ layoutManager = LinearLayoutManager(requireContext())
+ adapter = ChooseGamesAdapter(requireContext(), this@ChooseGamesFragment).apply {
+ mAdapter = this
+ }
+ mItemTouchHelper.attachToRecyclerView(this)
+ }
+
+ mBinding.addGamesButton.setOnClickListener {
+ requireContext().startActivity(AddGamesActivity.getIntent(requireContext()))
+ }
+
+ mBinding.addGamesTv.setOnClickListener { mBinding.addGamesButton.performClick() }
+
+ }
+
+ override fun startDragItem(holder: RecyclerView.ViewHolder) {
+ mItemTouchHelper.startDrag(holder)
+ }
+
+ override fun setToTop(holder: RecyclerView.ViewHolder) {
+ val holderPosition = holder.bindingAdapterPosition
+ for (i in holderPosition downTo 1) {
+ mAdapter.notifyItemMoved(i, i - 1)
+ Collections.swap(mAdapter.entityList, i, i - 1)
+ val games = mViewModel.chooseGamesLiveData.value ?: arrayListOf()
+ Collections.swap(games, i, i - 1)
+ }
+ }
+
+ override fun deleteItem(entity: GameEntity) {
+ val chooseGames = mViewModel.chooseGamesLiveData.value
+ chooseGames?.remove(entity)
+ mViewModel.chooseGamesLiveData.postValue(chooseGames)
+ }
+
+ override fun onBackPressed(): Boolean {
+ val games = mViewModel.chooseGamesLiveData.value ?: arrayListOf()
+ if (games.isNotEmpty()) {
+ DialogHelper.showDialog(requireContext(), "提示", "是否保存本次选择的游戏", "保存", "取消", {
+ requireActivity().finish()
+ }, {
+ mViewModel.chooseGamesLiveData.postValue(arrayListOf())
+ requireActivity().finish()
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
+ return true
+ }
+ return super.onBackPressed()
+ }
+
+ class CustomItemTouchHelper(val fragment: ChooseGamesFragment) : ItemTouchHelper.Callback() {
+
+ var fragmentReference: WeakReference = WeakReference(fragment)
+
+ override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
+ return makeMovementFlags(ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0)
+ }
+
+ override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
+ val fragment = fragmentReference.get()
+ fragment?.run {
+ mAdapter.notifyItemMoved(viewHolder.bindingAdapterPosition, target.bindingAdapterPosition)
+ Collections.swap(mAdapter.entityList, viewHolder.bindingAdapterPosition, target.bindingAdapterPosition)
+ val games = mViewModel.chooseGamesLiveData.value ?: arrayListOf()
+ Collections.swap(games, viewHolder.bindingAdapterPosition, target.bindingAdapterPosition)
+ }
+ return true
+ }
+
+ override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
+
+ }
+
+ override fun canDropOver(recyclerView: RecyclerView, current: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
+ return true
+ }
+
+ override fun isLongPressDragEnabled(): Boolean {
+ return false
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/choose/ChooseGamesRepository.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/ChooseGamesRepository.kt
new file mode 100644
index 0000000000..4ccdd3d248
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/ChooseGamesRepository.kt
@@ -0,0 +1,12 @@
+package com.gh.gamecenter.gamecollection.choose
+
+import androidx.lifecycle.MutableLiveData
+import com.gh.common.util.SingletonHolder
+import com.gh.gamecenter.entity.GameEntity
+
+class ChooseGamesRepository private constructor() {
+
+ val chooseGamesLiveData: MutableLiveData> = MutableLiveData()
+
+ companion object : SingletonHolder(::ChooseGamesRepository)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/choose/ChooseGamesViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/ChooseGamesViewModel.kt
new file mode 100644
index 0000000000..3822a7e5d1
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/choose/ChooseGamesViewModel.kt
@@ -0,0 +1,21 @@
+package com.gh.gamecenter.gamecollection.choose
+
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.halo.assistant.HaloApp
+
+class ChooseGamesViewModel(application: Application, repository: ChooseGamesRepository) : AndroidViewModel(application) {
+
+ val chooseGamesLiveData = repository.chooseGamesLiveData
+
+ class Factory : ViewModelProvider.NewInstanceFactory() {
+ override fun create(modelClass: Class): T {
+ return ChooseGamesViewModel(
+ HaloApp.getInstance().application,
+ ChooseGamesRepository.getInstance()
+ ) as T
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailActivity.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailActivity.kt
new file mode 100644
index 0000000000..8298502af8
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailActivity.kt
@@ -0,0 +1,38 @@
+package com.gh.gamecenter.gamecollection.detail
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import com.gh.common.util.DisplayUtils
+import com.gh.common.util.EntranceUtils
+import com.gh.gamecenter.NormalActivity
+import com.gh.gamecenter.R
+
+class GameCollectionDetailActivity : NormalActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ hideToolbar(true)
+ DisplayUtils.setStatusBarColor(this, R.color.transparent, false)
+ }
+
+ override fun provideNormalIntent(): Intent {
+ return getTargetIntent(this, GameCollectionDetailActivity::class.java, GameCollectionDetailFragment::class.java)
+ }
+
+ companion object {
+ @JvmStatic
+ fun getIntent(context: Context, gameCollectionId: String, isFromSquare: Boolean = false): Intent {
+ return getIntent(context, gameCollectionId, isFromSquare, false)
+ }
+
+ @JvmStatic
+ fun getIntent(context: Context, gameCollectionId: String, isFromSquare: Boolean = false, isScrollToCommentArea: Boolean = false): Intent {
+ val bundle = Bundle()
+ bundle.putString(EntranceUtils.KEY_GAME_COLLECTION_ID, gameCollectionId)
+ bundle.putBoolean(EntranceUtils.KEY_IS_FROM_SQUARE, isFromSquare)
+ bundle.putBoolean(EntranceUtils.KEY_SCROLL_TO_COMMENT_AREA, isScrollToCommentArea)
+ return getTargetIntent(context, GameCollectionDetailActivity::class.java, GameCollectionDetailFragment::class.java, bundle)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailAdapter.kt
new file mode 100644
index 0000000000..975dae3ae2
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailAdapter.kt
@@ -0,0 +1,552 @@
+package com.gh.gamecenter.gamecollection.detail
+
+import android.content.Context
+import android.text.SpannableStringBuilder
+import android.text.TextUtils
+import android.util.SparseArray
+import android.view.View
+import android.view.ViewGroup
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.exposure.ExposureEvent
+import com.gh.common.exposure.ExposureSource
+import com.gh.common.exposure.ExposureType
+import com.gh.common.exposure.IExposable
+import com.gh.common.syncpage.SyncDataEntity
+import com.gh.common.syncpage.SyncFieldConstants
+import com.gh.common.syncpage.SyncPageRepository
+import com.gh.common.util.*
+import com.gh.common.view.GridSpacingItemColorDecoration
+import com.gh.gamecenter.GameDetailActivity
+import com.gh.gamecenter.R
+import com.gh.gamecenter.databinding.GameCollectionGameItemBinding
+import com.gh.gamecenter.databinding.ItemArticleDetailCommentBinding
+import com.gh.gamecenter.entity.CommentEntity
+import com.gh.gamecenter.entity.GameEntity
+import com.gh.gamecenter.eventbus.EBDownloadStatus
+import com.gh.gamecenter.gamecollection.detail.conversation.GameCollectionCommentConversationAdapter
+import com.gh.gamecenter.qa.article.detail.CommentItemData
+import com.gh.gamecenter.qa.comment.CommentActivity
+import com.gh.gamecenter.qa.comment.CommentPictureAdapter
+import com.gh.gamecenter.qa.comment.OnCommentOptionClickListener
+import com.gh.gamecenter.qa.comment.base.BaseCommentAdapter
+import com.lightgame.download.DownloadEntity
+import java.util.ArrayList
+import java.util.HashMap
+
+open class GameCollectionDetailAdapter(
+ context: Context,
+ private val type: AdapterType,
+ private val mEntrance: String,
+ val mViewModel: GameCollectionDetailViewModel,
+ commentClosure: ((CommentEntity) -> Unit)? = null
+) : BaseCommentAdapter(context, mViewModel, type, mEntrance, commentClosure), IExposable {
+
+ val positionAndPackageMap = HashMap()
+ private var mExposureEventArray: SparseArray? = null
+
+ override fun setListData(updateData: MutableList?) {
+ mExposureEventArray = SparseArray(updateData?.size ?: 0)
+ // 记录游戏位置
+ if (updateData != null) {
+ for (i in 0 until updateData.size) {
+ val gameEntity = updateData[i].game
+ if (gameEntity != null) {
+ var packages = gameEntity.id
+ for (apkEntity in gameEntity.getApk()) {
+ packages += apkEntity.packageName
+ }
+ gameEntity.sequence = i
+ positionAndPackageMap[packages + i] = i
+ }
+ }
+ }
+ super.setListData(updateData)
+ }
+
+ override fun getItemViewType(position: Int): Int {
+ val item = mEntityList[position]
+ return when {
+ item.game != null -> ITEM_GAME
+ item.gameEmpty != null -> ITEM_GAME_EMPTY
+ item.divider != null -> ITEM_DIVIDER
+ else -> super.getItemViewType(position)
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ return when (viewType) {
+ ITEM_GAME -> GameCollectionGameItemViewHolder(
+ GameCollectionGameItemBinding.bind(
+ mLayoutInflater.inflate(
+ R.layout.game_collection_game_item,
+ parent,
+ false
+ )
+ )
+ )
+
+ ITEM_GAME_EMPTY -> GameCollectionGameEmptyViewHolder(
+ mLayoutInflater.inflate(
+ R.layout.game_collection_detail_none_game_item,
+ parent,
+ false
+ )
+ )
+
+ ITEM_DIVIDER -> GameCollectionDividerViewHolder(
+ mLayoutInflater.inflate(
+ R.layout.game_collection_detail_divider_item,
+ parent,
+ false
+ )
+ )
+
+ else -> super.onCreateViewHolder(parent, viewType)
+ }
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ when (holder) {
+ is CommentFilterViewHolder -> {
+ holder.bindView(gameCollection = true)
+ }
+
+ is GameCollectionGameItemViewHolder -> {
+ holder.bindView(mEntityList[position].game!!, position)
+ }
+
+ is CommentItemViewHolder -> {
+ bindComment(holder.binding, mEntityList[position].commentNormal!!) { deleteCommentEntity ->
+ val findEntity =
+ mEntityList.find { it.commentNormal != null && it.commentNormal?.id == deleteCommentEntity.id }
+ val index = mEntityList.indexOf(findEntity)
+ mEntityList.remove(findEntity)
+ notifyItemRemoved(index)
+
+ //刷新 ITEM_FILTER
+ mViewModel.commentCount -= 1
+ if (this !is GameCollectionCommentConversationAdapter) {
+ notifyItemChanged(mViewModel.filterPos)
+ }
+
+ mEntityList[0].commentTop?.reply = (mEntityList[0].commentTop?.reply
+ ?: 0) - 1
+ SyncPageRepository.postSyncData(
+ SyncDataEntity(
+ mEntityList[0].commentTop?.id
+ ?: "",
+ SyncFieldConstants.ARTICLE_COMMENT_REPLY_COUNT,
+ mEntityList[0].commentTop?.reply,
+ checkFieldEntity = true
+ )
+ )
+ //刷新评论详情头部
+// notifyItemChanged(0)
+ }
+ }
+
+ is CommentFooterViewHolder -> {
+ holder.bindView(mIsLoading, mIsNetworkError, mIsOver, R.string.game_collection_load_over_hint)
+ }
+
+ else -> super.onBindViewHolder(holder, position)
+ }
+ }
+
+ fun bindComment(
+ binding: ItemArticleDetailCommentBinding,
+ comment: CommentEntity,
+ deleteCallBack: ((comment: CommentEntity) -> Unit)? = null
+ ) {
+ bindNormalComment(binding, comment, deleteCallBack)
+ binding.run {
+ if (type == AdapterType.COMMENT) {
+ // 游戏单详情页面用的样式
+ updateSubComment(this, comment)
+
+ floorHintTv.visibility = View.INVISIBLE
+ bottomDivider.visibility = View.VISIBLE
+
+ root.setOnClickListener {
+ mContext.startActivity(
+ CommentActivity.getGameCollectionCommentReplyIntent(
+ mContext,
+ mViewModel.gameCollectionId,
+ comment.id ?: "",
+ mViewModel.commentCount,
+ comment
+ )
+ )
+ }
+
+ commentCountTv.setOnClickListener {
+ mContext.startActivity(
+ CommentActivity.getGameCollectionCommentDetailIntent(
+ mContext,
+ comment.id ?: "",
+ mViewModel.gameCollectionId,
+ false,
+ mEntrance,
+ "游戏单详情"
+ )
+ )
+ }
+
+ contentTv.text = comment.content
+
+ commentCountTv.text = mViewModel.getCommentText(comment.reply, "回复")
+ } else {
+ // 评论详情用的样式
+ floorHintTv.text = CommentUtils.getCommentTime(comment.time)
+ commentCountTv.setOnClickListener { commentClosure?.invoke(comment) }
+ commentCountTv.setCompoundDrawables(null, null, null, null)
+ commentCountTv.text = "回复"
+ likeCountTv.text = mViewModel.getLikeText(comment.vote, "")
+ root.setOnClickListener { binding.commentCountTv.performClick() }
+
+ if (comment.parentUser != null && !TextUtils.isEmpty(comment.parentUser!!.id) ) {
+ val prefix = "回复"
+ val colon = " :"
+ val parentUserName = " ${comment.parentUser?.name} "
+
+ val prefixSpan = SpanBuilder(prefix).color(
+ binding.root.context,
+ 0,
+ prefix.length,
+ R.color.text_999999
+ ).build()
+ val parentUserNameSpan = SpanBuilder(parentUserName)
+ .bold(0, parentUserName.length)
+ .click(0, parentUserName.length, R.color.text_666666) {
+ DirectUtils.directToHomeActivity(
+ binding.root.context,
+ comment.user.id,
+ 1,
+ mEntrance,
+ PATH_ARTICLE_DETAIL_COMMENT
+ )
+ MtaHelper.onEvent("帖子详情", "引用回复区域", "用户名字")
+ }.build()
+ val colonSpan = SpanBuilder(colon).color(
+ binding.root.context,
+ 0,
+ colon.length,
+ R.color.text_999999
+ ).build()
+ val authorSpan = if (comment.parentUser?.me?.isCommentOwner == true) {
+ SpanBuilder("作者").image(0, "作者".length, R.drawable.ic_hint_author).build()
+ } else {
+ ""
+ }
+
+ contentTv.text = SpannableStringBuilder()
+ .append(prefixSpan)
+ .append(parentUserNameSpan)
+ .append(authorSpan)
+ .append(colonSpan)
+ .append(comment.content)
+ } else {
+ contentTv.text = comment.content
+ }
+ contentTv.maxLines = Int.MAX_VALUE
+ }
+ }
+ }
+
+ fun bindNormalComment(
+ binding: ItemArticleDetailCommentBinding,
+ comment: CommentEntity,
+ deleteCallBack: ((comment: CommentEntity) -> Unit)?
+ ) {
+ binding.run {
+ if (!comment.images.isNullOrEmpty()) {
+ if (commentPictureRv.adapter == null) {
+ commentPictureRv.apply {
+ layoutManager = GridLayoutManager(context, 3)
+ adapter = CommentPictureAdapter(context, comment.images!!, "")
+ if (itemDecorationCount == 0) {
+ addItemDecoration(GridSpacingItemColorDecoration(context, 2, R.color.white))
+ }
+ visibility = View.VISIBLE
+ }
+ } else {
+ (commentPictureRv.adapter as CommentPictureAdapter).checkResetData(comment.images!!)
+ }
+ } else {
+ binding.commentPictureRv.visibility = View.GONE
+ }
+ this.comment = comment
+ contentTv.setExpandMaxLines(if (comment.isExpand) Int.MAX_VALUE else 4)
+ contentTv.setIsExpanded(comment.isExpand)
+ collapseTv.goneIf(!comment.isExpand)
+ contentTv.setExpandCallback {
+ comment.isExpand = true
+ collapseTv.visibility = View.VISIBLE
+ this.comment = comment
+ }
+ collapseTv.setOnClickListener {
+ comment.isExpand = false
+ collapseTv.visibility = View.GONE
+ contentTv.setExpandMaxLines(4)
+ contentTv.setIsExpanded(false)
+ this.comment = comment
+ }
+ userIconIv.display(
+ comment.user.border,
+ comment.user.icon,
+ comment.user.auth?.icon
+ )
+
+ userIconIv.setOnClickListener {
+ DirectUtils.directToHomeActivity(
+ mContext,
+ comment.user.id,
+ "",
+ "游戏单详情-评论"
+ )
+ }
+
+ userNameTv.setOnClickListener {
+ DirectUtils.directToHomeActivity(
+ mContext,
+ comment.user.id,
+ "",
+ "游戏单详情-评论"
+ )
+ }
+
+ likeCountTv.text = mViewModel.getLikeText(comment.vote)
+
+ if (comment.me?.isCommentVoted == true) {
+ likeCountTv.setCompoundDrawablesWithIntrinsicBounds(
+ R.drawable.comment_vote_select,
+ 0,
+ 0,
+ 0
+ )
+ } else {
+ likeCountTv.setCompoundDrawablesWithIntrinsicBounds(
+ R.drawable.comment_vote_unselect,
+ 0,
+ 0,
+ 0
+ )
+ }
+
+ likeCountTv.setDebouncedClickListener {
+ likeCountTv.context.ifLogin("游戏单详情-评论-点赞") {
+ mViewModel.postVoteGameCollectionComment(comment) {
+ likeCountTv.setCompoundDrawablesWithIntrinsicBounds(
+ if (comment.me?.isCommentVoted == true) R.drawable.comment_vote_select else R.drawable.comment_vote_unselect,
+ 0,
+ 0,
+ 0
+ )
+ likeCountTv.text = mViewModel.getLikeText(comment.vote)
+ }
+ }
+ }
+
+ badgeTv.setOnClickListener {
+ DialogUtils.showViewBadgeDialog(mContext, comment.user.badge) {
+ DirectUtils.directToBadgeWall(
+ mContext,
+ comment.user.id,
+ comment.user.name,
+ comment.user.icon
+ )
+ }
+ }
+
+ badgeIv.setOnClickListener { badgeTv.performClick() }
+
+ moreIv.setOnClickListener {
+ CommentHelper.showGameCollectionCommentOption(
+ it,
+ comment,
+ object : OnCommentOptionClickListener {
+ override fun onCommentOptionClick(entity: CommentEntity, option: String) {
+ when (option) {
+ "删除评论" -> {
+ DialogHelper.showDialog(
+ binding.moreIv.context,
+ "提示",
+ "删除评论后,评论下所有的回复都将被删除",
+ "删除",
+ "取消",
+ {
+ mViewModel.deleteComment(comment) {
+ deleteCallBack?.invoke(comment)
+ }
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
+ )
+ }
+ }
+ }
+ }
+ )
+ }
+ }
+ }
+
+ private fun updateSubComment(
+ binding: ItemArticleDetailCommentBinding,
+ comment: CommentEntity,
+ ) {
+ val subCommentList = comment.subCommentList
+ val ownerUserId = mViewModel.ownerUserId
+ binding.moreSubCommentBtn.goneIf(comment.reply < 3)
+ binding.moreSubCommentBtn.text = "查看全部${comment.reply}条回复"
+ binding.subCommentContainer.goneIf(subCommentList.isNullOrEmpty())
+ binding.firstSubCommentTv.goneIf(subCommentList?.firstOrNull() == null)
+ binding.secondSubCommentTv.goneIf(subCommentList?.secondOrNull() == null)
+ binding.subCommentContainer.setRoundedColorBackground(R.color.text_F5F5F5, 5F)
+
+ subCommentList?.firstOrNull()?.let {
+ binding.firstSubCommentTv.text = getSubCommentSpanned(
+ it.user.name,
+ if (it.user.id == ownerUserId) "作者" else "",
+ it.content
+ )
+ }
+ subCommentList?.secondOrNull()?.let {
+ binding.secondSubCommentTv.text = getSubCommentSpanned(
+ it.user.name,
+ if (it.user.id == ownerUserId) "作者" else "",
+ it.content
+ )
+ }
+ binding.subCommentContainer.setOnClickListener {
+ mContext.startActivity(
+ CommentActivity.getGameCollectionCommentDetailIntent(
+ mContext,
+ comment.id ?: "",
+ mViewModel.gameCollectionId,
+ false,
+ mEntrance,
+ "游戏单详情"
+ )
+ )
+ }
+ }
+
+ private fun getSubCommentSpanned(
+ name: String?,
+ author: String?,
+ content: String?
+ ): SpannableStringBuilder {
+ val finalAuthor = author ?: ""
+ val finalName = "$name "
+ val colon = " :"
+
+ val nameSpan =
+ SpanBuilder(finalName).color(0, finalName.length, R.color.theme_font).build()
+ val authorSpan = if (finalAuthor.isNotEmpty()) SpanBuilder(finalAuthor).image(
+ 0,
+ finalAuthor.length,
+ R.drawable.ic_hint_author
+ ).build() else ""
+ val colonSpan = SpanBuilder(colon).color(0, colon.length, R.color.theme_font).build()
+ return SpannableStringBuilder().append(nameSpan).append(authorSpan).append(colonSpan)
+ .append(content)
+ }
+
+ fun notifyItemByDownload(download: DownloadEntity) {
+ for (key in positionAndPackageMap.keys) {
+ if (key.contains(download.packageName) && key.contains(download.gameId)) {
+ val position = positionAndPackageMap[key]
+ if (position != null && mEntityList != null && position < mEntityList.size && mEntityList[position].game != null) {
+ mEntityList[position].game!!.getEntryMap()[download.platform] = download
+ notifyItemChanged(position)
+ }
+ }
+ }
+ }
+
+ fun notifyItemAndRemoveDownload(status: EBDownloadStatus) {
+ for (key in positionAndPackageMap.keys) {
+ if (key.contains(status.packageName) && key.contains(status.gameId)) {
+ val position = positionAndPackageMap[key]
+ if (position != null && mEntityList != null && position < mEntityList.size && mEntityList[position].game != null) {
+ mEntityList[position].game!!.getEntryMap().remove(status.platform)
+ notifyItemChanged(position)
+ }
+ }
+ }
+ }
+
+ inner class GameCollectionGameEmptyViewHolder(view: View): RecyclerView.ViewHolder(view)
+
+ inner class GameCollectionDividerViewHolder(view: View): RecyclerView.ViewHolder(view)
+
+ inner class GameCollectionGameItemViewHolder(val binding: GameCollectionGameItemBinding): RecyclerView.ViewHolder(binding.root) {
+
+ fun bindView(gameEntity: GameEntity, position: Int) {
+ binding.run {
+ game = gameEntity
+ executePendingBindings()
+
+ val exposureSources = ArrayList().apply {
+ add(ExposureSource("首页搜索", "${mViewModel.gameCollectionTitle}+${mViewModel.gameCollectionId}"))
+ }
+ val exposureEvent = ExposureEvent.createEvent(
+ gameEntity,
+ exposureSources,
+ null,
+ ExposureType.EXPOSURE
+ )
+ mExposureEventArray!!.put(position, exposureEvent)
+
+ recommendTv.post {
+ if (!TextUtils.isEmpty(gameEntity.recommendText)) {
+ ConstraintSet().apply {
+ clone(container)
+ clear(recommendTv.id, ConstraintSet.BOTTOM)
+ if (recommendTv.lineCount == 1) {
+ recommendTv.setPadding(0, 0, 0, 0)
+ connect(recommendTv.id, ConstraintSet.BOTTOM, recommendPref.id, ConstraintSet.BOTTOM)
+ } else {
+ recommendTv.setPadding(0, 0, 0, 8F.dip2px())
+ connect(recommendTv.id, ConstraintSet.BOTTOM, container.id, ConstraintSet.BOTTOM)
+ }
+ applyTo(container)
+ }
+ }
+ }
+
+ root.setOnClickListener {
+ GameDetailActivity.startGameDetailActivity(
+ mContext,
+ gameEntity.id,
+ mEntrance,
+ exposureEvent
+ )
+ }
+
+ DownloadItemUtils.setOnClickListener(
+ mContext,
+ binding.downloadBtn,
+ gameEntity,
+ position,
+ this@GameCollectionDetailAdapter,
+ mEntrance,
+ "游戏单详情-游戏列表:${gameEntity.name}",
+ exposureEvent)
+
+ DownloadItemUtils.updateDownloadButton(mContext, downloadBtn, gameEntity, false)
+ }
+ }
+ }
+
+ override fun getEventByPosition(pos: Int): ExposureEvent? = mExposureEventArray!!.get(pos)
+
+ override fun getEventListByPosition(pos: Int): List? = null
+
+ companion object {
+ const val ITEM_GAME = 900
+ const val ITEM_GAME_EMPTY = 901
+ const val ITEM_DIVIDER = 902
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailFragment.kt
new file mode 100644
index 0000000000..8d49061d53
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailFragment.kt
@@ -0,0 +1,883 @@
+package com.gh.gamecenter.gamecollection.detail
+
+import android.app.Activity
+import android.content.Intent
+import android.graphics.Color
+import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewTreeObserver
+import androidx.annotation.ColorRes
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.Lifecycle
+import androidx.recyclerview.widget.RecyclerView
+import butterknife.OnClick
+import com.gh.common.constant.Constants
+import com.gh.common.exposure.ExposureListener
+import com.gh.common.history.HistoryHelper
+import com.gh.common.util.*
+import com.gh.common.xapk.XapkInstaller
+import com.gh.common.xapk.XapkUnzipStatus
+import com.gh.download.DownloadManager
+import com.gh.gamecenter.R
+import com.gh.gamecenter.baselist.ListFragment
+import com.gh.gamecenter.baselist.LoadType
+import com.gh.gamecenter.databinding.FragmentGameCollectionDetailBinding
+import com.gh.gamecenter.databinding.LayoutGameCollectionTagBinding
+import com.gh.gamecenter.entity.*
+import com.gh.gamecenter.eventbus.EBShare
+import com.gh.gamecenter.eventbus.EBUserFollow
+import com.gh.gamecenter.gamedetail.GameDetailFragment
+import com.gh.gamecenter.home.video.ScrollCalculatorHelper
+import com.gh.gamecenter.manager.UserManager
+import com.gh.gamecenter.qa.article.detail.CommentItemData
+import com.gh.gamecenter.qa.comment.CommentActivity
+import com.gh.gamecenter.qa.comment.base.BaseCommentAdapter
+import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel
+import com.gh.gamecenter.setting.VideoSettingFragment
+import com.gh.gamecenter.video.detail.CustomManager
+import com.google.android.material.appbar.AppBarLayout
+import com.lightgame.download.DataWatcher
+import com.lightgame.download.DownloadEntity
+import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
+import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack
+import com.shuyu.gsyvideoplayer.utils.OrientationUtils
+import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
+import kotlinx.android.synthetic.main.item_article_detail_comment.view.*
+import kotlinx.android.synthetic.main.piece_game_detail_video.*
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+import kotlin.math.abs
+
+class GameCollectionDetailFragment :
+ ListFragment() {
+
+ private var mBinding: FragmentGameCollectionDetailBinding? = null
+ private var mAdapter: GameCollectionDetailAdapter? = null
+ private var mEntity: GamesCollectionDetailEntity? = null
+ private var mGameCollectionId = ""
+ private var mGameCollectionTitle = ""
+ private var mScrollToCommentArea = false
+ private var mFromSquare = false
+ private var mIsLight = false
+ private var mIsPauseTopVideo = false
+ private var mOrientationUtils: OrientationUtils? = null
+ private val mDataWatcher = object : DataWatcher() {
+ override fun onDataChanged(downloadEntity: DownloadEntity) {
+ mAdapter?.notifyItemByDownload(downloadEntity)
+
+ if (downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS] == XapkUnzipStatus.FAILURE.name) {
+ showUnzipFailureDialog(downloadEntity)
+ }
+ }
+ }
+
+ override fun getLayoutId() = 0
+
+ override fun getInflatedLayout() =
+ FragmentGameCollectionDetailBinding.inflate(layoutInflater).apply { mBinding = this }.root
+
+ override fun provideListViewModel() =
+ viewModelProvider(GameCollectionDetailViewModel.Factory(mGameCollectionId))
+
+ override fun provideListAdapter() =
+ mAdapter ?: GameCollectionDetailAdapter(requireContext(), BaseCommentAdapter.AdapterType.COMMENT, mEntrance, mListViewModel).apply { mAdapter = this }
+
+ override fun getItemDecoration() = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ mGameCollectionId = arguments?.getString(EntranceUtils.KEY_GAME_COLLECTION_ID) ?: ""
+ mFromSquare = arguments?.getBoolean(EntranceUtils.KEY_IS_FROM_SQUARE, false) ?: false
+ mScrollToCommentArea = arguments?.getBoolean(EntranceUtils.KEY_SCROLL_TO_COMMENT_AREA, false) ?: false
+ super.onCreate(savedInstanceState)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ initView()
+ initObserver()
+ mListViewModel.getGameCollectionDetail()
+
+ mListRv.addOnScrollListener(ExposureListener(this, provideListAdapter()))
+ }
+
+ private fun initView() {
+ mBinding?.run {
+ inputContainer.run {
+ bottomShareGroup.visibility = View.VISIBLE
+ replyTv.setBackgroundResource(R.drawable.button_round_f5f5f5)
+ replyTv.text = "说点什么吧"
+ }
+ fixedTopFilterView.run {
+ (root.layoutParams as ViewGroup.MarginLayoutParams).apply {
+ topMargin = DisplayUtils.getStatusBarHeight(resources) + 48F.dip2px()
+ root.layoutParams = this
+ }
+ filterLatestTv.setOnClickListener {
+ getFilterVH()?.binding?.filterLatestTv?.performClick()
+ updateFilterView()
+ }
+ filterOldestTv.setOnClickListener {
+ getFilterVH()?.binding?.filterOldestTv?.performClick()
+ updateFilterView()
+ }
+ commentHintTv.text = "游戏单评论"
+ filterLatestTv.text = "最新"
+ filterOldestTv.text = "最早"
+ }
+ }
+ }
+
+ private fun initObserver() {
+ mListViewModel.loadResultLiveData.observeNonNull(this) {
+ when (it) {
+ BaseCommentViewModel.LoadResult.SUCCESS -> {
+ mEntity = mListViewModel.gameCollectionDetail
+ mGameCollectionTitle = mListViewModel.gameCollectionDetail?.title ?: ""
+
+ postDelayedRunnable({
+ tryCatchInRelease {
+ logEvent("view_game_collect_detail")
+ }
+ }, 2000)
+
+ updateView()
+ initViewListener()
+ }
+
+ else -> {
+ if (it == BaseCommentViewModel.LoadResult.DELETED) {
+ mReuseNoConn?.visibility = View.GONE
+ mReuseNoData?.visibility = View.VISIBLE
+ toast(R.string.content_delete_toast)
+ } else {
+ mReuseNoConn?.visibility = View.VISIBLE
+ mReuseNoData?.visibility = View.GONE
+ mReuseNoConn?.setOnClickListener {
+ mListViewModel.getGameCollectionDetail()
+ mReuseNoConn?.visibility = View.GONE
+ mBinding?.root?.setBackgroundColor(Color.WHITE)
+ }
+ }
+
+ DisplayUtils.setStatusBarColor(requireActivity(), R.color.white, true)
+ mBinding?.toolbarContainer?.setBackgroundColor(Color.WHITE)
+ mBinding?.backIv?.setImageResource(R.drawable.ic_bar_back)
+
+ mListLoading?.visibility = View.GONE
+ mBinding?.inputContainer?.bottomContainer?.visibility = View.GONE
+ mBinding?.bottomShadowView?.visibility = View.GONE
+ mBinding?.root?.setBackgroundColor(Color.TRANSPARENT)
+ }
+ }
+ }
+
+ mListViewModel.followLiveData.observeNonNull(this) {
+ updateFollowView()
+ }
+
+ mListViewModel.favoriteLiveData.observeNonNull(this) {
+ updateStartView()
+ }
+
+ mListViewModel.likeLiveData.observeNonNull(this) {
+ updateLikeView()
+ }
+
+ mListViewModel.shareLiveData.observeNonNull(this) {
+ updateShareView()
+ }
+ }
+
+ private fun initViewListener() {
+ mBinding?.appbar?.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
+ if (!isAdded) return@OnOffsetChangedListener
+
+ val absVerticalOffset = abs(verticalOffset)
+ mListRefresh?.isEnabled = absVerticalOffset <= 2
+
+ mBinding?.run {
+ val bgOffset = if (mListViewModel.displayTopVideo) {
+ videoItem.player.bottom - DisplayUtils.getStatusBarHeight(resources) - 48F.dip2px()
+ } else {
+ imageItem.root.bottom - DisplayUtils.getStatusBarHeight(resources) - 48F.dip2px()
+ }
+ mIsLight = absVerticalOffset < bgOffset
+ updateFollowView()
+ updateToolbar()
+
+ if (mListViewModel.displayTopVideo) {
+ if (absVerticalOffset == appBarLayout.totalScrollRange
+ && videoItem.player.currentState == GSYVideoView.CURRENT_STATE_PLAYING
+ ) {
+ pauseVideo()
+ mIsPauseTopVideo = true
+ } else if (mIsPauseTopVideo
+ && absVerticalOffset == 0
+ && videoItem.player.currentState == GSYVideoView.CURRENT_STATE_PAUSE
+ ) {
+ resumeVideo()
+ mIsPauseTopVideo = false
+ }
+ }
+ }
+ })
+
+ mListRv?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+ override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+ super.onScrolled(recyclerView, dx, dy)
+ val firstCompletelyVisiblePosition = mLayoutManager.findFirstCompletelyVisibleItemPosition()
+ if (RecyclerView.NO_POSITION == firstCompletelyVisiblePosition) return
+
+ val filterView = mLayoutManager.findViewByPosition(mListViewModel.filterPos)
+
+ if (firstCompletelyVisiblePosition >= mListViewModel.filterPos + 1 && filterView == null) {
+ mBinding?.fixedTopFilterView?.root?.visibility = View.VISIBLE
+ updateFilterView()
+ } else {
+ filterView?.let {
+ if (it.top <= 0 && mBinding?.fixedTopFilterView?.root?.visibility == View.GONE) {
+ mBinding?.fixedTopFilterView?.root?.visibility = View.VISIBLE
+ updateFilterView()
+ } else if (it.top > 0 && mBinding?.fixedTopFilterView?.root?.visibility == View.VISIBLE) {
+ mBinding?.fixedTopFilterView?.root?.visibility = View.GONE
+ }
+ }
+ }
+ }
+ })
+ }
+
+ private fun updateToolbar() {
+ mBinding?.run {
+ if (mIsLight) {
+ DisplayUtils.setStatusBarColor(requireActivity(), R.color.transparent, false)
+ toolbarContainer.setBackgroundColor(Color.TRANSPARENT)
+ backIv.setImageResource(R.drawable.ic_bar_back_light)
+ squareIv.setImageResource(R.drawable.ic_game_collection_square_light)
+ toolbarUserContainer.visibility = View.GONE
+ if (!mListViewModel.displayTopVideo) {
+ toolbarLightUserContainer.visibility = View.VISIBLE
+ }
+ } else {
+ DisplayUtils.setStatusBarColor(requireActivity(), R.color.white, true)
+ toolbarContainer.setBackgroundColor(Color.WHITE)
+ backIv.setImageResource(R.drawable.ic_bar_back)
+ squareIv.setImageResource(R.drawable.ic_game_collection_square)
+ toolbarUserContainer.visibility = View.VISIBLE
+ if (!mListViewModel.displayTopVideo) {
+ toolbarLightUserContainer.visibility = View.GONE
+ }
+ }
+ }
+ }
+
+ private fun updateView() {
+ mReuseNoConn?.visibility = View.GONE
+ mListLoading?.visibility = View.GONE
+
+ scrollToComment()
+
+ initTopView()
+ updateFollowView()
+ updateStartView()
+ updateLikeView()
+ updateShareView()
+
+ mReuseNoConn?.setOnClickListener {
+ mReuseNoConn?.visibility = View.GONE
+ mListLoading?.visibility = View.VISIBLE
+ mListViewModel.getGameCollectionDetail()
+ }
+ }
+
+ private fun scrollToComment() {
+ if (mScrollToCommentArea) {
+ val listener = object : ViewTreeObserver.OnGlobalLayoutListener {
+ override fun onGlobalLayout() {
+ mBinding?.appbar?.setExpanded(false)
+ mLayoutManager?.scrollToPositionWithOffset(mListViewModel?.filterPos ?: 0, 0)
+ if (mListViewModel?.filterPos ?: 0 >= mLayoutManager?.findFirstVisibleItemPosition() ?: 0
+ && mListViewModel?.filterPos ?: 0 <= mLayoutManager?.findLastVisibleItemPosition() ?: 0) {
+ mListRv?.viewTreeObserver?.removeOnGlobalLayoutListener(this)
+ }
+ }
+ }
+ mListRv?.viewTreeObserver?.addOnGlobalLayoutListener(listener)
+ mListRv.postDelayed({
+ tryCatchInRelease {
+ mListRv?.viewTreeObserver?.removeOnGlobalLayoutListener(listener)
+ }
+ }, 2000)
+ }
+ }
+
+ private fun initTopView() {
+ mBinding?.run {
+ mBinding?.run {
+ entity = mEntity
+ executePendingBindings()
+ squareIv.goneIf(mFromSquare)
+ }
+
+ if (!mListViewModel.displayTopVideo) {
+ imageItem.root.visibility = View.VISIBLE
+ videoItem.root.visibility = View.GONE
+ initImageTypeView()
+ } else {
+ imageItem.root.visibility = View.GONE
+ videoItem.root.visibility = View.VISIBLE
+ initVideoTypeView()
+ }
+ }
+ }
+
+ private fun initImageTypeView() {
+ mBinding?.imageItem?.run {
+ mEntity?.run {
+ entity = this
+ executePendingBindings()
+
+ desTv.text = "游戏单简介:${intro}"
+
+ when (stamp) {
+ "special_choice" -> {
+ tagIv.setBackgroundResource(R.drawable.ic_chosen_big)
+ }
+ "official" -> {
+ tagIv.setBackgroundResource(R.drawable.ic_official_big)
+ }
+ }
+
+ if (!UserManager.getInstance().isLoggedIn) {
+ tags?.forEachIndexed { index, tag ->
+ tagList.addView(
+ getTagView(
+ tag.name,
+ index == tags!!.size - 1,
+ R.color.white,
+ R.color.white_alpha_20
+ )
+ )
+ }
+ }
+ }
+ }
+ }
+
+ private fun initVideoTypeView() {
+ mBinding?.videoItem?.run {
+ mEntity?.run {
+ entity = this
+ executePendingBindings()
+
+ desTv.text = "游戏单简介:${intro}"
+
+ when (stamp) {
+ "special_choice" -> {
+ tagIv.setBackgroundResource(R.drawable.ic_chosen_big)
+ }
+ "official" -> {
+ tagIv.setBackgroundResource(R.drawable.ic_official_big)
+ }
+ }
+
+ if (!UserManager.getInstance().isLoggedIn) {
+ tags?.forEachIndexed { index, tag ->
+ tagList.addView(
+ getTagView(
+ tag.name,
+ index == tags!!.size - 1,
+ R.color.theme,
+ R.color.theme_alpha_20
+ )
+ )
+ }
+ }
+
+ userIcon.display(user?.border, user?.icon, user?.auth?.icon)
+
+ setUpTopVideo(video!!)
+ }
+ }
+ }
+
+ private fun getTagView(
+ content: String,
+ isLast: Boolean,
+ @ColorRes tvColorRes: Int,
+ @ColorRes dividerColorRes: Int
+ ): View {
+ return LayoutGameCollectionTagBinding.inflate(layoutInflater).apply {
+ divider.goneIf(isLast)
+ divider.setBackgroundColor(dividerColorRes.toColor())
+ contentTv.text = content
+ contentTv.setTextColor(tvColorRes.toColor())
+ }.root
+ }
+
+ private fun updateFollowView() {
+ if (!mListViewModel.displayTopVideo) {
+ updateImageItemFollowView()
+ } else {
+ updateVideoItemFollowView()
+ }
+ }
+
+ private fun updateImageItemFollowView() {
+ mBinding?.toolbarFollowTv?.run {
+ val isFollow = mEntity?.me?.isFollower ?: false
+ visibility = View.VISIBLE
+ text = if (isFollow) "已关注" else "关注"
+ if (mIsLight) {
+ setBackgroundResource(if (isFollow) R.drawable.button_round_black_alpha_10 else R.drawable.button_round_black_alpha_30)
+ setTextColor(if (isFollow) R.color.white_alpha_60.toColor() else R.color.white.toColor())
+ } else {
+ setBackgroundResource(if (isFollow) R.drawable.button_round_f5f5f5 else R.drawable.button_round_1a2496ff)
+ setTextColor(if (isFollow) R.color.text_999999.toColor() else R.color.theme.toColor())
+ }
+ }
+ }
+
+ private fun updateVideoItemFollowView() {
+ val isFollow = mEntity?.me?.isFollower ?: false
+ mBinding?.videoItem?.videoItemFollowTv?.run {
+ text = if (isFollow) "已关注" else "关注"
+ setBackgroundResource(if (isFollow) R.drawable.button_round_f5f5f5 else R.drawable.button_round_1a2496ff)
+ setTextColor(if (isFollow) R.color.text_999999.toColor() else R.color.theme.toColor())
+ }
+ mBinding?.toolbarFollowTv?.run {
+ if (mIsLight) {
+ visibility = View.GONE
+ } else {
+ visibility = View.VISIBLE
+ text = if (isFollow) "已关注" else "关注"
+ setBackgroundResource(if (isFollow) R.drawable.button_round_f5f5f5 else R.drawable.button_round_1a2496ff)
+ setTextColor(if (isFollow) R.color.text_999999.toColor() else R.color.theme.toColor())
+ }
+ }
+ }
+
+ private fun updateStartView() {
+ mBinding?.inputContainer?.run {
+ bottomStarTv.text = mListViewModel.getStarText()
+ if (mEntity?.me?.isFavorite == true) {
+ bottomStarIv.setImageResource(R.drawable.ic_article_detail_stared_bottom_bar)
+ } else {
+ bottomStarIv.setImageResource(R.drawable.ic_article_detail_star_bottom_bar)
+ }
+ }
+ }
+
+ private fun updateLikeView() {
+ mBinding?.inputContainer?.run {
+ bottomLikeTv.text = mListViewModel.getLikeText(mEntity?.count?.vote ?: 0)
+ if (mEntity?.me?.vote == true) {
+ bottomLikeIv.setImageResource(R.drawable.ic_article_detail_liked_bottom_bar)
+ } else {
+ bottomLikeIv.setImageResource(R.drawable.ic_article_detail_like_bottom_bar)
+ }
+ }
+ }
+
+ private fun updateShareView() {
+ mBinding?.inputContainer?.run {
+ bottomShareTv.text = mListViewModel.getShareText()
+ }
+ }
+
+ private fun setUpTopVideo(video: GamesCollectionDetailEntity.Video) {
+ mBinding?.videoItem?.player?.run {
+ mOrientationUtils = OrientationUtils(requireActivity(), this)
+ mOrientationUtils?.isEnable = false
+
+ GSYVideoOptionBuilder()
+ .setIsTouchWigetFull(false)
+ .setIsTouchWiget(false)
+ .setRotateViewAuto(false)
+ .setShowFullAnimation(false)
+ .setSeekRatio(1f)
+ .setUrl(video.url)
+ .setCacheWithPlay(true)
+ .setVideoAllCallBack(object : GSYSampleCallBack() {
+ override fun onQuitFullscreen(url: String?, vararg objects: Any) {
+ mOrientationUtils?.backToProtVideo()
+ logVideoEvent("video_game_collect_detail_full_cancel")
+ }
+ })
+ .build(this)
+
+ gameCollectionId = mGameCollectionId
+ gameCollectionTitle = mGameCollectionTitle
+ viewModel = mListViewModel
+ this.video = video
+ updateThumb(video.poster)
+
+ //val trafficVideo = PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SettingsFragment.TRAFFIC_VIDEO_SP_KEY, false)
+ val videoOption = SPUtils.getString(
+ Constants.SP_HOME_OR_DETAIL_VIDEO_OPTION,
+ VideoSettingFragment.VIDEO_OPTION_WIFI
+ )
+ ?: VideoSettingFragment.VIDEO_OPTION_WIFI
+ when (videoOption) {
+ VideoSettingFragment.VIDEO_OPTION_ALL -> {
+ startPlayLogic(isAutoPlay = true)
+ }
+
+ VideoSettingFragment.VIDEO_OPTION_WIFI -> {
+ if (NetworkUtils.isWifiConnected(requireContext()) /*|| !trafficVideo*/) {
+ if (mListViewModel.isTopVideoPartlyCached(video.url)) {
+ startPlayLogic(isAutoPlay = true)
+ } else {
+ // 未有缓存时,为避免影响页面加载,延迟自动播放视频
+ postDelayedRunnable({
+ if (activity != null && activity?.isFinishing != true) {
+ startPlayLogic(isAutoPlay = true)
+ }
+ }, GameDetailFragment.INITIAL_DELAY)
+ }
+ }
+ }
+
+ else -> {
+ }
+ }
+
+ fullscreenButton.setOnClickListener {
+ val horizontalVideoView =
+ startWindowFullscreen(requireContext(), true, true) as? GameCollectionVideoView
+ if (horizontalVideoView == null) {
+ toastInInternalRelease("全屏失败,请向技术人员提供具体的操作步骤")
+ return@setOnClickListener
+ }
+ mOrientationUtils?.resolveByClick()
+ horizontalVideoView.uuid = uuid
+ horizontalVideoView.viewModel = mListViewModel
+ horizontalVideoView.video = video
+ horizontalVideoView.updateThumb(video.poster)
+ horizontalVideoView.violenceUpdateMuteStatus()
+ logVideoEvent("video_game_collect_detail_full")
+ }
+
+ observeVolume(this@GameCollectionDetailFragment)
+ }
+ }
+
+ override fun onLoadRefresh() {
+// showSkeleton(true)
+ }
+
+ override fun onLoadDone() {
+// showSkeleton(false)
+ mReuseNoConn?.visibility = View.GONE
+ mReuseNoData?.visibility = View.GONE
+ mListLoading?.visibility = View.GONE
+
+ mListRv.visibility = View.VISIBLE
+ hideRefreshingLayout()
+
+ mListRv.postDelayed({
+ if (provideListAdapter().itemCount < theNumberNeededToFillAScreen()) {
+ autoLoadMore()
+ }
+ }, autoLoadMoreDelay.toLong())
+ }
+
+ override fun onLoadEmpty() {
+// showSkeleton(false)
+ mListRv.visibility = View.VISIBLE
+ }
+
+ override fun onLoadError() {
+ super.onLoadError()
+ mListRv.visibility = View.VISIBLE
+ }
+
+ override fun onResume() {
+ if (isEverPause && mAdapter != null) mAdapter?.notifyDataSetChanged()
+ super.onResume()
+ DownloadManager.getInstance(context).addObserver(mDataWatcher)
+
+ if (!mIsPauseTopVideo) {
+ resumeVideo()
+ }
+ }
+
+ override fun onPause() {
+ super.onPause()
+ DownloadManager.getInstance(context).removeObserver(mDataWatcher)
+
+ pauseVideo()
+ if (mListViewModel.displayTopVideo) {
+ mBinding?.videoItem?.player?.run {
+ val currentPosition = getCurrentPosition()
+ val topVideo = mEntity?.video
+ if (topVideo != null) {
+ ScrollCalculatorHelper.savePlaySchedule(
+ MD5Utils.getContentMD5(topVideo.url),
+ currentPosition
+ )
+ }
+ }
+ }
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+
+ if (requestCode == CommentActivity.REQUEST_CODE && resultCode == Activity.RESULT_OK) {
+ val commentCount = data?.getIntExtra(CommentActivity.COMMENT_COUNT, 0)
+ if (commentCount != 0 && commentCount != null) {
+ mEntity?.count?.comment = commentCount
+ mBinding?.inputContainer?.bottomCommentTv?.text = mListViewModel.getCommentText(
+ mEntity?.count?.comment
+ ?: 0, "评论"
+ )
+ updateFilterView()
+ mListViewModel.load(LoadType.REFRESH)
+ }
+ }
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ mEntity?.run {
+ if (status == "pass" && display != "self_only") {
+ HistoryHelper.insertGamesCollectionEntity(this)
+ }
+ }
+ }
+
+ override fun onBackPressed(): Boolean {
+ mOrientationUtils?.backToProtVideo()
+
+ if (CustomManager.backFromWindowFull(requireActivity(), mBinding?.videoItem?.player?.getKey())) {
+ return true
+ }
+
+ return super.onBackPressed()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ releaseVideo()
+ }
+
+ private fun pauseVideo() {
+ if (mListViewModel.displayTopVideo) {
+ mBinding?.videoItem?.player?.onVideoPause()
+ }
+ }
+
+ private fun resumeVideo() {
+ if (mListViewModel.displayTopVideo) {
+ mBinding?.videoItem?.player?.onVideoResume()
+ }
+ }
+
+ private fun releaseVideo() {
+ if (mListViewModel.displayTopVideo) {
+ mBinding?.videoItem?.player?.release()
+ mBinding?.videoItem?.player?.disposableTimer()
+ }
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ fun onUserFollow(change: EBUserFollow) {
+ mEntity?.me?.isFollower = change.isFollow
+ updateFollowView()
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ fun onEventMainThread(share: EBShare?) {
+ postDelayedRunnable({
+ tryCatchInRelease {
+ if (share != null && share.shareEntrance == ShareUtils.ShareEntrance.gameCollection && isAdded) {
+ mListViewModel.postShareGameCollection()
+ }
+ }
+ }, 200)
+ }
+
+ @OnClick(R.id.backIv, R.id.desContainer, R.id.videoDesContainer, R.id.toolbarLightUserContainer, R.id.toolbarUserContainer,
+ R.id.videoItemUserContainer, R.id.toolbarFollowTv, R.id.videoItemFollowTv, R.id.squareIv, R.id.bottomStarIv,
+ R.id.bottomStarTv, R.id.bottomLikeIv, R.id.bottomLikeTv, R.id.bottomShareIv, R.id.bottomShareTv, R.id.replyTv,
+ R.id.bottomCommentIv, R.id.bottomCommentTv)
+ override fun onClick(v: View) {
+ when (v.id) {
+ R.id.backIv -> requireActivity().finish()
+
+ R.id.desContainer,
+ R.id.videoDesContainer -> {
+ logEvent("click_game_collect_detail_product")
+ startActivity(GameCollectionPosterActivity.getIntent(requireContext(), mEntity ?: GamesCollectionDetailEntity()))
+ }
+
+ R.id.toolbarLightUserContainer,
+ R.id.toolbarUserContainer,
+ R.id.videoItemUserContainer -> {
+ DirectUtils.directToHomeActivity(requireContext(), mEntity?.user?.id, "", "游戏单详情-导航栏")
+ }
+
+ R.id.toolbarFollowTv,
+ R.id.videoItemFollowTv -> {
+ ifLogin("游戏单详情") {
+ if (mEntity?.me?.isFollower == false) {
+ logEvent("click_game_collect_detail_follow")
+ mListViewModel?.followingCommand(mEntity?.user?.id ?: "", true)
+ } else {
+ DialogHelper.showDialog(
+ requireContext(),
+ "取消关注",
+ "确定要取消关注 ${mEntity?.user?.name} 吗?",
+ "确定取消",
+ "暂不取消",
+ {
+ logEvent("click_game_collect_detail_follow_cancel")
+ mListViewModel?.followingCommand(mEntity?.user?.id ?: "", false)
+ },
+ extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
+ )
+ }
+ }
+ }
+
+ R.id.squareIv -> {
+ DirectUtils.directToGameCollectionSquare(
+ requireContext(),
+ "游戏单详情",
+ "",
+ mGameCollectionTitle,
+ mGameCollectionId
+ )
+ }
+
+ R.id.replyTv -> {
+ if (isSelfOnly()) return
+ debounceActionWithInterval(v.id) {
+ startCommentActivity()
+ }
+ }
+
+ R.id.bottomCommentIv,
+ R.id.bottomCommentTv -> {
+ mListRv.post {
+ mBinding?.appbar?.setExpanded(false)
+ mLayoutManager.scrollToPositionWithOffset(mListViewModel?.filterPos ?: 0, 0)
+ }
+ }
+
+ R.id.bottomStarIv,
+ R.id.bottomStarTv -> {
+ if (isSelfOnly()) return
+ debounceActionWithInterval(v.id) {
+ ifLogin("游戏单详情") {
+ if (mEntity?.me?.isFavorite == true) {
+ logEvent("click_game_collect_detail_favorite_cancel")
+ } else {
+ logEvent("click_game_collect_detail_favorite")
+ }
+ mListViewModel?.postFavoriteGameCollection()
+ }
+ }
+ }
+
+ R.id.bottomLikeIv,
+ R.id.bottomLikeTv -> {
+ if (isSelfOnly()) return
+ debounceActionWithInterval(v.id) {
+ ifLogin("游戏单详情") {
+ mListViewModel?.postVoteGameCollection()
+ }
+ }
+ }
+
+ R.id.bottomShareIv,
+ R.id.bottomShareTv -> {
+ if (isSelfOnly()) return
+ showMoreItemDialog()
+ }
+ }
+ }
+
+ private fun updateFilterView() {
+ mBinding?.fixedTopFilterView?.run {
+ getFilterVH()?.binding?.commentHintCountTv?.text = "${provideListViewModel().commentCount}"
+
+ filterLatestTv.setTextColor(getFilterVH()?.binding?.filterLatestTv?.textColors)
+ filterOldestTv.setTextColor(getFilterVH()?.binding?.filterOldestTv?.textColors)
+ commentHintTv.text = getFilterVH()?.binding?.commentHintTv?.text
+ commentHintCountTv.text = getFilterVH()?.binding?.commentHintCountTv?.text
+ }
+ }
+
+ private fun getFilterVH(): BaseCommentAdapter.CommentFilterViewHolder? {
+ return (provideListAdapter() as BaseCommentAdapter).filterVH
+ }
+
+ private fun isSelfOnly(): Boolean {
+ val isSelfOnly = mEntity?.display == "self_only"
+ if (isSelfOnly) toast("游戏单为仅自己可见状态")
+ return isSelfOnly
+ }
+
+ private fun showMoreItemDialog() {
+ if (!lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) return
+ mEntity?.run {
+ GameCollectionShareDialog.showMoreDialog(
+ requireActivity() as AppCompatActivity,
+ getShareEntity(this)
+ )
+ }
+ }
+
+ private fun startCommentActivity() {
+ mEntity?.run {
+ val intent = CommentActivity.getGameCollectionCommentIntent(
+ requireContext(),
+ id,
+ count?.comment ?: 0
+ )
+ startActivityForResult(intent, CommentActivity.REQUEST_CODE)
+ }
+ }
+
+ private fun getShareEntity(entity: GamesCollectionDetailEntity): NormalShareEntity {
+ val shareUrl = if (isPublishEnv()) {
+ Constants.GAME_COLLECTION_SHARE_ADDRESS
+ } else {
+ Constants.GAME_COLLECTION_SHARE_ADDRESS_DEV
+ } + "&id=${entity.id}"
+ return NormalShareEntity(
+ id = entity.id,
+ shareUrl = shareUrl,
+ shareIcon = entity.cover,
+ shareTitle = entity.title,
+ shareSummary = entity.intro,
+ shareEntrance = ShareUtils.ShareEntrance.gameCollection
+ )
+ }
+
+ fun showUnzipFailureDialog(downloadEntity: DownloadEntity) {
+ val data = mAdapter?.positionAndPackageMap ?: return
+ for (gameAndPosition in data) {
+ if (gameAndPosition.key.contains(downloadEntity.packageName)) {
+ val targetView = mLayoutManager.findViewByPosition(gameAndPosition.value)
+ if (targetView != null) {
+ DialogUtils.showUnzipFailureDialog(requireContext(), downloadEntity)
+ return
+ }
+ }
+ }
+ }
+
+ fun logEvent(event: String, shareType: String = "") {
+ NewLogUtils.logViewOrClickGameCollectionDetail(
+ event,
+ mGameCollectionTitle,
+ mGameCollectionId,
+ shareType
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailViewModel.kt
new file mode 100644
index 0000000000..706f20ec94
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionDetailViewModel.kt
@@ -0,0 +1,340 @@
+package com.gh.gamecenter.gamecollection.detail
+
+import android.annotation.SuppressLint
+import android.app.Application
+import android.net.Uri
+import android.os.Build
+import android.text.TextUtils
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.gh.common.constant.Constants
+import com.gh.common.util.*
+import com.gh.gamecenter.R
+import com.gh.gamecenter.baselist.LoadStatus
+import com.gh.gamecenter.entity.CommentEntity
+import com.gh.gamecenter.entity.GamesCollectionDetailEntity
+import com.gh.gamecenter.eventbus.EBUserFollow
+import com.gh.gamecenter.manager.UserManager
+import com.gh.gamecenter.qa.article.detail.CommentItemData
+import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel
+import com.gh.gamecenter.retrofit.BiResponse
+import com.gh.gamecenter.retrofit.Response
+import com.gh.gamecenter.retrofit.RetrofitManager
+import com.halo.assistant.HaloApp
+import com.lightgame.utils.Utils
+import io.reactivex.Single
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import okhttp3.ResponseBody
+import org.greenrobot.eventbus.EventBus
+import org.json.JSONObject
+import retrofit2.HttpException
+import tv.danmaku.ijk.media.exo2.ExoSourceManager
+
+open class GameCollectionDetailViewModel(application: Application,
+ var gameCollectionId: String) :
+ BaseCommentViewModel(application, "", "", "", "") {
+
+ var followLiveData = MutableLiveData()
+ val favoriteLiveData = MutableLiveData()
+ val likeLiveData = MutableLiveData()
+ val shareLiveData = MutableLiveData()
+ var gameCollectionDetail: GamesCollectionDetailEntity? = null
+ var gameCollectionTitle = ""
+ var ownerUserId = ""
+ var filterPos = 0
+ var displayTopVideo: Boolean = false
+ var videoIsMuted = SPUtils.getBoolean(Constants.SP_VIDEO_PLAY_MUTE, true)
+
+ @SuppressLint("CheckResult")
+ fun getGameCollectionDetail() {
+ mApi.getGameCollectionDetail(gameCollectionId)
+ .compose(singleToMain())
+ .subscribe(object : BiResponse() {
+ override fun onSuccess(data: GamesCollectionDetailEntity) {
+ // 4.4以下设备不显示顶部视频
+ displayTopVideo = data.video != null
+ && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
+ gameCollectionDetail = data
+ gameCollectionTitle = data.title
+ commentCount = data.count?.comment ?: 0
+ ownerUserId = data.user?.id ?: ""
+ filterPos = (data.games?.size ?: 1) + 1
+ loadResultLiveData.postValue(LoadResult.SUCCESS)
+ mergeData(mListLiveData.value)
+ }
+
+ override fun onFailure(exception: Exception) {
+ super.onFailure(exception)
+ if (exception is HttpException) {
+ if (exception.code().toString().startsWith("404")) {
+ loadResultLiveData.postValue(LoadResult.DELETED)
+ } else {
+ loadResultLiveData.postValue(LoadResult.NETWORK_ERROR)
+ }
+ }
+ }
+ })
+ }
+
+ override fun provideDataObservable(page: Int) = null
+
+ override fun provideDataSingle(page: Int): Single> {
+ val sortType = if (currentSortType == SortType.LATEST) "earliest" else "latest"
+ return mApi.getGameCollectionComments(gameCollectionId, page, sortType)
+ }
+
+ override fun mergeResultLiveData() {
+ mResultLiveData.addSource(mListLiveData) { mergeData(it) }
+ }
+
+ fun mergeData(list: List?) {
+ gameCollectionDetail?.run {
+ val itemDataList = arrayListOf().apply {
+ if (games?.isEmpty() == true) {
+ add(CommentItemData(gameEmpty = true))
+ } else {
+ val gameLastIndex = games!!.size - 1
+ if (mResultLiveData.value?.get(0)?.game != null
+ && mResultLiveData.value?.get(gameLastIndex)?.game != null) {
+ for (i in 0..gameLastIndex) {
+ add(mResultLiveData.value!![i])
+ }
+ } else {
+ games?.forEach {
+ add(CommentItemData(game = it))
+ }
+ }
+ }
+
+ add(CommentItemData(divider = true))
+ add(CommentItemData(filter = true))
+
+ if (list.isNullOrEmpty() && mLoadStatusLiveData.value == LoadStatus.INIT_EMPTY) {
+ add(CommentItemData(errorEmpty = true))
+ } else if (list.isNullOrEmpty() && mLoadStatusLiveData.value == LoadStatus.INIT_FAILED) {
+ add(CommentItemData(errorConnection = true))
+ } else {
+ list?.forEach {
+ add(CommentItemData(commentNormal = it))
+ }
+ add(CommentItemData(footer = true))
+ }
+ }
+
+ mResultLiveData.postValue(itemDataList)
+ }
+ }
+
+ fun followingCommand(userId: String, isFollow: Boolean) {
+ val observable = if (isFollow) {
+ RetrofitManager.getInstance(getApplication()).api.postFollowing(userId)
+ } else {
+ RetrofitManager.getInstance(getApplication()).api.deleteFollowing(userId)
+ }
+ observable
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(object : Response() {
+ override fun onResponse(response: ResponseBody?) {
+ super.onResponse(response)
+ if (isFollow) {
+ Utils.toast(getApplication(), R.string.concern_success)
+ } else {
+ Utils.toast(getApplication(), R.string.concern_cancel)
+ }
+ gameCollectionDetail?.me?.isFollower =
+ gameCollectionDetail?.me?.isFollower != true
+ followLiveData.postValue(isFollow)
+ EventBus.getDefault().post(EBUserFollow(userId, isFollow))
+ }
+
+ override fun onFailure(e: HttpException?) {
+ super.onFailure(e)
+ Utils.toast(getApplication(), R.string.loading_failed_hint)
+ }
+ })
+ }
+
+ @SuppressLint("CheckResult")
+ fun postFavoriteGameCollection() {
+ if (gameCollectionDetail == null) return
+ val single = if (gameCollectionDetail?.me?.isFavorite == true) {
+ mApi.deleteFavoriteGameCollection(UserManager.getInstance().userId, gameCollectionId)
+ } else {
+ mApi.favoriteGameCollection(UserManager.getInstance().userId, gameCollectionId)
+ }
+ single.compose(singleToMain())
+ .subscribe(object : BiResponse() {
+ override fun onSuccess(data: ResponseBody) {
+ if (gameCollectionDetail?.me?.isFavorite == true) {
+ gameCollectionDetail!!.count!!.favorite--
+ ToastUtils.showToast("取消收藏")
+ } else {
+ gameCollectionDetail!!.count!!.favorite++
+ ToastUtils.showToast("收藏成功")
+ }
+ gameCollectionDetail?.me?.isFavorite =
+ gameCollectionDetail?.me?.isFavorite != true
+ favoriteLiveData.postValue(true)
+ }
+
+ override fun onFailure(exception: Exception) {
+ super.onFailure(exception)
+
+ if (exception is HttpException) {
+ ErrorHelper.handleError(
+ getApplication(),
+ exception.response()?.errorBody()?.string()
+ )
+ }
+ }
+ })
+ }
+
+ @SuppressLint("CheckResult")
+ fun postVoteGameCollection() {
+ if (gameCollectionDetail == null) return
+ val single = if (gameCollectionDetail?.me?.vote == true) {
+ mApi.unVoteGameCollection(gameCollectionId)
+ } else {
+ mApi.voteGameCollection(gameCollectionId)
+ }
+ single.compose(singleToMain())
+ .subscribe(object : BiResponse() {
+ override fun onSuccess(data: ResponseBody) {
+ if (gameCollectionDetail?.me?.vote == true) {
+ gameCollectionDetail!!.count!!.vote--
+ ToastUtils.showToast("取消点赞")
+ } else {
+ gameCollectionDetail!!.count!!.vote++
+ ToastUtils.showToast("点赞成功")
+ }
+ gameCollectionDetail?.me?.vote =
+ gameCollectionDetail?.me?.vote != true
+ likeLiveData.postValue(true)
+ }
+
+ override fun onFailure(exception: Exception) {
+ super.onFailure(exception)
+
+ if (exception is HttpException) {
+ ErrorHelper.handleError(
+ getApplication(),
+ exception.response()?.errorBody()?.string()
+ )
+ }
+ }
+ })
+ }
+ @SuppressLint("CheckResult")
+ fun postShareGameCollection() {
+ if (gameCollectionDetail == null) return
+ mApi.shareGameCollection(gameCollectionId)
+ .compose(singleToMain())
+ .subscribe(object : BiResponse() {
+ override fun onSuccess(data: ResponseBody) {
+ gameCollectionDetail!!.count!!.share++
+ shareLiveData.postValue(true)
+ }
+
+ override fun onFailure(exception: Exception) {
+ super.onFailure(exception)
+
+ if (exception is HttpException) {
+ ErrorHelper.handleError(
+ getApplication(),
+ exception.response()?.errorBody()?.string()
+ )
+ }
+ }
+ })
+ }
+
+
+ @SuppressLint("CheckResult")
+ fun postVoteGameCollectionComment(comment: CommentEntity, successCallback: (() -> Unit)) {
+ mApi.voteGameCollectionComment(gameCollectionId, comment.id)
+ .compose(singleToMain())
+ .subscribe(object : BiResponse() {
+ override fun onSuccess(data: ResponseBody) {
+ if (comment.me?.isCommentVoted == true) {
+ comment.vote--
+ ToastUtils.showToast("取消点赞")
+ } else {
+ comment.vote++
+ ToastUtils.showToast("点赞成功")
+ }
+ comment.me?.isCommentVoted = !(comment.me?.isCommentVoted ?: false)
+ successCallback.invoke()
+ }
+
+ override fun onFailure(exception: Exception) {
+ super.onFailure(exception)
+
+ if (exception is HttpException) {
+ ErrorHelper.handleError(
+ getApplication(),
+ exception.response()?.errorBody()?.string()
+ )
+ }
+ }
+ })
+ }
+
+ @SuppressLint("CheckResult")
+ override fun deleteComment(entity: CommentEntity, callback: () -> Unit) {
+ mApi.deleteGameCollectionComment(gameCollectionId, entity.id)
+ .compose(observableToMain())
+ .subscribe(object : Response() {
+ override fun onResponse(response: ResponseBody?) {
+ hideCommentSuccess()
+ callback.invoke()
+ }
+
+ override fun onFailure(e: HttpException?) {
+ super.onFailure(e)
+ e?.let { httpException ->
+ if (httpException.code() == 403) {
+ val string = e.response().errorBody()?.string() ?: ""
+ val errorJson = JSONObject(string)
+ val errorCode = errorJson.getInt("code")
+ if (errorCode == 403059) {
+ Utils.toast(getApplication(), "权限错误,请刷新后重试")
+ return
+ } else {
+ Utils.toast(getApplication(), e.message())
+ }
+ }
+ }
+ }
+ })
+ }
+
+ fun getStarText(): String {
+ return if (gameCollectionDetail?.count?.favorite == 0) "收藏" else "${gameCollectionDetail?.count?.favorite}"
+ }
+
+ fun getShareText(): String {
+ return if (gameCollectionDetail?.count?.share == 0) "分享" else "${gameCollectionDetail?.count?.share}"
+ }
+
+ fun isTopVideoPartlyCached(topVideoUrl: String): Boolean {
+ val cache = ExoSourceManager.getCacheSingleInstance(HaloApp.getInstance().application, null)
+ val key = Uri.parse(topVideoUrl).toString()
+ return if (!TextUtils.isEmpty(key)) {
+ val cachedSpans = cache.getCachedSpans(key)
+ cachedSpans.size != 0
+ } else {
+ false
+ }
+ }
+
+ class Factory(private val gameCollectionId: String) : ViewModelProvider.NewInstanceFactory() {
+
+ override fun create(modelClass: Class): T {
+ return GameCollectionDetailViewModel(HaloApp.getInstance().application, gameCollectionId) as T
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionPosterActivity.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionPosterActivity.kt
new file mode 100644
index 0000000000..491c030e9c
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionPosterActivity.kt
@@ -0,0 +1,28 @@
+package com.gh.gamecenter.gamecollection.detail
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import com.gh.common.util.DisplayUtils
+import com.gh.common.util.EntranceUtils
+import com.gh.gamecenter.NormalActivity
+import com.gh.gamecenter.R
+import com.gh.gamecenter.entity.GamesCollectionDetailEntity
+
+class GameCollectionPosterActivity : NormalActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ hideToolbar(true)
+ DisplayUtils.setStatusBarColor(this, R.color.transparent, false)
+ }
+
+ companion object {
+ @JvmStatic
+ fun getIntent(context: Context, entity: GamesCollectionDetailEntity): Intent {
+ val bundle = Bundle()
+ bundle.putParcelable(EntranceUtils.KEY_DATA, entity)
+ return getTargetIntent(context, GameCollectionPosterActivity::class.java, GameCollectionPosterFragment::class.java, bundle)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionPosterFragment.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionPosterFragment.kt
new file mode 100644
index 0000000000..ca56229379
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionPosterFragment.kt
@@ -0,0 +1,119 @@
+package com.gh.gamecenter.gamecollection.detail
+
+import android.graphics.Bitmap
+import android.os.Build
+import android.os.Bundle
+import android.view.View
+import androidx.annotation.RequiresApi
+import butterknife.OnClick
+import com.gh.common.runOnUiThread
+import com.gh.common.util.*
+import com.gh.gamecenter.R
+import com.gh.gamecenter.databinding.FragmentGameCollectionPosterBinding
+import com.gh.gamecenter.databinding.LayoutGameCollectionTagBinding
+import com.gh.gamecenter.entity.GamesCollectionDetailEntity
+import com.gh.gamecenter.normal.NormalFragment
+
+class GameCollectionPosterFragment : NormalFragment() {
+
+ private var mBinding: FragmentGameCollectionPosterBinding? = null
+ private var mViewModel: GameCollectionPosterViewModel? = null
+ private var mEntity = GamesCollectionDetailEntity()
+
+ override fun getLayoutId() = 0
+
+ override fun getInflatedLayout() =
+ FragmentGameCollectionPosterBinding.inflate(layoutInflater).apply { mBinding = this }.root
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ mViewModel = viewModelProvider()
+ mEntity = arguments?.getParcelable(EntranceUtils.KEY_DATA) ?: GamesCollectionDetailEntity()
+
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ mViewModel?.followLiveData?.observeNonNull(viewLifecycleOwner) {
+ setFollowStatus(it)
+ }
+
+ mBinding?.apply {
+ mEntity.apply {
+ entity = this
+ executePendingBindings()
+
+ ImageUtils.getBitmap(cover, object : BiCallback {
+ @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+ override fun onFirst(first: Bitmap) {
+ val blurBitmap = BitmapUtils.getBlurBitmap(requireContext(), first, 16)
+ runOnUiThread {
+ posterBg.setImageBitmap(blurBitmap)
+ }
+ }
+
+ override fun onSecond(second: Boolean) {}
+ })
+
+ userIcon.display(user?.border, user?.icon, user?.auth?.icon)
+
+ tags?.forEachIndexed { index, tag ->
+ tagContainer.addView(getTagView(tag.name, index == tags!!.size - 1))
+ }
+
+ setFollowStatus(me?.isFollower == true)
+ }
+ }
+ }
+
+ private fun setFollowStatus(isFollow: Boolean) {
+ mBinding?.followTv?.run {
+ setBackgroundResource(if (isFollow) R.drawable.button_round_white_alpha_10 else R.drawable.button_round_white_alpha_20)
+ setTextColor(if (isFollow) R.color.white_alpha_60.toColor() else R.color.white.toColor())
+ text = if (isFollow) "已关注" else "关注"
+ }
+ }
+
+ private fun getTagView(content: String, isLast: Boolean): View {
+ return LayoutGameCollectionTagBinding.inflate(layoutInflater).apply {
+ root.setPadding(0, 12F.dip2px(), 0, 0)
+ divider.goneIf(isLast)
+ contentTv.text = content
+ }.root
+ }
+
+ @OnClick(R.id.backIv, R.id.userIcon, R.id.userName, R.id.followTv)
+ override fun onClick(view: View) {
+ when (view.id) {
+ R.id.backIv -> requireActivity().finish()
+
+ R.id.userIcon -> {
+ DirectUtils.directToHomeActivity(requireContext(), mEntity.user?.id, "", "游戏单详情-封面页")
+ }
+
+ R.id.userName -> {
+ DirectUtils.directToHomeActivity(requireContext(), mEntity.user?.id, "", "游戏单详情-封面页")
+ }
+
+ R.id.followTv -> {
+ ifLogin("游戏单详情-封面页") {
+ if (mBinding?.followTv?.text == "关注") {
+ mViewModel?.followingCommand(mEntity.user?.id ?: "", true)
+ } else {
+ DialogHelper.showDialog(
+ requireContext(),
+ "取消关注",
+ "确定要取消关注 ${mEntity.user?.name} 吗?",
+ "确定取消",
+ "暂不取消",
+ { mViewModel?.followingCommand(mEntity.user?.id ?: "", false) },
+ extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
+ )
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionPosterViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionPosterViewModel.kt
new file mode 100644
index 0000000000..bc37e692d1
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionPosterViewModel.kt
@@ -0,0 +1,48 @@
+package com.gh.gamecenter.gamecollection.detail
+
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.MutableLiveData
+import com.gh.gamecenter.R
+import com.gh.gamecenter.eventbus.EBUserFollow
+import com.gh.gamecenter.retrofit.Response
+import com.gh.gamecenter.retrofit.RetrofitManager
+import com.lightgame.utils.Utils
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import okhttp3.ResponseBody
+import org.greenrobot.eventbus.EventBus
+import retrofit2.HttpException
+
+class GameCollectionPosterViewModel(application: Application) : AndroidViewModel(application) {
+
+ var followLiveData = MutableLiveData()
+
+ fun followingCommand(userId: String, isFollow: Boolean) {
+ val observable = if (isFollow) {
+ RetrofitManager.getInstance(getApplication()).api.postFollowing(userId)
+ } else {
+ RetrofitManager.getInstance(getApplication()).api.deleteFollowing(userId)
+ }
+ observable
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(object : Response() {
+ override fun onResponse(response: ResponseBody?) {
+ super.onResponse(response)
+ if (isFollow) {
+ Utils.toast(getApplication(), R.string.concern_success)
+ } else {
+ Utils.toast(getApplication(), R.string.concern_cancel)
+ }
+ followLiveData.postValue(isFollow)
+ EventBus.getDefault().post(EBUserFollow(userId, isFollow))
+ }
+
+ override fun onFailure(e: HttpException?) {
+ super.onFailure(e)
+ Utils.toast(getApplication(), R.string.loading_failed_hint)
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionShareDialog.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionShareDialog.kt
new file mode 100644
index 0000000000..f89eeca996
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionShareDialog.kt
@@ -0,0 +1,131 @@
+package com.gh.gamecenter.gamecollection.detail
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.appcompat.app.AppCompatActivity
+import com.gh.common.dialog.BaseDraggableDialogFragment
+import com.gh.common.util.*
+import com.gh.gamecenter.databinding.DialogGameCollectionShareBinding
+import com.gh.gamecenter.entity.NormalShareEntity
+import com.gh.gamecenter.eventbus.EBShare
+import org.greenrobot.eventbus.EventBus
+
+class GameCollectionShareDialog : BaseDraggableDialogFragment() {
+
+ private lateinit var mBinding: DialogGameCollectionShareBinding
+ private var mShareEntity: NormalShareEntity? = null
+ private var mShareUtils: ShareUtils? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ mShareEntity = requireArguments().getParcelable(KEY_SHARE)
+ mShareUtils = getShareUtils()
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ return DialogGameCollectionShareBinding.inflate(inflater, container, false)
+ .apply { mBinding = this }.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ mBinding.run {
+ wechatItem.setOnClickListener {
+ logEvent("微信")
+ mShareUtils?.wechatShare()
+ }
+
+ wechatMomentsItem.setOnClickListener {
+ logEvent("朋友圈")
+ mShareUtils?.wechatMomentsShare()
+ }
+
+ qqItem.setOnClickListener {
+ logEvent("QQ好友")
+ mShareUtils?.qqShare()
+ }
+
+ qqZoneItem.setOnClickListener {
+ logEvent("QQ空间")
+ mShareUtils?.qZoneShare()
+ }
+
+ weiboItem.setOnClickListener {
+ logEvent("新浪微博")
+ mShareUtils?.sinaWeiboShare()
+ }
+
+ smsItem.setOnClickListener {
+ logEvent("短信")
+ EventBus.getDefault().post(EBShare(ShareUtils.shareEntrance))
+ mShareUtils?.shortMessageShare()
+ }
+
+ copyItem.setOnClickListener {
+ logEvent("复制链接")
+ EventBus.getDefault().post(EBShare(ShareUtils.shareEntrance))
+ mShareUtils?.copyLink(mShareUtils?.shareUrl ?: "")
+ }
+
+ cancelTv.setOnClickListener {
+ dismissAllowingStateLoss()
+ }
+ }
+ }
+
+ private fun getShareUtils(): ShareUtils {
+ val shareUtils = ShareUtils.getInstance(requireContext())
+ mShareEntity?.run {
+ shareUtils.shareParamsDetail(
+ requireActivity(),
+ shareUrl,
+ shareIcon,
+ shareTitle,
+ shareSummary,
+ shareEntrance,
+ id,
+ null
+ )
+ }
+ return shareUtils
+ }
+
+ private fun logEvent(shareType: String) {
+ NewLogUtils.logViewOrClickGameCollectionDetail(
+ "click_game_collect_detail_share",
+ mShareEntity?.shareTitle ?: "",
+ mShareEntity?.id ?: "",
+ shareType
+ )
+ }
+
+ override fun getRootView(): View = mBinding.root
+ override fun getDragCloseView(): View = mBinding.dragClose
+
+ companion object {
+ const val KEY_SHARE = "share"
+ const val REQUEST_CODE = 1105
+
+ @JvmStatic
+ fun showMoreDialog(
+ activity: AppCompatActivity,
+ share: NormalShareEntity,
+ ) {
+ GameCollectionShareDialog().apply {
+ arguments = Bundle().apply {
+ putParcelable(KEY_SHARE, share)
+ }
+ }.show(
+ activity.supportFragmentManager,
+ GameCollectionShareDialog::class.java.name
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionVideoView.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionVideoView.kt
new file mode 100644
index 0000000000..cbe674df92
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/GameCollectionVideoView.kt
@@ -0,0 +1,430 @@
+package com.gh.gamecenter.gamecollection.detail
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.GestureDetector
+import android.view.MotionEvent
+import android.view.Surface
+import android.view.View
+import android.widget.ImageView
+import android.widget.SeekBar
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentManager
+import com.gh.common.observer.MuteCallback
+import com.gh.common.observer.VolumeObserver
+import com.gh.common.runOnIoThread
+import com.gh.common.util.*
+import com.gh.gamecenter.R
+import com.gh.gamecenter.entity.GamesCollectionDetailEntity
+import com.gh.gamecenter.home.video.ScrollCalculatorHelper
+import com.gh.gamecenter.video.detail.CustomManager
+import com.lightgame.utils.Utils
+import com.shuyu.gsyvideoplayer.utils.CommonUtil
+import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
+import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
+import com.shuyu.gsyvideoplayer.video.base.GSYVideoViewBridge
+import com.squareup.picasso.Picasso
+import io.reactivex.disposables.Disposable
+import kotlinx.android.synthetic.main.layout_game_detail_video_portrait.view.*
+import kotlinx.android.synthetic.main.piece_video_control.view.*
+import kotlinx.android.synthetic.main.piece_video_replay.view.*
+import java.text.DecimalFormat
+import java.util.*
+
+class GameCollectionVideoView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : StandardGSYVideoPlayer(context, attrs) {
+
+ private var mMuteCallback: MuteCallback
+ private var mVolumeObserver: VolumeObserver
+
+ var gameName = ""
+ var gameCollectionId = ""
+ var gameCollectionTitle = ""
+ var video: GamesCollectionDetailEntity.Video? = null
+ var viewModel: GameCollectionDetailViewModel? = null
+ var uuid = UUID.randomUUID().toString()
+ private var mMuteDisposable: Disposable? = null
+ private var mIsAutoPlay = false
+ private var mIsManualStop = false
+
+ init {
+ post {
+ gestureDetector = GestureDetector(getContext().applicationContext, object : GestureDetector.SimpleOnGestureListener() {
+ override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
+ if (!mChangePosition && !mChangeVolume && !mBrightness) {
+ onClickUiToggle(e)
+ }
+ return super.onSingleTapConfirmed(e)
+ }
+ })
+
+ if (mIfCurrentIsFullscreen) {
+ showBackBtn()
+ } else {
+ hideBackBtn()
+ }
+
+ volume.setOnClickListener { toggleMute() }
+ }
+
+ mMuteCallback = object : MuteCallback {
+ override fun onMute(isMute: Boolean) {
+ if (isMute) {
+ mute()
+ } else {
+ unMute()
+ }
+ }
+ }
+
+ mVolumeObserver = VolumeObserver(mMuteCallback)
+
+ setBackFromFullScreenListener {
+ clearFullscreenLayout()
+ }
+
+ errorBtn?.setOnClickListener {
+ debounceActionWithInterval(errorBtn.id, 1000) {
+ if (!com.shuyu.gsyvideoplayer.utils.NetworkUtils.isAvailable(mContext)) {
+ Utils.toast(context, "网络异常,请检查手机网络状态")
+ setViewShowState(mStartButton, View.INVISIBLE)
+ errorContainer.visibility = View.VISIBLE
+ return@debounceActionWithInterval
+ }
+ startPlayLogic(false)
+ }
+ }
+ }
+
+ //这个必须配置最上面的构造才能生效
+ override fun getLayoutId(): Int {
+ return R.layout.layout_game_detail_video_portrait
+ }
+
+ fun observeVolume(fragment: Fragment?) {
+ fragment?.context?.applicationContext?.contentResolver?.registerContentObserver(
+ android.provider.Settings.System.CONTENT_URI, true, mVolumeObserver)
+
+ fragment?.fragmentManager?.registerFragmentLifecycleCallbacks(
+ object : FragmentManager.FragmentLifecycleCallbacks() {
+ override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
+ if (f === fragment) {
+ fragment.context?.applicationContext?.contentResolver?.unregisterContentObserver(mVolumeObserver)
+ fragment.fragmentManager?.unregisterFragmentLifecycleCallbacks(this)
+ }
+ }
+ }, false)
+ }
+
+ fun startPlayLogic(isAutoPlay: Boolean) {
+ mIsAutoPlay = isAutoPlay
+ violenceUpdateMuteStatus()
+ logVideoEvent("video_game_collect_detail_play", if (isAutoPlay) "自动播放" else "手动播放")
+ if (isAutoPlay) {
+ val seekTime = ScrollCalculatorHelper.getPlaySchedule(MD5Utils.getContentMD5(video?.url))
+ seekOnStart = seekTime
+ }
+ startPlayLogic()
+ }
+
+ fun violenceUpdateMuteStatus() {
+ if (mMuteDisposable != null) {
+ mMuteDisposable?.dispose()
+ mMuteDisposable = null
+ }
+ mMuteDisposable = rxTimer(25) {
+ if (it >= 400) {
+ mMuteDisposable?.dispose()
+ mMuteDisposable = null
+ }
+ updateMuteStatus()
+ }
+ }
+
+ fun disposableTimer() {
+ if (mMuteDisposable != null && !mMuteDisposable!!.isDisposed) {
+ mMuteDisposable?.dispose()
+ mMuteDisposable = null
+ }
+ }
+
+ private fun toggleMute() {
+ if (viewModel?.videoIsMuted == true) {
+ unMute(true)
+ } else {
+ mute(true)
+ }
+ }
+
+ fun updateMuteStatus() {
+ if (viewModel?.videoIsMuted == true) {
+ mute()
+ } else {
+ unMute()
+ }
+ }
+
+ private fun mute(isManual: Boolean = false) {
+ viewModel?.videoIsMuted = true
+ volume.setImageResource(R.drawable.ic_game_detail_volume_off)
+ CustomManager.getCustomManager(getKey()).isNeedMute = true
+ if (isManual) {
+ Utils.toast(context, "当前处于静音状态")
+ logVideoEvent("video_game_collect_detail_mute")
+ }
+ }
+
+ private fun unMute(isManual: Boolean = false) {
+ viewModel?.videoIsMuted = false
+ volume.setImageResource(R.drawable.ic_game_detail_volume_on)
+ CustomManager.getCustomManager(getKey()).isNeedMute = false
+ if (isManual) {
+ logVideoEvent("video_game_collect_detail_mute_cancel")
+ }
+ }
+
+ // 重载以减少横竖屏切换的时间
+ override fun checkoutState() {
+ removeCallbacks(mCheckoutTask)
+ postDelayed(mCheckoutTask, 300)
+ }
+
+ override fun clearFullscreenLayout() {
+ super.clearFullscreenLayout()
+ updateMuteStatus()
+ hideBackBtn()
+ }
+
+ fun updateThumb(url: String) {
+ Picasso.with(context).load(url).fit().into(findViewById(R.id.thumbImage))
+ }
+
+ override fun touchDoubleUp(e: MotionEvent?) {
+ // we do not need double click to play or pause
+ }
+
+ // 不需要弹弹窗,直接播放
+ override fun showWifiDialog() {
+ startPlayLogic(false)
+ //val trafficVideo = PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SettingsFragment.TRAFFIC_VIDEO_SP_KEY, false)
+ //if (trafficVideo) {
+ // 不延迟的话 isCacheFile 可能直接返回 false
+ postDelayed({
+ // 这个库的 NetworkUtils.isWifiConnected 可能会触发空指针,这里换为我们自己的
+ if (!com.shuyu.gsyvideoplayer.utils.NetworkUtils.isAvailable(mContext) && !gsyVideoManager.isCacheFile) {
+ Utils.toast(context, "网络异常,请检查手机网络状态")
+ } else if (!NetworkUtils.isWifiConnected(mContext) && !gsyVideoManager.isCacheFile) {
+ Utils.toast(context, "当前为非Wi-Fi环境,请注意流量消耗")
+ }
+ }, 100)
+ // }
+ }
+
+ override fun getGSYVideoManager(): GSYVideoViewBridge {
+ CustomManager.getCustomManager(getKey()).initContext(context.applicationContext)
+ return CustomManager.getCustomManager(getKey())
+ }
+
+ fun getKey(): String {
+ return uuid
+ }
+
+ override fun onAutoCompletion() {
+ // 这个方法在内核被释放时也会被回调,所以可以用来统计播放量和播放时长
+ val playedTime = (gsyVideoManager.currentPosition / 1000).toInt()
+
+ //播放完成后判断是否已缓冲完毕,没有完成显示播放错误状态
+ if (mBufferPoint != 0 && mBufferPoint != 100 && isShown) {
+ gsyVideoManager.releaseMediaPlayer()
+ changeUiToPreparingShow()
+ postDelayed({
+ if (!com.shuyu.gsyvideoplayer.utils.NetworkUtils.isAvailable(mContext)) {
+ Utils.toast(context, "网络错误,视频播放失败")
+ changeUiToError()
+ }
+ }, 10 * 1000)
+ }
+ logVideoEvent("video_game_collect_detail_stop", stopAction = "播放完毕")
+ super.onAutoCompletion()
+ }
+
+ override fun onStopTrackingTouch(seekBar: SeekBar?) {
+ super.onStopTrackingTouch(seekBar)
+ logVideoEvent("video_game_collect_detail_progress_drag")
+ }
+
+ override fun isShowNetConfirm(): Boolean {
+ return (!mOriginUrl.startsWith("file") && !mOriginUrl.startsWith("android.resource") && !CommonUtil.isWifiConnected(context)
+ && mNeedShowWifiTip)
+ }
+
+ override fun updateStartImage() {
+ if (mStartButton is ImageView) {
+ val imageView = mStartButton as ImageView
+ when (mCurrentState) {
+ GSYVideoView.CURRENT_STATE_PLAYING -> imageView.setImageResource(R.drawable.ic_game_detail_pause)
+ GSYVideoView.CURRENT_STATE_ERROR -> imageView.setImageResource(R.drawable.ic_game_detail_play)
+ else -> imageView.setImageResource(R.drawable.ic_game_detail_play)
+ }
+ }
+ }
+
+ override fun setStateAndUi(state: Int) {
+ super.setStateAndUi(state)
+
+ if (state == CURRENT_STATE_AUTO_COMPLETE) {
+ hideAllWidget()
+ replayContainer.visibility = View.VISIBLE
+ mTopContainer.visibility = View.VISIBLE
+ replayIv.setOnClickListener {
+ startButton.performClick()
+ violenceUpdateMuteStatus()
+ logVideoEvent("video_game_collect_detail_play", "再次播放")
+ }
+ updateThumb(video!!.poster)
+ } else {
+ replayContainer.visibility = View.GONE
+ }
+ }
+
+ private fun showBackBtn() {
+ mTopContainer.background = ContextCompat.getDrawable(context, R.drawable.video_title_bg)
+ back.visibility = View.VISIBLE
+ }
+
+ private fun hideBackBtn() {
+ mTopContainer?.setBackgroundResource(0)
+ back.visibility = View.GONE
+ }
+
+ override fun getEnlargeImageRes(): Int {
+ return R.drawable.ic_game_detail_enter_full_screen
+ }
+
+ override fun getShrinkImageRes(): Int {
+ return R.drawable.ic_game_detail_exit_full_screen
+ }
+
+ override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
+ if (!isIfCurrentIsFullscreen) {
+ parent.requestDisallowInterceptTouchEvent(true)
+ }
+ return super.onInterceptTouchEvent(ev)
+ }
+
+ /******************* 下方两个重载方法,在播放开始前不屏蔽封面,不需要可屏蔽 ********************/
+
+ override fun onSurfaceUpdated(surface: Surface) {
+ super.onSurfaceUpdated(surface)
+ if (mThumbImageViewLayout != null && mThumbImageViewLayout.visibility == View.VISIBLE) {
+ mThumbImageViewLayout.visibility = View.INVISIBLE
+ }
+ }
+
+ override fun setViewShowState(view: View?, visibility: Int) {
+ if (view === mThumbImageViewLayout && visibility != View.VISIBLE) {
+ return
+ }
+ super.setViewShowState(view, visibility)
+ }
+
+ /********************************各类UI的状态显示*********************************************/
+
+ override fun changeUiToNormal() {
+ super.changeUiToNormal()
+ errorContainer.visibility = View.GONE
+ }
+
+ override fun changeUiToPreparingShow() {
+ super.changeUiToPreparingShow()
+ errorContainer.visibility = View.GONE
+ }
+
+ override fun changeUiToPlayingShow() {
+ super.changeUiToPlayingShow()
+ errorContainer.visibility = View.GONE
+ }
+
+ override fun changeUiToPauseShow() {
+ super.changeUiToPauseShow()
+ errorContainer.visibility = View.GONE
+ }
+
+ override fun changeUiToCompleteShow() {
+ super.changeUiToCompleteShow()
+ errorContainer.visibility = View.GONE
+ }
+
+ override fun changeUiToError() {
+ super.changeUiToError()
+ setViewShowState(mStartButton, View.INVISIBLE)
+ errorContainer.visibility = View.VISIBLE
+ }
+
+ override fun netWorkErrorLogic() {
+ super.netWorkErrorLogic()
+ Utils.toast(context, "网络错误,视频播放失败")
+ setViewShowState(mStartButton, View.INVISIBLE)
+ errorContainer.visibility = View.VISIBLE
+ }
+
+ //监控播放错误
+ override fun onError(what: Int, extra: Int) {
+ super.onError(what, extra)
+ Utils.toast(context, "网络错误,视频播放失败")
+ setViewShowState(mStartButton, View.INVISIBLE)
+ errorContainer.visibility = View.VISIBLE
+ }
+
+ override fun releaseVideos() {
+ CustomManager.releaseAllVideos(getKey())
+ }
+
+ override fun onVideoPause() {
+ super.onVideoPause()
+ logVideoEvent("video_game_collect_detail_stop", stopAction = if (mIsManualStop) "手动停止" else "自动停止")
+ mIsManualStop = false
+ }
+
+ override fun onVideoResume() {
+ super.onVideoResume()
+ logVideoEvent("video_game_collect_detail_play", "继续播放")
+ }
+
+ override fun onClick(v: View) {
+ when (v.id) {
+ R.id.start -> {
+ when (currentState) {
+ GSYVideoView.CURRENT_STATE_PLAYING -> mIsManualStop = true
+
+ GSYVideoView.CURRENT_STATE_PAUSE -> logVideoEvent("video_game_collect_detail_play", "继续播放")
+ }
+ super.onClick(v)
+ }
+ else -> super.onClick(v)
+ }
+ }
+
+ fun getCurrentPosition(): Long {
+ return mCurrentPosition
+ }
+
+ fun logVideoEvent(event: String, playAction: String = "", stopAction: String = "") {
+ if (video == null || video?.url.isNullOrEmpty()) return
+ val videoPlayTs = currentPositionWhenPlaying / 1000
+ val videoTotalTime = duration / 1000
+ val progress = if (videoTotalTime != 0) videoPlayTs.toFloat() / videoTotalTime.toFloat() * 100 else 0f
+ //https://exoplayer.dev/hello-world.html#a-note-on-threading
+ runOnIoThread {
+ NewLogUtils.logGameCollectionVideoEvent(
+ event,
+ gameCollectionTitle,
+ gameCollectionId,
+ DecimalFormat("#.00").format(progress).toDouble(),
+ videoPlayTs,
+ playAction,
+ stopAction
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/conversation/GameCollectionCommentConversationAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/conversation/GameCollectionCommentConversationAdapter.kt
new file mode 100644
index 0000000000..f766c23e31
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/conversation/GameCollectionCommentConversationAdapter.kt
@@ -0,0 +1,93 @@
+package com.gh.gamecenter.gamecollection.detail.conversation
+
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.databinding.DataBindingUtil
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.util.*
+import com.gh.gamecenter.R
+import com.gh.gamecenter.databinding.ItemArticleDetailCommentBinding
+import com.gh.gamecenter.entity.CommentEntity
+import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailAdapter
+import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailViewModel
+
+class GameCollectionCommentConversationAdapter(
+ context: Context,
+ mViewModel: GameCollectionDetailViewModel,
+ type: AdapterType,
+ mEntrance: String,
+ commentClosure: ((CommentEntity) -> Unit)? = null
+) : GameCollectionDetailAdapter(context, type, mEntrance, mViewModel, commentClosure) {
+
+ var topCommentVH: TopCommentItemViewHolder? = null
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ return when (viewType) {
+ ITEM_COMMENT_TOP -> {
+ val binding: ItemArticleDetailCommentBinding =
+ DataBindingUtil.inflate(mLayoutInflater, R.layout.item_article_detail_comment, parent, false)
+ TopCommentItemViewHolder(binding).apply { topCommentVH = this }
+ }
+
+ else -> super.onCreateViewHolder(parent, viewType)
+ }
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ when (holder) {
+ is TopCommentItemViewHolder -> {
+ holder.bindView(mEntityList[position].commentTop!!)
+ }
+
+ else -> super.onBindViewHolder(holder, position)
+ }
+ }
+
+ inner class TopCommentItemViewHolder(var binding: ItemArticleDetailCommentBinding) : RecyclerView.ViewHolder(binding.root) {
+
+ fun bindView(comment: CommentEntity) {
+ ConstraintSet().apply {
+ clone(binding.contentTv.parent as ConstraintLayout)
+ clear(binding.contentTv.id, ConstraintSet.START)
+ connect(binding.contentTv.id, ConstraintSet.START, binding.userIconIv.id, ConstraintSet.START)
+
+ clear(binding.commentPictureRv.id, ConstraintSet.START)
+ connect(binding.commentPictureRv.id, ConstraintSet.START, binding.userIconIv.id, ConstraintSet.START)
+
+ clear(binding.floorHintTv.id, ConstraintSet.START)
+ connect(binding.floorHintTv.id, ConstraintSet.START, binding.userIconIv.id, ConstraintSet.START)
+
+ applyTo(binding.contentTv.parent as ConstraintLayout)
+ }
+ (binding.contentTv.layoutParams as ConstraintLayout.LayoutParams).apply {
+ topMargin = 16F.dip2px()
+ leftMargin = 9F.dip2px()
+ binding.contentTv.layoutParams = this
+ }
+
+ (binding.commentPictureRv.layoutParams as ConstraintLayout.LayoutParams).apply {
+ leftMargin = 9F.dip2px()
+ binding.commentPictureRv.layoutParams = this
+ }
+
+ (binding.floorHintTv.layoutParams as ConstraintLayout.LayoutParams).apply {
+ leftMargin = 9F.dip2px()
+ binding.floorHintTv.layoutParams = this
+ }
+
+ binding.comment = comment
+ binding.moreIv.visibility = View.GONE
+ binding.divider.visibility = View.VISIBLE
+ binding.commentCountTv.visibility = View.GONE
+ binding.floorHintTv.text = if (comment.floor != 0) "${comment.floor}楼" else ""
+ binding.contentTv.text = comment.content
+ binding.contentTv.maxLines = Int.MAX_VALUE
+
+ bindComment(binding, comment)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/conversation/GameCollectionCommentConversationFragment.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/conversation/GameCollectionCommentConversationFragment.kt
new file mode 100644
index 0000000000..e868027ac6
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/conversation/GameCollectionCommentConversationFragment.kt
@@ -0,0 +1,171 @@
+package com.gh.gamecenter.gamecollection.detail.conversation
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import com.ethanhua.skeleton.Skeleton
+import com.gh.common.AppExecutor
+import com.gh.common.syncpage.SyncDataEntity
+import com.gh.common.syncpage.SyncFieldConstants
+import com.gh.common.syncpage.SyncPageRepository
+import com.gh.common.util.*
+import com.gh.gamecenter.R
+import com.gh.gamecenter.baselist.ListAdapter
+import com.gh.gamecenter.baselist.LoadType
+import com.gh.gamecenter.databinding.FragmentArticleDetailCommentBinding
+import com.gh.gamecenter.entity.CommentEntity
+import com.gh.gamecenter.manager.UserManager
+import com.gh.gamecenter.qa.comment.base.BaseCommentAdapter
+import com.gh.gamecenter.qa.comment.base.BaseCommentFragment
+import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel
+import com.gh.gamecenter.qa.article.detail.CommentItemData
+import com.gh.gamecenter.qa.comment.CommentActivity
+import com.halo.assistant.HaloApp
+
+class GameCollectionCommentConversationFragment : BaseCommentFragment() {
+ private lateinit var mViewModel: GameCollectionCommentConversationViewModel
+ private lateinit var mBinding: FragmentArticleDetailCommentBinding
+ private var mAdapterCommunity: GameCollectionCommentConversationAdapter? = null
+
+ override fun getLayoutId() = R.layout.fragment_article_detail_comment
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ mViewModel = provideListViewModel()
+ super.onCreate(savedInstanceState)
+ mViewModel.getComment()
+ mViewModel.positionInOriginList = arguments?.getInt(EntranceUtils.KEY_POSITION)
+ ?: -1
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ initView()
+ initObserver()
+ }
+
+ override fun getInflatedLayout(): View {
+ return FragmentArticleDetailCommentBinding.inflate(LayoutInflater.from(requireContext()), null, false).apply { mBinding = this }.root
+ }
+
+ override fun provideListAdapter(): ListAdapter<*> {
+ return mAdapterCommunity
+ ?: GameCollectionCommentConversationAdapter(requireContext(), mViewModel, BaseCommentAdapter.AdapterType.SUB_COMMENT, mEntrance) {
+ if (it.user.id == UserManager.getInstance().userId) {
+ toast("不能回复自己")
+ } else {
+ startCommentActivity(it)
+ }
+ }.apply {
+ mAdapterCommunity = this
+ }
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ val commentCount = data?.getIntExtra(CommentActivity.COMMENT_COUNT, 0)
+ debounceActionWithInterval(Activity.RESULT_OK) {
+ if (commentCount != null && commentCount != 0) {
+ mViewModel.commentDetail?.reply = commentCount
+ mViewModel.commentCount = commentCount
+ mViewModel.load(LoadType.REFRESH)
+ mBinding.toolbarContainer.commentDialogCountTv.text = "${mViewModel.commentDetail?.reply}条回复"
+ SyncPageRepository.postSyncData(SyncDataEntity(mViewModel.commentId, SyncFieldConstants.ARTICLE_COMMENT_REPLY_COUNT, commentCount))
+ }
+ }
+ }
+
+ private fun initView() {
+ mSkeletonScreen = Skeleton.bind(skeletonView).shimmer(false).load(R.layout.fragment_article_detail_comment_skeleton).show()
+
+ mBinding.inputContainer.bottomCommentIv.visibility = View.GONE
+ mBinding.inputContainer.bottomCommentTv.visibility = View.GONE
+ mBinding.inputContainer.bottomLikeIv.visibility = View.GONE
+ mBinding.inputContainer.bottomLikeTv.visibility = View.GONE
+ mBinding.inputContainer.bottomStarIv.visibility = View.GONE
+ mBinding.inputContainer.bottomStarTv.visibility = View.GONE
+
+ mBinding.inputContainer.replyTv.setRoundedColorBackground(R.color.text_F0F0F0, 19F)
+ mBinding.inputContainer.replyTv.setDebouncedClickListener {
+ mViewModel.commentDetail?.let { startCommentActivity(it) }
+ }
+ mBinding.toolbarContainer.commentCloseIv.setOnClickListener { requireActivity().finish() }
+ }
+
+ @SuppressLint("SetTextI18n")
+ private fun initObserver() {
+ mViewModel.loadResultLiveData.observeNonNull(this) {
+ when (it) {
+ BaseCommentViewModel.LoadResult.SUCCESS -> {
+ mReuseNoConn?.visibility = View.GONE
+ mListLoading?.visibility = View.GONE
+
+ val showKeyboard = arguments?.getBoolean(EntranceUtils.KEY_SHOW_KEYBOARD_IF_NEEDED)
+ ?: false
+ if (showKeyboard) {
+ mBinding.inputContainer.replyTv.performClick()
+ }
+
+ mBinding.inputContainer.replyTv.text = "回复:${mViewModel.commentDetail?.user?.name}"
+ mBinding.toolbarContainer.commentDialogCountTv.text = "${mViewModel.commentDetail?.reply}条回复"
+ AppExecutor.uiExecutor.executeWithDelay(Runnable {
+ if ((mAdapterCommunity?.entityList?.size ?: 0) > 2) {
+ mListRv.smoothScrollToPosition(1)
+ }
+ }, 100)
+ }
+ else -> {
+ if (it == BaseCommentViewModel.LoadResult.DELETED) {
+ mReuseNoConn?.visibility = View.GONE
+ mReuseNoData?.visibility = View.VISIBLE
+ toast(R.string.content_delete_toast)
+ } else {
+ mReuseNoConn?.visibility = View.VISIBLE
+ mReuseNoData?.visibility = View.GONE
+ mReuseNoConn?.setOnClickListener {
+ mViewModel.getComment()
+ mReuseNoConn?.visibility = View.GONE
+ showSkeleton(true)
+ }
+ }
+
+ mListLoading?.visibility = View.GONE
+ mBinding.inputContainer.bottomContainer.visibility = View.GONE
+ mBinding.bottomShadowView.visibility = View.GONE
+ showSkeleton(false)
+ }
+ }
+ }
+ }
+
+ override fun provideListViewModel(): GameCollectionCommentConversationViewModel {
+ return viewModelProvider(
+ GameCollectionCommentConversationViewModel.Factory(
+ HaloApp.getInstance().application,
+ arguments?.getString(CommentActivity.GAME_COLLECTION_ID) ?: "",
+ arguments?.getString(EntranceUtils.KEY_COMMENT_ID) ?: ""
+ )
+ )
+ }
+
+ override fun onBackPressed(): Boolean {
+ requireActivity().finish()
+ return super.onBackPressed()
+ }
+
+ override fun onLoadDone() {
+ showSkeleton(false)
+ super.onLoadDone()
+ }
+
+ private fun startCommentActivity(comment: CommentEntity) {
+ val intent = CommentActivity.getGameCollectionCommentReplyIntent(requireContext(),
+ mViewModel.gameCollectionId,
+ arguments?.getString(EntranceUtils.KEY_COMMENT_ID) ?: "",
+ mViewModel.commentCount,
+ comment)
+ startActivityForResult(intent, CommentActivity.REQUEST_CODE)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/detail/conversation/GameCollectionCommentConversationViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/conversation/GameCollectionCommentConversationViewModel.kt
new file mode 100644
index 0000000000..411eaf376f
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/detail/conversation/GameCollectionCommentConversationViewModel.kt
@@ -0,0 +1,69 @@
+package com.gh.gamecenter.gamecollection.detail.conversation
+
+import android.annotation.SuppressLint
+import android.app.Application
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.gh.gamecenter.entity.CommentEntity
+import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailViewModel
+import com.gh.gamecenter.qa.article.detail.CommentItemData
+import com.gh.gamecenter.retrofit.BiResponse
+import io.reactivex.Single
+import io.reactivex.schedulers.Schedulers
+import retrofit2.HttpException
+
+class GameCollectionCommentConversationViewModel(application: Application,
+ gameCollectionId: String = "",
+ var commentId: String = "")
+ : GameCollectionDetailViewModel(application, gameCollectionId) {
+ var commentDetail: CommentEntity? = null
+ var positionInOriginList = -1
+
+ override fun provideDataObservable(page: Int) = null
+
+ override fun provideDataSingle(page: Int): Single> {
+ return mApi.getGameCollectionCommentReply(gameCollectionId, commentId, page)
+ }
+
+ @SuppressLint("CheckResult")
+ fun getComment() {
+ mApi.getGameCollectionComment(gameCollectionId, commentId)
+ .subscribeOn(Schedulers.io())
+ .subscribe(object : BiResponse() {
+ @SuppressLint("CheckResult")
+ override fun onSuccess(data: CommentEntity) {
+ commentDetail = data
+ commentDetail?.floor = positionInOriginList
+ commentCount = data.reply
+ topItemData = CommentItemData(commentTop = data)
+ loadResultLiveData.postValue(LoadResult.SUCCESS)
+ mergeListData(mListLiveData.value, hasFilter = false)
+ }
+
+ override fun onFailure(exception: Exception) {
+ if (exception is HttpException && exception.code().toString().contains("404")) {
+ loadResultLiveData.postValue(LoadResult.DELETED)
+ } else {
+ loadResultLiveData.postValue(LoadResult.NETWORK_ERROR)
+ }
+ }
+ })
+ }
+
+ override fun mergeResultLiveData() {
+ mResultLiveData.addSource(mListLiveData) { mergeListData(it, hasFilter = false) }
+ }
+
+
+ class Factory(private val application: Application,
+ private val gameCollectionId: String = "",
+ private val commentId: String) : ViewModelProvider.NewInstanceFactory() {
+
+ override fun create(modelClass: Class): T {
+ return GameCollectionCommentConversationViewModel(
+ application = application,
+ gameCollectionId = gameCollectionId,
+ commentId = commentId) as T
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/mine/MyGameCollectionActivity.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/mine/MyGameCollectionActivity.kt
new file mode 100644
index 0000000000..2836609f67
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/mine/MyGameCollectionActivity.kt
@@ -0,0 +1,18 @@
+package com.gh.gamecenter.gamecollection.mine
+
+import android.content.Context
+import android.content.Intent
+import com.gh.gamecenter.NormalActivity
+
+class MyGameCollectionActivity : NormalActivity() {
+
+ override fun provideNormalIntent(): Intent {
+ return getTargetIntent(this, MyGameCollectionActivity::class.java, MyGameCollectionFragment::class.java)
+ }
+
+ companion object {
+ fun getIntent(context: Context): Intent {
+ return getTargetIntent(context, MyGameCollectionActivity::class.java, MyGameCollectionFragment::class.java)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/mine/MyGameCollectionAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/mine/MyGameCollectionAdapter.kt
new file mode 100644
index 0000000000..3eab62f0f9
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/mine/MyGameCollectionAdapter.kt
@@ -0,0 +1,74 @@
+package com.gh.gamecenter.gamecollection.mine
+
+import android.content.Context
+import android.view.ViewGroup
+import androidx.core.content.ContextCompat
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.constant.ItemViewType
+import com.gh.common.util.DisplayUtils
+import com.gh.common.util.toBinding
+import com.gh.gamecenter.R
+import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
+import com.gh.gamecenter.baselist.ListAdapter
+import com.gh.gamecenter.entity.GamesCollectionEntity
+
+class MyGameCollectionAdapter(
+ context: Context,
+ val mViewModel: MyGameCollectionViewModel,
+ val entrance: String,
+ val path: String
+) : ListAdapter(context) {
+
+ override fun getItemViewType(position: Int): Int {
+ return if (position == itemCount - 1) {
+ ItemViewType.ITEM_FOOTER
+ } else {
+ ItemViewType.ITEM_BODY
+ }
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ return when (viewType) {
+ ItemViewType.ITEM_BODY -> MyGameCollectionViewHolder(parent.toBinding(), mViewModel, entrance, path)
+ ItemViewType.ITEM_FOOTER -> {
+ FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false))
+ }
+ else -> MyGameCollectionViewHolder(parent.toBinding(), mViewModel, entrance, path)
+ }
+ }
+
+ override fun areItemsTheSame(oldItem: GamesCollectionEntity?, newItem: GamesCollectionEntity?): Boolean {
+ return oldItem == newItem || oldItem?.id == newItem?.id
+ }
+
+ override fun areContentsTheSame(oldItem: GamesCollectionEntity?, newItem: GamesCollectionEntity?): Boolean {
+ return oldItem?.id == newItem?.id
+ && oldItem?.title == newItem?.title
+ && oldItem?.intro == newItem?.intro
+ && oldItem?.cover == newItem?.cover
+ && oldItem?.display == newItem?.display
+ && oldItem?.status == newItem?.status
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ when (holder) {
+ is MyGameCollectionViewHolder -> {
+ val entity = mEntityList[position]
+ holder.bindGameCollectionItem(entity)
+ }
+ is FooterViewHolder -> {
+ holder.initItemPadding()
+ holder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver)
+ holder.hint.setTextColor(ContextCompat.getColor(mContext, R.color.aaaaaa))
+ val lp = holder.itemView.layoutParams as RecyclerView.LayoutParams
+ lp.height = DisplayUtils.dip2px(48F)
+ lp.width = ViewGroup.LayoutParams.MATCH_PARENT
+ holder.itemView.layoutParams = lp
+ }
+ }
+ }
+
+ override fun getItemCount(): Int {
+ return if (mEntityList == null || mEntityList.isEmpty()) return 0 else mEntityList.size + 1
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/mine/MyGameCollectionFragment.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/mine/MyGameCollectionFragment.kt
new file mode 100644
index 0000000000..a6bd76620e
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/mine/MyGameCollectionFragment.kt
@@ -0,0 +1,105 @@
+package com.gh.gamecenter.gamecollection.mine
+
+import android.content.Intent
+import android.os.Bundle
+import android.view.MenuItem
+import android.view.View
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.constant.Constants
+import com.gh.common.util.NewLogUtils
+import com.gh.common.util.showRegulationTestDialogIfNeeded
+import com.gh.common.view.VerticalItemDecoration
+import com.gh.gamecenter.R
+import com.gh.gamecenter.WebActivity
+import com.gh.gamecenter.baselist.ListAdapter
+import com.gh.gamecenter.baselist.ListFragment
+import com.gh.gamecenter.baselist.LoadType
+import com.gh.gamecenter.databinding.FragmentMyGameCollectionListBinding
+import com.gh.gamecenter.entity.GamesCollectionEntity
+import com.gh.gamecenter.eventbus.EBReuse
+import com.gh.gamecenter.gamecollection.publish.GameCollectionEditActivity
+import com.gh.gamecenter.gamecollection.square.GameCollectionSquareActivity
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+
+class MyGameCollectionFragment : ListFragment() {
+
+ private var mAdapter: MyGameCollectionAdapter? = null
+ private lateinit var mBinding: FragmentMyGameCollectionListBinding
+
+ override fun getLayoutId(): Int = 0
+
+ override fun getInflatedLayout(): View {
+ return FragmentMyGameCollectionListBinding.inflate(layoutInflater, null, false).apply {
+ mBinding = this
+ }.root
+ }
+
+ override fun onMenuItemClick(menuItem: MenuItem?) {
+ super.onMenuItemClick(menuItem)
+ menuItem?.run {
+ if (itemId == R.id.menu_game_collection_square) {
+ startActivity(Intent(requireContext(), GameCollectionSquareActivity::class.java))
+ }
+ }
+ }
+
+ override fun provideListAdapter(): ListAdapter<*> {
+ return mAdapter ?: MyGameCollectionAdapter(requireContext(), mListViewModel, mEntrance, "我的游戏单").apply {
+ mAdapter = this
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ NewLogUtils.logEnterMyGameCollection()
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ setNavigationTitle("我的游戏单")
+ initMenu(R.menu.menu_my_game_collection)
+
+ mListViewModel.deleteLiveData.observe(viewLifecycleOwner) {
+ val index = mAdapter?.entityList?.indexOf(it) ?: -1
+ mAdapter?.entityList?.removeAt(index)
+ if (mAdapter?.entityList?.isNullOrEmpty() == true) {
+ onLoadEmpty()
+ } else {
+ mAdapter?.notifyItemRemoved(index)
+ }
+
+ toast("删除成功")
+ }
+
+ mListViewModel.publishLiveData.observe(viewLifecycleOwner) {
+ mListViewModel.load(LoadType.REFRESH)
+ }
+
+ mBinding.createBtn.setOnClickListener {
+ showRegulationTestDialogIfNeeded {
+ startActivity(GameCollectionEditActivity.getIntent(requireContext(), mEntrance, "我的游戏单"))
+ }
+ }
+
+ mBinding.reuseNoneDataIv.setOnClickListener {
+ mBinding.createBtn.performClick()
+ }
+
+ mBinding.specificationLinkTv.setOnClickListener {
+ startActivity(WebActivity.getWebIntent(requireContext(), "游戏单管理规范", Constants.GAME_COLLECTION_RULE))
+ }
+ }
+
+ override fun getItemDecoration(): RecyclerView.ItemDecoration {
+ return VerticalItemDecoration(requireContext(), 16F, true, R.color.white)
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ fun onEventMainThread(changed: EBReuse) {
+ if (changed.type == "createGameCollectionSuccess") {
+ mListViewModel.load(LoadType.REFRESH)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/mine/MyGameCollectionViewHolder.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/mine/MyGameCollectionViewHolder.kt
new file mode 100644
index 0000000000..5f8cf5878e
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/mine/MyGameCollectionViewHolder.kt
@@ -0,0 +1,87 @@
+package com.gh.gamecenter.gamecollection.mine
+
+import android.view.LayoutInflater
+import com.gh.base.BaseRecyclerViewHolder
+import com.gh.common.util.DialogHelper
+import com.gh.common.util.goneIf
+import com.gh.gamecenter.databinding.ItemGameCollectionFlexTagBinding
+import com.gh.gamecenter.databinding.ItemMyGameCollectionBinding
+import com.gh.gamecenter.entity.GamesCollectionEntity
+import com.gh.gamecenter.entity.TagInfoEntity
+import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
+import com.gh.gamecenter.gamecollection.publish.GameCollectionEditActivity
+
+class MyGameCollectionViewHolder(
+ val binding: ItemMyGameCollectionBinding,
+ val mViewModel: MyGameCollectionViewModel,
+ val entrance: String,
+ val path: String
+) :
+ BaseRecyclerViewHolder(binding.root) {
+
+ fun bindGameCollectionItem(entity: GamesCollectionEntity) {
+ binding.entity = entity
+ initTagsUI(entity.tags ?: arrayListOf())
+ val statusLabelRes = entity.getStatusLabelRes()
+ if (statusLabelRes > 0) {
+ binding.statusView.setImageResource(statusLabelRes)
+ }
+
+ binding.statusView.setOnClickListener {
+ when {
+ entity.display == "self_only" && entity.status == "draft" -> {
+ DialogHelper.showDialog(binding.root.context, "仅自己可见", "游戏单开启“仅自己可见”后,将不会对其他用户展示,您可以通过关闭仅自己可见或者投稿分享游戏单", "我知道了", "", {
+
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
+ }
+ entity.status == "pending" -> {
+ DialogHelper.showDialog(binding.root.context, "审核中", "游戏单会在1-2个工作日内审核完成,请您耐心等候", "我知道了", "", {
+
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
+ }
+ entity.status == "failed" -> {
+ DialogHelper.showDialog(binding.root.context, "未通过", "您的游戏单可能含有违规内容或语意不明确,请您仔细检查后再次尝试提交", "我知道了", "", {
+
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
+ }
+ }
+ }
+ binding.root.setOnClickListener {
+ if (entity.status == "pass" || (entity.display == "self_only" && entity.status == "draft")) {
+ binding.root.context.startActivity(GameCollectionDetailActivity.getIntent(binding.root.context, entity.id))
+ } else {
+ binding.statusView.performClick()
+ }
+ }
+
+ binding.publishBtn.setOnClickListener {
+ if ((entity.count?.game ?: 0) >= 8) {
+ DialogHelper.showDialog(binding.root.context, "温馨提示", "投稿通过后,将自动关闭“仅自己可见”,所有用户都能浏览到游戏单,确定投稿?", "确定", "取消", {
+ mViewModel.publishGameCollection(entity)
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
+ } else {
+ DialogHelper.showDialog(binding.root.context, "温馨提示", "游戏单需要收录至少8个游戏,才可以投稿至游戏单广场哦~", "添加游戏", "我知道了", {
+ binding.root.context.startActivity(GameCollectionEditActivity.getIntent(binding.root.context, entity, entrance, path))
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
+ }
+ }
+ binding.editBtn.setOnClickListener {
+ binding.root.context.startActivity(GameCollectionEditActivity.getIntent(binding.root.context, entity, entrance, path))
+ }
+ binding.deleteBtn.setOnClickListener {
+ DialogHelper.showDialog(binding.root.context, "温馨提示", "游戏单删除后将无法恢复,是否确认删除", "确定", "取消", {
+ mViewModel.deleteGameCollection(entity)
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
+ }
+ }
+
+ private fun initTagsUI(tags: ArrayList) {
+ binding.gameCollectionTagsContainer.removeAllViews()
+ tags.forEachIndexed { index, tag ->
+ val tagBinding = ItemGameCollectionFlexTagBinding.inflate(LayoutInflater.from(binding.root.context), null, false)
+ tagBinding.tagNameTv.text = tag.name
+ tagBinding.divider.goneIf(index == tags.size - 1)
+ binding.gameCollectionTagsContainer.addView(tagBinding.root)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/mine/MyGameCollectionViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/mine/MyGameCollectionViewModel.kt
new file mode 100644
index 0000000000..76811de00e
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/mine/MyGameCollectionViewModel.kt
@@ -0,0 +1,60 @@
+package com.gh.gamecenter.gamecollection.mine
+
+import android.app.Application
+import androidx.lifecycle.MutableLiveData
+import com.gh.common.util.ToastUtils
+import com.gh.common.util.observableToMain
+import com.gh.gamecenter.baselist.ListViewModel
+import com.gh.gamecenter.entity.GamesCollectionEntity
+import com.gh.gamecenter.manager.UserManager
+import com.gh.gamecenter.retrofit.Response
+import com.gh.gamecenter.retrofit.RetrofitManager
+import com.halo.assistant.HaloApp
+import io.reactivex.Observable
+import okhttp3.ResponseBody
+import retrofit2.HttpException
+
+class MyGameCollectionViewModel(application: Application) : ListViewModel(application) {
+ private val mApi = RetrofitManager.getInstance(HaloApp.getInstance()).api
+ val deleteLiveData = MutableLiveData()
+ val publishLiveData = MutableLiveData()
+ override fun provideDataObservable(page: Int): Observable>? {
+ return mApi.getGameCollectionList(UserManager.getInstance().userId)
+ }
+
+ override fun mergeResultLiveData() {
+ mResultLiveData.addSource(mListLiveData) { mResultLiveData.postValue(it) }
+ }
+
+ fun deleteGameCollection(entity: GamesCollectionEntity) {
+ mApi.deleteGameCollection(entity.id)
+ .compose(observableToMain())
+ .subscribe(object : Response() {
+ override fun onResponse(response: ResponseBody?) {
+ super.onResponse(response)
+ deleteLiveData.postValue(entity)
+ }
+
+ override fun onFailure(e: HttpException?) {
+ super.onFailure(e)
+ ToastUtils.showToast("删除失败")
+ }
+ })
+ }
+
+ fun publishGameCollection(entity: GamesCollectionEntity){
+ mApi.deleteGameCollection(entity.id)
+ .compose(observableToMain())
+ .subscribe(object : Response() {
+ override fun onResponse(response: ResponseBody?) {
+ super.onResponse(response)
+ publishLiveData.postValue(entity)
+ }
+
+ override fun onFailure(e: HttpException?) {
+ super.onFailure(e)
+ ToastUtils.showToast("投稿失败")
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/publish/GameCollectionEditActivity.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/publish/GameCollectionEditActivity.kt
new file mode 100644
index 0000000000..900f3ada7a
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/publish/GameCollectionEditActivity.kt
@@ -0,0 +1,439 @@
+package com.gh.gamecenter.gamecollection.publish
+
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.MenuItem
+import android.view.View
+import androidx.core.widget.doOnTextChanged
+import com.gh.base.ToolBarActivity
+import com.gh.base.fragment.WaitingDialogFragment
+import com.gh.common.constant.Constants
+import com.gh.common.util.*
+import com.gh.gamecenter.CropImageActivity
+import com.gh.gamecenter.R
+import com.gh.gamecenter.WebActivity
+import com.gh.gamecenter.databinding.ActivityGameCollectionEditBinding
+import com.gh.gamecenter.databinding.ItemGameCollectionFlexTagBinding
+import com.gh.gamecenter.entity.GameCollectionDraft
+import com.gh.gamecenter.entity.GamesCollectionEntity
+import com.gh.gamecenter.entity.TagInfoEntity
+import com.gh.gamecenter.eventbus.EBReuse
+import com.gh.gamecenter.gamecollection.choose.ChooseGamesActivity
+import com.gh.gamecenter.gamecollection.choose.ChooseGamesViewModel
+import com.gh.gamecenter.gamecollection.tag.GameCollectionTagSelectActivity
+import com.gh.gamecenter.gamecollection.tag.GameCollectionTagSelectFragment
+import com.gh.gamecenter.mvvm.Status
+import com.gh.gamecenter.qa.editor.LocalMediaActivity
+import com.zhihu.matisse.Matisse
+import com.zhihu.matisse.internal.utils.PathUtils
+import org.greenrobot.eventbus.EventBus
+
+class GameCollectionEditActivity : ToolBarActivity() {
+
+ private lateinit var mMenuPost: MenuItem
+ private lateinit var mBinding: ActivityGameCollectionEditBinding
+ private lateinit var mViewModel: GameCollectionEditViewModel
+ private lateinit var mChooseGamesViewModel: ChooseGamesViewModel
+ private var mProcessingDialog: WaitingDialogFragment? = null
+ private var mPatchCommitCount = 0
+
+ override fun getLayoutId(): Int = R.layout.activity_game_collection_edit
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ mBinding = ActivityGameCollectionEditBinding.bind(mContentView)
+ mViewModel = viewModelProvider()
+ mChooseGamesViewModel = viewModelProvider(ChooseGamesViewModel.Factory())
+ setToolbarMenu(R.menu.menu_game_collection_edit)
+ mMenuPost = getMenuItem(R.id.menu_game_collection_post)
+ setNavigationTitle("创建游戏单")
+ mViewModel.gameCollectionPatch = intent.getParcelableExtra(GamesCollectionEntity::class.java.name)
+ val path = intent.getStringExtra(EntranceUtils.KEY_PATH) ?: ""
+ if (path.isNotEmpty()) {
+ NewLogUtils.logEnterGameCollectionEdit(path)
+ }
+
+ initData()
+ observeData()
+ initListener()
+ }
+
+ private fun initListener() {
+ mBinding.gameCollectionTitleEt.run {
+ doOnTextChanged { text, start, _, _ ->
+ if (text?.contains("\n") == true) {
+ setText(text.toString().replace("\n", ""))
+ setSelection(start)
+ return@doOnTextChanged
+ }
+ if (PatternUtils.isHasSpace(text.toString())) {
+ setText(PatternUtils.replaceSpace(text.toString()))
+ setSelection(start)
+ return@doOnTextChanged
+ }
+ }
+ }
+ mBinding.gameCollectionIntroduceEt.run {
+ doOnTextChanged { text, start, _, _ ->
+ if (PatternUtils.isHasWrap(text.toString())) {
+ setText(PatternUtils.replaceWrap(text.toString()))
+ setSelection(start)
+ return@doOnTextChanged
+ }
+ if (PatternUtils.isHasSpace(text.toString())) {
+ setText(PatternUtils.replaceSpace(text.toString()))
+ setSelection(start)
+ return@doOnTextChanged
+ }
+ }
+ }
+ mBinding.uploadPictureBtn.setOnClickListener {
+ PermissionHelper.checkStoragePermissionBeforeAction(
+ this,
+ object : EmptyCallback {
+ override fun onCallback() {
+ startActivityForResult(
+ LocalMediaActivity.getIntent(
+ this@GameCollectionEditActivity,
+ LocalMediaActivity.ChooseType.IMAGE,
+ 1,
+ "创建游戏单"
+ ), REQUEST_CODE_IMAGE
+ )
+ }
+ })
+ }
+
+ mBinding.changePosterBtn.setOnClickListener { mBinding.uploadPictureBtn.performClick() }
+
+ mBinding.deleteBtn.setOnClickListener {
+ mViewModel.imageUrl = ""
+ mViewModel.imagePath = ""
+ mBinding.uploadPictureBtn.text = "点击上传图片"
+ initPosterUI()
+ }
+
+ mBinding.gameCollectionIntroduceEt.doOnTextChanged { text, _, _, _ ->
+ mBinding.introduceSizeTv.text = "${text?.length ?: 0}/200"
+ }
+
+ mBinding.chooseLabelContainer.setOnClickListener {
+ startActivityForResult(GameCollectionTagSelectActivity.getIntent(this), REQUEST_CHOOSE_TAG)
+ }
+
+ mBinding.chooseGameContainer.setOnClickListener {
+ startActivity(ChooseGamesActivity.getIntent(this))
+ }
+ mBinding.normsLinkTv.setOnClickListener {
+ startActivity(WebActivity.getWebIntent(this, "游戏单管理规范", Constants.GAME_COLLECTION_RULE))
+ }
+ }
+
+ private fun initData(isFirst: Boolean = true) {
+ mBinding.gameCollectionTitleEt.filters = arrayOf(TextHelper.getFilter(20, "最多输入20个字"))
+ mBinding.gameCollectionIntroduceEt.filters = arrayOf(TextHelper.getFilter(200, "最多输入200个字"))
+ initTagsUI(mViewModel.tags)
+
+ mViewModel.gameCollectionPatch?.run {
+ mViewModel.imageUrl = cover
+ if (status.isNotEmpty() && (status != "draft" || display == "self_only")) {
+ setNavigationTitle("编辑游戏单")
+ }
+ initPosterUI()
+ mBinding.gameCollectionTitleEt.setText(title)
+ mBinding.gameCollectionTitleEt.setSelection(title.length)
+ mBinding.gameCollectionIntroduceEt.setText(intro)
+ mBinding.gameCollectionIntroduceEt.setSelection(intro.length)
+ mBinding.selfOnlyCb.isChecked = display == "self_only"
+ if (isFirst) {
+ mViewModel.getGameCollectionDetail(id)
+ }
+ } ?: mViewModel.getDraft()
+ }
+
+ private fun observeData() {
+ mChooseGamesViewModel.chooseGamesLiveData.observe(this) {
+ mBinding.gamesTv.text = if (it.isEmpty()) "选择游戏" else "已选 ${it.size} 款游戏"
+ mBinding.gamesTipTv.goneIf(it.isNotEmpty())
+ }
+ mViewModel.processDialog.observe(this) {
+ if (it.isShow) {
+ if (mProcessingDialog?.dialog?.isShowing == true) {
+ mProcessingDialog?.uploadWaitingHint(it.msg)
+ } else {
+ mProcessingDialog = WaitingDialogFragment.newInstance(it.msg, false)
+ mProcessingDialog?.show(supportFragmentManager, null)
+ }
+ } else {
+ mProcessingDialog?.dismiss()
+ }
+ }
+ mViewModel.uploadImageSuccessLiveData.observe(this) {
+ if (it.isNotEmpty()) {
+ initPosterUI()
+ }
+ mBinding.uploadPictureBtn.text = "点击上传图片"
+ }
+ mViewModel.postLiveData.observe(this) {
+ if (it.status == Status.SUCCESS) {
+ toast("提交成功")
+ EventBus.getDefault().post(EBReuse("createGameCollectionSuccess"))
+ finish()
+ } else {
+ ErrorHelper.handleError(this, it.exception?.response()?.errorBody()?.string())
+ }
+ }
+ mViewModel.detailLiveData.observe(this) {
+ mViewModel.gameCollectionPatch?.apply {
+ games = it.games
+ tags = it.tags
+ title = it.title
+ intro = it.intro
+ }
+ mViewModel.gameCollectionPatch?.run {
+ initData(false)
+ mViewModel.tags = tags ?: arrayListOf()
+ initTagsUI(mViewModel.tags)
+ val simpleGames = games?.map { game -> game.toGameEntity() }?.toList()
+ mChooseGamesViewModel.chooseGamesLiveData.postValue(ArrayList(simpleGames))
+ }
+ }
+ mViewModel.draftLiveData.observe(this) {
+ mViewModel.gameCollectionPatch = it.convertGameCollectionEntity()
+ mViewModel.gameCollectionPatch?.run {
+ initData(false)
+ mViewModel.tags = tags ?: arrayListOf()
+ initTagsUI(mViewModel.tags)
+ val simpleGames = games?.map { game -> game.toGameEntity() }
+ mChooseGamesViewModel.chooseGamesLiveData.postValue(ArrayList(simpleGames))
+ }
+ }
+ }
+
+ override fun onMenuItemClick(item: MenuItem?): Boolean {
+ item?.run {
+ if (itemId == R.id.menu_game_collection_post) {
+ debounceActionWithInterval(R.id.menu_game_collection_post, 3000L) {
+ verifyData()
+ }
+ }
+ }
+ return super.onMenuItemClick(item)
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ if (data == null || resultCode != Activity.RESULT_OK) return
+ when (requestCode) {
+ REQUEST_CODE_IMAGE -> {
+ val selectedPaths = Matisse.obtainResult(data)
+ if (!selectedPaths.isNullOrEmpty()) {
+ val path = PathUtils.getPath(this, selectedPaths[0])
+ val intent = CropImageActivity.getIntent(this, path, 142 / 328F, false, mEntrance)
+ startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP)
+ }
+ }
+ REQUEST_CODE_IMAGE_CROP -> {
+ val imagePath = data.getStringExtra(CropImageActivity.RESULT_CLIP_PATH) ?: ""
+ mViewModel.imageUrl = ""
+ mViewModel.imagePath = imagePath
+ if (imagePath.isEmpty()) {
+ mBinding.uploadPictureBtn.text = "点击上传图片"
+ } else {
+ mBinding.uploadPictureBtn.text = "图片上传中..."
+ mViewModel.uploadPoster()
+ }
+ initPosterUI()
+ }
+ REQUEST_CHOOSE_TAG -> {
+ val tags = data.getParcelableArrayListExtra(GameCollectionTagSelectFragment.SELECTED_TAG) ?: arrayListOf()
+ mViewModel.tags = tags
+ initTagsUI(tags)
+ }
+ }
+ }
+
+ private fun initPosterUI() {
+ mBinding.placeholderView.goneIf(mViewModel.imageUrl.isNotEmpty())
+ mBinding.uploadPictureBtn.goneIf(mViewModel.imageUrl.isNotEmpty())
+ mBinding.posterView.goneIf(mViewModel.imageUrl.isEmpty())
+ mBinding.changePosterBtn.goneIf(mViewModel.imageUrl.isEmpty())
+ mBinding.deleteBtn.goneIf(mViewModel.imageUrl.isEmpty())
+ if (mViewModel.imageUrl.isNotEmpty()) {
+ ImageUtils.display(mBinding.posterView, mViewModel.imageUrl)
+ }
+ }
+
+ private fun initTagsUI(tags: ArrayList) {
+ mBinding.gameCollectionTagsContainer.removeAllViews()
+ mBinding.labelTipTv.goneIf(tags.isNotEmpty())
+ if (tags.isEmpty()) {
+ val tagBinding = ItemGameCollectionFlexTagBinding.inflate(LayoutInflater.from(this), null, false)
+ tagBinding.tagNameTv.run {
+ text = "选择标签"
+ setTextColor(R.color.text_333333.toColor())
+ textSize = 14f
+ }
+ tagBinding.divider.visibility = View.GONE
+ mBinding.gameCollectionTagsContainer.addView(tagBinding.root)
+ } else {
+ tags.forEachIndexed { index, tag ->
+ val tagBinding = ItemGameCollectionFlexTagBinding.inflate(LayoutInflater.from(this), null, false)
+ tagBinding.tagNameTv.run {
+ text = tag.name
+ setTextColor(R.color.text_333333.toColor())
+ textSize = 14f
+ }
+ tagBinding.divider.run {
+ alpha = 0.2f
+ setBackgroundColor(R.color.text_333333.toColor())
+ goneIf(index == tags.size - 1)
+ setPadding(8f.dip2px(), 0, 8f.dip2px(), 0)
+ }
+ mBinding.gameCollectionTagsContainer.addView(tagBinding.root)
+ }
+ }
+ }
+
+ override fun handleBackPressed(): Boolean {
+ val patch = mViewModel.gameCollectionPatch
+ if (patch != null && patch.status.isNotEmpty() && (patch.status != "draft" || patch.display == "self_only")) {
+ DialogHelper.showDialog(this, "温馨提示", "退出将不会保留本次游戏单编辑的内容,是否确定退出", "确定", "取消", {
+ finish()
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
+ return true
+ } else {
+ val games = mChooseGamesViewModel.chooseGamesLiveData.value ?: arrayListOf()
+ val title = mBinding.gameCollectionTitleEt.text.toString()
+ val introduce = mBinding.gameCollectionIntroduceEt.text.toString()
+ if (mViewModel.imageUrl.isNotEmpty()
+ || mViewModel.tags.isNotEmpty()
+ || games.isNotEmpty()
+ || title.isNotEmpty()
+ || introduce.isNotEmpty()
+ ) {
+ val entity = GameCollectionDraft()
+ entity.tags = mViewModel.tags
+ entity.title = title
+ entity.intro = introduce
+ entity.cover = mViewModel.imageUrl
+ entity.display = if (mBinding.selfOnlyCb.isChecked) "self_only" else ""
+ entity.games = arrayListOf()
+ entity.games?.addAll(games.map { it.toSimpleGame() }.toList())
+ mViewModel.addDraft(entity)
+ }
+ }
+ return super.handleBackPressed()
+ }
+
+ private fun verifyData() {
+ if (mViewModel.imageUrl.isEmpty()) {
+ toast("请上传游戏单的封面")
+ return
+ }
+ if (mViewModel.tags.isEmpty()) {
+ toast("请选择游戏单的标签")
+ return
+ }
+ val games = mChooseGamesViewModel.chooseGamesLiveData.value ?: arrayListOf()
+
+ val title = mBinding.gameCollectionTitleEt.text.toString().trim()
+ if (title.isEmpty()) {
+ toast("请填写游戏单的标题")
+ return
+ }
+ val introduce = mBinding.gameCollectionIntroduceEt.text.toString().trim()
+ if (introduce.length < 10) {
+ toast("介绍至少10个字")
+ return
+ }
+
+ val isSelfOnly = mBinding.selfOnlyCb.isChecked
+ val requestMap = hashMapOf(
+ "id" to (mViewModel.gameCollectionPatch?.id ?: ""),
+ "title" to title,
+ "intro" to introduce,
+ "tag_ids" to mViewModel.tags.map { it.id }.toList(),
+ "cover" to mViewModel.imageUrl,
+ "display" to if (isSelfOnly) "self_only" else "",
+ "games" to games.map {
+ hashMapOf(
+ "_id" to it.id,
+ "recommend_star" to it.recommendStar,
+ "recommend_text" to it.recommendText,
+ )
+ }.toList()
+ )
+
+ val patch = mViewModel.gameCollectionPatch
+ if (patch != null
+ && patch.status.isNotEmpty()
+ && patch.status != "draft"
+ && games.size < 8
+ ) {
+ if (mPatchCommitCount < 2) {
+ toast("游戏单收录的游戏不能少于8款")
+ mPatchCommitCount++
+ return
+ } else {
+ if (!mBinding.selfOnlyCb.isChecked) {
+ toast("没想好收录的游戏,开启仅自己可见试试")
+ mPatchCommitCount++
+ return
+ }
+ }
+ }
+
+ if (isSelfOnly) {
+ DialogHelper.showDialog(this, "温馨提示", "游戏单开启“仅自己可见”后,将不会对其他用户展示,是否继续提交", "确定", "取消", {
+ mViewModel.uploadContent(requestMap)
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
+ } else {
+ if (games.size < 8) {
+ DialogHelper.showDialog(this, "温馨提示", "游戏单需要收录至少8个游戏,才可以投稿至游戏单广场,是否在“我的光环-我的游戏单”继续保存为草稿", "继续保存", "添加游戏", {
+ mViewModel.uploadContent(requestMap)
+ }, {
+ startActivity(ChooseGamesActivity.getIntent(this))
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
+ } else {
+ DialogHelper.showDialog(this, "温馨提示", "游戏单会在1-2个工作日内审核完成,您可以在“我的光环-我的游戏单”查看进度", "继续提交", "取消", {
+ mViewModel.uploadContent(requestMap)
+ }, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
+ }
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ mChooseGamesViewModel.chooseGamesLiveData.postValue(arrayListOf())
+ }
+
+
+ companion object {
+
+ const val REQUEST_CODE_IMAGE = 100
+ const val REQUEST_CODE_IMAGE_CROP = 101
+ const val REQUEST_CHOOSE_GAMES = 102
+ const val REQUEST_CHOOSE_TAG = 103
+
+ @JvmStatic
+ fun getIntent(context: Context, entrance: String = "", path: String = ""): Intent {
+ val intent = Intent(context, GameCollectionEditActivity::class.java)
+ intent.putExtra(EntranceUtils.KEY_ENTRANCE, mergeEntranceAndPath(entrance, path))
+ intent.putExtra(EntranceUtils.KEY_PATH, path)
+ return intent
+ }
+
+ @JvmStatic
+ fun getIntent(context: Context, entity: GamesCollectionEntity, entrance: String = "", path: String = ""): Intent {
+ val intent = Intent(context, GameCollectionEditActivity::class.java)
+ intent.putExtra(GamesCollectionEntity::class.java.name, entity)
+ intent.putExtra(EntranceUtils.KEY_ENTRANCE, mergeEntranceAndPath(entrance, path))
+ intent.putExtra(EntranceUtils.KEY_PATH, path)
+ return intent
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/publish/GameCollectionEditViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/publish/GameCollectionEditViewModel.kt
new file mode 100644
index 0000000000..2e3e2f061a
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/publish/GameCollectionEditViewModel.kt
@@ -0,0 +1,139 @@
+package com.gh.gamecenter.gamecollection.publish
+
+import android.annotation.SuppressLint
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.MediatorLiveData
+import androidx.lifecycle.MutableLiveData
+import com.gh.base.fragment.WaitingDialogFragment
+import com.gh.common.runOnIoThread
+import com.gh.common.util.*
+import com.gh.gamecenter.entity.GameCollectionDraft
+import com.gh.gamecenter.entity.GamesCollectionEntity
+import com.gh.gamecenter.entity.TagInfoEntity
+import com.gh.gamecenter.mvvm.Resource
+import com.gh.gamecenter.retrofit.BiResponse
+import com.gh.gamecenter.retrofit.Response
+import com.gh.gamecenter.retrofit.RetrofitManager
+import com.gh.gamecenter.room.AppDatabase
+import com.halo.assistant.HaloApp
+import okhttp3.ResponseBody
+import org.json.JSONObject
+import retrofit2.HttpException
+
+class GameCollectionEditViewModel(application: Application) : AndroidViewModel(application) {
+ var imagePath = ""
+ var imageUrl = ""
+ var tags = ArrayList()
+ var gameCollectionPatch: GamesCollectionEntity? = null
+ var uploadImageSuccessLiveData = MutableLiveData()
+ var detailLiveData = MutableLiveData()
+ var draftLiveData = MutableLiveData()
+ val postLiveData = MutableLiveData>()
+ val processDialog = MediatorLiveData()
+ private val mApi = RetrofitManager.getInstance(HaloApp.getInstance()).api
+ private val mDraftDao = AppDatabase.getInstance(HaloApp.getInstance()).gameCollectionDraftDao()
+
+ fun uploadPoster() {
+ if (imagePath.isEmpty()) return
+ UploadImageUtils.uploadImage(UploadImageUtils.UploadType.poster, imagePath, object : UploadImageUtils.OnUploadImageListener {
+ override fun onSuccess(imageUrl: String) {
+ this@GameCollectionEditViewModel.imageUrl = imageUrl
+ uploadImageSuccessLiveData.postValue(imageUrl)
+ }
+
+ override fun onError(e: Throwable?) {
+ uploadImageSuccessLiveData.postValue("")
+ ToastUtils.showToast("图片上传失败")
+ }
+
+ override fun onProgress(total: Long, progress: Long) {}
+ })
+ }
+
+ fun uploadContent(requestMap: HashMap) {
+ val id = requestMap["id"]?.toString() ?: ""
+ requestMap.remove("id")
+ postContent(requestMap, id)
+ }
+
+ private fun postContent(requestMap: HashMap, gameCollectionId: String) {
+ processDialog.postValue(WaitingDialogFragment.WaitingDialogData("提交中...", true))
+ val requestBody = requestMap.toRequestBody()
+ val observable = if (gameCollectionId.isEmpty()) {
+ mApi.createGameCollection(requestBody)
+ } else {
+ mApi.patchGameCollection(requestBody, gameCollectionId)
+ }
+ observable
+ .compose(observableToMain())
+ .subscribe(object : Response() {
+ override fun onResponse(response: ResponseBody?) {
+ super.onResponse(response)
+ val data = response?.string()
+ val id = if (!data.isNullOrEmpty()) {
+ JSONObject(data).optString("_id")
+ } else ""
+ postLiveData.postValue(Resource.success(id))
+ processDialog.postValue(WaitingDialogFragment.WaitingDialogData("", false))
+ deleteAllDraft()
+ }
+
+ override fun onFailure(e: HttpException?) {
+ super.onFailure(e)
+ postLiveData.postValue(Resource.error(e))
+ processDialog.postValue(WaitingDialogFragment.WaitingDialogData("", false))
+ }
+ })
+ }
+
+ fun getGameCollectionDetail(gameCollectionId: String) {
+ if (gameCollectionId.isEmpty()) return
+ processDialog.postValue(WaitingDialogFragment.WaitingDialogData("加载中...", true))
+ mApi.getGameCollectionDetailForDraft(gameCollectionId)
+ .compose(observableToMain())
+ .subscribe(object : Response() {
+ override fun onResponse(response: GamesCollectionEntity?) {
+ super.onResponse(response)
+ if (response != null) {
+ detailLiveData.postValue(response)
+ processDialog.postValue(WaitingDialogFragment.WaitingDialogData("", false))
+ }
+ }
+
+ override fun onFailure(e: HttpException?) {
+ super.onFailure(e)
+ processDialog.postValue(WaitingDialogFragment.WaitingDialogData("", false))
+ }
+ })
+ }
+
+ @SuppressLint("CheckResult")
+ fun getDraft() {
+ mDraftDao.getAllDraft()
+ .compose(singleToMain())
+ .subscribe(object : BiResponse>() {
+ override fun onSuccess(data: List) {
+ if (data.isNotEmpty()) {
+ val draftEntity = data[0]
+ draftLiveData.postValue(draftEntity)
+ }
+ }
+ })
+ }
+
+ fun addDraft(entity: GameCollectionDraft) {
+ runOnIoThread {
+ val drafts = mDraftDao.getDrafts()
+ mDraftDao.delete(drafts)
+ mDraftDao.addDraft(entity)
+ }
+ }
+
+ fun deleteAllDraft(){
+ runOnIoThread {
+ val drafts = mDraftDao.getDrafts()
+ mDraftDao.delete(drafts)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionAmwayAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionAmwayAdapter.kt
new file mode 100644
index 0000000000..9fc148d7ec
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionAmwayAdapter.kt
@@ -0,0 +1,54 @@
+package com.gh.gamecenter.gamecollection.square
+
+import android.content.Context
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.util.TextHelper
+import com.gh.gamecenter.R
+import com.gh.gamecenter.databinding.GameCollectionAmwayContentItemBinding
+import com.gh.gamecenter.entity.AmwayCommentEntity
+import com.lightgame.adapter.BaseRecyclerAdapter
+
+class GameCollectionAmwayAdapter(context: Context) :
+ BaseRecyclerAdapter(context) {
+
+ private var mAmwayList = listOf()
+
+ fun setAmwayList(amwayList: List) {
+ mAmwayList = amwayList
+ notifyDataSetChanged()
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
+ GameCollectionAmwayContentItemViewHolder(GameCollectionAmwayContentItemBinding.inflate(mLayoutInflater, parent, false))
+
+ override fun getItemCount() = if (getRealCount() > 1) getRealCount() + INCREASE_COUNT else getRealCount()
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ if (holder is GameCollectionAmwayContentItemViewHolder) {
+ holder.binding.entity = mAmwayList[getRealPosition(position)]
+ holder.binding.amwayTv.text = TextHelper.getCommentLabelSpannableStringBuilder(mAmwayList[getRealPosition(position)].comment.content, R.color.white)
+ }
+ }
+
+ class GameCollectionAmwayContentItemViewHolder(var binding: GameCollectionAmwayContentItemBinding) :
+ RecyclerView.ViewHolder(binding.root)
+
+ fun getRealCount(): Int = mAmwayList.size
+
+ fun getRealPosition(position: Int) = when (position) {
+ 0 -> {
+ getRealCount() - 1
+ }
+ getRealCount() + 1 -> {
+ 0
+ }
+ else -> {
+ position - 1
+ }
+ }
+
+ companion object{
+ const val INCREASE_COUNT = 2
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionAmwayViewHolder.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionAmwayViewHolder.kt
new file mode 100644
index 0000000000..a7f8d3ce6b
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionAmwayViewHolder.kt
@@ -0,0 +1,114 @@
+package com.gh.gamecenter.gamecollection.square
+
+import android.animation.Animator
+import android.animation.TimeInterpolator
+import android.animation.ValueAnimator
+import android.view.animation.AccelerateDecelerateInterpolator
+import androidx.recyclerview.widget.RecyclerView
+import androidx.viewpager2.widget.ViewPager2
+import com.gh.common.util.DirectUtils
+import com.gh.common.util.NewLogUtils
+import com.gh.gamecenter.databinding.GameCollectionSquareAmwayItemBinding
+import com.gh.gamecenter.entity.AmwayCommentEntity
+import java.lang.ref.WeakReference
+
+class GameCollectionAmwayViewHolder(var binding: GameCollectionSquareAmwayItemBinding) : RecyclerView.ViewHolder(binding.root) {
+ val mAdapter = GameCollectionAmwayAdapter(binding.root.context)
+ val mLoopTask = object : Runnable {
+ private val reference: WeakReference = WeakReference(binding.amwayVp)
+ override fun run() {
+ val vp: ViewPager2? = reference.get()
+ if (vp != null) {
+ val count = mAdapter.itemCount
+ if (count == 0) return
+ val next = (vp.currentItem + 1) % count
+ vp.setCurrentItem(next, 1000)
+ vp.postDelayed(this, AMWAY_LOOP_TIME)
+ }
+ }
+ }
+
+ fun bindAmway(amwayList: List) {
+ mAdapter.setAmwayList(amwayList)
+ binding.amwayVp.run {
+ if (adapter is GameCollectionAmwayAdapter) return
+ isUserInputEnabled = false
+ adapter = mAdapter
+ orientation = ViewPager2.ORIENTATION_VERTICAL
+ registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
+ private var mTempPosition = GameCollectionSquareAdapter.INVALID_VALUE
+ private var isScrolled = false
+
+ override fun onPageSelected(position: Int) {
+ if (isScrolled) {
+ mTempPosition = position
+ }
+ }
+
+ override fun onPageScrollStateChanged(state: Int) {
+ //手势滑动中,代码执行滑动中
+ if (state == ViewPager2.SCROLL_STATE_DRAGGING || state == ViewPager2.SCROLL_STATE_SETTLING) {
+ isScrolled = true
+ } else if (state == ViewPager2.SCROLL_STATE_IDLE) {
+ //滑动闲置或滑动结束
+ isScrolled = false
+ if (mTempPosition != GameCollectionSquareAdapter.INVALID_VALUE) {
+ if (mTempPosition == 0) {
+ setCurrentItem(mAdapter.getRealCount(), false)
+ } else if (mTempPosition == mAdapter.itemCount - 1) {
+ setCurrentItem(1, false)
+ }
+ }
+ }
+ }
+ })
+ setCurrentItem(1, false)
+ postDelayed(mLoopTask, AMWAY_LOOP_TIME)
+ }
+ binding.root.setOnClickListener {
+ NewLogUtils.logClickGameCollectionAmway()
+ DirectUtils.directToAmway(binding.root.context)
+ NewLogUtils.logEnterGameCollectionAmway()
+ }
+ }
+
+ fun start() {
+ stop()
+ binding.amwayVp.postDelayed(mLoopTask, AMWAY_LOOP_TIME)
+ }
+
+ fun stop() {
+ binding.amwayVp.removeCallbacks(mLoopTask)
+ }
+
+ fun ViewPager2.setCurrentItem(
+ item: Int,
+ duration: Long,
+ interpolator: TimeInterpolator = AccelerateDecelerateInterpolator(),
+ pagePxHeight: Int = height
+ ) {
+ val pxToDrag: Int = pagePxHeight * (item - currentItem)
+ val animator = ValueAnimator.ofInt(0, pxToDrag)
+ var previousValue = 0
+ animator.addUpdateListener { valueAnimator ->
+ val currentValue = valueAnimator.animatedValue as Int
+ val currentPxToDrag = (currentValue - previousValue).toFloat()
+ fakeDragBy(-currentPxToDrag)
+ previousValue = currentValue
+ }
+ animator.addListener(object : Animator.AnimatorListener {
+ override fun onAnimationStart(animation: Animator?) { beginFakeDrag() }
+ override fun onAnimationEnd(animation: Animator?) { endFakeDrag() }
+ override fun onAnimationCancel(animation: Animator?) { }
+ override fun onAnimationRepeat(animation: Animator?) { }
+ })
+ animator.interpolator = interpolator
+ animator.duration = duration
+ animator.start()
+ }
+
+ companion object {
+ // 安利墙卡片轮播时间
+ const val AMWAY_LOOP_TIME = 5000L
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionListItemData.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionListItemData.kt
new file mode 100644
index 0000000000..8a0852d932
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionListItemData.kt
@@ -0,0 +1,7 @@
+package com.gh.gamecenter.gamecollection.square
+
+import com.gh.gamecenter.entity.GamesCollectionEntity
+import com.gh.gamecenter.home.LegacyHomeItemData
+
+data class GameCollectionListItemData(var gameCollectionItem: GamesCollectionEntity? = null, var gameStartPosition: Int = 0) :
+ LegacyHomeItemData()
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareActivity.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareActivity.kt
new file mode 100644
index 0000000000..d61d327fba
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareActivity.kt
@@ -0,0 +1,23 @@
+package com.gh.gamecenter.gamecollection.square
+
+import android.os.Bundle
+import com.gh.base.BaseActivity
+import com.gh.common.util.DisplayUtils
+import com.gh.gamecenter.R
+
+class GameCollectionSquareActivity : BaseActivity() {
+ override fun getLayoutId(): Int {
+ return R.layout.activity_amway
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ DisplayUtils.transparentStatusBar(this)
+
+ val containerFragment = supportFragmentManager.findFragmentByTag(
+ GameCollectionSquareFragment::class.java.simpleName)
+ ?: GameCollectionSquareFragment().with(intent.extras)
+ supportFragmentManager.beginTransaction().replace(R.id.placeholder, containerFragment, GameCollectionSquareFragment::class.java.simpleName).commitAllowingStateLoss()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareAdapter.kt
new file mode 100644
index 0000000000..90adeb1433
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareAdapter.kt
@@ -0,0 +1,237 @@
+package com.gh.gamecenter.gamecollection.square
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.graphics.Color
+import android.util.SparseArray
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+import androidx.core.graphics.drawable.toDrawable
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.base.BaseActivity
+import com.gh.common.constant.ItemViewType
+import com.gh.common.exposure.ExposureEvent
+import com.gh.common.exposure.ExposureSource
+import com.gh.common.exposure.IExposable
+import com.gh.common.util.*
+import com.gh.gamecenter.GameDetailActivity
+import com.gh.gamecenter.R
+import com.gh.gamecenter.adapter.viewholder.FooterViewHolder
+import com.gh.gamecenter.baselist.ListAdapter
+import com.gh.gamecenter.databinding.GameCollectionSquareAmwayItemBinding
+import com.gh.gamecenter.databinding.GameCollectionSquareItemBinding
+import com.gh.gamecenter.entity.AmwayCommentEntity
+import com.gh.gamecenter.entity.GamesCollectionEntity
+import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
+
+class GameCollectionSquareAdapter(
+ context: Context,
+ private val isHome: Boolean = false,
+ private val mViewModel: GameCollectionSquareViewModel,
+ private var mBasicExposureSource: List,
+ private val mOuterSequence: Int = -1
+) :
+ ListAdapter(context), IExposable {
+
+ private var mAmwayList = listOf()
+
+ fun setAmwayList(amwayList: List) {
+ if (isHome) {
+ mAmwayList = amwayList
+ notifyItemChanged(0)
+ }
+ }
+
+ override fun getItemViewType(position: Int): Int {
+ return if (isHome && position == 0) ItemViewType.ITEM_HEADER else if (position == itemCount - 1) ItemViewType.ITEM_FOOTER else ItemViewType.ITEM_BODY
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ return when (viewType) {
+ ItemViewType.ITEM_HEADER -> {
+ GameCollectionAmwayViewHolder(
+ GameCollectionSquareAmwayItemBinding.bind(
+ mLayoutInflater.inflate(
+ R.layout.game_collection_square_amway_item,
+ parent,
+ false
+ )
+ )
+ )
+ }
+
+ ItemViewType.ITEM_BODY -> {
+ GameCollectionSquareItemViewHolder(
+ GameCollectionSquareItemBinding.bind(
+ mLayoutInflater.inflate(
+ R.layout.game_collection_square_item,
+ parent,
+ false
+ )
+ )
+ )
+ }
+
+ ItemViewType.ITEM_FOOTER -> FooterViewHolder(
+ mLayoutInflater.inflate(
+ R.layout.refresh_footerview,
+ parent,
+ false
+ )
+ )
+
+ else -> GameCollectionSquareItemViewHolder(
+ GameCollectionSquareItemBinding.bind(
+ mLayoutInflater.inflate(
+ R.layout.game_collection_square_item,
+ parent,
+ false
+ )
+ )
+ )
+ }
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ when (holder) {
+ is GameCollectionAmwayViewHolder -> {
+ holder.bindAmway(mAmwayList)
+ }
+ is GameCollectionSquareItemViewHolder -> {
+ val realPosition = if (isHome) position - 1 else position
+ val itemData = mEntityList[realPosition]
+ val filterTagName = mViewModel.selectedTagName
+ val exposureEventList = arrayListOf()
+ itemData.gameCollectionItem?.games?.get(0)?.let {
+ exposureEventList.add(
+ ExposureEvent.createEventWithSourceConcat(
+ it.toGameEntity().apply {
+ outerSequence = mOuterSequence; sequence =
+ itemData.gameStartPosition + 1
+ },
+ mBasicExposureSource,
+ listOf(
+ ExposureSource(
+ "游戏单",
+ if (isHome) "${itemData.gameCollectionItem?.title} + ${itemData.gameCollectionItem?.id}" else "${itemData.gameCollectionItem?.title} + ${itemData.gameCollectionItem?.id} + $filterTagName"
+ )
+ )
+ )
+ )
+ }
+ itemData.gameCollectionItem?.games?.get(1)?.let {
+ exposureEventList.add(ExposureEvent.createEventWithSourceConcat(it.toGameEntity().apply { outerSequence = mOuterSequence; sequence = itemData.gameStartPosition + 2 }, mBasicExposureSource, listOf(ExposureSource("游戏单", if (isHome) "${itemData.gameCollectionItem?.title} + ${itemData.gameCollectionItem?.id}" else "${itemData.gameCollectionItem?.title} + ${itemData.gameCollectionItem?.id} + $filterTagName"))))
+ }
+ itemData.gameCollectionItem?.games?.get(2)?.let {
+ exposureEventList.add(ExposureEvent.createEventWithSourceConcat(it.toGameEntity().apply { outerSequence = mOuterSequence; sequence = itemData.gameStartPosition + 3 }, mBasicExposureSource, listOf(ExposureSource("游戏单", if (isHome) "${itemData.gameCollectionItem?.title} + ${itemData.gameCollectionItem?.id}" else "${itemData.gameCollectionItem?.title} + ${itemData.gameCollectionItem?.id} + $filterTagName"))))
+ }
+ itemData.exposureEventList = exposureEventList
+ itemData.gameCollectionItem?.let {
+ holder.bindGameCollection(mViewModel, it, itemData)
+ }
+ }
+ is FooterViewHolder -> {
+ holder.initItemPadding()
+ holder.initFooterViewHolder(mViewModel, mIsLoading, mIsNetworkError, mIsOver)
+ holder.hint.setTextColor(ContextCompat.getColor(mContext, R.color.text_B3B3B3))
+ val lp = holder.itemView.layoutParams as RecyclerView.LayoutParams
+ lp.height = DisplayUtils.dip2px(48F)
+ lp.width = ViewGroup.LayoutParams.MATCH_PARENT
+ holder.itemView.layoutParams = lp
+ }
+ }
+ }
+
+ override fun getItemCount() = if (mEntityList.isNullOrEmpty()) 0 else if (isHome) mEntityList.size + 2 else mEntityList.size + 1
+
+ class GameCollectionSquareItemViewHolder(var binding: GameCollectionSquareItemBinding) :
+ RecyclerView.ViewHolder(binding.root) {
+ @SuppressLint("SetTextI18n")
+ fun bindGameCollection(viewModel: GameCollectionSquareViewModel, gamesCollectionEntity: GamesCollectionEntity, itemData: GameCollectionListItemData) {
+ binding.run {
+ val context = root.context
+ entity = gamesCollectionEntity
+ stampIv.setImageDrawable(if (gamesCollectionEntity.stamp == "official") R.drawable.ic_official.toDrawable() else R.drawable.ic_chosen.toDrawable())
+ tagContainer.removeAllViews()
+ if (!gamesCollectionEntity.tags.isNullOrEmpty()) {
+ for ((index, tagEntity) in gamesCollectionEntity.tags!!.withIndex()) {
+ // 添加分隔线
+ if (index != 0) tagContainer.addView(View(context).apply {
+ layoutParams = ViewGroup.LayoutParams(1F.dip2px(), 14F.dip2px())
+ setBackgroundColor(Color.parseColor("#33FFFFFF"))
+ })
+ // 添加标签
+ tagContainer.addView(TextView(context).apply {
+ layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
+ setPadding(if (index == 0) 0 else 6F.dip2px(), 0, 6F.dip2px(), 0)
+ text = tagEntity.name
+ setTextColor(R.color.white.toColor())
+ textSize = 10F
+ })
+ }
+ }
+ tagContainer.goneIf(CheckLoginUtils.isLogin())
+ playedGamesContainer.goneIf(!CheckLoginUtils.isLogin())
+ iconIvOne.setOnClickListener {
+ val game = gamesCollectionEntity.games?.get(0)
+ NewLogUtils.logClickGameCollectionGameIcon(
+ gamesCollectionEntity.title,
+ gamesCollectionEntity.id,
+ game?.name ?: "",
+ game?.id ?: ""
+ )
+ game?.id?.let { id ->
+ GameDetailActivity.startGameDetailActivity(context, id, BaseActivity.mergeEntranceAndPath(viewModel.entrance, "游戏单广场"), itemData.exposureEventList?.safelyGetInRelease(0))
+ }
+ }
+ iconIvTwo.setOnClickListener {
+ val game = gamesCollectionEntity.games?.get(1)
+ NewLogUtils.logClickGameCollectionGameIcon(
+ gamesCollectionEntity.title,
+ gamesCollectionEntity.id,
+ game?.name ?: "",
+ game?.id ?: ""
+ )
+ game?.id?.let { id ->
+ GameDetailActivity.startGameDetailActivity(context, id, BaseActivity.mergeEntranceAndPath(viewModel.entrance, "游戏单广场"), itemData.exposureEventList?.safelyGetInRelease(1))
+ }
+ }
+ iconIvThree.setOnClickListener {
+ val game = gamesCollectionEntity.games?.get(2)
+ NewLogUtils.logClickGameCollectionGameIcon(
+ gamesCollectionEntity.title,
+ gamesCollectionEntity.id,
+ game?.name ?: "",
+ game?.id ?: ""
+ )
+ game?.id?.let { id ->
+ GameDetailActivity.startGameDetailActivity(context, id, BaseActivity.mergeEntranceAndPath(viewModel.entrance, "游戏单广场"), itemData.exposureEventList?.safelyGetInRelease(2))
+ }
+ }
+ userContainer.setOnClickListener {
+ NewLogUtils.logClickGameCollectionAuthor(gamesCollectionEntity.title, gamesCollectionEntity.id)
+ DirectUtils.directToHomeActivity(context, gamesCollectionEntity.user?.id, 0, viewModel.entrance, "游戏单广场")
+ }
+ root.setOnClickListener {
+ NewLogUtils.logEnterGameCollectionDetail(gamesCollectionEntity.title, gamesCollectionEntity.id)
+ context.startActivity(GameCollectionDetailActivity.getIntent(context, gamesCollectionEntity.id, true))
+ }
+ }
+ }
+ }
+
+ companion object {
+ const val INVALID_VALUE = -1
+ }
+
+ override fun getEventByPosition(pos: Int): ExposureEvent? {
+ return mEntityList[pos].exposureEvent
+ }
+
+ override fun getEventListByPosition(pos: Int): List? {
+ return mEntityList[pos].exposureEventList
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareFragment.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareFragment.kt
new file mode 100644
index 0000000000..726fbae2e9
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareFragment.kt
@@ -0,0 +1,259 @@
+package com.gh.gamecenter.gamecollection.square
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.ViewCompat
+import com.gh.common.exposure.ExposureListener
+import com.gh.common.exposure.ExposureSource
+import com.gh.common.util.*
+import com.gh.common.view.VerticalItemDecoration
+import com.gh.gamecenter.R
+import com.gh.gamecenter.baselist.LazyListFragment
+import com.gh.gamecenter.baselist.ListAdapter
+import com.gh.gamecenter.baselist.LoadType
+import com.gh.gamecenter.databinding.FragmentGameCollectionSquareAlBinding
+import com.gh.gamecenter.databinding.FragmentGameCollectionSquareBinding
+import com.gh.gamecenter.entity.GamesCollectionEntity
+import com.gh.gamecenter.entity.TagInfoEntity
+import com.gh.gamecenter.eventbus.EBReuse
+import com.gh.gamecenter.gamecollection.publish.GameCollectionEditActivity
+import com.gh.gamecenter.gamecollection.tag.GameCollectionTagSelectActivity
+import com.gh.gamecenter.gamecollection.tag.GameCollectionTagSelectFragment
+import com.gh.gamecenter.personal.PersonalFragment
+import com.google.android.material.appbar.AppBarLayout
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+import kotlin.math.abs
+
+class GameCollectionSquareFragment : LazyListFragment() {
+ private lateinit var mViewModel: GameCollectionSquareViewModel
+ private lateinit var mExposureListener: ExposureListener
+
+ private lateinit var mDefaultBinding: FragmentGameCollectionSquareBinding
+ private lateinit var mAlternativeBinding: FragmentGameCollectionSquareAlBinding
+
+ private var mAdapter: GameCollectionSquareAdapter? = null
+
+ private var mUseAlternativeLayout = false
+ private var mForumName = ""
+ private var mGameCollectionTitle = ""
+ private var mGameCollectionId = ""
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ mUseAlternativeLayout = arguments?.getBoolean(EntranceUtils.KEY_IS_HOME, false) ?: false
+ mForumName = arguments?.getString(EntranceUtils.KEY_FORUM_NAME, "") ?: ""
+ mGameCollectionTitle = arguments?.getString(EntranceUtils.KEY_GAME_COLLECTION_TITLE, "") ?: ""
+ mGameCollectionId = arguments?.getString(EntranceUtils.KEY_GAME_COLLECTION_ID, "") ?: ""
+ super.onCreate(savedInstanceState)
+ }
+
+ override fun getLayoutId() = R.layout.fragment_stub
+
+ override fun getRealLayoutId(): Int {
+ return if (mUseAlternativeLayout) R.layout.fragment_game_collection_square_al else R.layout.fragment_game_collection_square
+ }
+
+ override fun onFragmentFirstVisible() {
+ super.onFragmentFirstVisible()
+ mViewModel.entrance = mEntrance
+ mViewModel.isHome = mUseAlternativeLayout
+ mListViewModel.load(LoadType.NORMAL)
+
+ NewLogUtils.logEnterGameCollectionSquare(mEntrance, mForumName, mGameCollectionTitle, mGameCollectionId)
+ }
+
+ override fun isAutomaticLoad() = false
+
+ override fun onRealLayoutInflated(inflatedView: View) {
+ super.onRealLayoutInflated(inflatedView)
+ if (mUseAlternativeLayout) {
+ mAlternativeBinding = FragmentGameCollectionSquareAlBinding.bind(inflatedView)
+ } else {
+ mDefaultBinding = FragmentGameCollectionSquareBinding.bind(inflatedView)
+ }
+ }
+
+ override fun initRealView() {
+ super.initRealView()
+
+ mExposureListener = ExposureListener(this, mAdapter!!)
+ mListRv.addOnScrollListener(mExposureListener)
+
+ if (!mUseAlternativeLayout) {
+ initDefaultLayout()
+ } else {
+ initAlternativeLayout()
+ }
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ if (data == null || resultCode != Activity.RESULT_OK) return
+ if (requestCode == REQUEST_SELECT_TAG) {
+ val tagInfoEntity = data.getParcelableExtra(GameCollectionTagSelectFragment.SELECTED_TAG)
+ mDefaultBinding.tagTv.text = tagInfoEntity?.name ?: "标签筛选"
+ mViewModel.selectedTagEntity = tagInfoEntity
+ mViewModel.selectedTagId = tagInfoEntity?.id ?: ""
+ mViewModel.selectedTagName = tagInfoEntity?.name ?: "全部标签"
+ onLoadRefresh()
+ }
+ }
+
+ override fun provideListViewModel(): GameCollectionSquareViewModel {
+ mViewModel = viewModelProvider()
+ return mViewModel
+ }
+
+ override fun getItemDecoration() = VerticalItemDecoration(context, 16F, false, R.color.white)
+
+ override fun provideListAdapter(): ListAdapter<*> {
+ if (mAdapter == null) {
+ val outerSequence = arguments?.getInt(EntranceUtils.KEY_TAB_INDEX)
+ val tabName = arguments?.getString(EntranceUtils.KEY_NAME) ?: ""
+ val basicExposureSource = arrayListOf().apply {
+ add(ExposureSource(if (mUseAlternativeLayout) "顶部tab" else "游戏单广场", if (mUseAlternativeLayout) tabName else ""))
+ }
+ mAdapter = GameCollectionSquareAdapter(requireContext(), mUseAlternativeLayout, mViewModel, basicExposureSource, outerSequence?:(-1))
+ }
+ return mAdapter!!
+ }
+
+ private fun initDefaultLayout() {
+ // toolbar 消费 fitsSystemWindows 避免在 collapsingToolbar 下面出现多出来的 padding
+ // [https://stackoverflow.com/questions/48137666/viewgroup-inside-collapsingtoolbarlayout-show-extra-bottom-padding-when-set-fits]
+ ViewCompat.setOnApplyWindowInsetsListener(mDefaultBinding.appbar) { _, insets ->
+ (mDefaultBinding.toolbar.layoutParams as ViewGroup.MarginLayoutParams).topMargin = insets.systemWindowInsetTop
+ insets.consumeSystemWindowInsets()
+ }
+
+ val collapsingTrigger = 66F.dip2px() + DisplayUtils.getStatusBarHeight(context?.resources)
+
+ mDefaultBinding.toolbar.setNavigationOnClickListener { requireActivity().finish() }
+
+ mDefaultBinding.collapsingToolbar.scrimVisibleHeightTrigger = collapsingTrigger
+ mDefaultBinding.collapsingToolbar.scrimShownAction = {
+ DisplayUtils.setLightStatusBar(requireActivity(), it)
+ if (it) {
+ mDefaultBinding.titleTv.alpha = 1F
+ mDefaultBinding.titleTv.visibility = View.VISIBLE
+ mDefaultBinding.titleTv.setTextColor(R.color.black.toColor())
+ mDefaultBinding.toolbar.navigationIcon = R.drawable.ic_bar_back.toDrawable()
+ } else {
+ mDefaultBinding.titleTv.visibility = View.GONE
+ mDefaultBinding.toolbar.navigationIcon = R.drawable.ic_bar_back_light.toDrawable()
+ }
+ }
+
+ mDefaultBinding.titleTv.setOnClickListener {
+ if (ClickUtils.isFastDoubleClick(mDefaultBinding.titleTv.id, 300)) {
+ scrollToTop()
+ }
+ }
+
+ mDefaultBinding.appbar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { _, verticalOffset ->
+ val absOffset = abs(verticalOffset)
+ val invisibleOffset = DisplayUtils.dip2px(30F)
+
+ if (absOffset <= invisibleOffset) {
+ mDefaultBinding.titleTv.alpha = 1 - (absOffset.toFloat() / invisibleOffset)
+ } else {
+ mDefaultBinding.titleTv.alpha = 0F
+ }
+
+ mListRefresh?.isEnabled = absOffset <= 2
+ })
+
+ mDefaultBinding.orderRg.setOnCheckedChangeListener { _, checkedId ->
+ mViewModel.view = if (checkedId == R.id.hotRb) "hot" else "new"
+ onLoadRefresh()
+ }
+
+ mDefaultBinding.fab.setOnClickListener {
+ // 创建游戏单
+ ifLogin(mEntrance) {
+ showRegulationTestDialogIfNeeded {
+ startActivity(GameCollectionEditActivity.getIntent(requireContext(), mEntrance, "游戏单广场"))
+ }
+ }
+ }
+
+ mDefaultBinding.tagFilter.setOnClickListener {
+ startActivityForResult(GameCollectionTagSelectActivity.getIntent(requireContext(), true, mViewModel.selectedTagEntity), REQUEST_SELECT_TAG)
+ }
+
+ mListRefresh?.setProgressViewOffset(false, 0, 118F.dip2px() + DisplayUtils.getStatusBarHeight(requireContext().resources))
+// mSkeletonScreen = Skeleton.bind(mDefaultBinding?.skeletonPlaceholder).shimmer(false).load(R.layout.fragment_amway_skeleton).show()
+ }
+
+ private fun initAlternativeLayout() {
+ mAlternativeBinding.fab.setOnClickListener {
+ // 创建游戏单
+ ifLogin(mEntrance) {
+ showRegulationTestDialogIfNeeded {
+ startActivity(GameCollectionEditActivity.getIntent(requireContext(), mEntrance, "游戏单广场"))
+ }
+ }
+ }
+
+ mViewModel.mAmwayCommentList.observeNonNull(this) {
+ mAdapter?.setAmwayList(it)
+ }
+
+// mSkeletonScreen = Skeleton.bind(mAlternativeBinding?.skeletonPlaceholder).shimmer(false).load(
+// R.layout.fragment_amway_skeleton_al).show()
+ }
+
+ @SuppressLint("NotifyDataSetChanged")
+ override fun onResume() {
+ if (isEverPause) mAdapter?.notifyDataSetChanged()
+ super.onResume()
+ }
+
+ override fun onLoadEmpty() {
+ super.onLoadEmpty()
+ if (!mUseAlternativeLayout) mDefaultBinding.tagFilterContainer.visibility = View.VISIBLE
+ }
+
+ override fun onLoadDone() {
+ super.onLoadDone()
+ if (!mUseAlternativeLayout) mDefaultBinding.tagFilterContainer.visibility = View.VISIBLE
+ }
+
+ override fun onLoadError() {
+ super.onLoadError()
+ if (!mUseAlternativeLayout) mDefaultBinding.tagFilterContainer.visibility = View.GONE
+ }
+
+ override fun onLoadRefresh() {
+ super.onLoadRefresh()
+ if (!mUseAlternativeLayout) mDefaultBinding.tagFilterContainer.visibility = View.VISIBLE
+ mViewModel.getAmwayCommentList()
+ }
+
+ private fun scrollToTop() {
+ val firstItemPosition = mLayoutManager.findFirstVisibleItemPosition()
+ if (firstItemPosition >= 10) {
+ mListRv.scrollToPosition(6)
+ }
+ mListRv.smoothScrollToPosition(0)
+ mDefaultBinding.appbar.setExpanded(true)
+ }
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ fun onEventMainThread(reuse: EBReuse) {
+ if ("Refresh" == reuse.type) {
+ mAdapter?.notifyDataSetChanged()
+ } else if (reuse.type == PersonalFragment.LOGIN_TAG) { // 登入
+ scrollToTop()
+ onRefresh()
+ }
+ }
+
+ companion object {
+ const val REQUEST_SELECT_TAG = 100
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareViewModel.kt
new file mode 100644
index 0000000000..b8b5afd501
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/square/GameCollectionSquareViewModel.kt
@@ -0,0 +1,76 @@
+package com.gh.gamecenter.gamecollection.square
+
+import android.annotation.SuppressLint
+import android.app.Application
+import androidx.lifecycle.MutableLiveData
+import com.gh.gamecenter.baselist.ListViewModel
+import com.gh.gamecenter.baselist.LoadParams
+import com.gh.gamecenter.baselist.LoadStatus
+import com.gh.gamecenter.entity.AmwayCommentEntity
+import com.gh.gamecenter.entity.GamesCollectionEntity
+import com.gh.gamecenter.entity.TagInfoEntity
+import com.gh.gamecenter.retrofit.BiResponse
+import com.gh.gamecenter.retrofit.RetrofitManager
+import io.reactivex.Observable
+import io.reactivex.Single
+import io.reactivex.schedulers.Schedulers
+import java.util.*
+
+class GameCollectionSquareViewModel(application: Application) :
+ ListViewModel(application) {
+
+ var entrance: String? = null
+ var selectedTagEntity: TagInfoEntity? = null
+ var selectedTagId = ""
+ var selectedTagName = "全部标签"
+ var view = "hot"
+ var isHome = false
+
+ val mAmwayCommentList = MutableLiveData>()
+
+ init {
+ getAmwayCommentList()
+ }
+
+ override fun initLoadParams() {
+ mCurLoadParams = LoadParams(PAGE_SIZE, LoadParams.DEFAULT_OFFSET)
+ mLoadStatusLiveData.value = LoadStatus.INIT
+ }
+
+ override fun provideDataSingle(page: Int): Single> =
+ if (isHome) RetrofitManager.getInstance(getApplication())
+ .api.getHomeGameCollectionSquareList(UUID.randomUUID().toString(), page, PAGE_SIZE)
+ else RetrofitManager.getInstance(getApplication())
+ .api.getGameCollectionSquareList(view, selectedTagId, page, PAGE_SIZE)
+
+ override fun mergeResultLiveData() {
+ mResultLiveData.addSource(mListLiveData) { list ->
+ val itemDataList = arrayListOf().apply {
+ var position = 0
+ for (item in list) {
+ add(GameCollectionListItemData(gameCollectionItem = item, gameStartPosition = position))
+ position += if (item.count?.game!! > 2) 3 else item.count?.game ?: 0
+ }
+ }
+ mResultLiveData.postValue(itemDataList)
+ }
+ }
+
+ override fun provideDataObservable(page: Int): Observable>? = null
+
+ @SuppressLint("CheckResult")
+ fun getAmwayCommentList() {
+ RetrofitManager.getInstance(getApplication()).api
+ .getAmwayCommentList(1, 10)
+ .subscribeOn(Schedulers.io())
+ .subscribe(object : BiResponse>() {
+ override fun onSuccess(data: List) {
+ mAmwayCommentList.postValue(data)
+ }
+ })
+ }
+
+ companion object {
+ const val PAGE_SIZE = 15
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/tag/GameCollectionTagAdapter.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/tag/GameCollectionTagAdapter.kt
new file mode 100644
index 0000000000..e65bb188a0
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/tag/GameCollectionTagAdapter.kt
@@ -0,0 +1,145 @@
+package com.gh.gamecenter.gamecollection.tag
+
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.util.DisplayUtils
+import com.gh.common.util.dip2px
+import com.gh.common.util.goneIf
+import com.gh.gamecenter.databinding.*
+import com.gh.gamecenter.entity.GameCollectionTagEntity
+import com.gh.gamecenter.entity.TagInfoEntity
+import com.lightgame.adapter.BaseRecyclerAdapter
+
+class GameCollectionTagAdapter(
+ context: Context,
+ val singleChoice: Boolean = true,
+ val singleSelectedTag: TagInfoEntity? = null,
+ private val updateCallback: (() -> Unit)
+) :
+ BaseRecyclerAdapter(context) {
+
+ private var mTagViewList = arrayListOf()
+ var mTagList = arrayListOf()
+ var selectedTagEntity: TagInfoEntity? = null
+ var selectedTagCategory = ""
+ var selectedTagEntityList = arrayListOf()
+ private var flagFirst = true
+
+ fun setTagList(tagList: ArrayList) {
+ mTagList = tagList
+ notifyDataSetChanged()
+ }
+
+ override fun getItemViewType(position: Int): Int {
+ return if (!singleChoice && position == 0) SELECTED_TAGS else TAG_ITEM
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = when (viewType){
+ SELECTED_TAGS -> GameCollectionSelectedTagViewHolder(
+ GameCollectionSelectedTagItemBinding.inflate(mLayoutInflater, parent, false)
+ )
+ else -> GameCollectionTagItemViewHolder(
+ GameCollectionTagItemBinding.inflate(mLayoutInflater, parent, false)
+ )
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ when (holder) {
+ is GameCollectionSelectedTagViewHolder -> {
+ holder.binding.selectedTagFlexbox.removeAllViews()
+ holder.binding.hintTv.goneIf(selectedTagEntityList.size != 0)
+ for (tag in selectedTagEntityList) {
+ val selectedTagView =
+ ItemGameCollectionSelectedTagBinding.inflate(mLayoutInflater)
+ .apply {
+ tagTv.text = tag.name
+ root.setOnClickListener {
+ selectedTagEntityList.remove(tag)
+ updateCallback.invoke()
+ notifyDataSetChanged()
+ }
+ }.root
+ holder.binding.selectedTagFlexbox.addView(selectedTagView)
+ }
+ }
+ is GameCollectionTagItemViewHolder -> {
+ val data = mTagList[if (singleChoice) position else position - 1]
+ holder.binding.tagFlexbox.removeAllViews()
+ holder.binding.titleTv.text = data.categoryName
+ holder.binding.titleTv.setPadding(
+ 16F.dip2px(),
+ if (position == 0) 40F.dip2px() else 10F.dip2px(),
+ 16F.dip2px(),
+ 10F.dip2px()
+ )
+ holder.binding.tagFlexbox.setPadding(
+ 12F.dip2px(),
+ 5F.dip2px(),
+ 12F.dip2px(),
+ if (position == itemCount - 1) 97F.dip2px() else 15F.dip2px()
+ )
+ for (tagEntity in data.tags) {
+ val tag = if (singleChoice) getSingleTag(tagEntity, data.categoryName) else getMultipleTag(tagEntity)
+ mTagViewList.add(tag)
+ holder.binding.tagFlexbox.addView(tag.root)
+ }
+ }
+ }
+ }
+
+ private fun getSingleTag(tag: TagInfoEntity, tagCategory: String) = ItemGameCollectionTagBinding.inflate(mLayoutInflater).apply {
+ tagTv.text = tag.name
+ tagTv.layoutParams = tagTv.layoutParams.apply { width = (DisplayUtils.getScreenWidth() - 56F.dip2px()) / 4 }
+ singleSelectedTag?.let {
+ if (flagFirst && tag == it) {
+ tagTv.isChecked = true
+ selectedTagEntity = tag
+ }
+ }
+ root.setOnClickListener {
+ for (tagView in mTagViewList) {
+ if (tagView.tagTv != tagTv) tagView.tagTv.isChecked = false
+ }
+ tagTv.isChecked = !tagTv.isChecked
+ if (tagTv.isChecked) {
+ selectedTagEntity = tag
+ selectedTagCategory = tagCategory
+ } else {
+ selectedTagEntity = null
+ selectedTagCategory = ""
+ }
+ }
+ }
+
+ private fun getMultipleTag(tag: TagInfoEntity) =
+ ItemGameCollectionTagBinding.inflate(mLayoutInflater).apply {
+ tagTv.layoutParams = tagTv.layoutParams.apply { width = (DisplayUtils.getScreenWidth() - 56F.dip2px()) / 4 }
+ tagTv.text = tag.name
+ if (selectedTagEntityList.contains(tag)) tagTv.isChecked = true
+ root.setOnClickListener {
+ tagTv.isChecked = !tagTv.isChecked
+ if (tagTv.isChecked) {
+ selectedTagEntityList.add(tag)
+ } else {
+ if (selectedTagEntityList.contains(tag)) selectedTagEntityList.remove(tag)
+ }
+ updateCallback.invoke()
+ notifyItemChanged(0)
+ }
+ }
+
+ override fun getItemCount() = if (singleChoice) mTagList.size else mTagList.size + 1
+
+ class GameCollectionSelectedTagViewHolder(var binding: GameCollectionSelectedTagItemBinding) :
+ RecyclerView.ViewHolder(binding.root)
+
+ class GameCollectionTagItemViewHolder(var binding: GameCollectionTagItemBinding) :
+ RecyclerView.ViewHolder(binding.root)
+
+ companion object {
+ const val SELECTED_TAGS = 100
+ const val TAG_ITEM = 101
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/tag/GameCollectionTagSelectActivity.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/tag/GameCollectionTagSelectActivity.kt
new file mode 100644
index 0000000000..10b184eeb1
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/tag/GameCollectionTagSelectActivity.kt
@@ -0,0 +1,35 @@
+package com.gh.gamecenter.gamecollection.tag
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import com.gh.gamecenter.NormalActivity
+import com.gh.gamecenter.R
+import com.gh.gamecenter.entity.TagInfoEntity
+
+class GameCollectionTagSelectActivity : NormalActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setNavigationTitle("选择标签")
+ setToolbarMenu(R.menu.menu_save)
+ }
+
+ companion object {
+ const val KEY_IS_SINGLE_CHOICE = "single_choice"
+ const val KEY_SINGLE_SELECTED_TAG = "single_selected_tag"
+
+ @JvmStatic
+ fun getIntent(context: Context, singleChoice: Boolean = false, singleSelectedTag: TagInfoEntity? = null): Intent {
+ val bundle = Bundle()
+ bundle.putBoolean(KEY_IS_SINGLE_CHOICE, singleChoice)
+ bundle.putParcelable(KEY_SINGLE_SELECTED_TAG, singleSelectedTag)
+ return getTargetIntent(
+ context,
+ GameCollectionTagSelectActivity::class.java,
+ GameCollectionTagSelectFragment::class.java,
+ bundle
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/tag/GameCollectionTagSelectFragment.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/tag/GameCollectionTagSelectFragment.kt
new file mode 100644
index 0000000000..1d6c2eb5ab
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/tag/GameCollectionTagSelectFragment.kt
@@ -0,0 +1,102 @@
+package com.gh.gamecenter.gamecollection.tag
+
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.view.MenuItem
+import android.view.View
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.util.NewLogUtils
+import com.gh.common.util.viewModelProvider
+import com.gh.gamecenter.R
+import com.gh.gamecenter.databinding.FragmentGameCollectionTagSelectBinding
+import com.gh.gamecenter.databinding.ItemGameCollectionSelectedTagBinding
+import com.gh.gamecenter.entity.TagInfoEntity
+import com.gh.gamecenter.normal.NormalFragment
+
+class GameCollectionTagSelectFragment : NormalFragment() {
+
+ private var mSingleChoice = false
+ private var mSelectedTag: TagInfoEntity? = null
+ private lateinit var mBinding: FragmentGameCollectionTagSelectBinding
+ private lateinit var mAdapter: GameCollectionTagAdapter
+ private lateinit var mViewModel: GameCollectionTagViewModel
+ private var firstVisibleItemPosition = 0
+
+ private val updateSelectedTagView: (() -> Unit) = {
+ mAdapter.selectedTagEntityList.let { list ->
+ mBinding.selectedTagContainer.removeAllViews()
+ for (tag in list) {
+ val selectedTagView = ItemGameCollectionSelectedTagBinding.inflate(layoutInflater)
+ selectedTagView.run {
+ tagTv.text = tag.name
+ root.setOnClickListener {
+ list.remove(tag)
+ mBinding.selectedTagContainer.removeView(selectedTagView.root)
+ mAdapter.notifyDataSetChanged()
+ mBinding.selectedTagScrollView.visibility = if (firstVisibleItemPosition == 0 || list.isEmpty()) View.GONE else View.VISIBLE
+ }
+ }
+ mBinding.selectedTagContainer.addView(selectedTagView.root)
+ }
+ mBinding.selectedTagScrollView.visibility = if (firstVisibleItemPosition == 0 || list.isEmpty()) View.GONE else View.VISIBLE
+ }
+ }
+
+ override fun getLayoutId(): Int = 0
+
+ override fun getInflatedLayout() =
+ FragmentGameCollectionTagSelectBinding.inflate(layoutInflater).apply {
+ mBinding = this
+ }.root
+
+ override fun onMenuItemClick(menuItem: MenuItem?) {
+ if (menuItem?.itemId == R.id.layout_menu_save) {
+ if (mSingleChoice) {
+ if (mAdapter.selectedTagEntity != null) {
+ NewLogUtils.logFilterGameCollectionTag(mAdapter.selectedTagCategory, mAdapter.selectedTagEntity!!.name)
+ }
+ requireActivity().setResult(
+ Activity.RESULT_OK,
+ Intent().putExtra(SELECTED_TAG, mAdapter.selectedTagEntity)
+ )
+ } else {
+ requireActivity().setResult(
+ Activity.RESULT_OK,
+ Intent().putExtra(SELECTED_TAG, mAdapter.selectedTagEntityList)
+ )
+ }
+ requireActivity().finish()
+ }
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ mSingleChoice = arguments?.getBoolean(GameCollectionTagSelectActivity.KEY_IS_SINGLE_CHOICE) ?: false
+ mSelectedTag = arguments?.getParcelable(GameCollectionTagSelectActivity.KEY_SINGLE_SELECTED_TAG)
+ mAdapter = GameCollectionTagAdapter(requireContext(), mSingleChoice, mSelectedTag, updateSelectedTagView)
+ mViewModel = viewModelProvider()
+ if (mSingleChoice) NewLogUtils.logEnterGameCollectionTag()
+ mBinding.tagRv.run {
+ layoutManager = LinearLayoutManager(requireContext())
+ adapter = mAdapter
+ addOnScrollListener(object :RecyclerView.OnScrollListener() {
+
+ override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+ super.onScrolled(recyclerView, dx, dy)
+ firstVisibleItemPosition = (layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()
+ mBinding.selectedTagScrollView.visibility = if (firstVisibleItemPosition == 0 || mAdapter.selectedTagEntityList.isEmpty()) View.GONE else View.VISIBLE
+ }
+ })
+ }
+
+ mViewModel.tagListLiveData.observe(viewLifecycleOwner) {
+ mAdapter.setTagList(it)
+ }
+ }
+
+ companion object {
+ const val SELECTED_TAG = "selected_tag"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/gamecollection/tag/GameCollectionTagViewModel.kt b/app/src/main/java/com/gh/gamecenter/gamecollection/tag/GameCollectionTagViewModel.kt
new file mode 100644
index 0000000000..f4c26d2804
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/gamecollection/tag/GameCollectionTagViewModel.kt
@@ -0,0 +1,33 @@
+package com.gh.gamecenter.gamecollection.tag
+
+import android.annotation.SuppressLint
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.MutableLiveData
+import com.gh.gamecenter.entity.GameCollectionTagEntity
+import com.gh.gamecenter.retrofit.BiResponse
+import com.gh.gamecenter.retrofit.RetrofitManager
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+
+class GameCollectionTagViewModel(application: Application) : AndroidViewModel(application) {
+
+ var tagListLiveData = MutableLiveData>()
+ private val mApi = RetrofitManager.getInstance(getApplication()).api
+
+ init {
+ getGameCollectionTagList()
+ }
+
+ @SuppressLint("CheckResult")
+ fun getGameCollectionTagList() {
+ mApi.gameCollectionTagList
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(object: BiResponse>(){
+ override fun onSuccess(data: ArrayList) {
+ tagListLiveData.postValue(data)
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/history/HistoryWrapperFragment.kt b/app/src/main/java/com/gh/gamecenter/history/HistoryWrapperFragment.kt
index 85f5205222..971dcfc6e5 100644
--- a/app/src/main/java/com/gh/gamecenter/history/HistoryWrapperFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/history/HistoryWrapperFragment.kt
@@ -6,15 +6,16 @@ import com.gh.base.fragment.BaseFragment_TabLayout
import com.gh.common.util.EntranceUtils
import com.gh.common.util.MtaHelper
import com.gh.gamecenter.R
-import com.gh.gamecenter.collection.AnswerFragment
-import com.gh.gamecenter.collection.ArticleFragment
-import com.gh.gamecenter.collection.CommunityArticleFragment
-import com.gh.gamecenter.collection.VideoFragment
+import com.gh.gamecenter.collection.*
+import com.gh.gamecenter.manager.UserManager
class HistoryWrapperFragment : BaseFragment_TabLayout() {
+ override fun getLayoutId() = R.layout.fragment_no_padding_tablayout_viewpager
+
override fun initTabTitleList(tabTitleList: MutableList) {
tabTitleList.add(getString(R.string.main_game))
+ tabTitleList.add(getString(R.string.game_collection))
tabTitleList.add(getString(R.string.video))
tabTitleList.add(getString(R.string.answer))
tabTitleList.add(getString(R.string.collection_article))
@@ -23,6 +24,10 @@ class HistoryWrapperFragment : BaseFragment_TabLayout() {
override fun initFragmentList(fragments: MutableList) {
fragments.add(HistoryGameListFragment().with(arguments))
+ fragments.add(GamesCollectionFragment().with(arguments?.apply {
+ putString(EntranceUtils.KEY_USER_ID, UserManager.getInstance().userId)
+ putString(EntranceUtils.KEY_TYPE, GamesCollectionFragment.TYPE_HISTORY)
+ }))
fragments.add(VideoFragment().with(arguments?.apply {
putString("videoStyle", VideoFragment.VideoStyle.BROWSING_HISTORY.value)
}))
diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt b/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt
index b3cc9e8de1..b4d6113e2f 100644
--- a/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt
@@ -21,10 +21,13 @@ import com.gh.gamecenter.baselist.DiffUtilAdapter
import com.gh.gamecenter.baselist.LoadStatus
import com.gh.gamecenter.databinding.*
import com.gh.gamecenter.entity.AmwayCommentEntity
+import com.gh.gamecenter.entity.GamesCollectionEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.game.GameAndPosition
import com.gh.gamecenter.game.rank.RankCollectionAdapter
import com.gh.gamecenter.game.vertical.GameVerticalAdapter
+import com.gh.gamecenter.gamecollection.square.GameCollectionListItemData
+import com.gh.gamecenter.home.gamecollection.HomeGameCollectionViewHolder
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
import com.gh.gamecenter.home.amway.HomeAmwayListViewHolder
import com.gh.gamecenter.home.slide.HomeSlideListAdapter
@@ -32,6 +35,7 @@ import com.gh.gamecenter.home.slide.HomeSlideListViewHolder
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
import com.halo.assistant.fragment.game.GamePluginAdapter
import com.lightgame.download.DownloadEntity
+import com.lightgame.utils.Utils
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
import java.util.*
@@ -96,6 +100,7 @@ class HomeFragmentAdapter(
if (itemData.recommends != null) return RECOMMENDS_ITEM
if (itemData.attachGame != null) return GAME_ITEM
if (itemData.amway != null) return AMWAY_ITEM
+ if (itemData.gameCollection != null) return GAME_COLLECTION_ITEM
if (itemData.lineDivider != null) return DIVIDER_ITEM
if (itemData.unknownData != null) return UNKNOWN_ITEM
@@ -121,6 +126,10 @@ class HomeFragmentAdapter(
view = mLayoutInflater.inflate(R.layout.home_amway_list, parent, false)
HomeAmwayListViewHolder(HomeAmwayListBinding.bind(view))
}
+ GAME_COLLECTION_ITEM -> {
+ view = mLayoutInflater.inflate(R.layout.home_game_collection_item, parent, false)
+ HomeGameCollectionViewHolder(HomeGameCollectionItemBinding.bind(view))
+ }
DIVIDER_ITEM -> {
view = mLayoutInflater.inflate(R.layout.home_divider_item, parent, false)
HomeDividerViewHolder(HomeDividerItemBinding.bind(view))
@@ -160,6 +169,7 @@ class HomeFragmentAdapter(
is FooterViewHolder -> bindFooterView(holder)
is ReuseViewHolder -> bindUnknown(holder)
is HomeDividerViewHolder -> holder.bindView(mDataList[position].lineDivider ?: 1F)
+ is HomeGameCollectionViewHolder -> bindGameCollection(holder, position)
else -> mLegacyHomeFragmentAdapterAssistant.bindLegacyViewHolder(
holder,
@@ -222,6 +232,53 @@ class HomeFragmentAdapter(
holder.bindAmwayList(amwayList, clickClosure)
}
+ private fun bindGameCollection(holder: HomeGameCollectionViewHolder, position: Int) {
+ val homeItemData = mDataList[position]
+ val gameCollectionItemDataList = homeItemData.gameCollection?: listOf()
+
+ val exposureList = arrayListOf()
+ for (gameCollectionItemData in gameCollectionItemDataList) {
+ runOnIoThread(true) {
+ val gameCollection = gameCollectionItemData.gameCollectionItem
+ val gameCollectionSource = listOf(ExposureSource("游戏单", "${gameCollection?.title} + ${gameCollection?.id}"))
+ val gameExposureList = arrayListOf()
+ gameCollection?.games?.get(0)?.let {
+ gameExposureList.add(ExposureEvent.createEventWithSourceConcat(
+ gameEntity = it.toGameEntity().apply { outerSequence = homeItemData.blockPosition; sequence = gameCollectionItemData.gameStartPosition + 1 },
+ basicSource = mBasicExposureSource,
+ source = gameCollectionSource
+ ))
+ }
+ gameCollection?.games?.get(1)?.let {
+ gameExposureList.add(ExposureEvent.createEventWithSourceConcat(
+ gameEntity = it.toGameEntity().apply { outerSequence = homeItemData.blockPosition; sequence = gameCollectionItemData.gameStartPosition + 2 },
+ basicSource = mBasicExposureSource,
+ source = gameCollectionSource
+ ))
+ }
+ gameCollection?.games?.get(2)?.let {
+ gameExposureList.add(ExposureEvent.createEventWithSourceConcat(
+ gameEntity = it.toGameEntity().apply { outerSequence = homeItemData.blockPosition; sequence = gameCollectionItemData.gameStartPosition + 3 },
+ basicSource = mBasicExposureSource,
+ source = gameCollectionSource
+ ))
+ }
+ gameCollectionItemData.exposureEventList = gameExposureList
+ exposureList.addAll(gameExposureList)
+ }
+ }
+ homeItemData.exposureEventList = exposureList
+ holder.bindGameCollectionList(gameCollectionItemDataList, "首页内容列表")
+// val testData = arrayListOf(
+// GameCollectionListItemData(gameCollectionItem = GamesCollectionEntity(title = "1111"), gameStartPosition = 0),
+// GameCollectionListItemData(gameCollectionItem = GamesCollectionEntity(title = "2222"), gameStartPosition = 0),
+// GameCollectionListItemData(gameCollectionItem = GamesCollectionEntity(title = "3333"), gameStartPosition = 0),
+// GameCollectionListItemData(gameCollectionItem = GamesCollectionEntity(title = "4444"), gameStartPosition = 0),
+// GameCollectionListItemData(gameCollectionItem = GamesCollectionEntity(title = "55555"), gameStartPosition = 0)
+// )
+// holder.bindGameCollectionList(testData, "首页内容列表")
+ }
+
private fun bindAttachGame(holder: HomeGameItemViewHolder, position: Int) {
val homeItemData = mDataList[position]
val game = homeItemData.attachGame?.linkGame!!
@@ -460,5 +517,6 @@ class HomeFragmentAdapter(
const val FOOTER_ITEM: Int = 110
const val UNKNOWN_ITEM: Int = 111
const val COMMON_ITEM: Int = 115
+ const val GAME_COLLECTION_ITEM: Int = 116
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeItemData.kt b/app/src/main/java/com/gh/gamecenter/home/HomeItemData.kt
index 96fa562399..6c35cae520 100644
--- a/app/src/main/java/com/gh/gamecenter/home/HomeItemData.kt
+++ b/app/src/main/java/com/gh/gamecenter/home/HomeItemData.kt
@@ -1,10 +1,12 @@
package com.gh.gamecenter.home
import com.gh.gamecenter.entity.*
+import com.gh.gamecenter.gamecollection.square.GameCollectionListItemData
data class HomeItemData(var slides: List? = null,
var recommends: List? = null,
var amway: List? = null,
+ var gameCollection: List? = null,
var attachGame: HomeContent? = null,
var lineDivider: Float? = null,
var unknownData: Any? = null) : LegacyHomeItemData()
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt b/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt
index d78bed91c5..84bb6980b4 100644
--- a/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt
@@ -13,6 +13,7 @@ import com.gh.download.DownloadManager
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.baselist.LoadStatus
import com.gh.gamecenter.entity.*
+import com.gh.gamecenter.gamecollection.square.GameCollectionListItemData
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.Response
@@ -23,7 +24,10 @@ import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import retrofit2.HttpException
+import java.io.BufferedReader
+import java.io.InputStreamReader
import java.util.*
+import java.util.stream.Collectors
import kotlin.collections.ArrayList
import kotlin.collections.set
@@ -398,6 +402,25 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
commonCollectionItem.commonCollection = subjectEntity
commonCollectionItem.blockPosition = i
mSnapshotItemList.add(commonCollectionItem)
+ } else if (linkType == "game_list_collection") {
+ val head = HomeItemData()
+ head.columnHead = SubjectEntity(type = linkType, name = "热门游戏单")
+ mSnapshotItemList.add(LegacyHomeSubjectTransformer.getBlankSpacingItem(HomeItemData()) as HomeItemData)
+ mSnapshotItemList.add(head)
+
+ val gameCollection = HomeItemData()
+ gameCollection.blockPosition = i
+ val itemDataList = arrayListOf().apply {
+ if (!homeContent.linkGameCollection.isNullOrEmpty()) {
+ var position = 0
+ for (item in homeContent.linkGameCollection) {
+ add(GameCollectionListItemData(gameCollectionItem = item, gameStartPosition = position))
+ position += if (item.count?.game!! > 2) 3 else item.count?.game ?: 0
+ }
+ }
+ }
+ gameCollection.gameCollection = itemDataList
+ mSnapshotItemList.add(gameCollection)
} else {
val unknown = HomeItemData()
unknown.blockPosition = i + 1
diff --git a/app/src/main/java/com/gh/gamecenter/home/LegacyHomeFragmentAdapterAssistant.kt b/app/src/main/java/com/gh/gamecenter/home/LegacyHomeFragmentAdapterAssistant.kt
index 0f5921e79a..ad31d4d7da 100644
--- a/app/src/main/java/com/gh/gamecenter/home/LegacyHomeFragmentAdapterAssistant.kt
+++ b/app/src/main/java/com/gh/gamecenter/home/LegacyHomeFragmentAdapterAssistant.kt
@@ -583,6 +583,8 @@ class LegacyHomeFragmentAdapterAssistant(
)
)
NewLogUtils.logAccessToCommonCollectionDetail(column.id ?: "", column.name ?: "", "首页内容列表")
+ } else if (column.type == "game_list_collection") {
+ DirectUtils.directToGameCollectionSquare(mContext, "首页内容列表", column.name ?: "")
} else {
if (column.indexRightTopLink != null) {
val link = column.indexRightTopLink!!
diff --git a/app/src/main/java/com/gh/gamecenter/home/gamecollection/GameCollectionStackAnimation.kt b/app/src/main/java/com/gh/gamecenter/home/gamecollection/GameCollectionStackAnimation.kt
new file mode 100644
index 0000000000..010e20c8b3
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/home/gamecollection/GameCollectionStackAnimation.kt
@@ -0,0 +1,144 @@
+package com.gh.gamecenter.home.gamecollection
+
+import android.view.View
+import com.gh.common.util.DisplayUtils
+import com.gh.common.view.stacklayoutmanager.StackAnimation
+import com.gh.common.view.stacklayoutmanager.StackLayoutManager
+import com.gh.gamecenter.R
+import com.halo.assistant.HaloApp
+import com.lightgame.utils.Utils
+import kotlin.math.pow
+
+class GameCollectionStackAnimation(
+ scrollOrientation: StackLayoutManager.ScrollOrientation,
+ visibleCount: Int
+) : StackAnimation(scrollOrientation, visibleCount) {
+ private var mScale = 0.9F
+ private var mOutScale = 1.0F
+ private var mOutRotation = 0
+
+ /**
+ * 设置 item 缩放比例.
+ * @param scale 缩放比例
+ */
+ fun setItemScaleRate(scale: Float) {
+ mScale = scale
+ }
+
+ /**
+ * 获取item缩放比例.
+ * @return item缩放比例
+ */
+ fun getItemScaleRate(): Float {
+ return mScale
+ }
+
+ /**
+ * 设置 itemView 离开屏幕时候的缩放比例.
+ * @param scale 缩放比例
+ */
+ fun setOutScale(scale: Float) {
+ mOutScale = scale
+ }
+
+ /**
+ * 获取 itemView 离开屏幕时候的缩放比例.
+ * @return 缩放比例
+ */
+ fun getOutScale(): Float {
+ return mOutScale
+ }
+
+ /**
+ * 设置 itemView 离开屏幕时候的旋转角度.
+ * @param rotation 旋转角度
+ */
+ fun setOutRotation(rotation: Int) {
+ mOutRotation = rotation
+ }
+
+ /**
+ * 获取 itemView 离开屏幕时候的旋转角度
+ * @return 旋转角度
+ */
+ fun getOutRotation(): Int {
+ return mOutRotation
+ }
+
+ override fun doAnimation(firstMovePercent: Float, itemView: View, position: Int) {
+ val cover = itemView.findViewById(R.id.cover)
+ val content = itemView.findViewById(R.id.content)
+ val scale: Float
+ var alpha = 1.0F
+ val rotation: Float
+ if (position == 0) {
+ // 顶层item透明度变化
+ cover.alpha = 0F
+ content.alpha = 1F
+ if (firstMovePercent > 0.5) alpha = 1F - 2 * (firstMovePercent - 0.5F)
+ scale = 1 - ((1 - mOutScale) * firstMovePercent)
+ rotation = mOutRotation * firstMovePercent
+ } else {
+ val minScale = (mScale.toDouble().pow(position.toDouble())).toFloat()
+ val maxScale = (mScale.toDouble().pow((position - 1).toDouble())).toFloat()
+ scale = minScale + (maxScale - minScale) * firstMovePercent
+ when (position) {
+ 1 -> {
+ cover.alpha = 0.3F - 0.3F * firstMovePercent
+ content.alpha = firstMovePercent
+ }
+ 2 -> cover.alpha = 0.6F - 0.3F * firstMovePercent
+ 3 -> {
+ cover.alpha = 1F - 0.4F * firstMovePercent
+ // 如果不改变会出现残留边框
+// alpha = if (firstMovePercent == 0F) 0F else 1F
+ }
+ }
+ rotation = 0F
+ }
+
+ setItemPivotXY(mScrollOrientation, itemView)
+ rotationFirstVisibleItem(mScrollOrientation, itemView, rotation)
+ itemView.scaleX = scale
+ itemView.scaleY = scale
+ itemView.alpha = alpha
+ }
+
+ private fun setItemPivotXY(
+ scrollOrientation: StackLayoutManager.ScrollOrientation,
+ view: View
+ ) {
+ when (scrollOrientation) {
+ StackLayoutManager.ScrollOrientation.RIGHT_TO_LEFT -> {
+ view.pivotX = view.measuredWidth.toFloat()
+ view.pivotY = view.measuredHeight.toFloat() / 2
+ }
+ StackLayoutManager.ScrollOrientation.LEFT_TO_RIGHT -> {
+ view.pivotX = 0F
+ view.pivotY = view.measuredHeight.toFloat() / 2
+ }
+ StackLayoutManager.ScrollOrientation.BOTTOM_TO_TOP -> {
+ view.pivotX = view.measuredWidth.toFloat() / 2
+ view.pivotY = view.measuredHeight.toFloat()
+ }
+ StackLayoutManager.ScrollOrientation.TOP_TO_BOTTOM -> {
+ view.pivotX = view.measuredWidth.toFloat() / 2
+ view.pivotY = 0F
+ }
+ }
+ }
+
+ private fun rotationFirstVisibleItem(
+ scrollOrientation: StackLayoutManager.ScrollOrientation,
+ view: View,
+ rotation: Float
+ ) {
+ when (scrollOrientation) {
+ StackLayoutManager.ScrollOrientation.RIGHT_TO_LEFT -> view.rotationY = rotation
+ StackLayoutManager.ScrollOrientation.LEFT_TO_RIGHT -> view.rotationY = -rotation
+ StackLayoutManager.ScrollOrientation.BOTTOM_TO_TOP -> view.rotationX = -rotation
+ StackLayoutManager.ScrollOrientation.TOP_TO_BOTTOM -> view.rotationX = rotation
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/gh/gamecenter/home/gamecollection/GameCollectionStackLayout.kt b/app/src/main/java/com/gh/gamecenter/home/gamecollection/GameCollectionStackLayout.kt
new file mode 100644
index 0000000000..67fd5e3bfc
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/home/gamecollection/GameCollectionStackLayout.kt
@@ -0,0 +1,110 @@
+package com.gh.gamecenter.home.gamecollection
+
+import android.view.View
+import com.gh.common.util.dip2px
+import com.gh.common.view.stacklayoutmanager.StackLayout
+import com.gh.common.view.stacklayoutmanager.StackLayoutManager
+
+class GameCollectionStackLayout(
+ scrollOrientation: StackLayoutManager.ScrollOrientation,
+ visibleCount: Int,
+ perItemOffset: Int
+) : StackLayout(scrollOrientation, visibleCount, perItemOffset) {
+
+ private var mHasMeasureItemSize = false
+ private var mWidthSpace = 0
+ private var mHeightSpace = 0
+ private var mStartMargin = 0
+
+ private var mWidth = 0
+ private var mHeight = 0
+ private var mScrollOffset = 0
+
+ override fun doLayout(
+ stackLayoutManager: StackLayoutManager,
+ scrollOffset: Int,
+ firstMovePercent: Float,
+ itemView: View,
+ position: Int
+ ) {
+ mWidth = stackLayoutManager.width
+ mHeight = stackLayoutManager.height
+ mScrollOffset = scrollOffset
+ if (!mHasMeasureItemSize) {
+ mWidthSpace =
+ mWidth - stackLayoutManager.getDecoratedMeasuredWidth(itemView) - 18F.dip2px()
+ mHeightSpace = mHeight - stackLayoutManager.getDecoratedMeasuredHeight(itemView)
+ mStartMargin = 16F.dip2px()
+ mHasMeasureItemSize = true
+ }
+ val left: Int
+ val top: Int
+ if (position == 0) {
+ left = getFirstVisibleItemLeft()
+ top = getFirstVisibleItemTop()
+ } else {
+ left = getAfterFirstVisibleItemLeft(position, firstMovePercent)
+ top = getAfterFirstVisibleItemTop(position, firstMovePercent)
+ }
+
+ val right = left + stackLayoutManager.getDecoratedMeasuredWidth(itemView)
+ val bottom = top + stackLayoutManager.getDecoratedMeasuredHeight(itemView)
+
+ stackLayoutManager.layoutDecorated(itemView, left, top, right, bottom)
+ }
+
+ override fun requestLayout() {
+ mHasMeasureItemSize = false //表示尺寸可能发生了改变
+ }
+
+ private fun getFirstVisibleItemLeft(): Int {
+ return when (mScrollOrientation) {
+ StackLayoutManager.ScrollOrientation.RIGHT_TO_LEFT -> mStartMargin - mScrollOffset % mWidth
+ StackLayoutManager.ScrollOrientation.LEFT_TO_RIGHT -> {
+ return if (mScrollOffset % mWidth == 0) {
+ mStartMargin
+ } else {
+ mStartMargin + (mWidth - mScrollOffset % mWidth)
+ }
+ }
+ else -> mWidthSpace / 2
+ }
+ }
+
+ private fun getFirstVisibleItemTop(): Int {
+ return when (mScrollOrientation) {
+ StackLayoutManager.ScrollOrientation.BOTTOM_TO_TOP -> mStartMargin - mScrollOffset % mHeight
+ StackLayoutManager.ScrollOrientation.TOP_TO_BOTTOM -> {
+ return if (mScrollOffset % mHeight == 0) {
+ mStartMargin
+ } else {
+ mStartMargin + (mHeight - mScrollOffset % mHeight)
+ }
+ }
+ else -> mHeightSpace / 2
+ }
+ }
+
+ private fun getAfterFirstVisibleItemLeft(visiblePosition: Int, movePercent: Float): Int {
+ return when (mScrollOrientation) {
+ StackLayoutManager.ScrollOrientation.RIGHT_TO_LEFT -> (mStartMargin + mPerItemOffset * (visiblePosition - movePercent)).toInt()
+ StackLayoutManager.ScrollOrientation.LEFT_TO_RIGHT -> (mStartMargin - mPerItemOffset * (visiblePosition - movePercent)).toInt()
+ else -> mWidthSpace / 2
+ }
+ }
+
+ private fun getAfterFirstVisibleItemTop(visiblePosition: Int, movePercent: Float): Int {
+ return when (mScrollOrientation) {
+ StackLayoutManager.ScrollOrientation.BOTTOM_TO_TOP -> (mStartMargin + mPerItemOffset * (visiblePosition - movePercent)).toInt()
+ StackLayoutManager.ScrollOrientation.TOP_TO_BOTTOM -> (mStartMargin - mPerItemOffset * (visiblePosition - movePercent)).toInt()
+ else -> mHeightSpace / 2
+ }
+ }
+
+ private fun getStartMargin(): Int {
+ return when (mScrollOrientation) {
+ StackLayoutManager.ScrollOrientation.RIGHT_TO_LEFT, StackLayoutManager.ScrollOrientation.LEFT_TO_RIGHT -> mWidthSpace / 2
+ else -> mHeightSpace / 2
+ }
+ }
+}
diff --git a/app/src/main/java/com/gh/gamecenter/home/gamecollection/HomeGameCollectionAdapter.kt b/app/src/main/java/com/gh/gamecenter/home/gamecollection/HomeGameCollectionAdapter.kt
new file mode 100644
index 0000000000..5e76a14984
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/home/gamecollection/HomeGameCollectionAdapter.kt
@@ -0,0 +1,123 @@
+package com.gh.gamecenter.home.gamecollection
+
+import android.content.Context
+import android.view.ViewGroup
+import androidx.core.graphics.drawable.toDrawable
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.base.BaseActivity
+import com.gh.common.util.DirectUtils
+import com.gh.common.util.NewLogUtils
+import com.gh.common.util.safelyGetInRelease
+import com.gh.gamecenter.GameDetailActivity
+import com.gh.gamecenter.R
+import com.gh.gamecenter.databinding.HomeGameCollectionCardItemBinding
+import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
+import com.gh.gamecenter.gamecollection.square.GameCollectionListItemData
+import com.lightgame.adapter.BaseRecyclerAdapter
+
+class HomeGameCollectionAdapter(context: Context, private val entrance: String) :
+ BaseRecyclerAdapter(context) {
+
+ private var mGameCollectionItemDataList = listOf()
+
+ fun setGameCollectionList(gameCollectionItemDataList: List) {
+ mGameCollectionItemDataList = gameCollectionItemDataList
+ notifyDataSetChanged()
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = HomeGameCollectionCardViewHolder(
+ HomeGameCollectionCardItemBinding.bind(
+ mLayoutInflater.inflate(
+ R.layout.home_game_collection_card_item,
+ parent,
+ false
+ )
+ )
+ )
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ if (holder is HomeGameCollectionCardViewHolder && mGameCollectionItemDataList.isNotEmpty()) {
+ val realPosition: Int
+ when (position) {
+ 0 -> {
+ realPosition = getRealCount() - 2
+ }
+ 1 -> {
+ realPosition = getRealCount() - 1
+ }
+ itemCount - 2 -> {
+ realPosition = 0
+ }
+ itemCount - 1 -> {
+ realPosition = 1
+ }
+ else -> {
+ realPosition = position - 2
+ }
+ }
+ holder.bindGameListCard(mGameCollectionItemDataList[realPosition], entrance)
+ }
+ }
+
+ override fun getItemCount() = getRealCount() + 4
+
+ fun getRealCount() = mGameCollectionItemDataList.size
+
+ class HomeGameCollectionCardViewHolder(val binding: HomeGameCollectionCardItemBinding) :
+ RecyclerView.ViewHolder(binding.root) {
+ fun bindGameListCard(itemData: GameCollectionListItemData, entrance: String) {
+ binding.run {
+ val context = root.context
+ val gamesCollectionEntity = itemData.gameCollectionItem
+ if (gamesCollectionEntity != null) {
+ entity = gamesCollectionEntity
+ stampIv.setImageDrawable(if (gamesCollectionEntity.stamp == "official") R.drawable.ic_official.toDrawable() else R.drawable.ic_chosen.toDrawable())
+ iconIvOne.setOnClickListener {
+ val game = gamesCollectionEntity.games?.get(0)
+ NewLogUtils.logClickGameCollectionGameIcon(
+ gamesCollectionEntity.title,
+ gamesCollectionEntity.id,
+ game?.name ?: "",
+ game?.id ?: ""
+ )
+ game?.id?.let { id ->
+ GameDetailActivity.startGameDetailActivity(context, id, BaseActivity.mergeEntranceAndPath(entrance, "游戏单"), itemData.exposureEventList?.safelyGetInRelease(0))
+ }
+ }
+ iconIvTwo.setOnClickListener {
+ val game = gamesCollectionEntity.games?.get(1)
+ NewLogUtils.logClickGameCollectionGameIcon(
+ gamesCollectionEntity.title,
+ gamesCollectionEntity.id,
+ game?.name ?: "",
+ game?.id ?: ""
+ )
+ game?.id?.let { id ->
+ GameDetailActivity.startGameDetailActivity(context, id, BaseActivity.mergeEntranceAndPath(entrance, "游戏单"), itemData.exposureEventList?.safelyGetInRelease(1))
+ }
+ }
+ iconIvThree.setOnClickListener {
+ val game = gamesCollectionEntity.games?.get(2)
+ NewLogUtils.logClickGameCollectionGameIcon(
+ gamesCollectionEntity.title,
+ gamesCollectionEntity.id,
+ game?.name ?: "",
+ game?.id ?: ""
+ )
+ game?.id?.let { id ->
+ GameDetailActivity.startGameDetailActivity(context, id, BaseActivity.mergeEntranceAndPath(entrance, "游戏单"), itemData.exposureEventList?.safelyGetInRelease(2))
+ }
+ }
+ userContainer.setOnClickListener {
+ NewLogUtils.logClickGameCollectionAuthor(gamesCollectionEntity.title, gamesCollectionEntity.id)
+ DirectUtils.directToHomeActivity(context, gamesCollectionEntity.user?.id, 0, entrance, "游戏单")
+ }
+ root.setOnClickListener {
+ NewLogUtils.logEnterGameCollectionDetail(gamesCollectionEntity.title, gamesCollectionEntity.id)
+ context.startActivity(GameCollectionDetailActivity.getIntent(context, gamesCollectionEntity.id, true))
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/home/gamecollection/HomeGameCollectionViewHolder.kt b/app/src/main/java/com/gh/gamecenter/home/gamecollection/HomeGameCollectionViewHolder.kt
new file mode 100644
index 0000000000..25c67b9ef9
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/home/gamecollection/HomeGameCollectionViewHolder.kt
@@ -0,0 +1,46 @@
+package com.gh.gamecenter.home.gamecollection
+
+import com.gh.base.BaseRecyclerViewHolder
+import com.gh.common.util.dip2px
+import com.gh.common.view.stacklayoutmanager.StackLayoutManager
+import com.gh.gamecenter.databinding.HomeGameCollectionItemBinding
+import com.gh.gamecenter.gamecollection.square.GameCollectionListItemData
+
+class HomeGameCollectionViewHolder(val binding: HomeGameCollectionItemBinding) :
+ BaseRecyclerViewHolder(binding.root) {
+ fun bindGameCollectionList(gameCollectionItemDataList: List, entrance: String) {
+ if (binding.recyclerView.adapter is HomeGameCollectionAdapter) {
+ return
+ }
+ val adapter = HomeGameCollectionAdapter(binding.root.context, entrance)
+ val manager = StackLayoutManager(
+ StackLayoutManager.ScrollOrientation.RIGHT_TO_LEFT,
+ 3,
+ GameCollectionStackAnimation::class.java,
+ GameCollectionStackLayout::class.java
+ )
+ manager.setItemOffset(9F.dip2px())
+ manager.setItemChangedListener(object : StackLayoutManager.ItemChangedListener {
+ override fun onItemChanged(position: Int) {
+ when (position) {
+ 0 -> binding.recyclerView.scrollToPosition(adapter.itemCount - 3)
+ // 最后一个item跳转
+ adapter.itemCount - 3 -> binding.recyclerView.scrollToPosition(1)
+ }
+ }
+ })
+ binding.recyclerView.layoutManager = manager
+ binding.recyclerView.adapter = adapter
+ binding.recyclerView.isNestedScrollingEnabled = false
+
+ adapter.setGameCollectionList(gameCollectionItemDataList)
+ binding.recyclerView.post {
+ // 定位到实际的第一个item
+ manager.scrollToPosition(FIRST_ITEM_POSITION)
+ }
+ }
+
+ companion object {
+ const val FIRST_ITEM_POSITION = 2
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/message/MessageItemViewHolder.java b/app/src/main/java/com/gh/gamecenter/message/MessageItemViewHolder.java
index 4bd813c2d5..948994a277 100644
--- a/app/src/main/java/com/gh/gamecenter/message/MessageItemViewHolder.java
+++ b/app/src/main/java/com/gh/gamecenter/message/MessageItemViewHolder.java
@@ -26,6 +26,7 @@ import com.gh.gamecenter.entity.LinkEntity;
import com.gh.gamecenter.entity.MessageEntity;
import com.gh.gamecenter.entity.MessageFold;
import com.gh.gamecenter.entity.UserEntity;
+import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity;
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity;
import com.gh.gamecenter.manager.UserManager;
import com.gh.gamecenter.qa.answer.detail.SimpleAnswerDetailActivity;
@@ -413,6 +414,50 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder
mBinding.messageArticleIcon.setVisibility(View.GONE);
voteMoreUser(messageEntity);
break;
+ case "game_list_vote":
+ mBinding.messageCommand.setText("赞了你的游戏单");
+ mBinding.messageContent.setVisibility(View.GONE);
+ mBinding.messageOriginalTitle.setText(messageEntity.getGameList().getTitle());
+ targetUrl = messageEntity.getGameList().getCover();
+ ImageUtils.displayIcon(mBinding.messageAskIcon, targetUrl);
+ mBinding.messageAskIcon.setVisibility(View.VISIBLE);
+ mBinding.messageArticleIcon.setVisibility(View.GONE);
+ voteMoreUser(messageEntity);
+ break;
+ case "game_list_comment":
+ mBinding.messageCommand.setText("评论了你");
+ mBinding.messageContent.setVisibility(View.VISIBLE);
+ mBinding.messageContent.setMaxLines(Integer.MAX_VALUE);
+ mBinding.messageContent.setText(messageEntity.getComment().getContent());
+ mBinding.messageOriginalTitle.setText(messageEntity.getGameList().getTitle());
+ targetUrl = messageEntity.getGameList().getCover();
+ ImageUtils.displayIcon(mBinding.messageAskIcon, targetUrl);
+ mBinding.messageAskIcon.setVisibility(View.VISIBLE);
+ mBinding.messageArticleIcon.setVisibility(View.GONE);
+ voteMoreUser(messageEntity);
+ break;
+ case "game_list_comment_reply":
+ mBinding.messageCommand.setText("回复了你");
+ mBinding.messageContent.setVisibility(View.VISIBLE);
+ mBinding.messageContent.setMaxLines(Integer.MAX_VALUE);
+ mBinding.messageContent.setText(messageEntity.getComment().getContent());
+ mBinding.messageOriginalTitle.setText(messageEntity.getGameList().getTitle());
+ targetUrl = messageEntity.getGameList().getCover();
+ ImageUtils.displayIcon(mBinding.messageAskIcon, targetUrl);
+ mBinding.messageAskIcon.setVisibility(View.VISIBLE);
+ mBinding.messageArticleIcon.setVisibility(View.GONE);
+ voteMoreUser(messageEntity);
+ break;
+ case "game_list_comment_vote":
+ mBinding.messageCommand.setText("赞了你的评论");
+ mBinding.messageContent.setVisibility(View.GONE);
+ mBinding.messageOriginalTitle.setText(messageEntity.getGameList().getTitle());
+ targetUrl = messageEntity.getGameList().getCover();
+ ImageUtils.displayIcon(mBinding.messageAskIcon, targetUrl);
+ mBinding.messageAskIcon.setVisibility(View.VISIBLE);
+ mBinding.messageArticleIcon.setVisibility(View.GONE);
+ voteMoreUser(messageEntity);
+ break;
}
switch (messageEntity.getType()) {
case "video_comment":
@@ -661,6 +706,33 @@ public class MessageItemViewHolder extends BaseRecyclerViewHolder
context.startActivity(WebActivity.getIntent(context, entity.getActivity().getUrlComment(), true));
}
break;
+
+ case "game_list_comment":
+ context.startActivity(GameCollectionDetailActivity.getIntent(context, entity.getGameList().getId(), false, true));
+ break;
+ case "game_list_comment_reply":
+ context.startActivity(CommentActivity.getGameCollectionCommentDetailIntent(
+ context,
+ entity.getComment().getTopId(),
+ entity.getGameList().getId(),
+ false,
+ entrance,
+ path
+ ));
+ break;
+ case "game_list_comment_vote":
+ context.startActivity(CommentActivity.getGameCollectionCommentDetailIntent(
+ context,
+ entity.getComment().getId(),
+ entity.getGameList().getId(),
+ false,
+ entrance,
+ path
+ ));
+ break;
+ case "game_list_vote":
+ context.startActivity(GameCollectionDetailActivity.getIntent(context, entity.getGameList().getId(), false));
+ break;
}
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/mygame/MyGameActivity.kt b/app/src/main/java/com/gh/gamecenter/mygame/MyGameActivity.kt
index 2df1c1b7d8..1a61e45d12 100644
--- a/app/src/main/java/com/gh/gamecenter/mygame/MyGameActivity.kt
+++ b/app/src/main/java/com/gh/gamecenter/mygame/MyGameActivity.kt
@@ -3,15 +3,26 @@ package com.gh.gamecenter.mygame
import android.content.Context
import android.content.Intent
import android.os.Bundle
+import android.view.Gravity
+import android.view.MenuItem
+import android.widget.LinearLayout
import androidx.fragment.app.Fragment
import com.gh.base.BaseActivity_TabLayout
-import com.gh.common.util.MtaHelper
+import com.gh.common.AppExecutor
+import com.gh.common.constant.Constants
+import com.gh.common.util.*
+import com.gh.common.view.BugFixedPopupWindow
+import com.gh.gamecenter.R
+import com.gh.gamecenter.databinding.PopupMyGameGuideBinding
+import com.gh.gamecenter.gamecollection.publish.GameCollectionEditActivity
class MyGameActivity : BaseActivity_TabLayout() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setNavigationTitle("我的游戏")
+ setToolbarMenu(R.menu.menu_my_game)
+ showGuide()
}
override fun initFragmentList(fragments: MutableList?) {
@@ -32,6 +43,33 @@ class MyGameActivity : BaseActivity_TabLayout() {
MtaHelper.onEvent("我的光环_新", "我的游戏", "${mTabTitleList[position]}Tab")
}
+ override fun onMenuItemClick(item: MenuItem?): Boolean {
+ if (item?.itemId == R.id.menu_create_game_collection) {
+ showRegulationTestDialogIfNeeded {
+ startActivity(GameCollectionEditActivity.getIntent(this, mEntrance, "我的游戏"))
+ }
+ }
+ return super.onMenuItemClick(item)
+ }
+
+ private fun showGuide() {
+ AppExecutor.uiExecutor.executeWithDelay({
+ if (!SPUtils.getBoolean(Constants.SP_MY_GAME_GUIDE)) {
+ val binding = PopupMyGameGuideBinding.inflate(layoutInflater, null, false)
+ val popupWindow = BugFixedPopupWindow(binding.root, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT)
+ binding.root.setOnClickListener {
+ SPUtils.setBoolean(Constants.SP_MY_GAME_GUIDE, true)
+ popupWindow.dismiss()
+ }
+ popupWindow.run {
+ isTouchable = true
+ isFocusable = true
+ showAtLocation(window.decorView, Gravity.TOP, 0, 0)
+ }
+ }
+ }, 500)
+ }
+
companion object {
@JvmStatic
fun getIntentWithConfig(context: Context, defaultFragmentPosition: Int): Intent {
diff --git a/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameViewModel.kt b/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameViewModel.kt
index 203f6982f9..17bb6bd809 100644
--- a/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/mygame/PlayedGameViewModel.kt
@@ -16,8 +16,8 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
-class PlayedGameViewModel(application: Application, var userId: String)
- : ListViewModel(application) {
+class PlayedGameViewModel(application: Application, var userId: String, val isKeepTagStyle: Boolean = false) :
+ ListViewModel(application) {
override fun provideDataObservable(page: Int): Observable>? {
return null
@@ -29,9 +29,11 @@ class PlayedGameViewModel(application: Application, var userId: String)
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) {
- it.forEach { game ->
- game.hideSizeInsideDes = true
- game.tagStyle.clear()
+ if (!isKeepTagStyle) {
+ it.forEach { game ->
+ game.hideSizeInsideDes = true
+ game.tagStyle.clear()
+ }
}
mResultLiveData.postValue(it)
}
@@ -40,32 +42,32 @@ class PlayedGameViewModel(application: Application, var userId: String)
@SuppressLint("CheckResult")
fun deletePlayedGame(gameEntity: GameEntity) {
RetrofitManager.getInstance(getApplication()).api
- .deletePlayedGame(userId, gameEntity.playedGameId)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(object : BiResponse() {
- override fun onSuccess(data: ResponseBody) {
- mListLiveData.value?.let {
- for (game in it) {
- if (gameEntity.id == game.id) {
- it.remove(game)
- mListLiveData.postValue(it)
- break
- }
+ .deletePlayedGame(userId, gameEntity.playedGameId)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(object : BiResponse() {
+ override fun onSuccess(data: ResponseBody) {
+ mListLiveData.value?.let {
+ for (game in it) {
+ if (gameEntity.id == game.id) {
+ it.remove(game)
+ mListLiveData.postValue(it)
+ break
}
}
}
+ }
- override fun onFailure(exception: Exception) {
- super.onFailure(exception)
- Utils.toast(getApplication(), exception.localizedMessage)
- }
- })
+ override fun onFailure(exception: Exception) {
+ super.onFailure(exception)
+ Utils.toast(getApplication(), exception.localizedMessage)
+ }
+ })
}
- class Factory(private val mUserId: String) : ViewModelProvider.NewInstanceFactory() {
+ class Factory(private val mUserId: String, val isKeepTagStyle: Boolean = false) : ViewModelProvider.NewInstanceFactory() {
override fun create(modelClass: Class): T {
- return PlayedGameViewModel(HaloApp.getInstance().application, mUserId) as T
+ return PlayedGameViewModel(HaloApp.getInstance().application, mUserId, isKeepTagStyle) as T
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/personal/PersonalFunctionAdapter.kt b/app/src/main/java/com/gh/gamecenter/personal/PersonalFunctionAdapter.kt
index 316bdfac35..ef399a48fd 100644
--- a/app/src/main/java/com/gh/gamecenter/personal/PersonalFunctionAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/personal/PersonalFunctionAdapter.kt
@@ -18,6 +18,7 @@ import com.gh.gamecenter.entity.FunctionalGroupEntity
import com.gh.gamecenter.entity.FunctionalLinkEntity
import com.gh.gamecenter.entity.FunctionalMessageType
import com.gh.gamecenter.game.upload.GameSubmissionActivity
+import com.gh.gamecenter.gamecollection.mine.MyGameCollectionActivity
import com.gh.gamecenter.gamedetail.myrating.MyRatingActivity
import com.gh.gamecenter.history.HistoryActivity
import com.gh.gamecenter.manager.UserManager
@@ -32,8 +33,8 @@ import com.gh.gamecenter.video.videomanager.VideoManagerActivity
import com.halo.assistant.HaloApp
import com.lightgame.adapter.BaseRecyclerAdapter
-class PersonalFunctionAdapter(val context: Context, val groupName: String, var mEntityList: ArrayList)
- : BaseRecyclerAdapter(context) {
+class PersonalFunctionAdapter(val context: Context, val groupName: String, var mEntityList: ArrayList) :
+ BaseRecyclerAdapter(context) {
private var mDisplayUpdateHint = false
private val gameTrendsDao = GameTrendsDao(HaloApp.getInstance().application)
@@ -287,6 +288,13 @@ class PersonalFunctionAdapter(val context: Context, val groupName: String, var m
"青少年模式" -> {
context.startActivity(TeenagerModeActivity.getIntent(context))
}
+ "我的游戏单" -> {
+ if (UserManager.getInstance().isLoggedIn) {
+ context.startActivity(MyGameCollectionActivity.getIntent(context))
+ } else {
+ CheckLoginUtils.checkLogin(context, "我的光环-我的游戏单") { }
+ }
+ }
else -> {
DirectUtils.directToLinkPage(context, linkEntity, "", "我的光环")
}
diff --git a/app/src/main/java/com/gh/gamecenter/personal/PersonalViewModel.kt b/app/src/main/java/com/gh/gamecenter/personal/PersonalViewModel.kt
index 66d7b945c4..44086bad67 100644
--- a/app/src/main/java/com/gh/gamecenter/personal/PersonalViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/personal/PersonalViewModel.kt
@@ -44,7 +44,8 @@ class PersonalViewModel(application: Application) : AndroidViewModel(application
Triple("浏览记录", R.drawable.personal_browsing_history, "浏览记录"),
Triple("账号安全", R.drawable.personal_account_security, "账号安全"),
Triple("模拟器游戏", R.drawable.personal_simulator_game, "模拟器游戏"),
- Triple("收货信息", R.drawable.personal_delivery_info, "收货信息")
+ Triple("收货信息", R.drawable.personal_delivery_info, "收货信息"),
+ Triple("我的游戏单", R.drawable.icon_game_collection, "我的游戏单")
)
private val contentCenterFuncs = arrayListOf(
Triple("游戏动态", R.drawable.personal_game_dynamic, "游戏动态"),
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt
index b3da17d5bf..0549a8ef36 100644
--- a/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/UserHomeFragment.kt
@@ -345,7 +345,7 @@ class UserHomeFragment : NormalFragment() {
val tag = "android:switcher:${mHomeBinding?.viewpager?.id}:"
val gameFragment = childFragmentManager.findFragmentByTag("${tag}0")
- ?: UserGameFragment.getInstance(mUserHomeViewModel.userId, count.gameComment)
+ ?: UserGameFragment.getInstance(mUserHomeViewModel.userId, count)
val qaFragment = childFragmentManager.findFragmentByTag("${tag}1")
?: UserHistoryFragment.getInstance(
mUserHomeViewModel.userId,
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/home/game/UserGameFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/home/game/UserGameFragment.kt
index 2d12705a54..2bdfdfbebb 100644
--- a/app/src/main/java/com/gh/gamecenter/personalhome/home/game/UserGameFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/home/game/UserGameFragment.kt
@@ -10,22 +10,24 @@ import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf
import com.gh.common.util.*
-import com.gh.common.util.EntranceUtils.KEY_COMMENT_COUNT
-import com.gh.common.util.EntranceUtils.KEY_USER_ID
+import com.gh.common.util.EntranceUtils.*
import com.gh.gamecenter.R
+import com.gh.gamecenter.collection.GamesCollectionFragment
import com.gh.gamecenter.databinding.FragmentUserGameBinding
+import com.gh.gamecenter.entity.PersonalEntity
import com.gh.gamecenter.normal.NormalFragment
class UserGameFragment: NormalFragment() {
private var mBinding: FragmentUserGameBinding? = null
private var mViewModel: UserGameViewModel? = null
+ private var mGamesCollectionFragment: GamesCollectionFragment? = null
private var mPlayedGameFragment: UserPlayedGameFragment? = null
private var mCommentFragment: UserCommentHistoryFragment? = null
private var mUserId: String = ""
private var mFilter: String = "全部"
- private var mCommentCount = 0
- private var mCurrentType = TYPE_PLAYED_GAME
+ private var mCount = PersonalEntity.Count()
+ private var mCurrentType = TYPE_GAME_COLLECTION
override fun getLayoutId() = 0
@@ -34,9 +36,9 @@ class UserGameFragment: NormalFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mUserId = arguments?.getString(KEY_USER_ID, "") ?: ""
- mCommentCount = arguments?.getInt(KEY_COMMENT_COUNT, 0) ?: 0
+ mCount = arguments?.getParcelable(COUNT) ?: PersonalEntity.Count()
mViewModel = viewModelProvider(UserGameViewModel.Factory(mUserId))
- changeType(TYPE_PLAYED_GAME)
+ changeType(TYPE_GAME_COLLECTION)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -47,20 +49,23 @@ class UserGameFragment: NormalFragment() {
}
mBinding?.run {
- commentType.text = "评论 $mCommentCount"
+ gameCollectionType.text = "游戏单 ${mCount.gameList}"
+ commentType.text = "评论 ${mCount.gameComment}"
- gameType.setOnClickListener {
- if (mCurrentType == TYPE_PLAYED_GAME) return@setOnClickListener
- mCurrentType = TYPE_PLAYED_GAME
- updateTypeView(TYPE_PLAYED_GAME)
- changeType(TYPE_PLAYED_GAME)
- }
+ val typePairList = arrayListOf(
+ Pair(TYPE_GAME_COLLECTION, gameCollectionType),
+ Pair(TYPE_PLAYED_GAME, gameType),
+ Pair(TYPE_COMMENT, commentType)
+ )
- commentType.setOnClickListener {
- if (mCurrentType == TYPE_COMMENT) return@setOnClickListener
- mCurrentType = TYPE_COMMENT
- updateTypeView(TYPE_COMMENT)
- changeType(TYPE_COMMENT)
+ typePairList.forEach { pair ->
+ pair.second.setOnClickListener {
+ if (mCurrentType != pair.first) {
+ mCurrentType = pair.first
+ updateTypeView(pair.first)
+ changeType(pair.first)
+ }
+ }
}
commentSubType.setOnClickListener {
@@ -71,35 +76,62 @@ class UserGameFragment: NormalFragment() {
private fun updateTypeView(type: Int) {
mBinding?.run {
- if (type == TYPE_PLAYED_GAME) {
- commentSubType.visibility = View.GONE
- arrowIv.visibility = View.GONE
- gameType.setBackgroundResource(R.drawable.button_round_f0f8ff)
- gameType.setTextColor(R.color.theme_font.toColor())
- commentType.setBackgroundResource(R.drawable.button_round_fafafa)
- commentType.setTextColor(R.color.text_333333.toColor())
- } else {
- commentSubType.visibility = View.VISIBLE
- arrowIv.visibility = View.VISIBLE
- gameType.setBackgroundResource(R.drawable.button_round_fafafa)
- gameType.setTextColor(R.color.text_333333.toColor())
- commentType.setBackgroundResource(R.drawable.button_round_f0f8ff)
- commentType.setTextColor(R.color.theme_font.toColor())
+ when (type) {
+ TYPE_GAME_COLLECTION -> {
+ commentSubType.visibility = View.GONE
+ arrowIv.visibility = View.GONE
+ gameCollectionType.setBackgroundResource(R.drawable.button_round_f0f8ff)
+ gameCollectionType.setTextColor(R.color.theme_font.toColor())
+ gameType.setBackgroundResource(R.drawable.button_round_fafafa)
+ gameType.setTextColor(R.color.text_333333.toColor())
+ commentType.setBackgroundResource(R.drawable.button_round_fafafa)
+ commentType.setTextColor(R.color.text_333333.toColor())
+ }
+ TYPE_PLAYED_GAME -> {
+ commentSubType.visibility = View.GONE
+ arrowIv.visibility = View.GONE
+ gameCollectionType.setBackgroundResource(R.drawable.button_round_fafafa)
+ gameCollectionType.setTextColor(R.color.text_333333.toColor())
+ gameType.setBackgroundResource(R.drawable.button_round_f0f8ff)
+ gameType.setTextColor(R.color.theme_font.toColor())
+ commentType.setBackgroundResource(R.drawable.button_round_fafafa)
+ commentType.setTextColor(R.color.text_333333.toColor())
+ }
+ else -> {
+ commentSubType.visibility = View.VISIBLE
+ arrowIv.visibility = View.VISIBLE
+ gameCollectionType.setBackgroundResource(R.drawable.button_round_fafafa)
+ gameCollectionType.setTextColor(R.color.text_333333.toColor())
+ gameType.setBackgroundResource(R.drawable.button_round_fafafa)
+ gameType.setTextColor(R.color.text_333333.toColor())
+ commentType.setBackgroundResource(R.drawable.button_round_f0f8ff)
+ commentType.setTextColor(R.color.theme_font.toColor())
+ }
}
}
}
private fun changeType(type: Int) {
- if (type == TYPE_PLAYED_GAME) {
- mPlayedGameFragment = childFragmentManager.findFragmentByTag(UserPlayedGameFragment::class.java.simpleName) as? UserPlayedGameFragment
+ when (type) {
+ TYPE_GAME_COLLECTION -> {
+ mGamesCollectionFragment = childFragmentManager.findFragmentByTag(UserPlayedGameFragment::class.java.simpleName) as? GamesCollectionFragment
+ ?: GamesCollectionFragment()
+ mGamesCollectionFragment?.arguments =
+ bundleOf(KEY_USER_ID to mUserId, KEY_TYPE to GamesCollectionFragment.TYPE_USER)
+ childFragmentManager.beginTransaction().replace(R.id.contentContainer, mGamesCollectionFragment!!, GamesCollectionFragment::class.java.simpleName).commitAllowingStateLoss()
+ }
+ TYPE_PLAYED_GAME -> {
+ mPlayedGameFragment = childFragmentManager.findFragmentByTag(UserPlayedGameFragment::class.java.simpleName) as? UserPlayedGameFragment
?: UserPlayedGameFragment()
- mPlayedGameFragment?.arguments = bundleOf(KEY_USER_ID to mUserId)
- childFragmentManager.beginTransaction().replace(R.id.contentContainer, mPlayedGameFragment!!, UserPlayedGameFragment::class.java.simpleName).commitAllowingStateLoss()
- } else {
- mCommentFragment = childFragmentManager.findFragmentByTag(UserCommentHistoryFragment::class.java.simpleName) as? UserCommentHistoryFragment
+ mPlayedGameFragment?.arguments = bundleOf(KEY_USER_ID to mUserId)
+ childFragmentManager.beginTransaction().replace(R.id.contentContainer, mPlayedGameFragment!!, UserPlayedGameFragment::class.java.simpleName).commitAllowingStateLoss()
+ }
+ else -> {
+ mCommentFragment = childFragmentManager.findFragmentByTag(UserCommentHistoryFragment::class.java.simpleName) as? UserCommentHistoryFragment
?: UserCommentHistoryFragment()
- mCommentFragment?.arguments = bundleOf(KEY_USER_ID to mUserId)
- childFragmentManager.beginTransaction().replace(R.id.contentContainer, mCommentFragment!!, UserCommentHistoryFragment::class.java.simpleName).commitAllowingStateLoss()
+ mCommentFragment?.arguments = bundleOf(KEY_USER_ID to mUserId)
+ childFragmentManager.beginTransaction().replace(R.id.contentContainer, mCommentFragment!!, UserCommentHistoryFragment::class.java.simpleName).commitAllowingStateLoss()
+ }
}
}
@@ -154,14 +186,16 @@ class UserGameFragment: NormalFragment() {
}
companion object {
- private const val TYPE_PLAYED_GAME = 100
- private const val TYPE_COMMENT = 101
+ private const val TYPE_GAME_COLLECTION = 100
+ private const val TYPE_PLAYED_GAME = 101
+ private const val TYPE_COMMENT = 102
+ const val COUNT = "count"
- fun getInstance(userId: String, commentCount: Int): UserGameFragment {
+ fun getInstance(userId: String, count: PersonalEntity.Count): UserGameFragment {
return UserGameFragment().apply {
with(bundleOf(
- KEY_USER_ID to userId,
- KEY_COMMENT_COUNT to commentCount
+ KEY_USER_ID to userId,
+ COUNT to count
))
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/personalhome/home/game/UserPlayedGameFragment.kt b/app/src/main/java/com/gh/gamecenter/personalhome/home/game/UserPlayedGameFragment.kt
index 5eab999e09..e810967e03 100644
--- a/app/src/main/java/com/gh/gamecenter/personalhome/home/game/UserPlayedGameFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/personalhome/home/game/UserPlayedGameFragment.kt
@@ -26,7 +26,7 @@ import com.lightgame.download.DownloadEntity
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
-class UserPlayedGameFragment: ListFragment() {
+open class UserPlayedGameFragment: ListFragment() {
private var mUserId = ""
private var mAdapter: UserPlayedGameAdapter? = null
diff --git a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailFragment.kt
index 4d0009d7a7..c95a6e392e 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/answer/detail/AnswerDetailFragment.kt
@@ -635,8 +635,8 @@ open class AnswerDetailFragment : NormalFragment() {
}
}
- private fun getShareEntity(answer: AnswerDetailEntity): ForumShareEntity {
- return ForumShareEntity(
+ private fun getShareEntity(answer: AnswerDetailEntity): NormalShareEntity {
+ return NormalShareEntity(
id = mAnswerId,
shareUrl = if (isPublishEnv()) {
getString(R.string.share_answers_url, mAnswerId)
diff --git a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailFragment.kt
index 21a6b49f39..11aaa9b9ed 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/article/detail/ArticleDetailFragment.kt
@@ -26,7 +26,6 @@ import com.gh.common.util.*
import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.ListAdapter
-import com.gh.gamecenter.baselist.LoadStatus
import com.gh.gamecenter.baselist.LoadType
import com.gh.gamecenter.databinding.FragmentArticleDetailBinding
import com.gh.gamecenter.entity.*
@@ -575,8 +574,8 @@ class ArticleDetailFragment : BaseCommentFragment {
+ GameCollectionCommentConversationFragment().with(intent.extras)
+ }
isCommentConversation && commentId.isNotEmpty() -> {
CommentConversationFragment().with(intent.extras)
}
@@ -96,6 +102,17 @@ class CommentActivity : BaseActivity() {
commentEntity,
commentCallback)
}
+ gameCollectionId.isNotEmpty() -> {
+ NewCommentFragment.getGameCollectionCommentInstance(
+ gameCollectionId,
+ commentId,
+ showKeyboard,
+ commentCount,
+ mShowInputOnly,
+ useReplyApi,
+ commentEntity,
+ commentCallback)
+ }
else -> {
NewCommentFragment.getVideoCommentInstance(
videoId,
@@ -158,6 +175,8 @@ class CommentActivity : BaseActivity() {
const val VIDEO_ID = "video_id"
+ const val GAME_COLLECTION_ID = "game_collection_id"
+
const val REQUEST_CODE = 8123
@JvmStatic
@@ -337,5 +356,65 @@ class CommentActivity : BaseActivity() {
}
return intent
}
+
+ /**
+ * 评论游戏单
+ */
+ @JvmStatic
+ fun getGameCollectionCommentIntent(context: Context,
+ gameCollectionId: String,
+ commentCount: Int? = 0): Intent {
+ val intent = Intent(context, CommentActivity::class.java)
+ intent.putExtra(GAME_COLLECTION_ID, gameCollectionId)
+ intent.putExtra(COMMENT_COUNT, commentCount)
+ intent.putExtra(SHOW_KEYBOARD, true)
+ intent.putExtra(SHOW_INPUT_ONLY, true)
+ if (context is Activity) {
+ context.overridePendingTransition(0, 0)
+ }
+ return intent
+ }
+
+ /**
+ * 回复游戏单评论
+ */
+ fun getGameCollectionCommentReplyIntent(context: Context,
+ gameCollectionId: String,
+ commentId: String,
+ commentCount: Int? = 0,
+ commentEntity: CommentEntity? = null): Intent {
+ val intent = Intent(context, CommentActivity::class.java)
+ intent.putExtra(GAME_COLLECTION_ID, gameCollectionId)
+ intent.putExtra(KEY_COMMENT_ID, commentId)
+ intent.putExtra(COMMENT_COUNT, commentCount)
+ intent.putExtra(SHOW_KEYBOARD, true)
+ intent.putExtra(SHOW_INPUT_ONLY, true)
+ intent.putExtra(COMMENT_ENTITY, commentEntity)
+ intent.putExtra(USE_REPLY_API, true)
+ if (context is Activity) {
+ context.overridePendingTransition(0, 0)
+ }
+ return intent
+ }
+
+ /**
+ * 游戏单评论对话
+ */
+ @JvmStatic
+ fun getGameCollectionCommentDetailIntent(context: Context,
+ commentId: String,
+ gameCollectionId: String,
+ showKeyboard: Boolean = false,
+ entrance: String,
+ path: String): Intent {
+ val intent = Intent(context, CommentActivity::class.java)
+ intent.putExtra(EntranceUtils.KEY_ENTRANCE, NormalActivity.mergeEntranceAndPath(entrance, path))
+ intent.putExtra(GAME_COLLECTION_ID, gameCollectionId)
+ intent.putExtra(EntranceUtils.KEY_COMMENT_ID, commentId)
+ intent.putExtra(EntranceUtils.KEY_SHOW_KEYBOARD_IF_NEEDED, showKeyboard)
+ intent.putExtra(EntranceUtils.KEY_PATH, path)
+ intent.putExtra(EntranceUtils.KEY_IS_COMMENT_CONVERSATION, true)
+ return intent
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentAdapter.kt
index 90e6f16681..75246370ca 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentAdapter.kt
@@ -232,6 +232,9 @@ class NewCommentAdapter(
CommentType.COMMUNITY_QUESTION,
CommentType.COMMUNITY_QUESTION_CONVERSATION -> "问题详情-评论管理"
+
+ CommentType.GAME_COLLECTION,
+ CommentType.GAME_COLLECTION_CONVERSATION -> "游戏单详情-评论管理"
}
val userHomePageTabPosition = if (mViewModel.commentType.isVideo()) 2 else 1
diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt
index 13dff479ff..c1e7bd4c63 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt
@@ -25,6 +25,7 @@ import com.gh.common.syncpage.SyncDataEntity
import com.gh.common.syncpage.SyncFieldConstants
import com.gh.common.syncpage.SyncPageRepository
import com.gh.common.util.*
+import com.gh.common.util.EntranceUtils.KEY_COMMENT_ID
import com.gh.common.view.VerticalItemDecoration
import com.gh.gamecenter.CommentDetailActivity
import com.gh.gamecenter.R
@@ -37,6 +38,7 @@ import com.gh.gamecenter.eventbus.EBCommentSuccess
import com.gh.gamecenter.eventbus.EBDeleteComment
import com.gh.gamecenter.eventbus.EBReuse
import com.gh.gamecenter.qa.answer.detail.AnswerDetailFragment
+import com.gh.gamecenter.qa.comment.CommentActivity.Companion.GAME_COLLECTION_ID
import com.gh.gamecenter.qa.comment.CommentActivity.Companion.QUESTION_ID
import com.gh.gamecenter.qa.editor.LocalMediaActivity
import com.halo.assistant.HaloApp
@@ -113,7 +115,9 @@ open class NewCommentFragment : ListFragment
protected var mCommunityId: String = ""
protected var mVideoId: String = ""
protected var mQuestionId: String = ""
+ protected var mGameCollectionId: String = ""
protected var mCommentId: String = ""
+ protected var mRootCommentId: String = ""
protected var mShowInputOnly: Boolean = false // 是否只显示输入框,不显示列表
protected var mIsVideoAuthor: Boolean = false//是否是视频作者
protected var mCommentType = CommentType.ANSWER
@@ -135,7 +139,9 @@ open class NewCommentFragment : ListFragment
mAnswerId = getString(ANSWER_ID, "")
mArticleId = getString(ARTICLE_ID, "")
mVideoId = getString(VIDEO_ID, "")
- mQuestionId = getString(CommentActivity.QUESTION_ID, "")
+ mQuestionId = getString(QUESTION_ID, "")
+ mGameCollectionId = getString(GAME_COLLECTION_ID, "")
+ mRootCommentId = getString(KEY_COMMENT_ID, "")
mCommentCount = getInt(COMMENT_COUNT, 0)
mCommentType = getSerializable(COMMENT_TYPE) as? CommentType ?: CommentType.ANSWER
mCommunityId = getString(COMMUNITY_ID, "")
@@ -358,6 +364,8 @@ open class NewCommentFragment : ListFragment
commentId = mCommentId,
videoId = mVideoId,
questionId = mQuestionId,
+ gameCollectionId = mGameCollectionId,
+ rootCommentId = mRootCommentId,
commentType = mCommentType,
isVideoAuthor = mIsVideoAuthor
)
@@ -379,6 +387,9 @@ open class NewCommentFragment : ListFragment
CommentType.VIDEO,
CommentType.VIDEO_CONVERSATION -> "(视频详情-评论列表)"
+
+ CommentType.GAME_COLLECTION,
+ CommentType.GAME_COLLECTION_CONVERSATION -> "(游戏单详情-评论列表)"
}
mAdapter = NewCommentAdapter(requireContext(), mViewModel, true, this, this, entrance)
}
@@ -544,6 +555,15 @@ open class NewCommentFragment : ListFragment
"问题详情-评论-回复"
}
}
+
+ CommentType.GAME_COLLECTION,
+ CommentType.GAME_COLLECTION_CONVERSATION -> {
+ if (mCommentEntity == null) {
+ "游戏单详情-评论-写评论"
+ } else {
+ "游戏单详情-评论-回复"
+ }
+ }
}
}
@@ -580,7 +600,7 @@ open class NewCommentFragment : ListFragment
mAnswerContent.orientation = LinearLayout.VERTICAL
mAnswerContent.background = ContextCompat.getDrawable(requireActivity(), R.drawable.bg_shape_white_radius_10_top_only)
mPlaceholderView.visibility = View.VISIBLE
- mImageBtn.goneIf(mCommentEntity != null)
+ mImageBtn.goneIf(mCommentEntity != null || mGameCollectionId.isNotEmpty())
mScrollViewParams.width = LinearLayout.LayoutParams.MATCH_PARENT
mScrollViewParams.height = 76f.dip2px()
mScrollViewParams.topMargin = 4f.dip2px()
@@ -854,5 +874,37 @@ open class NewCommentFragment : ListFragment
}
+
+ fun getGameCollectionCommentInstance(
+ gameCollectionId: String,
+ commentId: String,
+ showSoftKeyboardOnStartUp: Boolean,
+ commentCount: Int,
+ showInputOnly: Boolean,
+ useReplyApi: Boolean,
+ commentEntity: CommentEntity?,
+ listener: AnswerDetailFragment.CommentListener
+ )
+ : NewCommentFragment {
+ val commentType = if (useReplyApi) {
+ CommentType.GAME_COLLECTION_CONVERSATION
+ } else {
+ CommentType.GAME_COLLECTION
+ }
+ return NewCommentFragment().apply {
+ mCommentListener = listener
+ with(
+ bundleOf(
+ SHOW_SOFT_KEY_BOARD_ON_STARTUP to showSoftKeyboardOnStartUp,
+ GAME_COLLECTION_ID to gameCollectionId,
+ KEY_COMMENT_ID to commentId,
+ COMMENT_COUNT to commentCount,
+ COMMENT_TYPE to commentType,
+ SHOW_INPUT_ONLY to showInputOnly,
+ COMMENT_ENTITY to commentEntity
+ )
+ )
+ }
+ }
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentViewModel.kt
index 357aa0737a..b21f6ed186 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentViewModel.kt
@@ -6,7 +6,6 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
-import com.gh.common.json.json
import com.gh.common.syncpage.SyncDataEntity
import com.gh.common.syncpage.SyncFieldConstants
import com.gh.common.syncpage.SyncPageRepository
@@ -14,7 +13,6 @@ import com.gh.common.util.*
import com.gh.gamecenter.baselist.ListViewModel
import com.gh.gamecenter.entity.CommentDraft
import com.gh.gamecenter.entity.CommentEntity
-import com.gh.gamecenter.entity.ErrorEntity
import com.gh.gamecenter.retrofit.BiResponse
import com.gh.gamecenter.retrofit.Response
import com.gh.gamecenter.retrofit.RetrofitManager
@@ -37,6 +35,8 @@ open class NewCommentViewModel(
var communityId: String = "",
var videoId: String = "",
var questionId: String = "",
+ var gameCollectionId: String = "",
+ var rootCommentId: String = "",
var commentType: CommentType = CommentType.ANSWER,
var isVideoAuthor: Boolean = false
) : ListViewModel(application) {
@@ -119,6 +119,9 @@ open class NewCommentViewModel(
if (!imageUrls.isNullOrEmpty()) {
requestMap["images"] = imageUrls
}
+ if (gameCollectionId.isNotEmpty() && commentEntity != null) {
+ requestMap["root"] = rootCommentId
+ }
val body = requestMap.createRequestBodyAny()
val observable =
@@ -154,6 +157,14 @@ open class NewCommentViewModel(
api.postReplyToVideoComment(videoId, commentEntity.id, body)
}
}
+
+ CommentType.GAME_COLLECTION, CommentType.GAME_COLLECTION_CONVERSATION -> {
+ if (commentEntity == null) {
+ api.postGameCollectionComment(gameCollectionId, body)
+ } else {
+ api.postReplyToGameCollectionComment(gameCollectionId, commentEntity.id, body)
+ }
+ }
}
// TODO Remove this apiResponse crap.
@@ -330,6 +341,8 @@ open class NewCommentViewModel(
private val communityId: String = "",
private val videoId: String = "",
private val questionId: String = "",
+ private val gameCollectionId: String = "",
+ private val rootCommentId: String = "",
private val isVideoAuthor: Boolean = false,
private val commentType: CommentType
) : ViewModelProvider.NewInstanceFactory() {
@@ -342,7 +355,9 @@ open class NewCommentViewModel(
communityId = communityId,
videoId = videoId,
questionId = questionId,
+ gameCollectionId = gameCollectionId,
commentId = commentId,
+ rootCommentId = rootCommentId,
commentType = commentType,
isVideoAuthor = isVideoAuthor
) as T
@@ -361,7 +376,10 @@ enum class CommentType {
COMMUNITY_QUESTION_CONVERSATION,
VIDEO,
- VIDEO_CONVERSATION;
+ VIDEO_CONVERSATION,
+
+ GAME_COLLECTION,
+ GAME_COLLECTION_CONVERSATION;
fun isVideo(): Boolean {
return (this == VIDEO || this == VIDEO_CONVERSATION)
diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/StairsCommentFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/StairsCommentFragment.kt
index 12be0a6886..bbad14693e 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/comment/StairsCommentFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/comment/StairsCommentFragment.kt
@@ -41,6 +41,9 @@ class StairsCommentFragment : NewCommentFragment() {
CommentType.COMMUNITY_QUESTION,
CommentType.COMMUNITY_QUESTION_CONVERSATION -> "(问题详情-评论列表)"
+
+ CommentType.GAME_COLLECTION,
+ CommentType.GAME_COLLECTION_CONVERSATION -> "(游戏单详情-评论列表)"
}
mAdapter = StairsCommentAdapter(requireContext(), mViewModel, true, this, this, entrance)
}
diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/StairsCommentViewHolder.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/StairsCommentViewHolder.kt
index d0777345a8..5ea550c3fd 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/comment/StairsCommentViewHolder.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/comment/StairsCommentViewHolder.kt
@@ -298,6 +298,9 @@ class StairsCommentViewHolder(
CommentType.COMMUNITY_QUESTION,
CommentType.COMMUNITY_QUESTION_CONVERSATION -> "问题详情-评论管理"
+
+ CommentType.GAME_COLLECTION,
+ CommentType.GAME_COLLECTION_CONVERSATION -> "游戏单详情-评论管理"
}
holder.binding.commentUserIcon.setOnClickListener {
DirectUtils.directToHomeActivity(
diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentAdapter.kt
index 8a778f6f24..7d4fbf71c5 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentAdapter.kt
@@ -3,9 +3,9 @@ package com.gh.gamecenter.qa.comment.base
import android.annotation.SuppressLint
import android.content.Context
import android.text.SpannableStringBuilder
-import android.util.SparseBooleanArray
import android.view.View
import android.view.ViewGroup
+import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.GridLayoutManager
@@ -213,7 +213,7 @@ abstract class BaseCommentAdapter(
inner class CommentFooterViewHolder(var binding: ItemArticleDetailCommentFooterBinding) :
RecyclerView.ViewHolder(binding.root) {
- fun bindView(isLoading: Boolean, isNetworkError: Boolean, isOver: Boolean) {
+ fun bindView(isLoading: Boolean, isNetworkError: Boolean, isOver: Boolean, @StringRes loadOverHint: Int = R.string.load_over_hint) {
when {
isNetworkError -> {
binding.progressBar.visibility = View.GONE
@@ -221,7 +221,7 @@ abstract class BaseCommentAdapter(
}
isOver -> {
binding.progressBar.visibility = View.GONE
- binding.footerTv.setText(R.string.load_over_hint)
+ binding.footerTv.setText(loadOverHint)
}
isLoading -> {
binding.progressBar.visibility = View.VISIBLE
@@ -241,7 +241,8 @@ abstract class BaseCommentAdapter(
fun bindView(
article: ArticleDetailEntity? = null,
questions: QuestionsDetailEntity? = null,
- comment: CommentEntity? = null
+ comment: CommentEntity? = null,
+ gameCollection: Boolean? = null
) {
binding.run {
val commentCount = mViewModel.commentCount
@@ -255,12 +256,24 @@ abstract class BaseCommentAdapter(
comment != null -> {
"全部回复"
}
+ gameCollection != null -> {
+ "游戏单评论"
+ }
else -> {
""
}
}
+
commentHintCountTv.text = NumberUtils.transSimpleCount(commentCount)
+ if (gameCollection != null) {
+ filterLatestTv.text = "最新"
+ filterOldestTv.text = "最早"
+ } else {
+ filterLatestTv.text = "倒序"
+ filterOldestTv.text = "正序"
+ }
+
filterLatestTv.setOnClickListener {
mViewModel.changeSort(BaseCommentViewModel.SortType.LATEST)
updateSortType()
diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentFragment.kt
index 7abc55a1b2..49642d441c 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentFragment.kt
@@ -12,6 +12,7 @@ import com.gh.common.view.CustomDividerItemDecoration
import com.gh.common.view.vertical_recycler.SnappingLinearLayoutManager
import com.gh.gamecenter.R
import com.gh.gamecenter.baselist.ListFragment
+import com.gh.gamecenter.gamecollection.detail.conversation.GameCollectionCommentConversationFragment
import com.gh.gamecenter.qa.comment.conversation.CommentConversationFragment
abstract class BaseCommentFragment : ListFragment() {
@@ -40,7 +41,8 @@ abstract class BaseCommentFragment : ListFragment<
mListRv.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
- if (this@BaseCommentFragment is CommentConversationFragment) return
+ if (this@BaseCommentFragment is CommentConversationFragment
+ || this@BaseCommentFragment is GameCollectionCommentConversationFragment) return
val firstCompletelyVisiblePosition = mLayoutManager.findFirstCompletelyVisibleItemPosition()
if (RecyclerView.NO_POSITION == firstCompletelyVisiblePosition) return
diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentViewModel.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentViewModel.kt
index b025d3e774..695ec77801 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/comment/base/BaseCommentViewModel.kt
@@ -200,7 +200,7 @@ abstract class BaseCommentViewModel(
}
@SuppressLint("CheckResult")
- fun deleteComment(entity: CommentEntity, callback: () -> Unit) {
+ open fun deleteComment(entity: CommentEntity, callback: () -> Unit) {
val observable = when {
videoId.isNotEmpty() -> {
if (entity.me?.isModerator == true) {
diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/conversation/CommentConversationFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/conversation/CommentConversationFragment.kt
index ed25b34f9c..b4062c022d 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/comment/conversation/CommentConversationFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/comment/conversation/CommentConversationFragment.kt
@@ -1,11 +1,11 @@
package com.gh.gamecenter.qa.comment.conversation
import android.annotation.SuppressLint
+import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
-import androidx.appcompat.app.AppCompatActivity
import com.ethanhua.skeleton.Skeleton
import com.gh.common.AppExecutor
import com.gh.common.syncpage.SyncDataEntity
@@ -66,12 +66,14 @@ class CommentConversationFragment : BaseCommentFragment {
mApi.getQuestionCommentReply(questionId, commentId, currentSortType.value, page)
}
+ gameCollectionId.isNotEmpty() -> {
+ mApi.getGameCollectionCommentReply(gameCollectionId, commentId, page)
+ }
else -> null
}
}
@@ -53,6 +57,9 @@ class CommentConversationViewModel(application: Application,
questionId.isNotEmpty() -> {
mApi.getCommunityQuestionComment(questionId, commentId)
}
+ gameCollectionId.isNotEmpty() -> {
+ mApi.getGameCollectionComment(gameCollectionId, commentId)
+ }
else -> null
} ?: return
single.subscribeOn(Schedulers.io())
@@ -87,6 +94,7 @@ class CommentConversationViewModel(application: Application,
private val videoId: String = "",
private val questionId: String = "",
private val communityId: String = "",
+ private val gameCollectionId: String = "",
private val commentId: String) : ViewModelProvider.NewInstanceFactory() {
override fun create(modelClass: Class): T {
@@ -96,6 +104,7 @@ class CommentConversationViewModel(application: Application,
videoId = videoId,
questionId = questionId,
communityId = communityId,
+ gameCollectionId = gameCollectionId,
commentId = commentId) as T
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/qa/dialog/MoreFunctionPanelDialog.kt b/app/src/main/java/com/gh/gamecenter/qa/dialog/MoreFunctionPanelDialog.kt
index 19d80c5739..142d8af081 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/dialog/MoreFunctionPanelDialog.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/dialog/MoreFunctionPanelDialog.kt
@@ -15,7 +15,7 @@ import com.gh.common.dialog.BaseDraggableDialogFragment
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.databinding.DialogGameDetailMoreBinding
-import com.gh.gamecenter.entity.ForumShareEntity
+import com.gh.gamecenter.entity.NormalShareEntity
import com.gh.gamecenter.entity.MenuItemEntity
class MoreFunctionPanelDialog : BaseDraggableDialogFragment() {
@@ -25,7 +25,7 @@ class MoreFunctionPanelDialog : BaseDraggableDialogFragment() {
private var mTitle: String = ""
private var mParentTag: String = ""
private var mStatus: String = ""
- private var mShareEntity: ForumShareEntity? = null
+ private var mShareEntity: NormalShareEntity? = null
private var mShareUtils: ShareUtils? = null
override fun onCreate(savedInstanceState: Bundle?) {
@@ -197,7 +197,7 @@ class MoreFunctionPanelDialog : BaseDraggableDialogFragment() {
activity: AppCompatActivity,
menuItems: ArrayList,
title: String,
- share: ForumShareEntity,
+ share: NormalShareEntity,
status: String,
parentTag: String
) {
diff --git a/app/src/main/java/com/gh/gamecenter/qa/editor/GameActivity.kt b/app/src/main/java/com/gh/gamecenter/qa/editor/GameActivity.kt
index 0028f12c36..bddaa7d784 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/editor/GameActivity.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/editor/GameActivity.kt
@@ -2,201 +2,22 @@ package com.gh.gamecenter.qa.editor
import android.content.Context
import android.content.Intent
-import android.os.Bundle
-import android.os.Message
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.View
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import androidx.lifecycle.ViewModelProviders
-import androidx.recyclerview.widget.RecyclerView
-import com.gh.common.constant.Config
+import androidx.core.os.bundleOf
import com.gh.common.util.EntranceUtils
-import com.gh.common.view.FixLinearLayoutManager
-import com.gh.common.view.VerticalItemDecoration
-import com.gh.gamecenter.BuildConfig
-import com.gh.gamecenter.R
-import com.gh.gamecenter.baselist.ListActivity
-import com.gh.gamecenter.baselist.NormalListViewModel
-import com.gh.gamecenter.entity.GameEntity
-import com.gh.gamecenter.manager.UserManager
-import com.gh.gamecenter.qa.entity.EditorInsertDefaultEntity
-import com.gh.gamecenter.retrofit.Response
-import com.gh.gamecenter.retrofit.RetrofitManager
-import com.google.android.material.appbar.AppBarLayout
-import com.halo.assistant.HaloApp
-import com.lightgame.utils.Util_System_Keyboard
-import io.reactivex.Observable
-import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.schedulers.Schedulers
-import kotterknife.bindView
+import com.gh.gamecenter.NormalActivity
-class GameActivity : ListActivity>() {
+class GameActivity : NormalActivity() {
- val searchEt by bindView(R.id.search_input)
- val searchTv by bindView(R.id.search_button)
- val searchBack by bindView(R.id.search_back)
- val appBar by bindView(R.id.list_appbar)
- val noneText by bindView(R.id.reuse_tv_none_data)
- val defaultList by bindView(R.id.default_list)
- val defaultListContainer by bindView(R.id.default_list_container)
-
- private var mAdapter: GameAdapter? = null
-
- private var mSearchKey: String = ""
-
- override fun handleMessage(msg: Message) {
- if (msg.what == 1) {
- if (mSearchKey.isEmpty()) {
- clearPage()
- } else {
- search()
- }
- }
- }
-
- override fun getLayoutId(): Int {
- return R.layout.activity_editor_insert_game
- }
-
- override fun isAutomaticLoad(): Boolean {
- return false
- }
-
- override fun getItemDecoration(): RecyclerView.ItemDecoration {
- return VerticalItemDecoration(this, 8f, false)
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- val title = intent?.getStringExtra(EntranceUtils.KEY_NAVIGATION_TITLE) ?: INSERT_GAME_TITLE
- setNavigationTitle(title)
- noneText.text = "搜索结果为空"
- mListLoading.visibility = View.GONE
- mListRefresh.isEnabled = false
-// appBar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
-// val totalScrollRange = appBarLayout.totalScrollRange
-// if (totalScrollRange == -verticalOffset) {
-// Util_System_Keyboard.hideSoftKeyboard(this)
-// }
-// })
-
- searchEt.setOnEditorActionListener { _, actionId, _ ->
- if (actionId == EditorInfo.IME_ACTION_SEARCH) {
- search()
- }
- false
- }
-
- searchTv.setOnClickListener {
- search()
- Util_System_Keyboard.hideSoftKeyboard(this)
- }
- searchBack.setOnClickListener {
- searchEt.setText("")
- }
-
- searchEt.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
- }
-
- override fun afterTextChanged(s: Editable) {
- val newSearchKey = s.toString().trim()
- if (newSearchKey != mSearchKey) {
- mBaseHandler.removeMessages(1)
- mSearchKey = newSearchKey
- mBaseHandler.sendEmptyMessageDelayed(1, 500)
- }
- searchBack.visibility = if (newSearchKey.isNotEmpty()) View.VISIBLE
- else View.GONE
- }
- })
-
- mListRv.clearOnScrollListeners()
-
- // default open soft keyboard
- searchEt.requestFocus()
- Util_System_Keyboard.showSoftKeyboard(this, searchEt)
-
- if (title == SELECT_GAME_TITLE) initDefaultData()
- }
-
- private fun clearPage() {
- mAdapter?.setListData(ArrayList())
- mListLoading.visibility = View.GONE
- mReuseNoData.visibility = View.GONE
- mReuseNoConn.visibility = View.GONE
- mListRv.visibility = View.GONE
- }
-
- fun search() {
- if (mSearchKey.isEmpty()) {
- toast("请输入搜索关键字")
- } else {
- clearPage()
- onLoadRefresh()
- }
- }
-
- override fun provideListAdapter(): GameAdapter? {
- if (mAdapter == null) {
- mAdapter = GameAdapter(this)
- }
- return mAdapter
- }
-
- override fun provideDataObservable(page: Int): Observable>? {
- return RetrofitManager
- .getInstance(this).api
- .getSearchGame(Config.SENSITIVE_API_HOST + "games:search?keyword=" + searchEt.text + "&view=digest" + "&channel=" + HaloApp.getInstance().channel + "&version" + BuildConfig.VERSION_NAME)
- }
-
- override fun provideListViewModel(): NormalListViewModel {
- val factory = NormalListViewModel.Factory(HaloApp.getInstance().application, this)
- return ViewModelProviders.of(this, factory).get(NormalListViewModel::class.java) as NormalListViewModel
- }
-
- private fun initDefaultData() {
- RetrofitManager.getInstance(this).api
- .getEditorInsertDefaultData(UserManager.getInstance().userId)
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(object : Response>() {
- override fun onResponse(response: List?) {
- if (response == null || response.isEmpty()) return
- // init default page
- defaultList.layoutManager = FixLinearLayoutManager(baseContext)
- defaultList.adapter = GameDefaultAdapter(this@GameActivity, response)
- defaultListContainer.visibility = View.VISIBLE
- }
- })
- }
-
- override fun onLoadRefresh() {
- super.onLoadRefresh()
- mListRv.visibility = View.VISIBLE
- }
-
- override fun onLoadEmpty() {
- super.onLoadEmpty()
- mListRv.visibility = View.VISIBLE
- }
-
- override fun onLoadDone() {
- super.onLoadDone()
- mListRv.visibility = View.VISIBLE
+ override fun provideNormalIntent(): Intent {
+ return getTargetIntent(this, GameActivity::class.java, GameFragment::class.java)
}
companion object {
fun getIntent(context: Context, title: String): Intent {
- val intent = Intent(context, GameActivity::class.java)
- intent.putExtra(EntranceUtils.KEY_NAVIGATION_TITLE, title)
- return intent
+ val bundle = bundleOf(
+ EntranceUtils.KEY_NAVIGATION_TITLE to title
+ )
+ return getTargetIntent(context, GameActivity::class.java, GameFragment::class.java, bundle)
}
const val INSERT_GAME_TITLE = "插入游戏"
diff --git a/app/src/main/java/com/gh/gamecenter/qa/editor/GameAdapter.kt b/app/src/main/java/com/gh/gamecenter/qa/editor/GameAdapter.kt
index 332bd4e242..735ed0b950 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/editor/GameAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/editor/GameAdapter.kt
@@ -11,7 +11,7 @@ import com.gh.gamecenter.databinding.GameItemBinding
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.game.GameItemViewHolder
-class GameAdapter(context: Context) : ListAdapter(context) {
+open class GameAdapter(context: Context) : ListAdapter(context) {
public override fun setListData(updateData: MutableList?) {
super.setListData(updateData)
diff --git a/app/src/main/java/com/gh/gamecenter/qa/editor/GameFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/editor/GameFragment.kt
new file mode 100644
index 0000000000..8fa0824cef
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/qa/editor/GameFragment.kt
@@ -0,0 +1,190 @@
+package com.gh.gamecenter.qa.editor
+
+import android.os.Bundle
+import android.os.Message
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.View
+import android.view.inputmethod.EditorInfo
+import android.widget.EditText
+import android.widget.TextView
+import androidx.lifecycle.ViewModelProviders
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.constant.Config
+import com.gh.common.util.EntranceUtils
+import com.gh.common.view.FixLinearLayoutManager
+import com.gh.common.view.VerticalItemDecoration
+import com.gh.gamecenter.BuildConfig
+import com.gh.gamecenter.R
+import com.gh.gamecenter.baselist.ListFragment
+import com.gh.gamecenter.baselist.NormalListViewModel
+import com.gh.gamecenter.entity.GameEntity
+import com.gh.gamecenter.manager.UserManager
+import com.gh.gamecenter.qa.entity.EditorInsertDefaultEntity
+import com.gh.gamecenter.retrofit.Response
+import com.gh.gamecenter.retrofit.RetrofitManager
+import com.google.android.material.appbar.AppBarLayout
+import com.halo.assistant.HaloApp
+import com.lightgame.utils.Util_System_Keyboard
+import io.reactivex.Observable
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.schedulers.Schedulers
+import kotterknife.bindView
+
+open class GameFragment : ListFragment>() {
+ val searchEt by bindView(R.id.search_input)
+ val searchTv by bindView(R.id.search_button)
+ val searchBack by bindView(R.id.search_back)
+ val appBar by bindView(R.id.list_appbar)
+ val noneText by bindView(R.id.reuse_tv_none_data)
+ val defaultList by bindView(R.id.default_list)
+ val defaultListContainer by bindView(R.id.default_list_container)
+
+ protected var mAdapter: GameAdapter? = null
+
+ private var mSearchKey: String = ""
+
+ override fun handleMessage(msg: Message) {
+ if (msg.what == 1) {
+ if (mSearchKey.isEmpty()) {
+ clearPage()
+ } else {
+ search()
+ }
+ }
+ }
+
+ override fun getLayoutId(): Int {
+ return R.layout.activity_editor_insert_game
+ }
+
+ override fun isAutomaticLoad(): Boolean {
+ return false
+ }
+
+ override fun getItemDecoration(): RecyclerView.ItemDecoration? {
+ return VerticalItemDecoration(requireContext(), 8f, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ val title = arguments?.getString(EntranceUtils.KEY_NAVIGATION_TITLE) ?: ""
+ if (title.isNotEmpty()) {
+ setNavigationTitle(title)
+ }
+ noneText.text = "搜索结果为空"
+ mListLoading?.visibility = View.GONE
+ mListRefresh?.isEnabled = false
+
+ searchEt.setOnEditorActionListener { _, actionId, _ ->
+ if (actionId == EditorInfo.IME_ACTION_SEARCH) {
+ search()
+ }
+ false
+ }
+
+ searchTv.setOnClickListener {
+ search()
+ Util_System_Keyboard.hideSoftKeyboard(requireActivity())
+ }
+ searchBack.setOnClickListener {
+ searchEt.setText("")
+ }
+
+ searchEt.addTextChangedListener(object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+ }
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+ }
+
+ override fun afterTextChanged(s: Editable) {
+ val newSearchKey = s.toString().trim()
+ if (newSearchKey != mSearchKey) {
+ mBaseHandler.removeMessages(1)
+ mSearchKey = newSearchKey
+ mBaseHandler.sendEmptyMessageDelayed(1, 500)
+ }
+ searchBack.visibility = if (newSearchKey.isNotEmpty()) View.VISIBLE else View.GONE
+ }
+ })
+
+ mListRv.clearOnScrollListeners()
+
+ // default open soft keyboard
+ if (isAutoShowKeyboard()) {
+ searchEt.requestFocus()
+ }
+ Util_System_Keyboard.showSoftKeyboard(requireActivity(), searchEt)
+
+ if (title == GameActivity.SELECT_GAME_TITLE) initDefaultData()
+ }
+
+ private fun clearPage() {
+ mAdapter?.setListData(ArrayList())
+ mListLoading?.visibility = View.GONE
+ mReuseNoData?.visibility = View.GONE
+ mReuseNoConn?.visibility = View.GONE
+ mListRv.visibility = View.GONE
+ }
+
+ fun search() {
+ if (mSearchKey.isEmpty()) {
+ toast("请输入搜索关键字")
+ } else {
+ clearPage()
+ onLoadRefresh()
+ }
+ }
+
+ override fun provideListAdapter(): GameAdapter? {
+ if (mAdapter == null) {
+ mAdapter = GameAdapter(requireContext())
+ }
+ return mAdapter
+ }
+
+ override fun provideDataObservable(page: Int): Observable>? {
+ return RetrofitManager
+ .getInstance(requireContext()).api
+ .getSearchGame(Config.SENSITIVE_API_HOST + "games:search?keyword=" + searchEt.text + "&view=digest" + "&channel=" + HaloApp.getInstance().channel + "&version" + BuildConfig.VERSION_NAME)
+ }
+
+ override fun provideListViewModel(): NormalListViewModel {
+ val factory = NormalListViewModel.Factory(HaloApp.getInstance().application, this)
+ return ViewModelProviders.of(this, factory).get(NormalListViewModel::class.java) as NormalListViewModel
+ }
+
+ private fun initDefaultData() {
+ RetrofitManager.getInstance(requireContext()).api
+ .getEditorInsertDefaultData(UserManager.getInstance().userId)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(object : Response>() {
+ override fun onResponse(response: List?) {
+ if (response == null || response.isEmpty()) return
+ // init default page
+ defaultList.layoutManager = FixLinearLayoutManager(requireContext())
+ defaultList.adapter = GameDefaultAdapter(requireContext(), response)
+ defaultListContainer.visibility = View.VISIBLE
+ }
+ })
+ }
+
+ override fun onLoadRefresh() {
+ super.onLoadRefresh()
+ mListRv.visibility = View.VISIBLE
+ }
+
+ override fun onLoadEmpty() {
+ super.onLoadEmpty()
+ mListRv.visibility = View.VISIBLE
+ }
+
+ override fun onLoadDone() {
+ super.onLoadDone()
+ mListRv.visibility = View.VISIBLE
+ }
+
+ open fun isAutoShowKeyboard(): Boolean = true
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/qa/editor/InsertGameCollectionWrapperActivity.kt b/app/src/main/java/com/gh/gamecenter/qa/editor/InsertGameCollectionWrapperActivity.kt
new file mode 100644
index 0000000000..0baf3555ef
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/qa/editor/InsertGameCollectionWrapperActivity.kt
@@ -0,0 +1,48 @@
+package com.gh.gamecenter.qa.editor
+
+import android.content.Context
+import android.content.Intent
+import androidx.core.os.bundleOf
+import androidx.fragment.app.Fragment
+import com.gh.base.BaseActivity_TabLayout
+import com.gh.common.util.EntranceUtils
+import com.gh.gamecenter.R
+import com.gh.gamecenter.collection.GamesCollectionFragment
+import com.gh.gamecenter.manager.UserManager
+
+class InsertGameCollectionWrapperActivity : BaseActivity_TabLayout() {
+
+ override fun getLayoutId(): Int = R.layout.activity_tablayout_no_title_viewpager
+
+ override fun initFragmentList(fragments: MutableList?) {
+ fragments?.add(
+ GamesCollectionFragment().with(
+ bundleOf(
+ EntranceUtils.KEY_USER_ID to UserManager.getInstance().userId,
+ EntranceUtils.KEY_TYPE to GamesCollectionFragment.TYPE_USER,
+ EntranceUtils.KEY_INSERT_GAME_COLLECTION to true
+ )
+ )
+ )
+ fragments?.add(
+ GamesCollectionFragment().with(
+ bundleOf(
+ EntranceUtils.KEY_USER_ID to UserManager.getInstance().userId,
+ EntranceUtils.KEY_TYPE to GamesCollectionFragment.TYPE_COLLECT,
+ EntranceUtils.KEY_INSERT_GAME_COLLECTION to true
+ )
+ )
+ )
+ }
+
+ override fun initTabTitleList(tabTitleList: MutableList?) {
+ tabTitleList?.add("我的游戏单")
+ tabTitleList?.add("收藏游戏单")
+ }
+
+ companion object {
+ fun getIntent(context: Context): Intent {
+ return Intent(context, InsertGameCollectionWrapperActivity::class.java)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/qa/editor/OnLinkClickListener.kt b/app/src/main/java/com/gh/gamecenter/qa/editor/OnLinkClickListener.kt
index ef565f6dff..ad169d2a6d 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/editor/OnLinkClickListener.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/editor/OnLinkClickListener.kt
@@ -4,26 +4,27 @@ import android.content.Context
import android.webkit.JavascriptInterface
import com.gh.base.BaseActivity
import com.gh.common.AppExecutor
-import com.gh.common.DefaultJsApi
import com.gh.common.util.*
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.entity.CommunityEntity
import com.gh.gamecenter.entity.MtaEvent
import com.gh.gamecenter.entity.MyVideoEntity
+import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
import com.gh.gamecenter.qa.answer.detail.SimpleAnswerDetailActivity
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
import com.gh.gamecenter.qa.entity.EditorInsertEntity
-import com.lightgame.utils.Utils
/**
* 富文本编辑框的链接回调
*/
-class OnLinkClickListener(val context: Context,
- val title: String = "",
- val status: String = "",
- val entrance: String,
- val path: String,
- val mtaEvent: MtaEvent? = null) {
+class OnLinkClickListener(
+ val context: Context,
+ val title: String = "",
+ val status: String = "",
+ val entrance: String,
+ val path: String,
+ val mtaEvent: MtaEvent? = null
+) {
@JavascriptInterface
fun onClick(content: String) {
AppExecutor.uiExecutor.execute {
@@ -31,25 +32,34 @@ class OnLinkClickListener(val context: Context,
val insertEntity = GsonUtils.fromJson(content, EditorInsertEntity::class.java)
when (insertEntity.type) {
"answer" -> {
- val intent = SimpleAnswerDetailActivity.getIntent(context,
- insertEntity.id ?: "",
- entrance,
- "$path-链接")
+ val intent = SimpleAnswerDetailActivity.getIntent(
+ context,
+ insertEntity.id ?: "",
+ entrance,
+ "$path-链接"
+ )
context.startActivity(intent)
}
"community_article" -> {
val community = CommunityEntity(insertEntity.communityId!!, "")
- val intent = ArticleDetailActivity.getIntent(context,
- community,
- insertEntity.id!!,
- entrance,
- "$path-链接")
+ val intent = ArticleDetailActivity.getIntent(
+ context,
+ community,
+ insertEntity.id!!,
+ entrance,
+ "$path-链接"
+ )
context.startActivity(intent)
}
"game" -> {
- GameDetailActivity.startGameDetailActivity(context,
- insertEntity.id,
- BaseActivity.mergeEntranceAndPath(entrance, "$path-链接"))
+ GameDetailActivity.startGameDetailActivity(
+ context,
+ insertEntity.id,
+ BaseActivity.mergeEntranceAndPath(entrance, "$path-链接")
+ )
+ }
+ "game_collection" -> {
+ context.startActivity(GameCollectionDetailActivity.getIntent(context, insertEntity.id ?: ""))
}
}
}
@@ -62,7 +72,7 @@ class OnLinkClickListener(val context: Context,
tryWithDefaultCatch {
if (mtaEvent != null) MtaHelper.onEvent(mtaEvent.name, mtaEvent.key, mtaEvent.value)
val videoEntity = GsonUtils.fromJson(content, MyVideoEntity::class.java)
- clickToastByStatus(videoEntity.status){
+ clickToastByStatus(videoEntity.status) {
FullScreenVideoActivity.start(context, title, videoEntity.url, videoEntity.poster)
}
}
@@ -71,7 +81,7 @@ class OnLinkClickListener(val context: Context,
@JavascriptInterface
fun onVideoClick(url: String, poster: String) {
- clickToastByStatus(status){
+ clickToastByStatus(status) {
FullScreenVideoActivity.start(context, title, url, poster)
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/qa/entity/ArticleEntity.kt b/app/src/main/java/com/gh/gamecenter/qa/entity/ArticleEntity.kt
index f7eb8ac1a8..cf617121c7 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/entity/ArticleEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/entity/ArticleEntity.kt
@@ -22,47 +22,47 @@ import kotlinx.android.parcel.Parcelize
@Entity
@Parcelize
data class ArticleEntity(
- @PrimaryKey
- @SerializedName("_id")
- var id: String = "",
- var title: String = "",
- var brief: String = "",
- var active: Boolean = true,
- var orderTag: Long = 0,
- @TypeConverters(ListStringConverter::class)
- var images: List = ArrayList(),
- @TypeConverters(ImageInfoConverter::class)
- @SerializedName("images_info")
- var imagesInfo: List = ArrayList(),
- @TypeConverters(CommunityVideoConverter::class)
- var videos: List = ArrayList(),
- var count: Count = Count(),
- var community: CommunityEntity = CommunityEntity(),
- var time: TimeEntity? = TimeEntity(),
- var user: UserEntity = UserEntity(),
- @Ignore
- var read: Boolean = true,
- @Ignore
- var me: MeEntity = MeEntity(),
- @Ignore
- var commentable: Boolean = true,
- @Ignore
- var bbs: CommunityEntity = CommunityEntity(),
- var des: String = "",
- var url: String = "",
- @TypeConverters(VideoInfoConverter::class)
- @SerializedName("video_info")
- var videoInfo: VideoInfo = VideoInfo(),
- var poster: String = "",
- var length: Long = 0,
- @Ignore
- var type: String = "",
- var status: String = "",
- var content: String = "",
- @SyncIgnore // questions里的vote当前entity的vote冲突
- @TypeConverters(QuestionsConverter::class)
- @SerializedName("question")
- var questions: Questions = Questions()
+ @PrimaryKey
+ @SerializedName("_id")
+ var id: String = "",
+ var title: String = "",
+ var brief: String = "",
+ var active: Boolean = true,
+ var orderTag: Long = 0,
+ @TypeConverters(ListStringConverter::class)
+ var images: List = ArrayList(),
+ @TypeConverters(ImageInfoConverter::class)
+ @SerializedName("images_info")
+ var imagesInfo: List = ArrayList(),
+ @TypeConverters(CommunityVideoConverter::class)
+ var videos: List = ArrayList(),
+ var count: Count = Count(),
+ var community: CommunityEntity = CommunityEntity(),
+ var time: TimeEntity? = TimeEntity(),
+ var user: UserEntity = UserEntity(),
+ @Ignore
+ var read: Boolean = true,
+ @Ignore
+ var me: MeEntity = MeEntity(),
+ @Ignore
+ var commentable: Boolean = true,
+ @Ignore
+ var bbs: CommunityEntity = CommunityEntity(),
+ var des: String = "",
+ var url: String = "",
+ @TypeConverters(VideoInfoConverter::class)
+ @SerializedName("video_info")
+ var videoInfo: VideoInfo = VideoInfo(),
+ var poster: String = "",
+ var length: Long = 0,
+ @Ignore
+ var type: String = "",
+ var status: String = "",
+ var content: String = "",
+ @SyncIgnore // questions里的vote当前entity的vote冲突
+ @TypeConverters(QuestionsConverter::class)
+ @SerializedName("question")
+ var questions: Questions = Questions()
) : Parcelable {
fun getPassVideos(): List {
@@ -147,13 +147,19 @@ data class ArticleEntity(
@Parcelize
data class Count(
- @SyncPage(syncNames = [SyncFieldConstants.ARTICLE_COMMENT_COUNT, SyncFieldConstants.ANSWER_COMMENT_COUNT])
- var comment: Int = 0,
- @SyncPage(syncNames = [SyncFieldConstants.ARTICLE_VOTE_COUNT, SyncFieldConstants.ANSWER_VOTE_COUNT])
- var vote: Int = 0,
- var favorite: Int = 0,
- @SyncPage(syncNames = [SyncFieldConstants.ANSWER_COMMENT_REPLY_COUNT])
- var reply: Int = 0) : Parcelable {
+ @SyncPage(syncNames = [SyncFieldConstants.ARTICLE_COMMENT_COUNT, SyncFieldConstants.ANSWER_COMMENT_COUNT])
+ var comment: Int = 0,
+ @SyncPage(syncNames = [SyncFieldConstants.ARTICLE_VOTE_COUNT, SyncFieldConstants.ANSWER_VOTE_COUNT])
+ var vote: Int = 0,
+ var favorite: Int = 0,
+ @SyncPage(syncNames = [SyncFieldConstants.ANSWER_COMMENT_REPLY_COUNT])
+ var reply: Int = 0,
+ var game: Int = 0,
+ @SerializedName("game_played")
+ var playedGame: Int = 0,
+ var hot: Int = 0,
+ var share: Int = 0
+) : Parcelable {
@SyncPage(syncNames = [SyncFieldConstants.ANSWER_COUNT])
var answer: Int = 0
@@ -181,7 +187,9 @@ data class Count(
}
@Parcelize
-data class TimeEntity(var create: Long = 0,
- var update: Long = 0,
- var edit: Long = 0,
- var upload: Long = 0) : Parcelable
\ No newline at end of file
+data class TimeEntity(
+ var create: Long = 0,
+ var update: Long = 0,
+ var edit: Long = 0,
+ var upload: Long = 0
+) : Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/qa/entity/EditorInsertEntity.kt b/app/src/main/java/com/gh/gamecenter/qa/entity/EditorInsertEntity.kt
index cae2ca5aa5..5d4ae3ff93 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/entity/EditorInsertEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/entity/EditorInsertEntity.kt
@@ -3,16 +3,19 @@ package com.gh.gamecenter.qa.entity
import android.os.Parcelable
import com.gh.common.util.eliminateDoubleQuote
import com.gh.gamecenter.entity.GameEntity
+import com.gh.gamecenter.entity.GamesCollectionEntity
import kotlinx.android.parcel.Parcelize
@Parcelize
-data class EditorInsertEntity(var id: String? = "",
- var communityId: String? = "",
- var type: String? = "",
- var title: String? = "",
- var brief: String? = "",
- var icon: String? = "",
- var tags: List? = null) : Parcelable {
+data class EditorInsertEntity(
+ var id: String? = "",
+ var communityId: String? = "",
+ var type: String? = "",
+ var title: String? = "",
+ var brief: String? = "",
+ var icon: String? = "",
+ var tags: List? = null
+) : Parcelable {
companion object {
@JvmStatic
@@ -48,5 +51,16 @@ data class EditorInsertEntity(var id: String? = "",
entity.icon = game.icon
return entity
}
+
+ @JvmStatic
+ fun transform(game: GamesCollectionEntity): EditorInsertEntity {
+ val entity = EditorInsertEntity()
+ entity.id = game.id
+ entity.type = "game_collection"
+ entity.title = game.title
+ entity.brief = game.intro
+ entity.icon = "https://static-web.ghzs.com/website-static/images/icon_game_collection.png"
+ return entity
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/qa/questions/detail/QuestionsDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/questions/detail/QuestionsDetailFragment.kt
index 8bf3d17a15..02c96cabab 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/questions/detail/QuestionsDetailFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/questions/detail/QuestionsDetailFragment.kt
@@ -33,7 +33,7 @@ import com.gh.gamecenter.SuggestionActivity
import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.baselist.ListFragment
import com.gh.gamecenter.baselist.LoadType
-import com.gh.gamecenter.entity.ForumShareEntity
+import com.gh.gamecenter.entity.NormalShareEntity
import com.gh.gamecenter.entity.MenuItemEntity
import com.gh.gamecenter.entity.Permissions
import com.gh.gamecenter.entity.SpecialColumn
@@ -446,8 +446,8 @@ class QuestionsDetailFragment :
}
}
- private fun getShareEntity(questionEntity: QuestionsDetailEntity): ForumShareEntity {
- return ForumShareEntity(
+ private fun getShareEntity(questionEntity: QuestionsDetailEntity): NormalShareEntity {
+ return NormalShareEntity(
id = questionEntity.id ?: "",
shareUrl = if (isPublishEnv()) {
getString(R.string.share_questions_url, questionEntity.id)
diff --git a/app/src/main/java/com/gh/gamecenter/qa/questions/newdetail/NewQuestionDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/questions/newdetail/NewQuestionDetailFragment.kt
index e1dd264230..eb9792a79b 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/questions/newdetail/NewQuestionDetailFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/questions/newdetail/NewQuestionDetailFragment.kt
@@ -23,7 +23,7 @@ import com.gh.gamecenter.baselist.ListAdapter
import com.gh.gamecenter.baselist.LoadType
import com.gh.gamecenter.databinding.FragmentArticleDetailBinding
import com.gh.gamecenter.entity.CommunityEntity
-import com.gh.gamecenter.entity.ForumShareEntity
+import com.gh.gamecenter.entity.NormalShareEntity
import com.gh.gamecenter.entity.MenuItemEntity
import com.gh.gamecenter.entity.Permissions
import com.gh.gamecenter.eventbus.EBDeleteDetail
@@ -529,8 +529,8 @@ class NewQuestionDetailFragment :
}
}
- private fun getShareEntity(questionEntity: QuestionsDetailEntity): ForumShareEntity {
- return ForumShareEntity(
+ private fun getShareEntity(questionEntity: QuestionsDetailEntity): NormalShareEntity {
+ return NormalShareEntity(
id = questionEntity.id ?: "",
shareUrl = if (isPublishEnv()) {
getString(R.string.share_questions_url, questionEntity.id)
diff --git a/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailFragment.kt
index 16a1cb74d0..9c53a92203 100644
--- a/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/qa/video/detail/ForumVideoDetailFragment.kt
@@ -505,8 +505,8 @@ class ForumVideoDetailFragment : BaseFragment_TabLayout() {
}
}
- private fun getShareEntity(): ForumShareEntity {
- return ForumShareEntity(
+ private fun getShareEntity(): NormalShareEntity {
+ return NormalShareEntity(
id = mForumVideoEntity?.id ?: "",
shareUrl = if (isPublishEnv()) {
"https://m.ghzs666.com/video/${mForumVideoEntity?.id}"
diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java
index 1b8236d4e0..4fe22ad017 100644
--- a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java
+++ b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java
@@ -3270,4 +3270,154 @@ public interface ApiService {
*/
@PUT("api_go/teen_mode/password")
Single putTeenModePassword(@Body RequestBody body);
+
+ /**
+ * 游戏单列表(返回所有数据)
+ */
+ @GET("users/{user_id}/game_lists?view=draft")
+ Observable> getGameCollectionList(@Path("user_id") String userId);
+
+ /**
+ * 创建游戏单
+ */
+ @POST("game_lists")
+ Observable createGameCollection(@Body RequestBody body);
+
+ /**
+ * 编辑游戏单
+ */
+ @PUT("game_lists/{game_list_id}")
+ Observable patchGameCollection(@Body RequestBody body, @Path("game_list_id") String id);
+
+ /**
+ * 游戏单详情(用户编辑自己的游戏单时调用)
+ */
+ @GET("game_lists/{game_list_id}?view=draft")
+ Observable getGameCollectionDetailForDraft(@Path("game_list_id") String id);
+
+ /**
+ * 删除单条游戏单数据
+ */
+ @DELETE("game_lists/{game_list_id}")
+ Observable deleteGameCollection(@Path("game_list_id") String id);
+
+ /**
+ * 提交审核 (投稿)
+ */
+ @POST("game_lists/{game_list_id}:submit")
+ Observable publishGameCollection(@Path("game_list_id") String id);
+
+ /**
+ * 用户游戏单列表
+ */
+ @GET("users/{user_id}/game_lists")
+ Single> getUserGameCollectionList(@Path("user_id") String userId, @QueryMap Map params);
+
+ /**
+ * 游戏单详情
+ */
+ @GET("game_lists/{game_list_id}")
+ Single getGameCollectionDetail(@Path("game_list_id") String id);
+
+ /**
+ * 获取游戏单广场列表
+ */
+ @GET("game_lists")
+ Single> getGameCollectionSquareList(@Query("view") String view, @Query("tag_id") String tagId, @Query("page") int page, @Query("page_size") int pageSize);
+
+ /**
+ * 获取游戏单标签列表
+ */
+ @GET("game_lists/tags")
+ Single> getGameCollectionTagList();
+
+ /**
+ * 获取用户收藏的游戏单列表
+ */
+ @GET("users/{user_id}/favorites/game_list")
+ Single> getFavoriteGameCollectionList(@Path("user_id") String userId);
+
+ /**
+ * 添加游戏单收藏
+ */
+ @POST("users/{user_id}/favorites/game_list/{game_list_id}")
+ Single favoriteGameCollection(@Path("user_id") String userId, @Path("game_list_id") String id);
+
+ /**
+ * 取消游戏单收藏
+ */
+ @DELETE("users/{user_id}/favorites/game_list/{game_list_id}")
+ Single deleteFavoriteGameCollection(@Path("user_id") String userId, @Path("game_list_id") String id);
+
+ /**
+ * 点赞游戏单
+ */
+ @POST("game_lists/{game_list_id}:vote")
+ Single voteGameCollection(@Path("game_list_id") String id);
+
+ /**
+ * 取消点赞游戏单
+ */
+ @POST("game_lists/{game_list_id}:unvote")
+ Single unVoteGameCollection(@Path("game_list_id") String id);
+
+ /**
+ * 分享游戏单统计
+ */
+ @POST("game_lists/{game_list_id}:share")
+ Single shareGameCollection(@Path("game_list_id") String gameCollectionId);
+
+ /**
+ * 获取首页tab游戏单广场列表
+ */
+ @GET("game_lists?view=hot")
+ Single> getHomeGameCollectionSquareList(@Query("random") String id, @Query("page") int page, @Query("page_size") int pageSize);
+
+ /**
+ * 游戏单评论列表
+ */
+ @GET("api_go/game_list/{game_list_id}/comment")
+ Single> getGameCollectionComments(@Path("game_list_id") String id, @Query("page") int page, @Query("sort") String sort);
+
+ /**
+ * 获取单条游戏单评论
+ */
+ @GET("api_go/game_list/{game_list_id}/comment/{comment_id}")
+ Single getGameCollectionComment(@Path("game_list_id") String gameCollectionId, @Path("comment_id") String commentId);
+
+ /**
+ * 获取游戏单评论的回复列表
+ */
+ @GET("api_go/game_list/{game_list_id}/comment/{comment_id}/reply")
+ Single> getGameCollectionCommentReply(@Path("game_list_id") String gameCollectionId, @Path("comment_id") String commentId, @Query("page") int page);
+
+ /**
+ * 游戏单添加评论
+ */
+ @POST("api_go/game_list/{game_list_id}/comment")
+ Observable postGameCollectionComment(@Path("game_list_id") String gameCollectionId, @Body RequestBody body);
+
+ /**
+ * 点赞游戏单评论
+ */
+ @POST("api_go/game_list/{game_list_id}/comment/{comment_id}/like")
+ Single