Compare commits
83 Commits
chen/accel
...
feat/apk_m
| Author | SHA1 | Date | |
|---|---|---|---|
| cef4526b35 | |||
| 0e9301f4dc | |||
| 8436b2e3aa | |||
| c57af24811 | |||
| 8a6d476636 | |||
| 17b34c9e6f | |||
| 69241c489b | |||
| 97b3efc968 | |||
| 288f7370aa | |||
| f9db7068f2 | |||
| b4390f2811 | |||
| dbc2be5bc6 | |||
| dec2c35ff4 | |||
| 77514aa2a9 | |||
| 40cdda7bae | |||
| 4917b1d4ff | |||
| d646e971f7 | |||
| af9ba8a4d0 | |||
| 738dfd3b4d | |||
| 0f0962b261 | |||
| ffa61e8b96 | |||
| b460750f5a | |||
| 528d7511f9 | |||
| 02523b9e33 | |||
| bfc4083544 | |||
| 18e14d3811 | |||
| 89901028ea | |||
| 20c3f5cf46 | |||
| 9bc155816a | |||
| 92366c5629 | |||
| a1fd894dde | |||
| 03757b22c7 | |||
| ce10d82a8f | |||
| 74a4feee9e | |||
| 9cb0736e30 | |||
| b954df3267 | |||
| 0607a37256 | |||
| 00e4c7f1bd | |||
| 7d94250914 | |||
| 7b8634aa40 | |||
| 210e18eb34 | |||
| 957eff3c1e | |||
| 72b953b7c8 | |||
| 53fb77d2dc | |||
| f78e7a10a6 | |||
| 6aebea14bc | |||
| fd0fc31fc3 | |||
| 889558eb4b | |||
| 37ec9ae66c | |||
| f4d34a635a | |||
| 024895838c | |||
| 740bdbf79a | |||
| 73f7bee3cc | |||
| b37f247b14 | |||
| 811378f411 | |||
| f910cb67da | |||
| 4f2874877c | |||
| 15b35fd6b7 | |||
| cd64bb79a2 | |||
| d57c03b1f8 | |||
| 1895977d4c | |||
| 08571998b6 | |||
| 21cdadca13 | |||
| 54dfa46204 | |||
| c9f14641c9 | |||
| 0e95c0cbf6 | |||
| 2a93af56ee | |||
| 28e785745b | |||
| 317620daf4 | |||
| bf95a00bc6 | |||
| cb05c8a020 | |||
| d458898eb1 | |||
| f4f422b089 | |||
| e48b11f19d | |||
| b6fe834406 | |||
| d0bf23ae48 | |||
| 8b1f35516d | |||
| b2fde1e0af | |||
| ab1350ff46 | |||
| 7f991e29d4 | |||
| 40edf76aed | |||
| aaeb83c5df | |||
| 5739f0a800 |
@ -72,8 +72,6 @@ android_build:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-6976
|
||||
- feat/GHZSCY-6976-log
|
||||
|
||||
# 代码检查
|
||||
sonarqube_analysis:
|
||||
@ -105,8 +103,6 @@ sonarqube_analysis:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-6976
|
||||
- feat/GHZSCY-6976-log
|
||||
|
||||
## 发送简易检测结果报告
|
||||
send_sonar_report:
|
||||
@ -125,8 +121,6 @@ send_sonar_report:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-6976
|
||||
- feat/GHZSCY-6976-log
|
||||
|
||||
oss-upload&send-email:
|
||||
tags:
|
||||
@ -163,5 +157,3 @@ oss-upload&send-email:
|
||||
only:
|
||||
- dev
|
||||
- release
|
||||
- feat/GHZSCY-6976
|
||||
- feat/GHZSCY-6976-log
|
||||
|
||||
@ -346,7 +346,7 @@ repositories {
|
||||
android.applicationVariants.configureEach { variant ->
|
||||
variant.mergeAssets.doLast {
|
||||
def assetDir = variant.mergeAssetsProvider.get().outputDir.get()
|
||||
def unwantedAssets = ['2011394667', 'gdt_plugin/gdtadv2.jar']
|
||||
def unwantedAssets = ['1832823466', 'gdt_plugin/gdtadv2.jar']
|
||||
|
||||
unwantedAssets.each { assetPath ->
|
||||
def file = new File([assetDir, assetPath].join(File.separator))
|
||||
@ -515,6 +515,7 @@ dependencies {
|
||||
}
|
||||
|
||||
implementation(project(':feature:media_select'))
|
||||
implementation(project(':feature:apk_manager'))
|
||||
|
||||
implementation(project(":module_va_api"))
|
||||
implementation(project(":va-archive-common"))
|
||||
|
||||
@ -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
|
||||
|
||||
@ -83,29 +83,9 @@
|
||||
tv.danmaku.ijk.media.exo2,
|
||||
pl.droidsonroids.gif,
|
||||
com.lzf.easyfloat,
|
||||
com.airbnb.lottie.compose,
|
||||
androidx.compose.ui.platform,
|
||||
androidx.compose.material.icons,
|
||||
androidx.activity.compose,
|
||||
androidx.compose.ui.tooling,
|
||||
androidx.compose.ui.tooling.data,
|
||||
androidx.compose.material.ripple,
|
||||
androidx.compose.foundation,
|
||||
androidx.compose.animation,
|
||||
androidx.compose.foundation.layout,
|
||||
androidx.compose.ui.text,
|
||||
androidx.compose.ui.graphics,
|
||||
androidx.compose.ui.unit,
|
||||
androidx.compose.ui.util,
|
||||
androidx.compose.ui.geometry,
|
||||
androidx.compose.runtime.saveable,
|
||||
androidx.compose.animation.core,
|
||||
androidx.constraintlayout.compose,
|
||||
androidx.compose.ui.test.manifest,
|
||||
com.bytedance.sdk.openadsdk,
|
||||
com.bykv.vk.openvk,
|
||||
com.bytedance.tools,
|
||||
androidx.compose.ui.tooling.preview,
|
||||
com.tencent.qqmini,
|
||||
com.tencent.qqmini.minigame.external,
|
||||
com.tencent.qqmini.minigame.opensdk,
|
||||
@ -817,11 +797,7 @@
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name="com.halo.assistant.member.MemberActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<activity
|
||||
android:name=".BatchRegisterActivity"
|
||||
android:name="com.halo.assistant.accelerator.MyAssetsActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
||||
<!-- <activity-->
|
||||
|
||||
@ -27,8 +27,8 @@ import com.gh.gamecenter.MainActivity
|
||||
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.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.exposure.meta.MetaUtil
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
@ -178,6 +178,15 @@ object AdDelegateHelper {
|
||||
when (config.location) {
|
||||
"halo_launch" -> {
|
||||
config.ownerAd?.startAd?.let { it.id = config.ownerAd.id }
|
||||
|
||||
// HarmonyOS 2.2.0 版本不展示第三方开屏广告 (因为会引起奇怪的闪退)
|
||||
if (MetaUtil.getRom().name == "HarmonyOS"
|
||||
&& MetaUtil.getRom().versionName == "2.2.0"
|
||||
&& config.displayRule.adSource == "third_party_ads") {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
mSplashAd = config
|
||||
}
|
||||
|
||||
|
||||
@ -19,10 +19,10 @@ import java.net.URLConnection
|
||||
|
||||
object AdPluginDownloadHelper : InnerDownloadListener {
|
||||
|
||||
private const val CSJ_FILE_NAME = "2011394667"
|
||||
private const val CSJ_FILE_NAME = "1832823466"
|
||||
private const val GDT_FILE_NAME = "gdt_plugin/gdtadv2.jar"
|
||||
|
||||
private const val CSJ_PLUGIN_URL = "https://and-static.ghzs66.com/android/static/2011394667"
|
||||
private const val CSJ_PLUGIN_URL = "https://and-static.ghzs66.com/android/static/1832823466"
|
||||
private const val GDT_PLUGIN_URL = "https://and-static.ghzs66.com/android/static/gdtadv2.jar"
|
||||
|
||||
private var csjDownloadedCallback: (() -> Unit)? = null
|
||||
|
||||
@ -2,9 +2,9 @@ package com.gh.base
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.therouter.TheRouter
|
||||
import com.gh.ad.AdDelegateHelper
|
||||
import com.gh.common.util.FloatingBackViewManager
|
||||
import com.gh.common.xapk.XapkInstaller
|
||||
@ -15,27 +15,45 @@ import com.gh.gamecenter.SplashAdActivity
|
||||
import com.gh.gamecenter.SplashScreenActivity
|
||||
import com.gh.gamecenter.authorization.AuthorizationActivity
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager
|
||||
import com.gh.gamecenter.common.constant.RouteConsts
|
||||
import com.gh.gamecenter.common.provider.IHelpAndFeedbackProvider
|
||||
import com.gh.gamecenter.common.utils.PackageFlavorHelper
|
||||
import com.gh.gamecenter.core.provider.IPushProvider
|
||||
import com.gh.gamecenter.login.utils.QuickLoginHelper
|
||||
import com.gh.gamecenter.login.view.LoginActivity
|
||||
import com.gh.gamecenter.va.VCore
|
||||
import com.gh.gamecenter.login.utils.QuickLoginHelper
|
||||
import com.gh.vspace.VHelper
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.therouter.TheRouter
|
||||
|
||||
// TODO:移动到对应的模块
|
||||
class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
|
||||
private var isFromBackgroundToForeground = false // 是否后台回到前台
|
||||
|
||||
override fun onActivityPreCreated(activity: Activity, savedInstanceState: Bundle?) {
|
||||
if (QuickLoginHelper.isLoginAuthPage(activity)) {
|
||||
try {
|
||||
val resources = activity.resources
|
||||
val config = Configuration(resources.configuration)
|
||||
config.fontScale = 1.0f
|
||||
|
||||
// 更新Resources配置
|
||||
val metrics = resources.displayMetrics
|
||||
metrics.scaledDensity = metrics.density
|
||||
resources.updateConfiguration(config, metrics)
|
||||
|
||||
} catch (e: Exception) {
|
||||
// 设置字体失败
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
override fun onActivityStarted(activity: Activity) {
|
||||
GlobalActivityManager.currentActivity = activity
|
||||
GlobalActivityManager.activityCount ++
|
||||
GlobalActivityManager.activityCount++
|
||||
if (GlobalActivityManager.activityCount == 1 && isFromBackgroundToForeground) {
|
||||
if (AdDelegateHelper.shouldShowStartUpAd(true)
|
||||
&& !HaloApp.getInstance().isDisableSplashAdTemporarily
|
||||
@ -111,7 +129,7 @@ class GlobalActivityLifecycleObserver : Application.ActivityLifecycleCallbacks {
|
||||
}
|
||||
|
||||
override fun onActivityStopped(activity: Activity) {
|
||||
GlobalActivityManager.activityCount --
|
||||
GlobalActivityManager.activityCount--
|
||||
isFromBackgroundToForeground = GlobalActivityManager.activityCount <= 0
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,6 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.therouter.TheRouter
|
||||
import com.gh.common.exposure.ExposureManager
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.LogUtils
|
||||
@ -36,7 +35,6 @@ import com.gh.gamecenter.common.utils.SensorsBridge.EVENT_NAME
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge.KEY_IS_FIRST_TIME
|
||||
import com.gh.gamecenter.common.view.dsbridge.CompletionHandler
|
||||
import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.core.provider.IAcceleratorProvider
|
||||
import com.gh.gamecenter.core.provider.IPushProvider
|
||||
import com.gh.gamecenter.core.runOnIoThread
|
||||
import com.gh.gamecenter.core.runOnUiThread
|
||||
@ -59,13 +57,14 @@ import com.gh.gamecenter.personalhome.border.AvatarBorderActivity
|
||||
import com.gh.gamecenter.setting.SettingBridge
|
||||
import com.gh.vspace.VHelper
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.halo.assistant.member.MemberRepository
|
||||
import com.halo.assistant.member.MemberRepository.Companion.PAYMENT_TYPE_ALIPAY
|
||||
import com.halo.assistant.member.MemberRepository.Companion.PAYMENT_TYPE_WECHAT
|
||||
import com.halo.assistant.accelerator.repository.AccelerationRepository.Companion.PAYMENT_TYPE_ALIPAY
|
||||
import com.halo.assistant.accelerator.repository.AccelerationRepository.Companion.PAYMENT_TYPE_WECHAT
|
||||
import com.halo.assistant.accelerator.repository.AcceleratorDataHolder
|
||||
import com.lightgame.download.DataWatcher
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.download.DownloadStatus.*
|
||||
import com.lightgame.utils.Utils
|
||||
import com.therouter.TheRouter
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
@ -743,13 +742,7 @@ class DefaultJsApi(
|
||||
|
||||
@JavascriptInterface
|
||||
fun getCurAcctGameId(): String {
|
||||
val isSpeeding = TheRouter.get(IAcceleratorProvider::class.java)?.isCurAccSuccess() ?: false
|
||||
val gameId = if (isSpeeding) {
|
||||
MemberRepository.instance.acctGameRecord.gameId
|
||||
} else {
|
||||
""
|
||||
}
|
||||
return gameId
|
||||
return AcceleratorDataHolder.instance.getAcceleratingGameId()
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
|
||||
@ -201,7 +201,8 @@ public class BindingAdapters {
|
||||
gameEntity,
|
||||
traceEvent,
|
||||
entrance,
|
||||
location + ":" + gameEntity.getName());
|
||||
location + ":" + gameEntity.getName(),
|
||||
null);
|
||||
return null;
|
||||
});
|
||||
final DownloadChainHandler chainHandler = builder.buildHandlerChain();
|
||||
@ -246,7 +247,8 @@ public class BindingAdapters {
|
||||
gameEntity,
|
||||
traceEvent,
|
||||
entrance,
|
||||
location + ":" + gameEntity.getName());
|
||||
location + ":" + gameEntity.getName(),
|
||||
null);
|
||||
}
|
||||
break;
|
||||
case INSTALL_PLUGIN:
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
package com.gh.common.provider
|
||||
|
||||
import com.gh.gamecenter.core.provider.IAcceleratorDataHolderProvider
|
||||
import com.gh.gamecenter.feature.entity.VipEntity
|
||||
import com.halo.assistant.accelerator.repository.AcceleratorDataHolder
|
||||
|
||||
@com.therouter.inject.ServiceProvider
|
||||
class IAcceleratorDataHolderProviderImpl : IAcceleratorDataHolderProvider {
|
||||
override fun setVipEntity(vip: Any) {
|
||||
if (vip is VipEntity) {
|
||||
AcceleratorDataHolder.instance.setVipEntity(vip)
|
||||
}
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
AcceleratorDataHolder.instance.clear()
|
||||
}
|
||||
}
|
||||
@ -7,9 +7,6 @@ import com.gh.gamecenter.feature.provider.IRegionSettingHelperProvider
|
||||
|
||||
@com.therouter.inject.ServiceProvider
|
||||
class RegionSettingHelperProviderImpl : IRegionSettingHelperProvider {
|
||||
override fun shouldThisGameDisplayMirrorInfo(gameId: String): Boolean {
|
||||
return RegionSettingHelper.shouldThisGameDisplayMirrorInfo(gameId)
|
||||
}
|
||||
|
||||
override fun getMirrorPosition(gameId: String): Int {
|
||||
return RegionSettingHelper.getMirrorPosition(gameId)
|
||||
|
||||
@ -3,21 +3,18 @@ package com.gh.common.provider
|
||||
import android.annotation.SuppressLint
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.core.provider.IAcceleratorProvider
|
||||
import com.gh.gamecenter.core.provider.IWechatPayResultProvider
|
||||
import com.gh.gamecenter.feature.entity.OrderEntity
|
||||
import com.gh.gamecenter.feature.entity.VipEntity
|
||||
import com.gh.gamecenter.feature.eventbus.EBPayState
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.login.user.UserRepository
|
||||
import com.halo.assistant.member.MemberRepository
|
||||
import com.therouter.TheRouter
|
||||
import com.halo.assistant.accelerator.repository.AccelerationRepository
|
||||
import com.halo.assistant.accelerator.repository.AcceleratorDataHolder
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
@com.therouter.inject.ServiceProvider
|
||||
class WechatPayResultProviderImpl : IWechatPayResultProvider {
|
||||
|
||||
private val repository = MemberRepository.instance
|
||||
private val repository = AccelerationRepository.newInstance()
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
override fun onPayComplete(nonceStr: String, order: Any?) {
|
||||
@ -29,32 +26,28 @@ class WechatPayResultProviderImpl : IWechatPayResultProvider {
|
||||
EventBus.getDefault().post(EBPayState.PaySuccess)
|
||||
|
||||
// 先刷新本地状态,支付成功,肯定是付费会员
|
||||
TheRouter.get(IAcceleratorProvider::class.java)?.setVipEntity(
|
||||
AcceleratorDataHolder.instance.setVipEntity(
|
||||
VipEntity(
|
||||
_vipStatus = true,
|
||||
_isNewUser = false,
|
||||
_isTryVip = false
|
||||
)
|
||||
)
|
||||
val userId = UserManager.getInstance().userId
|
||||
if (userId.isNotBlank()) {
|
||||
UserRepository.getInstance().refreshVipStatus(userId, true)
|
||||
}
|
||||
|
||||
SensorsBridge.trackMemberRechargeResult(
|
||||
MemberRepository.PAYMENT_TYPE_WECHAT,
|
||||
AccelerationRepository.PAYMENT_TYPE_WECHAT,
|
||||
orderEntity?.setMenuName ?: "",
|
||||
orderEntity?.paymentAmount ?: "",
|
||||
MemberRepository.RECHARGE_RESULT_SUCCESS
|
||||
AccelerationRepository.RECHARGE_RESULT_SUCCESS
|
||||
)
|
||||
}, {
|
||||
// 支付失败
|
||||
EventBus.getDefault().post(EBPayState.PayFail)
|
||||
SensorsBridge.trackMemberRechargeResult(
|
||||
MemberRepository.PAYMENT_TYPE_WECHAT,
|
||||
AccelerationRepository.PAYMENT_TYPE_WECHAT,
|
||||
orderEntity?.setMenuName ?: "",
|
||||
orderEntity?.paymentAmount ?: "",
|
||||
MemberRepository.RECHARGE_RESULT_FAILURE
|
||||
AccelerationRepository.RECHARGE_RESULT_FAILURE
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@ -13,7 +13,6 @@ import com.therouter.TheRouter;
|
||||
import com.gh.ad.AdDelegateHelper;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
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;
|
||||
@ -150,6 +149,7 @@ public class DataUtils {
|
||||
/**
|
||||
* 获取应用 gid 绑定的实名信息
|
||||
*/
|
||||
// TODO 这个方法启动时会被调用多次,后面考虑优化优化
|
||||
@SuppressLint("CheckResult")
|
||||
public static void getDeviceCertification(String gid) {
|
||||
RetrofitManager.getInstance()
|
||||
|
||||
@ -5,8 +5,6 @@ import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import com.gh.common.filter.RegionSetting;
|
||||
import com.gh.common.filter.RegionSettingHelper;
|
||||
import com.gh.common.repository.ReservationRepository;
|
||||
@ -55,9 +53,6 @@ public class DetailDownloadUtils {
|
||||
if (viewHolder.getMultiVersionDownloadTv() != null) {
|
||||
viewHolder.getMultiVersionDownloadTv().setVisibility(View.GONE);
|
||||
}
|
||||
if (viewHolder.getSpeedContainer() != null) {
|
||||
viewHolder.getSpeedContainer().setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
viewHolder.setSpeedViewsVisible(false);
|
||||
|
||||
@ -143,6 +138,12 @@ public class DetailDownloadUtils {
|
||||
showDualDownloadButton,
|
||||
downloadEntity
|
||||
);
|
||||
|
||||
if(!showVGame){
|
||||
String rawBtnText = GameUtils.getDownloadBtnText(viewHolder.getContext(), gameEntity, false, showVGame, PluginLocation.only_game);
|
||||
viewHolder.checkIfShowSpeedUi(rawBtnText);
|
||||
}
|
||||
|
||||
} else {
|
||||
// 游戏包含多 APK 的情况
|
||||
viewHolder.getMultiVersionDownloadTv().setText("选择下载你的版本" + (TextUtils.isEmpty(downloadAddWord) ? "" : "-" + downloadAddWord));
|
||||
@ -254,30 +255,22 @@ public class DetailDownloadUtils {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
boolean isLaunchState = false;
|
||||
// 非畅玩,显示为普通游戏
|
||||
if (context.getString(com.gh.gamecenter.feature.R.string.pluggable).equals(rawBtnText)) {
|
||||
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.PLUGIN);
|
||||
} else if (context.getString(com.gh.gamecenter.feature.R.string.launch).equals(rawBtnText)) {
|
||||
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.LAUNCH_OR_OPEN);
|
||||
isLaunchState = true;
|
||||
} else if (context.getString(com.gh.gamecenter.feature.R.string.install).equals(rawBtnText)) {
|
||||
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.INSTALL_NORMAL);
|
||||
} else {
|
||||
downloadButton.setButtonStyle(DownloadButton.ButtonStyle.NORMAL);
|
||||
}
|
||||
// 只有下载按钮状态为 “启动” 时,才需要展示加速ui
|
||||
if (isLaunchState) {
|
||||
viewHolder.showAcceleratorGuideLayer();
|
||||
} else {
|
||||
viewHolder.hideSpeedUi();
|
||||
}
|
||||
|
||||
if (showDualDownloadButton && viewHolder.getLocalDownloadSizeTv() != null) {
|
||||
viewHolder.getLocalDownloadSizeTv().setVisibility(View.GONE);
|
||||
String size = viewHolder.getGameEntity().getApk().isEmpty() ? "" : viewHolder.getGameEntity().getApk().get(0).getSize();
|
||||
if (size != null) {
|
||||
String sizeWithoutDigit = size.replaceAll("(?<=\\d)\\.[0-9]+(?!\\d)", "");
|
||||
String sizeWithoutDigit = convertSizeString(size);
|
||||
viewHolder.getLocalDownloadSizeTv().setText(sizeWithoutDigit);
|
||||
}
|
||||
|
||||
@ -617,6 +610,30 @@ public class DetailDownloadUtils {
|
||||
return (int) Math.ceil(downloadEntity.getPercent());
|
||||
}
|
||||
|
||||
private static String convertSizeString(String sizeString) {
|
||||
String numberPart;
|
||||
String indicator;
|
||||
|
||||
// Check if the string ends with "MB"
|
||||
if (sizeString.endsWith("MB")) {
|
||||
numberPart = sizeString.substring(0, sizeString.length() - 2);
|
||||
indicator = "MB";
|
||||
} else if (sizeString.endsWith("G")) {
|
||||
numberPart = sizeString.substring(0, sizeString.length() - 1);
|
||||
indicator = "G";
|
||||
} else {
|
||||
return sizeString;
|
||||
}
|
||||
|
||||
// Round number
|
||||
double number = Double.parseDouble(numberPart);
|
||||
long roundedNumber = Math.round(number);
|
||||
|
||||
// Combine rounded number and size indicator
|
||||
return roundedNumber + indicator;
|
||||
}
|
||||
|
||||
|
||||
private static boolean handleDownloadButtonAsXapk(DownloadEntity downloadEntity, DownloadButton downloadButton) {
|
||||
String xapkStatus = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_STATUS);
|
||||
|
||||
|
||||
@ -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,6 +56,7 @@ 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.ServersSubscribedGameListActivity
|
||||
import com.gh.gamecenter.gamedetail.history.HistoryApkListActivity
|
||||
@ -193,6 +195,8 @@ object DirectUtils {
|
||||
"simulator",
|
||||
"teen_mode",
|
||||
"message_center",
|
||||
"archive",
|
||||
"my_assets",
|
||||
)
|
||||
|
||||
fun directToLinkPage(
|
||||
@ -613,6 +617,10 @@ object DirectUtils {
|
||||
|
||||
"message_center" -> directToMessageCenter(0, entrance)
|
||||
|
||||
"archive" -> directToCloudArchive(context, linkEntity.link ?: "", linkEntity.text ?: "", "", entrance)
|
||||
|
||||
"my_assets" -> navigateToMyAssetsPage(context, entrance)
|
||||
|
||||
"" -> {
|
||||
// do nothing
|
||||
}
|
||||
@ -849,30 +857,37 @@ object DirectUtils {
|
||||
traceEvent: ExposureEvent? = null
|
||||
) {
|
||||
if (id.isEmpty()) return
|
||||
val bundle = Bundle()
|
||||
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
|
||||
bundle.putString(KEY_TO, GameDetailActivity::class.java.simpleName)
|
||||
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)
|
||||
|
||||
val uri = Uri.Builder()
|
||||
.path(RouteConsts.activity.gameDetailActivity)
|
||||
.appendQueryParameter(KEY_ENTRANCE, entrance)
|
||||
.appendQueryParameter(KEY_GAME_ID, id)
|
||||
.build()
|
||||
|
||||
TheRouter
|
||||
.build(uri.toString())
|
||||
.fillParams { bundle ->
|
||||
if (!TextUtils.isEmpty(tab)) {
|
||||
when (tab) {
|
||||
"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) {
|
||||
val clickEvent = createEvent(
|
||||
GameEntity(id = id, name = name),
|
||||
traceEvent.source,
|
||||
appendTrace(traceEvent),
|
||||
ExposureType.CLICK
|
||||
)
|
||||
log(clickEvent)
|
||||
bundle.putParcelable(KEY_TRACE_EVENT, clickEvent)
|
||||
}
|
||||
bundle.putBoolean(KEY_AUTO_DOWNLOAD, autoDownload ?: false)
|
||||
}
|
||||
}
|
||||
if (traceEvent != null) {
|
||||
val clickEvent = createEvent(
|
||||
GameEntity(id = id, name = name),
|
||||
traceEvent.source,
|
||||
appendTrace(traceEvent),
|
||||
ExposureType.CLICK
|
||||
)
|
||||
log(clickEvent)
|
||||
bundle.putParcelable(KEY_TRACE_EVENT, clickEvent)
|
||||
}
|
||||
bundle.putBoolean(KEY_AUTO_DOWNLOAD, autoDownload ?: false)
|
||||
jumpActivity(context, bundle)
|
||||
.navigation(context)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -903,7 +918,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,15 +926,21 @@ 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()
|
||||
bundle.putString(KEY_TO, GameDetailActivity::class.java.name)
|
||||
bundle.putString(KEY_ENTRANCE, entrance)
|
||||
bundle.putString(KEY_GAMEID, id)
|
||||
bundle.putString(KEY_TARGET, defaultTab)
|
||||
jumpActivity(context, bundle)
|
||||
val uri = Uri.Builder()
|
||||
.path(RouteConsts.activity.gameDetailActivity)
|
||||
.appendQueryParameter(KEY_ENTRANCE, entrance)
|
||||
.appendQueryParameter(KEY_GAME_ID, id)
|
||||
.build()
|
||||
|
||||
TheRouter
|
||||
.build(uri.toString())
|
||||
.fillParams { bundle ->
|
||||
bundle.putString(KEY_TARGET, defaultTab)
|
||||
}
|
||||
.navigation(context)
|
||||
}
|
||||
|
||||
// 专栏
|
||||
@ -1569,7 +1590,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)
|
||||
}
|
||||
@ -1682,7 +1703,7 @@ object DirectUtils {
|
||||
fun directToHelpAndFeedback(context: Context, bundle: Bundle? = null) {
|
||||
TheRouter.build(RouteConsts.activity.helpAndFeedbackActivity)
|
||||
.fillParams {
|
||||
it.putAll(bundle)
|
||||
bundle?.run { it.putAll(this) }
|
||||
}
|
||||
.navigation(context)
|
||||
}
|
||||
@ -2294,4 +2315,32 @@ object DirectUtils {
|
||||
.withBoolean(KEY_DISPLAY_TYPE, isLogoutStyle)
|
||||
.navigation()
|
||||
}
|
||||
|
||||
// 跳转云存档详情页
|
||||
@JvmStatic
|
||||
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))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun navigateToMyAssetsPage(context: Context, entrance: String?) {
|
||||
if (CheckLoginUtils.isLogin()) {
|
||||
TheRouter.build(RouteConsts.activity.myAssetsActivity).navigation(context)
|
||||
} else {
|
||||
CheckLoginUtils.checkLogin(context, entrance, null)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -176,7 +176,8 @@ object DownloadItemUtils {
|
||||
pluginLocation: PluginLocation? = PluginLocation.only_game,
|
||||
hideDownloadBtnIfNoAvailableContent: Boolean = false,
|
||||
briefStyle: String? = null,
|
||||
isShowRecommendStar: Boolean = false
|
||||
isShowRecommendStar: Boolean = false,
|
||||
listener: DownloadButton.OnUpdateListener? = null
|
||||
) {
|
||||
holder.gameDownloadBtn.putObject(gameEntity)
|
||||
|
||||
@ -189,7 +190,8 @@ object DownloadItemUtils {
|
||||
holder.gameDownloadBtn,
|
||||
gameEntity,
|
||||
hideDownloadBtnIfNoAvailableContent,
|
||||
pluginLocation
|
||||
pluginLocation,
|
||||
listener
|
||||
)
|
||||
return
|
||||
}
|
||||
@ -210,7 +212,8 @@ object DownloadItemUtils {
|
||||
holder.gameDownloadBtn,
|
||||
gameEntity,
|
||||
hideDownloadBtnIfNoAvailableContent,
|
||||
pluginLocation
|
||||
pluginLocation,
|
||||
listener
|
||||
)
|
||||
}
|
||||
|
||||
@ -219,7 +222,8 @@ object DownloadItemUtils {
|
||||
downloadBtn: DownloadButton,
|
||||
gameEntity: GameEntity,
|
||||
hideDownloadBtnIfNoAvailableContent: Boolean = false,
|
||||
pluginLocation: PluginLocation? = PluginLocation.only_game
|
||||
pluginLocation: PluginLocation? = PluginLocation.only_game,
|
||||
listener: DownloadButton.OnUpdateListener?
|
||||
) {
|
||||
// 控制是否显示下载按钮
|
||||
downloadBtn.goneIf(context.getString(R.string.app_name) == gameEntity.name)
|
||||
@ -227,6 +231,7 @@ object DownloadItemUtils {
|
||||
if (SPUtils.getBoolean(Constants.SP_TEENAGER_MODE) || gameEntity.isSpecialDownload()) {
|
||||
downloadBtn.text = "查看"
|
||||
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.TEENAGER_MODE
|
||||
listener?.completion(downloadBtn.text)
|
||||
return
|
||||
}
|
||||
if (gameEntity.isReservable) {
|
||||
@ -239,6 +244,7 @@ object DownloadItemUtils {
|
||||
buttonStyle = DownloadButton.ButtonStyle.RESERVED
|
||||
}
|
||||
}
|
||||
listener?.completion(downloadBtn.text)
|
||||
return
|
||||
}
|
||||
if (RegionSettingHelper.getGameH5DownloadByGameId(gameEntity.id) != null) {
|
||||
@ -248,6 +254,7 @@ object DownloadItemUtils {
|
||||
setBackgroundResource(com.gh.gamecenter.common.R.drawable.download_button_normal_style)
|
||||
setTextColor(com.gh.gamecenter.common.R.color.white.toColor(context))
|
||||
}
|
||||
listener?.completion(downloadBtn.text)
|
||||
return
|
||||
}
|
||||
if (gameEntity.isMiniGame()) {
|
||||
@ -265,6 +272,7 @@ object DownloadItemUtils {
|
||||
text = context.getString(com.gh.gamecenter.feature.R.string.quick_play)
|
||||
}
|
||||
}
|
||||
listener?.completion(downloadBtn.text)
|
||||
return
|
||||
}
|
||||
if (gameEntity.getApk().isEmpty() || gameEntity.downloadOffStatus != null) {
|
||||
@ -296,6 +304,7 @@ object DownloadItemUtils {
|
||||
downloadBtn.isClickable = false
|
||||
}
|
||||
}
|
||||
listener?.completion(downloadBtn.text)
|
||||
} else if (gameEntity.getApk().size == 1) {
|
||||
// 来自于下载管理的实体快照
|
||||
val entityFromDownloadManager = DownloadManager.getInstance().getDownloadEntitySnapshot(gameEntity)
|
||||
@ -354,43 +363,60 @@ object DownloadItemUtils {
|
||||
downloadBtn.apply {
|
||||
when (downloadEntity.status) {
|
||||
DownloadStatus.done -> {
|
||||
if (downloadEntity.isSimulatorGame() && gameEntity.simulator != null) {
|
||||
GameUtils.setDownloadBtnStatus(context, gameEntity, downloadBtn, pluginLocation)
|
||||
} else if (isVGamePreferred) {
|
||||
buttonStyle =
|
||||
if (PackagesManager.isCanUpdate(
|
||||
downloadEntity.gameId,
|
||||
downloadEntity.packageName,
|
||||
asVGame = true
|
||||
)
|
||||
) {
|
||||
setText(com.gh.gamecenter.feature.R.string.update)
|
||||
DownloadButton.ButtonStyle.NORMAL
|
||||
} else {
|
||||
setText(com.gh.gamecenter.feature.R.string.launch)
|
||||
DownloadButton.ButtonStyle.LAUNCH_OR_OPEN
|
||||
}
|
||||
} else {
|
||||
val xapkStatus = downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS]
|
||||
if (XapkUnzipStatus.SUCCESS.name == xapkStatus && isInstalling(downloadEntity.path)) {
|
||||
val xapkStatus = downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS]
|
||||
when {
|
||||
downloadEntity.isSimulatorGame() && gameEntity.simulator != null -> {
|
||||
GameUtils.setDownloadBtnStatus(
|
||||
context,
|
||||
gameEntity,
|
||||
downloadBtn,
|
||||
pluginLocation,
|
||||
listener
|
||||
)
|
||||
}
|
||||
|
||||
isVGamePreferred -> {
|
||||
buttonStyle =
|
||||
if (PackagesManager.isCanUpdate(
|
||||
downloadEntity.gameId,
|
||||
downloadEntity.packageName,
|
||||
asVGame = true
|
||||
)
|
||||
) {
|
||||
setText(com.gh.gamecenter.feature.R.string.update)
|
||||
DownloadButton.ButtonStyle.NORMAL
|
||||
} else {
|
||||
setText(com.gh.gamecenter.feature.R.string.launch)
|
||||
DownloadButton.ButtonStyle.LAUNCH_OR_OPEN
|
||||
}
|
||||
listener?.completion(downloadBtn.text)
|
||||
}
|
||||
|
||||
XapkUnzipStatus.SUCCESS.name == xapkStatus && isInstalling(downloadEntity.path) -> {
|
||||
progress = 100
|
||||
setText(com.gh.gamecenter.feature.R.string.installing)
|
||||
buttonStyle = DownloadButton.ButtonStyle.INSTALL_NORMAL
|
||||
listener?.completion(downloadBtn.text)
|
||||
return
|
||||
}
|
||||
if (XapkUnzipStatus.UNZIPPING.name == xapkStatus) {
|
||||
|
||||
XapkUnzipStatus.UNZIPPING.name == xapkStatus -> {
|
||||
val percent = downloadEntity.meta[XapkInstaller.XAPK_UNZIP_PERCENT]
|
||||
progress = (java.lang.Float.valueOf(percent) * 10).toInt()
|
||||
text = "$percent%"
|
||||
buttonStyle = DownloadButton.ButtonStyle.XAPK_UNZIPPING
|
||||
return
|
||||
} else if (XapkUnzipStatus.FAILURE.name == xapkStatus) {
|
||||
setText(com.gh.gamecenter.feature.R.string.install)
|
||||
buttonStyle = DownloadButton.ButtonStyle.INSTALL_NORMAL
|
||||
listener?.completion(downloadBtn.text)
|
||||
return
|
||||
}
|
||||
|
||||
if (PackagesManager.isInstalled(downloadEntity.packageName) && !downloadEntity.isUpdate) {
|
||||
XapkUnzipStatus.FAILURE.name == xapkStatus -> {
|
||||
setText(com.gh.gamecenter.feature.R.string.install)
|
||||
buttonStyle = DownloadButton.ButtonStyle.INSTALL_NORMAL
|
||||
listener?.completion(downloadBtn.text)
|
||||
return
|
||||
}
|
||||
|
||||
PackagesManager.isInstalled(downloadEntity.packageName) && !downloadEntity.isUpdate -> {
|
||||
// 双下载按钮快速安装时存在已下载的安装包过时,需要重新下载的情况
|
||||
if (PackagesManager.isCanUpdate(
|
||||
downloadEntity.gameId,
|
||||
@ -403,9 +429,13 @@ object DownloadItemUtils {
|
||||
buttonStyle = DownloadButton.ButtonStyle.LAUNCH_OR_OPEN
|
||||
setText(com.gh.gamecenter.feature.R.string.launch)
|
||||
}
|
||||
} else {
|
||||
listener?.completion(downloadBtn.text)
|
||||
}
|
||||
|
||||
else -> {
|
||||
buttonStyle = DownloadButton.ButtonStyle.INSTALL_NORMAL
|
||||
setText(com.gh.gamecenter.feature.R.string.install)
|
||||
listener?.completion(downloadBtn.text)
|
||||
}
|
||||
}
|
||||
buttonStyle =
|
||||
@ -425,22 +455,24 @@ object DownloadItemUtils {
|
||||
DownloadStatus.overflow -> {
|
||||
buttonStyle = DownloadButton.ButtonStyle.NORMAL
|
||||
setText(com.gh.gamecenter.feature.R.string.resume)
|
||||
listener?.completion(downloadBtn.text)
|
||||
}
|
||||
|
||||
DownloadStatus.cancel -> {
|
||||
GameUtils.setDownloadBtnStatus(context, gameEntity, downloadBtn, pluginLocation)
|
||||
GameUtils.setDownloadBtnStatus(context, gameEntity, downloadBtn, pluginLocation, listener)
|
||||
}
|
||||
|
||||
else -> {
|
||||
// do nothing
|
||||
listener?.completion(downloadBtn.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GameUtils.setDownloadBtnStatus(context, gameEntity, downloadBtn, pluginLocation)
|
||||
GameUtils.setDownloadBtnStatus(context, gameEntity, downloadBtn, pluginLocation, listener)
|
||||
}
|
||||
} else {
|
||||
GameUtils.setDownloadBtnStatus(context, gameEntity, downloadBtn, pluginLocation)
|
||||
GameUtils.setDownloadBtnStatus(context, gameEntity, downloadBtn, pluginLocation, listener)
|
||||
}
|
||||
}
|
||||
|
||||
@ -510,13 +542,18 @@ object DownloadItemUtils {
|
||||
DownloadStatus.downloading -> {
|
||||
if (isMultiVersion) {
|
||||
holder.gameDownloadBtn.buttonStyle = DownloadButton.ButtonStyle.NORMAL
|
||||
val darkMode = (holder.gameDownloadTips?.getTag(com.gh.gamecenter.common.R.string.is_dark_mode_on_id) as? Boolean) ?: false
|
||||
val darkMode =
|
||||
(holder.gameDownloadTips?.getTag(com.gh.gamecenter.common.R.string.is_dark_mode_on_id) as? Boolean)
|
||||
?: false
|
||||
val isDarkModeChanged = DarkModeUtils.isDarkModeOn(context) != darkMode
|
||||
if (holder.gameDownloadTips?.visibility == View.GONE || holder.gameDownloadTips?.isAnimating == false || isDarkModeChanged) {
|
||||
holder.gameDownloadTips?.visibility = View.VISIBLE
|
||||
holder.gameDownloadTips?.setDownloadTipsAnimation(true)
|
||||
}
|
||||
holder.gameDownloadTips?.setTag(com.gh.gamecenter.common.R.string.is_dark_mode_on_id, DarkModeUtils.isDarkModeOn(context))
|
||||
holder.gameDownloadTips?.setTag(
|
||||
com.gh.gamecenter.common.R.string.is_dark_mode_on_id,
|
||||
DarkModeUtils.isDarkModeOn(context)
|
||||
)
|
||||
} else {
|
||||
holder.gameDownloadTips?.visibility = View.GONE
|
||||
holder.gameDownloadBtn.buttonStyle = DownloadButton.ButtonStyle.DOWNLOADING_NORMAL
|
||||
@ -961,7 +998,8 @@ object DownloadItemUtils {
|
||||
traceEvent: ExposureEvent? = null,
|
||||
refreshCallback: EmptyCallback? = null
|
||||
) {
|
||||
val str = if (downloadBtn is DownloadButton) downloadBtn.text else context.getString(com.gh.gamecenter.feature.R.string.download)
|
||||
val str =
|
||||
if (downloadBtn is DownloadButton) downloadBtn.text else context.getString(com.gh.gamecenter.feature.R.string.download)
|
||||
if (gameEntity.getApk().isEmpty()) return
|
||||
val apk = gameEntity.getApk().safelyGetInRelease(0) ?: return
|
||||
|
||||
@ -980,7 +1018,16 @@ object DownloadItemUtils {
|
||||
addHandler(CheckDownloadHandler())
|
||||
}
|
||||
.setProcessEndCallback(gameEntity.id) { asVGame, isSubscribe ->
|
||||
download(context, gameEntity, downloadBtn, entrance, location, asVGame, isSubscribe as Boolean, traceEvent)
|
||||
download(
|
||||
context,
|
||||
gameEntity,
|
||||
downloadBtn,
|
||||
entrance,
|
||||
location,
|
||||
asVGame,
|
||||
isSubscribe as Boolean,
|
||||
traceEvent
|
||||
)
|
||||
}
|
||||
.buildHandlerChain()
|
||||
?.handleRequest(context, gameEntity, shouldPerformAsVGame)
|
||||
@ -999,7 +1046,16 @@ object DownloadItemUtils {
|
||||
addHandler(CheckDownloadHandler())
|
||||
}
|
||||
.setProcessEndCallback(gameEntity.id) { asVGame, isSubscribe ->
|
||||
download(context, gameEntity, downloadBtn, entrance, location, asVGame, isSubscribe as Boolean, traceEvent)
|
||||
download(
|
||||
context,
|
||||
gameEntity,
|
||||
downloadBtn,
|
||||
entrance,
|
||||
location,
|
||||
asVGame,
|
||||
isSubscribe as Boolean,
|
||||
traceEvent
|
||||
)
|
||||
}
|
||||
.buildHandlerChain()
|
||||
?.handleRequest(context, gameEntity, shouldPerformAsVGame)
|
||||
@ -1018,7 +1074,16 @@ object DownloadItemUtils {
|
||||
addHandler(CheckDownloadHandler())
|
||||
}
|
||||
.setProcessEndCallback(gameEntity.id) { asVGame, isSubscribe ->
|
||||
download(context, gameEntity, downloadBtn, entrance, location, asVGame, isSubscribe as Boolean, traceEvent)
|
||||
download(
|
||||
context,
|
||||
gameEntity,
|
||||
downloadBtn,
|
||||
entrance,
|
||||
location,
|
||||
asVGame,
|
||||
isSubscribe as Boolean,
|
||||
traceEvent
|
||||
)
|
||||
}
|
||||
.buildHandlerChain()
|
||||
?.handleRequest(context, gameEntity, shouldPerformAsVGame)
|
||||
|
||||
@ -25,7 +25,10 @@ object GameUtils {
|
||||
/**
|
||||
* 去除与重复sourceList相同的数据
|
||||
*/
|
||||
fun removeDuplicateData(sourceList: MutableList<GameEntity>?, rawList: MutableList<GameEntity>?): MutableList<GameEntity>? {
|
||||
fun removeDuplicateData(
|
||||
sourceList: MutableList<GameEntity>?,
|
||||
rawList: MutableList<GameEntity>?
|
||||
): MutableList<GameEntity>? {
|
||||
if (sourceList.isNullOrEmpty() || rawList.isNullOrEmpty()) {
|
||||
return rawList
|
||||
}
|
||||
@ -52,7 +55,8 @@ object GameUtils {
|
||||
context: Context,
|
||||
gameEntity: GameEntity,
|
||||
downloadBtn: DownloadButton,
|
||||
pluginLocation: PluginLocation?
|
||||
pluginLocation: PluginLocation?,
|
||||
listener: DownloadButton.OnUpdateListener? = null
|
||||
) {
|
||||
// getDownloadBtnText 里包括查询数据库、根据包名读取包体 meta 信息等
|
||||
lightWeightIoExecutor.execute {
|
||||
@ -73,6 +77,7 @@ object GameUtils {
|
||||
} else {
|
||||
downloadBtn.buttonStyle = DownloadButton.ButtonStyle.NORMAL
|
||||
}
|
||||
listener?.completion(downloadBtn.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -85,11 +90,13 @@ object GameUtils {
|
||||
*/
|
||||
@WorkerThread
|
||||
@JvmStatic
|
||||
fun getDownloadBtnText(context: Context,
|
||||
gameEntity: GameEntity,
|
||||
isFromList: Boolean,
|
||||
fixedAsVGame: Boolean,
|
||||
pluginLocation: PluginLocation?): String {
|
||||
fun getDownloadBtnText(
|
||||
context: Context,
|
||||
gameEntity: GameEntity,
|
||||
isFromList: Boolean,
|
||||
fixedAsVGame: Boolean,
|
||||
pluginLocation: PluginLocation?
|
||||
): String {
|
||||
if (gameEntity.getApk().size > 1) {
|
||||
return ""
|
||||
}
|
||||
@ -138,7 +145,8 @@ object GameUtils {
|
||||
} else if (!isFromList) {
|
||||
if (!performAsVGame
|
||||
&& gameEntity.isDualBtnModeEnabled()
|
||||
&& downloadEntity?.isVGameDownloadInDualDownloadMode() == true) {
|
||||
&& downloadEntity?.isVGameDownloadInDualDownloadMode() == true
|
||||
) {
|
||||
// 下载的任务是由畅玩触发的,并且双下载按钮启用,游戏详情页不需判定为需要安装
|
||||
downloadEntity = null
|
||||
} else if (performAsVGame && downloadEntity?.isLocalDownloadInDualDownloadMode() == true) {
|
||||
|
||||
@ -14,25 +14,26 @@ import androidx.core.content.ContextCompat;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.adapter.LibaoDetailAdapter;
|
||||
import com.gh.gamecenter.common.constant.Constants;
|
||||
import com.gh.gamecenter.common.entity.NotificationUgc;
|
||||
import com.gh.gamecenter.common.eventbus.EBReuse;
|
||||
import com.gh.gamecenter.common.retrofit.JSONObjectResponse;
|
||||
import com.gh.gamecenter.common.retrofit.Response;
|
||||
import com.gh.gamecenter.common.utils.DialogHelper;
|
||||
import com.gh.gamecenter.common.utils.ExtensionsKt;
|
||||
import com.gh.gamecenter.common.utils.NotificationHelper;
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge;
|
||||
import com.gh.gamecenter.core.utils.ToastUtils;
|
||||
import com.gh.gamecenter.core.utils.UrlFilterUtils;
|
||||
import com.gh.gamecenter.eventbus.EBUISwitch;
|
||||
import com.gh.gamecenter.feature.entity.ApkEntity;
|
||||
import com.gh.gamecenter.feature.entity.LibaoEntity;
|
||||
import com.gh.gamecenter.feature.entity.LibaoStatusEntity;
|
||||
import com.gh.gamecenter.feature.entity.MeEntity;
|
||||
import com.gh.gamecenter.common.entity.NotificationUgc;
|
||||
import com.gh.gamecenter.feature.entity.UserDataLibaoEntity;
|
||||
import com.gh.gamecenter.common.eventbus.EBReuse;
|
||||
import com.gh.gamecenter.eventbus.EBUISwitch;
|
||||
import com.gh.gamecenter.feature.utils.PlatformUtils;
|
||||
import com.gh.gamecenter.geetest.GeetestUtils;
|
||||
import com.gh.gamecenter.login.user.UserManager;
|
||||
import com.gh.gamecenter.common.retrofit.JSONObjectResponse;
|
||||
import com.gh.gamecenter.common.retrofit.Response;
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager;
|
||||
import com.halo.assistant.HaloApp;
|
||||
import com.lightgame.utils.Utils;
|
||||
@ -480,7 +481,7 @@ public class LibaoUtils {
|
||||
UserDataLibaoEntity me = new UserDataLibaoEntity(libaoCode, "ling", Utils.getTime(context));
|
||||
initLibaoCode(libaoEntity, me);
|
||||
if (adapter != null) adapter.initLibaoCode(me);
|
||||
EventBus.getDefault().post(new EBReuse("libaoChanged"));
|
||||
EventBus.getDefault().post(new EBReuse(Constants.LIBAO_CHANGED_TAG));
|
||||
if (listener != null) listener.onLibaoStatusChange();
|
||||
uploadEvent(libaoEntity, true, entrance);
|
||||
String des;
|
||||
@ -620,7 +621,7 @@ public class LibaoUtils {
|
||||
UserDataLibaoEntity me = new UserDataLibaoEntity(libaoCode, "ling", Utils.getTime(context));
|
||||
initLibaoCode(libaoEntity, me);
|
||||
if (listener != null) listener.onLibaoStatusChange();
|
||||
EventBus.getDefault().post(new EBReuse("libaoChanged"));
|
||||
EventBus.getDefault().post(new EBReuse(Constants.LIBAO_CHANGED_TAG));
|
||||
uploadEvent(libaoEntity, false, entrance);
|
||||
|
||||
if (adapter != null) {
|
||||
|
||||
@ -12,6 +12,7 @@ import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.download.server.BrowserInstallHelper
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.DialogHelper
|
||||
import com.gh.gamecenter.common.utils.PermissionHelper
|
||||
@ -24,7 +25,6 @@ import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.entity.WhitePackageListEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.entity.SettingsEntity
|
||||
import com.gh.gamecenter.feature.utils.SentryHelper
|
||||
import com.gh.gamecenter.manager.PackagesManager
|
||||
import com.gh.gamecenter.packagehelper.PackageRepository
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
@ -459,6 +459,9 @@ object PackageHelper {
|
||||
PackageRepository.initData {
|
||||
refreshLocalPackageList()
|
||||
refreshPackageNameList()
|
||||
|
||||
// 初始化使用浏览器安装的条件
|
||||
BrowserInstallHelper.initIfConditionMatched(Config.getNewSettingsEntity())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -69,18 +69,24 @@ object PackageInstaller {
|
||||
val isDownloadAsVGame = downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.VGAME
|
||||
|| downloadEntity.getMetaExtra(Constants.EXTRA_DOWNLOAD_TYPE) == Constants.DUAL_DOWNLOAD_VGAME
|
||||
|
||||
val currentActivity = AppManager.getInstance().currentActivity() ?: return
|
||||
val properContext = if (context is AppCompatActivity && !context.isFinishing) {
|
||||
context
|
||||
} else {
|
||||
AppManager.getInstance().currentActivity()
|
||||
}
|
||||
|
||||
properContext ?: return
|
||||
|
||||
if (!ignoreAsVGame && isDownloadAsVGame) {
|
||||
VHelper.install(currentActivity, downloadEntity)
|
||||
VHelper.install(properContext, downloadEntity)
|
||||
return
|
||||
}
|
||||
|
||||
// 已知问题
|
||||
// 1. 此处可能遇到 activity 是 WXEntryActivity,因为 WXEntryActivity 不是 AppCompatActivity 调不起弹窗
|
||||
// 2. 当 activity 全部出栈,但是应用还在下载游戏,下载完会唤不起安装
|
||||
if (currentActivity is AppCompatActivity && !currentActivity.isFinishing) {
|
||||
InstallPermissionDialogFragment.show(currentActivity, downloadEntity) { isFromPermissionGrantedCallback ->
|
||||
if (properContext is AppCompatActivity && !properContext.isFinishing) {
|
||||
InstallPermissionDialogFragment.show(properContext, downloadEntity) { isFromPermissionGrantedCallback ->
|
||||
// 取消状态栏下载完成的通知,若存在
|
||||
downloadEntity.meta[Constants.MARK_ALREADY_TRIGGERED_INSTALLATION] = "YES"
|
||||
DownloadNotificationHelper.addOrUpdateDownloadNotification(downloadEntity)
|
||||
|
||||
@ -32,6 +32,7 @@ import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.ResponseBody
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
|
||||
@ -229,15 +230,19 @@ object UsageStatsHelper {
|
||||
mApi.getUsageStatusUpdateTime(HaloApp.getInstance().gid)
|
||||
.subscribe(object : BiResponse<ResponseBody>() {
|
||||
override fun onSuccess(data: ResponseBody) {
|
||||
val body = JSONObject(data.string())
|
||||
val lastPostTime = body.getLong("update_time") * 1000
|
||||
try {
|
||||
val body = JSONObject(data.string())
|
||||
val lastPostTime = body.getLong("update_time") * 1000
|
||||
|
||||
val beginTime = if (lastPostTime == 0L) {
|
||||
getDefaultBeginTime()
|
||||
} else {
|
||||
lastPostTime
|
||||
val beginTime = if (lastPostTime == 0L) {
|
||||
getDefaultBeginTime()
|
||||
} else {
|
||||
lastPostTime
|
||||
}
|
||||
postUsageStats(beginTime)
|
||||
} catch (e: JSONException) {
|
||||
Utils.log("UsageStats: 获取上次上传时间失败,错误信息:${e.message}")
|
||||
}
|
||||
postUsageStats(beginTime)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -32,6 +32,7 @@ class FlexLinearLayout @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
private var mLastItemWidth = 0//最后更多按钮宽度
|
||||
private var mTotalWidth = 0
|
||||
private var mStrokeWidth = 0
|
||||
private var mShowMore = true
|
||||
var onClickListener: OnItemClickListener? = null
|
||||
|
||||
init {
|
||||
@ -44,11 +45,12 @@ class FlexLinearLayout @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
mTextSize = ta.getDimension(R.styleable.FlexLinearLayout_itemTextSize, 10F.sp2px().toFloat())
|
||||
mLastItemWidth = ta.getDimensionPixelSize(R.styleable.FlexLinearLayout_lastItemWidth, 18F.dip2px())
|
||||
mStrokeWidth = ta.getDimensionPixelSize(R.styleable.FlexLinearLayout_strokeWidth, 0.5F.dip2px())
|
||||
mShowMore = ta.getBoolean(R.styleable.FlexLinearLayout_showMore, true)
|
||||
|
||||
ta.recycle()
|
||||
}
|
||||
|
||||
fun setTags(tags: ArrayList<TagStyleEntity>) {
|
||||
fun setTags(tags: List<TagStyleEntity>) {
|
||||
mTags.clear()
|
||||
mTotalCount = tags.size
|
||||
mTotalWidth = measuredWidth
|
||||
@ -86,7 +88,7 @@ class FlexLinearLayout @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
mTags.forEachIndexed { index, tag ->
|
||||
addView(createView(tag, index))
|
||||
}
|
||||
if (mTotalCount != mTags.size) {
|
||||
if (mShowMore && mTotalCount != mTags.size) {
|
||||
val imageView = ImageView(context).apply {
|
||||
val params = LayoutParams(mLastItemWidth, mItemHeight)
|
||||
layoutParams = params
|
||||
|
||||
@ -3,9 +3,15 @@ package com.gh.common.xapk
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.provider.DocumentsContract
|
||||
import android.provider.Settings
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.DownloadNotificationHelper
|
||||
@ -24,6 +30,7 @@ import com.gh.gamecenter.xapk.core.XApkUnZipCallback
|
||||
import com.gh.gamecenter.xapk.core.XApkUnZipEntry
|
||||
import com.gh.gamecenter.xapk.core.XApkUnZipOutputFactory
|
||||
import com.gh.gamecenter.xapk.io.NonSplitApksOutput
|
||||
import com.gh.gamecenter.xapk.io.OBBDocOutput
|
||||
import com.gh.gamecenter.xapk.io.OBBFileOutput
|
||||
import com.gh.gamecenter.xapk.io.SplitApksOutput
|
||||
import com.gh.gamecenter.xapk.io.XApkFileOutput
|
||||
@ -34,6 +41,8 @@ import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.utils.Utils
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import androidx.core.net.toUri
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
|
||||
/**
|
||||
* 目前已知的Xapk内容是:只有一个apk包和一个或做多个obb数据包(多余文件不解压,如果存在多个apk包,则以下安装无效)
|
||||
@ -65,6 +74,10 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
|
||||
systemMatched && fileListMatched
|
||||
}
|
||||
|
||||
// 是否使用 DocumentUi 的方式访问 obb 文件夹
|
||||
private var useDocStyleToUnzip = false
|
||||
private var tempLauncher: ActivityResultLauncher<Uri>? = null
|
||||
|
||||
private const val GUIDE_TYPE_MIUI_OPTIMIZATION = "miui_optimization"
|
||||
private const val MIUI_OPTIMIZATION_WARNING_DIALOG_ENTRANCE = "MIUI优化关闭提示弹窗"
|
||||
|
||||
@ -121,13 +134,39 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
|
||||
}
|
||||
|
||||
PermissionHelper.checkManageAllFilesOrStoragePermissionBeforeAction(context) {
|
||||
DownloadManager.getInstance().getDownloadEntitySnapshot(downloadEntity.url, downloadEntity.gameId)
|
||||
?.let {
|
||||
unzipXapkFile(it)
|
||||
if (showUnzipToast) {
|
||||
Utils.toast(mContext, "解压过程请勿退出光环助手!")
|
||||
val unzipAction = {
|
||||
DownloadManager.getInstance().getDownloadEntitySnapshot(downloadEntity.url, downloadEntity.gameId)
|
||||
?.let {
|
||||
unzipXapkFile(it)
|
||||
if (showUnzipToast) {
|
||||
Utils.toast(mContext, "解压过程请勿退出光环助手!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// XAPK (apks) 格式,不在乎 obb 文件夹是否可读
|
||||
if (downloadEntity.format == Constants.XAPK_APKS_FORMAT) {
|
||||
unzipAction.invoke()
|
||||
return@checkManageAllFilesOrStoragePermissionBeforeAction
|
||||
}
|
||||
|
||||
// 以 file 的方式访问 obb 文件夹是否可行
|
||||
val isFileStyleObbFolderReadable =
|
||||
if (systemHasFlaw) {
|
||||
File(Environment.getExternalStorageDirectory().path, "\u200bAndroid/obb").list() != null
|
||||
} else {
|
||||
File(Environment.getExternalStorageDirectory().path, "Android/obb").list() != null
|
||||
}
|
||||
|
||||
// 如果是文件夹风格的 obb 文件夹可读,或当前上下文不是 AppCompatActivity,或当前上下文已经被销毁,则直接解压
|
||||
if (isFileStyleObbFolderReadable
|
||||
|| context !is AppCompatActivity
|
||||
|| context.isFinishing
|
||||
) {
|
||||
unzipAction.invoke()
|
||||
} else {
|
||||
unzipWithCulpritHandled(context, downloadEntity.url, unzipAction)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throwExceptionInDebug("如果是Apk包请使用PackageInstaller进行安装")
|
||||
@ -135,6 +174,82 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 兜底解压方案,适用于一些奇葩系统
|
||||
*/
|
||||
private fun unzipWithCulpritHandled(activity: AppCompatActivity, xApkUrl: String, unzipAction: () -> Unit?) {
|
||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R
|
||||
|| Build.VERSION.SDK_INT == Build.VERSION_CODES.S
|
||||
) {
|
||||
val isDocStyleObbFolderReadable = isDocStyleObbFolderReadable(activity)
|
||||
|
||||
if (isDocStyleObbFolderReadable) {
|
||||
useDocStyleToUnzip = true
|
||||
unzipAction.invoke()
|
||||
} else {
|
||||
DialogHelper.showDialog(
|
||||
context = activity,
|
||||
title = "安装提示",
|
||||
content = "为了安装 XAPK 文件,请授予 OBB 文件夹的访问权限",
|
||||
confirmText = "确定",
|
||||
cancelText = "取消",
|
||||
confirmClickCallback = {
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
intent.setFlags(
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
and Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
and Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
|
||||
and Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
|
||||
)
|
||||
|
||||
val obbUri = OBBDocOutput.ANDROID_OBB_DOC_STYLE_URI.toUri()
|
||||
val df = DocumentFile.fromTreeUri(activity, obbUri)
|
||||
if (df != null) {
|
||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, df.uri)
|
||||
}
|
||||
|
||||
tempLauncher =
|
||||
activity.registerActivityResultLauncher(ActivityResultContracts.OpenDocumentTree()) { uri ->
|
||||
if (uri != null) {
|
||||
activity.contentResolver.takePersistableUriPermission(
|
||||
uri,
|
||||
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
)
|
||||
|
||||
useDocStyleToUnzip = true
|
||||
unzipAction.invoke()
|
||||
}
|
||||
|
||||
tempLauncher?.unregister()
|
||||
}
|
||||
|
||||
tempLauncher?.launch(obbUri)
|
||||
},
|
||||
cancelClickCallback = {
|
||||
unzipAction.invoke()
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
PermissionHelper.checkStoragePermissionBeforeAction(activity) {
|
||||
// 设备大于 12,需要重启才能生效 (是的,我们又重启了!)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
// 记录应用重启前需要重解压的信息
|
||||
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, activity.javaClass.name)
|
||||
SPUtils.setString(Constants.SP_XAPK_URL, xApkUrl)
|
||||
|
||||
val pm = activity.packageManager
|
||||
val intent = pm.getLaunchIntentForPackage(activity.packageName)
|
||||
val mainIntent = Intent.makeRestartActivityTask(intent!!.component)
|
||||
activity.startActivity(mainIntent)
|
||||
Runtime.getRuntime().exit(0)
|
||||
} else {
|
||||
unzipAction.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun unzipXapkFile(downloadEntity: DownloadEntity) {
|
||||
mXApkUnZipper.unzip(
|
||||
XApkUnZipEntry(
|
||||
@ -324,7 +439,7 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
|
||||
}
|
||||
|
||||
override fun onCreateOBBOutput(apk: XApkFile): XApkFileOutput<Unit> {
|
||||
return OBBFileOutput()
|
||||
return if (useDocStyleToUnzip) OBBDocOutput(mContext) else OBBFileOutput()
|
||||
}
|
||||
|
||||
override fun onCreateApkOutput(apk: XApkFile): XApkFileOutput<IPackageInstaller> {
|
||||
@ -340,6 +455,16 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否能以 DocumentUi 的方式访问 obb 文件夹
|
||||
*/
|
||||
private fun isDocStyleObbFolderReadable(context: Context): Boolean {
|
||||
return context
|
||||
.contentResolver
|
||||
.persistedUriPermissions
|
||||
.any { it.uri == OBBDocOutput.ANDROID_OBB_URI.toUri() }
|
||||
}
|
||||
|
||||
private class SplitApksInstaller(
|
||||
private val xApkFile: XApkFile,
|
||||
private val sessionId: Int,
|
||||
@ -351,7 +476,12 @@ object XapkInstaller : XApkUnZipCallback, XApkUnZipOutputFactory {
|
||||
|
||||
mPendingSessionInfoMap[downloadEntity.path] = XapkPendingSessionInfo(downloadEntity.path, sessionId)
|
||||
AppExecutor.ioExecutor.execute {// 有可能卡顿造成anr
|
||||
PackageInstaller.installMultiple(applicationContext, downloadEntity.packageName, downloadEntity.path, sessionId)
|
||||
PackageInstaller.installMultiple(
|
||||
applicationContext,
|
||||
downloadEntity.packageName,
|
||||
downloadEntity.path,
|
||||
sessionId
|
||||
)
|
||||
NDataChanger.notifyDataChanged(downloadEntity)
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,15 +17,6 @@ import androidx.collection.ArrayMap;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager;
|
||||
import com.gh.gamecenter.common.utils.ExtensionsKt;
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge;
|
||||
import com.gh.gamecenter.core.AppExecutor;
|
||||
import com.gh.gamecenter.common.constant.Constants;
|
||||
import com.gh.gamecenter.core.GHThreadFactory;
|
||||
import com.gh.gamecenter.feature.entity.TagStyleEntity;
|
||||
import com.gh.gamecenter.feature.entity.CustomPageTrackData;
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent;
|
||||
import com.gh.common.exposure.ExposureUtils;
|
||||
import com.gh.common.history.HistoryHelper;
|
||||
import com.gh.common.simulator.SimulatorGameManager;
|
||||
@ -36,10 +27,16 @@ import com.gh.common.util.LunchType;
|
||||
import com.gh.common.util.PackageInstaller;
|
||||
import com.gh.common.util.PackageUtils;
|
||||
import com.gh.gamecenter.BuildConfig;
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager;
|
||||
import com.gh.gamecenter.common.constant.Constants;
|
||||
import com.gh.gamecenter.common.exposure.meta.MetaUtil;
|
||||
import com.gh.gamecenter.common.utils.DeviceUtils;
|
||||
import com.gh.gamecenter.common.utils.ExtensionsKt;
|
||||
import com.gh.gamecenter.common.utils.FileUtils;
|
||||
import com.gh.gamecenter.common.utils.NetworkUtils;
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge;
|
||||
import com.gh.gamecenter.core.AppExecutor;
|
||||
import com.gh.gamecenter.core.GHThreadFactory;
|
||||
import com.gh.gamecenter.core.utils.GsonUtils;
|
||||
import com.gh.gamecenter.core.utils.PageSwitchDataHelper;
|
||||
import com.gh.gamecenter.core.utils.SPUtils;
|
||||
@ -48,8 +45,11 @@ import com.gh.gamecenter.entity.GameUpdateEntity;
|
||||
import com.gh.gamecenter.entity.HomePluggableFilterEntity;
|
||||
import com.gh.gamecenter.eventbus.EBDownloadStatus;
|
||||
import com.gh.gamecenter.feature.entity.ApkEntity;
|
||||
import com.gh.gamecenter.feature.entity.CustomPageTrackData;
|
||||
import com.gh.gamecenter.feature.entity.GameEntity;
|
||||
import com.gh.gamecenter.feature.entity.PluginLocation;
|
||||
import com.gh.gamecenter.feature.entity.TagStyleEntity;
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent;
|
||||
import com.gh.gamecenter.feature.utils.SentryHelper;
|
||||
import com.gh.gamecenter.login.user.UserManager;
|
||||
import com.gh.gamecenter.manager.PackagesManager;
|
||||
@ -1296,7 +1296,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
getInstance().packageExecutor.execute(() -> {
|
||||
boolean markHasChanged = false;
|
||||
|
||||
ArrayList<GameUpdateEntity> updates = PackageRepository.INSTANCE.getGameUpdate();
|
||||
List<GameUpdateEntity> updates = PackageRepository.INSTANCE.getGameUpdate();
|
||||
for (GameUpdateEntity update : updates) {
|
||||
if (update == null) continue;
|
||||
String mark = update.getId() + update.getPackageName();
|
||||
@ -1317,7 +1317,7 @@ public class DownloadManager implements DownloadStatusListener {
|
||||
* 将可用更新标记为已读的事件
|
||||
*/
|
||||
public void saveUpdateMarkToStorage() {
|
||||
ArrayList<GameUpdateEntity> updates = PackageRepository.INSTANCE.getGameUpdate();
|
||||
List<GameUpdateEntity> updates = PackageRepository.INSTANCE.getGameUpdate();
|
||||
if (updates.size() == mUpdateMarks.size()) {
|
||||
SPUtils.setStringSet(UPDATE_IS_READ_MARK, mUpdateMarks);
|
||||
return;
|
||||
|
||||
@ -15,7 +15,8 @@ import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.recyclerview.widget.*
|
||||
import androidx.recyclerview.widget.RecyclerView.SmoothScroller
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.DialogUtils
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.R
|
||||
@ -30,9 +31,9 @@ import com.gh.gamecenter.core.AppExecutor
|
||||
import com.gh.gamecenter.core.utils.TimeElapsedHelper
|
||||
import com.gh.gamecenter.databinding.DialogDownloadBinding
|
||||
import com.gh.gamecenter.entity.GamePlatform
|
||||
import com.gh.gamecenter.eventbus.EBPackage
|
||||
import com.gh.gamecenter.feature.entity.ApkEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.eventbus.EBPackage
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DataWatcher
|
||||
@ -70,6 +71,8 @@ class DownloadDialog : BaseDraggableDialogFragment() {
|
||||
private var mEntrance: String = "" // 入口位置
|
||||
private var mLocation: String = "" // 最终位置
|
||||
|
||||
private var onDownloadClickAction: ((Boolean) -> Unit)? = null
|
||||
|
||||
|
||||
private val mDataWatcher = object : DataWatcher() {
|
||||
override fun onDataChanged(downloadEntity: DownloadEntity) {
|
||||
@ -122,7 +125,7 @@ class DownloadDialog : BaseDraggableDialogFragment() {
|
||||
}
|
||||
mViewModel.listLiveData.observeNonNull(this, callback = { itemList ->
|
||||
mAdapter =
|
||||
DownloadDialogAdapter(requireContext(), mViewModel, itemList, false, mTraceEvent, mEntrance, mLocation)
|
||||
DownloadDialogAdapter(requireContext(), mViewModel, itemList, false, mTraceEvent, mEntrance, mLocation, onDownloadClickAction)
|
||||
mBinding.contentList.layoutManager = createLayoutManager(itemList)
|
||||
mBinding.contentList.adapter = mAdapter
|
||||
performAutoDownload(itemList, mBinding.contentList)
|
||||
@ -426,7 +429,8 @@ class DownloadDialog : BaseDraggableDialogFragment() {
|
||||
gameEntity: GameEntity,
|
||||
traceEvent: ExposureEvent?,
|
||||
entrance: String?,
|
||||
location: String?
|
||||
location: String?,
|
||||
onDownloadClickAction: ((Boolean) -> Unit)? = null
|
||||
) {
|
||||
val fragmentActivity: FragmentActivity = if (context is FragmentActivity) {
|
||||
context
|
||||
@ -452,6 +456,7 @@ class DownloadDialog : BaseDraggableDialogFragment() {
|
||||
bundle.putParcelable(EntranceConsts.KEY_TRACE_EVENT, traceEvent)
|
||||
arguments = bundle
|
||||
}
|
||||
downloadDialog.onDownloadClickAction = onDownloadClickAction
|
||||
downloadDialog.show(fragmentActivity.supportFragmentManager, DownloadDialog::class.java.name)
|
||||
}
|
||||
|
||||
|
||||
@ -24,7 +24,8 @@ class DownloadDialogAdapter(
|
||||
val isCollectionPage: Boolean,
|
||||
private val mTraceEvent: ExposureEvent?,
|
||||
private val mEntrance: String,
|
||||
private val mLocation: String
|
||||
private val mLocation: String,
|
||||
private val onDownloadClickAction: ((Boolean) -> Unit)? = null
|
||||
) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
|
||||
|
||||
private val mPath = if (isCollectionPage) {
|
||||
@ -170,7 +171,8 @@ class DownloadDialogAdapter(
|
||||
mTraceEvent,
|
||||
mEntrance,
|
||||
mPath,
|
||||
mLocation
|
||||
mLocation,
|
||||
onDownloadClickAction
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +41,8 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
traceEvent: ExposureEvent?,
|
||||
entrance: String,
|
||||
path: String,
|
||||
location: String
|
||||
location: String,
|
||||
onDownloadClickAction: ((Boolean) -> Unit)? = null
|
||||
) {
|
||||
|
||||
val apkEntity = listData[position].normal!!
|
||||
@ -181,7 +182,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
}
|
||||
}
|
||||
|
||||
setDownloadClickListener(itemView, apkEntity, viewModel, traceEvent, entrance, path, location)
|
||||
setDownloadClickListener(itemView, apkEntity, viewModel, traceEvent, entrance, path, location, onDownloadClickAction)
|
||||
}
|
||||
|
||||
private fun changeRecommendUI(apkEntity: ApkEntity, listData: List<DownloadDialogItemData>, position: Int) {
|
||||
@ -226,7 +227,8 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
traceEvent: ExposureEvent?,
|
||||
entrance: String,
|
||||
path: String,
|
||||
location: String
|
||||
location: String,
|
||||
onDownloadClickAction: ((Boolean) -> Unit)? = null
|
||||
) {
|
||||
|
||||
val gameEntity = viewModel.gameEntity
|
||||
@ -234,6 +236,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
when (itemView.getTag(DownloadDialogAdapter.ITEM_TAG_KEY)) {
|
||||
DownloadDialogItemStatus.DOWNLOAD -> {
|
||||
createDownloadTask(it.context, apkEntity, gameEntity, traceEvent, entrance, location)
|
||||
onDownloadClickAction?.invoke(false)
|
||||
}
|
||||
DownloadDialogItemStatus.LAUNCH -> {
|
||||
PackageLauncher.launchApp(it.context, gameEntity, apkEntity.packageName)
|
||||
@ -291,6 +294,7 @@ class DownloadDialogItemViewHolder(val binding: DownloadDialogItemBinding) : Bas
|
||||
}
|
||||
DownloadDialogItemStatus.UPDATE -> {
|
||||
createDownloadTask(it.context, apkEntity, gameEntity, traceEvent, entrance, location)
|
||||
onDownloadClickAction?.invoke(true)
|
||||
}
|
||||
DownloadDialogItemStatus.COLLECTION -> {
|
||||
val apkCollection = apkEntity.apkCollection
|
||||
|
||||
@ -3,6 +3,7 @@ package com.gh.download.server
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.util.Base64
|
||||
import androidx.annotation.WorkerThread
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.LogUtils
|
||||
@ -246,6 +247,19 @@ object BrowserInstallHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化是否满足开启浏览器安装的条件(后续会使用缓存来判断)
|
||||
* @param settingsEntity 服务器返回的配置
|
||||
*
|
||||
* 因为可能需要查询已安装的应用,所以需要在子线程中调用
|
||||
*/
|
||||
@WorkerThread
|
||||
fun initIfConditionMatched(settingsEntity: NewSettingsEntity?) {
|
||||
settingsEntity?.let {
|
||||
isConditionMatched(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否满足开启浏览器安装的条件
|
||||
*/
|
||||
|
||||
@ -1,81 +0,0 @@
|
||||
package com.gh.gamecenter
|
||||
|
||||
import android.os.Bundle
|
||||
import android.widget.Button
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.core.provider.IAcceleratorProvider
|
||||
import com.gh.gamecenter.feature.entity.BaseEntity
|
||||
import com.gh.gamecenter.login.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.therouter.TheRouter
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import retrofit2.HttpException
|
||||
|
||||
|
||||
/**
|
||||
* 奇游用户批量注册
|
||||
*/
|
||||
class BatchRegisterActivity : AppCompatActivity() {
|
||||
|
||||
private val userIds = listOf(
|
||||
""
|
||||
)
|
||||
private var iAcceleratorProvider: IAcceleratorProvider? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_batch_register)
|
||||
|
||||
iAcceleratorProvider = TheRouter.get(IAcceleratorProvider::class.java)
|
||||
val btnRegister = findViewById<Button>(R.id.btn_register)
|
||||
btnRegister.setOnClickListener {
|
||||
doRegister()
|
||||
}
|
||||
}
|
||||
|
||||
private fun doRegister() {
|
||||
println("kayn -->doRegister:${userIds.size}")
|
||||
Observable.fromIterable(userIds)
|
||||
.flatMap({ userId ->
|
||||
RetrofitManager.getInstance().newApi
|
||||
.getQyToken(userId, "gjonline_vip")
|
||||
.onErrorReturnItem(BaseEntity())
|
||||
.flatMap { entity ->
|
||||
val token = entity.data?.token ?: ""
|
||||
Single.create<Pair<Boolean, String>> {
|
||||
if (token.isBlank()) {
|
||||
it.onSuccess(false to userId)
|
||||
} else {
|
||||
iAcceleratorProvider?.setQyUserToken(token) { isSuccess ->
|
||||
it.onSuccess(isSuccess to userId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.toObservable()
|
||||
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Response<Pair<Boolean, String>>() {
|
||||
override fun onNext(response: Pair<Boolean, String>) {
|
||||
super.onNext(response)
|
||||
val (isSuccess, userId) = response
|
||||
println("kayn -->isSuccess:$isSuccess --userId:$userId")
|
||||
}
|
||||
|
||||
override fun onFailure(e: HttpException?) {
|
||||
super.onFailure(e)
|
||||
}
|
||||
|
||||
override fun onComplete() {
|
||||
super.onComplete()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
|
||||
@ -136,6 +136,7 @@ import io.reactivex.SingleSource;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.functions.Function;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import kotlin.Pair;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
import okhttp3.RequestBody;
|
||||
@ -181,7 +182,6 @@ public class MainActivity extends BaseActivity {
|
||||
.get(MainWrapperViewModel.class);
|
||||
|
||||
DisplayUtils.transparentStatusBar(this);
|
||||
DisplayUtils.updateGlobalScreen(this);
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
setStatusBarColor(Color.TRANSPARENT);
|
||||
@ -1084,4 +1084,12 @@ public class MainActivity extends BaseActivity {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<String, String> getBusinessId() {
|
||||
if (mMainWrapperFragment != null) {
|
||||
return mMainWrapperFragment.getBusinessId();
|
||||
}
|
||||
return super.getBusinessId();
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +91,6 @@ open class SearchActivity : BaseActivity() {
|
||||
mSourceEntrance = intent.getStringExtra(EntranceConsts.KEY_SOURCE_ENTRANCE) ?: ""
|
||||
val hint = intent.getStringExtra(EntranceConsts.KEY_HINT)
|
||||
val searchImmediately = intent.getBooleanExtra(KEY_SEARCH_IMMEDIATELY, false)
|
||||
var ignoreTextChanges = savedInstanceState != null
|
||||
|
||||
mPublishSubject = PublishSubject.create()
|
||||
|
||||
@ -102,12 +101,9 @@ open class SearchActivity : BaseActivity() {
|
||||
.subscribe {
|
||||
if (searchEt.text.isNotEmpty()
|
||||
&& searchEt.text != searchEt.hint
|
||||
&& !ignoreTextChanges
|
||||
) {
|
||||
search(SearchType.AUTO, it)
|
||||
}
|
||||
|
||||
ignoreTextChanges = false
|
||||
}
|
||||
|
||||
initSearchBar()
|
||||
@ -202,7 +198,6 @@ open class SearchActivity : BaseActivity() {
|
||||
|
||||
protected open fun handleEmptySearch(newSearchKey: String) {
|
||||
popBackToFragment(SearchDefaultFragment::class.java.name)// 回退到搜索首页
|
||||
updateDisplayType(DisplayType.DEFAULT)
|
||||
mPublishSubject?.onNext(newSearchKey)
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -14,6 +14,8 @@ import androidx.core.app.NotificationCompat
|
||||
import androidx.core.text.bold
|
||||
import androidx.core.text.buildSpannedString
|
||||
import androidx.core.text.color
|
||||
import com.therouter.TheRouter
|
||||
import com.therouter.router.Route
|
||||
import com.gh.common.dialog.NewPrivacyPolicyDialogFragment
|
||||
import com.gh.common.util.DeviceTokenUtils
|
||||
import com.gh.common.util.DialogUtils
|
||||
@ -30,14 +32,13 @@ import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.iinterface.ISplashScreen
|
||||
import com.gh.gamecenter.core.provider.IAppProvider
|
||||
import com.gh.gamecenter.core.provider.IPackageUtilsProvider
|
||||
import com.gh.gamecenter.core.provider.IPushProvider
|
||||
import com.gh.gamecenter.core.runOnIoThread
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.feature.utils.PlatformUtils
|
||||
import com.gh.gamecenter.pkg.PkgHelper
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.therouter.TheRouter
|
||||
import com.therouter.router.Route
|
||||
import org.json.JSONObject
|
||||
import splitties.systemservices.notificationManager
|
||||
import java.text.SimpleDateFormat
|
||||
@ -89,9 +90,8 @@ class SplashScreenActivity : BaseActivity(), ISplashScreen {
|
||||
showPrivacyDialog()
|
||||
} else {
|
||||
val spanBuilder = buildSpannedString {
|
||||
append(
|
||||
"这个弹窗只会在右上角有环境标签的测试包出现" +
|
||||
"\n进入应用以后还可以到关于我们页面长按应用图标重新选择"
|
||||
append("这个弹窗只会在右上角有环境标签的测试包出现" +
|
||||
"\n进入应用以后还可以到关于我们页面长按应用图标重新选择"
|
||||
)
|
||||
bold {
|
||||
color(com.gh.gamecenter.common.R.color.text_theme.toColor(this@SplashScreenActivity)) {
|
||||
@ -104,7 +104,7 @@ class SplashScreenActivity : BaseActivity(), ISplashScreen {
|
||||
executeDex2OatInAdvance()
|
||||
DialogHelper.showDialog(
|
||||
context = this,
|
||||
title = "选择环境",
|
||||
title ="选择环境",
|
||||
content = spanBuilder,
|
||||
confirmText = "正式环境",
|
||||
cancelText = "测试环境",
|
||||
@ -131,7 +131,6 @@ class SplashScreenActivity : BaseActivity(), ISplashScreen {
|
||||
} else {
|
||||
launchMainActivity()
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
|
||||
SPUtils.setString(Constants.SP_XAPK_UNZIP_ACTIVITY, "")
|
||||
SPUtils.setString(Constants.SP_XAPK_URL, "")
|
||||
|
||||
@ -6,19 +6,17 @@ import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import com.gh.common.constant.Config
|
||||
import com.therouter.router.Route
|
||||
import com.gh.gamecenter.common.base.activity.ToolBarActivity
|
||||
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.entity.ToolBoxEntity
|
||||
import com.gh.gamecenter.common.utils.EnvHelper
|
||||
import com.gh.gamecenter.common.utils.updateStatusBarColor
|
||||
import com.gh.gamecenter.feature.entity.ConcernEntity
|
||||
import com.gh.gamecenter.feature.entity.NewsEntity
|
||||
import com.gh.gamecenter.common.entity.ToolBoxEntity
|
||||
import com.halo.assistant.fragment.WebFragment
|
||||
import com.halo.assistant.member.MemberActivity
|
||||
import com.therouter.router.Route
|
||||
|
||||
@Route(path = RouteConsts.activity.webActivity)
|
||||
open class WebActivity : ToolBarActivity() {
|
||||
@ -31,8 +29,6 @@ open class WebActivity : ToolBarActivity() {
|
||||
val mIsBackpressRequireConfirmation =
|
||||
bundle.getBoolean(WebFragment.KEY_REQUIRE_BACK_CONFIRMATION, false)
|
||||
mIsFullScreen = !TextUtils.isEmpty(mGameName) && mIsBackpressRequireConfirmation
|
||||
mIsFullScreen = true
|
||||
|
||||
if (mIsFullScreen) {
|
||||
setTheme(R.style.AppFullScreenTheme)
|
||||
}
|
||||
@ -309,17 +305,5 @@ open class WebActivity : ToolBarActivity() {
|
||||
intent.putExtra(NORMAL_FRAGMENT_BUNDLE, bundle)
|
||||
return intent
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getMyAssetsIntent(context: Context): Intent {
|
||||
val intent = Intent(context, MemberActivity::class.java)
|
||||
val url = if (EnvHelper.isDevEnv) {
|
||||
Constants.MY_ASSETS_DEV
|
||||
} else {
|
||||
Constants.MY_ASSETS
|
||||
}
|
||||
intent.putExtra(EntranceConsts.KEY_URL, url)
|
||||
return intent
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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,14 @@ 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.generic.RoundingParams;
|
||||
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 +38,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 +87,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 +326,35 @@ 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).getImg();
|
||||
SimpleDraweeView imageView = new SimpleDraweeView(mContext);
|
||||
RoundingParams roundingParams = new RoundingParams();
|
||||
roundingParams.setCornersRadius(DisplayUtils.dip2px(4F));
|
||||
roundingParams.setOverlayColor(ContextCompat.getColor(mContext, com.gh.gamecenter.common.R.color.ui_surface));
|
||||
imageView.setHierarchy(new GenericDraweeHierarchyBuilder(mContext.getResources())
|
||||
.setFadeDuration(500)
|
||||
.setRoundingParams(roundingParams)
|
||||
.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.getMaterialImgList(), index, mImageViewList, mEntrance);
|
||||
mContext.startActivity(intent);
|
||||
});
|
||||
mImageViewList.add(imageView);
|
||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(DisplayUtils.dip2px(24F), DisplayUtils.dip2px(24F));
|
||||
layoutParams.setMargins(DisplayUtils.dip2px(i == 0 ? 8F : 16F), 0, 0, 0);
|
||||
holder.binding.imagesContainer.addView(imageView, layoutParams);
|
||||
}
|
||||
}
|
||||
if (mLibaoDetailEntity != null) {
|
||||
holder.binding.libaodetailTimeLl.setVisibility(View.VISIBLE);
|
||||
|
||||
|
||||
@ -35,7 +35,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
|
||||
@ -48,9 +47,10 @@ 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.accelerator.GameDetailAcceleratorUiHelper
|
||||
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
|
||||
@ -61,6 +61,7 @@ import java.io.File
|
||||
// 虽然叫 ViewHolder,但其实就是一个用来临时放 View 和相关操作的包裹类
|
||||
class DetailViewHolder(
|
||||
view: View,
|
||||
val viewModel: GameDetailViewModel?,
|
||||
val gameEntity: GameEntity,
|
||||
val isNewsDetail: Boolean, // 新闻详情不显示下载的游戏名, 只显示下载状态
|
||||
entrance: String?,
|
||||
@ -68,7 +69,8 @@ class DetailViewHolder(
|
||||
title: String?,
|
||||
val traceEvent: ExposureEvent?,
|
||||
val isSupportDualButton: Boolean = false, // 是否支持双下载按钮,不支持的时候跟普通列表意义选用优先级高的那个来显示,
|
||||
val acceleratorUiHelper: GameDetailAcceleratorUiHelper? = null // 网速加速,只有游戏详情才有
|
||||
val acceleratorUiHelper: GameDetailAcceleratorUiHelper? = null, // 网速加速,只有游戏详情才有
|
||||
onDownloadClickAction: ((Boolean) -> Unit)? = null
|
||||
) {
|
||||
var context: Context
|
||||
var downloadBottom: View
|
||||
@ -131,7 +133,8 @@ class DetailViewHolder(
|
||||
mTitle = title ?: "",
|
||||
mAsVGame = false,
|
||||
mShowDualDownloadButton = gameDownloadMode == GameEntity.GAME_DOWNLOAD_BUTTON_MODE_DUAL,
|
||||
mTraceEvent = traceEvent
|
||||
mTraceEvent = traceEvent,
|
||||
onDownloadClickAction = onDownloadClickAction
|
||||
)
|
||||
|
||||
val vGameDownloadListener = OnDetailDownloadClickListener(
|
||||
@ -141,7 +144,8 @@ class DetailViewHolder(
|
||||
mTitle = title ?: "",
|
||||
mAsVGame = true,
|
||||
mShowDualDownloadButton = gameDownloadMode == GameEntity.GAME_DOWNLOAD_BUTTON_MODE_DUAL,
|
||||
mTraceEvent = traceEvent
|
||||
mTraceEvent = traceEvent,
|
||||
onDownloadClickAction = onDownloadClickAction
|
||||
)
|
||||
|
||||
// 不支持双下载按钮的情况时,优选一个下载方式显示
|
||||
@ -194,12 +198,26 @@ class DetailViewHolder(
|
||||
gamePermissionDialogFragment?.dismissAllowingStateLoss()
|
||||
}
|
||||
|
||||
fun hideSpeedUi() {
|
||||
acceleratorUiHelper?.showSpeedUi = false
|
||||
}
|
||||
|
||||
fun showAcceleratorGuideLayer() {
|
||||
acceleratorUiHelper?.checkIfShowGuideLayer(context)
|
||||
fun checkIfShowSpeedUi(rawBtnText: String) {
|
||||
acceleratorUiHelper?.let {
|
||||
when {
|
||||
rawBtnText == "启动" && gameEntity.canSpeed -> {
|
||||
downloadPb.goneIf(true)
|
||||
localDownloadButton?.goneIf(true)
|
||||
it.checkIfShowSpeedUi(true)
|
||||
}
|
||||
|
||||
rawBtnText == "更新" && gameEntity.canSpeed -> {
|
||||
it.checkIfShowSpeedUi(true)
|
||||
}
|
||||
|
||||
else -> {
|
||||
it.checkIfShowSpeedUi(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun setSpeedViewsVisible(isVisible: Boolean) {
|
||||
@ -214,7 +232,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
|
||||
@ -312,11 +331,13 @@ class DetailViewHolder(
|
||||
showLandPageAddressDialogIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
"toast" -> {
|
||||
EventBus.getDefault().post(EBReuse(GameDetailFragment.SKIP_RATING))
|
||||
mViewHolder.viewModel?.performTabSelected(GameDetailTabEntity.TYPE_COMMENT)
|
||||
ToastUtils.toast("该游戏因故暂不提供下载,具体详情可在相关评论中查看,敬请谅解~")
|
||||
showLandPageAddressDialogIfNeeded()
|
||||
}
|
||||
|
||||
"third_party" -> {
|
||||
showLandPageAddressDialogIfNeeded()
|
||||
}
|
||||
@ -397,7 +418,8 @@ class DetailViewHolder(
|
||||
gameEntity = mGameEntity,
|
||||
traceEvent = mTraceEvent,
|
||||
entrance = StringUtils.buildString(mEntrance, "+(", mName, "[", mTitle, "])"),
|
||||
location = "$mName:$mTitle"
|
||||
location = "$mName:$mTitle",
|
||||
onDownloadClickAction = onDownloadClickAction
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -715,6 +737,7 @@ class DetailViewHolder(
|
||||
builder.addHandler(OverseaDownloadHandler())
|
||||
builder.addHandler(CheckDownloadHandler())
|
||||
builder.setProcessEndCallback(mGameEntity.id) { asVGame: Boolean, isSubscribe: Any? ->
|
||||
performDownloadClickAction()
|
||||
download(asVGame, isSubscribe as Boolean)
|
||||
}
|
||||
} else {
|
||||
@ -732,7 +755,8 @@ class DetailViewHolder(
|
||||
mTitle,
|
||||
"])"
|
||||
),
|
||||
"$mName:$mTitle"
|
||||
"$mName:$mTitle",
|
||||
onDownloadClickAction
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -743,5 +767,20 @@ class DetailViewHolder(
|
||||
mAsVGame
|
||||
)
|
||||
}
|
||||
|
||||
private fun performDownloadClickAction() {
|
||||
val buttonText = if (mShowDualDownloadButton && !mAsVGame) {
|
||||
mViewHolder.localDownloadTitleTv?.text?.ifEmpty {
|
||||
mViewHolder.downloadPb.text.ifEmpty {
|
||||
mViewHolder.overlayTv?.text ?: ""
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mViewHolder.downloadPb.text.ifEmpty { mViewHolder.overlayTv?.text ?: "" }
|
||||
}
|
||||
val isUpdate =
|
||||
buttonText?.contains(mViewHolder.context.getString(com.gh.gamecenter.feature.R.string.update)) == true
|
||||
onDownloadClickAction?.invoke(isUpdate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
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
|
||||
@ -22,6 +24,7 @@ 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
|
||||
|
||||
/**
|
||||
@ -139,7 +142,7 @@ class AuthorizationActivity : ToolBarActivity() {
|
||||
override fun onRestart() {
|
||||
super.onRestart()
|
||||
if (!CheckLoginUtils.isLogin()) {
|
||||
finish()
|
||||
finishAndRemoveTask()
|
||||
} else {
|
||||
initUserInfo()
|
||||
initData()
|
||||
@ -150,12 +153,12 @@ class AuthorizationActivity : ToolBarActivity() {
|
||||
private fun checkParam() {
|
||||
val uri = intent.data
|
||||
if (uri == null) {
|
||||
finish()
|
||||
finishAndRemoveTask()
|
||||
return
|
||||
}
|
||||
val host = uri.host
|
||||
if (host != "authorize") {
|
||||
finish()
|
||||
finishAndRemoveTask()
|
||||
return
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
@ -168,7 +171,7 @@ class AuthorizationActivity : ToolBarActivity() {
|
||||
gameName = uri.getQueryParameter(EntranceConsts.KEY_GAME_NAME) ?: ""
|
||||
gameUid = uri.getQueryParameter(EntranceConsts.KEY_UID)?.toIntOrNull() ?: -1
|
||||
if (mRemotePkgName == null) {
|
||||
finish()
|
||||
finishAndRemoveTask()
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -221,7 +224,7 @@ class AuthorizationActivity : ToolBarActivity() {
|
||||
val remotePkgName = mRemotePkgName
|
||||
if (remotePkgName == null) {
|
||||
logAuthResult(false)
|
||||
finish()
|
||||
finishAndRemoveTask()
|
||||
return
|
||||
}
|
||||
if (mToken.isEmpty()) {
|
||||
@ -242,13 +245,44 @@ class AuthorizationActivity : ToolBarActivity() {
|
||||
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) {
|
||||
sendBroadcastAsUser(intent, UserHandle.getUserHandleForUid(gameUid))
|
||||
try {
|
||||
sendBroadcastAsUser(intent, UserHandle.getUserHandleForUid(gameUid))
|
||||
} catch (e: Exception) {
|
||||
// 双开/分身游戏进行授权时,如果无 INTERACT_ACROSS_USERS 权限,则使用Activity传递授权结果
|
||||
authByActivity(intent)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
logAuthResult(true)
|
||||
backToLaunchApp()
|
||||
finish()
|
||||
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)
|
||||
}
|
||||
|
||||
private fun logAuthResult(isSuccess: Boolean) {
|
||||
@ -277,7 +311,7 @@ class AuthorizationActivity : ToolBarActivity() {
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
super.onBackPressed()
|
||||
finishAndRemoveTask()
|
||||
|
||||
backToLaunchApp(false)
|
||||
|
||||
@ -292,6 +326,7 @@ 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"
|
||||
}
|
||||
|
||||
}
|
||||
@ -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() {}
|
||||
|
||||
@ -216,7 +216,7 @@ class CloudArchiveManagerActivity : BaseActivity_TabLayout(), ArchiveLimitSelect
|
||||
|
||||
private fun initDownloadBtn() {
|
||||
mGameEntity?.let { gameEntity ->
|
||||
DownloadItemUtils.updateDownloadButton(this, mBinding.downloadBtn, gameEntity)
|
||||
DownloadItemUtils.updateDownloadButton(this, mBinding.downloadBtn, gameEntity, listener = null)
|
||||
DownloadItemUtils.setOnClickListener(this, mBinding.downloadBtn, gameEntity, 0, null, mEntrance, "")
|
||||
}
|
||||
}
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
import com.gh.gamecenter.feature.entity.SimpleGame
|
||||
import com.gh.gamecenter.feature.entity.Count
|
||||
import com.gh.gamecenter.feature.entity.SimpleGame
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class GameDetailRecommendGameEntity(
|
||||
data class GameDetailRecommendGameCollectionEntity(
|
||||
@SerializedName("_id")
|
||||
val id: String = "",
|
||||
val cover: String = "",
|
||||
@ -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? = "",
|
||||
)
|
||||
@ -0,0 +1,5 @@
|
||||
package com.gh.gamecenter.eventbus
|
||||
|
||||
import com.gh.gamecenter.feature.entity.AcctGameInfo
|
||||
|
||||
class EBStartupAcceleration(val acctGameInfo: AcctGameInfo)
|
||||
@ -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()
|
||||
|
||||
@ -3,26 +3,29 @@ 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
|
||||
|
||||
class GameHorizontalAdapter(
|
||||
context: Context,
|
||||
private var mSubjectEntity: SubjectEntity,
|
||||
var subjectEntity: 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 = ""
|
||||
@ -37,15 +40,15 @@ class GameHorizontalAdapter(
|
||||
|
||||
init {
|
||||
var dataIds = ""
|
||||
mSubjectEntity.data?.forEach {
|
||||
subjectEntity.data?.forEach {
|
||||
dataIds += it.id
|
||||
}
|
||||
if (dataIds.isNotEmpty()) countAndKey = Pair(mSubjectEntity.data?.size ?: 0, dataIds)
|
||||
if (dataIds.isNotEmpty()) countAndKey = Pair(subjectEntity.data?.size ?: 0, dataIds)
|
||||
}
|
||||
|
||||
fun getIndex(): Int {
|
||||
if (mSubjectEntity.data!!.isNotEmpty()) {
|
||||
return if (mSubjectEntity.data!![0].image.isNullOrEmpty()) 0 else 1
|
||||
if (subjectEntity.data!!.isNotEmpty()) {
|
||||
return if (subjectEntity.data!![0].image.isNullOrEmpty()) 0 else 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@ -53,13 +56,13 @@ class GameHorizontalAdapter(
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = GameHorizontalItemViewHolder(parent.toBinding())
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
val size = mSubjectEntity.data!!.size - getIndex()
|
||||
val size = subjectEntity.data!!.size - getIndex()
|
||||
return when (type) {
|
||||
GameHorizontalListType.GameDetailHorizontalType -> {
|
||||
size
|
||||
}
|
||||
GameHorizontalListType.MiniGameSubjectHorizontalType -> {
|
||||
mSubjectEntity.data!!.size
|
||||
subjectEntity.data!!.size
|
||||
}
|
||||
else -> when {
|
||||
size < 4 -> size
|
||||
@ -80,14 +83,15 @@ class GameHorizontalAdapter(
|
||||
}
|
||||
holder.binding.root.layoutParams = params
|
||||
|
||||
val gameEntity = mSubjectEntity.data!![position + getIndex()]
|
||||
val gameEntity = subjectEntity.data!![position + getIndex()]
|
||||
holder.binding.simpleGameContainer.run {
|
||||
gameIcon.displayGameIcon(gameEntity)
|
||||
GameHorizontalSimpleItemViewHolder.setHorizontalNameAndGravity(gameName, gameEntity.name)
|
||||
downloadBtn.goneIf(!mSubjectEntity.showDownload)
|
||||
gameName.maxLines = if (mSubjectEntity.showDownload) 1 else 2
|
||||
downloadBtn.goneIf(!subjectEntity.showDownload)
|
||||
gameName.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(mContext))
|
||||
gameName.maxLines = if (subjectEntity.showDownload) 1 else 2
|
||||
}
|
||||
holder.bindGameHorizontalItem(gameEntity, mSubjectEntity)
|
||||
holder.bindGameHorizontalItem(gameEntity, subjectEntity)
|
||||
val entranceResult: String
|
||||
val locationResult: String
|
||||
if (type == GameHorizontalListType.GameDetailHorizontalType) {
|
||||
@ -104,37 +108,35 @@ class GameHorizontalAdapter(
|
||||
locationResult = StringUtils.buildString("游戏详情-", gameName, "-${path}", ":", gameEntity.name)
|
||||
} else {
|
||||
entranceResult =
|
||||
StringUtils.buildString("(游戏-专题:", mSubjectEntity.name, "-列表[", (position + 1).toString(), "])")
|
||||
locationResult = StringUtils.buildString("游戏-专题-", mSubjectEntity.name, ":", gameEntity.name)
|
||||
StringUtils.buildString("(游戏-专题:", subjectEntity.name, "-列表[", (position + 1).toString(), "])")
|
||||
locationResult = StringUtils.buildString("游戏-专题-", subjectEntity.name, ":", gameEntity.name)
|
||||
}
|
||||
holder.itemView.setOnClickListener {
|
||||
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,
|
||||
linkType = "game",
|
||||
linkId = gameEntity.id,
|
||||
linkText = gameEntity.name ?: "",
|
||||
gameStatus = getGameStatus?.invoke()
|
||||
)
|
||||
if (!gameEntity.isMiniGame() && trackColumnClick) {
|
||||
SensorsBridge.trackColumnClick(
|
||||
location = "游戏详情",
|
||||
gameName = gameName,
|
||||
gameId = gameId,
|
||||
gameColumnName = mSubjectEntity.name ?: "",
|
||||
gameColumnId = mSubjectEntity.id ?: "",
|
||||
gameColumnName = subjectEntity.name ?: "",
|
||||
gameColumnId = subjectEntity.id ?: "",
|
||||
text = "游戏",
|
||||
columnPattern = subjectTypeToComponentStyle[mSubjectEntity.type] ?: ""
|
||||
columnPattern = subjectTypeToComponentStyle[subjectEntity.type] ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -151,7 +153,7 @@ class GameHorizontalAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
if (mSubjectEntity.showDownload && type != GameHorizontalListType.GameDetailHorizontalType) {
|
||||
if (subjectEntity.showDownload && type != GameHorizontalListType.GameDetailHorizontalType) {
|
||||
DownloadItemUtils.setOnClickListener(
|
||||
mContext,
|
||||
holder.binding.simpleGameContainer.downloadBtn,
|
||||
@ -179,7 +181,7 @@ class GameHorizontalAdapter(
|
||||
if (downloadEntity == null) {
|
||||
notifyDataSetChanged()
|
||||
} else {
|
||||
mSubjectEntity.data?.forEachIndexed { position, gameEntity ->
|
||||
subjectEntity.data?.forEachIndexed { position, gameEntity ->
|
||||
if (downloadEntity.gameId == gameEntity.id) {
|
||||
notifyItemChanged(position - getIndex())
|
||||
return
|
||||
@ -189,7 +191,7 @@ class GameHorizontalAdapter(
|
||||
}
|
||||
|
||||
fun notifyChildItem(packageName: String) {
|
||||
mSubjectEntity.data?.forEachIndexed { position, gameEntity ->
|
||||
subjectEntity.data?.forEachIndexed { position, gameEntity ->
|
||||
gameEntity.getApk().forEach { apkEntity ->
|
||||
if (apkEntity.packageName == packageName) {
|
||||
notifyItemChanged(position - getIndex())
|
||||
@ -206,11 +208,11 @@ class GameHorizontalAdapter(
|
||||
dataIds += it.id
|
||||
}
|
||||
|
||||
mSubjectEntity = subjectEntity
|
||||
if (countAndKey?.first == subjectEntity.data?.size && countAndKey?.second != dataIds) { // 数量不变,内容发生改变
|
||||
notifyItemRangeChanged(0, itemCount)
|
||||
} else if (countAndKey?.first != subjectEntity.data?.size) { // 数量发生改变
|
||||
this.subjectEntity = subjectEntity
|
||||
if (countAndKey?.first != subjectEntity.data?.size) { // 数量发生改变
|
||||
notifyDataSetChanged()
|
||||
} else {
|
||||
notifyItemRangeChanged(0, itemCount)
|
||||
}
|
||||
|
||||
// 重新刷新数据标识
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1210,4 +1206,8 @@ class GameCollectionDetailFragment :
|
||||
appbar.setExpanded(true)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val INITIAL_DELAY = 500L
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
@ -73,6 +73,7 @@ class GameCollectionHotListAdapter(
|
||||
if (holder is GameCollectionPlayerCreationAdapter.GameCollectionPlayerCreationHeaderItemViewHolder) {
|
||||
holder.binding.run {
|
||||
root.setPadding(0, if (mIsFromDetail) 16F.dip2px() else 0, 0, 12F.dip2px())
|
||||
timeSfv.visibility = View.GONE
|
||||
tipsIv.visibility = View.GONE
|
||||
tipsTv.text = mGameCollectionListEntity?.explain
|
||||
tipsTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(mContext))
|
||||
|
||||
@ -617,6 +617,7 @@ class GameCollectionSquareFragment : LazyListFragment<GamesCollectionEntity, Gam
|
||||
mAlternativeBinding.listRv.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
super.onScrollStateChanged(recyclerView, newState)
|
||||
if (!isSupportVisible) return
|
||||
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
|
||||
setFabStatus(mPostFabView, View.GONE)
|
||||
setFabStatus(mRefreshFabView, View.GONE)
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
package com.gh.gamecenter.gamedetail
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.halo.assistant.member.MemberUseCase
|
||||
import com.halo.assistant.accelerator.AccelerationUseCase
|
||||
|
||||
class AcceleratorZoneViewModel : ViewModel() {
|
||||
|
||||
val useCase = MemberUseCase()
|
||||
val useCase = AccelerationUseCase()
|
||||
|
||||
override fun onCleared() {
|
||||
useCase.onClear()
|
||||
|
||||
@ -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
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,22 +5,21 @@ import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.core.provider.IAcceleratorProvider
|
||||
import com.gh.gamecenter.feature.entity.BaseEntity
|
||||
import com.gh.gamecenter.feature.entity.TrialEntity
|
||||
import com.gh.gamecenter.feature.entity.VipEntity
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.login.user.UserRepository
|
||||
import com.halo.assistant.member.MemberUseCase
|
||||
import com.therouter.TheRouter
|
||||
import com.halo.assistant.accelerator.AccelerationUseCase
|
||||
import com.halo.assistant.accelerator.repository.AcceleratorDataHolder
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
|
||||
class StartingAcceleratorViewModel : ViewModel() {
|
||||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
val useCase = MemberUseCase()
|
||||
val useCase = AccelerationUseCase()
|
||||
|
||||
private val _restartingAcceleratorAction = MutableLiveData<Event<Boolean>>()
|
||||
val restartingAcceleratorAction: LiveData<Event<Boolean>> = _restartingAcceleratorAction
|
||||
@ -43,15 +42,15 @@ class StartingAcceleratorViewModel : ViewModel() {
|
||||
override fun onSuccess(data: BaseEntity<TrialEntity>) {
|
||||
if (data.data?.result == true) {
|
||||
// 刷新vip状态
|
||||
// 这里先刷新内存数据,再去刷新api数据
|
||||
TheRouter.get(IAcceleratorProvider::class.java)?.setVipEntity(
|
||||
// 这里先刷新内存数据
|
||||
AcceleratorDataHolder.instance.setVipEntity(
|
||||
VipEntity(
|
||||
_vipStatus = true,
|
||||
_isNewUser = false,
|
||||
_isTryVip = true
|
||||
)
|
||||
)
|
||||
refreshVipStatus(userId)
|
||||
|
||||
_rechargeTrailResult.value = Event(true)
|
||||
} else {
|
||||
_rechargeTrailResult.value = Event(false)
|
||||
@ -65,10 +64,6 @@ class StartingAcceleratorViewModel : ViewModel() {
|
||||
}).let(compositeDisposable::add)
|
||||
}
|
||||
|
||||
private fun refreshVipStatus(userId: String) {
|
||||
UserRepository.getInstance().refreshVipStatus(userId, true)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
compositeDisposable.clear()
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
package com.gh.gamecenter.gamedetail.accelerator
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import androidx.room.Upsert
|
||||
import com.gh.gamecenter.feature.entity.AcctGameInfo
|
||||
import com.gh.gamecenter.feature.entity.AcctRecord
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
|
||||
@Dao
|
||||
interface AccelerationDao {
|
||||
|
||||
@Upsert
|
||||
fun upsertAcctGameInfo(gameInfo: AcctGameInfo): Single<Long>
|
||||
|
||||
@Upsert
|
||||
fun upsertAcctRecord(record: AcctRecord): Single<Long>
|
||||
|
||||
/**
|
||||
* 为什么这里定义成 Observable<List<AcctGameInfo>> 而不是 Observable<AcctGameInfo>
|
||||
* 因为当返回值为 Observable<T> 时,当表中未查询到数据,则不会收到任何回调
|
||||
* 使用 Observable<List<AcctGameInfo>>时,为查询到数据时会返回空数组
|
||||
*/
|
||||
@Query("SELECT * FROM AcctGameInfo WHERE gameId = :gameId")
|
||||
fun getAcctGameInfoByGameIdObservable(gameId: String): Observable<List<AcctGameInfo>>
|
||||
|
||||
@Query("SELECT EXISTS(SELECT 1 FROM AcctGameInfo LIMIT 1)")
|
||||
fun hasAnyAcctGameInfo(): Single<Boolean>
|
||||
|
||||
@Query("SELECT * FROM AcctGameInfo WHERE gameId IN (:gameIds)")
|
||||
fun queryAcctGameInfoByGameId(gameIds: List<String>): List<AcctGameInfo>
|
||||
|
||||
@Query("SELECT * FROM AcctRecord ORDER BY createTime DESC LIMIT 20")
|
||||
fun loadAcctRecordsObservable(): Observable<List<AcctRecord>>
|
||||
|
||||
@Query("SELECT * FROM AcctRecord ORDER BY createTime DESC LIMIT 20")
|
||||
fun loadAcctRecords(): List<AcctRecord>
|
||||
|
||||
/**
|
||||
* 获取最新的记录(根据createTime排序)
|
||||
* @return 最新的AcctRecord记录
|
||||
*/
|
||||
@Query("SELECT * FROM AcctRecord ORDER BY createTime DESC LIMIT 1")
|
||||
fun loadLatestRecord(): Single<AcctRecord>
|
||||
|
||||
@Query("SELECT EXISTS(SELECT 1 FROM AcctRecord LIMIT 1)")
|
||||
fun getAnyAcctRecordObservable(): Observable<Boolean>
|
||||
}
|
||||
@ -5,14 +5,16 @@ import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.gh.gamecenter.feature.entity.AcctGameInfo
|
||||
import com.gh.gamecenter.feature.entity.AcctZoneListBean
|
||||
import com.gh.gamecenter.feature.entity.AcctRecord
|
||||
import com.gh.gamecenter.room.converter.AcctGameInfoConverter
|
||||
import com.halo.assistant.HaloApp
|
||||
|
||||
@Database(
|
||||
entities = [AcctGameInfo::class, AcctZoneListBean::class],
|
||||
version = 1,
|
||||
entities = [AcctGameInfo::class, AcctRecord::class],
|
||||
version = 2,
|
||||
exportSchema = false
|
||||
)
|
||||
@TypeConverters(
|
||||
@ -20,7 +22,7 @@ import com.halo.assistant.HaloApp
|
||||
)
|
||||
abstract class AccelerationDataBase : RoomDatabase() {
|
||||
|
||||
abstract fun accelerationDao(): AcceleratorDao
|
||||
abstract fun accelerationDao(): AccelerationDao
|
||||
|
||||
companion object {
|
||||
private const val DATABASE_NAME: String = "acceleration_db"
|
||||
@ -29,7 +31,63 @@ abstract class AccelerationDataBase : RoomDatabase() {
|
||||
|
||||
private fun buildDatabase(context: Context): AccelerationDataBase {
|
||||
return Room.databaseBuilder(context, AccelerationDataBase::class.java, DATABASE_NAME)
|
||||
.addMigrations(MIGRATION_1_2)
|
||||
.allowMainThreadQueries()
|
||||
.build()
|
||||
}
|
||||
|
||||
private val MIGRATION_1_2 = object : Migration(1, 2) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
// 删除表 AcctZoneListBean
|
||||
db.execSQL("DROP TABLE IF EXISTS AcctZoneListBean")
|
||||
// 创建新表的SQL ,游戏加速成功记录
|
||||
createAcctRecordTab(db)
|
||||
|
||||
renamePrimaryKeyWithAcctGameInfoTab(db)
|
||||
|
||||
}
|
||||
|
||||
private fun createAcctRecordTab(db: SupportSQLiteDatabase) {
|
||||
db.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS AcctRecord (
|
||||
gameId TEXT PRIMARY KEY NOT NULL,
|
||||
game TEXT NOT NULL,
|
||||
zoneInfo TEXT NOT NULL,
|
||||
hasMultiZone INTEGER NOT NULL,
|
||||
createTime INTEGER NOT NULL
|
||||
)
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 重命名表 AcctGameInfo 主键
|
||||
* 游戏旧表中没有 gameId 字段,这里将旧表数据直接清空
|
||||
*/
|
||||
private fun renamePrimaryKeyWithAcctGameInfoTab(db: SupportSQLiteDatabase) {
|
||||
// 1. 创建临时表(包含新的结构)
|
||||
db.execSQL(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS AcctGameInfo_temp (
|
||||
gameId TEXT PRIMARY KEY NOT NULL,
|
||||
accGamePkgName TEXT NOT NULL,
|
||||
zoneInfo TEXT NOT NULL,
|
||||
notifyGameName TEXT,
|
||||
notifyGameTxtTitle TEXT,
|
||||
notifyGameSmallLogo INTEGER,
|
||||
notifyGameLargeLogo INTEGER,
|
||||
notifyClickParam TEXT
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
// 2. 删除旧表
|
||||
db.execSQL("DROP TABLE AcctGameInfo")
|
||||
|
||||
// 3. 重命名新表
|
||||
db.execSQL("ALTER TABLE AcctGameInfo_temp RENAME TO AcctGameInfo")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
package com.gh.gamecenter.gamedetail.accelerator
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Query
|
||||
import androidx.room.Upsert
|
||||
import com.gh.gamecenter.feature.entity.AcctGameInfo
|
||||
import com.gh.gamecenter.feature.entity.AcctZoneListBean
|
||||
import io.reactivex.Single
|
||||
|
||||
@Dao
|
||||
interface AcceleratorDao {
|
||||
|
||||
@Upsert
|
||||
fun upsertAcctGameInfo(gameInfo: AcctGameInfo): Single<Long>
|
||||
|
||||
@Query("SELECT * FROM AcctGameInfo WHERE accGamePkgName = :pkgName")
|
||||
fun findByPackageName(pkgName: String): LiveData<AcctGameInfo?>
|
||||
|
||||
@Upsert
|
||||
fun upsertAcctZoneListBean(acctZoneListBean: AcctZoneListBean): Single<Long>
|
||||
|
||||
@Query("SELECT * FROM AcctZoneListBean WHERE pkgName = :pkgName")
|
||||
fun findZoneListBeanByPkgName(pkgName: String): LiveData<AcctZoneListBean?>
|
||||
}
|
||||
@ -12,16 +12,17 @@ import com.gh.gamecenter.core.callback.AccelerateState
|
||||
import com.gh.gamecenter.core.callback.OnAccelerateListener
|
||||
import com.gh.gamecenter.core.provider.IAcceleratorProvider
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.databinding.DetailDownloadItemBinding
|
||||
import com.gh.gamecenter.feature.entity.AcctGameInfo
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.gamedetail.accelerator.chain.*
|
||||
import com.gh.gamecenter.feature.entity.VipEntity
|
||||
import com.gh.gamecenter.gamedetail.accelerator.chain.AcceleratorClient
|
||||
import com.gh.gamecenter.gamedetail.accelerator.chain.AcceleratorValidator
|
||||
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorDialogFragment
|
||||
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorDialogFragment.Companion.SPEED_STOP
|
||||
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorZoneDialogFragment
|
||||
import com.gh.gamecenter.gamedetail.accelerator.dialog.StartingAcceleratorDialogFragment
|
||||
import com.halo.assistant.member.MemberRepository
|
||||
import com.halo.assistant.accelerator.repository.AcceleratorDataHolder
|
||||
import com.therouter.TheRouter
|
||||
|
||||
class GameDetailAcceleratorUiHelper(private val binding: DetailDownloadItemBinding) {
|
||||
@ -30,54 +31,41 @@ class GameDetailAcceleratorUiHelper(private val binding: DetailDownloadItemBindi
|
||||
|
||||
private var guideView: AcceleratorGuideView? = null
|
||||
|
||||
val isGuideLayerShowing: Boolean
|
||||
get() = guideView?.isShowing ?: false
|
||||
private lateinit var game: GameEntity
|
||||
|
||||
private val zoneList = arrayListOf<AcctGameInfo>()
|
||||
private var hasZoneListLoaded = false
|
||||
private var isGuideLayerShowing = false
|
||||
|
||||
private var _last: AcctGameInfo? = null
|
||||
val last: AcctGameInfo?
|
||||
private val last: AcctGameInfo?
|
||||
get() = _last
|
||||
|
||||
private val hasMultiZone: Boolean
|
||||
get() = zoneList.size > 1
|
||||
|
||||
private val hasZone: Boolean
|
||||
get() = zoneList.isNotEmpty()
|
||||
get() = game.serviceArea.size > 1
|
||||
|
||||
private val isVip: Boolean
|
||||
get() = iAcceleratorProvider?.isVip() ?: false
|
||||
get() = AcceleratorDataHolder.instance.isVip
|
||||
|
||||
val isNewUser: Boolean
|
||||
get() = iAcceleratorProvider?.isNewUser() ?: false
|
||||
get() = AcceleratorDataHolder.instance.isNewUser
|
||||
|
||||
private var canSpeed = false
|
||||
private val isInit: Boolean
|
||||
get() = ::game.isInitialized
|
||||
|
||||
var showSpeedUi = false
|
||||
val context: Context
|
||||
get() = binding.root.context
|
||||
|
||||
private var _game: GameEntity? = null
|
||||
fun setGame(game: GameEntity?) {
|
||||
_game = game
|
||||
}
|
||||
private var hasAnyAcctRecord = false
|
||||
|
||||
private val accelerationListener = object : OnAccelerateListener {
|
||||
override fun onStateChanged(state: AccelerateState) {
|
||||
when (state) {
|
||||
is AccelerateState.Success -> {
|
||||
_game?.let {
|
||||
val acctGameInfo = state.acctGameInfo
|
||||
if (acctGameInfo is AcctGameInfo) {
|
||||
setCurrentAcctGameInfo(acctGameInfo)
|
||||
}
|
||||
updateSpeedUi()
|
||||
}
|
||||
updateSpeedUi()
|
||||
|
||||
}
|
||||
|
||||
is AccelerateState.Normal -> {
|
||||
if (!state.isTokenExpired) {
|
||||
updateSpeedUi()
|
||||
}
|
||||
updateSpeedUi()
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
@ -86,94 +74,78 @@ class GameDetailAcceleratorUiHelper(private val binding: DetailDownloadItemBindi
|
||||
|
||||
override fun onProgress(progress: Int, curGamePkgName: String?, curGameZoneFlag: String?) = Unit
|
||||
|
||||
override fun onVipStatusChanged(isNewUser: Boolean, isVip: Boolean) {
|
||||
binding.ivFreeVipTag.visibleIf(
|
||||
showSpeedUi &&
|
||||
CheckLoginUtils.isLogin() &&
|
||||
isNewUser &&
|
||||
!isGuideLayerShowing
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun initSpeedUi(context: Context) {
|
||||
canSpeed = true
|
||||
|
||||
_game?.let {
|
||||
iAcceleratorProvider?.bindAccRelatedListener(it.getUniquePackageName() ?: "", accelerationListener)
|
||||
private val onDataHolderListener = object : AcceleratorDataHolder.OnDataHolderListener {
|
||||
override fun onVipStateChanged(vip: VipEntity) {
|
||||
showFreeTag()
|
||||
}
|
||||
}
|
||||
|
||||
fun initUi(game: GameEntity, context: Context) {
|
||||
this.game = game
|
||||
iAcceleratorProvider?.bindAccRelatedListener(game.getUniquePackageName() ?: "", accelerationListener)
|
||||
AcceleratorDataHolder.instance.addListener(onDataHolderListener)
|
||||
|
||||
binding.vSpeedContent.setOnClickListener {
|
||||
_game?.let { game ->
|
||||
checkDataReady {
|
||||
startAccelerating(context, game, false)
|
||||
}
|
||||
}
|
||||
startAccelerating(context, game, false)
|
||||
}
|
||||
binding.vMoreZone.setOnClickListener {
|
||||
_game?.let { game ->
|
||||
checkDataReady {
|
||||
showZoneList(context, game)
|
||||
}
|
||||
}
|
||||
showZoneList(context, game)
|
||||
}
|
||||
|
||||
binding.tvStopSpeed.setOnClickListener {
|
||||
_game?.let {
|
||||
SensorsBridge.trackNetworkAccelerationOtherButtonClick(
|
||||
it.getUniquePackageName() ?: "",
|
||||
it.id,
|
||||
it.name ?: "",
|
||||
iAcceleratorProvider?.getMemberType() ?: "",
|
||||
BUTTON_NAME_STOP_ACCELERATOR,
|
||||
SOURCE_ENTRANCE_GAME_DETAIL
|
||||
)
|
||||
|
||||
AcceleratorDialogFragment.show(
|
||||
SPEED_STOP, it.getUniquePackageName() ?: "", it.id, it.name ?: "",
|
||||
SOURCE_ENTRANCE_GAME_DETAIL, context
|
||||
)
|
||||
}
|
||||
|
||||
SensorsBridge.trackNetworkAccelerationOtherButtonClick(
|
||||
game.getUniquePackageName() ?: "",
|
||||
game.id,
|
||||
game.name ?: "",
|
||||
AcceleratorDataHolder.instance.memberType,
|
||||
BUTTON_NAME_STOP_ACCELERATOR,
|
||||
SOURCE_ENTRANCE_GAME_DETAIL
|
||||
)
|
||||
|
||||
AcceleratorDialogFragment.show(
|
||||
SPEED_STOP, game.getUniquePackageName() ?: "", game.id, game.name ?: "",
|
||||
SOURCE_ENTRANCE_GAME_DETAIL, context
|
||||
)
|
||||
}
|
||||
|
||||
binding.tvEnterGame.setOnClickListener {
|
||||
_game?.let { game ->
|
||||
SensorsBridge.trackNetworkAccelerationOtherButtonClick(
|
||||
game.getUniquePackageName() ?: "",
|
||||
game.id,
|
||||
game.name ?: "",
|
||||
iAcceleratorProvider?.getMemberType() ?: "",
|
||||
BUTTON_NAME_ENTER_GAME,
|
||||
SOURCE_ENTRANCE_GAME_DETAIL
|
||||
)
|
||||
PackageLauncher.launchApp(context, game, game.getUniquePackageName())
|
||||
}
|
||||
|
||||
SensorsBridge.trackNetworkAccelerationOtherButtonClick(
|
||||
game.getUniquePackageName() ?: "",
|
||||
game.id,
|
||||
game.name ?: "",
|
||||
AcceleratorDataHolder.instance.memberType,
|
||||
BUTTON_NAME_ENTER_GAME,
|
||||
SOURCE_ENTRANCE_GAME_DETAIL
|
||||
)
|
||||
PackageLauncher.launchApp(context, game, game.getUniquePackageName())
|
||||
}
|
||||
|
||||
updateSpeedUi()
|
||||
}
|
||||
|
||||
fun updateSpeedUi() {
|
||||
if (!showSpeedUi) {
|
||||
if (!isInit || !showSpeedUi) {
|
||||
return
|
||||
}
|
||||
val hasGameBeingAccelerated = iAcceleratorProvider?.isCurAccSuccess() ?: false
|
||||
val isCurAccSuccess = hasGameBeingAccelerated &&
|
||||
MemberRepository.instance.acctGameRecord.gameId == (_game?.id ?: "")
|
||||
binding.detailProgressbar.goneIf(isCurAccSuccess)
|
||||
binding.clSpeed.goneIf(isCurAccSuccess)
|
||||
binding.gAccelerating.goneIf(!isCurAccSuccess)
|
||||
|
||||
val isCurrentGameAccelerating = AcceleratorDataHolder.instance.isCurrentGameAccelerating(game.id)
|
||||
|
||||
when {
|
||||
isCurrentGameAccelerating -> {// 如果当前游戏正处于加速状态,则需要隐藏当前下载按钮
|
||||
binding.detailProgressbar.goneIf(true)
|
||||
}
|
||||
|
||||
binding.detailProgressbar.text == "更新" -> { // 游戏没有处于加速状态,如果 下载按钮为 “更新” 状态,则需要显示出来
|
||||
binding.detailProgressbar.goneIf(false)
|
||||
}
|
||||
}
|
||||
|
||||
binding.clSpeed.goneIf(isCurrentGameAccelerating)
|
||||
binding.gAccelerating.goneIf(!isCurrentGameAccelerating)
|
||||
binding.gMoreZone.goneIf(!hasMultiZone)
|
||||
binding.ivFreeVipTag.visibleIf(
|
||||
showSpeedUi &&
|
||||
CheckLoginUtils.isLogin() &&
|
||||
isNewUser &&
|
||||
!isGuideLayerShowing
|
||||
)
|
||||
showFreeTag()
|
||||
binding.tvSpeed.text = if (hasMultiZone) {
|
||||
last?.zoneName
|
||||
} else {
|
||||
@ -181,67 +153,81 @@ class GameDetailAcceleratorUiHelper(private val binding: DetailDownloadItemBindi
|
||||
} ?: R.string.network_acceleration.toResString()
|
||||
}
|
||||
|
||||
/**
|
||||
* 在这个方法里确定是否需要展示 加速ui
|
||||
* 当 clSpeedContainer没有显示时,调用updateSpeedUi()无效,可以调用initSpeedUi()
|
||||
* 请注意,只要是 gameDetail 发生变化,这里就会回调,所以当 canSpeed 确定之后,这里最少还会回调一次
|
||||
*/
|
||||
fun checkIfShowGuideLayer(context: Context) {
|
||||
showSpeedUi = canSpeed
|
||||
fun checkIfShowSpeedUi(show: Boolean) {
|
||||
if (!isInit) {
|
||||
return
|
||||
}
|
||||
showSpeedUi = show
|
||||
binding.clSpeedContainer.goneIf(!showSpeedUi) {
|
||||
// canSpeed =true 说明detail接口已完成
|
||||
binding.detailProgressbar.setBackgroundResource(com.gh.gamecenter.common.R.drawable.bg_common_button_light_fill_blue)
|
||||
binding.detailProgressbar.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
// 是否需要展示弹窗
|
||||
showGuideLayerIfNeed()
|
||||
updateSpeedUi()
|
||||
if (CheckLoginUtils.isLogin()) {
|
||||
if (!hasShow()) {
|
||||
// 优先显示弹窗
|
||||
binding.ivFreeVipTag.visibleIf(false)
|
||||
showGuideLayer(context)
|
||||
}
|
||||
} else {
|
||||
// 未登录
|
||||
binding.ivFreeVipTag.visibleIf(false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showFreeTag() {
|
||||
binding.ivFreeVipTag.visibleIf(
|
||||
showSpeedUi && last == null && !isGuideLayerShowing &&
|
||||
(!CheckLoginUtils.isLogin() || isNewUser)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 需要同时满足这四个条件,才需要判断是否需要展示弹窗
|
||||
*/
|
||||
var isButtonSizeDetermined = false // 底部下载按钮尺寸是否已确定
|
||||
private var isLastLoaded = false // 本地存在区服记录(用户点击过选择区服/启动加速)
|
||||
private var hasAnyAcctRecordLoaded = false // 已获取:是否存在加速成功的游戏记录
|
||||
private var showSpeedUi = false // 显示加速器ui
|
||||
fun showGuideLayerIfNeed() {
|
||||
if (isButtonSizeDetermined && hasAnyAcctRecordLoaded && isLastLoaded && showSpeedUi) {
|
||||
if (shouldShowGuideLayer()) {
|
||||
isGuideLayerShowing = true
|
||||
showGuideLayer(context)
|
||||
}
|
||||
showFreeTag()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun shouldShowGuideLayer() =
|
||||
!SPUtils.getBoolean(Constants.SP_HAS_SHOW_ACCELERATION_GUIDE_LAYER) &&
|
||||
!hasAnyAcctRecord &&
|
||||
last == null &&
|
||||
!isGuideLayerShowing
|
||||
|
||||
private fun showGuideLayer(context: Context) {
|
||||
if (!hasShow()) {
|
||||
binding.root.post {
|
||||
val uiListener = object : OnAcceleratorListener {
|
||||
override fun onStartAccelerator() {
|
||||
_game?.let {
|
||||
startAccelerating(context, it, true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onGuideLayerDismiss() {
|
||||
binding.ivFreeVipTag.visibleIf(CheckLoginUtils.isLogin() && hasZone && isNewUser)
|
||||
}
|
||||
|
||||
binding.root.post {
|
||||
val uiListener = object : OnAcceleratorListener {
|
||||
override fun onStartAccelerator() {
|
||||
startAccelerating(context, game, true)
|
||||
}
|
||||
SPUtils.setBoolean(Constants.SP_HAS_SHOW_ACCELERATION_GUIDE_LAYER, true)
|
||||
if (guideView == null) {
|
||||
guideView = AcceleratorGuideView(context).apply {
|
||||
setDismissListener(uiListener::onGuideLayerDismiss)
|
||||
}
|
||||
|
||||
override fun onGuideLayerDismiss() {
|
||||
isGuideLayerShowing = false
|
||||
showFreeTag()
|
||||
}
|
||||
(guideView?.parent as? ViewGroup)?.removeView(guideView)
|
||||
if (context is AppCompatActivity) {
|
||||
_game?.let {
|
||||
SensorsBridge.trackNetworkAccelerationGuidanceDiagramShow(
|
||||
it.getUniquePackageName() ?: "",
|
||||
it.id,
|
||||
it.name ?: ""
|
||||
)
|
||||
}
|
||||
guideView?.show(binding.clSpeedContainer, context, uiListener::onStartAccelerator)
|
||||
|
||||
}
|
||||
SPUtils.setBoolean(Constants.SP_HAS_SHOW_ACCELERATION_GUIDE_LAYER, true)
|
||||
if (guideView == null) {
|
||||
guideView = AcceleratorGuideView(context).apply {
|
||||
setDismissListener(uiListener::onGuideLayerDismiss)
|
||||
}
|
||||
}
|
||||
(guideView?.parent as? ViewGroup)?.removeView(guideView)
|
||||
if (context is AppCompatActivity) {
|
||||
SensorsBridge.trackNetworkAccelerationGuidanceDiagramShow(
|
||||
game.getUniquePackageName() ?: "",
|
||||
game.id,
|
||||
game.name ?: ""
|
||||
)
|
||||
guideView?.show(binding.clSpeedContainer, context, uiListener::onStartAccelerator)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun onBack(): Boolean {
|
||||
@ -254,21 +240,13 @@ class GameDetailAcceleratorUiHelper(private val binding: DetailDownloadItemBindi
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasShow(): Boolean {
|
||||
return SPUtils.getBoolean(Constants.SP_HAS_SHOW_ACCELERATION_GUIDE_LAYER)
|
||||
}
|
||||
|
||||
private fun startAccelerating(context: Context, game: GameEntity, isShowing: Boolean) {
|
||||
if (isInvalidClick() || !hasZone) {
|
||||
if (isInvalidClick()) {
|
||||
return
|
||||
}
|
||||
val lastAcctGameInfo = last
|
||||
|
||||
val memberType = if (CheckLoginUtils.isLogin()) {
|
||||
iAcceleratorProvider?.getMemberType() ?: ""
|
||||
} else {
|
||||
MEMBER_TYPE_NOT_LOGIN
|
||||
}
|
||||
val memberType = AcceleratorDataHolder.instance.memberType
|
||||
val districtServer = when {
|
||||
hasMultiZone && lastAcctGameInfo != null -> lastAcctGameInfo.zoneName
|
||||
hasMultiZone -> DISTRICT_SERVER_EMPTY
|
||||
@ -286,34 +264,44 @@ class GameDetailAcceleratorUiHelper(private val binding: DetailDownloadItemBindi
|
||||
|
||||
when {
|
||||
lastAcctGameInfo != null ->
|
||||
doStartAccelerating(context, game, lastAcctGameInfo)
|
||||
doStartAccelerating(context, game, lastAcctGameInfo.zoneInfo)
|
||||
|
||||
hasMultiZone -> context.ifLogin("[网络加速]") {
|
||||
AcceleratorZoneDialogFragment.show(
|
||||
context, last?.zoneInfo?.id, game.serviceArea, game,
|
||||
SOURCE_ENTRANCE_GAME_DETAIL
|
||||
)
|
||||
}
|
||||
|
||||
hasMultiZone -> AcceleratorZoneDialogFragment.show(context, zoneList, game)
|
||||
else -> {
|
||||
val gameInfo = zoneList.firstOrNull() ?: AcctGameInfo("", AcctGameInfo.ZoneInfo(0))
|
||||
val gameInfo = game.serviceArea.firstOrNull() ?: AcctGameInfo.ZoneInfo(0)
|
||||
doStartAccelerating(context, game, gameInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showZoneList(context: Context, game: GameEntity) {
|
||||
if (isInvalidClick() || !hasZone) {
|
||||
if (isInvalidClick()) {
|
||||
return
|
||||
}
|
||||
AcceleratorZoneDialogFragment.show(context, zoneList, game)
|
||||
|
||||
context.ifLogin("[网络加速]") {
|
||||
AcceleratorZoneDialogFragment.show(
|
||||
context, last?.zoneInfo?.id, game.serviceArea, game,
|
||||
SOURCE_ENTRANCE_GAME_DETAIL
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private var clickTime = 0L
|
||||
|
||||
private fun doStartAccelerating(context: Context, game: GameEntity, acctGameInfo: AcctGameInfo) {
|
||||
private fun doStartAccelerating(context: Context, game: GameEntity, zoneInfo: AcctGameInfo.ZoneInfo) {
|
||||
|
||||
val request = AcceleratorValidator.Request(isVip, isNewUser, game, SOURCE_ENTRANCE_GAME_DETAIL)
|
||||
AcceleratorClient.newInstance()
|
||||
.execute(context, request, object : AcceleratorValidator.ValidateListener {
|
||||
override fun finished(context: Context) {
|
||||
StartingAcceleratorDialogFragment.show(
|
||||
context, acctGameInfo, game, true, hasMultiZone,
|
||||
context, zoneInfo, game, true, hasMultiZone,
|
||||
SOURCE_ENTRANCE_GAME_DETAIL,
|
||||
)
|
||||
}
|
||||
@ -321,27 +309,18 @@ class GameDetailAcceleratorUiHelper(private val binding: DetailDownloadItemBindi
|
||||
}
|
||||
|
||||
fun setCurrentAcctGameInfo(acctGameInfo: AcctGameInfo?) {
|
||||
_last = acctGameInfo
|
||||
if (hasZoneListLoaded) {
|
||||
isLastLoaded = true
|
||||
if (last?.zoneInfo?.id != acctGameInfo?.zoneInfo?.id) {
|
||||
_last = acctGameInfo
|
||||
updateSpeedUi()
|
||||
}
|
||||
|
||||
showGuideLayerIfNeed()
|
||||
}
|
||||
|
||||
/**
|
||||
* 第一次调用 setZoneList 是使用缓存中的数据
|
||||
* 第二次调用,是使用sdk中的最新数据
|
||||
* 这里优先使用缓存中的,sdk中的数据更新到数据库后,待下次进入详情页在显示
|
||||
* 当zoneList为null时,说明磁盘上没有数据,这时候使用sdk中的
|
||||
*
|
||||
*/
|
||||
fun setZoneList(newZoneList: ArrayList<AcctGameInfo>?) {
|
||||
if (newZoneList != null && zoneList.isEmpty()) {
|
||||
hasZoneListLoaded = true
|
||||
zoneList.clear()
|
||||
zoneList.addAll(newZoneList)
|
||||
updateSpeedUi()
|
||||
}
|
||||
fun setHasAnyAcctRecord(hasAnyAcctRecord: Boolean) {
|
||||
hasAnyAcctRecordLoaded = true
|
||||
this.hasAnyAcctRecord = hasAnyAcctRecord
|
||||
showGuideLayerIfNeed()
|
||||
}
|
||||
|
||||
private fun isInvalidClick(): Boolean {
|
||||
@ -355,38 +334,26 @@ class GameDetailAcceleratorUiHelper(private val binding: DetailDownloadItemBindi
|
||||
return false
|
||||
}
|
||||
|
||||
private fun checkDataReady(block: () -> Unit) {
|
||||
when {
|
||||
!hasZoneListLoaded -> {
|
||||
ToastUtils.showToast("区服信息正在加载中,请稍后再试!")
|
||||
}
|
||||
|
||||
zoneList.isEmpty() -> {
|
||||
ToastUtils.showToast("区服信息加载失败,请稍后再试!")
|
||||
}
|
||||
|
||||
else -> {
|
||||
block()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
iAcceleratorProvider?.unBindAccRelatedListener(accelerationListener)
|
||||
AcceleratorDataHolder.instance.removeListener(onDataHolderListener)
|
||||
guideView?.dismiss()
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
|
||||
private const val CLICK_DURATION = 300
|
||||
const val MEMBER_TYPE_NOT_LOGIN = "未登录"
|
||||
|
||||
private const val DISTRICT_SERVER_EMPTY = "空"
|
||||
|
||||
const val DISTRICT_SERVER_EMPTY = "空"
|
||||
const val DISTRICT_SERVER_HAVA = "有"
|
||||
private const val SCENE_TYPE_HAVE_GUIDE_LAYER = "有引导图"
|
||||
const val SCENE_TYPE_NO_GUIDE_LAYER = "无引导图"
|
||||
const val SOURCE_ENTRANCE_GAME_DETAIL = "游戏详情页"
|
||||
const val SOURCE_ENTRANCE_MY_ASSETS = "我的资产"
|
||||
const val SOURCE_ENTRANCE_SEARCH = "搜索页"
|
||||
const val SOURCE_ENTRANCE_RECENTLY_PLAYED = "最近在玩"
|
||||
const val BUTTON_NAME_ENTER_GAME = "进入游戏"
|
||||
const val BUTTON_NAME_STOP_ACCELERATOR = "停止加速"
|
||||
|
||||
|
||||
@ -2,7 +2,10 @@ package com.gh.gamecenter.gamedetail.accelerator.chain
|
||||
|
||||
import android.content.Context
|
||||
import com.gh.gamecenter.core.provider.IAcceleratorProvider
|
||||
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorDialogFragment
|
||||
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorDialogFragment.Companion.SPEED_CURRENT_ACCELERATING
|
||||
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorReplaceDialogFragment
|
||||
import com.halo.assistant.accelerator.repository.AcceleratorDataHolder
|
||||
import com.therouter.TheRouter
|
||||
|
||||
class AcceleratorStateInterceptor : AcceleratorValidator.Interceptor {
|
||||
@ -16,18 +19,30 @@ class AcceleratorStateInterceptor : AcceleratorValidator.Interceptor {
|
||||
val isAccelerating = iAcceleratorProvider?.isCurAccSuccess() ?: false
|
||||
if (isAccelerating) {
|
||||
val game = request.game
|
||||
AcceleratorReplaceDialogFragment.show(
|
||||
context,
|
||||
game.getUniquePackageName() ?: "",
|
||||
game.id,
|
||||
game.name ?: "",
|
||||
request.sourceEntrance
|
||||
) {
|
||||
if (chain.isValidContext(context)) {
|
||||
listener?.finished(context)
|
||||
val isCurrentAccelerating = AcceleratorDataHolder.instance.isCurrentGameAccelerating(game.id)
|
||||
if (isCurrentAccelerating) {
|
||||
AcceleratorDialogFragment.show(
|
||||
SPEED_CURRENT_ACCELERATING,
|
||||
game.getUniquePackageName() ?: "",
|
||||
game.id,
|
||||
game.name ?: "",
|
||||
request.sourceEntrance,
|
||||
context
|
||||
)
|
||||
} else {
|
||||
AcceleratorReplaceDialogFragment.show(
|
||||
context,
|
||||
game.getUniquePackageName() ?: "",
|
||||
game.id,
|
||||
game.name ?: "",
|
||||
request.sourceEntrance
|
||||
) {
|
||||
if (chain.isValidContext(context)) {
|
||||
listener?.finished(context)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
chain.proceed(context, request, listener)
|
||||
}
|
||||
|
||||
@ -10,7 +10,6 @@ import androidx.annotation.IntDef
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.common.HaloApp
|
||||
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
@ -56,6 +55,11 @@ class AcceleratorDialogFragment : BaseDialogFragment() {
|
||||
|
||||
SPEED_STOP -> StopSpeedUi()
|
||||
SPEED_NOT_INSTALLED -> NotInstalledUi()
|
||||
SPEED_CURRENT_ACCELERATING -> {
|
||||
SensorsBridge.trackStopAcceleratingDialogShow(gameId, gameName, pkgName)
|
||||
CurrentAcceleratingUi()
|
||||
}
|
||||
|
||||
else -> throw IllegalArgumentException("请传递正确的参数 SpeedType !")
|
||||
}
|
||||
}
|
||||
@ -102,8 +106,7 @@ class AcceleratorDialogFragment : BaseDialogFragment() {
|
||||
sourceEntrance
|
||||
)
|
||||
SensorsBridge.trackMyAssetsPageShow(pkgName, gameId, gameName, sourceEntrance)
|
||||
val intent = WebActivity.getMyAssetsIntent(requireContext())
|
||||
startActivity(intent)
|
||||
DirectUtils.navigateToMyAssetsPage(requireContext(), sourceEntrance)
|
||||
}
|
||||
|
||||
is SpeedFailureUi -> {
|
||||
@ -113,7 +116,7 @@ class AcceleratorDialogFragment : BaseDialogFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
is StopSpeedUi -> {
|
||||
is StopSpeedUi, is CurrentAcceleratingUi -> {
|
||||
TheRouter.get(IAcceleratorProvider::class.java)?.stopQyGameAccelerate()
|
||||
}
|
||||
|
||||
@ -134,6 +137,7 @@ class AcceleratorDialogFragment : BaseDialogFragment() {
|
||||
const val SPEED_START_FAILURE = 2
|
||||
const val SPEED_STOP = 3
|
||||
const val SPEED_NOT_INSTALLED = 4
|
||||
const val SPEED_CURRENT_ACCELERATING = 5
|
||||
|
||||
fun show(
|
||||
@SpeedType type: Int,
|
||||
@ -163,7 +167,7 @@ class AcceleratorDialogFragment : BaseDialogFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
@IntDef(SPEED_ENABLE_VIP, SPEED_START_FAILURE, SPEED_STOP, SPEED_NOT_INSTALLED)
|
||||
@IntDef(SPEED_ENABLE_VIP, SPEED_START_FAILURE, SPEED_STOP, SPEED_NOT_INSTALLED, SPEED_CURRENT_ACCELERATING)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class SpeedType
|
||||
|
||||
@ -238,4 +242,19 @@ class AcceleratorDialogFragment : BaseDialogFragment() {
|
||||
override val submitResId: Int
|
||||
get() = R.string.dialog_hint_confirm
|
||||
}
|
||||
|
||||
class CurrentAcceleratingUi : SpeedDialogUiHelper() {
|
||||
override val contentResId: Int
|
||||
get() = R.string.speed_current_game_accelerating
|
||||
|
||||
override val isShowCancelButton: Boolean
|
||||
get() = true
|
||||
|
||||
override val submitResId: Int
|
||||
get() = R.string.stop_speed
|
||||
|
||||
override val cancelResId: Int
|
||||
get() = R.string.cancel
|
||||
|
||||
}
|
||||
}
|
||||
@ -13,26 +13,20 @@ import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import com.gh.common.util.CheckLoginUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.BaseBottomDialogFragment
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.core.provider.IAcceleratorProvider
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.CurrentActivityHolder
|
||||
import com.gh.gamecenter.databinding.DialogFragmentAcceleratorZoneBinding
|
||||
import com.gh.gamecenter.databinding.RecyclerAcceleratorZoneBinding
|
||||
import com.gh.gamecenter.feature.entity.AcctGameInfo
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.gamedetail.accelerator.GameDetailAcceleratorUiHelper.Companion.MEMBER_TYPE_NOT_LOGIN
|
||||
import com.gh.gamecenter.gamedetail.accelerator.GameDetailAcceleratorUiHelper.Companion.SCENE_TYPE_NO_GUIDE_LAYER
|
||||
import com.gh.gamecenter.gamedetail.accelerator.GameDetailAcceleratorUiHelper.Companion.SOURCE_ENTRANCE_GAME_DETAIL
|
||||
import com.gh.gamecenter.gamedetail.AcceleratorZoneViewModel
|
||||
import com.gh.gamecenter.gamedetail.accelerator.GameDetailAcceleratorUiHelper.Companion.SCENE_TYPE_NO_GUIDE_LAYER
|
||||
import com.gh.gamecenter.gamedetail.accelerator.chain.AcceleratorClient
|
||||
import com.gh.gamecenter.gamedetail.accelerator.chain.AcceleratorValidator
|
||||
import com.therouter.TheRouter
|
||||
import com.halo.assistant.accelerator.repository.AcceleratorDataHolder
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class AcceleratorZoneDialogFragment : BaseBottomDialogFragment<DialogFragmentAcceleratorZoneBinding>() {
|
||||
@ -41,21 +35,31 @@ class AcceleratorZoneDialogFragment : BaseBottomDialogFragment<DialogFragmentAcc
|
||||
|
||||
private lateinit var adapter: ZoneAdapter
|
||||
|
||||
private var sourceEntrance = ""
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
sourceEntrance = arguments?.getString(EntranceConsts.KEY_SOURCE_ENTRANCE) ?: ""
|
||||
}
|
||||
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val data =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
arguments?.getParcelableArrayList(KEY_DATA, AcctGameInfo::class.java)
|
||||
arguments?.getParcelableArrayList(EntranceConsts.KEY_DATA, AcctGameInfo.ZoneInfo::class.java)
|
||||
} else {
|
||||
arguments?.getParcelableArrayList(KEY_DATA)
|
||||
} ?: listOf<AcctGameInfo>()
|
||||
arguments?.getParcelableArrayList(EntranceConsts.KEY_DATA)
|
||||
} ?: listOf<AcctGameInfo.ZoneInfo>()
|
||||
|
||||
val game = arguments?.getParcelable<GameEntity>(KEY_GAME)!!
|
||||
val game = arguments?.getParcelable<GameEntity>(EntranceConsts.KEY_GAME)!!
|
||||
val selectedId = arguments?.getInt(KEY_SELECTED_ID) ?: -1
|
||||
|
||||
mBinding.titleView.setOnRightClickListener {
|
||||
dismiss()
|
||||
}
|
||||
|
||||
adapter = ZoneAdapter {
|
||||
startAccelerating(game, it)
|
||||
dismiss()
|
||||
@ -63,39 +67,38 @@ class AcceleratorZoneDialogFragment : BaseBottomDialogFragment<DialogFragmentAcc
|
||||
mBinding.recyclerZone.layoutManager = GridLayoutManager(requireContext(), 3)
|
||||
mBinding.recyclerZone.addItemDecoration(MyDecorationItem())
|
||||
mBinding.recyclerZone.adapter = adapter
|
||||
adapter.submitList(data)
|
||||
adapter.setData(selectedId, data)
|
||||
}
|
||||
|
||||
private fun startAccelerating(game: GameEntity, acctGameInfo: AcctGameInfo) {
|
||||
private fun startAccelerating(game: GameEntity, zoneInfo: AcctGameInfo.ZoneInfo) {
|
||||
context?.let {
|
||||
viewModel.useCase.insertAcctGameInfo(acctGameInfo)
|
||||
val iAcceleratorProvider = TheRouter.get(IAcceleratorProvider::class.java)
|
||||
|
||||
val memberType = if (CheckLoginUtils.isLogin()) {
|
||||
iAcceleratorProvider?.getMemberType() ?: ""
|
||||
} else {
|
||||
MEMBER_TYPE_NOT_LOGIN
|
||||
}
|
||||
viewModel.useCase.insertAcctGameInfo(AcctGameInfo(game.id, game.getUniquePackageName() ?: "", zoneInfo))
|
||||
val acceleratorDataHolder = AcceleratorDataHolder.instance
|
||||
val memberType = acceleratorDataHolder.memberType
|
||||
|
||||
SensorsBridge.trackNetworkAccelerationButtonClick(
|
||||
game.getUniquePackageName() ?: "",
|
||||
game.id,
|
||||
game.name ?: "",
|
||||
memberType,
|
||||
acctGameInfo.zoneInfo.cnName ?: "",
|
||||
zoneInfo.cnName ?: "",
|
||||
SCENE_TYPE_NO_GUIDE_LAYER,
|
||||
SOURCE_ENTRANCE_GAME_DETAIL
|
||||
sourceEntrance
|
||||
)
|
||||
|
||||
val isVip = iAcceleratorProvider?.isVip() ?: false
|
||||
val isNewUser = iAcceleratorProvider?.isNewUser() ?: false
|
||||
val request = AcceleratorValidator.Request(isVip, isNewUser, game, SOURCE_ENTRANCE_GAME_DETAIL)
|
||||
val isVip = acceleratorDataHolder.isVip
|
||||
val isNewUser = acceleratorDataHolder.isNewUser
|
||||
val request = AcceleratorValidator.Request(isVip, isNewUser, game, sourceEntrance)
|
||||
AcceleratorClient.newInstance()
|
||||
.execute(it, request, object : AcceleratorValidator.ValidateListener {
|
||||
override fun finished(context: Context) {
|
||||
StartingAcceleratorDialogFragment.show(
|
||||
context, acctGameInfo, game, isNeedRecord = true, hasMultiZone = true,
|
||||
sourceEntrance = SOURCE_ENTRANCE_GAME_DETAIL
|
||||
context,
|
||||
zoneInfo,
|
||||
game,
|
||||
isNeedRecord = false,
|
||||
hasMultiZone = true,
|
||||
sourceEntrance = sourceEntrance
|
||||
)
|
||||
}
|
||||
|
||||
@ -105,9 +108,14 @@ class AcceleratorZoneDialogFragment : BaseBottomDialogFragment<DialogFragmentAcc
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_DATA = "key_data"
|
||||
private const val KEY_GAME = "key_game"
|
||||
fun show(context: Context, data: ArrayList<AcctGameInfo>, game: GameEntity) {
|
||||
private const val KEY_SELECTED_ID = "key_selected_id"
|
||||
fun show(
|
||||
context: Context,
|
||||
selectedId: Int? = null,
|
||||
data: List<AcctGameInfo.ZoneInfo>,
|
||||
game: GameEntity,
|
||||
sourceEntrance: String
|
||||
) {
|
||||
if (context is AppCompatActivity) {
|
||||
context.supportFragmentManager
|
||||
} else {
|
||||
@ -115,8 +123,10 @@ class AcceleratorZoneDialogFragment : BaseBottomDialogFragment<DialogFragmentAcc
|
||||
}?.let {
|
||||
val fragment = AcceleratorZoneDialogFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putParcelableArrayList(KEY_DATA, data)
|
||||
putParcelable(KEY_GAME, game)
|
||||
putParcelableArrayList(EntranceConsts.KEY_DATA, data.toArrayList())
|
||||
putParcelable(EntranceConsts.KEY_GAME, game)
|
||||
putInt(KEY_SELECTED_ID, selectedId ?: -1)
|
||||
putString(EntranceConsts.KEY_SOURCE_ENTRANCE, sourceEntrance)
|
||||
}
|
||||
}
|
||||
fragment.show(it, fragment::class.java.simpleName)
|
||||
@ -140,10 +150,15 @@ class AcceleratorZoneDialogFragment : BaseBottomDialogFragment<DialogFragmentAcc
|
||||
}
|
||||
}
|
||||
|
||||
class ZoneAdapter(private val click: (AcctGameInfo) -> Unit) :
|
||||
ListAdapter<AcctGameInfo, ZoneAdapter.ZoneViewHolder>(diffCallback) {
|
||||
class ZoneAdapter(private val click: (AcctGameInfo.ZoneInfo) -> Unit) :
|
||||
ListAdapter<AcctGameInfo.ZoneInfo, ZoneAdapter.ZoneViewHolder>(diffCallback) {
|
||||
|
||||
private var selectedPosition = -1
|
||||
private var selectedId = -1
|
||||
|
||||
fun setData(selectedId: Int, data: List<AcctGameInfo.ZoneInfo>) {
|
||||
this.selectedId = selectedId
|
||||
submitList(data)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ZoneViewHolder {
|
||||
return ZoneViewHolder(parent.toBinding())
|
||||
@ -159,15 +174,15 @@ class AcceleratorZoneDialogFragment : BaseBottomDialogFragment<DialogFragmentAcc
|
||||
|
||||
override fun onBindViewHolder(holder: ZoneViewHolder, position: Int) {
|
||||
val item = getItem(position) ?: return
|
||||
updateSelectedState(holder, position)
|
||||
holder.binding.tvName.text = item.zoneName
|
||||
updateSelectedState(holder, item.id)
|
||||
holder.binding.tvName.text = item.cnName
|
||||
holder.itemView.setOnClickListener {
|
||||
click(item)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSelectedState(holder: ZoneViewHolder, position: Int) {
|
||||
val (textColorResId, backgroundResId) = if (position == selectedPosition) {
|
||||
private fun updateSelectedState(holder: ZoneViewHolder, zoneId: Int) {
|
||||
val (textColorResId, backgroundResId) = if (selectedId == zoneId) {
|
||||
com.gh.gamecenter.common.R.color.text_theme to R.drawable.bg_shape_2496ff_alpha_10_radius_8
|
||||
} else {
|
||||
com.gh.gamecenter.common.R.color.text_secondary to R.drawable.bg_shape_f8_radius_8
|
||||
@ -178,14 +193,15 @@ class AcceleratorZoneDialogFragment : BaseBottomDialogFragment<DialogFragmentAcc
|
||||
|
||||
companion object {
|
||||
|
||||
private const val SELECTED_CHANGED_PAYLOAD = "selected_changed_payload"
|
||||
|
||||
private val diffCallback = object : DiffUtil.ItemCallback<AcctGameInfo>() {
|
||||
override fun areItemsTheSame(oldItem: AcctGameInfo, newItem: AcctGameInfo): Boolean {
|
||||
return oldItem.zoneInfo.id == newItem.zoneInfo.id
|
||||
private val diffCallback = object : DiffUtil.ItemCallback<AcctGameInfo.ZoneInfo>() {
|
||||
override fun areItemsTheSame(oldItem: AcctGameInfo.ZoneInfo, newItem: AcctGameInfo.ZoneInfo): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: AcctGameInfo, newItem: AcctGameInfo): Boolean {
|
||||
override fun areContentsTheSame(
|
||||
oldItem: AcctGameInfo.ZoneInfo,
|
||||
newItem: AcctGameInfo.ZoneInfo
|
||||
): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
|
||||
|
||||
@ -22,12 +22,17 @@ import com.gh.gamecenter.core.utils.CurrentActivityHolder
|
||||
import com.gh.gamecenter.core.utils.ToastUtils
|
||||
import com.gh.gamecenter.databinding.DialogFragmentStartingAcceleratorBinding
|
||||
import com.gh.gamecenter.feature.entity.AcctGameInfo
|
||||
import com.gh.gamecenter.feature.entity.AcctRecord
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.gamedetail.StartingAcceleratorViewModel
|
||||
import com.gh.gamecenter.gamedetail.accelerator.GameDetailAcceleratorUiHelper.Companion.DISTRICT_SERVER_HAVA
|
||||
import com.gh.gamecenter.gamedetail.accelerator.GameDetailAcceleratorUiHelper.Companion.SOURCE_ENTRANCE_GAME_DETAIL
|
||||
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorDialogFragment.Companion.SPEED_ENABLE_VIP
|
||||
import com.gh.gamecenter.gamedetail.accelerator.dialog.AcceleratorDialogFragment.Companion.SPEED_START_FAILURE
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.login.user.UserRepository
|
||||
import com.halo.assistant.accelerator.repository.AcceleratorDataHolder
|
||||
import com.therouter.TheRouter
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import kotlin.math.max
|
||||
@ -38,7 +43,7 @@ class StartingAcceleratorDialogFragment : BaseDialogFragment() {
|
||||
|
||||
private lateinit var binding: DialogFragmentStartingAcceleratorBinding
|
||||
|
||||
private lateinit var acctGameInfo: AcctGameInfo
|
||||
private lateinit var zoneInfo: AcctGameInfo.ZoneInfo
|
||||
private lateinit var game: GameEntity
|
||||
private var isNeedRecord: Boolean = false
|
||||
private var iAcceleratorProvider: IAcceleratorProvider? = null
|
||||
@ -51,6 +56,8 @@ class StartingAcceleratorDialogFragment : BaseDialogFragment() {
|
||||
|
||||
private var refreshTokenCount = 0
|
||||
|
||||
private val acceleratorDataHolder = AcceleratorDataHolder.instance
|
||||
|
||||
private val accelerationListener = object : OnAccelerateListener {
|
||||
override fun onStateChanged(state: AccelerateState) {
|
||||
// 如果状态能成功回,则移除计时
|
||||
@ -60,10 +67,8 @@ class StartingAcceleratorDialogFragment : BaseDialogFragment() {
|
||||
ToastUtils.showToast("加速成功")
|
||||
// 加速成功,启动游戏
|
||||
PackageLauncher.launchApp(requireContext(), game, game.getUniquePackageName())
|
||||
// 记录加速记录
|
||||
if (isNeedRecord) {
|
||||
viewModel.useCase.recordAcctGameInfo(game.id, acctGameInfo, hasMultiZone)
|
||||
}
|
||||
// 记录加速成功的游戏
|
||||
viewModel.useCase.recordAcctGameInfo(game, zoneInfo, hasMultiZone)
|
||||
|
||||
trackNetworkAccelerationStartupResult("成功")
|
||||
dismissAllowingStateLoss()
|
||||
@ -84,14 +89,26 @@ class StartingAcceleratorDialogFragment : BaseDialogFragment() {
|
||||
sourceEntrance,
|
||||
it
|
||||
)
|
||||
// 加速失败,上传奇游加速器log
|
||||
unloadAcceleratorErrorLog(game)
|
||||
}
|
||||
}
|
||||
|
||||
if (state.isPermissionExpired) {
|
||||
// 加速会员过期,刷新本地vip状态
|
||||
val userId = UserManager.getInstance().userId
|
||||
UserRepository.getInstance().refreshVipStatus(userId, true)
|
||||
// 加速失败,上传奇游加速器log
|
||||
unloadAcceleratorErrorLog(game)
|
||||
}
|
||||
|
||||
dismissAllowingStateLoss()
|
||||
trackNetworkAccelerationStartupResult("失败(${state.code})")
|
||||
}
|
||||
}
|
||||
|
||||
is AccelerateState.Normal -> {
|
||||
|
||||
if (state.isTokenExpired || state.isTokenEmpty) {
|
||||
// token过期/登录时token设置失败,在此获取token并重新启动加速(最多重试三次)
|
||||
if (refreshTokenCount < REFRESH_TOKEN_MAX_COUNT) {
|
||||
@ -110,8 +127,10 @@ class StartingAcceleratorDialogFragment : BaseDialogFragment() {
|
||||
binding.tvProgress.text = getString(R.string.accelerating_with_progress, "$progress")
|
||||
}
|
||||
|
||||
override fun onVipStatusChanged(isNewUser: Boolean, isVip: Boolean) = Unit
|
||||
}
|
||||
|
||||
private fun unloadAcceleratorErrorLog(game: GameEntity) {
|
||||
viewModel.useCase.unloadAcceleratorErrorLog(game)
|
||||
}
|
||||
|
||||
private fun trackNetworkAccelerationStartupResult(result: String) {
|
||||
@ -119,8 +138,8 @@ class StartingAcceleratorDialogFragment : BaseDialogFragment() {
|
||||
game.getUniquePackageName() ?: "",
|
||||
game.id,
|
||||
game.name ?: "",
|
||||
iAcceleratorProvider?.getMemberType() ?: "",
|
||||
if (hasMultiZone) acctGameInfo.zoneInfo.cnName ?: "" else DISTRICT_SERVER_HAVA,
|
||||
acceleratorDataHolder.memberType,
|
||||
if (hasMultiZone) zoneInfo.cnName ?: "" else DISTRICT_SERVER_HAVA,
|
||||
result,
|
||||
sourceEntrance
|
||||
)
|
||||
@ -137,7 +156,7 @@ class StartingAcceleratorDialogFragment : BaseDialogFragment() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
iAcceleratorProvider = TheRouter.get(IAcceleratorProvider::class.java)
|
||||
acctGameInfo = arguments?.getParcelable(EntranceConsts.KEY_ACCT_GAME_INFO)!!
|
||||
zoneInfo = arguments?.getParcelable(EntranceConsts.KEY_ACCT_ZONE_INFO)!!
|
||||
game = arguments?.getParcelable(EntranceConsts.KEY_GAME)!!
|
||||
isNeedRecord = arguments?.getBoolean(EntranceConsts.KEY_IS_NEED_RECORD) ?: false
|
||||
hasMultiZone = arguments?.getBoolean(EntranceConsts.KEY_HAS_MULTI_ZONE) ?: false
|
||||
@ -160,8 +179,8 @@ class StartingAcceleratorDialogFragment : BaseDialogFragment() {
|
||||
|
||||
binding.tvProgress.text = getString(R.string.accelerating_with_progress, "0")
|
||||
iAcceleratorProvider?.bindAccRelatedListener("", accelerationListener)
|
||||
val isVip = iAcceleratorProvider?.isVip() ?: false
|
||||
val isNewUser = iAcceleratorProvider?.isNewUser() ?: false
|
||||
val isVip = acceleratorDataHolder.isVip
|
||||
val isNewUser = acceleratorDataHolder.isNewUser
|
||||
if (isNewUser && !isVip) {
|
||||
// 新用户,并且还不是vip
|
||||
viewModel.rechargeTrial()
|
||||
@ -199,18 +218,21 @@ class StartingAcceleratorDialogFragment : BaseDialogFragment() {
|
||||
// 15s以后,不管成功还是失败,都要关闭当前页面
|
||||
dismissAllowingStateLoss()
|
||||
}, TIME_OUT)
|
||||
viewModel.useCase.setLastAcctGameRecord(game)
|
||||
iAcceleratorProvider?.startQyGameAccelerate(acctGameInfo)
|
||||
AcceleratorDataHolder.instance.acctGameRecord = AcctRecord(game.id, game, zoneInfo, hasMultiZone, 0)
|
||||
iAcceleratorProvider?.startQyGameAccelerate(game.id, game.getUniquePackageName() ?: "", zoneInfo)
|
||||
if (isNeedRecord) {
|
||||
viewModel.useCase.insertAcctGameInfo(acctGameInfo)
|
||||
viewModel.useCase.insertAcctGameInfo(
|
||||
AcctGameInfo(game.id, game.getUniquePackageName() ?: "", zoneInfo)
|
||||
)
|
||||
}
|
||||
if (refreshTokenCount == 0) {
|
||||
|
||||
SensorsBridge.trackNetworkAccelerationStartup(
|
||||
game.getUniquePackageName() ?: "",
|
||||
game.id,
|
||||
game.name ?: "",
|
||||
iAcceleratorProvider?.getMemberType() ?: "",
|
||||
if (hasMultiZone) acctGameInfo.zoneInfo.cnName ?: "" else DISTRICT_SERVER_HAVA,
|
||||
acceleratorDataHolder.memberType,
|
||||
if (hasMultiZone) zoneInfo.cnName ?: "" else DISTRICT_SERVER_HAVA,
|
||||
sourceEntrance
|
||||
)
|
||||
}
|
||||
@ -231,7 +253,7 @@ class StartingAcceleratorDialogFragment : BaseDialogFragment() {
|
||||
|
||||
fun show(
|
||||
context: Context,
|
||||
acctGameInfo: AcctGameInfo,
|
||||
zoneInfo: AcctGameInfo.ZoneInfo,
|
||||
game: GameEntity,
|
||||
isNeedRecord: Boolean,
|
||||
hasMultiZone: Boolean,
|
||||
@ -244,7 +266,7 @@ class StartingAcceleratorDialogFragment : BaseDialogFragment() {
|
||||
}?.let {
|
||||
val fragment = StartingAcceleratorDialogFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putParcelable(EntranceConsts.KEY_ACCT_GAME_INFO, acctGameInfo)
|
||||
putParcelable(EntranceConsts.KEY_ACCT_ZONE_INFO, zoneInfo)
|
||||
putParcelable(EntranceConsts.KEY_GAME, game)
|
||||
putBoolean(EntranceConsts.KEY_IS_NEED_RECORD, isNeedRecord)
|
||||
putBoolean(EntranceConsts.KEY_HAS_MULTI_ZONE, hasMultiZone)
|
||||
|
||||
@ -1,81 +1,125 @@
|
||||
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()
|
||||
if (mUseAlternativeLayout) {
|
||||
requireActivity().updateStatusBarColor(com.gh.gamecenter.common.R.color.ui_surface, com.gh.gamecenter.common.R.color.ui_surface)
|
||||
}
|
||||
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.backBtn.setOnClickListener {
|
||||
requireActivity().onBackPressed()
|
||||
}
|
||||
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 +143,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 +157,7 @@ class CloudArchiveFragment : LazyFragment() {
|
||||
.replace(
|
||||
R.id.contentFragment,
|
||||
fragment,
|
||||
SpecialCatalogFragment::class.java.name
|
||||
CloudArchiveListFragment::class.java.name
|
||||
)
|
||||
.commitAllowingStateLoss()
|
||||
}
|
||||
@ -122,14 +166,36 @@ 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()
|
||||
if (mUseAlternativeLayout) {
|
||||
requireActivity().updateStatusBarColor(com.gh.gamecenter.common.R.color.ui_surface, com.gh.gamecenter.common.R.color.ui_surface)
|
||||
}
|
||||
mAlternativeBinding?.reuseToolbar?.run {
|
||||
normalToolbar.setBackgroundColor(
|
||||
com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()))
|
||||
backBtn.setImageResource(com.gh.gamecenter.common.R.drawable.ic_bar_back)
|
||||
normalTitle.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
}
|
||||
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())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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)
|
||||
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.gh.gamecenter.gamedetail.detail
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.view.FixAppBarLayoutBehavior
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import kotlin.math.abs
|
||||
|
||||
class GameDetailAppBarBehavior @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) : FixAppBarLayoutBehavior(context, attrs) {
|
||||
private var maxScrollHeight = 0
|
||||
|
||||
override fun setTopAndBottomOffset(offset: Int): Boolean {
|
||||
val finalOffset = if (maxScrollHeight > 0 && maxScrollHeight <= abs(offset)) -maxScrollHeight else offset
|
||||
return super.setTopAndBottomOffset(finalOffset)
|
||||
}
|
||||
|
||||
override fun onLayoutChild(parent: CoordinatorLayout, abl: AppBarLayout, layoutDirection: Int): Boolean {
|
||||
calculateMaxScrollHeight(parent, abl)
|
||||
return super.onLayoutChild(parent, abl, layoutDirection)
|
||||
}
|
||||
|
||||
private fun calculateMaxScrollHeight(parent: CoordinatorLayout, child: AppBarLayout) {
|
||||
val recyclerView = parent.findViewById<RecyclerView>(R.id.detailRv) ?: return
|
||||
val parentHeight = parent.measuredHeight
|
||||
val recyclerViewHeight = recyclerView.measuredHeight
|
||||
val childScrollTotalHeight = child.totalScrollRange
|
||||
|
||||
maxScrollHeight = (childScrollTotalHeight - parentHeight + recyclerViewHeight).coerceAtLeast(0)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.gh.gamecenter.gamedetail.detail
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.utils.LeftPagerSnapHelper
|
||||
|
||||
class GameDetailCoverSnapHelper: LeftPagerSnapHelper() {
|
||||
override fun findTargetSnapPosition(
|
||||
layoutManager: RecyclerView.LayoutManager,
|
||||
velocityX: Int,
|
||||
velocityY: Int
|
||||
): Int {
|
||||
val closestChild = findSnapView(layoutManager) ?: return RecyclerView.NO_POSITION
|
||||
val position = layoutManager.getPosition(closestChild)
|
||||
return if (position == RecyclerView.NO_POSITION) {
|
||||
RecyclerView.NO_POSITION
|
||||
} else {
|
||||
val forwardDirection = if (layoutManager.canScrollHorizontally()) velocityX > 0 else velocityY > 0
|
||||
if (forwardDirection) position + 1 else position - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
package com.gh.gamecenter.gamedetail.desc
|
||||
package com.gh.gamecenter.gamedetail.detail.adapter
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@ -6,23 +6,26 @@ 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.R
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.GamedetailItemGameCollectionBinding
|
||||
import com.gh.gamecenter.entity.GameDetailRecommendGameEntity
|
||||
import com.gh.gamecenter.entity.GameDetailRecommendGameCollectionEntity
|
||||
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>,
|
||||
private val mRecommendGameList: ArrayList<GameDetailRecommendGameCollectionEntity>,
|
||||
private val mGameId: String,
|
||||
private val mGameName: String,
|
||||
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() }
|
||||
@ -39,7 +42,7 @@ class GameCollectionAdapter(
|
||||
if (holder is GameCollectionItemViewHolder) {
|
||||
val entity = mRecommendGameList[position]
|
||||
holder.binding.run {
|
||||
root.background = com.gh.gamecenter.common.R.drawable.background_shape_white_radius_5.toDrawable(root.context)
|
||||
root.background = R.drawable.bg_shape_space_radius_5.toDrawable(root.context)
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(root.context))
|
||||
titleTv.text = entity.title
|
||||
ImageUtils.display(coverImage, entity.cover)
|
||||
@ -72,20 +75,20 @@ 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.moduleName,
|
||||
trackData.sequence,
|
||||
entity.title,
|
||||
position + 1,
|
||||
"game_list_detail",
|
||||
entity.id,
|
||||
entity.title,
|
||||
getGameStatus()
|
||||
)
|
||||
DirectUtils.directToGameCollectionDetail(
|
||||
it.context,
|
||||
@ -0,0 +1,199 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.adapter
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.util.SparseArray
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.core.util.forEach
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.gamecenter.ImageViewerActivity
|
||||
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
|
||||
import com.gh.gamecenter.common.utils.ImageUtils
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.utils.toastInInternalRelease
|
||||
import com.gh.gamecenter.databinding.ItemGameCoverGalleryBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameCoverVideoBinding
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.detail.GameDetailFragment
|
||||
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 viewModel: GameDetailViewModel,
|
||||
private val showOrHideCoverFilter: ((Boolean) -> Unit)
|
||||
) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
|
||||
|
||||
private var coverRecyclerView: RecyclerView? = null
|
||||
private var coverList = arrayListOf<CoverEntity>()
|
||||
private var isSingleGallery = false
|
||||
private var hasSetFixedHeight = false
|
||||
private val imageUrlList = arrayListOf<String>()
|
||||
private val imageViewArray = SparseArray<SimpleDraweeView>()
|
||||
|
||||
fun submitList(data: List<CoverEntity>) {
|
||||
imageUrlList.clear()
|
||||
coverList = ArrayList(data)
|
||||
isSingleGallery = coverList.count { it.gallery != null } == 1
|
||||
coverList.mapNotNullTo(imageUrlList) { it.gallery?.url }
|
||||
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 == viewModel.defaultCoverEntity?.index && !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)
|
||||
.setAutoFullWithSize(true)
|
||||
.setDismissControlTime(5000)
|
||||
.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.showOrHideCoverFilter = showOrHideCoverFilter
|
||||
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) 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 == viewModel.defaultCoverEntity?.index && !hasSetFixedHeight) {
|
||||
holder.binding.root.post {
|
||||
coverRecyclerView?.updateLayoutParams<ViewGroup.LayoutParams> { height = holder.binding.root.height }
|
||||
hasSetFixedHeight = true
|
||||
}
|
||||
}
|
||||
holder.binding.galleryIv.setTag(ImageUtils.TAG_TARGET_WIDTH, imageWidth)
|
||||
ImageUtils.display(holder.binding.galleryIv, imageUrl)
|
||||
imageViewArray[entity.galleryIndex] = holder.binding.galleryIv
|
||||
holder.binding.root.setOnClickListener {
|
||||
val imageViewList = arrayListOf<View>()
|
||||
imageViewArray.forEach { _, value -> imageViewList.add(value) }
|
||||
val intent = ImageViewerActivity.getIntent(
|
||||
mContext,
|
||||
imageUrlList,
|
||||
entity.galleryIndex,
|
||||
imageViewList,
|
||||
"游戏详情-视频/图片区域"
|
||||
)
|
||||
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)
|
||||
}
|
||||
@ -0,0 +1,139 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.adapter
|
||||
|
||||
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 -> 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 {
|
||||
if (oldItem.linkLibao != null && newItem.linkLibao != null) {
|
||||
return false
|
||||
}
|
||||
if (oldItem.linkEveryonePlaying != null && newItem.linkEveryonePlaying != null) {
|
||||
return false
|
||||
}
|
||||
if (oldItem.linkContentRecommend != null && newItem.linkContentRecommend != null) {
|
||||
return false
|
||||
}
|
||||
if (oldItem.recommendColumn != null && newItem.recommendColumn != null) {
|
||||
return false
|
||||
}
|
||||
return oldItem.areContentsTheSame(newItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,39 +1,37 @@
|
||||
package com.gh.gamecenter.gamedetail.desc
|
||||
package com.gh.gamecenter.gamedetail.detail.adapter
|
||||
|
||||
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
|
||||
|
||||
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 - 56F.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)
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gh.gamecenter.gamedetail.desc
|
||||
package com.gh.gamecenter.gamedetail.detail.adapter
|
||||
|
||||
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
|
||||
@ -0,0 +1,330 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.adapter
|
||||
|
||||
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.children
|
||||
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.generic.RoundingParams
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.common.util.LibaoUtils
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.ImageViewerActivity
|
||||
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.gamedetail.detail.viewholder.BaseGameDetailItemViewHolder.GameDetailModuleTrackData
|
||||
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,
|
||||
private val trackData: GameDetailModuleTrackData? = null,
|
||||
private val getGameStatus: (() -> String)? = null
|
||||
) :
|
||||
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, trackData, getGameStatus)
|
||||
}
|
||||
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,
|
||||
gameDetailModuleTrackData: GameDetailModuleTrackData? = null,
|
||||
getGameStatus: (() -> String)? = null
|
||||
) {
|
||||
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()) {
|
||||
if (binding.imagesContainer.tag == libaoEntity.id) {
|
||||
binding.imagesContainer.children.forEach { view ->
|
||||
if (view is SimpleDraweeView) {
|
||||
view.hierarchy.roundingParams = RoundingParams().apply {
|
||||
setCornersRadius(4F.dip2px().toFloat())
|
||||
setOverlayColor(com.gh.gamecenter.common.R.color.ui_container_1.toColor(context))
|
||||
}
|
||||
}
|
||||
}
|
||||
return@goneIf
|
||||
}
|
||||
binding.imagesContainer.removeAllViews()
|
||||
val imageViewList = arrayListOf<View>()
|
||||
libaoEntity.materials.forEachIndexed { index, material ->
|
||||
binding.imagesContainer.addView(SimpleDraweeView(context).apply {
|
||||
val roundingParams = RoundingParams().apply {
|
||||
setCornersRadius(4F.dip2px().toFloat())
|
||||
setOverlayColor(com.gh.gamecenter.common.R.color.ui_container_1.toColor(context))
|
||||
}
|
||||
hierarchy = GenericDraweeHierarchyBuilder(resources)
|
||||
.setFadeDuration(500)
|
||||
.setRoundingParams(roundingParams)
|
||||
.setPlaceholderImage(com.gh.gamecenter.common.R.drawable.occupy, ScalingUtils.ScaleType.FIT_XY)
|
||||
.build()
|
||||
ImageUtils.display(this, material.img)
|
||||
}.apply {
|
||||
imageViewList.add(this)
|
||||
setOnClickListener {
|
||||
context.startActivity(ImageViewerActivity.getIntent(context, libaoEntity.getMaterialImgList(), index, imageViewList, null))
|
||||
}
|
||||
}, LinearLayout.LayoutParams(24F.dip2px(), 24F.dip2px()).apply {
|
||||
setMargins(if (index != 0) 16F.dip2px() else 8F.dip2px(), 0, 0, 0)
|
||||
})
|
||||
}
|
||||
binding.imagesContainer.tag = libaoEntity.id
|
||||
}
|
||||
|
||||
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, "礼包详情")
|
||||
if (gameDetailModuleTrackData != null && getGameStatus != null) {
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameDetailModuleTrackData.gameId,
|
||||
gameDetailModuleTrackData.gameName,
|
||||
gameDetailModuleTrackData.gameType,
|
||||
"组件内容",
|
||||
gameDetailModuleTrackData.moduleType,
|
||||
gameDetailModuleTrackData.moduleName,
|
||||
gameDetailModuleTrackData.sequence,
|
||||
libaoEntity.name,
|
||||
position + 1,
|
||||
"libao",
|
||||
libaoEntity.id,
|
||||
libaoEntity.name,
|
||||
getGameStatus()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
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.download.DownloadManager
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
import com.lightgame.download.DownloadStatus
|
||||
|
||||
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, viewModel)
|
||||
|
||||
protected val baseTrackData
|
||||
get() = GameDetailModuleTrackData(
|
||||
gameId = gameId,
|
||||
gameName = gameName,
|
||||
gameType = gameId,
|
||||
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 supSequence: Int = 0
|
||||
)
|
||||
|
||||
companion object {
|
||||
fun getGameStatus(buttonStyle: DownloadButton.ButtonStyle?, viewModel: GameDetailViewModel) = when (buttonStyle) {
|
||||
DownloadButton.ButtonStyle.WAITING,
|
||||
DownloadButton.ButtonStyle.UPDATING,
|
||||
DownloadButton.ButtonStyle.PAUSE,
|
||||
DownloadButton.ButtonStyle.FAILURE,
|
||||
DownloadButton.ButtonStyle.DOWNLOADING_NORMAL,
|
||||
DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN -> "下载中"
|
||||
|
||||
DownloadButton.ButtonStyle.LAUNCH_OR_OPEN -> "已安装"
|
||||
DownloadButton.ButtonStyle.RESERVABLE -> "预约"
|
||||
DownloadButton.ButtonStyle.RESERVED -> "已预约"
|
||||
else -> determineStatus(viewModel)
|
||||
}
|
||||
|
||||
private fun determineStatus(viewModel: GameDetailViewModel): String {
|
||||
viewModel.updateGameStatus()
|
||||
if (viewModel.isGameInstalled) {
|
||||
return "已安装"
|
||||
}
|
||||
|
||||
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshot("", viewModel.gameId)
|
||||
return when (downloadEntity?.status) {
|
||||
DownloadStatus.done -> "待安装"
|
||||
null,
|
||||
DownloadStatus.cancel,
|
||||
DownloadStatus.hijack,
|
||||
DownloadStatus.notfound,
|
||||
DownloadStatus.uncertificated,
|
||||
DownloadStatus.unqualified,
|
||||
DownloadStatus.unavailable,
|
||||
DownloadStatus.banned -> "未下载"
|
||||
else -> "下载中"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Animatable
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.facebook.drawee.controller.BaseControllerListener
|
||||
import com.facebook.imagepipeline.image.ImageInfo
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
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, false, "游戏详情-广告推荐", baseTrackData) { gameStatus }
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun bindImageItem(
|
||||
context: Context,
|
||||
binding: ItemGameDetailImageLinkBinding,
|
||||
data: GameDetailLink,
|
||||
isAnnouncement: Boolean,
|
||||
entrance: String,
|
||||
trackData: GameDetailModuleTrackData,
|
||||
getGameStatus: () -> String
|
||||
) {
|
||||
binding.run {
|
||||
if (data.img.isNotEmpty()) {
|
||||
imageIv.updateRoundingParams {
|
||||
setOverlayColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(context))
|
||||
}
|
||||
ImageUtils.displayWithCallback(imageIv, data.img, false, object : BaseControllerListener<ImageInfo>() {
|
||||
override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
|
||||
if (imageInfo == null || imageInfo.height == 0) {
|
||||
return
|
||||
}
|
||||
val scale = imageInfo.width.toFloat() / imageInfo.height.toFloat()
|
||||
maskView.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
height = if (scale > 2F) 40F.dip2px() else 60F.dip2px()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
iconIv.goneIf(data.componentIcon?.icon.isNullOrEmpty()) {
|
||||
iconIv.setFixedHeight(14)
|
||||
iconIv.setTag(ImageUtils.TAG_TARGET_WIDTH, DisplayUtils.getScreenWidth() - 32F.dip2px())
|
||||
ImageUtils.display(iconIv, data.componentIcon?.icon)
|
||||
}
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_aw_primary.toColor(context))
|
||||
titleTv.text = if (isAnnouncement) data.text else data.title
|
||||
linkTv.goneIf(data.text.isEmpty() || isAnnouncement) {
|
||||
linkTv.text = data.text
|
||||
linkTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
}
|
||||
arrowIv.goneIf(data.text.isNotEmpty() || isAnnouncement)
|
||||
container.setOnClickListener { _ ->
|
||||
data.link?.let {
|
||||
DirectUtils.directToLinkPage(context, it, entrance, "")
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
trackData.gameId,
|
||||
trackData.gameName,
|
||||
trackData.gameType,
|
||||
"组件内容",
|
||||
trackData.moduleType,
|
||||
trackData.moduleName,
|
||||
trackData.sequence,
|
||||
trackData.subModuleName,
|
||||
trackData.supSequence,
|
||||
it.type,
|
||||
it.link,
|
||||
it.link,
|
||||
getGameStatus()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
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, false, "游戏详情-广告推荐", baseTrackData) { gameStatus }
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun bindItem(
|
||||
context: Context,
|
||||
binding: ItemGameDetailLinkBinding,
|
||||
data: GameDetailLink,
|
||||
isAnnouncement: Boolean,
|
||||
entrance: String,
|
||||
trackData: GameDetailModuleTrackData,
|
||||
getGameStatus: () -> String
|
||||
) {
|
||||
binding.run {
|
||||
container.updateLayoutParams { height = if (isAnnouncement) 28F.dip2px() else 40F.dip2px() }
|
||||
container.background = if (isAnnouncement) null else R.drawable.bg_shape_ui_container_1_radius_8_item_style.toDrawable(context)
|
||||
iconIv.goneIf(data.componentIcon?.icon.isNullOrEmpty()) {
|
||||
iconIv.setFixedHeight(14)
|
||||
iconIv.setTag(ImageUtils.TAG_TARGET_WIDTH, DisplayUtils.getScreenWidth() - 32F.dip2px())
|
||||
ImageUtils.display(iconIv, data.componentIcon?.icon)
|
||||
iconIv.updateRoundingParams {
|
||||
setOverlayColor(com.gh.gamecenter.common.R.color.ui_container_1.toColor(context))
|
||||
}
|
||||
}
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
titleTv.textSize = if (isAnnouncement) 12F else 13F
|
||||
titleTv.text = if (isAnnouncement) data.text else 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,
|
||||
trackData.subModuleName,
|
||||
trackData.supSequence,
|
||||
it.type,
|
||||
it.link,
|
||||
it.link,
|
||||
getGameStatus()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
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.dip2px
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
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)
|
||||
} 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) {
|
||||
holder.binding.root.setPadding(4F.dip2px(), 0, 4F.dip2px(), 0)
|
||||
GameDetailAdvertisingItemViewHolder.bindItem(
|
||||
context,
|
||||
holder.binding,
|
||||
data,
|
||||
true,
|
||||
"游戏详情-资讯公告",
|
||||
baseTrackData.apply {
|
||||
moduleName = itemData?.linkAnnouncement?.name ?: ""
|
||||
subModuleName = data.text
|
||||
supSequence = position + 1
|
||||
}) { gameStatus }
|
||||
}
|
||||
if (holder is GameDetailAnnouncementImageItemViewHolder) {
|
||||
holder.binding.root.setPadding(16F.dip2px(), 0, 16F.dip2px(), if (position == itemCount - 1) 0 else 12F.dip2px())
|
||||
GameDetailAdvertisingImageItemViewHolder.bindImageItem(
|
||||
context,
|
||||
holder.binding,
|
||||
data,
|
||||
true,
|
||||
"游戏详情-资讯公告",
|
||||
baseTrackData.apply {
|
||||
moduleName = itemData?.linkAnnouncement?.name ?: ""
|
||||
subModuleName = data.text
|
||||
supSequence = position + 1
|
||||
}
|
||||
) { 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
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,160 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
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.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
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.isNullOrEmpty()) {
|
||||
bindGamesTags(entity.gameTags)
|
||||
}
|
||||
briefTv.text = TextHelper.getHighlightedSpannableStringThatIsWrappedInsideWrapper(
|
||||
context,
|
||||
entity.des,
|
||||
Constants.DEFAULT_TEXT_WRAPPER_2,
|
||||
highlightedTextClickListener = TextHelper.CopyToClipboardHighlightedTextClick()
|
||||
)
|
||||
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,
|
||||
"游戏信息",
|
||||
entity.des
|
||||
)
|
||||
}
|
||||
divider.goneIf(entity.awardData.isEmpty())
|
||||
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, "游戏详情-游戏简介", "")
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
itemData?.linkGameBrief?.name,
|
||||
sequence,
|
||||
awardData.award,
|
||||
index + 1,
|
||||
link.type,
|
||||
link.link,
|
||||
link.text,
|
||||
gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
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<SimpleDraweeView>(R.id.iconIv)?.updateRoundingParams {
|
||||
setOverlayColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(context))
|
||||
}
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,402 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
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(R.drawable.ic_auxiliary_arrow_right_text_theme_12.toDrawable(context))
|
||||
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.isNestedScrollingEnabled = false
|
||||
(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))
|
||||
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
|
||||
}
|
||||
commentTv.setExpandCallback {
|
||||
root.performClick()
|
||||
}
|
||||
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,
|
||||
"游戏详情-玩家评论"
|
||||
)
|
||||
)
|
||||
}
|
||||
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) {
|
||||
MORE_COPY -> {
|
||||
commentData.content.replace(RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), "")
|
||||
.copyTextAndToast()
|
||||
}
|
||||
|
||||
MORE_MODIFY -> {
|
||||
val intent =
|
||||
RatingEditActivity.getPatchIntent(context, viewModel.game!!, commentData)
|
||||
SyncDataBetweenPageHelper.startActivityForResult(
|
||||
context,
|
||||
intent,
|
||||
RATING_PATCH_REQUEST,
|
||||
position
|
||||
)
|
||||
}
|
||||
|
||||
MORE_REPORT -> {
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MORE_DELETE -> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
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(MORE_COPY, MORE_MODIFY, MORE_DELETE)
|
||||
else arrayListOf(MORE_COPY, MORE_REPORT)
|
||||
|
||||
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
|
||||
const val MORE_COPY = "复制"
|
||||
const val MORE_MODIFY = "修改"
|
||||
const val MORE_DELETE = "删除"
|
||||
const val MORE_REPORT = "投诉"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,313 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.graphics.Typeface
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.ExtraTagHandler
|
||||
import com.gh.gamecenter.databinding.*
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailComprehensivePanelItem
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailComprehensivePanelItem.Companion.FUNCTION_TYPE_ONE_LINE_ONE_POINT
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailComprehensivePanelItem.Companion.SHOW_TYPE_PART
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailComprehensivePanelItem.ContentData
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
import splitties.views.topPadding
|
||||
|
||||
class GameDetailComprehensivePanelItemViewHolder(
|
||||
val binding: ItemGameDetailComprehensivePanelBinding,
|
||||
downloadBtn: DownloadButton?,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkComprehensive ?: return
|
||||
val dataList = entity.data ?: return
|
||||
binding.run {
|
||||
root.topPadding = if (entity.showName) 0 else 16F.dip2px()
|
||||
panelRv.background = com.gh.gamecenter.common.R.drawable.bg_shape_f8_radius_8.toDrawable(context)
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
titleTv.goneIf(!entity.showName) {
|
||||
titleTv.text = entity.name
|
||||
}
|
||||
if (panelRv.adapter !is ComprehensivePanelAdapter) {
|
||||
panelRv.isNestedScrollingEnabled = false
|
||||
(panelRv.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
panelRv.layoutManager = LinearLayoutManager(context)
|
||||
panelRv.adapter = ComprehensivePanelAdapter(dataList)
|
||||
} else {
|
||||
if (sequence != panelRv.tag) {
|
||||
(panelRv.adapter as? ComprehensivePanelAdapter)?.dataList = dataList
|
||||
}
|
||||
panelRv.adapter?.run { notifyItemRangeChanged(0, itemCount) }
|
||||
}
|
||||
panelRv.tag = sequence
|
||||
}
|
||||
}
|
||||
|
||||
inner class ComprehensivePanelAdapter(var dataList: List<GameDetailComprehensivePanelItem>) :
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
val data = dataList[position]
|
||||
return when (data.type) {
|
||||
GameDetailComprehensivePanelItem.TYPE_FUNCTION -> ITEM_FUNCTION
|
||||
GameDetailComprehensivePanelItem.TYPE_FAQ -> ITEM_FAQ
|
||||
else -> ITEM_DECLARATION
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return when (viewType) {
|
||||
ITEM_FUNCTION -> ComprehensivePanelFunctionViewHolder(parent.toBinding())
|
||||
ITEM_FAQ -> ComprehensivePanelFAQViewHolder(parent.toBinding())
|
||||
else -> ComprehensivePanelDeclarationViewHolder(parent.toBinding())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val data = dataList.getOrNull(position) ?: return
|
||||
if (holder is ComprehensivePanelFunctionViewHolder) {
|
||||
holder.binding.run {
|
||||
root.updateLayoutParams<MarginLayoutParams> {
|
||||
topMargin = if (position == 0) 0 else 8F.dip2px()
|
||||
}
|
||||
titleTv.goneIf(!data.showTitle) {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
titleTv.text = data.title
|
||||
}
|
||||
val contentData = data.data ?: return
|
||||
holder.showPart = data.functionType == FUNCTION_TYPE_ONE_LINE_ONE_POINT && data.showType == SHOW_TYPE_PART
|
||||
expandTv.isVisible = viewModel.comprehensivePanelExpandBtnStatusMap.getOrPut("${sequence}${position}") { holder.showPart && contentData.size > data.showRowNum }
|
||||
expandTv.text = if (holder.isExpand) "收起" else "全部"
|
||||
expandTv.setOnClickListener { _ ->
|
||||
holder.isExpand = !holder.isExpand
|
||||
(recyclerView.adapter as? ComprehensivePanelFunctionAdapter)?.dataList =
|
||||
if (holder.showPart && !holder.isExpand) {
|
||||
contentData.take(data.showRowNum)
|
||||
} else {
|
||||
contentData
|
||||
}
|
||||
recyclerView.adapter?.notifyDataSetChanged()
|
||||
expandTv.text = if (holder.isExpand) "收起" else "全部"
|
||||
}
|
||||
val spanCount = if (data.functionType == FUNCTION_TYPE_ONE_LINE_ONE_POINT) 1 else 2
|
||||
val finalContentData = if (holder.showPart && !holder.isExpand) {
|
||||
contentData.take(data.showRowNum)
|
||||
} else {
|
||||
contentData
|
||||
}
|
||||
if (recyclerView.adapter !is ComprehensivePanelFunctionAdapter) {
|
||||
recyclerView.isNestedScrollingEnabled = false
|
||||
(recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
recyclerView.layoutManager = GridLayoutManager(context, spanCount)
|
||||
recyclerView.adapter = ComprehensivePanelFunctionAdapter(data, finalContentData, holder)
|
||||
} else {
|
||||
(recyclerView.layoutManager as? GridLayoutManager)?.spanCount = spanCount
|
||||
(recyclerView.adapter as? ComprehensivePanelFunctionAdapter)?.run {
|
||||
dataList = finalContentData
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (holder is ComprehensivePanelFAQViewHolder) {
|
||||
holder.binding.run {
|
||||
root.updateLayoutParams<MarginLayoutParams> {
|
||||
topMargin = if (position == 0) 0 else 16F.dip2px()
|
||||
bottomMargin = if (position == itemCount - 1) 0 else if (data.showTitle) 12F.dip2px() else 8F.dip2px()
|
||||
}
|
||||
titleTv.goneIf(!data.showTitle) {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
titleTv.text = data.title
|
||||
}
|
||||
val contentData = data.data ?: return
|
||||
if (recyclerView.adapter !is ComprehensivePanelFAQAdapter) {
|
||||
recyclerView.isNestedScrollingEnabled = false
|
||||
(recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
recyclerView.layoutManager = LinearLayoutManager(context)
|
||||
recyclerView.adapter = ComprehensivePanelFAQAdapter(data.title, contentData)
|
||||
} else {
|
||||
(recyclerView.adapter as? ComprehensivePanelFAQAdapter)?.run {
|
||||
dataList = contentData
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (holder is ComprehensivePanelDeclarationViewHolder) {
|
||||
holder.binding.run {
|
||||
root.updateLayoutParams<MarginLayoutParams> {
|
||||
topMargin = if (position == 0) 0 else 12F.dip2px()
|
||||
}
|
||||
titleTv.goneIf(!data.showTitle) {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
titleTv.text = data.title
|
||||
}
|
||||
declarationTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
declarationTv.setTextWithInterceptingInternalUrl(
|
||||
data.declaration.dropFontColorInDarkMode(declarationTv.context)
|
||||
.fromHtmlCompat(PicassoImageGetter(declarationTv), ExtraTagHandler())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = dataList.size
|
||||
}
|
||||
|
||||
inner class ComprehensivePanelFunctionAdapter(
|
||||
private val gameDetailComprehensivePanelItem: GameDetailComprehensivePanelItem,
|
||||
var dataList: List<ContentData>,
|
||||
private val parentViewHolder: ComprehensivePanelFunctionViewHolder
|
||||
) :
|
||||
RecyclerView.Adapter<ComprehensivePanelFunctionItemViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ComprehensivePanelFunctionItemViewHolder =
|
||||
ComprehensivePanelFunctionItemViewHolder(parent.toBinding())
|
||||
|
||||
override fun getItemCount(): Int = dataList.size
|
||||
|
||||
override fun onBindViewHolder(holder: ComprehensivePanelFunctionItemViewHolder, position: Int) {
|
||||
val data = dataList.getOrNull(position) ?: return
|
||||
holder.binding.numberIv.setImageResource(R.drawable.bg_game_detail_comprehensive_panel_function_number)
|
||||
holder.binding.numberTv.run {
|
||||
setTextColor(com.gh.gamecenter.common.R.color.text_aw_primary.toColor(context))
|
||||
setTypeface(Typeface.createFromAsset(context.assets, Constants.DIN_FONT_PATH))
|
||||
text = (position + 1).toString()
|
||||
}
|
||||
holder.binding.contentTv.run {
|
||||
setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
maxLines = if (parentViewHolder.showPart && !parentViewHolder.isExpand) 1 else Int.MAX_VALUE
|
||||
text = data.text
|
||||
post {
|
||||
val hasEllipsize = layout.getEllipsisCount(0) > 0
|
||||
if (parentViewHolder.showPart && hasEllipsize && !parentViewHolder.binding.expandTv.isVisible) {
|
||||
parentViewHolder.binding.expandTv.isVisible = true
|
||||
viewModel.comprehensivePanelExpandBtnStatusMap["${sequence}${parentViewHolder.bindingAdapterPosition}"] = true
|
||||
}
|
||||
|
||||
// 计算最后一行是否有足够位置放下 全部/收起 按钮
|
||||
if (position == itemCount - 1) {
|
||||
val lastLine = layout.lineCount - 1
|
||||
val lastLineString = text.substring(layout.getLineStart(lastLine), layout.getLineEnd(lastLine))
|
||||
val distanceToEnd = width - paint.measureText(lastLineString)
|
||||
val showExpandInTheLastLine = distanceToEnd >= parentViewHolder.binding.expandTv.width
|
||||
ConstraintSet().apply {
|
||||
clone(parentViewHolder.binding.root)
|
||||
clear(parentViewHolder.binding.expandTv.id, ConstraintSet.TOP)
|
||||
clear(parentViewHolder.binding.expandTv.id, ConstraintSet.BOTTOM)
|
||||
if (showExpandInTheLastLine) {
|
||||
connect(parentViewHolder.binding.expandTv.id, ConstraintSet.BOTTOM, parentViewHolder.binding.recyclerView.id, ConstraintSet.BOTTOM)
|
||||
} else {
|
||||
connect(parentViewHolder.binding.expandTv.id, ConstraintSet.TOP, parentViewHolder.binding.recyclerView.id, ConstraintSet.BOTTOM)
|
||||
connect(parentViewHolder.binding.expandTv.id, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM)
|
||||
}
|
||||
}.applyTo(parentViewHolder.binding.root)
|
||||
}
|
||||
}
|
||||
}
|
||||
holder.binding.root.setOnClickListener { _ ->
|
||||
data.link?.let {
|
||||
DirectUtils.directToLinkPage(context, it, "游戏详情-功能说明", "")
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
"功能说明",
|
||||
sequence,
|
||||
gameDetailComprehensivePanelItem.title,
|
||||
position + 1,
|
||||
it.type,
|
||||
it.link,
|
||||
it.text,
|
||||
gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class ComprehensivePanelFAQAdapter(private val subModuleName: String, var dataList: List<ContentData>) :
|
||||
RecyclerView.Adapter<ComprehensivePanelFAQItemViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ComprehensivePanelFAQItemViewHolder =
|
||||
ComprehensivePanelFAQItemViewHolder(parent.toBinding())
|
||||
|
||||
override fun getItemCount(): Int = dataList.size
|
||||
|
||||
override fun onBindViewHolder(holder: ComprehensivePanelFAQItemViewHolder, position: Int) {
|
||||
val data = dataList.getOrNull(position) ?: return
|
||||
holder.binding.root.updateLayoutParams<MarginLayoutParams> {
|
||||
topMargin = if (position == 0) 0 else 8F.dip2px()
|
||||
}
|
||||
holder.binding.root.background = R.drawable.bg_shape_ui_surface_radius_4_item_style.toDrawable(context)
|
||||
holder.binding.contentTv.run {
|
||||
setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
text = data.text
|
||||
}
|
||||
holder.binding.arrowIv.goneIf(data.link == null) {
|
||||
holder.binding.arrowIv.setImageResource(R.drawable.ic_auxiliary_arrow_right_8)
|
||||
}
|
||||
holder.binding.root.setOnClickListener { _ ->
|
||||
data.link?.let {
|
||||
DirectUtils.directToLinkPage(context, it, "游戏详情-功能说明", "")
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
"功能说明",
|
||||
sequence,
|
||||
subModuleName,
|
||||
position + 1,
|
||||
it.type,
|
||||
it.link,
|
||||
it.text,
|
||||
gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class ComprehensivePanelFunctionViewHolder(val binding: ItemGameDetailComprehensivePanelRvBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
var showPart: Boolean = false
|
||||
var isExpand = false
|
||||
get() = viewModel.comprehensivePanelExpandTextStatusMap.getOrPut("${sequence}${bindingAdapterPosition}") { !showPart }
|
||||
set(value) {
|
||||
viewModel.comprehensivePanelExpandTextStatusMap["${sequence}${bindingAdapterPosition}"] = value
|
||||
field = value
|
||||
}
|
||||
}
|
||||
|
||||
inner class ComprehensivePanelFAQViewHolder(val binding: ItemGameDetailComprehensivePanelRvBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
inner class ComprehensivePanelDeclarationViewHolder(val binding: ItemGameDetailComprehensivePanelDeclarationBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
inner class ComprehensivePanelFunctionItemViewHolder(val binding: ItemGameDetailComprehensivePanelFunctionBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
inner class ComprehensivePanelFAQItemViewHolder(val binding: ItemGameDetailComprehensivePanelFaqBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
companion object {
|
||||
const val ITEM_FUNCTION = 0
|
||||
const val ITEM_FAQ = 1
|
||||
const val ITEM_DECLARATION = 2
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailContentCardDoubleBinding
|
||||
import com.gh.gamecenter.databinding.LayoutGameDetailContentCardBinding
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.ContentCardEntity
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
|
||||
class GameDetailContentCardDoubleItemViewHolder(
|
||||
val binding: ItemGameDetailContentCardDoubleBinding,
|
||||
downloadBtn: DownloadButton?,
|
||||
viewModel: GameDetailViewModel,
|
||||
private val lifecycleOwner: LifecycleOwner
|
||||
) :
|
||||
BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
data.linkContentCard?.let {
|
||||
val getGameStatus = { gameStatus }
|
||||
bindContentCard(
|
||||
lifecycleOwner,
|
||||
viewModel,
|
||||
it.first(),
|
||||
binding.firstCardContainer,
|
||||
baseTrackData.apply { supSequence = 0 },
|
||||
getGameStatus
|
||||
)
|
||||
bindContentCard(
|
||||
lifecycleOwner,
|
||||
viewModel,
|
||||
it[1],
|
||||
binding.secondCardContainer,
|
||||
baseTrackData.apply { supSequence = 1 },
|
||||
getGameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun bindContentCard(
|
||||
lifecycleOwner: LifecycleOwner,
|
||||
viewModel: GameDetailViewModel,
|
||||
contentCardEntity: ContentCardEntity,
|
||||
itemBinding: LayoutGameDetailContentCardBinding,
|
||||
trackData: GameDetailModuleTrackData,
|
||||
getGameStatus: () -> String
|
||||
) {
|
||||
itemBinding.run {
|
||||
GameDetailContentCardSingleItemViewHolder.bindContentCard(
|
||||
root.context,
|
||||
lifecycleOwner,
|
||||
viewModel,
|
||||
contentCardEntity,
|
||||
root,
|
||||
titleTv,
|
||||
iconIv,
|
||||
contentTv,
|
||||
contentBannerView,
|
||||
redDotTv,
|
||||
newIv,
|
||||
trackData,
|
||||
getGameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,281 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.gamecenter.ShellActivity
|
||||
import com.gh.gamecenter.ShellActivity.Type
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.view.TextBannerView
|
||||
import com.gh.gamecenter.core.utils.TimeUtils
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailContentCardSingleBinding
|
||||
import com.gh.gamecenter.feature.entity.MeEntity
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.ContentCardEntity
|
||||
import com.gh.gamecenter.gamedetail.entity.ContentCardEntity.Companion.TYPE_ARCHIVE
|
||||
import com.gh.gamecenter.gamedetail.entity.ContentCardEntity.Companion.TYPE_BBS
|
||||
import com.gh.gamecenter.gamedetail.entity.ContentCardEntity.Companion.TYPE_GIFT
|
||||
import com.gh.gamecenter.gamedetail.entity.ContentCardEntity.Companion.TYPE_RELATED_VERSION
|
||||
import com.gh.gamecenter.gamedetail.entity.ContentCardEntity.Companion.TYPE_SERVER
|
||||
import com.gh.gamecenter.gamedetail.entity.ContentCardEntity.Companion.TYPE_TOOLKIT
|
||||
import com.gh.gamecenter.gamedetail.entity.ContentCardEntity.Companion.TYPE_ZONE
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailTabEntity
|
||||
import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarActivity
|
||||
import com.gh.gamecenter.gamedetail.libao.LibaoListFragment
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import com.gh.gamecenter.newsdetail.NewsDetailActivity
|
||||
import kotlin.math.abs
|
||||
|
||||
class GameDetailContentCardSingleItemViewHolder(
|
||||
val binding: ItemGameDetailContentCardSingleBinding,
|
||||
downloadBtn: DownloadButton?,
|
||||
viewModel: GameDetailViewModel,
|
||||
private val lifecycleOwner: LifecycleOwner,
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val contentCardEntity = data.linkContentCard?.first() ?: return
|
||||
binding.run {
|
||||
bindContentCard(
|
||||
context,
|
||||
lifecycleOwner,
|
||||
viewModel,
|
||||
contentCardEntity,
|
||||
container,
|
||||
titleTv,
|
||||
iconIv,
|
||||
contentTv,
|
||||
contentBannerView,
|
||||
redDotTv,
|
||||
newIv,
|
||||
baseTrackData.apply { supSequence = 0 }
|
||||
) { gameStatus }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun bindContentCard(
|
||||
context: Context,
|
||||
lifecycleOwner: LifecycleOwner,
|
||||
viewModel: GameDetailViewModel,
|
||||
contentCardEntity: ContentCardEntity,
|
||||
containerView: ConstraintLayout,
|
||||
titleTv: TextView,
|
||||
iconIv: SimpleDraweeView,
|
||||
contentTv: TextView,
|
||||
contentBannerView: TextBannerView,
|
||||
redDotTv: TextView,
|
||||
newIv: ImageView,
|
||||
trackData: GameDetailModuleTrackData,
|
||||
getGameStatus: () -> String
|
||||
) {
|
||||
if (contentCardEntity.id == containerView.tag) {
|
||||
if (contentBannerView.isVisible) contentBannerView.updateView()
|
||||
containerView.background = com.gh.gamecenter.common.R.drawable.bg_shape_f8_radius_8.toDrawable(context)
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
contentTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
containerView.tag = contentCardEntity.id
|
||||
titleTv.text = contentCardEntity.title
|
||||
ImageUtils.display(iconIv, contentCardEntity.icon)
|
||||
|
||||
val showContentTv =
|
||||
contentCardEntity.showDes && (contentCardEntity.des.isNotEmpty() || contentCardEntity.link.type == TYPE_GIFT)
|
||||
contentTv.visibleIf(showContentTv) {
|
||||
contentTv.text =
|
||||
if (contentCardEntity.link.type == TYPE_GIFT && contentCardEntity.des.isEmpty()) "${contentCardEntity.libao?.total}个游戏礼包" else contentCardEntity.des
|
||||
contentTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
}
|
||||
|
||||
val showContentBannerView =
|
||||
contentCardEntity.showDes && contentCardEntity.link.type == TYPE_SERVER && contentCardEntity.server != null && contentCardEntity.des.isEmpty()
|
||||
contentBannerView.goneIf(!showContentBannerView) {
|
||||
val server = contentCardEntity.server ?: return@goneIf
|
||||
val nowTime = System.currentTimeMillis()
|
||||
var timeDiff = 0L
|
||||
var closestIndex = 0
|
||||
val bannerTextDataList = server.calendar.mapIndexed { index, serverCalendarEntity ->
|
||||
val diff = abs(nowTime - serverCalendarEntity.getTime() * 1000L)
|
||||
if (diff < timeDiff || index == 0) {
|
||||
timeDiff = diff
|
||||
closestIndex = index
|
||||
}
|
||||
val serverTime =
|
||||
if (TimeUtils.isToday(serverCalendarEntity.getTime()))
|
||||
serverCalendarEntity.getFormatTime("今天 HH:mm")
|
||||
else if (TimeUtils.isTomorrow(serverCalendarEntity.getTime()))
|
||||
serverCalendarEntity.getFormatTime("明天 HH:mm")
|
||||
else
|
||||
serverCalendarEntity.getFormatTime("MM-dd HH:mm")
|
||||
TextBannerView.BannerTextData("${serverTime ?: ""} ${serverCalendarEntity.type}")
|
||||
}
|
||||
contentBannerView.setDataList(bannerTextDataList, closestIndex)
|
||||
contentBannerView.startBannerLoop()
|
||||
}
|
||||
|
||||
redDotTv.goneIf(!((contentCardEntity.link.type == TYPE_SERVER && contentCardEntity.server?.total != 0) || contentCardEntity.link.type == TYPE_GIFT)) {
|
||||
if ((contentCardEntity.link.type == TYPE_SERVER) && (contentCardEntity.server?.calendar?.isNotEmpty() == true))
|
||||
redDotTv.text = contentCardEntity.server?.total.toString()
|
||||
if ((contentCardEntity.link.type == TYPE_GIFT) && (contentCardEntity.libao != null))
|
||||
redDotTv.text = contentCardEntity.libao?.total.toString()
|
||||
}
|
||||
|
||||
val showNewTag = contentCardEntity.link.type == TYPE_ARCHIVE && contentCardEntity.archive != null && contentCardEntity.showNewTag
|
||||
newIv.goneIf(!showNewTag)
|
||||
|
||||
containerView.setOnClickListener {
|
||||
NewFlatLogUtils.logGameDetailGameContentCardClick(
|
||||
contentCardEntity.title ?: "",
|
||||
viewModel.game?.name ?: "",
|
||||
viewModel.game?.id ?: "",
|
||||
contentCardEntity.link.type ?: "",
|
||||
contentCardEntity.link.link ?: "",
|
||||
contentCardEntity.link.text ?: ""
|
||||
)
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId = trackData.gameId,
|
||||
gameName = trackData.gameName,
|
||||
gameType = trackData.gameType,
|
||||
contentType = "组件内容",
|
||||
moduleType = trackData.moduleType,
|
||||
moduleName = trackData.moduleName,
|
||||
sequence = trackData.sequence,
|
||||
linkText = contentCardEntity.link.text ?: "",
|
||||
linkType = contentCardEntity.link.type ?: "",
|
||||
linkId = contentCardEntity.id,
|
||||
gameStatus = getGameStatus()
|
||||
)
|
||||
|
||||
val dialog = contentCardEntity.dialog
|
||||
if (dialog != null) {// 展示内容卡片提示弹窗
|
||||
DialogHelper.showDialog(
|
||||
context = context,
|
||||
title = dialog.title ?: "",
|
||||
content = dialog.body ?: "",
|
||||
confirmText = context.getString(com.gh.gamecenter.common.R.string.confirm),
|
||||
cancelText = context.getString(com.gh.gamecenter.common.R.string.cancel),
|
||||
confirmClickCallback = {
|
||||
jumpToContentCardLink(context, contentCardEntity, viewModel)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
jumpToContentCardLink(context, contentCardEntity, viewModel)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.contentCardClickedLiveData.observe(lifecycleOwner) {
|
||||
if (it.peekContent() == contentCardEntity.link.type) {
|
||||
it.getContentWithHandled()?.let { containerView.performClick() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun jumpToContentCardLink(context: Context, contentCardEntity: ContentCardEntity, viewModel: GameDetailViewModel) {
|
||||
val path = "游戏详情->内容卡片"
|
||||
when (contentCardEntity.link.type) {
|
||||
TYPE_GIFT,
|
||||
TYPE_ARCHIVE -> {
|
||||
val type = if (contentCardEntity.link.type == TYPE_GIFT) GameDetailTabEntity.TYPE_GIFT else GameDetailTabEntity.TYPE_ARCHIVE
|
||||
val tabList = viewModel.gameDetailTabListLiveData.value?.data
|
||||
if (tabList?.find { it.type == type } != null) {
|
||||
viewModel.performTabSelected(type)
|
||||
} else if (contentCardEntity.link.type == TYPE_GIFT) {
|
||||
val bundle = LibaoListFragment.getBundle(viewModel.game, false)
|
||||
context.startActivity(ShellActivity.getIntent(context, Type.SIMPLE_LIBAO_LIST, bundle))
|
||||
} else if (contentCardEntity.link.type == TYPE_ARCHIVE) {
|
||||
DirectUtils.directToCloudArchive(context, viewModel.game?.id ?: "", viewModel.game?.name ?: "", "", "游戏详情页-内容卡片")
|
||||
}
|
||||
}
|
||||
|
||||
TYPE_SERVER -> {
|
||||
if (viewModel.game != null && contentCardEntity.server != null) {
|
||||
context.startActivity(
|
||||
ServersCalendarActivity.getIntent(
|
||||
context,
|
||||
viewModel.game!!, contentCardEntity.server!!,
|
||||
MeEntity()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
TYPE_RELATED_VERSION -> {
|
||||
viewModel.scrollToListPositionLiveData.postValue(Event(LinkEntity(type = GameDetailData.TYPE_RELATED_GAME)))
|
||||
}
|
||||
|
||||
TYPE_ZONE -> {
|
||||
if (contentCardEntity.zoneTab && viewModel.game?.zone != null && viewModel.game?.zone!!.style == "link") {
|
||||
context.startActivity(
|
||||
WebActivity.getIntent(
|
||||
context,
|
||||
viewModel.game?.zone!!.link,
|
||||
true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
TYPE_BBS -> {
|
||||
val funcBbs = contentCardEntity.funcBbs
|
||||
funcBbs?.let {
|
||||
DirectUtils.directForumDetail(context, it.link, path)
|
||||
}
|
||||
}
|
||||
|
||||
TYPE_TOOLKIT -> {
|
||||
if (contentCardEntity.toolkit.isNotEmpty()) {
|
||||
contentCardEntity.toolkit.safelyGetInRelease(0)?.let {
|
||||
val url = it.url
|
||||
if (url != null && url.contains(Config.URL_ARTICLE)) {
|
||||
val newsId = url.substring(url.lastIndexOf("/") + 1, url.length - 5) // 5: ".html"
|
||||
val intent = NewsDetailActivity.getIntentById(context, newsId, path)
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
context.startActivity(
|
||||
WebActivity.getWebByCollectionTools(
|
||||
context,
|
||||
it,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> DirectUtils.directToLinkPage(
|
||||
context,
|
||||
contentCardEntity.link,
|
||||
viewModel.entrance ?: "",
|
||||
path,
|
||||
ExposureEvent.createEvent(
|
||||
null,
|
||||
listOf(
|
||||
ExposureSource("游戏详情", viewModel.game?.id ?: ""),
|
||||
ExposureSource("内容卡片", contentCardEntity.id)
|
||||
)
|
||||
),
|
||||
"游戏详情页-内容卡片"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailContentCardTripleBinding
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.detail.viewholder.GameDetailContentCardDoubleItemViewHolder.Companion.bindContentCard
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
|
||||
class GameDetailContentCardTripleItemViewHolder(
|
||||
val binding: ItemGameDetailContentCardTripleBinding,
|
||||
downloadBtn: DownloadButton?,
|
||||
viewModel: GameDetailViewModel,
|
||||
private val lifecycleOwner: LifecycleOwner
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
data.linkContentCard?.let {
|
||||
val getGameStatus = { gameStatus }
|
||||
bindContentCard(
|
||||
lifecycleOwner,
|
||||
viewModel,
|
||||
it.first(),
|
||||
binding.firstCardContainer,
|
||||
baseTrackData.apply { supSequence = 0 },
|
||||
getGameStatus
|
||||
)
|
||||
bindContentCard(
|
||||
lifecycleOwner,
|
||||
viewModel,
|
||||
it[1].apply { showDes = false },
|
||||
binding.secondCardContainer,
|
||||
baseTrackData.apply { supSequence = 1 },
|
||||
getGameStatus
|
||||
)
|
||||
bindContentCard(
|
||||
lifecycleOwner,
|
||||
viewModel,
|
||||
it[2].apply { showDes = false },
|
||||
binding.thirdCardContainer,
|
||||
baseTrackData.apply { supSequence = 2 },
|
||||
getGameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,157 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager
|
||||
import com.gh.gamecenter.common.entity.PKEntity
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.TimeUtils
|
||||
import com.gh.gamecenter.databinding.ItemPkBinding
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
|
||||
class GameDetailContentRecommendItemViewHolder(
|
||||
val binding: ItemPkBinding,
|
||||
downloadBtn: DownloadButton?,
|
||||
viewModel: GameDetailViewModel,
|
||||
private val lifecycleOwner: LifecycleOwner,
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
private var pkEntity: PKEntity? = null
|
||||
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val link = data.linkContentRecommend ?: return
|
||||
pkEntity = data.pkData
|
||||
if (pkEntity == null) {
|
||||
binding.root.updateLayoutParams<MarginLayoutParams> { height = 0 }
|
||||
return
|
||||
}
|
||||
|
||||
binding.run {
|
||||
if (link.type == TYPE_PK) {
|
||||
if (!pkView.isInitialized()) {
|
||||
viewModel.pkVoteResultLiveData.observe(lifecycleOwner) {
|
||||
if (it.peekContent().first == pkEntity?.id) {
|
||||
val pair = it.getContentWithHandled()
|
||||
if (pair != null && pkView.isInitialized()) {
|
||||
pkView.vote(pair.second)
|
||||
statisticsTv.text = "已有${pkEntity?.totalNum}人参与"
|
||||
pkView.showResultWithAnimation()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pkView.updateView()
|
||||
}
|
||||
binding.root.updateLayoutParams<MarginLayoutParams> {
|
||||
height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
setMargins(16F.dip2px(), 16F.dip2px(), 16F.dip2px(), 8F.dip2px())
|
||||
}
|
||||
bindPKItem(context, this, pkEntity!!, onPositiveClickAction = positive@{
|
||||
if (pkEntity == null) return@positive
|
||||
SensorsBridge.trackPKClick(
|
||||
GlobalActivityManager.getCurrentPageEntity().pageId,
|
||||
GlobalActivityManager.getCurrentPageEntity().pageName,
|
||||
GlobalActivityManager.getCurrentPageEntity().pageBusinessId,
|
||||
pkEntity!!.id,
|
||||
pkEntity!!.title,
|
||||
pkEntity!!.option1.text,
|
||||
clickSite = "选项"
|
||||
)
|
||||
viewModel.postPKVote(pkEntity!!.id, true)
|
||||
}, onNegativeClickAction = negative@{
|
||||
if (pkEntity == null) return@negative
|
||||
SensorsBridge.trackPKClick(
|
||||
GlobalActivityManager.getCurrentPageEntity().pageId,
|
||||
GlobalActivityManager.getCurrentPageEntity().pageName,
|
||||
GlobalActivityManager.getCurrentPageEntity().pageBusinessId,
|
||||
pkEntity!!.id,
|
||||
pkEntity!!.title,
|
||||
pkEntity!!.option2.text,
|
||||
clickSite = "选项"
|
||||
)
|
||||
viewModel.postPKVote(pkEntity!!.id, false)
|
||||
}) {
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
pkEntity?.title,
|
||||
sequence,
|
||||
null,
|
||||
null,
|
||||
pkEntity?.link?.type,
|
||||
pkEntity?.link?.link,
|
||||
pkEntity?.link?.text,
|
||||
gameStatus
|
||||
)
|
||||
SensorsBridge.trackPKClick(
|
||||
GlobalActivityManager.getCurrentPageEntity().pageId,
|
||||
GlobalActivityManager.getCurrentPageEntity().pageName,
|
||||
GlobalActivityManager.getCurrentPageEntity().pageBusinessId,
|
||||
pkEntity!!.id,
|
||||
pkEntity!!.title,
|
||||
"",
|
||||
pkEntity!!.link?.type ?: "",
|
||||
pkEntity!!.link?.link ?: "",
|
||||
pkEntity!!.link?.text ?: "",
|
||||
clickSite = "跳转链接"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TYPE_PK = "pk"
|
||||
const val TIME_PATTERN = "yyyy.MM.dd HH:mm:ss"
|
||||
|
||||
fun bindPKItem(
|
||||
context: Context,
|
||||
binding: ItemPkBinding,
|
||||
pkEntity: PKEntity,
|
||||
onPositiveClickAction: () -> Unit,
|
||||
onNegativeClickAction: () -> Unit,
|
||||
onLinkClickAction: () -> Unit
|
||||
) {
|
||||
binding.run {
|
||||
root.background = R.drawable.bg_shape_f8_radius_8.toDrawable(context)
|
||||
pkTitleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
endDateTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
statisticsTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
linkTv.background = com.gh.gamecenter.common.R.drawable.button_round_theme_alpha_10.toDrawable(context)
|
||||
linkTv.setTextColor(com.gh.gamecenter.common.R.color.primary_theme.toColor(context))
|
||||
pkView.run {
|
||||
setData(pkEntity)
|
||||
onPositiveClick = onPositiveClickAction
|
||||
onNegativeClick = onNegativeClickAction
|
||||
}
|
||||
pkTitleTv.text = pkEntity.title
|
||||
val endDateText = if (pkEntity.isExpired) "已" else "将"
|
||||
endDateTv.text = "${endDateText}于${TimeUtils.getFormatTime(pkEntity.time.end, TIME_PATTERN)}结束"
|
||||
statisticsTv.text = "已有${pkEntity.totalNum}人参与"
|
||||
linkTv.goneIf(pkEntity.link == null) {
|
||||
linkTv.setOnClickListener { _ ->
|
||||
pkEntity.link?.let {
|
||||
DirectUtils.directToLinkPage(
|
||||
context,
|
||||
it,
|
||||
"内容推荐-PK",
|
||||
""
|
||||
)
|
||||
}
|
||||
onLinkClickAction.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user