Compare commits

..

1 Commits

Author SHA1 Message Date
cfde1e1e62 重构数据解析,ui组件刷新逻辑 2025-06-13 16:15:25 +08:00
25 changed files with 1420 additions and 1270 deletions

View File

@ -72,7 +72,6 @@ android_build:
only:
- dev
- release
- feat/GHZSCY-8069
# 代码检查
sonarqube_analysis:
@ -104,7 +103,6 @@ sonarqube_analysis:
only:
- dev
- release
- feat/GHZSCY-8069
## 发送简易检测结果报告
send_sonar_report:
@ -123,7 +121,6 @@ send_sonar_report:
only:
- dev
- release
- feat/GHZSCY-8069
oss-upload&send-email:
tags:
@ -160,5 +157,4 @@ oss-upload&send-email:
only:
- dev
- release
- feat/GHZSCY-8069

View File

@ -246,10 +246,9 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable, IB
setNavigationTitle(it.title)
})
dataList.observe(viewLifecycleOwner) {
adapter.submitList(it) {
dataList.observe(viewLifecycleOwner) { (shouldScrollToTop, data) ->
adapter.submitList(data) {
if (shouldScrollToTop) {
shouldScrollToTop = false
binding.gameList.scrollToPosition(0)
}
}

View File

@ -29,7 +29,7 @@ interface OnCustomPageEventListener {
/**
* 换一批
*/
fun onChangeABatch(subjectEntity: SubjectEntity)
fun onChangeABatch(componentId: String, subjectEntity: SubjectEntity)
fun onChangeAppBarColor(color: Int)
@ -56,7 +56,10 @@ interface OnCustomPageEventListener {
/**
* 点击进入专题详情
*/
fun navigateSubjectDetailPage(item: CustomSubjectCollectionItem, subject: CustomPageData.LinkColumnCollection.CustomSubjectEntity)
fun navigateSubjectDetailPage(
item: CustomSubjectCollectionItem,
subject: CustomPageData.LinkColumnCollection.CustomSubjectEntity
)
/**

View File

@ -35,9 +35,11 @@ class SubjectEventHelper(viewModel: CustomPageViewModel) : CustomPageItemChildEv
gameEntity.tempDspLogMap = map.toMap() // Return an immutable copy
}
}
gameEntity.isMiniGame() -> {
tracker.trackMiniGameClick(_item, gameEntity)
}
else -> {
tracker.trackColumnClick(_item, gameEntity, "游戏")
}
@ -51,9 +53,11 @@ class SubjectEventHelper(viewModel: CustomPageViewModel) : CustomPageItemChildEv
gameEntity.isDspGame -> {
tracker.trackDspGameClick(_item, gameEntity, "按钮", "自定义页面")
}
gameEntity.isMiniGame() -> {
tracker.trackMiniGameClick(_item, gameEntity)
}
else -> {
tracker.trackColumnClick(_item, gameEntity, "按钮")
}
@ -67,9 +71,9 @@ class SubjectEventHelper(viewModel: CustomPageViewModel) : CustomPageItemChildEv
}
}
fun onChangeABatch(subject: SubjectEntity) {
fun onChangeABatch(componentId: String, subject: SubjectEntity) {
tracker.trackColumnClick(_item, null, "右上角", "换一批")
viewModel.onChangeABatch(subject)
viewModel.onChangeABatch(componentId,subject)
}
fun onMoreClick(link: LinkEntity) {

View File

@ -0,0 +1,185 @@
package com.gh.gamecenter.home.custom.model
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.entity.PKEntity
import com.gh.gamecenter.entity.AmwayCommentEntity
import com.gh.gamecenter.entity.DiscoveryCardEntity
import com.gh.gamecenter.entity.HomeItemTestV2Entity
import com.gh.gamecenter.entity.SubjectEntity
import com.gh.gamecenter.feature.entity.AcctRecord
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_LINK_TYPE_COLUMN_COLLECTION
import com.gh.vspace.VGameItemData
/**
* 接口返回的原始数据模型,最终需要转化成 CustomPageItem 在ui层呈现
*/
sealed class CustomItemDTO(
val componentId: String, // 当前组件的唯一标识,用于后续更新单个数据时,快速找到目标数据
val link: LinkEntity
)
// 游戏专题:展开大图样式专用
class GameItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
val data: GameEntity,
val linkColumn: SubjectEntity?,
) : CustomItemDTO(_componentId, _link)
//游戏专题
data class SubjectItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
var data: SubjectEntity
) : CustomItemDTO(_componentId, _link) {
val scrollState = ScrollState()
}
// 专题合集/游戏单合集
class CollectionItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
val data: CustomPageData.LinkColumnCollection
) : CustomItemDTO(_componentId, _link) {
val isSubjectCollection: Boolean // 是否是专题合集(还有可能是游戏单合集)
get() = link.type == CUSTOM_LINK_TYPE_COLUMN_COLLECTION
var showPage: Int = 0
var loadPage: Int = 1
var isLoadedEnd: Boolean = false
val uiState = UIState()
/**
* 保存ui层状态
*/
data class UIState(
var isBackToStart: Boolean = false
)
}
// 最近在玩
data class RecentGamesItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
var data: List<VGameItemData>
) : CustomItemDTO(_componentId, _link)
// 微信小游戏-最近在玩
data class RecentWechatMiniGamesItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
var data: List<GameEntity>
) : CustomItemDTO(_componentId, _link)
// qq小游戏-最近在玩
data class RecentQqMiniGamesItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
var data: List<GameEntity>,
val linkQqGameRecentlyPlayed: CustomPageData.LinkRecentlyPlayed
) : CustomItemDTO(_componentId, _link)
// 加速游戏最近在玩
data class RecentAcceleratorGamesItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
var data: List<AcctRecord>,
val moreLink: LinkEntity?
) : CustomItemDTO(_componentId, _link)
// qq小游戏专题
data class QqMiniGamesItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
val data: SubjectEntity
) : CustomItemDTO(_componentId, _link) {
val scrollState = ScrollState()
}
// 微信小游戏专题
data class WechatMiniGamesItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
val data: SubjectEntity
) : CustomItemDTO(_componentId, _link) {
val scrollState = ScrollState()
}
// 微信小游戏CPM专题组件
data class WeChatMiniGamesCPMSubjectItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
var data: SubjectEntity
) : CustomItemDTO(_componentId, _link){
val scrollState = ScrollState()
}
// DSP专题组件
data class DSPItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
var data: SubjectEntity
) : CustomItemDTO(_componentId, _link){
val scrollState = ScrollState()
}
// 插件化区域
data class PluginItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
var data: List<GameEntity>
) : CustomItemDTO(_componentId, _link)
// 新游开测
data class GameTestV2ItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
val data: HomeItemTestV2Entity
) : CustomItemDTO(_componentId, _link)
// 光环推荐
data class DiscoverCardItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
var data: DiscoveryCardEntity?
) : CustomItemDTO(_componentId, _link)
// 安利墙
data class AmwayItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
val data: List<AmwayCommentEntity>
) : CustomItemDTO(_componentId, _link)
// 内容卡片
data class ContentCardItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
val data: CustomPageData.ContentCard
) : CustomItemDTO(_componentId, _link)
// 通用内容合集
data class CommonContentCollectionItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
val data: CustomPageData.CommonContentCollection
) : CustomItemDTO(_componentId, _link)
// PK
data class PKItemDTO(
private val _componentId: String,
private val _link: LinkEntity,
var data: PKEntity?
) : CustomItemDTO(_componentId, _link)
class ScrollState(
var scrolledOffset: Int = 0
)

