Compare commits

..

27 Commits

Author SHA1 Message Date
9368d44093 feat: 整理代码 2024-11-05 17:35:34 +08:00
6b04649c34 fix: 修复深色模式显示问题 2024-11-05 17:02:24 +08:00
4497d03dbf feat: 游戏详情页改版优化 https://jira.shanqu.cc/browse/GHZSCY-5855 2024-11-05 17:02:24 +08:00
287bbe7901 feat: 官方入驻标识—客户端 https://jira.shanqu.cc/browse/GHZSCY-6624 2024-11-05 14:09:06 +08:00
fe8f9fcf83 feat: 游戏详情页-自定义栏目-APP—客户端 https://jira.shanqu.cc/browse/GHZSCY-6374 2024-11-05 14:09:06 +08:00
0786342e00 feat: 游戏详情页-综合面板-APP—客户端 https://jira.shanqu.cc/browse/GHZSCY-6167 2024-11-05 14:08:59 +08:00
1676f8bffb feat: 游戏详情页-抽屉列表-APP—客户端 https://jira.shanqu.cc/browse/GHZSCY-6170 2024-11-05 13:36:29 +08:00
2e95a42f3c feat: 游戏详情页-功能标签-APP—客户端 https://jira.shanqu.cc/browse/GHZSCY-6157 2024-11-05 13:36:29 +08:00
da3b3360df fix: 修复深色模式显示问题 2024-11-05 13:36:29 +08:00
080397e0d2 feat: 游戏详情页-内容卡片-APP—客户端 https://jira.shanqu.cc/browse/GHZSCY-6160 2024-11-05 13:36:29 +08:00
48d6533857 feat: 新增PK组件-APP—客户端 https://jira.shanqu.cc/browse/GHZSCY-6194 2024-11-05 13:36:29 +08:00
36bcf7f52a feat: 游戏详情页-内容卡片-APP—客户端 https://jira.shanqu.cc/browse/GHZSCY-6160 2024-11-05 13:36:29 +08:00
da2b817d23 feat: 游戏详情页-游戏礼包-APP—客户端 https://jira.shanqu.cc/browse/GHZSCY-6266 2024-11-05 13:36:29 +08:00
afd0cce849 feat: 游戏详情页改版优化 https://jira.shanqu.cc/browse/GHZSCY-5855 2024-11-05 13:36:29 +08:00
6970aedbd4 feat: 游戏详情页改版优化 https://jira.shanqu.cc/browse/GHZSCY-5855 2024-11-05 13:36:29 +08:00
df21c88ad2 feat: 游戏详情页-详情tab头部信息-APP—客户端 https://jira.shanqu.cc/browse/GHZSCY-6296 2024-11-05 13:36:29 +08:00
7638296860 feat: 游戏详情页改版优化 https://jira.shanqu.cc/browse/GHZSCY-5855 2024-11-05 13:36:29 +08:00
27058d5551 feat: 游戏详情页改版优化 https://jira.shanqu.cc/browse/GHZSCY-5855 2024-11-05 13:36:29 +08:00
74b7bd8b47 feat: 游戏详情页改版优化 https://jira.shanqu.cc/browse/GHZSCY-5855 2024-11-05 13:36:29 +08:00
539c9fb436 feat: 游戏详情页改版优化 https://jira.shanqu.cc/browse/GHZSCY-5855 2024-11-05 13:36:29 +08:00
bc57ba207c feat: 游戏详情页改版优化 https://jira.shanqu.cc/browse/GHZSCY-5855 2024-11-05 13:36:29 +08:00
90b63b287f feat: 游戏详情页改版优化 https://jira.shanqu.cc/browse/GHZSCY-5855 2024-11-05 13:36:29 +08:00
1233ff8458 feat: 游戏详情页改版优化 https://jira.shanqu.cc/browse/GHZSCY-5855 2024-11-05 13:36:28 +08:00
b75fd9cc9b feat: 游戏详情页改版优化 https://jira.shanqu.cc/browse/GHZSCY-5855 2024-11-05 13:36:28 +08:00
6d992c77c7 feat: 游戏详情页改版优化 https://jira.shanqu.cc/browse/GHZSCY-5855 2024-11-05 13:36:28 +08:00
d5dc79f753 feat: 游戏详情页改版优化 https://jira.shanqu.cc/browse/GHZSCY-5855 2024-11-05 13:36:28 +08:00
168f20a162 feat: 游戏详情页改版优化 https://jira.shanqu.cc/browse/GHZSCY-5855 2024-11-05 13:36:28 +08:00
495 changed files with 16831 additions and 12979 deletions

View File

