Compare commits

...

6 Commits

18 changed files with 309 additions and 204 deletions

View File

@ -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

View File

@ -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()
)
)

View File

@ -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

View File

@ -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()
}

View File

@ -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)

View File

@ -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> {

View File

@ -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
}
}

View File

@ -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()
}

View File

@ -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)

View File

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

View File

@ -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) }

View File

@ -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)

View File

@ -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
}
}

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 {

View File

@ -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"

View File

@ -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>

View File

@ -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>

View File

@ -7,8 +7,8 @@ ext {
targetSdkVersion = 30 // 升级targetSdkVersion到 34 时需要根据官方文档补全前台服务的权限类型。比如 NDownloadServiceKeepAliveService
// 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"