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 + +