Compare commits

..

6 Commits

53 changed files with 364 additions and 386 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

@ -18,7 +18,6 @@ import com.therouter.TheRouter
import com.facebook.drawee.controller.BaseControllerListener
import com.facebook.drawee.view.SimpleDraweeView
import com.facebook.imagepipeline.image.ImageInfo
import com.g00fy2.versioncompare.Version
import com.gh.common.exposure.ExposureManager
import com.gh.common.util.DirectUtils.directToLinkPage
import com.gh.common.util.LogUtils
@ -187,11 +186,11 @@ object AdDelegateHelper {
"halo_launch" -> {
config.ownerAd?.startAd?.let { it.id = config.ownerAd.id }
// HarmonyOS 4.2.0 版本不展示第三方开屏广告 (因为会引起奇怪的闪退)
if (MetaUtil.getRom().romName == "HarmonyOS"
&& Version(MetaUtil.getRom().romVersion).isLowerThan(Version("4.2.0"))
&& config.displayRule.adSource == AD_TYPE_SDK
) {
// HarmonyOS 2.2.0 版本不展示第三方开屏广告 (因为会引起奇怪的闪退)
if (MetaUtil.getRom().name == "HarmonyOS"
&& MetaUtil.getRom().versionName == "2.2.0"
&& config.displayRule.adSource == AD_TYPE_SDK) {
return
}

View File

@ -390,7 +390,7 @@ public class Config {
"manufacturer", Build.MANUFACTURER,
"model", Build.MODEL,
"android_sdk_version", String.valueOf(Build.VERSION.SDK_INT),
"rom", MetaUtil.INSTANCE.getRom().getRomName() + " " + MetaUtil.INSTANCE.getRom().getRomVersion()
"rom", MetaUtil.INSTANCE.getRom().name() + " " + MetaUtil.INSTANCE.getRom().getVersionName()
);
RetrofitManager.getInstance()

View File

@ -16,7 +16,6 @@ class DefaultExposureStateChangeListener : IExposureStateChangeListener {
val exposureStatus = if (inExposure) "曝光中" else "结束曝光"
val isCPMExposureEvent = exposureEvent.payload.miniGameType == Constants.WECHAT_MINI_GAME_CPM
val isDSPExposureEvent = exposureEvent.payload.miniGameType == Constants.DSP_GAME
Utils.log(
RecyclerViewExposureHelper.TAG,
@ -30,12 +29,6 @@ class DefaultExposureStateChangeListener : IExposureStateChangeListener {
"上报 CPM 曝光 ${exposureEvent.payload.gameName} ${exposureEvent.id}"
)
ExposureManager.logCPM(exposureEvent)
} else if (isDSPExposureEvent && inExposure) {
Utils.log(
RecyclerViewExposureHelper.TAG,
"上报 DSP 曝光 ${exposureEvent.payload.gameName} ${exposureEvent.id}"
)
ExposureManager.logDSP(exposureEvent)
}
if (!inExposure

View File

@ -111,12 +111,6 @@ object ExposureManager {
}
}
fun logDSP(event: ExposureEvent) {
AppExecutor.logExecutor.execute {
DspReportHelper.report(event.payload.showUrl)
}
}
/**
* @param forcedUpload Ignore all restrictions.
*/

View File

@ -73,7 +73,7 @@ object RegionSettingHelper {
if (list is ArrayList) return list
}
val listCopy: ArrayList<GameEntity> = ArrayList(list)
val listCopy: ArrayList<GameEntity> = if (list is ArrayList) list else ArrayList(list)
listCopy.removeAll { mFilterGameIdSet?.contains(it.id) ?: false }
return listCopy
}

View File

@ -108,32 +108,21 @@ object GameSubstituteRepositoryHelper {
var thisPositionNeedToBeReplaced = false
// 检查是否已安装该游戏里同包名的 APK
if (game.getApk().size == 1) {
val apk = game.getApk().firstOrNull()
// 若该游戏只有一个 APK且该 APK 的包名在本地已安装的包名列表中
if (PackageHelper.localPackageNameSet.contains(apk?.packageName)) {
for (apk in game.getApk()) {
if (PackageHelper.validLocalPackageNameSet.contains(apk.packageName)) {
// 将该位置的游戏标记为需要替换
positionOfGameToBeReplacedList.add(index)
thisPositionNeedToBeReplaced = true
}
} else {
// 检查是否已安装该游戏里同包名的 APK
for (apk in game.getApk()) {
if (PackageHelper.validLocalPackageNameSet.contains(apk.packageName)) {
// 将该位置的游戏标记为需要替换
positionOfGameToBeReplacedList.add(index)
thisPositionNeedToBeReplaced = true
break
}
break
}
}
// 检查是否已安装该游戏 id
if (!thisPositionNeedToBeReplaced && PackagesManager.getInstalledDataByGameId(game.id) != null) {
if (PackagesManager.getInstalledDataByGameId(game.id) != null) {
// 将该位置的游戏标记为需要替换
positionOfGameToBeReplacedList.add(index)
thisPositionNeedToBeReplaced = true
continue
break
}
// 若此游戏所包含的 apk 没有已安装,那么再检查是否已安装有预设相关包名
@ -163,19 +152,11 @@ object GameSubstituteRepositoryHelper {
if (mGameCollectionList.isNullOrEmpty()) return
// 临时的游戏 ID 列表(包含 gameList 的游戏),避免重复替换
val tempDisplayingGameIdSet = HashSet(displayingGameIdSet)
gameList.forEach {
tempDisplayingGameIdSet.add(it.id)
}
for (position in positionOfGameToBeReplacedList) {
val validGame = getValidGame(relatedCollectionId, tempDisplayingGameIdSet)
val validGame = getValidGame(relatedCollectionId, displayingGameIdSet)
validGame?.let {
gameList[position] = it
displayingGameIdSet.add(it.id)
tempDisplayingGameIdSet.add(it.id)
}
}
}

View File

@ -245,7 +245,6 @@ public class LogUtils {
object.put("jnfj", MetaUtil.getBase64EncodedIMEI());
object.put("G_ID", UserManager.getInstance().getDeviceId());
object.put("oaid", HaloApp.getInstance().getOAID());
object.put("rom", MetaUtil.getMeta().getRom());
} catch (JSONException e) {
e.printStackTrace();
}
@ -265,7 +264,6 @@ public class LogUtils {
object.put("channel", HaloApp.getInstance().getChannel());
object.put("dia", MetaUtil.getBase64EncodedAndroidId());
object.put("oaid", MetaUtil.INSTANCE.getMeta().getOaid());
object.put("rom", MetaUtil.getMeta().getRom());
object.put("time", Utils.getTime(context));
object.put("network", DeviceUtils.getNetwork(context));
object.put("user_id", UserManager.getInstance().getUserId());
@ -291,7 +289,6 @@ public class LogUtils {
metaObject.put("channel", meta.getChannel());
metaObject.put("gid", meta.getGid());
metaObject.put("oaid", meta.getOaid());
metaObject.put("rom", MetaUtil.getMeta().getRom());
metaObject.put("jnfj", MetaUtil.getBase64EncodedIMEI());
metaObject.put("mac", meta.getMac());
metaObject.put("manufacturer", meta.getManufacturer());
@ -498,7 +495,6 @@ public class LogUtils {
metaObject.put("os", meta.getOs());
metaObject.put("userId", meta.getUserId());
metaObject.put("oaid", HaloApp.getInstance().getOAID());
metaObject.put("rom", MetaUtil.getMeta().getRom());
} catch (JSONException e) {
e.printStackTrace();

View File

@ -33,7 +33,6 @@ import com.lightgame.utils.Utils
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.*
import java.util.HashMap
import java.util.Locale
import java.util.concurrent.Executors
import kotlin.collections.ArrayList
import kotlin.collections.HashSet
@ -289,22 +288,12 @@ object PackageHelper {
* 用户是否已经使用另类方式获取已安装应用列表
*/
private fun isUseAlternativeWayToGetInstalledPackages(): Boolean {
if (isBuggyHuaweiDevice()) {
useAlternativeWayToGetInstalledPackages = false
return false
}
return useAlternativeWayToGetInstalledPackages
|| (SPUtils.getBoolean(SP_GET_INSTALLED_PACKAGES_BY_ALTERNATIVE_API)
.also { useAlternativeWayToGetInstalledPackages = it })
}
private fun updateUseAlternativeWayToGetInstalledPackages() {
if (isBuggyHuaweiDevice()) {
useAlternativeWayToGetInstalledPackages = false
return
}
// 启用另类获取已安装应用列表的 API
useAlternativeWayToGetInstalledPackages = true
SPUtils.setBoolean(SP_GET_INSTALLED_PACKAGES_BY_ALTERNATIVE_API, true)
@ -489,12 +478,7 @@ object PackageHelper {
/**
* 是否支持动态获取已安装应用列表权限
*/
private fun isSupportGetInstalledAppsPermission(context: Context): Boolean {
if (isBuggyHuaweiDevice()) {
// 华为系 Android 10 设备存在 bug调用过多可能会触发 DeadSystemException
return false
}
fun isSupportGetInstalledAppsPermission(context: Context): Boolean {
if (isUseAlternativeWayToGetInstalledPackages()) {
// 已经使用另类获取已安装应用列表形式,强制判定为不支持动态获取已安装应用列表权限
return false
@ -805,13 +789,4 @@ object PackageHelper {
return packageList
}
private fun isBuggyHuaweiDevice(): Boolean {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
val manufacturer = Build.MANUFACTURER.lowercase(Locale.CHINA) ?: ""
return manufacturer == "huawei" || manufacturer == "honor"
} else {
return false
}
}
}

View File

@ -37,7 +37,7 @@ public class PostCommentUtils {
device.put("model", Build.MODEL);
device.put("manufacturer", Build.MANUFACTURER);
device.put("android_version", android.os.Build.VERSION.RELEASE);
device.put("rom", MetaUtil.INSTANCE.getRom().getRomName() + " " + MetaUtil.INSTANCE.getRom().getRomVersion());
device.put("rom", MetaUtil.INSTANCE.getRom().name() + " " + MetaUtil.INSTANCE.getRom().getVersionName());
content.put("device", device);
} catch (Exception e) {
e.printStackTrace();

View File

@ -9,14 +9,15 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.gh.common.constant.Config
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.entity.NewApiSettingsEntity
import com.lightgame.utils.Utils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.enlargeTouchArea
import com.gh.gamecenter.common.utils.setDrawableEnd
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.entity.NewApiSettingsEntity
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
/**
* 处理厂商纯净/安全模式的辅助类
@ -312,11 +313,9 @@ object PureModeHelper {
intent.setPackage("com.huawei.security.privacycenter")
intent.setAction("com.huawei.securitycenter.PURE_MODE_ACTIVITY")
intent.putExtra("intent_from_settings", true)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
HaloApp.getInstance().startActivity(intent)
context.startActivity(intent)
} catch (_: Exception) {
toSystemSettings(context)
}
}

View File

@ -9,11 +9,7 @@ import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.exposure.meta.MetaUtil
import com.gh.gamecenter.common.exposure.meta.MetaUtil.getMeta
import com.gh.gamecenter.common.loghub.LoghubUtils
import com.gh.gamecenter.common.utils.DeviceUtils
import com.gh.gamecenter.common.utils.asVGame
import com.gh.gamecenter.common.utils.getExtension
import com.gh.gamecenter.common.utils.getMetaExtra
import com.gh.gamecenter.common.utils.isSimulatorGame
import com.gh.gamecenter.common.utils.*
import com.gh.ndownload.NDataChanger
import com.gh.ndownload.NDownloadBridge
import com.halo.assistant.HaloApp
@ -431,7 +427,6 @@ object DownloadDataHelper {
metaObject.put("channel", meta.channel)
metaObject.put("gid", meta.gid)
metaObject.put("oaid", meta.oaid)
metaObject.put("rom", meta.rom)
metaObject.put("manufacturer", meta.manufacturer)
metaObject.put("model", meta.model)
metaObject.put("network", DeviceUtils.getNetwork(context))

View File

@ -3,6 +3,9 @@ package com.gh.download
import android.annotation.SuppressLint
import android.text.TextUtils
import com.gh.common.util.*
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.PackageInstaller
import com.gh.common.util.PackageUtils
import com.gh.common.xapk.XapkInstaller
import com.gh.download.server.BrowserInstallHelper
import com.gh.gamecenter.common.constant.Constants
@ -30,7 +33,9 @@ import com.lightgame.download.DownloadEntity
import com.lightgame.utils.Utils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONException
import org.json.JSONObject

View File

@ -7,7 +7,6 @@ import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.common.DefaultUrlHandler
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.loadDataCompat
import com.gh.gamecenter.databinding.DownloadDialogInstructionItemBinding
class DownloadDialogInstructionItemViewHolder(val binding: DownloadDialogInstructionItemBinding) :
@ -15,8 +14,11 @@ class DownloadDialogInstructionItemViewHolder(val binding: DownloadDialogInstruc
fun bindItem(listData: List<DownloadDialogItemData>, position: Int, entrance: String) {
val instruction = listData[position].instruction
binding.webView.loadDataCompat(
binding.webView.loadDataWithBaseURL(
null,
"<body style='margin:0;padding:0;color:#666666;font-size:12px;line-height:18px;'>$instruction</body>",
"text/html",
"utf-8", null
)
binding.webView.settings
binding.webView.setBackgroundColor(Color.TRANSPARENT)

View File

@ -9,7 +9,6 @@ import androidx.fragment.app.FragmentActivity
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.common.utils.loadDataCompat
import com.gh.gamecenter.databinding.DialogDownloadLinkBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.halo.assistant.HaloApp
@ -28,7 +27,10 @@ class DownloadLinkDialog : BaseDialogFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val binding: DialogDownloadLinkBinding = DialogDownloadLinkBinding.inflate(layoutInflater, container, false)
binding.title.text = mLinkEntity?.title
binding.webView.loadDataCompat(mLinkEntity?.content ?: "")
binding.webView.loadDataWithBaseURL(
null,
mLinkEntity?.content ?: "", "text/html", "utf-8", null
)
binding.confirm.setOnClickListener {
dismissAllowingStateLoss()

View File

@ -886,7 +886,7 @@ class GameDetailViewModel(
params["source"] = HaloApp.getInstance().application.getString(R.string.app_name)
params["jnfj"] = MetaUtil.getBase64EncodedIMEI()
params["manufacturer"] = Build.MANUFACTURER
params["rom"] = MetaUtil.getRom().romName + " " + MetaUtil.getRom().romVersion
params["rom"] = MetaUtil.getRom().name + " " + MetaUtil.getRom().versionName
params["suggestion_type"] = "游戏求更新"
params["game_id"] = game?.id ?: ""

View File

@ -815,10 +815,7 @@ class GameDetailWrapperFragment : BaseLazyFragment(), IScrollable {
downloadStatus = gameEntity?.downloadStatusChinese ?: "",
gameType = gameEntity?.categoryChinese ?: "",
position = position,
tabContent = tabEntity.name,
linkType = tabEntity.link?.type ?: "",
linkId = tabEntity.link?.link ?: "",
linkText = tabEntity.link?.text ?: ""
tabContent = tabEntity.name
)
val entrance = if (mEntrance.contains("论坛详情")) "论坛" else "游戏"

View File

@ -7,7 +7,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import android.widget.LinearLayout
import androidx.core.view.forEach
import androidx.core.view.children
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.RecyclerView
@ -117,7 +117,7 @@ class GameLibaoAdapter(
binding.horizontalScrollView.goneIf(libaoEntity.materials.isEmpty()) {
if (binding.imagesContainer.tag == libaoEntity.id) {
binding.imagesContainer.forEach { view ->
binding.imagesContainer.children.forEach { view ->
if (view is SimpleDraweeView) {
view.hierarchy.roundingParams = RoundingParams().apply {
setCornersRadius(4F.dip2px().toFloat())

View File

@ -541,7 +541,7 @@ class RatingEditActivity : ToolBarActivity(), KeyboardHeightObserver {
jsonObject.put("game_version", gameVersion)
jsonObject.put("source", if (mFromAmway) "anliwall" else "game_detail")
jsonObject.put("plugin_version", PackageUtils.getMetaData(this, mInstallPackageName, "gh_version"))
jsonObject.put("rom", MetaUtil.getRom().romName + " " + MetaUtil.getRom().romVersion)
jsonObject.put("rom", MetaUtil.getRom().name + " " + MetaUtil.getRom().versionName)
jsonObject.put("again", again)
val body = jsonObject.toString().toRequestBody("application/json".toMediaTypeOrNull())

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

@ -6,7 +6,6 @@ import androidx.recyclerview.widget.DiffUtil.ItemCallback
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.debounceActionWithInterval
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.view.Chips
import com.gh.gamecenter.databinding.ItemColumnCollectionCustomTabBinding
@ -31,10 +30,8 @@ class CustomTabFollowAdapter(private val viewModel: ColumnCollectionTabViewModel
endIcon.setImageResource(R.drawable.ic_basic_x_8_secondary)
endIcon.imageTintList = null
setOnClickListener {
debounceActionWithInterval(500) {
if (!isForbidden) {
viewModel?.addMore(subjectData)
}
if (!isForbidden) {
viewModel?.addMore(subjectData)
}
}
}

View File

@ -6,7 +6,6 @@ import androidx.recyclerview.widget.DiffUtil.ItemCallback
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.debounceActionWithInterval
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.view.Chips
import com.gh.gamecenter.databinding.ItemColumnCollectionCustomTabBinding
@ -27,9 +26,7 @@ class CustomTabMoreAdapter(private val viewModel: ColumnCollectionTabViewModel?)
startIcon.setImageResource(R.drawable.ic_auxiliary_plus_secondary_8)
startIcon.imageTintList = null
setOnClickListener {
debounceActionWithInterval(500) {
viewModel?.addFollow(subjectData)
}
viewModel?.addFollow(subjectData)
}
}
}

View File

@ -812,8 +812,6 @@ class SubjectTabFragment : ToolbarFragment() {
}
override fun onBackPressed(): Boolean {
if (!isAdded) return super.onBackPressed()
if (binding.settingGuideContainer.isVisible) {
binding.settingGuideContainer.performClick()
return true

View File

@ -118,8 +118,6 @@ class TabWrapperFragment: BaseTabWrapperFragment(), ISmartRefresh, ISmartRefresh
if (shouldShow && guide != null && guidePosition != -1) {
tabLayout?.post {
if (activity == null) return@post
val tabView = tabLayout?.getTabAt(guidePosition)?.view
if (tabView != null) {
if (!isDefaultCustomPageFragment() && priorityChain.isHandlerQueueEmpty()) {
@ -135,7 +133,7 @@ class TabWrapperFragment: BaseTabWrapperFragment(), ISmartRefresh, ISmartRefresh
} else {
multiTabGuideHandler.doPreProcess(
true,
activity,
requireActivity(),
mBaseHandler,
guide,
tabLayout,

View File

@ -243,7 +243,7 @@ class VFeedbackDialogFragment : BaseDialogFragment() {
"source" to HaloApp.getInstance().application.getString(R.string.app_name)
"jnfj" to MetaUtil.getBase64EncodedIMEI()
"manufacturer" to Build.MANUFACTURER
"rom" to MetaUtil.getRom().romName + " " + MetaUtil.getRom().romVersion
"rom" to MetaUtil.getRom().name + " " + MetaUtil.getRom().versionName
"suggestion_type" to "游戏问题"
"game_id" to game.id

View File

@ -152,7 +152,7 @@ class AccelerationUseCase {
"from" to "",
"game_id" to game.id,
"manufacturer" to Build.MANUFACTURER,
"rom" to MetaUtil.getRom().romName + " " + MetaUtil.getRom().romVersion,
"rom" to MetaUtil.getRom().name + " " + MetaUtil.getRom().versionName,
"suggestion_type" to "加速器失败",
"message" to "加速失败, 游戏ID: ${game.id}, 游戏名: ${game.name ?: ""}",
"log" to it

View File

@ -693,7 +693,7 @@ class WebFragment : LazyFragment(), IScrollable {
webview.loadUrl(mWebUrl)
}
} else {
webview.loadDataCompat(mWebUrl)
webview.loadDataWithBaseURL(null, mWebUrl, "text/html", "utf-8", null)
}
}
if (mIsHorizontalDispatcherEnabled) {

View File

@ -15,14 +15,9 @@ import com.tencent.vasdolly.helper.ChannelReaderUtil
class FlavorProviderImp : IFlavorProvider {
private var isInit = false
private val pendingEvent = arrayListOf<String>()
override fun init(application: Application, activity: Activity, activateRatio: Int) {
SMHelper.init(application, getChannelStr(application))
isInit = true
if (HaloApp.getInstance().isBrandNewInstall) {
logEvent("EVENT_ACTIVE")
SPUtils.setLong("TIME_OF_BRAND_NEW_INSTALL", System.currentTimeMillis() / 1000)
@ -36,8 +31,6 @@ class FlavorProviderImp : IFlavorProvider {
SPUtils.setBoolean("SHOULD_SEND_RETENTION_EVENT", false)
}
}
pendingEvent.forEach(SMHelper::onEvent)
pendingEvent.clear()
}
override fun getChannelStr(application: Application): String {
@ -50,11 +43,7 @@ class FlavorProviderImp : IFlavorProvider {
}
override fun logEvent(content: String) {
if (isInit) {
SMHelper.onEvent(content)
} else {
pendingEvent.add(content)
}
SMHelper.onEvent(content)
}
override fun logCoreEvent() {

View File

@ -7,8 +7,8 @@ ext {
targetSdkVersion = 30 // 升级targetSdkVersion到 34 时需要根据官方文档补全前台服务的权限类型。比如 NDownloadServiceKeepAliveService
// application info (每个大版本之间的 versionCode 增加 20)
versionCode = 1195
versionName = "5.42.5"
versionCode = 1210
versionName = "5.43.0"
applicationId = "com.gh.gamecenter"
applicationIdGat = "com.gh.gamecenter.intl"
@ -99,7 +99,7 @@ ext {
verifier = "1.0.6"
skeleton = "1.1.5"
mta = "6.8.0"
romChecker = "2.0.0"
romChecker = "1.0.3"
oss = "2.8.8"
desugarJdkLibs = "1.1.5"
toolargetool = "0.3.0"

View File

@ -39,7 +39,7 @@ class QaFeedbackViewModel(application: Application, private val contentId: Strin
map["source"] = HaloApp.getInstance().getString(R.string.app_name)
map["jnfj"] = getBase64EncodedIMEI()
map["manufacturer"] = Build.MANUFACTURER
map["rom"] = MetaUtil.getRom().romName + " " + MetaUtil.getRom().romVersion
map["rom"] = MetaUtil.getRom().name + " " + MetaUtil.getRom().versionName
val requestBody = map.toRequestBody()
RetrofitManager.getInstance().api

View File

@ -209,7 +209,7 @@ class SuggestViewModel(
"source" to getApplication<Application>().getString(R.string.app_name)
"jnfj" to getBase64EncodedIMEI()
"manufacturer" to Build.MANUFACTURER
"rom" to MetaUtil.getRom().romName + " " + MetaUtil.getRom().romVersion
"rom" to MetaUtil.getRom().name + " " + MetaUtil.getRom().versionName
"suggestion_type" to suggestType
"from" to contact
"contact_func" to contactType.value
@ -318,7 +318,7 @@ class SuggestViewModel(
"source" to getApplication<Application>().getString(R.string.app_name)
"jnfj" to getBase64EncodedIMEI()
"manufacturer" to Build.MANUFACTURER
"rom" to MetaUtil.getRom().romName + " " + MetaUtil.getRom().romVersion
"rom" to MetaUtil.getRom().name + " " + MetaUtil.getRom().versionName
"suggestion_type" to mSuggestType
"app_name" to appName
"owner_type" to copyrightIdentity

View File

@ -63,7 +63,7 @@ dependencies {
kapt "com.google.auto.service:auto-service:${autoServiceVersion}"
api "com.louiscad.splitties:splitties-views-dsl:${splitties}"
api "com.louiscad.splitties:splitties-views-dsl-constraintlayout:${splitties}"
api "com.lg:romchecker:${romChecker}"
api "com.github.nichbar:AndroidRomChecker:${romChecker}"
api "androidx.cardview:cardview:${cardView}"
api "com.google.android.material:material:${material}"
api "com.scwang.smartrefresh:SmartRefreshLayout:${smartRefreshLayout}"

View File

@ -33,6 +33,7 @@ object MetaUtil {
private var rom: Rom? = null
fun refreshMeta() {
val appProvider = TheRouter.get(IAppProvider::class.java)
val buildConfigProvider = TheRouter.get(IBuildConfigProvider::class.java)
val userManagerProvider = TheRouter.get(IUserManagerProvider::class.java)
@ -54,7 +55,7 @@ object MetaUtil {
exposureVersion = buildConfigProvider?.getExposureVersion(),
session_id = Tracker.sessionId,
launch_id = Tracker.launchId,
rom = getRom().romName + " " + getRom().romVersion
rom = ""
)
}
@ -67,13 +68,7 @@ object MetaUtil {
}
fun getRom(): Rom {
val appProvider = TheRouter.get(IAppProvider::class.java)
if (appProvider?.isUserAcceptPrivacyPolicy(HaloApp.getInstance()) == false) {
// 如果用户没有同意隐私政策,则返回一个默认的 Rom 对象
return Rom.create("unknown", "unknown", "unknown")
}
if (rom == null || rom?.romName == "unknown") {
if (rom == null) {
rom = RomIdentifier.getRom()
}
return rom!!

View File

@ -167,22 +167,20 @@ object TrackerLogger {
}
private fun getMeta(): JSONObject {
val meta = MetaUtil.getMeta()
val (_, _, model, manufacturer, _, _, android_version, network, _, gid, oaid, channel, appVersion, userId) = MetaUtil.getMeta()
val metaObject = JSONObject()
try {
metaObject.put("dia", getBase64EncodedAndroidId())
metaObject.put("android_version", meta.android_version)
metaObject.put("app_version", meta.appVersion)
metaObject.put("channel", meta.channel)
metaObject.put("gid", meta.gid)
metaObject.put("oaid", meta.oaid)
metaObject.put("rom", meta.rom)
metaObject.put("android_version", android_version)
metaObject.put("app_version", appVersion)
metaObject.put("channel", channel)
metaObject.put("gid", gid)
metaObject.put("oaid", oaid)
metaObject.put("jnfj", getBase64EncodedIMEI())
metaObject.put("manufacturer", meta.manufacturer)
metaObject.put("model", meta.model)
metaObject.put("network", meta.network)
metaObject.put("user_id", meta.userId)
metaObject.put("manufacturer", manufacturer)
metaObject.put("model", model)
metaObject.put("network", network)
metaObject.put("user_id", userId)
} catch (e: JSONException) {
e.printStackTrace()
}

View File

@ -1494,26 +1494,6 @@ fun WebView.enableForceDark(isDarkModeOn: Boolean) {
}
}
fun WebView.loadDataCompat(data: String, mimeType: String = "text/html", encoding: String = "utf-8") {
try {
this.loadDataWithBaseURL(
null,
data,
mimeType,
encoding,
null
)
} catch (e: NullPointerException) {
this.loadDataWithBaseURL(
"localhost",
data,
"text/html",
"utf-8",
null
)
}
}
/**
* WebView是否启用强制深色模式
*/

View File

@ -52,7 +52,7 @@ public class LogUtils {
metaObject.put("os", meta.getOs());
metaObject.put("userId", meta.getUserId());
metaObject.put("oaid", appProvider.getOaid());
metaObject.put("rom", meta.getRom());
} catch (JSONException e) {
e.printStackTrace();
}
@ -71,7 +71,6 @@ public class LogUtils {
metaObject.put("channel", meta.getChannel());
metaObject.put("gid", meta.getGid());
metaObject.put("oaid", meta.getOaid());
metaObject.put("rom", meta.getRom());
metaObject.put("jnfj", MetaUtil.getBase64EncodedIMEI());
metaObject.put("mac", meta.getMac());
metaObject.put("manufacturer", meta.getManufacturer());
@ -80,7 +79,7 @@ public class LogUtils {
metaObject.put("os", meta.getOs());
metaObject.put("user_id", meta.getUserId());
metaObject.put("oaid", appProvider.getOaid());
metaObject.put("rom", meta.getRom());
} catch (JSONException e) {
e.printStackTrace();
}
@ -133,7 +132,7 @@ public class LogUtils {
metaObject.put("os", meta.getOs());
metaObject.put("userId", meta.getUserId());
metaObject.put("oaid", meta.getOaid());
metaObject.put("rom", meta.getRom());
object.put("event", "SHARE");
object.put("meta", metaObject);
object.put("timestamp", System.currentTimeMillis() / 1000);

View File

@ -517,10 +517,7 @@ object SensorsBridge {
downloadStatus: String,
gameType: String,
position: Int,
tabContent: String,
linkType: String,
linkId: String,
linkText: String,
tabContent: String
) {
val json = json {
KEY_GAME_ID to gameId
@ -535,9 +532,6 @@ object SensorsBridge {
KEY_GAME_TYPE to gameType
KEY_POSITION to position
KEY_TAB_CONTENT to tabContent
KEY_LINK_TYPE to linkType
KEY_LINK_ID to linkId
KEY_LINK_TEXT to linkText
}
trackEvent(EVENT_GAME_DETAIL_PAGE_TAB_SELECT, json)

View File

@ -65,7 +65,6 @@ object AppExecutor {
val cachedScheduler by lazy { Schedulers.from(ioExecutor) }
val computationScheduler by lazy { Schedulers.from(heavyWeightIoExecutor) }
val logScheduler by lazy { Schedulers.from(logExecutor) }
class MainThreadExecutor : Executor {
private val mainThreadHandler = Handler(Looper.getMainLooper())

View File

@ -49,12 +49,7 @@ data class ExposureEvent(
eTrace: List<ExposureEvent>? = null,
event: ExposureType = ExposureType.EXPOSURE
) {
val currentActivity = try {
CurrentActivityHolder.getCurrentActivity()
} catch (e: Exception) {
// 捕获异常,避免在获取当前 Activity 时出现问题
null
}
val currentActivity = CurrentActivityHolder.getCurrentActivity()
val currentActivitySimpleName = if (currentActivity != null) currentActivity::class.simpleName else "unknown"
val businessId = if (currentActivity is IBusiness) currentActivity.getBusinessId() else null

View File

@ -72,7 +72,7 @@ class RecyclerViewExposureHelper(
init {
val disposable = collectExposureSubject
.throttleLatest(SAMPLE_RATE, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(AndroidSchedulers.mainThread())
.subscribe({
collectExposureData()
}, {

View File

@ -169,7 +169,7 @@ class Va : IVa {
LogConstants.KEY_MANUFACTURER to Build.MANUFACTURER,
LogConstants.KEY_MODEL to Build.MODEL,
LogConstants.KEY_NETWORK to (MetaUtil.getMeta().network ?: ""),
LogConstants.KEY_ROM to RomIdentifier.getRom().romName + " " + RomIdentifier.getRom().romVersion,
LogConstants.KEY_ROM to RomIdentifier.getRom().name + " " + RomIdentifier.getRom().versionName,
LogConstants.KEY_HOST_VERSION to hostVersion,
LogConstants.KEY_HOST_CHANNEL to hostChannel,
LogConstants.KEY_OAID to oaid,

2
vasdk

Submodule vasdk updated: 16201868dd...02d9241f8d