diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 089d884a3c..c2bc541b41 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -739,6 +739,10 @@
android:name=".BbsCertificationActivity"
android:screenOrientation="portrait" />
+
+
diff --git a/app/src/main/java/com/gh/common/util/DialogUtils.java b/app/src/main/java/com/gh/common/util/DialogUtils.java
index 5900cdc175..5140f7d833 100644
--- a/app/src/main/java/com/gh/common/util/DialogUtils.java
+++ b/app/src/main/java/com/gh/common/util/DialogUtils.java
@@ -6,13 +6,11 @@ import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.CountDownTimer;
-import android.preference.PreferenceManager;
import android.provider.Settings;
import android.text.Html;
import android.text.Spannable;
@@ -1325,6 +1323,7 @@ public class DialogUtils {
dialog.show();
}
}
+
public static void showGameH5DownloadDialog(Context context, GameEntity gameEntity, RegionSetting.GameH5Download gameH5Download) {
context = checkDialogContext(context);
@@ -1906,13 +1905,21 @@ public class DialogUtils {
}
}
- @SuppressLint("SetTextI18n")
public static void showReportReasonDialog(Context context, ArrayList items, ReportReasonCallBack callBack) {
+ showReportReasonDialog(context, items, "", callBack);
+ }
+
+ @SuppressLint("SetTextI18n")
+ public static void showReportReasonDialog(Context context, ArrayList items, String title, ReportReasonCallBack callBack) {
context = checkDialogContext(context);
final Dialog dialog = new Dialog(context, R.style.DialogWindowTransparent);
DialogReportReasonBinding binding = DialogReportReasonBinding.inflate(LayoutInflater.from(context));
+ if (!title.isEmpty()) {
+ binding.reasonTitle.setText(title);
+ }
+
ReportReasonAdapter reportReasonAdapter = new ReportReasonAdapter(context, items, reason -> {
if (reason.equals("其他原因")) {
binding.reasonTitle.setText(R.string.report_reason_other_title);
diff --git a/app/src/main/java/com/gh/common/util/DirectUtils.kt b/app/src/main/java/com/gh/common/util/DirectUtils.kt
index 24c6a1e02f..d2b9fd74eb 100644
--- a/app/src/main/java/com/gh/common/util/DirectUtils.kt
+++ b/app/src/main/java/com/gh/common/util/DirectUtils.kt
@@ -35,6 +35,7 @@ import com.gh.gamecenter.common.entity.LinkEntity
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.ToastUtils
+import com.gh.gamecenter.discovery.DiscoveryActivity
import com.gh.gamecenter.download.DownloadFragment.Companion.INDEX_UPDATE
import com.gh.gamecenter.entity.*
import com.gh.gamecenter.eventbus.EBSkip
@@ -95,7 +96,14 @@ object DirectUtils {
* 跳转到特定页面,根据 [type] 决定跳转页面,[path] 为跳转前的页面名称
*/
@JvmStatic
- fun directToSpecificPage(context: Context, type: String, link: String, text: String? = "", entrance: String? = null, path: String? = null) {
+ fun directToSpecificPage(
+ context: Context,
+ type: String,
+ link: String,
+ text: String? = "",
+ entrance: String? = null,
+ path: String? = null
+ ) {
when (type) {
HOST_ARTICLE -> directToArticle(context, id = link, entrance = entrance)
@@ -111,9 +119,19 @@ object DirectUtils {
HOST_WEB -> directToWebView(context, url = link, entrance = entrance)
- HOST_DOWNLOAD -> directToDownloadManagerAndStartDownload(context, gameId = link, packageName = text, entrance = entrance)
+ HOST_DOWNLOAD -> directToDownloadManagerAndStartDownload(
+ context,
+ gameId = link,
+ packageName = text,
+ entrance = entrance
+ )
- HOST_UPDATE -> directToDownloadManagerAndStartUpdate(context, gameId = link, packageName = text, entrance = entrance)
+ HOST_UPDATE -> directToDownloadManagerAndStartUpdate(
+ context,
+ gameId = link,
+ packageName = text,
+ entrance = entrance
+ )
HOST_LIBAO -> directToGiftDetail(context, giftId = link, entrance = entrance)
@@ -126,7 +144,13 @@ object DirectUtils {
directToLinkPage(context, linkEntity, entrance, path, null)
}
- fun directToLinkPage(context: Context, linkEntity: LinkEntity, entrance: String, path: String, exposureEvent: ExposureEvent? = null) {
+ fun directToLinkPage(
+ context: Context,
+ linkEntity: LinkEntity,
+ entrance: String,
+ path: String,
+ exposureEvent: ExposureEvent? = null
+ ) {
directToLinkPage(context, linkEntity, entrance, path, exposureEvent, null)
}
@@ -209,9 +233,21 @@ object DirectUtils {
directToCommunity(context, CommunityEntity(linkEntity.link!!, linkEntity.text!!))
}
- "community_article", "社区文章" -> directToCommunityArticle(context, linkEntity.community!!, linkEntity.link!!, entrance, path)
+ "community_article", "社区文章" -> directToCommunityArticle(
+ context,
+ linkEntity.community!!,
+ linkEntity.link!!,
+ entrance,
+ path
+ )
- "community_column", "社区专题" -> directToCommunityColumn(context, linkEntity.community, linkEntity.link!!, entrance, path)
+ "community_column", "社区专题" -> directToCommunityColumn(
+ context,
+ linkEntity.community,
+ linkEntity.link!!,
+ entrance,
+ path
+ )
"community_special_column" -> directAskColumnDetail(
context, linkEntity.link
@@ -223,7 +259,11 @@ object DirectUtils {
linkEntity.link!!.contains("v.douyin") && PackageHelper.localPackageNameSet.contains("com.ss.android.ugc.aweme") -> {
directDouyin(context, "1402577827140941")
}
- else -> directToWebView(context, url = linkEntity.link!!, entrance = BaseActivity.mergeEntranceAndPath(entrance, path))
+ else -> directToWebView(
+ context,
+ url = linkEntity.link!!,
+ entrance = BaseActivity.mergeEntranceAndPath(entrance, path)
+ )
}
}
@@ -233,7 +273,16 @@ object DirectUtils {
"qqqun", "QQ群" -> directToQqGroup(context, linkEntity.link!!)
- "tag" -> context.startActivity(TagsActivity.getIntent(context, linkEntity.text!!, linkEntity.title, entrance, path, exposureEvent?.source))
+ "tag" -> context.startActivity(
+ TagsActivity.getIntent(
+ context,
+ linkEntity.text!!,
+ linkEntity.title,
+ entrance,
+ path,
+ exposureEvent?.source
+ )
+ )
"all_community_article" -> directSimpleArticleList(
context, linkEntity.link
@@ -244,7 +293,14 @@ object DirectUtils {
"catalog" -> directCatalog(context, linkEntity.link!!, linkEntity.text!!, entrance, path)
- "category_v2" -> directCategoryV2(context, linkEntity.link!!, linkEntity.text!!, entrance, path, exposureEvent)
+ "category_v2" -> directCategoryV2(
+ context,
+ linkEntity.link!!,
+ linkEntity.text!!,
+ entrance,
+ path,
+ exposureEvent
+ )
"block", "版块" -> {
if (linkEntity.link.isNullOrEmpty()) return
@@ -365,7 +421,13 @@ object DirectUtils {
"halo_tab" -> directToPersonalTab(context)
- "common_collection" -> directToCommonCollectionDetail(context, linkEntity.link ?: "", linkEntity.blockId, linkEntity.blockName, entrance)
+ "common_collection" -> directToCommonCollectionDetail(
+ context,
+ linkEntity.link ?: "",
+ linkEntity.blockId,
+ linkEntity.blockName,
+ entrance
+ )
//"h5_game_center" -> directLetoGameCenter(context)
@@ -373,6 +435,8 @@ object DirectUtils {
"game_list_detail" -> directToGameCollectionDetail(context, linkEntity.link ?: "", entrance)
+ "explore_column" -> context.startActivity(DiscoveryActivity.getIntent(context, entrance))
+
"" -> {
// do nothing
}
@@ -416,7 +480,13 @@ object DirectUtils {
* 跳转至专题合集
*/
@JvmStatic
- fun directToColumnCollection(context: Context, id: String, position: Int = -1, entrance: String, columnName: String = "") {
+ fun directToColumnCollection(
+ context: Context,
+ id: String,
+ position: Int = -1,
+ entrance: String,
+ columnName: String = ""
+ ) {
if (id.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_TO, ColumnCollectionDetailActivity::class.java.name)
@@ -594,7 +664,12 @@ object DirectUtils {
* 跳转到游戏评分详情
*/
@JvmStatic
- fun directToGameRatingDetail(context: Context, gameId: String? = "", commentId: String? = "", entrance: String? = null) {
+ fun directToGameRatingDetail(
+ context: Context,
+ gameId: String? = "",
+ commentId: String? = "",
+ entrance: String? = null
+ ) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_GAMEID, gameId)
@@ -618,7 +693,12 @@ object DirectUtils {
}
@JvmStatic
- fun directToGameDetail(context: Context, id: String, defaultTab: Int = GameDetailFragment.INDEX_DESC, entrance: String? = null) {
+ fun directToGameDetail(
+ context: Context,
+ id: String,
+ defaultTab: Int = GameDetailFragment.INDEX_DESC,
+ entrance: String? = null
+ ) {
val bundle = Bundle()
bundle.putString(KEY_TO, GameDetailActivity::class.java.name)
bundle.putString(KEY_ENTRANCE, entrance)
@@ -634,14 +714,23 @@ object DirectUtils {
// 专栏
@JvmStatic
- fun directToSubject(context: Context, id: String, subjectName: String? = "", entrance: String? = null, exposureEvent: ExposureEvent? = null) {
+ fun directToSubject(
+ context: Context,
+ id: String,
+ subjectName: String? = "",
+ entrance: String? = null,
+ exposureEvent: ExposureEvent? = null
+ ) {
if (id.isEmpty()) return
val bundle = Bundle()
val subjectData = SubjectData(subjectId = id, subjectName = subjectName, isOrder = false)
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, SubjectActivity::class.java.name)
bundle.putParcelable(EntranceConsts.KEY_SUBJECT_DATA, subjectData)
- if (exposureEvent != null) bundle.putParcelableArrayList(KEY_EXPOSURE_SOURCE_LIST, ArrayList(exposureEvent.source))
+ if (exposureEvent != null) bundle.putParcelableArrayList(
+ KEY_EXPOSURE_SOURCE_LIST,
+ ArrayList(exposureEvent.source)
+ )
jumpActivity(context, bundle)
}
@@ -693,7 +782,12 @@ object DirectUtils {
* 跳转到下载管理器并开始下载 [gameId] 和 [packageName] 用于唯一确定一个下载文件
*/
@JvmStatic
- fun directToDownloadManagerAndStartDownload(context: Context, gameId: String? = "", packageName: String? = "", entrance: String? = null) {
+ fun directToDownloadManagerAndStartDownload(
+ context: Context,
+ gameId: String? = "",
+ packageName: String? = "",
+ entrance: String? = null
+ ) {
DownloadHelper.createABrandNewDownloadTaskQuietly(gameId, packageName) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
@@ -706,7 +800,12 @@ object DirectUtils {
}
@JvmStatic
- fun directToDownloadManagerAndStartUpdate(context: Context, gameId: String? = "", packageName: String? = "", entrance: String? = null) {
+ fun directToDownloadManagerAndStartUpdate(
+ context: Context,
+ gameId: String? = "",
+ packageName: String? = "",
+ entrance: String? = null
+ ) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, DownloadManagerActivity.TAG)
@@ -892,7 +991,13 @@ object DirectUtils {
}
@JvmStatic
- fun directToCommunityArticle(context: Context, articleId: String?, communityId: String?, entrance: String?, path: String?) {
+ fun directToCommunityArticle(
+ context: Context,
+ articleId: String?,
+ communityId: String?,
+ entrance: String?,
+ path: String?
+ ) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_PATH, path)
@@ -903,7 +1008,13 @@ object DirectUtils {
}
@JvmStatic
- fun directToCommunityArticle(context: Context, community: CommunityEntity?, articleId: String?, entrance: String?, path: String?) {
+ fun directToCommunityArticle(
+ context: Context,
+ community: CommunityEntity?,
+ articleId: String?,
+ entrance: String?,
+ path: String?
+ ) {
if (articleId.isNullOrEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
@@ -918,7 +1029,13 @@ object DirectUtils {
* 跳转到社区专题
*/
@JvmStatic
- fun directToCommunityColumn(context: Context, community: CommunityEntity?, subjectId: String, entrance: String?, path: String?) {
+ fun directToCommunityColumn(
+ context: Context,
+ community: CommunityEntity?,
+ subjectId: String,
+ entrance: String?,
+ path: String?
+ ) {
if (subjectId.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_PATH, path)
@@ -1008,7 +1125,12 @@ object DirectUtils {
* @param fixedTopAmwayCommentId 需要置顶的安利Id
*/
@JvmStatic
- fun directToAmway(context: Context, fixedTopAmwayCommentId: String? = null, entrance: String? = null, path: String? = "") {
+ fun directToAmway(
+ context: Context,
+ fixedTopAmwayCommentId: String? = null,
+ entrance: String? = null,
+ path: String? = ""
+ ) {
val bundle = Bundle()
bundle.putString(KEY_ENTRANCE, entrance ?: ENTRANCE_BROWSER)
bundle.putString(KEY_TO, AmwayActivity::class.java.name)
@@ -1149,7 +1271,13 @@ object DirectUtils {
* 跳转分类
*/
@JvmStatic
- fun directCategoryDirectory(context: Context, categoryId: String, categoryTitle: String, entrance: String? = null, path: String? = "") {
+ fun directCategoryDirectory(
+ context: Context,
+ categoryId: String,
+ categoryTitle: String,
+ entrance: String? = null,
+ path: String? = ""
+ ) {
if (categoryId.isEmpty()) return
val bundle = Bundle()
bundle.putString(KEY_TO, CategoryDirectoryActivity::class.java.name)
@@ -1198,7 +1326,10 @@ object DirectUtils {
bundle.putString(KEY_CATEGORY_ID, categoryId)
bundle.putString(KEY_CATEGORY_TITLE, categoryTitle)
bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path))
- if (exposureEvent != null) bundle.putParcelableArrayList(KEY_EXPOSURE_SOURCE_LIST, ArrayList(exposureEvent.source))
+ if (exposureEvent != null) bundle.putParcelableArrayList(
+ KEY_EXPOSURE_SOURCE_LIST,
+ ArrayList(exposureEvent.source)
+ )
jumpActivity(context, bundle)
}
@@ -1206,7 +1337,13 @@ object DirectUtils {
* 跳转到问题标签详情
*/
@JvmStatic
- fun directAskColumnLabelDetail(context: Context, tag: String, community: CommunityEntity, entrance: String? = null, path: String? = "") {
+ fun directAskColumnLabelDetail(
+ context: Context,
+ tag: String,
+ community: CommunityEntity,
+ entrance: String? = null,
+ path: String? = ""
+ ) {
// val bundle = Bundle()
// bundle.putString(KEY_TO, AskColumnDetailActivity::class.java.name)
// bundle.putString(KEY_ASK_TAG, tag)
@@ -1220,7 +1357,13 @@ object DirectUtils {
* 跳转到专栏详情
*/
@JvmStatic
- fun directAskColumnDetail(context: Context, columnId: String, community: CommunityEntity, entrance: String? = null, path: String? = "") {
+ fun directAskColumnDetail(
+ context: Context,
+ columnId: String,
+ community: CommunityEntity,
+ entrance: String? = null,
+ path: String? = ""
+ ) {
// if (columnId.isEmpty()) return
// val bundle = Bundle()
// bundle.putString(KEY_TO, AskColumnDetailActivity::class.java.name)
@@ -1430,7 +1573,13 @@ object DirectUtils {
Constants.COMMODITY_DETAIL_ADDRESS
}
- url = String.format(Locale.CHINA, "%s&shopid=%s×tamp=%d", url, commodityId, (Date().time / 1000 / 1000.toFloat()).roundToInt())
+ url = String.format(
+ Locale.CHINA,
+ "%s&shopid=%s×tamp=%d",
+ url,
+ commodityId,
+ (Date().time / 1000 / 1000.toFloat()).roundToInt()
+ )
directToFullScreenWebPage(context, url, true)
}
@@ -1450,7 +1599,13 @@ object DirectUtils {
Constants.ENERGY_RECORD_ADDRESS
}
- url = String.format(Locale.CHINA, "%s&position=%s×tamp=%d", url, position, (Date().time / 1000 / 1000.toFloat()).roundToInt())
+ url = String.format(
+ Locale.CHINA,
+ "%s&position=%s×tamp=%d",
+ url,
+ position,
+ (Date().time / 1000 / 1000.toFloat()).roundToInt()
+ )
directToFullScreenWebPage(context, url, true)
}
@@ -1478,7 +1633,13 @@ object DirectUtils {
Constants.ORDER_DETAIL_ADDRESS
}
- url = String.format(Locale.CHINA, "%s&order_id=%s×tamp=%d", url, orderId, (Date().time / 1000 / 1000.toFloat()).roundToInt())
+ url = String.format(
+ Locale.CHINA,
+ "%s&order_id=%s×tamp=%d",
+ url,
+ orderId,
+ (Date().time / 1000 / 1000.toFloat()).roundToInt()
+ )
directToFullScreenWebPage(context, url, true)
}
diff --git a/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryActivity.kt b/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryActivity.kt
new file mode 100644
index 0000000000..ff327ad4a2
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryActivity.kt
@@ -0,0 +1,36 @@
+package com.gh.gamecenter.discovery
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import com.gh.gamecenter.R
+import com.gh.gamecenter.common.base.activity.ToolBarActivity
+import com.gh.gamecenter.common.constant.EntranceConsts
+import com.gh.gamecenter.common.utils.updateStatusBarColor
+
+/**
+ * 猜你喜欢-发现页
+ */
+class DiscoveryActivity : ToolBarActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ updateStatusBarColor(R.color.background_white, R.color.background_white)
+ setNavigationTitle("发现")
+ }
+
+ override fun isAutoResetViewBackgroundEnabled(): Boolean = true
+
+ override fun onDarkModeChanged() {
+ super.onDarkModeChanged()
+ updateStatusBarColor(R.color.background_white, R.color.background_white)
+ }
+
+ companion object {
+ fun getIntent(context: Context, entrance: String): Intent {
+ val bundle = Bundle()
+ bundle.putString(EntranceConsts.KEY_ENTRANCE, entrance)
+ return getTargetIntent(context, DiscoveryActivity::class.java, DiscoveryFragment::class.java, bundle)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryAdapter.kt b/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryAdapter.kt
new file mode 100644
index 0000000000..cfdc504bae
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryAdapter.kt
@@ -0,0 +1,262 @@
+package com.gh.gamecenter.discovery
+
+import android.content.Context
+import android.util.SparseArray
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.exposure.ExposureEvent
+import com.gh.common.exposure.ExposureSource
+import com.gh.common.exposure.ExposureType
+import com.gh.common.exposure.IExposable
+import com.gh.common.util.DialogUtils
+import com.gh.common.util.DirectUtils
+import com.gh.common.util.DownloadItemUtils
+import com.gh.gamecenter.GameDetailActivity
+import com.gh.gamecenter.MainActivity
+import com.gh.gamecenter.R
+import com.gh.gamecenter.adapter.viewholder.GameViewHolder
+import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
+import com.gh.gamecenter.common.base.activity.BaseActivity
+import com.gh.gamecenter.common.baselist.ListAdapter
+import com.gh.gamecenter.common.constant.Constants
+import com.gh.gamecenter.common.constant.ItemViewType
+import com.gh.gamecenter.common.utils.dip2px
+import com.gh.gamecenter.common.utils.goneIf
+import com.gh.gamecenter.common.utils.ifLogin
+import com.gh.gamecenter.common.utils.toBinding
+import com.gh.gamecenter.common.viewholder.FooterViewHolder
+import com.gh.gamecenter.core.utils.StringUtils
+import com.gh.gamecenter.databinding.ItemRecommendInterestBinding
+import com.gh.gamecenter.databinding.ItemRecommendInterestFooterBinding
+import com.gh.gamecenter.databinding.ItemRecommendInterestImageBinding
+import com.gh.gamecenter.entity.GameEntity
+import com.gh.gamecenter.eventbus.EBDownloadStatus
+import com.gh.gamecenter.eventbus.EBSkip
+import com.gh.gamecenter.fragment.MainWrapperFragment
+import com.gh.gamecenter.game.GameItemViewHolder
+import com.lightgame.download.DownloadEntity
+import org.greenrobot.eventbus.EventBus
+
+class DiscoveryAdapter(
+ context: Context,
+ val mViewModel: DiscoveryViewModel,
+ val entrance: String
+) : ListAdapter(context), IExposable {
+
+ private val mExposureEventSparseArray: SparseArray = SparseArray()
+
+ override fun getItemViewType(position: Int): Int {
+ when (position) {
+ itemCount - 2 -> {
+ return ITEM_DIRECT_GAME_BLOCK
+ }
+ itemCount - 1 -> {
+ return ItemViewType.ITEM_FOOTER
+ }
+ else -> {
+ val itemData = mEntityList[position]
+ return when {
+ itemData.interestCardLabels != null -> {
+ ITEM_RECOMMEND_INTEREST
+ }
+ itemData.interestImageCardLabel != null -> {
+ ITEM_RECOMMEND_INTEREST_IMAGE
+ }
+ else -> {
+ ItemViewType.GAME_NORMAL
+ }
+ }
+ }
+ }
+
+ }
+
+ override fun areItemsTheSame(oldItem: DiscoveryItemData?, newItem: DiscoveryItemData?): Boolean {
+ return oldItem?.gameEntity?.id == newItem?.gameEntity?.id
+ || oldItem?.interestCardLabels?.firstOrNull()?.id == newItem?.interestCardLabels?.firstOrNull()?.id
+ || oldItem?.interestImageCardLabel?.id == newItem?.interestImageCardLabel?.id
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ return when (viewType) {
+ ItemViewType.GAME_NORMAL -> {
+ GameItemViewHolder(parent.toBinding())
+ }
+ ItemViewType.ITEM_FOOTER -> {
+ FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false))
+ }
+ ITEM_DIRECT_GAME_BLOCK -> {
+ DirectGameBlockViewHolder(parent.toBinding())
+ }
+ ITEM_RECOMMEND_INTEREST -> {
+ RecommendInterestViewHolder(parent.toBinding())
+ }
+ ITEM_RECOMMEND_INTEREST_IMAGE -> {
+ RecommendInterestImageViewHolder(parent.toBinding())
+ }
+ else -> {
+ throw NullPointerException()
+ }
+ }
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ when (holder) {
+ is GameItemViewHolder -> {
+ val itemData = mEntityList[position]
+ val gameEntity = itemData.gameEntity!!
+ holder.bindGameItem(gameEntity)
+
+ val exposureSources = ArrayList()
+ val event = ExposureEvent.createEvent(gameEntity, exposureSources, null, ExposureType.EXPOSURE)
+ mExposureEventSparseArray.put(position, event)
+
+ holder.itemView.setOnClickListener {
+ GameDetailActivity.startGameDetailActivity(
+ mContext,
+ gameEntity,
+ StringUtils.buildString("(${entrance}", "-列表[", (position).toString(), "])"),
+ traceEvent = event
+ )
+ }
+ holder.itemView.setOnLongClickListener {
+ discoveryFeedback(position, gameEntity)
+ true
+ }
+ DownloadItemUtils.setOnClickListener(
+ mContext,
+ holder.binding.downloadBtn,
+ gameEntity,
+ position,
+ this,
+ StringUtils.buildString("(${entrance}", "-列表[", (position).toString(), "])"),
+ StringUtils.buildString(entrance, ":", gameEntity.name),
+ event
+ )
+
+ DownloadItemUtils.updateItem(mContext, gameEntity, GameViewHolder(holder.binding), true)
+ holder.itemView.setPadding(16f.dip2px(), 8f.dip2px(), 16f.dip2px(), 8f.dip2px())
+ }
+ is RecommendInterestViewHolder -> {
+ val labels = mEntityList[position].interestCardLabels ?: return
+ holder.binding.labelTv1.goneIf(labels.size < 1) {
+ holder.binding.labelTv1.text = labels[0].title
+ holder.binding.labelTv1.setOnClickListener {
+ DirectUtils.directToLinkPage(holder.binding.root.context, labels[0], entrance, "")
+ }
+ }
+ holder.binding.labelTv2.goneIf(labels.size < 2) {
+ holder.binding.labelTv2.text = labels[1].title
+ holder.binding.labelTv2.setOnClickListener {
+ DirectUtils.directToLinkPage(holder.binding.root.context, labels[1], entrance, "")
+ }
+ }
+ holder.binding.labelTv3.goneIf(labels.size < 3) {
+ holder.binding.labelTv3.text = labels[2].title
+ holder.binding.labelTv3.setOnClickListener {
+ DirectUtils.directToLinkPage(holder.binding.root.context, labels[2], entrance, "")
+ }
+ }
+ }
+ is RecommendInterestImageViewHolder -> {
+ val label = mEntityList[position].interestImageCardLabel ?: return
+ holder.binding.root.setOnClickListener {
+ DirectUtils.directToLinkPage(holder.binding.root.context, label, entrance, "")
+ }
+ }
+ is DirectGameBlockViewHolder -> {
+ holder.binding.root.setOnClickListener {
+ EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_GAME))
+ }
+ }
+
+ is FooterViewHolder -> {
+ holder.initFooterViewHolder(mIsLoading, mIsNetworkError, mIsOver)
+ }
+ }
+ }
+
+ override fun getItemCount(): Int {
+ return if (mEntityList == null || mEntityList.isEmpty()) return 0 else mEntityList.size + 2
+ }
+
+ private fun discoveryFeedback(position: Int, gameEntity: GameEntity) {
+ mContext.ifLogin(entrance) {
+ DialogUtils.showReportReasonDialog(
+ mContext,
+ Constants.FEEDBACK_REASON_LIST.toList() as ArrayList,
+ "不喜欢的原因"
+ ) { reason, desc ->
+ mViewModel.discoveryFeedback(gameEntity.id, reason, gameEntity.type ?: "") {
+ mEntityList.removeAt(position)
+ notifyItemRemoved(position)
+ }
+ }
+ }
+ }
+
+ fun notifyItemByDownload(download: DownloadEntity) {
+ val positionAndPackageMap = mViewModel.positionAndPackageMap
+ for (key in positionAndPackageMap.keys) {
+ if (key.contains(download.packageName)) {
+ val position = positionAndPackageMap[key]
+ if (position != null && mEntityList != null && position < mEntityList.size) {
+ mEntityList[position].gameEntity?.let {
+ it.getEntryMap()[download.platform] = download
+ }
+ notifyItemChanged(position)
+ }
+ }
+ }
+ }
+
+ fun notifyItemAndRemoveDownload(status: EBDownloadStatus) {
+ val positionAndPackageMap = mViewModel.positionAndPackageMap
+ for (key in positionAndPackageMap.keys) {
+ if (key.contains(status.packageName)) {
+ val position = positionAndPackageMap[key]
+ if (position != null && mEntityList != null && position < mEntityList.size) {
+ mEntityList[position].gameEntity?.let {
+ it.getEntryMap().remove(status.platform)
+ }
+ notifyItemChanged(position)
+ }
+ }
+ }
+ }
+
+ fun clearPositionAndPackageMap() {
+ mViewModel.positionAndPackageMap.clear()
+ }
+
+ override fun getEventByPosition(pos: Int): ExposureEvent? {
+ return mExposureEventSparseArray.get(pos)
+ }
+
+ override fun getEventListByPosition(pos: Int): List? {
+ return null
+ }
+
+
+ class RecommendInterestViewHolder(val binding: ItemRecommendInterestBinding) :
+ BaseRecyclerViewHolder(binding.root) {
+
+ }
+
+ class RecommendInterestImageViewHolder(val binding: ItemRecommendInterestImageBinding) :
+ BaseRecyclerViewHolder(binding.root) {
+
+ }
+
+ class DirectGameBlockViewHolder(val binding: ItemRecommendInterestFooterBinding) :
+ BaseRecyclerViewHolder(binding.root) {
+
+ }
+
+ companion object {
+ const val ITEM_RECOMMEND_INTEREST = 200
+ const val ITEM_RECOMMEND_INTEREST_IMAGE = 201
+ const val ITEM_DIRECT_GAME_BLOCK = 202
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryFragment.kt b/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryFragment.kt
new file mode 100644
index 0000000000..67778fde98
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryFragment.kt
@@ -0,0 +1,158 @@
+package com.gh.gamecenter.discovery
+
+import android.view.LayoutInflater
+import android.widget.FrameLayout
+import android.widget.RelativeLayout
+import androidx.appcompat.app.AppCompatActivity
+import androidx.recyclerview.widget.RecyclerView
+import com.ethanhua.skeleton.Skeleton
+import com.gh.common.util.DialogUtils
+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.LazyListFragment
+import com.gh.gamecenter.common.baselist.ListAdapter
+import com.gh.gamecenter.common.constant.Constants
+import com.gh.gamecenter.common.utils.dip2px
+import com.gh.gamecenter.common.utils.getBitmapFromView
+import com.gh.gamecenter.common.utils.toColor
+import com.gh.gamecenter.core.AppExecutor
+import com.gh.gamecenter.core.utils.SPUtils
+import com.gh.gamecenter.databinding.LayoutDiscoveryGuideBinding
+import com.gh.gamecenter.eventbus.EBDownloadStatus
+import com.gh.gamecenter.eventbus.EBPackage
+import com.lightgame.download.DataWatcher
+import com.lightgame.download.DownloadEntity
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
+
+class DiscoveryFragment : LazyListFragment() {
+
+ private var mAdapter: DiscoveryAdapter? = null
+
+ private val dataWatcher = object : DataWatcher() {
+ override fun onDataChanged(downloadEntity: DownloadEntity) {
+ mAdapter?.notifyItemByDownload(downloadEntity)
+ if (downloadEntity.meta[XapkInstaller.XAPK_UNZIP_STATUS] == XapkUnzipStatus.FAILURE.name) {
+ showUnzipFailureDialog(downloadEntity)
+ }
+ }
+
+ override fun onDataInit(downloadEntity: DownloadEntity) {
+ mAdapter?.notifyItemByDownload(downloadEntity)
+ }
+ }
+
+ override fun initRealView() {
+ super.initRealView()
+ mSkeletonScreen = Skeleton.bind(mSkeletonScreenView)
+ .shimmer(true)
+ .angle(Constants.SHIMMER_ANGLE)
+ .color(R.color.skeleton_shimmer_color)
+ .duration(Constants.SHIMMER_DURATION)
+ .maskWidth(Constants.MASK_WIDTH)
+ .gradientCenterColorWidth(Constants.GRADIENT_CENTER_COLOR_WIDTH)
+ .apply {
+ load(R.layout.fragment_discovery_skeleton)
+ }
+ .show()
+ }
+
+
+ override fun provideListAdapter(): ListAdapter<*> {
+ return mAdapter ?: DiscoveryAdapter(requireContext(), mListViewModel,"发现页").also { mAdapter = it }
+ }
+
+ override fun onFragmentResume() {
+ super.onFragmentResume()
+ DownloadManager.getInstance().addObserver(dataWatcher)
+ }
+
+ override fun onFragmentPause() {
+ super.onFragmentPause()
+ DownloadManager.getInstance().removeObserver(dataWatcher)
+ }
+
+ override fun getItemDecoration(): RecyclerView.ItemDecoration? = null
+
+ private fun showUnzipFailureDialog(downloadEntity: DownloadEntity) {
+ val data = mListViewModel.positionAndPackageMap
+ for (gameAndPosition in data) {
+ if (gameAndPosition.key.contains(downloadEntity.packageName)) {
+ val targetView = mLayoutManager.findViewByPosition(gameAndPosition.value)
+ if (targetView != null) {
+ DialogUtils.showUnzipFailureDialog(requireContext(), downloadEntity)
+ return
+ }
+ }
+ }
+ }
+
+ override fun onChanged(ts: MutableList?) {
+ super.onChanged(ts)
+ val isFirstGuide = SPUtils.getBoolean(Constants.SP_DISCOVERY_GUIDE, true)
+ if (!isFirstGuide) return
+ AppExecutor.uiExecutor.executeWithDelay({
+ showGuideView()
+ SPUtils.setBoolean(Constants.SP_DISCOVERY_GUIDE, false)
+ }, 800)
+ }
+
+ private fun showGuideView() {
+ if (!isSupportVisible) return
+ val firstView = mListRv.layoutManager?.findViewByPosition(0)
+ if (firstView != null && requireActivity() is AppCompatActivity) {
+ val location = IntArray(2)
+ firstView.getLocationInWindow(location)
+ val decorView = requireActivity().window.decorView as? FrameLayout
+ val guideViewBinding =
+ LayoutDiscoveryGuideBinding.inflate(LayoutInflater.from(requireContext()), decorView, true)
+ val originalBackground = firstView.background
+ firstView.setBackgroundColor(
+ if (mIsDarkModeOn) R.color.black.toColor(requireContext()) else R.color.white.toColor(
+ requireContext()
+ )
+ )
+ guideViewBinding.guideImageContainer.setCardBackgroundColor(
+ if (mIsDarkModeOn) R.color.black.toColor(requireContext()) else R.color.white.toColor(
+ requireContext()
+ )
+ )
+ val snapshotBitmap = firstView.getBitmapFromView(
+ firstView.width - 16f.dip2px(),
+ firstView.height,
+ -8f.dip2px().toFloat(),
+ 0f
+ )
+ firstView.background = originalBackground
+ guideViewBinding.guideImage.setImageBitmap(snapshotBitmap)
+ (guideViewBinding.guideImageContainer.layoutParams as RelativeLayout.LayoutParams).run {
+ topMargin = location[1]
+ guideViewBinding.guideImageContainer.layoutParams = this
+ }
+ guideViewBinding.root.setOnClickListener {
+ decorView?.removeView(it)
+ }
+ }
+ }
+
+ override fun isAutomaticLoad(): Boolean = false
+
+ // 下载被删除事件
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ fun onEventMainThread(status: EBDownloadStatus) {
+ if ("delete" == status.status) {
+ mAdapter?.notifyItemAndRemoveDownload(status)
+ }
+ }
+
+ // 安装/卸载 事件
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ fun onEventMainThread(busFour: EBPackage) {
+ if ("安装" == busFour.type || "卸载" == busFour.type) {
+ mAdapter?.notifyDataSetChanged()
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryItemData.kt b/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryItemData.kt
new file mode 100644
index 0000000000..f2257e7b3c
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryItemData.kt
@@ -0,0 +1,12 @@
+package com.gh.gamecenter.discovery
+
+import androidx.annotation.Keep
+import com.gh.gamecenter.entity.DiscoveryGameCardLabel
+import com.gh.gamecenter.entity.GameEntity
+
+@Keep
+data class DiscoveryItemData(
+ val gameEntity: GameEntity? = null,
+ val interestCardLabels: ArrayList? = null,
+ val interestImageCardLabel: DiscoveryGameCardLabel? = null
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryViewModel.kt b/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryViewModel.kt
new file mode 100644
index 0000000000..b85b2f68a1
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryViewModel.kt
@@ -0,0 +1,159 @@
+package com.gh.gamecenter.discovery
+
+import android.annotation.SuppressLint
+import android.app.Application
+import com.gh.download.DownloadManager
+import com.gh.gamecenter.common.baselist.ListViewModel
+import com.gh.gamecenter.common.baselist.LoadStatus
+import com.gh.gamecenter.common.baselist.LoadType
+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.EnvHelper
+import com.gh.gamecenter.common.utils.observableToMain
+import com.gh.gamecenter.common.utils.singleToMain
+import com.gh.gamecenter.common.utils.toRequestBody
+import com.gh.gamecenter.entity.DiscoveryGameCardLabel
+import com.gh.gamecenter.entity.GameEntity
+import com.gh.gamecenter.entity.TagEntity
+import com.gh.gamecenter.retrofit.RetrofitManager
+import io.reactivex.Observable
+import okhttp3.ResponseBody
+import retrofit2.HttpException
+
+class DiscoveryViewModel(application: Application) : ListViewModel(application) {
+
+ val positionAndPackageMap = HashMap()
+ private val mApi = RetrofitManager.getInstance().api
+ private var mGameTags: ArrayList? = null
+ private var mDiscoveryGameCardLabels: ArrayList? = null
+ private var mDiscoveryGameCardLabelMap: LinkedHashMap> = linkedMapOf()
+
+ init {
+ getCardLabels()
+ }
+
+ override fun mergeResultLiveData() {
+ mResultLiveData.addSource(mListLiveData) {
+ val itemDataList = arrayListOf()
+ it.forEachIndexed { index, gameEntity ->
+ itemDataList.add(DiscoveryItemData(gameEntity))
+ addGamePositionAndPackage(index, gameEntity)
+ //第6、12、18、24个游戏后面固定插入兴趣推荐卡片
+ when (index) {
+ 5 -> {
+ itemDataList.add(DiscoveryItemData(interestCardLabels = mDiscoveryGameCardLabelMap["卡片一"]))
+ }
+ 11 -> {
+ itemDataList.add(
+ DiscoveryItemData(
+ interestImageCardLabel = mDiscoveryGameCardLabelMap["卡片二"]?.get(0)
+ )
+ )
+ }
+ 17 -> {
+ itemDataList.add(DiscoveryItemData(interestCardLabels = mDiscoveryGameCardLabelMap["卡片三"]))
+ }
+ 23 -> {
+ itemDataList.add(DiscoveryItemData(interestCardLabels = mDiscoveryGameCardLabelMap["卡片四"]))
+ }
+ else -> {
+ //do nothing
+ }
+ }
+ }
+ mResultLiveData.postValue(itemDataList)
+ }
+ }
+
+ override fun provideDataObservable(page: Int): Observable>? {
+ return mApi.getDiscoveryGames(page).map {
+ if (page == 1) {
+ mGameTags = it.gameTags
+ groupingDiscoveryLabel()
+ }
+ it.games
+ }
+ }
+
+ //按照card字段分组
+ private fun groupingDiscoveryLabel() {
+ mDiscoveryGameCardLabelMap.clear()
+ var tagIndex = 0
+ mDiscoveryGameCardLabels?.forEach {
+ if (mDiscoveryGameCardLabelMap.contains(it.card)) {
+ mDiscoveryGameCardLabelMap[it.card]?.add(it)
+ } else {
+ mDiscoveryGameCardLabelMap[it.card] = arrayListOf(it)
+ }
+ }
+ //如果it.link为空需要在mGameTags中依次获取
+ mDiscoveryGameCardLabelMap.keys.forEach {
+ val labels = mDiscoveryGameCardLabelMap[it]
+ labels?.forEach { label ->
+ if (!mGameTags.isNullOrEmpty() && mGameTags!!.size > tagIndex && label.link.isNullOrEmpty()) {
+ val gameTag = mGameTags!![tagIndex]
+ label.link = gameTag.link
+ label.type = gameTag.type
+ label.text = gameTag.linkText
+ label.title = gameTag.linkText
+ tagIndex++
+ }
+ }
+
+ }
+ }
+
+ private fun getCardLabels() {
+ mApi.cardLabels
+ .compose(observableToMain())
+ .subscribe(object : Response>() {
+ override fun onResponse(response: ArrayList?) {
+ super.onResponse(response)
+ mDiscoveryGameCardLabels = response
+ initLoadParams()
+ loadData()
+ }
+
+ override fun onFailure(e: HttpException?) {
+ super.onFailure(e)
+ mLoadStatusLiveData.value = LoadStatus.INIT_FAILED
+ }
+ })
+ }
+
+ @SuppressLint("CheckResult")
+ fun discoveryFeedback(gameId: String, reason: String, type: String, callback: () -> Unit) {
+ val paramsMap = mapOf(
+ "reason" to reason,
+ "type" to type
+ )
+ mApi.discorveryFeedback(gameId, paramsMap.toRequestBody())
+ .compose(singleToMain())
+ .subscribe(object : BiResponse() {
+ override fun onSuccess(data: ResponseBody) {
+ callback.invoke()
+ }
+ })
+ }
+
+ private fun addGamePositionAndPackage(position: Int, game: GameEntity) {
+ var packages = ""
+ for (apkEntity in game.getApk()) {
+ packages += apkEntity.packageName
+ }
+ positionAndPackageMap[packages + (position)] = position
+ game.gameLocation = GameEntity.GameLocation.INDEX
+ game.setEntryMap(DownloadManager.getInstance().getEntryMap(game.name))
+ }
+
+ override fun load(loadType: LoadType?) {
+ if (loadType == LoadType.REFRESH) {
+ getCardLabels()
+ } else {
+ super.load(loadType)
+ }
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/entity/DiscoveryGameCardEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/DiscoveryGameCardEntity.kt
new file mode 100644
index 0000000000..f7c1568edf
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/entity/DiscoveryGameCardEntity.kt
@@ -0,0 +1,14 @@
+package com.gh.gamecenter.entity
+
+import com.gh.gamecenter.common.entity.LinkEntity
+import com.google.gson.annotations.SerializedName
+
+data class DiscoveryGameCardEntity(
+ val more: Int,
+ @SerializedName("game_tags")
+ val gameTags: ArrayList = arrayListOf(),
+ @SerializedName("data")
+ val games: ArrayList = arrayListOf()
+)
+
+
diff --git a/app/src/main/java/com/gh/gamecenter/entity/DiscoveryGameCardLabel.kt b/app/src/main/java/com/gh/gamecenter/entity/DiscoveryGameCardLabel.kt
new file mode 100644
index 0000000000..9f15a3e35b
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/entity/DiscoveryGameCardLabel.kt
@@ -0,0 +1,11 @@
+package com.gh.gamecenter.entity
+
+import com.gh.gamecenter.common.entity.LinkEntity
+import com.google.gson.annotations.SerializedName
+
+data class DiscoveryGameCardLabel(
+ @SerializedName("_id")
+ val id: String = "",
+ val card: String = "",
+ val order: Int = 0,
+) : LinkEntity()
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt
index f70d0e2032..c1aef91805 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt
@@ -291,6 +291,9 @@ data class GameEntity(
var welcomeDialogId: String? = null,
var welcomeDialogTitle: String? = null,
+ @SerializedName("column_rank")
+ var columnRank: ColumnRank? = null,//榜单详情
+
// 专题id,用于曝光使用
var subjectId: String? = null,
// 专题名字,用于曝光使用
@@ -836,6 +839,12 @@ data class GameEntity(
var url: String = ""
) : Parcelable
}
+
+ @Parcelize
+ data class ColumnRank(
+ val name: String = "",
+ val position: Int = 0
+ ) : Parcelable
}
@Parcelize
diff --git a/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperFragment.kt b/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperFragment.kt
index 5d833664c8..5618a77bc0 100644
--- a/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/fragment/HomeSearchToolWrapperFragment.kt
@@ -25,6 +25,7 @@ import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.databinding.FragmentMainHomeWrapperBinding
import com.gh.gamecenter.databinding.TabItemMainBinding
+import com.gh.gamecenter.discovery.DiscoveryFragment
import com.gh.gamecenter.entity.SubjectData
import com.gh.gamecenter.entity.SubjectRecommendEntity
import com.gh.gamecenter.game.GameFragment
@@ -207,7 +208,10 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
if (isContentStyleChanged) {
updateIndicatorDrawable()
- DisplayUtils.setLightStatusBar(requireActivity(), !mIsDisplayingLightContent && !mIsDarkModeOn)
+ DisplayUtils.setLightStatusBar(
+ requireActivity(),
+ !mIsDisplayingLightContent && !mIsDarkModeOn
+ )
}
mTabTitleList[position].run {
@@ -277,10 +281,12 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
tab.customView = tabViewBinding.root
tab.view.setPadding(0, 0, 0, 0)
if (i == 0) {
- tab.view.layoutParams = (tab.view.layoutParams as LinearLayout.LayoutParams).apply { setMargins(10F.dip2px(), 0, 0, 0) }
+ tab.view.layoutParams =
+ (tab.view.layoutParams as LinearLayout.LayoutParams).apply { setMargins(10F.dip2px(), 0, 0, 0) }
}
if (i == mBinding?.tabLayout?.tabCount!! - 1) {
- tab.view.layoutParams = (tab.view.layoutParams as LinearLayout.LayoutParams).apply { setMargins(0, 0, 10F.dip2px(), 0) }
+ tab.view.layoutParams =
+ (tab.view.layoutParams as LinearLayout.LayoutParams).apply { setMargins(0, 0, 10F.dip2px(), 0) }
}
}
}
@@ -307,7 +313,8 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
currentTab?.offsetRatio = offset / totalHeight.toFloat()
if ((currentTab?.isTopViewShow == true && offset >= totalHeight)
- || currentTab?.isSlideEmpty == true) {
+ || currentTab?.isSlideEmpty == true
+ ) {
currentTab.isTopViewShow = false
currentTab.primaryColor = backgroundWhiteColor
currentTab.useLightStyle = false
@@ -374,7 +381,11 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
currentTab.currentSelectColor = color
if (currentTab.isTopViewShow) {
val colorInBetween =
- ColorUtils.blendARGB(color, R.color.background_white.toColor(requireContext()), currentTab.offsetRatio)
+ ColorUtils.blendARGB(
+ color,
+ R.color.background_white.toColor(requireContext()),
+ currentTab.offsetRatio
+ )
currentTab.primaryColor = colorInBetween
updateAppBarStyle(colorInBetween, colorInBetween != R.color.background_white.toColor(requireContext()))
}
@@ -476,6 +487,9 @@ class HomeSearchToolWrapperFragment : SearchToolWrapperFragment() {
putString(EntranceConsts.KEY_COLLECTION_ID, tab.link)
putString(EntranceConsts.KEY_COLUMNNAME, tab.text)
})
+ "explore_column" -> DiscoveryFragment().with(Bundle().apply {
+ putString(EntranceConsts.KEY_ENTRANCE, "首页")
+ })
"bbs" -> Fragment()
else -> Fragment()
}
diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java
index 76198e0662..a7d7245915 100644
--- a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java
+++ b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java
@@ -2987,4 +2987,22 @@ public interface ApiService {
*/
@POST("mobile_auth/{user_id}:unbind")
Single unBindPhone();
+
+ /**
+ * 获取发现页游戏列表
+ */
+ @GET("home/explore/games")
+ Observable getDiscoveryGames(@Query("page") int page);
+
+ /**
+ * 获取发现页卡片列表
+ */
+ @GET("home/explore/cards")
+ Observable> getCardLabels();
+
+ /**
+ * 反馈游戏
+ */
+ @POST("home/explore/games/{game_id}/feedback")
+ Single discorveryFeedback(@Path("game_id") String gameId, @Body RequestBody body);
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable-night-xxxhdpi/bg_recommend_interest.webp b/app/src/main/res/drawable-night-xxxhdpi/bg_recommend_interest.webp
new file mode 100644
index 0000000000..5d38c081b3
Binary files /dev/null and b/app/src/main/res/drawable-night-xxxhdpi/bg_recommend_interest.webp differ
diff --git a/app/src/main/res/drawable-night-xxxhdpi/bg_recommend_interest_footer.webp b/app/src/main/res/drawable-night-xxxhdpi/bg_recommend_interest_footer.webp
new file mode 100644
index 0000000000..c69e8e6dc9
Binary files /dev/null and b/app/src/main/res/drawable-night-xxxhdpi/bg_recommend_interest_footer.webp differ
diff --git a/app/src/main/res/drawable-night-xxxhdpi/ic_discovery_guide.webp b/app/src/main/res/drawable-night-xxxhdpi/ic_discovery_guide.webp
new file mode 100644
index 0000000000..e66cfccd57
Binary files /dev/null and b/app/src/main/res/drawable-night-xxxhdpi/ic_discovery_guide.webp differ
diff --git a/app/src/main/res/drawable-night-xxxhdpi/ic_interest_arrow.png b/app/src/main/res/drawable-night-xxxhdpi/ic_interest_arrow.png
new file mode 100644
index 0000000000..b43159152d
Binary files /dev/null and b/app/src/main/res/drawable-night-xxxhdpi/ic_interest_arrow.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/bg_recommend_interest.webp b/app/src/main/res/drawable-xxxhdpi/bg_recommend_interest.webp
new file mode 100644
index 0000000000..590092f152
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_recommend_interest.webp differ
diff --git a/app/src/main/res/drawable-xxxhdpi/bg_recommend_interest_footer.webp b/app/src/main/res/drawable-xxxhdpi/bg_recommend_interest_footer.webp
new file mode 100644
index 0000000000..081fb54b0c
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/bg_recommend_interest_footer.webp differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_discovery_guide.webp b/app/src/main/res/drawable-xxxhdpi/ic_discovery_guide.webp
new file mode 100644
index 0000000000..dc82ce95af
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_discovery_guide.webp differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_interest.webp b/app/src/main/res/drawable-xxxhdpi/ic_interest.webp
new file mode 100644
index 0000000000..f2cff1e433
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_interest.webp differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_interest_arrow.png b/app/src/main/res/drawable-xxxhdpi/ic_interest_arrow.png
new file mode 100644
index 0000000000..b371bb7ba8
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_interest_arrow.png differ
diff --git a/app/src/main/res/drawable/bg_shape_white_radius_4.xml b/app/src/main/res/drawable/bg_shape_white_radius_4.xml
new file mode 100644
index 0000000000..4e6ce5c702
--- /dev/null
+++ b/app/src/main/res/drawable/bg_shape_white_radius_4.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_discovery_skeleton.xml b/app/src/main/res/layout/fragment_discovery_skeleton.xml
new file mode 100644
index 0000000000..c4db497e9c
--- /dev/null
+++ b/app/src/main/res/layout/fragment_discovery_skeleton.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_recommend_interest.xml b/app/src/main/res/layout/item_recommend_interest.xml
new file mode 100644
index 0000000000..e1503d85bd
--- /dev/null
+++ b/app/src/main/res/layout/item_recommend_interest.xml
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_recommend_interest_footer.xml b/app/src/main/res/layout/item_recommend_interest_footer.xml
new file mode 100644
index 0000000000..d3c03a261e
--- /dev/null
+++ b/app/src/main/res/layout/item_recommend_interest_footer.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_recommend_interest_image.xml b/app/src/main/res/layout/item_recommend_interest_image.xml
new file mode 100644
index 0000000000..51c90be3ca
--- /dev/null
+++ b/app/src/main/res/layout/item_recommend_interest_image.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_skeleton_discovery_list.xml b/app/src/main/res/layout/item_skeleton_discovery_list.xml
new file mode 100644
index 0000000000..1ea06a8538
--- /dev/null
+++ b/app/src/main/res/layout/item_skeleton_discovery_list.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_discovery_guide.xml b/app/src/main/res/layout/layout_discovery_guide.xml
new file mode 100644
index 0000000000..8d7e80afb7
--- /dev/null
+++ b/app/src/main/res/layout/layout_discovery_guide.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/module_common/src/main/java/com/gh/gamecenter/common/baselist/LazyListFragment.java b/module_common/src/main/java/com/gh/gamecenter/common/baselist/LazyListFragment.java
index c10e95ccfd..54f45bfe19 100644
--- a/module_common/src/main/java/com/gh/gamecenter/common/baselist/LazyListFragment.java
+++ b/module_common/src/main/java/com/gh/gamecenter/common/baselist/LazyListFragment.java
@@ -2,6 +2,7 @@ package com.gh.gamecenter.common.baselist;
import android.view.View;
import android.view.ViewStub;
+import android.widget.FrameLayout;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
@@ -55,6 +56,8 @@ public abstract class LazyListFragment
+
+