diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4a38b82275..5dc4de1fba 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -717,6 +717,10 @@
android:name=".savegame.GameArchiveListActivity"
android:screenOrientation="portrait" />
+
+
diff --git a/app/src/main/java/com/gh/common/constant/Config.java b/app/src/main/java/com/gh/common/constant/Config.java
index dd3975990a..fff3065c17 100644
--- a/app/src/main/java/com/gh/common/constant/Config.java
+++ b/app/src/main/java/com/gh/common/constant/Config.java
@@ -248,6 +248,14 @@ public class Config {
}
}
+ public static boolean getUserInterestedGame() {
+ if (mNewApiSettingsEntity != null) {
+ return mNewApiSettingsEntity.getUserInterestedGame();
+ } else {
+ return false;
+ }
+ }
+
@Nullable
public static NewSettingsEntity getNewSettingsEntity() {
if (mNewSettingsEntity == null) {
diff --git a/app/src/main/java/com/gh/common/util/NewFlatLogUtils.kt b/app/src/main/java/com/gh/common/util/NewFlatLogUtils.kt
index e9715fed98..59798989ed 100644
--- a/app/src/main/java/com/gh/common/util/NewFlatLogUtils.kt
+++ b/app/src/main/java/com/gh/common/util/NewFlatLogUtils.kt
@@ -1044,4 +1044,83 @@ object NewFlatLogUtils {
}
log(json, "event", false)
}
+
+ // 进入发现页详情
+ fun logDiscoverDetailPageEnter(entrance: String, blockName: String = "") {
+ val json = json {
+ "event" to "discover_detail_page_enter"
+ "entrance" to entrance
+ if (blockName.isNotBlank()) {
+ "block_name" to blockName
+ }
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ // 点击设置偏好
+ fun logInterestedGameClick(entrance: String, blockName: String = "") {
+ val json = json {
+ "event" to "discover_preference_settings_click"
+ "entrance" to entrance
+ if (blockName.isNotBlank()) {
+ "block_name" to blockName
+ }
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ // 进入游戏偏好页面
+ fun logInterestedGamePageEnter(frequency: String, prefer: String, tendency: String, typeTags: JSONArray) {
+ val json = json {
+ "event" to "discover_preference_game_page_enter"
+ "frequency" to frequency
+ "prefer" to prefer
+ "tendency" to tendency
+ "type_tags" to typeTags
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ // 离开游戏偏好页面
+ fun logInterestedGamePageExit(
+ frequency: String,
+ prefer: String,
+ tendency: String,
+ typeTags: JSONArray,
+ interval: Long
+ ) {
+ val json = json {
+ "event" to "discover_preference_game_page_quit"
+ "frequency" to frequency
+ "prefer" to prefer
+ "tendency" to tendency
+ "interval" to interval
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ // 展开感兴趣的分类弹窗
+ fun logInterestedGameTypeDialogShow(typeTags: JSONArray) {
+ val json = json {
+ "event" to "discover_preference_type_tags_dialog_show"
+ "type_tags" to typeTags
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
+
+ // 关闭感兴趣的分类弹窗
+ fun logInterestedGameTypeDialogClose(typeTags: JSONArray, interval: Long) {
+ val json = json {
+ "event" to "discover_preference_type_tags_dialog_close"
+ "type_tags" to typeTags
+ "interval" to interval
+ parseAndPutMeta().invoke(this)
+ }
+ log(json, "event", false)
+ }
}
\ 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
index ca4d351607..3fba89dfb4 100644
--- a/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryAdapter.kt
@@ -9,6 +9,7 @@ import android.view.ViewGroup
import android.widget.Space
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.constant.Config
import com.gh.common.databind.BindingAdapters
import com.gh.common.exposure.ExposureEvent
import com.gh.common.exposure.ExposureSource
@@ -34,6 +35,8 @@ import com.gh.gamecenter.databinding.DiscoveryGameItemBinding
import com.gh.gamecenter.databinding.ItemRecommendInterestBinding
import com.gh.gamecenter.databinding.ItemRecommendInterestFooterBinding
import com.gh.gamecenter.databinding.ItemRecommendInterestImageBinding
+import com.gh.gamecenter.discovery.DiscoveryFragment.Companion.INTERESTED_GAME_REQUEST_CODE
+import com.gh.gamecenter.discovery.interestedgame.InterestedGameActivity
import com.gh.gamecenter.entity.DiscoveryGameCardLabel
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.eventbus.EBDownloadStatus
@@ -45,6 +48,7 @@ import org.greenrobot.eventbus.EventBus
class DiscoveryAdapter(
context: Context,
+ private val mFragment: DiscoveryFragment,
private val mViewModel: DiscoveryViewModel,
private val mBaseExposureSource: ArrayList,
private val mOuterSequence: Int,
@@ -198,16 +202,35 @@ class DiscoveryAdapter(
}
}
is DirectGameBlockViewHolder -> {
- holder.binding.root.setBackgroundColor(R.color.background_white.toColor(mContext))
- holder.binding.root.setOnClickListener {
- val navBar = MainWrapperRepository.getInstance().getNavBarLiveData().value
- if (navBar == null || mContext is DiscoveryActivity) {
- val blockData = HomeBottomBarHelper.getDefaultGameBarData()
- mContext.startActivity(BlockActivity.getIntent(mContext, blockData, mEntrance))
- } else {
- EventBus.getDefault().post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_GAME))
+ holder.binding.run {
+ val userInterestedGame = Config.getUserInterestedGame()
+ val padTop = if (userInterestedGame) 0 else 16F.dip2px()
+ root.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 16F.dip2px())
+ root.setBackgroundColor(R.color.background_white.toColor(mContext))
+ interestedGameTv.goneIf(!userInterestedGame) {
+ interestedGameTv.text = mContext.getString(R.string.interested_game_footer_hint).fromHtml()
+ interestedGameTv.setOnClickListener {
+ mFragment.startActivityForResult(
+ InterestedGameActivity.getIntent(
+ mContext,
+ "发现页-底部"
+ ),
+ INTERESTED_GAME_REQUEST_CODE
+ )
+ NewFlatLogUtils.logInterestedGameClick("发现页底部")
+ }
+ }
+ recommendIv.setOnClickListener {
+ val navBar = MainWrapperRepository.getInstance().getNavBarLiveData().value
+ if (navBar == null || mContext is DiscoveryActivity) {
+ val blockData = HomeBottomBarHelper.getDefaultGameBarData()
+ mContext.startActivity(BlockActivity.getIntent(mContext, blockData, mEntrance))
+ } else {
+ EventBus.getDefault()
+ .post(EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_GAME))
+ }
+ NewFlatLogUtils.logDiscoverPageJumpGamesLibraries()
}
- NewFlatLogUtils.logDiscoverPageJumpGamesLibraries()
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryFragment.kt b/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryFragment.kt
index 159387885f..cd0c62e1d1 100644
--- a/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/discovery/DiscoveryFragment.kt
@@ -1,5 +1,7 @@
package com.gh.gamecenter.discovery
+import android.app.Activity
+import android.content.Intent
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
@@ -149,6 +151,7 @@ class DiscoveryFragment : LazyListFragment,
+ private val mViewModel: InterestedGameViewModel,
+) : BaseRecyclerAdapter(context) {
+
+ private var countAndKey: Pair? = null
+
+ init {
+ var dataIds = ""
+ mList.forEach {
+ dataIds += it.id
+ }
+ if (dataIds.isNotEmpty()) countAndKey = Pair(mList.size, dataIds)
+ }
+
+ override fun getItemCount() = mList.size
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
+ InterestGameSubTagItemViewHolder(parent.toBinding())
+
+ override fun onBindViewHolder(holder: InterestGameSubTagItemViewHolder, position: Int) {
+ holder.binding.tagTv.run {
+ val tag = mList[position]
+ text = tag.name
+ isChecked = mViewModel.getTempSelectedTagList().contains(tag)
+ setOnClickListener {
+ isChecked = !isChecked
+ mViewModel.run {
+ isModify = true
+ if (isChecked) {
+ increaseSelectedCount()
+ addTempTag(tag)
+ } else {
+ decreaseSelectedCount()
+ removeTempTag(tag)
+ }
+ }
+ }
+ }
+ }
+
+ fun checkResetData(update: List) {
+ var dataIds = ""
+ update.forEach { dataIds += it.id }
+
+ mList = update
+ if (countAndKey?.first == update.size && countAndKey?.second != dataIds) { // 数量不变,内容发生改变
+ notifyItemRangeChanged(0, itemCount)
+ } else if (countAndKey?.first != update.size) { // 数量发生改变
+ notifyDataSetChanged()
+ } else {
+ notifyItemRangeChanged(0, itemCount)
+ }
+
+ // 重新刷新数据标识
+ countAndKey = Pair(update.size, dataIds)
+ }
+
+ class InterestGameSubTagItemViewHolder(val binding: InterestedGameSubTagItemBinding) :
+ BaseRecyclerViewHolder(binding.root)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/discovery/interestedgame/InterestedGameActivity.kt b/app/src/main/java/com/gh/gamecenter/discovery/interestedgame/InterestedGameActivity.kt
new file mode 100644
index 0000000000..e7a4f9e5f1
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/discovery/interestedgame/InterestedGameActivity.kt
@@ -0,0 +1,39 @@
+package com.gh.gamecenter.discovery.interestedgame
+
+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 InterestedGameActivity : ToolBarActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ updateStatusBarColor(R.color.background_white, R.color.background_white)
+ setNavigationTitle("游戏偏好")
+ }
+
+ 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,
+ InterestedGameActivity::class.java,
+ InterestedGameFragment::class.java,
+ bundle
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/discovery/interestedgame/InterestedGameFragment.kt b/app/src/main/java/com/gh/gamecenter/discovery/interestedgame/InterestedGameFragment.kt
new file mode 100644
index 0000000000..39fc39fbee
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/discovery/interestedgame/InterestedGameFragment.kt
@@ -0,0 +1,295 @@
+package com.gh.gamecenter.discovery.interestedgame
+
+import android.app.Activity
+import android.os.Bundle
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.widget.CheckedTextView
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.content.res.AppCompatResources
+import androidx.fragment.app.viewModels
+import com.gh.common.util.NewFlatLogUtils
+import com.gh.gamecenter.R
+import com.gh.gamecenter.common.base.fragment.ToolbarFragment
+import com.gh.gamecenter.common.utils.*
+import com.gh.gamecenter.databinding.FragmentInterestedGameBinding
+import com.gh.gamecenter.entity.InterestedGameEntity
+import com.gh.gamecenter.entity.InterestedGameEntity.TypeTag.Tag
+import com.gh.gamecenter.entity.InterestedGamePostEntity
+import org.json.JSONArray
+
+class InterestedGameFragment : ToolbarFragment() {
+
+ private val mViewModel: InterestedGameViewModel by viewModels()
+ private val mBinding by lazy { FragmentInterestedGameBinding.inflate(layoutInflater) }
+ private val mFrequencyViewList by lazy {
+ listOf(
+ mBinding.frequencyOne,
+ mBinding.frequencyTwo,
+ mBinding.frequencyThree
+ )
+ }
+ private val mConditionViewList by lazy {
+ listOf(
+ mBinding.conditionOne,
+ mBinding.conditionTwo
+ )
+ }
+ private val mTendencyViewList by lazy {
+ listOf(
+ mBinding.tendencyOne,
+ mBinding.tendencyTwo,
+ mBinding.tendencyThree
+ )
+ }
+ private val mFrequencyList by lazy {
+ listOf(
+ "daily",
+ "holiday",
+ "sometime"
+ )
+ }
+ private val mConditionList by lazy {
+ listOf(
+ "new",
+ "old"
+ )
+ }
+ private val mTendencyList by lazy {
+ listOf(
+ "single",
+ "friend",
+ "others"
+ )
+ }
+ private var mCurrentFrequencyIndex = -1
+ private var mCurrentConditionIndex = -1
+ private var mCurrentTendencyIndex = -1
+ private val mSelectedTagViewList = arrayListOf()
+ private var mDialogStayTime = 0L
+
+ override fun getLayoutId() = 0
+
+ override fun getInflatedLayout() = mBinding.root
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ initObserver()
+ initView()
+ }
+
+ override fun onStop() {
+ super.onStop()
+ val frequency =
+ if (mCurrentFrequencyIndex == -1) "" else mFrequencyViewList[mCurrentFrequencyIndex].text.toString()
+ val prefer =
+ if (mCurrentConditionIndex == -1) "" else mConditionViewList[mCurrentConditionIndex].text.toString()
+ val tendency = if (mCurrentTendencyIndex == -1) "" else mTendencyViewList[mCurrentTendencyIndex].text.toString()
+ val stayTime = (System.currentTimeMillis() - startPageTime) / 1000
+ NewFlatLogUtils.logInterestedGamePageExit(
+ frequency,
+ prefer,
+ tendency,
+ JSONArray(mViewModel.getSelectedTagIdList()),
+ stayTime
+ )
+ }
+
+ private fun initObserver() {
+ mViewModel.interestedGameData.observeNonNull(this) {
+ initStatus(it)
+ }
+ mViewModel.postResult.observeNonNull(this) {
+ if (it) {
+ toast("已根据你的偏好优化推荐机制~")
+ requireActivity().setResult(Activity.RESULT_OK)
+ requireActivity().finish()
+ } else {
+ toast("保存失败")
+ }
+ }
+ mViewModel.selectedTagLisLiveData.observeNonNull(this) {
+ removeAllTagView()
+ it.forEach { tag ->
+ addTagView(tag)
+ }
+ }
+ }
+
+ private fun removeAllTagView() {
+ mSelectedTagViewList.clear()
+ if (mBinding.typeFlexBox.childCount > 1) {
+ mBinding.typeFlexBox.removeViews(1, mBinding.typeFlexBox.childCount - 1)
+ }
+ }
+
+ private fun initView() {
+ mBinding.run {
+ typeFlexBox.addView(getAddTypeView())
+ mFrequencyViewList.forEachIndexed { index, view ->
+ view.setOnClickListener {
+ if (mCurrentFrequencyIndex != index) {
+ mViewModel.isModify = true
+ mCurrentFrequencyIndex = index
+ updateViewList(mFrequencyViewList, index)
+ }
+ }
+ }
+ mConditionViewList.forEachIndexed { index, view ->
+ view.setOnClickListener {
+ if (mCurrentConditionIndex != index) {
+ mViewModel.isModify = true
+ mCurrentConditionIndex = index
+ updateViewList(mConditionViewList, index)
+ }
+ }
+ }
+ mTendencyViewList.forEachIndexed { index, view ->
+ view.setOnClickListener {
+ if (mCurrentTendencyIndex != index) {
+ mViewModel.isModify = true
+ mCurrentTendencyIndex = index
+ updateViewList(mTendencyViewList, index)
+ }
+ }
+ }
+ saveBtn.setOnClickListener {
+ postInterestedGameData()
+ }
+ }
+ }
+
+ private fun initStatus(entity: InterestedGameEntity) {
+ mCurrentFrequencyIndex = mFrequencyList.indexOf(entity.playFrequency)
+ mCurrentConditionIndex = mConditionList.indexOf(entity.gameCondition)
+ mCurrentTendencyIndex = mTendencyList.indexOf(entity.playType)
+ updateViewList(mFrequencyViewList, mCurrentFrequencyIndex)
+ updateViewList(mConditionViewList, mCurrentConditionIndex)
+ updateViewList(mTendencyViewList, mCurrentTendencyIndex)
+
+ val frequency =
+ if (mCurrentFrequencyIndex == -1) "" else mFrequencyViewList[mCurrentFrequencyIndex].text.toString()
+ val prefer =
+ if (mCurrentConditionIndex == -1) "" else mConditionViewList[mCurrentConditionIndex].text.toString()
+ val tendency = if (mCurrentTendencyIndex == -1) "" else mTendencyViewList[mCurrentTendencyIndex].text.toString()
+ NewFlatLogUtils.logInterestedGamePageEnter(
+ frequency,
+ prefer,
+ tendency,
+ JSONArray(entity.tags)
+ )
+ }
+
+ private fun updateViewList(list: List, selectedIndex: Int) {
+ if (selectedIndex == -1) return
+
+ list.forEachIndexed { index, view ->
+ view.isChecked = index == selectedIndex
+ }
+
+ if (listOf(mCurrentFrequencyIndex, mCurrentConditionIndex, mCurrentTendencyIndex).all { it != -1 }) {
+ mBinding.saveBtn.alpha = 1.0F
+ }
+ }
+
+ private fun getAddTypeView(): View {
+ return TextView(requireContext()).apply {
+ layoutParams = ViewGroup.MarginLayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ 32F.dip2px()
+ ).apply { topMargin = 8F.dip2px() }
+ setPadding(12F.dip2px(), 0, 12F.dip2px(), 0)
+ setBackgroundResource(R.drawable.bg_shape_2496ff_alpha_10_radius_8)
+ gravity = Gravity.CENTER
+ setDrawableStart(R.drawable.ic_interested_game_add)
+ compoundDrawablePadding = 4F.dip2px()
+ setTextColor(R.color.theme_font.toColor(requireContext()))
+ textSize = 12F
+ text = "添加类型"
+ setOnClickListener {
+ if (mViewModel.getTypeTags().isNotEmpty()) {
+ InterestedGameTypeDialogFragment.show(requireActivity() as AppCompatActivity, mViewModel) {
+ val stayTime = (System.currentTimeMillis() - mDialogStayTime) / 1000
+ NewFlatLogUtils.logInterestedGameTypeDialogClose(
+ JSONArray(mViewModel.getSelectedTagIdList()),
+ stayTime
+ )
+ }
+ mDialogStayTime = System.currentTimeMillis()
+ NewFlatLogUtils.logInterestedGameTypeDialogShow(JSONArray(mViewModel.getSelectedTagIdList()))
+ }
+ }
+ }
+ }
+
+ private fun addTagView(tag: Tag) {
+ val tagView = TextView(requireContext()).apply {
+ layoutParams = ViewGroup.MarginLayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ 32F.dip2px()
+ ).apply {
+ topMargin = 8F.dip2px()
+ leftMargin = 8F.dip2px()
+ }
+ setPadding(12F.dip2px(), 0, 12F.dip2px(), 0)
+ setBackgroundResource(R.drawable.border_round_transparent_stroke_divider)
+ gravity = Gravity.CENTER
+ setDrawableEnd(AppCompatResources.getDrawable(requireContext(), R.drawable.ic_interested_game_tag_delete))
+ compoundDrawablePadding = 4F.dip2px()
+ setTextColor(R.color.text_subtitle.toColor(requireContext()))
+ text = tag.name
+ setOnClickListener {
+ removeTagView(tag)
+ mViewModel.decreaseSelectedCount()
+ mViewModel.removeTag(tag)
+ }
+ }
+ mSelectedTagViewList.add(tagView)
+ mBinding.typeFlexBox.addView(tagView)
+ }
+
+ private fun removeTagView(tag: Tag) {
+ val index = mViewModel.getTagIndex(tag)
+ if (index < mSelectedTagViewList.size) {
+ mBinding.typeFlexBox.removeView(mSelectedTagViewList[index])
+ mSelectedTagViewList.removeAt(index)
+ }
+ }
+
+ override fun onBackPressed(): Boolean {
+ if (mViewModel.isModify) {
+ showSaveDialog()
+ return true
+ }
+ return super.onBackPressed()
+ }
+
+ private fun showSaveDialog() {
+ DialogHelper.showDialog(
+ requireContext(),
+ "提示",
+ "是否保存本次的修改?",
+ "保存",
+ "取消",
+ { postInterestedGameData() },
+ { requireActivity().finish() },
+ extraConfig = DialogHelper.Config(centerTitle = true, centerContent = true)
+ )
+ }
+
+ private fun postInterestedGameData() {
+ if (listOf(mCurrentFrequencyIndex, mCurrentConditionIndex, mCurrentTendencyIndex).any { it == -1 }) {
+ toast("请完善你的游戏偏好")
+ return
+ }
+ val postEntity = InterestedGamePostEntity(
+ mFrequencyList[mCurrentFrequencyIndex],
+ mConditionList[mCurrentConditionIndex],
+ mTendencyList[mCurrentTendencyIndex],
+ mViewModel.getSelectedTagIdList()
+ )
+ mViewModel.postInterestedGameData(postEntity)
+ }
+}
diff --git a/app/src/main/java/com/gh/gamecenter/discovery/interestedgame/InterestedGameTypeAdapter.kt b/app/src/main/java/com/gh/gamecenter/discovery/interestedgame/InterestedGameTypeAdapter.kt
new file mode 100644
index 0000000000..17b95cdcd4
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/discovery/interestedgame/InterestedGameTypeAdapter.kt
@@ -0,0 +1,44 @@
+package com.gh.gamecenter.discovery.interestedgame
+
+import android.content.Context
+import android.view.ViewGroup
+import androidx.recyclerview.widget.GridLayoutManager
+import com.gh.gamecenter.R
+import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
+import com.gh.gamecenter.common.utils.dip2px
+import com.gh.gamecenter.common.utils.toBinding
+import com.gh.gamecenter.common.view.GridSpacingItemColorDecoration
+import com.gh.gamecenter.databinding.InterestedGameTypeItemBinding
+import com.lightgame.adapter.BaseRecyclerAdapter
+
+class InterestedGameTypeAdapter(
+ context: Context,
+ private val mViewModel: InterestedGameViewModel
+) : BaseRecyclerAdapter(context) {
+
+ override fun getItemCount() = mViewModel.getTypeTags().size
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
+ InterestedGameTypeViewHolder(parent.toBinding())
+
+ override fun onBindViewHolder(holder: InterestedGameTypeViewHolder, position: Int) {
+ holder.binding.run {
+ val padTop = if (position == 0) 16F.dip2px() else 0F.dip2px()
+ root.setPadding(16F.dip2px(), padTop, 16F.dip2px(), 16F.dip2px())
+ val entity = mViewModel.getTypeTags()[position]
+ typeTv.text = entity.name
+ subTagRv.run {
+ if (adapter is InterestGameSubTagAdapter) {
+ (adapter as InterestGameSubTagAdapter).checkResetData(entity.tags)
+ } else {
+ layoutManager = GridLayoutManager(mContext, 4)
+ adapter = InterestGameSubTagAdapter(mContext, entity.tags, mViewModel)
+ addItemDecoration(GridSpacingItemColorDecoration(mContext, 8, 8, R.color.transparent))
+ }
+ }
+ }
+ }
+
+ inner class InterestedGameTypeViewHolder(val binding: InterestedGameTypeItemBinding) :
+ BaseRecyclerViewHolder(binding.root)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/discovery/interestedgame/InterestedGameTypeDialogFragment.kt b/app/src/main/java/com/gh/gamecenter/discovery/interestedgame/InterestedGameTypeDialogFragment.kt
new file mode 100644
index 0000000000..edc1d27c96
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/discovery/interestedgame/InterestedGameTypeDialogFragment.kt
@@ -0,0 +1,106 @@
+package com.gh.gamecenter.discovery.interestedgame
+
+import android.app.Dialog
+import android.content.DialogInterface
+import android.os.Bundle
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.appcompat.app.AppCompatActivity
+import com.gh.gamecenter.R
+import com.gh.gamecenter.common.base.fragment.BaseDialogFragment
+import com.gh.gamecenter.common.utils.dip2px
+import com.gh.gamecenter.common.utils.observeNonNull
+import com.gh.gamecenter.common.utils.setRootBackgroundDrawable
+import com.gh.gamecenter.common.view.FixLinearLayoutManager
+import com.gh.gamecenter.core.utils.EmptyCallback
+import com.gh.gamecenter.databinding.DialogInterestedGameTypeBinding
+import com.halo.assistant.HaloApp
+
+class InterestedGameTypeDialogFragment(
+ private val mViewModel: InterestedGameViewModel,
+ private val dismissCallback: EmptyCallback
+) : BaseDialogFragment() {
+
+ private val mBinding by lazy { DialogInterestedGameTypeBinding.inflate(layoutInflater) }
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+ return mBinding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ mViewModel.initTempTagList()
+ mViewModel.selectedCountLiveData.observeNonNull(this) {
+ updateConfirmBtnText(it)
+ }
+ mBinding.run {
+ updateConfirmBtnText(mViewModel.getSelectedCount())
+ cancelTv.setOnClickListener {
+ dismissAllowingStateLoss()
+ }
+ typeRv.run {
+ layoutManager = FixLinearLayoutManager(requireContext())
+ adapter = InterestedGameTypeAdapter(requireContext(), mViewModel)
+ }
+ clearBtn.setOnClickListener {
+ if (mViewModel.getSelectedCount() > 0) {
+ mViewModel.resetTemp()
+ typeRv.adapter?.notifyDataSetChanged()
+ }
+ }
+ confirmBtn.setOnClickListener {
+ mViewModel.confirmTempList()
+ dismissAllowingStateLoss()
+ }
+ }
+ }
+
+ private fun updateConfirmBtnText(count: Int) {
+ val suffix = if (count > 0) "(${count})" else ""
+ mBinding.confirmBtn.text = "确认$suffix"
+ }
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ val createDialog = super.onCreateDialog(savedInstanceState)
+ createDialog.setCanceledOnTouchOutside(true)
+ val window = createDialog.window
+ window?.setGravity(Gravity.BOTTOM)
+ window?.setWindowAnimations(R.style.community_publication_animation)
+ return createDialog
+ }
+
+ override fun onStart() {
+ super.onStart()
+ val width = HaloApp.getInstance().application.resources.displayMetrics.widthPixels
+ val height = 384F.dip2px()
+ dialog?.window?.setLayout(width, height)
+ }
+
+ override fun onDarkModeChanged() {
+ super.onDarkModeChanged()
+ mBinding.run {
+ root.setRootBackgroundDrawable(R.drawable.background_shape_white_radius_12_top_only)
+ }
+ }
+
+ override fun onDismiss(dialog: DialogInterface) {
+ super.onDismiss(dialog)
+ dismissCallback.onCallback()
+ }
+
+ companion object {
+
+ fun show(
+ activity: AppCompatActivity,
+ viewModel: InterestedGameViewModel,
+ dismissCallback: EmptyCallback
+ ) {
+ InterestedGameTypeDialogFragment(viewModel, dismissCallback).show(
+ activity.supportFragmentManager,
+ InterestedGameTypeDialogFragment::class.java.name
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/discovery/interestedgame/InterestedGameViewModel.kt b/app/src/main/java/com/gh/gamecenter/discovery/interestedgame/InterestedGameViewModel.kt
new file mode 100644
index 0000000000..bbf12e7ad9
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/discovery/interestedgame/InterestedGameViewModel.kt
@@ -0,0 +1,138 @@
+package com.gh.gamecenter.discovery.interestedgame
+
+import android.annotation.SuppressLint
+import android.app.Application
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.MutableLiveData
+import com.gh.gamecenter.common.retrofit.BiResponse
+import com.gh.gamecenter.common.utils.singleToMain
+import com.gh.gamecenter.common.utils.toRequestBody
+import com.gh.gamecenter.entity.InterestedGameEntity
+import com.gh.gamecenter.entity.InterestedGameEntity.TypeTag.Tag
+import com.gh.gamecenter.entity.InterestedGamePostEntity
+import com.gh.gamecenter.retrofit.RetrofitManager
+import okhttp3.ResponseBody
+import java.util.*
+
+class InterestedGameViewModel(application: Application) : AndroidViewModel(application) {
+
+ private val mApi = RetrofitManager.getInstance().newApi
+ private var mTypeTags: List = listOf()
+ private val mSelectedTagList = arrayListOf()
+ private val mTempSelectedTagList = arrayListOf()
+ private var mSelectedCount = 0
+ var interestedGameData = MutableLiveData()
+ var postResult = MutableLiveData()
+ var selectedCountLiveData = MutableLiveData()
+ var selectedTagLisLiveData = MutableLiveData>()
+ var isModify = false
+
+ init {
+ getInterestedGameData()
+ }
+
+ fun getTypeTags() = mTypeTags
+
+ fun getSelectedCount() = mSelectedCount
+
+ fun getSelectedTagList() = mSelectedTagList
+
+ fun getTempSelectedTagList() = mTempSelectedTagList
+
+ fun getSelectedTagIdList() = mSelectedTagList.map { it.id }
+
+ fun getTagIndex(tag: Tag) = mSelectedTagList.indexOf(tag)
+
+ @SuppressLint("CheckResult")
+ fun getInterestedGameData() {
+ mApi.interestedGame
+ .compose(singleToMain())
+ .subscribe(object : BiResponse() {
+ override fun onSuccess(data: InterestedGameEntity) {
+ mTypeTags = data.typeTag.filter { it.tags.isNotEmpty() }
+ initSelectedTags(data.tags)
+ interestedGameData.postValue(data)
+ }
+ })
+ }
+
+ @SuppressLint("CheckResult")
+ fun postInterestedGameData(data: InterestedGamePostEntity) {
+ mApi.postInterestedGame(data.toRequestBody())
+ .compose(singleToMain())
+ .subscribe(object : BiResponse() {
+ override fun onSuccess(data: ResponseBody) {
+ postResult.postValue(true)
+ }
+
+ override fun onFailure(exception: Exception) {
+ postResult.postValue(false)
+ }
+ })
+ }
+
+ fun initSelectedTags(tagIdList: List) {
+ mTypeTags.forEach {
+ it.tags.forEach { tag ->
+ if (tagIdList.contains(tag.id)) {
+ addTag(tag)
+ }
+ }
+ }
+ mSelectedCount = mSelectedTagList.size
+ if (mSelectedTagList.isNotEmpty()) postSelectedTagList()
+ }
+
+ fun postSelectedTagList() {
+ selectedTagLisLiveData.postValue(mSelectedTagList)
+ }
+
+ fun postSelectedCount() {
+ selectedCountLiveData.postValue(mSelectedCount)
+ }
+
+ fun increaseSelectedCount() {
+ mSelectedCount++
+ postSelectedCount()
+ }
+
+ fun decreaseSelectedCount() {
+ if (mSelectedCount > 0) mSelectedCount--
+ postSelectedCount()
+ }
+
+ fun addTag(tag: Tag) {
+ mSelectedTagList.add(tag)
+ }
+
+ fun removeTag(tag: Tag) {
+ mSelectedTagList.remove(tag)
+ }
+
+ fun addTempTag(tag: Tag) {
+ mTempSelectedTagList.add(tag)
+ }
+
+ fun removeTempTag(tag: Tag) {
+ mTempSelectedTagList.remove(tag)
+ }
+
+ fun confirmTempList() {
+ mSelectedTagList.clear()
+ mSelectedTagList.addAll(mTempSelectedTagList)
+ postSelectedTagList()
+ }
+
+ fun initTempTagList() {
+ mTempSelectedTagList.clear()
+ mTempSelectedTagList.addAll(mSelectedTagList)
+ mSelectedCount = mTempSelectedTagList.size
+ postSelectedCount()
+ }
+
+ fun resetTemp() {
+ mTempSelectedTagList.clear()
+ mSelectedCount = 0
+ postSelectedCount()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/entity/DiscoveryCardEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/DiscoveryCardEntity.kt
new file mode 100644
index 0000000000..7e12bd8fbd
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/entity/DiscoveryCardEntity.kt
@@ -0,0 +1,6 @@
+package com.gh.gamecenter.entity
+
+data class DiscoveryCardEntity(
+ val games: ArrayList = arrayListOf(),
+ val label: List = listOf()
+)
\ 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
index f7c1568edf..9bc4d43ea7 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/DiscoveryGameCardEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/DiscoveryGameCardEntity.kt
@@ -8,7 +8,7 @@ data class DiscoveryGameCardEntity(
@SerializedName("game_tags")
val gameTags: ArrayList = arrayListOf(),
@SerializedName("data")
- val games: ArrayList = arrayListOf()
+ var games: ArrayList = arrayListOf()
)
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 f196cdb8cd..e9097c7636 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/GameEntity.kt
@@ -628,6 +628,14 @@ data class GameEntity(
fun isSpecialDownload() = RegionSettingHelper.shouldThisGameShowSpecialDownload(id)
+ fun getTypeName() =
+ when (type) {
+ "filter" -> "算法过滤"
+ "recommend" -> "专题推荐"
+ "ad" -> "游戏广告"
+ else -> ""
+ }
+
fun toSimpleGame(): SimpleGame {
val simpleGame = SimpleGame()
simpleGame.id = id
diff --git a/app/src/main/java/com/gh/gamecenter/entity/InterestedGameEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/InterestedGameEntity.kt
new file mode 100644
index 0000000000..b60331c5e7
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/entity/InterestedGameEntity.kt
@@ -0,0 +1,50 @@
+package com.gh.gamecenter.entity
+
+import android.os.Parcelable
+import com.google.gson.annotations.SerializedName
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class InterestedGameEntity(
+ @SerializedName("_id")
+ var id: String = "",
+ @SerializedName("play_frequency")
+ var playFrequency: String = "", // 玩游戏的评率:每天daily,节假日holiday,偶尔sometime
+ @SerializedName("game_new_old")
+ var gameCondition: String = "", // 游戏新旧:新new,旧old
+ @SerializedName("play_type")
+ var playType: String = "", // 玩游戏的类型:单人-single, 朋友-friend, 其他-others
+ var tags: List = listOf(), // 关注的标签_id
+ @SerializedName("type_tag")
+ var typeTag: List = listOf(), // 后台设置的分类及标签
+) : Parcelable {
+
+ @Parcelize
+ data class TypeTag(
+ @SerializedName("_id")
+ var id: String = "",
+ var name: String = "",
+ var tags: ArrayList = arrayListOf()
+ ) : Parcelable {
+
+ @Parcelize
+ data class Tag(
+ @SerializedName("_id")
+ var id: String = "",
+ var name: String = "",
+ var style: TagStyleEntity = TagStyleEntity(),
+ ) : Parcelable
+
+ }
+}
+
+@Parcelize
+data class InterestedGamePostEntity(
+ @SerializedName("play_frequency")
+ var playFrequency: String = "", // 玩游戏的评率:每天daily,节假日holiday,偶尔sometime
+ @SerializedName("game_new_old")
+ var gameCondition: String = "", // 游戏新旧:新new,旧old
+ @SerializedName("play_type")
+ var playType: String = "", // 玩游戏的类型:单人-single, 朋友-friend, 其他-others
+ var tags: List = listOf(), // 关注的标签_id
+) : Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/entity/NewApiSettingsEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/NewApiSettingsEntity.kt
index fdfd6b438f..166fd7a5e9 100644
--- a/app/src/main/java/com/gh/gamecenter/entity/NewApiSettingsEntity.kt
+++ b/app/src/main/java/com/gh/gamecenter/entity/NewApiSettingsEntity.kt
@@ -8,7 +8,9 @@ data class NewApiSettingsEntity(
var simulator: SimulatorEntity? = null,
@SerializedName("start_ad")
var startAd: StartupAdEntity? = null,//开屏图片广告
- var startup: StartupAdEntity? = null//启动文案广告
+ var startup: StartupAdEntity? = null,//启动文案广告
+ @SerializedName("user_interested_game")
+ var userInterestedGame: Boolean = false //偏好设置状态开关
) {
/**
*
diff --git a/app/src/main/java/com/gh/gamecenter/game/GameFragment.kt b/app/src/main/java/com/gh/gamecenter/game/GameFragment.kt
index d9cea6299e..2396978056 100644
--- a/app/src/main/java/com/gh/gamecenter/game/GameFragment.kt
+++ b/app/src/main/java/com/gh/gamecenter/game/GameFragment.kt
@@ -18,19 +18,19 @@ import com.gh.common.xapk.XapkUnzipStatus
import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.LazyFragment
-import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.baselist.LoadStatus
+import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.EntranceConsts
+import com.gh.gamecenter.common.eventbus.EBReuse
+import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.FixLinearLayoutManager
+import com.gh.gamecenter.core.AppExecutor
+import com.gh.gamecenter.core.utils.MD5Utils
+import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.databinding.FragmentGameBinding
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.eventbus.EBUISwitch
-import com.gh.gamecenter.common.eventbus.EBReuse
-import com.gh.gamecenter.common.utils.*
-import com.gh.gamecenter.core.AppExecutor
-import com.gh.gamecenter.core.utils.MD5Utils
-import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.fragment.MainWrapperFragment
import com.gh.gamecenter.game.data.GameItemData
import com.gh.gamecenter.home.video.ScrollCalculatorHelper
@@ -300,7 +300,7 @@ class GameFragment : LazyFragment() {
if (::mListAdapter.isInitialized) {
val data = mListAdapter.getGameEntityByPackage(busFour.packageName)
for (gameAndPosition in data) {
- mListAdapter.notifyChildItem(gameAndPosition.position)
+ mListAdapter.notifyChildItem(gameAndPosition.position, busFour.packageName)
}
}
}
diff --git a/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt
index 9af9385ef5..a75e6fe4a7 100644
--- a/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/game/GameFragmentAdapter.kt
@@ -69,6 +69,8 @@ import com.gh.gamecenter.game.vertical.OnPagerSnapScrollListener
import com.gh.gamecenter.home.BlankDividerViewHolder
import com.gh.gamecenter.home.HomeDividerViewHolder
import com.gh.gamecenter.home.HomeGameItemViewHolder
+import com.gh.gamecenter.home.discovercard.DiscoverCardGameAdapter
+import com.gh.gamecenter.home.discovercard.HomeDiscoverCardViewHolder
import com.gh.gamecenter.home.gamecollection.HomeGameCollectionViewHolder
import com.gh.gamecenter.servers.GameServersActivity
import com.gh.gamecenter.subject.SubjectActivity
@@ -131,6 +133,7 @@ class GameFragmentAdapter(
if (itemData.bigImageRecommend != null) return ItemViewType.BIG_IMAGE_RECOMMEND
if (itemData.attachGame != null) return ItemViewType.GAME_ITEM
if (itemData.lineDivider != null) return ItemViewType.DIVIDER_ITEM
+ if (itemData.discoverCard != null) return ItemViewType.DISCOVER_CARD
return ItemViewType.LOADING
}
@@ -168,6 +171,7 @@ class GameFragmentAdapter(
ItemViewType.BIG_IMAGE_RECOMMEND -> BigImageRecommendViewHolder(parent.toBinding())
ItemViewType.GAME_ITEM -> HomeGameItemViewHolder(parent.toBinding())
ItemViewType.DIVIDER_ITEM -> HomeDividerViewHolder(parent.toBinding())
+ ItemViewType.DISCOVER_CARD -> HomeDiscoverCardViewHolder(parent.toBinding())
else -> GameItemViewHolder(GameItemBinding.bind(mLayoutInflater.inflate(R.layout.game_item, parent, false)))
}
@@ -196,6 +200,7 @@ class GameFragmentAdapter(
is BigImageRecommendViewHolder -> bindBigImageRecommend(holder, position)
is HomeGameItemViewHolder -> bindAttachGame(holder, position)
is HomeDividerViewHolder -> holder.bindView(mItemDataList[position].lineDivider ?: 1F)
+ is HomeDiscoverCardViewHolder -> bindDiscoverCard(holder, position)
}
}
@@ -1225,6 +1230,52 @@ class GameFragmentAdapter(
}
}
+ private fun bindDiscoverCard(holder: HomeDiscoverCardViewHolder, position: Int) {
+ val item = mItemDataList[position]
+ val discoverCard = item.discoverCard!!
+ val binding = holder.binding
+ val exposureEventList = arrayListOf()
+ val listExposureEventList = arrayListOf()
+ val spanCount = 3
+
+ val snapHelper = holder.bindView(item.discoverCard!!, "版块", mViewModel.blockData?.name ?: "")
+
+ val exposureClosure: (Int) -> Unit = {
+ val gameList = discoverCard.games
+ runOnIoThread(true) {
+ listExposureEventList.clear()
+
+ val startOffset = it * spanCount
+ val endOffset = if (startOffset + spanCount >= gameList.size) {
+ gameList.size
+ } else {
+ startOffset + spanCount
+ }
+ for (i in startOffset until endOffset) {
+ val event = ExposureEvent.createEventWithSourceConcat(
+ gameEntity = gameList[i].apply {
+ outerSequence = position
+ sequence = i
+ },
+ basicSource = mBasicExposureSource,
+ source = listOf(ExposureSource("发现", gameList[i].getTypeName()))
+ )
+ gameList[i].exposureEvent = event
+ listExposureEventList.add(event)
+ }
+ exposureEventList.addAll(listExposureEventList)
+ }
+ }
+ exposureClosure(0)
+
+ binding.recyclerView.addOnScrollListener(OnPagerSnapScrollListener(snapHelper) {
+ exposureClosure(it)
+ })
+
+ item.exposureEventList = exposureEventList
+
+ }
+
override fun getItemCount(): Int {
return if (mItemDataList.size > 0) mItemDataList.size + 1 else mItemDataList.size
}
@@ -1236,12 +1287,15 @@ class GameFragmentAdapter(
val entryMap = gameAndPosition.entity.getEntryMap()
entryMap[download.platform] = download
}
- if (getItemViewType(gameAndPosition.position) == ItemViewType.VERTICAL_SLIDE_ITEM) {
+ if (getItemViewType(gameAndPosition.position) == ItemViewType.VERTICAL_SLIDE_ITEM
+ || getItemViewType(gameAndPosition.position) == ItemViewType.DISCOVER_CARD
+ ) {
val view = layoutManager?.findViewByPosition(gameAndPosition.position)
val recyclerView = view?.findViewById(R.id.recycler_view)
when (val adapter = recyclerView?.adapter) {
is GameVerticalAdapter -> adapter.notifyItemByDownload(download)
is RankCollectionAdapter -> adapter.notifyItemByDownload(download)
+ is DiscoverCardGameAdapter -> adapter.notifyItemByDownload(download)
}
} else {
notifyItemChanged(gameAndPosition.position)
@@ -1256,20 +1310,21 @@ class GameFragmentAdapter(
gameAndPosition.entity.getEntryMap().remove(status.platform)
}
- notifyChildItem(gameAndPosition.position)
+ notifyChildItem(gameAndPosition.position, status.packageName)
}
}
- fun notifyChildItem(position: Int) {
- if (getItemViewType(position) == ItemViewType.VERTICAL_SLIDE_ITEM ||
- getItemViewType(position) == ItemViewType.RANK_COLLECTION
+ fun notifyChildItem(position: Int, packageName: String) {
+ if (getItemViewType(position) == ItemViewType.VERTICAL_SLIDE_ITEM
+ || getItemViewType(position) == ItemViewType.RANK_COLLECTION
+ || getItemViewType(position) == ItemViewType.DISCOVER_CARD
) {
val view = layoutManager?.findViewByPosition(position)
val recyclerView = view?.findViewById(R.id.recycler_view)
- if (recyclerView?.adapter is RankCollectionAdapter) {
- (recyclerView.adapter as RankCollectionAdapter).notifyChildItem()
- } else {
- recyclerView?.adapter?.notifyDataSetChanged()
+ when (val adapter = recyclerView?.adapter) {
+ is RankCollectionAdapter -> adapter.notifyChildItem()
+ is DiscoverCardGameAdapter -> adapter.notifyChildItem(packageName)
+ else -> recyclerView?.adapter?.notifyDataSetChanged()
}
} else {
notifyItemChanged(position)
@@ -1323,6 +1378,18 @@ class GameFragmentAdapter(
continue
}
+ val discoverCard = mItemDataList[position].discoverCard
+ if (discoverCard != null) {
+ discoverCard.games.forEach {
+ for (apkEntity in it.getApk()) {
+ if (apkEntity.packageName == packageName) {
+ positionList.add(GameAndPosition(it, position))
+ }
+ }
+ }
+ continue
+ }
+
val image = mItemDataList[position].image
if (image != null) positionList.add(GameAndPosition(image, position))
}
diff --git a/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt b/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt
index d99c9ae68d..902b31a0bd 100644
--- a/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/game/GameViewModel.kt
@@ -33,6 +33,7 @@ import com.gh.gamecenter.home.BlankDividerViewHolder
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.setting.view.SettingsFragment
import com.lightgame.utils.Utils
+import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import retrofit2.HttpException
@@ -51,6 +52,8 @@ class GameViewModel(application: Application, var blockData: SubjectRecommendEnt
private val mSubjectChangedMap: ArrayMap> = ArrayMap() // 存储换一换的数据
private val mSubjectRefreshMap: ArrayMap> = ArrayMap() // 存储专题刷新数据
private var mSmartSubject: SubjectEntity? = null // 猜你喜欢专题
+ private var mDiscoveryGameCard: DiscoveryGameCardEntity? = null
+ private var mDiscoveryGameCardLabels: List? = null
private var mSubjectPage = 1 // 专题分页
private var mIsLoading = false
@@ -470,6 +473,71 @@ class GameViewModel(application: Application, var blockData: SubjectRecommendEnt
transformationItemData()
}
+ // 获取发现卡片数据
+ private fun getDiscoverCardData() {
+ val discoveryGamesObservable = mSensitiveApi.getDiscoveryGames(1, mapOf("refresh" to "true"))
+ val cardLabelsObservable = mSensitiveApi.cardLabels
+ when {
+ mDiscoveryGameCard == null && mDiscoveryGameCardLabels == null -> {
+ Observable.mergeDelayError(cardLabelsObservable, discoveryGamesObservable)
+ .compose(observableToMain())
+ .subscribe(object : Response() {
+ override fun onNext(response: Any) {
+ when (response) {
+ is ArrayList<*> -> mDiscoveryGameCardLabels =
+ response as ArrayList
+ is DiscoveryGameCardEntity -> mDiscoveryGameCard =
+ response.apply { games = ArrayList(games.take(18)) }
+ }
+ }
+
+ override fun onComplete() {
+ filterDiscoveryLabel()
+ transformationItemData()
+ }
+ })
+ }
+ mDiscoveryGameCard == null -> {
+ discoveryGamesObservable.compose(observableToMain())
+ .subscribe(object : Response() {
+ override fun onResponse(response: DiscoveryGameCardEntity?) {
+ mDiscoveryGameCard = response?.apply { games = ArrayList(games.take(18)) }
+ filterDiscoveryLabel()
+ transformationItemData()
+ }
+ })
+ }
+ mDiscoveryGameCardLabels == null -> {
+ cardLabelsObservable.compose(observableToMain())
+ .subscribe(object : Response>() {
+ override fun onResponse(response: ArrayList?) {
+ super.onResponse(response)
+ mDiscoveryGameCardLabels = response
+ filterDiscoveryLabel()
+ transformationItemData()
+ }
+ })
+ }
+ }
+ }
+
+ // 过滤分组,现只需要"卡片一"分组
+ private fun filterDiscoveryLabel() {
+ mDiscoveryGameCardLabels = mDiscoveryGameCardLabels?.filter { it.card == "卡片一" }
+ // 如果link_type为空需要在mGameTags中依次获取
+ val gameTags = mDiscoveryGameCard?.gameTags
+ if (gameTags.isNullOrEmpty()) return
+ mDiscoveryGameCardLabels?.forEachIndexed { index, label ->
+ if (gameTags.size > index && label.type.isNullOrEmpty()) {
+ val gameTag = gameTags[index]
+ label.link = gameTag.link
+ label.type = gameTag.type
+ label.linkText = gameTag.linkText
+ label.title = gameTag.linkText
+ }
+ }
+ }
+
private fun transformationItemData() {
mItemDataListCache.clear()
positionAndPackageMap.clear()
@@ -833,6 +901,24 @@ class GameViewModel(application: Application, var blockData: SubjectRecommendEnt
continue
}
+ if (subjectEntity.type == "explore") {
+ if (mDiscoveryGameCard == null || mDiscoveryGameCardLabels == null) {
+ getDiscoverCardData()
+ } else {
+ val itemItemData = GameItemData().apply {
+ discoverCard = DiscoveryCardEntity(
+ mDiscoveryGameCard?.games ?: arrayListOf(),
+ mDiscoveryGameCardLabels ?: listOf()
+ )
+ }
+ mItemDataListCache.add(itemItemData)
+ mDiscoveryGameCard?.games?.forEach {
+ addGamePositionAndPackage(it)
+ }
+ }
+ continue
+ }
+
appendAdditionalInfoToSubjectGame(subjectEntity, index)
}
diff --git a/app/src/main/java/com/gh/gamecenter/game/data/GameItemData.kt b/app/src/main/java/com/gh/gamecenter/game/data/GameItemData.kt
index 5a0beeb4ab..ab174ea15b 100644
--- a/app/src/main/java/com/gh/gamecenter/game/data/GameItemData.kt
+++ b/app/src/main/java/com/gh/gamecenter/game/data/GameItemData.kt
@@ -2,10 +2,7 @@ package com.gh.gamecenter.game.data
import com.gh.common.exposure.ExposureEvent
import com.gh.gamecenter.common.entity.LinkEntity
-import com.gh.gamecenter.entity.GameEntity
-import com.gh.gamecenter.entity.GameNavigationEntity
-import com.gh.gamecenter.entity.SubjectEntity
-import com.gh.gamecenter.entity.SubjectRecommendEntity
+import com.gh.gamecenter.entity.*
import com.gh.gamecenter.gamecollection.square.GameCollectionListItemData
class GameItemData {
@@ -35,6 +32,8 @@ class GameItemData {
var bigImageRecommend: SubjectEntity? = null //提问、帖子、视频帖、文章
+ var discoverCard: DiscoveryCardEntity? = null // 发现页卡片
+
var blankDivider: Float? = null // 空白的空间补全item
var lineDivider: Float? = null
diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt b/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt
index 59957a8204..53facec106 100644
--- a/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt
+++ b/app/src/main/java/com/gh/gamecenter/home/HomeFragmentAdapter.kt
@@ -30,8 +30,11 @@ import com.gh.gamecenter.game.horizontal.GameHorizontalAdapter
import com.gh.gamecenter.game.horizontal.GameHorizontalSlideAdapter
import com.gh.gamecenter.game.rank.RankCollectionAdapter
import com.gh.gamecenter.game.vertical.GameVerticalAdapter
+import com.gh.gamecenter.game.vertical.OnPagerSnapScrollListener
import com.gh.gamecenter.gamedetail.rating.RatingReplyActivity
import com.gh.gamecenter.home.amway.HomeAmwayListViewHolder
+import com.gh.gamecenter.home.discovercard.DiscoverCardGameAdapter
+import com.gh.gamecenter.home.discovercard.HomeDiscoverCardViewHolder
import com.gh.gamecenter.home.gamecollection.HomeGameCollectionViewHolder
import com.gh.gamecenter.home.slide.HomeSlideListAdapter
import com.gh.gamecenter.home.slide.HomeSlideListViewHolder
@@ -143,6 +146,10 @@ class HomeFragmentAdapter(
return oldItem.blankDivider == newItem.blankDivider
}
+ if (oldItem?.discoverCard != null && newItem?.discoverCard != null) {
+ return oldItem.discoverCard == newItem.discoverCard
+ }
+
return false
}
@@ -166,6 +173,7 @@ class HomeFragmentAdapter(
if (itemData.amway != null) return AMWAY_ITEM
if (itemData.gameCollection != null) return GAME_COLLECTION_ITEM
if (itemData.recentVGame != null) return RECENT_V_GAME
+ if (itemData.discoverCard != null) return DISCOVER_CARD
if (itemData.lineDivider != null) return DIVIDER_ITEM
if (itemData.unknownData != null) return UNKNOWN_ITEM
@@ -181,6 +189,7 @@ class HomeFragmentAdapter(
GAME_COLLECTION_ITEM -> HomeGameCollectionViewHolder(parent.toBinding())
DIVIDER_ITEM -> HomeDividerViewHolder(parent.toBinding())
RECENT_V_GAME -> HomeRecentVGameViewHolder(parent.toBinding())
+ DISCOVER_CARD -> HomeDiscoverCardViewHolder(parent.toBinding())
FOOTER_ITEM -> FooterViewHolder(mLayoutInflater.inflate(R.layout.refresh_footerview, parent, false))
UNKNOWN_ITEM -> ReuseViewHolder(mLayoutInflater.inflate(R.layout.home_unknown_item, parent, false))
@@ -211,6 +220,7 @@ class HomeFragmentAdapter(
is HomeDividerViewHolder -> holder.bindView(mDataList[position].lineDivider ?: 1F)
is HomeGameCollectionViewHolder -> bindGameCollection(holder, position)
is HomeRecentVGameViewHolder -> bindRecentVGame(holder, position)
+ is HomeDiscoverCardViewHolder -> bindDiscoverCard(holder, position)
else -> mLegacyHomeFragmentAdapterAssistant.bindLegacyViewHolder(holder, mDataList[position], position)
}
@@ -326,6 +336,51 @@ class HomeFragmentAdapter(
}
}
+ private fun bindDiscoverCard(holder: HomeDiscoverCardViewHolder, position: Int) {
+ val homeItemData = mDataList[position]
+ val discoverCard = homeItemData.discoverCard!!
+ val binding = holder.binding
+ val exposureEventList = arrayListOf()
+ val listExposureEventList = arrayListOf()
+ val spanCount = 3
+
+ val snapHelper = holder.bindView(discoverCard, "首页")
+
+ val exposureClosure: (Int) -> Unit = {
+ val gameList = discoverCard.games
+ runOnIoThread(true) {
+ listExposureEventList.clear()
+
+ val startOffset = it * spanCount
+ val endOffset = if (startOffset + spanCount >= gameList.size) {
+ gameList.size
+ } else {
+ startOffset + spanCount
+ }
+ for (i in startOffset until endOffset) {
+ val event = ExposureEvent.createEventWithSourceConcat(
+ gameEntity = gameList[i].apply {
+ outerSequence = homeItemData.blockPosition
+ sequence = i
+ },
+ basicSource = mBasicExposureSource,
+ source = listOf(ExposureSource("发现", gameList[i].getTypeName()))
+ )
+ gameList[i].exposureEvent = event
+ listExposureEventList.add(event)
+ }
+ exposureEventList.addAll(listExposureEventList)
+ }
+ }
+ exposureClosure(0)
+
+ binding.recyclerView.addOnScrollListener(OnPagerSnapScrollListener(snapHelper) {
+ exposureClosure(it)
+ })
+
+ homeItemData.exposureEventList = exposureEventList
+ }
+
private fun bindAttachGame(holder: HomeGameItemViewHolder, position: Int) {
val homeItemData = mDataList[position]
val attachGame = homeItemData.attachGame
@@ -372,6 +427,7 @@ class HomeFragmentAdapter(
|| getItemViewType(gameAndPosition.position) == RECENT_V_GAME
|| getItemViewType(gameAndPosition.position) == ItemViewType.GAME_SUBJECT
|| getItemViewType(gameAndPosition.position) == ItemViewType.GAME_SUBJECT_SLIDE
+ || getItemViewType(gameAndPosition.position) == DISCOVER_CARD
) {
val view = mLayoutManager.findViewByPosition(gameAndPosition.position)
val recyclerView = view?.findViewById(R.id.recycler_view)
@@ -383,6 +439,7 @@ class HomeFragmentAdapter(
is GameHorizontalAdapter -> adapter.notifyItemByDownload(download)
is GameHorizontalSlideAdapter -> adapter.notifyItemByDownload(download)
is HomeRecentVGameAdapter -> adapter.notifyItemByDownload(download)
+ is DiscoverCardGameAdapter -> adapter.notifyItemByDownload(download)
}
} else {
notifyItemChanged(gameAndPosition.position)
@@ -407,6 +464,7 @@ class HomeFragmentAdapter(
|| getItemViewType(position) == ItemViewType.RANK_COLLECTION
|| getItemViewType(position) == ItemViewType.GAME_SUBJECT
|| getItemViewType(position) == ItemViewType.GAME_SUBJECT_SLIDE
+ || getItemViewType(position) == DISCOVER_CARD
) {
val view = mLayoutManager.findViewByPosition(position)
val recyclerView = view?.findViewById(R.id.recycler_view)
@@ -415,6 +473,7 @@ class HomeFragmentAdapter(
is GameVerticalAdapter -> adapter.notifyChildItem(packageName)
is GameHorizontalAdapter -> adapter.notifyChildItem(packageName)
is GameHorizontalSlideAdapter -> adapter.notifyChildItem(packageName)
+ is DiscoverCardGameAdapter -> adapter.notifyChildItem(packageName)
else -> recyclerView?.adapter?.notifyDataSetChanged()
}
} else {
@@ -456,6 +515,18 @@ class HomeFragmentAdapter(
continue
}
+ val discoverCard = itemData.discoverCard
+ if (discoverCard != null) {
+ discoverCard.games.forEach {
+ for (apkEntity in it.getApk()) {
+ if (apkEntity.packageName == packageName) {
+ positionList.add(GameAndPosition(it, position))
+ }
+ }
+ }
+ continue
+ }
+
// 原游戏板块样式
mLegacyHomeFragmentAdapterAssistant.getLegacyGameEntityByPackage(
positionList,
@@ -486,5 +557,6 @@ class HomeFragmentAdapter(
const val UNKNOWN_ITEM: Int = 111
const val GAME_COLLECTION_ITEM: Int = 116
const val RECENT_V_GAME: Int = 117
+ const val DISCOVER_CARD: Int = 118
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeItemData.kt b/app/src/main/java/com/gh/gamecenter/home/HomeItemData.kt
index c928f6f710..0fa045ae28 100644
--- a/app/src/main/java/com/gh/gamecenter/home/HomeItemData.kt
+++ b/app/src/main/java/com/gh/gamecenter/home/HomeItemData.kt
@@ -1,9 +1,6 @@
package com.gh.gamecenter.home
-import com.gh.gamecenter.entity.AmwayCommentEntity
-import com.gh.gamecenter.entity.HomeContent
-import com.gh.gamecenter.entity.HomeRecommend
-import com.gh.gamecenter.entity.HomeSlide
+import com.gh.gamecenter.entity.*
import com.gh.gamecenter.gamecollection.square.GameCollectionListItemData
import com.gh.vspace.VGameItemData
@@ -14,6 +11,7 @@ data class HomeItemData(
var gameCollection: List? = null,
var attachGame: HomeContent? = null,
var recentVGame: ArrayList? = null,
+ var discoverCard: DiscoveryCardEntity? = null,
var lineDivider: Float? = null,
var unknownData: Any? = null
) : LegacyHomeItemData()
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt b/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt
index 2f3b3a103a..3f7e1d98b1 100644
--- a/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt
+++ b/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt
@@ -18,6 +18,7 @@ import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.Response
+import com.gh.gamecenter.common.utils.observableToMain
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.RandomUtils
import com.gh.gamecenter.core.utils.SPUtils
@@ -32,6 +33,7 @@ import com.gh.vspace.VHelper
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
import com.lightgame.utils.Utils
+import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import retrofit2.HttpException
@@ -51,6 +53,8 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
private var mPluginList: List? = null // 插件化
private var mSmartSubject: SubjectEntity? = null // 智能推荐专题
private var mVGameList: ArrayList? = null // 最近的畅玩游戏
+ private var mDiscoveryGameCard: DiscoveryGameCardEntity? = null
+ private var mDiscoveryGameCardLabels: List? = null
private var mContentPage = 1 // 专题分页
private var mIsLoading = false
@@ -292,6 +296,70 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
}
}
+ private fun getDiscoverCardData() {
+ val discoveryGamesObservable = mApi.getDiscoveryGames(1, mapOf("refresh" to "true"))
+ val cardLabelsObservable = mApi.cardLabels
+ when {
+ mDiscoveryGameCard == null && mDiscoveryGameCardLabels == null -> {
+ Observable.mergeDelayError(cardLabelsObservable, discoveryGamesObservable)
+ .compose(observableToMain())
+ .subscribe(object : Response() {
+ override fun onNext(response: Any) {
+ when (response) {
+ is ArrayList<*> -> mDiscoveryGameCardLabels =
+ response as ArrayList
+ is DiscoveryGameCardEntity -> mDiscoveryGameCard =
+ response.apply { games = ArrayList(games.take(18)) }
+ }
+ }
+
+ override fun onComplete() {
+ filterDiscoveryLabel()
+ transformationItemData(mHomeContents)
+ }
+ })
+ }
+ mDiscoveryGameCard == null -> {
+ discoveryGamesObservable.compose(observableToMain())
+ .subscribe(object : Response() {
+ override fun onResponse(response: DiscoveryGameCardEntity?) {
+ mDiscoveryGameCard = response?.apply { games = ArrayList(games.take(18)) }
+ filterDiscoveryLabel()
+ transformationItemData(mHomeContents)
+ }
+ })
+ }
+ mDiscoveryGameCardLabels == null -> {
+ cardLabelsObservable.compose(observableToMain())
+ .subscribe(object : Response>() {
+ override fun onResponse(response: ArrayList?) {
+ super.onResponse(response)
+ mDiscoveryGameCardLabels = response
+ filterDiscoveryLabel()
+ transformationItemData(mHomeContents)
+ }
+ })
+ }
+ }
+ }
+
+ // 过滤分组,现只需要"卡片一"分组
+ private fun filterDiscoveryLabel() {
+ mDiscoveryGameCardLabels = mDiscoveryGameCardLabels?.filter { it.card == "卡片一" }
+ // 如果link_type为空需要在mGameTags中依次获取
+ val gameTags = mDiscoveryGameCard?.gameTags
+ if (gameTags.isNullOrEmpty()) return
+ mDiscoveryGameCardLabels?.forEachIndexed { index, label ->
+ if (gameTags.size > index && label.type.isNullOrEmpty()) {
+ val gameTag = gameTags[index]
+ label.link = gameTag.link
+ label.type = gameTag.type
+ label.linkText = gameTag.linkText
+ label.title = gameTag.linkText
+ }
+ }
+ }
+
//换一批
private fun getChangeSubjectGame(subjectId: String) {
mApi
@@ -599,6 +667,22 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) {
}
mSnapshotItemList.add(LegacyHomeSubjectTransformer.getBlankSpacingItem(HomeItemData()) as HomeItemData)
mSnapshotItemList.add(homeItemData)
+ } else if (linkType == "explore") {
+ if (mDiscoveryGameCard == null || mDiscoveryGameCardLabels == null) {
+ getDiscoverCardData()
+ } else {
+ val homeItemData = HomeItemData().apply {
+ blockPosition = i
+ discoverCard = DiscoveryCardEntity(
+ mDiscoveryGameCard?.games ?: arrayListOf(),
+ mDiscoveryGameCardLabels ?: listOf()
+ )
+ }
+ mSnapshotItemList.add(homeItemData)
+ mDiscoveryGameCard?.games?.forEach {
+ addGamePositionAndPackage(it)
+ }
+ }
} else {
val unknown = HomeItemData()
unknown.blockPosition = i + 1
diff --git a/app/src/main/java/com/gh/gamecenter/home/discovercard/DiscoverCardGameAdapter.kt b/app/src/main/java/com/gh/gamecenter/home/discovercard/DiscoverCardGameAdapter.kt
new file mode 100644
index 0000000000..51027dc550
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/home/discovercard/DiscoverCardGameAdapter.kt
@@ -0,0 +1,227 @@
+package com.gh.gamecenter.home.discovercard
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.Context
+import android.view.Gravity
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import android.widget.RelativeLayout
+import android.widget.TextView
+import com.gh.common.util.DownloadItemUtils
+import com.gh.gamecenter.GameDetailActivity
+import com.gh.gamecenter.R
+import com.gh.gamecenter.common.constant.Constants
+import com.gh.gamecenter.common.retrofit.BiResponse
+import com.gh.gamecenter.common.utils.*
+import com.gh.gamecenter.core.utils.StringUtils
+import com.gh.gamecenter.core.utils.ToastUtils
+import com.gh.gamecenter.databinding.LayoutPopupDiscoveryDislikeBinding
+import com.gh.gamecenter.discovery.DiscoveryAdapter.DiscoveryGameViewHolder
+import com.gh.gamecenter.entity.GameEntity
+import com.gh.gamecenter.retrofit.RetrofitManager
+import com.google.android.flexbox.FlexboxLayout
+import com.lightgame.adapter.BaseRecyclerAdapter
+import com.lightgame.download.DownloadEntity
+import okhttp3.ResponseBody
+
+class DiscoverCardGameAdapter(
+ context: Context,
+ private var mEntrance: String,
+ private var mList: ArrayList
+) : BaseRecyclerAdapter(context) {
+
+ private var countAndKey: Pair? = null
+
+ init {
+ var dataIds = ""
+ mList.forEach {
+ dataIds += it.id
+ }
+ if (dataIds.isNotEmpty()) countAndKey = Pair(mList.size, dataIds)
+ }
+
+ override fun getItemCount() = mList.size
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DiscoveryGameViewHolder {
+ return DiscoveryGameViewHolder(parent.toBinding())
+ }
+
+ override fun onBindViewHolder(holder: DiscoveryGameViewHolder, position: Int) {
+ val gameEntity = mList[position]
+ val isEndOfRow = position >= if (itemCount % SPAN_COUNT == 0) {
+ itemCount - SPAN_COUNT
+ } else {
+ itemCount - itemCount % SPAN_COUNT
+ }
+ val screenWidth = mContext.resources.displayMetrics.widthPixels
+ if (!isEndOfRow) {
+ holder.itemView.layoutParams = ViewGroup.LayoutParams(screenWidth - 58F.dip2px(), 76F.dip2px())
+ holder.itemView.setPadding(14F.dip2px(), 0, 0, 0)
+ } else {
+ holder.itemView.layoutParams = ViewGroup.LayoutParams(screenWidth - 44F.dip2px(), 76F.dip2px())
+ holder.itemView.setPadding(14F.dip2px(), 0, 14F.dip2px(), 0)
+ }
+ holder.itemView.setBackgroundResource(R.color.transparent.toColor(mContext))
+ DownloadItemUtils.updateItem(mContext, gameEntity, holder, true, "star")
+ holder.bindGameItem(gameEntity)
+ holder.itemView.setOnClickListener {
+ GameDetailActivity.startGameDetailActivity(
+ mContext,
+ gameEntity,
+ StringUtils.buildString("(${mEntrance}", "-发现页卡片[", (position).toString(), "])"),
+ traceEvent = gameEntity.exposureEvent
+ )
+ }
+ holder.itemView.setOnLongClickListener {
+ showDislikeWindow(holder.itemView, position, gameEntity)
+ true
+ }
+ DownloadItemUtils.setOnClickListener(
+ mContext,
+ holder.binding.downloadBtn,
+ gameEntity,
+ position,
+ this,
+ StringUtils.buildString("(${mEntrance}", "-发现页卡片[", (position).toString(), "])"),
+ StringUtils.buildString(mEntrance, ":", gameEntity.name),
+ gameEntity.exposureEvent
+ )
+ }
+
+ @SuppressLint("CheckResult")
+ private fun showDislikeWindow(view: View, position: Int, gameEntity: GameEntity) {
+ val decorView = (mContext as Activity).window.decorView as? FrameLayout
+ val binding = LayoutPopupDiscoveryDislikeBinding.inflate(LayoutInflater.from(mContext), decorView, true)
+ binding.reasonFlex.removeAllViews()
+ Constants.FEEDBACK_REASON_LIST.toList().forEach {
+ val popupItem = getPopupItem(it)
+ val params =
+ FlexboxLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
+ binding.reasonFlex.addView(popupItem, params)
+ popupItem.setOnClickListener {
+ discoveryFeedback(gameEntity.id, popupItem.text.toString(), gameEntity.type ?: "") {
+ mList.removeAt(position)
+ notifyItemRemoved(position)
+ decorView?.removeView(binding.root)
+ ToastUtils.showToast("已根据你的偏好优化推荐机制~", Gravity.CENTER)
+ }
+ }
+ }
+ binding.root.setOnClickListener {
+ decorView?.removeView(it)
+ }
+ binding.contentView.visibility = View.INVISIBLE
+ binding.contentView.post {
+ val (windowPosition, isNeedShowUp) = getWindowPosition(view, binding.contentView, 36F.dip2px())
+ (binding.contentView.layoutParams as RelativeLayout.LayoutParams).run {
+ topMargin = windowPosition[1]
+ binding.contentView.layoutParams = this
+ }
+ binding.anchorUpIv.goneIf(isNeedShowUp)
+ binding.anchorDownIv.goneIf(!isNeedShowUp)
+ binding.contentView.visibility = View.VISIBLE
+ }
+ }
+
+ private fun getPopupItem(reason: String): TextView {
+ return TextView(mContext).apply {
+ height = 32F.dip2px()
+ text = reason
+ textSize = 12F
+ includeFontPadding = false
+ setTextColor(R.color.text_subtitle.toColor(mContext))
+ gravity = Gravity.CENTER
+ setPadding(12F.dip2px(), 0F.dip2px(), 12F.dip2px(), 0F.dip2px())
+ background = R.drawable.bg_shape_space_radius_8.toDrawable(mContext)
+ }
+ }
+
+ private fun getWindowPosition(
+ anchorView: View,
+ contentView: View,
+ distanceY: Int = 0
+ ): Pair {
+ val windowPos = IntArray(2)
+ val anchorLoc = IntArray(2)
+ anchorView.getLocationInWindow(anchorLoc)
+ val anchorHeight = anchorView.height
+ val screenHeight = anchorView.context.resources.displayMetrics.heightPixels
+ contentView.measure(0, 0)
+ val contentViewWidth = contentView.width
+ val contentViewHeight = contentView.height
+ val isNeedShowUp = screenHeight - anchorLoc[1] - anchorHeight < contentViewHeight
+ windowPos[1] = if (isNeedShowUp) {
+ anchorLoc[1] - contentViewHeight + distanceY
+ } else {
+ anchorLoc[1] + anchorHeight - distanceY
+ }
+ windowPos[0] = (anchorLoc[0] - contentViewWidth + anchorView.width) / 2
+ return Pair(windowPos, isNeedShowUp)
+ }
+
+ @SuppressLint("CheckResult")
+ private fun discoveryFeedback(gameId: String, reason: String, type: String, callback: () -> Unit) {
+ val paramsMap = mapOf(
+ "reason" to reason,
+ "type" to type
+ )
+ RetrofitManager.getInstance().api.discorveryFeedback(gameId, paramsMap.toRequestBody())
+ .compose(singleToMain())
+ .subscribe(object : BiResponse() {
+
+ override fun onSuccess(data: ResponseBody) {
+ callback.invoke()
+ }
+
+ override fun onFailure(exception: Exception) {
+ super.onFailure(exception)
+ ToastUtils.showToast("反馈失败")
+ }
+ })
+ }
+
+ fun notifyItemByDownload(downloadEntity: DownloadEntity?) {
+ if (downloadEntity == null) {
+ notifyDataSetChanged()
+ } else {
+ mList.forEachIndexed { position, gameEntity ->
+ if (downloadEntity.gameId == gameEntity.id) {
+ notifyItemChanged(position)
+ }
+ }
+ }
+ }
+
+ fun notifyChildItem(packageName: String) {
+ mList.forEachIndexed { position, gameEntity ->
+ gameEntity.getApk().forEach { apkEntity ->
+ if (apkEntity.packageName == packageName) {
+ notifyItemChanged(position)
+ return
+ }
+ }
+ }
+ }
+
+ fun checkResetData(update: ArrayList) {
+ var dataIds = ""
+ update.forEach { dataIds += it.id }
+
+ mList = update
+ if (countAndKey?.first == update.size && countAndKey?.second != dataIds) { // 数量不变,内容发生改变
+ notifyItemRangeChanged(0, itemCount)
+ } else if (countAndKey?.first != update.size) { // 数量发生改变
+ notifyDataSetChanged()
+ }
+
+ // 重新刷新数据标识
+ countAndKey = Pair(update.size, dataIds)
+ }
+
+ companion object {
+ const val SPAN_COUNT = 3
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/home/discovercard/HomeDiscoverCardViewHolder.kt b/app/src/main/java/com/gh/gamecenter/home/discovercard/HomeDiscoverCardViewHolder.kt
new file mode 100644
index 0000000000..ffa5034053
--- /dev/null
+++ b/app/src/main/java/com/gh/gamecenter/home/discovercard/HomeDiscoverCardViewHolder.kt
@@ -0,0 +1,108 @@
+package com.gh.gamecenter.home.discovercard
+
+import android.content.Context
+import android.view.Gravity
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.recyclerview.widget.DefaultItemAnimator
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.gh.common.constant.Config
+import com.gh.common.util.DirectUtils
+import com.gh.common.util.NewFlatLogUtils
+import com.gh.gamecenter.R
+import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
+import com.gh.gamecenter.common.utils.dip2px
+import com.gh.gamecenter.common.utils.goneIf
+import com.gh.gamecenter.common.utils.setDrawableEnd
+import com.gh.gamecenter.common.utils.toColor
+import com.gh.gamecenter.databinding.HomeDiscoverCardItemBinding
+import com.gh.gamecenter.discovery.DiscoveryActivity
+import com.gh.gamecenter.discovery.interestedgame.InterestedGameActivity
+import com.gh.gamecenter.entity.DiscoveryCardEntity
+import com.gh.gamecenter.entity.DiscoveryGameCardLabel
+import com.gh.gamecenter.game.vertical.SpanCountPagerSnapHelper
+import splitties.views.dsl.core.endMargin
+
+class HomeDiscoverCardViewHolder(val binding: HomeDiscoverCardItemBinding) : BaseRecyclerViewHolder(binding.root) {
+
+ fun bindView(
+ entity: DiscoveryCardEntity,
+ entrance: String, blockName: String = ""
+ ): SpanCountPagerSnapHelper {
+ val spanCount = 3
+ val snapHelper = SpanCountPagerSnapHelper(spanCount, true)
+ binding.run {
+ val context = root.context
+ prefsIv.goneIf(!Config.getUserInterestedGame()) {
+ prefsIv.setOnClickListener {
+ context.startActivity(InterestedGameActivity.getIntent(context, "${entrance}-发现页卡片"))
+ NewFlatLogUtils.logInterestedGameClick(entrance, blockName)
+ }
+ }
+ allTv.setOnClickListener {
+ context.startActivity(DiscoveryActivity.getIntent(context, "${entrance}-发现页卡片"))
+ NewFlatLogUtils.logDiscoverDetailPageEnter(entrance, blockName)
+ }
+ recyclerView.run {
+ clearOnScrollListeners()
+ (itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false
+ onFlingListener = null
+
+ if (layoutManager !is GridLayoutManager) {
+ layoutManager = GridLayoutManager(context, spanCount, RecyclerView.HORIZONTAL, false)
+ }
+
+ if (adapter is DiscoverCardGameAdapter) {
+ val discoverCardGameAdapter = adapter as DiscoverCardGameAdapter
+ discoverCardGameAdapter.checkResetData(entity.games)
+ } else {
+ adapter = DiscoverCardGameAdapter(context, entrance, entity.games)
+ }
+ snapHelper.attachToRecyclerView(this)
+ isNestedScrollingEnabled = false
+ }
+
+ val childCount = labelContainer.childCount
+ entity.label.forEachIndexed { index, label ->
+ if (index < childCount) {
+ val labelView = labelContainer.getChildAt(index) as TextView
+ updateLabelView(context, labelView, label, index == entity.label.size - 1)
+ } else {
+ val newLabelView = TextView(context)
+ updateLabelView(context, newLabelView, label, index == entity.label.size - 1)
+ labelContainer.addView(newLabelView)
+ }
+ }
+ }
+ return snapHelper
+ }
+
+ private fun updateLabelView(
+ context: Context,
+ textView: TextView,
+ label: DiscoveryGameCardLabel,
+ isLast: Boolean
+ ) {
+ if (textView.text == label.title) return
+
+ textView.run {
+ layoutParams = LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ 36F.dip2px()
+ ).apply { endMargin = if (isLast) 14F.dip2px() else 8F.dip2px() }
+ setPadding(12F.dip2px(), 0, 12F.dip2px(), 0)
+ setBackgroundResource(R.drawable.bg_shape_space_radius_4)
+ gravity = Gravity.CENTER
+ setDrawableEnd(R.drawable.ic_interest_arrow)
+ compoundDrawablePadding = 8F.dip2px()
+ setTextColor(R.color.text_subtitle.toColor(context))
+ textSize = 12F
+ text = label.title
+ label.text = label.linkText
+ setOnClickListener {
+ DirectUtils.directToLinkPage(context, label, "发现页卡片", "")
+ }
+ }
+ }
+}
\ No newline at end of file
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 58a56dfb17..e7c67f145e 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
@@ -50,6 +50,7 @@ import com.gh.gamecenter.entity.HelpEntity;
import com.gh.gamecenter.entity.HomeContent;
import com.gh.gamecenter.entity.HomeDataEntity;
import com.gh.gamecenter.entity.ImageInfoEntity;
+import com.gh.gamecenter.entity.InterestedGameEntity;
import com.gh.gamecenter.entity.LibaoDetailEntity;
import com.gh.gamecenter.entity.LibaoEntity;
import com.gh.gamecenter.entity.LibaoStatusEntity;
@@ -3106,4 +3107,15 @@ public interface ApiService {
@POST("games/archives/configs")
Observable> getGamesArchiveConfigs(@Body RequestBody body);
+ /**
+ * 获取偏好设置(分类标签)的配置数据及用户状态
+ */
+ @GET("user/_interested_game")
+ Single getInterestedGame();
+
+ /**
+ * 更新用户偏好设置
+ */
+ @PUT("user/_interested_game")
+ Single postInterestedGame(@Body RequestBody body);
}
\ No newline at end of file
diff --git a/app/src/main/res/color/interested_game_tag_text_selector.xml b/app/src/main/res/color/interested_game_tag_text_selector.xml
new file mode 100644
index 0000000000..c838ad7d30
--- /dev/null
+++ b/app/src/main/res/color/interested_game_tag_text_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable-night-xxxhdpi/pic_discover_card_title.webp b/app/src/main/res/drawable-night-xxxhdpi/pic_discover_card_title.webp
new file mode 100644
index 0000000000..b196bbb91a
Binary files /dev/null and b/app/src/main/res/drawable-night-xxxhdpi/pic_discover_card_title.webp differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_discover_card_prefs.webp b/app/src/main/res/drawable-xxxhdpi/ic_discover_card_prefs.webp
new file mode 100644
index 0000000000..6c44f69a7c
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_discover_card_prefs.webp differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_interested_game_add.png b/app/src/main/res/drawable-xxxhdpi/ic_interested_game_add.png
new file mode 100644
index 0000000000..b9a5d24a18
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_interested_game_add.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/pic_discover_card_title.webp b/app/src/main/res/drawable-xxxhdpi/pic_discover_card_title.webp
new file mode 100644
index 0000000000..5314e9709b
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/pic_discover_card_title.webp differ
diff --git a/app/src/main/res/drawable/bg_discover_card.xml b/app/src/main/res/drawable/bg_discover_card.xml
new file mode 100644
index 0000000000..540a81c3f2
--- /dev/null
+++ b/app/src/main/res/drawable/bg_discover_card.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_shape_2496ff_alpha_10_radius_8.xml b/app/src/main/res/drawable/bg_shape_2496ff_alpha_10_radius_8.xml
new file mode 100644
index 0000000000..1c1b2c9c97
--- /dev/null
+++ b/app/src/main/res/drawable/bg_shape_2496ff_alpha_10_radius_8.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/border_round_transparent_stroke_divider.xml b/app/src/main/res/drawable/border_round_transparent_stroke_divider.xml
new file mode 100644
index 0000000000..dbc21ae1f3
--- /dev/null
+++ b/app/src/main/res/drawable/border_round_transparent_stroke_divider.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_interested_game_tag_delete.xml b/app/src/main/res/drawable/ic_interested_game_tag_delete.xml
new file mode 100644
index 0000000000..eab80245fe
--- /dev/null
+++ b/app/src/main/res/drawable/ic_interested_game_tag_delete.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable/interested_game_tag_selector.xml b/app/src/main/res/drawable/interested_game_tag_selector.xml
new file mode 100644
index 0000000000..9f5b239710
--- /dev/null
+++ b/app/src/main/res/drawable/interested_game_tag_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_interested_game_type.xml b/app/src/main/res/layout/dialog_interested_game_type.xml
new file mode 100644
index 0000000000..4dc401718b
--- /dev/null
+++ b/app/src/main/res/layout/dialog_interested_game_type.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_interested_game.xml b/app/src/main/res/layout/fragment_interested_game.xml
new file mode 100644
index 0000000000..07a5612d96
--- /dev/null
+++ b/app/src/main/res/layout/fragment_interested_game.xml
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/home_discover_card_item.xml b/app/src/main/res/layout/home_discover_card_item.xml
new file mode 100644
index 0000000000..b6ddf9dd8b
--- /dev/null
+++ b/app/src/main/res/layout/home_discover_card_item.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/interested_game_sub_tag_item.xml b/app/src/main/res/layout/interested_game_sub_tag_item.xml
new file mode 100644
index 0000000000..56bbdbeba9
--- /dev/null
+++ b/app/src/main/res/layout/interested_game_sub_tag_item.xml
@@ -0,0 +1,15 @@
+
+
diff --git a/app/src/main/res/layout/interested_game_type_item.xml b/app/src/main/res/layout/interested_game_type_item.xml
new file mode 100644
index 0000000000..a0f0402305
--- /dev/null
+++ b/app/src/main/res/layout/interested_game_type_item.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
\ 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
index d3c03a261e..8b074b29c2 100644
--- a/app/src/main/res/layout/item_recommend_interest_footer.xml
+++ b/app/src/main/res/layout/item_recommend_interest_footer.xml
@@ -6,7 +6,20 @@
android:background="@color/background_white"
android:padding="16dp">
+
+
+ app:layout_constraintTop_toBottomOf="@+id/interestedGameTv" />
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index aaaad60087..632c055f07 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -483,6 +483,8 @@
安装游戏
使用云存档后,将会覆盖您畅玩助手内的相关游戏进度,若您想保留自己的游戏数据,请先上传您当前的游戏存档后再使用
+ 去 设置偏好]]> ,让推荐更懂你的心~
+
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 1119427cec..e52044a8cc 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -279,4 +279,34 @@
- @drawable/button_round_gray_light
- @color/text_subtitle
+
+
+
+
+
+
\ No newline at end of file
diff --git a/module_common/src/main/java/com/gh/gamecenter/common/constant/ItemViewType.java b/module_common/src/main/java/com/gh/gamecenter/common/constant/ItemViewType.java
index df954ee2bf..3ef86f01b3 100644
--- a/module_common/src/main/java/com/gh/gamecenter/common/constant/ItemViewType.java
+++ b/module_common/src/main/java/com/gh/gamecenter/common/constant/ItemViewType.java
@@ -44,6 +44,7 @@ public class ItemViewType {
public static final int COMMON_LINK_COLLECTION12 = 35; // 通用链接合集(1-2样式)
public static final int GAME_ITEM = 36;
public static final int DIVIDER_ITEM = 37;
+ public static final int DISCOVER_CARD = 38;
/**
* 普通列表
diff --git a/module_common/src/main/res/drawable/background_shape_white_radius_6_bottom_only.xml b/module_common/src/main/res/drawable/background_shape_white_radius_6_bottom_only.xml
new file mode 100644
index 0000000000..4e61dbb44a
--- /dev/null
+++ b/module_common/src/main/res/drawable/background_shape_white_radius_6_bottom_only.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/module_common/src/main/res/drawable/background_shape_white_radius_6_top_only.xml b/module_common/src/main/res/drawable/background_shape_white_radius_6_top_only.xml
new file mode 100644
index 0000000000..3160a50005
--- /dev/null
+++ b/module_common/src/main/res/drawable/background_shape_white_radius_6_top_only.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file