View File

@ -0,0 +1,42 @@
package com.gh.gamecenter.home.custom.model
import android.util.LruCache
import com.gh.gamecenter.feature.entity.GameEntity
import io.reactivex.Observable
import io.reactivex.Single
class CustomPageCacheDataSource {
// 计算内存缓存大小这里取应用最大可用内存的1/8单位KB
private fun calculateMemoryCacheSize(): Int {
val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()
return maxMemory / 8
}
private val memoryCache: LruCache<String, List<GameEntity>> =
object : LruCache<String, List<GameEntity>>(calculateMemoryCacheSize()) {
override fun sizeOf(key: String, value: List<GameEntity>): Int {
return value.toTypedArray().size / 1024 // 单位KB
}
}
fun getGameList(subjectId: String) = Observable.create {
val gameList = memoryCache.get(subjectId)
if (gameList.isNullOrEmpty()) {
it.onComplete()
} else {
it.onNext(gameList)
}
}
fun putGameList(subjectId: String?, data: List<GameEntity>) {
if (!subjectId.isNullOrBlank()) {
memoryCache.put(subjectId, data)
}
}
fun onClear() {
memoryCache.evictAll()
}
}

View File

@ -15,10 +15,10 @@ import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.vspace.VGameItemData
abstract class CustomPageItem(
// 当前模块在数据列表中的位置注意非ui页面的位置而是数据列表中的位置因为某条数据可能会拆分成多个item
val link: LinkEntity,
var position: Int,
val componentPosition: Int
var position: Int,// 当前模块在数据列表中的位置注意非ui页面的位置而是数据列表中的位置因为某条数据可能会拆分成多个item
val componentPosition: Int,
val componentId: String,
) {
abstract val itemType: Int
@ -362,9 +362,11 @@ abstract class CustomPageItem(
data class CustomSubjectItem(
private val _link: LinkEntity,
val data: SubjectEntity,
private val scrollState: ScrollState,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int,
private val _componentId: String,
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
override val itemType: Int
get() = subjectTypeMap[data.type] ?: CUSTOM_PAGE_ITEM_TYPE_INVALID
@ -379,7 +381,11 @@ data class CustomSubjectItem(
get() = data.data ?: emptyList()
// 临时变量,记录横向列表滚动的距离
var scrolledOffset: Int = 0
var scrolledOffset: Int
get() = scrollState.scrolledOffset
set(value) {
scrollState.scrolledOffset = value
}
val exposureSource: List<ExposureSource>
get() = listOf(ExposureSource("专题", "${data.name ?: ""}+$componentStyle+${data.id}"))
@ -420,7 +426,7 @@ data class CustomSubjectItem(
if (latestDayBeforeTodayPair.first >= testDayOffset) {
latestDayBeforeTodayPair = Pair(testDayOffset, index)
}
} else if (testDayOffset > 0) {
} else {
if (testDayOffset <= latestDayAfterTodayPair.first) {
latestDayAfterTodayPair = Pair(testDayOffset, index)
}
@ -440,11 +446,12 @@ data class CustomSubjectItem(
data class CustomSplitSubjectItem(
private val _link: LinkEntity,
var data: SubjectEntity,
val step: Int,
val startChildPosition: Int,
private val _position: Int,
private val _componentPosition: Int,
val step: Int,
val startChildPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentId: String,
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
var splitItemCount: Int = -1 // 游戏专题拆分出来的子项数量
@ -509,8 +516,9 @@ data class CustomGameItem(
val linkColumn: SubjectEntity?,
val childPosition: Int,
private val _position: Int, // 当前 item 在 ui 中的位置
private val _componentPosition: Int // 当前组件的位置
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int, // 当前组件的位置
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
override val itemType: Int
get() = CUSTOM_PAGE_ITEM_TYPE_GAME_HOME_GAME_ITEM
@ -546,9 +554,11 @@ data class CustomGameItem(
data class CustomSubjectCollectionItem(
private val _link: LinkEntity,
val data: CustomPageData.LinkColumnCollection,
val uiState: CollectionItemDTO.UIState,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int,
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
val isSubjectCollection: Boolean // 是否是专题合集(还有可能是游戏单合集)
get() = link.type == CUSTOM_LINK_TYPE_COLUMN_COLLECTION
@ -572,19 +582,14 @@ data class CustomSubjectCollectionItem(
emptyList()
}
// 临时变量:记录合集中,轮换刷新时当前显示的页码
//当前显示的页码
var showPage: Int = 0
// 临时变量:记录合集中,轮换刷新时当前加载的页码
var loadPage: Int = 1
// 临时变量记录点击轮换刷新时是否正在loading
var isLoading: Boolean = false
// 临时变量,数据是否已全部加载完毕
var isLoadedEnd: Boolean = false
var isBackToStart = true
var isBackToStart: Boolean
get() = uiState.isBackToStart
set(value) {
uiState.isBackToStart = value
}
val showSubject: CustomPageData.LinkColumnCollection.CustomSubjectEntity?
get() = data.data.getOrNull(showPage % data.data.size)
@ -592,14 +597,12 @@ data class CustomSubjectCollectionItem(
override fun doAreItemsTheSame(other: CustomPageItem): Boolean {
return other is CustomSubjectCollectionItem
&& data.id == other.data.id
}
override fun doAreContentsTheSames(other: CustomPageItem): Boolean {
return other is CustomSubjectCollectionItem
&& showPage == other.showPage
&& isLoading == other.isLoading
&& isLoadedEnd == other.isLoadedEnd
&& showSubject == other.showSubject
}
}
@ -608,8 +611,9 @@ data class CustomRecentGamesItem(
private val _link: LinkEntity,
val data: List<VGameItemData>,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int,
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
override val itemType: Int
get() = CUSTOM_PAGE_ITEM_TYPE_RECENT_PLAY
@ -628,8 +632,9 @@ data class CustomRecentWeChatMiniGamesItem(
private val _link: LinkEntity,
val data: List<GameEntity>,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int,
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
override val itemType: Int
get() = CUSTOM_PAGE_ITEM_TYPE_MINI_GAME_RECENT_PLAY
@ -647,8 +652,9 @@ data class CustomWeChatMiniGamesCPMSubjectItem(
private val _link: LinkEntity,
val data: SubjectEntity,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int,
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
override val itemType: Int
get() = CUSTOM_PAGE_ITEM_TYPE_MINI_GAME_RECENT_PLAY
@ -667,8 +673,9 @@ data class CustomRecentQqMiniGamesItem(
val data: List<GameEntity>,
val linkQqGameRecentlyPlayed: CustomPageData.LinkRecentlyPlayed,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int,
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
override val itemType: Int
get() = CUSTOM_PAGE_ITEM_TYPE_MINI_GAME_RECENT_PLAY
@ -690,8 +697,9 @@ data class CustomRecentAcceleratorItem(
val data: List<AcctRecord>,
val moreLink: LinkEntity?,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int,
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
override val itemType: Int
get() = CUSTOM_PAGE_ITEM_TYPE_ACCELERATOR_RECENT_PLAYED
@ -713,8 +721,9 @@ data class CustomPluginItem(
private val _link: LinkEntity,
val data: List<GameEntity>,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int,
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
override val itemType: Int
get() = CUSTOM_PAGE_ITEM_TYPE_PLUGIN
@ -735,8 +744,9 @@ data class CustomGameTestV2Item(
private val _link: LinkEntity,
val data: HomeItemTestV2Entity,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int,
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
override val itemType: Int
get() = CUSTOM_PAGE_ITEM_TYPE_NEW_GAME_TEST
@ -754,8 +764,9 @@ data class CustomDiscoverCardItem(
private val _link: LinkEntity,
val data: DiscoveryCardEntity?,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int,
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
val spanCount = 3
@ -781,8 +792,9 @@ data class CustomAmwayItem(
private val _link: LinkEntity,
val data: List<AmwayCommentEntity>,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int,
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
override val itemType: Int
get() = CUSTOM_PAGE_ITEM_TYPE_AMWAY_WALL
@ -800,8 +812,9 @@ data class CustomContentCardItem(
private val _link: LinkEntity,
val data: CustomPageData.ContentCard,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int,
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
override val itemType: Int
get() = CUSTOM_PAGE_ITEM_TYPE_CONTENT_CARD
@ -822,8 +835,9 @@ data class CustomCommonContentCollectionItem(
private val _link: LinkEntity,
val data: CustomPageData.CommonContentCollection,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int,
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
override val itemType: Int
get() = if (data.layout == COMMON_CONTENT_COLLECTION_LAYOUT_BANNER) {
@ -861,10 +875,11 @@ data class CustomCommonContentCollectionItem(
data class CustomSplitCommonContentCollectionItem(
private val _link: LinkEntity,
val data: CustomPageData.CommonContentCollection,
val leftPosition: Int,
private val _position: Int,
private val _componentPosition: Int,
val leftPosition: Int,
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
override val itemType
get() = commonContentCollection[data.layout] ?: CUSTOM_PAGE_ITEM_TYPE_INVALID
@ -897,8 +912,9 @@ data class CustomPKItem(
private val _link: LinkEntity,
val data: PKEntity?,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int,
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
override val itemType: Int
get() = CUSTOM_PAGE_ITEM_TYPE_PK
@ -916,8 +932,9 @@ data class CustomDspPlaceholderItem(
private val _link: LinkEntity,
val data: SubjectEntity,
private val _position: Int,
private val _componentPosition: Int
) : CustomPageItem(_link, _position, _componentPosition) {
private val _componentPosition: Int,
private val _componentId: String
) : CustomPageItem(_link, _position, _componentPosition, _componentId) {
override val itemType: Int
get() = CUSTOM_PAGE_ITEM_TYPE_MINI_GAME_RECENT_PLAY
@ -930,14 +947,9 @@ data class CustomDspPlaceholderItem(
}
}
object CustomFooterItem : CustomPageItem(LinkEntity(), -1, -1) {
object CustomFooterItem : CustomPageItem(LinkEntity(), -1, -1, "") {
override val itemType: Int
get() = CUSTOM_PAGE_ITEM_TYPE_FOOTER
}
object CustomInvalidItem : CustomPageItem(LinkEntity(), -2, -2) {
override val itemType: Int
get() = CUSTOM_PAGE_ITEM_TYPE_INVALID
}

View File

@ -1,8 +1,10 @@
package com.gh.gamecenter.home.custom.model
import android.content.Context
import android.util.LruCache
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.feature.entity.FloatingWindowEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.halo.assistant.HaloApp
import java.text.SimpleDateFormat
import java.util.*

View File

@ -56,12 +56,17 @@ class CustomPageRemoteDataSource(
}
}
fun loadCollectionContent(item: CustomSubjectCollectionItem): Single<List<CustomPageData.LinkColumnCollection.CustomSubjectEntity>> =
if (item.isSubjectCollection) {
newApi.getColumnsCollectionContents(item.data.id, "component", item.loadPage + 1, 1)
} else {
newApi.getGameCollectionContents(item.data.id, "component", item.loadPage + 1, 1)
}
fun loadColumnsCollectionContents(
collectionId: String,
page: Int
): Single<MutableList<CustomPageData.LinkColumnCollection.CustomSubjectEntity>> =
newApi.getColumnsCollectionContents(collectionId, "component", page, 1)
fun loadGameCollectionContents(
collectionId: String,
page: Int
): Single<MutableList<CustomPageData.LinkColumnCollection.CustomSubjectEntity>> =
newApi.getGameCollectionContents(collectionId, "component", page, 1)
fun loadChangeSubjectGame(subjectEntity: SubjectEntity): Observable<List<GameEntity>> =
if (subjectEntity.isQQColumn) {

View File

@ -2,10 +2,13 @@ package com.gh.gamecenter.home.custom.model
import androidx.annotation.MainThread
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.asLiveData
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.util.HomePluggableHelper
import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.Constants.SP_HIDDEN_NOTIFICATIONS
import com.gh.gamecenter.common.utils.observableToMain
@ -17,7 +20,9 @@ import com.gh.gamecenter.entity.DiscoveryGameCardEntity
import com.gh.gamecenter.entity.DiscoveryGameCardLabel
import com.gh.gamecenter.feature.entity.AcctRecord
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.PluginLocation
import com.gh.gamecenter.gamedetail.accelerator.AccelerationDataBase
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.retrofit.RetrofitManager
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
@ -34,6 +39,30 @@ class CustomPageShareRepository private constructor() {
private val compositeDisposable = CompositeDisposable()
private val _pluginGames = MediatorLiveData<List<GameEntity>>().apply {
addSource(PackageRepository.gameUpdateLiveData) { updateList ->
val gameList = arrayListOf<GameEntity>()
updateList.forEach {
if (it.isPluggable && it.indexPlugin == "open" && it.isShowPlugin(PluginLocation.only_index)) {
val game = it.transformGameEntity()
if (HomePluggableHelper.showHomePluggable(game)) {
game.setEntryMap(DownloadManager.getInstance().getEntryMap(game.name))
gameList.add(game)
}
}
}
// 下载七天排序
gameList.sortWith { o1, o2 -> o2.download - o1.download }
value = gameList
}
}
val pluginGames: LiveData<List<GameEntity>> = _pluginGames
fun temporarilyBlockGameInPluginItem(gameId: String) {
val gameList = _pluginGames.value ?: return
_pluginGames.value = gameList.filterNot { it.id == gameId }
}
private val _discoverData = MutableLiveData<DiscoveryCardEntity>()
val discoverData: LiveData<DiscoveryCardEntity> = _discoverData

View File

@ -26,10 +26,7 @@ import com.gh.gamecenter.home.custom.createExposureEvent
import com.gh.gamecenter.home.custom.eventlistener.CustomPageItemChildEventHelper
import com.gh.gamecenter.home.custom.eventlistener.GameSubjectCollectionEventHelper
import com.gh.gamecenter.home.custom.eventlistener.SubjectEventHelper
import com.gh.gamecenter.home.custom.model.CustomPageItem
import com.gh.gamecenter.home.custom.model.CustomSplitSubjectItem
import com.gh.gamecenter.home.custom.model.CustomSubjectCollectionItem
import com.gh.gamecenter.home.custom.model.CustomSubjectItem
import com.gh.gamecenter.home.custom.model.*
import com.lightgame.download.DownloadEntity
abstract class BaseCustomViewHolder(
@ -98,7 +95,14 @@ abstract class BaseCustomViewHolder(
titleBinding.root.goneIf(false)
setSubjectTitle(
titleBinding,
CustomSubjectItem(item.link, item.data, item.position, item.componentPosition),
CustomSubjectItem(
item.link,
item.data,
ScrollState(),
item.position,
item.componentPosition,
item.componentId
),
eventHelper,
titleType
)
@ -189,7 +193,7 @@ abstract class BaseCustomViewHolder(
when (subject.home) {
HOME_CHANGE -> {
// 点击换一批
eventHelper.onChangeABatch(subject)
eventHelper.onChangeABatch(item.componentId, subject)
}
HOME_MORE -> {

View File

@ -88,7 +88,7 @@ class CustomRefreshIconViewHolder(
} else {
_subjectEntity = subjectEntity
}
println("kayn -->isBackToStart:${item.isBackToStart}")
// 如果游戏全部被屏蔽,自动加载下一页
if (subjectEntity.games.isEmpty()) {
childEventHelper.onRotateRefresh()

View File

@ -38,19 +38,12 @@ object MiniGameRecentlyPlayUseCase {
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<List<GameEntity>>() {
override fun onSuccess(data: List<GameEntity>) {
if (gameType == Constants.QQ_MINI_GAME) {
_qqRecentGamesItemLiveData.value = data
} else {
_wechatRecentGamesItemLiveData.value = data
}
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
if (gameType == Constants.QQ_MINI_GAME) {
_qqRecentGamesItemLiveData.value = emptyList()
} else {
_wechatRecentGamesItemLiveData.value = emptyList()
if (data.isNotEmpty()) {
if (gameType == Constants.QQ_MINI_GAME) {
_qqRecentGamesItemLiveData.value = data
} else {
_wechatRecentGamesItemLiveData.value = data
}
}
}
})
@ -90,10 +83,7 @@ object MiniGameRecentlyPlayUseCase {
_qqRecentGamesItemLiveData.value
} else {
_wechatRecentGamesItemLiveData.value
} ?: let {
loadRecentlyPlayedMiniGameList(gameType)// 最近在玩数据为空时,则调用接口获取数据
emptyList()
}
} ?: emptyList()
fun clearRecentlyPlayedMiniGameList(gameType: String = "") {
when (gameType) {

View File

@ -19,6 +19,7 @@ class QGameSubjectListRepository(
order: String?,
ad: String?,
columnCollectionId: String?,
minimumSize: Int,
onlyFee: Boolean,
): Single<MutableList<GameEntity>> {
return api.getQGameColumn(column_id, order, page, 20)

View File

@ -17,9 +17,10 @@ class WGameSubjectCPMListRepository(
order: String?,
ad: String?,
columnCollectionId: String?,
minimumSize: Int,
onlyFee: Boolean
): Single<MutableList<GameEntity>> {
return dataSource.getEditorRecommendCPMList(page = page, onlyFee = onlyFee)
return dataSource.getEditorRecommendCPMList(page = page, minimumSize = minimumSize, onlyFee = onlyFee)
}
override fun getColumnSettings(column_id: String?): Observable<SubjectSettingEntity> {

View File

@ -1,11 +1,13 @@
package com.gh.gamecenter.minigame.wechat
import android.annotation.SuppressLint
import androidx.lifecycle.LiveData
import com.gh.gamecenter.common.livedata.NonStickyMutableLiveData
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.feature.entity.GameEntity
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
/**
* 微信小游戏CPM-网域层
@ -13,88 +15,26 @@ import io.reactivex.disposables.CompositeDisposable
class WGameSubjectCPMListUseCase(
private val repository: WGameSubjectCPMListRepository = WGameSubjectCPMListRepository()
) {
private val compositeDisposable = CompositeDisposable()
/**
* 微信小游戏CPM列表这里的LiveData充当类似于EventBus的角色因此使用NonStickyMutableLiveData
*/
private val _wechatMiniGameCPMListLiveData = NonStickyMutableLiveData<Pair<Int, List<GameEntity>>>()
val wechatMiniGameCPMListLiveData: LiveData<Pair<Int, List<GameEntity>>> = _wechatMiniGameCPMListLiveData
private val _wechatMiniGameCPMListLiveData = NonStickyMutableLiveData<Pair<String, List<GameEntity>>>()
val wechatMiniGameCPMListLiveData: LiveData<Pair<String, List<GameEntity>>> = _wechatMiniGameCPMListLiveData
/**
* componentPosition:组件位置记录当前cpm数据需要插入的位置
* 由于用户触发下拉刷新componentPosition位置可能发生变化所以当出现下拉刷新时需要取消这里的所有请求
*/
fun getWechatMiniGameCPMList(componentPosition: Int, onlyFee: Boolean, targetSize: Int, minimumSize: Int) {
loadCpmGameList(1, componentPosition, onlyFee, targetSize, minimumSize, 0, 1, listOf())
}
fun loadCpmGameList(
page: Int,
componentPosition: Int,
onlyFee: Boolean,
targetSize: Int,
minimumSize: Int,
currentSize: Int,
count: Int,
gameList: List<GameEntity>
) {
repository.getColumn(null, page, null, null, null, null, onlyFee)
.compose(singleToMain())
fun getWechatMiniGameCPMList(componentId: String, minimumSize: Int, onlyFee: Boolean) {
repository.getColumn(null, 1, null, null, null, null, minimumSize, onlyFee)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<List<GameEntity>>() {
override fun onSuccess(data: List<GameEntity>) {
val total = currentSize + data.size
val needShowGames = gameList + data
if (total >= targetSize || count >= MAX_LOAD_COUNT) {
// 停止继续加载
if (total >= minimumSize && needShowGames.isNotEmpty()) {
// 游戏数量不小于最小游戏数量才可以显示
_wechatMiniGameCPMListLiveData.value = componentPosition to needShowGames
}
} else {
// 继续加载下一页数据
if (total >= minimumSize) {
// 游戏数量不小于最小游戏数量才可以显示
if (needShowGames.isNotEmpty()) {
_wechatMiniGameCPMListLiveData.value = componentPosition to needShowGames
}
loadCpmGameList(
page + 1,
componentPosition,
onlyFee,
targetSize,
minimumSize,
total,
count + 1,
listOf()
)
} else {
// 游戏数量太少,暂不显示,等后续数据加载出来,达到最小数量限制后一起显示
loadCpmGameList(
page + 1,
componentPosition,
onlyFee,
targetSize,
minimumSize,
total,
count + 1,
needShowGames
)
}
}
_wechatMiniGameCPMListLiveData.value = componentId to data
}
}).let(compositeDisposable::add)
}
fun clear() {
fun onClear() {
compositeDisposable.clear()
}
companion object {
private const val MAX_LOAD_COUNT = 6
}
}

View File

@ -17,6 +17,7 @@ class WGameSubjectCPMRemoteDataSource(
fun getEditorRecommendCPMList(
page: Int,
pageSize: Int = 10,
minimumSize: Int,
onlyFee: Boolean
): Single<MutableList<GameEntity>> {
val meta = MetaUtil.getMeta()
@ -38,33 +39,38 @@ class WGameSubjectCPMRemoteDataSource(
return api.getEditorRecommendList(request.toRequestBody())
.map {
if (it.ret == 0) {
it.appInfoList.map { info ->
GameEntity(
mName = info.appName,
mIcon = info.logo,
mBrief = info.briefIntro,
miniGameUid = info.appID,
miniGameAppId = info.userName,
miniGameCategory = Constants.WECHAT_MINI_GAME,
profit = Constants.WECHAT_MINI_GAME_PROFIT_CPM,
miniGameAppStatus = 2,
miniGameAppPath = info.wechatAppPath,
miniGameExtData = info.extData,
miniGameRecommendId = info.recommendID,
mTagStyle = arrayListOf(
TagStyleEntity(
name = info.categoryName,
color = TAG_COLOR,
background = TAG_BACKGROUND
),
TagStyleEntity(
name = info.subcategoryName,
color = TAG_COLOR,
background = TAG_BACKGROUND
// 数量不满足最小值时直接返回空
if (onlyFee && minimumSize > 0 && it.appInfoList.size < minimumSize) {
mutableListOf()
} else {
it.appInfoList.map { info ->
GameEntity(
mName = info.appName,
mIcon = info.logo,
mBrief = info.briefIntro,
miniGameUid = info.appID,
miniGameAppId = info.userName,
miniGameCategory = Constants.WECHAT_MINI_GAME,
profit = Constants.WECHAT_MINI_GAME_PROFIT_CPM,
miniGameAppStatus = 2,
miniGameAppPath = info.wechatAppPath,
miniGameExtData = info.extData,
miniGameRecommendId = info.recommendID,
mTagStyle = arrayListOf(
TagStyleEntity(
name = info.categoryName,
color = TAG_COLOR,
background = TAG_BACKGROUND
),
TagStyleEntity(
name = info.subcategoryName,
color = TAG_COLOR,
background = TAG_BACKGROUND
)
)
)
)
}.toMutableList()
}.toMutableList()
}
} else {
mutableListOf()
}

View File

@ -19,6 +19,7 @@ class WGameSubjectListRepository(
order: String?,
ad: String?,
columnCollectionId: String?,
minimumSize: Int,
onlyFee: Boolean,
): Single<MutableList<GameEntity>> {
return api.getWGameColumn(column_id, order, page, 20)

View File

@ -14,6 +14,7 @@ interface ISubjectListRepository {
order: String?,
ad: String?,
columnCollectionId: String?,
minimumSize: Int,
onlyFee: Boolean
): Single<MutableList<GameEntity>>

View File

@ -302,14 +302,6 @@ open class SubjectListFragment : LazyListFragment<GameEntity, SubjectListViewMod
}
}
override fun theNumberNeededToFillAScreen(): Int {
return if (mListViewModel.subjectData.subjectType == SubjectData.SubjectType.WECHAT_GAME_CPM) 20 else super.theNumberNeededToFillAScreen()
}
override fun autoLoadMore() {
mListViewModel.load(LoadType.NORMAL)
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
mAdapter?.let { it.notifyItemRangeChanged(0, it.itemCount) }

View File

@ -18,6 +18,7 @@ class SubjectListRepository(
order: String?,
ad: String?,
columnCollectionId: String?,
minimumSize: Int,
onlyFee: Boolean,
): Single<MutableList<GameEntity>> {
return api.getColumn(column_id, sort, order, ad, columnCollectionId, page)

View File

@ -6,7 +6,6 @@ import androidx.lifecycle.ViewModelProvider
import com.gh.common.exposure.ExposureUtils
import com.gh.common.util.AdHelper
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.baselist.LoadParams
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.baselist.LoadType
import com.gh.gamecenter.common.exposure.ExposureSource
@ -18,6 +17,7 @@ import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.PageLocation
import com.gh.gamecenter.feature.entity.TagStyleEntity
import com.gh.gamecenter.feature.exposure.ExposureConstants
import com.gh.gamecenter.retrofit.RetrofitManager
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
@ -38,8 +38,6 @@ open class SubjectListViewModel(
var lastPageDataMap: HashMap<String, String>? = null
private var total = 0
private val repository = SubjectRepositoryFactory.createListRepo(subjectData.subjectType)
override fun provideDataObservable(page: Int): Observable<List<GameEntity>>? = null
@ -52,6 +50,7 @@ open class SubjectListViewModel(
subjectData.filter.ifEmpty { "type:全部" },
AdHelper.getIdfaString(),
columnCollectionId,
-1,
false
)
}
@ -111,7 +110,6 @@ open class SubjectListViewModel(
override fun load(loadType: LoadType) {
if (loadType == LoadType.REFRESH) {
total = 0
initLoadParams()
} else if (loadType == LoadType.RETRY) {
mLoadStatusLiveData.value = LoadStatus.LIST_LOADED
@ -124,49 +122,6 @@ open class SubjectListViewModel(
}
}
override fun loadStatusControl(size: Int) {
if (size > 0) {
total += size
}
if (subjectData.subjectType == SubjectData.SubjectType.WECHAT_GAME_CPM) {
if (mCurLoadParams.loadOffset == LoadParams.DEFAULT_OFFSET) {
// 第一页不管有没有数据,都设置初始化完毕状态(如果游戏数量不够,会触发自动加载下一页)
mLoadStatusLiveData.value = LoadStatus.INIT_LOADED
} else {
when {
total >= CPM_MAX_SIZE -> { // 请求游戏个数到达最大显示数量,列表加载完毕
mLoadStatusLiveData.value = LoadStatus.LIST_OVER
}
mCurLoadParams.loadOffset >= CPM_MAX_LOAD_COUNT && total > 0 -> { // 请求次数到达最大请求次数且游戏总量大于0列表加载完毕
mLoadStatusLiveData.value = LoadStatus.LIST_OVER
}
mCurLoadParams.loadOffset >= CPM_MAX_LOAD_COUNT -> { // 请求次数搭配大最大请求次数且游戏总量为0说明没有数据
mLoadStatusLiveData.value = LoadStatus.INIT_EMPTY
}
else -> {
mLoadStatusLiveData.value = LoadStatus.LIST_LOADED
// 继续加载下一页数据
load(LoadType.NORMAL)
}
}
}
mCurLoadParams.loadOffset += 1
} else {
super.loadStatusControl(size)
}
}
companion object {
private const val CPM_MAX_LOAD_COUNT = 6
private const val CPM_MAX_SIZE = 20
private const val AUTO_LOAD_DURATION = 500L
}
class Factory(
private val mApplication: Application,
private val subjectData: SubjectData,
@ -175,13 +130,7 @@ open class SubjectListViewModel(
private val columnCollectionId: String? = null
) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return SubjectListViewModel(
mApplication,
subjectData,
pageLocation,
exposureSourceList,
columnCollectionId
) as T
return SubjectListViewModel(mApplication, subjectData, pageLocation, exposureSourceList, columnCollectionId) as T
}
}

View File

@ -20,7 +20,7 @@ class SubjectViewModel(
) : AndroidViewModel(application) {
val subjectNameLD = MutableLiveData<String>()
val subjectSettingLD = MutableLiveData<SubjectSettingEntity?>()
val subjectSettingLD = MutableLiveData<SubjectSettingEntity>()
private val repository =
SubjectRepositoryFactory.createRepo(subjectData?.subjectType ?: SubjectData.SubjectType.NORMAL)
@ -34,7 +34,7 @@ class SubjectViewModel(
if (subjectData?.subjectName.isNullOrEmpty()) {
loadSubjectName()
} else {
subjectNameLD.postValue(subjectData?.subjectName ?: "")
subjectNameLD.postValue(subjectData?.subjectName)
loadSubjectType()
}
} else {