package com.gh.gamecenter.home import android.content.Context import android.view.View import android.view.ViewGroup import androidx.constraintlayout.widget.ConstraintLayout import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.gh.common.exposure.ExposureEvent import com.gh.common.exposure.ExposureSource import com.gh.common.exposure.IExposable import com.gh.common.util.DirectUtils import com.gh.common.util.NewLogUtils import com.gh.gamecenter.GameDetailActivity import com.gh.gamecenter.R import com.gh.gamecenter.adapter.viewholder.ReuseViewHolder import com.gh.gamecenter.common.baselist.DiffUtilAdapter import com.gh.gamecenter.common.baselist.LoadStatus import com.gh.gamecenter.common.constant.ItemViewType import com.gh.gamecenter.common.utils.dip2px import com.gh.gamecenter.common.utils.safelyGetInRelease import com.gh.gamecenter.common.utils.toBinding import com.gh.gamecenter.common.viewholder.FooterViewHolder import com.gh.gamecenter.core.runOnIoThread import com.gh.gamecenter.entity.AmwayCommentEntity import com.gh.gamecenter.entity.SubjectEntity import com.gh.gamecenter.eventbus.EBDownloadStatus import com.gh.gamecenter.game.GameAndPosition import com.gh.gamecenter.game.horizontal.GameHorizontalAdapter import com.gh.gamecenter.game.horizontal.GameHorizontalSlideAdapter import com.gh.gamecenter.game.rank.RankCollectionAdapter import com.gh.gamecenter.game.vertical.GameVerticalAdapter import com.gh.gamecenter.game.vertical.OnPagerSnapScrollListener import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity import com.gh.gamecenter.home.amway.HomeAmwayListViewHolder import com.gh.gamecenter.home.discovercard.DiscoverCardGameAdapter import com.gh.gamecenter.home.discovercard.HomeDiscoverCardViewHolder import com.gh.gamecenter.home.gamecollection.HomeGameCollectionViewHolder import com.gh.gamecenter.home.slide.HomeSlideListAdapter import com.gh.gamecenter.home.slide.HomeSlideListViewHolder import com.gh.gamecenter.setting.SettingBridge import com.gh.vspace.HomeRecentVGameAdapter import com.gh.vspace.HomeRecentVGameViewHolder import com.gh.vspace.VHelper import com.halo.assistant.fragment.game.GamePluginAdapter import com.lightgame.download.DownloadEntity class HomeFragmentAdapter( context: Context, val viewModel: HomeViewModel, private val mLayoutManager: LinearLayoutManager, private val mCallback: (colorStr: Int) -> Unit ) : DiffUtilAdapter(context), IExposable { private var mLoadStatus: LoadStatus? = null private val mLegacyHomeFragmentAdapterAssistant by lazy { LegacyHomeFragmentAdapterAssistant(mContext, this, mBasicExposureSource) } private val mBasicExposureSource by lazy { listOf(ExposureSource("新首页", "")) } override fun areItemsTheSame(oldItem: HomeItemData?, newItem: HomeItemData?): Boolean { // recyclerView 仅只会存在一个 item 的,只要 item 对应的值不为空即为 true if (oldItem?.slides != null && newItem?.slides != null) return true if (oldItem?.recommends != null && newItem?.recommends != null) return true if (oldItem?.pluginList != null && newItem?.pluginList != null) return true if (oldItem?.recentVGame != null && newItem?.recentVGame != null) return true // recyclerView 可存在多个 item 的,需要需要比较它们的 id 或特征值 if (oldItem?.amway != null && newItem?.amway != null) { return oldItem.amway?.firstOrNull()?.id == newItem.amway?.firstOrNull()?.id } if (oldItem?.gameCollection != null && newItem?.gameCollection != null) { return oldItem.gameCollection?.firstOrNull()?.gameCollectionItem?.id == newItem.gameCollection?.firstOrNull()?.gameCollectionItem?.id } if (oldItem?.attachGame != null && newItem?.attachGame != null) { return oldItem.attachGame?.linkId == newItem.attachGame?.linkId } if (oldItem?.lineDivider != null && newItem?.lineDivider != null) { return oldItem.lineDivider == newItem.lineDivider } if (oldItem?.game != null && newItem?.game != null) { return oldItem.game?.id == newItem.game?.id } if (oldItem?.columnHead != null && newItem?.columnHead != null) { return oldItem.columnHead?.name == newItem.columnHead?.name } if (oldItem?.horizontalColumn != null && newItem?.horizontalColumn != null) { return oldItem.horizontalColumn?.id == newItem.horizontalColumn?.id } if (oldItem?.image != null && newItem?.image != null) { return oldItem.image?.id == newItem.image?.id } if (oldItem?.verticalSlide != null && newItem?.verticalSlide != null) { return oldItem.verticalSlide?.id == newItem.verticalSlide?.id } if (oldItem?.horizontalSlide != null && newItem?.horizontalSlide != null) { return oldItem.horizontalSlide?.id == newItem.horizontalSlide?.id } if (oldItem?.gallery != null && newItem?.gallery != null) { return oldItem.gallery?.id == newItem.gallery?.id } if (oldItem?.gallerySlide != null && newItem?.gallerySlide != null) { return oldItem.gallerySlide?.id == newItem.gallerySlide?.id } if (oldItem?.imageSlide != null && newItem?.imageSlide != null) { return oldItem.imageSlide?.id == newItem.imageSlide?.id } if (oldItem?.columnCollection != null && newItem?.columnCollection != null) { return oldItem.columnCollection?.id == newItem.columnCollection?.id } if (oldItem?.commonCollection != null && newItem?.commonCollection != null) { return oldItem.commonCollection?.id == newItem.commonCollection?.id } if (oldItem?.commonCollection12 != null && newItem?.commonCollection12 != null) { return oldItem.commonCollection12?.id == newItem.commonCollection12?.id && oldItem.offset == newItem.offset } if (oldItem?.rankCollection != null && newItem?.rankCollection != null) { return oldItem.rankCollection?.id == newItem.rankCollection?.id } if (oldItem?.doubleCardColumn != null && newItem?.doubleCardColumn != null) { return oldItem.doubleCardColumn?.id == newItem.doubleCardColumn?.id && oldItem.offset == newItem.offset } if (oldItem?.bigImageRecommend != null && newItem?.bigImageRecommend != null) { return oldItem.bigImageRecommend?.id == newItem.bigImageRecommend?.id } if (oldItem?.blankDivider != null && newItem?.blankDivider != null) { return oldItem.blankDivider == newItem.blankDivider } if (oldItem?.discoverCard != null && newItem?.discoverCard != null) { return oldItem.discoverCard == newItem.discoverCard } return false } fun setLoadStatus(status: LoadStatus) { // 重置偏移 if (status == LoadStatus.INIT_LOADED) { mLegacyHomeFragmentAdapterAssistant.resetOffset() } this.mLoadStatus = status notifyItemChanged(itemCount - 1) } override fun getItemViewType(position: Int): Int { if (itemCount == position + 1) return FOOTER_ITEM val itemData = mDataList[position] if (itemData.slides != null) return SLIDE_ITEM 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.recentVGame != null) return RECENT_V_GAME if (itemData.discoverCard != null) return DISCOVER_CARD if (itemData.lineDivider != null) return DIVIDER_ITEM if (itemData.unknownData != null) return UNKNOWN_ITEM return mLegacyHomeFragmentAdapterAssistant.getLegacyItemType(itemData) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when (viewType) { SLIDE_ITEM -> HomeSlideListViewHolder(parent.toBinding(), mCallback) RECOMMENDS_ITEM -> HomeRecommendItemViewHolder(parent.toBinding()) GAME_ITEM -> HomeGameItemViewHolder(parent.toBinding()) AMWAY_ITEM -> HomeAmwayListViewHolder(parent.toBinding()) GAME_COLLECTION_ITEM -> HomeGameCollectionViewHolder(parent.toBinding()) DIVIDER_ITEM -> HomeDividerViewHolder(parent.toBinding()) RECENT_V_GAME -> HomeRecentVGameViewHolder(parent.toBinding()) DISCOVER_CARD -> HomeDiscoverCardViewHolder(parent.toBinding()) FOOTER_ITEM -> FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false)) UNKNOWN_ITEM -> ReuseViewHolder(mLayoutInflater.inflate(R.layout.home_unknown_item, parent, false)) // 原游戏板块样式 else -> return mLegacyHomeFragmentAdapterAssistant.createLegacyViewHolder(parent, viewType) } } override fun getItemCount(): Int { return if (mDataList.isEmpty()) 0 else mDataList.size + 1 // 1: footer } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { when (holder) { is HomeSlideListViewHolder -> { // 根据首页是否有其它 tab 设置不同的 marginTop val marginTop = if (viewModel.homeOnlyWithoutOtherTab) 4F.dip2px() else 0 (holder.binding.recyclerView.layoutParams as ConstraintLayout.LayoutParams) .setMargins(0, marginTop, 0, 0) holder.bindSlideList(mDataList[position], mBasicExposureSource) } is HomeRecommendItemViewHolder -> holder.bindRecommend(mDataList[position], mBasicExposureSource) is HomeAmwayListViewHolder -> bindAmway(holder, position) is HomeGameItemViewHolder -> bindAttachGame(holder, position) is FooterViewHolder -> bindFooterView(holder) is ReuseViewHolder -> bindUnknown(holder) is HomeDividerViewHolder -> holder.bindView(mDataList[position].lineDivider ?: 1F) is HomeGameCollectionViewHolder -> bindGameCollection(holder, position) is HomeRecentVGameViewHolder -> bindRecentVGame(holder, position) is HomeDiscoverCardViewHolder -> bindDiscoverCard(holder, position) else -> mLegacyHomeFragmentAdapterAssistant.bindLegacyViewHolder(holder, mDataList[position], position) } } private fun bindUnknown(holder: ReuseViewHolder) { holder.itemView.setOnClickListener { mContext.startActivity(SettingBridge.getAboutIntent(mContext, true)) } } private fun bindAmway(holder: HomeAmwayListViewHolder, position: Int) { val homeItemData = mDataList[position] val amwayList = homeItemData.amway!! val exposureList = arrayListOf() for (amway in amwayList) { runOnIoThread(true) { val event = ExposureEvent.createEventWithSourceConcat( gameEntity = amway.game.toGameEntity(), basicSource = mBasicExposureSource, source = listOf(ExposureSource("安利墙", "")) ) exposureList.add(event) } } homeItemData.exposureEventList = exposureList val clickClosure: (View, Int, AmwayCommentEntity) -> Unit = { v, itemPosition, amway -> val path = "(首页安利墙)" when (v.id) { R.id.rating_block -> { val intent = RatingReplyActivity.getIntent( mContext, amway.game.id, amway.comment.id, false, path, "" ) mContext.startActivity(intent) NewLogUtils.logHomeShareWallCardClick(amway.game.name ?: "", amway.game.id, "评论内容") } R.id.user_icon_container -> { DirectUtils.directToHomeActivity(mContext, amway.comment.user.id, path, "") NewLogUtils.logHomeShareWallCardClick(amway.game.name ?: "", amway.game.id, "用户信息") } else -> { GameDetailActivity.startGameDetailActivity( mContext, amway.game.id, path, homeItemData.exposureEventList?.safelyGetInRelease(itemPosition) ) NewLogUtils.logHomeShareWallCardClick(amway.game.name ?: "", amway.game.id, "游戏信息") } } } 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?.take(3)?.forEachIndexed { index, game -> gameExposureList.add( ExposureEvent.createEventWithSourceConcat( gameEntity = game.toGameEntity().apply { isAdData = gameCollection.adIconActive outerSequence = homeItemData.blockPosition sequence = gameCollectionItemData.gameStartPosition + index + 1 }, basicSource = mBasicExposureSource, source = gameCollectionSource ) ) } gameCollectionItemData.exposureEventList = gameExposureList exposureList.addAll(gameExposureList) } } homeItemData.exposureEventList = exposureList holder.bindGameCollectionList(gameCollectionItemDataList, "首页内容列表") } private fun bindRecentVGame(holder: HomeRecentVGameViewHolder, position: Int) { val homeItemData = mDataList[position] val exposureEventList = arrayListOf() runOnIoThread(true) { homeItemData.recentVGame?.forEach { val event = ExposureEvent.createEventWithSourceConcat( gameEntity = VHelper.toGameEntity(it.downloadEntity), basicSource = mBasicExposureSource, source = listOf(ExposureSource("最近在玩", "")) ) exposureEventList.add(event) } } homeItemData.exposureEventList = exposureEventList if (!homeItemData.recentVGame.isNullOrEmpty()) { holder.bindView(homeItemData.recentVGame!!) } } private fun bindDiscoverCard(holder: HomeDiscoverCardViewHolder, position: Int) { val homeItemData = mDataList[position] val discoverCard = homeItemData.discoverCard!! val binding = holder.binding val exposureEventList = arrayListOf() val listExposureEventList = arrayListOf() val spanCount = 3 val snapHelper = holder.bindView(discoverCard, "首页") val exposureClosure: (Int) -> Unit = { val gameList = discoverCard.games runOnIoThread(true) { listExposureEventList.clear() val startOffset = it * spanCount val endOffset = if (startOffset + spanCount >= gameList.size) { gameList.size } else { startOffset + spanCount } for (i in startOffset until endOffset) { val event = ExposureEvent.createEventWithSourceConcat( gameEntity = gameList[i].apply { outerSequence = homeItemData.blockPosition sequence = i }, basicSource = mBasicExposureSource, source = listOf(ExposureSource("发现", gameList[i].getTypeName())) ) gameList[i].exposureEvent = event listExposureEventList.add(event) } exposureEventList.addAll(listExposureEventList) } } exposureClosure(0) binding.recyclerView.addOnScrollListener(OnPagerSnapScrollListener(snapHelper) { exposureClosure(it) }) homeItemData.exposureEventList = exposureEventList } private fun bindAttachGame(holder: HomeGameItemViewHolder, position: Int) { val homeItemData = mDataList[position] val attachGame = homeItemData.attachGame val subjectEntity = SubjectEntity().apply { id = attachGame?.linkId type = attachGame?.linkType linkText = attachGame?.linkText ?: "" displayContent = attachGame?.displayContent ?: "" recommendText = attachGame?.recommendText ?: "" linkGame = attachGame?.linkGame } holder.bindAttachGame(holder, subjectEntity, this, mBasicExposureSource, position, "新首页") { homeItemData.exposureEvent = it } } private fun bindFooterView(holder: FooterViewHolder) { holder.initFooterViewHolder( mLoadStatus == LoadStatus.LIST_LOADING, mLoadStatus == LoadStatus.LIST_FAILED, mLoadStatus == LoadStatus.LIST_OVER, R.string.load_over_with_click_hint ) { if (mLoadStatus == LoadStatus.LIST_OVER) { mLayoutManager.scrollToPosition(0) } else if (mLoadStatus == LoadStatus.LIST_FAILED) { viewModel.getHomeContent(false) notifyItemChanged(itemCount - 1) } } } fun notifyItemByDownload(download: DownloadEntity) { val data = getGameEntityByPackage(download.packageName) for (gameAndPosition in data) { if (gameAndPosition.entity != null && gameAndPosition.entity.name == download.name) { val entryMap = gameAndPosition.entity.getEntryMap() entryMap[download.platform] = download } if (getItemViewType(gameAndPosition.position) == ItemViewType.VERTICAL_SLIDE_ITEM || getItemViewType(gameAndPosition.position) == ItemViewType.GAME_PLUGIN || getItemViewType(gameAndPosition.position) == SLIDE_ITEM || getItemViewType(gameAndPosition.position) == ItemViewType.RANK_COLLECTION || getItemViewType(gameAndPosition.position) == RECENT_V_GAME || getItemViewType(gameAndPosition.position) == ItemViewType.GAME_SUBJECT || getItemViewType(gameAndPosition.position) == ItemViewType.GAME_SUBJECT_SLIDE || getItemViewType(gameAndPosition.position) == DISCOVER_CARD ) { val view = mLayoutManager.findViewByPosition(gameAndPosition.position) val recyclerView = view?.findViewById(R.id.recycler_view) when (val adapter = recyclerView?.adapter) { is GameVerticalAdapter -> adapter.notifyItemByDownload(download) is GamePluginAdapter -> adapter.notifyItemByDownload(download) is HomeSlideListAdapter -> adapter.notifyItemByDownload(download) is RankCollectionAdapter -> adapter.notifyItemByDownload(download) is GameHorizontalAdapter -> adapter.notifyItemByDownload(download) is GameHorizontalSlideAdapter -> adapter.notifyItemByDownload(download) is HomeRecentVGameAdapter -> adapter.notifyItemByDownload(download) is DiscoverCardGameAdapter -> adapter.notifyItemByDownload(download) } } else { notifyItemChanged(gameAndPosition.position) } } } fun notifyItemAndRemoveDownload(status: EBDownloadStatus) { val data = getGameEntityByPackage(status.packageName) for (gameAndPosition in data) { if (gameAndPosition.entity != null && gameAndPosition.entity.name == status.name) { gameAndPosition.entity.getEntryMap().remove(status.platform) } notifyChildItem(gameAndPosition.position, status.packageName) } } fun notifyChildItem(position: Int, packageName: String) { if (getItemViewType(position) == ItemViewType.VERTICAL_SLIDE_ITEM || getItemViewType(position) == ItemViewType.GAME_PLUGIN || getItemViewType(position) == SLIDE_ITEM || getItemViewType(position) == ItemViewType.RANK_COLLECTION || getItemViewType(position) == ItemViewType.GAME_SUBJECT || getItemViewType(position) == ItemViewType.GAME_SUBJECT_SLIDE || getItemViewType(position) == DISCOVER_CARD ) { val view = mLayoutManager.findViewByPosition(position) val recyclerView = view?.findViewById(R.id.recycler_view) when (val adapter = recyclerView?.adapter) { is RankCollectionAdapter -> adapter.notifyChildItem() is GameVerticalAdapter -> adapter.notifyChildItem(packageName) is GameHorizontalAdapter -> adapter.notifyChildItem(packageName) is GameHorizontalSlideAdapter -> adapter.notifyChildItem(packageName) is DiscoverCardGameAdapter -> adapter.notifyChildItem(packageName) else -> recyclerView?.adapter?.notifyDataSetChanged() } } else { notifyItemChanged(position) } } fun getGameEntityByPackage(packageName: String): List { val positionList = ArrayList() val positionMap = viewModel.positionAndPackageMap.value ?: return positionList for (key in positionMap.keys) { if (key.contains(packageName)) { val position = positionMap[key]!! if (position >= mDataList.size) return arrayListOf() val itemData = mDataList[position] val slides = itemData.slides if (slides != null) { main@ for (slide in slides) { val linkGame = slide.linkGame if (linkGame != null) { for (apkEntity in linkGame.getApk()) { if (apkEntity.packageName == packageName) { positionList.add(GameAndPosition(linkGame, position)) break@main } } } } continue } val attachGame = itemData.attachGame?.linkGame val recentVGame = itemData.recentVGame if (attachGame != null || recentVGame != null) { positionList.add(GameAndPosition(attachGame, position)) continue } val discoverCard = itemData.discoverCard if (discoverCard != null) { discoverCard.games.forEach { for (apkEntity in it.getApk()) { if (apkEntity.packageName == packageName) { positionList.add(GameAndPosition(it, position)) } } } continue } // 原游戏板块样式 mLegacyHomeFragmentAdapterAssistant.getLegacyGameEntityByPackage( positionList, itemData, packageName, position ) } } return positionList } override fun getEventByPosition(pos: Int): ExposureEvent? { return mDataList[pos].exposureEvent } override fun getEventListByPosition(pos: Int): List? { return mDataList[pos].exposureEventList } companion object { const val SLIDE_ITEM: Int = 100 const val RECOMMENDS_ITEM: Int = 101 const val GAME_ITEM: Int = 102 const val AMWAY_ITEM: Int = 103 const val DIVIDER_ITEM: Int = 114 const val FOOTER_ITEM: Int = 110 const val UNKNOWN_ITEM: Int = 111 const val GAME_COLLECTION_ITEM: Int = 116 const val RECENT_V_GAME: Int = 117 const val DISCOVER_CARD: Int = 118 } }