Merge remote-tracking branch 'origin/release' into dev
# Conflicts: # app/src/main/java/com/gh/gamecenter/search/viewmodel/SearchGameListViewModel.kt # dependencies.gradle # feature/floating-window/src/demo/java/com/gh/gamecenter/feedback/view/help/QaFeedbackDialogFragment.kt # vasdk
This commit is contained in:
@ -659,7 +659,8 @@
|
||||
android:name=".authorization.AuthorizationActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait">
|
||||
android:screenOrientation="portrait"
|
||||
android:taskAffinity=".auth">
|
||||
<intent-filter>
|
||||
<data android:scheme="ghzhushou_authorization" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
package com.gh.common.fragment
|
||||
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import java.lang.reflect.Field
|
||||
|
||||
fun FragmentManager.popBackStackAllowStateLoss() {
|
||||
popBackStackAllowStateLoss(-1, 0)
|
||||
}
|
||||
|
||||
fun FragmentManager.popBackStackAllowStateLoss(id: Int, flags: Int) {
|
||||
if (!isStateSaved) {
|
||||
popBackStack(id, flags)
|
||||
} else {
|
||||
hook { popBackStack(id, flags) }
|
||||
}
|
||||
}
|
||||
|
||||
fun FragmentManager.popBackStackAllowStateLoss(name: String?, flags: Int) {
|
||||
if (!isStateSaved) {
|
||||
popBackStack(name, flags)
|
||||
} else {
|
||||
hook { popBackStack(name, flags) }
|
||||
}
|
||||
}
|
||||
|
||||
fun FragmentManager.popBackStackImmediateAllowStateLoss() = popBackStackAllowStateLoss(-1, 0)
|
||||
|
||||
fun FragmentManager.popBackStackImmediateAllowStateLoss(id: Int, flags: Int) =
|
||||
if (!isStateSaved) {
|
||||
popBackStackImmediate(id, flags)
|
||||
} else {
|
||||
hook { popBackStackImmediate(id, flags) }
|
||||
}
|
||||
|
||||
fun FragmentManager.popBackStackImmediateAllowStateLoss(name: String?, flags: Int): Boolean =
|
||||
if (!isStateSaved) {
|
||||
popBackStackImmediate(name, flags)
|
||||
} else {
|
||||
hook { popBackStackImmediate(name, flags) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过反射将FragmentManager的mStateSaved和mStopped设为false,否则Activity在回调onSavedInstance以后,
|
||||
* 调用Fragment的popBackStack和popBackStackImmediate方法会触发“java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState”的异常。
|
||||
* @see <a href="https://sentry.shanqu.cc/organizations/lightgame/issues/418688/?project=22">Sentry-418688</a>
|
||||
*/
|
||||
private fun <T> FragmentManager.hook(callback: FragmentManager.() -> T): T {
|
||||
val mStateSavedField = getField(this::class.java,"mStateSaved")
|
||||
val stateSaved = mStateSavedField.get(this);
|
||||
mStateSavedField.set(this, false)
|
||||
val mStoppedField = getField(this::class.java,"mStopped")
|
||||
val stopped = mStateSavedField.get(this);
|
||||
mStoppedField.set(this, false)
|
||||
val result = callback.invoke(this)
|
||||
mStateSavedField.set(this, stateSaved)
|
||||
mStoppedField.set(this, stopped)
|
||||
return result
|
||||
}
|
||||
|
||||
@Throws(NoSuchFieldException::class)
|
||||
private fun getField(clazz: Class<*>, name: String): Field {
|
||||
var cls: Class<*>? = clazz
|
||||
while (cls != null) {
|
||||
try {
|
||||
val declaredField = cls.getDeclaredField(name)
|
||||
declaredField.isAccessible = true
|
||||
return declaredField
|
||||
} catch (e: NoSuchFieldException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
cls = cls.superclass
|
||||
}
|
||||
throw NoSuchFieldException()
|
||||
}
|
||||
@ -121,7 +121,7 @@ class DownloadButtonClickedProviderImpl : IDownloadButtonClickedProvider {
|
||||
"game_name", gameName,
|
||||
"game_type", gameTypeInChinese,
|
||||
"download_status", downloadStatusInChinese,
|
||||
"button_name", downloadButton.text,
|
||||
"button_name", text,
|
||||
"game_schema_type", gameSchemaType,
|
||||
"download_type", downloadType,
|
||||
"page_name", GlobalActivityManager.getCurrentPageEntity().pageName,
|
||||
|
||||
@ -139,6 +139,7 @@ public class DetailDownloadUtils {
|
||||
// 游戏包含多 APK 的情况
|
||||
viewHolder.getMultiVersionDownloadTv().setText("选择下载你的版本" + (TextUtils.isEmpty(downloadAddWord) ? "" : "-" + downloadAddWord));
|
||||
viewHolder.getMultiVersionDownloadTv().setVisibility(View.VISIBLE);
|
||||
viewHolder.getDownloadPb().setTag(com.gh.gamecenter.feature.R.string.download, viewHolder.getMultiVersionDownloadTv().getText());
|
||||
viewHolder.getDownloadPb().setText("");
|
||||
viewHolder.getDownloadPb().setButtonStyle(DownloadButton.ButtonStyle.NORMAL);
|
||||
DownloadEntity downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity);
|
||||
|
||||
@ -284,7 +284,12 @@ object PackageInstaller {
|
||||
installIntent.setDataAndType(uri, "application/vnd.android.package-archive")
|
||||
}
|
||||
|
||||
updateSystemInstallerIfAvailable(context, installIntent)
|
||||
// 优选系统的安装器(遇到 Exception 就回落到正常的安装器)
|
||||
try {
|
||||
updateSystemInstallerIfAvailable(context, installIntent)
|
||||
} catch (ignored: Exception) {
|
||||
// ignored
|
||||
}
|
||||
|
||||
InstallUtils.getInstance()
|
||||
.addInstall(PackageUtils.getPackageNameByPath(context, path))
|
||||
|
||||
@ -7,7 +7,7 @@ import com.gh.gamecenter.common.utils.isVGameDownloadInDualDownloadMode
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.entity.GameInstall
|
||||
import com.gh.gamecenter.packagehelper.PackageRepository
|
||||
import com.gh.gamecenter.manager.PackagesManager
|
||||
import com.gh.vspace.VHelper
|
||||
|
||||
object PackageLauncher {
|
||||
@ -91,7 +91,7 @@ object PackageLauncher {
|
||||
val gameInstall = if (gameEntity != null) {
|
||||
GameInstall.transformGameInstall(gameEntity, packageName)
|
||||
} else {
|
||||
PackageRepository.gameInstalled.find { it.packageName == packageName }
|
||||
PackagesManager.getInstalledList().find { it.packageName == packageName }
|
||||
}
|
||||
|
||||
if (gameInstall != null) {
|
||||
|
||||
@ -542,10 +542,8 @@ public class PackageUtils {
|
||||
try {
|
||||
Intent intent = context.getApplicationContext().getPackageManager().getLaunchIntentForPackage(packageName);
|
||||
return intent != null;
|
||||
} catch (IllegalArgumentException exception) {
|
||||
// 一些设备调用获取 intent 的时候会触发 Parcel.readException !
|
||||
exception.printStackTrace();
|
||||
return false;
|
||||
} catch (Exception exception) {
|
||||
return PackageHelper.INSTANCE.getLocalPackageNameSet().contains(packageName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1045,6 +1045,7 @@ public class MainActivity extends BaseActivity {
|
||||
blackList.add(R.id.historyTv);
|
||||
blackList.add(R.id.myCollectionTv);
|
||||
blackList.add(R.id.searchTv);
|
||||
blackList.add(R.id.subject_tab);
|
||||
updateStaticView(view, blackList);
|
||||
|
||||
View communityHomeWrapper = view.findViewById(R.id.communityHomeContainer);
|
||||
|
||||
@ -15,6 +15,7 @@ import androidx.core.widget.doAfterTextChanged
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import com.gh.common.fragment.popBackStackAllowStateLoss
|
||||
import com.gh.common.util.DataCollectionUtils
|
||||
import com.gh.common.util.LogUtils
|
||||
import com.gh.gamecenter.DisplayType.*
|
||||
@ -381,7 +382,7 @@ open class SearchActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
protected fun popBackToFragment(tag: String) {
|
||||
supportFragmentManager.popBackStack(tag, 0)
|
||||
supportFragmentManager.popBackStackAllowStateLoss(tag, 0)
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
|
||||
@ -242,10 +242,10 @@ class AuthorizationActivity : ToolBarActivity() {
|
||||
VHelper.launch(this, gamePkg, ignoreGApps = true, showLoading = showLoading)
|
||||
return
|
||||
}
|
||||
val remotePkgName = this.mRemotePkgName
|
||||
if (remotePkgName != null) {// 跳转回其他授权app
|
||||
startActivity(packageManager.getLaunchIntentForPackage(remotePkgName))
|
||||
}
|
||||
// val remotePkgName = this.mRemotePkgName
|
||||
// if (remotePkgName != null) {// 跳转回其他授权app
|
||||
// startActivity(packageManager.getLaunchIntentForPackage(remotePkgName))
|
||||
// }
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
|
||||
@ -18,7 +18,13 @@ data class SearchSubjectEntity(
|
||||
@SerializedName("ad_icon_active")
|
||||
val adIconActive: Boolean = false,
|
||||
// 本地字段,标记是否为微信小游戏CPM专题
|
||||
var isWGameSubjectCPM: Boolean = false
|
||||
var isWGameSubjectCPM: Boolean = false,
|
||||
val type: String = ""
|
||||
) : Parcelable {
|
||||
|
||||
companion object {
|
||||
const val TYPE_WECHAT_GAME_CPM_COLUMN = "wechat_game_cpm_column"
|
||||
}
|
||||
|
||||
fun getFilterGame() = RegionSettingHelper.filterGame(games)
|
||||
}
|
||||
@ -983,14 +983,17 @@ class DescAdapter(
|
||||
setExpandMaxLines(maxDesLines)
|
||||
setIsExpanded(Int.MAX_VALUE == maxDesLines)
|
||||
if (customColumn.isHtmlDes == true) {
|
||||
val decoratedDesBrief = (customColumn.desBrief ?: "").dropFontColorInDarkMode(contentTv.context)
|
||||
val decoratedDes = (customColumn.des ?: "").dropFontColorInDarkMode(contentTv.context)
|
||||
|
||||
shrankSpanned = HtmlCompat.fromHtml(
|
||||
customColumn.desBrief ?: "",
|
||||
decoratedDesBrief,
|
||||
HtmlCompat.FROM_HTML_MODE_COMPACT,
|
||||
PicassoImageGetter(contentTv),
|
||||
ExtraTagHandler()
|
||||
)
|
||||
expandedSpanned = HtmlCompat.fromHtml(
|
||||
customColumn.des ?: "",
|
||||
decoratedDes,
|
||||
HtmlCompat.FROM_HTML_MODE_COMPACT,
|
||||
PicassoImageGetter(contentTv),
|
||||
ExtraTagHandler()
|
||||
|
||||
@ -25,10 +25,10 @@ import com.gh.gamecenter.common.utils.toPx
|
||||
import com.gh.gamecenter.core.iinterface.IScrollable
|
||||
import com.gh.gamecenter.core.utils.MtaHelper
|
||||
import com.gh.gamecenter.core.utils.SpanBuilder
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.RatingComment
|
||||
import com.gh.gamecenter.eventbus.EBStar
|
||||
import com.gh.gamecenter.eventbus.EBTypeChange
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.gamedetail.GameDetailFragment
|
||||
import com.halo.assistant.HaloApp
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
@ -60,7 +60,7 @@ class RatingFragment : LazyListFragment<RatingComment, RatingViewModel>(), IScro
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == RATING_EDIT_REQUEST && resultCode == Activity.RESULT_OK) {
|
||||
mListViewModel.initData()
|
||||
mListViewModel?.initData()
|
||||
} else if (
|
||||
(requestCode == RATING_REPLAY_REQUEST || requestCode == RATING_PATCH_REQUEST)
|
||||
&& resultCode == Activity.RESULT_OK
|
||||
|
||||
@ -806,7 +806,7 @@ class CustomPageRepository private constructor(
|
||||
|
||||
fun loadChangeSubjectGame(subjectEntity: SubjectEntity): Observable<List<GameEntity>> =
|
||||
if (subjectEntity.isWechatColumnCPM) {// 微信小游戏CPM专题的“换一批”接口
|
||||
wGameSubjectCPMRemoteDataSource.getRecommendCPMList(2, 10).toObservable()
|
||||
wGameSubjectCPMRemoteDataSource.getEditorRecommendCPMList(2, 10).toObservable()
|
||||
} else {
|
||||
remoteDataSource.loadChangeSubjectGame(subjectEntity)
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ class CustomGameGallerySlideViewHolder(
|
||||
override fun bindView(item: CustomPageItem) {
|
||||
super.bindView(item)
|
||||
if (item is CustomSubjectItem) {
|
||||
|
||||
binding.cardView.setCardBackgroundColor(com.gh.gamecenter.common.R.color.ui_container_1.toColor(binding.root.context))
|
||||
if (item.data == cachedSubject) return
|
||||
|
||||
cachedSubject = item.data
|
||||
@ -77,7 +77,6 @@ class CustomGameGallerySlideViewHolder(
|
||||
val gameList = item.data.data ?: emptyList()
|
||||
(recyclerView.adapter as? GameGallerySlideAdapter)?.submitList(gameList)
|
||||
}
|
||||
binding.cardView.setCardBackgroundColor(com.gh.gamecenter.common.R.color.text_FAFAFA.toColor(binding.root.context))
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -26,6 +26,6 @@ class MiniGameSearchResultRepository(
|
||||
}
|
||||
|
||||
override fun getWGameCPMGameList(): Single<MutableList<GameEntity>> {
|
||||
return mWGameSubjectCPMDataSource.getRecommendCPMList(1)
|
||||
return mWGameSubjectCPMDataSource.getUserRecommendCPMList()
|
||||
}
|
||||
}
|
||||
@ -11,7 +11,7 @@ class WGameSubjectCPMListRepository(
|
||||
) : ISubjectListRepository {
|
||||
|
||||
override fun getColumn(column_id: String?, page: Int, sort: String?, order: String?): Single<MutableList<GameEntity>> {
|
||||
return dataSource.getRecommendCPMList(page)
|
||||
return dataSource.getEditorRecommendCPMList(page)
|
||||
}
|
||||
|
||||
override fun getColumnSettings(column_id: String?): Observable<SubjectSettingEntity> {
|
||||
|
||||
@ -14,7 +14,50 @@ class WGameSubjectCPMRemoteDataSource(
|
||||
private val api: WGameCPMApiService = RetrofitManager.getInstance().wGameCPMApi
|
||||
) {
|
||||
|
||||
fun getRecommendCPMList(page: Int, pageSize: Int = 10): Single<MutableList<GameEntity>> {
|
||||
fun getEditorRecommendCPMList(page: Int, pageSize: Int = 10): Single<MutableList<GameEntity>> {
|
||||
val meta = MetaUtil.getMeta()
|
||||
val request = mapOf(
|
||||
"head" to mapOf(
|
||||
"busiAppid" to Config.WGAME_CPM_BUSIAPPID,
|
||||
"oaid" to (meta.oaid ?: ""),
|
||||
"manufacturer" to (meta.manufacturer ?: ""),
|
||||
"mode" to (meta.model ?: ""),
|
||||
"androidId" to (MetaUtil.getAndroidId()),
|
||||
"imei" to (MetaUtil.getIMEI())
|
||||
),
|
||||
"body" to mapOf(
|
||||
"page" to page - 1,
|
||||
"pageSize" to pageSize,
|
||||
)
|
||||
)
|
||||
return api.getEditorRecommendList(request.toRequestBody())
|
||||
.map {
|
||||
if (it.ret == 0) {
|
||||
it.appInfoList.map { info ->
|
||||
GameEntity(
|
||||
mName = info.appName,
|
||||
mIcon = info.logo,
|
||||
mBrief = info.briefIntro,
|
||||
miniGameUid = info.appID,
|
||||
miniGameAppId = info.userName,
|
||||
miniGameType = Constants.WECHAT_MINI_GAME_CPM,
|
||||
miniGameAppStatus = 2,
|
||||
miniGameAppPath = info.wechatAppPath,
|
||||
miniGameExtData = info.extData,
|
||||
miniGameRecommendId = info.recommendID,
|
||||
mTagStyle = arrayListOf(
|
||||
TagStyleEntity(name = info.categoryName),
|
||||
TagStyleEntity(name = info.subcategoryName)
|
||||
)
|
||||
)
|
||||
}.toMutableList()
|
||||
} else {
|
||||
mutableListOf()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getUserRecommendCPMList(page: Int = 1, pageSize: Int = 10): Single<MutableList<GameEntity>> {
|
||||
val meta = MetaUtil.getMeta()
|
||||
val request = mapOf(
|
||||
"head" to mapOf(
|
||||
|
||||
@ -108,6 +108,7 @@ class SearchGameResultAdapter(
|
||||
return when {
|
||||
oldItem?.subject != null && newItem?.subject != null -> {
|
||||
oldItem.subject.columnId == newItem.subject.columnId
|
||||
&& oldItem.subject.games == newItem.subject.games
|
||||
}
|
||||
|
||||
oldItem?.game != null && newItem?.game != null -> {
|
||||
@ -122,6 +123,7 @@ class SearchGameResultAdapter(
|
||||
return when {
|
||||
oldItem?.subject != null && newItem?.subject != null -> {
|
||||
oldItem.subject.columnId == newItem.subject.columnId
|
||||
&& oldItem.subject.games == newItem.subject.games
|
||||
}
|
||||
|
||||
oldItem?.game != null && newItem?.game != null -> {
|
||||
@ -170,39 +172,50 @@ class SearchGameResultAdapter(
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is SearchSubjectItemViewHolder -> {
|
||||
holder.binding.run {
|
||||
when {
|
||||
position == 0 -> topDivider.visibility = View.GONE
|
||||
position > 0 -> {
|
||||
val gameEntity = mEntityList[position - 1].game
|
||||
if (gameEntity != null) {
|
||||
val isShowTag = gameEntity.contentTag != null
|
||||
&& (gameEntity.contentTag!!.custom.isNotEmpty()
|
||||
|| gameEntity.contentTag!!.zone.link.isNotEmpty()
|
||||
|| gameEntity.contentTag!!.isLibaoExists
|
||||
|| gameEntity.contentTag!!.server)
|
||||
val isShowTagByMirror =
|
||||
if (gameEntity.shouldUseMirrorInfo()) isShowTag && gameEntity.obtainMirrorData()?.contentTagStatus == "on" else isShowTag
|
||||
if (isShowTagByMirror) {
|
||||
topDivider.visibility = View.GONE
|
||||
val itemData = mEntityList[position]
|
||||
if (itemData.subject == null || itemData.subject.games.isEmpty()) {
|
||||
holder.binding.topDivider.visibility = View.GONE
|
||||
holder.binding.bottomDivider.visibility = View.GONE
|
||||
holder.binding.headContainer.root.visibility = View.GONE
|
||||
holder.binding.subjectRv.visibility = View.GONE
|
||||
} else {
|
||||
holder.binding.headContainer.root.visibility = View.VISIBLE
|
||||
holder.binding.subjectRv.visibility = View.VISIBLE
|
||||
|
||||
holder.binding.run {
|
||||
when {
|
||||
position == 0 -> topDivider.visibility = View.GONE
|
||||
position > 0 -> {
|
||||
val gameEntity = mEntityList[position - 1].game
|
||||
if (gameEntity != null) {
|
||||
val isShowTag = gameEntity.contentTag != null
|
||||
&& (gameEntity.contentTag!!.custom.isNotEmpty()
|
||||
|| gameEntity.contentTag!!.zone.link.isNotEmpty()
|
||||
|| gameEntity.contentTag!!.isLibaoExists
|
||||
|| gameEntity.contentTag!!.server)
|
||||
val isShowTagByMirror =
|
||||
if (gameEntity.shouldUseMirrorInfo()) isShowTag && gameEntity.obtainMirrorData()?.contentTagStatus == "on" else isShowTag
|
||||
if (isShowTagByMirror) {
|
||||
topDivider.visibility = View.GONE
|
||||
} else {
|
||||
topDivider.visibility = View.VISIBLE
|
||||
}
|
||||
} else {
|
||||
topDivider.visibility = View.VISIBLE
|
||||
topDivider.visibility = View.GONE
|
||||
}
|
||||
} else {
|
||||
topDivider.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
bottomDivider.visibility = View.VISIBLE
|
||||
}
|
||||
bottomDivider.visibility = View.VISIBLE
|
||||
holder.bindSubjectItem(
|
||||
mContext,
|
||||
itemData,
|
||||
SearchType.fromString(type).toChinese(),
|
||||
key,
|
||||
dao,
|
||||
sourceEntrance = sourceEntrance
|
||||
)
|
||||
}
|
||||
holder.bindSubjectItem(
|
||||
mContext,
|
||||
mEntityList[position],
|
||||
SearchType.fromString(type).toChinese(),
|
||||
key,
|
||||
dao,
|
||||
sourceEntrance = sourceEntrance
|
||||
)
|
||||
}
|
||||
|
||||
is SearchGameFirstItemViewHolder -> {
|
||||
|
||||
@ -36,6 +36,6 @@ class SearchGameResultRepository(
|
||||
}
|
||||
|
||||
override fun getWGameCPMGameList(): Single<MutableList<GameEntity>> {
|
||||
return mWGameSubjectCPMDataSource.getRecommendCPMList(1)
|
||||
return mWGameSubjectCPMDataSource.getUserRecommendCPMList()
|
||||
}
|
||||
}
|
||||
@ -76,40 +76,39 @@ class SearchGameResultViewModel(
|
||||
refreshWrongInstallStatus()
|
||||
|
||||
repository.getSearchSubject(mSearchKey, mPage)
|
||||
.map { dataList ->
|
||||
mSearchSubjects.addAll(dataList)
|
||||
var cpmSearchSubject: SearchSubjectEntity? = null
|
||||
mSearchSubjects.forEach {
|
||||
// 微信小游戏CPM专题需要等搜索广告位插入完成后再插入
|
||||
if (it.location == WGAME_CPM_SUBJECT_POSITION) {
|
||||
cpmSearchSubject = it.apply { isWGameSubjectCPM = true }
|
||||
} else {
|
||||
val item = SearchItemData(subject = it)
|
||||
if (it.location <= 0 || it.location > itemDataList.size) {
|
||||
itemDataList.add(item)
|
||||
} else {
|
||||
itemDataList.add(it.location - 1, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
cpmSearchSubject to dataList
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ result ->
|
||||
.subscribe({ mutableList ->
|
||||
val cpmSearchSubjects = mutableListOf<SearchSubjectEntity>()
|
||||
mSearchSubjects.addAll(mutableList)
|
||||
mSearchSubjects.forEach {
|
||||
if (it.type == SearchSubjectEntity.TYPE_WECHAT_GAME_CPM_COLUMN) {
|
||||
cpmSearchSubjects.add(it.apply { isWGameSubjectCPM = true })
|
||||
}
|
||||
val item = SearchItemData(subject = it)
|
||||
if (it.location <= 0 || it.location > itemDataList.size) {
|
||||
itemDataList.add(item)
|
||||
} else {
|
||||
itemDataList.add(it.location - 1, item)
|
||||
}
|
||||
}
|
||||
// 处理初始化列表且游戏列表size为0的情况
|
||||
handleLoadStatusWhenGameListIsEmpty(list, itemDataList)
|
||||
|
||||
if (mIsManuallySearch) {
|
||||
if (mSearchKey == AdDelegateHelper.gameSearchKeyword) {
|
||||
updateAdConfigAndDecorateList(itemDataList, list, result.first)
|
||||
updateAdConfigAndDecorateList(itemDataList, list)
|
||||
} else {
|
||||
AdDelegateHelper.requestAdConfig(false, mSearchKey ?: "") {
|
||||
updateAdConfigAndDecorateList(itemDataList, list, result.first)
|
||||
updateAdConfigAndDecorateList(itemDataList, list)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
decorateWithWGameSubjectCPM(itemDataList, list, result.first)
|
||||
postResultList(itemDataList, list)
|
||||
}
|
||||
|
||||
if (cpmSearchSubjects.isNotEmpty()) {
|
||||
decorateListWithWGameCPM(cpmSearchSubjects, itemDataList, list)
|
||||
}
|
||||
}, {
|
||||
it.printStackTrace()
|
||||
@ -118,12 +117,50 @@ class SearchGameResultViewModel(
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求微信小游戏CPM接口获取专题游戏数据,并插入对应的专题项中,相关需求如下:
|
||||
* @see <a href="https://jira.shanqu.cc/browse/GHZSCY-6710">【光环助手】CPM微信小游戏API接入工作</a>
|
||||
* @see <a href="https://jira.shanqu.cc/browse/GHZSCY-6827">【光环助手】CPM微信小游戏一期优化</a>
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
private fun updateAdConfigAndDecorateList(
|
||||
private fun decorateListWithWGameCPM(
|
||||
subjects: List<SearchSubjectEntity>,
|
||||
itemDataList: ArrayList<SearchItemData>,
|
||||
list: MutableList<GameEntity>,
|
||||
cpmSubjectEntity: SearchSubjectEntity?
|
||||
list: MutableList<GameEntity>
|
||||
) {
|
||||
val subjectList = subjects.filterNot {
|
||||
it.games.isNotEmpty()
|
||||
}
|
||||
if (subjectList.isEmpty()) return
|
||||
val subjectSingleList = subjectList.map { subject ->
|
||||
repository.getWGameCPMGameList()
|
||||
.onErrorReturnItem(mutableListOf())
|
||||
.map { subject.columnId to it }
|
||||
}
|
||||
Single.zip(subjectSingleList) { it.map { item -> item as Pair<String, MutableList<GameEntity>> } }
|
||||
.map { dataList ->
|
||||
for (index in itemDataList.indices) {
|
||||
val itemData = itemDataList[index]
|
||||
val subject = itemData.subject ?: continue
|
||||
if (subject.games.isNotEmpty()) continue
|
||||
val pair = dataList.firstOrNull { data ->
|
||||
data.first == subject.columnId
|
||||
} ?: continue
|
||||
val newItemData = SearchItemData(
|
||||
subject = subject.copy(games = pair.second)
|
||||
)
|
||||
itemDataList[index] = newItemData
|
||||
}
|
||||
itemDataList
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ dataList -> postResultList(dataList, list) }, {})
|
||||
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun updateAdConfigAndDecorateList(itemDataList: ArrayList<SearchItemData>, list: MutableList<GameEntity>) {
|
||||
mGameSearchAdList =
|
||||
AdDelegateHelper.getGameSearchAdList().filter { AdDelegateHelper.shouldShowGameSearchAd(it) }.toArrayList()
|
||||
.apply { sortBy { it.position } }
|
||||
@ -137,7 +174,6 @@ class SearchGameResultViewModel(
|
||||
mAdPositionSet = adPositionSet
|
||||
|
||||
if (adPositionSet.isNotEmpty()) {
|
||||
val decoratedItemDataList = ArrayList(itemDataList)
|
||||
val ownerAdList = arrayListOf<AdConfig>()
|
||||
val thirdPartyAdList = arrayListOf<AdConfig>()
|
||||
|
||||
@ -175,18 +211,18 @@ class SearchGameResultViewModel(
|
||||
Single.zip(requestSingleList) {}
|
||||
.compose(singleToMain())
|
||||
.subscribe({
|
||||
decorateListWithAd(itemDataList, decoratedItemDataList, list, cpmSubjectEntity)
|
||||
decorateListWithAd(itemDataList, list)
|
||||
}, {
|
||||
decorateListWithAd(itemDataList, decoratedItemDataList, list, cpmSubjectEntity)
|
||||
decorateListWithAd(itemDataList, list)
|
||||
})
|
||||
} else {
|
||||
decorateListWithAd(itemDataList, decoratedItemDataList, list, cpmSubjectEntity)
|
||||
decorateListWithAd(itemDataList, list)
|
||||
}
|
||||
} else {
|
||||
decorateListWithThirdPartyAdOnly(decoratedItemDataList, thirdPartyAdList, list, cpmSubjectEntity)
|
||||
decorateListWithThirdPartyAdOnly(itemDataList, thirdPartyAdList, list)
|
||||
}
|
||||
} else {
|
||||
decorateWithWGameSubjectCPM(itemDataList, list, cpmSubjectEntity)
|
||||
postResultList(itemDataList, list)
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,27 +233,25 @@ class SearchGameResultViewModel(
|
||||
}
|
||||
|
||||
private fun decorateListWithThirdPartyAdOnly(
|
||||
decoratedItemDataList: ArrayList<SearchItemData>,
|
||||
itemDataList: ArrayList<SearchItemData>,
|
||||
thirdPartyAdList: List<AdConfig>,
|
||||
list: List<GameEntity>,
|
||||
cpmSubjectEntity: SearchSubjectEntity?
|
||||
list: List<GameEntity>
|
||||
) {
|
||||
thirdPartyAdList.forEach {
|
||||
decoratedItemDataList.add(it.position - 1, SearchItemData(ad = it.thirdPartyAd, adConfig = it))
|
||||
itemDataList.add(it.position - 1, SearchItemData(ad = it.thirdPartyAd, adConfig = it))
|
||||
SPUtils.setLong(Constants.SP_LAST_GAME_SEARCH_AD_SHOW_TIME + it.position, System.currentTimeMillis())
|
||||
}
|
||||
decorateWithWGameSubjectCPM(decoratedItemDataList, list, cpmSubjectEntity)
|
||||
postResultList(itemDataList, list)
|
||||
}
|
||||
|
||||
private fun decorateListWithAd(
|
||||
itemDataList: ArrayList<SearchItemData>,
|
||||
decoratedItemDataList: ArrayList<SearchItemData>,
|
||||
list: List<GameEntity>,
|
||||
cpmSubjectEntity: SearchSubjectEntity?
|
||||
list: List<GameEntity>
|
||||
) {
|
||||
val adGameOneIdSet = HashSet<String>() // 展示样式为单个游戏时记录游戏ID,避免重复
|
||||
val decoratedItemDataSize = itemDataList.size
|
||||
for ((index, position) in mAdPositionSet!!.withIndex()) {
|
||||
if (position < itemDataList.size + index + 1) {
|
||||
if (position < decoratedItemDataSize + index + 1) {
|
||||
val adConfig = mGameSearchAdList!!.safelyGetInRelease(index)
|
||||
val showThirdPartyAd = adConfig?.displayRule?.adSource == AdDelegateHelper.AD_TYPE_SDK
|
||||
val showOwnerAd = adConfig?.displayRule?.adSource == AdDelegateHelper.AD_TYPE_OWNER
|
||||
@ -225,7 +259,7 @@ class SearchGameResultViewModel(
|
||||
if ((showThirdPartyAd && adConfig?.thirdPartyAd != null)
|
||||
|| (showOwnerAd && adConfig?.ownerAd == null && adConfig?.thirdPartyAd != null && showOnFailed)
|
||||
) {
|
||||
decoratedItemDataList.add(position - 1, SearchItemData(ad = adConfig.thirdPartyAd, adConfig = adConfig))
|
||||
itemDataList.add(position - 1, SearchItemData(ad = adConfig.thirdPartyAd, adConfig = adConfig))
|
||||
SPUtils.setLong(
|
||||
Constants.SP_LAST_GAME_SEARCH_AD_SHOW_TIME + adConfig.position,
|
||||
System.currentTimeMillis()
|
||||
@ -237,7 +271,7 @@ class SearchGameResultViewModel(
|
||||
if (!gameList.isNullOrEmpty()) {
|
||||
if (adConfig.ownerAd.adSource?.displayStyle == "game_zone") {
|
||||
// 游戏专题
|
||||
decoratedItemDataList.add(
|
||||
itemDataList.add(
|
||||
position - 1,
|
||||
SearchItemData(
|
||||
subject = SearchSubjectEntity(
|
||||
@ -259,7 +293,7 @@ class SearchGameResultViewModel(
|
||||
}
|
||||
randomGameEntity?.id?.let { adGameOneIdSet.add(it) }
|
||||
|
||||
decoratedItemDataList.add(
|
||||
itemDataList.add(
|
||||
position - 1,
|
||||
SearchItemData(game = randomGameEntity, adConfig = adConfig)
|
||||
)
|
||||
@ -270,7 +304,7 @@ class SearchGameResultViewModel(
|
||||
)
|
||||
} else if (showOnFailed && adConfig.thirdPartyAd != null) {
|
||||
// 自有广告为空时,显示第三方广告
|
||||
decoratedItemDataList.add(position - 1, SearchItemData(ad = adConfig.thirdPartyAd, adConfig = adConfig))
|
||||
itemDataList.add(position - 1, SearchItemData(ad = adConfig.thirdPartyAd, adConfig = adConfig))
|
||||
SPUtils.setLong(
|
||||
Constants.SP_LAST_GAME_SEARCH_AD_SHOW_TIME + adConfig.position,
|
||||
System.currentTimeMillis()
|
||||
@ -281,41 +315,7 @@ class SearchGameResultViewModel(
|
||||
break
|
||||
}
|
||||
}
|
||||
decorateWithWGameSubjectCPM(decoratedItemDataList, list, cpmSubjectEntity)
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun decorateWithWGameSubjectCPM(
|
||||
resultList: ArrayList<SearchItemData>,
|
||||
list: List<GameEntity>,
|
||||
cpmSubjectEntity: SearchSubjectEntity?
|
||||
) {
|
||||
// 微信小游戏CPM专题搜索结果存在,则请求CPM接口获取微信小游戏列表数据,并将列表数据插入缓存的CPM专题中,
|
||||
// 再根据location的值(固定为4)将CPM专题插入搜索结果列表中
|
||||
// 相关需求:https://jira.shanqu.cc/browse/GHZSCY-6710
|
||||
cpmSubjectEntity?.let { subject ->
|
||||
if (subject.games.isNotEmpty()) {
|
||||
Single.just(subject.games.toMutableList())
|
||||
} else {
|
||||
repository.getWGameCPMGameList()
|
||||
.onErrorReturnItem(mutableListOf())
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{
|
||||
val cpmSearchItemData = SearchItemData(subject = subject.apply { games = it })
|
||||
if (subject.location <= 0 || subject.location > resultList.size) {
|
||||
resultList.add(cpmSearchItemData)
|
||||
} else {
|
||||
resultList.add(subject.location - 1, cpmSearchItemData)
|
||||
}
|
||||
postResultList(resultList, list)
|
||||
},
|
||||
{
|
||||
postResultList(resultList, list)
|
||||
})
|
||||
} ?: postResultList(resultList, list)
|
||||
postResultList(itemDataList, list)
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
@ -343,7 +343,7 @@ class SearchGameResultViewModel(
|
||||
}
|
||||
|
||||
private fun postResultList(resultList: ArrayList<SearchItemData>, list: List<GameEntity>) {
|
||||
mResultLiveData.postValue(resultList)
|
||||
mResultLiveData.postValue(resultList.toMutableList())
|
||||
if (mPage == 1) {
|
||||
if (repository is MiniGameSearchResultRepository) {
|
||||
SensorsBridge.trackMiniGameSearchResultReturn(
|
||||
@ -362,7 +362,6 @@ class SearchGameResultViewModel(
|
||||
mSearchKey ?: "",
|
||||
SearchActivity.toTrackSearchType(mSearchType),
|
||||
list.isNotEmpty()
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
@ -431,7 +430,6 @@ class SearchGameResultViewModel(
|
||||
|
||||
companion object {
|
||||
const val AD_SUBJECT_GAME_MAX_COUNT = 8
|
||||
const val WGAME_CPM_SUBJECT_POSITION = 4
|
||||
}
|
||||
|
||||
}
|
||||
@ -9,6 +9,7 @@ import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.clearHtmlFormatCompletely
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageData
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
@ -153,7 +154,7 @@ class SearchGameListViewModel : ViewModel() {
|
||||
SearchActivity.toTrackSearchType(type),
|
||||
location,
|
||||
collection.id,
|
||||
collection.title,
|
||||
collection.title.clearHtmlFormatCompletely(),
|
||||
position
|
||||
)
|
||||
}
|
||||
|
||||
@ -102,6 +102,7 @@ abstract class BaseTabWrapperFragment : BaseLazyFragment(), IMultiTab {
|
||||
noDataStub = mCachedView.findViewById(R.id.reuse_no_data_stub)
|
||||
noConnectionStub = mCachedView.findViewById(R.id.reuse_no_connection_stub)
|
||||
loadingStub = mCachedView.findViewById(R.id.reuse_loading_stub)
|
||||
showLoading(true)
|
||||
|
||||
backgroundColor = com.gh.gamecenter.common.R.color.ui_background.toColor(requireContext())
|
||||
backgroundWhiteColor = com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext())
|
||||
|
||||
@ -61,6 +61,7 @@ import com.gh.gamecenter.eventbus.EBPackage
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.feature.exposure.time.TimeUtil
|
||||
import com.gh.gamecenter.feature.game.GameItemViewHolder
|
||||
import com.gh.gamecenter.feature.utils.SentryHelper
|
||||
import com.gh.gamecenter.gamecollection.square.GameCollectionSquareFragment
|
||||
import com.gh.gamecenter.home.custom.CustomPageFragment
|
||||
import com.gh.gamecenter.home.video.AutomaticVideoView
|
||||
@ -214,7 +215,16 @@ class SearchToolbarTabWrapperFragment : BaseTabWrapperFragment(), ISearchToolbar
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
binding = FragmentSearchToolbarTabWrapperBinding.inflate(layoutInflater)
|
||||
binding = try {
|
||||
FragmentSearchToolbarTabWrapperBinding.inflate(layoutInflater)
|
||||
} catch (e: Exception) {
|
||||
SentryHelper.onEvent("VIEW_BINDING_BIND_ERROR",
|
||||
"digest", e.localizedMessage,
|
||||
"gid", HaloApp.getInstance().gid
|
||||
)
|
||||
// 玄学,重试一次,该闪退闪退
|
||||
FragmentSearchToolbarTabWrapperBinding.inflate(layoutInflater)
|
||||
}
|
||||
mCachedView = binding.root
|
||||
return mCachedView
|
||||
}
|
||||
@ -966,6 +976,8 @@ class SearchToolbarTabWrapperFragment : BaseTabWrapperFragment(), ISearchToolbar
|
||||
}
|
||||
|
||||
override fun setPullDownPush(pullDownPush: PullDownPush?, pullDownPushHandler: PullDownPushHandler?) {
|
||||
if (!isAdded) return
|
||||
|
||||
if (autoVideoView == null) {
|
||||
binding.autoVideoViewStub.setOnInflateListener { _, inflated ->
|
||||
autoVideoView = LayoutAutoVideoViewBinding.bind(inflated).root
|
||||
|
||||
@ -17,6 +17,7 @@ import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.ImageUtils
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.layoutInflater
|
||||
import com.gh.gamecenter.common.utils.safelyGetInRelease
|
||||
import com.gh.gamecenter.common.view.PageControllerAdapter
|
||||
import com.gh.gamecenter.common.view.PageTransformerAdapter
|
||||
import com.gh.gamecenter.common.view.ScrollEventListener
|
||||
@ -151,7 +152,8 @@ class VGameInstalledLaunchDialog : DialogFragment() {
|
||||
|
||||
launch.setOnClickListener { view ->
|
||||
val currentItem = pageControllerAdapter.currentItem
|
||||
val installedGame = installAdapter.currentList[currentItem]
|
||||
val installedGame =
|
||||
installAdapter.currentList.safelyGetInRelease(currentItem) ?: return@setOnClickListener
|
||||
val vDownloadEntity =
|
||||
VHelper.getVDownloadEntitySnapshot(installedGame.gameId, installedGame.packageName)
|
||||
?: return@setOnClickListener
|
||||
|
||||
@ -143,7 +143,7 @@ ext {
|
||||
|
||||
acloudPush = "3.8.8.1"
|
||||
jpushVersion = "5.4.0"
|
||||
jverifiationVersion = "3.1.7"
|
||||
jverifiationVersion = "3.2.5"
|
||||
honorPushVersion = "7.0.61.303"
|
||||
|
||||
volcTlsVersion = "1.1.4"
|
||||
|
||||
@ -453,6 +453,17 @@ fun String.containHtmlTag(): Boolean {
|
||||
return matcher.find()
|
||||
}
|
||||
|
||||
fun String.dropFontColorInDarkMode(context: Context) : String {
|
||||
return if (DarkModeUtils.isDarkModeOn(context)) {
|
||||
val fontColorRegex = Pattern.compile("<font[^>]*color[^>]*>")
|
||||
val matcher = fontColorRegex.matcher(this)
|
||||
|
||||
return matcher.replaceAll("")
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户行为相关
|
||||
*/
|
||||
|
||||
@ -9,6 +9,9 @@ import retrofit2.http.POST
|
||||
|
||||
interface WGameCPMApiService {
|
||||
|
||||
@POST("geteditorrecommend")
|
||||
fun getEditorRecommendList(@Body body: RequestBody): Single<WXMiniGameCPMEntity>
|
||||
|
||||
@POST("getuserrecommend")
|
||||
fun getUserRecommendList(@Body body: RequestBody): Single<WXMiniGameCPMEntity>
|
||||
|
||||
|
||||
@ -98,6 +98,8 @@ public class WXEntryActivity extends Activity implements IWXAPIEventHandler, WeC
|
||||
&& !((SendAuth.Resp) baseResp).state.contains("qqminigame")
|
||||
) {
|
||||
WXAPIProxyFactory.getLiveData().postValue(baseResp);
|
||||
} else if (baseResp.getType() == ConstantsAPI.COMMAND_SUBSCRIBE_MESSAGE) {
|
||||
WXAPIProxyFactory.getLiveData().postValue(baseResp);
|
||||
}
|
||||
|
||||
String resultString = "";
|
||||
|
||||
@ -3,32 +3,50 @@ package com.gh.gamecenter.va
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import com.gh.gamecenter.core.iinterface.IApplication
|
||||
import com.google.auto.service.AutoService
|
||||
import com.lg.vspace.common.CommonApp
|
||||
import com.lg.vspace.App64
|
||||
|
||||
@AutoService(IApplication::class)
|
||||
class HaloApp : IApplication {
|
||||
|
||||
private val commonApp = CommonApp()
|
||||
private val app = App64()
|
||||
private val isDeviceSupportVa = Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
commonApp.attachBaseContext(base)
|
||||
if (isDeviceSupportVa) {
|
||||
app.attachBaseContext(base)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(application: Application) {
|
||||
commonApp.onCreate(application)
|
||||
if (isDeviceSupportVa) {
|
||||
app.onCreate(application)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onLowMemory() {
|
||||
if (isDeviceSupportVa) {
|
||||
app.onLowMemory()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTerminate() {
|
||||
if (isDeviceSupportVa) {
|
||||
app.onTerminate()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTrimMemory(level: Int) {
|
||||
if (isDeviceSupportVa) {
|
||||
app.onTrimMemory(level)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
if (isDeviceSupportVa) {
|
||||
app.onConfigurationChanged(newConfig)
|
||||
}
|
||||
}
|
||||
}
|
||||
2
vasdk
2
vasdk
Submodule vasdk updated: 9e26684b22...d591639243
Reference in New Issue
Block a user