Compare commits
6 Commits
release
...
feat/GHZSC
| Author | SHA1 | Date | |
|---|---|---|---|
| e2ebaa303e | |||
| e4f32302a5 | |||
| f227146f72 | |||
| 0f382baec1 | |||
| 62f80bbfdd | |||
| 63be9ac221 |
@ -72,6 +72,7 @@ android_build:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-8069
|
||||
|
||||
# 代码检查
|
||||
sonarqube_analysis:
|
||||
@ -103,6 +104,7 @@ sonarqube_analysis:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-8069
|
||||
|
||||
## 发送简易检测结果报告
|
||||
send_sonar_report:
|
||||
@ -121,6 +123,7 @@ send_sonar_report:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-8069
|
||||
|
||||
oss-upload&send-email:
|
||||
tags:
|
||||
@ -157,4 +160,5 @@ oss-upload&send-email:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-8069
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.menu.ActionMenuItemView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.doOnNextLayout
|
||||
import androidx.core.view.isVisible
|
||||
@ -96,6 +97,7 @@ import io.reactivex.disposables.Disposable
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import retrofit2.HttpException
|
||||
import splitties.views.horizontalPadding
|
||||
import java.util.*
|
||||
|
||||
class GameDetailWrapperFragment : BaseLazyFragment(), IScrollable {
|
||||
@ -286,7 +288,7 @@ class GameDetailWrapperFragment : BaseLazyFragment(), IScrollable {
|
||||
initSkeleton()
|
||||
|
||||
binding.reuseNoneData.reuseNoneDataTv.text = "页面不见了"
|
||||
bodyBinding.tabIndicator.setIndicatorWidth(12)
|
||||
bodyBinding.tabIndicator.setIndicatorWidth(16)
|
||||
bodyBinding.viewPager.offscreenPageLimit = 4
|
||||
binding.expandSpecialDownloadIv.enlargeTouchArea()
|
||||
|
||||
@ -357,8 +359,14 @@ class GameDetailWrapperFragment : BaseLazyFragment(), IScrollable {
|
||||
}
|
||||
backBtn.setOnClickListener { requireActivity().finish() }
|
||||
moreMenuItem = actionMenuView.menu.findItem(R.id.menu_more)
|
||||
downloadMenuItem = actionMenuView.menu.findItem(R.id.menu_download)
|
||||
downloadMenuItem = actionMenuView.menu.findItem(R.id.menu_download)?.apply {
|
||||
actionView?.updateLayoutParams<LayoutParams> { width = 40F.dip2px() }
|
||||
}
|
||||
downloadMenuItem?.isVisible = Config.isShow()
|
||||
actionMenuView.findViewById<ActionMenuItemView>(R.id.menu_more)?.run {
|
||||
updateLayoutParams<LayoutParams> { width = 40F.dip2px() }
|
||||
horizontalPadding = 8F.dip2px()
|
||||
}
|
||||
}
|
||||
|
||||
downloadMenuIcon = downloadMenuItem?.actionView?.findViewById(R.id.menu_download_iv)
|
||||
@ -910,7 +918,7 @@ class GameDetailWrapperFragment : BaseLazyFragment(), IScrollable {
|
||||
tab.customView = tabItemBinding.root
|
||||
updateTabStyle(tab, i == bodyBinding.viewPager.currentItem)
|
||||
tab.view.clipChildren = false
|
||||
tab.view.setPadding(0, 0, 0, 0)
|
||||
tab.view.setPadding(0, 0, if (i == tabEntityList.size - 1) 8F.dip2px() else 0, 0)
|
||||
tab.view.setOnTouchListener { _, event ->
|
||||
if (event.action == MotionEvent.ACTION_DOWN) {
|
||||
handleTabTouchEvent(tabEntity?.name ?: "")
|
||||
@ -937,7 +945,7 @@ class GameDetailWrapperFragment : BaseLazyFragment(), IScrollable {
|
||||
tab.customView?.findViewById<TextView>(R.id.tab_title)
|
||||
?.setTypeface(if (isChecked) Typeface.DEFAULT_BOLD else Typeface.DEFAULT)
|
||||
tab.customView?.findViewById<TextView>(R.id.tab_title)?.setTextColor(
|
||||
if (isChecked) com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()) else com.gh.gamecenter.common.R.color.text_tertiary.toColor(
|
||||
if (isChecked) com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()) else com.gh.gamecenter.common.R.color.text_secondary.toColor(
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
|
||||
@ -3,12 +3,7 @@ package com.gh.gamecenter.home.custom
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import androidx.collection.ArrayMap
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MediatorLiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.*
|
||||
import com.gh.common.util.GameUtils
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.common.util.NewLogUtils
|
||||
@ -33,24 +28,10 @@ import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.home.PageConfigure
|
||||
import com.gh.gamecenter.home.custom.GamePositionAndPackageHelper.Companion.putGameWithPosition
|
||||
import com.gh.gamecenter.home.custom.eventlistener.OnCustomPageEventListener
|
||||
import com.gh.gamecenter.home.custom.model.CustomCommonContentCollectionItem
|
||||
import com.gh.gamecenter.home.custom.model.CustomDspPlaceholderItem
|
||||
import com.gh.gamecenter.home.custom.model.CustomPKItem
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageData
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem
|
||||
import com.gh.gamecenter.home.custom.model.*
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMPONENTS_COLLECTION_STYLE_REFRESH_ICONS_4_2
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMPONENTS_COLLECTION_STYLE_REFRESH_SLIDE_LIST
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageRepository
|
||||
import com.gh.gamecenter.home.custom.model.CustomPluginItem
|
||||
import com.gh.gamecenter.home.custom.model.CustomRecentGamesItem
|
||||
import com.gh.gamecenter.home.custom.model.CustomSplitCommonContentCollectionItem
|
||||
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.CustomWeChatMiniGamesCPMSubjectItem
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import com.gh.gamecenter.login.user.UserRepository
|
||||
import com.gh.gamecenter.login.user.UserViewModel
|
||||
import com.gh.gamecenter.wrapper.SearchToolbarTabWrapperViewModel
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
@ -117,11 +98,6 @@ class CustomPageViewModel(application: Application) : AndroidViewModel(applicati
|
||||
|
||||
private val subjectChangedMap: ArrayMap<SubjectChanged, List<GameEntity>> = ArrayMap()
|
||||
|
||||
/**
|
||||
* 微信CPM专题当前的页码记录
|
||||
*/
|
||||
private val cpmSubjectChangedPageMap: ArrayMap<String, Int> = ArrayMap()
|
||||
|
||||
private lateinit var _pageTracker: CustomPageTracker
|
||||
|
||||
val pageTracker: CustomPageTracker
|
||||
@ -134,6 +110,9 @@ class CustomPageViewModel(application: Application) : AndroidViewModel(applicati
|
||||
|
||||
var shouldScrollToTop: Boolean = false
|
||||
|
||||
private var loadFirstDisposable: Disposable? = null
|
||||
private var loadMoreDisposable: Disposable? = null
|
||||
|
||||
fun init(
|
||||
pageConfigure: PageConfigure,
|
||||
searchToolbarTabWrapperViewModel: SearchToolbarTabWrapperViewModel?,
|
||||
@ -208,7 +187,15 @@ class CustomPageViewModel(application: Application) : AndroidViewModel(applicati
|
||||
|
||||
fun loadFirst(isPullToRefresh: Boolean, forceLoad: Boolean = false) {
|
||||
_loadStatus.value = LoadStatus.INIT_LOADING to isPullToRefresh
|
||||
repository.loadFirstCustomPageData(pageConfigure.pageId, forceLoad)
|
||||
|
||||
if (loadFirstDisposable != null && !loadFirstDisposable!!.isDisposed) {
|
||||
// 有可能上一次刷新数据还未获取成功,又再次触发了下拉刷新
|
||||
loadFirstDisposable?.dispose()
|
||||
}
|
||||
if (loadMoreDisposable != null && !loadMoreDisposable!!.isDisposed) {
|
||||
loadMoreDisposable?.dispose()
|
||||
}
|
||||
loadFirstDisposable = repository.loadFirstCustomPageData(pageConfigure.pageId, forceLoad)
|
||||
.map { (custom, list) ->
|
||||
Triple(custom, list, getPositionAndPackageMap(list))
|
||||
}
|
||||
@ -255,7 +242,7 @@ class CustomPageViewModel(application: Application) : AndroidViewModel(applicati
|
||||
|
||||
}
|
||||
|
||||
}).addDisposable()
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@ -273,7 +260,7 @@ class CustomPageViewModel(application: Application) : AndroidViewModel(applicati
|
||||
}
|
||||
if (repository.isLoadingPKData) return
|
||||
_loadStatus.value = LoadStatus.LIST_LOADING to false
|
||||
repository.loadNextCustomPageData(pageConfigure.pageId)
|
||||
loadMoreDisposable = repository.loadNextCustomPageData(pageConfigure.pageId)
|
||||
.map {
|
||||
it to getPositionAndPackageMap(it)
|
||||
}
|
||||
@ -298,7 +285,7 @@ class CustomPageViewModel(application: Application) : AndroidViewModel(applicati
|
||||
super.onFailure(exception)
|
||||
_loadStatus.value = LoadStatus.LIST_FAILED to false
|
||||
}
|
||||
}).addDisposable()
|
||||
})
|
||||
}
|
||||
|
||||
override fun onRetry() {
|
||||
@ -388,59 +375,7 @@ class CustomPageViewModel(application: Application) : AndroidViewModel(applicati
|
||||
}
|
||||
|
||||
override fun onChangeABatch(subjectEntity: SubjectEntity) =
|
||||
if (subjectEntity.isWechatColumnCPM) {
|
||||
onChangeWGameCPMABatch(subjectEntity)
|
||||
} else {
|
||||
onChangeNormalGameABatch(subjectEntity)
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信小游戏CPM的“换一批”功能实现
|
||||
*
|
||||
* @see <a href="https://jira.shanqu.cc/browse/GHZSCY-7167">【光环助手】CPM微信小游戏“换一批”功能优化</a>
|
||||
*/
|
||||
private fun onChangeWGameCPMABatch(subjectEntity: SubjectEntity) {
|
||||
val subjectId = subjectEntity.id ?: return
|
||||
val page = cpmSubjectChangedPageMap[subjectId] ?: let {
|
||||
// 第一次点击“换一批”时,先缓存第一页的数据
|
||||
subjectChangedMap[SubjectChanged(subjectId, 1)] = subjectEntity.data
|
||||
2
|
||||
}
|
||||
val subjectChanged = SubjectChanged(subjectId, page)
|
||||
val gameList = subjectChangedMap[subjectChanged]
|
||||
if (gameList != null) {// 直接读取缓存数据
|
||||
notifyWGameCPMABatchChanged(gameList, subjectId, page)
|
||||
} else {
|
||||
repository.loadChangeSubjectWGameCPM(page, subjectEntity.size.limit, subjectEntity.onlyFee)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Response<List<GameEntity>>() {
|
||||
override fun onResponse(response: List<GameEntity>?) {
|
||||
if (response != null) {
|
||||
subjectChangedMap[subjectChanged] = response
|
||||
notifyWGameCPMABatchChanged(response, subjectId, page)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(e: HttpException?) {
|
||||
Utils.toast(getApplication(), "网络异常")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyWGameCPMABatchChanged(gameList: List<GameEntity>, subjectId: String, page: Int) {
|
||||
val nextPage: Int
|
||||
val cpmGameList = if (gameList.isEmpty()) {
|
||||
nextPage = 1// 已经到最后一页了,下一页是第一页
|
||||
subjectChangedMap[SubjectChanged(subjectId, 1)]!!
|
||||
} else {
|
||||
nextPage = page + 1
|
||||
gameList
|
||||
}
|
||||
cpmSubjectChangedPageMap[subjectId] = nextPage// 加载下一页数据
|
||||
changeSubjectCustomPageItem(subjectId, ArrayList(cpmGameList))
|
||||
}
|
||||
onChangeNormalGameABatch(subjectEntity)
|
||||
|
||||
/**
|
||||
* 光环游戏的“换一批”功能实现
|
||||
@ -564,40 +499,94 @@ class CustomPageViewModel(application: Application) : AndroidViewModel(applicati
|
||||
/**
|
||||
* 通过CPM接口异步请求获取的微信小游戏数据插入
|
||||
*/
|
||||
private fun notifyWechatMiniGameCPMSubjectItemChanged(result: Pair<String, List<GameEntity>>) {
|
||||
private fun notifyWechatMiniGameCPMSubjectItemChanged(result: Pair<Int, List<GameEntity>>) {
|
||||
|
||||
val (componentPosition, gameList) = result
|
||||
val oldData = _dataList.value ?: return
|
||||
val index = oldData.indexOfFirst {
|
||||
it is CustomWeChatMiniGamesCPMSubjectItem && it.data.id == result.first
|
||||
}
|
||||
if (index == -1) return
|
||||
val subjectItem = (oldData[index] as CustomWeChatMiniGamesCPMSubjectItem).apply {
|
||||
data.data = result.second.toMutableList()
|
||||
data.isWechatColumnCPM = true
|
||||
}
|
||||
val position = subjectItem.position
|
||||
val componentPosition = subjectItem.componentPosition
|
||||
val newData = oldData.toMutableList()
|
||||
val customPageItemList = repository.convertColumnDetailSubjectItems(
|
||||
position,
|
||||
componentPosition,
|
||||
subjectItem.link,
|
||||
subjectItem.data
|
||||
)
|
||||
if (customPageItemList.isEmpty()) return
|
||||
|
||||
if (index == 0) {
|
||||
shouldScrollToTop = true
|
||||
// 是否是cpm第一页数据
|
||||
val itemPosition = oldData.indexOfFirst { it.componentPosition == componentPosition }
|
||||
val targetItem = oldData.getOrNull(itemPosition)
|
||||
when {
|
||||
targetItem is CustomWeChatMiniGamesCPMSubjectItem -> {
|
||||
// 第一次添加数据
|
||||
val subject = targetItem.data
|
||||
subject.data = gameList.toMutableList()
|
||||
subject.isWechatColumnCPM = true
|
||||
|
||||
val cpmSubjectItemList = repository.convertColumnDetailSubjectItems(
|
||||
targetItem.position,
|
||||
componentPosition,
|
||||
targetItem.link,
|
||||
subject
|
||||
)
|
||||
if (cpmSubjectItemList.isEmpty()) return
|
||||
|
||||
if (itemPosition == 0) {
|
||||
shouldScrollToTop = true
|
||||
}
|
||||
|
||||
val newData = oldData.toMutableList()
|
||||
newData[itemPosition] = cpmSubjectItemList[0]
|
||||
newData.addAll(itemPosition + 1, cpmSubjectItemList.subList(1, cpmSubjectItemList.size))
|
||||
newData.forEachIndexed { pos, customPageItem ->
|
||||
customPageItem.position = pos
|
||||
}
|
||||
repository.notifyPositionChanged(newData.size)
|
||||
gamePositionAndPackageHelper.clear()
|
||||
gamePositionAndPackageHelper.putAll(getPositionAndPackageMap(newData))
|
||||
_dataList.value = newData
|
||||
}
|
||||
|
||||
targetItem is CustomSplitSubjectItem -> {// 添加后续的数据
|
||||
val subject = targetItem.data
|
||||
subject.data = ((subject.data ?: emptyList()) + gameList).toMutableList()
|
||||
subject.isWechatColumnCPM = true
|
||||
|
||||
val cpmSubjectItemList = repository.convertColumnDetailSubjectItems(
|
||||
targetItem.position,
|
||||
componentPosition,
|
||||
targetItem.link,
|
||||
subject
|
||||
)
|
||||
if (cpmSubjectItemList.isEmpty()) return
|
||||
val newData = oldData.toMutableList()
|
||||
|
||||
val position = newData.indexOfFirst { it.componentPosition == componentPosition }
|
||||
// 移除旧数据
|
||||
newData.removeAll { it.componentPosition == componentPosition }
|
||||
// 在原来的位置上插入新数据
|
||||
newData.addAll(position, cpmSubjectItemList)
|
||||
newData.forEachIndexed { pos, customPageItem ->
|
||||
customPageItem.position = pos
|
||||
}
|
||||
repository.notifyPositionChanged(newData.size)
|
||||
gamePositionAndPackageHelper.clear()
|
||||
gamePositionAndPackageHelper.putAll(getPositionAndPackageMap(newData))
|
||||
_dataList.value = newData
|
||||
}
|
||||
|
||||
targetItem is CustomSubjectItem -> {
|
||||
val subject = targetItem.data.copy()
|
||||
val originalGameList = subject.data ?: mutableListOf()
|
||||
subject.data = (originalGameList + gameList).toMutableList()
|
||||
subject.isWechatColumnCPM = true
|
||||
val cpmSubjectItemList = repository.convertColumnDetailSubjectItems(
|
||||
targetItem.position,
|
||||
componentPosition,
|
||||
targetItem.link,
|
||||
subject
|
||||
)
|
||||
if (cpmSubjectItemList.isEmpty()) return
|
||||
|
||||
val newData = oldData.toMutableList()
|
||||
newData[itemPosition] = cpmSubjectItemList.first()
|
||||
gamePositionAndPackageHelper.clear()
|
||||
gamePositionAndPackageHelper.putAll(getPositionAndPackageMap(newData))
|
||||
_dataList.value = newData
|
||||
}
|
||||
}
|
||||
|
||||
newData[index] = customPageItemList[0]
|
||||
newData.addAll(index + 1, customPageItemList.subList(1, customPageItemList.size))
|
||||
newData.forEachIndexed { pos, customPageItem ->
|
||||
customPageItem.position = pos
|
||||
}
|
||||
repository.notifyPositionChanged(newData.size)
|
||||
gamePositionAndPackageHelper.clear()
|
||||
gamePositionAndPackageHelper.putAll(getPositionAndPackageMap(newData))
|
||||
_dataList.value = newData
|
||||
}
|
||||
|
||||
/**
|
||||
@ -926,6 +915,12 @@ class CustomPageViewModel(application: Application) : AndroidViewModel(applicati
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
if (loadFirstDisposable != null && !loadFirstDisposable!!.isDisposed) {
|
||||
loadFirstDisposable?.dispose()
|
||||
}
|
||||
if (loadMoreDisposable != null && !loadMoreDisposable!!.isDisposed) {
|
||||
loadMoreDisposable?.dispose()
|
||||
}
|
||||
compositeDisposable.clear()
|
||||
repository.onClear()
|
||||
}
|
||||
@ -952,8 +947,7 @@ class CustomPageViewModel(application: Application) : AndroidViewModel(applicati
|
||||
|
||||
}
|
||||
|
||||
class Factory(private val mApplication: Application)
|
||||
: ViewModelProvider.NewInstanceFactory() {
|
||||
class Factory(private val mApplication: Application) : ViewModelProvider.NewInstanceFactory() {
|
||||
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return CustomPageViewModel(mApplication) as T
|
||||
|
||||
@ -159,7 +159,7 @@ class CustomPageRepository private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
val wechatMiniGameCPMItemLiveData: LiveData<Pair<String, List<GameEntity>>> =
|
||||
val wechatMiniGameCPMItemLiveData: LiveData<Pair<Int, List<GameEntity>>> =
|
||||
wGameSubjectCPMListUseCase.wechatMiniGameCPMListLiveData
|
||||
|
||||
val hiddenNotifications: LiveData<HashMap<String, MutableSet<String>>>
|
||||
@ -257,7 +257,8 @@ class CustomPageRepository private constructor(
|
||||
gameChildPosition = 0
|
||||
displayingGameIdSet.clear()
|
||||
isLoadingPKData = false
|
||||
return remoteDataSource.loadCustomPageData(pageId, pageInfo.page, forceLoad)
|
||||
wGameSubjectCPMListUseCase.clear()
|
||||
return remoteDataSource.loadCustomPageData(pageId, 1, forceLoad)
|
||||
.map {
|
||||
it to transformRawDataIntoItemData(it, forceLoad)
|
||||
}
|
||||
@ -367,7 +368,12 @@ class CustomPageRepository private constructor(
|
||||
pageInfo.componentPosition
|
||||
)
|
||||
)
|
||||
wGameSubjectCPMListUseCase.getWechatMiniGameCPMList(subject.id, subject.size.limit, subject.onlyFee)
|
||||
wGameSubjectCPMListUseCase.getWechatMiniGameCPMList(
|
||||
pageInfo.componentPosition,
|
||||
subject.onlyFee,
|
||||
subject.size.index,
|
||||
subject.size.limit,
|
||||
)
|
||||
pageInfo.positionIncrement()
|
||||
pageInfo.componentPositionIncrement()
|
||||
}
|
||||
@ -903,12 +909,6 @@ class CustomPageRepository private constructor(
|
||||
.map(RegionSettingHelper.filterGame)
|
||||
.map(ApkActiveUtils.filterMapperList)
|
||||
|
||||
fun loadChangeSubjectWGameCPM(page: Int, minimumSize: Int, onlyFee: Boolean): Observable<MutableList<GameEntity>> =
|
||||
wGameSubjectCPMRemoteDataSource.getEditorRecommendCPMList(page = page, minimumSize = minimumSize, onlyFee = onlyFee)// 微信小游戏CPM专题的“换一批”接口
|
||||
.toObservable()
|
||||
.map(RegionSettingHelper.filterGame)
|
||||
.map(ApkActiveUtils.filterMapperList)
|
||||
|
||||
fun loadSlideDiscoverCardGames(): Observable<List<GameEntity>> =
|
||||
remoteDataSource.loadSlideDiscoverCardGames()
|
||||
.map(RegionSettingHelper.filterGame)
|
||||
@ -1013,6 +1013,7 @@ class CustomPageRepository private constructor(
|
||||
}
|
||||
|
||||
fun onClear() {
|
||||
wGameSubjectCPMListUseCase.clear()
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
|
||||
@ -19,7 +19,6 @@ class QGameSubjectListRepository(
|
||||
order: String?,
|
||||
ad: String?,
|
||||
columnCollectionId: String?,
|
||||
minimumSize: Int,
|
||||
onlyFee: Boolean,
|
||||
): Single<MutableList<GameEntity>> {
|
||||
return api.getQGameColumn(column_id, order, page, 20)
|
||||
|
||||
@ -17,10 +17,9 @@ class WGameSubjectCPMListRepository(
|
||||
order: String?,
|
||||
ad: String?,
|
||||
columnCollectionId: String?,
|
||||
minimumSize: Int,
|
||||
onlyFee: Boolean
|
||||
): Single<MutableList<GameEntity>> {
|
||||
return dataSource.getEditorRecommendCPMList(page = page, minimumSize = minimumSize, onlyFee = onlyFee)
|
||||
return dataSource.getEditorRecommendCPMList(page = page, onlyFee = onlyFee)
|
||||
}
|
||||
|
||||
override fun getColumnSettings(column_id: String?): Observable<SubjectSettingEntity> {
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
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.schedulers.Schedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
||||
/**
|
||||
* 微信小游戏CPM-网域层
|
||||
@ -15,32 +14,87 @@ class WGameSubjectCPMListUseCase(
|
||||
private val repository: WGameSubjectCPMListRepository = WGameSubjectCPMListRepository()
|
||||
) {
|
||||
|
||||
/**
|
||||
* 微信专题CPM请求记录,用于避免重复请求,以专题ID作为Key
|
||||
*/
|
||||
private val requestKeyList = mutableListOf<String>()
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
/**
|
||||
* 微信小游戏CPM列表,这里的LiveData充当类似于EventBus的角色,因此使用NonStickyMutableLiveData
|
||||
*/
|
||||
private val _wechatMiniGameCPMListLiveData = NonStickyMutableLiveData<Pair<String, List<GameEntity>>>()
|
||||
val wechatMiniGameCPMListLiveData: LiveData<Pair<String, List<GameEntity>>> = _wechatMiniGameCPMListLiveData
|
||||
private val _wechatMiniGameCPMListLiveData = NonStickyMutableLiveData<Pair<Int, List<GameEntity>>>()
|
||||
val wechatMiniGameCPMListLiveData: LiveData<Pair<Int, List<GameEntity>>> = _wechatMiniGameCPMListLiveData
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun getWechatMiniGameCPMList(subjectId: String?, minimumSize: Int, onlyFee: Boolean) {
|
||||
if (subjectId.isNullOrEmpty() || requestKeyList.contains(subjectId)) {
|
||||
return
|
||||
}
|
||||
/**
|
||||
* componentPosition:组件位置,记录当前cpm数据需要插入的位置
|
||||
* 由于用户触发下拉刷新,componentPosition位置可能发生变化,所以当出现下拉刷新时,需要取消这里的所有请求
|
||||
*/
|
||||
fun getWechatMiniGameCPMList(componentPosition: Int, onlyFee: Boolean, targetSize: Int, minimumSize: Int) {
|
||||
loadCpmGameList(1, componentPosition, onlyFee, targetSize, minimumSize, 0, 1, listOf())
|
||||
}
|
||||
|
||||
requestKeyList.add(subjectId)
|
||||
repository.getColumn(null, 1, null, null, null, null, minimumSize, onlyFee)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
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())
|
||||
.subscribe(object : BiResponse<List<GameEntity>>() {
|
||||
override fun onSuccess(data: List<GameEntity>) {
|
||||
requestKeyList.remove(subjectId)
|
||||
_wechatMiniGameCPMListLiveData.value = subjectId to data
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
compositeDisposable.clear()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val MAX_LOAD_COUNT = 6
|
||||
}
|
||||
}
|
||||
@ -17,7 +17,6 @@ class WGameSubjectCPMRemoteDataSource(
|
||||
fun getEditorRecommendCPMList(
|
||||
page: Int,
|
||||
pageSize: Int = 10,
|
||||
minimumSize: Int,
|
||||
onlyFee: Boolean
|
||||
): Single<MutableList<GameEntity>> {
|
||||
val meta = MetaUtil.getMeta()
|
||||
@ -39,38 +38,33 @@ class WGameSubjectCPMRemoteDataSource(
|
||||
return api.getEditorRecommendList(request.toRequestBody())
|
||||
.map {
|
||||
if (it.ret == 0) {
|
||||
// 数量不满足最小值时直接返回空
|
||||
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
|
||||
)
|
||||
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()
|
||||
}
|
||||
|
||||
@ -19,7 +19,6 @@ class WGameSubjectListRepository(
|
||||
order: String?,
|
||||
ad: String?,
|
||||
columnCollectionId: String?,
|
||||
minimumSize: Int,
|
||||
onlyFee: Boolean,
|
||||
): Single<MutableList<GameEntity>> {
|
||||
return api.getWGameColumn(column_id, order, page, 20)
|
||||
|
||||
@ -14,7 +14,6 @@ interface ISubjectListRepository {
|
||||
order: String?,
|
||||
ad: String?,
|
||||
columnCollectionId: String?,
|
||||
minimumSize: Int,
|
||||
onlyFee: Boolean
|
||||
): Single<MutableList<GameEntity>>
|
||||
|
||||
|
||||
@ -302,6 +302,14 @@ 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) }
|
||||
|
||||
@ -18,7 +18,6 @@ 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)
|
||||
|
||||
@ -6,6 +6,7 @@ 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
|
||||
@ -17,7 +18,6 @@ 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,6 +38,8 @@ 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
|
||||
@ -50,7 +52,6 @@ open class SubjectListViewModel(
|
||||
subjectData.filter.ifEmpty { "type:全部" },
|
||||
AdHelper.getIdfaString(),
|
||||
columnCollectionId,
|
||||
-1,
|
||||
false
|
||||
)
|
||||
}
|
||||
@ -110,6 +111,7 @@ 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
|
||||
@ -122,6 +124,49 @@ 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,
|
||||
@ -130,7 +175,13 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/text_tertiary"
|
||||
android:textColor="@color/text_secondary"
|
||||
android:textSize="@dimen/secondary_title_text_size"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
@ -33,14 +33,15 @@
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/backContainer"
|
||||
android:layout_width="48dp"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="48dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/backBtn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="12dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
@ -73,8 +74,8 @@
|
||||
<com.gh.gamecenter.common.view.TabIndicatorView
|
||||
android:id="@+id/tabIndicator"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/default_tab_indicator_height"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_height="4dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:indicatorColor="@color/primary_theme"
|
||||
app:disableIndicatorScaling="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
@ -97,6 +98,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginHorizontal="8dp"
|
||||
android:minWidth="44dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@ -14,10 +14,4 @@
|
||||
android:title="@string/menu_more"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item
|
||||
android:orderInCategory="-1"
|
||||
android:title=""
|
||||
app:actionLayout="@layout/layout_menu_inset"
|
||||
app:showAsAction="always" />
|
||||
|
||||
</menu>
|
||||
@ -7,8 +7,8 @@ ext {
|
||||
targetSdkVersion = 30 // 升级targetSdkVersion到 34 时需要根据官方文档补全前台服务的权限类型。比如 NDownloadService,KeepAliveService
|
||||
|
||||
// application info (每个大版本之间的 versionCode 增加 20)
|
||||
versionCode = 1190
|
||||
versionName = "5.42.0"
|
||||
versionCode = 1210
|
||||
versionName = "5.43.0"
|
||||
applicationId = "com.gh.gamecenter"
|
||||
applicationIdGat = "com.gh.gamecenter.intl"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user