Compare commits
27 Commits
feat/dsp-o
...
feat/GHZSC
| Author | SHA1 | Date | |
|---|---|---|---|
| 9368d44093 | |||
| 6b04649c34 | |||
| 4497d03dbf | |||
| 287bbe7901 | |||
| fe8f9fcf83 | |||
| 0786342e00 | |||
| 1676f8bffb | |||
| 2e95a42f3c | |||
| da3b3360df | |||
| 080397e0d2 | |||
| 48d6533857 | |||
| 36bcf7f52a | |||
| da2b817d23 | |||
| afd0cce849 | |||
| 6970aedbd4 | |||
| df21c88ad2 | |||
| 7638296860 | |||
| 27058d5551 | |||
| 74b7bd8b47 | |||
| 539c9fb436 | |||
| bc57ba207c | |||
| 90b63b287f | |||
| 1233ff8458 | |||
| b75fd9cc9b | |||
| 6d992c77c7 | |||
| d5dc79f753 | |||
| 168f20a162 |
@ -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
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -11,7 +11,6 @@ import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.os.bundleOf
|
||||
import com.therouter.TheRouter
|
||||
import com.gh.ad.AdPluginDownloadHelper
|
||||
import com.gh.common.constant.Config
|
||||
import com.gh.common.exposure.ExposureManager.log
|
||||
@ -19,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
|
||||
@ -56,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.ServersCalendarManagementActivity
|
||||
import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersSubscribedGameListActivity
|
||||
@ -77,7 +78,6 @@ import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
|
||||
import com.gh.gamecenter.qa.subject.CommunitySubjectActivity
|
||||
import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.gh.gamecenter.SearchActivity
|
||||
import com.gh.gamecenter.servers.GameServerTestActivity
|
||||
import com.gh.gamecenter.servers.GameServersActivity
|
||||
import com.gh.gamecenter.servers.gametest2.GameServerTestV2Activity
|
||||
@ -98,6 +98,7 @@ import com.halo.assistant.fragment.WebFragment
|
||||
import com.lightgame.utils.Utils
|
||||
import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram
|
||||
import com.tencent.mm.opensdk.openapi.WXAPIFactory
|
||||
import com.therouter.TheRouter
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import retrofit2.HttpException
|
||||
@ -178,7 +179,8 @@ object DirectUtils {
|
||||
"qa",
|
||||
"feedback",
|
||||
"toolkit",
|
||||
"float_window_game"
|
||||
"float_window_game",
|
||||
"archive"
|
||||
)
|
||||
|
||||
fun directToLinkPage(
|
||||
@ -568,6 +570,8 @@ object DirectUtils {
|
||||
}
|
||||
}
|
||||
|
||||
"archive" -> directToCloudArchive(context, linkEntity.link ?: "", linkEntity.text ?: "", "", entrance)
|
||||
|
||||
"" -> {
|
||||
// do nothing
|
||||
}
|
||||
@ -810,10 +814,10 @@ object DirectUtils {
|
||||
bundle.putString(KEY_GAMEID, id)
|
||||
if (!TextUtils.isEmpty(tab)) {
|
||||
when (tab) {
|
||||
"comment" -> bundle.putString(KEY_TARGET, EntranceConsts.TAB_TYPE_RATING)
|
||||
"desc" -> bundle.putString(KEY_TARGET, EntranceConsts.TAB_TYPE_DESC)
|
||||
"forum" -> bundle.putString(KEY_TARGET, EntranceConsts.TAB_TYPE_BBS)
|
||||
"zone" -> bundle.putString(KEY_TARGET, EntranceConsts.TAB_TYPE_TRENDS)
|
||||
"comment" -> bundle.putString(KEY_TARGET, GameDetailTabEntity.TYPE_COMMENT)
|
||||
"desc" -> bundle.putString(KEY_TARGET, GameDetailTabEntity.TYPE_DETAIL)
|
||||
"forum" -> bundle.putString(KEY_TARGET, GameDetailTabEntity.TYPE_BBS)
|
||||
"zone" -> bundle.putString(KEY_TARGET, GameDetailTabEntity.TYPE_ZONE)
|
||||
}
|
||||
}
|
||||
if (traceEvent != null) {
|
||||
@ -858,7 +862,7 @@ object DirectUtils {
|
||||
bundle.putString(KEY_ENTRANCE, entrance)
|
||||
bundle.putString(KEY_GAMEID, id)
|
||||
bundle.putBoolean(KEY_OPEN_VIDEO_STREAMING, true)
|
||||
bundle.putString(KEY_TARGET, EntranceConsts.TAB_TYPE_DESC)
|
||||
bundle.putString(KEY_TARGET, GameDetailTabEntity.TYPE_DETAIL)
|
||||
jumpActivity(context, bundle)
|
||||
}
|
||||
|
||||
@ -866,7 +870,7 @@ object DirectUtils {
|
||||
fun directToGameDetail(
|
||||
context: Context,
|
||||
id: String,
|
||||
defaultTab: String = EntranceConsts.TAB_TYPE_DESC,
|
||||
defaultTab: String = GameDetailTabEntity.TYPE_DETAIL,
|
||||
entrance: String? = null
|
||||
) {
|
||||
val bundle = Bundle()
|
||||
@ -1524,7 +1528,7 @@ object DirectUtils {
|
||||
response?.apply {
|
||||
if (zone.status == "on") {
|
||||
if (zone.style == "link") {
|
||||
directToGameDetail(context, gameId, EntranceConsts.TAB_TYPE_TRENDS, entrance)
|
||||
directToGameDetail(context, gameId, GameDetailTabEntity.TYPE_ZONE, entrance)
|
||||
} else {
|
||||
directToWebView(context, url, entrance)
|
||||
}
|
||||
@ -2149,4 +2153,16 @@ object DirectUtils {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 跳转云存档详情页
|
||||
@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))
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
@ -48,7 +48,7 @@ class FlexLinearLayout @JvmOverloads constructor(context: Context, attrs: Attrib
|
||||
ta.recycle()
|
||||
}
|
||||
|
||||
fun setTags(tags: ArrayList<TagStyleEntity>) {
|
||||
fun setTags(tags: List<TagStyleEntity>) {
|
||||
mTags.clear()
|
||||
mTotalCount = tags.size
|
||||
mTotalWidth = measuredWidth
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -2,6 +2,7 @@ package com.gh.gamecenter.adapter;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
@ -12,6 +13,7 @@ import android.text.style.ClickableSpan;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
@ -20,9 +22,13 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
|
||||
import com.facebook.drawee.drawable.ScalingUtils;
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
||||
import com.facebook.drawee.view.SimpleDraweeView;
|
||||
import com.gh.common.util.DirectUtils;
|
||||
import com.gh.common.util.LibaoUtils;
|
||||
import com.gh.gamecenter.GameDetailActivity;
|
||||
import com.gh.gamecenter.ImageViewerActivity;
|
||||
import com.gh.gamecenter.R;
|
||||
import com.gh.gamecenter.adapter.viewholder.LibaoDetailContentViewHolder;
|
||||
import com.gh.gamecenter.adapter.viewholder.LibaoDetailTopViewHolder;
|
||||
@ -31,6 +37,7 @@ import com.gh.gamecenter.common.entity.SimpleGameEntity;
|
||||
import com.gh.gamecenter.common.entity.SuggestType;
|
||||
import com.gh.gamecenter.common.retrofit.Response;
|
||||
import com.gh.gamecenter.common.utils.ExtensionsKt;
|
||||
import com.gh.gamecenter.common.utils.ImageUtils;
|
||||
import com.gh.gamecenter.common.utils.PicassoImageGetter;
|
||||
import com.gh.gamecenter.common.viewholder.FooterViewHolder;
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils;
|
||||
@ -79,6 +86,7 @@ public class LibaoDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
private String mEntrance;
|
||||
private final int TYPE_FOOTER = 100;
|
||||
public LibaoDetailTopViewHolder libaoDetailTopViewHolder;
|
||||
private ArrayList<View> mImageViewList = new ArrayList<>();
|
||||
|
||||
public LibaoDetailAdapter(Context context, OnRequestCallBackListener onRequestCallBackListener,
|
||||
OnCodeScrollListener onCodeScrollListener, LibaoEntity libaoEntity,
|
||||
@ -317,6 +325,31 @@ public class LibaoDetailAdapter extends BaseRecyclerAdapter<ViewHolder> {
|
||||
holder.binding.libaodetailContentLl.setVisibility(View.VISIBLE);
|
||||
holder.binding.libaodetailContent.setText(Html.fromHtml(mLibaoEntity.getContent()));
|
||||
}
|
||||
if (mLibaoEntity.getMaterials().isEmpty()) {
|
||||
holder.binding.horizontalScrollView.setVisibility(View.GONE);
|
||||
} else {
|
||||
holder.binding.horizontalScrollView.setVisibility(View.VISIBLE);
|
||||
holder.binding.imagesContainer.removeAllViews();
|
||||
mImageViewList.clear();
|
||||
for (int i = 0; i < mLibaoEntity.getMaterials().size(); i++) {
|
||||
String imageUrl = mLibaoEntity.getMaterials().get(i);
|
||||
SimpleDraweeView imageView = new SimpleDraweeView(mContext);
|
||||
imageView.setHierarchy(new GenericDraweeHierarchyBuilder(mContext.getResources())
|
||||
.setFadeDuration(500)
|
||||
.setPlaceholderImage(com.gh.gamecenter.common.R.drawable.occupy, ScalingUtils.ScaleType.FIT_XY)
|
||||
.build());
|
||||
ImageUtils.display(imageView, imageUrl);
|
||||
final int index = i;
|
||||
imageView.setOnClickListener(v -> {
|
||||
Intent intent = ImageViewerActivity.getIntent(mContext, mLibaoEntity.getMaterials(), index, mImageViewList, mEntrance);
|
||||
mContext.startActivity(intent);
|
||||
});
|
||||
mImageViewList.add(imageView);
|
||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(DisplayUtils.dip2px(24F), DisplayUtils.dip2px(24F));
|
||||
layoutParams.setMargins(i != 0 ? DisplayUtils.dip2px(16F) : 0, 0, 0, 0);
|
||||
holder.binding.imagesContainer.addView(imageView, layoutParams);
|
||||
}
|
||||
}
|
||||
if (mLibaoDetailEntity != null) {
|
||||
holder.binding.libaodetailTimeLl.setVisibility(View.VISIBLE);
|
||||
|
||||
|
||||
@ -31,7 +31,6 @@ import com.gh.gamecenter.common.base.GlobalActivityManager.getCurrentPageEntity
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager.getLastPageEntity
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.eventbus.EBReuse
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.utils.NewFlatLogUtils
|
||||
import com.gh.gamecenter.core.runOnIoThread
|
||||
@ -44,8 +43,9 @@ import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.feature.view.DownloadButton.ButtonStyle
|
||||
import com.gh.gamecenter.gamedetail.GameDetailFragment
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailTabEntity
|
||||
import com.gh.gamecenter.teenagermode.TeenagerModeActivity.Companion.getIntent
|
||||
import com.gh.vspace.VHelper
|
||||
import com.lightgame.download.DownloadEntity
|
||||
@ -56,13 +56,15 @@ import java.io.File
|
||||
// 虽然叫 ViewHolder,但其实就是一个用来临时放 View 和相关操作的包裹类
|
||||
class DetailViewHolder(
|
||||
view: View,
|
||||
val viewModel: GameDetailViewModel?,
|
||||
val gameEntity: GameEntity,
|
||||
val isNewsDetail: Boolean, // 新闻详情不显示下载的游戏名, 只显示下载状态
|
||||
entrance: String?,
|
||||
name: String?,
|
||||
title: String?,
|
||||
val traceEvent: ExposureEvent?,
|
||||
val isSupportDualButton: Boolean = false // 是否支持双下载按钮,不支持的时候跟普通列表意义选用优先级高的那个来显示
|
||||
val isSupportDualButton: Boolean = false, // 是否支持双下载按钮,不支持的时候跟普通列表意义选用优先级高的那个来显示
|
||||
onDownloadClickAction: ((Boolean) -> Unit)? = null
|
||||
) {
|
||||
var context: Context
|
||||
var downloadBottom: View
|
||||
@ -115,7 +117,8 @@ class DetailViewHolder(
|
||||
mTitle = title ?: "",
|
||||
mAsVGame = false,
|
||||
mShowDualDownloadButton = gameDownloadMode == GameEntity.GAME_DOWNLOAD_BUTTON_MODE_DUAL,
|
||||
mTraceEvent = traceEvent
|
||||
mTraceEvent = traceEvent,
|
||||
onDownloadClickAction = onDownloadClickAction
|
||||
)
|
||||
|
||||
val vGameDownloadListener = OnDetailDownloadClickListener(
|
||||
@ -125,7 +128,8 @@ class DetailViewHolder(
|
||||
mTitle = title ?: "",
|
||||
mAsVGame = true,
|
||||
mShowDualDownloadButton = gameDownloadMode == GameEntity.GAME_DOWNLOAD_BUTTON_MODE_DUAL,
|
||||
mTraceEvent = traceEvent
|
||||
mTraceEvent = traceEvent,
|
||||
onDownloadClickAction = onDownloadClickAction
|
||||
)
|
||||
|
||||
// 不支持双下载按钮的情况时,优选一个下载方式显示
|
||||
@ -183,7 +187,8 @@ class DetailViewHolder(
|
||||
private val mTitle: String,
|
||||
private val mAsVGame: Boolean,
|
||||
private val mShowDualDownloadButton: Boolean,
|
||||
private val mTraceEvent: ExposureEvent?
|
||||
private val mTraceEvent: ExposureEvent?,
|
||||
private val onDownloadClickAction: ((Boolean) -> Unit)? = null
|
||||
) : View.OnClickListener {
|
||||
|
||||
private val mGameEntity: GameEntity = mViewHolder.gameEntity
|
||||
@ -276,7 +281,7 @@ class DetailViewHolder(
|
||||
showLandPageAddressDialogIfNeeded()
|
||||
}
|
||||
} else if ("toast" == offStatus) {
|
||||
EventBus.getDefault().post(EBReuse(GameDetailFragment.SKIP_RATING))
|
||||
mViewHolder.viewModel?.performTabSelected(GameDetailTabEntity.TYPE_COMMENT)
|
||||
ToastUtils.toast("该游戏因故暂不提供下载,具体详情可在相关评论中查看,敬请谅解~")
|
||||
showLandPageAddressDialogIfNeeded()
|
||||
}
|
||||
@ -295,6 +300,10 @@ class DetailViewHolder(
|
||||
DataLogUtils.uploadGameLog(mViewHolder.context, mGameEntity.id, mGameEntity.name, mEntrance)
|
||||
}
|
||||
|
||||
val buttonText = mViewHolder.downloadPb.text.ifEmpty { mViewHolder.overlayTv?.text ?: "" }
|
||||
val isUpdate = mViewHolder.context.getString(com.gh.gamecenter.feature.R.string.update_v) == buttonText || buttonText.contains(mViewHolder.context.getString(com.gh.gamecenter.feature.R.string.update))
|
||||
onDownloadClickAction?.invoke(isUpdate)
|
||||
|
||||
preDownload()
|
||||
}
|
||||
|
||||
|
||||
@ -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() {}
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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? = "",
|
||||
)
|
||||
@ -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,18 +3,19 @@ package com.gh.gamecenter.game.horizontal
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.DataCollectionUtils
|
||||
import com.gh.common.util.DownloadItemUtils
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.GameDetailActivity
|
||||
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.StringUtils
|
||||
import com.gh.gamecenter.entity.SubjectEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.subjectTypeToComponentStyle
|
||||
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
|
||||
import com.gh.gamecenter.gamedetail.detail.viewholder.BaseGameDetailItemViewHolder
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.subjectTypeToComponentStyle
|
||||
import com.lightgame.adapter.BaseRecyclerAdapter
|
||||
import com.lightgame.download.DownloadEntity
|
||||
|
||||
@ -22,7 +23,9 @@ class GameHorizontalAdapter(
|
||||
context: Context,
|
||||
private var mSubjectEntity: SubjectEntity,
|
||||
private var type: GameHorizontalListType = GameHorizontalListType.SubjectHorizontalType,
|
||||
private val trackColumnClick: Boolean = true
|
||||
private val trackColumnClick: Boolean = true,
|
||||
private val gameDetailTrackData: BaseGameDetailItemViewHolder.GameDetailModuleTrackData? = null,
|
||||
private val getGameStatus: (() -> String)? = null
|
||||
) : BaseRecyclerAdapter<GameHorizontalItemViewHolder>(context) {
|
||||
|
||||
var gameName = ""
|
||||
@ -85,6 +88,7 @@ class GameHorizontalAdapter(
|
||||
gameIcon.displayGameIcon(gameEntity)
|
||||
GameHorizontalSimpleItemViewHolder.setHorizontalNameAndGravity(gameName, gameEntity.name)
|
||||
downloadBtn.goneIf(!mSubjectEntity.showDownload)
|
||||
gameName.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(mContext))
|
||||
gameName.maxLines = if (mSubjectEntity.showDownload) 1 else 2
|
||||
}
|
||||
holder.bindGameHorizontalItem(gameEntity, mSubjectEntity)
|
||||
@ -111,20 +115,15 @@ class GameHorizontalAdapter(
|
||||
if (type == GameHorizontalListType.GameDetailHorizontalType) {
|
||||
DataCollectionUtils.uploadClick(mContext, path, "游戏详情", gameEntity.name)
|
||||
NewLogUtils.logGameDetailPopularClick(gameName, gameId, "game", gameEntity.name ?: "")
|
||||
SensorsBridge.trackGameDetailPagePopularClick(
|
||||
gameId = gameId,
|
||||
gameName = gameName,
|
||||
pageName = GlobalActivityManager.getCurrentPageEntity().pageName,
|
||||
pageId = GlobalActivityManager.getCurrentPageEntity().pageId,
|
||||
pageBusinessId = GlobalActivityManager.getCurrentPageEntity().pageBusinessId,
|
||||
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
|
||||
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
|
||||
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId,
|
||||
downloadStatus = game?.downloadStatusChinese ?: "",
|
||||
gameType = game?.categoryChinese ?: "",
|
||||
clickGameType = gameEntity.categoryChinese,
|
||||
clickGameName = gameEntity.name ?: "",
|
||||
clickGameId = gameEntity.id
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameDetailTrackData?.gameId,
|
||||
gameDetailTrackData?.gameName,
|
||||
gameDetailTrackData?.gameType,
|
||||
"右上角",
|
||||
gameDetailTrackData?.moduleType,
|
||||
gameDetailTrackData?.moduleName,
|
||||
gameDetailTrackData?.sequence,
|
||||
gameStatus = getGameStatus?.invoke()
|
||||
)
|
||||
if (!gameEntity.isMiniGame() && trackColumnClick) {
|
||||
SensorsBridge.trackColumnClick(
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1209,4 +1205,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 {
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,81 +1,119 @@
|
||||
package com.gh.gamecenter.gamedetail.cloudarchive
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.core.os.bundleOf
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.catalog.SpecialCatalogFragment
|
||||
import com.gh.gamecenter.cloudarchive.CloudArchiveManagerActivity
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager
|
||||
import com.gh.gamecenter.common.base.fragment.LazyFragment
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toResString
|
||||
import com.gh.gamecenter.common.json.json
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.FragmentCloudArchiveAlBinding
|
||||
import com.gh.gamecenter.databinding.FragmentCloudArchiveBinding
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
|
||||
class CloudArchiveFragment : LazyFragment() {
|
||||
|
||||
private var mUseAlternativeLayout = false
|
||||
private var mGameEntity: GameEntity? = null
|
||||
private var mBinding: FragmentCloudArchiveBinding? = null
|
||||
private var mAlternativeBinding: FragmentCloudArchiveAlBinding? = null
|
||||
private var mSearchFragment: CloudArchiveListFragment? = null
|
||||
private var mNormalFragment: CloudArchiveListFragment? = null
|
||||
private var mIsSearch = false
|
||||
private var mOrderList =
|
||||
listOf(CloudArchiveListViewModel.SortType.NEWEST, CloudArchiveListViewModel.SortType.HOTTEST)
|
||||
|
||||
override fun getRealLayoutId() = R.layout.fragment_cloud_archive
|
||||
private val searchBarBinding
|
||||
get() = if (mUseAlternativeLayout) mAlternativeBinding?.searchBar else mBinding?.searchBar
|
||||
|
||||
private val orderSfv
|
||||
get() = if (mUseAlternativeLayout) mAlternativeBinding?.orderSfv else mBinding?.orderSfv
|
||||
|
||||
private val archiveManageTv
|
||||
get() = if (mUseAlternativeLayout) mAlternativeBinding?.archiveManageTv else mBinding?.archiveManageTv
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
mUseAlternativeLayout = arguments?.getBoolean(EntranceConsts.KEY_USE_ALTERNATIVE_LAYOUT) ?: false
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun getRealLayoutId() =
|
||||
if (mUseAlternativeLayout) R.layout.fragment_cloud_archive_al else R.layout.fragment_cloud_archive
|
||||
|
||||
override fun onRealLayoutInflated(inflatedView: View) {
|
||||
mBinding = FragmentCloudArchiveBinding.bind(inflatedView)
|
||||
if (mUseAlternativeLayout) {
|
||||
mAlternativeBinding = FragmentCloudArchiveAlBinding.bind(inflatedView)
|
||||
} else {
|
||||
mBinding = FragmentCloudArchiveBinding.bind(inflatedView)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFragmentFirstVisible() {
|
||||
mGameEntity = arguments?.getParcelable(EntranceConsts.KEY_GAME)
|
||||
mGameEntity = arguments?.getParcelable(EntranceConsts.KEY_GAME_ENTITY)
|
||||
super.onFragmentFirstVisible()
|
||||
changeContentFragment()
|
||||
|
||||
SensorsBridge.trackEvent("CloudSavePageView", json {
|
||||
"game_id" to mGameEntity?.id
|
||||
"game_name" to mGameEntity?.name
|
||||
"last_page_name" to GlobalActivityManager.getLastPageEntity().pageName
|
||||
"last_page_id" to GlobalActivityManager.getLastPageEntity().pageId
|
||||
})
|
||||
}
|
||||
|
||||
override fun inflateRealView() {
|
||||
super.inflateRealView()
|
||||
mBinding?.run {
|
||||
searchBar.etSearch.hint = R.string.game_detail_cloud_archive_search_hint.toResString()
|
||||
orderSfv.setItemList(mOrderList.map { it.value }, 1)
|
||||
orderSfv.setOnCheckedCallback {
|
||||
mAlternativeBinding?.run {
|
||||
reuseToolbar.normalTitle.run {
|
||||
text = "${mGameEntity?.name}-云存档"
|
||||
marqueeOnce()
|
||||
}
|
||||
}
|
||||
orderSfv?.run {
|
||||
setItemList(mOrderList.map { it.value }, 1)
|
||||
setOnCheckedCallback {
|
||||
if (mIsSearch) {
|
||||
mSearchFragment?.updateSortType(mOrderList[it])
|
||||
} else {
|
||||
mNormalFragment?.updateSortType(mOrderList[it])
|
||||
}
|
||||
}
|
||||
searchBar.etSearch.setOnEditorActionListener { _, actionId, _ ->
|
||||
}
|
||||
searchBarBinding?.run {
|
||||
etSearch.hint = R.string.game_detail_cloud_archive_search_hint.toResString()
|
||||
tvBack.setOnClickListener {
|
||||
changeSearchStatus(false)
|
||||
etSearch.setText("")
|
||||
}
|
||||
etSearch.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||
searchBar.tvSearch.performClick()
|
||||
tvSearch.performClick()
|
||||
}
|
||||
false
|
||||
}
|
||||
searchBar.tvSearch.setOnClickListener {
|
||||
val keyWord = searchBar.etSearch.text.toString().trim { it <= ' ' }
|
||||
tvSearch.setOnClickListener {
|
||||
val keyWord = etSearch.text.toString().trim { it <= ' ' }
|
||||
if (keyWord.isBlank()) {
|
||||
toast(R.string.search_hint)
|
||||
} else {
|
||||
changeSearchStatus(true)
|
||||
}
|
||||
}
|
||||
searchBar.tvBack.setOnClickListener {
|
||||
changeSearchStatus(false)
|
||||
searchBar.etSearch.setText("")
|
||||
}
|
||||
archiveManageTv.setOnClickListener {
|
||||
startActivity(
|
||||
CloudArchiveManagerActivity.getIntent(
|
||||
requireContext(),
|
||||
mGameEntity ?: GameEntity(),
|
||||
arguments?.getString(EntranceConsts.KEY_ARCHIVE_CONFIG_URL) ?: "",
|
||||
"游戏详情页"
|
||||
)
|
||||
}
|
||||
archiveManageTv?.setOnClickListener {
|
||||
startActivity(
|
||||
CloudArchiveManagerActivity.getIntent(
|
||||
requireContext(),
|
||||
mGameEntity ?: GameEntity(),
|
||||
arguments?.getString(EntranceConsts.KEY_ARCHIVE_CONFIG_URL) ?: "",
|
||||
"游戏详情页"
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,7 +137,7 @@ class CloudArchiveFragment : LazyFragment() {
|
||||
EntranceConsts.KEY_ARCHIVE_CONFIG_URL to arguments?.getString(EntranceConsts.KEY_ARCHIVE_CONFIG_URL, "")
|
||||
)
|
||||
if (mIsSearch) {
|
||||
val keyWord = mBinding?.searchBar?.etSearch?.text?.toString()?.trim { it <= ' ' }
|
||||
val keyWord = searchBarBinding?.etSearch?.text?.toString()?.trim { it <= ' ' }
|
||||
bundle.putString(EntranceConsts.KEY_SEARCHKEY, keyWord)
|
||||
NewFlatLogUtils.logCloudArchiveSearchKeyUpload(
|
||||
mGameEntity?.id ?: "",
|
||||
@ -113,7 +151,7 @@ class CloudArchiveFragment : LazyFragment() {
|
||||
.replace(
|
||||
R.id.contentFragment,
|
||||
fragment,
|
||||
SpecialCatalogFragment::class.java.name
|
||||
CloudArchiveListFragment::class.java.name
|
||||
)
|
||||
.commitAllowingStateLoss()
|
||||
}
|
||||
@ -122,14 +160,27 @@ class CloudArchiveFragment : LazyFragment() {
|
||||
when {
|
||||
mIsSearch != isSearch -> {
|
||||
mIsSearch = isSearch
|
||||
mBinding?.searchBar?.tvBack?.goneIf(!mIsSearch)
|
||||
searchBarBinding?.tvBack?.goneIf(!mIsSearch)
|
||||
changeContentFragment()
|
||||
}
|
||||
|
||||
mIsSearch -> {
|
||||
val keyWord = mBinding?.searchBar?.etSearch?.text?.toString()?.trim { it <= ' ' } ?: ""
|
||||
val keyWord = searchBarBinding?.etSearch?.text?.toString()?.trim { it <= ' ' } ?: ""
|
||||
NewFlatLogUtils.logCloudArchiveSearchKeyUpload(mGameEntity?.id ?: "", mGameEntity?.name ?: "", keyWord)
|
||||
mSearchFragment?.updateSearchKeyWord(keyWord)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
orderSfv?.run {
|
||||
setContainerBackground(com.gh.gamecenter.common.R.drawable.button_round_f5f5f5.toDrawable(requireContext()))
|
||||
setIndicatorBackground(R.drawable.bg_game_collection_sfv_indicator.toDrawable(requireContext()))
|
||||
setTextColor(
|
||||
com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()),
|
||||
com.gh.gamecenter.common.R.color.text_tertiary.toColor(requireContext())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gh.gamecenter.gamedetail.desc
|
||||
package com.gh.gamecenter.gamedetail.detail
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@ -6,7 +6,6 @@ import com.gh.common.exposure.ExposureManager
|
||||
import com.gh.common.filter.RegionSettingHelper
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.GameDetailActivity
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
@ -14,6 +13,7 @@ import com.gh.gamecenter.databinding.GamedetailItemGameCollectionBinding
|
||||
import com.gh.gamecenter.entity.GameDetailRecommendGameEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.gamedetail.detail.viewholder.BaseGameDetailItemViewHolder
|
||||
|
||||
class GameCollectionAdapter(
|
||||
private val mRecommendGameList: ArrayList<GameDetailRecommendGameEntity>,
|
||||
@ -22,7 +22,9 @@ class GameCollectionAdapter(
|
||||
private val mGame: GameEntity?,
|
||||
private val mEntrance: String,
|
||||
private val mPath: String,
|
||||
private val mBasicExposureSource: List<ExposureSource>
|
||||
private val mBasicExposureSource: List<ExposureSource>,
|
||||
private val trackData: BaseGameDetailItemViewHolder.GameDetailModuleTrackData,
|
||||
private val getGameStatus: () -> String
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
private val mDefaultHorizontalPadding by lazy { com.gh.gamecenter.common.R.dimen.game_detail_item_horizontal_padding.toPx() }
|
||||
@ -72,20 +74,16 @@ class GameCollectionAdapter(
|
||||
}
|
||||
gameCountTv.text = "+${entity.count.game - games.size}"
|
||||
root.setOnClickListener {
|
||||
SensorsBridge.trackGameDetailPageGameCollectRecommendClick(
|
||||
gameId = mGameId,
|
||||
gameName = mGameName,
|
||||
pageName = GlobalActivityManager.getCurrentPageEntity().pageName,
|
||||
pageId = GlobalActivityManager.getCurrentPageEntity().pageId,
|
||||
pageBusinessId = GlobalActivityManager.getCurrentPageEntity().pageBusinessId,
|
||||
lastPageId = GlobalActivityManager.getCurrentPageEntity().pageId,
|
||||
lastPageName = GlobalActivityManager.getCurrentPageEntity().pageName,
|
||||
lastPageBusinessId = GlobalActivityManager.getCurrentPageEntity().pageBusinessId,
|
||||
downloadStatus = mGame?.downloadStatusChinese ?: "",
|
||||
gameType = mGame?.categoryChinese ?: "",
|
||||
text = "游戏单",
|
||||
gameCollectId = entity.id,
|
||||
gameCollectTitle = entity.title
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
trackData.gameId,
|
||||
trackData.gameName,
|
||||
trackData.gameType,
|
||||
"组件内容",
|
||||
trackData.moduleType,
|
||||
"游戏单推荐",
|
||||
trackData.sequence,
|
||||
supSequence = position + 1,
|
||||
gameStatus = getGameStatus()
|
||||
)
|
||||
DirectUtils.directToGameCollectionDetail(
|
||||
it.context,
|
||||
@ -0,0 +1,186 @@
|
||||
package com.gh.gamecenter.gamedetail.detail
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.ImageViewerActivity
|
||||
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.databinding.ItemGameCoverGalleryBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameCoverVideoBinding
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.CoverEntity
|
||||
import com.gh.gamecenter.gamedetail.video.TopVideoView
|
||||
import com.lightgame.adapter.BaseRecyclerAdapter
|
||||
import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder
|
||||
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack
|
||||
import com.shuyu.gsyvideoplayer.utils.OrientationUtils
|
||||
|
||||
class GameDetailCoverAdapter(
|
||||
context: Context,
|
||||
private val fragment: GameDetailFragment,
|
||||
private val snapHelper: LeftPagerSnapHelper,
|
||||
private val viewModel: GameDetailViewModel
|
||||
) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
|
||||
|
||||
private var coverRecyclerView: RecyclerView? = null
|
||||
private var coverList = arrayListOf<CoverEntity>()
|
||||
private val imageViewWidth = ((DisplayUtils.getScreenWidth(fragment.activity) / 2F) - 16F.dip2px()).toInt()
|
||||
private var firstGalleryItemPosition = -1
|
||||
private var isSingleGallery = false
|
||||
private var hasSetFixedHeight = false
|
||||
|
||||
fun submitList(data: List<CoverEntity>) {
|
||||
coverList = ArrayList(data)
|
||||
firstGalleryItemPosition = coverList.indexOfFirst { it.gallery != null }
|
||||
isSingleGallery = coverList.count { it.gallery != null } == 1
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
|
||||
super.onAttachedToRecyclerView(recyclerView)
|
||||
coverRecyclerView = recyclerView
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
val coverEntity = coverList.getOrNull(position)
|
||||
return when {
|
||||
coverEntity?.video != null -> ITEM_VIDEO
|
||||
else -> ITEM_GALLERY
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return when (viewType) {
|
||||
ITEM_VIDEO -> GameDetailCoverVideoItemViewHolder(parent.toBinding())
|
||||
else -> GameDetailCoverGalleryItemViewHolder(parent.toBinding())
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = coverList.size
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
coverList.getOrNull(position)?.let {
|
||||
if (holder is GameDetailCoverVideoItemViewHolder) {
|
||||
bindVideoItem(holder, it, position)
|
||||
}
|
||||
if (holder is GameDetailCoverGalleryItemViewHolder) {
|
||||
bindGalleryItem(holder, it, position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindVideoItem(holder: GameDetailCoverVideoItemViewHolder, entity: CoverEntity, position: Int) {
|
||||
if (position == 0 && !hasSetFixedHeight) {
|
||||
holder.binding.root.post {
|
||||
coverRecyclerView?.updateLayoutParams<ViewGroup.LayoutParams> { height = holder.binding.root.height }
|
||||
hasSetFixedHeight = true
|
||||
}
|
||||
}
|
||||
|
||||
val topVideo = entity.video ?: return
|
||||
val orientationUtils = OrientationUtils(mContext as Activity, holder.binding.player)
|
||||
orientationUtils.isEnable = false
|
||||
GSYVideoOptionBuilder()
|
||||
.setIsTouchWigetFull(false)
|
||||
.setIsTouchWiget(false)
|
||||
.setRotateViewAuto(false)
|
||||
.setShowFullAnimation(false)
|
||||
.setSeekRatio(1F)
|
||||
.setUrl(topVideo.url)
|
||||
.setCacheWithPlay(true)
|
||||
.setShowPauseCover(true)
|
||||
.setReleaseWhenLossAudio(false)
|
||||
.setVideoAllCallBack(object : GSYSampleCallBack() {
|
||||
override fun onQuitFullscreen(url: String?, vararg objects: Any) {
|
||||
orientationUtils.backToProtVideo()
|
||||
holder.binding.player.uploadVideoStreamingPlaying("退出全屏")
|
||||
}
|
||||
})
|
||||
.build(holder.binding.player)
|
||||
|
||||
holder.binding.player.gameName = viewModel.game?.name ?: ""
|
||||
holder.binding.player.viewModel = viewModel
|
||||
holder.binding.player.video = topVideo
|
||||
holder.binding.player.updateThumb(topVideo.poster)
|
||||
|
||||
holder.binding.player.fullscreenButton.setOnClickListener {
|
||||
val horizontalVideoView =
|
||||
holder.binding.player.startWindowFullscreen(mContext, true, true) as? TopVideoView
|
||||
if (horizontalVideoView == null) {
|
||||
toastInInternalRelease("全屏失败,请向技术人员提供具体的操作步骤")
|
||||
return@setOnClickListener
|
||||
}
|
||||
orientationUtils.resolveByClick()
|
||||
horizontalVideoView.uuid = holder.binding.player.uuid
|
||||
horizontalVideoView.viewModel = viewModel
|
||||
horizontalVideoView.video = topVideo
|
||||
horizontalVideoView.updateThumb(topVideo.poster)
|
||||
horizontalVideoView.violenceUpdateMuteStatus()
|
||||
holder.binding.player.uploadVideoStreamingPlaying("开始播放")
|
||||
holder.binding.player.uploadVideoStreamingPlaying("点击全屏")
|
||||
}
|
||||
|
||||
holder.binding.player.observeVolume(fragment)
|
||||
}
|
||||
|
||||
private fun bindGalleryItem(holder: GameDetailCoverGalleryItemViewHolder, entity: CoverEntity, position: Int) {
|
||||
val imageUrl = entity.gallery?.url ?: ""
|
||||
val isLastItem = position == coverList.lastIndex
|
||||
val imageWidth = (entity.gallery?.width ?: return).toInt()
|
||||
val imageHeight = (entity.gallery?.height ?: return).toInt()
|
||||
val isLandscape = imageWidth >= imageHeight
|
||||
val ratio = imageWidth / imageHeight.toFloat()
|
||||
ConstraintSet().also {
|
||||
it.clone(holder.binding.root)
|
||||
it.setDimensionRatio(holder.binding.galleryIv.id, if (isLandscape) "h,344:193" else "")
|
||||
}.applyTo(holder.binding.root)
|
||||
holder.binding.root.updateLayoutParams<MarginLayoutParams> {
|
||||
width = if (isLandscape || isSingleGallery) ViewGroup.LayoutParams.MATCH_PARENT else ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
height = if (isLandscape || isSingleGallery) ViewGroup.LayoutParams.WRAP_CONTENT else PORTRAIT_IMAGE_HEIGHT_DP.dip2px()
|
||||
rightMargin = if (isLandscape || isSingleGallery || isLastItem) 8F.dip2px() else 0
|
||||
}
|
||||
holder.binding.galleryIv.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
width = if (isLandscape) 0 else (PORTRAIT_IMAGE_HEIGHT_DP.dip2px() * ratio).toInt()
|
||||
height = if (isLandscape) 0 else PORTRAIT_IMAGE_HEIGHT_DP.dip2px()
|
||||
}
|
||||
if (position == 0 && !hasSetFixedHeight) {
|
||||
holder.binding.root.post {
|
||||
coverRecyclerView?.updateLayoutParams<ViewGroup.LayoutParams> { height = holder.binding.root.height }
|
||||
hasSetFixedHeight = true
|
||||
}
|
||||
}
|
||||
|
||||
holder.binding.galleryIv.setTag(ImageUtils.TAG_TARGET_WIDTH, imageViewWidth)
|
||||
ImageUtils.display(holder.binding.galleryIv, imageUrl)
|
||||
holder.binding.root.setOnClickListener {
|
||||
val intent = ImageViewerActivity.getIntent(
|
||||
mContext,
|
||||
arrayListOf(imageUrl),
|
||||
0,
|
||||
listOf(holder.binding.galleryIv),
|
||||
"游戏详情-视频/图片区域"
|
||||
)
|
||||
mContext.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ITEM_VIDEO = 0
|
||||
const val ITEM_GALLERY = 1
|
||||
|
||||
private const val PORTRAIT_IMAGE_HEIGHT_DP = 280F
|
||||
}
|
||||
|
||||
class GameDetailCoverVideoItemViewHolder(val binding: ItemGameCoverVideoBinding) :
|
||||
BaseRecyclerViewHolder<Any>(binding.root)
|
||||
|
||||
class GameDetailCoverGalleryItemViewHolder(val binding: ItemGameCoverGalleryBinding) :
|
||||
BaseRecyclerViewHolder<Any>(binding.root)
|
||||
}
|
||||
@ -0,0 +1,876 @@
|
||||
package com.gh.gamecenter.gamedetail.detail
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.graphics.drawable.TransitionDrawable
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.iterator
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.RecyclerView.OnScrollListener
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.common.view.FlexLinearLayout
|
||||
import com.gh.gamecenter.ImageViewerActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager.getCurrentPageEntity
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager.getLastPageEntity
|
||||
import com.gh.gamecenter.common.base.fragment.LazyFragment
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.eventbus.EBReuse
|
||||
import com.gh.gamecenter.common.json.json
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.view.ScrollEventListener
|
||||
import com.gh.gamecenter.common.view.TextBannerView
|
||||
import com.gh.gamecenter.core.iinterface.IScrollable
|
||||
import com.gh.gamecenter.core.provider.IFloatingWindowProvider
|
||||
import com.gh.gamecenter.core.utils.*
|
||||
import com.gh.gamecenter.databinding.FragmentNewGameDetailBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailDataInfoBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailFunctionTagBinding
|
||||
import com.gh.gamecenter.databinding.LayoutGuideGameDetailFunctionTagBinding
|
||||
import com.gh.gamecenter.entity.RatingComment
|
||||
import com.gh.gamecenter.eventbus.EBTypeChange
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.entity.TagStyleEntity
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.GameDetailWrapperFragment
|
||||
import com.gh.gamecenter.gamedetail.detail.viewholder.BaseGameDetailItemViewHolder.Companion.getGameStatus
|
||||
import com.gh.gamecenter.gamedetail.detail.viewholder.GameDetailCommentItemViewHolder
|
||||
import com.gh.gamecenter.gamedetail.dialog.GameBigEventDialogFragment
|
||||
import com.gh.gamecenter.gamedetail.dialog.GameFunctionDialogFragment
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailDataInfo
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailInfoTag
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailTabEntity
|
||||
import com.gh.gamecenter.gamedetail.rating.RatingFragment
|
||||
import com.gh.gamecenter.gamedetail.video.GameDetailScrollCalculatorHelper
|
||||
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
|
||||
import com.gh.gamecenter.livedata.EventObserver
|
||||
import com.gh.gamecenter.tag.TagsActivity
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
|
||||
import com.therouter.TheRouter
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
|
||||
class GameDetailFragment(private val downloadButton: DownloadButton) : LazyFragment(), IScrollable {
|
||||
private lateinit var binding: FragmentNewGameDetailBinding
|
||||
private lateinit var viewModel: GameDetailViewModel
|
||||
private lateinit var scrollCalculatorHelper: GameDetailScrollCalculatorHelper
|
||||
private val coverAdapter by lazy {
|
||||
GameDetailCoverAdapter(
|
||||
requireContext(),
|
||||
this@GameDetailFragment,
|
||||
snapHelper,
|
||||
viewModel
|
||||
)
|
||||
}
|
||||
private val coverLayoutManager by lazy {
|
||||
LinearLayoutManager(requireContext(), RecyclerView.HORIZONTAL, false)
|
||||
}
|
||||
private val snapHelper by lazy { LeftPagerSnapHelper() }
|
||||
private val coverScrollEventListener by lazy { ScrollEventListener(binding.coverRv) }
|
||||
private val detailListAdapter by lazy {
|
||||
GameDetailListAdapter(downloadButton, viewModel, viewLifecycleOwner)
|
||||
}
|
||||
private val detailLayoutManager by lazy { LinearLayoutManager(requireContext()) }
|
||||
|
||||
private var lastCompletelyVisibleCoverPosition = 0
|
||||
private var isCoverHeightAnimating = false
|
||||
private var coverPosition = 0
|
||||
private var bigEventTransitionDrawable: TransitionDrawable? = null
|
||||
private var gameEntity: GameEntity? = null
|
||||
private val gameStatus
|
||||
get() = getGameStatus(downloadButton.buttonStyle)
|
||||
|
||||
private var functionTagGuide: ViewGroup? = null
|
||||
private var compositeDisposable = CompositeDisposable()
|
||||
private var isPauseCoverVideo = false
|
||||
|
||||
override fun getRealLayoutId(): Int = R.layout.fragment_new_game_detail
|
||||
|
||||
override fun onRealLayoutInflated(inflatedView: View) {
|
||||
super.onRealLayoutInflated(inflatedView)
|
||||
binding = FragmentNewGameDetailBinding.bind(inflatedView)
|
||||
scrollCalculatorHelper = GameDetailScrollCalculatorHelper(binding.coverRv, R.id.player, 0)
|
||||
|
||||
showFloatingWindowIfNeeded()
|
||||
}
|
||||
|
||||
override fun onFragmentFirstVisible() {
|
||||
super.onFragmentFirstVisible()
|
||||
|
||||
val gameId = arguments?.getString(EntranceConsts.KEY_GAME_ID) ?: ""
|
||||
gameEntity = arguments?.getParcelable(EntranceConsts.KEY_GAME_ENTITY)
|
||||
val factory = GameDetailViewModel.Factory(
|
||||
HaloApp.getInstance().application,
|
||||
gameId,
|
||||
gameEntity,
|
||||
mEntrance
|
||||
)
|
||||
viewModel = viewModelProviderFromParent(factory, gameId)
|
||||
|
||||
initCover()
|
||||
initDetailRv()
|
||||
observeData()
|
||||
|
||||
binding.gamedetailAppbar.addOnOffsetChangedListener { _, verticalOffset ->
|
||||
if (!isAdded) return@addOnOffsetChangedListener
|
||||
|
||||
val absVerticalOffset = abs(verticalOffset)
|
||||
val coverHeight = binding.coverRv.height
|
||||
if (viewModel.displayCoverVideo && coverHeight != 0) {
|
||||
val player = scrollCalculatorHelper.currentPlayer
|
||||
if (absVerticalOffset > coverHeight && !isPauseCoverVideo && player?.currentState == GSYVideoView.CURRENT_STATE_PLAYING) {
|
||||
pauseVideo()
|
||||
isPauseCoverVideo = true
|
||||
} else if (absVerticalOffset == 0 && isPauseCoverVideo && player?.currentState == GSYVideoView.CURRENT_STATE_PAUSE) {
|
||||
resumeVideo()
|
||||
isPauseCoverVideo = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeData() {
|
||||
viewModel.coverListLiveData.observeNonNull(viewLifecycleOwner) {
|
||||
coverAdapter.submitList(it)
|
||||
binding.run {
|
||||
val defaultCoverEntity = it.find { coverEntity -> coverEntity.isDefault }
|
||||
val tabNameList = it.map { coverEntity -> coverEntity.tabName }.distinct()
|
||||
coverSfv.goneIf(tabNameList.size < 2) {
|
||||
val defaultTabPosition =
|
||||
tabNameList.indexOfFirst { tabName -> defaultCoverEntity?.tabName == tabName }
|
||||
coverSfv.setItemList(tabNameList, if (defaultTabPosition != -1) defaultTabPosition else 0)
|
||||
coverSfv.setOnCheckedCallback { position ->
|
||||
val checkedText = tabNameList.getOrNull(position)
|
||||
val currentCoverEntity = it.getOrNull(coverPosition)
|
||||
if (currentCoverEntity?.tabName == checkedText) return@setOnCheckedCallback
|
||||
|
||||
val checkPosition = it.indexOfFirst { coverEntity -> coverEntity.tabName == checkedText }
|
||||
if (checkPosition != -1) {
|
||||
coverRv.setCurrentItem(checkPosition)
|
||||
SensorsBridge.trackEvent("GameDetailMediaTabClick", json {
|
||||
"game_id" to gameEntity?.id
|
||||
"game_name" to gameEntity?.name
|
||||
"sequence" to position + 1
|
||||
"tab_name" to checkedText
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
coverRv.scrollToPosition(defaultCoverEntity?.index ?: 0)
|
||||
coverPosition = defaultCoverEntity?.index ?: 0
|
||||
}
|
||||
|
||||
if (viewModel.isTopVideoPartlyCached(viewModel.coverListLiveData.value?.first()?.video?.url ?: "")) {
|
||||
postRunnable {
|
||||
notifyScrollStateChanged(RecyclerView.SCROLL_STATE_IDLE)
|
||||
}
|
||||
} else {
|
||||
// 未有缓存时,为避免影响页面加载,延迟自动播放视频
|
||||
postDelayedRunnable({
|
||||
if (activity != null && activity?.isFinishing != true) {
|
||||
notifyScrollStateChanged(RecyclerView.SCROLL_STATE_IDLE)
|
||||
}
|
||||
}, COVER_VIDEO_INITIAL_DELAY)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.basicInfoLiveData.observeNonNull(viewLifecycleOwner) {
|
||||
initBasicInfo(it)
|
||||
}
|
||||
|
||||
viewModel.bigEventLiveData.observeNonNull(viewLifecycleOwner) {
|
||||
GameBigEventDialogFragment.show(
|
||||
requireContext(),
|
||||
gameEntity?.id ?: "",
|
||||
gameEntity?.name ?: "",
|
||||
it
|
||||
) { link, _ ->
|
||||
DirectUtils.directToLinkPage(requireContext(), link, mEntrance, "游戏大事件弹窗", "游戏详情页-大事件")
|
||||
NewFlatLogUtils.logGameDetailMajorEventDetailClick(
|
||||
gameEntity?.name ?: "",
|
||||
gameEntity?.id ?: "",
|
||||
link.link ?: "",
|
||||
link.type ?: "",
|
||||
link.text ?: ""
|
||||
)
|
||||
SensorsBridge.trackGameDetailPageMajorEventClick(
|
||||
gameId = gameEntity?.id ?: "",
|
||||
gameName = gameEntity?.name ?: "",
|
||||
pageName = getCurrentPageEntity().pageName,
|
||||
pageId = getCurrentPageEntity().pageId,
|
||||
pageBusinessId = getCurrentPageEntity().pageBusinessId,
|
||||
lastPageName = getLastPageEntity().pageName,
|
||||
lastPageId = getLastPageEntity().pageId,
|
||||
lastPageBusinessId = getLastPageEntity().pageBusinessId,
|
||||
downloadStatus = gameEntity?.downloadStatusChinese ?: "",
|
||||
gameType = gameEntity?.categoryChinese ?: "",
|
||||
action = "跳转链接",
|
||||
linkText = link.text ?: "",
|
||||
linkType = link.type ?: "",
|
||||
linkId = link.link ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.dataInfoLiveData.observeNonNull(viewLifecycleOwner) {
|
||||
initDataInfo(it)
|
||||
}
|
||||
|
||||
viewModel.infoTagLiveData.observeNonNull(viewLifecycleOwner) {
|
||||
initInfoTags(it)
|
||||
}
|
||||
|
||||
viewModel.detailDataListLiveData.observeNonNull(viewLifecycleOwner) {
|
||||
if (it.isNotEmpty()) {
|
||||
detailListAdapter.submitList(it)
|
||||
} else {
|
||||
binding.coordinator.isVisible = false
|
||||
binding.reuseNoneData.root.isVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.scrollToListPositionLiveData.observe(viewLifecycleOwner, EventObserver { type ->
|
||||
val position = viewModel.detailDataListLiveData.value?.indexOfFirst { it.type == type } ?: -1
|
||||
if (position != -1) {
|
||||
binding.gamedetailAppbar.setExpanded(false, true)
|
||||
detailLayoutManager.scrollToPositionWithOffset(position, 0)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun initDetailRv() {
|
||||
binding.detailRv.run {
|
||||
(itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
layoutManager = detailLayoutManager
|
||||
adapter = detailListAdapter
|
||||
addOnScrollListener(object : OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
super.onScrollStateChanged(recyclerView, newState)
|
||||
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
viewModel.pageDepth = detailLayoutManager.findLastCompletelyVisibleItemPosition()
|
||||
.coerceAtLeast(viewModel.pageDepth)
|
||||
}
|
||||
if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
|
||||
EventBus.getDefault().post(EBTypeChange(GameDetailWrapperFragment.EB_SCROLLING, 0))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun initCover() {
|
||||
binding.run {
|
||||
coverRv.layoutManager = coverLayoutManager
|
||||
coverRv.adapter = coverAdapter
|
||||
(coverRv.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
coverRv.isNestedScrollingEnabled = false
|
||||
coverRv.onFlingListener = null
|
||||
snapHelper.attachToRecyclerView(coverRv)
|
||||
coverRv.addOnScrollListener(coverScrollEventListener.apply {
|
||||
registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
|
||||
super.onPageScrolled(position, positionOffset, positionOffsetPixels)
|
||||
val firstCompletelyVisibleItemPosition =
|
||||
coverLayoutManager.findFirstCompletelyVisibleItemPosition()
|
||||
if (!isCoverHeightAnimating &&
|
||||
firstCompletelyVisibleItemPosition > -1 &&
|
||||
firstCompletelyVisibleItemPosition != lastCompletelyVisibleCoverPosition) {
|
||||
val firstCompletelyVisibleItemView =
|
||||
coverLayoutManager.findViewByPosition(firstCompletelyVisibleItemPosition)
|
||||
firstCompletelyVisibleItemView?.post {
|
||||
if (firstCompletelyVisibleItemView.height > 0 && coverRv.height != firstCompletelyVisibleItemView.height) {
|
||||
startCoverHeightAnimation(coverRv.height, firstCompletelyVisibleItemView.height)
|
||||
}
|
||||
}
|
||||
}
|
||||
lastCompletelyVisibleCoverPosition = firstCompletelyVisibleItemPosition
|
||||
}
|
||||
|
||||
override fun onPageSelected(position: Int) {
|
||||
super.onPageSelected(position)
|
||||
if (position != coverPosition) {
|
||||
val selectedCoverEntity = viewModel.coverListLiveData.value?.getOrNull(position)
|
||||
coverPosition = position
|
||||
|
||||
if (coverSfv.isVisible) {
|
||||
val sfvPosition = coverSfv.getItemList().indexOfFirst { it == selectedCoverEntity?.tabName }
|
||||
coverSfv.setChecked(sfvPosition, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
super.onPageScrollStateChanged(state)
|
||||
notifyScrollStateChanged(state)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun initBasicInfo(basicInfo: GameEntity) {
|
||||
binding.run {
|
||||
gameIconIv.displayGameIcon(basicInfo)
|
||||
|
||||
val gameSubtitleStyle = basicInfo.subtitleStyle
|
||||
val advanceDownload = basicInfo.advanceDownload
|
||||
val subtitleLayout = FrameLayout(requireContext())
|
||||
val subtitleTextView = TextView(requireContext()).apply {
|
||||
layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, 14F.dip2px())
|
||||
text = if (advanceDownload) "预下载" else basicInfo.subtitle
|
||||
textSize = 10F
|
||||
setPadding(2F.dip2px(), 0, 2F.dip2px(), 0)
|
||||
if (gameSubtitleStyle != null && !advanceDownload) {
|
||||
setTextColor("#${gameSubtitleStyle.color}".hexStringToIntColor())
|
||||
background = GradientDrawable().apply {
|
||||
cornerRadius = 2F.dip2px().toFloat()
|
||||
if (gameSubtitleStyle.style == "border") {
|
||||
setColor(Color.TRANSPARENT)
|
||||
setStroke(0.5F.dip2px(), "#${gameSubtitleStyle.background}".hexStringToIntColor())
|
||||
} else {
|
||||
shape = GradientDrawable.RECTANGLE
|
||||
setColor("#${gameSubtitleStyle.background}".hexStringToIntColor())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()))
|
||||
background = com.gh.gamecenter.feature.R.drawable.bg_advance_download_game_subtitle.toDrawable(requireContext())
|
||||
}
|
||||
}
|
||||
subtitleLayout.addView(
|
||||
subtitleTextView,
|
||||
FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, 14F.dip2px()).apply {
|
||||
leftMargin = 4F.dip2px()
|
||||
})
|
||||
val subtitleBitmap = subtitleLayout.convertViewToBitmap()
|
||||
basicInfo.name?.let { name ->
|
||||
gameNameTv.text = SpannableStringBuilder("$name ").apply {
|
||||
subtitleBitmap?.let {
|
||||
setSpan(
|
||||
CenterImageSpan(
|
||||
context,
|
||||
it
|
||||
), name.length, name.length + 1, Spanned.SPAN_EXCLUSIVE_INCLUSIVE
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
gameNameTv.marqueeOnce()
|
||||
officialEntryTv.isVisible = basicInfo.officialEntry
|
||||
descTv.text = basicInfo.sellingPointsText
|
||||
|
||||
mBaseHandler.postDelayed({
|
||||
gameEntity?.gameType = basicInfo.gameTags.joinToString("-") { it.name }
|
||||
tagContainer.setTags(basicInfo.gameTags.take(3))
|
||||
}, 5)
|
||||
tagContainer.onClickListener = object :FlexLinearLayout.OnItemClickListener {
|
||||
override fun onMoreClickListener() {}
|
||||
override fun onItemClickListener(tag: TagStyleEntity, position: Int) {
|
||||
NewLogUtils.logGameDetailTagClick(
|
||||
gameEntity?.id ?: "",
|
||||
gameEntity?.name ?: "",
|
||||
tag.id,
|
||||
tag.name,
|
||||
tag.isTop
|
||||
)
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameEntity?.id,
|
||||
gameEntity?.name,
|
||||
gameEntity?.categoryChinese,
|
||||
"组件内容",
|
||||
"卖点标签",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
requireContext().startActivity(
|
||||
TagsActivity.getIntent(requireContext(), tag.name, tag.name, mEntrance, "游戏介绍")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
scoreContainer.goneIf(basicInfo.welfareText?.status == "on") {
|
||||
scoreTv.setTypeface(Typeface.createFromAsset(requireContext().assets, Constants.DIN_FONT_PATH))
|
||||
scoreTv.text = String.format(Locale.getDefault(), "%.1f", basicInfo.star)
|
||||
scoreContainer.setOnClickListener {
|
||||
viewModel.performTabSelected(GameDetailTabEntity.TYPE_COMMENT)
|
||||
}
|
||||
}
|
||||
discountContainer.goneIf(basicInfo.welfareText == null || basicInfo.welfareText?.status == "off") {
|
||||
discountTv.setTypeface(Typeface.createFromAsset(requireContext().assets, Constants.DIN_FONT_PATH))
|
||||
discountTextTv.text = basicInfo.welfareText?.text
|
||||
discountTv.text = basicInfo.welfareText?.discount
|
||||
}
|
||||
bigEventContainer.goneIf(basicInfo.event.isNullOrEmpty()) {
|
||||
basicInfo.event?.let {
|
||||
bigEventTransitionDrawable = R.drawable.transition_bg_game_detail_big_event.toDrawable(requireContext()) as TransitionDrawable
|
||||
bigEventContainer.background = bigEventTransitionDrawable
|
||||
val index = if (binding.bigEventBannerView.currentIndex != -1) binding.bigEventBannerView.currentIndex else 0
|
||||
val isHighLight = it.getOrNull(index)?.highLight ?: false
|
||||
if (isHighLight) bigEventTransitionDrawable?.reverseTransition(0)
|
||||
|
||||
bigEventBannerView.setOnClickListener { _ ->
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameEntity?.id,
|
||||
gameEntity?.name,
|
||||
gameEntity?.categoryChinese,
|
||||
"组件内容",
|
||||
"大事件",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
viewModel.getBigEvent()
|
||||
}
|
||||
bigEventBannerView.setDataList(it.map { event ->
|
||||
var eventStr = if (event.highLight) {
|
||||
"${TimeUtils.getFormatTime(event.time, "MM-dd")}${TimeUtils.getDayString(event.time)}:${event.content}"
|
||||
} else {
|
||||
if (TimeUtils.getBeforeDays(event.time) <= 15) "${
|
||||
TimeUtils.getFormatTime(event.time, "MM-dd")
|
||||
}${TimeUtils.getDayString(event.time)}:${event.content}" else event.content
|
||||
}
|
||||
if (eventStr.contains("\n")) eventStr = eventStr.substring(0, eventStr.indexOf("\n"))
|
||||
TextBannerView.BannerTextData(text = eventStr, highLight = event.highLight)
|
||||
})
|
||||
bigEventBannerView.onTextUpdateListener = { lastIndex, nextIndex ->
|
||||
if (lastIndex in it.indices && nextIndex in it.indices) {
|
||||
val lastEvent = it[lastIndex]
|
||||
val nextEvent = it[nextIndex]
|
||||
if (lastEvent.highLight != nextEvent.highLight) {
|
||||
bigEventTransitionDrawable?.reverseTransition(
|
||||
BIG_EVENT_TRANSITION_DURATION
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
bigEventBannerView.startBannerLoop()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initDataInfo(dataList: List<GameDetailDataInfo>) {
|
||||
binding.dataContainer.removeAllViews()
|
||||
dataList.forEachIndexed { index, dataInfo ->
|
||||
binding.dataContainer.addView(getDataInfoItemView(dataInfo), 68F.dip2px(), 46F.dip2px())
|
||||
if (index != dataList.size - 1) {
|
||||
binding.dataContainer.addView(View(requireContext()).apply {
|
||||
setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(requireContext()))
|
||||
}, 1F.dip2px(), 24F.dip2px())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initInfoTags(gameDetailInfoTag: GameDetailInfoTag) {
|
||||
val isSpeedStatusOn = gameDetailInfoTag.requestSpeedStatus == "on"
|
||||
val showInfoTags = gameDetailInfoTag.infoTags.isNotEmpty()
|
||||
binding.infoTagContainer.goneIf(!isSpeedStatusOn && !showInfoTags) {
|
||||
binding.accelerateTv.goneIf(!isSpeedStatusOn) {
|
||||
if (gameDetailInfoTag.infoTags.isEmpty()) {
|
||||
binding.infoTagContainer.updateLayoutParams<LinearLayout.LayoutParams> { width = LinearLayout.LayoutParams.WRAP_CONTENT }
|
||||
binding.accelerateTipsTv.visibility = View.VISIBLE
|
||||
}
|
||||
binding.accelerateTv.setOnClickListener {
|
||||
it.context.ifLogin("游戏详情-求加速") {
|
||||
NewFlatLogUtils.logGameDetailClickForAccelerate(gameEntity?.id ?: "", gameEntity?.name ?: "")
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameEntity?.id,
|
||||
gameEntity?.name,
|
||||
gameEntity?.categoryChinese,
|
||||
"组件内容",
|
||||
"功能标签",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
DialogHelper.showDialog(
|
||||
requireContext(), "版本求加速", "如果游戏需要加速版本,您可以提交申请,让小助手尽快研究给您喔!",
|
||||
"提交申请", "取消", {
|
||||
viewModel.postRequestSpeed()
|
||||
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
}
|
||||
}
|
||||
if (SPUtils.getBoolean(Constants.SP_SHOW_GAME_DETAIL_FUNCTION_TAG_GUIDE, true)) {
|
||||
binding.coverRv.post {
|
||||
showFunctionTagGuide()
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.functionTagContainer.goneIf(!showInfoTags) {
|
||||
val iterator = binding.functionTagContainer.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val childView = iterator.next()
|
||||
if (childView.id != R.id.moreContainer) {
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
val showTags = gameDetailInfoTag.infoTags.take(3)
|
||||
showTags.forEachIndexed { index, infoTag ->
|
||||
binding.functionTagContainer.addView(
|
||||
getFunctionTagView(infoTag),
|
||||
index,
|
||||
LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
).apply {
|
||||
if (index != 0) {
|
||||
setMargins(8F.dip2px(), 0, 0, 0)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
binding.moreContainer.goneIf(gameDetailInfoTag.infoTags.size < 3) {
|
||||
binding.moreTv.text = "+${gameDetailInfoTag.infoTags.size - 3}"
|
||||
}
|
||||
binding.functionTagContainer.setOnClickListener {
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameEntity?.id,
|
||||
gameEntity?.name,
|
||||
gameEntity?.categoryChinese,
|
||||
"组件内容",
|
||||
"功能标签",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
GameFunctionDialogFragment.show(
|
||||
requireContext(),
|
||||
gameEntity?.id ?: "",
|
||||
gameEntity?.name ?: "",
|
||||
gameDetailInfoTag.infoTags
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showFunctionTagGuide() {
|
||||
val decorView = activity?.window?.decorView as? FrameLayout
|
||||
LayoutGuideGameDetailFunctionTagBinding.inflate(layoutInflater, decorView, true).run {
|
||||
functionTagGuide = root
|
||||
val screenWidth = DisplayUtils.getScreenWidth(requireActivity())
|
||||
val infoTagLocation = IntArray(2)
|
||||
binding.infoTagContainer.getLocationInWindow(infoTagLocation)
|
||||
val top = (infoTagLocation[1] - 12F.dip2px()).toFloat()
|
||||
root.targetRect.set(8F.dip2px().toFloat(), top, (screenWidth - 8F.dip2px()).toFloat(), top + 53F.dip2px())
|
||||
guideIv.translationY = top - 56F.dip2px()
|
||||
root.setOnClickListener {
|
||||
hideFunctionTagGuide()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun hideFunctionTagGuide() {
|
||||
val decorView = activity?.window?.decorView as? FrameLayout
|
||||
functionTagGuide?.animate()?.alpha(0F)?.setDuration(300L)?.apply {
|
||||
doOnEnd {
|
||||
decorView?.removeView(functionTagGuide)
|
||||
functionTagGuide = null
|
||||
}
|
||||
}?.start()
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_GAME_DETAIL_FUNCTION_TAG_GUIDE, false)
|
||||
}
|
||||
|
||||
private fun getFunctionTagView(infoTag: GameDetailInfoTag.InfoTag) =
|
||||
ItemGameDetailFunctionTagBinding.inflate(layoutInflater).apply {
|
||||
ImageUtils.display(iconIv, infoTag.icon)
|
||||
nameTv.text = infoTag.name
|
||||
}.root
|
||||
|
||||
private fun getDataInfoItemView(dataInfo: GameDetailDataInfo) = ItemGameDetailDataInfoBinding.inflate(layoutInflater).apply {
|
||||
nameTv.text = dataInfo.nameCn
|
||||
when (dataInfo.name) {
|
||||
"ranking" -> {
|
||||
if (dataInfo.ranking != null) {
|
||||
nameTv.text = dataInfo.ranking.columnName
|
||||
infoTv.text = "#${dataInfo.ranking.no}"
|
||||
infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
infoTv.setTypeface(Typeface.createFromAsset(requireContext().assets, Constants.DIN_FONT_PATH))
|
||||
infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext()))
|
||||
root.setOnClickListener {
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameEntity?.id,
|
||||
gameEntity?.name,
|
||||
gameEntity?.categoryChinese,
|
||||
"组件内容",
|
||||
"数据信息栏",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
DirectUtils.directToColumnCollection(
|
||||
requireContext(),
|
||||
dataInfo.ranking.collectionId,
|
||||
entrance = mEntrance,
|
||||
columnName = dataInfo.ranking.columnName,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
"real_name" -> {
|
||||
if (dataInfo.realName != null) {
|
||||
infoTv.text = if (dataInfo.realName.state == "yes") "有" else "无"
|
||||
if (dataInfo.realName.certificationScreenshot.isNotEmpty()) {
|
||||
infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(requireContext()))
|
||||
root.setOnClickListener {
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameEntity?.id,
|
||||
gameEntity?.name,
|
||||
gameEntity?.categoryChinese,
|
||||
"组件内容",
|
||||
"数据信息栏",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
startActivity(
|
||||
ImageViewerActivity.getSingleIntent(
|
||||
requireContext(),
|
||||
dataInfo.realName.certificationScreenshot,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
infoTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(requireContext()))
|
||||
infoTv.text = dataInfo.value
|
||||
}
|
||||
}
|
||||
}.root
|
||||
|
||||
private fun notifyScrollStateChanged(state: Int) {
|
||||
val firstVisibleItem = coverLayoutManager.findFirstVisibleItemPosition()
|
||||
val lastVisibleItem = coverLayoutManager.findLastVisibleItemPosition()
|
||||
scrollCalculatorHelper.onScrollStateChanged(firstVisibleItem, lastVisibleItem, state)
|
||||
}
|
||||
|
||||
private fun RecyclerView.setCurrentItem(position: Int) {
|
||||
if (position == coverPosition) return
|
||||
|
||||
coverScrollEventListener.notifyProgrammaticScroll(position, true)
|
||||
if (abs(position - coverPosition) > 3) {
|
||||
scrollToPosition(if (position > coverPosition) position - 3 else position + 3)
|
||||
post {
|
||||
smoothScrollToPosition(position)
|
||||
}
|
||||
} else {
|
||||
smoothScrollToPosition(position)
|
||||
}
|
||||
coverPosition = position
|
||||
}
|
||||
|
||||
override fun onFragmentPause() {
|
||||
super.onFragmentPause()
|
||||
pauseVideo()
|
||||
binding.bigEventBannerView.stopBannerLoop()
|
||||
}
|
||||
|
||||
override fun onFragmentResume() {
|
||||
super.onFragmentResume()
|
||||
resumeVideo()
|
||||
|
||||
if (!viewModel.basicInfoLiveData.value?.event.isNullOrEmpty()) {
|
||||
binding.bigEventBannerView.startBannerLoop()
|
||||
}
|
||||
}
|
||||
|
||||
private fun pauseVideo() {
|
||||
val currentPlayer = scrollCalculatorHelper.currentPlayer
|
||||
if (currentPlayer != null) {
|
||||
currentPlayer.onVideoPause()
|
||||
val currentPosition = currentPlayer.getCurrentPosition()
|
||||
|
||||
val videoUrl = currentPlayer.getUrl()
|
||||
if (videoUrl.isNotEmpty()) {
|
||||
ScrollCalculatorHelper.savePlaySchedule(MD5Utils.getContentMD5(videoUrl), currentPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resumeVideo() {
|
||||
val currentPlayer = scrollCalculatorHelper.currentPlayer
|
||||
if (currentPlayer != null) {
|
||||
val videoUrl = currentPlayer.getUrl()
|
||||
if (videoUrl.isNotEmpty()) {
|
||||
val position = ScrollCalculatorHelper.getPlaySchedule(MD5Utils.getContentMD5(videoUrl))
|
||||
//这里必须要延迟操作,否则会白屏
|
||||
mBaseHandler.postDelayed({
|
||||
if (position != 0L) {
|
||||
scrollCalculatorHelper.currentPlayer?.seekTo(position)
|
||||
scrollCalculatorHelper.currentPlayer?.onVideoResume(false)
|
||||
} else {
|
||||
scrollCalculatorHelper.currentPlayer?.release()
|
||||
}
|
||||
}, 50)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showFloatingWindowIfNeeded() {
|
||||
val floatingWindowProvider = TheRouter.get(IFloatingWindowProvider::class.java)
|
||||
|
||||
floatingWindowProvider?.getAndShowFloatingWindow(
|
||||
gameEntity?.id ?: "",
|
||||
gameEntity?.name ?: "",
|
||||
"游戏详情",
|
||||
this,
|
||||
binding.detailRv
|
||||
)?.let {
|
||||
compositeDisposable.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
compositeDisposable.dispose()
|
||||
if (::scrollCalculatorHelper.isInitialized) {
|
||||
scrollCalculatorHelper.release()
|
||||
}
|
||||
}
|
||||
|
||||
private fun startCoverHeightAnimation(startHeight: Int, targetHeight: Int) {
|
||||
if (isCoverHeightAnimating) return
|
||||
|
||||
ValueAnimator.ofInt(startHeight, targetHeight).apply {
|
||||
duration = COVER_HEIGHT_ANIMATION_DURATION
|
||||
doOnStart {
|
||||
isCoverHeightAnimating = true
|
||||
}
|
||||
doOnEnd {
|
||||
isCoverHeightAnimating = false
|
||||
}
|
||||
addUpdateListener { va ->
|
||||
binding.coverRv.updateLayoutParams<ViewGroup.LayoutParams> {
|
||||
height = va.animatedValue as Int
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
override fun scrollToTop() {
|
||||
binding.gamedetailAppbar.setExpanded(true)
|
||||
binding.detailRv.scrollToPosition(0)
|
||||
}
|
||||
|
||||
// 登录事件
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEventMainThread(reuse: EBReuse) {
|
||||
if (reuse.type == Constants.LOGIN_TAG) {
|
||||
viewModel.detailDataListLiveData.value?.let { viewModel.getUserRelatedInfo(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
val commentPosition = detailListAdapter.currentList.indexOfFirst { it.linkComment != null }
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (GameDetailCommentItemViewHolder.RATING_REPLY_REQUEST == requestCode || GameDetailCommentItemViewHolder.RATING_PATCH_REQUEST == requestCode) {
|
||||
SyncDataBetweenPageHelper.resultHandle(data, object : OnSyncCallBack<RatingComment> {
|
||||
override fun onData(dataPosition: Int): RatingComment? {
|
||||
return if (commentPosition != -1) {
|
||||
val commentList = detailListAdapter.currentList[commentPosition].linkComment?.data ?: return null
|
||||
commentList.getOrNull(dataPosition)?.apply {
|
||||
if (GameDetailCommentItemViewHolder.RATING_PATCH_REQUEST == requestCode) {
|
||||
ignore = gameEntity?.ignoreComment ?: false
|
||||
}
|
||||
}
|
||||
} else null
|
||||
}
|
||||
|
||||
override fun onNotify(dataPosition: Int) {
|
||||
if (commentPosition != -1) {
|
||||
detailListAdapter.notifyItemChanged(commentPosition)
|
||||
}
|
||||
}
|
||||
})
|
||||
} else if (requestCode == GameLibaoAdapter.LIBAO_REQUEST) {
|
||||
val position = detailListAdapter.currentList.indexOfFirst { it.linkLibao != null }
|
||||
if (position != -1) {
|
||||
detailListAdapter.notifyItemChanged(position)
|
||||
}
|
||||
}
|
||||
} else if (requestCode == GameDetailCommentItemViewHolder.RATING_REPLY_REQUEST && resultCode == RatingFragment.RATING_DELETE_RESULT) {
|
||||
data?.getParcelableExtra<RatingComment>(RatingComment::class.java.simpleName)?.run {
|
||||
if (commentPosition != -1) {
|
||||
val commentList = detailListAdapter.currentList[commentPosition].linkComment?.data ?: return
|
||||
val deleteCommentPosition = commentList.indexOfFirst { it.id == id }
|
||||
if (deleteCommentPosition != -1) {
|
||||
commentList.removeAt(deleteCommentPosition)
|
||||
}
|
||||
detailListAdapter.notifyItemChanged(commentPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed(): Boolean {
|
||||
if (functionTagGuide != null) {
|
||||
hideFunctionTagGuide()
|
||||
return true
|
||||
}
|
||||
return super.onBackPressed()
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
viewModel.basicInfoLiveData.value?.let { initBasicInfo(it) }
|
||||
|
||||
val dataInfoList = viewModel.dataInfoLiveData.value
|
||||
if (!dataInfoList.isNullOrEmpty()) {
|
||||
initDataInfo(dataInfoList)
|
||||
}
|
||||
|
||||
viewModel.infoTagLiveData.value?.let { initInfoTags(it) }
|
||||
|
||||
detailListAdapter.run { notifyItemRangeChanged(0, itemCount) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val COVER_HEIGHT_ANIMATION_DURATION = 400L
|
||||
private const val COVER_VIDEO_INITIAL_DELAY = 500L
|
||||
private const val BIG_EVENT_TRANSITION_DURATION = 1000
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,127 @@
|
||||
package com.gh.gamecenter.gamedetail.detail
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.recyclerview.widget.DiffUtil.ItemCallback
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.detail.viewholder.*
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
|
||||
class GameDetailListAdapter(
|
||||
private val downloadBtn: DownloadButton,
|
||||
private val viewModel: GameDetailViewModel,
|
||||
private val lifecycleOwner: LifecycleOwner
|
||||
) :
|
||||
ListAdapter<GameDetailData, BaseGameDetailItemViewHolder>(createDiffCallback()) {
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
val data = currentList[position]
|
||||
return when {
|
||||
data?.linkContentCard != null -> {
|
||||
when (data.linkContentCard.size) {
|
||||
1 -> ITEM_CONTENT_CARD_SINGLE
|
||||
2 -> ITEM_CONTENT_CARD_DOUBLE
|
||||
else -> ITEM_CONTENT_CARD_TRIPLE
|
||||
}
|
||||
}
|
||||
|
||||
data?.linkAdvertising != null -> if (data.linkAdvertising.img.isEmpty()) ITEM_ADVERTISING else ITEM_ADVERTISING_IMAGE
|
||||
data?.linkComprehensive != null -> ITEM_COMPREHENSIVE_PANEL
|
||||
data?.linkCustomColumn != null -> ITEM_CUSTOM_COLUMN
|
||||
data?.linkDrawer != null -> ITEM_DRAWER
|
||||
data?.linkAnnouncement != null -> ITEM_ANNOUNCEMENT
|
||||
data?.linkGameBrief != null -> ITEM_GAME_BRIEF
|
||||
data?.linkDeveloperWord != null -> ITEM_DEVELOPER_WORD
|
||||
data?.linkUpdate != null -> ITEM_UPDATE
|
||||
data?.linkComment != null -> ITEM_COMMENT
|
||||
data?.linkInfo != null -> ITEM_DETAIL_INFO
|
||||
data?.linkContentRecommend != null -> ITEM_CONTENT_RECOMMEND
|
||||
data?.linkGameVideo != null -> ITEM_GAME_VIDEO
|
||||
data?.linkGameGuide != null -> ITEM_GAME_STRATEGY
|
||||
data?.linkServer != null -> ITEM_SERVER
|
||||
data?.linkLibao != null -> ITEM_GIFT
|
||||
data?.linkRelatedGame != null -> ITEM_RELATED_GAME
|
||||
data?.linkImageRecommend != null -> ITEM_RECOMMEND_IMAGE
|
||||
data?.linkEveryonePlaying != null -> ITEM_RECOMMEND_GAME
|
||||
data?.linkRecommendGameList != null -> ITEM_RECOMMEND_GAME_COLLECTION
|
||||
else -> ITEM_RECOMMEND_COLUMN
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseGameDetailItemViewHolder {
|
||||
return when (viewType) {
|
||||
ITEM_CONTENT_CARD_SINGLE -> GameDetailContentCardSingleItemViewHolder(parent.toBinding(), downloadBtn, viewModel, lifecycleOwner)
|
||||
ITEM_CONTENT_CARD_DOUBLE -> GameDetailContentCardDoubleItemViewHolder(parent.toBinding(), downloadBtn, viewModel, lifecycleOwner)
|
||||
ITEM_CONTENT_CARD_TRIPLE -> GameDetailContentCardTripleItemViewHolder(parent.toBinding(), downloadBtn, viewModel, lifecycleOwner)
|
||||
ITEM_ADVERTISING -> GameDetailAdvertisingItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_ADVERTISING_IMAGE -> GameDetailAdvertisingImageItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_COMPREHENSIVE_PANEL -> GameDetailComprehensivePanelItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_CUSTOM_COLUMN -> GameDetailCustomColumnItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_DRAWER -> GameDetailDrawerItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_ANNOUNCEMENT -> GameDetailAnnouncementItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_GAME_BRIEF -> GameDetailBriefItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_DEVELOPER_WORD -> com.gh.gamecenter.gamedetail.detail.viewholder.GameDetailDeveloperWordItemViewHolder(
|
||||
parent.toBinding(),
|
||||
downloadBtn,
|
||||
viewModel
|
||||
)
|
||||
ITEM_UPDATE -> GameDetailUpdateItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_COMMENT -> GameDetailCommentItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_DETAIL_INFO -> GameDetailInfoItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_CONTENT_RECOMMEND -> GameDetailContentRecommendItemViewHolder(parent.toBinding(), downloadBtn, viewModel, lifecycleOwner)
|
||||
ITEM_GAME_VIDEO -> GameDetailVideoItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_GAME_STRATEGY -> GameDetailStrategyItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_SERVER -> GameDetailServerItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_GIFT -> GameDetailGiftItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_RELATED_GAME -> GameDetailRelatedGameItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_RECOMMEND_IMAGE -> GameDetailRecommendImageItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_RECOMMEND_GAME -> GameDetailRecommendGameItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
ITEM_RECOMMEND_GAME_COLLECTION -> GameDetailRecommendGameCollectionItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
else -> GameDetailRecommendColumnItemViewHolder(parent.toBinding(), downloadBtn, viewModel)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: BaseGameDetailItemViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
holder.bindView(item)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ITEM_CONTENT_CARD_SINGLE = 0 // 内容卡片-单个
|
||||
const val ITEM_CONTENT_CARD_DOUBLE = 1 // 内容卡片-两个
|
||||
const val ITEM_CONTENT_CARD_TRIPLE = 2 // 内容卡片-三个
|
||||
const val ITEM_ADVERTISING = 3 // 广告推荐-无图片
|
||||
const val ITEM_ADVERTISING_IMAGE = 4 // 广告推荐-带图片
|
||||
const val ITEM_COMPREHENSIVE_PANEL = 5 // 综合面板
|
||||
const val ITEM_CUSTOM_COLUMN = 6 // 自定义栏目
|
||||
const val ITEM_DRAWER = 7 // 列表抽屉
|
||||
const val ITEM_ANNOUNCEMENT = 8 // 资讯公告
|
||||
const val ITEM_GAME_BRIEF = 9 // 游戏简介
|
||||
const val ITEM_DEVELOPER_WORD = 10 // 开发者的话
|
||||
const val ITEM_UPDATE = 11 // 更新内容
|
||||
const val ITEM_COMMENT = 12 // 玩家评论
|
||||
const val ITEM_DETAIL_INFO = 13 // 详情信息
|
||||
const val ITEM_CONTENT_RECOMMEND = 14 // 内容推荐(PK组件)
|
||||
const val ITEM_GAME_VIDEO = 15 // 视频
|
||||
const val ITEM_GAME_STRATEGY = 16 // 游戏攻略
|
||||
const val ITEM_SERVER = 17 // 游戏开服
|
||||
const val ITEM_GIFT = 18 // 游戏礼包
|
||||
const val ITEM_RELATED_GAME = 19 // 相关游戏
|
||||
const val ITEM_RECOMMEND_IMAGE = 20 // 图片推荐
|
||||
const val ITEM_RECOMMEND_GAME = 21 // 大家都在玩
|
||||
const val ITEM_RECOMMEND_GAME_COLLECTION = 22 // 游戏单推荐
|
||||
const val ITEM_RECOMMEND_COLUMN = 23 // 专题推荐
|
||||
|
||||
fun createDiffCallback() = object : ItemCallback<GameDetailData>() {
|
||||
override fun areItemsTheSame(oldItem: GameDetailData, newItem: GameDetailData): Boolean {
|
||||
return oldItem.areItemsTheSame(newItem)
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: GameDetailData, newItem: GameDetailData): Boolean {
|
||||
return oldItem.areContentsTheSame(newItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,39 +1,37 @@
|
||||
package com.gh.gamecenter.gamedetail.desc
|
||||
package com.gh.gamecenter.gamedetail.detail
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.databind.BindingAdapters
|
||||
import com.gh.gamecenter.GameDetailActivity
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.MtaHelper
|
||||
import com.gh.gamecenter.core.utils.StringUtils
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailRelatedVersionBinding
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.feature.game.GameItemViewHolder
|
||||
import com.gh.gamecenter.gamedetail.entity.RelatedVersion
|
||||
import com.gh.gamecenter.gamedetail.detail.viewholder.BaseGameDetailItemViewHolder
|
||||
|
||||
class GameRelatedVersionAdapter(
|
||||
private val mContext: Context,
|
||||
private val mGameId: String,
|
||||
private val mGameName: String,
|
||||
private val mGame: GameEntity?,
|
||||
private val mDatas: ArrayList<RelatedVersion>,
|
||||
private val mEntrance: String
|
||||
class GameDetailRelatedGameAdapter(
|
||||
private val context: Context,
|
||||
private val game: GameEntity?,
|
||||
private val relatedGameList: ArrayList<GameEntity>,
|
||||
private val entrance: String,
|
||||
private val trackData: BaseGameDetailItemViewHolder.GameDetailModuleTrackData,
|
||||
private val getGameStatus: () -> String
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
var exposureEventList: ArrayList<ExposureEvent> = arrayListOf()
|
||||
private val mMaxWidth = mContext.resources.displayMetrics.widthPixels - 32F.dip2px()
|
||||
private val maxWidth = context.resources.displayMetrics.widthPixels - 32F.dip2px()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return GameDetailRelatedViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = mDatas.size
|
||||
override fun getItemCount(): Int = relatedGameList.size
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val relatedVersion = mDatas[position]
|
||||
val gameEntity = relatedGameList.getOrNull(position) ?: return
|
||||
if (holder is GameDetailRelatedViewHolder) {
|
||||
val paddingStart = 16F.dip2px()
|
||||
val isEndOfRow = position >= if (itemCount % 3 == 0) {
|
||||
@ -46,48 +44,42 @@ class GameRelatedVersionAdapter(
|
||||
var paddingEnd = if (isEndOfRow) 16F.dip2px() else 0F.dip2px()
|
||||
holder.itemView.layoutParams = if (!isEndOfRow) {
|
||||
paddingEnd += 1
|
||||
ViewGroup.LayoutParams(mMaxWidth - 24F.dip2px(), ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
ViewGroup.LayoutParams(maxWidth - 24F.dip2px(), ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
} else {
|
||||
ViewGroup.LayoutParams(mMaxWidth - 1, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
ViewGroup.LayoutParams(maxWidth - 1, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
}
|
||||
holder.binding.root.setPadding(paddingStart, 8F.dip2px(), paddingEnd, 8F.dip2px())
|
||||
val gameEntity = relatedVersion.game ?: return
|
||||
holder.binding.gameNameTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(mContext))
|
||||
holder.binding.gameNameTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
holder.binding.gameNameTv.text = gameEntity.name
|
||||
BindingAdapters.setGameTags(holder.binding.gameLabelLl, gameEntity)
|
||||
holder.binding.gameIconView.displayGameIcon(gameEntity)
|
||||
holder.binding.gameIconView.setBorderColor(com.gh.gamecenter.common.R.color.resource_border)
|
||||
holder.itemView.setOnClickListener {
|
||||
MtaHelper.onEvent("游戏详情_新", "相关游戏版本", "${mGameName}+${relatedVersion.gameName}")
|
||||
GameDetailActivity.startGameDetailActivity(
|
||||
mContext,
|
||||
relatedVersion.gameId,
|
||||
context,
|
||||
gameEntity.id,
|
||||
StringUtils.buildString(
|
||||
mEntrance,
|
||||
entrance,
|
||||
"+(",
|
||||
"游戏详情",
|
||||
"[",
|
||||
relatedVersion.gameName,
|
||||
gameEntity.name,
|
||||
"]:相关游戏[",
|
||||
(position + 1).toString(),
|
||||
"])"
|
||||
),
|
||||
exposureEventList.safelyGetInRelease(position)
|
||||
)
|
||||
SensorsBridge.trackGameDetailPageRelatedGameClick(
|
||||
gameId = mGameId,
|
||||
gameName = mGameName,
|
||||
pageName = GlobalActivityManager.getCurrentPageEntity().pageName,
|
||||
pageId = GlobalActivityManager.getCurrentPageEntity().pageId,
|
||||
pageBusinessId = GlobalActivityManager.getCurrentPageEntity().pageBusinessId,
|
||||
lastPageName = GlobalActivityManager.getLastPageEntity().pageName,
|
||||
lastPageId = GlobalActivityManager.getLastPageEntity().pageId,
|
||||
lastPageBusinessId = GlobalActivityManager.getLastPageEntity().pageBusinessId,
|
||||
downloadStatus = mGame?.downloadStatusChinese ?: "",
|
||||
gameType = mGame?.categoryChinese ?: "",
|
||||
clickGameId = gameEntity.id,
|
||||
clickGameName = gameEntity.name ?: "",
|
||||
clickGameType = gameEntity.categoryChinese
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
trackData.gameId,
|
||||
trackData.gameName,
|
||||
trackData.gameType,
|
||||
"组件内容",
|
||||
trackData.moduleType,
|
||||
"相关游戏",
|
||||
trackData.sequence,
|
||||
supSequence = position + 1,
|
||||
gameStatus = getGameStatus()
|
||||
)
|
||||
}
|
||||
GameItemViewHolder.initGameSubtitleAndAdLabel(gameEntity, holder.binding.gameSubtitleTv)
|
||||
@ -1,4 +1,4 @@
|
||||
package com.gh.gamecenter.gamedetail.desc
|
||||
package com.gh.gamecenter.gamedetail.detail
|
||||
|
||||
import android.content.Context
|
||||
import android.view.Gravity
|
||||
@ -8,9 +8,9 @@ import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.core.utils.TimeUtils
|
||||
import com.gh.gamecenter.common.utils.safelyGetInRelease
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.core.utils.TimeUtils
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailLatestServiceBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailMoreBinding
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
@ -0,0 +1,276 @@
|
||||
package com.gh.gamecenter.gamedetail.detail
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.facebook.drawee.drawable.ScalingUtils
|
||||
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.gh.common.util.LibaoUtils
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.common.databinding.RefreshFooterviewBinding
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.MtaHelper
|
||||
import com.gh.gamecenter.core.utils.SpanBuilder
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailMoreBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameLibaoBinding
|
||||
import com.gh.gamecenter.feature.entity.LibaoEntity
|
||||
import com.gh.gamecenter.libao.LibaoDetailActivity
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
|
||||
class GameLibaoAdapter(
|
||||
val context: Context,
|
||||
var libaos: ArrayList<LibaoEntity>,
|
||||
val gameName: String,
|
||||
val gameId: String,
|
||||
showExpandIcon: Boolean = true
|
||||
) :
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
private var mIsExpand = false
|
||||
private val mShowItemCount: Int = if (showExpandIcon) 3 else Int.MAX_VALUE // 最多展示多少个礼包
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return when(viewType) {
|
||||
LIBAO_ITEM -> LibaoViewHolder(parent.toBinding())
|
||||
FOOTER_ITEM -> FooterViewHolder(parent.toBinding())
|
||||
else -> MoreViewHolder(ItemGameDetailMoreBinding.inflate(LayoutInflater.from(context), parent, false))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return if (libaos.size > mShowItemCount) {
|
||||
if (!mIsExpand) {
|
||||
if (position == mShowItemCount) MORE else LIBAO_ITEM
|
||||
} else {
|
||||
if (position == libaos.size) MORE else LIBAO_ITEM
|
||||
}
|
||||
} else {
|
||||
LIBAO_ITEM
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return if (libaos.size > mShowItemCount) {
|
||||
if (mIsExpand) libaos.size + 1 else mShowItemCount + 1
|
||||
} else {
|
||||
libaos.size
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is LibaoViewHolder -> {
|
||||
val libaoEntity = libaos[position]
|
||||
holder.bindItem(context, this, gameId, gameName, libaoEntity)
|
||||
}
|
||||
is MoreViewHolder -> {
|
||||
holder.binding.arrowIv.rotation = if (mIsExpand) 180f else 0f
|
||||
holder.itemView.setOnClickListener {
|
||||
if (!mIsExpand) MtaHelper.onEvent("游戏详情_新", "游戏礼包_展开", gameName)
|
||||
mIsExpand = !mIsExpand
|
||||
notifyDataSetChanged()
|
||||
NewLogUtils.logGameDetailGiftClick(gameName, gameId, "展开")
|
||||
}
|
||||
}
|
||||
is FooterViewHolder -> {
|
||||
holder.binding.footerviewHint.setTextColor(com.gh.gamecenter.common.R.color.text_instance.toColor(context))
|
||||
holder.binding.footerviewHint.text = "没有更多内容了"
|
||||
holder.binding.footerviewLoading.isVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LibaoViewHolder(var binding: ItemGameLibaoBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||
fun bindItem(context: Context, adapter: RecyclerView.Adapter<*>, gameId: String, gameName: String, libaoEntity: LibaoEntity) {
|
||||
val position = bindingAdapterPosition
|
||||
binding.root.updateLayoutParams<MarginLayoutParams> { topMargin = if (position == 0) 0 else 8F.dip2px() }
|
||||
binding.root.background = com.gh.gamecenter.common.R.drawable.bg_shape_f8_radius_8.toDrawable(context)
|
||||
binding.libaoNameTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
binding.contentTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
binding.remainingTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
binding.libaoCodeTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
|
||||
binding.libaoNameTv.text = libaoEntity.name
|
||||
binding.contentTv.text = libaoEntity.content?.fromHtml()
|
||||
|
||||
binding.horizontalScrollView.goneIf(libaoEntity.materials.isEmpty()) {
|
||||
binding.imagesContainer.removeAllViews()
|
||||
libaoEntity.materials.forEachIndexed { index, image ->
|
||||
binding.imagesContainer.addView(SimpleDraweeView(context).apply {
|
||||
hierarchy = GenericDraweeHierarchyBuilder(resources)
|
||||
.setFadeDuration(500)
|
||||
.setPlaceholderImage(com.gh.gamecenter.common.R.drawable.occupy, ScalingUtils.ScaleType.FIT_XY)
|
||||
.build()
|
||||
ImageUtils.display(this, image)
|
||||
}, LinearLayout.LayoutParams(24F.dip2px(), 24F.dip2px()).apply {
|
||||
setMargins(if (index != 0) 16F.dip2px() else 0, 0, 0, 0)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
val isTypeCopy = libaoEntity.receiveMethod == "copy"
|
||||
if (isTypeCopy) {
|
||||
// 类型为复制,不需要登录也能直接领取
|
||||
binding.libaoSchedulePb.visibility = View.GONE
|
||||
binding.remainingTv.visibility = View.GONE
|
||||
binding.libaoCodeTv.visibility = View.VISIBLE
|
||||
|
||||
val text = "兑换码:${libaoEntity.code}"
|
||||
binding.libaoCodeTv.text = SpanBuilder(text).color(
|
||||
binding.root.context,
|
||||
4,
|
||||
text.length,
|
||||
com.gh.gamecenter.common.R.color.text_theme
|
||||
).build()
|
||||
binding.copyLibaoCodeIv.visibility = View.VISIBLE
|
||||
binding.copyLibaoCodeIv.setOnClickListener {
|
||||
binding.receiveTv.performClick()
|
||||
}
|
||||
} else if (libaoEntity.universal || libaoEntity.status == "check") {
|
||||
//通用码礼包/或者还未添加礼包码时,不显示进度条,显示礼包码
|
||||
binding.libaoSchedulePb.visibility = View.GONE
|
||||
binding.remainingTv.visibility = View.GONE
|
||||
binding.libaoCodeTv.visibility = View.VISIBLE
|
||||
binding.copyLibaoCodeIv.visibility = View.GONE
|
||||
|
||||
if (!UserManager.getInstance().isLoggedIn) {
|
||||
binding.libaoCodeTv.text = "礼包码:-"
|
||||
} else {
|
||||
when (libaoEntity.status) {
|
||||
"linged", "repeatLing", "repeatLinged", "taoed", "repeatTao", "repeatTaoed" -> {
|
||||
val size = libaoEntity.me?.userDataLibaoList?.size ?: 0
|
||||
val code = libaoEntity.me?.userDataLibaoList?.get(size - 1)?.code ?: ""
|
||||
val text = "礼包码:$code"
|
||||
binding.libaoCodeTv.text = SpanBuilder(text).color(
|
||||
binding.root.context,
|
||||
4,
|
||||
text.length,
|
||||
com.gh.gamecenter.common.R.color.text_theme
|
||||
).build()
|
||||
binding.copyLibaoCodeIv.visibility = View.VISIBLE
|
||||
binding.copyLibaoCodeIv.setOnClickListener {
|
||||
code.copyTextAndToast("$code 复制成功")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
binding.libaoCodeTv.text = "礼包码:-"
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!UserManager.getInstance().isLoggedIn) {
|
||||
binding.libaoSchedulePb.visibility = View.VISIBLE
|
||||
binding.remainingTv.visibility = View.VISIBLE
|
||||
binding.libaoCodeTv.visibility = View.GONE
|
||||
binding.copyLibaoCodeIv.visibility = View.GONE
|
||||
|
||||
initProgressUI(libaoEntity)
|
||||
} else {
|
||||
when (libaoEntity.status) {
|
||||
"linged", "repeatLing", "repeatLinged", "taoed", "repeatTao", "repeatTaoed" -> {
|
||||
binding.libaoSchedulePb.visibility = View.GONE
|
||||
binding.remainingTv.visibility = View.GONE
|
||||
binding.libaoCodeTv.visibility = View.VISIBLE
|
||||
|
||||
val size = libaoEntity.me?.userDataLibaoList?.size ?: 0
|
||||
val code = libaoEntity.me?.userDataLibaoList?.get(size - 1)?.code ?: ""
|
||||
val text = "礼包码:$code"
|
||||
binding.libaoCodeTv.text = SpanBuilder(text).color(
|
||||
binding.root.context,
|
||||
4,
|
||||
text.length,
|
||||
com.gh.gamecenter.common.R.color.text_theme
|
||||
).build()
|
||||
binding.copyLibaoCodeIv.visibility = View.VISIBLE
|
||||
binding.copyLibaoCodeIv.setOnClickListener {
|
||||
code.copyTextAndToast("$code 复制成功")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
binding.libaoSchedulePb.visibility = View.VISIBLE
|
||||
binding.remainingTv.visibility = View.VISIBLE
|
||||
binding.libaoCodeTv.visibility = View.GONE
|
||||
binding.copyLibaoCodeIv.visibility = View.GONE
|
||||
|
||||
initProgressUI(libaoEntity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// LibaoUtils.setLiBaoBtnStatusRound(holder.binding.receiveTv, libaoEntity,true, context)
|
||||
LibaoUtils.initLibaoBtn(
|
||||
context,
|
||||
binding.receiveTv,
|
||||
libaoEntity,
|
||||
false,
|
||||
null,
|
||||
true,
|
||||
"游戏详情",
|
||||
"游戏详情"
|
||||
) {
|
||||
adapter.notifyItemChanged(position)
|
||||
}
|
||||
if (!libaoEntity.packageName.isNullOrEmpty()) {
|
||||
binding.receiveTv.setOnClickListener {
|
||||
val intent = LibaoDetailActivity.getIntent(context, libaoEntity, true, "游戏详情")
|
||||
if (it.context is Activity) {
|
||||
(it.context as Activity).startActivityForResult(intent, LIBAO_REQUEST)
|
||||
}
|
||||
}
|
||||
}
|
||||
itemView.setOnClickListener {
|
||||
if (isTypeCopy) {
|
||||
// do nothing
|
||||
} else {
|
||||
val intent = LibaoDetailActivity.getIntent(context, libaoEntity, "游戏详情")
|
||||
if (it.context is Activity) {
|
||||
(it.context as Activity).startActivityForResult(intent, LIBAO_REQUEST)
|
||||
}
|
||||
|
||||
NewLogUtils.logGameDetailGiftClick(gameName, gameId, "礼包详情")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initProgressUI(libaoEntity: LibaoEntity) {
|
||||
val total = libaoEntity.total
|
||||
val available = libaoEntity.available
|
||||
if (total != 0) {
|
||||
val availablePercent = (available) / total.toFloat() * 100
|
||||
val count = when {
|
||||
availablePercent >= 1F -> {
|
||||
availablePercent.toInt()
|
||||
}
|
||||
availablePercent == 0F -> {
|
||||
0
|
||||
}
|
||||
else -> {
|
||||
1
|
||||
}
|
||||
}
|
||||
binding.remainingTv.text = "剩余${count}%"
|
||||
binding.libaoSchedulePb.progress = count
|
||||
}
|
||||
}
|
||||
}
|
||||
class MoreViewHolder(var binding: ItemGameDetailMoreBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
class FooterViewHolder(var binding: RefreshFooterviewBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
companion object {
|
||||
const val MORE = 0
|
||||
const val LIBAO_ITEM = 1
|
||||
const val FOOTER_ITEM = 2
|
||||
|
||||
const val LIBAO_REQUEST = 100
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
|
||||
abstract class BaseGameDetailItemViewHolder(val itemView: View, val downloadBtn: DownloadButton, val viewModel: GameDetailViewModel) : RecyclerView.ViewHolder(itemView) {
|
||||
protected val context: Context = itemView.context
|
||||
protected var itemData: GameDetailData? = null
|
||||
protected val gameId
|
||||
get() = viewModel.game?.id ?: ""
|
||||
protected val gameName
|
||||
get() = viewModel.game?.name ?: ""
|
||||
protected val gameType
|
||||
get() = viewModel.game?.categoryChinese ?: ""
|
||||
protected val moduleType
|
||||
get() = itemData?.typeChinese ?: ""
|
||||
protected val sequence
|
||||
get() = itemData?.position?.plus(1) ?: 0
|
||||
protected val gameStatus
|
||||
get() = getGameStatus(downloadBtn.buttonStyle)
|
||||
|
||||
protected val baseTrackData
|
||||
get() = GameDetailModuleTrackData(
|
||||
gameId = gameId,
|
||||
gameName = gameName,
|
||||
gameType = gameId,
|
||||
gameStatus = gameStatus,
|
||||
moduleType = moduleType,
|
||||
sequence = sequence,
|
||||
)
|
||||
|
||||
@CallSuper
|
||||
open fun bindView(data: GameDetailData) {
|
||||
itemData = data
|
||||
}
|
||||
|
||||
data class GameDetailModuleTrackData(
|
||||
var gameId: String = "",
|
||||
var gameName: String = "",
|
||||
var gameType: String = "",
|
||||
var gameStatus: String = "",
|
||||
var moduleType: String = "",
|
||||
var moduleName: String = "",
|
||||
var sequence: Int = 0,
|
||||
var subModuleName: String = "",
|
||||
var subSequence: Int = 0
|
||||
)
|
||||
|
||||
companion object {
|
||||
fun getGameStatus(buttonStyle: DownloadButton.ButtonStyle) = when (buttonStyle) {
|
||||
DownloadButton.ButtonStyle.WAITING,
|
||||
DownloadButton.ButtonStyle.UPDATING,
|
||||
DownloadButton.ButtonStyle.PAUSE,
|
||||
DownloadButton.ButtonStyle.FAILURE,
|
||||
DownloadButton.ButtonStyle.DOWNLOADING_NORMAL,
|
||||
DownloadButton.ButtonStyle.DOWNLOADING_PLUGIN -> "下载中"
|
||||
|
||||
DownloadButton.ButtonStyle.XAPK_UNZIPPING,
|
||||
DownloadButton.ButtonStyle.XAPK_SUCCESS,
|
||||
DownloadButton.ButtonStyle.XAPK_FAILURE,
|
||||
DownloadButton.ButtonStyle.INSTALL_NORMAL,
|
||||
DownloadButton.ButtonStyle.INSTALL_PLUGIN -> "待安装"
|
||||
|
||||
DownloadButton.ButtonStyle.LAUNCH_OR_OPEN -> "已安装"
|
||||
DownloadButton.ButtonStyle.RESERVABLE -> "预约"
|
||||
DownloadButton.ButtonStyle.RESERVED -> "已预约"
|
||||
else -> "未下载"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.content.Context
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailImageLinkBinding
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailLink
|
||||
|
||||
class GameDetailAdvertisingImageItemViewHolder(
|
||||
val binding: ItemGameDetailImageLinkBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkAdvertising ?: return
|
||||
bindImageItem(context, binding, entity, "游戏详情-广告推荐", baseTrackData) { gameStatus }
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun bindImageItem(
|
||||
context: Context,
|
||||
binding: ItemGameDetailImageLinkBinding,
|
||||
data: GameDetailLink,
|
||||
entrance: String,
|
||||
trackData: GameDetailModuleTrackData,
|
||||
getGameStatus: () -> String
|
||||
) {
|
||||
binding.run {
|
||||
if (data.img.isNotEmpty() && data.imgScale.isNotEmpty()) {
|
||||
imageIv.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
dimensionRatio = data.imgScale
|
||||
}
|
||||
maskView.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
height = if (data.imgScale == "4:1") 40F.dip2px() else 60F.dip2px()
|
||||
}
|
||||
ImageUtils.display(imageIv, data.img)
|
||||
}
|
||||
iconIv.goneIf(data.componentIcon?.icon.isNullOrEmpty()) {
|
||||
ImageUtils.display(iconIv, data.componentIcon?.icon)
|
||||
}
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_aw_primary.toColor(context))
|
||||
titleTv.text = data.title
|
||||
linkTv.goneIf(data.text.isEmpty()) {
|
||||
linkTv.text = data.text
|
||||
linkTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
}
|
||||
container.setOnClickListener { _ ->
|
||||
data.link?.let {
|
||||
DirectUtils.directToLinkPage(context, it, entrance, "")
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
trackData.gameId,
|
||||
trackData.gameName,
|
||||
trackData.gameType,
|
||||
"组件内容",
|
||||
trackData.moduleType,
|
||||
trackData.moduleName,
|
||||
trackData.sequence,
|
||||
null,
|
||||
null,
|
||||
it.type,
|
||||
it.link,
|
||||
it.link,
|
||||
getGameStatus()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.content.Context
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailLinkBinding
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailLink
|
||||
|
||||
class GameDetailAdvertisingItemViewHolder(
|
||||
val binding: ItemGameDetailLinkBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkAdvertising ?: return
|
||||
bindItem(context, binding, entity, "游戏详情-广告推荐", baseTrackData) { gameStatus }
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun bindItem(
|
||||
context: Context,
|
||||
binding: ItemGameDetailLinkBinding,
|
||||
data: GameDetailLink,
|
||||
entrance: String,
|
||||
trackData: GameDetailModuleTrackData,
|
||||
getGameStatus: () -> String
|
||||
) {
|
||||
binding.run {
|
||||
container.background = R.drawable.bg_shape_ui_container_1_radius_8_item_style.toDrawable(context)
|
||||
iconIv.goneIf(data.componentIcon?.icon.isNullOrEmpty()) {
|
||||
ImageUtils.display(iconIv, data.componentIcon?.icon)
|
||||
}
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
titleTv.text = data.title
|
||||
container.setOnClickListener { _ ->
|
||||
data.link?.let {
|
||||
DirectUtils.directToLinkPage(context, it, entrance, "")
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
trackData.gameId,
|
||||
trackData.gameName,
|
||||
trackData.gameType,
|
||||
"组件内容",
|
||||
trackData.moduleType,
|
||||
trackData.moduleName,
|
||||
trackData.sequence,
|
||||
null,
|
||||
null,
|
||||
it.type,
|
||||
it.link,
|
||||
it.link,
|
||||
getGameStatus()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.view.VerticalItemDecoration
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailAnnouncementBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailImageLinkBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailLinkBinding
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailLink
|
||||
|
||||
class GameDetailAnnouncementItemViewHolder(
|
||||
val binding: ItemGameDetailAnnouncementBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkAnnouncement ?: return
|
||||
binding.run {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
titleTv.text = entity.name
|
||||
if (recyclerView.adapter !is GameDetailAnnouncementAdapter) {
|
||||
recyclerView.isNestedScrollingEnabled = false
|
||||
recyclerView.layoutManager = LinearLayoutManager(context)
|
||||
recyclerView.adapter = GameDetailAnnouncementAdapter(entity.data)
|
||||
recyclerView.addItemDecoration(VerticalItemDecoration(context, 8F, false, com.gh.gamecenter.common.R.color.transparent))
|
||||
} else {
|
||||
recyclerView.adapter?.run { notifyItemRangeChanged(0, itemCount) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class GameDetailAnnouncementAdapter(val dataList: List<GameDetailLink>) :
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
val data = dataList[position]
|
||||
return if (data.img.isEmpty()) ITEM_LINK else ITEM_IMAGE_LINK
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return if (viewType == ITEM_LINK) {
|
||||
GameDetailAnnouncementItemViewHolder(parent.toBinding())
|
||||
} else {
|
||||
GameDetailAnnouncementImageItemViewHolder(parent.toBinding())
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = dataList.size
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val data = dataList.getOrNull(position) ?: return
|
||||
if (holder is GameDetailAnnouncementItemViewHolder) {
|
||||
GameDetailAdvertisingItemViewHolder.bindItem(
|
||||
context,
|
||||
holder.binding,
|
||||
data,
|
||||
"游戏详情-资讯公告",
|
||||
baseTrackData.apply {
|
||||
moduleName = itemData?.linkAnnouncement?.name ?: ""
|
||||
}) { gameStatus }
|
||||
holder.binding.container.background = null
|
||||
}
|
||||
if (holder is GameDetailAnnouncementImageItemViewHolder) {
|
||||
GameDetailAdvertisingImageItemViewHolder.bindImageItem(
|
||||
context,
|
||||
holder.binding,
|
||||
data,
|
||||
"游戏详情-资讯公告",
|
||||
baseTrackData.apply {
|
||||
moduleName = itemData?.linkAnnouncement?.name ?: ""
|
||||
}
|
||||
) { gameStatus }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inner class GameDetailAnnouncementItemViewHolder(val binding: ItemGameDetailLinkBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
inner class GameDetailAnnouncementImageItemViewHolder(val binding: ItemGameDetailImageLinkBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
companion object {
|
||||
const val ITEM_LINK = 0
|
||||
const val ITEM_IMAGE_LINK = 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,135 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.text.Html
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.forEach
|
||||
import androidx.core.view.isEmpty
|
||||
import androidx.core.view.isVisible
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailBriefAwardBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailBriefBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailBriefTagBinding
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.dialog.GameDetailScrollableTextDialogFragment
|
||||
import com.gh.gamecenter.gamedetail.entity.GameBrief
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
import com.gh.gamecenter.tag.TagsActivity
|
||||
import splitties.systemservices.layoutInflater
|
||||
|
||||
class GameDetailBriefItemViewHolder(
|
||||
val binding: ItemGameDetailBriefBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkGameBrief ?: return
|
||||
binding.run {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
briefTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
divider.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(context))
|
||||
expandTv.background = R.drawable.bg_ui_surface_expand_gradient.toDrawable(context)
|
||||
expandTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
titleTv.text = entity.name
|
||||
tagScrollView.goneIf(entity.gameTags.isEmpty()) {
|
||||
bindGamesTags(entity.gameTags)
|
||||
}
|
||||
briefTv.text = Html.fromHtml(entity.des)
|
||||
briefTv.post {
|
||||
expandTv.isVisible = briefTv.lineCount == 3 && briefTv.layout.getEllipsisCount(2) > 0
|
||||
}
|
||||
expandTv.setOnClickListener {
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
entity.name,
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
GameDetailScrollableTextDialogFragment.show(
|
||||
context,
|
||||
viewModel.game?.id ?: "",
|
||||
viewModel.game?.name ?: "",
|
||||
"游戏信息",
|
||||
entity.des
|
||||
)
|
||||
}
|
||||
awardScrollView.goneIf(entity.awardData.isEmpty()) {
|
||||
bindAwards(entity.awardData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindGamesTags(gameTags: List<GameBrief.GameTag>) {
|
||||
if (binding.tagContainer.isEmpty()) {
|
||||
gameTags.forEachIndexed { index, gameTag ->
|
||||
val tagBinding = ItemGameDetailBriefTagBinding.inflate(context.layoutInflater)
|
||||
tagBinding.root.text = gameTag.name
|
||||
tagBinding.root.setOnClickListener {
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
itemData?.linkGameBrief?.name,
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
context.startActivity(
|
||||
TagsActivity.getIntent(
|
||||
context,
|
||||
gameTag.name,
|
||||
gameTag.name,
|
||||
"游戏详情-游戏简介",
|
||||
""
|
||||
)
|
||||
)
|
||||
}
|
||||
binding.tagContainer.addView(
|
||||
tagBinding.root,
|
||||
LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, 24F.dip2px()).apply {
|
||||
leftMargin = if (index == 0) 0 else 4F.dip2px()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
binding.tagContainer.forEach {
|
||||
(it as? TextView)?.run {
|
||||
setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
background = com.gh.gamecenter.common.R.drawable.bg_shape_ui_container_1_stroke_radius_6.toDrawable(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindAwards(awardList: List<GameBrief.AwardData>) {
|
||||
if (binding.awardContainer.isEmpty()) {
|
||||
awardList.forEachIndexed { index, awardData ->
|
||||
val awardBinding = ItemGameDetailBriefAwardBinding.inflate(context.layoutInflater)
|
||||
awardBinding.iconIv.display(awardData.icon)
|
||||
awardBinding.nameTv.text = awardData.award
|
||||
awardBinding.typeTv.text = awardData.awardType
|
||||
awardBinding.root.setOnClickListener {
|
||||
awardData.link?.let { link -> DirectUtils.directToLinkPage(context, link, "游戏详情-游戏简介", "") }
|
||||
}
|
||||
binding.awardContainer.addView(
|
||||
awardBinding.root,
|
||||
LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, 26F.dip2px()).apply {
|
||||
leftMargin = if (index == 0) 0 else 24F.dip2px()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
binding.awardContainer.forEach {
|
||||
it.findViewById<TextView>(R.id.nameTv)?.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
it.findViewById<TextView>(R.id.typeTv)?.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,403 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.*
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.activity.BaseActivity
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.SpanBuilder
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailRecyclerViewBinding
|
||||
import com.gh.gamecenter.databinding.SubItemGameDetailCommentBinding
|
||||
import com.gh.gamecenter.entity.RatingComment
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailTabEntity
|
||||
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
|
||||
import com.gh.gamecenter.gamedetail.rating.edit.RatingEditActivity
|
||||
import com.gh.gamecenter.gamedetail.rating.logs.CommentLogsActivity
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class GameDetailCommentItemViewHolder(
|
||||
val binding: ItemGameDetailRecyclerViewBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkComment ?: return
|
||||
binding.run {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
moreTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
moreTv.setDrawableEnd(com.gh.gamecenter.common.R.drawable.ic_auxiliary_arrow_right_12.toDrawable(context)?.apply {
|
||||
colorFilter = PorterDuffColorFilter(com.gh.gamecenter.common.R.color.text_theme.toColor(context), PorterDuff.Mode.SRC_ATOP)
|
||||
})
|
||||
titleTv.text = entity.name
|
||||
moreTv.isVisible = true
|
||||
moreTv.text = "更多"
|
||||
moreTv.setOnClickListener {
|
||||
viewModel.performTabSelected(GameDetailTabEntity.TYPE_COMMENT)
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"右上角",
|
||||
moduleType,
|
||||
entity.name,
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
|
||||
if (recyclerView.adapter !is CommentItemAdapter) {
|
||||
(recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
recyclerView.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
recyclerView.adapter = CommentItemAdapter(entity.data)
|
||||
} else {
|
||||
recyclerView.adapter?.run { notifyItemRangeChanged(0, itemCount) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class CommentItemAdapter(val dataList: ArrayList<RatingComment>) :
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
private val path = "游戏详情-玩家评论"
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
|
||||
CommentItemViewHolder(parent.toBinding())
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val commentData = dataList.getOrNull(position) ?: return
|
||||
var isChildLongClick = false
|
||||
if (holder is CommentItemViewHolder) {
|
||||
holder.binding.run {
|
||||
root.background = R.drawable.bg_shape_f8_radius_8.toDrawable(context)
|
||||
root.updateLayoutParams<MarginLayoutParams> {
|
||||
leftMargin = if (position == 0) 16F.dip2px() else 8F.dip2px()
|
||||
rightMargin = if (position == itemCount - 1) 16F.dip2px() else 0
|
||||
}
|
||||
userNameTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
tvBadgeName.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
commentTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
ipRegionTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
expandTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
moreIv.setImageResource(R.drawable.game_comment_more)
|
||||
userIcon.display(commentData.user.border, commentData.user.icon, commentData.user.auth?.icon)
|
||||
userNameTv.text = commentData.user.name
|
||||
ratingStar.rating = commentData.star.toFloat()
|
||||
if (commentData.user.badge != null) {
|
||||
sdvUserBadge.visibility = View.VISIBLE
|
||||
tvBadgeName.visibility = View.VISIBLE
|
||||
ImageUtils.display(sdvUserBadge, commentData.user.badge?.icon)
|
||||
tvBadgeName.text = commentData.user.badge?.name
|
||||
} else {
|
||||
sdvUserBadge.visibility = View.GONE
|
||||
tvBadgeName.visibility = View.GONE
|
||||
}
|
||||
val p = Pattern.compile(RatingEditActivity.LABEL_REGEX)
|
||||
val m = p.matcher(commentData.content)
|
||||
if (m.find()) {
|
||||
val contents =
|
||||
TextHelper.getCommentLabelSpannableStringBuilder(commentData.content, com.gh.gamecenter.common.R.color.text_theme)
|
||||
commentTv.setTextWithHighlightedTextWrappedInsideWrapper(
|
||||
text = contents,
|
||||
highlightedTextClickListener = TextHelper.DirectToWebViewHighlightedTextClick(
|
||||
context,
|
||||
"游戏详情-玩家评论"
|
||||
)
|
||||
)
|
||||
} else {
|
||||
commentTv.setTextWithHighlightedTextWrappedInsideWrapper(
|
||||
text = commentData.content,
|
||||
highlightedTextClickListener = TextHelper.DirectToWebViewHighlightedTextClick(
|
||||
context,
|
||||
"游戏详情-玩家评论"
|
||||
)
|
||||
)
|
||||
}
|
||||
commentTv.post {
|
||||
expandTv.isVisible = commentTv.lineCount == 5 && commentTv.layout.getEllipsisCount(4) > 0
|
||||
}
|
||||
ipRegionTv.goneIf(!(commentData.source != null && commentData.source.region.isNotEmpty()))
|
||||
ipRegionTv.text = " · ${commentData.source?.region}"
|
||||
when {
|
||||
commentData.isEditContent == null -> {
|
||||
timeTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
timeTv.text = if (commentData.ignore) {
|
||||
val s = "${NewsUtils.getFormattedTime(commentData.time)} 保护期评论不计入总分"
|
||||
SpanBuilder(s).image(s.length - 12, s.length - 11, R.drawable.ic_ignore_rating_tips)
|
||||
.color(context, s.length - 10, s.length, com.gh.gamecenter.common.R.color.text_secondary).build()
|
||||
} else {
|
||||
NewsUtils.getFormattedTime(commentData.time)
|
||||
}
|
||||
}
|
||||
|
||||
commentData.isEditContent!! -> {
|
||||
timeTv.setTextColor(com.gh.gamecenter.common.R.color.text_F56614.toColor(context))
|
||||
timeTv.text = if (commentData.ignore) {
|
||||
"${NewsUtils.getFormattedTime(commentData.time)} 保护期间修改评论 >"
|
||||
} else {
|
||||
"${NewsUtils.getFormattedTime(commentData.time)} 已修改 >"
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
timeTv.setTextColor(com.gh.gamecenter.common.R.color.text_F56614.toColor(context))
|
||||
timeTv.text = if (commentData.ignore) {
|
||||
"${NewsUtils.getFormattedTime(commentData.time)} 保护期间修改评论"
|
||||
} else {
|
||||
"${NewsUtils.getFormattedTime(commentData.time)} 已修改"
|
||||
}
|
||||
}
|
||||
}
|
||||
sdvUserBadge.setOnClickListener {
|
||||
DialogUtils.showViewBadgeDialog(context, commentData.user.badge) {
|
||||
DirectUtils.directToBadgeWall(
|
||||
context,
|
||||
commentData.user.id,
|
||||
commentData.user.name,
|
||||
commentData.user.icon
|
||||
)
|
||||
}
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
itemData?.linkComment?.name,
|
||||
sequence,
|
||||
subModuleName = "玩家评论列表",
|
||||
supSequence = position + 1,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
userIcon.setOnClickListener {
|
||||
DirectUtils.directToHomeActivity(
|
||||
context,
|
||||
commentData.user.id,
|
||||
viewModel.entrance,
|
||||
path
|
||||
)
|
||||
NewLogUtils.logGameDetailCommentClick(
|
||||
viewModel.game?.name ?: "",
|
||||
viewModel.game?.id ?: "",
|
||||
"个人主页"
|
||||
)
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
itemData?.linkComment?.name,
|
||||
sequence,
|
||||
subModuleName = "玩家评论列表",
|
||||
supSequence = position + 1,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
userNameTv.setOnClickListener {
|
||||
userIcon.performClick()
|
||||
}
|
||||
tvBadgeName.setOnClickListener { sdvUserBadge.performClick() }
|
||||
commentTv.setOnLongClickListener(View.OnLongClickListener {
|
||||
isChildLongClick = true
|
||||
commentData.content.replace(RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), "")
|
||||
.copyTextAndToast()
|
||||
return@OnLongClickListener true
|
||||
})
|
||||
moreIv.setOnClickListener {
|
||||
showMorePopWindow(it, commentData.user.id == UserManager.getInstance().userId) { text ->
|
||||
when (text) {
|
||||
"复制" -> {
|
||||
commentData.content.replace(RatingEditActivity.LABEL_REPLACE_REGEX.toRegex(), "")
|
||||
.copyTextAndToast()
|
||||
}
|
||||
|
||||
"修改" -> {
|
||||
val intent =
|
||||
RatingEditActivity.getPatchIntent(context, viewModel.game!!, commentData)
|
||||
SyncDataBetweenPageHelper.startActivityForResult(
|
||||
context,
|
||||
intent,
|
||||
RATING_PATCH_REQUEST,
|
||||
position
|
||||
)
|
||||
}
|
||||
|
||||
"投诉" -> {
|
||||
context.ifLogin(BaseActivity.mergeEntranceAndPath(viewModel.entrance, path)) {
|
||||
DialogUtils.showReportReasonDialog(
|
||||
context,
|
||||
Constants.REPORT_LIST.toList() as java.util.ArrayList<String>
|
||||
) { reason, desc ->
|
||||
SimpleRequestHelper.reportGameComment(
|
||||
viewModel.game?.id ?: "",
|
||||
commentData.id,
|
||||
if (reason != "其他原因") reason else desc
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"删除" -> {
|
||||
DialogHelper.showDeleteGameCommentDialog(
|
||||
context,
|
||||
R.string.delete_game_comment.toResString()
|
||||
) {
|
||||
SimpleRequestHelper.deleteGameComment(
|
||||
viewModel.game?.id ?: "",
|
||||
commentData.id
|
||||
) {
|
||||
// 删除列表中的评论(如果当前列表有的话)
|
||||
val index = dataList.indexOfFirst { item ->
|
||||
item.id == commentData.id
|
||||
}
|
||||
if (index != -1) {
|
||||
dataList.removeAt(index)
|
||||
notifyItemRemoved(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
timeTv.setOnClickListener {
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
itemData?.linkComment?.name,
|
||||
sequence,
|
||||
subModuleName = "玩家评论列表",
|
||||
supSequence = position + 1,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
if (commentData.isEditContent == null && commentData.ignore) {
|
||||
DialogUtils.showStopServerExplanationDialog(
|
||||
context,
|
||||
if (viewModel.game?.commentDescription?.isNotEmpty() == true)
|
||||
viewModel.game?.commentDescription else context.getString(R.string.rating_protection),
|
||||
viewModel.game?.name
|
||||
?: ""
|
||||
)
|
||||
} else if (commentData.isEditContent == true) {
|
||||
val intent = CommentLogsActivity.getIntent(context, viewModel.game!!.id, commentData.id)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
expandTv.setOnClickListener { root.performClick() }
|
||||
root.setOnClickListener {
|
||||
if (isChildLongClick) {
|
||||
isChildLongClick = false
|
||||
return@setOnClickListener
|
||||
}
|
||||
val exposureSource = arrayListOf(
|
||||
ExposureSource("游戏详情"),
|
||||
ExposureSource("详情tab"),
|
||||
ExposureSource("玩家评价"),
|
||||
).toJson()
|
||||
val intent = RatingReplyActivity.getIntent(
|
||||
context = context,
|
||||
gameId = viewModel.game?.id ?: "",
|
||||
commentId = commentData.id,
|
||||
exposureSource = exposureSource,
|
||||
entrance = viewModel.entrance ?: "",
|
||||
path = path
|
||||
)
|
||||
SyncDataBetweenPageHelper.startActivityForResult(
|
||||
context,
|
||||
intent,
|
||||
RATING_REPLY_REQUEST,
|
||||
position
|
||||
)
|
||||
NewLogUtils.logGameDetailCommentClick(
|
||||
viewModel.game?.name ?: "",
|
||||
viewModel.game?.id ?: "",
|
||||
"评论内容"
|
||||
)
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
itemData?.linkComment?.name,
|
||||
sequence,
|
||||
subModuleName = "玩家评论列表",
|
||||
supSequence = position + 1,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showMorePopWindow(v: View, isMyRating: Boolean, clickListener: (String) -> Unit) {
|
||||
val contentList = if (isMyRating) arrayListOf("复制", "修改", "删除")
|
||||
else arrayListOf("复制", "投诉")
|
||||
|
||||
val inflater = LayoutInflater.from(v.context)
|
||||
val layout = inflater.inflate(com.gh.gamecenter.common.R.layout.layout_popup_container, null)
|
||||
val popupWindow = PopupWindow(
|
||||
layout,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
popupWindow.apply {
|
||||
setBackgroundDrawable(ColorDrawable(0))
|
||||
isTouchable = true
|
||||
isFocusable = true
|
||||
isOutsideTouchable = true
|
||||
}
|
||||
|
||||
val container = layout.findViewById<LinearLayout>(R.id.container)
|
||||
for (text in contentList) {
|
||||
val item = inflater.inflate(R.layout.layout_popup_option_item, container, false)
|
||||
container.addView(item)
|
||||
|
||||
val hitText = item.findViewById<TextView>(R.id.hint_text)
|
||||
hitText.text = text
|
||||
|
||||
item.setOnClickListener {
|
||||
clickListener.invoke(text)
|
||||
popupWindow.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
popupWindow.showAutoOrientation(v)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = dataList.size
|
||||
}
|
||||
|
||||
inner class CommentItemViewHolder(val binding: SubItemGameDetailCommentBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
companion object {
|
||||
const val RATING_REPLY_REQUEST = 233
|
||||
const val RATING_PATCH_REQUEST = 234
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,249 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.graphics.Typeface
|
||||
import android.text.Html
|
||||
import android.view.ViewGroup
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
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.common.view.VerticalItemDecoration
|
||||
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
|
||||
|
||||
class GameDetailComprehensivePanelItemViewHolder(
|
||||
val binding: ItemGameDetailComprehensivePanelBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val dataList = data.linkComprehensive ?: return
|
||||
binding.run {
|
||||
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))
|
||||
if (panelRv.adapter !is ComprehensivePanelAdapter) {
|
||||
(panelRv.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
panelRv.layoutManager = LinearLayoutManager(context)
|
||||
panelRv.adapter = ComprehensivePanelAdapter(dataList)
|
||||
} else {
|
||||
panelRv.adapter?.run { notifyItemRangeChanged(0, itemCount) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class ComprehensivePanelAdapter(val 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 {
|
||||
titleTv.goneIf(data.title.isEmpty()) {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
titleTv.text = data.title
|
||||
}
|
||||
val contentData = data.data ?: return
|
||||
val showPart = data.functionType == FUNCTION_TYPE_ONE_LINE_ONE_POINT && data.showType == SHOW_TYPE_PART
|
||||
if (recyclerView.adapter !is ComprehensivePanelFunctionAdapter) {
|
||||
val spanCount = if (data.functionType == FUNCTION_TYPE_ONE_LINE_ONE_POINT) 1 else 2
|
||||
val shrinkHeightDp = data.showRowNum * SHRANK_ONE_LINE_HEIGHT_DP
|
||||
recyclerView.isNestedScrollingEnabled = false
|
||||
(recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
recyclerView.layoutManager = object : GridLayoutManager(context, spanCount) {
|
||||
override fun canScrollVertically(): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
recyclerView.adapter = ComprehensivePanelFunctionAdapter(data.title, contentData)
|
||||
recyclerView.post {
|
||||
expandTv.goneIf(!showPart || recyclerView.height <= shrinkHeightDp.dip2px()) {
|
||||
var isExpand = false
|
||||
expandTv.text = "展开"
|
||||
recyclerView.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
height = shrinkHeightDp.dip2px()
|
||||
}
|
||||
expandTv.setOnClickListener {
|
||||
isExpand = !isExpand
|
||||
recyclerView.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
height = if (isExpand) {
|
||||
ConstraintLayout.LayoutParams.WRAP_CONTENT
|
||||
} else {
|
||||
shrinkHeightDp.dip2px()
|
||||
}
|
||||
}
|
||||
expandTv.text = if (isExpand) "收起" else "全部"
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
recyclerView.adapter?.run { notifyItemRangeChanged(0, itemCount) }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (holder is ComprehensivePanelFAQViewHolder) {
|
||||
holder.binding.run {
|
||||
titleTv.goneIf(data.title.isEmpty()) {
|
||||
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)
|
||||
recyclerView.addItemDecoration(VerticalItemDecoration(context, 8F, false, com.gh.gamecenter.common.R.color.transparent))
|
||||
} else {
|
||||
recyclerView.adapter?.run { notifyItemRangeChanged(0, itemCount) }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (holder is ComprehensivePanelDeclarationViewHolder) {
|
||||
holder.binding.run {
|
||||
titleTv.goneIf(data.title.isEmpty()) {
|
||||
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.text = Html.fromHtml(data.declaration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = dataList.size
|
||||
}
|
||||
|
||||
inner class ComprehensivePanelFunctionAdapter(private val subModuleName: String, val dataList: List<ContentData>) :
|
||||
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))
|
||||
text = data.text
|
||||
}
|
||||
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 ComprehensivePanelFAQAdapter(private val subModuleName: String, val 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.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)
|
||||
|
||||
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
|
||||
|
||||
const val SHRANK_ONE_LINE_HEIGHT_DP = 24F
|
||||
}
|
||||
}
|
||||
@ -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 { subSequence = 0 },
|
||||
getGameStatus
|
||||
)
|
||||
bindContentCard(
|
||||
lifecycleOwner,
|
||||
viewModel,
|
||||
it[1],
|
||||
binding.secondCardContainer,
|
||||
baseTrackData.apply { subSequence = 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,284 @@
|
||||
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.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 { subSequence = 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
|
||||
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?.id ?: "",
|
||||
viewModel.game?.name ?: "",
|
||||
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(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 { subSequence = 0 },
|
||||
getGameStatus
|
||||
)
|
||||
bindContentCard(
|
||||
lifecycleOwner,
|
||||
viewModel,
|
||||
it[1].apply { showDes = false },
|
||||
binding.secondCardContainer,
|
||||
baseTrackData.apply { subSequence = 1 },
|
||||
getGameStatus
|
||||
)
|
||||
bindContentCard(
|
||||
lifecycleOwner,
|
||||
viewModel,
|
||||
it[2].apply { showDes = false },
|
||||
binding.thirdCardContainer,
|
||||
baseTrackData.apply { subSequence = 2 },
|
||||
getGameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,143 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.content.Context
|
||||
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.LinkEntity
|
||||
import com.gh.gamecenter.common.entity.PKEntity
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.toDrawable
|
||||
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 ?: 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()
|
||||
}
|
||||
bindPKItem(context, this, link, pkEntity!!, onPositiveClickAction = positive@{
|
||||
if (pkEntity == null) return@positive
|
||||
SensorsBridge.trackPKClick(
|
||||
GlobalActivityManager.getCurrentPageEntity().pageName,
|
||||
GlobalActivityManager.getCurrentPageEntity().pageId,
|
||||
pkEntity!!.id,
|
||||
pkEntity!!.title,
|
||||
pkEntity!!.option1.text,
|
||||
pkEntity!!.link?.type ?: "",
|
||||
pkEntity!!.link?.link ?: "",
|
||||
pkEntity!!.link?.text ?: ""
|
||||
)
|
||||
viewModel.postPKVote(pkEntity!!.id, true)
|
||||
}, onNegativeClickAction = negative@{
|
||||
if (pkEntity == null) return@negative
|
||||
SensorsBridge.trackPKClick(
|
||||
GlobalActivityManager.getCurrentPageEntity().pageName,
|
||||
GlobalActivityManager.getCurrentPageEntity().pageId,
|
||||
pkEntity!!.id,
|
||||
pkEntity!!.title,
|
||||
pkEntity!!.option2.text,
|
||||
pkEntity!!.link?.type ?: "",
|
||||
pkEntity!!.link?.link ?: "",
|
||||
pkEntity!!.link?.text ?: ""
|
||||
)
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TYPE_PK = "pk"
|
||||
const val TIME_PATTERN = "yyyy.MM.dd HH:mm:ss"
|
||||
|
||||
fun bindPKItem(
|
||||
context: Context,
|
||||
binding: ItemPkBinding,
|
||||
link: LinkEntity,
|
||||
pkEntity: PKEntity,
|
||||
onPositiveClickAction: () -> Unit,
|
||||
onNegativeClickAction: () -> Unit,
|
||||
onLinkClickAction: () -> Unit
|
||||
) {
|
||||
binding.run {
|
||||
container.background = R.drawable.bg_shape_f8_radius_8.toDrawable(context)
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(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))
|
||||
titleTv.text = link.text
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,115 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailCustomColumnBinding
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailCustomColumn.Companion.SHOW_DES_TYPE_ALL
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailCustomColumn.RightTopInfo.Companion.TYPE_BUTTON
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailCustomColumn.RightTopInfo.Companion.TYPE_TEXT
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
|
||||
class GameDetailCustomColumnItemViewHolder(
|
||||
val binding: ItemGameDetailCustomColumnBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkCustomColumn ?: return
|
||||
binding.run {
|
||||
columnContainer.background = com.gh.gamecenter.common.R.drawable.bg_shape_f8_radius_8.toDrawable(context)
|
||||
titleTv.goneIf(!entity.showName) {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
titleTv.text = entity.name
|
||||
}
|
||||
imageIv.display(entity.img, true)
|
||||
columnTitleContainer.goneIf(entity.titleInfo == null) {
|
||||
gameIconIv.displayGameIcon(entity.titleInfo?.icon, entity.titleInfo?.iconSubscript, true, entity.titleInfo?.iconFloat)
|
||||
columnTitleTv.goneIf(entity.titleInfo?.showTitle == false) {
|
||||
columnTitleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
columnTitleTv.text = entity.titleInfo?.title
|
||||
}
|
||||
columnDesTv.text = entity.titleInfo?.text
|
||||
columnDesTv.setTextColor(if (entity.titleInfo?.link == null) com.gh.gamecenter.common.R.color.text_tertiary.toColor(context) else com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
columnDesTv.setOnClickListener { _ ->
|
||||
entity.titleInfo?.link?.let {
|
||||
DirectUtils.directToLinkPage(context, it, "游戏详情-自定义栏目", "")
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
entity.name,
|
||||
sequence,
|
||||
null,
|
||||
null,
|
||||
it.type,
|
||||
it.link,
|
||||
it.text,
|
||||
gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
secondTitleContainer.goneIf(entity.secondTitleInfo == null) {
|
||||
secondTitleIconIv.display(entity.secondTitleInfo?.icon, true)
|
||||
secondTitleTv.goneIf(entity.secondTitleInfo?.showTitle == false) {
|
||||
secondTitleTv.setTextColor(
|
||||
entity.secondTitleInfo?.color?.hexStringToIntColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context)) ?: com.gh.gamecenter.common.R.color.text_primary.toColor(context)
|
||||
)
|
||||
secondTitleTv.text = entity.secondTitleInfo?.text
|
||||
}
|
||||
}
|
||||
rightTopContainer.goneIf(entity.rightTopInfo == null) {
|
||||
rightTopIconIv.goneIf(entity.rightTopInfo?.icon.isNullOrEmpty() || entity.rightTopInfo?.style == TYPE_BUTTON) {
|
||||
ImageUtils.display(rightTopIconIv, entity.rightTopInfo?.icon)
|
||||
}
|
||||
rightTopButtonTv.goneIf(entity.rightTopInfo?.style == TYPE_TEXT) {
|
||||
rightTopButtonTv.background = com.gh.gamecenter.common.R.drawable.download_button_normal_style.toDrawable(context)
|
||||
rightTopButtonTv.text = entity.rightTopInfo?.text
|
||||
}
|
||||
rightTopTextTv.goneIf(entity.rightTopInfo?.style == TYPE_BUTTON) {
|
||||
rightTopTextTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
rightTopTextTv.text = entity.rightTopInfo?.text
|
||||
}
|
||||
rightTopContainer.setOnClickListener {
|
||||
entity.rightTopInfo?.link?.let {
|
||||
DirectUtils.directToLinkPage(context, it, "游戏详情-自定义栏目", "")
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"右上角",
|
||||
moduleType,
|
||||
entity.name,
|
||||
sequence,
|
||||
null,
|
||||
null,
|
||||
it.type,
|
||||
it.link,
|
||||
it.text,
|
||||
gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentTv.run {
|
||||
setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
shrinkLines = entity.showDesRowNum
|
||||
isExpanded = viewModel.expandTextStatusSparseBooleanArray.get(data.position, entity.showDesType == SHOW_DES_TYPE_ALL)
|
||||
setTextWithInterceptingInternalUrl(entity.tagDes)
|
||||
onExpandCallback = {
|
||||
viewModel.expandTextStatusSparseBooleanArray.put(data.position, true)
|
||||
}
|
||||
onShrinkCallback = {
|
||||
viewModel.expandTextStatusSparseBooleanArray.put(data.position, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.text.Html
|
||||
import androidx.core.view.isVisible
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.toDrawable
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailDeveloperWordBinding
|
||||
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.GameDetailData
|
||||
|
||||
class GameDetailDeveloperWordItemViewHolder(
|
||||
val binding: ItemGameDetailDeveloperWordBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : com.gh.gamecenter.gamedetail.detail.viewholder.BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkDeveloperWord ?: return
|
||||
binding.run {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
contentTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
titleTv.text = entity.name
|
||||
contentTv.text = Html.fromHtml(entity.text)
|
||||
contentTv.post {
|
||||
expandTv.isVisible = contentTv.lineCount == 3 && contentTv.layout.getEllipsisCount(2) > 0
|
||||
}
|
||||
expandTv.background = R.drawable.bg_ui_surface_expand_gradient.toDrawable(context)
|
||||
expandTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
expandTv.setOnClickListener {
|
||||
GameDetailScrollableTextDialogFragment.show(
|
||||
context,
|
||||
viewModel.game?.id ?: "",
|
||||
viewModel.game?.name ?: "",
|
||||
entity.name,
|
||||
entity.text
|
||||
)
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
entity.name,
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.text.Html
|
||||
import androidx.core.view.isVisible
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailDrawerBinding
|
||||
import com.gh.gamecenter.databinding.SubItemGameDetailDrawerBinding
|
||||
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 GameDetailDrawerItemViewHolder(
|
||||
val binding: ItemGameDetailDrawerBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkDrawer ?: return
|
||||
binding.drawer2Container.root.isVisible = entity.data.size > 1
|
||||
binding.dividerContainer.isVisible = entity.data.size > 1
|
||||
binding.dividerContainer.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_container_1.toColor(context))
|
||||
binding.divider.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(context))
|
||||
binding.titleTv.goneIf(!entity.showName) {
|
||||
binding.titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
binding.titleTv.text = entity.name
|
||||
}
|
||||
entity.data.getOrNull(0)?.let {
|
||||
binding.drawer1Container.root.background = R.drawable.bg_game_detail_drawer_left_item_style.toDrawable(context)
|
||||
bindSubView(binding.drawer1Container, it)
|
||||
}
|
||||
entity.data.getOrNull(1)?.let {
|
||||
binding.drawer2Container.root.background = R.drawable.bg_game_detail_drawer_right_item_style.toDrawable(context)
|
||||
bindSubView(binding.drawer2Container, it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindSubView(subBinding: SubItemGameDetailDrawerBinding, data: GameDetailLink) {
|
||||
subBinding.run {
|
||||
iconIv.goneIf(data.componentIcon?.icon.isNullOrEmpty()) {
|
||||
ImageUtils.display(iconIv, data.componentIcon?.icon)
|
||||
}
|
||||
contentTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
contentTv.text = Html.fromHtml(data.title)
|
||||
arrowIv.goneIf(data.link == null) {
|
||||
arrowIv.setImageResource(com.gh.gamecenter.common.R.drawable.ic_auxiliary_arrow_right_12)
|
||||
}
|
||||
root.setOnClickListener { _ ->
|
||||
data.link?.let {
|
||||
DirectUtils.directToLinkPage(context, it, "游戏详情-抽屉列表", "")
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
itemData?.linkDrawer?.name,
|
||||
sequence,
|
||||
null,
|
||||
null,
|
||||
it.type,
|
||||
it.link,
|
||||
it.text,
|
||||
gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.gh.gamecenter.ShellActivity
|
||||
import com.gh.gamecenter.ShellActivity.Type
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailRecyclerViewBinding
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.detail.GameLibaoAdapter
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailTabEntity
|
||||
import com.gh.gamecenter.gamedetail.libao.LibaoListFragment
|
||||
|
||||
class GameDetailGiftItemViewHolder(
|
||||
val binding: ItemGameDetailRecyclerViewBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val giftList = data.linkLibao ?: return
|
||||
binding.run {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
moreTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
moreTv.setDrawableEnd(com.gh.gamecenter.common.R.drawable.ic_auxiliary_arrow_right_12.toDrawable(context)?.apply {
|
||||
colorFilter = PorterDuffColorFilter(com.gh.gamecenter.common.R.color.text_theme.toColor(context), PorterDuff.Mode.SRC_ATOP)
|
||||
})
|
||||
titleTv.text = "游戏礼包"
|
||||
moreTv.goneIf(giftList.size <= 3) {
|
||||
moreTv.text = "更多"
|
||||
moreTv.setOnClickListener {
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"右上角",
|
||||
moduleType,
|
||||
"游戏礼包",
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
|
||||
val tabList = viewModel.gameDetailTabListLiveData.value?.data
|
||||
if (tabList?.find { it.type == GameDetailTabEntity.TYPE_GIFT } != null) {
|
||||
viewModel.performTabSelected(GameDetailTabEntity.TYPE_GIFT)
|
||||
} else {
|
||||
val bundle = LibaoListFragment.getBundle(
|
||||
viewModel.game?.id ?: "",
|
||||
viewModel.game?.name ?: "",
|
||||
false
|
||||
)
|
||||
context.startActivity(ShellActivity.getIntent(context, Type.SIMPLE_LIBAO_LIST, bundle))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (recyclerView.adapter !is GameLibaoAdapter) {
|
||||
recyclerView.isNestedScrollingEnabled = false
|
||||
(recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
recyclerView.layoutManager = LinearLayoutManager(context)
|
||||
recyclerView.adapter = GameLibaoAdapter(context, giftList, viewModel.game?.name ?: "", viewModel.game?.id ?: "")
|
||||
} else {
|
||||
(recyclerView.adapter as GameLibaoAdapter).run {
|
||||
libaos = giftList
|
||||
notifyItemRangeChanged(0, itemCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,256 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.text.Html
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.DefaultUrlHandler
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.WebActivity
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.TimeUtils
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailInfoBinding
|
||||
import com.gh.gamecenter.databinding.SubItemGameDetailInfoBinding
|
||||
import com.gh.gamecenter.feature.entity.GameInfo
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.dialog.GameInfoDialogFragment
|
||||
import com.gh.gamecenter.gamedetail.dialog.GamePermissionDialogFragment
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailInfo
|
||||
|
||||
class GameDetailInfoItemViewHolder(
|
||||
val binding: ItemGameDetailInfoBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) :
|
||||
BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkInfo ?: return
|
||||
binding.run {
|
||||
container.background = R.drawable.bg_shape_f8_radius_8.toDrawable(context)
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
moreTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
moreTv.setDrawableEnd(com.gh.gamecenter.common.R.drawable.ic_auxiliary_arrow_right_12.toDrawable(context)?.apply {
|
||||
colorFilter = PorterDuffColorFilter(com.gh.gamecenter.common.R.color.text_theme.toColor(context), PorterDuff.Mode.SRC_ATOP)
|
||||
})
|
||||
titleTv.text = entity.name
|
||||
divider1.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(context))
|
||||
|
||||
bindStaticInfo(context, entity, viewModel, privacyPolicyTv, permissionsTv, requestUpdateTv) {
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
entity.name,
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
|
||||
divider2.goneIf(entity.des.isEmpty()) {
|
||||
divider2.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_divider.toColor(context))
|
||||
}
|
||||
desTv.goneIf(entity.des.isEmpty()) {
|
||||
desTv.text = Html.fromHtml(entity.des)
|
||||
}
|
||||
moreTv.setOnClickListener {
|
||||
GameInfoDialogFragment.show(context, viewModel.game, entity)
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"右上角",
|
||||
moduleType,
|
||||
entity.name,
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
|
||||
if (gameInfoRv.adapter !is InfoItemAdapter) {
|
||||
val normalTypeKeys = normalTypeNameMap.keys
|
||||
val showFirstList = entity.fields.filter { normalTypeKeys.contains(it.name) && it.isFirst }.sortedBy { it.order }
|
||||
gameInfoRv.isNestedScrollingEnabled = false
|
||||
(gameInfoRv.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
gameInfoRv.layoutManager = LinearLayoutManager(context)
|
||||
gameInfoRv.adapter = InfoItemAdapter(showFirstList)
|
||||
} else {
|
||||
gameInfoRv.adapter?.run { notifyItemRangeChanged(0, itemCount) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class InfoItemAdapter(val dataList: List<GameDetailInfo.InfoItem>) :
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
|
||||
InfoItemViewHolder(parent.toBinding()) {
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
itemData?.linkInfo?.name,
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = dataList.size
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val data = dataList.getOrNull(position) ?: return
|
||||
if (holder is InfoItemViewHolder) {
|
||||
holder.bindInfoItem(context, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class InfoItemViewHolder(val binding: SubItemGameDetailInfoBinding, val onClickAction: (() -> Unit)? = null) : RecyclerView.ViewHolder(binding.root) {
|
||||
fun bindInfoItem(context: Context, data: GameDetailInfo.InfoItem) {
|
||||
binding.run {
|
||||
nameTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
infoTv.setTextColor(if (data.name == TYPE_ICP) com.gh.gamecenter.common.R.color.text_theme.toColor(context) else com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
nameTv.text = normalTypeNameMap[data.name]
|
||||
infoTv.text = when (data.name) {
|
||||
TYPE_INTERNET -> if (data.value == "yes") "是" else "否"
|
||||
TYPE_UPDATE_TIME -> data.value.toLongOrNull()?.let { TimeUtils.getFormatTime(it) }
|
||||
else -> data.value
|
||||
}
|
||||
infoTv.setOnClickListener {
|
||||
when (data.name) {
|
||||
TYPE_ICP -> {
|
||||
DirectUtils.directToExternalBrowser(context, context.getString(com.gh.gamecenter.common.R.string.icp_url))
|
||||
}
|
||||
}
|
||||
onClickAction?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TYPE_PRIVACY_POLICY = "privacy_policy_url"
|
||||
const val TYPE_PERMISSIONS = "permissions"
|
||||
const val TYPE_REQUEST_UPDATE = "request_update_status"
|
||||
|
||||
const val TYPE_INTERNET = "internet_app"
|
||||
const val TYPE_ICP = "ICP"
|
||||
const val TYPE_DEVELOPER = "developer"
|
||||
const val TYPE_PUBLISHER = "publisher"
|
||||
const val TYPE_MANUFACTURER = "manufacturer"
|
||||
const val TYPE_VERSION = "version"
|
||||
const val TYPE_UPDATE_TIME = "update_time"
|
||||
const val TYPE_RECOMMEND_AGE = "recommend_age"
|
||||
const val TYPE_CREDIT_CODE = "credit_code"
|
||||
const val TYPE_SIZE = "size"
|
||||
|
||||
// 固定信息类型
|
||||
val staticTypeNameMap = mapOf(
|
||||
TYPE_PRIVACY_POLICY to "隐私政策",
|
||||
TYPE_PERMISSIONS to "权限及用途",
|
||||
TYPE_REQUEST_UPDATE to "版本求更新"
|
||||
)
|
||||
|
||||
val normalTypeNameMap = mapOf(
|
||||
TYPE_INTERNET to "联网App",
|
||||
TYPE_ICP to "ICP备案号",
|
||||
TYPE_DEVELOPER to "开发者",
|
||||
TYPE_PUBLISHER to "发行商",
|
||||
TYPE_MANUFACTURER to "厂商",
|
||||
TYPE_VERSION to "当前版本",
|
||||
TYPE_UPDATE_TIME to "更新时间",
|
||||
TYPE_RECOMMEND_AGE to "适龄等级",
|
||||
TYPE_CREDIT_CODE to "统一社会信用代码",
|
||||
TYPE_SIZE to "游戏大小"
|
||||
)
|
||||
|
||||
fun bindStaticInfo(
|
||||
context: Context,
|
||||
entity: GameDetailInfo,
|
||||
viewModel: GameDetailViewModel,
|
||||
privacyPolicyTv: TextView,
|
||||
permissionsTv: TextView,
|
||||
requestUpdateTv: TextView,
|
||||
onClickAction: (() -> Unit)? = null
|
||||
) {
|
||||
val privacyPolicyInfo = entity.fields.find { it.name == TYPE_PRIVACY_POLICY }
|
||||
privacyPolicyTv.goneIf(privacyPolicyInfo == null) {
|
||||
privacyPolicyTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
privacyPolicyTv.setDrawableEnd(R.drawable.ic_auxiliary_arrow_right_8.toDrawable(context)?.apply {
|
||||
colorFilter = PorterDuffColorFilter(com.gh.gamecenter.common.R.color.text_secondary.toColor(context), PorterDuff.Mode.SRC_ATOP)
|
||||
})
|
||||
privacyPolicyTv.setOnClickListener {
|
||||
privacyPolicyInfo?.value?.let {
|
||||
if (!DefaultUrlHandler.transformNormalScheme(context, it, "隐私政策", "")) {
|
||||
val intent = WebActivity.getIntent(context, it, "隐私政策", false, false)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
onClickAction?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
val permissionsInfo = entity.fields.find { it.name == TYPE_PERMISSIONS }
|
||||
permissionsTv.goneIf(permissionsInfo == null) {
|
||||
permissionsTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
permissionsTv.setDrawableEnd(R.drawable.ic_auxiliary_arrow_right_8.toDrawable(context)?.apply {
|
||||
colorFilter = PorterDuffColorFilter(com.gh.gamecenter.common.R.color.text_secondary.toColor(context), PorterDuff.Mode.SRC_ATOP)
|
||||
})
|
||||
permissionsTv.setOnClickListener {
|
||||
var version = ""
|
||||
var manufacturerType = ""
|
||||
var manufacturer = ""
|
||||
var privacyPolicyUrl = ""
|
||||
entity.fields.forEach {
|
||||
when (it.name) {
|
||||
TYPE_DEVELOPER, TYPE_PUBLISHER, TYPE_MANUFACTURER -> {
|
||||
manufacturerType = it.name
|
||||
manufacturer = it.value
|
||||
}
|
||||
TYPE_VERSION -> version = it.value
|
||||
TYPE_PRIVACY_POLICY -> privacyPolicyUrl = it.value
|
||||
}
|
||||
}
|
||||
val gameInfo = GameInfo(
|
||||
version = version,
|
||||
manufacturerType = manufacturerType,
|
||||
manufacturer = manufacturer,
|
||||
privacyPolicyUrl = privacyPolicyUrl,
|
||||
permissions = permissionsInfo?.permissions
|
||||
)
|
||||
GamePermissionDialogFragment.show(context as AppCompatActivity, viewModel.game, gameInfo)
|
||||
onClickAction?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
val requestUpdateInfo = entity.fields.find { it.name == TYPE_REQUEST_UPDATE }
|
||||
requestUpdateTv.goneIf(requestUpdateInfo == null || requestUpdateInfo.value == "off") {
|
||||
requestUpdateTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
requestUpdateTv.setDrawableEnd(R.drawable.ic_auxiliary_arrow_right_8.toDrawable(context)?.apply {
|
||||
colorFilter = PorterDuffColorFilter(com.gh.gamecenter.common.R.color.text_theme.toColor(context), PorterDuff.Mode.SRC_ATOP)
|
||||
})
|
||||
requestUpdateTv.setOnClickListener {
|
||||
DialogHelper.showDialog(
|
||||
context, "版本求更新", "如果游戏上线了新版本,您可以提交申请,让小助手尽快更新版本喔!",
|
||||
"提交申请", "取消", {
|
||||
viewModel.sendSuggestion()
|
||||
}, extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
|
||||
)
|
||||
onClickAction?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,151 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.exposure.ExposureManager
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.view.divider.VerticalDividerItemDecoration
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailRecyclerViewBinding
|
||||
import com.gh.gamecenter.entity.SubjectEntity
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.game.horizontal.GameHorizontalAdapter
|
||||
import com.gh.gamecenter.game.horizontal.GameHorizontalListType
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
|
||||
class GameDetailRecommendColumnItemViewHolder(
|
||||
val binding: ItemGameDetailRecyclerViewBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val columnData = data.recommendColumn ?: return
|
||||
binding.run {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
moreTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
moreTv.setDrawableEnd(com.gh.gamecenter.common.R.drawable.ic_auxiliary_arrow_right_12.toDrawable(context)?.apply {
|
||||
colorFilter = PorterDuffColorFilter(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context), PorterDuff.Mode.SRC_ATOP)
|
||||
})
|
||||
titleTv.text = columnData.columnTitle
|
||||
moreTv.isEnabled = true
|
||||
headPb.isVisible = false
|
||||
moreTv.goneIf(columnData.displayHome.isEmpty()) {
|
||||
moreTv.run {
|
||||
text = columnData.displayHome
|
||||
setDebouncedClickListener {
|
||||
NewFlatLogUtils.logGameDetailColumnRecommendUpperRightClick(
|
||||
viewModel.game?.name ?: "",
|
||||
viewModel.game?.id ?: "",
|
||||
columnData.displayHome,
|
||||
columnData.columnTitle,
|
||||
columnData.columnId,
|
||||
columnData.moreLink?.text ?: "",
|
||||
columnData.moreLink?.type ?: "",
|
||||
columnData.moreLink?.link ?: ""
|
||||
)
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"右上角",
|
||||
moduleType,
|
||||
columnData.columnTitle,
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
SensorsBridge.trackColumnClick(
|
||||
location = "游戏详情",
|
||||
gameName = gameName,
|
||||
gameId = gameId,
|
||||
gameColumnName = columnData.columnTitle,
|
||||
gameColumnId = columnData.columnId,
|
||||
linkText = columnData.moreLink?.text ?: "",
|
||||
linkType = columnData.moreLink?.type ?: "",
|
||||
linkId = columnData.moreLink?.link ?: "",
|
||||
text = "右上角",
|
||||
buttonType = columnData.displayHome
|
||||
)
|
||||
if (columnData.displayHome == "换一批") {
|
||||
headPb.isVisible = true
|
||||
moreTv.isEnabled = false
|
||||
viewModel.changeSubjectGame(columnData.columnId, columnData.gameCount) {
|
||||
headPb.isVisible = false
|
||||
moreTv.isEnabled = true
|
||||
}
|
||||
} else {
|
||||
columnData.moreLink?.let {
|
||||
DirectUtils.directToLinkPage(
|
||||
context,
|
||||
it,
|
||||
viewModel.entrance ?: "",
|
||||
"游戏详情[${viewModel.game?.name ?: ""}]:专题游戏单推荐"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (recyclerView.adapter !is GameHorizontalAdapter) {
|
||||
recyclerView.run {
|
||||
isNestedScrollingEnabled = false
|
||||
(itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
val subjectEntity = SubjectEntity().apply {
|
||||
id = columnData.columnId
|
||||
name = columnData.columnTitle
|
||||
this.data = columnData.columnGames
|
||||
}
|
||||
val exposureEventList = arrayListOf<ExposureEvent>()
|
||||
for ((index, game) in subjectEntity.data!!.withIndex()) {
|
||||
game.sequence = index
|
||||
val event = ExposureEvent.createEvent(
|
||||
gameEntity = game,
|
||||
source = listOf(
|
||||
ExposureSource("游戏详情", viewModel.game?.name ?: ""),
|
||||
ExposureSource("专题推荐", columnData.columnTitle)
|
||||
)
|
||||
)
|
||||
exposureEventList.add(event)
|
||||
ExposureManager.log(event)
|
||||
}
|
||||
val subjectAdapter =
|
||||
GameHorizontalAdapter(
|
||||
context,
|
||||
subjectEntity,
|
||||
GameHorizontalListType.GameDetailHorizontalType,
|
||||
gameDetailTrackData = baseTrackData.apply {
|
||||
moduleName = columnData.columnTitle
|
||||
},
|
||||
getGameStatus = { gameStatus })
|
||||
subjectAdapter.gameName = viewModel.game?.name ?: ""
|
||||
subjectAdapter.game = viewModel.game
|
||||
subjectAdapter.gameId = viewModel.game?.id ?: ""
|
||||
subjectAdapter.entrance = viewModel.entrance ?: ""
|
||||
subjectAdapter.path = "专题游戏单推荐"
|
||||
subjectAdapter.exposureEventList = exposureEventList
|
||||
(itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
val itemDecoration = VerticalDividerItemDecoration.Builder(context)
|
||||
.size(8F.dip2px())
|
||||
.color(com.gh.gamecenter.common.R.color.transparent.toColor(context))
|
||||
.build()
|
||||
addItemDecoration(itemDecoration)
|
||||
adapter = subjectAdapter
|
||||
}
|
||||
} else {
|
||||
recyclerView.adapter?.run {
|
||||
notifyItemRangeChanged(0, itemCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.setDrawableEnd
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.toDrawable
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailRecyclerViewBinding
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.detail.GameCollectionAdapter
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
|
||||
class GameDetailRecommendGameCollectionItemViewHolder(
|
||||
val binding: ItemGameDetailRecyclerViewBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val gameCollectionList = data.linkRecommendGameList ?: return
|
||||
binding.run {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
moreTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
moreTv.setDrawableEnd(com.gh.gamecenter.common.R.drawable.ic_auxiliary_arrow_right_12.toDrawable(context)?.apply {
|
||||
colorFilter = PorterDuffColorFilter(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context), PorterDuff.Mode.SRC_ATOP)
|
||||
})
|
||||
titleTv.text = "游戏单推荐"
|
||||
moreTv.isVisible = true
|
||||
moreTv.text = "游戏单广场"
|
||||
moreTv.setOnClickListener {
|
||||
NewFlatLogUtils.logGameDetailGameListRecommendSquareJump(viewModel.game?.name ?: "", viewModel.game?.id ?: "")
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"右上角",
|
||||
moduleType,
|
||||
"游戏单推荐",
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
DirectUtils.directToGameCollectionSquare(it.context, viewModel.entrance ?: "")
|
||||
}
|
||||
|
||||
if (recyclerView.adapter !is GameCollectionAdapter) {
|
||||
recyclerView.run {
|
||||
isNestedScrollingEnabled = false
|
||||
(itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
adapter = GameCollectionAdapter(
|
||||
gameCollectionList,
|
||||
viewModel.game?.id ?: "",
|
||||
viewModel.game?.name ?: "",
|
||||
viewModel.game,
|
||||
viewModel.entrance ?: "",
|
||||
"游戏详情[${viewModel.game?.name ?: ""}]:游戏单推荐",
|
||||
listOf(ExposureSource("游戏详情", "${viewModel.game?.name ?: ""}+${viewModel.game?.id ?: ""}")), baseTrackData) { gameStatus }
|
||||
}
|
||||
} else {
|
||||
recyclerView.adapter?.run {
|
||||
notifyItemRangeChanged(0, itemCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.exposure.ExposureManager
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.setDrawableEnd
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.toDrawable
|
||||
import com.gh.gamecenter.common.view.divider.VerticalDividerItemDecoration
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailRecyclerViewBinding
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.game.horizontal.GameHorizontalAdapter
|
||||
import com.gh.gamecenter.game.horizontal.GameHorizontalListType
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
|
||||
class GameDetailRecommendGameItemViewHolder(
|
||||
val binding: ItemGameDetailRecyclerViewBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkEveryonePlaying ?: return
|
||||
binding.run {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
moreTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
moreTv.setDrawableEnd(com.gh.gamecenter.common.R.drawable.ic_auxiliary_arrow_right_12.toDrawable(context)?.apply {
|
||||
colorFilter = PorterDuffColorFilter(com.gh.gamecenter.common.R.color.text_theme.toColor(context), PorterDuff.Mode.SRC_ATOP)
|
||||
})
|
||||
titleTv.text = "大家都在玩"
|
||||
moreTv.isVisible = false
|
||||
|
||||
val subjectEntity = entity.recommendedGames ?: return
|
||||
if (recyclerView.adapter !is GameHorizontalAdapter) {
|
||||
recyclerView.run {
|
||||
isNestedScrollingEnabled = false
|
||||
(itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
val exposureEventList = arrayListOf<ExposureEvent>()
|
||||
val itemDecoration = VerticalDividerItemDecoration.Builder(context)
|
||||
.size(8F.dip2px())
|
||||
.color(com.gh.gamecenter.common.R.color.transparent.toColor(context))
|
||||
.build()
|
||||
|
||||
for ((index, game) in subjectEntity.data!!.withIndex()) {
|
||||
game.sequence = index
|
||||
val event = ExposureEvent.createEvent(
|
||||
gameEntity = game,
|
||||
source = listOf(
|
||||
ExposureSource("游戏详情", viewModel.game?.name ?: ""),
|
||||
ExposureSource("大家都在玩", game.recommendType)
|
||||
)
|
||||
)
|
||||
exposureEventList.add(event)
|
||||
ExposureManager.log(event)
|
||||
}
|
||||
|
||||
layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
val subjectAdapter =
|
||||
GameHorizontalAdapter(
|
||||
context,
|
||||
subjectEntity,
|
||||
GameHorizontalListType.GameDetailHorizontalType,
|
||||
false,
|
||||
baseTrackData.apply { moduleName = "大家都在玩" }
|
||||
) { gameStatus }
|
||||
subjectAdapter.gameName = viewModel.game?.name ?: ""
|
||||
subjectAdapter.game = viewModel.game
|
||||
subjectAdapter.gameId = viewModel.game?.id ?: ""
|
||||
subjectAdapter.entrance = viewModel.entrance ?: ""
|
||||
subjectAdapter.path = "大家都在玩"
|
||||
subjectAdapter.exposureEventList = exposureEventList
|
||||
(itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
addItemDecoration(itemDecoration)
|
||||
adapter = subjectAdapter
|
||||
}
|
||||
} else {
|
||||
(recyclerView.adapter as GameHorizontalAdapter).run {
|
||||
checkResetData(subjectEntity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.display
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailRecommendImageBinding
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
|
||||
class GameDetailRecommendImageItemViewHolder(
|
||||
val binding: ItemGameDetailRecommendImageBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkImageRecommend ?: return
|
||||
binding.run {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
titleTv.text = entity.title
|
||||
imageIv.display(entity.img)
|
||||
root.setOnClickListener { _ ->
|
||||
entity.link?.let {
|
||||
DirectUtils.directToLinkPage(
|
||||
context = context,
|
||||
linkEntity = it,
|
||||
entrance = viewModel.entrance ?: "",
|
||||
path = "游戏详情"
|
||||
)
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
entity.title,
|
||||
sequence,
|
||||
null,
|
||||
null,
|
||||
it.type,
|
||||
it.link,
|
||||
it.link,
|
||||
gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.utils.setDrawableEnd
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.toDrawable
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailRecyclerViewBinding
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.game.vertical.SpanCountPagerSnapHelper
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.detail.GameDetailRelatedGameAdapter
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
|
||||
class GameDetailRelatedGameItemViewHolder(
|
||||
val binding: ItemGameDetailRecyclerViewBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val gameList = data.linkRelatedGame ?: return
|
||||
binding.run {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
moreTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
moreTv.setDrawableEnd(com.gh.gamecenter.common.R.drawable.ic_auxiliary_arrow_right_12.toDrawable(context)?.apply {
|
||||
colorFilter = PorterDuffColorFilter(com.gh.gamecenter.common.R.color.text_theme.toColor(context), PorterDuff.Mode.SRC_ATOP)
|
||||
})
|
||||
titleTv.text = "相关游戏"
|
||||
moreTv.isVisible = false
|
||||
|
||||
if (recyclerView.adapter !is GameDetailRelatedGameAdapter) {
|
||||
recyclerView.run {
|
||||
isNestedScrollingEnabled = false
|
||||
(itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
if (gameList.size > 3) {
|
||||
layoutManager = GridLayoutManager(context, 3, RecyclerView.HORIZONTAL, false)
|
||||
clearOnScrollListeners()
|
||||
(itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
onFlingListener = null
|
||||
val snapHelper = SpanCountPagerSnapHelper(3, true)
|
||||
snapHelper.attachToRecyclerView(this)
|
||||
} else {
|
||||
layoutManager = LinearLayoutManager(context)
|
||||
}
|
||||
adapter = GameDetailRelatedGameAdapter(context, viewModel.game, gameList, viewModel.entrance ?: "", baseTrackData) { gameStatus }
|
||||
}
|
||||
} else {
|
||||
recyclerView.adapter?.run {
|
||||
notifyItemRangeChanged(0, itemCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,186 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.view.Gravity
|
||||
import android.view.View.MeasureSpec
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewTreeObserver
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.TimeUtils
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailMoreBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailRecyclerViewBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailServerBinding
|
||||
import com.gh.gamecenter.feature.entity.ServerCalendarEntity
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.detail.GameLatestServiceAdapter
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailData
|
||||
import com.gh.gamecenter.gamedetail.fuli.kaifu.ServersCalendarActivity
|
||||
|
||||
class GameDetailServerItemViewHolder(
|
||||
val binding: ItemGameDetailRecyclerViewBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkServer ?: return
|
||||
binding.run {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
moreTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
moreTv.setDrawableEnd(com.gh.gamecenter.common.R.drawable.ic_auxiliary_arrow_right_12.toDrawable(context)?.apply {
|
||||
colorFilter = PorterDuffColorFilter(com.gh.gamecenter.common.R.color.text_theme.toColor(context), PorterDuff.Mode.SRC_ATOP)
|
||||
})
|
||||
titleTv.text = "游戏开服"
|
||||
moreTv.goneIf(entity.calendar.isEmpty()) {
|
||||
moreTv.text = "更多"
|
||||
moreTv.setOnClickListener {
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"右上角",
|
||||
moduleType,
|
||||
"游戏开服",
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
val intent = ServersCalendarActivity.getIntent(
|
||||
context,
|
||||
viewModel.game!!,
|
||||
entity,
|
||||
null
|
||||
)
|
||||
context.startActivity(intent)
|
||||
viewModel.game?.let {
|
||||
NewLogUtils.logGameDetailOpenListClick(it.name ?: "", it.id, "更多")
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entity.calendar.isNotEmpty()) {
|
||||
if (recyclerView.adapter !is ServerItemAdapter) {
|
||||
recyclerView.isNestedScrollingEnabled = false
|
||||
(recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
recyclerView.layoutManager = LinearLayoutManager(context)
|
||||
recyclerView.adapter = ServerItemAdapter(entity.calendar)
|
||||
} else {
|
||||
recyclerView.adapter?.run { notifyItemRangeChanged(0, itemCount) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class ServerItemAdapter(val dataList: ArrayList<ServerCalendarEntity>) :
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
private val showItemCount: Int = 3
|
||||
private val maxItemCount: Int = 10
|
||||
private var isExpand = false
|
||||
private var expandEntities = arrayListOf<ServerCalendarEntity>()
|
||||
private var shrinkEntities = arrayListOf<ServerCalendarEntity>()
|
||||
|
||||
init {
|
||||
expandEntities.clear()
|
||||
expandEntities.addAll(dataList.take(maxItemCount))
|
||||
//举例:当前时间为9点
|
||||
//全部开服 展示的3条
|
||||
//7、8、9、10 8、9、10
|
||||
//7、8、9、10、11、12、13 10、11、12
|
||||
//6、7、8、9 7、8、9
|
||||
//获取未来最靠近当前时间的3条
|
||||
shrinkEntities.clear()
|
||||
val currentHour = TimeUtils.getCurrentHour()
|
||||
dataList.forEach {
|
||||
val hour = TimeUtils.getFormatTime(it.getTime(), "HH").toInt()
|
||||
if (hour > currentHour && shrinkEntities.size < showItemCount) {
|
||||
shrinkEntities.add(it)
|
||||
}
|
||||
}
|
||||
//判断不足3条,向前补齐
|
||||
if (shrinkEntities.size < showItemCount) {
|
||||
if (shrinkEntities.isEmpty()) {
|
||||
shrinkEntities.addAll(dataList.takeLast(showItemCount))
|
||||
} else {
|
||||
val firstIndex = dataList.indexOf(shrinkEntities[0])
|
||||
for (index in dataList.size - 1 downTo 0) {
|
||||
if (index < firstIndex && shrinkEntities.size < showItemCount) {
|
||||
shrinkEntities.add(0, dataList[index])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return if (expandEntities.size > showItemCount) {
|
||||
if (position == itemCount - 1) GameLatestServiceAdapter.MORE else GameLatestServiceAdapter.SERVICE_ITEM
|
||||
} else {
|
||||
GameLatestServiceAdapter.SERVICE_ITEM
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
|
||||
if (viewType == ITEM_SERVER) ServerItemViewHolder(parent.toBinding()) else MoreViewHolder(parent.toBinding())
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
if (holder is ServerItemViewHolder) {
|
||||
val entity = if (expandEntities.size > showItemCount) {
|
||||
if (isExpand) expandEntities.safelyGetInRelease(position) else
|
||||
shrinkEntities.safelyGetInRelease(position)
|
||||
} else {
|
||||
expandEntities.safelyGetInRelease(position)
|
||||
} ?: return
|
||||
holder.binding.timeTv.setDrawableStart(R.drawable.ic_game_detail_server)
|
||||
holder.binding.timeTv.text = TimeUtils.getFormatDate(entity.getTime())
|
||||
holder.binding.serviceNameTv.text = "${entity.getNote()} ${entity.remark}"
|
||||
|
||||
holder.binding.serviceNameTv.viewTreeObserver.addOnGlobalLayoutListener(object :
|
||||
ViewTreeObserver.OnGlobalLayoutListener {
|
||||
override fun onGlobalLayout() {
|
||||
holder.binding.serviceNameTv.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||
|
||||
holder.binding.serviceNameTv.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
|
||||
val measuredWidth = holder.binding.serviceNameTv.measuredWidth
|
||||
val width = holder.binding.serviceNameTv.width
|
||||
if (measuredWidth > width) {
|
||||
holder.binding.serviceNameTv.isSelected = true
|
||||
holder.binding.serviceNameTv.gravity = Gravity.LEFT
|
||||
} else {
|
||||
holder.binding.serviceNameTv.gravity = Gravity.RIGHT
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
if (holder is MoreViewHolder) {
|
||||
holder.binding.arrowIv.rotation = if (isExpand) 180f else 0f
|
||||
holder.itemView.setOnClickListener {
|
||||
isExpand = !isExpand
|
||||
notifyDataSetChanged()
|
||||
viewModel.game?.let {
|
||||
NewLogUtils.logGameDetailOpenListClick(it.name ?: "", it.id, "展开")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = if (expandEntities.size > showItemCount) {
|
||||
if (isExpand) expandEntities.size + 1 else showItemCount + 1
|
||||
} else expandEntities.size
|
||||
}
|
||||
|
||||
inner class ServerItemViewHolder(val binding: ItemGameDetailServerBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
inner class MoreViewHolder(var binding: ItemGameDetailMoreBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
companion object {
|
||||
const val ITEM_MORE = 0
|
||||
const val ITEM_SERVER = 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,223 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
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.DataCollectionUtils
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.NewsUtils
|
||||
import com.gh.gamecenter.GameNewsActivity
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.utils.TimeUtils
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailRecyclerViewBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailStrategyBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailStrategyFixedTopBinding
|
||||
import com.gh.gamecenter.feature.entity.NewsEntity
|
||||
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
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailStrategy
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailTabEntity
|
||||
import com.gh.gamecenter.newsdetail.NewsDetailActivity
|
||||
|
||||
class GameDetailStrategyItemViewHolder(
|
||||
val binding: ItemGameDetailRecyclerViewBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkGameGuide ?: return
|
||||
binding.run {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
moreTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
moreTv.setDrawableEnd(com.gh.gamecenter.common.R.drawable.ic_auxiliary_arrow_right_12.toDrawable(context)?.apply {
|
||||
colorFilter = PorterDuffColorFilter(com.gh.gamecenter.common.R.color.text_theme.toColor(context), PorterDuff.Mode.SRC_ATOP)
|
||||
})
|
||||
titleTv.text = entity.name
|
||||
if (entity.rightTop == "link") {
|
||||
moreTv.text = "攻略专区"
|
||||
moreTv.isVisible = true
|
||||
moreTv.setOnClickListener {
|
||||
val tabList = viewModel.gameDetailTabListLiveData.value?.data
|
||||
if (tabList?.find { it.type == GameDetailTabEntity.TYPE_ZONE } != null) {
|
||||
viewModel.performTabSelected(GameDetailTabEntity.TYPE_ZONE)
|
||||
} else {
|
||||
viewModel.performContentCardClicked(ContentCardEntity.TYPE_ZONE)
|
||||
}
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"右上角",
|
||||
moduleType,
|
||||
entity.name,
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
} else if (entity.rightTop == "more") {
|
||||
moreTv.text = "更多"
|
||||
moreTv.goneIf(entity.data.size < 3)
|
||||
moreTv.setOnClickListener {
|
||||
val intent = GameNewsActivity.getIntent(
|
||||
context,
|
||||
viewModel.game?.name,
|
||||
viewModel.game?.id,
|
||||
viewModel.entrance + "+(游戏详情[" + viewModel.game?.name + "]:新手攻略-全部)"
|
||||
)
|
||||
context.startActivity(intent)
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"右上角",
|
||||
moduleType,
|
||||
entity.name,
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (recyclerView.adapter !is StrategyItemAdapter) {
|
||||
(recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
recyclerView.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
val dataList = if (entity.articleTop.isNotEmpty()) {
|
||||
entity.articleTop.map { GameDetailStrategy.StrategyData(type = "article", linkArticle = it, isFixedTop = true) } + entity.data
|
||||
} else {
|
||||
entity.data
|
||||
}
|
||||
recyclerView.adapter = StrategyItemAdapter(dataList)
|
||||
} else {
|
||||
recyclerView.adapter?.run { notifyItemRangeChanged(0, itemCount) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class StrategyItemAdapter(val dataList: List<GameDetailStrategy.StrategyData>) :
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
override fun getItemViewType(position: Int): Int = if (dataList[position].isFixedTop) ITEM_FIXED_TOP else ITEM_NORMAL
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
|
||||
if (viewType == ITEM_FIXED_TOP) FixedTopStrategyItemViewHolder(parent.toBinding()) else StrategyItemViewHolder(parent.toBinding())
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val strategyData = dataList.getOrNull(position) ?: return
|
||||
val newsEntity = strategyData.linkArticle
|
||||
val communityArticleEntity = strategyData.linkCommunityArticle
|
||||
if (holder is StrategyItemViewHolder) {
|
||||
holder.binding.run {
|
||||
root.updateLayoutParams<MarginLayoutParams> {
|
||||
leftMargin = if (position == 0) 16F.dip2px() else 8F.dip2px()
|
||||
rightMargin = if (position == itemCount - 1) 16F.dip2px() else 0
|
||||
}
|
||||
root.background = 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))
|
||||
timeTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
newsEntity?.let {
|
||||
titleTv.text = it.title ?: ""
|
||||
contentTv.text = it.intro ?: ""
|
||||
timeTv.text =
|
||||
if (TimeUtils.isToday(it.publishOn)) "今天" else TimeUtils.getFormatTime(it.publishOn)
|
||||
root.setOnClickListener { _ ->
|
||||
skipNewsDetail(it, position)
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
itemData?.linkGameGuide?.name,
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
communityArticleEntity?.let {
|
||||
titleTv.text = it.title
|
||||
contentTv.text = it.content
|
||||
timeTv.text =
|
||||
if (TimeUtils.isToday(it.time?.create ?: 0L)) "今天" else TimeUtils.getFormatTime(it.time?.create ?: 0L)
|
||||
root.setOnClickListener { _ ->
|
||||
DirectUtils.directToCommunityArticle(context, it.community, it.id, viewModel.entrance, "游戏详情-游戏攻略")
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
itemData?.linkGameGuide?.name,
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (holder is FixedTopStrategyItemViewHolder) {
|
||||
holder.binding.run {
|
||||
root.updateLayoutParams<MarginLayoutParams> {
|
||||
leftMargin = if (position == 0) 16F.dip2px() else 8F.dip2px()
|
||||
rightMargin = if (position == itemCount - 1) 16F.dip2px() else 0
|
||||
}
|
||||
root.background = R.drawable.bg_shape_f8_radius_8.toDrawable(context)
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
descTv.setTextColor(com.gh.gamecenter.common.R.color.text_tertiary.toColor(context))
|
||||
newsEntity?.let {
|
||||
ImageUtils.display(backgroundIv, it.thumb)
|
||||
titleTv.text = it.title ?: ""
|
||||
descTv.text = it.type ?: ""
|
||||
root.setOnClickListener { _ ->
|
||||
skipNewsDetail(it, position)
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
itemData?.linkGameGuide?.name,
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = dataList.size
|
||||
|
||||
private fun skipNewsDetail(article: NewsEntity, position: Int) {
|
||||
DataCollectionUtils.uploadClick(context, "新手攻略", "游戏详情", article.title)
|
||||
|
||||
// 统计阅读量
|
||||
NewsUtils.statNewsViews(article.id)
|
||||
NewsDetailActivity.startNewsDetailActivity(
|
||||
context, article,
|
||||
viewModel.entrance + "+(游戏详情[" + viewModel.game?.name + "]:新手攻略-列表[" + (position + 1) + "])"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
inner class StrategyItemViewHolder(val binding: ItemGameDetailStrategyBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
inner class FixedTopStrategyItemViewHolder(val binding: ItemGameDetailStrategyFixedTopBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
companion object {
|
||||
const val ITEM_FIXED_TOP = 0
|
||||
const val ITEM_NORMAL = 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.text.Html
|
||||
import androidx.core.view.isVisible
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.setDrawableEnd
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.utils.toDrawable
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailUpdateBinding
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
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.GameDetailData
|
||||
import com.gh.gamecenter.gamedetail.history.HistoryApkListActivity
|
||||
|
||||
class GameDetailUpdateItemViewHolder(
|
||||
val binding: ItemGameDetailUpdateBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkUpdate ?: return
|
||||
binding.run {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
contentTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(context))
|
||||
historyTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
historyTv.setDrawableEnd(com.gh.gamecenter.common.R.drawable.ic_auxiliary_arrow_right_12.toDrawable(context)?.apply {
|
||||
colorFilter = PorterDuffColorFilter(com.gh.gamecenter.common.R.color.text_theme.toColor(context), PorterDuff.Mode.SRC_ATOP)
|
||||
})
|
||||
historyTv.isVisible = entity.historyApkStatus == "on" && entity.historyApkCount >= 1
|
||||
titleTv.text = entity.name
|
||||
contentTv.text = Html.fromHtml(entity.updateDes)
|
||||
contentTv.post {
|
||||
expandTv.isVisible = contentTv.lineCount == 3 && contentTv.layout.getEllipsisCount(2) > 0
|
||||
}
|
||||
expandTv.background = R.drawable.bg_ui_surface_expand_gradient.toDrawable(context)
|
||||
expandTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
expandTv.setOnClickListener {
|
||||
GameDetailScrollableTextDialogFragment.show(
|
||||
context,
|
||||
viewModel.game?.id ?: "",
|
||||
viewModel.game?.name ?: "",
|
||||
entity.name,
|
||||
entity.updateDes
|
||||
)
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
entity.name,
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
historyTv.setOnClickListener {
|
||||
context.startActivity(
|
||||
HistoryApkListActivity.getIntent(
|
||||
context,
|
||||
viewModel.game ?: GameEntity(),
|
||||
viewModel.entrance ?: "",
|
||||
"游戏详情-更新内容"
|
||||
))
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"右上角",
|
||||
moduleType,
|
||||
entity.name,
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
package com.gh.gamecenter.gamedetail.detail.viewholder
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
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.DirectUtils
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailRecyclerViewBinding
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailVideoBinding
|
||||
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.GameDetailVideo
|
||||
import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel
|
||||
|
||||
class GameDetailVideoItemViewHolder(
|
||||
val binding: ItemGameDetailRecyclerViewBinding,
|
||||
downloadBtn: DownloadButton,
|
||||
viewModel: GameDetailViewModel
|
||||
) : BaseGameDetailItemViewHolder(binding.root, downloadBtn, viewModel) {
|
||||
override fun bindView(data: GameDetailData) {
|
||||
super.bindView(data)
|
||||
val entity = data.linkGameVideo ?: return
|
||||
binding.run {
|
||||
titleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
moreTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(context))
|
||||
moreTv.setDrawableEnd(com.gh.gamecenter.common.R.drawable.ic_auxiliary_arrow_right_12.toDrawable(context)?.apply {
|
||||
colorFilter = PorterDuffColorFilter(com.gh.gamecenter.common.R.color.text_theme.toColor(context), PorterDuff.Mode.SRC_ATOP)
|
||||
})
|
||||
titleTv.text = "游戏视频"
|
||||
moreTv.goneIf(entity.count < 3) {
|
||||
moreTv.text = "更多"
|
||||
moreTv.setOnClickListener {
|
||||
DirectUtils.directToGameVideo(context, viewModel.gameId ?: "", viewModel.entrance, "游戏详情")
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"右上角",
|
||||
moduleType,
|
||||
"游戏视频",
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (recyclerView.adapter !is VideoItemAdapter) {
|
||||
(recyclerView.itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
recyclerView.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
|
||||
recyclerView.adapter = VideoItemAdapter(entity.video)
|
||||
} else {
|
||||
recyclerView.adapter?.run { notifyItemRangeChanged(0, itemCount) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class VideoItemAdapter(val dataList: List<GameDetailVideo.Video>) :
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
|
||||
VideoItemViewHolder(parent.toBinding())
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val video = dataList.getOrNull(position) ?: return
|
||||
if (holder is VideoItemViewHolder) {
|
||||
holder.binding.run {
|
||||
root.updateLayoutParams<MarginLayoutParams> {
|
||||
leftMargin = if (position == 0) 16F.dip2px() else 8F.dip2px()
|
||||
rightMargin = if (position == itemCount - 1) 16F.dip2px() else 0
|
||||
}
|
||||
videoTitleTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(context))
|
||||
videoTitleTv.text = video.title
|
||||
ImageUtils.display(videoIv, video.poster)
|
||||
root.setOnClickListener {
|
||||
NewFlatLogUtils.logClickGameDetailVideoCategory(
|
||||
"video",
|
||||
video.id,
|
||||
video.user?.id ?: ""
|
||||
)
|
||||
DirectUtils.directToVideoDetail(
|
||||
context, video.id, VideoDetailContainerViewModel.Location.GAME_DETAIL.value,
|
||||
false, viewModel.game?.id ?: "", viewModel.entrance, "游戏详情"
|
||||
)
|
||||
SensorsBridge.trackGameDetailModuleClick(
|
||||
gameId,
|
||||
gameName,
|
||||
gameType,
|
||||
"组件内容",
|
||||
moduleType,
|
||||
"游戏视频",
|
||||
sequence,
|
||||
gameStatus = gameStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = dataList.size
|
||||
}
|
||||
|
||||
inner class VideoItemViewHolder(val binding: ItemGameDetailVideoBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
}
|
||||
@ -8,37 +8,51 @@ import android.text.method.LinkMovementMethod
|
||||
import android.text.style.ClickableSpan
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.core.utils.TimeUtils
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailBigEventBinding
|
||||
import com.gh.gamecenter.gamedetail.entity.BigEvent
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.utils.toColor
|
||||
import com.gh.gamecenter.common.viewholder.FooterViewHolder
|
||||
import com.gh.gamecenter.core.utils.TimeUtils
|
||||
import com.gh.gamecenter.databinding.ItemNewGameDetailBigEventBinding
|
||||
import com.gh.gamecenter.feature.entity.BigEvent
|
||||
import com.lightgame.adapter.BaseRecyclerAdapter
|
||||
|
||||
class GameBigEventAdapter(
|
||||
val context: Context,
|
||||
val bigEvents: List<BigEvent>,
|
||||
context: Context,
|
||||
private val bigEvents: List<BigEvent>,
|
||||
val onLinkClick: (LinkEntity, Int) -> Unit
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return GameBigEventViewHolder(parent.toBinding())
|
||||
) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return if (position == itemCount - 1) {
|
||||
ITEM_FOOTER
|
||||
} else {
|
||||
ITEM_CONTENT
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = bigEvents.size
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return if (viewType == ITEM_CONTENT) {
|
||||
NewGameBigEventViewHolder(parent.toBinding())
|
||||
} else {
|
||||
FooterViewHolder(mLayoutInflater.inflate(com.gh.gamecenter.common.R.layout.refresh_footerview, parent, false))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = if (bigEvents.isNotEmpty()) bigEvents.size + 1 else 0
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
val bigEvent = bigEvents[position]
|
||||
if (holder is GameBigEventViewHolder) {
|
||||
holder.binding.timeTv.text = TimeUtils.getFormatTime(bigEvent.time)
|
||||
if (bigEvent.link == null) {
|
||||
holder.binding.contentTv.text = bigEvent.content
|
||||
if (holder is NewGameBigEventViewHolder) {
|
||||
val bigEvent = bigEvents.getOrNull(position)
|
||||
holder.binding.timeTv.text = TimeUtils.getFormatTime(bigEvent?.time ?: 0L)
|
||||
if (bigEvent?.link == null) {
|
||||
holder.binding.contentTv.text = bigEvent?.content
|
||||
} else {
|
||||
val content = "${bigEvent.content} ${bigEvent.link?.value}"
|
||||
val builder = SpannableStringBuilder(content)
|
||||
builder.setSpan(object : ClickableSpan() {
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
ds.color = ContextCompat.getColor(context, com.gh.gamecenter.common.R.color.text_theme)
|
||||
ds.color = com.gh.gamecenter.common.R.color.text_theme.toColor(mContext)
|
||||
ds.isUnderlineText = true
|
||||
}
|
||||
|
||||
@ -50,7 +64,20 @@ class GameBigEventAdapter(
|
||||
holder.binding.contentTv.text = builder
|
||||
}
|
||||
}
|
||||
if (holder is FooterViewHolder) {
|
||||
holder.run {
|
||||
loading.visibility = View.GONE
|
||||
itemView.isClickable = false
|
||||
hint.setText(com.gh.gamecenter.common.R.string.load_over_hint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GameBigEventViewHolder(var binding: ItemGameDetailBigEventBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
class NewGameBigEventViewHolder(var binding: ItemNewGameDetailBigEventBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
companion object {
|
||||
private const val ITEM_CONTENT = 0
|
||||
private const val ITEM_FOOTER = 1
|
||||
}
|
||||
}
|
||||
@ -1,96 +0,0 @@
|
||||
package com.gh.gamecenter.gamedetail.dialog
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Window
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.TrackableDialog
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.view.VerticalItemDecoration
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.gamedetail.entity.BigEvent
|
||||
|
||||
class GameBigEventDialog(
|
||||
context: Context,
|
||||
val gameName: String,
|
||||
val gameId: String,
|
||||
val bigEvents: List<BigEvent>,
|
||||
val onLinkClick: (LinkEntity, Int) -> Unit,
|
||||
mEvent: String,
|
||||
mKey: String,
|
||||
mValue: String,
|
||||
) : TrackableDialog(context, com.gh.gamecenter.common.R.style.GhAlertDialog, mEvent, mKey, mValue) {
|
||||
|
||||
private val mDelayLogRunnable = Runnable {
|
||||
NewLogUtils.logGameDetailMajorEventView(gameName, gameId)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
if (window != null) {
|
||||
window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
val params = window!!.attributes
|
||||
params.width = context.resources.displayMetrics.widthPixels - DisplayUtils.dip2px(40f)
|
||||
window!!.attributes = params
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE)
|
||||
|
||||
val contentView = LayoutInflater.from(context).inflate(R.layout.dialog_game_big_event, null)
|
||||
setContentView(contentView)
|
||||
|
||||
val bigEventRv = contentView.findViewById<RecyclerView>(R.id.bigEventRv)
|
||||
bigEventRv.adapter = GameBigEventAdapter(context, bigEvents, onLinkClick)
|
||||
bigEventRv.layoutManager = LinearLayoutManager(context)
|
||||
bigEventRv.addItemDecoration(VerticalItemDecoration(context, 19F, false, com.gh.gamecenter.common.R.color.ui_surface))
|
||||
|
||||
val closeTv = contentView.findViewById<TextView>(R.id.dialog_close)
|
||||
closeTv.setOnClickListener {
|
||||
dismiss()
|
||||
}
|
||||
setOnCancelListener {
|
||||
mHandler.removeCallbacks(mDelayLogRunnable)
|
||||
}
|
||||
|
||||
mHandler.postDelayed(mDelayLogRunnable, 3000)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val mHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
fun showGameBigEventDialog(
|
||||
context: Context,
|
||||
gameName: String,
|
||||
gameId: String,
|
||||
bigEvents: List<BigEvent>,
|
||||
onLinkClick: (LinkEntity, Int) -> Unit
|
||||
): Dialog {
|
||||
return GameBigEventDialog(
|
||||
context,
|
||||
gameName,
|
||||
gameId,
|
||||
bigEvents,
|
||||
onLinkClick,
|
||||
"游戏大事件",
|
||||
"弹窗",
|
||||
gameName
|
||||
).apply {
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
package com.gh.gamecenter.gamedetail.dialog
|
||||
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.common.base.fragment.BaseBottomDialogFragment
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.databinding.DialogGameDetailRecyclerViewBinding
|
||||
import com.gh.gamecenter.feature.entity.BigEvent
|
||||
import com.lightgame.utils.AppManager
|
||||
|
||||
class GameBigEventDialogFragment(
|
||||
val gameName: String,
|
||||
val gameId: String,
|
||||
private val bigEvents: List<BigEvent>,
|
||||
private val onLinkClick: (LinkEntity, Int) -> Unit,
|
||||
): BaseBottomDialogFragment<DialogGameDetailRecyclerViewBinding>() {
|
||||
private val adapter by lazy { GameBigEventAdapter(requireContext(), bigEvents, onLinkClick) }
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
mBinding.titleTv.text = "游戏大事件"
|
||||
mBinding.closeIv.setOnClickListener {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
mBinding.recyclerView.run {
|
||||
layoutManager = LinearLayoutManager(requireContext())
|
||||
adapter = this@GameBigEventDialogFragment.adapter
|
||||
(itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
adapter.notifyItemRangeChanged(0, adapter.itemCount)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun show(context: Context?, gameId: String, gameName: String, bigEvents: List<BigEvent>, onLinkClick: (LinkEntity, Int) -> Unit) {
|
||||
val fragmentActivity: FragmentActivity = if (context is FragmentActivity) {
|
||||
context
|
||||
} else if (BuildConfig.DEBUG) {
|
||||
throw IllegalStateException("GameBigEventDialogFragment context must be FragmentActivity")
|
||||
} else {
|
||||
val currentActivity = AppManager.getInstance().currentActivity()
|
||||
if (currentActivity is FragmentActivity) {
|
||||
currentActivity
|
||||
} else {
|
||||
throw IllegalStateException("current activity context must be FragmentActivity")
|
||||
}
|
||||
}
|
||||
|
||||
// 防止重复弹出
|
||||
if (hasDialogInCurrentActivity(fragmentActivity)) return
|
||||
|
||||
val dialogFragment = GameBigEventDialogFragment(gameId, gameName, bigEvents, onLinkClick)
|
||||
dialogFragment.show(fragmentActivity.supportFragmentManager, GameBigEventDialogFragment::class.java.name)
|
||||
}
|
||||
|
||||
private fun hasDialogInCurrentActivity(fragmentActivity: FragmentActivity): Boolean {
|
||||
val fragments: List<Fragment> = fragmentActivity.supportFragmentManager.fragments
|
||||
fragments.forEach { fragment ->
|
||||
if (fragment is GameBigEventDialogFragment) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package com.gh.gamecenter.gamedetail.dialog
|
||||
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.common.base.fragment.BaseBottomDialogFragment
|
||||
import com.gh.gamecenter.databinding.DialogGameDetailScrollableTextBinding
|
||||
import com.lightgame.utils.AppManager
|
||||
|
||||
class GameDetailScrollableTextDialogFragment(
|
||||
val gameName: String,
|
||||
val gameId: String,
|
||||
private val title: String,
|
||||
private val content: String,
|
||||
): BaseBottomDialogFragment<DialogGameDetailScrollableTextBinding>() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
mBinding.closeIv.setOnClickListener {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
mBinding.titleTv.text = title
|
||||
mBinding.contentTv.text = Html.fromHtml(content)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun show(context: Context?, gameId: String, gameName: String, title: String, content: String) {
|
||||
val fragmentActivity: FragmentActivity = if (context is FragmentActivity) {
|
||||
context
|
||||
} else if (BuildConfig.DEBUG) {
|
||||
throw IllegalStateException("GameDetailScrollableTextDialogFragment context must be FragmentActivity")
|
||||
} else {
|
||||
val currentActivity = AppManager.getInstance().currentActivity()
|
||||
if (currentActivity is FragmentActivity) {
|
||||
currentActivity
|
||||
} else {
|
||||
throw IllegalStateException("current activity context must be FragmentActivity")
|
||||
}
|
||||
}
|
||||
|
||||
// 防止重复弹出
|
||||
if (hasDialogInCurrentActivity(fragmentActivity)) return
|
||||
|
||||
val dialogFragment = GameDetailScrollableTextDialogFragment(gameId, gameName, title, content)
|
||||
dialogFragment.show(fragmentActivity.supportFragmentManager, GameDetailScrollableTextDialogFragment::class.java.name)
|
||||
}
|
||||
|
||||
private fun hasDialogInCurrentActivity(fragmentActivity: FragmentActivity): Boolean {
|
||||
val fragments: List<Fragment> = fragmentActivity.supportFragmentManager.fragments
|
||||
fragments.forEach { fragment ->
|
||||
if (fragment is GameDetailScrollableTextDialogFragment) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.gh.gamecenter.gamedetail.dialog
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.toColor
|
||||
import com.gh.gamecenter.databinding.ItemGameDetailFunctionBinding
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailInfoTag
|
||||
import com.lightgame.adapter.BaseRecyclerAdapter
|
||||
|
||||
class GameFunctionAdapter(
|
||||
context: Context,
|
||||
private val infoTags: List<GameDetailInfoTag.InfoTag>
|
||||
) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return GameFunctionItemViewHolder(parent.toBinding())
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = infoTags.size
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
if (holder is GameFunctionItemViewHolder) {
|
||||
holder.binding.root.updateLayoutParams<MarginLayoutParams> {
|
||||
setMargins(0, if (position == 0) 8F.dip2px() else 20F.dip2px(), 0, 0)
|
||||
}
|
||||
|
||||
val infoTag = infoTags.getOrNull(position)
|
||||
ImageUtils.display(holder.binding.iconIv, infoTag?.icon)
|
||||
holder.binding.nameTv.setTextColor(com.gh.gamecenter.common.R.color.text_primary.toColor(mContext))
|
||||
holder.binding.desTv.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(mContext))
|
||||
holder.binding.nameTv.text = infoTag?.name
|
||||
holder.binding.desTv.text = infoTag?.des
|
||||
}
|
||||
}
|
||||
|
||||
class GameFunctionItemViewHolder(var binding: ItemGameDetailFunctionBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
package com.gh.gamecenter.gamedetail.dialog
|
||||
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.common.base.fragment.BaseBottomDialogFragment
|
||||
import com.gh.gamecenter.databinding.DialogGameDetailRecyclerViewBinding
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailInfoTag
|
||||
import com.lightgame.utils.AppManager
|
||||
|
||||
class GameFunctionDialogFragment(
|
||||
val gameName: String,
|
||||
val gameId: String,
|
||||
private val infoTags: List<GameDetailInfoTag.InfoTag>
|
||||
): BaseBottomDialogFragment<DialogGameDetailRecyclerViewBinding>() {
|
||||
private val adapter by lazy { GameFunctionAdapter(requireContext(), infoTags) }
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
mBinding.titleTv.text = "功能说明"
|
||||
mBinding.closeIv.setOnClickListener {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
mBinding.recyclerView.run {
|
||||
layoutManager = LinearLayoutManager(requireContext())
|
||||
adapter = this@GameFunctionDialogFragment.adapter
|
||||
(itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
adapter.notifyItemRangeChanged(0, adapter.itemCount)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun show(context: Context?, gameId: String, gameName: String, infoTags: List<GameDetailInfoTag.InfoTag>) {
|
||||
val fragmentActivity: FragmentActivity = if (context is FragmentActivity) {
|
||||
context
|
||||
} else if (BuildConfig.DEBUG) {
|
||||
throw IllegalStateException("GameFunctionDialogFragment context must be FragmentActivity")
|
||||
} else {
|
||||
val currentActivity = AppManager.getInstance().currentActivity()
|
||||
if (currentActivity is FragmentActivity) {
|
||||
currentActivity
|
||||
} else {
|
||||
throw IllegalStateException("current activity context must be FragmentActivity")
|
||||
}
|
||||
}
|
||||
|
||||
// 防止重复弹出
|
||||
if (hasDialogInCurrentActivity(fragmentActivity)) return
|
||||
|
||||
val dialogFragment = GameFunctionDialogFragment(gameId, gameName, infoTags)
|
||||
dialogFragment.show(fragmentActivity.supportFragmentManager, GameFunctionDialogFragment::class.java.name)
|
||||
}
|
||||
|
||||
private fun hasDialogInCurrentActivity(fragmentActivity: FragmentActivity): Boolean {
|
||||
val fragments: List<Fragment> = fragmentActivity.supportFragmentManager.fragments
|
||||
fragments.forEach { fragment ->
|
||||
if (fragment is GameFunctionDialogFragment) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
package com.gh.gamecenter.gamedetail.dialog
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.databinding.ItemDialogGameInfoOtherBinding
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.detail.viewholder.GameDetailInfoItemViewHolder
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailInfo
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailInfo.InfoItem
|
||||
import com.lightgame.adapter.BaseRecyclerAdapter
|
||||
|
||||
class GameInfoAdapter(
|
||||
context: Context,
|
||||
private val data: GameDetailInfo,
|
||||
private val infoList: List<InfoItem>,
|
||||
private val viewModel: GameDetailViewModel
|
||||
) : BaseRecyclerAdapter<RecyclerView.ViewHolder>(context) {
|
||||
override fun getItemViewType(position: Int): Int = if (position == itemCount - 1) TYPE_OTHER else TYPE_INFO
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return if (viewType == TYPE_INFO) {
|
||||
GameDetailInfoItemViewHolder.InfoItemViewHolder(parent.toBinding())
|
||||
} else {
|
||||
GameInfoDialogOtherViewHolder(parent.toBinding())
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = infoList.size + 1
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
if (holder is GameDetailInfoItemViewHolder.InfoItemViewHolder) {
|
||||
val info = infoList.getOrNull(position) ?: return
|
||||
holder.bindInfoItem(mContext, info)
|
||||
}
|
||||
if (holder is GameInfoDialogOtherViewHolder) {
|
||||
holder.binding.run {
|
||||
GameDetailInfoItemViewHolder.bindStaticInfo(
|
||||
mContext,
|
||||
data,
|
||||
viewModel,
|
||||
privacyPolicyTv,
|
||||
permissionsTv,
|
||||
requestUpdateTv
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GameInfoDialogOtherViewHolder(val binding: ItemDialogGameInfoOtherBinding): RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
companion object {
|
||||
const val TYPE_INFO = 0
|
||||
const val TYPE_OTHER = 0
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
package com.gh.gamecenter.gamedetail.dialog
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.common.base.fragment.BaseBottomDialogFragment
|
||||
import com.gh.gamecenter.common.utils.dip2px
|
||||
import com.gh.gamecenter.common.utils.viewModelProviderFromParent
|
||||
import com.gh.gamecenter.databinding.DialogGameDetailRecyclerViewBinding
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.detail.viewholder.GameDetailInfoItemViewHolder.Companion.normalTypeNameMap
|
||||
import com.gh.gamecenter.gamedetail.entity.GameDetailInfo
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.AppManager
|
||||
|
||||
class GameInfoDialogFragment(
|
||||
val gameEntity: GameEntity?,
|
||||
private val data: GameDetailInfo,
|
||||
): BaseBottomDialogFragment<DialogGameDetailRecyclerViewBinding>() {
|
||||
private val viewModel: GameDetailViewModel by lazy {
|
||||
val factory = GameDetailViewModel.Factory(
|
||||
HaloApp.getInstance().application,
|
||||
gameEntity?.id,
|
||||
gameEntity
|
||||
)
|
||||
viewModelProviderFromParent(factory, gameEntity?.id ?: "")
|
||||
}
|
||||
private val adapter by lazy {
|
||||
val normalTypeKeys = normalTypeNameMap.keys
|
||||
val infoList = data.fields.filter { normalTypeKeys.contains(it.name) }.sortedBy { it.order }
|
||||
GameInfoAdapter(requireContext(), data, infoList, viewModel)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
mBinding.titleTv.text = data.name
|
||||
mBinding.closeIv.setOnClickListener {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
mBinding.recyclerView.run {
|
||||
setPadding(16F.dip2px(), 16F.dip2px(), 16F.dip2px(), 16F.dip2px())
|
||||
layoutManager = LinearLayoutManager(requireContext())
|
||||
adapter = this@GameInfoDialogFragment.adapter
|
||||
(itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDarkModeChanged() {
|
||||
super.onDarkModeChanged()
|
||||
adapter.notifyItemRangeChanged(0, adapter.itemCount)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun show(context: Context?, gameEntity: GameEntity?, data: GameDetailInfo) {
|
||||
val fragmentActivity: FragmentActivity = if (context is FragmentActivity) {
|
||||
context
|
||||
} else if (BuildConfig.DEBUG) {
|
||||
throw IllegalStateException("GameInfoDialogFragment context must be FragmentActivity")
|
||||
} else {
|
||||
val currentActivity = AppManager.getInstance().currentActivity()
|
||||
if (currentActivity is FragmentActivity) {
|
||||
currentActivity
|
||||
} else {
|
||||
throw IllegalStateException("current activity context must be FragmentActivity")
|
||||
}
|
||||
}
|
||||
|
||||
// 防止重复弹出
|
||||
if (hasDialogInCurrentActivity(fragmentActivity)) return
|
||||
|
||||
val dialogFragment = GameInfoDialogFragment(gameEntity, data)
|
||||
dialogFragment.show(fragmentActivity.supportFragmentManager, GameInfoDialogFragment::class.java.name)
|
||||
}
|
||||
|
||||
private fun hasDialogInCurrentActivity(fragmentActivity: FragmentActivity): Boolean {
|
||||
val fragments: List<Fragment> = fragmentActivity.supportFragmentManager.fragments
|
||||
fragments.forEach { fragment ->
|
||||
if (fragment is GameInfoDialogFragment) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,10 +12,8 @@ import androidx.fragment.app.FragmentActivity
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.download.dialog.DownloadDialog
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager
|
||||
import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.view.divider.HorizontalDividerItemDecoration
|
||||
import com.gh.gamecenter.core.utils.DisplayUtils
|
||||
import com.gh.gamecenter.core.utils.MtaHelper
|
||||
@ -82,21 +80,6 @@ class GameTagsDialog : BaseDialogFragment() {
|
||||
tag.name, tag.name, "", "游戏介绍"
|
||||
)
|
||||
)
|
||||
SensorsBridge.trackGameDetailPageGameTagClick(
|
||||
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 = mDownloadStatus,
|
||||
gameType = mGameType,
|
||||
position = position,
|
||||
gameTag = listOf(tag.name),
|
||||
gameTagId = tag.id,
|
||||
)
|
||||
NewLogUtils.logGameDetailTagClick(mGameId, mGameName, tag.id, tag.name, tag.isTop)
|
||||
MtaHelper.onEvent("游戏标签弹窗", "进入标签", "${mGameName}+${tag.name}")
|
||||
}
|
||||
|
||||
@ -4,11 +4,7 @@ import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.view.*
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
@ -20,23 +16,26 @@ import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.ShellActivity
|
||||
import com.gh.gamecenter.ShellActivity.Type
|
||||
import com.gh.gamecenter.databinding.FragmentDialogSpecialDownloadBinding
|
||||
import com.gh.gamecenter.common.base.fragment.BaseDraggableDialogFragment
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.asVGame
|
||||
import com.gh.gamecenter.common.utils.viewModelProviderFromParent
|
||||
import com.gh.gamecenter.core.utils.SpeedUtils
|
||||
import com.gh.gamecenter.databinding.FragmentDialogSpecialDownloadBinding
|
||||
import com.gh.gamecenter.feature.entity.GameDetailServer
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.entity.LibaoEntity
|
||||
import com.gh.gamecenter.feature.entity.MeEntity
|
||||
import com.gh.gamecenter.feature.view.TrapezoidDownloadButton
|
||||
import com.gh.gamecenter.gamedetail.LibaoListFragment
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
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.manager.PackagesManager
|
||||
import com.gh.ndownload.NDownloadService
|
||||
import com.gh.ndownload.suspendwindow.utils.NDownloadSuspendWindowHelper
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.download.DataWatcher
|
||||
import com.lightgame.download.DownloadConfig
|
||||
import com.lightgame.download.DownloadEntity
|
||||
@ -51,6 +50,7 @@ class SpecialDownloadDialogFragment : BaseDraggableDialogFragment() {
|
||||
|
||||
private var viewModel: SpecialDownloadDialogViewModel? = null
|
||||
private var visibilityViewModel: SpecialDownloadVisibilityViewModel? = null
|
||||
private var gameDetailViewModel: GameDetailViewModel? = null
|
||||
|
||||
private var installedVersionMisMatched = false
|
||||
|
||||
@ -139,6 +139,14 @@ class SpecialDownloadDialogFragment : BaseDraggableDialogFragment() {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
boundedGameEntity = arguments?.getParcelable(KEY_GAME_ENTITY)
|
||||
|
||||
val factory = GameDetailViewModel.Factory(
|
||||
HaloApp.getInstance().application,
|
||||
boundedGameEntity?.id,
|
||||
boundedGameEntity
|
||||
)
|
||||
gameDetailViewModel = viewModelProviderFromParent(factory, boundedGameEntity?.id ?: "")
|
||||
|
||||
val installHint = arguments?.getParcelable(KEY_INSTALL_HINT) ?: LinkEntity()
|
||||
|
||||
binding.collapseIv.setOnClickListener {
|
||||
@ -293,12 +301,17 @@ class SpecialDownloadDialogFragment : BaseDraggableDialogFragment() {
|
||||
titleIv.setImageResource(R.drawable.ic_special_download_text_gift)
|
||||
hintTv.setText(getString(R.string.special_download_tips_collect_immediately))
|
||||
subTipsView.setOnClickListener {
|
||||
val bundle = LibaoListFragment.getBundle(
|
||||
boundedGameEntity?.id ?: "",
|
||||
boundedGameEntity?.name ?: "",
|
||||
content.libaoList
|
||||
)
|
||||
startActivity(ShellActivity.getIntent(requireContext(), Type.SIMPLE_LIBAO_LIST, bundle))
|
||||
val tabList = gameDetailViewModel?.gameDetailTabListLiveData?.value?.data
|
||||
if (tabList?.find { it.type == GameDetailTabEntity.TYPE_GIFT } != null) {
|
||||
gameDetailViewModel?.performTabSelected(GameDetailTabEntity.TYPE_GIFT)
|
||||
} else {
|
||||
val bundle = LibaoListFragment.getBundle(
|
||||
boundedGameEntity?.id ?: "",
|
||||
boundedGameEntity?.name ?: "",
|
||||
false
|
||||
)
|
||||
startActivity(ShellActivity.getIntent(requireContext(), Type.SIMPLE_LIBAO_LIST, bundle))
|
||||
}
|
||||
trackEvent(boundedGameEntity!!, "游戏礼包", true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
package com.gh.gamecenter.gamedetail.entity
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.entity.Display
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.entity.ToolBoxEntity
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.feature.entity.GameDetailServer
|
||||
import com.gh.gamecenter.feature.entity.LibaoEntity
|
||||
import com.google.gson.annotations.SerializedName
|
||||
@ -14,39 +11,11 @@ import com.google.gson.annotations.SerializedName
|
||||
class ContentCardEntity(
|
||||
@SerializedName("_id")
|
||||
var id: String = "",
|
||||
var name: String? = "", // tag
|
||||
var title: String? = "",
|
||||
var image: String? = "",
|
||||
@SerializedName("target", alternate = ["link", "link_id"])
|
||||
var link: String? = "",
|
||||
@SerializedName("type", alternate = ["link_type"])
|
||||
var type: String? = "",
|
||||
var icon: String = "",
|
||||
@SerializedName("game_icon")
|
||||
var gameIcon: String? = "",
|
||||
@SerializedName("game_icon_subscript")
|
||||
var gameIconSubscript: String? = "",
|
||||
var text: String? = "",
|
||||
@SerializedName("link_text")
|
||||
var linkText: String? = "",//游戏详情弹窗,兼容旧版本用
|
||||
var value: String? = "",
|
||||
@SerializedName("community_id")
|
||||
var communityId: String? = "",
|
||||
@SerializedName("link_community", alternate = ["community"])
|
||||
var community: CommunityEntity? = CommunityEntity(),
|
||||
var display: Display? = null, // 板块
|
||||
@SerializedName("close_button")
|
||||
var closeButton: String = "open",//用户判断h5游戏关闭按钮是否显示,hide(隐藏)、open(开启)
|
||||
@SerializedName("button_link")
|
||||
var buttonLink: Boolean = false,
|
||||
@SerializedName("activity_id")
|
||||
var activityId: String = "",
|
||||
var style: String = "",
|
||||
|
||||
var des: String = "",
|
||||
var link: LinkEntity = LinkEntity(), // 其中功能类,func_server:游戏开服、func_libao:游戏礼包、func_related_version:相关版本、func_zone:专区、func_tool_kit:工具、func_bbs:论坛、func_archive:云存档
|
||||
var server: GameDetailServer? = null,
|
||||
@SerializedName("mirror_server")
|
||||
var mirrorServer: GameDetailServer? = null,
|
||||
var libao: LibaoEntity? = null,
|
||||
@SerializedName("zone_tab")
|
||||
var zoneTab: Boolean = false,
|
||||
@ -55,7 +24,11 @@ class ContentCardEntity(
|
||||
var toolkit: ArrayList<ToolBoxEntity> = ArrayList(),
|
||||
@SerializedName("func_bbs")
|
||||
val funcBbs: LinkEntity? = null,
|
||||
val dialog: Dialog? = null
|
||||
val archive: Archive? = null,
|
||||
val dialog: Dialog? = null,
|
||||
// 本地字段
|
||||
var showDes: Boolean = true,
|
||||
var showNewTag: Boolean = false,
|
||||
) {
|
||||
|
||||
@Keep
|
||||
@ -66,26 +39,21 @@ class ContentCardEntity(
|
||||
val body: String? = ""
|
||||
)
|
||||
|
||||
fun toLinkEntity(): LinkEntity {
|
||||
return LinkEntity(
|
||||
name = name,
|
||||
title = title,
|
||||
image = image,
|
||||
link = link,
|
||||
type = type,
|
||||
icon = icon,
|
||||
gameIcon = gameIcon,
|
||||
gameIconSubscript = gameIconSubscript,
|
||||
text = text,
|
||||
linkText = linkText,
|
||||
value = value,
|
||||
communityId = communityId,
|
||||
community = community,
|
||||
display = display,
|
||||
closeButton = closeButton,
|
||||
buttonLink = buttonLink,
|
||||
activityId = activityId,
|
||||
style = style
|
||||
)
|
||||
@Keep
|
||||
class Archive(
|
||||
@SerializedName("_id")
|
||||
val id: String = "",
|
||||
val name: String = "",
|
||||
val time: Long = 0L
|
||||
)
|
||||
|
||||
companion object {
|
||||
const val TYPE_GIFT = "func_libao"
|
||||
const val TYPE_SERVER = "func_server"
|
||||
const val TYPE_RELATED_VERSION = "func_related_version"
|
||||
const val TYPE_ZONE = "func_zone"
|
||||
const val TYPE_BBS = "func_bbs"
|
||||
const val TYPE_TOOLKIT = "func_tool_kit"
|
||||
const val TYPE_ARCHIVE = "func_archive"
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,10 @@
|
||||
package com.gh.gamecenter.gamedetail.entity
|
||||
|
||||
data class CoverEntity(
|
||||
var index: Int = -1,
|
||||
var isDefault: Boolean = false,
|
||||
var tabName: String = "",
|
||||
var video: CoverTabEntity.Video? = null,
|
||||
var gallery: CoverTabEntity.Gallery? = null,
|
||||
var coverTabEntity: CoverTabEntity? = null
|
||||
)
|
||||
@ -1,212 +0,0 @@
|
||||
package com.gh.gamecenter.gamedetail.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.Keep
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.feature.entity.*
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Keep
|
||||
class DetailEntity(
|
||||
var type: String = "",
|
||||
@SerializedName("new_notice")
|
||||
var noticeList: ArrayList<LinkEntity>? = null,
|
||||
var des: String? = null,// 介绍文案
|
||||
var gallery: ArrayList<String>? = null,
|
||||
@SerializedName("count")
|
||||
var videoCount: Int = 0,//视频数量
|
||||
var video: ArrayList<Video>? = null,
|
||||
var comment: ArrayList<RatingComment>? = null,
|
||||
var info: GameInfo? = null,
|
||||
var update: UpdateContent? = null,
|
||||
var libao: ArrayList<LibaoEntity>? = null,
|
||||
@SerializedName("related_version")
|
||||
var relatedVersion: ArrayList<RelatedVersion>? = null,
|
||||
var server: GameDetailServer? = null,
|
||||
@SerializedName("image_recommend")
|
||||
var imageRecommend: LinkEntity? = null,
|
||||
@SerializedName("custom_column")
|
||||
var customColumn: CustomColumn? = null,
|
||||
@SerializedName("related_game")
|
||||
var relatedGames: ArrayList<GameDetailRelatedGame>? = null,//原推荐游戏
|
||||
@SerializedName("download_game")
|
||||
var downloadGames: ArrayList<String>? = null,// 下载推荐
|
||||
@SerializedName("install_game")
|
||||
var installGames: ArrayList<String>? = null,// 安装推荐
|
||||
var recommendedGames: SubjectEntity? = null,
|
||||
var article: ArrayList<NewsEntity>? = null,
|
||||
@SerializedName("article_top")
|
||||
var articleTop: ArrayList<NewsEntity>? = null,
|
||||
@SerializedName("recommend_game_list")
|
||||
var recommendGameList: ArrayList<GameDetailRecommendGameEntity>? = null,
|
||||
//专题游戏单推荐
|
||||
@SerializedName("column_id")
|
||||
var columnId: String = "",
|
||||
@SerializedName("title")
|
||||
var columnTitle: String = "",
|
||||
@SerializedName("display.home")
|
||||
var displayHome: String = "",//右上角文案
|
||||
@SerializedName("size.index")
|
||||
var gameCount: Int = 0,//显示多少条数
|
||||
@SerializedName("display.more_link")
|
||||
var moreLink: LinkEntity? = null,
|
||||
@SerializedName("column_game")
|
||||
var columnGames: ArrayList<GameEntity>? = null,
|
||||
|
||||
// 仅用于镜像
|
||||
@SerializedName(value = "new_tag_style")
|
||||
var tagStyle: ArrayList<TagStyleEntity> = ArrayList(),
|
||||
// 仅用于镜像
|
||||
var apk: ArrayList<ApkEntity>? = ArrayList(),
|
||||
// 仅用于镜像
|
||||
@SerializedName("custom_columns")
|
||||
var customColumnList: ArrayList<CustomColumn>? = null,
|
||||
// 仅用于镜像
|
||||
var manufacturer: String? = null,
|
||||
// 仅用于镜像
|
||||
@SerializedName("privacy_policy_url")
|
||||
var privacyPolicyUrl: String? = null,
|
||||
// 仅用于镜像
|
||||
@SerializedName("manufacturer_type")
|
||||
var manufacturerType: String = "",
|
||||
// 仅用于镜像
|
||||
var publisher: String = "",
|
||||
// 仅用于镜像
|
||||
var developer: String = "",
|
||||
// 仅用于镜像
|
||||
var supplier: String = "",
|
||||
// 仅用于镜像
|
||||
@SerializedName("credit_code")
|
||||
var creditCode: String = "",
|
||||
// 仅用于镜像
|
||||
@SerializedName("update_des")
|
||||
var updateDes: String = "",
|
||||
// 仅用于镜像
|
||||
@SerializedName("update_time")
|
||||
var updateTime: Long = 0,
|
||||
// 仅用于镜像
|
||||
@SerializedName("content_card_status")
|
||||
var contentCardStatus: String = "off", //on(生效)/off(不生效)
|
||||
|
||||
@SerializedName("detail_dialogs")
|
||||
var detailDialogs: ArrayList<GameEntity.Dialog> = arrayListOf(),
|
||||
|
||||
// 是否与前一个 item 连成整体,是否与后一个 item 连成整体
|
||||
var shouldBoundWithPreviousItem: Boolean = false,
|
||||
var shouldBoundWithNextItem: Boolean = false,
|
||||
// 上下 padding
|
||||
var paddingTop: Int = 0,
|
||||
var paddingBottom: Int = 0
|
||||
) {
|
||||
|
||||
enum class Type(val value: String) {
|
||||
IMAGE_GALLERY("gallery"),
|
||||
VIDEOS("video"),
|
||||
COMMENTS("comment"),
|
||||
GAME_INFO("info"),
|
||||
UPDATE_CONTENT("update"),
|
||||
LATEST_SERVER("server"),
|
||||
RELATED_VERSION("related_version"),
|
||||
IMAGE("image_recommend"),
|
||||
LIBAO("libao"),
|
||||
INFO_GUIDE("article"),
|
||||
RECOMMENDED_GAMES("related_game"),
|
||||
CUSTOM_COLUMN("custom_column"),
|
||||
DES("des"),
|
||||
NOTICE("notice"),
|
||||
RECOMMEND_GAME_LIST("recommend_game_list"),
|
||||
COLUMN_RECOMMEND("column_recommend"),
|
||||
}
|
||||
}
|
||||
|
||||
@Keep
|
||||
class CustomColumn(
|
||||
@SerializedName("_id")
|
||||
var id: String = "",
|
||||
var name: String = "",
|
||||
@SerializedName("show_name")
|
||||
var showName: Boolean? = true,
|
||||
@SerializedName("name_icon")
|
||||
var nameIcon: String? = "",
|
||||
@SerializedName("name_link")
|
||||
var nameLink: LinkEntity? = null,
|
||||
var link: LinkEntity? = null,
|
||||
var order: Long? = 0, // 权重
|
||||
var title: Title? = null,
|
||||
var des: String? = "",
|
||||
@SerializedName("tag_des")
|
||||
var desFull: String? = null,
|
||||
@SerializedName("tag_des_brief")
|
||||
var desBrief: String? = "",
|
||||
@SerializedName("show_des_type")
|
||||
var showDesType: String? = "",
|
||||
@SerializedName("show_des_row_num")
|
||||
var showDesRowNum: Int? = 3,
|
||||
@SerializedName("show_info_tag")
|
||||
var showInfoTag: Boolean? = false,
|
||||
@SerializedName("show_info_tag_des")
|
||||
var showInfoTagDes: Boolean? = false,
|
||||
@SerializedName("show_info_tag_des_type")
|
||||
var showInfoTagDesType: String? = "", // first_expand (用于默认展开), collapse, expand
|
||||
@SerializedName("info_tag")
|
||||
var infoTag: List<TagEntity>? = listOf(),
|
||||
var time: Long? = 0,
|
||||
|
||||
var isHtmlDes: Boolean? = true,
|
||||
// 是否显示自定义栏目的提示浮窗 (本地字段)
|
||||
var showExpandTagsHint: Boolean? = false
|
||||
)
|
||||
|
||||
@Keep
|
||||
class Title(var icon: String, var value: String, var color: String)
|
||||
|
||||
@Keep
|
||||
class UpdateContent(
|
||||
@SerializedName("history_apk_count")
|
||||
val historyApkCount: Int = 0,
|
||||
@SerializedName("history_apk_status")
|
||||
var historyApkStatus: String = "",
|
||||
@SerializedName("update_des")
|
||||
var updateDes: String = ""
|
||||
)
|
||||
|
||||
@Keep
|
||||
@Parcelize
|
||||
class Video(
|
||||
@SerializedName("_id", alternate = ["video_id"])
|
||||
var videoId: String = "",
|
||||
@SerializedName(
|
||||
"new_video_count",
|
||||
alternate = ["video_count"]
|
||||
) // 选用 JSON 最后一个值作为 videoCount 的值
|
||||
var videoCount: Int = 0,
|
||||
var poster: String = "",
|
||||
var title: String = "",
|
||||
var url: String = "",
|
||||
var user: User? = null,
|
||||
var vote: Int = 0
|
||||
) : Parcelable
|
||||
|
||||
@Keep
|
||||
@Parcelize
|
||||
class RelatedVersion(
|
||||
var first: Boolean = false,
|
||||
var last: Boolean = false,
|
||||
var game: GameEntity? = null,
|
||||
@SerializedName("game_id")
|
||||
var gameId: String = "",
|
||||
@SerializedName("game_name")
|
||||
private var mGameName: String = "",
|
||||
@SerializedName("game_icon")
|
||||
var gameIcon: String = "",
|
||||
@SerializedName(value = "game_tag", alternate = arrayOf("new_game_tag"))
|
||||
var gameTags: ArrayList<TagStyleEntity> = ArrayList(),
|
||||
var index: Int
|
||||
) : Parcelable {
|
||||
@IgnoredOnParcel
|
||||
val gameName: String
|
||||
get() = mGameName.removeSuffix(".")
|
||||
}
|
||||
@ -0,0 +1,462 @@
|
||||
package com.gh.gamecenter.gamedetail.entity
|
||||
|
||||
import com.gh.gamecenter.common.entity.IconFloat
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.entity.PKEntity
|
||||
import com.gh.gamecenter.entity.GameDetailRecommendGameEntity
|
||||
import com.gh.gamecenter.entity.GameDetailRelatedGame
|
||||
import com.gh.gamecenter.entity.RatingComment
|
||||
import com.gh.gamecenter.entity.SubjectEntity
|
||||
import com.gh.gamecenter.feature.entity.*
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
|
||||
data class GameDetailData(
|
||||
var position: Int = -1, // 本地字段
|
||||
var type: String = "",
|
||||
val order: Order = Order(),
|
||||
@SerializedName("link_video_img_area")
|
||||
val linkVideoImgArea: List<CoverTabEntity>? = null,
|
||||
@SerializedName("link_basic_info")
|
||||
val linkBasicInfo: GameEntity? = null,
|
||||
@SerializedName("link_data_info")
|
||||
val linkDataInfo: List<GameDetailDataInfo>? = null,
|
||||
@SerializedName("link_info_tag")
|
||||
val linkInfoTag: GameDetailInfoTag? = null,
|
||||
@SerializedName("link_content_card")
|
||||
val linkContentCard: List<ContentCardEntity>? = null,
|
||||
@SerializedName("link_advertising")
|
||||
val linkAdvertising: GameDetailLink? = null,
|
||||
@SerializedName("link_comprehensive")
|
||||
val linkComprehensive: List<GameDetailComprehensivePanelItem>? = null,
|
||||
@SerializedName("link_drawer")
|
||||
val linkDrawer: GameDetailLinksItem? = null,
|
||||
@SerializedName("link_announcement")
|
||||
val linkAnnouncement: GameDetailLinksItem? = null,
|
||||
@SerializedName("link_game_brief")
|
||||
val linkGameBrief: GameBrief? = null,
|
||||
@SerializedName("link_developer_word")
|
||||
val linkDeveloperWord: DeveloperWord? = null,
|
||||
@SerializedName("link_update")
|
||||
val linkUpdate: GameDetailUpdateContent? = null,
|
||||
@SerializedName("link_custom_column")
|
||||
val linkCustomColumn: GameDetailCustomColumn? = null,
|
||||
@SerializedName("link_comment")
|
||||
val linkComment: GameDetailComment? = null,
|
||||
@SerializedName("link_info")
|
||||
val linkInfo: GameDetailInfo? = null,
|
||||
@SerializedName("link_content_recommend")
|
||||
val linkContentRecommend: LinkEntity? = null,
|
||||
var pkData: PKEntity? = null,
|
||||
@SerializedName("link_game_video")
|
||||
val linkGameVideo: GameDetailVideo? = null,
|
||||
@SerializedName("link_game_guide")
|
||||
val linkGameGuide: GameDetailStrategy? = null,
|
||||
@SerializedName("link_server")
|
||||
val linkServer: GameDetailServer? = null,
|
||||
@SerializedName("link_libao")
|
||||
var linkLibao: ArrayList<LibaoEntity>? = null,
|
||||
@SerializedName("link_related_game")
|
||||
val linkRelatedGame: ArrayList<GameEntity>? = null,
|
||||
@SerializedName("link_image_recommend")
|
||||
val linkImageRecommend: GameDetailRecommendImage? = null,
|
||||
@SerializedName("link_everyone_playing")
|
||||
val linkEveryonePlaying: GameDetailRecommendGame? = null,
|
||||
@SerializedName("link_recommend_game_list")
|
||||
val linkRecommendGameList: ArrayList<GameDetailRecommendGameEntity>? = null,
|
||||
@SerializedName("link_column_recommend")
|
||||
val linkColumnRecommend: List<GameDetailRecommendColumn>? = null,
|
||||
val recommendColumn: GameDetailRecommendColumn? = null,
|
||||
) {
|
||||
val typeChinese
|
||||
get() = when (type) {
|
||||
TYPE_VIDEO_IMG_AREA -> "视频/图片区域"
|
||||
TYPE_BASIC_INFO -> "头部信息"
|
||||
TYPE_DATA_INFO -> "数据信息栏"
|
||||
TYPE_INFO_TAG -> "功能标签"
|
||||
TYPE_CONTENT_CARD -> "内容卡片"
|
||||
TYPE_ADVERTISING -> "广告推荐"
|
||||
TYPE_COMPREHENSIVE -> "综合面板"
|
||||
TYPE_CUSTOM_COLUMN -> "自定义栏目"
|
||||
TYPE_DRAWER -> "抽屉列表"
|
||||
TYPE_ANNOUNCEMENT -> "资讯公告"
|
||||
TYPE_GAME_BRIEF -> "游戏简介"
|
||||
TYPE_DEVELOPER_WORD -> "开发者的话"
|
||||
TYPE_UPDATE -> "更新内容"
|
||||
TYPE_COMMENT -> "玩家评论"
|
||||
TYPE_INFO -> "详情信息"
|
||||
TYPE_CONTENT_RECOMMEND -> "内容推荐(PK组件)"
|
||||
TYPE_GAME_VIDEO -> "游戏视频"
|
||||
TYPE_GAME_GUIDE -> "游戏攻略"
|
||||
TYPE_SERVER -> "游戏开服"
|
||||
TYPE_LIBAO -> "游戏礼包"
|
||||
TYPE_RELATED_GAME -> "相关游戏"
|
||||
TYPE_IMAGE_RECOMMEND -> "图片推荐"
|
||||
TYPE_EVERYONE_PLAYING -> "大家都在玩"
|
||||
TYPE_RECOMMEND_GAME_LIST -> "游戏单推荐"
|
||||
TYPE_COLUMN_RECOMMEND -> "专题推荐"
|
||||
else -> ""
|
||||
}
|
||||
|
||||
fun areItemsTheSame(other: GameDetailData) = type == other.type
|
||||
fun areContentsTheSame(other: GameDetailData) = type == other.type && this == other
|
||||
|
||||
companion object {
|
||||
const val TYPE_VIDEO_IMG_AREA = "video_img_area"
|
||||
const val TYPE_BASIC_INFO = "basic_info"
|
||||
const val TYPE_DATA_INFO = "data_info"
|
||||
const val TYPE_INFO_TAG = "info_tag"
|
||||
const val TYPE_CONTENT_CARD = "content_card"
|
||||
const val TYPE_ADVERTISING = "advertising"
|
||||
const val TYPE_COMPREHENSIVE = "comprehensive"
|
||||
const val TYPE_CUSTOM_COLUMN = "custom_column"
|
||||
const val TYPE_DRAWER = "drawer"
|
||||
const val TYPE_ANNOUNCEMENT = "announcement"
|
||||
const val TYPE_GAME_BRIEF = "game_brief"
|
||||
const val TYPE_DEVELOPER_WORD = "developer_word"
|
||||
const val TYPE_UPDATE = "update"
|
||||
const val TYPE_COMMENT = "comment"
|
||||
const val TYPE_INFO = "info"
|
||||
const val TYPE_CONTENT_RECOMMEND = "content_recommend"
|
||||
const val TYPE_GAME_VIDEO = "game_video"
|
||||
const val TYPE_GAME_GUIDE = "game_guide"
|
||||
const val TYPE_SERVER = "server"
|
||||
const val TYPE_LIBAO = "libao"
|
||||
const val TYPE_RELATED_GAME = "related_game"
|
||||
const val TYPE_IMAGE_RECOMMEND = "image_recommend"
|
||||
const val TYPE_EVERYONE_PLAYING = "everyone_playing"
|
||||
const val TYPE_RECOMMEND_GAME_LIST = "recommend_game_list"
|
||||
const val TYPE_COLUMN_RECOMMEND = "column_recommend"
|
||||
}
|
||||
}
|
||||
|
||||
data class Order(
|
||||
@SerializedName("before_download")
|
||||
val beforeDownload: Int = -1, // 下载前排序
|
||||
val installed: Int = -1, // 已安装排序
|
||||
val updateable: Int = -1, // 可更新排序
|
||||
)
|
||||
|
||||
data class CoverTabEntity(
|
||||
@SerializedName("_id")
|
||||
var id: String = "",
|
||||
@SerializedName("game_id")
|
||||
var gameId: String = "",
|
||||
var name: String = "",
|
||||
var type: String = "", // tab显示内容(图集:gallery、视频:video)
|
||||
var select: Boolean = false, // 是否默认选中
|
||||
@SerializedName("video_link")
|
||||
var video: Video? = null,
|
||||
@SerializedName("gallery_info")
|
||||
var gallery: List<Gallery>? = null,
|
||||
) {
|
||||
data class Gallery(
|
||||
var url: String = "",
|
||||
var width: String = "",
|
||||
var height: String = "",
|
||||
)
|
||||
|
||||
data class Video(
|
||||
@SerializedName("_id", alternate = ["video_id"])
|
||||
var videoId: String = "",
|
||||
var poster: String = "",
|
||||
var title: String = "",
|
||||
var url: String = "",
|
||||
)
|
||||
}
|
||||
|
||||
data class GameDetailDataInfo(
|
||||
val name: String = "", // 字段(ranking:榜单排名、size:游戏大小、recommend_age:适龄提示、language:语言、internet_app:需要联网、real_name:游戏内实名)
|
||||
@SerializedName("name_cn")
|
||||
val nameCn: String = "", // 字段中文
|
||||
val value: String = "", // 字段值
|
||||
|
||||
val ranking: Ranking? = null, // 榜单排名
|
||||
val size: String = "", // 游戏大小
|
||||
@SerializedName("recommend_age")
|
||||
val recommendAge: String = "", // 适龄等级
|
||||
val language: String = "", // 语言
|
||||
@SerializedName("internet_app")
|
||||
val internetApp: String = "", // 是否联网
|
||||
@SerializedName("real_name")
|
||||
val realName: RealName? = null // 实名
|
||||
) {
|
||||
data class Ranking(
|
||||
@SerializedName("collection_id")
|
||||
val collectionId: String = "", // 专题合集ID
|
||||
@SerializedName("collection_name")
|
||||
val collectionName: String = "", // 专题合集名称
|
||||
@SerializedName("column_id")
|
||||
val columnId: String = "", // 专题ID
|
||||
@SerializedName("column_name")
|
||||
val columnName: String = "", // 专题名称
|
||||
val no: Int = -1 // 名次
|
||||
)
|
||||
|
||||
data class RealName(
|
||||
val state: String = "", // 是否需要游戏内实名
|
||||
@SerializedName("certification_screenshot")
|
||||
val certificationScreenshot: String = "" // 实名认证截图
|
||||
)
|
||||
}
|
||||
|
||||
data class GameDetailInfoTag(
|
||||
@SerializedName("info_tags")
|
||||
val infoTags: List<InfoTag> = listOf(), // 功能标签
|
||||
@SerializedName("request_speed_status")
|
||||
val requestSpeedStatus: String = "" // 求加速状态, on/off
|
||||
) {
|
||||
data class InfoTag(
|
||||
val name: String = "", // 功能名称
|
||||
val des: String = "", // 功能说明
|
||||
val icon: String = "", // icon
|
||||
val color: String = "" // 颜色
|
||||
)
|
||||
}
|
||||
|
||||
data class GameDetailLink(
|
||||
val title: String = "", // 标题
|
||||
@SerializedName("component_icon")
|
||||
val componentIcon: ComponentIcon? = null, // 组件图标
|
||||
val img: String = "", // 图片
|
||||
@SerializedName("img_scale")
|
||||
val imgScale: String = "", // 图片比例,2:1、4:1
|
||||
val text: String = "", // 跳转文案
|
||||
val link: LinkEntity? = null // 跳转链接
|
||||
) {
|
||||
data class ComponentIcon(
|
||||
@SerializedName("_id")
|
||||
val id: String = "",
|
||||
val name: String = "",
|
||||
val icon: String = ""
|
||||
)
|
||||
}
|
||||
|
||||
data class GameDetailComprehensivePanelItem(
|
||||
val title: String = "", // 标题
|
||||
val type: String = "", // 板块类型(function:功能列表、FAQ:常见问题、declaration:声明信息)
|
||||
@SerializedName("show_title")
|
||||
val showTitle: Boolean = true, // 是否显示此标题(true:显示、false:隐藏)
|
||||
@SerializedName("function_type")
|
||||
val functionType: String = "", // 功能列表类型,type=function,(one_line_one_point:一行一分点、one_line_two_points:一行两分点)
|
||||
@SerializedName("show_type")
|
||||
val showType: String = "", // function_type=one_line_one_point, 一行一分点-显示内容(part:部分展开、all:展开全部)
|
||||
@SerializedName("show_row_num")
|
||||
val showRowNum: Int = 0, // show_type=part,一行一分点-显示内容-部分展开,填写展示分点数
|
||||
val data: List<ContentData>? = null, // 功能列表/常见问题 内容数据
|
||||
val declaration: String = "" // type=declaration时,才有此字段数据
|
||||
) {
|
||||
data class ContentData(
|
||||
val text: String = "", // 文案/分点内容
|
||||
val link: LinkEntity? = null // 跳转链接,type=FAQ时填写
|
||||
)
|
||||
|
||||
companion object {
|
||||
const val TYPE_FUNCTION = "function"
|
||||
const val TYPE_FAQ = "FAQ"
|
||||
const val TYPE_DECLARATION = "declaration"
|
||||
const val FUNCTION_TYPE_ONE_LINE_ONE_POINT = "one_line_one_point"
|
||||
const val FUNCTION_TYPE_ONE_LINE_TWO_POINTS = "one_line_two_points"
|
||||
const val SHOW_TYPE_PART = "part"
|
||||
const val SHOW_TYPE_ALL = "all"
|
||||
}
|
||||
}
|
||||
|
||||
data class GameDetailLinksItem(
|
||||
val name: String = "", // 标题
|
||||
@SerializedName("show_name")
|
||||
val showName: Boolean = true, // app是否显示组件标题(true:显示、false:隐藏)
|
||||
val data: List<GameDetailLink> = listOf()
|
||||
)
|
||||
|
||||
data class GameBrief(
|
||||
val name: String = "", // 组件标题
|
||||
@SerializedName("game_tags")
|
||||
val gameTags: List<GameTag> = listOf(), // 游戏标签
|
||||
val des: String = "", // 游戏介绍
|
||||
@SerializedName("award_data")
|
||||
val awardData: List<AwardData> = listOf() // 奖项数据
|
||||
) {
|
||||
data class GameTag(
|
||||
@SerializedName("_id")
|
||||
val id: String = "",
|
||||
@SerializedName("_seq")
|
||||
val seq: Int = 0,
|
||||
val name: String = "", // 功能名称
|
||||
val color: String = "", // 标签颜色
|
||||
val background: String = "", // 标签背景
|
||||
val column: String = "", // 排行榜专题标签颜色
|
||||
@SerializedName("is_top")
|
||||
val isTop: Boolean = false
|
||||
)
|
||||
|
||||
data class AwardData(
|
||||
val icon: String = "", // 图标
|
||||
val award: String = "", // 奖项名称
|
||||
@SerializedName("award_type")
|
||||
val awardType: String = "", // 奖项类别
|
||||
val link: LinkEntity? = null // 通用链接
|
||||
)
|
||||
}
|
||||
|
||||
data class GameDetailCustomColumn(
|
||||
val name: String = "", // 组件标题
|
||||
@SerializedName("show_name")
|
||||
val showName: Boolean = true, // 是否展示组件标题
|
||||
val img: String = "", // 图片
|
||||
@SerializedName("title_info")
|
||||
val titleInfo: TitleInfo? = null, // 栏目标题数据
|
||||
@SerializedName("right_top_info")
|
||||
val rightTopInfo: RightTopInfo? = null, // 右上角数据
|
||||
@SerializedName("second_title_info")
|
||||
val secondTitleInfo: SecondTitleInfo? = null, // 二级标题数据
|
||||
@SerializedName("show_des_type")
|
||||
val showDesType: String = "", // 显示内容(part:控制行数、all:展开全部)
|
||||
@SerializedName("show_des_row_num")
|
||||
val showDesRowNum: Int = 0, // 控制行数
|
||||
@SerializedName("tag_des")
|
||||
val tagDes: String = "" // 正文说明
|
||||
) {
|
||||
data class TitleInfo(
|
||||
val icon: String = "", // 栏目标题前图标
|
||||
@SerializedName("icon_subscript")
|
||||
val iconSubscript: String = "", // 栏目标题前图标
|
||||
@SerializedName("icon_float")
|
||||
var iconFloat: IconFloat? = null,
|
||||
val title: String = "", // 栏目标题
|
||||
@SerializedName("show_title")
|
||||
val showTitle: Boolean = true, // 是否显示栏目标题
|
||||
val text: String = "", // 栏目标题后文案
|
||||
val link: LinkEntity? = null // 标题后文案跳转链接
|
||||
)
|
||||
|
||||
data class RightTopInfo(
|
||||
val icon: String = "", // 右上角图标
|
||||
val style: String = "", // 文案样式(text:文本、button:按钮)
|
||||
val text: String = "", // 右上角文案
|
||||
val link: LinkEntity? = null // 右上角文案跳转链接
|
||||
) {
|
||||
companion object {
|
||||
const val TYPE_TEXT = "text"
|
||||
const val TYPE_BUTTON = "button"
|
||||
}
|
||||
}
|
||||
|
||||
data class SecondTitleInfo(
|
||||
val icon: String = "", // 二级标题前图标
|
||||
@SerializedName("show_title")
|
||||
val showTitle: Boolean = true, // 是否显示二级标题
|
||||
val text: String = "", // 二级标题内容
|
||||
val color: String = "" // 二级标题颜色
|
||||
)
|
||||
|
||||
companion object {
|
||||
const val SHOW_DES_TYPE_PART = "part"
|
||||
const val SHOW_DES_TYPE_ALL = "all"
|
||||
}
|
||||
}
|
||||
|
||||
data class DeveloperWord(
|
||||
val name: String = "",
|
||||
val text: String = "",
|
||||
)
|
||||
|
||||
data class GameDetailUpdateContent(
|
||||
val name: String = "",
|
||||
@SerializedName("history_apk_count")
|
||||
val historyApkCount: Int = 0,
|
||||
@SerializedName("history_apk_status")
|
||||
var historyApkStatus: String = "",
|
||||
@SerializedName("update_des")
|
||||
var updateDes: String = ""
|
||||
)
|
||||
|
||||
data class GameDetailComment(
|
||||
val name: String = "",
|
||||
val data: ArrayList<RatingComment> = arrayListOf()
|
||||
)
|
||||
|
||||
data class GameDetailInfo(
|
||||
val name: String = "",
|
||||
var fields: List<InfoItem> = listOf(),
|
||||
val des: String = ""
|
||||
) {
|
||||
data class InfoItem(
|
||||
val name: String = "",
|
||||
val value: String = "",
|
||||
@SerializedName("is_first")
|
||||
val isFirst: Boolean = true, // 是否显示在一级页面
|
||||
val order: Int = -1, // 排序
|
||||
val permissions: List<Permission>? = null
|
||||
)
|
||||
}
|
||||
|
||||
data class GameDetailVideo(
|
||||
val video: List<Video> = listOf(), // 视频列表
|
||||
val count: Int = 0 // 视频数量
|
||||
) {
|
||||
data class Video(
|
||||
@SerializedName("_id")
|
||||
val id: String = "",
|
||||
val poster: String = "", // 封面图
|
||||
val title: String = "",
|
||||
val url: String = "",
|
||||
val user: User? = null,
|
||||
val vote: Int = 0 // 点赞数
|
||||
)
|
||||
}
|
||||
|
||||
data class GameDetailStrategy(
|
||||
val name: String = "", // 组件标题
|
||||
@SerializedName("right_top")
|
||||
val rightTop: String = "", // 右上角文案(more:更多、link:攻略链接)
|
||||
@SerializedName("article_types")
|
||||
val articleTypes: List<String> = listOf(), // 游戏文章类型
|
||||
@SerializedName("article_top")
|
||||
val articleTop: List<NewsEntity> = listOf(), // 置顶文章
|
||||
val data: List<StrategyData> = listOf() // 文章数据
|
||||
) {
|
||||
data class StrategyData(
|
||||
val type: String = "", // 文章类型
|
||||
@SerializedName("link_article")
|
||||
val linkArticle: NewsEntity? = null, // 游戏文章
|
||||
@SerializedName("link_community_article")
|
||||
val linkCommunityArticle: ArticleEntity? = null, // 社区文章
|
||||
val isFixedTop: Boolean = false // 本地字段,是否置顶
|
||||
)
|
||||
}
|
||||
|
||||
data class GameDetailRecommendImage(
|
||||
val title: String = "",
|
||||
val img: String = "",
|
||||
val link: LinkEntity? = null
|
||||
)
|
||||
|
||||
data class GameDetailRecommendGame(
|
||||
@SerializedName("related_game")
|
||||
var relatedGames: ArrayList<GameDetailRelatedGame>? = null,//原推荐游戏
|
||||
@SerializedName("download_game")
|
||||
var downloadGames: ArrayList<String>? = null,// 下载推荐
|
||||
@SerializedName("install_game")
|
||||
var installGames: ArrayList<String>? = null,// 安装推荐
|
||||
var recommendedGames: SubjectEntity? = null,
|
||||
)
|
||||
|
||||
data class GameDetailRecommendColumn(
|
||||
@SerializedName("column_id")
|
||||
var columnId: String = "",
|
||||
@SerializedName("title")
|
||||
var columnTitle: String = "",
|
||||
@SerializedName("display.home")
|
||||
var displayHome: String = "",//右上角文案
|
||||
@SerializedName("size.index")
|
||||
var gameCount: Int = 0,//显示多少条数
|
||||
@SerializedName("display.more_link")
|
||||
var moreLink: LinkEntity? = null,
|
||||
@SerializedName("column_game")
|
||||
var columnGames: ArrayList<GameEntity>? = null,
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
package com.gh.gamecenter.gamedetail.entity
|
||||
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.entity.SimpleGame
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class GameDetailSetting(
|
||||
@SerializedName("download_position_link")
|
||||
val downloadPositionLink: LinkEntity? = null, // 触发下载定位
|
||||
@SerializedName("update_download_position_link")
|
||||
val updateDownloadPositionLink: LinkEntity? = null, // 触发更新下载定位
|
||||
@SerializedName("_seq")
|
||||
val shortId: String = "",
|
||||
@SerializedName("appointment_switch_status")
|
||||
var appointmentSwitchStatus: Boolean = false,
|
||||
@SerializedName("smooth_relation_game")
|
||||
var smoothRelatedGame: SimpleGame? = null,
|
||||
@SerializedName("detail_dialogs")
|
||||
var detailDialogs: ArrayList<GameEntity.Dialog> = arrayListOf(),
|
||||
val item: List<GameDetailItemSetting> = listOf() // 组件设置
|
||||
) {
|
||||
class GameDetailItemSetting(
|
||||
val type: String = "",
|
||||
val order: Order = Order(),
|
||||
)
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.gh.gamecenter.gamedetail.entity
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
@Keep
|
||||
data class GameDetailTabEntity(
|
||||
@SerializedName("_id")
|
||||
var id: String = "",
|
||||
var name: String = "",
|
||||
var type: String = "", // tab类型(game_detail:详情、comment:评论、archive:云存档、bbs:论坛、zone:专区、web:web链接、libao:礼包、custom_page:自定义页面)
|
||||
@SerializedName("archive_config_url")
|
||||
var archiveConfigUrl: String = "", // type=archive时,才有此云存档配置
|
||||
var link: LinkEntity? = null, // 只有:论坛、web链接、自定义页面,才有此字段数据
|
||||
@SerializedName("default_data")
|
||||
var defaultData: List<GameDetailData>? = null, // type=game_detail时,才有默认数据
|
||||
) {
|
||||
companion object {
|
||||
const val TYPE_DETAIL = "game_detail"
|
||||
const val TYPE_COMMENT = "comment"
|
||||
const val TYPE_ARCHIVE = "archive"
|
||||
const val TYPE_BBS = "bbs"
|
||||
const val TYPE_ZONE = "zone"
|
||||
const val TYPE_WEB = "web"
|
||||
const val TYPE_GIFT = "libao"
|
||||
const val TYPE_CUSTOM_PAGE = "custom_page"
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
package com.gh.gamecenter.gamedetail.entity
|
||||
|
||||
import androidx.annotation.Keep
|
||||
|
||||
@Keep
|
||||
class GameInfoItemData(
|
||||
var info: String = "",
|
||||
var title: String = "",
|
||||
var actionStr: String = "",
|
||||
var action2Str: String = "",
|
||||
var key: String = ""
|
||||
)
|
||||
@ -1,98 +0,0 @@
|
||||
package com.gh.gamecenter.gamedetail.entity
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.feature.entity.*
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
@Keep
|
||||
class NewGameDetailEntity(
|
||||
@SerializedName("show_comment")
|
||||
var showComment: Boolean = false,//游戏评论开关
|
||||
@SerializedName("direct_comment")
|
||||
var directComment: Boolean = false,//安装游戏才能评论
|
||||
var star: Float = 0f,
|
||||
@SerializedName("comment_count")
|
||||
var commentCount: Int = 0,
|
||||
var ranking: Ranking? = null,// 游戏榜单排名,无排名时,字段不存在
|
||||
@SerializedName("top_video")
|
||||
var topVideo: Video? = null,
|
||||
@SerializedName("me")
|
||||
var me: MeEntity? = null,
|
||||
var event: BigEvent? = null,//游戏大事件
|
||||
@SerializedName("detail_dialogs")
|
||||
var detailDialogs: ArrayList<GameEntity.Dialog> = arrayListOf(),
|
||||
@SerializedName("new_tag_style")
|
||||
var tagStyle: ArrayList<TagStyleEntity> = ArrayList(),
|
||||
@SerializedName("detail_tab")
|
||||
var detailEntity: ArrayList<DetailEntity> = ArrayList(),
|
||||
@SerializedName("zone_tab")
|
||||
var zone: ZoneEntity? = null,
|
||||
@SerializedName("appointment_switch_status")
|
||||
var appointmentSwitchStatus: Boolean = false,
|
||||
@SerializedName("recommend_age")
|
||||
var recommendAge: String = "",//适龄等级
|
||||
@SerializedName("_seq")
|
||||
val shortId: String = "",
|
||||
|
||||
@SerializedName("mirror_status")
|
||||
var mirrorStatus: String? = "",
|
||||
@SerializedName("mirror_data")
|
||||
var mirrorData: DetailEntity? = null,
|
||||
@SerializedName("mirror_status2")
|
||||
var mirrorStatus2: String? = "",
|
||||
@SerializedName("mirror_data2")
|
||||
var mirrorData2: DetailEntity? = null,
|
||||
@SerializedName("bbs_tab")
|
||||
var bbsTab: LinkEntity? = null,
|
||||
@SerializedName("certification_tag")
|
||||
var certificateTag: Screenshot? = null,
|
||||
@SerializedName("content_card")
|
||||
var contentCard: ArrayList<ContentCardEntity> = ArrayList(),
|
||||
|
||||
@SerializedName("smooth_relation_game")
|
||||
var smoothRelatedGame: SimpleGame? = null,
|
||||
|
||||
@SerializedName("show_archive")
|
||||
var showArchive: Boolean = false, //云存档开关
|
||||
@SerializedName("archive_tab")
|
||||
var archiveTab: ArchiveTab = ArchiveTab(),
|
||||
|
||||
@SerializedName("new_notice")
|
||||
var newNotice: ArrayList<LinkEntity>? = null,
|
||||
) {
|
||||
fun isShowContentCard(gameEntity: GameEntity?): Boolean {
|
||||
return contentCard.size > 1 && (gameEntity?.shouldUseMirrorInfo() == false || (gameEntity?.shouldUseMirrorInfo() == true && mirrorData?.contentCardStatus == "on"))
|
||||
}
|
||||
}
|
||||
|
||||
@Keep
|
||||
class Ranking(
|
||||
@SerializedName("collection_id")
|
||||
var collectionId: String = "",//合集id
|
||||
@SerializedName("collection_name")
|
||||
var collectionName: String = "",//合集名称
|
||||
@SerializedName("column_id")
|
||||
var columnId: String = "",//专题id
|
||||
@SerializedName("column_name")
|
||||
var columnName: String = "",// 专题标题
|
||||
var no: String = ""// 排名名次
|
||||
)
|
||||
|
||||
@Keep
|
||||
class BigEvent(
|
||||
var time: Long = 0,
|
||||
var content: String = "",
|
||||
@SerializedName("high_light")
|
||||
var highLight: Boolean = false,
|
||||
var link: LinkEntity? = null
|
||||
)
|
||||
|
||||
@Keep
|
||||
class Screenshot(var screenshot: String = "")
|
||||
|
||||
@Keep
|
||||
class ArchiveTab(@SerializedName("config_url") var configUrl: String = "")
|
||||
|
||||
|
||||
@ -2,8 +2,6 @@ package com.gh.gamecenter.gamedetail.fuli
|
||||
|
||||
import android.content.Intent
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.ethanhua.skeleton.Skeleton
|
||||
@ -14,13 +12,16 @@ import com.gh.gamecenter.common.base.fragment.LazyFragment
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.eventbus.EBReuse
|
||||
import com.gh.gamecenter.common.mvvm.Status
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
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.databinding.FragmentFuliBinding
|
||||
import com.gh.gamecenter.eventbus.EBTypeChange
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.gamedetail.GameDetailFragment
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.GameDetailWrapperFragment
|
||||
import com.halo.assistant.HaloApp
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
@ -73,11 +74,11 @@ class FuLiFragment : LazyFragment(), IScrollable {
|
||||
mFuLiViewModel?.updateGameEntity(gameEntity)
|
||||
}
|
||||
|
||||
mGameDetailViewModel?.gameDetailLiveData?.value?.data?.zone?.let {
|
||||
mGameDetailViewModel?.game?.zone?.let {
|
||||
mFuLiViewModel?.updateUnifiedGameDetailEntity(it)
|
||||
}
|
||||
|
||||
mFuLiViewModel?.fuFiDataLD?.observe(this, Observer {
|
||||
mFuLiViewModel?.fuFiDataLD?.observe(this) {
|
||||
mViewSkeletonScreen.hide()
|
||||
mBinding?.loadingContainer?.reuseLlLoading?.visibility = View.GONE
|
||||
|
||||
@ -86,19 +87,16 @@ class FuLiFragment : LazyFragment(), IScrollable {
|
||||
mAdapter?.notifyDataSetChanged()
|
||||
} else {
|
||||
mBinding?.containerRl?.setBackgroundColor(
|
||||
ContextCompat.getColor(
|
||||
requireContext(),
|
||||
com.gh.gamecenter.common.R.color.ui_surface
|
||||
com.gh.gamecenter.common.R.color.ui_surface.toColor(
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
mBinding?.reuseNoneData?.root?.visibility = View.VISIBLE
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
mGameDetailViewModel?.unifiedGameDetailWithUserRelatedInfoForChildLiveData?.observeNonNull(this) { entity ->
|
||||
entity.zone?.let {
|
||||
mFuLiViewModel?.updateUnifiedGameDetailEntity(it)
|
||||
}
|
||||
mGameDetailViewModel?.zoneLiveData?.observeNonNull(this) {
|
||||
mFuLiViewModel?.updateUnifiedGameDetailEntity(it)
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,7 +125,7 @@ class FuLiFragment : LazyFragment(), IScrollable {
|
||||
.show()
|
||||
mAdapter = FuLiAdapter(requireContext(), mFuLiViewModel, mEntrance)
|
||||
mBinding?.fmFuliRv?.adapter = mAdapter
|
||||
layoutManager = object : androidx.recyclerview.widget.LinearLayoutManager(context) {
|
||||
layoutManager = object : LinearLayoutManager(context) {
|
||||
override fun canScrollVertically(): Boolean {
|
||||
return isCanScroll
|
||||
}
|
||||
@ -137,7 +135,7 @@ class FuLiFragment : LazyFragment(), IScrollable {
|
||||
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))
|
||||
EventBus.getDefault().post(EBTypeChange(GameDetailWrapperFragment.EB_SCROLLING, 0))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -3,10 +3,10 @@ package com.gh.gamecenter.gamedetail.fuli
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.mvvm.Resource
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.entity.ZoneContentEntity
|
||||
import com.gh.gamecenter.feature.entity.ZoneEntity
|
||||
import com.gh.gamecenter.common.mvvm.Resource
|
||||
|
||||
class FuLiViewModel : ViewModel() {
|
||||
|
||||
@ -21,7 +21,7 @@ class FuLiViewModel : ViewModel() {
|
||||
|
||||
fun updateUnifiedGameDetailEntity(zoneEntity: ZoneEntity) {
|
||||
if (zoneEntity.style == "default") {
|
||||
if (!zoneEntity.content.isNullOrEmpty()) {
|
||||
if (zoneEntity.content.isNotEmpty()) {
|
||||
fuFiDataLD.postValue(Resource.success(zoneEntity.content))
|
||||
} else {//无内容
|
||||
fuFiDataLD.postValue(Resource.error(null))
|
||||
|
||||
@ -1,34 +1,31 @@
|
||||
package com.gh.gamecenter.gamedetail.history
|
||||
|
||||
import android.content.Context
|
||||
import android.util.SparseBooleanArray
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.g00fy2.versioncompare.Version
|
||||
import com.gh.gamecenter.common.constant.ItemViewType
|
||||
import com.gh.gamecenter.feature.exposure.ExposureEvent
|
||||
import com.gh.common.exposure.IExposable
|
||||
import com.gh.common.util.*
|
||||
import com.gh.gamecenter.feature.view.DownloadButton
|
||||
import com.gh.common.util.DownloadItemUtils
|
||||
import com.gh.common.util.PackageUtils
|
||||
import com.gh.common.xapk.XapkInstaller
|
||||
import com.gh.common.xapk.XapkUnzipStatus
|
||||
import com.gh.download.DownloadManager
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.baselist.ListAdapter
|
||||
import com.gh.gamecenter.common.constant.ItemViewType
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.common.utils.DialogHelper
|
||||
import com.gh.gamecenter.core.utils.TimeUtils
|
||||
import com.gh.gamecenter.common.utils.getMetaExtra
|
||||
import com.gh.gamecenter.common.utils.setRootBackgroundColor
|
||||
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.ItemHistoryApkBinding
|
||||
import com.gh.gamecenter.feature.entity.ApkEntity
|
||||
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.gamedetail.dialog.GameDetailScrollableTextDialogFragment
|
||||
import com.gh.gamecenter.manager.PackagesManager
|
||||
import com.lightgame.download.DownloadEntity
|
||||
import com.lightgame.download.DownloadStatus
|
||||
@ -42,10 +39,6 @@ class HistoryApkListAdapter(
|
||||
|
||||
private val mBasicExposureSource by lazy { ExposureSource("历史版本", "") }
|
||||
|
||||
private var mExpandSparseBooleanArray = SparseBooleanArray()
|
||||
private var mDescExpandedMarginRight = -1
|
||||
private var mDescShrankMarginRight = -1
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val view: View
|
||||
return when (viewType) {
|
||||
@ -62,25 +55,26 @@ class HistoryApkListAdapter(
|
||||
is HistoryApkViewHolder -> {
|
||||
val gameEntity = mEntityList[position]
|
||||
val apkEntity = gameEntity.getApk().first()
|
||||
val maxDesLines = if (mExpandSparseBooleanArray.get(holder.adapterPosition)) Int.MAX_VALUE else 3
|
||||
|
||||
val exposureEvent =
|
||||
ExposureEvent.createEvent(gameEntity = gameEntity, source = listOf(mBasicExposureSource))
|
||||
|
||||
holder.binding.root.setRootBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface)
|
||||
holder.binding.expandTv.background = R.drawable.bg_ui_surface_expand_gradient.toDrawable(mContext)
|
||||
holder.binding.expandTv.setTextColor(com.gh.gamecenter.common.R.color.text_theme.toColor(mContext))
|
||||
holder.binding.updateDescTv.text = apkEntity.updateDesc
|
||||
holder.binding.updateDescTv.post {
|
||||
holder.binding.expandTv.isVisible = holder.binding.updateDescTv.lineCount == 3 && holder.binding.updateDescTv.layout.getEllipsisCount(2) > 0
|
||||
}
|
||||
holder.binding.versionTv.text = "版本${apkEntity.version}"
|
||||
holder.binding.updateDescTv.setExpandMaxLines(maxDesLines)
|
||||
holder.binding.updateDescTv.setIsExpanded(maxDesLines == Int.MAX_VALUE)
|
||||
holder.binding.releaseDateTv.text = TimeUtils.getFormatTime(apkEntity.updateTime)
|
||||
holder.binding.updateDescTv.setExpandCallback {
|
||||
mExpandSparseBooleanArray.put(holder.adapterPosition, true)
|
||||
updateDescMarginRight(
|
||||
holder.binding.updateDescTv,
|
||||
mExpandSparseBooleanArray.get(holder.adapterPosition),
|
||||
holder.binding.downloadBtn.visibility == View.VISIBLE
|
||||
holder.binding.expandTv.setOnClickListener {
|
||||
GameDetailScrollableTextDialogFragment.show(
|
||||
mContext,
|
||||
gameEntity.id,
|
||||
gameEntity.name ?: "",
|
||||
"更新说明",
|
||||
apkEntity.updateDesc
|
||||
)
|
||||
MtaHelper.onEvent("历史版本", "展开", "${mViewModel.game?.name}+${apkEntity.version}")
|
||||
}
|
||||
holder.binding.downloadBtn.run {
|
||||
setOnTouchListener { _, event ->
|
||||
@ -155,34 +149,10 @@ class HistoryApkListAdapter(
|
||||
text = downloadText
|
||||
}
|
||||
}
|
||||
updateDescMarginRight(
|
||||
holder.binding.updateDescTv,
|
||||
mExpandSparseBooleanArray.get(holder.adapterPosition),
|
||||
holder.binding.downloadBtn.visibility == View.VISIBLE
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// damn, 设计师说要存在下载按钮和不存在下载按钮时有不一样的收起/展开效果
|
||||
private fun updateDescMarginRight(descTv: TextView, isExpanded: Boolean, isDownloadBtnVisible: Boolean) {
|
||||
if (mDescExpandedMarginRight == -1) {
|
||||
mDescExpandedMarginRight = 0
|
||||
mDescShrankMarginRight =
|
||||
mContext.resources.getDimension(com.gh.gamecenter.common.R.dimen.history_apk_desc_shrank_margin_right).toInt()
|
||||
}
|
||||
|
||||
val constraintSet = ConstraintSet()
|
||||
constraintSet.clone(descTv.parent as ConstraintLayout)
|
||||
|
||||
if (!isDownloadBtnVisible || isExpanded) {
|
||||
constraintSet.setMargin(descTv.id, ConstraintSet.RIGHT, mDescExpandedMarginRight)
|
||||
} else {
|
||||
constraintSet.setMargin(descTv.id, ConstraintSet.RIGHT, mDescShrankMarginRight)
|
||||
}
|
||||
constraintSet.applyTo(descTv.parent as ConstraintLayout)
|
||||
}
|
||||
|
||||
private fun souldShowDowngradeDialog(apkEntity: ApkEntity, btnText: CharSequence): Boolean {
|
||||
when (btnText) {
|
||||
"下载" -> MtaHelper.onEvent("历史版本", "下载", "${mViewModel.game?.name}_${apkEntity.version}")
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
package com.gh.gamecenter.gamedetail.libao
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.baselist.ListAdapter
|
||||
import com.gh.gamecenter.common.constant.ItemViewType
|
||||
import com.gh.gamecenter.common.utils.toBinding
|
||||
import com.gh.gamecenter.common.viewholder.FooterViewHolder
|
||||
import com.gh.gamecenter.feature.entity.LibaoEntity
|
||||
import com.gh.gamecenter.gamedetail.detail.GameLibaoAdapter.LibaoViewHolder
|
||||
|
||||
class LibaoListAdapter(
|
||||
context: Context,
|
||||
private val viewModel: LibaoListViewModel,
|
||||
private val gameId: String,
|
||||
private val gameName: String
|
||||
) : ListAdapter<LibaoEntity>(context) {
|
||||
override fun getItemCount() =
|
||||
if (mEntityList.isNullOrEmpty()) 0 else mEntityList.size + FOOTER_ITEM_COUNT
|
||||
|
||||
override fun getItemViewType(position: Int) =
|
||||
when (position) {
|
||||
itemCount - 1 -> ItemViewType.ITEM_FOOTER
|
||||
else -> ItemViewType.ITEM_BODY
|
||||
}
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return when (viewType) {
|
||||
ItemViewType.ITEM_BODY -> LibaoViewHolder(parent.toBinding())
|
||||
else -> FooterViewHolder(mLayoutInflater.inflate(com.gh.gamecenter.common.R.layout.refresh_footerview, parent, false))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is LibaoViewHolder -> {
|
||||
val entity = mEntityList[position]
|
||||
holder.bindItem(mContext, this, gameId, gameName, entity)
|
||||
}
|
||||
is FooterViewHolder -> holder.initFooterViewHolder(viewModel, mIsLoading, mIsNetworkError, mIsOver)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
package com.gh.gamecenter.gamedetail.libao
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.GlobalActivityManager
|
||||
import com.gh.gamecenter.common.baselist.LazyListFragment
|
||||
import com.gh.gamecenter.common.baselist.ListAdapter
|
||||
import com.gh.gamecenter.common.json.json
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.goneIf
|
||||
import com.gh.gamecenter.common.utils.marqueeOnce
|
||||
import com.gh.gamecenter.common.utils.viewModelProvider
|
||||
import com.gh.gamecenter.feature.entity.LibaoEntity
|
||||
|
||||
class LibaoListFragment : LazyListFragment<LibaoEntity, LibaoListViewModel>() {
|
||||
private var gameId = ""
|
||||
private var gameName = ""
|
||||
private var hideToolbar = false
|
||||
|
||||
private var adapter: LibaoListAdapter? = null
|
||||
|
||||
override fun getRealLayoutId() = R.layout.fragment_libao_list
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
gameId = arguments?.getString(ARG_GAME_ID) ?: ""
|
||||
gameName = arguments?.getString(ARG_GAME_NAME) ?: ""
|
||||
hideToolbar = arguments?.getBoolean(HIDE_TOOLBAR, false) ?: false
|
||||
}
|
||||
|
||||
override fun initRealView() {
|
||||
super.initRealView()
|
||||
val toolbarContainer = mCachedView.findViewById<RelativeLayout>(R.id.reuseToolbar)
|
||||
val toolbarTitleTv = toolbarContainer.findViewById<TextView>(R.id.normal_title)
|
||||
val toolbarBackContainer = toolbarContainer.findViewById<View>(com.gh.gamecenter.selector.R.id.backContainer)
|
||||
|
||||
toolbarBackContainer.setOnClickListener { requireActivity().onBackPressed() }
|
||||
|
||||
toolbarContainer.goneIf(hideToolbar) {
|
||||
toolbarTitleTv.text = "${gameName}-礼包"
|
||||
toolbarTitleTv.marqueeOnce()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFragmentFirstVisible() {
|
||||
super.onFragmentFirstVisible()
|
||||
|
||||
SensorsBridge.trackEvent("GameGiftPageView", json {
|
||||
"game_id" to gameId
|
||||
"game_name" to gameName
|
||||
"last_page_name" to GlobalActivityManager.getLastPageEntity().pageName
|
||||
"last_page_id" to GlobalActivityManager.getLastPageEntity().pageId
|
||||
})
|
||||
}
|
||||
|
||||
override fun provideListAdapter(): ListAdapter<*> =
|
||||
adapter ?: LibaoListAdapter(
|
||||
requireContext(),
|
||||
mListViewModel ?: provideListViewModel(),
|
||||
gameId,
|
||||
gameName
|
||||
).apply { adapter = this }
|
||||
|
||||
override fun provideListViewModel(): LibaoListViewModel =
|
||||
viewModelProvider<LibaoListViewModel>(LibaoListViewModel.Factory(arguments?.getString(ARG_GAME_ID) ?: ""))
|
||||
|
||||
override fun getItemDecoration(): RecyclerView.ItemDecoration? = null
|
||||
|
||||
companion object {
|
||||
|
||||
private const val ARG_GAME_ID = "game_id"
|
||||
private const val ARG_GAME_NAME = "game_name"
|
||||
private const val HIDE_TOOLBAR = "hide_toolbar"
|
||||
|
||||
fun getBundle(gameId: String, gameName: String, hideToolbar: Boolean) = Bundle().apply {
|
||||
putString(ARG_GAME_ID, gameId)
|
||||
putString(ARG_GAME_NAME, gameName)
|
||||
putBoolean(HIDE_TOOLBAR, hideToolbar)
|
||||
}
|
||||
|
||||
fun newInstance(bundle: Bundle?) = LibaoListFragment().apply {
|
||||
if (bundle != null) {
|
||||
arguments = bundle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
package com.gh.gamecenter.gamedetail.libao
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.gh.common.util.LibaoUtils
|
||||
import com.gh.gamecenter.common.baselist.ListViewModel
|
||||
import com.gh.gamecenter.common.utils.observableToMain
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.core.utils.UrlFilterUtils
|
||||
import com.gh.gamecenter.feature.entity.LibaoEntity
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
|
||||
class LibaoListViewModel(application: Application, private val gameId: String) :
|
||||
ListViewModel<LibaoEntity, LibaoEntity>(application) {
|
||||
private val api = RetrofitManager.getInstance().api
|
||||
override fun provideDataObservable(page: Int): Observable<MutableList<LibaoEntity>>? = null
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
override fun provideDataSingle(page: Int): Single<MutableList<LibaoEntity>> {
|
||||
return Single.create { emitter ->
|
||||
api.getGameLibaoList(gameId, page)
|
||||
.compose(singleToMain())
|
||||
.subscribe({ libaoList ->
|
||||
if (libaoList.isEmpty()) {
|
||||
emitter.onSuccess(libaoList)
|
||||
} else {
|
||||
val builder = StringBuilder()
|
||||
var i = 0
|
||||
val size = libaoList.size
|
||||
while (i < size) {
|
||||
builder.append(libaoList[i].id)
|
||||
builder.append("-")
|
||||
i++
|
||||
}
|
||||
builder.deleteCharAt(builder.length - 1)
|
||||
val ids = builder.toString()
|
||||
api.getLibaoStatus(UrlFilterUtils.getFilterQuery("libao_ids", ids))
|
||||
.compose(observableToMain())
|
||||
.subscribe({
|
||||
LibaoUtils.initLiBaoEntity(it, libaoList)
|
||||
GameDetailViewModel.sortLibaoList(libaoList)
|
||||
emitter.onSuccess(libaoList)
|
||||
}, {
|
||||
Utils.toast(getApplication(), "获取礼包状态失败")
|
||||
emitter.onSuccess(libaoList)
|
||||
})
|
||||
}
|
||||
}, {
|
||||
emitter.onError(it)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun mergeResultLiveData() {
|
||||
mResultLiveData.addSource(mListLiveData) { list ->
|
||||
mResultLiveData.postValue(list)
|
||||
}
|
||||
}
|
||||
|
||||
class Factory(private val gameId: String) : ViewModelProvider.NewInstanceFactory() {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return LibaoListViewModel(HaloApp.getInstance().application, gameId) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -25,11 +25,11 @@ import com.gh.gamecenter.common.utils.toPx
|
||||
import com.gh.gamecenter.core.iinterface.IScrollable
|
||||
import com.gh.gamecenter.core.utils.MtaHelper
|
||||
import com.gh.gamecenter.core.utils.SpanBuilder
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.entity.RatingComment
|
||||
import com.gh.gamecenter.eventbus.EBStar
|
||||
import com.gh.gamecenter.eventbus.EBTypeChange
|
||||
import com.gh.gamecenter.gamedetail.GameDetailFragment
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.gamedetail.GameDetailWrapperFragment
|
||||
import com.halo.assistant.HaloApp
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
@ -161,7 +161,7 @@ class RatingFragment : LazyListFragment<RatingComment, RatingViewModel>(), IScro
|
||||
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))
|
||||
EventBus.getDefault().post(EBTypeChange(GameDetailWrapperFragment.EB_SCROLLING, 0))
|
||||
}
|
||||
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
var position = mLayoutManager.findLastCompletelyVisibleItemPosition()
|
||||
|
||||
@ -0,0 +1,133 @@
|
||||
package com.gh.gamecenter.gamedetail.video
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.utils.NetworkUtils
|
||||
import com.gh.gamecenter.core.utils.MD5Utils
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
|
||||
import com.gh.gamecenter.video.detail.CustomManager
|
||||
import com.halo.assistant.HaloApp
|
||||
import com.lightgame.utils.Utils
|
||||
|
||||
class GameDetailScrollCalculatorHelper(val listRv: RecyclerView, private val playId: Int, private val rangeTop: Int) {
|
||||
private var firstVisible = -1
|
||||
private var lastVisible = 0
|
||||
private var runnable: PlayRunnable? = null
|
||||
private val playHandler = Handler(Looper.getMainLooper())
|
||||
var currentPlayer: TopVideoView? = null
|
||||
|
||||
fun onScrollStateChanged(firstVisibleItem: Int, lastVisibleItem: Int, scrollState: Int) {
|
||||
if (scrollState == RecyclerView.SCROLL_STATE_IDLE) {
|
||||
firstVisible = firstVisibleItem
|
||||
lastVisible = lastVisibleItem
|
||||
stopIfNeeded()
|
||||
playVideo(listRv)
|
||||
}
|
||||
}
|
||||
|
||||
//判断player是否划出了屏幕,划出了屏幕则需要释放
|
||||
private fun stopIfNeeded() {
|
||||
if (currentPlayer != null) {
|
||||
//保存进度
|
||||
val currentScheduler = currentPlayer?.currentPositionWhenPlaying?.toLong() ?: 0L
|
||||
ScrollCalculatorHelper.savePlaySchedule(MD5Utils.getContentMD5(currentPlayer?.getUrl()), currentScheduler)
|
||||
currentPlayer?.initUIState()
|
||||
// currentPlayer?.resetDetailMask()
|
||||
currentPlayer = null
|
||||
runnable?.let { playHandler.removeCallbacks(it) }
|
||||
}
|
||||
}
|
||||
|
||||
fun release() {
|
||||
if (currentPlayer != null) {
|
||||
val currentScheduler = currentPlayer?.currentPositionWhenPlaying?.toLong() ?: 0L
|
||||
ScrollCalculatorHelper.savePlaySchedule(MD5Utils.getContentMD5(currentPlayer?.getUrl()), currentScheduler)
|
||||
CustomManager.releaseAllVideos(currentPlayer?.getKey())
|
||||
runnable?.let { playHandler.removeCallbacks(it) }
|
||||
// currentPlayer?.resetDetailMask()
|
||||
currentPlayer = null
|
||||
}
|
||||
}
|
||||
|
||||
private fun playVideo(view: RecyclerView?) {
|
||||
if (view == null) return
|
||||
val layoutManager = view.layoutManager
|
||||
var gsyBaseVideoPlayer: TopVideoView
|
||||
for (i in firstVisible until lastVisible + 1) {
|
||||
if (layoutManager == null) return
|
||||
|
||||
val child = listRv.findViewHolderForAdapterPosition(i)?.itemView
|
||||
val player: View? = child?.findViewById(playId)
|
||||
|
||||
if (player == null || player.visibility != View.VISIBLE || player !is TopVideoView) continue
|
||||
|
||||
val rect = Rect()
|
||||
player.getLocalVisibleRect(rect)
|
||||
val width = player.width
|
||||
val height = player.height
|
||||
if (rect.left == 0 && rect.right == width && rect.top == 0 && rect.bottom == height) {
|
||||
gsyBaseVideoPlayer = player
|
||||
if (runnable != null) {
|
||||
playHandler.removeCallbacks(runnable!!)
|
||||
runnable = null
|
||||
}
|
||||
if (currentPlayer == gsyBaseVideoPlayer) return
|
||||
|
||||
val screenPosition = IntArray(2)
|
||||
gsyBaseVideoPlayer.getLocationInWindow(screenPosition)
|
||||
val rangePosition = screenPosition[1]
|
||||
if (rangePosition >= rangeTop) {
|
||||
runnable?.let { playHandler.removeCallbacks(it) }
|
||||
runnable = PlayRunnable(gsyBaseVideoPlayer)
|
||||
if (currentPlayer != null) {
|
||||
currentPlayer?.initUIState()
|
||||
// currentPlayer?.resetDetailMask()
|
||||
}
|
||||
//降低频率
|
||||
playHandler.postDelayed(runnable!!, 100)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class PlayRunnable(var videoView: TopVideoView?) : Runnable {
|
||||
override fun run() {
|
||||
if (videoView != null && !videoView!!.isInPlayingState) {
|
||||
|
||||
val videoOption =
|
||||
SPUtils.getString(Constants.SP_HOME_OR_DETAIL_VIDEO_OPTION, Constants.VIDEO_OPTION_WIFI)
|
||||
?: Constants.VIDEO_OPTION_WIFI
|
||||
|
||||
when (videoOption) {
|
||||
Constants.VIDEO_OPTION_ALL -> {
|
||||
startPlayLogic(videoView)
|
||||
}
|
||||
|
||||
Constants.VIDEO_OPTION_WIFI -> {
|
||||
if (NetworkUtils.isWifiConnected(HaloApp.getInstance().application)) {
|
||||
startPlayLogic(videoView)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun startPlayLogic(videoView: TopVideoView?) {
|
||||
Utils.log("GameDetailScrollCalculatorHelper", "startPlayLogic $videoView")
|
||||
|
||||
videoView?.startPlayLogic(true)
|
||||
currentPlayer = videoView
|
||||
}
|
||||
|
||||
}
|
||||
@ -8,9 +8,9 @@ import android.view.*
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.SeekBar
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.gh.common.util.LogUtils
|
||||
import com.gh.download.cache.ExoCacheManager
|
||||
import com.gh.gamecenter.R
|
||||
@ -20,15 +20,14 @@ import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.core.runOnIoThread
|
||||
import com.gh.gamecenter.core.runOnUiThread
|
||||
import com.gh.gamecenter.core.utils.MD5Utils
|
||||
import com.gh.gamecenter.core.utils.MtaHelper
|
||||
import com.gh.gamecenter.core.utils.StringUtils
|
||||
import com.gh.gamecenter.gamedetail.GameDetailViewModel
|
||||
import com.gh.gamecenter.gamedetail.entity.Video
|
||||
import com.gh.gamecenter.gamedetail.entity.CoverTabEntity
|
||||
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
|
||||
import com.gh.gamecenter.video.detail.CustomManager
|
||||
import com.lightgame.utils.Utils
|
||||
import com.shuyu.gsyvideoplayer.utils.CommonUtil
|
||||
import com.shuyu.gsyvideoplayer.utils.Debuger
|
||||
import com.shuyu.gsyvideoplayer.utils.GSYVideoType
|
||||
import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer
|
||||
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
|
||||
import com.shuyu.gsyvideoplayer.video.base.GSYVideoViewBridge
|
||||
@ -42,7 +41,7 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
|
||||
private var mVolumeObserver: VolumeObserver? = null
|
||||
|
||||
var gameName = ""
|
||||
var video: Video? = null
|
||||
var video: CoverTabEntity.Video? = null
|
||||
var viewModel: GameDetailViewModel? = null
|
||||
var uuid = UUID.randomUUID().toString()
|
||||
private var mMuteDisposable: Disposable? = null
|
||||
@ -50,9 +49,6 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
|
||||
private var mIsAutoPlay = false
|
||||
private var mLastGetContentLengthTime = 0L
|
||||
|
||||
val combinedTitleAndId: String
|
||||
get() = StringUtils.combineTwoString(video?.title, video?.videoId)
|
||||
|
||||
init {
|
||||
post {
|
||||
gestureDetector =
|
||||
@ -89,11 +85,11 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
|
||||
}
|
||||
|
||||
setBackFromFullScreenListener {
|
||||
if (it.id == R.id.fullscreen) {
|
||||
MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-退出全屏", combinedTitleAndId)
|
||||
} else if (it.id == R.id.back) {
|
||||
MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-点击返回", combinedTitleAndId)
|
||||
}
|
||||
// if (it.id == R.id.fullscreen) {
|
||||
// MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-退出全屏", combinedTitleAndId)
|
||||
// } else if (it.id == R.id.back) {
|
||||
// MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-点击返回", combinedTitleAndId)
|
||||
// }
|
||||
clearFullscreenLayout()
|
||||
}
|
||||
|
||||
@ -112,39 +108,34 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
|
||||
|
||||
//这个必须配置最上面的构造才能生效
|
||||
override fun getLayoutId(): Int {
|
||||
return R.layout.layout_game_detail_video_portrait
|
||||
return R.layout.layout_new_game_detail_video_portrait
|
||||
}
|
||||
|
||||
fun observeVolume(fragment: Fragment?) {
|
||||
fragment?.context?.applicationContext?.contentResolver?.registerContentObserver(
|
||||
android.provider.Settings.System.CONTENT_URI, true, mVolumeObserver!!
|
||||
)
|
||||
}
|
||||
|
||||
fragment?.fragmentManager?.registerFragmentLifecycleCallbacks(
|
||||
object : FragmentManager.FragmentLifecycleCallbacks() {
|
||||
override fun onFragmentPaused(fm: FragmentManager, f: Fragment) {
|
||||
if (f === fragment) {
|
||||
fragment.context?.applicationContext?.contentResolver?.unregisterContentObserver(mVolumeObserver!!)
|
||||
fragment.fragmentManager?.unregisterFragmentLifecycleCallbacks(this)
|
||||
}
|
||||
}
|
||||
}, false
|
||||
)
|
||||
fun unObserveVolume(activity: AppCompatActivity) {
|
||||
activity.contentResolver?.unregisterContentObserver(mVolumeObserver!!)
|
||||
}
|
||||
|
||||
fun startPlayLogic(isAutoPlay: Boolean) {
|
||||
mIsAutoPlay = isAutoPlay
|
||||
violenceUpdateMuteStatus()
|
||||
if (isAutoPlay) {
|
||||
MtaHelper.onEvent("游戏详情_顶部视频", "视频播放方式", "自动播放")
|
||||
MtaHelper.onEvent("游戏详情_顶部视频", "顶部视频-自动播放", combinedTitleAndId)
|
||||
} else {
|
||||
MtaHelper.onEvent("游戏详情_顶部视频", "视频播放方式", "手动播放")
|
||||
}
|
||||
// if (isAutoPlay) {
|
||||
// MtaHelper.onEvent("游戏详情_顶部视频", "视频播放方式", "自动播放")
|
||||
// MtaHelper.onEvent("游戏详情_顶部视频", "顶部视频-自动播放", combinedTitleAndId)
|
||||
// } else {
|
||||
// MtaHelper.onEvent("游戏详情_顶部视频", "视频播放方式", "手动播放")
|
||||
// }
|
||||
if (isAutoPlay) {
|
||||
val seekTime = ScrollCalculatorHelper.getPlaySchedule(MD5Utils.getContentMD5(video?.url))
|
||||
seekOnStart = seekTime
|
||||
mTouchingProgressBar = false
|
||||
}
|
||||
GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_FULL)
|
||||
startPlayLogic()
|
||||
}
|
||||
|
||||
@ -162,6 +153,12 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
disposableTimer()
|
||||
unObserveVolume(context as AppCompatActivity)
|
||||
}
|
||||
|
||||
fun disposableTimer() {
|
||||
if (mMuteDisposable != null && !mMuteDisposable!!.isDisposed) {
|
||||
mMuteDisposable?.dispose()
|
||||
@ -192,7 +189,7 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
|
||||
if (isManual) {
|
||||
Utils.toast(context, "当前处于静音状态")
|
||||
uploadVideoStreamingPlaying("点击静音")
|
||||
MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-点击静音", combinedTitleAndId)
|
||||
// MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-点击静音", combinedTitleAndId)
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,13 +204,13 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
|
||||
)
|
||||
if (isManual) {
|
||||
uploadVideoStreamingPlaying("取消静音")
|
||||
MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-解除静音", combinedTitleAndId)
|
||||
// MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-解除静音", combinedTitleAndId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSeekComplete() {
|
||||
super.onSeekComplete()
|
||||
MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-拖动进度条", combinedTitleAndId)
|
||||
// MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-拖动进度条", combinedTitleAndId)
|
||||
}
|
||||
|
||||
// 重载以减少横竖屏切换的时间
|
||||
@ -262,12 +259,16 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
|
||||
return uuid
|
||||
}
|
||||
|
||||
fun getUrl(): String {
|
||||
return mUrl
|
||||
}
|
||||
|
||||
override fun onAutoCompletion() {
|
||||
// 这个方法在内核被释放时也会被回调,所以可以用来统计播放量和播放时长
|
||||
val playedTime = (gsyVideoManager.currentPosition / 1000).toInt()
|
||||
|
||||
MtaHelper.onEventWithTime("视频播放量_按位置", playedTime, "游戏详情-顶部视频", combinedTitleAndId)
|
||||
MtaHelper.onEventWithTime("视频播放量_游戏加位置", playedTime, gameName, "游戏详情-顶部视频")
|
||||
// MtaHelper.onEventWithTime("视频播放量_按位置", playedTime, "游戏详情-顶部视频", combinedTitleAndId)
|
||||
// MtaHelper.onEventWithTime("视频播放量_游戏加位置", playedTime, gameName, "游戏详情-顶部视频")
|
||||
|
||||
//播放完成后判断是否已缓冲完毕,没有完成显示播放错误状态
|
||||
if (mBufferPoint != 0 && mBufferPoint != 100 && isShown) {
|
||||
@ -353,7 +354,7 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
|
||||
findViewById<LinearLayout>(R.id.replayContainer)?.visibility = View.VISIBLE
|
||||
mTopContainer.visibility = View.VISIBLE
|
||||
findViewById<ImageView>(R.id.replayIv).setOnClickListener {
|
||||
MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-点击重新播放", combinedTitleAndId)
|
||||
// MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-点击重新播放", combinedTitleAndId)
|
||||
startButton.performClick()
|
||||
violenceUpdateMuteStatus()
|
||||
uploadVideoStreamingPlaying("重新播放")
|
||||
@ -390,13 +391,6 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
|
||||
return R.drawable.ic_game_detail_exit_full_screen
|
||||
}
|
||||
|
||||
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
|
||||
if (!isIfCurrentIsFullscreen) {
|
||||
parent.requestDisallowInterceptTouchEvent(true)
|
||||
}
|
||||
return super.onInterceptTouchEvent(ev)
|
||||
}
|
||||
|
||||
/******************* 下方两个重载方法,在播放开始前不屏蔽封面,不需要可屏蔽 ********************/
|
||||
|
||||
override fun onSurfaceUpdated(surface: Surface) {
|
||||
@ -419,21 +413,25 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
|
||||
override fun changeUiToNormal() {
|
||||
super.changeUiToNormal()
|
||||
findViewById<LinearLayout>(R.id.errorContainer)?.visibility = View.GONE
|
||||
findViewById<LinearLayout>(R.id.loadingContainer)?.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun changeUiToPreparingShow() {
|
||||
super.changeUiToPreparingShow()
|
||||
findViewById<LinearLayout>(R.id.errorContainer)?.visibility = View.GONE
|
||||
findViewById<LinearLayout>(R.id.loadingContainer)?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
override fun changeUiToPlayingShow() {
|
||||
super.changeUiToPlayingShow()
|
||||
findViewById<LinearLayout>(R.id.errorContainer)?.visibility = View.GONE
|
||||
findViewById<LinearLayout>(R.id.loadingContainer)?.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun changeUiToPauseShow() {
|
||||
super.changeUiToPauseShow()
|
||||
findViewById<LinearLayout>(R.id.errorContainer)?.visibility = View.GONE
|
||||
findViewById<LinearLayout>(R.id.loadingContainer)?.visibility = View.GONE
|
||||
}
|
||||
|
||||
fun showFullPauseBitmap() {
|
||||
@ -450,12 +448,39 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
|
||||
override fun changeUiToCompleteShow() {
|
||||
super.changeUiToCompleteShow()
|
||||
findViewById<LinearLayout>(R.id.errorContainer)?.visibility = View.GONE
|
||||
findViewById<LinearLayout>(R.id.loadingContainer)?.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun changeUiToError() {
|
||||
super.changeUiToError()
|
||||
setViewShowState(mStartButton, View.INVISIBLE)
|
||||
findViewById<LinearLayout>(R.id.errorContainer)?.visibility = View.VISIBLE
|
||||
findViewById<LinearLayout>(R.id.loadingContainer)?.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun changeUiToPrepareingClear() {
|
||||
super.changeUiToPrepareingClear()
|
||||
findViewById<LinearLayout>(R.id.loadingContainer)?.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun changeUiToPlayingBufferingShow() {
|
||||
super.changeUiToPlayingBufferingShow()
|
||||
findViewById<LinearLayout>(R.id.loadingContainer)?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
override fun changeUiToPlayingBufferingClear() {
|
||||
super.changeUiToPlayingBufferingClear()
|
||||
findViewById<LinearLayout>(R.id.loadingContainer)?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
override fun changeUiToClear() {
|
||||
super.changeUiToClear()
|
||||
findViewById<LinearLayout>(R.id.loadingContainer)?.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun changeUiToCompleteClear() {
|
||||
super.changeUiToCompleteClear()
|
||||
findViewById<LinearLayout>(R.id.loadingContainer)?.visibility = View.GONE
|
||||
}
|
||||
|
||||
override fun netWorkErrorLogic() {
|
||||
@ -497,11 +522,11 @@ class TopVideoView @JvmOverloads constructor(context: Context, attrs: AttributeS
|
||||
override fun onClick(v: View) {
|
||||
when (v.id) {
|
||||
R.id.start -> {
|
||||
if (currentState == GSYVideoView.CURRENT_STATE_PLAYING) {
|
||||
MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-点击暂停", combinedTitleAndId)
|
||||
} else {
|
||||
MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-点击播放", combinedTitleAndId)
|
||||
}
|
||||
// if (currentState == GSYVideoView.CURRENT_STATE_PLAYING) {
|
||||
// MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-点击暂停", combinedTitleAndId)
|
||||
// } else {
|
||||
// MtaHelper.onEvent("游戏详情_顶部视频", "${getMtaKeyPrefix()}-点击播放", combinedTitleAndId)
|
||||
// }
|
||||
super.onClick(v)
|
||||
}
|
||||
|
||||
|
||||
@ -101,6 +101,7 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable {
|
||||
private var bottomTabId = ""
|
||||
private var bottomTabName = ""
|
||||
private var tabIndex = -1
|
||||
private var showFloatingWindow = true
|
||||
|
||||
private lateinit var pageLocation: PageLocation
|
||||
|
||||
@ -131,6 +132,7 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable {
|
||||
bottomTabId = arguments?.getString(EntranceConsts.KEY_BOTTOM_TAB_ID, "") ?: ""
|
||||
bottomTabName = arguments?.getString(EntranceConsts.KEY_BOTTOM_TAB_NAME, "") ?: ""
|
||||
tabIndex = arguments?.getInt(EntranceConsts.KEY_TAB_INDEX, -1) ?: -1
|
||||
showFloatingWindow = arguments?.getBoolean(EntranceConsts.KEY_SHOW_FLOATING_WINDOW, true) ?: true
|
||||
val tabName = arguments?.getString(EntranceConsts.KEY_TAB_NAME, "") ?: ""
|
||||
val multiTabNavId = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_ID, "") ?: ""
|
||||
val multiTabNavName = arguments?.getString(EntranceConsts.KEY_MULTI_TAB_NAV_NAME, "") ?: ""
|
||||
@ -555,37 +557,41 @@ class CustomPageFragment : LazyFragment(), ISmartRefreshContent, IScrollable {
|
||||
}
|
||||
|
||||
private fun buildPriorityChain() {
|
||||
val floatingWindowHandler = CustomFloatingWindowHandler(23)
|
||||
val videoHandler = VideoHandler(24, scrollCalculatorHelper)
|
||||
|
||||
priorityChain.addHandler(pullDownPushHandler)
|
||||
priorityChain.addHandler(floatingWindowHandler)
|
||||
|
||||
if (showFloatingWindow) {
|
||||
val floatingWindowHandler = CustomFloatingWindowHandler(23)
|
||||
priorityChain.addHandler(floatingWindowHandler)
|
||||
|
||||
viewModel.floatingWindows.observe(viewLifecycleOwner, EventObserver {
|
||||
floatingWindowHandler.setData(it)
|
||||
})
|
||||
|
||||
floatingWindowHandler.showFloatingAction.observe(viewLifecycleOwner, EventObserver {
|
||||
binding.floatingView.setData(
|
||||
it,
|
||||
pageLocation,
|
||||
viewModel.pageConfigure.exposureSourceList,
|
||||
floatingWindowHandler
|
||||
)
|
||||
floatViewManager.show(binding.floatingView)
|
||||
})
|
||||
|
||||
binding.floatingView.setExpandListener { entity, hasAnimation ->
|
||||
val dialog = CustomWelcomeDialogFragment.getInstance(entity, true, this, hasAnimation, pageLocation)
|
||||
dialog.setDismissListener {
|
||||
floatViewManager.resume()
|
||||
floatingWindowHandler.dismiss()
|
||||
}
|
||||
dialog.show(childFragmentManager, CustomWelcomeDialogFragment.TAG)
|
||||
}
|
||||
}
|
||||
|
||||
priorityChain.addHandler(videoHandler)
|
||||
(parentFragment as? BaseTabWrapperFragment)?.addTabGuideHandlerIfExists(priorityChain)
|
||||
|
||||
viewModel.floatingWindows.observe(viewLifecycleOwner, EventObserver {
|
||||
floatingWindowHandler.setData(it)
|
||||
})
|
||||
|
||||
floatingWindowHandler.showFloatingAction.observe(viewLifecycleOwner, EventObserver {
|
||||
binding.floatingView.setData(
|
||||
it,
|
||||
pageLocation,
|
||||
viewModel.pageConfigure.exposureSourceList,
|
||||
floatingWindowHandler
|
||||
)
|
||||
floatViewManager.show(binding.floatingView)
|
||||
})
|
||||
|
||||
binding.floatingView.setExpandListener { entity, hasAnimation ->
|
||||
val dialog = CustomWelcomeDialogFragment.getInstance(entity, true, this, hasAnimation, pageLocation)
|
||||
dialog.setDismissListener {
|
||||
floatViewManager.resume()
|
||||
floatingWindowHandler.dismiss()
|
||||
}
|
||||
dialog.show(childFragmentManager, CustomWelcomeDialogFragment.TAG)
|
||||
}
|
||||
|
||||
if (superiorChain != null) {
|
||||
superiorChain?.registerInferiorChain(priorityChain)
|
||||
} else {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.gh.gamecenter.home.custom
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import androidx.collection.ArrayMap
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
@ -10,9 +11,12 @@ import com.gh.common.util.GameUtils
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.common.util.NewLogUtils
|
||||
import com.gh.gamecenter.common.baselist.LoadStatus
|
||||
import com.gh.gamecenter.common.entity.ErrorEntity
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.common.utils.toObject
|
||||
import com.gh.gamecenter.core.utils.RandomUtils
|
||||
import com.gh.gamecenter.entity.PullDownPush
|
||||
import com.gh.gamecenter.entity.RatingComment
|
||||
@ -105,6 +109,8 @@ class CustomPageViewModel(
|
||||
val pageLocation: PageLocation
|
||||
get() = pageTracker.pageLocation
|
||||
|
||||
val pkVoteResultLiveData = MutableLiveData<Event<Pair<String, Boolean>>>()
|
||||
|
||||
fun init(
|
||||
pageConfigure: PageConfigure,
|
||||
searchToolbarTabWrapperViewModel: SearchToolbarTabWrapperViewModel?,
|
||||
@ -746,6 +752,25 @@ class CustomPageViewModel(
|
||||
_gameListSquareDestination.value = Event(item)
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun postPKVote(pkId: String, isPositive: Boolean) {
|
||||
repository.postPKVote(pkId, isPositive)
|
||||
.compose(singleToMain())
|
||||
.subscribe({
|
||||
pkVoteResultLiveData.postValue(Event(Pair(pkId, isPositive)))
|
||||
}, {
|
||||
if (it is HttpException) {
|
||||
val errorString = it.response().errorBody()?.string()
|
||||
val errorEntity = errorString?.toObject<ErrorEntity>()
|
||||
if (!errorEntity?.toast.isNullOrEmpty()) {
|
||||
Utils.toast(getApplication(), errorEntity?.toast)
|
||||
}
|
||||
} else {
|
||||
Utils.toast(getApplication(), "投票失败")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun hideNotificationItem(id: String, itemId: String) {
|
||||
repository.hideNotificationItem(id, itemId)
|
||||
}
|
||||
|
||||
@ -1,203 +0,0 @@
|
||||
package com.gh.gamecenter.home.custom.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.gh.common.util.*
|
||||
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.game.horizontal.GameHorizontalSimpleItemViewHolder
|
||||
import com.gh.gamecenter.home.PageConfigure
|
||||
import com.gh.gamecenter.home.custom.model.CustomSubjectItem
|
||||
import com.gh.gamecenter.home.custom.viewholder.CustomGameHorizontalItemViewHolder
|
||||
import com.gh.gamecenter.feature.minigame.MiniGameItemHelper
|
||||
import com.lightgame.download.DownloadEntity
|
||||
|
||||
class CustomGameHorizontalAdapter(
|
||||
context: Context,
|
||||
private val pageConfigure: PageConfigure
|
||||
) : CustomBaseChildAdapter<GameEntity, CustomGameHorizontalItemViewHolder>(context) {
|
||||
|
||||
var gameName = ""
|
||||
var gameId = ""
|
||||
var game: GameEntity? = null
|
||||
|
||||
var path = ""
|
||||
var exposureEventList: ArrayList<ExposureEvent>? = null
|
||||
private val mDefaultHorizontalPadding by lazy { com.gh.gamecenter.common.R.dimen.game_detail_item_horizontal_padding.toPx() }
|
||||
|
||||
private lateinit var _data: CustomSubjectItem
|
||||
|
||||
private val subjectEntity: SubjectEntity
|
||||
get() = _data.data
|
||||
|
||||
private val type: GameHorizontalListType
|
||||
get() = if (subjectEntity.isMiniGame) {
|
||||
GameHorizontalListType.MiniGameSubjectHorizontalType
|
||||
} else {
|
||||
GameHorizontalListType.SubjectHorizontalType
|
||||
}
|
||||
|
||||
fun setData(data: CustomSubjectItem) {
|
||||
_data = data
|
||||
submitList(data.data.data)
|
||||
}
|
||||
|
||||
override fun getKey(t: GameEntity): String {
|
||||
return t.id
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
|
||||
CustomGameHorizontalItemViewHolder(parent.toBinding())
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
val size = dataList.size
|
||||
return when (type) {
|
||||
GameHorizontalListType.GameDetailHorizontalType -> {
|
||||
size
|
||||
}
|
||||
GameHorizontalListType.MiniGameSubjectHorizontalType -> {
|
||||
dataList.size
|
||||
}
|
||||
else -> when {
|
||||
size < 4 -> size
|
||||
size < 8 -> 4
|
||||
else -> 8
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: CustomGameHorizontalItemViewHolder, position: Int) {
|
||||
val params = holder.binding.root.layoutParams as RecyclerView.LayoutParams
|
||||
params.width =
|
||||
if (gameName.isNotBlank()) RecyclerView.LayoutParams.WRAP_CONTENT else RecyclerView.LayoutParams.MATCH_PARENT
|
||||
if (type == GameHorizontalListType.GameDetailHorizontalType) {
|
||||
params.leftMargin = if (position == 0) mDefaultHorizontalPadding else 8F.dip2px()
|
||||
params.rightMargin = if (position == itemCount - 1) mDefaultHorizontalPadding else 0F.dip2px()
|
||||
}
|
||||
holder.binding.root.layoutParams = params
|
||||
|
||||
val gameEntity = getItem(position)
|
||||
holder.binding.simpleGameContainer.run {
|
||||
gameIcon.displayGameIcon(gameEntity)
|
||||
GameHorizontalSimpleItemViewHolder.setHorizontalNameAndGravity(gameName, gameEntity.name)
|
||||
downloadBtn.goneIf(!subjectEntity.showDownload)
|
||||
gameName.maxLines = if (subjectEntity.showDownload) 1 else 2
|
||||
}
|
||||
holder.bindGameHorizontalItem(gameEntity, subjectEntity, false, false)
|
||||
val entranceResult: String
|
||||
val locationResult: String
|
||||
if (type == GameHorizontalListType.GameDetailHorizontalType) {
|
||||
entranceResult = StringUtils.buildString(
|
||||
pageConfigure.entrance,
|
||||
"+(",
|
||||
"游戏详情",
|
||||
"[",
|
||||
gameName,
|
||||
"]:${path}[",
|
||||
(position + 1).toString(),
|
||||
"])"
|
||||
)
|
||||
locationResult = StringUtils.buildString("游戏详情-", gameName, "-${path}", ":", gameEntity.name)
|
||||
} else {
|
||||
entranceResult =
|
||||
StringUtils.buildString("(游戏-专题:", subjectEntity.name, "-列表[", (position + 1).toString(), "])")
|
||||
locationResult = StringUtils.buildString("游戏-专题-", subjectEntity.name, ":", gameEntity.name)
|
||||
}
|
||||
holder.itemView.setOnClickListener {
|
||||
if (type == GameHorizontalListType.GameDetailHorizontalType) {
|
||||
DataCollectionUtils.uploadClick(context, 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
|
||||
)
|
||||
}
|
||||
|
||||
if (gameEntity.isMiniGame()) {
|
||||
MiniGameItemHelper.launchMiniGame(gameEntity)
|
||||
} else {
|
||||
GameDetailActivity.startGameDetailActivity(
|
||||
context,
|
||||
gameEntity.id,
|
||||
entranceResult,
|
||||
exposureEventList?.get(position)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (subjectEntity.showDownload && type != GameHorizontalListType.GameDetailHorizontalType) {
|
||||
DownloadItemUtils.setOnClickListener(
|
||||
context,
|
||||
holder.binding.simpleGameContainer.downloadBtn,
|
||||
gameEntity,
|
||||
position,
|
||||
this,
|
||||
entranceResult,
|
||||
location = locationResult,
|
||||
traceEvent = if (position < (exposureEventList?.size ?: 0)) exposureEventList!![position] else null
|
||||
)
|
||||
|
||||
DownloadItemUtils.updateItem(
|
||||
context,
|
||||
gameEntity,
|
||||
GameViewHolder(holder.binding.simpleGameContainer.root).apply {
|
||||
gameDownloadBtn = holder.binding.simpleGameContainer.downloadBtn
|
||||
gameDownloadTips = holder.binding.simpleGameContainer.downloadTipsLottie
|
||||
multiVersionDownloadTv = holder.binding.simpleGameContainer.multiVersionDownloadTv
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun notifyItemByDownload(downloadEntity: DownloadEntity?) {
|
||||
if (downloadEntity == null) {
|
||||
notifyDataSetChanged()
|
||||
} else {
|
||||
subjectEntity.data?.forEachIndexed { position, gameEntity ->
|
||||
if (downloadEntity.gameId == gameEntity.id) {
|
||||
notifyItemChanged(position)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun notifyChildItem(packageName: String) {
|
||||
subjectEntity.data?.forEachIndexed { position, gameEntity ->
|
||||
gameEntity.getApk().forEach { apkEntity ->
|
||||
if (apkEntity.packageName == packageName) {
|
||||
notifyItemChanged(position)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sealed class GameHorizontalListType {
|
||||
object GameDetailHorizontalType : GameHorizontalListType()
|
||||
object SubjectHorizontalType : GameHorizontalListType()
|
||||
|
||||
object MiniGameSubjectHorizontalType : GameHorizontalListType()
|
||||
}
|
||||
@ -50,6 +50,7 @@ import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_MINI_GAME_RECENT_PLAY
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_NAVIGATION
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_NEW_GAME_TEST
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_PK
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_PLUGIN
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_RANK_COLLECTION
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageItem.Companion.CUSTOM_PAGE_ITEM_TYPE_RECENT_PLAY
|
||||
@ -274,6 +275,8 @@ class CustomPageAdapter(
|
||||
|
||||
CUSTOM_PAGE_ITEM_TYPE_FOOTER -> CustomFooterViewHolder(viewModel, parent.toBinding())
|
||||
|
||||
CUSTOM_PAGE_ITEM_TYPE_PK -> CustomPKItemViewHolder(viewModel, lifecycleOwner, parent.toBinding())
|
||||
|
||||
else -> InvalidViewHolder(viewModel, parent.toBinding())
|
||||
}
|
||||
|
||||
|
||||
@ -4,9 +4,10 @@ import com.gh.common.filter.RegionSettingHelper
|
||||
import com.gh.gamecenter.common.entity.CommunityEntity
|
||||
import com.gh.gamecenter.common.entity.Display
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.entity.PKEntity
|
||||
import com.gh.gamecenter.entity.*
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.entity.FloatingWindowEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
|
||||
@ -78,7 +79,10 @@ class CustomPageData(
|
||||
@SerializedName("link_common_collection")
|
||||
val linkCommonCollection: CommonContentCollection? = null,
|
||||
@SerializedName("link_qq_game_recently_played")
|
||||
val linkQqGameRecentlyPlayed: LinkQqGameRecentlyPlayed? = null
|
||||
val linkQqGameRecentlyPlayed: LinkQqGameRecentlyPlayed? = null,
|
||||
@SerializedName("link_pk")
|
||||
val linkPK: LinkEntity? = null,
|
||||
var pkData: PKEntity? = null,
|
||||
) {
|
||||
// 游戏专题
|
||||
val gameSubjectEntity: SubjectEntity?
|
||||
|
||||
@ -2,6 +2,7 @@ package com.gh.gamecenter.home.custom.model
|
||||
|
||||
import com.gh.common.util.ViewPagerFragmentHelper
|
||||
import com.gh.gamecenter.common.entity.LinkEntity
|
||||
import com.gh.gamecenter.common.entity.PKEntity
|
||||
import com.gh.gamecenter.common.exposure.ExposureSource
|
||||
import com.gh.gamecenter.core.utils.TimeUtils
|
||||
import com.gh.gamecenter.entity.*
|
||||
@ -170,6 +171,7 @@ abstract class CustomPageItem(
|
||||
const val CUSTOM_PAGE_ITEM_TYPE_MINI_GAME_RECENT_PLAY = 35
|
||||
const val CUSTOM_PAGE_ITEM_TYPE_SINGLE_GAME_CARD = 36
|
||||
const val CUSTOM_PAGE_ITEM_TYPE_DOUBLE_GAME_WELFARE_CARD = 37
|
||||
const val CUSTOM_PAGE_ITEM_TYPE_PK = 38
|
||||
|
||||
// 专题样式 to itemType
|
||||
val subjectTypeMap: HashMap<String, Int> = hashMapOf(
|
||||
@ -849,6 +851,26 @@ data class CustomSplitCommonContentCollectionItem(
|
||||
}
|
||||
}
|
||||
|
||||
// PK
|
||||
data class CustomPKItem(
|
||||
private val _link: LinkEntity,
|
||||
val data: PKEntity,
|
||||
private val _position: Int,
|
||||
private val _componentPosition: Int
|
||||
) : CustomPageItem(_link, _position, _componentPosition) {
|
||||
|
||||
override val itemType: Int
|
||||
get() = CUSTOM_PAGE_ITEM_TYPE_PK
|
||||
|
||||
override fun doAreContentsTheSames(other: CustomPageItem): Boolean {
|
||||
return other is CustomPKItem
|
||||
&& link == other.link
|
||||
&& data == other.data
|
||||
&& position == other.position
|
||||
&& componentPosition == other.componentPosition
|
||||
}
|
||||
}
|
||||
|
||||
object CustomFooterItem : CustomPageItem(LinkEntity(), -1, -1) {
|
||||
override val itemType: Int
|
||||
get() = CUSTOM_PAGE_ITEM_TYPE_FOOTER
|
||||
|
||||
@ -1,17 +1,23 @@
|
||||
package com.gh.gamecenter.home.custom.model
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import com.gh.gamecenter.BuildConfig
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.entity.PKEntity
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.common.utils.toRequestBody
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.entity.PullDownPush
|
||||
import com.gh.gamecenter.entity.SubjectEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.feature.entity.FloatingWindowEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.retrofit.service.ApiService
|
||||
import com.gh.gamecenter.wrapper.MainWrapperRepository
|
||||
import com.halo.assistant.HaloApp
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.SingleEmitter
|
||||
import okhttp3.ResponseBody
|
||||
|
||||
class CustomPageRemoteDataSource(
|
||||
private val api: ApiService,
|
||||
@ -26,17 +32,52 @@ class CustomPageRemoteDataSource(
|
||||
return newApi.loadPullDownPush(pageId, BuildConfig.VERSION_NAME, HaloApp.getInstance().channel)
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun loadCustomPageData(pageId: String, page: Int, forceLoad: Boolean = false): Single<CustomPageData> {
|
||||
return if (page == 1 &&
|
||||
pageId == mainWrapperRepository.defaultCustomPageId &&
|
||||
mainWrapperRepository.customPageLiveData.value != null &&
|
||||
!forceLoad
|
||||
) {
|
||||
Single.create {
|
||||
it.onSuccess(mainWrapperRepository.customPageLiveData.value!!)
|
||||
return Single.create { emitter ->
|
||||
val customPageData = mainWrapperRepository.customPageLiveData.value
|
||||
if (page == 1 &&
|
||||
pageId == mainWrapperRepository.defaultCustomPageId &&
|
||||
customPageData != null &&
|
||||
!forceLoad
|
||||
) {
|
||||
loadPKDataIfExists(customPageData, emitter)
|
||||
} else {
|
||||
newApi.getCustomPageData(pageId, page)
|
||||
.compose(singleToMain())
|
||||
.subscribe({
|
||||
loadPKDataIfExists(it, emitter)
|
||||
}, {
|
||||
emitter.onError(it)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun loadPKDataIfExists(customPageData: CustomPageData, emitter: SingleEmitter<CustomPageData>) {
|
||||
val pkIdList = arrayListOf<String>()
|
||||
customPageData.customsComponents.forEach { data ->
|
||||
if (data.linkPK != null) {
|
||||
data.linkPK.link?.let { id -> pkIdList.add(id) }
|
||||
}
|
||||
}
|
||||
if (pkIdList.isNotEmpty()) {
|
||||
loadPKData(pkIdList)
|
||||
.compose(singleToMain())
|
||||
.subscribe({ pkList ->
|
||||
pkList.forEach { pkEntity ->
|
||||
val data = customPageData.customsComponents.find { it.linkPK?.link == pkEntity.id }
|
||||
if (data != null) {
|
||||
data.pkData = pkEntity
|
||||
}
|
||||
}
|
||||
emitter.onSuccess(customPageData)
|
||||
}, {
|
||||
emitter.onSuccess(customPageData)
|
||||
})
|
||||
} else {
|
||||
newApi.getCustomPageData(pageId, page)
|
||||
emitter.onSuccess(customPageData)
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,4 +106,18 @@ class CustomPageRemoteDataSource(
|
||||
return api.getDiscoveryGames(1, paramsMap)
|
||||
.map { it.games }
|
||||
}
|
||||
|
||||
fun loadPKData(pkIdList: List<String>): Single<List<PKEntity>> {
|
||||
val data = mapOf(
|
||||
"pk_ids" to pkIdList
|
||||
)
|
||||
return newApi.getPKList(data.toRequestBody())
|
||||
}
|
||||
|
||||
fun postPKVote(pkId: String, isPositive: Boolean): Single<ResponseBody> {
|
||||
val data = mapOf(
|
||||
"result" to if (isPositive) "option1" else "option2"
|
||||
)
|
||||
return newApi.postPK(pkId, data.toRequestBody())
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user