@ -372,6 +372,8 @@ dependencies {
// debugImplementation "com.gu.android:toolargetool:${toolargetool}" // 需要使用调试时才启用
debugImplementation "com.github.nichbar:WhatTheStack:${whatTheStack}"
ksp project(":feature:route_doc")
implementation "androidx.multidex:multidex:${multiDex}"
implementation "androidx.fragment:fragment-ktx:${fragment}"
@ -447,14 +449,14 @@ dependencies {
exclude group: 'androidx.swiperefreshlayout'
}
implementation(project(':module_setting')) {
exclude group: 'androidx.swiperefreshlayout'
}
// implementation(project(':module_setting_compose')) {
// implementation(project(':module_setting')) {
// exclude group: 'androidx.swiperefreshlayout'
// }
implementation(project(':module_setting_compose')) {
exclude group: 'androidx.swiperefreshlayout'
}
if (!gradle.ext.excludeOptionalModules || gradle.ext.enablePkg) {
implementation(project(':feature:pkg'))
}
@ -510,10 +512,6 @@ dependencies {
implementation(project(':feature:sentry'))
}
if (gradle.ext.enableRouteDoc) {
ksp project(":feature:route_doc")
}
implementation(project(':feature:media_select'))
implementation(project(":module_va_api"))

View File

@ -20,6 +20,7 @@
-keep class com.gh.gamecenter.db.info.* {*;}
-keep class com.gh.gamecenter.entity.** {<fields>;}
-keep class com.gh.gamecenter.qa.entity.** {<fields>;}
-keep class com.gh.gamecenter.gamedetail.entity.** {<fields>;}
-keep class com.gh.download.DownloadDataSimpleEntity {<fields>;}
-keep class com.gh.gamecenter.floatingwindow.FloatingWindowEntity {<fields>;}
-keep class com.gh.gamecenter.BR

View File

@ -68,9 +68,6 @@
<!-- 悬浮窗 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 适配 双开/分身 游戏授权登录 -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-sdk tools:overrideLibrary="
com.shuyu.gsyvideoplayer,
com.shuyu.gsyvideoplayer.lib,
@ -520,6 +517,10 @@
android:name=".video.data.VideoDataActivity"
android:screenOrientation="portrait" />
<activity
android:name=".video.poster.PosterEditActivity"
android:screenOrientation="portrait" />
<activity
android:name=".forum.detail.ForumDetailActivity"
android:screenOrientation="portrait" />
@ -639,7 +640,6 @@
<activity
android:name="com.gh.gamecenter.SkipCompatActivity"
android:exported="true"
android:launchMode="singleTask"
android:theme="@style/Theme.AppCompat.Light.Fullscreen.Transparent">
<intent-filter>
<data android:scheme="ghzhushou" />
@ -663,8 +663,7 @@
android:name=".authorization.AuthorizationActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:taskAffinity=".auth">
android:screenOrientation="portrait">
<intent-filter>
<data android:scheme="ghzhushou_authorization" />
<category android:name="android.intent.category.DEFAULT" />
@ -810,10 +809,6 @@
android:screenOrientation="portrait"
android:theme="@style/AppCompatTheme.APP" />
<activity
android:name=".video.poster.PosterEditActivity"
android:screenOrientation="portrait" />
<!-- <activity-->
<!-- android:name="${applicationId}.douyinapi.DouYinEntryActivity"-->
<!-- android:launchMode="singleTask"-->
@ -869,6 +864,10 @@
<!-- tools:node="remove" />-->
<!-- </provider>-->
<service android:name="com.gh.gamecenter.install.InstallService" />
<service android:name="com.gh.download.suspendwindow.DownloadSuspendWindowService" />
<receiver
android:name="com.gh.gamecenter.receiver.DownloadReceiver"
android:exported="false">

View File

@ -4,7 +4,6 @@ import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.SharedPreferences
import android.graphics.drawable.Animatable
import android.os.Message
import android.text.TextUtils
import android.view.View
@ -14,13 +13,11 @@ import android.widget.TextView
import androidx.appcompat.content.res.AppCompatResources
import androidx.fragment.app.Fragment
import com.therouter.TheRouter
import com.facebook.drawee.controller.BaseControllerListener
import com.facebook.drawee.view.SimpleDraweeView
import com.facebook.imagepipeline.image.ImageInfo
import com.gh.common.exposure.ExposureManager
import com.gh.common.util.DirectUtils.directToLinkPage
import com.gh.common.util.LogUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.common.util.NewFlatLogUtils.logOpenScreenAdSkip
import com.gh.common.util.PackageUtils
import com.gh.gamecenter.BuildConfig
import com.gh.gamecenter.MainActivity
@ -62,8 +59,6 @@ object AdDelegateHelper {
private val mGameSearchAdList: ArrayList<AdConfig> by lazy { arrayListOf() }
private var mVGameLaunchAd: AdConfig? = null
private var ownerSplashAdLoadTime = 0L
val vGameLaunchAd: AdConfig?
get() = mVGameLaunchAd
@ -81,7 +76,6 @@ object AdDelegateHelper {
}
var isShowingSplashAd = false // 是否正在显示开屏广告
var isOwnerSplashAdShown = false // 自有开屏广告是否展示
var gameSearchKeyword = ""
fun initAdSdk(context: Context) {
@ -308,7 +302,6 @@ object AdDelegateHelper {
) {
val hideCallback = {
isShowingSplashAd = false
isOwnerSplashAdShown = false
hideAction.invoke()
}
if (mSplashAd != null) {
@ -581,8 +574,6 @@ object AdDelegateHelper {
handler: BaseActivity.BaseHandler,
hideCallback: () -> Unit
) {
isOwnerSplashAdShown = false
val jumpBtn = startAdContainer.findViewById<TextView>(R.id.jumpBtn)
val jumpDetailBtn: TextView = startAdContainer.findViewById(R.id.jumpDetailBtn)
val adImage: SimpleDraweeView = startAdContainer.findViewById(R.id.adImage)
@ -601,62 +592,38 @@ object AdDelegateHelper {
)
adImage.visibleIf(true)
ImageUtils.displayWithCallback(adImage, ad.img, true, object : BaseControllerListener<ImageInfo>() {
override fun onSubmit(id: String?, callerContext: Any?) {
super.onSubmit(id, callerContext)
adImage.post {
ownerSplashAdLoadTime = System.currentTimeMillis()
NewFlatLogUtils.logSplashAdLoad(ad.id)
}
}
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
isOwnerSplashAdShown = true
adImage.post {
NewFlatLogUtils.logSplashAdShow(ad.id, System.currentTimeMillis() - ownerSplashAdLoadTime)
}
}
override fun onFailure(id: String?, throwable: Throwable?) {
super.onFailure(id, throwable)
NewFlatLogUtils.logSplashAdFail(ad.id, "启动广告图加载失败")
}
})
ImageUtils.display(adImage, ad.img)
if (ad.isImageType) {
adVideo.visibleIf(false)
} else {
adVideo.visibleIf(true)
adVideo.startPlay(ad.video.url)
}
startAdContainer.setOnClickListener {
// 拦截点击事件传递
}
jumpBtn.setOnClickListener {
it.debounceActionWithInterval(1000L) {
if (!isOwnerSplashAdShown) {
NewFlatLogUtils.logSplashAdFail(ad.id, "加载过程中点击跳过广告")
}
handler.removeMessages(MainActivity.COUNTDOWN_AD)
hideCallback.invoke()
val linkEntity = ad.jump
NewFlatLogUtils.logOpenScreenAdSkip(
ad.id,
(if (linkEntity.text != null) linkEntity.text else "")!!,
(if (linkEntity.type != null) linkEntity.type else "")!!,
(if (linkEntity.link != null) linkEntity.link else "")!!
)
SensorsBridge.trackEvent(
"SplashAdOwnSkip",
"splash_ad_id",
ad.id,
"link_type",
linkEntity.type ?: "",
"link_id",
linkEntity.link ?: "",
"link_text",
linkEntity.text ?: ""
)
}
handler.removeMessages(MainActivity.COUNTDOWN_AD)
hideCallback.invoke()
val linkEntity = ad.jump
logOpenScreenAdSkip(
ad.id,
(if (linkEntity.text != null) linkEntity.text else "")!!,
(if (linkEntity.type != null) linkEntity.type else "")!!,
(if (linkEntity.link != null) linkEntity.link else "")!!
)
SensorsBridge.trackEvent(
"SplashAdOwnSkip",
"splash_ad_id",
ad.id,
"link_type",
linkEntity.type ?: "",
"link_id",
linkEntity.link ?: "",
"link_text",
linkEntity.text ?: ""
)
}
val sources: MutableList<ExposureSource> = ArrayList()
sources.add(ExposureSource("开屏广告", ad.id))

View File

@ -44,16 +44,6 @@ class SplashAdVideoView @JvmOverloads constructor(
return R.layout.layout_splash_ad_video
}
override fun touchSurfaceMoveFullLogic(absDeltaX: Float, absDeltaY: Float) {
// no nothing
}
override fun onPrepared() {
super.onPrepared()
visibility = VISIBLE
}
override fun onAutoCompletion() {
setStateAndUi(CURRENT_STATE_AUTO_COMPLETE);

View File

@ -21,31 +21,26 @@ import com.gh.common.view.RichEditor
import com.gh.gamecenter.CropImageActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.entity.LocalVideoEntity
import com.gh.gamecenter.feature.selector.LocalMediaActivity
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.AppExecutor
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.entity.GamesCollectionEntity
import com.gh.gamecenter.entity.MyVideoEntity
import com.gh.gamecenter.entity.VideoEntity
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.qa.editor.*
import com.gh.gamecenter.feature.entity.AnswerEntity
import com.gh.gamecenter.feature.entity.ArticleEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.selector.ChooseType
import com.gh.gamecenter.feature.selector.LocalMediaActivity
import com.gh.gamecenter.qa.editor.*
import com.gh.gamecenter.qa.entity.EditorInsertEntity
import com.gh.gamecenter.video.poster.video.VideoPosterFragment
import com.gh.gamecenter.video.poster.PosterEditActivity
import com.gh.gamecenter.video.upload.UploadManager
import com.google.gson.JsonObject
import com.halo.assistant.HaloApp
import com.lightgame.utils.Util_System_Keyboard
import com.lightgame.utils.Utils
import com.lightgame.view.CheckableImageView
import com.therouter.TheRouter
import io.reactivex.disposables.Disposable
import org.json.JSONArray
import org.json.JSONObject
@ -234,7 +229,6 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
@SuppressLint("AddJavascriptInterface", "ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
VideoPosterFragment.createVideoCoverFile(this)
findView()
onRichClick()
mViewModel = provideViewModel()
@ -745,9 +739,9 @@ abstract class BaseRichEditorActivity<VM : BaseRichEditorViewModel> constructor(
mViewModel.id = id
mViewModel.videoId = videoId
val videoEntity = VideoEntity(url = url)
TheRouter.build(RouteConsts.activity.videoCoverEditActivity)
.withParcelable(EntranceConsts.KEY_VIDEO_ENTITY, videoEntity)
.navigation(this@BaseRichEditorActivity, REQUEST_CODE_IMAGE_CROP)
val intent =
PosterEditActivity.getIntentByVideo(this@BaseRichEditorActivity, videoEntity)
startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP)
}
@JavascriptInterface

View File

@ -17,7 +17,7 @@ import kotlin.concurrent.fixedRateTimer
object FixedRateJobHelper {
private const val CHECKER_PERIOD: Long = 15 * 1000L
private const val TIME_PERIOD: Long = 24 * 60 * 60 * 1000L
private const val TIME_PERIOD: Long = 10 * 60 * 1000L
private const val LOGHUB_PERIOD: Long = 2 * 60 * 1000L
private const val EXPOSURE_PERIOD: Long = 1 * 60 * 1000L
private const val REGION_SETTING_PERIOD: Long = 60 * 1000L
@ -35,7 +35,7 @@ object FixedRateJobHelper {
// 时间检查每15秒检查一次
fixedRateTimer("Global-Fixed-Rate-Timer", initialDelay = 100, period = CHECKER_PERIOD) {
val elapsedTime = mExecuteCount * CHECKER_PERIOD
// 时间校对,24 小时一次
// 时间校对,10分钟一次
if (elapsedTime % TIME_PERIOD == 0L) {
RetrofitManager.getInstance().api.time
.subscribeOn(Schedulers.io())

View File

@ -4,7 +4,6 @@ import android.app.Activity
import android.content.Context
import com.gh.common.util.DialogUtils
import com.gh.common.util.DirectUtils
import com.gh.common.util.PackageChangeHelper
import com.gh.common.util.TempCertificationUtils
import com.gh.gamecenter.feature.entity.GameEntity
@ -26,10 +25,6 @@ class LandPageAddressHandler : DownloadChainHandler() {
processEndCallback?.invoke(asVGame, null)
}
} else {
val packageName = gameEntity.getApk().firstOrNull()?.packageName
if (packageName?.isNotEmpty() == true) {
PackageChangeHelper.addInstallPendingPackage(packageName)
}
DirectUtils.directToExternalBrowser(context, gameEntity.landPageAddressDialog!!.link!!)
}
}

View File

@ -114,6 +114,8 @@ public class Config {
if (!TextUtils.isEmpty(json)) {
mSettingsEntity = GsonUtils.fromJson(json, SettingsEntity.class);
}
mSettingsEntity.setGameSmooth("off");
} catch (Exception e) {
e.printStackTrace();
}
@ -261,7 +263,8 @@ public class Config {
public void onSuccess(VSetting data) {
mVSetting = data;
SPUtils.setString(Constants.SP_V_SETTINGS, GsonUtils.toJson(data));
VHelper.checkVspaceUpdate(HaloApp.getInstance());
VHelper.init(HaloApp.getInstance());
}
});
}

View File

@ -15,10 +15,10 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.gh.common.chain.BrowserInstallHandler;
import com.gh.common.chain.CheckDownloadHandler;
import com.gh.common.chain.CheckStoragePermissionHandler;
import com.gh.common.chain.DownloadChainBuilder;
import com.gh.common.chain.DownloadChainHandler;
import com.gh.common.chain.CheckDownloadHandler;
import com.gh.common.chain.CheckStoragePermissionHandler;
import com.gh.common.chain.DownloadDialogHelperHandler;
import com.gh.common.chain.GamePermissionHandler;
import com.gh.common.chain.LandPageAddressHandler;
@ -287,11 +287,19 @@ public class BindingAdapters {
});
break;
case RESERVED:
ReservationHelper.showCancelReservationDialog(progressBar.getContext(),gameEntity, () -> {
ReservationHelper.cancelReservation(gameEntity, () -> {
updateReservation(progressBar, gameEntity);
if ("download".equals(gameEntity.getReserveStatus())) {
ReservationHelper.showDeleteReservationDialog(progressBar.getContext(), () -> {
ReservationHelper.deleteReservation(gameEntity, () -> {
updateReservation(progressBar, gameEntity);
});
});
});
} else {
ReservationHelper.showCancelReservationDialog(progressBar.getContext(),gameEntity, () -> {
ReservationHelper.cancelReservation(gameEntity, () -> {
updateReservation(progressBar, gameEntity);
});
});
}
break;
case H5_GAME:
LinkEntity linkEntity = gameEntity.getH5Link();
@ -337,9 +345,9 @@ public class BindingAdapters {
}
progressBar.setButtonStyle(DownloadButton.ButtonStyle.H5_GAME);
} else {
if (("dialog".equals(offStatus) || "third_party".equals(offStatus))) {
if (offStatus != null && "dialog".equals(offStatus)) {
progressBar.setText("查看");
progressBar.setButtonStyle(DownloadButton.ButtonStyle.NONE_WITH_HINT);
progressBar.setButtonStyle(DownloadButton.ButtonStyle.NONE);
} else if ("updating".equals(offStatus)) {
progressBar.setText("更新中");
progressBar.setButtonStyle(DownloadButton.ButtonStyle.UPDATING);

View File

@ -3,6 +3,7 @@ package com.gh.common.dialog
import android.animation.ValueAnimator
import android.content.Context
import android.content.DialogInterface
import android.content.pm.PackageInfo
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -18,6 +19,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.DirectUtils
import com.gh.common.util.LogUtils
import com.gh.common.util.PackageHelper
import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
@ -57,6 +59,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
private val mDuration = 3000
private var mDisposable: Disposable? = null
private var mAdapter: PackageCheckAdapter? = null
private var mAllInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
var gameEntity: GameEntity? = null
var callBack: ConfirmListener? = null
@ -192,7 +195,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
if (binding.noRemindAgainCb.isChecked) {
saveRecord(entity)
}
val isAllPackageInstalled = isAllPackageInstalled(entity)
val isAllPackageInstalled = isAllPackageInstalled(mAllInstalledPackages, entity)
if (isAllPackageInstalled) {
mDismissByTouchInside = true
callBack?.onConfirm()
@ -296,7 +299,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
private fun getNotInstalledLink(packageDialogEntity: PackageDialogEntity): LinkEntity? {
val links = LinkedHashSet<LinkEntity>()
packageDialogEntity.detectionObjects.forEach { obj ->
if (!checkDetectionsInstalled(obj.packages)) {
if (!checkDetectionsInstalled(mAllInstalledPackages, obj.packages)) {
obj.assignDownload.forEach {
links.add(packageDialogEntity.links[it])
}
@ -322,8 +325,9 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
override fun onResume() {
super.onResume()
mAllInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
gameEntity?.packageDialog?.let {
if (isAllPackageInstalled(it)) {
if (isAllPackageInstalled(mAllInstalledPackages, it)) {
callBack?.onConfirm()
dismissAllowingStateLoss()
}
@ -359,6 +363,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(busFour: EBPackage) {
if (busFour.isInstalledOrUninstalled()) {
mAllInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
mAdapter?.notifyDataSetChanged()
}
}
@ -383,7 +388,7 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
val entity = entities[position]
holder.binding.gameNameTv.text = entity.text
if (position <= index) {
val isAllInstalled = checkDetectionsInstalled(entity.packages)
val isAllInstalled = checkDetectionsInstalled(mAllInstalledPackages, entity.packages)
if (isAllInstalled) {
holder.binding.statusTv.text = "已安装"
holder.binding.statusTv.setTextColor(ContextCompat.getColor(context, com.gh.gamecenter.common.R.color.text_theme))
@ -411,7 +416,8 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
return
}
if (isAllPackageInstalled(packageDialogEntity)) {
val allInstalledPackages = PackageHelper.getInstalledPackageNameList(HaloApp.getInstance().application, 0)
if (isAllPackageInstalled(allInstalledPackages, packageDialogEntity)) {
callBack.onConfirm()
return
}
@ -447,11 +453,13 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
}
private fun checkDetectionsInstalled(
allInstalledPackages: List<String>,
packages: ArrayList<String>
): Boolean {
var isPackagesInstalled = false
packages.forEach { packageName ->
if (PackageUtils.isInstalledFromAllPackage(HaloApp.getInstance(), packageName)) {
val isInstalled = allInstalledPackages.find { it == packageName } != null
if (isInstalled) {
isPackagesInstalled = true
return@forEach
}
@ -461,14 +469,17 @@ class PackageCheckDialogFragment : BaseDialogFragment() {
fun isAllPackageInstalled(
allInstalledPackages: List<String>,
packageDialogEntity: PackageDialogEntity
): Boolean {
var isAllInstalled = true
packageDialogEntity.detectionObjects.forEach loop@{ obj ->
if (!checkDetectionsInstalled(obj.packages)) {
return false
if (!checkDetectionsInstalled(allInstalledPackages, obj.packages)) {
isAllInstalled = false
return isAllInstalled
}
}
return true
return isAllInstalled
}
}
}

View File

@ -17,7 +17,7 @@ import com.gh.gamecenter.common.entity.ErrorEntity
import com.gh.gamecenter.core.utils.CurrentActivityHolder
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.DialogWechatBindingFailedBinding
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.login.user.UserRepository
import com.lightgame.utils.Utils
class WechatBindingFailedDialogFragment : BaseDialogFragment() {
@ -48,10 +48,10 @@ class WechatBindingFailedDialogFragment : BaseDialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
UserManager.getInstance().userInfoEntity?.let {
currentUserId = it.getShortUserId()
binding.tvCurrentName.text = it.name ?: ""
binding.ivCurrentAvatar.displayAvatar(it.icon)
UserRepository.getInstance().loginUserInfo.observe(viewLifecycleOwner) {
currentUserId = it.data.getShortUserId()
binding.tvCurrentName.text = it.data.name
binding.ivCurrentAvatar.displayAvatar(it.data.icon)
binding.tvUserId.text = getString(R.string.user_id, currentUserId)
}

View File

@ -31,7 +31,6 @@ class ExposureListener(var fragment: Fragment, var exposable: IExposable) : Recy
override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
if (fragment == f) {
visibleState?.let { commitExposure(it) }
visibleState?.let { commitWXCPMExposure(it) }
throttleBus.clear()
}
}

View File

@ -1,45 +0,0 @@
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)
}
}
fun FragmentManager.popBackStackAllowStateLoss(name: String?, flags: Int) {
if (!isStateSaved) {
popBackStack(name, flags)
}
}
fun FragmentManager.popBackStackImmediateAllowStateLoss() = popBackStackAllowStateLoss(-1, 0)
fun FragmentManager.popBackStackImmediateAllowStateLoss(id: Int, flags: Int) =
if (!isStateSaved) {
popBackStackImmediate(id, flags)
} else {
false
}
@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()
}

View File

@ -7,19 +7,20 @@ import androidx.room.TypeConverters
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.gh.gamecenter.entity.GamesCollectionEntity
import com.gh.gamecenter.entity.HistoryGameDetailEntity
import com.gh.gamecenter.entity.HistoryGameEntity
import com.gh.gamecenter.entity.MyVideoEntity
import com.gh.gamecenter.feature.entity.NewsEntity
import com.gh.gamecenter.feature.entity.AnswerEntity
import com.gh.gamecenter.feature.entity.ArticleEntity
import com.gh.gamecenter.feature.entity.NewsEntity
import com.gh.gamecenter.feature.room.converter.*
import com.gh.gamecenter.room.converter.*
import com.gh.gamecenter.room.dao.*
import com.halo.assistant.HaloApp
@Database(
entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class, GamesCollectionEntity::class],
version = 14,
entities = [AnswerEntity::class, ArticleEntity::class, NewsEntity::class, HistoryGameEntity::class, MyVideoEntity::class, GamesCollectionEntity::class, HistoryGameDetailEntity::class],
version = 15,
exportSchema = false
)
@TypeConverters(
@ -53,6 +54,7 @@ abstract class HistoryDatabase : RoomDatabase() {
abstract fun gameDao(): GameDao
abstract fun videoHistoryDao(): VideoHistoryDao
abstract fun gamesCollectionDao(): GamesCollectionDao
abstract fun gameDetailDao(): GameDetailHistoryDao
companion object {
@ -152,6 +154,12 @@ abstract class HistoryDatabase : RoomDatabase() {
}
}
val MIGRATION_14_15: Migration = object : Migration(14, 15) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("CREATE TABLE HistoryGameDetailEntity (id TEXT NOT NULL PRIMARY KEY, name TEXT DEFAULT '')")
}
}
val instance by lazy {
Room.databaseBuilder(
HaloApp.getInstance().application,
@ -170,6 +178,7 @@ abstract class HistoryDatabase : RoomDatabase() {
.addMigrations(MIGRATION_11_12)
.addMigrations(MIGRATION_12_13)
.addMigrations(MIGRATION_13_14)
.addMigrations(MIGRATION_14_15)
.build()
}
}

View File

@ -44,6 +44,20 @@ object HistoryHelper {
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.gameDao().addGame(historyGameEntity) } }
}
@JvmStatic
fun insertGameDetail(gameEntity: GameEntity) {
val historyGameDetailEntity = HistoryGameDetailEntity(gameEntity.id, gameEntity.name)
runOnIoThread { tryCatchInRelease { HistoryDatabase.instance.gameDetailDao().addGame(historyGameDetailEntity) } }
}
@JvmStatic
fun getHistoryGameDetailById(id: String): HistoryGameDetailEntity? =
try {
HistoryDatabase.instance.gameDetailDao().getHistoryGameDetailById(id)
} catch (e: Throwable) {
null
}
private fun convertGameUpdateEntityToHistoryGameEntity(updateEntity: GameUpdateEntity): HistoryGameEntity {
val historyGame = HistoryGameEntity()
@ -142,6 +156,15 @@ object HistoryHelper {
}
}
@JvmStatic
fun deleteGameDetailEntity(gameId: String) {
runOnIoThread {
tryCatchInRelease {
HistoryDatabase.instance.gameDetailDao().deleteGame(HistoryGameDetailEntity(id = gameId))
}
}
}
@JvmStatic
fun emptyDatabase() {

View File

@ -1,9 +1,12 @@
package com.gh.common.iinterface
import com.scwang.smartrefresh.layout.api.RefreshLayout
import com.scwang.smartrefresh.layout.constant.RefreshState
interface ISmartRefreshContent {
/**
* 启用/关闭 页面滑动
* @param isScrollEnabled 是否启用
*/
fun setScrollEnabled(isScrollEnabled: Boolean)
fun onRefresh()
/**
@ -11,6 +14,4 @@ interface ISmartRefreshContent {
* @param isSwipeRefreshEnabled 是否启用
*/
fun setSwipeRefreshEnabled(isSwipeRefreshEnabled: Boolean)
fun onStateChanged(refreshLayout: RefreshLayout, oldState: RefreshState, newState: RefreshState)
}

View File

@ -1,58 +0,0 @@
package com.gh.common.provider
import android.content.Context
import android.content.Intent
import android.net.Uri
import com.gh.gamecenter.CropImageActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.core.provider.ICropImageProvider
import com.gh.gamecenter.personalhome.background.BackgroundClipActivity
import com.halo.assistant.fragment.user.UserPortraitCropImageActivity
import com.lightgame.utils.Utils
import com.zhihu.matisse.internal.utils.PathUtils
@com.therouter.inject.ServiceProvider
class CropImageProviderImpl : ICropImageProvider {
override fun getCropImageIntent(data: List<Uri>, imageType: Int, entrance: String, context: Context): Intent? {
if (data.isEmpty()) {
return null
}
val picturePath = PathUtils.getPath(context, data[0])
Utils.log("picturePath = $picturePath")
return when (imageType) {
IMAGE_TYPE_AVATAR -> {// 上传头像
UserPortraitCropImageActivity.getIntent(
context,
picturePath,
"我的光环(选择头像)"
)
}
IMAGE_TYPE_GAME_COLLECTION_COVER -> {// 游戏单封面
CropImageActivity.getIntent(
context,
picturePath,
142 / 328F,
false,
R.layout.layout_game_collection_crop_image_assist,
entrance
)
}
IMAGE_TYPE_PERSONAL_BACKGROUND -> { // 用户主页背景
BackgroundClipActivity.getIntent(context, picturePath, entrance)
}
else ->
null
}
}
companion object {
const val IMAGE_TYPE_AVATAR = 1
const val IMAGE_TYPE_GAME_COLLECTION_COVER = 2
const val IMAGE_TYPE_PERSONAL_BACKGROUND = 3
}
}

View File

@ -112,12 +112,6 @@ class DownloadButtonClickedProviderImpl : IDownloadButtonClickedProvider {
"本地下载"
}
// 小游戏的启动不需要上报下载点击事件
// @see https://jira.shanqu.cc/browse/GHZSCY-7013
if (boundedObject is GameEntity && boundedObject.isMiniGame()) {
return
}
// 上报神策点击事件
val customPageKV = customPageTrackData?.toKV() ?: arrayOf()
SensorsBridge.trackEventWithExposureSource(
@ -127,7 +121,7 @@ class DownloadButtonClickedProviderImpl : IDownloadButtonClickedProvider {
"game_name", gameName,
"game_type", gameTypeInChinese,
"download_status", downloadStatusInChinese,
"button_name", text,
"button_name", downloadButton.text,
"game_schema_type", gameSchemaType,
"download_type", downloadType,
"page_name", GlobalActivityManager.getCurrentPageEntity().pageName,

View File

@ -2,16 +2,18 @@ package com.gh.common.provider
import android.content.Context
import android.content.Intent
import com.therouter.router.Route
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.feature.provider.IGameCollectionDetailProvider
import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
@com.therouter.inject.ServiceProvider
class GameCollectionDetailProviderImpl : IGameCollectionDetailProvider {
override fun getIntent(context: Context, gameCollectionId: String, isFromSquare: Boolean, entrance: String): Intent {
return GameCollectionDetailActivity.getIntent(context, gameCollectionId, isFromSquare, entrance)
override fun getIntent(context: Context, gameCollectionId: String, isFromSquare: Boolean): Intent {
return GameCollectionDetailActivity.getIntent(context, gameCollectionId, isFromSquare)
}
override fun getSpecifiedCommentIntent(context: Context, gameCollectionId: String, topCommentId: String, entrance: String): Intent {
return GameCollectionDetailActivity.getSpecifiedCommentIntent(context, gameCollectionId, topCommentId, entrance)
override fun getSpecifiedCommentIntent(context: Context, gameCollectionId: String, topCommentId: String): Intent {
return GameCollectionDetailActivity.getSpecifiedCommentIntent(context, gameCollectionId, topCommentId)
}
}

View File

@ -4,8 +4,6 @@ import android.annotation.SuppressLint
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.database.sqlite.SQLiteDiskIOException
import android.database.sqlite.SQLiteException
import android.graphics.Bitmap
import android.net.Uri
import android.text.TextUtils
@ -286,11 +284,7 @@ object SimulatorGameManager {
entity.isRecentlyPlayed = it.id == gameId
simulatorGameRecordList.add(entity)
}
try {
simulatorGameDao.addSimulatorGameList(simulatorGameRecordList)
} catch (e: SQLiteException) {
e.printStackTrace()
}
simulatorGameDao.addSimulatorGameList(simulatorGameRecordList)
}
})
}

View File

@ -16,7 +16,6 @@ import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.RouteConsts;
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
import com.gh.gamecenter.common.retrofit.BiResponse;
import com.gh.gamecenter.common.utils.SensorsBridge;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.core.provider.ISentryProvider;
import com.gh.gamecenter.core.utils.GsonUtils;
@ -40,11 +39,6 @@ import io.reactivex.schedulers.Schedulers;
*/
public class DataUtils {
// 神策 OAID 是否已绑定
private static boolean isSensorOAIDBounded = false;
// 原始的 OAID 是否已成功获取
private static boolean originalOAIDIsReceived = false;
private DataUtils() {
throw new IllegalStateException("Utility class");
}
@ -71,6 +65,7 @@ public class DataUtils {
// 默认用 APP 级已存储的 GID 来使用,不使用外部 GID
String savedGid = SPUtils.getString(Constants.GID);
if (!TextUtils.isEmpty(savedGid)) {
HaloApp.getInstance().setGid(savedGid);
onGidReceived(savedGid);
} else {
GidHelper.getInstance().registerDevice(HaloApp.getInstance().getApplication(), new GidCallback() {
@ -94,8 +89,6 @@ public class DataUtils {
}
private static void onGidReceived(String gid) {
bindValidOaidToSensor(false);
HaloApp.getInstance().setGid(gid);
// 更新广告配置
AdDelegateHelper.INSTANCE.requestAdConfig(false, "", null);
@ -118,35 +111,6 @@ public class DataUtils {
});
}
/**
* 为神策绑定有效的 OAID
*/
public static void bindValidOaidToSensor(boolean fromOaidResult) {
if (isSensorOAIDBounded) return;
String oaid = HaloApp.getInstance().getOAID();
// 来自于 oaid 获取回调,或者说原始 oaid 已经获取成功
if (fromOaidResult || originalOAIDIsReceived) {
originalOAIDIsReceived = true;
// 遇到异常的 OAID
if (Constants.INVALID_OAID_1.equals(oaid)
|| Constants.INVALID_OAID_2.equals(oaid)
|| Constants.INVALID_OAID_3.equals(oaid)
|| TextUtils.isEmpty(oaid)) {
// 若 gid 不为空,那么整合 gid 作为 oaid https://jira.shanqu.cc/browse/GHZSCY-7004
if (HaloApp.getInstance().getGid() != null) {
oaid = "GID" + HaloApp.getInstance().getGid();
SensorsBridge.INSTANCE.setOAID(oaid);
isSensorOAIDBounded = true;
}
} else {
SensorsBridge.INSTANCE.setOAID(oaid);
isSensorOAIDBounded = true;
}
}
}
/**
* 获取应用 gid 绑定的实名信息
*/

View File

@ -139,7 +139,6 @@ 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);
@ -458,7 +457,7 @@ public class DetailDownloadUtils {
}
viewHolder.getDownloadPb().setButtonStyle(DownloadButton.ButtonStyle.H5_GAME);
} else {
if ("dialog".equals(gameEntity.getDownloadOffStatus()) || "third_party".equals(gameEntity.getDownloadOffStatus())) {
if ("dialog".equals(gameEntity.getDownloadOffStatus())) {
viewHolder.getDownloadPb().setText(TextUtils.isEmpty(gameEntity.getDownloadOffText()) ? "查看详情" : gameEntity.getDownloadOffText());
viewHolder.getDownloadPb().setButtonStyle(DownloadButton.ButtonStyle.NONE_WITH_HINT);
} else if ("updating".equals(gameEntity.getDownloadOffStatus())) {

View File

@ -18,6 +18,7 @@ import com.gh.common.exposure.ExposureTraceUtils.appendTrace
import com.gh.common.util.EntranceUtils.jumpActivity
import com.gh.common.util.EntranceUtils.jumpActivityCompat
import com.gh.gamecenter.*
import com.gh.gamecenter.ShellActivity.Type
import com.gh.gamecenter.amway.AmwayActivity
import com.gh.gamecenter.category2.CategoryV2Activity
import com.gh.gamecenter.common.base.activity.BaseActivity
@ -55,7 +56,9 @@ import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
import com.gh.gamecenter.gamecollection.hotlist.GameCollectionHotListActivity
import com.gh.gamecenter.gamecollection.hotlist.GameCollectionListDetailActivity
import com.gh.gamecenter.gamecollection.square.GameCollectionSquareActivity
import com.gh.gamecenter.gamedetail.entity.GameDetailTabEntity
import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarActivity
import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarManagementActivity
import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersSubscribedGameListActivity
import com.gh.gamecenter.gamedetail.history.HistoryApkListActivity
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
@ -177,22 +180,7 @@ object DirectUtils {
"feedback",
"toolkit",
"float_window_game",
"my_halo",
"my_game",
"server_manager",
"receiving_information",
"game_archive",
"game_dynamics",
"game_upload",
"certification",
"wechat_reminder",
"apk_clean",
"personal_center",
"video_upload",
"account_security",
"simulator",
"teen_mode",
"message_center",
"archive"
)
fun directToLinkPage(
@ -397,8 +385,8 @@ object DirectUtils {
}
}
"authentication", "certification" -> {
directToRealName(context)
"authentication" -> {
context.startActivity(ShellActivity.getIntent(context, ShellActivity.Type.REAL_NAME_INFO, null))
}
"user_background" -> {
@ -456,7 +444,7 @@ object DirectUtils {
} ?: ""
}
"my_halo", "halo_tab" -> directToHomeMyHaloTab(context)
"halo_tab" -> directToHomeMyHaloTab(context)
"common_collection" -> directToCommonCollectionDetail(
context,
@ -538,8 +526,7 @@ object DirectUtils {
ToolbarWrapperActivity.getMultiTabNavIntent(
context,
linkEntity.link ?: "",
linkEntity.text ?: "",
entrance
linkEntity.text ?: ""
)
)
@ -547,20 +534,16 @@ object DirectUtils {
ToolbarWrapperActivity.getCustomPageIntent(
context,
linkEntity.link ?: "",
linkEntity.text ?: "",
entrance
linkEntity.text ?: ""
)
)
// 选中首页底部 tab
"bottom_tab" -> {
if (HaloApp.getInstance().isRunningForeground) {
val intent = Intent(context, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
context.startActivity(intent)
} else {
jumpActivity(context, Bundle())
val intent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
}
context.startActivity(intent)
if (linkEntity is LaunchRedirect) {
MainWrapperRepository.getInstance().sendSelectTabEvent(linkEntity)
@ -587,31 +570,7 @@ object DirectUtils {
}
}
"my_game" -> directToMyGame(0, entrance)
"server_manager" -> directToServersCalendarManagement(entrance)
"receiving_information" -> directToDeliveryInfo(entrance)
"game_archive" -> directToGameArchive(entrance)
"game_dynamics" -> directToConcernInfo(context, entrance)
"wechat_reminder" -> CheckLoginUtils.checkLogin(context, entrance) {
context.startActivity(WebActivity.getBindWechatIntent(context))
}
"apk_clean" -> directToCleanApk(context, entrance)
"personal_center" -> directToUserInfo(entrance)
"simulator" -> directToSimulatorGame(entrance)
"account_security" -> directToAccountSecurity(entrance)
"teen_mode" -> directToTeenMode(entrance)
"message_center" -> directToMessageCenter(0, entrance)
"archive" -> directToCloudArchive(context, linkEntity.link ?: "", linkEntity.text ?: "", "", entrance)
"" -> {
// do nothing
@ -855,10 +814,10 @@ object DirectUtils {
bundle.putString(KEY_GAMEID, id)
if (!TextUtils.isEmpty(tab)) {
when (tab) {
"comment" -> bundle.putString(KEY_TARGET, EntranceConsts.TAB_TYPE_RATING)
"desc" -> bundle.putString(KEY_TARGET, EntranceConsts.TAB_TYPE_DESC)
"forum" -> bundle.putString(KEY_TARGET, EntranceConsts.TAB_TYPE_BBS)
"zone" -> bundle.putString(KEY_TARGET, EntranceConsts.TAB_TYPE_TRENDS)
"comment" -> bundle.putString(KEY_TARGET, GameDetailTabEntity.TYPE_COMMENT)
"desc" -> bundle.putString(KEY_TARGET, GameDetailTabEntity.TYPE_DETAIL)
"forum" -> bundle.putString(KEY_TARGET, GameDetailTabEntity.TYPE_BBS)
"zone" -> bundle.putString(KEY_TARGET, GameDetailTabEntity.TYPE_ZONE)
}
}
if (traceEvent != null) {
@ -903,7 +862,7 @@ object DirectUtils {
bundle.putString(KEY_ENTRANCE, entrance)
bundle.putString(KEY_GAMEID, id)
bundle.putBoolean(KEY_OPEN_VIDEO_STREAMING, true)
bundle.putString(KEY_TARGET, EntranceConsts.TAB_TYPE_DESC)
bundle.putString(KEY_TARGET, GameDetailTabEntity.TYPE_DETAIL)
jumpActivity(context, bundle)
}
@ -911,7 +870,7 @@ object DirectUtils {
fun directToGameDetail(
context: Context,
id: String,
defaultTab: String = EntranceConsts.TAB_TYPE_DESC,
defaultTab: String = GameDetailTabEntity.TYPE_DETAIL,
entrance: String? = null
) {
val bundle = Bundle()
@ -1569,7 +1528,7 @@ object DirectUtils {
response?.apply {
if (zone.status == "on") {
if (zone.style == "link") {
directToGameDetail(context, gameId, EntranceConsts.TAB_TYPE_TRENDS, entrance)
directToGameDetail(context, gameId, GameDetailTabEntity.TYPE_ZONE, entrance)
} else {
directToWebView(context, url, entrance)
}
@ -2128,17 +2087,13 @@ object DirectUtils {
/**
* 跳转到开服订阅页面
* @param context 上下文
*/
@JvmStatic
fun directToServersCalendarManagement(entrance: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.serversCalendarManagementActivity)
.appendQueryParameter(RouteConsts.QueryParams.REQUIRE_LOGIN, "true")
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, entrance)
.build()
TheRouter.build(uri.toString())
.navigation()
fun directToServersCalendarManagement(context: Context, entrance: String) {
CheckLoginUtils.checkLogin(context, entrance) {
context.startActivity(ServersCalendarManagementActivity.getIntent(context))
}
}
fun directToSearch(
@ -2199,99 +2154,15 @@ object DirectUtils {
}
}
// 跳转云存档详情页
@JvmStatic
fun directToMyGame(defaultTabIndex: Int, source: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.myGameActivity)
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
TheRouter.build(uri.toString())
.withInt(BaseActivity_TabLayout.PAGE_INDEX, defaultTabIndex)
.navigation()
}
@JvmStatic
fun directToDeliveryInfo(source: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.deliveryInfoActivity)
.appendQueryParameter(RouteConsts.QueryParams.REQUIRE_LOGIN, "true")
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
TheRouter.build(uri.toString())
.navigation()
}
@JvmStatic
fun directToGameArchive(source: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.gameArchiveListActivity)
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
TheRouter.build(uri.toString())
.navigation()
}
@JvmStatic
fun directToSimulatorGame(source: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.simulatorGameActivity)
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
TheRouter.build(uri.toString())
.navigation()
}
@JvmStatic
fun directToTeenMode(source: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.teenagerModeActivity)
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
TheRouter.build(uri.toString())
.navigation()
}
@JvmStatic
fun directToUserInfo(source: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.userInfoActivity)
.appendQueryParameter(RouteConsts.QueryParams.REQUIRE_LOGIN, "true")
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
TheRouter.build(uri.toString())
.navigation()
}
@JvmStatic
fun directToCleanApk(context: Context, source: String) {
val uri = Uri.Builder()
.path(RouteConsts.activity.cleanApkActivity)
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
PermissionHelper.checkManageAllFilesOrStoragePermissionBeforeAction(context) {
TheRouter.build(uri.toString())
.navigation()
}
}
@JvmStatic
fun directToAccountSecurity(source: String, isLogoutStyle: Boolean = false) {
val uri = Uri.Builder()
.path(RouteConsts.activity.securityActivity)
.appendQueryParameter(RouteConsts.QueryParams.REQUIRE_LOGIN, "true")
.appendQueryParameter(RouteConsts.QueryParams.SOURCE, source)
.build()
TheRouter.build(uri.toString())
.withString(KEY_ENTRANCE, source)
.withBoolean(KEY_DISPLAY_TYPE, isLogoutStyle)
.navigation()
fun directToCloudArchive(context: Context, gameId: String, gameName: String, configUrl: String = "", entrance: String = "") {
val bundle = Bundle()
val gameEntity = GameEntity(id = gameId, name = gameName)
bundle.putParcelable(KEY_GAME_ENTITY, gameEntity)
bundle.putString(KEY_ARCHIVE_CONFIG_URL, configUrl)
bundle.putString(KEY_ENTRANCE, entrance)
bundle.putBoolean(KEY_USE_ALTERNATIVE_LAYOUT, true)
context.startActivity(ShellActivity.getIntent(context, Type.CLOUD_ARCHIVE, bundle))
}
}

View File

@ -280,9 +280,9 @@ object DownloadItemUtils {
isClickable = true
buttonStyle = DownloadButton.ButtonStyle.NORMAL
} else {
if ("dialog" == offStatus || "third_party" == offStatus) {
if ("dialog" == offStatus) {
text = context.getString(com.gh.gamecenter.feature.R.string.check)
buttonStyle = DownloadButton.ButtonStyle.NONE_WITH_HINT
buttonStyle = DownloadButton.ButtonStyle.NORMAL
} else if ("updating" == offStatus) {
text = context.getString(com.gh.gamecenter.feature.R.string.updating)
buttonStyle = DownloadButton.ButtonStyle.UPDATING
@ -839,25 +839,34 @@ object DownloadItemUtils {
} else {
allStateClickCallback?.onCallback()
clickCallback?.onCallback()
ReservationHelper.showCancelReservationDialog(context, gameEntity, {
NewFlatLogUtils.logMyGameCancelReserveDialogClick(
"确定取消",
gameEntity.id,
gameEntity.name ?: ""
)
ReservationHelper.cancelReservation(gameEntity) {
adapter?.notifyItemChanged(position)
refreshCallback?.onCallback()
if ("download" == gameEntity.reserveStatus) {
ReservationHelper.showDeleteReservationDialog(context) {
ReservationHelper.deleteReservation(gameEntity) {
adapter?.notifyItemChanged(position)
refreshCallback?.onCallback()
}
}
}, object : CancelListener {
override fun onCancel() {
} else {
ReservationHelper.showCancelReservationDialog(context, gameEntity,{
NewFlatLogUtils.logMyGameCancelReserveDialogClick(
"关闭弹窗",
"确定取消",
gameEntity.id,
gameEntity.name ?: ""
)
}
})
ReservationHelper.cancelReservation(gameEntity) {
adapter?.notifyItemChanged(position)
refreshCallback?.onCallback()
}
}, object : CancelListener {
override fun onCancel() {
NewFlatLogUtils.logMyGameCancelReserveDialogClick(
"关闭弹窗",
gameEntity.id,
gameEntity.name ?: ""
)
}
})
}
}
}
return

View File

@ -53,7 +53,6 @@ object DownloadObserver {
private const val CORE_EVENT_DOWNLOAD_COMPLETE_LOGGED = "CORE_EVENT_DOWNLOAD_COMPLETE_LOGGED"
private val mRetryableHashMap = hashMapOf<String, Boolean>()
private val mRetryableProgressMap = hashMapOf<String, Long>()
/**
* 当下载任务是 预约上线提醒 触发的,则所有弹窗均不显示
@ -147,8 +146,7 @@ object DownloadObserver {
|| DownloadStatus.timeout == status
) {
if (mRetryableHashMap[downloadEntity.url] == true
&& (NetworkUtils.isWifiConnected(HaloApp.getInstance().application)
|| NDownloadBridge.isDownloadViaTrafficAllowed(downloadEntity))
&& NetworkUtils.isWifiConnected(HaloApp.getInstance().application)
) {
downloadManager.resumeDownload(downloadEntity.url)
mRetryableHashMap[downloadEntity.url] = false
@ -259,7 +257,6 @@ object DownloadObserver {
}
mRetryableHashMap.remove(downloadEntity.url)
mRetryableProgressMap.remove(downloadEntity.url)
EventBus.getDefault().post(EBDownloadStatus("done", "", "", "", downloadEntity.packageName, ""))
}
@ -267,9 +264,7 @@ object DownloadObserver {
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
// 如果已下载大小发生变化,表示成功恢复下载,则重置重试标记
if (status == DownloadStatus.downloading
&& downloadEntity.progress != mRetryableProgressMap[downloadEntity.url]) {
mRetryableProgressMap[downloadEntity.url] = downloadEntity.progress
if (status == DownloadStatus.downloading) {
mRetryableHashMap[downloadEntity.url] = true
}
}

View File

@ -135,16 +135,12 @@ object GameUtils {
// 畅玩状态优先,且畅玩实体不为空时将 downloadEntity 置为畅玩实体
if (performAsVGame && vGameDownloadEntity != null) {
downloadEntity = vGameDownloadEntity
} else if (!isFromList) {
if (!performAsVGame
&& gameEntity.isDualBtnModeEnabled()
&& downloadEntity?.isVGameDownloadInDualDownloadMode() == true) {
// 下载的任务是由畅玩触发的,并且双下载按钮启用,游戏详情页不需判定为需要安装
downloadEntity = null
} else if (performAsVGame && downloadEntity?.isLocalDownloadInDualDownloadMode() == true) {
// 下载的任务是由下载安装触发的,游戏详情页不需判定为需要安装
downloadEntity = null
}
} else if (!performAsVGame && !isFromList && downloadEntity?.isVGameDownloadInDualDownloadMode() == true) {
// 下载的任务是由畅玩触发的,游戏详情页不需判定为需要安装
downloadEntity = null
} else if (performAsVGame && !isFromList && downloadEntity?.isLocalDownloadInDualDownloadMode() == true) {
// 下载的任务是由下载安装触发的,游戏详情页不需判定为需要安装
downloadEntity = null
}
if (downloadEntity != null) {

View File

@ -2778,34 +2778,4 @@ object NewFlatLogUtils {
parseAndPutMeta()(this)
}.let(::log)
}
// 自有开屏广告加载
fun logSplashAdLoad(id: String) {
json {
KEY_EVENT to "splash_ad_load"
"ad_id" to id
parseAndPutMeta()(this)
}.let(::log)
}
// 自有开屏广告展示
fun logSplashAdShow(id: String, duration: Long) {
json {
KEY_EVENT to "splash_ad_show"
"ad_id" to id
"duration" to duration
parseAndPutMeta()(this)
}.let(::log)
}
// 自有开屏广告加载/展示失败
@JvmStatic
fun logSplashAdFail(id: String, error: String) {
json {
KEY_EVENT to "splash_ad_fail"
"ad_id" to id
"error" to error
parseAndPutMeta()(this)
}.let(::log)
}
}

View File

@ -578,6 +578,7 @@ object PackageHelper {
Utils.log(TAG, "refreshWrongInstallStatus 检查安装状态异常的应用")
val uninstalledButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val updatedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
for (packageName in packageNameSet) {
val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName)
@ -586,9 +587,18 @@ object PackageHelper {
&& installedVersionName == null
) {
uninstalledButKeepingWrongStatusPackageNameSet.add(packageName)
} else if (PackagesManager.isInstalled(packageName)
&& installedVersionName != null
&& !PackagesManager.isInstalledWithSpecificVersion(packageName, installedVersionName)
) {
updatedButKeepingWrongStatusPackageNameSet.add(packageName)
}
}
Utils.log(
TAG,
"refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}"
)
Utils.log(
TAG,
"refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}"
@ -606,6 +616,12 @@ object PackageHelper {
additionalWhiteListPackageNameSet.toString()
)
}
if (updatedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in updatedButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addUpdate(packageName)
}
}
}
}
}
@ -619,6 +635,7 @@ object PackageHelper {
val installedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val uninstalledButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val updatedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
for (game in gameEntityList) {
for (apk in game.getApk()) {
@ -634,6 +651,13 @@ object PackageHelper {
&& installedVersionName == null
) {
uninstalledButKeepingWrongStatusPackageNameSet.add(packageName)
} else if (PackagesManager.isInstalled(packageName)
&& installedVersionName != null
&& !PackagesManager.isInstalledWithSpecificVersion(packageName, installedVersionName)
&& !PackagesManager.isCanUpdate(game.id, packageName, false)
) {
cachedPkgNameAndGameEntityMap.put(packageName, game)
updatedButKeepingWrongStatusPackageNameSet.add(packageName)
}
}
}
@ -642,6 +666,10 @@ object PackageHelper {
TAG,
"refreshWrongInstallStatus 需要更新已安装状态的包数量为 ${installedButKeepingWrongStatusPackageNameSet.size}"
)
Utils.log(
TAG,
"refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}"
)
Utils.log(
TAG,
"refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}"
@ -671,6 +699,12 @@ object PackageHelper {
additionalWhiteListPackageNameSet.toString()
)
}
if (updatedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in updatedButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addUpdate(packageName, cachedPkgNameAndGameEntityMap.remove(packageName))
}
}
}
}
}

View File

@ -18,6 +18,7 @@ import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.install.InstallService
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
@ -193,6 +194,12 @@ object PackageInstaller {
private fun install(context: Context, pkgPath: String, pkgName: String?) {
HaloApp.put(Constants.LAST_INSTALL_GAME, pkgPath)
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU && Build.MANUFACTURER.lowercase().contains("xiaomi")) {
val foregroundServiceIntent = Intent(context, InstallService::class.java)
foregroundServiceIntent.putExtra(InstallService.KEY_SERVICE_ACTION, InstallService.START_FOREGROUND)
context.startForegroundService(foregroundServiceIntent)
}
val installIntent = getInstallIntent(context, pkgPath)
context.startActivity(installIntent)
@ -277,12 +284,7 @@ object PackageInstaller {
installIntent.setDataAndType(uri, "application/vnd.android.package-archive")
}
// 优选系统的安装器(遇到 Exception 就回落到正常的安装器)
try {
updateSystemInstallerIfAvailable(context, installIntent)
} catch (ignored: Exception) {
// ignored
}
updateSystemInstallerIfAvailable(context, installIntent)
InstallUtils.getInstance()
.addInstall(PackageUtils.getPackageNameByPath(context, path))

View File

@ -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.manager.PackagesManager
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.vspace.VHelper
object PackageLauncher {
@ -81,11 +81,28 @@ object PackageLauncher {
gameEntity: GameEntity? = null,
packageName: String?
) {
if (packageName.isNullOrEmpty()) {
ToastUtils.toast("启动失败")
return
}
// 获取 GameInstall 实体,用于记录启动日志用
val gameInstall = if (gameEntity != null) {
GameInstall.transformGameInstall(gameEntity, packageName)
} else {
PackageRepository.gameInstalled.find { it.packageName == packageName }
}
if (gameInstall != null) {
NewFlatLogUtils.logGameLaunch(
gameId = gameInstall.id ?: "unknown",
gameName = gameInstall.name ?: "unknown",
gameCategory = gameInstall.category ?: "unknown",
downloadStatus = if (gameInstall.downloadStatus == "demo") "试玩" else "下载"
)
}
try {
val intent = context.applicationContext.packageManager.getLaunchIntentForPackage(packageName)
if (intent != null) {
@ -96,26 +113,6 @@ object PackageLauncher {
} catch (e: Exception) {
ToastUtils.toast( "启动失败")
}
try {
// 获取 GameInstall 实体,用于记录启动日志用
val gameInstall = if (gameEntity != null) {
GameInstall.transformGameInstall(gameEntity, packageName)
} else {
PackagesManager.getInstalledList().find { it.packageName == packageName }
}
if (gameInstall != null) {
NewFlatLogUtils.logGameLaunch(
gameId = gameInstall.id ?: "unknown",
gameName = gameInstall.name ?: "unknown",
gameCategory = gameInstall.category ?: "unknown",
downloadStatus = if (gameInstall.downloadStatus == "demo") "试玩" else "下载"
)
}
} catch (e: RuntimeException) {
// 都 DeadSystemException 了,还想啥日志上报
}
}
}

View File

@ -14,6 +14,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.text.TextUtils;
import android.util.AndroidException;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -28,9 +29,9 @@ import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.core.utils.MD5Utils;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.feature.entity.ApkEntity;
import com.gh.gamecenter.feature.entity.GameEntity;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.feature.utils.SentryHelper;
import com.gh.gamecenter.manager.PackagesManager;
import com.gh.vspace.VHelper;
@ -301,7 +302,7 @@ public class PackageUtils {
Signature[] signatures = packageInfo.signatures;
// 使用幸运破解器破解安卓签名认证可能会出现不用签名也能装的情况,这里有可能是空的
if (signatures.length > 0 && signatures[0] != null) {
if (signatures[0] != null) {
return parseSignature(signatures[0].toByteArray());
} else {
return new String[]{null, null};
@ -541,8 +542,10 @@ public class PackageUtils {
try {
Intent intent = context.getApplicationContext().getPackageManager().getLaunchIntentForPackage(packageName);
return intent != null;
} catch (Exception exception) {
return PackageHelper.INSTANCE.getLocalPackageNameSet().contains(packageName);
} catch (IllegalArgumentException exception) {
// 一些设备调用获取 intent 的时候会触发 Parcel.readException !
exception.printStackTrace();
return false;
}
}
@ -642,19 +645,6 @@ public class PackageUtils {
return 0;
}
/*
* 获取应用的名称
*/
public static CharSequence getNameByPackageName(Context context, String packageName) {
try {
PackageManager packageManager = context.getApplicationContext().getPackageManager();
return packageManager.getApplicationLabel(packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA));
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/*
* 获取应用的 icon

View File

@ -29,31 +29,53 @@ import okhttp3.ResponseBody
object ReservationHelper {
@SuppressLint("CheckResult")
@JvmStatic
fun cancelReservation(
fun deleteReservation(game: GameEntity, refreshCallback: EmptyCallback) {
deleteOrCancelReservation(game, true, refreshCallback)
}
@JvmStatic
fun cancelReservation(game: GameEntity, refreshCallback: EmptyCallback) {
deleteOrCancelReservation(game, false, refreshCallback)
}
@SuppressLint("CheckResult")
private fun deleteOrCancelReservation(
game: GameEntity,
deleteReservation: Boolean,
refreshCallback: EmptyCallback
) {
val retrofit = RetrofitManager.getInstance()
retrofit.newApi
.cancelGameReservation(
game.id,
getReserveRequestBody(game, context = HaloApp.getInstance().application)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
ReservationRepository.removeReservationFromMemoryAndRefresh(game.id)
refreshCallback.onCallback()
}
override fun onFailure(exception: Exception) {
Utils.toast(HaloApp.getInstance().application, exception.message)
exception.printStackTrace()
}
})
val retrofit = RetrofitManager.getInstance()
val single = if (deleteReservation) {
retrofit.newApi
.deleteGameReservation(
game.id,
getReserveRequestBody(game, context = HaloApp.getInstance().application)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
} else {
retrofit.newApi
.cancelGameReservation(
game.id,
getReserveRequestBody(game, context = HaloApp.getInstance().application)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
single.subscribe(object : BiResponse<ResponseBody>() {
override fun onSuccess(data: ResponseBody) {
ReservationRepository.removeReservationFromMemoryAndRefresh(game.id)
refreshCallback.onCallback()
}
override fun onFailure(exception: Exception) {
Utils.toast(HaloApp.getInstance().application, exception.message)
exception.printStackTrace()
}
})
}
@JvmStatic
@ -124,6 +146,21 @@ object ReservationHelper {
})
}
@JvmStatic
fun showDeleteReservationDialog(context: Context, emptyCallback: EmptyCallback) {
DialogUtils.showCancelOrDeleteReservationDialog(
context,
"删除预约",
"游戏已上线,你可以删除此预约记录,确定删除吗?",
"确定删除",
"暂不删除", object : ConfirmListener {
override fun onConfirm() {
emptyCallback.onCallback()
}
}, null
)
}
@JvmStatic
fun showCancelReservationDialog(context: Context, game: GameEntity?, emptyCallback: EmptyCallback) {
showCancelReservationDialog(context, game, emptyCallback, null)

View File

@ -19,7 +19,7 @@ import com.gh.gamecenter.game.columncollection.detail.ColumnCollectionDetailFrag
import com.gh.gamecenter.game.commoncollection.detail.CustomCommonCollectionDetailFragment
import com.gh.gamecenter.gamecollection.hotlist.GameCollectionHotListWrapperFragment
import com.gh.gamecenter.gamecollection.square.GameCollectionSquareFragment
import com.gh.gamecenter.gamedetail.GameDetailFragment
import com.gh.gamecenter.gamedetail.GameDetailWrapperFragment
import com.gh.gamecenter.info.InfoWrapperFragment
import com.gh.gamecenter.libao.LibaoDetailFragment
import com.gh.gamecenter.libao.LibaoFragment
@ -88,7 +88,7 @@ object ViewPagerFragmentHelper {
// 游戏详情页
TYPE_GAME -> {
bundle.putString(EntranceConsts.KEY_GAMEID, linkEntity.link)
GameDetailFragment().with(bundle)
GameDetailWrapperFragment().with(bundle)
}
// 我的光环
TYPE_MY_HALO -> {
@ -149,11 +149,11 @@ object ViewPagerFragmentHelper {
NewQuestionDetailFragment().with(bundle)
}
// 其他原来带Toolbar的Fragment
else -> createToolbarWrapperFragment(parentFragment, bundle, linkEntity, isTabWrapper)
else -> createToolbarWrapperFragment(bundle, linkEntity, isTabWrapper)
}
}
private fun createToolbarWrapperFragment(parentFragment: Fragment?, bundle: Bundle, entity: LinkEntity, isTabWrapper: Boolean): Fragment {
private fun createToolbarWrapperFragment(bundle: Bundle, entity: LinkEntity, isTabWrapper: Boolean): Fragment {
var className = ReloadFragment::class.java.name
when (entity.type) {

View File

@ -48,7 +48,7 @@ class FlexLinearLayout @JvmOverloads constructor(context: Context, attrs: Attrib
ta.recycle()
}
fun setTags(tags: ArrayList<TagStyleEntity>) {
fun setTags(tags: List<TagStyleEntity>) {
mTags.clear()
mTotalCount = tags.size
mTotalWidth = measuredWidth

View File

@ -2,7 +2,6 @@ package com.gh.download.simple
import android.annotation.SuppressLint
import android.database.sqlite.SQLiteException
import android.database.sqlite.SQLiteFullException
import com.gh.gamecenter.core.utils.ToastUtils
import com.lg.download.*
import com.lg.download.listener.InnerDownloadListener
@ -175,9 +174,6 @@ object DownloadMessageHandler : InnerDownloadListener {
DownloadError.CONTENT_LENGTH_IS_ZERO -> {
ToastUtils.toast("下载链接异常,请检查")
}
DownloadError.DISK_IS_FULL -> {
ToastUtils.toast("磁盘已满,请清理空间后获得更好的体验")
}
else -> {
// 想怎么处理就怎么处理
}
@ -268,30 +264,18 @@ object DownloadMessageHandler : InnerDownloadListener {
}
fun insertDownloadToDatabase(downloadEntity: SimpleDownloadEntity) {
try {
mDownloadDao.insertDownloadEntity(downloadEntity)
updateDownloadList()
} catch (e: SQLiteException) {
if (e is SQLiteFullException) {
ToastUtils.showToast("磁盘已满,请清理空间获得更好的体验")
}
e.printStackTrace()
}
mDownloadDao.insertDownloadEntity(downloadEntity)
updateDownloadList()
}
fun updateDownloadToDatabase(
downloadEntity: SimpleDownloadEntity,
updateDownloadList: Boolean = false
) {
try {
mDownloadDao.updateDownloadEntity(downloadEntity)
mDownloadDao.updateDownloadEntity(downloadEntity)
if (updateDownloadList) {
updateDownloadList()
}
} catch (e: SQLiteFullException) {
// 底层的下载服务遇到 SQLiteFullException 时会自动暂停下载任务,上层这里就不用纠结处理方式了
e.printStackTrace()
if (updateDownloadList) {
updateDownloadList()
}
}

View File

@ -3,25 +3,26 @@ package com.gh.gamecenter;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import com.gh.gamecenter.common.base.activity.ToolBarActivity;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.utils.BitmapUtils;
import com.gh.gamecenter.common.view.CropImageCustom;
import com.gh.gamecenter.common.view.cropbox.CropBoxStyle;
import com.gh.gamecenter.core.utils.DisplayUtils;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.view.CropImageCustom;
import java.io.File;
import java.lang.ref.SoftReference;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
/**
* 裁剪图片
*/
@ -31,8 +32,6 @@ public class CropImageActivity extends ToolBarActivity {
public static final String RESULT_CLIP_PATH = "result_clip_path";
public static final String RESULT_ORIGINAL_PATH = "result_original_path";
private SoftReference<Bitmap> reference;
protected boolean mBlackTheme = false;
@ -52,7 +51,7 @@ public class CropImageActivity extends ToolBarActivity {
Intent intent = new Intent(context, CropImageActivity.class);
intent.putExtra(EntranceConsts.KEY_PATH, picturePath);
intent.putExtra(EntranceConsts.KEY_ENTRANCE, entrance);
intent.putExtra(EntranceConsts.KEY_IMAGE_CROP_STYLE, new CropBoxStyle.Rectangle(cropRatio));
intent.putExtra(EntranceConsts.KEY_IMAGE_CROP_RATIO, cropRatio);
intent.putExtra(EntranceConsts.KEY_BLACK_THEME, isBlackTheme);
intent.putExtra(EntranceConsts.KEY_ASSIST_RES, assistRes);
return intent;
@ -69,14 +68,20 @@ public class CropImageActivity extends ToolBarActivity {
super.onCreate(savedInstanceState);
mCropImageCustom = findViewById(R.id.cropimage_custom);
TextView tvCancel = findViewById(R.id.tv_cancel);
TextView tvSubmit = findViewById(R.id.tv_submit);
View statusBarView = findViewById(R.id.status_bar);
CropBoxStyle boxStyle = getIntent().getParcelableExtra(EntranceConsts.KEY_IMAGE_CROP_STYLE);
if (boxStyle == null) {
boxStyle = new CropBoxStyle.Rectangle(1F);
}
mCropImageCustom.setCropBoxStyle(boxStyle);
mTitleTv.setTextColor(mBlackTheme ? Color.WHITE : Color.BLACK);
mToolbar.setBackgroundColor(getResources().getColor(mBlackTheme ? com.gh.gamecenter.common.R.color.text_28282E : com.gh.gamecenter.common.R.color.white));
statusBarView.setBackgroundColor(getResources().getColor(mBlackTheme ? com.gh.gamecenter.common.R.color.text_28282E : com.gh.gamecenter.common.R.color.white));
setNavigationTitle(getString(R.string.title_crop_image));
setToolbarMenu(R.menu.menu_positive);
MenuItem menuItem = getMenuItem(R.id.layout_menu_positive);
TextView menuButton = menuItem.getActionView().findViewById(R.id.menu_answer_post);
menuButton.setTextColor(getResources().getColor(com.gh.gamecenter.common.R.color.text_theme));
float ratio = getIntent().getFloatExtra(EntranceConsts.KEY_IMAGE_CROP_RATIO, 1F);
mCropImageCustom.setCropRatio(ratio);
int assistRes = getIntent().getIntExtra(EntranceConsts.KEY_ASSIST_RES, -1);
if (assistRes > 0) {
@ -84,21 +89,8 @@ public class CropImageActivity extends ToolBarActivity {
addAssistView(view);
}
DisplayUtils.setLightStatusBar(this, false);
DisplayUtils.setStatusBarColor(this, com.gh.gamecenter.common.R.color.transparent, false);
tvCancel.setOnClickListener(v -> finish());
tvSubmit.setOnClickListener(v -> saveImage());
}
protected void saveImage() {
Intent data = new Intent();
String clipPath = getCacheDir().getAbsolutePath() + File.separator + System.currentTimeMillis() + ".jpg";
mCropImageCustom.savePicture(clipPath);
data.putExtra(RESULT_CLIP_PATH, clipPath);
setResult(RESULT_OK, data);
finish();
DisplayUtils.setLightStatusBar(this, !mBlackTheme);
DisplayUtils.setStatusBarColor(this, com.gh.gamecenter.common.R.color.transparent, !mBlackTheme);
}
@Override
@ -106,6 +98,20 @@ public class CropImageActivity extends ToolBarActivity {
return mBlackTheme ? com.gh.gamecenter.common.R.drawable.ic_toolbar_back_white : com.gh.gamecenter.common.R.drawable.ic_bar_back;
}
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.layout_menu_positive) {
Intent data = new Intent();
String clipPath = getCacheDir().getAbsolutePath() + File.separator + System.currentTimeMillis() + ".jpg";
mCropImageCustom.savePicture(clipPath);
data.putExtra(RESULT_CLIP_PATH, clipPath);
setResult(RESULT_OK, data);
finish();
}
return super.onMenuItemClick(item);
}
public void addAssistView(View view) {
mCropImageCustom.addAssistView(view);
}

View File

@ -5,15 +5,10 @@ import android.content.ContextWrapper
import android.content.Intent
import android.os.Bundle
import android.view.View
import com.therouter.router.Autowired
import com.therouter.router.Route
import com.therouter.TheRouter
import com.gh.base.DownloadToolbarActivity
import com.gh.common.exposure.ExposureManager
import com.gh.common.exposure.ExposureTraceUtils.appendTrace
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.base.activity.ToolBarActivity.NORMAL_FRAGMENT_BUNDLE
import com.gh.gamecenter.common.base.activity.ToolBarActivity.NORMAL_FRAGMENT_NAME
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.utils.toArrayList
@ -24,7 +19,11 @@ import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureEvent.Companion.createEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.gamedetail.GameDetailFragment
import com.gh.gamecenter.gamedetail.GameDetailWrapperFragment
import com.gh.gamecenter.gamedetail.entity.GameDetailTabEntity
import com.therouter.TheRouter
import com.therouter.router.Autowired
import com.therouter.router.Route
@Route(
path = RouteConsts.activity.gameDetailActivity,
@ -74,11 +73,11 @@ class GameDetailActivity : DownloadToolbarActivity() {
generateDataFromRoute()
super.onCreate(savedInstanceState)
DisplayUtils.transparentStatusBar(this)
DisplayUtils.setStatusBarColor(this, com.gh.gamecenter.common.R.color.transparent, !mIsDarkModeOn)
}
override fun provideNormalIntent(): Intent {
return getTargetIntent(this, GameDetailActivity::class.java, GameDetailFragment::class.java)
return getTargetIntent(this, GameDetailActivity::class.java, GameDetailWrapperFragment::class.java)
}
override fun getLayoutId() = R.layout.activity_game_detail
@ -127,10 +126,15 @@ class GameDetailActivity : DownloadToolbarActivity() {
private fun generateDataFromRoute() {
val bundle = intent.extras
intent?.putExtra(NORMAL_FRAGMENT_NAME, GameDetailFragment::class.java.canonicalName)
intent?.putExtra(NORMAL_FRAGMENT_NAME, GameDetailWrapperFragment::class.java.canonicalName)
intent?.putExtra(NORMAL_FRAGMENT_BUNDLE, bundle)
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
DisplayUtils.setStatusBarColor(this, com.gh.gamecenter.common.R.color.transparent, !mIsDarkModeOn)
}
companion object {
@JvmStatic
@ -190,12 +194,12 @@ class GameDetailActivity : DownloadToolbarActivity() {
}
if (scrollToLibao) {
bundle.putString(EntranceConsts.KEY_TARGET, EntranceConsts.TAB_TYPE_DESC)
bundle.putString(EntranceConsts.KEY_TARGET, GameDetailTabEntity.TYPE_DETAIL)
bundle.putBoolean(EntranceConsts.KEY_SCROLL_TO_LIBAO, true)
}
if (scrollToServer) {
bundle.putString(EntranceConsts.KEY_TARGET, EntranceConsts.TAB_TYPE_DESC)
bundle.putString(EntranceConsts.KEY_TARGET, GameDetailTabEntity.TYPE_DETAIL)
bundle.putBoolean(EntranceConsts.KEY_SCROLL_TO_SERVER, true)
}
@ -302,7 +306,7 @@ class GameDetailActivity : DownloadToolbarActivity() {
}
if (openVideoStreaming) {
bundle.putBoolean(EntranceConsts.KEY_OPEN_VIDEO_STREAMING, true)
bundle.putString(EntranceConsts.KEY_TARGET, EntranceConsts.TAB_TYPE_DESC)
bundle.putString(EntranceConsts.KEY_TARGET, GameDetailTabEntity.TYPE_DETAIL)
}
if (openPlatformWindow) {
bundle.putBoolean(EntranceConsts.KEY_OPEN_PLATFORM_WINDOW, true)
@ -316,7 +320,7 @@ class GameDetailActivity : DownloadToolbarActivity() {
}
}
if (scrollToLibao) {
bundle.putString(EntranceConsts.KEY_TARGET, EntranceConsts.TAB_TYPE_DESC)
bundle.putString(EntranceConsts.KEY_TARGET, GameDetailTabEntity.TYPE_DETAIL)
bundle.putBoolean(EntranceConsts.KEY_SCROLL_TO_LIBAO, true)
}
bundle.putString(EntranceConsts.KEY_GAME_ID, gameId)

View File

@ -166,13 +166,8 @@ public class MainActivity extends BaseActivity {
private final Handler handler = new Handler();
private boolean mShouldShowAd = false; // 是否显示广告
private Bundle mTempSavedInstanceState;
private boolean mFragmentIsCreated = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
mTempSavedInstanceState = savedInstanceState;
mShouldShowAd = getIntent().getBooleanExtra(SHOW_AD, false) && savedInstanceState == null
&& !HaloApp.getInstance().isAlreadyUpAndRunning;
HaloApp.getInstance().isAlreadyUpAndRunning = true;
@ -180,12 +175,21 @@ public class MainActivity extends BaseActivity {
mMainWrapperViewModel = new ViewModelProvider(this, new MainWrapperViewModel.Factory(HaloApp.getInstance()))
.get(MainWrapperViewModel.class);
DisplayUtils.transparentStatusBar(this);
DisplayUtils.updateGlobalScreen(this);
super.onCreate(savedInstanceState);
setStatusBarColor(Color.TRANSPARENT);
Fragment fragmentFromFM = getSupportFragmentManager().findFragmentById(com.gh.gamecenter.selector.R.id.layout_activity_content);
mMainWrapperFragment = fragmentFromFM != null ? (MainWrapperFragment) fragmentFromFM : new MainWrapperFragment();
if (savedInstanceState != null) {
mMainWrapperFragment.setArguments(savedInstanceState);
} else if (getIntent() != null) {
mMainWrapperFragment.setArguments(getIntent().getExtras());
}
replaceFragment(mMainWrapperFragment);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
if (HaloApp.getInstance().isNewForThisVersion) {
LunchType lunchType = HaloApp.getInstance().getLaunchType();
@ -211,6 +215,7 @@ public class MainActivity extends BaseActivity {
DataUtils.getGid();
}
mPackageViewModel = ViewModelProviders.of(this, new PackageViewModel.Factory()).get(PackageViewModel.class);
final boolean containsErrorMsg = com.gh.gamecenter.common.constant.Config.isContainsErrorMsg();
@ -268,7 +273,6 @@ public class MainActivity extends BaseActivity {
if (mShouldShowAd) {
showAd();
} else {
doInitMainFragment(mTempSavedInstanceState);
hideTextAd();
hideSplashAd();
}
@ -324,23 +328,6 @@ public class MainActivity extends BaseActivity {
CertificationSwitchHelper.getCertificationSwitch();
}
private void doInitMainFragment(Bundle savedInstanceState) {
if (mFragmentIsCreated) return;
mTempSavedInstanceState = null;
Fragment fragmentFromFM = getSupportFragmentManager().findFragmentById(com.gh.gamecenter.selector.R.id.layout_activity_content);
mMainWrapperFragment = fragmentFromFM != null ? (MainWrapperFragment) fragmentFromFM : new MainWrapperFragment();
if (savedInstanceState != null) {
mMainWrapperFragment.setArguments(savedInstanceState);
} else if (getIntent() != null) {
mMainWrapperFragment.setArguments(getIntent().getExtras());
}
replaceFragment(mMainWrapperFragment);
mFragmentIsCreated = true;
}
@SuppressLint("CheckResult")
private void getTeenagerMode() {
RetrofitManager.getInstance()
@ -554,31 +541,19 @@ public class MainActivity extends BaseActivity {
protected void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == COUNTDOWN_AD || msg.what == COUNTDOWN_SDK_AD) {
mCountdownCount++;
int maxCount;
if (msg.what == COUNTDOWN_AD) {
maxCount = mCountdownMaxCount;
} else {
maxCount = COUNTDOWN_SDK_MAX_COUNT;
}
// 读秒到一半的时候初始化 MainWrapperFragment
if (mCountdownCount == maxCount / 2) {
doInitMainFragment(mTempSavedInstanceState);
}
mCountdownCount++;
if (maxCount < mCountdownCount) {
AdDelegateHelper.INSTANCE.setShowingSplashAd(false);
hideSplashAd();
if (msg.what == COUNTDOWN_AD && msg.obj instanceof StartupAdEntity) {
StartupAdEntity ad = (StartupAdEntity) msg.obj;
if (!AdDelegateHelper.INSTANCE.isOwnerSplashAdShown()) {
com.gh.common.util.NewFlatLogUtils.logSplashAdFail(ad.getId(), "广告加载超时");
}
AdDelegateHelper.INSTANCE.setOwnerSplashAdShown(false);
LinkEntity linkEntity = ad.getJump();
SensorsBridge.trackEvent(
"SplashAdOwnSkip",
@ -658,11 +633,10 @@ public class MainActivity extends BaseActivity {
ExtensionsKt.removeFromParent(startSdkAdIcpContainer, true);
}
onAdHidden();
onSplashHidden();
}
private void onAdHidden() {
doInitMainFragment(mTempSavedInstanceState);
private void onSplashHidden() {
// 通知全局弹窗可以进行显示
AppExecutor.getUiExecutor().execute(GlobalPriorityChainHelper.INSTANCE::start);
}
@ -880,9 +854,7 @@ public class MainActivity extends BaseActivity {
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0
&& mMainWrapperFragment != null
&& !mMainWrapperFragment.onHandleBackPressed()) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0 && !mMainWrapperFragment.onHandleBackPressed()) {
DownloadEntity downloadEntity = null;
for (DownloadEntity entity : DownloadManager.getInstance().getAllDownloadEntityExcludeSilentTask()) {
if (entity.getStatus().equals(DownloadStatus.done)) {
@ -1073,7 +1045,6 @@ 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);

View File

@ -15,7 +15,6 @@ 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.*
@ -191,7 +190,6 @@ open class SearchActivity : BaseActivity() {
when (type) {
SearchType.AUTO -> handleAutoSearch(key)
SearchType.DEFAULT -> handleDefaultSearch(key)
SearchType.DISCOVERY -> handleDiscoverySearch(key)
SearchType.RANK -> handleRankSearch(key)
SearchType.HOT -> handleHotSearch(key)
SearchType.HISTORY -> handleHistorySearch(key)
@ -245,22 +243,6 @@ open class SearchActivity : BaseActivity() {
)
}
protected open fun handleDiscoverySearch(key: String?) {
mSearchKey = key
searchEt.setText(key)
searchEt.setSelection(searchEt.text.length)
updateDisplayType(GAME_DETAIL)
LogUtils.uploadSearchGame("searching", "搜索页", key, "搜索发现")
SensorsBridge.trackSearchButtonClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
key ?: "",
TRACK_SEARCH_TYPE_DISCOVERY,
mSourceEntrance
)
}
protected open fun handleDefaultSearch(key: String?) {
mSearchKey = key
searchEt.setText(key)
@ -329,19 +311,6 @@ open class SearchActivity : BaseActivity() {
// MtaHelper.onEvent("游戏搜索", "主动搜索", newSearchKey)
}
override fun onResume() {
super.onResume()
val newSearchKey = searchEt.text.toString().trim { it <= ' ' }
if (newSearchKey.isBlank()) {
try {
popBackToFragment(SearchDefaultFragment::class.java.name)
} catch (e: Exception) {
// no implement
}
}
}
protected open fun provideDao(): ISearchHistoryDao = SearchHistoryDao(this)
open fun updateDisplayType(type: DisplayType) {
@ -412,7 +381,7 @@ open class SearchActivity : BaseActivity() {
}
protected fun popBackToFragment(tag: String) {
supportFragmentManager.popBackStackAllowStateLoss(tag, 0)
supportFragmentManager.popBackStack(tag, 0)
}
@Subscribe(threadMode = ThreadMode.MAIN)
@ -421,7 +390,6 @@ open class SearchActivity : BaseActivity() {
SearchType.HISTORY.value -> search(SearchType.HISTORY, search.key)
SearchType.HOT.value -> search(SearchType.HOT, search.key)
SearchType.RANK.value -> search(SearchType.RANK, search.key)
SearchType.DISCOVERY.value -> search(SearchType.DISCOVERY, search.key)
"click" -> DataCollectionUtils.uploadSearchClick(
this, mSearchKey, mSearchType.value, "搜索页面",
@ -466,7 +434,6 @@ open class SearchActivity : BaseActivity() {
const val TRACK_SEARCH_TYPE_DEFAULT = "默认搜索"
const val TRACK_SEARCH_TYPE_HISTORY = "历史搜索"
const val TRACK_SEARCH_TYPE_RANK = "榜单搜索"
const val TRACK_SEARCH_TYPE_DISCOVERY = "搜索发现"
@JvmStatic
fun toTrackSearchType(type: String) = when (type) {
@ -474,7 +441,6 @@ open class SearchActivity : BaseActivity() {
SearchType.MANUAL.value -> TRACK_SEARCH_TYPE_INPUT
SearchType.HISTORY.value -> TRACK_SEARCH_TYPE_HISTORY
SearchType.RANK.value -> TRACK_SEARCH_TYPE_RANK
SearchType.DISCOVERY.value -> TRACK_SEARCH_TYPE_DISCOVERY
else -> TRACK_SEARCH_TYPE_DEFAULT
}
@ -524,8 +490,7 @@ enum class SearchType(var value: String) {
HISTORY("history"),
MANUAL("initiative"),
HOT("remen"),
RANK("rank"),
DISCOVERY("dicovery");
RANK("rank");
fun toChinese() = when (this) {
AUTO -> "自动搜索"
@ -534,7 +499,6 @@ enum class SearchType(var value: String) {
MANUAL -> "主动搜索"
HOT -> "热门搜索"
RANK -> "榜单搜索"
DISCOVERY -> "搜索发现"
}
companion object {

View File

@ -5,11 +5,12 @@ import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.view.View
import com.gh.gamecenter.amway.AmwaySuccessFragment
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.base.fragment.BaseFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.amway.AmwaySuccessFragment
import com.gh.gamecenter.gamedetail.LibaoListFragment
import com.gh.gamecenter.gamedetail.cloudarchive.CloudArchiveFragment
import com.gh.gamecenter.gamedetail.libao.LibaoListFragment
import com.halo.assistant.fragment.SwitchInstallMethodFragment
import com.halo.assistant.fragment.user.ManuallyRealNameFragment
import com.halo.assistant.fragment.user.RealNameInfoFragment
@ -38,6 +39,7 @@ class ShellActivity : ToolBarActivity() {
Type.REAL_NAME_INFO -> startFragment(RealNameInfoFragment().with(bundle))
Type.MANUALLY_REAL_NAME -> startFragment(ManuallyRealNameFragment().with(extraData))
Type.SIMPLE_LIBAO_LIST -> startFragment(LibaoListFragment.newInstance(extraData))
Type.CLOUD_ARCHIVE -> startFragment(CloudArchiveFragment().with(extraData))
}
}
@ -72,7 +74,8 @@ class ShellActivity : ToolBarActivity() {
SWITCH_INSTALL_METHOD("switch_install_method"),
REAL_NAME_INFO("real_name_info"),
MANUALLY_REAL_NAME("manually_real_name"),
SIMPLE_LIBAO_LIST("simple_libao_list");
SIMPLE_LIBAO_LIST("simple_libao_list"),
CLOUD_ARCHIVE("cloud_archive");
companion object {
fun fromString(typeString: String): Type {

View File

@ -62,16 +62,16 @@ import com.gh.gamecenter.common.base.activity.BaseActivity;
import com.gh.gamecenter.common.constant.Constants;
import com.gh.gamecenter.common.constant.EntranceConsts;
import com.gh.gamecenter.common.entity.CommunityEntity;
import com.gh.gamecenter.common.entity.LaunchRedirect;
import com.gh.gamecenter.common.entity.LinkEntity;
import com.gh.gamecenter.common.entity.SimpleGameEntity;
import com.gh.gamecenter.core.utils.GsonUtils;
import com.gh.gamecenter.core.utils.ToastUtils;
import com.gh.gamecenter.entity.SubjectData;
import com.gh.gamecenter.entity.SubjectRecommendEntity;
import com.gh.gamecenter.entity.VideoLinkEntity;
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper;
import com.gh.gamecenter.feature.utils.PlatformUtils;
import com.gh.gamecenter.login.view.LoginActivity;
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper;
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel;
import com.gh.gamecenter.video.videomanager.VideoManagerActivity;
import com.gh.vspace.VHelper;
@ -356,8 +356,8 @@ public class SkipActivity extends BaseActivity {
if (!TextUtils.isEmpty(dataString)) {
byte[] linkData = Base64.decode(dataString, Base64.DEFAULT);
String linkDataString = new String(linkData, "UTF-8");
LaunchRedirect launchRedirect = GsonUtils.fromJson(linkDataString, LaunchRedirect.class);
DirectUtils.directToLinkPage(this, launchRedirect, entrance, "", "");
LinkEntity le = GsonUtils.INSTANCE.getGson().fromJson(linkDataString, LinkEntity.class);
DirectUtils.directToLinkPage(this, le, entrance, "", "");
}
} catch (Exception e) {
e.printStackTrace();

View File

@ -282,11 +282,11 @@ class SplashScreenActivity : BaseActivity(), ISplashScreen {
SensorsBridge.init(HaloApp.getInstance(), HaloApp.getInstance().channel)
SensorsBridge.setOAID(HaloApp.getInstance().oaid)
// val pushProvider = ARouter.getInstance().build(RouteConsts.provider.push).navigation() as? IPushProvider
// val registrationId = pushProvider?.getRegistrationId(this)
// if (!registrationId.isNullOrEmpty()) {
// SensorsBridge.profileSet(KEY_REGISTRATION_ID, registrationId)
// }
val pushProvider = TheRouter.get(IPushProvider::class.java)
val registrationId = pushProvider?.getRegistrationId(this)
if (!registrationId.isNullOrEmpty()) {
SensorsBridge.profileAppend(KEY_REGISTRATION_ID, registrationId)
}
}
private fun prefetchData() {

View File

@ -4,15 +4,12 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.halo.assistant.fragment.user.UserInfoFragment
import com.therouter.router.Route
@Route(
path = RouteConsts.activity.userInfoActivity,
description = "个人中心"
)
/**
* 编辑资料
*/
class UserInfoActivity : ToolBarActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
@ -20,14 +17,6 @@ class UserInfoActivity : ToolBarActivity() {
updateStatusBarColor(com.gh.gamecenter.common.R.color.ui_surface, com.gh.gamecenter.common.R.color.ui_surface)
}
override fun provideNormalIntent(): Intent {
return getTargetIntent(
this,
UserInfoActivity::class.java,
UserInfoFragment::class.java
)
}
companion object {
fun getIntent(context: Context?): Intent? {
return getTargetIntent(

View File

@ -2,6 +2,7 @@ package com.gh.gamecenter.adapter;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.text.Html;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
@ -12,6 +13,7 @@ import android.text.style.ClickableSpan;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
@ -20,9 +22,13 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
import com.facebook.drawee.view.SimpleDraweeView;
import com.gh.common.util.DirectUtils;
import com.gh.common.util.LibaoUtils;
import com.gh.gamecenter.GameDetailActivity;
import com.gh.gamecenter.ImageViewerActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.LibaoDetailContentViewHolder;
import com.gh.gamecenter.adapter.viewholder.LibaoDetailTopViewHolder;
@ -31,6 +37,7 @@ import com.gh.gamecenter.common.entity.SimpleGameEntity;
import com.gh.gamecenter.common.entity.SuggestType;
import com.gh.gamecenter.common.retrofit.Response;
import com.gh.gamecenter.common.utils.ExtensionsKt;
import com.gh.gamecenter.common.utils.ImageUtils;
import com.gh.gamecenter.common.utils.PicassoImageGetter;
import com.gh.gamecenter.common.viewholder.FooterViewHolder;
import com.gh.gamecenter.core.utils.DisplayUtils;
@ -79,6 +86,7 @@ public class LibaoDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
private String mEntrance;
private final int TYPE_FOOTER = 100;
public LibaoDetailTopViewHolder libaoDetailTopViewHolder;
private ArrayList<View> mImageViewList = new ArrayList<>();
public LibaoDetailAdapter(Context context, OnRequestCallBackListener onRequestCallBackListener,
OnCodeScrollListener onCodeScrollListener, LibaoEntity libaoEntity,
@ -317,6 +325,31 @@ public class LibaoDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
holder.binding.libaodetailContentLl.setVisibility(View.VISIBLE);
holder.binding.libaodetailContent.setText(Html.fromHtml(mLibaoEntity.getContent()));
}
if (mLibaoEntity.getMaterials().isEmpty()) {
holder.binding.horizontalScrollView.setVisibility(View.GONE);
} else {
holder.binding.horizontalScrollView.setVisibility(View.VISIBLE);
holder.binding.imagesContainer.removeAllViews();
mImageViewList.clear();
for (int i = 0; i < mLibaoEntity.getMaterials().size(); i++) {
String imageUrl = mLibaoEntity.getMaterials().get(i);
SimpleDraweeView imageView = new SimpleDraweeView(mContext);
imageView.setHierarchy(new GenericDraweeHierarchyBuilder(mContext.getResources())
.setFadeDuration(500)
.setPlaceholderImage(com.gh.gamecenter.common.R.drawable.occupy, ScalingUtils.ScaleType.FIT_XY)
.build());
ImageUtils.display(imageView, imageUrl);
final int index = i;
imageView.setOnClickListener(v -> {
Intent intent = ImageViewerActivity.getIntent(mContext, mLibaoEntity.getMaterials(), index, mImageViewList, mEntrance);
mContext.startActivity(intent);
});
mImageViewList.add(imageView);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(DisplayUtils.dip2px(24F), DisplayUtils.dip2px(24F));
layoutParams.setMargins(i != 0 ? DisplayUtils.dip2px(16F) : 0, 0, 0, 0);
holder.binding.imagesContainer.addView(imageView, layoutParams);
}
}
if (mLibaoDetailEntity != null) {
holder.binding.libaodetailTimeLl.setVisibility(View.VISIBLE);

View File

@ -31,7 +31,6 @@ import com.gh.gamecenter.common.base.GlobalActivityManager.getCurrentPageEntity
import com.gh.gamecenter.common.base.GlobalActivityManager.getLastPageEntity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.utils.NewFlatLogUtils
import com.gh.gamecenter.core.runOnIoThread
@ -44,8 +43,9 @@ import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.feature.view.DownloadButton.ButtonStyle
import com.gh.gamecenter.gamedetail.GameDetailFragment
import com.gh.gamecenter.gamedetail.GameDetailViewModel
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
import com.gh.gamecenter.gamedetail.entity.GameDetailTabEntity
import com.gh.gamecenter.teenagermode.TeenagerModeActivity.Companion.getIntent
import com.gh.vspace.VHelper
import com.lightgame.download.DownloadEntity
@ -56,13 +56,15 @@ import java.io.File
// 虽然叫 ViewHolder但其实就是一个用来临时放 View 和相关操作的包裹类
class DetailViewHolder(
view: View,
val viewModel: GameDetailViewModel?,
val gameEntity: GameEntity,
val isNewsDetail: Boolean, // 新闻详情不显示下载的游戏名, 只显示下载状态
entrance: String?,
name: String?,
title: String?,
val traceEvent: ExposureEvent?,
val isSupportDualButton: Boolean = false // 是否支持双下载按钮,不支持的时候跟普通列表意义选用优先级高的那个来显示
val isSupportDualButton: Boolean = false, // 是否支持双下载按钮,不支持的时候跟普通列表意义选用优先级高的那个来显示
onDownloadClickAction: ((Boolean) -> Unit)? = null
) {
var context: Context
var downloadBottom: View
@ -115,7 +117,8 @@ class DetailViewHolder(
mTitle = title ?: "",
mAsVGame = false,
mShowDualDownloadButton = gameDownloadMode == GameEntity.GAME_DOWNLOAD_BUTTON_MODE_DUAL,
mTraceEvent = traceEvent
mTraceEvent = traceEvent,
onDownloadClickAction = onDownloadClickAction
)
val vGameDownloadListener = OnDetailDownloadClickListener(
@ -125,7 +128,8 @@ class DetailViewHolder(
mTitle = title ?: "",
mAsVGame = true,
mShowDualDownloadButton = gameDownloadMode == GameEntity.GAME_DOWNLOAD_BUTTON_MODE_DUAL,
mTraceEvent = traceEvent
mTraceEvent = traceEvent,
onDownloadClickAction = onDownloadClickAction
)
// 不支持双下载按钮的情况时,优选一个下载方式显示
@ -183,7 +187,8 @@ class DetailViewHolder(
private val mTitle: String,
private val mAsVGame: Boolean,
private val mShowDualDownloadButton: Boolean,
private val mTraceEvent: ExposureEvent?
private val mTraceEvent: ExposureEvent?,
private val onDownloadClickAction: ((Boolean) -> Unit)? = null
) : View.OnClickListener {
private val mGameEntity: GameEntity = mViewHolder.gameEntity
@ -194,10 +199,6 @@ class DetailViewHolder(
if (mGameEntity.isLandPageAddressDialog() && !mGameEntity.isLandPageAddressDialogShowOnly()) {
// 第三方落地页为开启状态并且展示状态不为“仅显示弹窗”,需要在点击确认后显示弹窗
DialogUtils.showLandPageAddressDialog(mViewHolder.context, mGameEntity) {
val packageName = mGameEntity.getApk().firstOrNull()?.packageName
if (packageName?.isNotEmpty() == true) {
PackageChangeHelper.addInstallPendingPackage(packageName)
}
DirectUtils.directToExternalBrowser(mViewHolder.context, mGameEntity.landPageAddressDialog!!.link!!)
}
}
@ -275,20 +276,14 @@ class DetailViewHolder(
ButtonStyle.NONE_WITH_HINT, ButtonStyle.NONE -> {
val offStatus = mGameEntity.downloadOffStatus
if (offStatus != null && "off" != offStatus) {
when (offStatus) {
"dialog" -> {
showOffServiceDialog(mGameEntity.downloadOffDialog) {
showLandPageAddressDialogIfNeeded()
}
}
"toast" -> {
EventBus.getDefault().post(EBReuse(GameDetailFragment.SKIP_RATING))
ToastUtils.toast("该游戏因故暂不提供下载,具体详情可在相关评论中查看,敬请谅解~")
showLandPageAddressDialogIfNeeded()
}
"third_party" -> {
if ("dialog" == offStatus) {
showOffServiceDialog(mGameEntity.downloadOffDialog) {
showLandPageAddressDialogIfNeeded()
}
} else if ("toast" == offStatus) {
mViewHolder.viewModel?.performTabSelected(GameDetailTabEntity.TYPE_COMMENT)
ToastUtils.toast("该游戏因故暂不提供下载,具体详情可在相关评论中查看,敬请谅解~")
showLandPageAddressDialogIfNeeded()
}
} else {
ToastUtils.toast("该游戏已关闭下载")
@ -305,6 +300,10 @@ class DetailViewHolder(
DataLogUtils.uploadGameLog(mViewHolder.context, mGameEntity.id, mGameEntity.name, mEntrance)
}
val buttonText = mViewHolder.downloadPb.text.ifEmpty { mViewHolder.overlayTv?.text ?: "" }
val isUpdate = mViewHolder.context.getString(com.gh.gamecenter.feature.R.string.update_v) == buttonText || buttonText.contains(mViewHolder.context.getString(com.gh.gamecenter.feature.R.string.update))
onDownloadClickAction?.invoke(isUpdate)
preDownload()
}
@ -465,9 +464,17 @@ class DetailViewHolder(
}
ButtonStyle.RESERVED -> {
ReservationHelper.showCancelReservationDialog(mViewHolder.context, mGameEntity) {
ReservationHelper.cancelReservation(mGameEntity) {
DetailDownloadUtils.updateViewHolder(mViewHolder)
if ("download" == mGameEntity.reserveStatus) {
ReservationHelper.showDeleteReservationDialog(mViewHolder.context) {
ReservationHelper.deleteReservation(mGameEntity) {
DetailDownloadUtils.updateViewHolder(mViewHolder)
}
}
} else {
ReservationHelper.showCancelReservationDialog(mViewHolder.context, mGameEntity) {
ReservationHelper.cancelReservation(mGameEntity) {
DetailDownloadUtils.updateViewHolder(mViewHolder)
}
}
}
}

View File

@ -1,16 +1,11 @@
package com.gh.gamecenter.authorization
import android.app.Activity
import android.app.Application.ActivityLifecycleCallbacks
import android.app.Dialog
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.os.UserHandle
import com.gh.common.util.CheckLoginUtils
import com.gh.common.util.DialogUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.common.util.PackageUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.ToolBarActivity
import com.gh.gamecenter.common.constant.EntranceConsts
@ -21,10 +16,8 @@ import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.ActivityAuthorizationBinding
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.login.user.UserRepository
import com.gh.gamecenter.login.view.LoginActivity
import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
/**
@ -75,13 +68,6 @@ class AuthorizationActivity : ToolBarActivity() {
//授权token
private var mToken = ""
/**
* 游戏UID (适配双开/分身游戏)
*/
private var gameUid = -1
private var loadingDialog: Dialog? = null
override fun getLayoutId(): Int {
return R.layout.activity_authorization
}
@ -94,16 +80,11 @@ class AuthorizationActivity : ToolBarActivity() {
mBinding = ActivityAuthorizationBinding.bind(mContentView)
checkParam()
initView()
mBaseHandler.post {
if (loadingDialog == null) {
loadingDialog = DialogUtils.showWaitDialog(this, "请稍后...")
}
}
UserRepository.getInstance().loginUserInfo.observe(this) {
mBinding.authorizeBtn.postDelayed({
checkLogin {
initUserInfo()
}
}
}, 500)
NewFlatLogUtils.logLoginFromGHZSShow(
gameId = gameId,
gameName = gameName
@ -116,21 +97,14 @@ class AuthorizationActivity : ToolBarActivity() {
}
private fun initData() {
if (mToken.isNotEmpty() || isFinishing) {
loadingDialog?.dismiss()
return
}
if (loadingDialog == null) {
loadingDialog = DialogUtils.showWaitDialog(this, "请稍后...")
} else if (loadingDialog?.isShowing == false) {
loadingDialog?.show()
}
if (mToken.isNotEmpty() || isFinishing) return
val loadingDialog = DialogUtils.showWaitDialog(this, "请稍后...")
mViewModel.getAccessToken(listOf(mContent), {
mToken = it
loadingDialog?.dismiss()
loadingDialog.dismiss()
}, {
toast("获取token失败")
loadingDialog?.dismiss()
loadingDialog.dismiss()
})
}
@ -142,7 +116,7 @@ class AuthorizationActivity : ToolBarActivity() {
override fun onRestart() {
super.onRestart()
if (!CheckLoginUtils.isLogin()) {
finishAndRemoveTask()
finish()
} else {
initUserInfo()
initData()
@ -153,12 +127,12 @@ class AuthorizationActivity : ToolBarActivity() {
private fun checkParam() {
val uri = intent.data
if (uri == null) {
finishAndRemoveTask()
finish()
return
}
val host = uri.host
if (host != "authorize") {
finishAndRemoveTask()
finish()
return
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
@ -169,9 +143,8 @@ class AuthorizationActivity : ToolBarActivity() {
mContent = uri.getQueryParameter(EntranceConsts.KEY_CONTENT) ?: ""
gameId = uri.getQueryParameter(EntranceConsts.KEY_GAME_ID) ?: ""
gameName = uri.getQueryParameter(EntranceConsts.KEY_GAME_NAME) ?: ""
gameUid = uri.getQueryParameter(EntranceConsts.KEY_UID)?.toIntOrNull() ?: -1
if (mRemotePkgName == null) {
finishAndRemoveTask()
finish()
return
}
}
@ -179,8 +152,8 @@ class AuthorizationActivity : ToolBarActivity() {
private fun initView() {
//通过包名获取app图标和名称
val pkgName = mRemotePkgName ?: return
val icon = PackageUtils.getIconByPackageName(this, pkgName)
val name = PackageUtils.getNameByPackageName(this, pkgName)
val icon = packageManager.getApplicationIcon(pkgName)
val name = packageManager.getApplicationLabel(packageManager.getApplicationInfo(pkgName, 0))
mBinding.authorizeAppIcon.setImageDrawable(icon)
mBinding.authorizeAppName.text = name
mBinding.authorizeBtn.setOnClickListener {
@ -224,7 +197,7 @@ class AuthorizationActivity : ToolBarActivity() {
val remotePkgName = mRemotePkgName
if (remotePkgName == null) {
logAuthResult(false)
finishAndRemoveTask()
finish()
return
}
if (mToken.isEmpty()) {
@ -244,45 +217,10 @@ class AuthorizationActivity : ToolBarActivity() {
intent.putExtra(EntranceConsts.KEY_USER_ID, userId)
intent.putExtra(EntranceConsts.KEY_USER_NAME, username)
intent.putExtra(EntranceConsts.KEY_USER_AVATAR, userAvatar)
if (gameUid != -1 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
try {
sendBroadcastAsUser(intent, UserHandle.getUserHandleForUid(gameUid))
} catch (e: Exception) {
// 双开/分身游戏进行授权时,如果无 INTERACT_ACROSS_USERS 权限则使用Activity传递授权结果
authByActivity(intent)
return
}
} else {
sendBroadcast(intent)
}
sendBroadcast(intent)
logAuthResult(true)
backToLaunchApp()
finishAndRemoveTask()
}
private fun authByActivity(intent: Intent) {
intent.setClassName(mRemotePkgName!!, AUTHORIZATION_RESULT_ACTIVITY)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
HaloApp.getInstance().registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
override fun onActivityStarted(activity: Activity) {}
override fun onActivityResumed(activity: Activity) {}
override fun onActivityPaused(activity: Activity) {}
override fun onActivityStopped(activity: Activity) {
if (activity == this@AuthorizationActivity) {
HaloApp.getInstance().unregisterActivityLifecycleCallbacks(this)
finishAndRemoveTask()
}
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {
if (activity == this@AuthorizationActivity) {
HaloApp.getInstance().unregisterActivityLifecycleCallbacks(this)
}
}
})
startActivity(intent)
logAuthResult(true)
finish()
}
private fun logAuthResult(isSuccess: Boolean) {
@ -304,14 +242,14 @@ 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() {
finishAndRemoveTask()
super.onBackPressed()
backToLaunchApp(false)
@ -326,7 +264,6 @@ class AuthorizationActivity : ToolBarActivity() {
private const val BUTTON_TYPE_CONFIRM = "确定"
private const val BUTTON_TYPE_BACK = "返回"
private const val TYPE_PLUGIN = "plugin"
private const val AUTHORIZATION_RESULT_ACTIVITY = "com.gh.plugin.AuthorizationResultActivity"
}
}

View File

@ -2,17 +2,30 @@ package com.gh.gamecenter.cloudarchive
import android.app.Application
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.utils.toRequestBody
import com.gh.gamecenter.entity.ArchiveEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.lightgame.utils.Utils
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.*
import retrofit2.HttpException
import java.io.IOException
open class BaseCloudArchiveViewModel(application: Application, private val mConfigUrl: String): ListViewModel<ArchiveEntity, ArchiveEntity>(application) {
open class BaseCloudArchiveViewModel(
application: Application,
private val mGameId: String,
private var mConfigUrl: String
) : ListViewModel<ArchiveEntity, ArchiveEntity>(application) {
private var mArchiveConfigStr = ""
init {
getArchiveConfigString()
if (mConfigUrl.isEmpty()) {
getArchiveConfigUrl()
} else {
getArchiveConfigString()
}
}
// 通过url获取config字符串内容
@ -41,6 +54,27 @@ open class BaseCloudArchiveViewModel(application: Application, private val mConf
}
}
// 获取游戏存档配置url
private fun getArchiveConfigUrl() {
val map = mapOf(
"game_ids" to listOf(mGameId)
)
RetrofitManager.getInstance().newApi.getGamesArchiveConfigs(map.toRequestBody())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : com.gh.gamecenter.common.retrofit.Response<List<ArchiveEntity>>() {
override fun onResponse(response: List<ArchiveEntity>?) {
mConfigUrl = response?.find { it.gameId == mGameId }?.configUrl ?: return
getArchiveConfigString()
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
Utils.toast(getApplication(), "获取存档配置失败")
}
})
}
override fun provideDataObservable(page: Int): Observable<List<ArchiveEntity>>? = null
override fun mergeResultLiveData() {}

View File

@ -8,7 +8,6 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.toJson
import com.gh.gamecenter.common.utils.toRequestBody
import com.gh.gamecenter.core.utils.GsonUtils
import com.gh.gamecenter.entity.ArchiveEntity
@ -22,7 +21,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import okhttp3.*
import okhttp3.ResponseBody
import retrofit2.HttpException
class CloudArchiveManagerViewModel(
@ -30,7 +29,7 @@ class CloudArchiveManagerViewModel(
val gameId: String,
val gameName: String,
configUrl: String
) : BaseCloudArchiveViewModel(application, configUrl) {
) : BaseCloudArchiveViewModel(application, gameId, configUrl) {
companion object {
private const val SORT_TYPE_CREATE = "time.create:-1"

View File

@ -132,13 +132,6 @@ class GamesCollectionAdapter(
)
mExposureEventArray?.put(position, exposureEvent)
val path = when (mViewModel.type) {
GamesCollectionFragment.TYPE_COLLECT -> "我的收藏-游戏单"
GamesCollectionFragment.TYPE_HISTORY -> "浏览记录-游戏单"
GamesCollectionFragment.TYPE_USER -> "个人主页-游戏单"
else -> ""
}
holder.binding.run {
ImageUtils.display(poster, itemEntity.cover)
nameTv.text = itemEntity.title
@ -256,6 +249,12 @@ class GamesCollectionAdapter(
}
userIcon.setOnClickListener {
val path = when (mViewModel.type) {
GamesCollectionFragment.TYPE_COLLECT -> "我的收藏-游戏单"
GamesCollectionFragment.TYPE_HISTORY -> "浏览记录-游戏单"
GamesCollectionFragment.TYPE_USER -> "个人主页-游戏单"
else -> ""
}
DirectUtils.directToHomeActivity(mContext, itemEntity.user?.id, "", path)
}
userName.setOnClickListener { userIcon.performClick() }
@ -267,8 +266,7 @@ class GamesCollectionAdapter(
mContext,
itemEntity.id,
isScrollToCommentArea = true,
exposureSourceList = ArrayList(exposureEvent.source),
entrance = path
exposureSourceList = ArrayList(exposureEvent.source)
)
)
}
@ -331,8 +329,7 @@ class GamesCollectionAdapter(
GameCollectionDetailActivity.getIntent(
mContext,
itemEntity.id,
exposureSourceList = ArrayList(exposureEvent.source),
entrance = path
exposureSourceList = ArrayList(exposureEvent.source)
)
)
} else {

View File

@ -12,7 +12,6 @@ import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.IExposable
import com.gh.common.util.DialogUtils
import com.gh.common.util.DirectUtils
import com.gh.common.util.PackageChangeHelper
import com.gh.common.util.PackageInstaller
import com.gh.common.util.PackageLauncher
import com.gh.download.DownloadManager
@ -399,10 +398,6 @@ class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) :
if (update.isLandPageAddressDialogShowOnly()) {
updateOrPluggable(updateBtn, update, downloadEntity, pluginDesc)
} else {
val packageName = update.packageName
if (packageName.isNotEmpty() == true) {
PackageChangeHelper.addInstallPendingPackage(packageName)
}
DirectUtils.directToExternalBrowser(it.context, update.landPageAddressDialog!!.link!!)
}
}

View File

@ -1,16 +0,0 @@
package com.gh.gamecenter.entity
import com.gh.gamecenter.feature.entity.SimpleGame
import com.google.gson.annotations.SerializedName
class GameServerTestTopGame(
@SerializedName("_id")
var id: String = "",
var game: SimpleGame? = null,
@SerializedName("column_test_v2_icon")
var icon: String = "",
@SerializedName("event_description")
var description: String = "",
@SerializedName("event_date")
var date: String = ""
)

View File

@ -0,0 +1,11 @@
package com.gh.gamecenter.entity
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
data class HistoryGameDetailEntity(
@PrimaryKey
var id: String = "",
var name: String? = "",
)

View File

@ -18,13 +18,7 @@ data class SearchSubjectEntity(
@SerializedName("ad_icon_active")
val adIconActive: Boolean = false,
// 本地字段标记是否为微信小游戏CPM专题
var isWGameSubjectCPM: Boolean = false,
val type: String = ""
var isWGameSubjectCPM: Boolean = false
) : Parcelable {
companion object {
const val TYPE_WECHAT_GAME_CPM_COLUMN = "wechat_game_cpm_column"
}
fun getFilterGame() = RegionSettingHelper.filterGame(games)
}

View File

@ -8,7 +8,6 @@ import android.text.SpannableStringBuilder
import android.view.View
import com.facebook.drawee.view.SimpleDraweeView
import com.gh.common.util.*
import com.gh.common.util.DialogUtils
import com.gh.common.util.LogUtils
import com.gh.common.util.NewLogUtils
import com.gh.common.view.ImageContainerView
@ -17,22 +16,18 @@ import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.entity.AdditionalParamsEntity
import com.gh.gamecenter.common.entity.CommunityEntity
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.SpanBuilder
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.databinding.CommunityAnswerItemBinding
import com.gh.gamecenter.feature.entity.ForumVideoEntity
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.qa.answer.BaseAnswerOrArticleItemViewHolder
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
import com.gh.gamecenter.feature.entity.AnswerEntity
import com.gh.gamecenter.feature.entity.ArticleEntity
import com.gh.gamecenter.feature.entity.CommunityItemData
import com.gh.gamecenter.feature.entity.ForumVideoEntity
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import com.gh.gamecenter.forum.home.ArticleItemVideoView.Companion.toArticleVideoData
import com.gh.gamecenter.forum.search.CommunitySearchEventListener
import com.gh.gamecenter.forum.search.CommunitySearchEventListener.Companion.SEARCH_BUTTON_COMMENT
@ -44,6 +39,9 @@ import com.gh.gamecenter.forum.search.CommunitySearchEventListener.Companion.SEA
import com.gh.gamecenter.forum.search.CommunitySearchEventListener.Companion.SEARCH_BUTTON_VIEW_IMAGE
import com.gh.gamecenter.forum.search.CommunitySearchEventListener.Companion.SEARCH_BUTTON_VIEW_USER_DETAIL
import com.gh.gamecenter.forum.search.CommunitySearchEventListener.Companion.htmlToString
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.qa.answer.BaseAnswerOrArticleItemViewHolder
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
import com.gh.gamecenter.qa.entity.QuestionsDetailEntity
import com.gh.gamecenter.qa.questions.invite.QuestionsInviteActivity
import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
@ -348,8 +346,8 @@ class ForumArticleAskItemViewHolder(
.setReleaseWhenLossAudio(true)
.setLooping(false)
.setShowFullAnimation(false)
.setEnlargeImageRes(R.drawable.ic_game_detail_enter_full_screen)
.setShrinkImageRes(R.drawable.ic_game_detail_exit_full_screen)
.setEnlargeImageRes(R.drawable.ic_video_enter_full_screen)
.setShrinkImageRes(R.drawable.ic_video_exit_full_screen)
.setVideoAllCallBack(object : GSYSampleCallBack() {
override fun onQuitFullscreen(url: String?, vararg objects: Any) {
orientationUtils.backToProtVideo()

View File

@ -288,8 +288,7 @@ class ForumContentSearchListFragment : LazyListFragment<AnswerEntity, ForumConte
mSearchKey,
SearchActivity.toTrackSearchType(mSearchType),
contentId ?: "",
title ?: "",
sequence
title ?: ""
)
NewFlatLogUtils.logSearchContentClick(

View File

@ -39,8 +39,8 @@ class ForumOrUserSearchDefaultFragment : SearchDefaultFragment() {
override fun initView() {
mBinding = FragmentSearchDefaultBinding.bind(mCachedView)
mBinding.hotAndDiscoveryTagHeadContainer.root.visibility = View.GONE
mBinding.hotAndDiscoveryTagFlexContainer.visibility = View.GONE
mBinding.hotTagHeadContainer.root.visibility = View.GONE
mBinding.hotTagFlexContainer.visibility = View.GONE
if (mEntrance == "论坛首页" || mEntrance == "搜索栏") {
mBinding.hotHeadContainer.headTitle.text = "热门论坛"
mViewModel.getForumSearchHotContent()

View File

@ -40,8 +40,7 @@ class UserSearchListFragment : LazyListFragment<FollowersOrFansEntity, UserSearc
mSearchKey,
SearchActivity.toTrackSearchType(mSearchType),
mListViewModel.sourceEntrance,
userId,
position
userId
)
NewFlatLogUtils.logSearchUserClick(
SearchType.fromString(mSearchType).toChinese(),

View File

@ -4,18 +4,14 @@ import android.os.Bundle
import android.view.View
import androidx.lifecycle.ViewModelProviders
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.baselist.LazyListFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.constant.EntranceConsts.KEY_SHOW_SUBJECT_TAB
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.json.json
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.observeNonNull
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.databinding.FragmentColumnCollectionDetailBinding
import com.gh.gamecenter.entity.GameColumnCollection
import com.gh.gamecenter.entity.SubjectData
import com.gh.gamecenter.subject.tab.SubjectTabFragment
@ -59,35 +55,9 @@ class ColumnCollectionDetailFragment : LazyListFragment<LinkEntity, ColumnCollec
mListViewModel.getGameColumnCollection()
mListViewModel.columnCollection.observeNonNull(this) {
setNavigationTitle(it.name)
mCachedView?.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()))
logPageShow(it)
}
}
private fun logPageShow(entity: GameColumnCollection) {
val tabIndex = arguments?.getInt(EntranceConsts.KEY_TAB_INDEX, -1) ?: -1
val tabName = arguments?.getString(EntranceConsts.KEY_TAB_NAME, "") ?: ""
val multiTabNavId = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_ID, "") ?: ""
val multiTabNavName = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_NAME, "") ?: ""
val bottomTabName = arguments?.getString(EntranceConsts.KEY_BOTTOM_TAB_NAME, "") ?: ""
mBaseHandler.postDelayed({
SensorsBridge.trackEvent("ColumnCollectionDetailPageShow", json {
"column_collection_name" to entity.name
"column_collection_id" to entity.id
"page_name" to GlobalActivityManager.getCurrentPageEntity().pageName
"page_id" to GlobalActivityManager.getCurrentPageEntity().pageId
"page_business_id" to GlobalActivityManager.getCurrentPageEntity().pageBusinessId
"last_page_name" to GlobalActivityManager.getLastPageEntity().pageName
"last_page_id" to GlobalActivityManager.getLastPageEntity().pageId
"last_page_business_id" to GlobalActivityManager.getLastPageEntity().pageBusinessId
"bottom_tab" to bottomTabName
"several_tab_page_name" to multiTabNavName
"several_tab_page_id" to multiTabNavId
"position" to tabIndex
"tab_content" to tabName
"source_entrance" to mEntrance
})
}, 3000L)
mCachedView?.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()))
}
}
override fun onChanged(list: MutableList<LinkEntity>?) {

View File

@ -11,22 +11,18 @@ import com.gh.common.exposure.ExposureListener
import com.gh.common.exposure.IExposable
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.baselist.LazyListFragment
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.json.json
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.common.view.FixGridLayoutManager
import com.gh.gamecenter.common.view.GridSpacingItemDecoration
import com.gh.gamecenter.common.view.VerticalItemDecoration
import com.gh.gamecenter.databinding.FragmentListBaseSkeletonBinding
import com.gh.gamecenter.entity.CommonCollectionEntity
import com.gh.gamecenter.home.custom.model.CustomPageItem
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.COMMON_CONTENT_COLLECTION_LAYOUT_HORIZONTAL_SLIDE_BANNER
@ -124,8 +120,6 @@ class CustomCommonCollectionDetailFragment : LazyListFragment<LinkEntity, Custom
}
mListRv?.removeItemDecorationAt(0)
mListRv?.addItemDecoration(itemDecoration)
logPageShow(it)
}
mListViewModel.loadExceptionLiveData.observe(viewLifecycleOwner) {
if (it != null && it.code() == 404) {
@ -160,32 +154,6 @@ class CustomCommonCollectionDetailFragment : LazyListFragment<LinkEntity, Custom
})
}
private fun logPageShow(entity: CommonCollectionEntity) {
val tabIndex = arguments?.getInt(EntranceConsts.KEY_TAB_INDEX, -1) ?: -1
val tabName = arguments?.getString(EntranceConsts.KEY_TAB_NAME, "") ?: ""
val multiTabNavId = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_ID, "") ?: ""
val multiTabNavName = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_NAME, "") ?: ""
val bottomTabName = arguments?.getString(EntranceConsts.KEY_BOTTOM_TAB_NAME, "") ?: ""
mBaseHandler.postDelayed({
SensorsBridge.trackEvent("LinkContentCollectionDetailPageShow", json {
"link_content_collection_name" to entity.name
"link_content_collection_id" to entity.id
"page_name" to GlobalActivityManager.getCurrentPageEntity().pageName
"page_id" to GlobalActivityManager.getCurrentPageEntity().pageId
"page_business_id" to GlobalActivityManager.getCurrentPageEntity().pageBusinessId
"last_page_name" to GlobalActivityManager.getLastPageEntity().pageName
"last_page_id" to GlobalActivityManager.getLastPageEntity().pageId
"last_page_business_id" to GlobalActivityManager.getLastPageEntity().pageBusinessId
"bottom_tab" to bottomTabName
"several_tab_page_name" to multiTabNavName
"several_tab_page_id" to multiTabNavId
"position" to tabIndex
"tab_content" to tabName
"source_entrance" to mEntrance
})
}, 3000L)
}
override fun getItemDecoration(): RecyclerView.ItemDecoration =
when (mCollectionStyle) {
"1-2" ->

View File

@ -3,18 +3,19 @@ package com.gh.gamecenter.game.horizontal
import android.content.Context
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.*
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.DownloadItemUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.StringUtils
import com.gh.gamecenter.entity.SubjectEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.subjectTypeToComponentStyle
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
import com.gh.gamecenter.gamedetail.detail.viewholder.BaseGameDetailItemViewHolder
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.subjectTypeToComponentStyle
import com.lightgame.adapter.BaseRecyclerAdapter
import com.lightgame.download.DownloadEntity
@ -22,7 +23,9 @@ class GameHorizontalAdapter(
context: Context,
private var mSubjectEntity: SubjectEntity,
private var type: GameHorizontalListType = GameHorizontalListType.SubjectHorizontalType,
private val trackColumnClick: Boolean = true
private val trackColumnClick: Boolean = true,
private val gameDetailTrackData: BaseGameDetailItemViewHolder.GameDetailModuleTrackData? = null,
private val getGameStatus: (() -> String)? = null
) : BaseRecyclerAdapter<GameHorizontalItemViewHolder>(context) {
var gameName = ""
@ -85,6 +88,7 @@ class GameHorizontalAdapter(
gameIcon.displayGameIcon(gameEntity)
GameHorizontalSimpleItemViewHolder.setHorizontalNameAndGravity(gameName, gameEntity.name)
downloadBtn.goneIf(!mSubjectEntity.showDownload)
gameName.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(mContext))
gameName.maxLines = if (mSubjectEntity.showDownload) 1 else 2
}
holder.bindGameHorizontalItem(gameEntity, mSubjectEntity)
@ -111,20 +115,15 @@ class GameHorizontalAdapter(
if (type == GameHorizontalListType.GameDetailHorizontalType) {
DataCollectionUtils.uploadClick(mContext, path, "游戏详情", gameEntity.name)
NewLogUtils.logGameDetailPopularClick(gameName, gameId, "game", gameEntity.name ?: "")
SensorsBridge.trackGameDetailPagePopularClick(
gameId = gameId,
gameName = gameName,
pageName = GlobalActivityManager.getCurrentPageEntity().pageName,
pageId = GlobalActivityManager.getCurrentPageEntity().pageId,
pageBusinessId = GlobalActivityManager.getCurrentPageEntity().pageBusinessId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId,
downloadStatus = game?.downloadStatusChinese ?: "",
gameType = game?.categoryChinese ?: "",
clickGameType = gameEntity.categoryChinese,
clickGameName = gameEntity.name ?: "",
clickGameId = gameEntity.id
SensorsBridge.trackGameDetailModuleClick(
gameDetailTrackData?.gameId,
gameDetailTrackData?.gameName,
gameDetailTrackData?.gameType,
"右上角",
gameDetailTrackData?.moduleType,
gameDetailTrackData?.moduleName,
gameDetailTrackData?.sequence,
gameStatus = getGameStatus?.invoke()
)
if (!gameEntity.isMiniGame() && trackColumnClick) {
SensorsBridge.trackColumnClick(

View File

@ -49,24 +49,21 @@ class GameCollectionDetailActivity : ToolBarActivity() {
fun getIntent(
context: Context,
gameCollectionId: String,
isFromSquare: Boolean = false,
entrance: String = ""
isFromSquare: Boolean = false
): Intent {
return getIntent(context, gameCollectionId, "", isFromSquare, false, entrance = entrance)
return getIntent(context, gameCollectionId, "", isFromSquare, false)
}
@JvmStatic
fun getSpecifiedCommentIntent(
context: Context,
gameCollectionId: String,
topCommentId: String,
entrance: String
topCommentId: String
): Intent {
return getIntent(
context, gameCollectionId, topCommentId,
isFromSquare = false,
isScrollToCommentArea = true,
entrance = entrance
isScrollToCommentArea = true
)
}
@ -77,15 +74,13 @@ class GameCollectionDetailActivity : ToolBarActivity() {
topCommentId: String = "",
isFromSquare: Boolean = false,
isScrollToCommentArea: Boolean = false,
exposureSourceList: ArrayList<ExposureSource>? = null,
entrance: String = ""
exposureSourceList: ArrayList<ExposureSource>? = null
): Intent {
val bundle = Bundle()
bundle.putString(EntranceConsts.KEY_GAME_COLLECTION_ID, gameCollectionId)
bundle.putString(EntranceConsts.KEY_TOP_COMMENT_ID, topCommentId)
bundle.putBoolean(EntranceConsts.KEY_IS_FROM_SQUARE, isFromSquare)
bundle.putBoolean(EntranceConsts.KEY_SCROLL_TO_COMMENT_AREA, isScrollToCommentArea)
bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance)
if (exposureSourceList != null) {
bundle.putParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST, exposureSourceList)
}

View File

@ -39,7 +39,6 @@ import com.gh.gamecenter.common.syncpage.SyncDataEntity
import com.gh.gamecenter.common.syncpage.SyncFieldConstants
import com.gh.gamecenter.common.syncpage.SyncPageRepository
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.SegmentedFilterView
import com.gh.gamecenter.core.iinterface.IScrollable
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.databinding.FragmentGameCollectionDetailBinding
@ -48,7 +47,6 @@ import com.gh.gamecenter.entity.GamesCollectionDetailEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.gamedetail.GameDetailFragment
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.login.user.UserViewModel
@ -187,12 +185,10 @@ class GameCollectionDetailFragment :
root.layoutParams = this
}
orderSfv.setItemList(listOf("正序", "倒序"), 0)
orderSfv.setOnCheckedCallback(object : SegmentedFilterView.OnCheckedCallback {
override fun onItemCheck(position: Int) {
getFilterVH()?.binding?.orderSfv?.performClick(position)
updateFilterView()
}
})
orderSfv.setOnCheckedCallback { position ->
getFilterVH()?.binding?.orderSfv?.performClick(position)
updateFilterView()
}
commentHintTv.text = "玩家评论"
}
}
@ -741,7 +737,7 @@ class GameCollectionDetailFragment :
if (activity != null && activity?.isFinishing != true) {
startPlayLogic(isAutoPlay = true)
}
}, GameDetailFragment.INITIAL_DELAY)
}, INITIAL_DELAY)
}
}
}
@ -851,7 +847,6 @@ class GameCollectionDetailFragment :
trackEvent.put("game_collect_title", mGameCollectionTitle)
trackEvent.put("game_collect_id", mGameCollectionId)
trackEvent.put("stay_length", mElapsedHelper?.elapsedTime)
trackEvent.put("source_entrance", mEntrance)
} catch (e: JSONException) {
e.printStackTrace()
}
@ -1210,4 +1205,8 @@ class GameCollectionDetailFragment :
appbar.setExpanded(true)
}
}
companion object {
const val INITIAL_DELAY = 500L
}
}

View File

@ -13,15 +13,15 @@ import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.observer.MuteCallback
import com.gh.gamecenter.common.observer.VolumeObserver
import com.gh.gamecenter.core.runOnIoThread
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.debounceActionWithInterval
import com.gh.gamecenter.common.utils.rxTimer
import com.gh.gamecenter.common.utils.ImageUtils
import com.gh.gamecenter.common.utils.NetworkUtils
import com.gh.gamecenter.common.utils.debounceActionWithInterval
import com.gh.gamecenter.common.utils.rxTimer
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.MD5Utils
import com.gh.gamecenter.entity.GamesCollectionDetailEntity
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
@ -180,7 +180,7 @@ class GameCollectionVideoView @JvmOverloads constructor(context: Context, attrs:
private fun mute(isManual: Boolean = false) {
viewModel?.videoIsMuted = true
volume.setImageResource(R.drawable.ic_game_detail_volume_off)
volume.setImageResource(R.drawable.ic_video_volume_off)
CustomManager.getCustomManager(getKey()).isNeedMute = true
if (isManual) {
Utils.toast(context, "当前处于静音状态")
@ -190,7 +190,7 @@ class GameCollectionVideoView @JvmOverloads constructor(context: Context, attrs:
private fun unMute(isManual: Boolean = false) {
viewModel?.videoIsMuted = false
volume.setImageResource(R.drawable.ic_game_detail_volume_on)
volume.setImageResource(R.drawable.ic_video_volume_on)
CustomManager.getCustomManager(getKey()).isNeedMute = false
if (isManual) {
logVideoEvent("video_game_collect_detail_mute_cancel")
@ -278,9 +278,9 @@ class GameCollectionVideoView @JvmOverloads constructor(context: Context, attrs:
if (mStartButton is ImageView) {
val imageView = mStartButton as ImageView
when (mCurrentState) {
GSYVideoView.CURRENT_STATE_PLAYING -> imageView.setImageResource(R.drawable.ic_game_detail_pause)
GSYVideoView.CURRENT_STATE_ERROR -> imageView.setImageResource(R.drawable.ic_game_detail_play)
else -> imageView.setImageResource(R.drawable.ic_game_detail_play)
GSYVideoView.CURRENT_STATE_PLAYING -> imageView.setImageResource(R.drawable.ic_video_pause)
GSYVideoView.CURRENT_STATE_ERROR -> imageView.setImageResource(R.drawable.ic_video_play)
else -> imageView.setImageResource(R.drawable.ic_video_play)
}
}
}
@ -314,11 +314,11 @@ class GameCollectionVideoView @JvmOverloads constructor(context: Context, attrs:
}
override fun getEnlargeImageRes(): Int {
return R.drawable.ic_game_detail_enter_full_screen
return R.drawable.ic_video_enter_full_screen
}
override fun getShrinkImageRes(): Int {
return R.drawable.ic_game_detail_exit_full_screen
return R.drawable.ic_video_exit_full_screen
}
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {

View File

@ -6,7 +6,6 @@ import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.ExposureListener
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.baselist.ListFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.exposure.ExposureSource
@ -59,7 +58,6 @@ class GameCollectionHotListFragment : ListFragment<GameCollectionListItemData, G
if (requireActivity() is GameCollectionListDetailActivity) {
mBasicExposureSourceList.add(ExposureSource("游戏单合集", mGameCollectionListEntity?.id ?: ""))
mBasicExposureSourceList.add(ExposureSource("合集详情", ""))
logPageShow()
} else {
mBasicExposureSourceList.add(ExposureSource("游戏单热榜", ""))
mBasicExposureSourceList.add(ExposureSource("游戏单合集", mGameCollectionListEntity?.id ?: ""))
@ -70,32 +68,6 @@ class GameCollectionHotListFragment : ListFragment<GameCollectionListItemData, G
}
}
private fun logPageShow() {
val tabIndex = arguments?.getInt(EntranceConsts.KEY_TAB_INDEX, -1) ?: -1
val tabName = arguments?.getString(EntranceConsts.KEY_TAB_NAME, "") ?: ""
val multiTabNavId = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_ID, "") ?: ""
val multiTabNavName = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_NAME, "") ?: ""
val bottomTabName = arguments?.getString(EntranceConsts.KEY_BOTTOM_TAB_NAME, "") ?: ""
mBaseHandler.postDelayed({
SensorsBridge.trackEvent("GameListCollectionDetailPageShow", json {
"game_list_collection_name" to mGameCollectionListEntity?.name
"game_list_collection_id" to mGameCollectionListEntity?.id
"page_name" to GlobalActivityManager.getCurrentPageEntity().pageName
"page_id" to GlobalActivityManager.getCurrentPageEntity().pageId
"page_business_id" to GlobalActivityManager.getCurrentPageEntity().pageBusinessId
"last_page_name" to GlobalActivityManager.getLastPageEntity().pageName
"last_page_id" to GlobalActivityManager.getLastPageEntity().pageId
"last_page_business_id" to GlobalActivityManager.getLastPageEntity().pageBusinessId
"bottom_tab" to bottomTabName
"several_tab_page_name" to multiTabNavName
"several_tab_page_id" to multiTabNavId
"position" to tabIndex
"tab_content" to tabName
"source_entrance" to mEntrance
})
}, 3000L)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
if (mListRefresh != null) {
mListRefresh!!.setColorSchemeResources(com.gh.gamecenter.common.R.color.primary_theme)

View File

@ -76,8 +76,7 @@ class MyGameCollectionViewHolder(
binding.root.context.startActivity(
GameCollectionDetailActivity.getIntent(
binding.root.context,
entity.id,
entrance = path
entity.id
)
)
} else {

View File

@ -11,7 +11,6 @@ import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import com.gh.common.provider.CropImageProviderImpl.Companion.IMAGE_TYPE_GAME_COLLECTION_COVER
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.common.util.NewLogUtils
@ -46,8 +45,7 @@ class ChooseGameCollectionCoverTypeDialog : BaseDialogFragment() {
requireContext(),
ChooseType.IMAGE,
1,
"创建游戏单",
IMAGE_TYPE_GAME_COLLECTION_COVER
"创建游戏单"
), REQUEST_CODE_IMAGE
)
}
@ -103,8 +101,7 @@ class ChooseGameCollectionCoverTypeDialog : BaseDialogFragment() {
com.gh.gamecenter.common.R.drawable.bg_choose_option_selector.toDrawable(requireContext())
defaultUploadContainer.background =
com.gh.gamecenter.common.R.drawable.bg_choose_option_selector.toDrawable(requireContext())
cancelBtn.background =
com.gh.gamecenter.common.R.drawable.bg_shape_f5_radius_999.toDrawable(requireContext())
cancelBtn.background = com.gh.gamecenter.common.R.drawable.bg_shape_f5_radius_999.toDrawable(requireContext())
recommentTv.background = R.drawable.bg_game_collection_cover_tag.toDrawable(requireContext())
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(requireContext()))
localUploadTitleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))

View File

@ -313,14 +313,14 @@ class GameCollectionEditActivity : ToolBarActivity(), ChooseGamesAdapter.ItemDra
val games = mChooseGamesViewModel.chooseGamesLiveData.value ?: arrayListOf()
if (mIsCreateGameCollection) {
SensorsBridge.trackEvent("GameCollectCreateSuccess", json {
"game_collect_status" to if (mBinding.selfOnlyCb.isChecked) "仅自己可见" else "公开"
"game_collect_status" to if(mBinding.selfOnlyCb.isChecked) "仅自己可见" else "公开"
"game_num" to games.size
"game_collect_title" to mBinding.gameCollectionTitleEt.text.toString().trim()
"game_collect_id" to it.data as String
})
} else if (mViewModel.gameCollectionPatch != null) {
SensorsBridge.trackEvent("GameCollectEditSuccess", json {
"game_collect_status" to if (mBinding.selfOnlyCb.isChecked) "仅自己可见" else "公开"
"game_collect_status" to if(mBinding.selfOnlyCb.isChecked) "仅自己可见" else "公开"
"game_num" to games.size
"game_collect_title" to mBinding.gameCollectionTitleEt.text.toString().trim()
"game_collect_id" to mViewModel.gameCollectionPatch?.id
@ -355,7 +355,7 @@ class GameCollectionEditActivity : ToolBarActivity(), ChooseGamesAdapter.ItemDra
CheckLoginUtils.checkLogin(this, mEntrance) {}
return@observe
}
ErrorHelper.handleError(this, errorMsg, false, "发布游戏单", "社区实名") {
ErrorHelper.handleError(this, errorMsg, false, "发布游戏单", "社区实名") {
if (::mMenuPost.isInitialized) {
onMenuItemClick(mMenuPost)
}
@ -433,6 +433,18 @@ class GameCollectionEditActivity : ToolBarActivity(), ChooseGamesAdapter.ItemDra
super.onActivityResult(requestCode, resultCode, data)
if (data == null || resultCode != Activity.RESULT_OK) return
when (requestCode) {
REQUEST_CODE_IMAGE_CROP -> {
val imagePath = data.getStringExtra(CropImageActivity.RESULT_CLIP_PATH) ?: ""
mViewModel.imageUrl = ""
mViewModel.imagePath = imagePath
if (imagePath.isEmpty()) {
mBinding.uploadPictureTv.text = "点击上传图片"
} else {
mBinding.uploadPictureTv.text = "图片上传中..."
mViewModel.uploadPoster()
}
initPosterUI()
}
REQUEST_CHOOSE_TAG -> {
val tags = data.getParcelableArrayListExtra<TagInfoEntity>(GameCollectionTagSelectFragment.SELECTED_TAG)
?: arrayListOf()
@ -445,16 +457,20 @@ class GameCollectionEditActivity : ToolBarActivity(), ChooseGamesAdapter.ItemDra
fun onActivityDialogResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK && data != null) {
if (requestCode == REQUEST_CODE_IMAGE) {
val imagePath = data.getStringExtra(CropImageActivity.RESULT_CLIP_PATH) ?: ""
mViewModel.imageUrl = ""
mViewModel.imagePath = imagePath
if (imagePath.isEmpty()) {
mBinding.uploadPictureTv.text = "点击上传图片"
} else {
mBinding.uploadPictureTv.text = "图片上传中..."
mViewModel.uploadPoster()
val selectedPaths = Matisse.obtainResult(data)
if (!selectedPaths.isNullOrEmpty()) {
val path = PathUtils.getPath(this, selectedPaths[0])
val intent =
CropImageActivity.getIntent(
this,
path,
142 / 328F,
false,
R.layout.layout_game_collection_crop_image_assist,
mEntrance
)
startActivityForResult(intent, REQUEST_CODE_IMAGE_CROP)
}
initPosterUI()
} else if (requestCode == ChooseGameCollectionDefaultCoverDialog.REQUEST_CODE_DEFAULT_IMAGE) {
val entity = data.getParcelableExtra<GameCollectionCoverEntity>(EntranceConsts.KEY_DATA)
if (entity != null) {
@ -715,17 +731,9 @@ class GameCollectionEditActivity : ToolBarActivity(), ChooseGamesAdapter.ItemDra
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
)
} else {
DialogHelper.showDialog(
this,
"温馨提示",
"游戏单会在1-2个工作日内审核完成您可以在“我的光环-我的游戏单”查看进度",
"继续提交",
"取消",
{
mViewModel.uploadContent(this, requestMap)
},
extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
)
DialogHelper.showDialog(this, "温馨提示", "游戏单会在1-2个工作日内审核完成您可以在“我的光环-我的游戏单”查看进度", "继续提交", "取消", {
mViewModel.uploadContent(this, requestMap)
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true))
}
}
}
@ -796,8 +804,7 @@ class GameCollectionEditActivity : ToolBarActivity(), ChooseGamesAdapter.ItemDra
activityDivider.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(this@GameCollectionEditActivity))
titleDivider.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(this@GameCollectionEditActivity))
introduceDivider.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(this@GameCollectionEditActivity))
placeholderView.background =
com.gh.gamecenter.common.R.drawable.bg_shape_f5_radius_8.toDrawable(this@GameCollectionEditActivity)
placeholderView.background = com.gh.gamecenter.common.R.drawable.bg_shape_f5_radius_8.toDrawable(this@GameCollectionEditActivity)
selfOnlyCb.background =
R.drawable.border_round_stroke_0dot5_eee_999.toDrawable(this@GameCollectionEditActivity)
uploadPictureTv.setTextColor(com.gh.gamecenter.common.R.color.text_instance.toColor(this@GameCollectionEditActivity))
@ -905,6 +912,7 @@ class GameCollectionEditActivity : ToolBarActivity(), ChooseGamesAdapter.ItemDra
companion object {
const val REQUEST_CODE_IMAGE = 100
const val REQUEST_CODE_IMAGE_CROP = 101
const val REQUEST_CHOOSE_GAMES = 102
const val REQUEST_CHOOSE_TAG = 103
const val REQUEST_CHOOSE_ACTIVITY = 105

View File

@ -596,8 +596,7 @@ class GameCollectionSquareAdapter(
context,
gamesCollectionEntity.id,
isFromSquare = true,
exposureSourceList = ArrayList(exposureSource),
entrance = "游戏单广场"
exposureSourceList = ArrayList(exposureSource)
)
)
}

View File

@ -209,7 +209,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (data == null || resultCode != Activity.RESULT_OK || !::mViewModel.isInitialized) return
if (data == null || resultCode != Activity.RESULT_OK) return
if (requestCode == REQUEST_SELECT_TAG) {
val tagInfoEntity = data.getParcelableExtra<TagInfoEntity>(GameCollectionTagSelectFragment.SELECTED_TAG)
val tagCategory = data.getStringExtra(GameCollectionTagSelectFragment.SELECTED_TAG_CATEGORY)

View File

@ -1,51 +0,0 @@
package com.gh.gamecenter.gamedetail
import android.content.Context
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.common.utils.safelyGetInRelease
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.databinding.ItemGameDetailContentCardContentBinding
import com.gh.gamecenter.gamedetail.entity.ContentCardEntity
import com.lightgame.adapter.BaseRecyclerAdapter
class GameDetailContentCardContentAdapter(
context: Context,
private val linkEntity: ContentCardEntity,
private val isHighlightBg: Boolean = false
) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
GameDetailContentCardContentItemViewHolder(parent.toBinding())
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is GameDetailContentCardContentItemViewHolder) {
holder.binding.root.setTextColor(
if (isHighlightBg) com.gh.gamecenter.common.R.color.text_secondary.toColor(mContext) else com.gh.gamecenter.common.R.color.text_tertiary.toColor(
mContext
)
)
if (linkEntity.type == "func_server" && linkEntity.server != null && linkEntity.server?.calendar?.isNotEmpty() == true) {
val calendarList = linkEntity.server!!.calendar
val realPosition = position % calendarList.size
calendarList.safelyGetInRelease(realPosition)?.let {
val serverTime =
if (TimeUtils.isToday(it.getTime()))
it.getFormatTime("今天 HH:mm")
else if (TimeUtils.isTomorrow(it.getTime()))
it.getFormatTime("明天 HH:mm")
else
it.getFormatTime("MM-dd HH:mm")
holder.binding.root.text = "$serverTime ${it.type}"
}
}
}
}
override fun getItemCount(): Int = Int.MAX_VALUE
class GameDetailContentCardContentItemViewHolder(var binding: ItemGameDetailContentCardContentBinding) :
RecyclerView.ViewHolder(binding.root)
}

File diff suppressed because it is too large Load Diff

View File

@ -1,57 +0,0 @@
package com.gh.gamecenter.gamedetail
import android.os.Bundle
import android.view.View
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.BaseFragment
import com.gh.gamecenter.common.utils.toDrawable
import com.gh.gamecenter.feature.entity.LibaoEntity
import com.gh.gamecenter.gamedetail.desc.GameLibaoAdapter
class LibaoListFragment : BaseFragment<Any>() {
override fun getLayoutId() = R.layout.fragment_libao_list
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val recyclerView = view.findViewById<RecyclerView>(R.id.recyclerView)
val toolbarTitleTv = view.findViewById<TextView>(R.id.normal_title)
val toolbarBackContainer = view.findViewById<View>(com.gh.gamecenter.selector.R.id.backContainer)
toolbarTitleTv.setText("游戏礼包")
toolbarBackContainer.setOnClickListener { requireActivity().onBackPressed() }
val gameId = arguments?.getString(ARG_GAME_ID) ?: ""
val gameName = arguments?.getString(ARG_GAME_NAME) ?: ""
val libaoList = arguments?.getParcelableArrayList<LibaoEntity>(ARG_LIBAO_LIST) ?: arrayListOf()
recyclerView?.apply {
layoutManager = LinearLayoutManager(requireContext())
adapter = adapter ?: GameLibaoAdapter(requireContext(), libaoList, gameName, gameId, false, true)
}
}
companion object {
private const val ARG_GAME_ID = "game_id"
private const val ARG_GAME_NAME = "game_name"
private const val ARG_LIBAO_LIST = "libao_list"
fun getBundle(gameId: String, gameName: String, libaoList: ArrayList<LibaoEntity>) = Bundle().apply {
putString(ARG_GAME_ID, gameId)
putString(ARG_GAME_NAME, gameName)
putParcelableArrayList(ARG_LIBAO_LIST, libaoList)
}
fun newInstance(bundle: Bundle?) = LibaoListFragment().apply {
if (bundle != null) {
arguments = bundle
}
}
}
}

View File

@ -1,81 +1,119 @@
package com.gh.gamecenter.gamedetail.cloudarchive
import android.os.Bundle
import android.view.View
import android.view.inputmethod.EditorInfo
import androidx.core.os.bundleOf
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.catalog.SpecialCatalogFragment
import com.gh.gamecenter.cloudarchive.CloudArchiveManagerActivity
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.base.fragment.LazyFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.toResString
import com.gh.gamecenter.common.json.json
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.databinding.FragmentCloudArchiveAlBinding
import com.gh.gamecenter.databinding.FragmentCloudArchiveBinding
import com.gh.gamecenter.feature.entity.GameEntity
class CloudArchiveFragment : LazyFragment() {
private var mUseAlternativeLayout = false
private var mGameEntity: GameEntity? = null
private var mBinding: FragmentCloudArchiveBinding? = null
private var mAlternativeBinding: FragmentCloudArchiveAlBinding? = null
private var mSearchFragment: CloudArchiveListFragment? = null
private var mNormalFragment: CloudArchiveListFragment? = null
private var mIsSearch = false
private var mOrderList =
listOf(CloudArchiveListViewModel.SortType.NEWEST, CloudArchiveListViewModel.SortType.HOTTEST)
override fun getRealLayoutId() = R.layout.fragment_cloud_archive
private val searchBarBinding
get() = if (mUseAlternativeLayout) mAlternativeBinding?.searchBar else mBinding?.searchBar
private val orderSfv
get() = if (mUseAlternativeLayout) mAlternativeBinding?.orderSfv else mBinding?.orderSfv
private val archiveManageTv
get() = if (mUseAlternativeLayout) mAlternativeBinding?.archiveManageTv else mBinding?.archiveManageTv
override fun onCreate(savedInstanceState: Bundle?) {
mUseAlternativeLayout = arguments?.getBoolean(EntranceConsts.KEY_USE_ALTERNATIVE_LAYOUT) ?: false
super.onCreate(savedInstanceState)
}
override fun getRealLayoutId() =
if (mUseAlternativeLayout) R.layout.fragment_cloud_archive_al else R.layout.fragment_cloud_archive
override fun onRealLayoutInflated(inflatedView: View) {
mBinding = FragmentCloudArchiveBinding.bind(inflatedView)
if (mUseAlternativeLayout) {
mAlternativeBinding = FragmentCloudArchiveAlBinding.bind(inflatedView)
} else {
mBinding = FragmentCloudArchiveBinding.bind(inflatedView)
}
}
override fun onFragmentFirstVisible() {
mGameEntity = arguments?.getParcelable(EntranceConsts.KEY_GAME)
mGameEntity = arguments?.getParcelable(EntranceConsts.KEY_GAME_ENTITY)
super.onFragmentFirstVisible()
changeContentFragment()
SensorsBridge.trackEvent("CloudSavePageView", json {
"game_id" to mGameEntity?.id
"game_name" to mGameEntity?.name
"last_page_name" to GlobalActivityManager.getLastPageEntity().pageName
"last_page_id" to GlobalActivityManager.getLastPageEntity().pageId
})
}
override fun inflateRealView() {
super.inflateRealView()
mBinding?.run {
searchBar.etSearch.hint = R.string.game_detail_cloud_archive_search_hint.toResString()
orderSfv.setItemList(mOrderList.map { it.value }, 1)
orderSfv.setOnCheckedCallback {
mAlternativeBinding?.run {
reuseToolbar.normalTitle.run {
text = "${mGameEntity?.name}-云存档"
marqueeOnce()
}
}
orderSfv?.run {
setItemList(mOrderList.map { it.value }, 1)
setOnCheckedCallback {
if (mIsSearch) {
mSearchFragment?.updateSortType(mOrderList[it])
} else {
mNormalFragment?.updateSortType(mOrderList[it])
}
}
searchBar.etSearch.setOnEditorActionListener { _, actionId, _ ->
}
searchBarBinding?.run {
etSearch.hint = R.string.game_detail_cloud_archive_search_hint.toResString()
tvBack.setOnClickListener {
changeSearchStatus(false)
etSearch.setText("")
}
etSearch.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
searchBar.tvSearch.performClick()
tvSearch.performClick()
}
false
}
searchBar.tvSearch.setOnClickListener {
val keyWord = searchBar.etSearch.text.toString().trim { it <= ' ' }
tvSearch.setOnClickListener {
val keyWord = etSearch.text.toString().trim { it <= ' ' }
if (keyWord.isBlank()) {
toast(R.string.search_hint)
} else {
changeSearchStatus(true)
}
}
searchBar.tvBack.setOnClickListener {
changeSearchStatus(false)
searchBar.etSearch.setText("")
}
archiveManageTv.setOnClickListener {
startActivity(
CloudArchiveManagerActivity.getIntent(
requireContext(),
mGameEntity ?: GameEntity(),
arguments?.getString(EntranceConsts.KEY_ARCHIVE_CONFIG_URL) ?: "",
"游戏详情页"
)
}
archiveManageTv?.setOnClickListener {
startActivity(
CloudArchiveManagerActivity.getIntent(
requireContext(),
mGameEntity ?: GameEntity(),
arguments?.getString(EntranceConsts.KEY_ARCHIVE_CONFIG_URL) ?: "",
"游戏详情页"
)
}
)
}
}
@ -99,7 +137,7 @@ class CloudArchiveFragment : LazyFragment() {
EntranceConsts.KEY_ARCHIVE_CONFIG_URL to arguments?.getString(EntranceConsts.KEY_ARCHIVE_CONFIG_URL, "")
)
if (mIsSearch) {
val keyWord = mBinding?.searchBar?.etSearch?.text?.toString()?.trim { it <= ' ' }
val keyWord = searchBarBinding?.etSearch?.text?.toString()?.trim { it <= ' ' }
bundle.putString(EntranceConsts.KEY_SEARCHKEY, keyWord)
NewFlatLogUtils.logCloudArchiveSearchKeyUpload(
mGameEntity?.id ?: "",
@ -113,7 +151,7 @@ class CloudArchiveFragment : LazyFragment() {
.replace(
R.id.contentFragment,
fragment,
SpecialCatalogFragment::class.java.name
CloudArchiveListFragment::class.java.name
)
.commitAllowingStateLoss()
}
@ -122,14 +160,27 @@ class CloudArchiveFragment : LazyFragment() {
when {
mIsSearch != isSearch -> {
mIsSearch = isSearch
mBinding?.searchBar?.tvBack?.goneIf(!mIsSearch)
searchBarBinding?.tvBack?.goneIf(!mIsSearch)
changeContentFragment()
}
mIsSearch -> {
val keyWord = mBinding?.searchBar?.etSearch?.text?.toString()?.trim { it <= ' ' } ?: ""
val keyWord = searchBarBinding?.etSearch?.text?.toString()?.trim { it <= ' ' } ?: ""
NewFlatLogUtils.logCloudArchiveSearchKeyUpload(mGameEntity?.id ?: "", mGameEntity?.name ?: "", keyWord)
mSearchFragment?.updateSearchKeyWord(keyWord)
}
}
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
orderSfv?.run {
setContainerBackground(com.gh.gamecenter.common.R.drawable.button_round_f5f5f5.toDrawable(requireContext()))
setIndicatorBackground(R.drawable.bg_game_collection_sfv_indicator.toDrawable(requireContext()))
setTextColor(
com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()),
com.gh.gamecenter.common.R.color.text_tertiary.toColor(requireContext())
)
}
}
}

View File

@ -15,7 +15,7 @@ class CloudArchiveListViewModel(
private val mGameId: String,
private var mKeyWord: String,
configUrl: String
) : BaseCloudArchiveViewModel(application, configUrl) {
) : BaseCloudArchiveViewModel(application, mGameId, configUrl) {
val refresh = MutableLiveData<Boolean>()
private var mSortType = SortType.HOTTEST

View File

@ -1,337 +0,0 @@
package com.gh.gamecenter.gamedetail.desc
import android.content.Context
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.PopupWindow
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.*
import com.gh.common.util.DialogUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.callback.ConfirmListener
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.ItemViewType
import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.SpanBuilder
import com.gh.gamecenter.databinding.ItemGameDetailRatingCommentBinding
import com.gh.gamecenter.entity.RatingComment
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.gamedetail.GameDetailFragment
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity
import com.gh.gamecenter.gamedetail.rating.logs.CommentLogsActivity
import com.gh.gamecenter.login.user.UserManager
import org.greenrobot.eventbus.EventBus
import java.util.regex.Pattern
class DescCommentsAdapter(
context: Context,
var mViewModel: DescViewModel,
private var mEntrance: String,
private var gameName: String?
) : ListAdapter<RatingComment>(context) {
var comments = ArrayList<RatingComment>()
val path = "游戏详情:介绍"
override fun getItemViewType(position: Int): Int {
return if (position == comments.size) {
ItemViewType.ITEM_FOOTER
} else {
ItemViewType.ITEM_BODY
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == ItemViewType.ITEM_BODY) {
GameDetailRatingCommentViewHolder(parent.toBinding())
} else {
MoreViewHolder(LayoutInflater.from(mContext).inflate(R.layout.item_game_detail_comment_more, parent, false))
}
}
override fun getItemCount(): Int {
return comments.size + 1
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is GameDetailRatingCommentViewHolder) {
val commentData = comments[position]
var isChildLongClick = false
holder.binding.run {
ImageUtils.display(userIcon, commentData.user.icon)
ImageUtils.display(userBadge, commentData.user.auth?.icon)
userName.text = commentData.user.name
ratingStart.rating = commentData.star.toFloat()
val p = Pattern.compile(RatingEditActivity.LABEL_REGEX)
val m = p.matcher(commentData.content)
if (m.find()) {
val contents =
TextHelper.getCommentLabelSpannableStringBuilder(commentData.content, com.gh.gamecenter.common.R.color.text_theme)
content.setTextWithHighlightedTextWrappedInsideWrapper(
text = contents,
highlightedTextClickListener = TextHelper.DirectToWebViewHighlightedTextClick(mContext, path)
)
} else {
content.setTextWithHighlightedTextWrappedInsideWrapper(
text = commentData.content,
highlightedTextClickListener = TextHelper.DirectToWebViewHighlightedTextClick(mContext, path)
)
}
if (commentData.user.badge != null) {
sdvUserBadge.visibility = View.VISIBLE
tvBadgeName.visibility = View.VISIBLE
ImageUtils.display(sdvUserBadge, commentData.user.badge?.icon)
tvBadgeName.text = commentData.user.badge?.name
} else {
sdvUserBadge.visibility = View.GONE
tvBadgeName.visibility = View.GONE
}
ipRegionTv.goneIf(!(commentData.source != null && commentData.source.region.isNotEmpty()))
ipRegionTv.text = " · ${commentData.source?.region}"
when {
commentData.isEditContent == null -> {
time.setTextColor(ContextCompat.getColor(mContext, com.gh.gamecenter.common.R.color.text_tertiary))
time.text = if (commentData.ignore) {
val s = "${NewsUtils.getFormattedTime(commentData.time)} 保护期评论不计入总分"
SpanBuilder(s).image(s.length - 12, s.length - 11, R.drawable.ic_ignore_rating_tips)
.color(mContext, s.length - 10, s.length, com.gh.gamecenter.common.R.color.text_secondary).build()
} else {
NewsUtils.getFormattedTime(commentData.time)
}
}
commentData.isEditContent!! -> {
time.setTextColor(ContextCompat.getColor(mContext, com.gh.gamecenter.common.R.color.text_F56614))
time.text = if (commentData.ignore) {
"${NewsUtils.getFormattedTime(commentData.time)} 保护期间修改评论 >"
} else {
"${NewsUtils.getFormattedTime(commentData.time)} 已修改 >"
}
}
else -> {
time.setTextColor(ContextCompat.getColor(mContext, com.gh.gamecenter.common.R.color.text_F56614))
time.text = if (commentData.ignore) {
"${NewsUtils.getFormattedTime(commentData.time)} 保护期间修改评论"
} else {
"${NewsUtils.getFormattedTime(commentData.time)} 已修改"
}
}
}
sdvUserBadge.setOnClickListener {
DialogUtils.showViewBadgeDialog(mContext, commentData.user.badge, object : ConfirmListener {
override fun onConfirm() {
MtaHelper.onEvent(
"进入徽章墙_用户记录",
"游戏详情-玩家评论",
"${commentData.user.name}${commentData.user.id}"
)
MtaHelper.onEvent("徽章中心", "进入徽章中心", "游戏详情-玩家评论")
DirectUtils.directToBadgeWall(
mContext,
commentData.user.id,
commentData.user.name,
commentData.user.icon
)
}
})
}
userIcon.setOnClickListener {
DirectUtils.directToHomeActivity(mContext, commentData.user.id, mEntrance, "游戏详情-玩家评论")
MtaHelper.onEvent("游戏详情_新", "玩家评论_点击用户头像", mViewModel.game?.name)
NewLogUtils.logGameDetailCommentClick(
mViewModel.game?.name ?: "",
mViewModel.game?.id ?: "",
"个人主页"
)
}
userName.setOnClickListener {
userIcon.performClick()
MtaHelper.onEvent("游戏详情_新", "玩家评论_点击用户名字", mViewModel.game?.name)
}
tvBadgeName.setOnClickListener { sdvUserBadge.performClick() }
commentItem.setOnClickListener {
if (isChildLongClick) {
isChildLongClick = false
return@setOnClickListener
}
val exposureSource = arrayListOf(
ExposureSource("游戏详情"),
ExposureSource("详情tab"),
ExposureSource("玩家评价"),
).toJson()
val intent = RatingReplyActivity.getIntent(
context = mContext,
gameId = mViewModel.game?.id ?: "",
commentId = commentData.id,
exposureSource = exposureSource,
entrance = mEntrance,
path = path
)
SyncDataBetweenPageHelper.startActivityForResult(mContext, intent, RATING_REPLY_REQUEST, position)
MtaHelper.onEvent("游戏详情_新", "玩家评论_点击评论", mViewModel.game?.name)
NewLogUtils.logGameDetailCommentClick(
mViewModel.game?.name ?: "",
mViewModel.game?.id ?: "",
"评论内容"
)
}
content.setExpandCallback {
MtaHelper.onEvent("游戏详情_新", "玩家评论_点击全文", mViewModel.game?.name)
}
content.setOnLongClickListener(View.OnLongClickListener {
isChildLongClick = true
commentData.content.replace(RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), "").copyTextAndToast()
return@OnLongClickListener true
})
more.setOnClickListener {
showMorePopWindow(it, commentData.user.id == UserManager.getInstance().userId) { text ->
when (text) {
"复制" -> {
commentData.content.replace(RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), "")
.copyTextAndToast()
MtaHelper.onEvent("游戏详情_新", "玩家评论_复制", mViewModel.game?.name)
}
"修改" -> {
MtaHelper.onEvent("游戏详情_新", "玩家评论_修改", mViewModel.game?.name)
val intent = RatingEditActivity.getPatchIntent(mContext, mViewModel.game!!, commentData)
SyncDataBetweenPageHelper.startActivityForResult(
mContext,
intent,
RATING_PATCH_REQUEST,
position
)
}
"投诉" -> {
MtaHelper.onEvent("游戏详情_新", "玩家评论_投诉", mViewModel.game?.name)
mContext.ifLogin(BaseActivity.mergeEntranceAndPath(mEntrance, path)) {
DialogUtils.showReportReasonDialog(
mContext,
Constants.REPORT_LIST.toList() as java.util.ArrayList<String>
) { reason, desc ->
SimpleRequestHelper.reportGameComment(
mViewModel.game?.id ?: "",
commentData.id,
if (reason != "其他原因") reason else desc
)
}
}
}
"删除" -> {
DialogHelper.showDeleteGameCommentDialog(
mContext,
R.string.delete_game_comment.toResString()
) {
SimpleRequestHelper.deleteGameComment(
mViewModel.game?.id ?: "",
commentData.id
) {
// 删除列表中的评论(如果当前列表有的话)
val index = comments.indexOfFirst { item ->
item.id == commentData.id
}
if (index != -1) {
comments.removeAt(index)
notifyItemRemoved(index)
}
}
}
}
}
}
}
time.setOnClickListener {
if (commentData.isEditContent == null && commentData.ignore) {
MtaHelper.onEvent("游戏详情_新", "玩家评论-评论说明", mViewModel.game?.name)
DialogUtils.showStopServerExplanationDialog(
mContext,
if (mViewModel.game?.commentDescription?.isNotEmpty() == true)
mViewModel.game?.commentDescription else mContext.getString(R.string.rating_protection),
mViewModel.game?.name
?: ""
)
} else if (commentData.isEditContent == true) {
MtaHelper.onEvent("游戏详情_新", "玩家评论-点击时间", mViewModel.game?.name)
val intent = CommentLogsActivity.getIntent(mContext, mViewModel.game!!.id, commentData.id)
mContext.startActivity(intent)
}
}
}
} else if (holder is MoreViewHolder) {
holder.itemView.setOnClickListener {
EventBus.getDefault().post(EBReuse(GameDetailFragment.SKIP_RATING))
MtaHelper.onEvent("游戏详情_新", "玩家评论_查看全部评论", gameName)
NewLogUtils.logGameDetailCommentClick(
mViewModel.game?.name ?: "",
mViewModel.game?.id ?: "",
"查看全部评论"
)
}
}
}
private fun showMorePopWindow(v: View, isMyRating: Boolean, clickListener: (String) -> Unit) {
val contentList = if (isMyRating) arrayListOf("复制", "修改", "删除")
else arrayListOf("复制", "投诉")
val inflater = LayoutInflater.from(v.context)
val layout = inflater.inflate(com.gh.gamecenter.common.R.layout.layout_popup_container, null)
val popupWindow = PopupWindow(
layout,
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
popupWindow.apply {
setBackgroundDrawable(ColorDrawable(0))
isTouchable = true
isFocusable = true
isOutsideTouchable = true
}
val container = layout.findViewById<LinearLayout>(R.id.container)
for (text in contentList) {
val item = inflater.inflate(R.layout.layout_popup_option_item, container, false)
container.addView(item)
val hitText = item.findViewById<TextView>(R.id.hint_text)
hitText.text = text
item.setOnClickListener {
clickListener.invoke(text)
popupWindow.dismiss()
}
}
popupWindow.showAutoOrientation(v)
}
class MoreViewHolder(var view: View) : RecyclerView.ViewHolder(view)
class GameDetailRatingCommentViewHolder(var binding: ItemGameDetailRatingCommentBinding) :
RecyclerView.ViewHolder(binding.root)
companion object {
const val RATING_REPLY_REQUEST = 233
const val RATING_PATCH_REQUEST = 234
}
}

View File

@ -1,322 +0,0 @@
package com.gh.gamecenter.gamedetail.desc
import android.app.Activity
import android.content.Intent
import android.graphics.Rect
import android.view.View
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.therouter.TheRouter
import com.gh.common.util.DirectUtils
import com.gh.common.util.OnSyncCallBack
import com.gh.common.util.SyncDataBetweenPageHelper
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.LazyFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.utils.observeNonNull
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.common.utils.viewModelProviderFromParent
import com.gh.gamecenter.core.iinterface.IScrollable
import com.gh.gamecenter.core.provider.IFloatingWindowProvider
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.FragmentDescBinding
import com.gh.gamecenter.entity.RatingComment
import com.gh.gamecenter.eventbus.EBScroll
import com.gh.gamecenter.eventbus.EBTypeChange
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.WelcomeDialogEntity
import com.gh.gamecenter.gamedetail.GameDetailFragment
import com.gh.gamecenter.gamedetail.GameDetailFragment.Companion.SKIP_DESC
import com.gh.gamecenter.gamedetail.GameDetailViewModel
import com.gh.gamecenter.gamedetail.entity.DetailEntity
import com.gh.gamecenter.gamedetail.entity.NewGameDetailEntity
import com.gh.gamecenter.gamedetail.rating.RatingFragment
import com.gh.gamecenter.video.detail.VideoDetailActivity
import com.halo.assistant.HaloApp
import io.reactivex.disposables.CompositeDisposable
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
// TODO 处理页面重建时会生成额外 Fragment 的问题
class DescFragment: LazyFragment(), IScrollable {
private var mAdapter: DescAdapter ? = null
private var mLayoutManager: LinearLayoutManager? = null
private var mGameEntity: GameEntity? = null
private var mNewDetailEntity: NewGameDetailEntity? = null
private lateinit var mViewModel: DescViewModel
private lateinit var mBinding: FragmentDescBinding
private var mCompositeDisposable = CompositeDisposable()
var openVideoStreaming = false // 是否自动打开视频流
private var mScrollToLibao = false
private var mScrollToServer = false
override fun getRealLayoutId() = R.layout.fragment_desc
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val adapter = mAdapter ?: return
if (resultCode == Activity.RESULT_OK) {
if (DescCommentsAdapter.RATING_REPLY_REQUEST == requestCode || DescCommentsAdapter.RATING_PATCH_REQUEST == requestCode) {
var commentPosition = 0
SyncDataBetweenPageHelper.resultHandle(data, object : OnSyncCallBack<RatingComment> {
override fun onData(dataPosition: Int): RatingComment? {
val descItemList = adapter.descItemList
for (i in 0 until descItemList.size) {
val comments = descItemList[i].comment
if (comments != null) {
commentPosition = i
val ratingComment = comments[dataPosition]
if (DescCommentsAdapter.RATING_PATCH_REQUEST == requestCode) {
ratingComment.ignore = mGameEntity?.ignoreComment ?: false
}
return ratingComment
}
}
return null
}
override fun onNotify(dataPosition: Int) {
adapter.notifyItemChanged(commentPosition)
}
})
} else if (requestCode == 100) {
val position = adapter.descItemList.indexOfFirst { it.type == DetailEntity.Type.LIBAO.value }
adapter.notifyItemChanged(position)
}
} else if (requestCode == DescCommentsAdapter.RATING_REPLY_REQUEST && resultCode == RatingFragment.RATING_DELETE_RESULT) {
data?.getParcelableExtra<RatingComment>(RatingComment::class.java.simpleName)?.run {
val descItemList = adapter.descItemList
var commentPosition = 0
for (i in 0 until descItemList.size) {
val comments = descItemList[i].comment
if (comments != null) {
commentPosition = i
val deleteCommentPosition = comments.indexOfFirst { it.id == id }
if (deleteCommentPosition != -1) comments.removeAt(deleteCommentPosition)
break
}
}
adapter.notifyItemChanged(commentPosition)
}
}
}
override fun onFragmentFirstVisible() {
mGameEntity = arguments?.getParcelable(EntranceConsts.KEY_GAME_ENTITY)
openVideoStreaming = arguments?.getBoolean(EntranceConsts.KEY_OPEN_VIDEO_STREAMING, false) ?: false
mScrollToLibao = arguments?.getBoolean(EntranceConsts.KEY_SCROLL_TO_LIBAO, false) ?: false
mScrollToServer = arguments?.getBoolean(EntranceConsts.KEY_SCROLL_TO_SERVER, false) ?: false
val gameDetailFactory =
GameDetailViewModel.Factory(HaloApp.getInstance().application, mGameEntity?.id, mGameEntity)
val gameDetailViewModel: GameDetailViewModel = viewModelProviderFromParent(gameDetailFactory, mGameEntity?.id ?: "")
mNewDetailEntity = gameDetailViewModel.gameDetailLiveData.value?.data
val factory = DescViewModel.Factory(HaloApp.getInstance().application, mGameEntity)
mViewModel = viewModelProvider(factory)
super.onFragmentFirstVisible()
gameDetailViewModel.gameDetailLiveData.observeNonNull(this) { gameDetail ->
if (gameDetail.data == null) return@observeNonNull
mAdapter?.updateDescItemList(mViewModel.decorateList(gameDetail.data!!.detailEntity))
// 非镜像游戏获取大家都在玩 (数据来源看具体方法内容) 数据
if (mGameEntity?.shouldUseMirrorInfo() == false) {
mViewModel.generateRecommendedGamesItem(gameDetail.data!!.detailEntity)
}
if (openVideoStreaming) {
gameDetail.data!!.detailEntity.forEach { entity ->
if (entity.video != null && activity !is VideoDetailActivity) {
DirectUtils.directToVideoDetail(
requireContext(), entity.video?.firstOrNull()?.videoId ?: "", entity.video?.firstOrNull()?.videoId, path = "游戏详情-介绍视频"
)
return@forEach
}
}
}
}
gameDetailViewModel.unifiedGameDetailWithUserRelatedInfoForChildLiveData.observeNonNull(this) {
mAdapter?.updateDescItemList(mViewModel.decorateList(it.detailEntity))
}
mViewModel.list.observe(this) {
mAdapter?.updateDescItemList(it)
if (mScrollToLibao && mViewModel.getLibaoIndexPosition() != -1) {
mScrollToLibao = false
mLayoutManager?.scrollToPositionWithOffset(mViewModel.getLibaoIndexPosition(), 0)
}
if (mScrollToServer && mViewModel.getServerIndexPosition() != -1) {
mScrollToServer = false
mLayoutManager?.scrollToPositionWithOffset(mViewModel.getServerIndexPosition(), 0)
}
}
mViewModel.changeColumnGameLiveData.observe(this) {
val viewHolder =
mBinding.recyclerview.findViewHolderForAdapterPosition(mViewModel.getColumnRecommendPosition()) as? DescAdapter.ColumnRecommendViewHolder
viewHolder?.binding?.run {
headPb.visibility = View.GONE
moreTv.isEnabled = true
}
if (it) {
mAdapter?.notifyItemChanged(mViewModel.getColumnRecommendPosition())
}
}
}
override fun onRealLayoutInflated(inflatedView: View) {
super.onRealLayoutInflated(inflatedView)
mBinding = FragmentDescBinding.bind(inflatedView)
showFloatingWindowIfNeeded()
mBinding.reuseLoading.root.visibility = View.GONE
mAdapter = DescAdapter(requireContext(), mEntrance, mViewModel, mNewDetailEntity)
(mBinding.recyclerview.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
mLayoutManager = LinearLayoutManager(context)
mBinding.recyclerview.layoutManager = mLayoutManager
mBinding.recyclerview.adapter = mAdapter
mBinding.recyclerview.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val firstCompletelyVisibleItemPosition = mLayoutManager!!.findFirstCompletelyVisibleItemPosition()
val lastCompletelyVisibleItemPosition = mLayoutManager!!.findLastCompletelyVisibleItemPosition()
for (i in firstCompletelyVisibleItemPosition..lastCompletelyVisibleItemPosition) {
if (i < 0) continue
if (mAdapter?.getItemViewType(i) == DescAdapter.CUSTOM_COLUMN
&& mAdapter!!.descItemList[i].customColumn?.showExpandTagsHint == true
) {
SPUtils.setBoolean(Constants.SP_HAS_SHOWN_EXPANDED_GAME_DETAIL_TAGS_HINT, true)
}
}
}
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
EventBus.getDefault().post(EBTypeChange(GameDetailFragment.EB_SCROLLING, 0))
}
exposureScroll(newState)
}
})
exposureScroll(RecyclerView.SCROLL_STATE_IDLE)
}
private fun exposureScroll(newState: Int) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
val layoutManager = mBinding.recyclerview.layoutManager as? LinearLayoutManager
val firstVisibleItem = layoutManager?.findFirstCompletelyVisibleItemPosition() ?: -1
val lastVisibleItem = layoutManager?.findLastCompletelyVisibleItemPosition() ?: -1
val childCount = mBinding.recyclerview.adapter?.itemCount ?: 0
if (firstVisibleItem == -1 || lastVisibleItem == -1) return
for (i in 0 until childCount) {
val viewHolder = mBinding.recyclerview.findViewHolderForAdapterPosition(i)
if (viewHolder != null && viewHolder is ExposureViewHolder) {
if (i in firstVisibleItem..lastVisibleItem) {
val rect = Rect()
viewHolder.itemView.getLocalVisibleRect(rect)
if (rect.top == 0 && rect.bottom == viewHolder.itemView.height) {
viewHolder.startDelayLogRunnable()
}
} else {
viewHolder.removeLogRunnable()
}
}
}
}
}
override fun onFragmentPause() {
super.onFragmentPause()
val childCount = mBinding.recyclerview.adapter?.itemCount ?: 0
for (i in 0 until childCount) {
val viewHolder = mBinding.recyclerview.findViewHolderForAdapterPosition(i)
if (viewHolder is ExposureViewHolder) {
viewHolder.removeLogRunnable()
}
}
}
override fun onDestroy() {
super.onDestroy()
mCompositeDisposable.dispose()
mAdapter?.stopHandlerThread()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(reuse: EBReuse) {
if (SKIP_DESC == reuse.type) {
mAdapter?.notifyDataSetChanged()
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(bean: EBScroll) {
if (mGameEntity?.id == bean.id) {
val position = mViewModel.getGameInfoPosition()
(mBinding.recyclerview.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(position, 0)
}
}
override fun scrollToTop() {
if (::mBinding.isInitialized) {
mBinding.recyclerview.scrollToPosition(0)
}
}
fun scrollToRelatedVersion() {
if (mViewModel.getRelatedVersionPosition() != -1) {
mLayoutManager?.scrollToPositionWithOffset(mViewModel.getRelatedVersionPosition(), 0)
}
}
fun scrollToLibao() {
if (mViewModel.getDetailLibaoPosition() != -1) {
mLayoutManager?.scrollToPositionWithOffset(mViewModel.getDetailLibaoPosition(), 0)
}
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
if (!::mBinding.isInitialized) return
mBinding.recyclerview.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_background.toColor(requireContext()))
mBinding.recyclerview.recycledViewPool.clear()
mAdapter?.let { it.notifyItemRangeChanged(0, it.itemCount) }
}
private fun showFloatingWindowIfNeeded() {
val floatingWindowProvider = TheRouter.get(IFloatingWindowProvider::class.java)
floatingWindowProvider?.getAndShowFloatingWindow(
mGameEntity?.id ?: "",
mGameEntity?.name ?: "",
"游戏详情",
this,
mBinding.recyclerview
)?.let {
mCompositeDisposable.add(it)
}
}
}

View File

@ -1,460 +0,0 @@
package com.gh.gamecenter.gamedetail.desc
import android.app.Application
import android.os.Build
import android.text.TextUtils
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.facebook.common.util.UriUtil
import com.gh.common.util.PackageUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.exposure.meta.MetaUtil
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.entity.SubjectEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.GameInfo
import com.gh.gamecenter.gamedetail.entity.CustomColumn
import com.gh.gamecenter.gamedetail.entity.DetailEntity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.google.gson.JsonArray
import com.google.gson.reflect.TypeToken
import com.halo.assistant.HaloApp
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.json.JSONObject
import retrofit2.HttpException
class DescViewModel(
application: Application,
var game: GameEntity?
) : AndroidViewModel(application) {
private var mDataList = arrayListOf<DetailEntity>()
private var mRelatedGameList = arrayListOf<GameEntity>()
private var mGameInfoPosition = 0
private var mLibaoPosition = -1
private var mServerPosition = -1
private var mDetailLibaoPosition = -1
private var mRelatedVersionPosition = -1
private var mColumnRecommendPosition = -1
private var mGameInfo: GameInfo? = null
private val mIdMaps = hashMapOf<String, String>()
private var mSubjectPage = 1
var list = MutableLiveData<ArrayList<DetailEntity>>()
var changeColumnGameLiveData = MutableLiveData<Boolean>()
var gameId = game?.id
/**
* 构建大家都在玩的item
*/
fun generateRecommendedGamesItem(mDataList: ArrayList<DetailEntity>) {
this.mDataList = mDataList
mIdMaps.clear()
val detailEntity = mDataList.find { it.type == DetailEntity.Type.RECOMMENDED_GAMES.value } ?: return
val relatedGames = detailEntity.relatedGames
val installGames = detailEntity.installGames
val downloadGames = detailEntity.downloadGames
if (relatedGames.isNullOrEmpty()
&& installGames.isNullOrEmpty()
&& downloadGames.isNullOrEmpty()
) {
assembleListWithRecommendedGames()
return
}
val labelGames = arrayListOf<String>()
for (relatedGame in relatedGames ?: listOf()) {
relatedGame.game?.let {
labelGames.addAll(it)
}
}
if (labelGames.isNotEmpty()) {
val gameIds = labelGames.take(4)
gameIds.forEach {
mIdMaps[it] = "标签推荐"
}
}
val labelGameCount = mIdMaps.size
if (installGames != null) {
val gameIds = installGames.take(4)
gameIds.forEach {
mIdMaps[it] = "安装推荐"
}
}
if (downloadGames != null) {
val gameIds = downloadGames.take(4)
gameIds.forEach {
mIdMaps[it] = "下载推荐"
}
}
if (mIdMaps.size < 6 && labelGames.size > labelGameCount) {
for (i in labelGameCount until labelGames.size) {
mIdMaps[labelGames[i]] = "标签推荐"
if (mIdMaps.size >= 6) break
}
}
if (mIdMaps.size < 6) {
val entity = mDataList.find { it.type == DetailEntity.Type.RECOMMENDED_GAMES.value }
mDataList.remove(entity)
assembleListWithRecommendedGames()
return
}
getGamesDigestByIds {
mRelatedGameList.clear()
mRelatedGameList.addAll(it)
assembleListWithRecommendedGames()
}
}
private fun getGamesDigestByIds(callback: (List<GameEntity>) -> Unit) {
val ids = mIdMaps.map { it.key }.toList().joinToString("-")
val filterQuery = UrlFilterUtils.getFilterQuery("game_ids", ids)
RetrofitManager.getInstance().api.getGamesDigestByIds(filterQuery)
.compose(observableToMain())
.subscribe(object : Response<List<GameEntity>>() {
override fun onResponse(response: List<GameEntity>?) {
super.onResponse(response)
response?.forEach { it.recommendType = mIdMaps[it.id] ?: "" }
response?.let(callback) ?: callback.invoke(listOf())
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
callback.invoke(listOf())
}
})
}
private fun assembleListWithRecommendedGames() {
for ((index, data) in mDataList.withIndex()) {
if (data.info != null) {
mGameInfoPosition = index
mGameInfo = data.info!!
}
if (data.server != null) {
mServerPosition = index
}
if (data.libao != null) {
mLibaoPosition = index
}
if (data.columnGames != null) {
mColumnRecommendPosition = index
}
if (data.relatedGames != null) {
mRelatedGameList.shuffle()
val recommendedGames = SubjectEntity().apply {
this.data = mRelatedGameList
}
data.recommendedGames = recommendedGames
}
}
list.postValue(mDataList)
}
fun changeSubjectGame(subjectId: String, gameCount: Int) {
RetrofitManager.getInstance().api
.getSubjectGame(subjectId, mSubjectPage)
.compose(observableToMain())
.subscribe(object : Response<retrofit2.Response<JsonArray>>() {
override fun onResponse(response: retrofit2.Response<JsonArray>?) {
super.onResponse(response)
if (response == null) return
val total = response.headers().get("total")?.toInt() ?: 0
val isHasNextPage = (total - mSubjectPage * 20) > 0
val type = object : TypeToken<ArrayList<GameEntity>>() {}.type
val games = GsonUtils.gson.fromJson<ArrayList<GameEntity>>(response.body()?.toJson() ?: "", type)
val detailEntity =
mDataList.find { data -> data.type == DetailEntity.Type.COLUMN_RECOMMEND.value } ?: return
val randomArray = RandomUtils.getRandomArray(gameCount, games.size)
detailEntity.columnGames?.run {
clear()
for (i in randomArray) {
add(games[i])
}
}
changeColumnGameLiveData.postValue(true)
mSubjectPage = if (isHasNextPage) mSubjectPage + 1 else 1
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
changeColumnGameLiveData.postValue(false)
}
})
}
fun sendSuggestion() {
val params = hashMapOf<String, String>()
params["from"] = ""
params["ghversion"] = PackageUtils.getGhVersionName()
params["channel"] = HaloApp.getInstance().channel
params["type"] = Build.MODEL
params["sdk"] = Build.VERSION.SDK_INT.toString()
params["version"] = Build.VERSION.RELEASE
params["source"] = HaloApp.getInstance().application.getString(R.string.app_name)
params["jnfj"] = MetaUtil.getBase64EncodedIMEI()
params["manufacturer"] = Build.MANUFACTURER
params["rom"] = MetaUtil.getRom().name + " " + MetaUtil.getRom().versionName
params["suggestion_type"] = "游戏求更新"
params["game_id"] = game?.id ?: ""
params["message"] =
"求更新:${game?.name}(${game?.getApk()?.firstOrNull()?.packageName}, ${game?.getApk()?.firstOrNull()?.version})"
val requestBody = params.createRequestBody()
RetrofitManager.getInstance().api.postSuggestion(requestBody)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody?>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
ToastUtils.showToast("感谢您的反馈信息,我们将尽快处理~")
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
e?.response()?.errorBody()?.let {
val content = JSONObject(it.string())
if (content.getInt("code") == 403208) {
ToastUtils.showToast("您已经提交过反馈信息,我们将尽快处理~")
}
}
}
})
}
// TODO 装饰操作放到子线程去做
// 装饰列表数据
fun decorateList(detailEntityList: ArrayList<DetailEntity>): ArrayList<DetailEntity> {
val specialPadding = DisplayUtils.dip2px(12F)
val defaultPadding = DisplayUtils.dip2px(15F)
var containsFirstTimeExpandCustomColumnTags = false
var hasShownCustomColumnTagsExpandHint =
SPUtils.getBoolean(Constants.SP_HAS_SHOWN_EXPANDED_GAME_DETAIL_TAGS_HINT)
// A 确定每个 item 的上下内边距
for ((index, rawItem) in detailEntityList.withIndex()) {
rawItem.paddingTop = defaultPadding
rawItem.paddingBottom = defaultPadding
if (index == 0) {
rawItem.paddingTop = specialPadding
}
}
// B 将游戏介绍转为简单的自定义栏目
for (rawItem in detailEntityList) {
if (rawItem.type == DetailEntity.Type.DES.value) {
rawItem.type = DetailEntity.Type.CUSTOM_COLUMN.value
rawItem.customColumn = CustomColumn(
name = "游戏简介",
order = 1,
nameIcon = UriUtil.getUriForResourceId(R.drawable.ic_game_desc).toString(),
des = rawItem.des,
isHtmlDes = false,
showDesRowNum = 3
)
break
}
}
// C 标记"公告"、"自定义栏目"、"详细信息" 的UI样式是否合并在一起处理置顶文章的内容
for ((index, rawItem) in detailEntityList.withIndex()) {
if (rawItem.type == DetailEntity.Type.NOTICE.value
|| rawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value
|| rawItem.type == DetailEntity.Type.GAME_INFO.value
) {
if (index + 1 != detailEntityList.size) {
val nextRawItem = detailEntityList[index + 1]
if (nextRawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value
|| nextRawItem.type == DetailEntity.Type.NOTICE.value
|| nextRawItem.type == DetailEntity.Type.GAME_INFO.value
) {
// 默认情况下 UI 与前后相连
rawItem.shouldBoundWithNextItem = true
nextRawItem.shouldBoundWithPreviousItem = true
// 特殊情况下,如果自定义栏目类型为按钮,且后续的项不是按钮就独立显示,后续的项也为按钮时合并显示 (仅按钮类型的自定义栏目合并)
if (rawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value
&& rawItem.customColumn?.link?.style == "button"
) {
val nextItemIsButtonStyleCustomColumn =
(nextRawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value && nextRawItem.customColumn?.link?.style == "button")
rawItem.paddingBottom = 0
rawItem.shouldBoundWithNextItem = nextItemIsButtonStyleCustomColumn
nextRawItem.shouldBoundWithPreviousItem = nextItemIsButtonStyleCustomColumn
rawItem.paddingTop = specialPadding
nextRawItem.paddingTop = specialPadding
}
// 若当前项不是自定义栏目按钮类型的项,并且下个项是自定义栏目的项,不合并相关 UI
if (nextRawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value
&& nextRawItem.customColumn?.link?.style == "button"
&& (rawItem.type != DetailEntity.Type.CUSTOM_COLUMN.value
|| rawItem.customColumn?.link?.style != "button")
) {
nextRawItem.shouldBoundWithPreviousItem = false
nextRawItem.paddingBottom = 0
}
}
}
}
// 处理置顶文章
if (rawItem.type == "article") {
if (rawItem.articleTop != null && rawItem.articleTop?.size != 0) {
for ((i, article) in rawItem.articleTop!!.withIndex()) {
article.priority = Int.MAX_VALUE
rawItem.article?.add(i, article)
}
rawItem.articleTop?.clear()
}
}
}
// D 处理自定义栏目相关的东西
for (rawItem in detailEntityList) {
if (rawItem.type == DetailEntity.Type.CUSTOM_COLUMN.value) {
// 判断自定义栏目的标签是否需要进入就自动展开
if (rawItem.customColumn?.showInfoTagDesType == "first_expand"
&& !SPUtils.getBoolean(Constants.SP_HAS_EXPANDED_GAME_DETAIL_TAGS)
) {
containsFirstTimeExpandCustomColumnTags = true
rawItem.customColumn?.showInfoTagDesType = "expand"
}
// 正文内容为空,但是后台配置了标签展开的默认展开
if (rawItem.customColumn?.showInfoTag == true
&& TextUtils.isEmpty(rawItem.customColumn?.des)
) {
rawItem.customColumn?.showInfoTagDesType = "expand"
}
// 判断是否显示标签展开提示
if (rawItem.customColumn?.showInfoTagDes == true
&& rawItem.customColumn?.infoTag?.size != 0
&& rawItem.customColumn?.showInfoTagDesType != "expand"
&& !hasShownCustomColumnTagsExpandHint
) {
rawItem.customColumn?.showExpandTagsHint = true
// 内存置为 true 避免出现多个提示
hasShownCustomColumnTagsExpandHint = true
}
// 不存在缩起正文的自定义栏目默认全显示
if (TextUtils.isEmpty(rawItem.customColumn?.desBrief) && rawItem.customColumn?.name != "游戏简介") {
rawItem.customColumn?.showDesType = "all"
}
// 将自定义栏目正文内容里低版本 android 系统不支持的 HTML Tag 转为手动处理
if (!TextUtils.isEmpty(rawItem.customColumn?.desBrief)) {
rawItem.customColumn?.desFull = rawItem.customColumn?.desFull?.replaceUnsupportedHtmlTag()
rawItem.customColumn?.desBrief = rawItem.customColumn?.desBrief?.replaceUnsupportedHtmlTag()
}
rawItem.customColumn?.des = rawItem.customColumn?.desFull
?: rawItem.customColumn?.des
}
}
for ((index, entity) in detailEntityList.withIndex()) {
if (entity.libao != null) {
mDetailLibaoPosition = index
}
if (entity.relatedVersion != null) {
mRelatedVersionPosition = index
}
}
if (containsFirstTimeExpandCustomColumnTags) {
SPUtils.setBoolean(Constants.SP_HAS_EXPANDED_GAME_DETAIL_TAGS, true)
}
loadCustomColumnImageInAdvance(detailEntityList)
return detailEntityList
}
fun getServerIndexPosition() = mServerPosition
fun getLibaoIndexPosition() = mLibaoPosition
fun getGameInfoPosition() = mGameInfoPosition
fun getDetailLibaoPosition() = mDetailLibaoPosition
fun getRelatedVersionPosition() = mRelatedVersionPosition
fun getColumnRecommendPosition() = mColumnRecommendPosition
fun getGameInfo() = mGameInfo
/**
* 预加载自定义栏目的标签小图标
*/
private fun loadCustomColumnImageInAdvance(detailEntityList: ArrayList<DetailEntity>) {
for (item in detailEntityList) {
if (item.type == DetailEntity.Type.CUSTOM_COLUMN.value) {
item.customColumn?.infoTag?.let {
for (tag in it) {
tryWithDefaultCatch {
ImageUtils.picasso.load(tag.icon).fetch()
}
}
}
}
}
}
fun postRequestSpeed() {
RetrofitManager.getInstance().newApi.postRequestSpeed(com.gh.gamecenter.login.user.UserManager.getInstance().userId, gameId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Response<ResponseBody>() {
override fun onResponse(response: ResponseBody?) {
super.onResponse(response)
ToastUtils.showToast("感谢您的反馈信息,我们将尽快处理~")
}
override fun onFailure(e: HttpException?) {
super.onFailure(e)
e?.response()?.errorBody()?.let {
val content = JSONObject(it.string())
if (content.getInt("code") == 403208) {
ToastUtils.showToast("您已经提交过反馈信息,我们将尽快处理~")
}
}
}
})
}
class Factory(
private val mApplication: Application,
private val game: GameEntity?
) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return DescViewModel(mApplication, game) as T
}
}
}

View File

@ -1,30 +0,0 @@
package com.gh.gamecenter.gamedetail.desc
import android.os.Handler
import android.view.View
import androidx.recyclerview.widget.RecyclerView
open class ExposureViewHolder(view: View, val handler: Handler) : RecyclerView.ViewHolder(view) {
private var mLogRunnable: Runnable? = null
fun startDelayLogRunnable() {
if (mLogRunnable == null) {
mLogRunnable = Runnable {
exposureLog()
}
handler.postDelayed(mLogRunnable!!, 3000)
}
}
open fun exposureLog() {
}
fun removeLogRunnable() {
if (mLogRunnable != null) {
handler.removeCallbacks(mLogRunnable!!)
mLogRunnable = null
}
}
}

View File

@ -1,84 +0,0 @@
package com.gh.gamecenter.gamedetail.desc
import android.content.Context
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.text.Spanned
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.utils.ImageUtils
import com.gh.gamecenter.common.view.CustomLinkMovementMethod
import com.gh.gamecenter.common.utils.dip2px
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.utils.tryWithDefaultCatch
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.databinding.GamedetailItemCustomColumnItemBinding
import com.gh.gamecenter.entity.TagEntity
import com.lightgame.adapter.BaseRecyclerAdapter
import com.squareup.picasso.Picasso
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
class GameDetailCustomColumnAdapter(context: Context) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
private var mTags: ArrayList<TagEntity> = arrayListOf()
private var mShowTagDes: Boolean = false
fun updateData(tags: ArrayList<TagEntity>, showTagDes: Boolean) {
this.mTags = tags
this.mShowTagDes = showTagDes
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return GameDetailCustomViewHolderViewHolder(parent.toBinding())
}
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
if (viewHolder is GameDetailCustomViewHolderViewHolder) {
val (_, name, icon, des, color) = mTags[position]
val marginBetweenIconAndName = " "
val content = if (mShowTagDes) "$marginBetweenIconAndName$name $des" else "$marginBetweenIconAndName$name"
val spannable = SpanBuilder(content)
.color(
marginBetweenIconAndName.length,
name?.length?.plus(marginBetweenIconAndName.length) ?: 1,
color ?: "#000000"
)
.build()
tryWithDefaultCatch {
Single.just(icon)
.map {
ImageUtils.picasso.load(Uri.parse(it)).priority(Picasso.Priority.HIGH).get()
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
val bitmapDrawable = BitmapDrawable(mContext.resources, it)
bitmapDrawable.setBounds(0, 0, 16F.dip2px(), 16F.dip2px())
spannable.setSpan(CenterImageSpan(bitmapDrawable), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
viewHolder.binding.contentTv.run {
movementMethod = CustomLinkMovementMethod.getInstance()
text = spannable
}
}, {
it.printStackTrace()
})
}
}
}
override fun getItemViewType(position: Int): Int {
return position
}
override fun getItemCount(): Int {
return mTags.size
}
class GameDetailCustomViewHolderViewHolder(val binding: GamedetailItemCustomColumnItemBinding) :
BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -1,217 +0,0 @@
package com.gh.gamecenter.gamedetail.desc
import android.content.Context
import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.DefaultUrlHandler
import com.gh.common.util.DirectUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.WebActivity
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.databinding.ItemGameInfoBinding
import com.gh.gamecenter.feature.entity.GameInfo
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
import com.gh.gamecenter.gamedetail.entity.GameInfoItemData
class GameDetailInfoItemAdapter(
val context: Context,
val gameInfo: GameInfo,
private val mViewModel: DescViewModel,
val gameName: String
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var datas = ArrayList<GameInfoItemData>()
init {
if (gameInfo.manufacturer.isNotEmpty()) {
when (gameInfo.manufacturerType) {
"manufacturer" -> {
datas.add(GameInfoItemData(title = "厂商", info = gameInfo.manufacturer))
}
"publisher" -> {
if (gameInfo.developer.isNotEmpty()) {
datas.add(GameInfoItemData(title = "开发商", info = gameInfo.developer))
}
datas.add(GameInfoItemData(title = "发行商", info = gameInfo.manufacturer))
}
"developer" -> {
datas.add(GameInfoItemData(title = "开发商", info = gameInfo.manufacturer))
if (gameInfo.publisher.isNotEmpty()) {
datas.add(GameInfoItemData(title = "发行商", info = gameInfo.publisher))
}
}
else -> {
//do nothing
}
}
}
if (gameInfo.supplier.isNotEmpty()) {
datas.add(GameInfoItemData(title = "供应商", info = gameInfo.supplier))
}
if (gameInfo.creditCode.isNotEmpty()) {
datas.add(GameInfoItemData(title = "统一社会信用代码", info = gameInfo.creditCode))
}
if (gameInfo.contact != null) {
datas.add(
GameInfoItemData(
title = gameInfo.contact!!.hint,
info = gameInfo.contact!!.qq,
actionStr = if (gameInfo.contact!!.type == "qq") "咨询" else if (gameInfo.contact?.key.isNullOrEmpty()) "复制" else "加入",
key = gameInfo.contact!!.key
)
)
}
if (gameInfo.version.isNotEmpty()) {
datas.add(
GameInfoItemData(
title = "当前版本",
info = gameInfo.version,
actionStr = "",
action2Str = if (gameInfo.requestUpdateStatus == "on" && mViewModel.game?.getApk()
?.isNotEmpty() == true
) "求更新" else ""
)
)
}
if (gameInfo.requestSpeedStatus == "on") {
datas.add(
GameInfoItemData(
title = "游戏加速",
info = "",
actionStr = "求加速",
action2Str = ""
)
)
}
if (gameInfo.size.isNotEmpty()) {
datas.add(GameInfoItemData(title = "游戏大小", info = gameInfo.size))
}
if (gameInfo.updateTime != 0L) {
datas.add(GameInfoItemData(title = "更新时间", info = TimeUtils.getFormatTime(gameInfo.updateTime)))
}
if (gameInfo.recommendAge.isNotEmpty()) {
datas.add(GameInfoItemData(title = "适龄等级", info = gameInfo.recommendAge))
}
if (!gameInfo.internetApp.isNullOrEmpty()) {
datas.add(GameInfoItemData(title = "联网APP", info = if (gameInfo.internetApp == "yes") "" else ""))
}
if (gameInfo.icp != null) {
datas.add(GameInfoItemData(title = "ICP备案号", info = gameInfo.icp?.number ?: ""))
}
if (!gameInfo.permissions.isNullOrEmpty()) {
datas.add(GameInfoItemData(title = "权限及用途", info = "查看"))
}
if (!gameInfo.privacyPolicyUrl.isNullOrEmpty()) {
datas.add(GameInfoItemData(title = "隐私政策", info = "查看"))
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return GameDetailInfoItemViewHolder(parent.toBinding())
}
override fun getItemCount(): Int = datas.size
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val gameInfoItemData = datas[position]
if (holder is GameDetailInfoItemViewHolder) {
holder.binding.divider.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(holder.binding.divider.context))
holder.binding.infoTv.isSelected = true
holder.binding.infoTv.text = gameInfoItemData.info
holder.binding.titleTv.text = gameInfoItemData.title
holder.binding.infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(holder.binding.infoTv.context))
holder.binding.titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(holder.binding.infoTv.context))
holder.binding.actionTv.goneIf(gameInfoItemData.actionStr.isEmpty()) {
holder.binding.actionTv.text = gameInfoItemData.actionStr
holder.binding.actionTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(holder.binding.infoTv.context))
}
holder.binding.action2Tv.goneIf(gameInfoItemData.action2Str.isEmpty()) {
holder.binding.action2Tv.text = gameInfoItemData.action2Str
holder.binding.action2Tv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(holder.binding.infoTv.context))
}
holder.binding.infoTv.layoutParams = (holder.binding.infoTv.layoutParams as MarginLayoutParams).apply {
rightMargin = if (!holder.binding.actionTv.isVisible && !holder.binding.action2Tv.isVisible) 0 else 8F.dip2px()
}
if (gameInfoItemData.title == "权限及用途"
|| gameInfoItemData.title == "隐私政策"
|| gameInfoItemData.title == "ICP备案号") {
holder.binding.infoTv.setTextColor(ContextCompat.getColor(context, com.gh.gamecenter.common.R.color.text_theme))
}
holder.binding.root.setOnClickListener {
when (gameInfoItemData.title) {
"ICP备案号" -> {
DirectUtils.directToExternalBrowser(context, context.getString(com.gh.gamecenter.common.R.string.icp_url))
}
"权限及用途" -> {
GamePermissionDialogFragment.show(context as AppCompatActivity, mViewModel.game, gameInfo)
}
"隐私政策" -> {
gameInfo.privacyPolicyUrl?.let {
if (!DefaultUrlHandler.transformNormalScheme(holder.binding.root.context, it, "隐私政策", "")) {
val intent =
WebActivity.getIntent(holder.binding.root.context, it, "隐私政策", false, false)
holder.binding.root.context.startActivity(intent)
}
}
}
}
}
listOf(holder.binding.actionTv, holder.binding.action2Tv).forEach {
it.setOnClickListener { _ ->
when (if (it == holder.binding.actionTv) gameInfoItemData.actionStr else gameInfoItemData.action2Str) {
"求加速" -> {
it.context.ifLogin("游戏详情-求加速") {
NewFlatLogUtils.logGameDetailClickForAccelerate(mViewModel.gameId ?: "", gameName)
DialogHelper.showDialog(
context, "版本求加速", "如果游戏需要加速版本,您可以提交申请,让小助手尽快研究给您喔!",
"提交申请", "取消", {
mViewModel.postRequestSpeed()
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
)
}
}
"求更新" -> {
MtaHelper.onEvent("游戏详情_新", "详细信息_我要求更新", gameName)
DialogHelper.showDialog(
context, "版本求更新", "如果游戏上线了新版本,您可以提交申请,让小助手尽快更新版本喔!",
"提交申请", "取消", {
mViewModel.sendSuggestion()
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
)
}
"咨询" -> {
MtaHelper.onEvent("游戏详情_新", "详细信息_咨询", gameName)
if (ShareUtils.isQQClientAvailable(context)) {
DirectUtils.directToQqConversation(context, gameInfoItemData.info)
} else {
gameInfoItemData.info.copyTextAndToast("已复制")
}
}
"加入" -> {
MtaHelper.onEvent("游戏详情_新", "详细信息_加入", gameName)
if (ShareUtils.isQQClientAvailable(context)) {
DirectUtils.directToQqGroup(context, gameInfoItemData.key)
} else {
gameInfoItemData.info.copyTextAndToast("已复制")
}
}
"复制" -> {
gameInfoItemData.info.copyTextAndToast()
}
}
}
}
}
}
class GameDetailInfoItemViewHolder(var binding: ItemGameInfoBinding) : RecyclerView.ViewHolder(binding.root)
}

View File

@ -1,141 +0,0 @@
package com.gh.gamecenter.gamedetail.desc
import android.content.Context
import android.util.SparseArray
import android.view.View
import android.view.ViewGroup
import androidx.core.util.forEach
import androidx.recyclerview.widget.RecyclerView
import com.facebook.drawee.view.SimpleDraweeView
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.DirectUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.WrapContentDraweeView
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.databinding.GalleryVideoItemBinding
import com.gh.gamecenter.databinding.GamedetailScreenshotItemBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.gamedetail.entity.Video
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
class GameGalleryAdapter(
var context: Context,
private val mVideo: ArrayList<Video>? = null,
private val mGallery: ArrayList<String>? = null,
val mGame: GameEntity,
private val mEntrance: String
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val mImageViewArray = SparseArray<SimpleDraweeView>()
private val mDefaultHorizontalPadding by lazy { com.gh.gamecenter.common.R.dimen.game_detail_item_horizontal_padding.toPx() }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
VIDEO -> {
VideoViewHolder(parent.toBinding())
}
IMAGE -> {
GameGalleryViewHolder(parent.toBinding())
}
else -> throw NullPointerException()
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is GameGalleryViewHolder -> {
holder.binding.screenshotItemIv.setTag(ImageUtils.TAG_TARGET_WIDTH, 260F.dip2px())
ImageUtils.display(holder.binding.screenshotItemIv, mGallery?.get(position))
holder.binding.screenshotItemIv.registerLoadingCallback(object : WrapContentDraweeView.LoadingCallback {
override fun loaded() {
holder.binding.screenshotItemIv.post {
holder.binding.screenshotItemIv.layoutParams.apply {
height = holder.binding.screenshotItemIv.height
width =
(holder.binding.screenshotItemIv.height * holder.binding.screenshotItemIv.aspectRatio).toInt()
holder.binding.screenshotItemIv.layoutParams = this
}
holder.itemView.requestLayout()
}
}
})
holder.itemView.setDebouncedClickListener {
DataCollectionUtils.uploadClick(context, "游戏介绍", "游戏详情")
MtaHelper.onEvent("游戏详情_新", "点击游戏截图", mGame.name)
val imageViewList = ArrayList<View>()
mImageViewArray.forEach { _, value ->
imageViewList.add(value)
}
val intent = ImageViewerActivity.getIntent(
context,
mGallery ?: arrayListOf(),
holder.adapterPosition,
imageViewList,
mEntrance
)
context.startActivity(intent)
}
mImageViewArray.put(position, holder.binding.screenshotItemIv)
}
is VideoViewHolder -> {
val video = mVideo?.get(position)
ImageUtils.display(holder.binding.screenshotItemIv, mVideo?.get(position)!!.poster)
holder.binding.videoTitleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(holder.binding.videoTitleTv.context))
holder.binding.usernameTv.text = video?.user?.name
holder.binding.videoTitleTv.text = video?.title
holder.binding.voteCountTv.text = video?.vote.toString()
holder.binding.screenshotItemIv.setOnClickListener {
MtaHelper.onEvent("游戏详情_新", "点击视频", "${mGame.name}+${video?.title}")
NewFlatLogUtils.logClickGameDetailVideoCategory(
"video",
video?.videoId ?: "",
video?.user?.id ?: ""
)
DirectUtils.directToVideoDetail(
context, video?.videoId
?: "", VideoDetailContainerViewModel.Location.GAME_DETAIL.value,
false, mGame.id, mEntrance, "游戏详情"
)
}
}
}
val params = holder.itemView.layoutParams as RecyclerView.LayoutParams
params.leftMargin = if (position == 0) mDefaultHorizontalPadding else 8F.dip2px()
params.rightMargin = if (position == itemCount - 1) mDefaultHorizontalPadding else 0F.dip2px()
holder.itemView.layoutParams = params
}
override fun getItemCount(): Int {
return when {
mVideo != null -> mVideo.size
mGallery != null -> mGallery.size
else -> 0
}
}
override fun getItemViewType(position: Int): Int {
return when {
mVideo != null -> VIDEO
mGallery != null -> IMAGE
else -> 0
}
}
companion object {
const val IMAGE = 223
const val VIDEO = 224
}
class GameGalleryViewHolder(val binding: GamedetailScreenshotItemBinding) :
BaseRecyclerViewHolder<Any>(binding.root)
class VideoViewHolder(var binding: GalleryVideoItemBinding) : RecyclerView.ViewHolder(binding.root)
}

View File

@ -1,244 +0,0 @@
package com.gh.gamecenter.gamedetail.desc
import android.app.Activity
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.LibaoUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.common.utils.copyTextAndToast
import com.gh.gamecenter.common.utils.fromHtml
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.SpanBuilder
import com.gh.gamecenter.databinding.ItemGameDetailMoreBinding
import com.gh.gamecenter.databinding.ItemGameLibaoBinding
import com.gh.gamecenter.feature.entity.LibaoEntity
import com.gh.gamecenter.libao.LibaoDetailActivity
import com.gh.gamecenter.login.user.UserManager
class GameLibaoAdapter(
val context: Context,
val libaos: ArrayList<LibaoEntity>,
val gameName: String,
val gameId: String,
val showExpandIcon: Boolean = true,
val standaloneStyle: Boolean = false,
) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var mIsExpand = false
private val mShowItemCount: Int = if (showExpandIcon) 3 else Int.MAX_VALUE // 最多展示多少个礼包
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == LIBAO_ITEM) {
LibaoViewHolder(parent.toBinding())
} else {
MoreViewHolder(ItemGameDetailMoreBinding.inflate(LayoutInflater.from(context), parent, false))
}
}
override fun getItemViewType(position: Int): Int {
return if (libaos.size > mShowItemCount) {
if (!mIsExpand) {
if (position == mShowItemCount) MORE else LIBAO_ITEM
} else {
if (position == libaos.size) MORE else LIBAO_ITEM
}
} else {
LIBAO_ITEM
}
}
override fun getItemCount(): Int {
return if (libaos.size > mShowItemCount) {
if (mIsExpand) libaos.size + 1 else mShowItemCount + 1
} else libaos.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is LibaoViewHolder -> {
if (standaloneStyle) {
if (position == 0) {
holder.binding.root.setBackgroundResource(com.gh.gamecenter.common.R.drawable.background_shape_white_radius_5_top_only)
} else if (position == itemCount - 1) {
holder.binding.root.setBackgroundResource(com.gh.gamecenter.common.R.drawable.background_shape_white_radius_5_bottm_only)
} else {
holder.binding.root.setBackgroundResource(com.gh.gamecenter.common.R.color.ui_surface)
}
}
val libaoEntity = libaos[position]
holder.binding.libaoNameTv.text = libaoEntity.name
holder.binding.contentTv.text = libaoEntity.content?.fromHtml()
val isTypeCopy = libaoEntity.receiveMethod == "copy"
if (isTypeCopy) {
// 类型为复制,不需要登录也能直接领取
holder.binding.libaoSchedulePb.visibility = View.GONE
holder.binding.remainingTv.visibility = View.GONE
holder.binding.libaoCodeTv.visibility = View.VISIBLE
val text = "兑换码:${libaoEntity.code}"
holder.binding.libaoCodeTv.text = SpanBuilder(text).color(
holder.binding.root.context,
4,
text.length,
com.gh.gamecenter.common.R.color.text_theme
).build()
holder.binding.copyLibaoCodeIv.visibility = View.VISIBLE
holder.binding.copyLibaoCodeIv.setOnClickListener {
holder.binding.receiveTv.performClick()
}
} else if (libaoEntity.universal || libaoEntity.status == "check") {
//通用码礼包/或者还未添加礼包码时,不显示进度条,显示礼包码
holder.binding.libaoSchedulePb.visibility = View.GONE
holder.binding.remainingTv.visibility = View.GONE
holder.binding.libaoCodeTv.visibility = View.VISIBLE
holder.binding.copyLibaoCodeIv.visibility = View.GONE
if (!UserManager.getInstance().isLoggedIn) {
holder.binding.libaoCodeTv.text = "礼包码:-"
} else {
when (libaoEntity.status) {
"linged", "repeatLing", "repeatLinged", "taoed", "repeatTao", "repeatTaoed" -> {
val size = libaoEntity.me?.userDataLibaoList?.size ?: 0
val code = libaoEntity.me?.userDataLibaoList?.get(size - 1)?.code ?: ""
val text = "礼包码:$code"
holder.binding.libaoCodeTv.text = SpanBuilder(text).color(
holder.binding.root.context,
4,
text.length,
com.gh.gamecenter.common.R.color.text_theme
).build()
holder.binding.copyLibaoCodeIv.visibility = View.VISIBLE
holder.binding.copyLibaoCodeIv.setOnClickListener {
code.copyTextAndToast("$code 复制成功")
}
}
else -> {
holder.binding.libaoCodeTv.text = "礼包码:-"
}
}
}
} else {
if (!UserManager.getInstance().isLoggedIn) {
holder.binding.libaoSchedulePb.visibility = View.VISIBLE
holder.binding.remainingTv.visibility = View.VISIBLE
holder.binding.libaoCodeTv.visibility = View.GONE
holder.binding.copyLibaoCodeIv.visibility = View.GONE
initProgressUI(libaoEntity, holder)
} else {
when (libaoEntity.status) {
"linged", "repeatLing", "repeatLinged", "taoed", "repeatTao", "repeatTaoed" -> {
holder.binding.libaoSchedulePb.visibility = View.GONE
holder.binding.remainingTv.visibility = View.GONE
holder.binding.libaoCodeTv.visibility = View.VISIBLE
val size = libaoEntity.me?.userDataLibaoList?.size ?: 0
val code = libaoEntity.me?.userDataLibaoList?.get(size - 1)?.code ?: ""
val text = "礼包码:$code"
holder.binding.libaoCodeTv.text = SpanBuilder(text).color(
holder.binding.root.context,
4,
text.length,
com.gh.gamecenter.common.R.color.text_theme
).build()
holder.binding.copyLibaoCodeIv.visibility = View.VISIBLE
holder.binding.copyLibaoCodeIv.setOnClickListener {
code.copyTextAndToast("$code 复制成功")
}
}
else -> {
holder.binding.libaoSchedulePb.visibility = View.VISIBLE
holder.binding.remainingTv.visibility = View.VISIBLE
holder.binding.libaoCodeTv.visibility = View.GONE
holder.binding.copyLibaoCodeIv.visibility = View.GONE
initProgressUI(libaoEntity, holder)
}
}
}
}
// LibaoUtils.setLiBaoBtnStatusRound(holder.binding.receiveTv, libaoEntity,true, context)
LibaoUtils.initLibaoBtn(
context,
holder.binding.receiveTv,
libaoEntity,
false,
null,
true,
"游戏详情",
"游戏详情"
) {
notifyItemChanged(position)
}
if (!libaoEntity.packageName.isNullOrEmpty()) {
holder.binding.receiveTv.setOnClickListener {
val intent = LibaoDetailActivity.getIntent(context, libaoEntity, true, "游戏详情")
if (it.context is Activity) {
(it.context as Activity).startActivityForResult(intent, 100)
}
}
}
holder.itemView.setOnClickListener {
if (isTypeCopy) {
// do nothing
} else {
val intent = LibaoDetailActivity.getIntent(context, libaoEntity, "游戏详情")
if (it.context is Activity) {
(it.context as Activity).startActivityForResult(intent, 100)
}
NewLogUtils.logGameDetailGiftClick(gameName, gameId, "礼包详情")
}
}
}
is MoreViewHolder -> {
holder.binding.arrowIv.rotation = if (mIsExpand) 180f else 0f
holder.itemView.setOnClickListener {
if (!mIsExpand) MtaHelper.onEvent("游戏详情_新", "游戏礼包_展开", gameName)
mIsExpand = !mIsExpand
notifyDataSetChanged()
NewLogUtils.logGameDetailGiftClick(gameName, gameId, "展开")
}
}
}
}
private fun initProgressUI(libaoEntity: LibaoEntity, holder: LibaoViewHolder) {
val total = libaoEntity.total
val available = libaoEntity.available
if (total != 0) {
val availablePercent = (available) / total.toFloat() * 100
val count = when {
availablePercent >= 1F -> {
availablePercent.toInt()
}
availablePercent == 0F -> {
0
}
else -> {
1
}
}
holder.binding.remainingTv.text = "剩余${count}%"
holder.binding.libaoSchedulePb.progress = count
}
}
class LibaoViewHolder(var binding: ItemGameLibaoBinding) : RecyclerView.ViewHolder(binding.root)
class MoreViewHolder(var binding: ItemGameDetailMoreBinding) : RecyclerView.ViewHolder(binding.root)
companion object {
const val MORE = 0
const val LIBAO_ITEM = 1
}
}

View File

@ -1,117 +0,0 @@
package com.gh.gamecenter.gamedetail.desc
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.DefaultUrlHandler
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.DirectUtils
import com.gh.common.util.LogUtils
import com.gh.common.util.NewsUtils
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.databinding.ItemGameRaidersBinding
import com.gh.gamecenter.databinding.ItemGameRaidersFixedTopBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.NewsEntity
import com.gh.gamecenter.newsdetail.NewsDetailActivity
class GameRaidersAdapter(
val context: Context,
val articles: ArrayList<NewsEntity>,
val mEntrance: String,
val game: GameEntity?
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val mDefaultHorizontalPadding by lazy { com.gh.gamecenter.common.R.dimen.game_detail_item_horizontal_padding.toPx() }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == TYPE_ARTICLE) {
RaidersViewHolder(parent.toBinding())
} else {
RaidersFixedTopViewHolder(
ItemGameRaidersFixedTopBinding.inflate(
LayoutInflater.from(context),
parent,
false
)
)
}
}
override fun getItemCount(): Int = articles.size
override fun getItemViewType(position: Int): Int {
return if (articles[position].priority == Int.MAX_VALUE) {
TYPE_ARTICLE_FIXED_TOP
} else {
TYPE_ARTICLE
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val params = holder.itemView.layoutParams as RecyclerView.LayoutParams
params.leftMargin = if (position == 0) mDefaultHorizontalPadding else 8F.dip2px()
params.rightMargin = if (position == itemCount - 1) mDefaultHorizontalPadding else 0F.dip2px()
holder.itemView.layoutParams = params
if (holder is RaidersViewHolder) {
val newsEntity = articles[position]
holder.binding.root.setRootBackgroundDrawable(com.gh.gamecenter.common.R.drawable.background_shape_white_radius_5)
holder.binding.titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
holder.binding.contentTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
holder.binding.timeTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
holder.binding.line.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(context))
holder.binding.titleTv.text = newsEntity.title ?: ""
holder.binding.contentTv.text = newsEntity.intro ?: ""
holder.binding.timeTv.text =
if (TimeUtils.isToday(newsEntity.publishOn)) "今天" else TimeUtils.getFormatTime(newsEntity.publishOn)
holder.itemView.setOnClickListener {
skipNewsDetail(newsEntity, position)
}
} else if (holder is RaidersFixedTopViewHolder) {
val newsEntity = articles[position]
holder.binding.root.setRootBackgroundDrawable(com.gh.gamecenter.common.R.drawable.background_shape_white_radius_5)
holder.binding.titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
holder.binding.descTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
holder.binding.titleTv.text = newsEntity.title ?: ""
ImageUtils.display(holder.binding.backgroundIv, newsEntity.thumb)
holder.binding.descTv.text = newsEntity.type
holder.itemView.setOnClickListener {
LogUtils.logGameDetailFixedTopArticleClick(game?.id, game?.name, newsEntity.link)
val isUrlIntercepted = DefaultUrlHandler.interceptUrl(
context,
newsEntity.link ?: "",
"新手攻略"
)
if (!isUrlIntercepted) {
DirectUtils.directToWebView(context, newsEntity.link ?: "")
}
}
}
}
private fun skipNewsDetail(article: NewsEntity, position: Int) {
DataCollectionUtils.uploadClick(context, "新手攻略", "游戏详情", article.title)
MtaHelper.onEvent("游戏详情_新", "新手攻略卡片", "${game?.name}+${article.title}")
// 统计阅读量
NewsUtils.statNewsViews(article.id)
NewsDetailActivity.startNewsDetailActivity(
context, article,
mEntrance + "+(游戏详情[" + game?.name + "]:新手攻略-列表[" + (position + 1) + "])"
)
}
companion object {
const val TYPE_ARTICLE = 123
const val TYPE_ARTICLE_FIXED_TOP = 124
}
class RaidersViewHolder(var binding: ItemGameRaidersBinding) : RecyclerView.ViewHolder(binding.root)
class RaidersFixedTopViewHolder(var binding: ItemGameRaidersFixedTopBinding) : RecyclerView.ViewHolder(binding.root)
}

View File

@ -1,4 +1,4 @@
package com.gh.gamecenter.gamedetail.desc
package com.gh.gamecenter.gamedetail.detail
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
@ -6,7 +6,6 @@ import com.gh.common.exposure.ExposureManager
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.*
@ -14,6 +13,7 @@ import com.gh.gamecenter.databinding.GamedetailItemGameCollectionBinding
import com.gh.gamecenter.entity.GameDetailRecommendGameEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.gamedetail.detail.viewholder.BaseGameDetailItemViewHolder
class GameCollectionAdapter(
private val mRecommendGameList: ArrayList<GameDetailRecommendGameEntity>,
@ -22,7 +22,9 @@ class GameCollectionAdapter(
private val mGame: GameEntity?,
private val mEntrance: String,
private val mPath: String,
private val mBasicExposureSource: List<ExposureSource>
private val mBasicExposureSource: List<ExposureSource>,
private val trackData: BaseGameDetailItemViewHolder.GameDetailModuleTrackData,
private val getGameStatus: () -> String
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val mDefaultHorizontalPadding by lazy { com.gh.gamecenter.common.R.dimen.game_detail_item_horizontal_padding.toPx() }
@ -72,20 +74,16 @@ class GameCollectionAdapter(
}
gameCountTv.text = "+${entity.count.game - games.size}"
root.setOnClickListener {
SensorsBridge.trackGameDetailPageGameCollectRecommendClick(
gameId = mGameId,
gameName = mGameName,
pageName = GlobalActivityManager.getCurrentPageEntity().pageName,
pageId = GlobalActivityManager.getCurrentPageEntity().pageId,
pageBusinessId = GlobalActivityManager.getCurrentPageEntity().pageBusinessId,
lastPageId = GlobalActivityManager.getCurrentPageEntity().pageId,
lastPageName = GlobalActivityManager.getCurrentPageEntity().pageName,
lastPageBusinessId = GlobalActivityManager.getCurrentPageEntity().pageBusinessId,
downloadStatus = mGame?.downloadStatusChinese ?: "",
gameType = mGame?.categoryChinese ?: "",
text = "游戏单",
gameCollectId = entity.id,
gameCollectTitle = entity.title
SensorsBridge.trackGameDetailModuleClick(
trackData.gameId,
trackData.gameName,
trackData.gameType,
"组件内容",
trackData.moduleType,
"游戏单推荐",
trackData.sequence,
supSequence = position + 1,
gameStatus = getGameStatus()
)
DirectUtils.directToGameCollectionDetail(
it.context,

View File

@ -0,0 +1,186 @@
package com.gh.gamecenter.gamedetail.detail
import android.app.Activity
import android.content.Context
import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.ItemGameCoverGalleryBinding
import com.gh.gamecenter.databinding.ItemGameCoverVideoBinding
import com.gh.gamecenter.gamedetail.GameDetailViewModel
import com.gh.gamecenter.gamedetail.entity.CoverEntity
import com.gh.gamecenter.gamedetail.video.TopVideoView
import com.lightgame.adapter.BaseRecyclerAdapter
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack
import com.shuyu.gsyvideoplayer.utils.OrientationUtils
class GameDetailCoverAdapter(
context: Context,
private val fragment: GameDetailFragment,
private val snapHelper: LeftPagerSnapHelper,
private val viewModel: GameDetailViewModel
) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
private var coverRecyclerView: RecyclerView? = null
private var coverList = arrayListOf<CoverEntity>()
private val imageViewWidth = ((DisplayUtils.getScreenWidth(fragment.activity) / 2F) - 16F.dip2px()).toInt()
private var firstGalleryItemPosition = -1
private var isSingleGallery = false
private var hasSetFixedHeight = false
fun submitList(data: List<CoverEntity>) {
coverList = ArrayList(data)
firstGalleryItemPosition = coverList.indexOfFirst { it.gallery != null }
isSingleGallery = coverList.count { it.gallery != null } == 1
notifyDataSetChanged()
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
coverRecyclerView = recyclerView
}
override fun getItemViewType(position: Int): Int {
val coverEntity = coverList.getOrNull(position)
return when {
coverEntity?.video != null -> ITEM_VIDEO
else -> ITEM_GALLERY
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
ITEM_VIDEO -> GameDetailCoverVideoItemViewHolder(parent.toBinding())
else -> GameDetailCoverGalleryItemViewHolder(parent.toBinding())
}
}
override fun getItemCount(): Int = coverList.size
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
coverList.getOrNull(position)?.let {
if (holder is GameDetailCoverVideoItemViewHolder) {
bindVideoItem(holder, it, position)
}
if (holder is GameDetailCoverGalleryItemViewHolder) {
bindGalleryItem(holder, it, position)
}
}
}
private fun bindVideoItem(holder: GameDetailCoverVideoItemViewHolder, entity: CoverEntity, position: Int) {
if (position == 0 && !hasSetFixedHeight) {
holder.binding.root.post {
coverRecyclerView?.updateLayoutParams<ViewGroup.LayoutParams> { height = holder.binding.root.height }
hasSetFixedHeight = true
}
}
val topVideo = entity.video ?: return
val orientationUtils = OrientationUtils(mContext as Activity, holder.binding.player)
orientationUtils.isEnable = false
GSYVideoOptionBuilder()
.setIsTouchWigetFull(false)
.setIsTouchWiget(false)
.setRotateViewAuto(false)
.setShowFullAnimation(false)
.setSeekRatio(1F)
.setUrl(topVideo.url)
.setCacheWithPlay(true)
.setShowPauseCover(true)
.setReleaseWhenLossAudio(false)
.setVideoAllCallBack(object : GSYSampleCallBack() {
override fun onQuitFullscreen(url: String?, vararg objects: Any) {
orientationUtils.backToProtVideo()
holder.binding.player.uploadVideoStreamingPlaying("退出全屏")
}
})
.build(holder.binding.player)
holder.binding.player.gameName = viewModel.game?.name ?: ""
holder.binding.player.viewModel = viewModel
holder.binding.player.video = topVideo
holder.binding.player.updateThumb(topVideo.poster)
holder.binding.player.fullscreenButton.setOnClickListener {
val horizontalVideoView =
holder.binding.player.startWindowFullscreen(mContext, true, true) as? TopVideoView
if (horizontalVideoView == null) {
toastInInternalRelease("全屏失败,请向技术人员提供具体的操作步骤")
return@setOnClickListener
}
orientationUtils.resolveByClick()
horizontalVideoView.uuid = holder.binding.player.uuid
horizontalVideoView.viewModel = viewModel
horizontalVideoView.video = topVideo
horizontalVideoView.updateThumb(topVideo.poster)
horizontalVideoView.violenceUpdateMuteStatus()
holder.binding.player.uploadVideoStreamingPlaying("开始播放")
holder.binding.player.uploadVideoStreamingPlaying("点击全屏")
}
holder.binding.player.observeVolume(fragment)
}
private fun bindGalleryItem(holder: GameDetailCoverGalleryItemViewHolder, entity: CoverEntity, position: Int) {
val imageUrl = entity.gallery?.url ?: ""
val isLastItem = position == coverList.lastIndex
val imageWidth = (entity.gallery?.width ?: return).toInt()
val imageHeight = (entity.gallery?.height ?: return).toInt()
val isLandscape = imageWidth >= imageHeight
val ratio = imageWidth / imageHeight.toFloat()
ConstraintSet().also {
it.clone(holder.binding.root)
it.setDimensionRatio(holder.binding.galleryIv.id, if (isLandscape) "h,344:193" else "")
}.applyTo(holder.binding.root)
holder.binding.root.updateLayoutParams<MarginLayoutParams> {
width = if (isLandscape || isSingleGallery) ViewGroup.LayoutParams.MATCH_PARENT else ViewGroup.LayoutParams.WRAP_CONTENT
height = if (isLandscape || isSingleGallery) ViewGroup.LayoutParams.WRAP_CONTENT else PORTRAIT_IMAGE_HEIGHT_DP.dip2px()
rightMargin = if (isLandscape || isSingleGallery || isLastItem) 8F.dip2px() else 0
}
holder.binding.galleryIv.updateLayoutParams<ConstraintLayout.LayoutParams> {
width = if (isLandscape) 0 else (PORTRAIT_IMAGE_HEIGHT_DP.dip2px() * ratio).toInt()
height = if (isLandscape) 0 else PORTRAIT_IMAGE_HEIGHT_DP.dip2px()
}
if (position == 0 && !hasSetFixedHeight) {
holder.binding.root.post {
coverRecyclerView?.updateLayoutParams<ViewGroup.LayoutParams> { height = holder.binding.root.height }
hasSetFixedHeight = true
}
}
holder.binding.galleryIv.setTag(ImageUtils.TAG_TARGET_WIDTH, imageViewWidth)
ImageUtils.display(holder.binding.galleryIv, imageUrl)
holder.binding.root.setOnClickListener {
val intent = ImageViewerActivity.getIntent(
mContext,
arrayListOf(imageUrl),
0,
listOf(holder.binding.galleryIv),
"游戏详情-视频/图片区域"
)
mContext.startActivity(intent)
}
}
companion object {
const val ITEM_VIDEO = 0
const val ITEM_GALLERY = 1
private const val PORTRAIT_IMAGE_HEIGHT_DP = 280F
}
class GameDetailCoverVideoItemViewHolder(val binding: ItemGameCoverVideoBinding) :
BaseRecyclerViewHolder<Any>(binding.root)
class GameDetailCoverGalleryItemViewHolder(val binding: ItemGameCoverGalleryBinding) :
BaseRecyclerViewHolder<Any>(binding.root)
}

View File

@ -0,0 +1,876 @@
package com.gh.gamecenter.gamedetail.detail
import android.animation.ValueAnimator
import android.app.Activity
import android.content.Intent
import android.graphics.Color
import android.graphics.Typeface
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.TransitionDrawable
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.view.isVisible
import androidx.core.view.iterator
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
import androidx.viewpager2.widget.ViewPager2
import com.gh.common.util.*
import com.gh.common.util.NewFlatLogUtils
import com.gh.common.util.NewLogUtils
import com.gh.common.view.FlexLinearLayout
import com.gh.gamecenter.ImageViewerActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.GlobalActivityManager.getCurrentPageEntity
import com.gh.gamecenter.common.base.GlobalActivityManager.getLastPageEntity
import com.gh.gamecenter.common.base.fragment.LazyFragment
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.eventbus.EBReuse
import com.gh.gamecenter.common.json.json
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.ScrollEventListener
import com.gh.gamecenter.common.view.TextBannerView
import com.gh.gamecenter.core.iinterface.IScrollable
import com.gh.gamecenter.core.provider.IFloatingWindowProvider
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.databinding.FragmentNewGameDetailBinding
import com.gh.gamecenter.databinding.ItemGameDetailDataInfoBinding
import com.gh.gamecenter.databinding.ItemGameDetailFunctionTagBinding
import com.gh.gamecenter.databinding.LayoutGuideGameDetailFunctionTagBinding
import com.gh.gamecenter.entity.RatingComment
import com.gh.gamecenter.eventbus.EBTypeChange
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.TagStyleEntity
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.gamedetail.GameDetailViewModel
import com.gh.gamecenter.gamedetail.GameDetailWrapperFragment
import com.gh.gamecenter.gamedetail.detail.viewholder.BaseGameDetailItemViewHolder.Companion.getGameStatus
import com.gh.gamecenter.gamedetail.detail.viewholder.GameDetailCommentItemViewHolder
import com.gh.gamecenter.gamedetail.dialog.GameBigEventDialogFragment
import com.gh.gamecenter.gamedetail.dialog.GameFunctionDialogFragment
import com.gh.gamecenter.gamedetail.entity.GameDetailDataInfo
import com.gh.gamecenter.gamedetail.entity.GameDetailInfoTag
import com.gh.gamecenter.gamedetail.entity.GameDetailTabEntity
import com.gh.gamecenter.gamedetail.rating.RatingFragment
import com.gh.gamecenter.gamedetail.video.GameDetailScrollCalculatorHelper
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
import com.gh.gamecenter.livedata.EventObserver
import com.gh.gamecenter.tag.TagsActivity
import com.halo.assistant.HaloApp
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
import com.therouter.TheRouter
import io.reactivex.disposables.CompositeDisposable
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.*
import kotlin.math.abs
class GameDetailFragment(private val downloadButton: DownloadButton) : LazyFragment(), IScrollable {
private lateinit var binding: FragmentNewGameDetailBinding
private lateinit var viewModel: GameDetailViewModel
private lateinit var scrollCalculatorHelper: GameDetailScrollCalculatorHelper
private val coverAdapter by lazy {
GameDetailCoverAdapter(
requireContext(),
this@GameDetailFragment,
snapHelper,
viewModel
)
}
private val coverLayoutManager by lazy {
LinearLayoutManager(requireContext(), RecyclerView.HORIZONTAL, false)
}
private val snapHelper by lazy { LeftPagerSnapHelper() }
private val coverScrollEventListener by lazy { ScrollEventListener(binding.coverRv) }
private val detailListAdapter by lazy {
GameDetailListAdapter(downloadButton, viewModel, viewLifecycleOwner)
}
private val detailLayoutManager by lazy { LinearLayoutManager(requireContext()) }
private var lastCompletelyVisibleCoverPosition = 0
private var isCoverHeightAnimating = false
private var coverPosition = 0
private var bigEventTransitionDrawable: TransitionDrawable? = null
private var gameEntity: GameEntity? = null
private val gameStatus
get() = getGameStatus(downloadButton.buttonStyle)
private var functionTagGuide: ViewGroup? = null
private var compositeDisposable = CompositeDisposable()
private var isPauseCoverVideo = false
override fun getRealLayoutId(): Int = R.layout.fragment_new_game_detail
override fun onRealLayoutInflated(inflatedView: View) {
super.onRealLayoutInflated(inflatedView)
binding = FragmentNewGameDetailBinding.bind(inflatedView)
scrollCalculatorHelper = GameDetailScrollCalculatorHelper(binding.coverRv, R.id.player, 0)
showFloatingWindowIfNeeded()
}
override fun onFragmentFirstVisible() {
super.onFragmentFirstVisible()
val gameId = arguments?.getString(EntranceConsts.KEY_GAME_ID) ?: ""
gameEntity = arguments?.getParcelable(EntranceConsts.KEY_GAME_ENTITY)
val factory = GameDetailViewModel.Factory(
HaloApp.getInstance().application,
gameId,
gameEntity,
mEntrance
)
viewModel = viewModelProviderFromParent(factory, gameId)
initCover()
initDetailRv()
observeData()
binding.gamedetailAppbar.addOnOffsetChangedListener { _, verticalOffset ->
if (!isAdded) return@addOnOffsetChangedListener
val absVerticalOffset = abs(verticalOffset)
val coverHeight = binding.coverRv.height
if (viewModel.displayCoverVideo && coverHeight != 0) {
val player = scrollCalculatorHelper.currentPlayer
if (absVerticalOffset > coverHeight && !isPauseCoverVideo && player?.currentState == GSYVideoView.CURRENT_STATE_PLAYING) {
pauseVideo()
isPauseCoverVideo = true
} else if (absVerticalOffset == 0 && isPauseCoverVideo && player?.currentState == GSYVideoView.CURRENT_STATE_PAUSE) {
resumeVideo()
isPauseCoverVideo = false
}
}
}
}
private fun observeData() {
viewModel.coverListLiveData.observeNonNull(viewLifecycleOwner) {
coverAdapter.submitList(it)
binding.run {
val defaultCoverEntity = it.find { coverEntity -> coverEntity.isDefault }
val tabNameList = it.map { coverEntity -> coverEntity.tabName }.distinct()
coverSfv.goneIf(tabNameList.size < 2) {
val defaultTabPosition =
tabNameList.indexOfFirst { tabName -> defaultCoverEntity?.tabName == tabName }
coverSfv.setItemList(tabNameList, if (defaultTabPosition != -1) defaultTabPosition else 0)
coverSfv.setOnCheckedCallback { position ->
val checkedText = tabNameList.getOrNull(position)
val currentCoverEntity = it.getOrNull(coverPosition)
if (currentCoverEntity?.tabName == checkedText) return@setOnCheckedCallback
val checkPosition = it.indexOfFirst { coverEntity -> coverEntity.tabName == checkedText }
if (checkPosition != -1) {
coverRv.setCurrentItem(checkPosition)
SensorsBridge.trackEvent("GameDetailMediaTabClick", json {
"game_id" to gameEntity?.id
"game_name" to gameEntity?.name
"sequence" to position + 1
"tab_name" to checkedText
})
}
}
}
coverRv.scrollToPosition(defaultCoverEntity?.index ?: 0)
coverPosition = defaultCoverEntity?.index ?: 0
}
if (viewModel.isTopVideoPartlyCached(viewModel.coverListLiveData.value?.first()?.video?.url ?: "")) {
postRunnable {
notifyScrollStateChanged(RecyclerView.SCROLL_STATE_IDLE)
}
} else {
// 未有缓存时,为避免影响页面加载,延迟自动播放视频
postDelayedRunnable({
if (activity != null && activity?.isFinishing != true) {
notifyScrollStateChanged(RecyclerView.SCROLL_STATE_IDLE)
}
}, COVER_VIDEO_INITIAL_DELAY)
}
}
viewModel.basicInfoLiveData.observeNonNull(viewLifecycleOwner) {
initBasicInfo(it)
}
viewModel.bigEventLiveData.observeNonNull(viewLifecycleOwner) {
GameBigEventDialogFragment.show(
requireContext(),
gameEntity?.id ?: "",
gameEntity?.name ?: "",
it
) { link, _ ->
DirectUtils.directToLinkPage(requireContext(), link, mEntrance, "游戏大事件弹窗", "游戏详情页-大事件")
NewFlatLogUtils.logGameDetailMajorEventDetailClick(
gameEntity?.name ?: "",
gameEntity?.id ?: "",
link.link ?: "",
link.type ?: "",
link.text ?: ""
)
SensorsBridge.trackGameDetailPageMajorEventClick(
gameId = gameEntity?.id ?: "",
gameName = gameEntity?.name ?: "",
pageName = getCurrentPageEntity().pageName,
pageId = getCurrentPageEntity().pageId,
pageBusinessId = getCurrentPageEntity().pageBusinessId,
lastPageName = getLastPageEntity().pageName,
lastPageId = getLastPageEntity().pageId,
lastPageBusinessId = getLastPageEntity().pageBusinessId,
downloadStatus = gameEntity?.downloadStatusChinese ?: "",
gameType = gameEntity?.categoryChinese ?: "",
action = "跳转链接",
linkText = link.text ?: "",
linkType = link.type ?: "",
linkId = link.link ?: ""
)
}
}
viewModel.dataInfoLiveData.observeNonNull(viewLifecycleOwner) {
initDataInfo(it)
}
viewModel.infoTagLiveData.observeNonNull(viewLifecycleOwner) {
initInfoTags(it)
}
viewModel.detailDataListLiveData.observeNonNull(viewLifecycleOwner) {
if (it.isNotEmpty()) {
detailListAdapter.submitList(it)
} else {
binding.coordinator.isVisible = false
binding.reuseNoneData.root.isVisible = true
}
}
viewModel.scrollToListPositionLiveData.observe(viewLifecycleOwner, EventObserver { type ->
val position = viewModel.detailDataListLiveData.value?.indexOfFirst { it.type == type } ?: -1
if (position != -1) {
binding.gamedetailAppbar.setExpanded(false, true)
detailLayoutManager.scrollToPositionWithOffset(position, 0)
}
})
}
private fun initDetailRv() {
binding.detailRv.run {
(itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
layoutManager = detailLayoutManager
adapter = detailListAdapter
addOnScrollListener(object : OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
viewModel.pageDepth = detailLayoutManager.findLastCompletelyVisibleItemPosition()
.coerceAtLeast(viewModel.pageDepth)
}
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
EventBus.getDefault().post(EBTypeChange(GameDetailWrapperFragment.EB_SCROLLING, 0))
}
}
})
}
}
private fun initCover() {
binding.run {
coverRv.layoutManager = coverLayoutManager
coverRv.adapter = coverAdapter
(coverRv.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
coverRv.isNestedScrollingEnabled = false
coverRv.onFlingListener = null
snapHelper.attachToRecyclerView(coverRv)
coverRv.addOnScrollListener(coverScrollEventListener.apply {
registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels)
val firstCompletelyVisibleItemPosition =
coverLayoutManager.findFirstCompletelyVisibleItemPosition()
if (!isCoverHeightAnimating &&
firstCompletelyVisibleItemPosition > -1 &&
firstCompletelyVisibleItemPosition != lastCompletelyVisibleCoverPosition) {
val firstCompletelyVisibleItemView =
coverLayoutManager.findViewByPosition(firstCompletelyVisibleItemPosition)
firstCompletelyVisibleItemView?.post {
if (firstCompletelyVisibleItemView.height > 0 && coverRv.height != firstCompletelyVisibleItemView.height) {
startCoverHeightAnimation(coverRv.height, firstCompletelyVisibleItemView.height)
}
}
}
lastCompletelyVisibleCoverPosition = firstCompletelyVisibleItemPosition
}
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
if (position != coverPosition) {
val selectedCoverEntity = viewModel.coverListLiveData.value?.getOrNull(position)
coverPosition = position
if (coverSfv.isVisible) {
val sfvPosition = coverSfv.getItemList().indexOfFirst { it == selectedCoverEntity?.tabName }
coverSfv.setChecked(sfvPosition, true)
}
}
}
override fun onPageScrollStateChanged(state: Int) {
super.onPageScrollStateChanged(state)
notifyScrollStateChanged(state)
}
})
})
}
}
private fun initBasicInfo(basicInfo: GameEntity) {
binding.run {
gameIconIv.displayGameIcon(basicInfo)
val gameSubtitleStyle = basicInfo.subtitleStyle
val advanceDownload = basicInfo.advanceDownload
val subtitleLayout = FrameLayout(requireContext())
val subtitleTextView = TextView(requireContext()).apply {
layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, 14F.dip2px())
text = if (advanceDownload) "预下载" else basicInfo.subtitle
textSize = 10F
setPadding(2F.dip2px(), 0, 2F.dip2px(), 0)
if (gameSubtitleStyle != null && !advanceDownload) {
setTextColor("#${gameSubtitleStyle.color}".hexStringToIntColor())
background = GradientDrawable().apply {
cornerRadius = 2F.dip2px().toFloat()
if (gameSubtitleStyle.style == "border") {
setColor(Color.TRANSPARENT)
setStroke(0.5F.dip2px(), "#${gameSubtitleStyle.background}".hexStringToIntColor())
} else {
shape = GradientDrawable.RECTANGLE
setColor("#${gameSubtitleStyle.background}".hexStringToIntColor())
}
}
} else {
setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()))
background = com.gh.gamecenter.feature.R.drawable.bg_advance_download_game_subtitle.toDrawable(requireContext())
}
}
subtitleLayout.addView(
subtitleTextView,
FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, 14F.dip2px()).apply {
leftMargin = 4F.dip2px()
})
val subtitleBitmap = subtitleLayout.convertViewToBitmap()
basicInfo.name?.let { name ->
gameNameTv.text = SpannableStringBuilder("$name ").apply {
subtitleBitmap?.let {
setSpan(
CenterImageSpan(
context,
it
), name.length, name.length + 1, Spanned.SPAN_EXCLUSIVE_INCLUSIVE
)
}
}
}
gameNameTv.marqueeOnce()
officialEntryTv.isVisible = basicInfo.officialEntry
descTv.text = basicInfo.sellingPointsText
mBaseHandler.postDelayed({
gameEntity?.gameType = basicInfo.gameTags.joinToString("-") { it.name }
tagContainer.setTags(basicInfo.gameTags.take(3))
}, 5)
tagContainer.onClickListener = object :FlexLinearLayout.OnItemClickListener {
override fun onMoreClickListener() {}
override fun onItemClickListener(tag: TagStyleEntity, position: Int) {
NewLogUtils.logGameDetailTagClick(
gameEntity?.id ?: "",
gameEntity?.name ?: "",
tag.id,
tag.name,
tag.isTop
)
SensorsBridge.trackGameDetailModuleClick(
gameEntity?.id,
gameEntity?.name,
gameEntity?.categoryChinese,
"组件内容",
"卖点标签",
null,
null,
null,
null,
gameStatus = gameStatus
)
requireContext().startActivity(
TagsActivity.getIntent(requireContext(), tag.name, tag.name, mEntrance, "游戏介绍")
)
}
}
scoreContainer.goneIf(basicInfo.welfareText?.status == "on") {
scoreTv.setTypeface(Typeface.createFromAsset(requireContext().assets, Constants.DIN_FONT_PATH))
scoreTv.text = String.format(Locale.getDefault(), "%.1f", basicInfo.star)
scoreContainer.setOnClickListener {
viewModel.performTabSelected(GameDetailTabEntity.TYPE_COMMENT)
}
}
discountContainer.goneIf(basicInfo.welfareText == null || basicInfo.welfareText?.status == "off") {
discountTv.setTypeface(Typeface.createFromAsset(requireContext().assets, Constants.DIN_FONT_PATH))
discountTextTv.text = basicInfo.welfareText?.text
discountTv.text = basicInfo.welfareText?.discount
}
bigEventContainer.goneIf(basicInfo.event.isNullOrEmpty()) {
basicInfo.event?.let {
bigEventTransitionDrawable = R.drawable.transition_bg_game_detail_big_event.toDrawable(requireContext()) as TransitionDrawable
bigEventContainer.background = bigEventTransitionDrawable
val index = if (binding.bigEventBannerView.currentIndex != -1) binding.bigEventBannerView.currentIndex else 0
val isHighLight = it.getOrNull(index)?.highLight ?: false
if (isHighLight) bigEventTransitionDrawable?.reverseTransition(0)
bigEventBannerView.setOnClickListener { _ ->
SensorsBridge.trackGameDetailModuleClick(
gameEntity?.id,
gameEntity?.name,
gameEntity?.categoryChinese,
"组件内容",
"大事件",
null,
null,
null,
null,
gameStatus = gameStatus
)
viewModel.getBigEvent()
}
bigEventBannerView.setDataList(it.map { event ->
var eventStr = if (event.highLight) {
"${TimeUtils.getFormatTime(event.time, "MM-dd")}${TimeUtils.getDayString(event.time)}${event.content}"
} else {
if (TimeUtils.getBeforeDays(event.time) <= 15) "${
TimeUtils.getFormatTime(event.time, "MM-dd")
}${TimeUtils.getDayString(event.time)}${event.content}" else event.content
}
if (eventStr.contains("\n")) eventStr = eventStr.substring(0, eventStr.indexOf("\n"))
TextBannerView.BannerTextData(text = eventStr, highLight = event.highLight)
})
bigEventBannerView.onTextUpdateListener = { lastIndex, nextIndex ->
if (lastIndex in it.indices && nextIndex in it.indices) {
val lastEvent = it[lastIndex]
val nextEvent = it[nextIndex]
if (lastEvent.highLight != nextEvent.highLight) {
bigEventTransitionDrawable?.reverseTransition(
BIG_EVENT_TRANSITION_DURATION
)
}
}
}
bigEventBannerView.startBannerLoop()
}
}
}
}
private fun initDataInfo(dataList: List<GameDetailDataInfo>) {
binding.dataContainer.removeAllViews()
dataList.forEachIndexed { index, dataInfo ->
binding.dataContainer.addView(getDataInfoItemView(dataInfo), 68F.dip2px(), 46F.dip2px())
if (index != dataList.size - 1) {
binding.dataContainer.addView(View(requireContext()).apply {
setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(requireContext()))
}, 1F.dip2px(), 24F.dip2px())
}
}
}
private fun initInfoTags(gameDetailInfoTag: GameDetailInfoTag) {
val isSpeedStatusOn = gameDetailInfoTag.requestSpeedStatus == "on"
val showInfoTags = gameDetailInfoTag.infoTags.isNotEmpty()
binding.infoTagContainer.goneIf(!isSpeedStatusOn && !showInfoTags) {
binding.accelerateTv.goneIf(!isSpeedStatusOn) {
if (gameDetailInfoTag.infoTags.isEmpty()) {
binding.infoTagContainer.updateLayoutParams<LinearLayout.LayoutParams> { width = LinearLayout.LayoutParams.WRAP_CONTENT }
binding.accelerateTipsTv.visibility = View.VISIBLE
}
binding.accelerateTv.setOnClickListener {
it.context.ifLogin("游戏详情-求加速") {
NewFlatLogUtils.logGameDetailClickForAccelerate(gameEntity?.id ?: "", gameEntity?.name ?: "")
SensorsBridge.trackGameDetailModuleClick(
gameEntity?.id,
gameEntity?.name,
gameEntity?.categoryChinese,
"组件内容",
"功能标签",
null,
null,
null,
null,
gameStatus = gameStatus
)
DialogHelper.showDialog(
requireContext(), "版本求加速", "如果游戏需要加速版本,您可以提交申请,让小助手尽快研究给您喔!",
"提交申请", "取消", {
viewModel.postRequestSpeed()
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
)
}
}
if (SPUtils.getBoolean(Constants.SP_SHOW_GAME_DETAIL_FUNCTION_TAG_GUIDE, true)) {
binding.coverRv.post {
showFunctionTagGuide()
}
}
}
binding.functionTagContainer.goneIf(!showInfoTags) {
val iterator = binding.functionTagContainer.iterator()
while (iterator.hasNext()) {
val childView = iterator.next()
if (childView.id != R.id.moreContainer) {
iterator.remove()
}
}
val showTags = gameDetailInfoTag.infoTags.take(3)
showTags.forEachIndexed { index, infoTag ->
binding.functionTagContainer.addView(
getFunctionTagView(infoTag),
index,
LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
).apply {
if (index != 0) {
setMargins(8F.dip2px(), 0, 0, 0)
}
}
)
}
binding.moreContainer.goneIf(gameDetailInfoTag.infoTags.size < 3) {
binding.moreTv.text = "+${gameDetailInfoTag.infoTags.size - 3}"
}
binding.functionTagContainer.setOnClickListener {
SensorsBridge.trackGameDetailModuleClick(
gameEntity?.id,
gameEntity?.name,
gameEntity?.categoryChinese,
"组件内容",
"功能标签",
null,
null,
null,
null,
gameStatus = gameStatus
)
GameFunctionDialogFragment.show(
requireContext(),
gameEntity?.id ?: "",
gameEntity?.name ?: "",
gameDetailInfoTag.infoTags
)
}
}
}
}
private fun showFunctionTagGuide() {
val decorView = activity?.window?.decorView as? FrameLayout
LayoutGuideGameDetailFunctionTagBinding.inflate(layoutInflater, decorView, true).run {
functionTagGuide = root
val screenWidth = DisplayUtils.getScreenWidth(requireActivity())
val infoTagLocation = IntArray(2)
binding.infoTagContainer.getLocationInWindow(infoTagLocation)
val top = (infoTagLocation[1] - 12F.dip2px()).toFloat()
root.targetRect.set(8F.dip2px().toFloat(), top, (screenWidth - 8F.dip2px()).toFloat(), top + 53F.dip2px())
guideIv.translationY = top - 56F.dip2px()
root.setOnClickListener {
hideFunctionTagGuide()
}
}
}
private fun hideFunctionTagGuide() {
val decorView = activity?.window?.decorView as? FrameLayout
functionTagGuide?.animate()?.alpha(0F)?.setDuration(300L)?.apply {
doOnEnd {
decorView?.removeView(functionTagGuide)
functionTagGuide = null
}
}?.start()
SPUtils.setBoolean(Constants.SP_SHOW_GAME_DETAIL_FUNCTION_TAG_GUIDE, false)
}
private fun getFunctionTagView(infoTag: GameDetailInfoTag.InfoTag) =
ItemGameDetailFunctionTagBinding.inflate(layoutInflater).apply {
ImageUtils.display(iconIv, infoTag.icon)
nameTv.text = infoTag.name
}.root
private fun getDataInfoItemView(dataInfo: GameDetailDataInfo) = ItemGameDetailDataInfoBinding.inflate(layoutInflater).apply {
nameTv.text = dataInfo.nameCn
when (dataInfo.name) {
"ranking" -> {
if (dataInfo.ranking != null) {
nameTv.text = dataInfo.ranking.columnName
infoTv.text = "#${dataInfo.ranking.no}"
infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
infoTv.setTypeface(Typeface.createFromAsset(requireContext().assets, Constants.DIN_FONT_PATH))
infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext()))
root.setOnClickListener {
SensorsBridge.trackGameDetailModuleClick(
gameEntity?.id,
gameEntity?.name,
gameEntity?.categoryChinese,
"组件内容",
"数据信息栏",
null,
null,
null,
null,
gameStatus = gameStatus
)
DirectUtils.directToColumnCollection(
requireContext(),
dataInfo.ranking.collectionId,
entrance = mEntrance,
columnName = dataInfo.ranking.columnName,
)
}
}
}
"real_name" -> {
if (dataInfo.realName != null) {
infoTv.text = if (dataInfo.realName.state == "yes") "" else ""
if (dataInfo.realName.certificationScreenshot.isNotEmpty()) {
infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext()))
root.setOnClickListener {
SensorsBridge.trackGameDetailModuleClick(
gameEntity?.id,
gameEntity?.name,
gameEntity?.categoryChinese,
"组件内容",
"数据信息栏",
null,
null,
null,
null,
gameStatus = gameStatus
)
startActivity(
ImageViewerActivity.getSingleIntent(
requireContext(),
dataInfo.realName.certificationScreenshot,
false
)
)
}
} else {
infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
}
}
}
else -> {
infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
infoTv.text = dataInfo.value
}
}
}.root
private fun notifyScrollStateChanged(state: Int) {
val firstVisibleItem = coverLayoutManager.findFirstVisibleItemPosition()
val lastVisibleItem = coverLayoutManager.findLastVisibleItemPosition()
scrollCalculatorHelper.onScrollStateChanged(firstVisibleItem, lastVisibleItem, state)
}
private fun RecyclerView.setCurrentItem(position: Int) {
if (position == coverPosition) return
coverScrollEventListener.notifyProgrammaticScroll(position, true)
if (abs(position - coverPosition) > 3) {
scrollToPosition(if (position > coverPosition) position - 3 else position + 3)
post {
smoothScrollToPosition(position)
}
} else {
smoothScrollToPosition(position)
}
coverPosition = position
}
override fun onFragmentPause() {
super.onFragmentPause()
pauseVideo()
binding.bigEventBannerView.stopBannerLoop()
}
override fun onFragmentResume() {
super.onFragmentResume()
resumeVideo()
if (!viewModel.basicInfoLiveData.value?.event.isNullOrEmpty()) {
binding.bigEventBannerView.startBannerLoop()
}
}
private fun pauseVideo() {
val currentPlayer = scrollCalculatorHelper.currentPlayer
if (currentPlayer != null) {
currentPlayer.onVideoPause()
val currentPosition = currentPlayer.getCurrentPosition()
val videoUrl = currentPlayer.getUrl()
if (videoUrl.isNotEmpty()) {
ScrollCalculatorHelper.savePlaySchedule(MD5Utils.getContentMD5(videoUrl), currentPosition)
}
}
}
private fun resumeVideo() {
val currentPlayer = scrollCalculatorHelper.currentPlayer
if (currentPlayer != null) {
val videoUrl = currentPlayer.getUrl()
if (videoUrl.isNotEmpty()) {
val position = ScrollCalculatorHelper.getPlaySchedule(MD5Utils.getContentMD5(videoUrl))
//这里必须要延迟操作,否则会白屏
mBaseHandler.postDelayed({
if (position != 0L) {
scrollCalculatorHelper.currentPlayer?.seekTo(position)
scrollCalculatorHelper.currentPlayer?.onVideoResume(false)
} else {
scrollCalculatorHelper.currentPlayer?.release()
}
}, 50)
}
}
}
private fun showFloatingWindowIfNeeded() {
val floatingWindowProvider = TheRouter.get(IFloatingWindowProvider::class.java)
floatingWindowProvider?.getAndShowFloatingWindow(
gameEntity?.id ?: "",
gameEntity?.name ?: "",
"游戏详情",
this,
binding.detailRv
)?.let {
compositeDisposable.add(it)
}
}
override fun onDestroy() {
super.onDestroy()
compositeDisposable.dispose()
if (::scrollCalculatorHelper.isInitialized) {
scrollCalculatorHelper.release()
}
}
private fun startCoverHeightAnimation(startHeight: Int, targetHeight: Int) {
if (isCoverHeightAnimating) return
ValueAnimator.ofInt(startHeight, targetHeight).apply {
duration = COVER_HEIGHT_ANIMATION_DURATION
doOnStart {
isCoverHeightAnimating = true
}
doOnEnd {
isCoverHeightAnimating = false
}
addUpdateListener { va ->
binding.coverRv.updateLayoutParams<ViewGroup.LayoutParams> {
height = va.animatedValue as Int
}
}
}.start()
}
override fun scrollToTop() {
binding.gamedetailAppbar.setExpanded(true)
binding.detailRv.scrollToPosition(0)
}
// 登录事件
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEventMainThread(reuse: EBReuse) {
if (reuse.type == Constants.LOGIN_TAG) {
viewModel.detailDataListLiveData.value?.let { viewModel.getUserRelatedInfo(it) }
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val commentPosition = detailListAdapter.currentList.indexOfFirst { it.linkComment != null }
if (resultCode == Activity.RESULT_OK) {
if (GameDetailCommentItemViewHolder.RATING_REPLY_REQUEST == requestCode || GameDetailCommentItemViewHolder.RATING_PATCH_REQUEST == requestCode) {
SyncDataBetweenPageHelper.resultHandle(data, object : OnSyncCallBack<RatingComment> {
override fun onData(dataPosition: Int): RatingComment? {
return if (commentPosition != -1) {
val commentList = detailListAdapter.currentList[commentPosition].linkComment?.data ?: return null
commentList.getOrNull(dataPosition)?.apply {
if (GameDetailCommentItemViewHolder.RATING_PATCH_REQUEST == requestCode) {
ignore = gameEntity?.ignoreComment ?: false
}
}
} else null
}
override fun onNotify(dataPosition: Int) {
if (commentPosition != -1) {
detailListAdapter.notifyItemChanged(commentPosition)
}
}
})
} else if (requestCode == GameLibaoAdapter.LIBAO_REQUEST) {
val position = detailListAdapter.currentList.indexOfFirst { it.linkLibao != null }
if (position != -1) {
detailListAdapter.notifyItemChanged(position)
}
}
} else if (requestCode == GameDetailCommentItemViewHolder.RATING_REPLY_REQUEST && resultCode == RatingFragment.RATING_DELETE_RESULT) {
data?.getParcelableExtra<RatingComment>(RatingComment::class.java.simpleName)?.run {
if (commentPosition != -1) {
val commentList = detailListAdapter.currentList[commentPosition].linkComment?.data ?: return
val deleteCommentPosition = commentList.indexOfFirst { it.id == id }
if (deleteCommentPosition != -1) {
commentList.removeAt(deleteCommentPosition)
}
detailListAdapter.notifyItemChanged(commentPosition)
}
}
}
}
override fun onBackPressed(): Boolean {
if (functionTagGuide != null) {
hideFunctionTagGuide()
return true
}
return super.onBackPressed()
}
override fun onDarkModeChanged() {
super.onDarkModeChanged()
viewModel.basicInfoLiveData.value?.let { initBasicInfo(it) }
val dataInfoList = viewModel.dataInfoLiveData.value
if (!dataInfoList.isNullOrEmpty()) {
initDataInfo(dataInfoList)
}
viewModel.infoTagLiveData.value?.let { initInfoTags(it) }
detailListAdapter.run { notifyItemRangeChanged(0, itemCount) }
}
companion object {
private const val COVER_HEIGHT_ANIMATION_DURATION = 400L
private const val COVER_VIDEO_INITIAL_DELAY = 500L
private const val BIG_EVENT_TRANSITION_DURATION = 1000
}
}

View File

@ -0,0 +1,127 @@
package com.gh.gamecenter.gamedetail.detail
import android.view.ViewGroup
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.DiffUtil.ItemCallback
import androidx.recyclerview.widget.ListAdapter
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.gamedetail.GameDetailViewModel
import com.gh.gamecenter.gamedetail.detail.viewholder.*
import com.gh.gamecenter.gamedetail.entity.GameDetailData
class GameDetailListAdapter(
private val downloadBtn: DownloadButton,
private val viewModel: GameDetailViewModel,
private val lifecycleOwner: LifecycleOwner
) :
ListAdapter<GameDetailData, BaseGameDetailItemViewHolder>(createDiffCallback()) {
override fun getItemViewType(position: Int): Int {
val data = currentList[position]
return when {
data?.linkContentCard != null -> {
when (data.linkContentCard.size) {
1 -> ITEM_CONTENT_CARD_SINGLE
2 -> ITEM_CONTENT_CARD_DOUBLE
else -> ITEM_CONTENT_CARD_TRIPLE
}
}
data?.linkAdvertising != null -> if (data.linkAdvertising.img.isEmpty()) ITEM_ADVERTISING else ITEM_ADVERTISING_IMAGE
data?.linkComprehensive != null -> ITEM_COMPREHENSIVE_PANEL
data?.linkCustomColumn != null -> ITEM_CUSTOM_COLUMN
data?.linkDrawer != null -> ITEM_DRAWER
data?.linkAnnouncement != null -> ITEM_ANNOUNCEMENT
data?.linkGameBrief != null -> ITEM_GAME_BRIEF
data?.linkDeveloperWord != null -> ITEM_DEVELOPER_WORD
data?.linkUpdate != null -> ITEM_UPDATE
data?.linkComment != null -> ITEM_COMMENT
data?.linkInfo != null -> ITEM_DETAIL_INFO
data?.linkContentRecommend != null -> ITEM_CONTENT_RECOMMEND
data?.linkGameVideo != null -> ITEM_GAME_VIDEO
data?.linkGameGuide != null -> ITEM_GAME_STRATEGY
data?.linkServer != null -> ITEM_SERVER
data?.linkLibao != null -> ITEM_GIFT
data?.linkRelatedGame != null -> ITEM_RELATED_GAME
data?.linkImageRecommend != null -> ITEM_RECOMMEND_IMAGE
data?.linkEveryonePlaying != null -> ITEM_RECOMMEND_GAME
data?.linkRecommendGameList != null -> ITEM_RECOMMEND_GAME_COLLECTION
else -> ITEM_RECOMMEND_COLUMN
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseGameDetailItemViewHolder {
return when (viewType) {
ITEM_CONTENT_CARD_SINGLE -> GameDetailContentCardSingleItemViewHolder(parent.toBinding(), downloadBtn, viewModel, lifecycleOwner)
ITEM_CONTENT_CARD_DOUBLE -> GameDetailContentCardDoubleItemViewHolder(parent.toBinding(), downloadBtn, viewModel, lifecycleOwner)
ITEM_CONTENT_CARD_TRIPLE -> GameDetailContentCardTripleItemViewHolder(parent.toBinding(), downloadBtn, viewModel, lifecycleOwner)
ITEM_ADVERTISING -> GameDetailAdvertisingItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_ADVERTISING_IMAGE -> GameDetailAdvertisingImageItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_COMPREHENSIVE_PANEL -> GameDetailComprehensivePanelItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_CUSTOM_COLUMN -> GameDetailCustomColumnItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_DRAWER -> GameDetailDrawerItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_ANNOUNCEMENT -> GameDetailAnnouncementItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_GAME_BRIEF -> GameDetailBriefItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_DEVELOPER_WORD -> com.gh.gamecenter.gamedetail.detail.viewholder.GameDetailDeveloperWordItemViewHolder(
parent.toBinding(),
downloadBtn,
viewModel
)
ITEM_UPDATE -> GameDetailUpdateItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_COMMENT -> GameDetailCommentItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_DETAIL_INFO -> GameDetailInfoItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_CONTENT_RECOMMEND -> GameDetailContentRecommendItemViewHolder(parent.toBinding(), downloadBtn, viewModel, lifecycleOwner)
ITEM_GAME_VIDEO -> GameDetailVideoItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_GAME_STRATEGY -> GameDetailStrategyItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_SERVER -> GameDetailServerItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_GIFT -> GameDetailGiftItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_RELATED_GAME -> GameDetailRelatedGameItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_RECOMMEND_IMAGE -> GameDetailRecommendImageItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_RECOMMEND_GAME -> GameDetailRecommendGameItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
ITEM_RECOMMEND_GAME_COLLECTION -> GameDetailRecommendGameCollectionItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
else -> GameDetailRecommendColumnItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
}
}
override fun onBindViewHolder(holder: BaseGameDetailItemViewHolder, position: Int) {
val item = getItem(position)
holder.bindView(item)
}
companion object {
const val ITEM_CONTENT_CARD_SINGLE = 0 // 内容卡片-单个
const val ITEM_CONTENT_CARD_DOUBLE = 1 // 内容卡片-两个
const val ITEM_CONTENT_CARD_TRIPLE = 2 // 内容卡片-三个
const val ITEM_ADVERTISING = 3 // 广告推荐-无图片
const val ITEM_ADVERTISING_IMAGE = 4 // 广告推荐-带图片
const val ITEM_COMPREHENSIVE_PANEL = 5 // 综合面板
const val ITEM_CUSTOM_COLUMN = 6 // 自定义栏目
const val ITEM_DRAWER = 7 // 列表抽屉
const val ITEM_ANNOUNCEMENT = 8 // 资讯公告
const val ITEM_GAME_BRIEF = 9 // 游戏简介
const val ITEM_DEVELOPER_WORD = 10 // 开发者的话
const val ITEM_UPDATE = 11 // 更新内容
const val ITEM_COMMENT = 12 // 玩家评论
const val ITEM_DETAIL_INFO = 13 // 详情信息
const val ITEM_CONTENT_RECOMMEND = 14 // 内容推荐PK组件
const val ITEM_GAME_VIDEO = 15 // 视频
const val ITEM_GAME_STRATEGY = 16 // 游戏攻略
const val ITEM_SERVER = 17 // 游戏开服
const val ITEM_GIFT = 18 // 游戏礼包
const val ITEM_RELATED_GAME = 19 // 相关游戏
const val ITEM_RECOMMEND_IMAGE = 20 // 图片推荐
const val ITEM_RECOMMEND_GAME = 21 // 大家都在玩
const val ITEM_RECOMMEND_GAME_COLLECTION = 22 // 游戏单推荐
const val ITEM_RECOMMEND_COLUMN = 23 // 专题推荐
fun createDiffCallback() = object : ItemCallback<GameDetailData>() {
override fun areItemsTheSame(oldItem: GameDetailData, newItem: GameDetailData): Boolean {
return oldItem.areItemsTheSame(newItem)
}
override fun areContentsTheSame(oldItem: GameDetailData, newItem: GameDetailData): Boolean {
return oldItem.areContentsTheSame(newItem)
}
}
}
}

View File

@ -1,39 +1,37 @@
package com.gh.gamecenter.gamedetail.desc
package com.gh.gamecenter.gamedetail.detail
import android.content.Context
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.databind.BindingAdapters
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.StringUtils
import com.gh.gamecenter.databinding.ItemGameDetailRelatedVersionBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.game.GameItemViewHolder
import com.gh.gamecenter.gamedetail.entity.RelatedVersion
import com.gh.gamecenter.gamedetail.detail.viewholder.BaseGameDetailItemViewHolder
class GameRelatedVersionAdapter(
private val mContext: Context,
private val mGameId: String,
private val mGameName: String,
private val mGame: GameEntity?,
private val mDatas: ArrayList<RelatedVersion>,
private val mEntrance: String
class GameDetailRelatedGameAdapter(
private val context: Context,
private val game: GameEntity?,
private val relatedGameList: ArrayList<GameEntity>,
private val entrance: String,
private val trackData: BaseGameDetailItemViewHolder.GameDetailModuleTrackData,
private val getGameStatus: () -> String
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var exposureEventList: ArrayList<ExposureEvent> = arrayListOf()
private val mMaxWidth = mContext.resources.displayMetrics.widthPixels - 32F.dip2px()
private val maxWidth = context.resources.displayMetrics.widthPixels - 32F.dip2px()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return GameDetailRelatedViewHolder(parent.toBinding())
}
override fun getItemCount(): Int = mDatas.size
override fun getItemCount(): Int = relatedGameList.size
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val relatedVersion = mDatas[position]
val gameEntity = relatedGameList.getOrNull(position) ?: return
if (holder is GameDetailRelatedViewHolder) {
val paddingStart = 16F.dip2px()
val isEndOfRow = position >= if (itemCount % 3 == 0) {
@ -46,48 +44,42 @@ class GameRelatedVersionAdapter(
var paddingEnd = if (isEndOfRow) 16F.dip2px() else 0F.dip2px()
holder.itemView.layoutParams = if (!isEndOfRow) {
paddingEnd += 1
ViewGroup.LayoutParams(mMaxWidth - 24F.dip2px(), ViewGroup.LayoutParams.WRAP_CONTENT)
ViewGroup.LayoutParams(maxWidth - 24F.dip2px(), ViewGroup.LayoutParams.WRAP_CONTENT)
} else {
ViewGroup.LayoutParams(mMaxWidth - 1, ViewGroup.LayoutParams.WRAP_CONTENT)
ViewGroup.LayoutParams(maxWidth - 1, ViewGroup.LayoutParams.WRAP_CONTENT)
}
holder.binding.root.setPadding(paddingStart, 8F.dip2px(), paddingEnd, 8F.dip2px())
val gameEntity = relatedVersion.game ?: return
holder.binding.gameNameTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(mContext))
holder.binding.gameNameTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
holder.binding.gameNameTv.text = gameEntity.name
BindingAdapters.setGameTags(holder.binding.gameLabelLl, gameEntity)
holder.binding.gameIconView.displayGameIcon(gameEntity)
holder.binding.gameIconView.setBorderColor(com.gh.gamecenter.common.R.color.resource_border)
holder.itemView.setOnClickListener {
MtaHelper.onEvent("游戏详情_新", "相关游戏版本", "${mGameName}+${relatedVersion.gameName}")
GameDetailActivity.startGameDetailActivity(
mContext,
relatedVersion.gameId,
context,
gameEntity.id,
StringUtils.buildString(
mEntrance,
entrance,
"+(",
"游戏详情",
"[",
relatedVersion.gameName,
gameEntity.name,
"]:相关游戏[",
(position + 1).toString(),
"])"
),
exposureEventList.safelyGetInRelease(position)
)
SensorsBridge.trackGameDetailPageRelatedGameClick(
gameId = mGameId,
gameName = mGameName,
pageName = GlobalActivityManager.getCurrentPageEntity().pageName,
pageId = GlobalActivityManager.getCurrentPageEntity().pageId,
pageBusinessId = GlobalActivityManager.getCurrentPageEntity().pageBusinessId,
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId,
downloadStatus = mGame?.downloadStatusChinese ?: "",
gameType = mGame?.categoryChinese ?: "",
clickGameId = gameEntity.id,
clickGameName = gameEntity.name ?: "",
clickGameType = gameEntity.categoryChinese
SensorsBridge.trackGameDetailModuleClick(
trackData.gameId,
trackData.gameName,
trackData.gameType,
"组件内容",
trackData.moduleType,
"相关游戏",
trackData.sequence,
supSequence = position + 1,
gameStatus = getGameStatus()
)
}
GameItemViewHolder.initGameSubtitleAndAdLabel(gameEntity, holder.binding.gameSubtitleTv)

View File

@ -1,4 +1,4 @@
package com.gh.gamecenter.gamedetail.desc
package com.gh.gamecenter.gamedetail.detail
import android.content.Context
import android.view.Gravity
@ -8,9 +8,9 @@ import android.view.ViewGroup
import android.view.ViewTreeObserver
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.common.utils.safelyGetInRelease
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.databinding.ItemGameDetailLatestServiceBinding
import com.gh.gamecenter.databinding.ItemGameDetailMoreBinding
import com.gh.gamecenter.feature.entity.GameEntity

View File

@ -0,0 +1,276 @@
package com.gh.gamecenter.gamedetail.detail
import android.app.Activity
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import android.widget.LinearLayout
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.RecyclerView
import com.facebook.drawee.drawable.ScalingUtils
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
import com.facebook.drawee.view.SimpleDraweeView
import com.gh.common.util.LibaoUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.common.databinding.RefreshFooterviewBinding
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.core.utils.SpanBuilder
import com.gh.gamecenter.databinding.ItemGameDetailMoreBinding
import com.gh.gamecenter.databinding.ItemGameLibaoBinding
import com.gh.gamecenter.feature.entity.LibaoEntity
import com.gh.gamecenter.libao.LibaoDetailActivity
import com.gh.gamecenter.login.user.UserManager
class GameLibaoAdapter(
val context: Context,
var libaos: ArrayList<LibaoEntity>,
val gameName: String,
val gameId: String,
showExpandIcon: Boolean = true
) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var mIsExpand = false
private val mShowItemCount: Int = if (showExpandIcon) 3 else Int.MAX_VALUE // 最多展示多少个礼包
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when(viewType) {
LIBAO_ITEM -> LibaoViewHolder(parent.toBinding())
FOOTER_ITEM -> FooterViewHolder(parent.toBinding())
else -> MoreViewHolder(ItemGameDetailMoreBinding.inflate(LayoutInflater.from(context), parent, false))
}
}
override fun getItemViewType(position: Int): Int {
return if (libaos.size > mShowItemCount) {
if (!mIsExpand) {
if (position == mShowItemCount) MORE else LIBAO_ITEM
} else {
if (position == libaos.size) MORE else LIBAO_ITEM
}
} else {
LIBAO_ITEM
}
}
override fun getItemCount(): Int {
return if (libaos.size > mShowItemCount) {
if (mIsExpand) libaos.size + 1 else mShowItemCount + 1
} else {
libaos.size
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is LibaoViewHolder -> {
val libaoEntity = libaos[position]
holder.bindItem(context, this, gameId, gameName, libaoEntity)
}
is MoreViewHolder -> {
holder.binding.arrowIv.rotation = if (mIsExpand) 180f else 0f
holder.itemView.setOnClickListener {
if (!mIsExpand) MtaHelper.onEvent("游戏详情_新", "游戏礼包_展开", gameName)
mIsExpand = !mIsExpand
notifyDataSetChanged()
NewLogUtils.logGameDetailGiftClick(gameName, gameId, "展开")
}
}
is FooterViewHolder -> {
holder.binding.footerviewHint.setTextColor(com.gh.gamecenter.common.R.color.text_instance.toColor(context))
holder.binding.footerviewHint.text = "没有更多内容了"
holder.binding.footerviewLoading.isVisible = false
}
}
}
class LibaoViewHolder(var binding: ItemGameLibaoBinding) : RecyclerView.ViewHolder(binding.root) {
fun bindItem(context: Context, adapter: RecyclerView.Adapter<*>, gameId: String, gameName: String, libaoEntity: LibaoEntity) {
val position = bindingAdapterPosition
binding.root.updateLayoutParams<MarginLayoutParams> { topMargin = if (position == 0) 0 else 8F.dip2px() }
binding.root.background = com.gh.gamecenter.common.R.drawable.bg_shape_f8_radius_8.toDrawable(context)
binding.libaoNameTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
binding.contentTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
binding.remainingTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
binding.libaoCodeTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
binding.libaoNameTv.text = libaoEntity.name
binding.contentTv.text = libaoEntity.content?.fromHtml()
binding.horizontalScrollView.goneIf(libaoEntity.materials.isEmpty()) {
binding.imagesContainer.removeAllViews()
libaoEntity.materials.forEachIndexed { index, image ->
binding.imagesContainer.addView(SimpleDraweeView(context).apply {
hierarchy = GenericDraweeHierarchyBuilder(resources)
.setFadeDuration(500)
.setPlaceholderImage(com.gh.gamecenter.common.R.drawable.occupy, ScalingUtils.ScaleType.FIT_XY)
.build()
ImageUtils.display(this, image)
}, LinearLayout.LayoutParams(24F.dip2px(), 24F.dip2px()).apply {
setMargins(if (index != 0) 16F.dip2px() else 0, 0, 0, 0)
})
}
}
val isTypeCopy = libaoEntity.receiveMethod == "copy"
if (isTypeCopy) {
// 类型为复制,不需要登录也能直接领取
binding.libaoSchedulePb.visibility = View.GONE
binding.remainingTv.visibility = View.GONE
binding.libaoCodeTv.visibility = View.VISIBLE
val text = "兑换码:${libaoEntity.code}"
binding.libaoCodeTv.text = SpanBuilder(text).color(
binding.root.context,
4,
text.length,
com.gh.gamecenter.common.R.color.text_theme
).build()
binding.copyLibaoCodeIv.visibility = View.VISIBLE
binding.copyLibaoCodeIv.setOnClickListener {
binding.receiveTv.performClick()
}
} else if (libaoEntity.universal || libaoEntity.status == "check") {
//通用码礼包/或者还未添加礼包码时,不显示进度条,显示礼包码
binding.libaoSchedulePb.visibility = View.GONE
binding.remainingTv.visibility = View.GONE
binding.libaoCodeTv.visibility = View.VISIBLE
binding.copyLibaoCodeIv.visibility = View.GONE
if (!UserManager.getInstance().isLoggedIn) {
binding.libaoCodeTv.text = "礼包码:-"
} else {
when (libaoEntity.status) {
"linged", "repeatLing", "repeatLinged", "taoed", "repeatTao", "repeatTaoed" -> {
val size = libaoEntity.me?.userDataLibaoList?.size ?: 0
val code = libaoEntity.me?.userDataLibaoList?.get(size - 1)?.code ?: ""
val text = "礼包码:$code"
binding.libaoCodeTv.text = SpanBuilder(text).color(
binding.root.context,
4,
text.length,
com.gh.gamecenter.common.R.color.text_theme
).build()
binding.copyLibaoCodeIv.visibility = View.VISIBLE
binding.copyLibaoCodeIv.setOnClickListener {
code.copyTextAndToast("$code 复制成功")
}
}
else -> {
binding.libaoCodeTv.text = "礼包码:-"
}
}
}
} else {
if (!UserManager.getInstance().isLoggedIn) {
binding.libaoSchedulePb.visibility = View.VISIBLE
binding.remainingTv.visibility = View.VISIBLE
binding.libaoCodeTv.visibility = View.GONE
binding.copyLibaoCodeIv.visibility = View.GONE
initProgressUI(libaoEntity)
} else {
when (libaoEntity.status) {
"linged", "repeatLing", "repeatLinged", "taoed", "repeatTao", "repeatTaoed" -> {
binding.libaoSchedulePb.visibility = View.GONE
binding.remainingTv.visibility = View.GONE
binding.libaoCodeTv.visibility = View.VISIBLE
val size = libaoEntity.me?.userDataLibaoList?.size ?: 0
val code = libaoEntity.me?.userDataLibaoList?.get(size - 1)?.code ?: ""
val text = "礼包码:$code"
binding.libaoCodeTv.text = SpanBuilder(text).color(
binding.root.context,
4,
text.length,
com.gh.gamecenter.common.R.color.text_theme
).build()
binding.copyLibaoCodeIv.visibility = View.VISIBLE
binding.copyLibaoCodeIv.setOnClickListener {
code.copyTextAndToast("$code 复制成功")
}
}
else -> {
binding.libaoSchedulePb.visibility = View.VISIBLE
binding.remainingTv.visibility = View.VISIBLE
binding.libaoCodeTv.visibility = View.GONE
binding.copyLibaoCodeIv.visibility = View.GONE
initProgressUI(libaoEntity)
}
}
}
}
// LibaoUtils.setLiBaoBtnStatusRound(holder.binding.receiveTv, libaoEntity,true, context)
LibaoUtils.initLibaoBtn(
context,
binding.receiveTv,
libaoEntity,
false,
null,
true,
"游戏详情",
"游戏详情"
) {
adapter.notifyItemChanged(position)
}
if (!libaoEntity.packageName.isNullOrEmpty()) {
binding.receiveTv.setOnClickListener {
val intent = LibaoDetailActivity.getIntent(context, libaoEntity, true, "游戏详情")
if (it.context is Activity) {
(it.context as Activity).startActivityForResult(intent, LIBAO_REQUEST)
}
}
}
itemView.setOnClickListener {
if (isTypeCopy) {
// do nothing
} else {
val intent = LibaoDetailActivity.getIntent(context, libaoEntity, "游戏详情")
if (it.context is Activity) {
(it.context as Activity).startActivityForResult(intent, LIBAO_REQUEST)
}
NewLogUtils.logGameDetailGiftClick(gameName, gameId, "礼包详情")
}
}
}
private fun initProgressUI(libaoEntity: LibaoEntity) {
val total = libaoEntity.total
val available = libaoEntity.available
if (total != 0) {
val availablePercent = (available) / total.toFloat() * 100
val count = when {
availablePercent >= 1F -> {
availablePercent.toInt()
}
availablePercent == 0F -> {
0
}
else -> {
1
}
}
binding.remainingTv.text = "剩余${count}%"
binding.libaoSchedulePb.progress = count
}
}
}
class MoreViewHolder(var binding: ItemGameDetailMoreBinding) : RecyclerView.ViewHolder(binding.root)
class FooterViewHolder(var binding: RefreshFooterviewBinding) : RecyclerView.ViewHolder(binding.root)
companion object {
const val MORE = 0
const val LIBAO_ITEM = 1
const val FOOTER_ITEM = 2
const val LIBAO_REQUEST = 100
}
}

View File

@ -0,0 +1,75 @@
package com.gh.gamecenter.gamedetail.detail.viewholder
import android.content.Context
import android.view.View
import androidx.annotation.CallSuper
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.gamedetail.GameDetailViewModel
import com.gh.gamecenter.gamedetail.entity.GameDetailData
abstract class BaseGameDetailItemViewHolder(val itemView: View, val downloadBtn: DownloadButton, val viewModel: GameDetailViewModel) : RecyclerView.ViewHolder(itemView) {
protected val context: Context = itemView.context
protected var itemData: GameDetailData? = null
protected val gameId
get() = viewModel.game?.id ?: ""
protected val gameName
get() = viewModel.game?.name ?: ""
protected val gameType
get() = viewModel.game?.categoryChinese ?: ""
protected val moduleType
get() = itemData?.typeChinese ?: ""
protected val sequence
get() = itemData?.position?.plus(1) ?: 0
protected val gameStatus
get() = getGameStatus(downloadBtn.buttonStyle)
protected val baseTrackData
get() = GameDetailModuleTrackData(
gameId = gameId,
gameName = gameName,
gameType = gameId,
gameStatus = gameStatus,
moduleType = moduleType,
sequence = sequence,
)
@CallSuper
open fun bindView(data: GameDetailData) {
itemData = data
}
data class GameDetailModuleTrackData(
var gameId: String = "",
var gameName: String = "",
var gameType: String = "",
var gameStatus: String = "",
var moduleType: String = "",
var moduleName: String = "",
var sequence: Int = 0,
var subModuleName: String = "",
var subSequence: Int = 0
)
companion object {
fun getGameStatus(buttonStyle: DownloadButton.ButtonStyle) = when (buttonStyle) {
DownloadButton.ButtonStyle.WAITING,
DownloadButton.ButtonStyle.UPDATING,
DownloadButton.ButtonStyle.PAUSE,
DownloadButton.ButtonStyle.FAILURE,
DownloadButton.ButtonStyle.DOWNLOADING_NORMAL,
DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN -> "下载中"
DownloadButton.ButtonStyle.XAPK_UNZIPPING,
DownloadButton.ButtonStyle.XAPK_SUCCESS,
DownloadButton.ButtonStyle.XAPK_FAILURE,
DownloadButton.ButtonStyle.INSTALL_NORMAL,
DownloadButton.ButtonStyle.INSTALL_PLUGIN -> "待安装"
DownloadButton.ButtonStyle.LAUNCH_OR_OPEN -> "已安装"
DownloadButton.ButtonStyle.RESERVABLE -> "预约"
DownloadButton.ButtonStyle.RESERVED -> "已预约"
else -> "未下载"
}
}
}

View File

@ -0,0 +1,76 @@
package com.gh.gamecenter.gamedetail.detail.viewholder
import android.content.Context
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.updateLayoutParams
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.databinding.ItemGameDetailImageLinkBinding
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.gamedetail.GameDetailViewModel
import com.gh.gamecenter.gamedetail.entity.GameDetailData
import com.gh.gamecenter.gamedetail.entity.GameDetailLink
class GameDetailAdvertisingImageItemViewHolder(
val binding: ItemGameDetailImageLinkBinding,
downloadBtn: DownloadButton,
viewModel: GameDetailViewModel
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
override fun bindView(data: GameDetailData) {
super.bindView(data)
val entity = data.linkAdvertising ?: return
bindImageItem(context, binding, entity, "游戏详情-广告推荐", baseTrackData) { gameStatus }
}
companion object {
fun bindImageItem(
context: Context,
binding: ItemGameDetailImageLinkBinding,
data: GameDetailLink,
entrance: String,
trackData: GameDetailModuleTrackData,
getGameStatus: () -> String
) {
binding.run {
if (data.img.isNotEmpty() && data.imgScale.isNotEmpty()) {
imageIv.updateLayoutParams<ConstraintLayout.LayoutParams> {
dimensionRatio = data.imgScale
}
maskView.updateLayoutParams<ConstraintLayout.LayoutParams> {
height = if (data.imgScale == "4:1") 40F.dip2px() else 60F.dip2px()
}
ImageUtils.display(imageIv, data.img)
}
iconIv.goneIf(data.componentIcon?.icon.isNullOrEmpty()) {
ImageUtils.display(iconIv, data.componentIcon?.icon)
}
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_aw_primary.toColor(context))
titleTv.text = data.title
linkTv.goneIf(data.text.isEmpty()) {
linkTv.text = data.text
linkTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
}
container.setOnClickListener { _ ->
data.link?.let {
DirectUtils.directToLinkPage(context, it, entrance, "")
SensorsBridge.trackGameDetailModuleClick(
trackData.gameId,
trackData.gameName,
trackData.gameType,
"组件内容",
trackData.moduleType,
trackData.moduleName,
trackData.sequence,
null,
null,
it.type,
it.link,
it.link,
getGameStatus()
)
}
}
}
}
}
}

View File

@ -0,0 +1,65 @@
package com.gh.gamecenter.gamedetail.detail.viewholder
import android.content.Context
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.databinding.ItemGameDetailLinkBinding
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.gamedetail.GameDetailViewModel
import com.gh.gamecenter.gamedetail.entity.GameDetailData
import com.gh.gamecenter.gamedetail.entity.GameDetailLink
class GameDetailAdvertisingItemViewHolder(
val binding: ItemGameDetailLinkBinding,
downloadBtn: DownloadButton,
viewModel: GameDetailViewModel
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
override fun bindView(data: GameDetailData) {
super.bindView(data)
val entity = data.linkAdvertising ?: return
bindItem(context, binding, entity, "游戏详情-广告推荐", baseTrackData) { gameStatus }
}
companion object {
fun bindItem(
context: Context,
binding: ItemGameDetailLinkBinding,
data: GameDetailLink,
entrance: String,
trackData: GameDetailModuleTrackData,
getGameStatus: () -> String
) {
binding.run {
container.background = R.drawable.bg_shape_ui_container_1_radius_8_item_style.toDrawable(context)
iconIv.goneIf(data.componentIcon?.icon.isNullOrEmpty()) {
ImageUtils.display(iconIv, data.componentIcon?.icon)
}
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
titleTv.text = data.title
container.setOnClickListener { _ ->
data.link?.let {
DirectUtils.directToLinkPage(context, it, entrance, "")
SensorsBridge.trackGameDetailModuleClick(
trackData.gameId,
trackData.gameName,
trackData.gameType,
"组件内容",
trackData.moduleType,
trackData.moduleName,
trackData.sequence,
null,
null,
it.type,
it.link,
it.link,
getGameStatus()
)
}
}
}
}
}
}

View File

@ -0,0 +1,95 @@
package com.gh.gamecenter.gamedetail.detail.viewholder
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.view.VerticalItemDecoration
import com.gh.gamecenter.databinding.ItemGameDetailAnnouncementBinding
import com.gh.gamecenter.databinding.ItemGameDetailImageLinkBinding
import com.gh.gamecenter.databinding.ItemGameDetailLinkBinding
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.gamedetail.GameDetailViewModel
import com.gh.gamecenter.gamedetail.entity.GameDetailData
import com.gh.gamecenter.gamedetail.entity.GameDetailLink
class GameDetailAnnouncementItemViewHolder(
val binding: ItemGameDetailAnnouncementBinding,
downloadBtn: DownloadButton,
viewModel: GameDetailViewModel
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
override fun bindView(data: GameDetailData) {
super.bindView(data)
val entity = data.linkAnnouncement ?: return
binding.run {
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
titleTv.text = entity.name
if (recyclerView.adapter !is GameDetailAnnouncementAdapter) {
recyclerView.isNestedScrollingEnabled = false
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.adapter = GameDetailAnnouncementAdapter(entity.data)
recyclerView.addItemDecoration(VerticalItemDecoration(context, 8F, false, com.gh.gamecenter.common.R.color.transparent))
} else {
recyclerView.adapter?.run { notifyItemRangeChanged(0, itemCount) }
}
}
}
inner class GameDetailAnnouncementAdapter(val dataList: List<GameDetailLink>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun getItemViewType(position: Int): Int {
val data = dataList[position]
return if (data.img.isEmpty()) ITEM_LINK else ITEM_IMAGE_LINK
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == ITEM_LINK) {
GameDetailAnnouncementItemViewHolder(parent.toBinding())
} else {
GameDetailAnnouncementImageItemViewHolder(parent.toBinding())
}
}
override fun getItemCount(): Int = dataList.size
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val data = dataList.getOrNull(position) ?: return
if (holder is GameDetailAnnouncementItemViewHolder) {
GameDetailAdvertisingItemViewHolder.bindItem(
context,
holder.binding,
data,
"游戏详情-资讯公告",
baseTrackData.apply {
moduleName = itemData?.linkAnnouncement?.name ?: ""
}) { gameStatus }
holder.binding.container.background = null
}
if (holder is GameDetailAnnouncementImageItemViewHolder) {
GameDetailAdvertisingImageItemViewHolder.bindImageItem(
context,
holder.binding,
data,
"游戏详情-资讯公告",
baseTrackData.apply {
moduleName = itemData?.linkAnnouncement?.name ?: ""
}
) { gameStatus }
}
}
}
inner class GameDetailAnnouncementItemViewHolder(val binding: ItemGameDetailLinkBinding) :
RecyclerView.ViewHolder(binding.root)
inner class GameDetailAnnouncementImageItemViewHolder(val binding: ItemGameDetailImageLinkBinding) :
RecyclerView.ViewHolder(binding.root)
companion object {
const val ITEM_LINK = 0
const val ITEM_IMAGE_LINK = 1
}
}

View File

@ -0,0 +1,135 @@
package com.gh.gamecenter.gamedetail.detail.viewholder
import android.text.Html
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.view.forEach
import androidx.core.view.isEmpty
import androidx.core.view.isVisible
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.databinding.ItemGameDetailBriefAwardBinding
import com.gh.gamecenter.databinding.ItemGameDetailBriefBinding
import com.gh.gamecenter.databinding.ItemGameDetailBriefTagBinding
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.gamedetail.GameDetailViewModel
import com.gh.gamecenter.gamedetail.dialog.GameDetailScrollableTextDialogFragment
import com.gh.gamecenter.gamedetail.entity.GameBrief
import com.gh.gamecenter.gamedetail.entity.GameDetailData
import com.gh.gamecenter.tag.TagsActivity
import splitties.systemservices.layoutInflater
class GameDetailBriefItemViewHolder(
val binding: ItemGameDetailBriefBinding,
downloadBtn: DownloadButton,
viewModel: GameDetailViewModel
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
override fun bindView(data: GameDetailData) {
super.bindView(data)
val entity = data.linkGameBrief ?: return
binding.run {
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
briefTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
divider.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(context))
expandTv.background = R.drawable.bg_ui_surface_expand_gradient.toDrawable(context)
expandTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
titleTv.text = entity.name
tagScrollView.goneIf(entity.gameTags.isEmpty()) {
bindGamesTags(entity.gameTags)
}
briefTv.text = Html.fromHtml(entity.des)
briefTv.post {
expandTv.isVisible = briefTv.lineCount == 3 && briefTv.layout.getEllipsisCount(2) > 0
}
expandTv.setOnClickListener {
SensorsBridge.trackGameDetailModuleClick(
gameId,
gameName,
gameType,
"组件内容",
moduleType,
entity.name,
sequence,
gameStatus = gameStatus
)
GameDetailScrollableTextDialogFragment.show(
context,
viewModel.game?.id ?: "",
viewModel.game?.name ?: "",
"游戏信息",
entity.des
)
}
awardScrollView.goneIf(entity.awardData.isEmpty()) {
bindAwards(entity.awardData)
}
}
}
private fun bindGamesTags(gameTags: List<GameBrief.GameTag>) {
if (binding.tagContainer.isEmpty()) {
gameTags.forEachIndexed { index, gameTag ->
val tagBinding = ItemGameDetailBriefTagBinding.inflate(context.layoutInflater)
tagBinding.root.text = gameTag.name
tagBinding.root.setOnClickListener {
SensorsBridge.trackGameDetailModuleClick(
gameId,
gameName,
gameType,
"组件内容",
moduleType,
itemData?.linkGameBrief?.name,
sequence,
gameStatus = gameStatus
)
context.startActivity(
TagsActivity.getIntent(
context,
gameTag.name,
gameTag.name,
"游戏详情-游戏简介",
""
)
)
}
binding.tagContainer.addView(
tagBinding.root,
LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, 24F.dip2px()).apply {
leftMargin = if (index == 0) 0 else 4F.dip2px()
})
}
} else {
binding.tagContainer.forEach {
(it as? TextView)?.run {
setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
background = com.gh.gamecenter.common.R.drawable.bg_shape_ui_container_1_stroke_radius_6.toDrawable(context)
}
}
}
}
private fun bindAwards(awardList: List<GameBrief.AwardData>) {
if (binding.awardContainer.isEmpty()) {
awardList.forEachIndexed { index, awardData ->
val awardBinding = ItemGameDetailBriefAwardBinding.inflate(context.layoutInflater)
awardBinding.iconIv.display(awardData.icon)
awardBinding.nameTv.text = awardData.award
awardBinding.typeTv.text = awardData.awardType
awardBinding.root.setOnClickListener {
awardData.link?.let { link -> DirectUtils.directToLinkPage(context, link, "游戏详情-游戏简介", "") }
}
binding.awardContainer.addView(
awardBinding.root,
LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, 26F.dip2px()).apply {
leftMargin = if (index == 0) 0 else 24F.dip2px()
})
}
} else {
binding.awardContainer.forEach {
it.findViewById<TextView>(R.id.nameTv)?.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
it.findViewById<TextView>(R.id.typeTv)?.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
}
}
}
}

View File

@ -0,0 +1,403 @@
package com.gh.gamecenter.gamedetail.detail.viewholder
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import android.widget.LinearLayout
import android.widget.PopupWindow
import android.widget.TextView
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.*
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.SpanBuilder
import com.gh.gamecenter.databinding.ItemGameDetailRecyclerViewBinding
import com.gh.gamecenter.databinding.SubItemGameDetailCommentBinding
import com.gh.gamecenter.entity.RatingComment
import com.gh.gamecenter.feature.view.DownloadButton
import com.gh.gamecenter.gamedetail.GameDetailViewModel
import com.gh.gamecenter.gamedetail.entity.GameDetailData
import com.gh.gamecenter.gamedetail.entity.GameDetailTabEntity
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity
import com.gh.gamecenter.gamedetail.rating.logs.CommentLogsActivity
import com.gh.gamecenter.login.user.UserManager
import java.util.regex.Pattern
class GameDetailCommentItemViewHolder(
val binding: ItemGameDetailRecyclerViewBinding,
downloadBtn: DownloadButton,
viewModel: GameDetailViewModel
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
override fun bindView(data: GameDetailData) {
super.bindView(data)
val entity = data.linkComment ?: return
binding.run {
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
moreTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
moreTv.setDrawableEnd(com.gh.gamecenter.common.R.drawable.ic_auxiliary_arrow_right_12.toDrawable(context)?.apply {
colorFilter = PorterDuffColorFilter(com.gh.gamecenter.common.R.color.text_theme.toColor(context), PorterDuff.Mode.SRC_ATOP)
})
titleTv.text = entity.name
moreTv.isVisible = true
moreTv.text = "更多"
moreTv.setOnClickListener {
viewModel.performTabSelected(GameDetailTabEntity.TYPE_COMMENT)
SensorsBridge.trackGameDetailModuleClick(
gameId,
gameName,
gameType,
"右上角",
moduleType,
entity.name,
sequence,
gameStatus = gameStatus
)
}
if (recyclerView.adapter !is CommentItemAdapter) {
(recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
recyclerView.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
recyclerView.adapter = CommentItemAdapter(entity.data)
} else {
recyclerView.adapter?.run { notifyItemRangeChanged(0, itemCount) }
}
}
}
inner class CommentItemAdapter(val dataList: ArrayList<RatingComment>) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val path = "游戏详情-玩家评论"
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
CommentItemViewHolder(parent.toBinding())
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val commentData = dataList.getOrNull(position) ?: return
var isChildLongClick = false
if (holder is CommentItemViewHolder) {
holder.binding.run {
root.background = R.drawable.bg_shape_f8_radius_8.toDrawable(context)
root.updateLayoutParams<MarginLayoutParams> {
leftMargin = if (position == 0) 16F.dip2px() else 8F.dip2px()
rightMargin = if (position == itemCount - 1) 16F.dip2px() else 0
}
userNameTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
tvBadgeName.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
commentTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
ipRegionTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
expandTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
moreIv.setImageResource(R.drawable.game_comment_more)
userIcon.display(commentData.user.border, commentData.user.icon, commentData.user.auth?.icon)
userNameTv.text = commentData.user.name
ratingStar.rating = commentData.star.toFloat()
if (commentData.user.badge != null) {
sdvUserBadge.visibility = View.VISIBLE
tvBadgeName.visibility = View.VISIBLE
ImageUtils.display(sdvUserBadge, commentData.user.badge?.icon)
tvBadgeName.text = commentData.user.badge?.name
} else {
sdvUserBadge.visibility = View.GONE
tvBadgeName.visibility = View.GONE
}
val p = Pattern.compile(RatingEditActivity.LABEL_REGEX)
val m = p.matcher(commentData.content)
if (m.find()) {
val contents =
TextHelper.getCommentLabelSpannableStringBuilder(commentData.content, com.gh.gamecenter.common.R.color.text_theme)
commentTv.setTextWithHighlightedTextWrappedInsideWrapper(
text = contents,
highlightedTextClickListener = TextHelper.DirectToWebViewHighlightedTextClick(
context,
"游戏详情-玩家评论"
)
)
} else {
commentTv.setTextWithHighlightedTextWrappedInsideWrapper(
text = commentData.content,
highlightedTextClickListener = TextHelper.DirectToWebViewHighlightedTextClick(
context,
"游戏详情-玩家评论"
)
)
}
commentTv.post {
expandTv.isVisible = commentTv.lineCount == 5 && commentTv.layout.getEllipsisCount(4) > 0
}
ipRegionTv.goneIf(!(commentData.source != null && commentData.source.region.isNotEmpty()))
ipRegionTv.text = " · ${commentData.source?.region}"
when {
commentData.isEditContent == null -> {
timeTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
timeTv.text = if (commentData.ignore) {
val s = "${NewsUtils.getFormattedTime(commentData.time)} 保护期评论不计入总分"
SpanBuilder(s).image(s.length - 12, s.length - 11, R.drawable.ic_ignore_rating_tips)
.color(context, s.length - 10, s.length, com.gh.gamecenter.common.R.color.text_secondary).build()
} else {
NewsUtils.getFormattedTime(commentData.time)
}
}
commentData.isEditContent!! -> {
timeTv.setTextColor(com.gh.gamecenter.common.R.color.text_F56614.toColor(context))
timeTv.text = if (commentData.ignore) {
"${NewsUtils.getFormattedTime(commentData.time)} 保护期间修改评论 >"
} else {
"${NewsUtils.getFormattedTime(commentData.time)} 已修改 >"
}
}
else -> {
timeTv.setTextColor(com.gh.gamecenter.common.R.color.text_F56614.toColor(context))
timeTv.text = if (commentData.ignore) {
"${NewsUtils.getFormattedTime(commentData.time)} 保护期间修改评论"
} else {
"${NewsUtils.getFormattedTime(commentData.time)} 已修改"
}
}
}
sdvUserBadge.setOnClickListener {
DialogUtils.showViewBadgeDialog(context, commentData.user.badge) {
DirectUtils.directToBadgeWall(
context,
commentData.user.id,
commentData.user.name,
commentData.user.icon
)
}
SensorsBridge.trackGameDetailModuleClick(
gameId,
gameName,
gameType,
"组件内容",
moduleType,
itemData?.linkComment?.name,
sequence,
subModuleName = "玩家评论列表",
supSequence = position + 1,
gameStatus = gameStatus
)
}
userIcon.setOnClickListener {
DirectUtils.directToHomeActivity(
context,
commentData.user.id,
viewModel.entrance,
path
)
NewLogUtils.logGameDetailCommentClick(
viewModel.game?.name ?: "",
viewModel.game?.id ?: "",
"个人主页"
)
SensorsBridge.trackGameDetailModuleClick(
gameId,
gameName,
gameType,
"组件内容",
moduleType,
itemData?.linkComment?.name,
sequence,
subModuleName = "玩家评论列表",
supSequence = position + 1,
gameStatus = gameStatus
)
}
userNameTv.setOnClickListener {
userIcon.performClick()
}
tvBadgeName.setOnClickListener { sdvUserBadge.performClick() }
commentTv.setOnLongClickListener(View.OnLongClickListener {
isChildLongClick = true
commentData.content.replace(RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), "")
.copyTextAndToast()
return@OnLongClickListener true
})
moreIv.setOnClickListener {
showMorePopWindow(it, commentData.user.id == UserManager.getInstance().userId) { text ->
when (text) {
"复制" -> {
commentData.content.replace(RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), "")
.copyTextAndToast()
}
"修改" -> {
val intent =
RatingEditActivity.getPatchIntent(context, viewModel.game!!, commentData)
SyncDataBetweenPageHelper.startActivityForResult(
context,
intent,
RATING_PATCH_REQUEST,
position
)
}
"投诉" -> {
context.ifLogin(BaseActivity.mergeEntranceAndPath(viewModel.entrance, path)) {
DialogUtils.showReportReasonDialog(
context,
Constants.REPORT_LIST.toList() as java.util.ArrayList<String>
) { reason, desc ->
SimpleRequestHelper.reportGameComment(
viewModel.game?.id ?: "",
commentData.id,
if (reason != "其他原因") reason else desc
)
}
}
}
"删除" -> {
DialogHelper.showDeleteGameCommentDialog(
context,
R.string.delete_game_comment.toResString()
) {
SimpleRequestHelper.deleteGameComment(
viewModel.game?.id ?: "",
commentData.id
) {
// 删除列表中的评论(如果当前列表有的话)
val index = dataList.indexOfFirst { item ->
item.id == commentData.id
}
if (index != -1) {
dataList.removeAt(index)
notifyItemRemoved(index)
}
}
}
}
}
}
}
timeTv.setOnClickListener {
SensorsBridge.trackGameDetailModuleClick(
gameId,
gameName,
gameType,
"组件内容",
moduleType,
itemData?.linkComment?.name,
sequence,
subModuleName = "玩家评论列表",
supSequence = position + 1,
gameStatus = gameStatus
)
if (commentData.isEditContent == null && commentData.ignore) {
DialogUtils.showStopServerExplanationDialog(
context,
if (viewModel.game?.commentDescription?.isNotEmpty() == true)
viewModel.game?.commentDescription else context.getString(R.string.rating_protection),
viewModel.game?.name
?: ""
)
} else if (commentData.isEditContent == true) {
val intent = CommentLogsActivity.getIntent(context, viewModel.game!!.id, commentData.id)
context.startActivity(intent)
}
}
expandTv.setOnClickListener { root.performClick() }
root.setOnClickListener {
if (isChildLongClick) {
isChildLongClick = false
return@setOnClickListener
}
val exposureSource = arrayListOf(
ExposureSource("游戏详情"),
ExposureSource("详情tab"),
ExposureSource("玩家评价"),
).toJson()
val intent = RatingReplyActivity.getIntent(
context = context,
gameId = viewModel.game?.id ?: "",
commentId = commentData.id,
exposureSource = exposureSource,
entrance = viewModel.entrance ?: "",
path = path
)
SyncDataBetweenPageHelper.startActivityForResult(
context,
intent,
RATING_REPLY_REQUEST,
position
)
NewLogUtils.logGameDetailCommentClick(
viewModel.game?.name ?: "",
viewModel.game?.id ?: "",
"评论内容"
)
SensorsBridge.trackGameDetailModuleClick(
gameId,
gameName,
gameType,
"组件内容",
moduleType,
itemData?.linkComment?.name,
sequence,
subModuleName = "玩家评论列表",
supSequence = position + 1,
gameStatus = gameStatus
)
}
}
}
}
private fun showMorePopWindow(v: View, isMyRating: Boolean, clickListener: (String) -> Unit) {
val contentList = if (isMyRating) arrayListOf("复制", "修改", "删除")
else arrayListOf("复制", "投诉")
val inflater = LayoutInflater.from(v.context)
val layout = inflater.inflate(com.gh.gamecenter.common.R.layout.layout_popup_container, null)
val popupWindow = PopupWindow(
layout,
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
popupWindow.apply {
setBackgroundDrawable(ColorDrawable(0))
isTouchable = true
isFocusable = true
isOutsideTouchable = true
}
val container = layout.findViewById<LinearLayout>(R.id.container)
for (text in contentList) {
val item = inflater.inflate(R.layout.layout_popup_option_item, container, false)
container.addView(item)
val hitText = item.findViewById<TextView>(R.id.hint_text)
hitText.text = text
item.setOnClickListener {
clickListener.invoke(text)
popupWindow.dismiss()
}
}
popupWindow.showAutoOrientation(v)
}
override fun getItemCount(): Int = dataList.size
}
inner class CommentItemViewHolder(val binding: SubItemGameDetailCommentBinding) :
RecyclerView.ViewHolder(binding.root)
companion object {
const val RATING_REPLY_REQUEST = 233
const val RATING_PATCH_REQUEST = 234
}
}

Some files were not shown because too many files have changed in this diff Show More