fix:【光环助手】搜索业务:搜索分类导航功能问题 https://jira.shanqu.cc/browse/GHZSCY-6728

This commit is contained in:
张晨
2024-09-26 17:36:34 +08:00
parent c775ddd922
commit ac38f3b239
26 changed files with 324 additions and 117 deletions

View File

@ -7,26 +7,31 @@ import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.*
import android.widget.EditText
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.core.widget.doAfterTextChanged
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import com.gh.common.util.*
import com.gh.common.util.DataCollectionUtils
import com.gh.common.util.LogUtils
import com.gh.gamecenter.DisplayType.*
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.TextHelper
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.updateStatusBarColor
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.db.SearchHistoryDao
import com.gh.gamecenter.eventbus.EBSearch
import com.gh.gamecenter.search.SearchTabActivity
import com.gh.gamecenter.search.SearchDefaultFragment
import com.gh.gamecenter.search.SearchGameIndexFragment
import com.gh.gamecenter.search.SearchGameResultFragment
import com.gh.gamecenter.search.SearchTabActivity
import com.lightgame.utils.Util_System_Keyboard
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.subjects.PublishSubject
@ -44,7 +49,7 @@ open class SearchActivity : BaseActivity() {
lateinit var backBtn: RelativeLayout
private lateinit var deleteIv: ImageView
protected val mDao: ISearchHistoryDao by lazy { provideDao() }
val mDao: ISearchHistoryDao by lazy { provideDao() }
protected var mSearchKey: String? = null
protected var mIsAutoSearchDisabled: Boolean = false
@ -123,10 +128,22 @@ open class SearchActivity : BaseActivity() {
updateDisplayType(DEFAULT)
}
val bottomTab = intent.getStringExtra(EntranceConsts.KEY_BOTTOM_TAB_NAME) ?: ""
val multiTabId = intent.getStringExtra(EntranceConsts.KEY_MULTI_TAB_NAV_ID) ?: ""
val multiTabName = intent.getStringExtra(EntranceConsts.KEY_MULTI_TAB_NAV_NAME) ?: ""
val customPageId = intent.getStringExtra(EntranceConsts.KEY_CUSTOM_PAGE_ID) ?: ""
val customPageName = intent.getStringExtra(EntranceConsts.KEY_CUSTOM_PAGE_NAME) ?: ""
val searchBoxPattern = intent.getStringExtra(EntranceConsts.KEY_SEARCH_BOX_PATTERN) ?: ""
SensorsBridge.trackGameSearchPageShow(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
mSourceEntrance
mSourceEntrance,
bottomTab,
multiTabId,
multiTabName,
customPageId,
customPageName,
searchBoxPattern
)
}
@ -325,10 +342,8 @@ open class SearchActivity : BaseActivity() {
else -> null
}
transaction?.let {
mDisplayType = type
it.commitAllowingStateLoss()
}
mDisplayType = type
transaction?.commitAllowingStateLoss()
}
protected fun <T : Fragment> showFragment(
@ -395,6 +410,9 @@ open class SearchActivity : BaseActivity() {
finish()
return true
}
if (supportFragmentManager.fragments.size > 1) {
mDisplayType = DEFAULT
}
return super.handleBackPressed()
}

View File

@ -1,9 +1,12 @@
package com.gh.gamecenter.amway.search
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.db.ISearchHistoryDao
class AmwaySearchDao : ISearchHistoryDao {
private val histories = MutableLiveData(all ?: emptyList())
override fun add(keyword: String) {
val originString = SPUtils.getString(SP_KEY)
@ -11,6 +14,7 @@ class AmwaySearchDao : ISearchHistoryDao {
if (originString.isEmpty()) {
// Insert keyword only for the very first time.
SPUtils.setString(SP_KEY, keyword)
histories.postValue(listOf(keyword))
} else {
getAll()?.let {
// Move keyword to the very front if it exists.
@ -26,6 +30,7 @@ class AmwaySearchDao : ISearchHistoryDao {
}
}
SPUtils.setString(SP_KEY, builder.toString())
histories.postValue(it)
}
}
}
@ -38,10 +43,15 @@ class AmwaySearchDao : ISearchHistoryDao {
override fun deleteAll() {
SPUtils.setString(SP_KEY, "")
histories.postValue(emptyList())
}
override fun delete(item: String) {}
override fun getHistoryLiveData(): LiveData<List<String>> {
return histories
}
companion object {
const val SP_KEY = "amway_key"
const val SEARCH_KEY_DIVIDER = "<-||->"

View File

@ -7,7 +7,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.databinding.FragmentAmwaySearchDefaultBinding
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.eventbus.EBSearch
import com.gh.gamecenter.search.SearchDefaultFragment
import com.lightgame.utils.Util_System_Keyboard
@ -42,7 +41,6 @@ class AmwaySearchDefaultFragment : SearchDefaultFragment() {
}
}
override fun provideDao(): ISearchHistoryDao = AmwaySearchDao()
override fun initView() {
mBinding = mAmwayBinding.searchContent
mBinding.searchDiscoveryHeadContainer.headTitle.text = "最近玩过"

View File

@ -1,5 +1,7 @@
package com.gh.gamecenter.db;
import androidx.lifecycle.LiveData;
import java.util.List;
public interface ISearchHistoryDao {
@ -11,4 +13,6 @@ public interface ISearchHistoryDao {
void delete(String item);
List<String> getAll();
LiveData<List<String>> getHistoryLiveData();
}

View File

@ -2,17 +2,23 @@ package com.gh.gamecenter.db;
import android.content.Context;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.gh.gamecenter.core.AppExecutor;
import com.gh.gamecenter.db.info.SearchHistoryInfo;
import com.j256.ormlite.dao.CloseableIterator;
import com.j256.ormlite.dao.Dao;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class SearchHistoryDao implements ISearchHistoryDao {
private final MutableLiveData<List<String>> histories = new MutableLiveData<>();
private DatabaseHelper helper;
private Dao<SearchHistoryInfo, String> dao;
@ -20,6 +26,7 @@ public class SearchHistoryDao implements ISearchHistoryDao {
try {
helper = DatabaseHelper.getHelper(context);
dao = helper.getDao(SearchHistoryInfo.class);
histories.postValue(getAll());
} catch (Exception e) {
e.printStackTrace();
}
@ -30,6 +37,7 @@ public class SearchHistoryDao implements ISearchHistoryDao {
AppExecutor.getIoExecutor().execute(() -> {
try {
dao.createOrUpdate(new SearchHistoryInfo(item));
histories.postValue(getAll());
} catch (Exception e) {
e.printStackTrace();
}
@ -41,6 +49,7 @@ public class SearchHistoryDao implements ISearchHistoryDao {
AppExecutor.getIoExecutor().execute(() -> {
try {
dao.deleteById(item);
histories.postValue(getAll());
} catch (Exception e) {
e.printStackTrace();
}
@ -58,6 +67,7 @@ public class SearchHistoryDao implements ISearchHistoryDao {
e.printStackTrace();
}
}
histories.postValue(Collections.emptyList());
});
return;
}
@ -79,5 +89,8 @@ public class SearchHistoryDao implements ISearchHistoryDao {
return history;
}
@Override
public LiveData<List<String>> getHistoryLiveData() {
return histories;
}
}

View File

@ -7,7 +7,6 @@ import androidx.constraintlayout.widget.ConstraintLayout
import com.gh.gamecenter.R
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.databinding.FragmentSearchDefaultBinding
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.eventbus.EBSearch
import com.gh.gamecenter.search.SearchDefaultFragment
import com.lightgame.utils.Util_System_Keyboard
@ -38,8 +37,6 @@ class ForumOrUserSearchDefaultFragment : SearchDefaultFragment() {
updateView()
}
override fun provideDao(): ISearchHistoryDao = ForumSearchDao()
override fun initView() {
mBinding = FragmentSearchDefaultBinding.bind(mCachedView)
mBinding.searchDiscoveryTagHeadContainer.root.visibility = View.GONE

View File

@ -1,15 +1,21 @@
package com.gh.gamecenter.forum.search
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.db.ISearchHistoryDao
class ForumSearchDao : ISearchHistoryDao {
private val histories = MutableLiveData(all ?: emptyList())
override fun add(keyword: String) {
val originString = SPUtils.getString(SP_KEY)
if (originString.isEmpty()) {
// Insert keyword only for the very first time.
SPUtils.setString(SP_KEY, keyword)
histories.postValue(listOf(keyword))
} else {
getAll()?.let {
// Move keyword to the very front if it exists.
@ -25,6 +31,7 @@ class ForumSearchDao : ISearchHistoryDao {
}
}
SPUtils.setString(SP_KEY, builder.toString())
histories.postValue(it)
}
}
}
@ -39,6 +46,11 @@ class ForumSearchDao : ISearchHistoryDao {
override fun deleteAll() {
SPUtils.setString(SP_KEY, "")
histories.postValue(emptyList())
}
override fun getHistoryLiveData(): LiveData<List<String>> {
return histories
}
companion object {

View File

@ -1,5 +1,7 @@
package com.gh.gamecenter.minigame
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.db.ISearchHistoryDao
@ -8,12 +10,15 @@ import com.gh.gamecenter.db.ISearchHistoryDao
*/
class MiniGameSearchDao : ISearchHistoryDao {
private val histories = MutableLiveData(all ?: emptyList())
override fun add(keyword: String) {
val originString = SPUtils.getString(SP_KEY)
if (originString.isEmpty()) {
// Insert keyword only for the very first time.
SPUtils.setString(SP_KEY, keyword)
histories.postValue(listOf(keyword))
} else {
all?.let {
// Move keyword to the very front if it exists.
@ -29,6 +34,7 @@ class MiniGameSearchDao : ISearchHistoryDao {
}
}
SPUtils.setString(SP_KEY, builder.toString())
histories.postValue(it)
}
}
}
@ -45,6 +51,9 @@ class MiniGameSearchDao : ISearchHistoryDao {
SPUtils.setString(SP_KEY, "")
}
override fun getHistoryLiveData(): LiveData<List<String>> {
return histories
}
companion object {
const val SP_KEY = "mini_game_key"

View File

@ -5,7 +5,6 @@ import com.gh.common.constant.Config
import com.gh.common.filter.RegionSettingHelper
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.databinding.FragmentSearchDefaultBinding
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.search.SearchDefaultFragment
@ -14,8 +13,6 @@ import com.gh.gamecenter.search.SearchDefaultFragment
*/
class MiniGameSearchDefaultFragment : SearchDefaultFragment() {
override fun provideDao(): ISearchHistoryDao = MiniGameSearchDao()
override fun initView() {
mBinding = FragmentSearchDefaultBinding.bind(mCachedView)
mRankList = Config.getNewApiSettingsEntity()?.search?.wechatGameSearchList?.apply {

View File

@ -17,6 +17,7 @@ import com.gh.common.exposure.ExposureManager
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.common.base.fragment.BaseFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.exposure.ExposureSource
@ -59,6 +60,8 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
// FlexboxLayout:maxLine 不符合需求
protected val mFlexMaxHeight = DisplayUtils.dip2px(57F)
private val mDao by lazy { provideDao() }
private val mSearchDiscoveryTagClickListener: (Int) -> Unit = {
val tag = mSearchDiscoveryTagList!![it]
val keyword = tag.keyword
@ -142,7 +145,11 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
}
mBinding.searchDiscoveryTagFlexContainer.setLimitHeight(mFlexMaxHeight)
createFlexContent(mBinding.searchDiscoveryTagFlex, getTagListString(), clickListener = mSearchDiscoveryTagClickListener)
createFlexContent(
mBinding.searchDiscoveryTagFlex,
getTagListString(),
clickListener = mSearchDiscoveryTagClickListener
)
initHeadView()
initRankViewPager()
}
@ -331,7 +338,8 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
}
mBinding.searchDiscoveryTagHeadContainer.root.visibility =
if (mViewModel?.isExistSearchDiscoveryTag == true) View.VISIBLE else View.GONE
mBinding.searchDiscoveryTagFlex.visibility = if (mViewModel?.isExistSearchDiscoveryTag == true) View.VISIBLE else View.GONE
mBinding.searchDiscoveryTagFlex.visibility =
if (mViewModel?.isExistSearchDiscoveryTag == true) View.VISIBLE else View.GONE
mBinding.searchDiscoveryHeadContainer.root.visibility =
if (mViewModel?.isExistHotSearch == true) View.VISIBLE else View.GONE
mBinding.searchDiscoveryList.visibility = if (mViewModel?.isExistHotSearch == true) View.VISIBLE else View.GONE
@ -415,10 +423,15 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
notifyItemRangeChanged(0, itemCount)
}
mViewModel?.historySearchLiveData?.value?.let { updateHistorySearchView(it) }
createFlexContent(mBinding.searchDiscoveryTagFlex, getTagListString(), clickListener = mSearchDiscoveryTagClickListener)
createFlexContent(
mBinding.searchDiscoveryTagFlex,
getTagListString(),
clickListener = mSearchDiscoveryTagClickListener
)
}
protected open fun provideDao(): ISearchHistoryDao = SearchHistoryDao(requireContext().applicationContext)
protected open fun provideDao(): ISearchHistoryDao =
(activity as? SearchActivity)?.mDao ?: SearchHistoryDao(requireContext())
protected open fun provideAdapter(pageRatio: Float): PagerAdapter =
SearchDefaultRankListAdapter(
@ -431,7 +444,7 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
)
private fun provideViewModel(): SearchDefaultViewModel {
val factory = SearchDefaultViewModel.Factory(provideDao())
val factory = SearchDefaultViewModel.Factory(mDao)
return viewModelProvider(factory)
}

View File

@ -1,41 +1,33 @@
package com.gh.gamecenter.search
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.db.ISearchHistoryDao
class SearchDefaultViewModel(private val dao: ISearchHistoryDao) : ViewModel() {
val historySearchLiveData = MutableLiveData<List<String>>()
val historySearchLiveData = Transformations.map(dao.historyLiveData){
it
}
var isExistHotSearch: Boolean = false
var isExistSearchDiscoveryTag: Boolean = false
var isExistHistory: Boolean = false
var isExistRankList: Boolean = false
init {
runOnIoThread {
historySearchLiveData.postValue(dao.all)
}
}
fun deleteAll() {
dao.deleteAll()
historySearchLiveData.postValue(emptyList())
}
fun add(item: String) {
val oldList = historySearchLiveData.value
if (oldList.isNullOrEmpty()) {
dao.add(item)
historySearchLiveData.postValue(listOf(item))
return
}
if (!oldList.contains(item)) {
dao.add(item)
historySearchLiveData.postValue(oldList + item)
}
}

View File

@ -24,6 +24,7 @@ import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.feature.game.GameItemViewHolder
import com.gh.gamecenter.SearchType
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.search.SearchGameResultAdapter.Companion.setItemCLick
import com.gh.gamecenter.search.SearchGameResultAdapter.Companion.showContentTag
import com.lzf.easyfloat.utils.DisplayUtils
@ -34,11 +35,13 @@ class SearchGameFirstItemViewHolder(
private val entrance: String,
private val sourceEntrance: String,
fragment: Fragment,
val binding: SearchGameFirstItemBinding
val binding: SearchGameFirstItemBinding,
private val dao: ISearchHistoryDao
) : RecyclerView.ViewHolder(binding.root) {
private var contentTag: GameEntity.ContentTag? = null
private var game: GameEntity? = null
private var key:String = ""
private val bannerBinding by lazy {
val inflater = LayoutInflater.from(binding.root.context)
@ -68,7 +71,7 @@ class SearchGameFirstItemViewHolder(
link.link,
link.text
)
dao.add(key)
DirectUtils.directToLinkPage(binding.root.context, link, "搜索banner", "")
}
@ -104,6 +107,7 @@ class SearchGameFirstItemViewHolder(
link.link,
link.text
)
dao.add(key)
DirectUtils.directToLinkPage(binding.root.context, link, "搜索卡片栏", "")
}
}
@ -122,6 +126,7 @@ class SearchGameFirstItemViewHolder(
item ?: return
val gameEntity = item.game ?: return
game = gameEntity
this.key = key
val context = binding.root.context
binding.gameItemIncluded.run {
@ -178,12 +183,33 @@ class SearchGameFirstItemViewHolder(
tagContainer.goneIf(!isShowTagByMirror)
if (isShowTagByMirror && gameEntity.contentTag != contentTag) {
contentTag = gameEntity.contentTag
showContentTag(entrance, type, key, bindingAdapterPosition, exposureEvent, gameEntity, tagContainer, sourceEntrance, 0)
showContentTag(
entrance,
type,
key,
bindingAdapterPosition,
exposureEvent,
gameEntity,
tagContainer,
sourceEntrance,
0
)
}
}
binding.root.setOnClickListener {
setItemCLick(entrance, type, key, searchMap, exposureEvent, item, bindingAdapterPosition, context, sourceEntrance)
dao.add(key)
setItemCLick(
entrance,
type,
key,
searchMap,
exposureEvent,
item,
bindingAdapterPosition,
context,
sourceEntrance
)
}
downloadListener(exposureEvent)

View File

@ -32,7 +32,7 @@ import com.gh.gamecenter.databinding.FmSearchHistoryItemBinding
import com.gh.gamecenter.databinding.LayoutSearchGameContentTagBinding
import com.gh.gamecenter.databinding.SearchGameIndexItemBinding
import com.gh.gamecenter.databinding.SearchSubjectItemBinding
import com.gh.gamecenter.db.SearchHistoryDao
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBSearch
import com.gh.gamecenter.feature.exposure.ExposureEvent
@ -47,12 +47,13 @@ import org.greenrobot.eventbus.EventBus
class SearchGameIndexAdapter(
context: Context,
val fragment: SearchGameIndexFragment,
private val dao: ISearchHistoryDao,
val entrance: String,
val type: String,
val sourceEntrance: String
) : ListAdapter<SearchItemData>(context), IExposable {
private val dao = SearchHistoryDao(mContext)
private var exposureEventArray: SparseArray<ExposureEvent>? = null
private var searchMap: ArrayMap<String, String> = ArrayMap()
@ -110,7 +111,14 @@ class SearchGameIndexAdapter(
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is SearchSubjectItemViewHolder) {
holder.binding.topDivider.goneIf(position == 0)
holder.bindSubjectItem(mContext, mEntityList[position], SearchType.fromString(type).toChinese(), key, dao, sourceEntrance)
holder.bindSubjectItem(
mContext,
mEntityList[position],
SearchType.fromString(type).toChinese(),
key,
dao,
sourceEntrance
)
} else {
val gameEntity = mEntityList[position].game!!
val gamePosition = mEntityList[position].gamePosition

View File

@ -25,6 +25,7 @@ import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.databinding.FragmentSearchResultBinding
import com.gh.gamecenter.db.SearchHistoryDao
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.entity.GameEntity
@ -75,10 +76,12 @@ class SearchGameIndexFragment : ListFragment<GameEntity, SearchGameResultViewMod
)
override fun provideListAdapter(): SearchGameIndexAdapter {
val dao = (activity as? SearchActivity)?.mDao
if (mAdapter == null) {
mAdapter = SearchGameIndexAdapter(
requireContext(),
this,
(activity as? SearchActivity)?.mDao ?: SearchHistoryDao(requireContext()),
mEntrance,
mType,
mListViewModel.sourceEntrance
@ -100,7 +103,11 @@ class SearchGameIndexFragment : ListFragment<GameEntity, SearchGameResultViewMod
mListRefresh?.isEnabled = false
mBinding.reuseNoneData.reuseNoneDataDescTv.visibility = View.VISIBLE
mBinding.reuseNoneData.reuseNoneDataTv.setText("没有找到你的游戏~")
mBinding.reuseNoneData.reuseNoneData.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()))
mBinding.reuseNoneData.reuseNoneData.setBackgroundColor(
com.gh.gamecenter.common.R.color.ui_surface.toColor(
requireContext()
)
)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

View File

@ -12,7 +12,7 @@ import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.DrawableView
import com.gh.gamecenter.databinding.SearchGameIndexItemBinding
import com.gh.gamecenter.databinding.SearchSubjectItemBinding
import com.gh.gamecenter.db.SearchHistoryDao
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.feature.databinding.GameItemBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
@ -60,7 +60,7 @@ class SearchSubjectItemViewHolder(var binding: SearchSubjectItemBinding) : Recyc
itemData: SearchItemData,
type: String,
key: String,
dao: SearchHistoryDao? = null,
dao: ISearchHistoryDao? = null,
sourceEntrance: String
) {
val entity = itemData.subject ?: return

View File

@ -36,6 +36,7 @@ import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.StringUtils
import com.gh.gamecenter.databinding.*
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBSearch
import com.gh.gamecenter.feature.databinding.GameItemBinding
@ -54,6 +55,7 @@ import kotlin.collections.set
class SearchGameResultAdapter(
context: Context,
val fragment: SearchGameResultFragment,
private val dao: ISearchHistoryDao,
val listViewModel: SearchGameResultViewModel,
val entrance: String,
val type: String,
@ -138,7 +140,7 @@ class SearchGameResultAdapter(
ITEM_GAME_FIRST -> {
val binding = SearchGameFirstItemBinding.inflate(mLayoutInflater, viewGroup, false)
SearchGameFirstItemViewHolder(type, searchMap, entrance, sourceEntrance, fragment, binding)
SearchGameFirstItemViewHolder(type, searchMap, entrance, sourceEntrance, fragment, binding, dao)
}
ItemViewType.ITEM_BODY -> {
@ -152,7 +154,8 @@ class SearchGameResultAdapter(
}
ItemViewType.ITEM_FOOTER -> {
val itemView = mLayoutInflater.inflate(com.gh.gamecenter.common.R.layout.refresh_footerview, viewGroup, false)
val itemView =
mLayoutInflater.inflate(com.gh.gamecenter.common.R.layout.refresh_footerview, viewGroup, false)
FooterViewHolder(itemView)
}
@ -196,6 +199,7 @@ class SearchGameResultAdapter(
mEntityList[position],
SearchType.fromString(type).toChinese(),
key,
dao,
sourceEntrance = sourceEntrance
)
}
@ -266,7 +270,14 @@ class SearchGameResultAdapter(
}
)
}
AdDelegateHelper.requestThirdPartyFlowAd(fragment, slotId, adContainer, screenWidthInDp, onAdShowAction, onAdClickAction) {
AdDelegateHelper.requestThirdPartyFlowAd(
fragment,
slotId,
adContainer,
screenWidthInDp,
onAdShowAction,
onAdClickAction
) {
}
}
@ -400,6 +411,7 @@ class SearchGameResultAdapter(
}
binding.root.setOnClickListener {
dao.add(key)
setItemCLick(
entrance,
type,

View File

@ -12,7 +12,6 @@ import android.view.animation.TranslateAnimation
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.exposure.ExposureListener
import com.gh.common.util.*
@ -20,6 +19,8 @@ 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.SearchActivity
import com.gh.gamecenter.SearchType
import com.gh.gamecenter.common.baselist.ListFragment
import com.gh.gamecenter.common.baselist.LoadType
import com.gh.gamecenter.common.constant.EntranceConsts
@ -29,12 +30,11 @@ import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.MtaHelper
import com.gh.gamecenter.databinding.FragmentSearchResultBinding
import com.gh.gamecenter.db.SearchHistoryDao
import com.gh.gamecenter.eventbus.EBDownloadStatus
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.help.HelpAndFeedbackBridge
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.SearchType
import com.gh.gamecenter.search.viewmodel.SearchTabViewModel
import com.halo.assistant.HaloApp
import com.lightgame.download.DataWatcher
@ -101,6 +101,7 @@ open class SearchGameResultFragment : ListFragment<GameEntity, SearchGameResultV
SearchGameResultAdapter(
requireContext(),
this,
(activity as? SearchActivity)?.mDao ?: SearchHistoryDao(requireContext()),
mListViewModel,
mEntrance,
mType,
@ -122,7 +123,11 @@ open class SearchGameResultFragment : ListFragment<GameEntity, SearchGameResultV
mListRefresh?.isEnabled = false
mBinding.reuseNoneData.reuseNoneDataDescTv.visibility = View.VISIBLE
mBinding.reuseNoneData.reuseNoneDataTv.setText("没有找到你的游戏~")
mBinding.reuseNoneData.reuseNoneData.setBackgroundColor(com.gh.gamecenter.common.R.color.ui_surface.toColor(requireContext()))
mBinding.reuseNoneData.reuseNoneData.setBackgroundColor(
com.gh.gamecenter.common.R.color.ui_surface.toColor(
requireContext()
)
)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

View File

@ -3,7 +3,6 @@ package com.gh.gamecenter.search
import android.os.Bundle
import androidx.activity.viewModels
import com.gh.gamecenter.DisplayType
import com.gh.gamecenter.R
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.search.fragment.SearchTabFragment
import com.gh.gamecenter.search.viewmodel.SearchTabActivityViewModel
@ -19,21 +18,20 @@ class SearchTabActivity : SearchActivity() {
override fun updateDisplayType(type: DisplayType) {
viewModel.updateSearchKeyAndType(mSearchKey, mSearchType.value)
val lastDisplayType = mDisplayType
mDisplayType = type
// 如果上一次展示的是SearchTabFragment并且当前需要展示的也是SearchTabFragment则无需重复显示
if (lastDisplayType != DisplayType.DEFAULT && type != DisplayType.DEFAULT) {
val topFragment = supportFragmentManager.fragments.lastOrNull()
if (topFragment is SearchTabFragment && type != DisplayType.DEFAULT) {
return
}
if (type == DisplayType.DEFAULT) {
super.updateDisplayType(type)
} else {
val transaction = supportFragmentManager.beginTransaction()
val fragment = supportFragmentManager.findFragmentByTag(SearchTabFragment::class.java.name)
?: SearchTabFragment.newInstance(mSourceEntrance)
transaction.replace(R.id.search_result, fragment)
transaction.commitAllowingStateLoss()
showFragment(SearchTabFragment::class.java.name, {
SearchTabFragment.newInstance(mSourceEntrance)
})
.commitAllowingStateLoss()
}
mDisplayType = type
}
}

View File

@ -1,27 +1,45 @@
package com.gh.gamecenter.search.adapter
import android.util.SparseArray
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.gh.common.exposure.IExposable
import com.gh.gamecenter.SearchType
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.toBinding
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.home.custom.model.CustomPageData
import com.gh.gamecenter.search.viewholder.SearchGameListFooterViewHolder
import com.gh.gamecenter.search.viewholder.SearchGameListViewHolder
import com.gh.gamecenter.search.viewmodel.SearchGameListViewModel
class SearchGameListAdapter(
private val viewModel: SearchGameListViewModel
private val viewModel: SearchGameListViewModel,
private val location: String,
) : ListAdapter<CustomPageData.LinkColumnCollection.CustomSubjectEntity, ViewHolder>(
createDiffUtil()
) {
), IExposable {
private var type = SearchType.DEFAULT.value
private var key = ""
private var exposureEventArray: SparseArray<ExposureEvent>? = null
private var _recyclerView: RecyclerView? = null
private var _loadStatus = LoadStatus.INIT
fun submitList(data: List<CustomPageData.LinkColumnCollection.CustomSubjectEntity>?, key: String, type: String) {
exposureEventArray = SparseArray(data?.size ?: 0)
this.key = key
this.type = type
submitList(data)
}
fun updateStatus(loadStatus: LoadStatus) {
_loadStatus = loadStatus
if (itemCount > 0) {
@ -33,27 +51,34 @@ class SearchGameListAdapter(
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return if (viewType == ITEM_TYPE_CONTENT) {
SearchGameListViewHolder(parent.toBinding(), object : SearchGameListViewHolder.SearchGameListListener {
SearchGameListViewHolder(
parent.toBinding(),
location,
exposureEventArray,
object : SearchGameListViewHolder.SearchGameListListener {
override fun navigateToGameDetailPage(
gameId: String,
collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity
) {
viewModel.navigateToGameDetailPage(gameId, collection)
}
override fun navigateToGameDetailPage(
gameId: String,
collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity
) {
viewModel.navigateToGameDetailPage(gameId, collection)
}
override fun navigateToHomePage(
userId: String,
collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity
) {
viewModel.navigateToHomePage(userId, collection)
}
override fun navigateToHomePage(
userId: String,
collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity
) {
viewModel.navigateToHomePage(userId, collection)
}
override fun navigateGameCollectionDetailPage(collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity) {
viewModel.navigateGameCollectionDetailPage(collection)
}
override fun navigateGameCollectionDetailPage(
collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity,
exposureSourceList: List<ExposureSource>
) {
viewModel.navigateGameCollectionDetailPage(collection, exposureSourceList)
}
})
})
} else {
SearchGameListFooterViewHolder(parent.toBinding(), object : SearchGameListFooterViewHolder.FooterListener {
override fun loadMore() {
@ -75,7 +100,7 @@ class SearchGameListAdapter(
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
when (holder) {
is SearchGameListViewHolder -> {
holder.bind(getItem(position))
holder.bind(getItem(position), key, type)
}
is SearchGameListFooterViewHolder -> {
@ -142,4 +167,10 @@ class SearchGameListAdapter(
}
}
override fun getEventByPosition(pos: Int): ExposureEvent? {
return exposureEventArray?.get(pos)
}
override fun getEventListByPosition(pos: Int): List<ExposureEvent>? = null
}

View File

@ -2,6 +2,7 @@ package com.gh.gamecenter.search.adapter
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.common.constant.EntranceConsts
@ -19,11 +20,15 @@ class SearchTabAdapter(
private val searchType: String?,
private val tabs: List<SettingsEntity.Search.Navigation>,
private val fragment: Fragment
) : FragmentStateAdapter(fragment) {
) : FragmentStatePagerAdapter(fragment.childFragmentManager,BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getItemCount() = tabs.size
override fun getPageTitle(position: Int): CharSequence {
return tabs[position].title
}
override fun createFragment(position: Int): Fragment {
override fun getCount(): Int = tabs.size
override fun getItem(position: Int): Fragment {
val navigation = tabs[position]
val bundle = Bundle().apply {
putBoolean(EntranceConsts.KEY_IS_AUTO_LOAD, false)

View File

@ -5,6 +5,7 @@ import android.os.Bundle
import android.view.View
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import com.gh.common.exposure.ExposureListener
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
@ -13,6 +14,7 @@ import com.gh.gamecenter.common.base.fragment.LazyFragment
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.common.utils.toArrayList
import com.gh.gamecenter.common.view.FixLinearLayoutManager
import com.gh.gamecenter.databinding.FragmentSearchGameListBinding
import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
@ -30,16 +32,16 @@ class SearchGameListFragment : LazyFragment() {
)
private var searchKey = ""
private var searchType = ""
private var location: String = ""
private lateinit var binding: FragmentSearchGameListBinding
private val adapter by lazy(LazyThreadSafetyMode.NONE) {
SearchGameListAdapter(viewModel)
SearchGameListAdapter(viewModel, location)
}
override fun onCreate(savedInstanceState: Bundle?) {
searchKey = arguments?.getString(EntranceConsts.KEY_SEARCHKEY, "") ?: ""
location = arguments?.getString(EntranceConsts.KEY_LOCATION, "") ?: ""
super.onCreate(savedInstanceState)
}
@ -54,7 +56,9 @@ class SearchGameListFragment : LazyFragment() {
@SuppressLint("NotifyDataSetChanged")
override fun initRealView() {
super.initRealView()
parentViewModel.searchKeyAndType.observe(viewLifecycleOwner, Observer { (key, type) ->
parentViewModel.searchKeyAndType.observe(viewLifecycleOwner) { (key, type) ->
this.searchKey = key
this.searchType = type
// 清空上一次的搜索结果
adapter.submitList(null)
// 上面调用了 adapter.submitList(null) ,这里为什么还要调用 notifyDataSetChanged 呢?
@ -62,7 +66,7 @@ class SearchGameListFragment : LazyFragment() {
// 此方法不会立马清空RecyclerView 的内容而是在postOnAnimation执行相关的移除工作这里为了让RecyclerView的内容立马清空需要再次调用adapter.notifyDataSetChanged()
adapter.notifyDataSetChanged()
viewModel.loadFirstData(key, type, location)
})
}
binding.rvGameList.layoutManager = FixLinearLayoutManager(context)
binding.rvGameList.adapter = adapter
@ -72,6 +76,8 @@ class SearchGameListFragment : LazyFragment() {
binding.reuseNoConnection.connectionReloadTv.setOnClickListener {
viewModel.retry()
}
binding.rvGameList.addOnScrollListener(ExposureListener(this, adapter))
with(viewModel) {
loadStatus.observe(viewLifecycleOwner) {
binding.rvGameList.goneIf(it == LoadStatus.INIT_LOADING || it == LoadStatus.INIT_FAILED || it == LoadStatus.INIT_EMPTY)
@ -82,7 +88,7 @@ class SearchGameListFragment : LazyFragment() {
}
dataList.observe(viewLifecycleOwner, Observer {
adapter.submitList(it)
adapter.submitList(it, searchKey, searchType)
})
gameDetailDestination.observe(viewLifecycleOwner, EventObserver {
@ -104,12 +110,13 @@ class SearchGameListFragment : LazyFragment() {
)
})
gameCollectionDetailDestination.observe(viewLifecycleOwner, EventObserver {
gameCollectionDetailDestination.observe(viewLifecycleOwner, EventObserver { (itemId, exposureSourceList) ->
startActivity(
GameCollectionDetailActivity.getIntent(
requireContext(),
it,
isFromSquare = false,
context = requireContext(),
itemId,
topCommentId = "",
exposureSourceList = exposureSourceList.toArrayList()
)
)
})

View File

@ -1,6 +1,5 @@
package com.gh.gamecenter.search.fragment
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -18,7 +17,6 @@ import com.gh.gamecenter.search.viewmodel.SearchTabActivityViewModel
import com.gh.gamecenter.search.viewmodel.SearchTabViewModel
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import com.google.android.material.tabs.TabLayoutMediator
class SearchTabFragment : BaseFragment<Any>() {
@ -105,10 +103,7 @@ class SearchTabFragment : BaseFragment<Any>() {
}
adapter = SearchTabAdapter(location, _searchType, tabs, this)
binding.viewPager.adapter = adapter
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
tab.text = tabs[position].title
tab.customView?.setBackgroundColor(Color.RED)
}.attach()
binding.tabLayout.setupWithViewPager(binding.viewPager)
}
private fun initSingleFragment() {

View File

@ -2,6 +2,8 @@ package com.gh.gamecenter.search.viewholder
import android.content.Context
import android.graphics.Color
import android.text.Html
import android.util.SparseArray
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
@ -11,12 +13,21 @@ import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.gh.common.util.CheckLoginUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.SearchType
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.HtmlUtils
import com.gh.gamecenter.databinding.GameCollectionSquareItemBinding
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
import com.gh.gamecenter.feature.exposure.ExposureType
import com.gh.gamecenter.home.custom.model.CustomPageData
class SearchGameListViewHolder(
val binding: GameCollectionSquareItemBinding,
private val location: String,
private val exposureEventArray: SparseArray<ExposureEvent>?,
private val listener: SearchGameListListener
) : ViewHolder(binding.root) {
@ -27,9 +38,20 @@ class SearchGameListViewHolder(
context.resources.displayMetrics.widthPixels - 32F.dip2px()
}
fun bind(item: CustomPageData.LinkColumnCollection.CustomSubjectEntity) {
fun bind(item: CustomPageData.LinkColumnCollection.CustomSubjectEntity, key: String, searchType: String) {
with(binding) {
val exposureEvent = ExposureEvent.createEvent(
GameEntity().apply {
sequence = bindingAdapterPosition
},
listOf(
ExposureSource(location, ""),
ExposureSource(SearchActivity.toTrackSearchType(searchType), key)
),
null,
ExposureType.EXPOSURE
)
exposureEventArray?.put(bindingAdapterPosition, exposureEvent)
root.updateLayoutParams {
if (this is MarginLayoutParams) {
topMargin = 16F.dip2px()
@ -100,7 +122,7 @@ class SearchGameListViewHolder(
listener.navigateToHomePage(item.user.id, item)
}
root.setOnClickListener {
listener.navigateGameCollectionDetailPage(item)
listener.navigateGameCollectionDetailPage(item, exposureEvent.source)
}
}
}
@ -114,6 +136,9 @@ class SearchGameListViewHolder(
fun navigateToHomePage(userId: String, collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity)
fun navigateGameCollectionDetailPage(collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity)
fun navigateGameCollectionDetailPage(
collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity,
exposureSourceList: List<ExposureSource>
)
}
}

View File

@ -6,6 +6,7 @@ import androidx.lifecycle.ViewModel
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.singleToMain
@ -63,10 +64,10 @@ class SearchGameListViewModel : ViewModel() {
override fun onSuccess(data: List<CustomPageData.LinkColumnCollection.CustomSubjectEntity>) {
if (page == 1) {
_dataList.value = data
_loadStatus.value = if (data.isEmpty()) {
LoadStatus.INIT_EMPTY
} else {
LoadStatus.INIT_LOADED
_loadStatus.value = when {
data.isEmpty() -> LoadStatus.INIT_EMPTY
data.size < 10 -> LoadStatus.LIST_OVER
else -> LoadStatus.INIT_LOADED
}
SensorsBridge.trackGameCollectSearchResultReturn(
GlobalActivityManager.getCurrentPageEntity().pageId,
@ -78,7 +79,7 @@ class SearchGameListViewModel : ViewModel() {
)
} else {
addData(data)
_loadStatus.value = if (data.isEmpty()) {
_loadStatus.value = if (data.size < 10) {
LoadStatus.LIST_OVER
} else {
LoadStatus.LIST_LOADED
@ -120,11 +121,16 @@ class SearchGameListViewModel : ViewModel() {
_homeDestination.value = Event(userId)
}
private val _gameCollectionDetailDestination = MutableLiveData<Event<String>>()
val gameCollectionDetailDestination: LiveData<Event<String>> = _gameCollectionDetailDestination
fun navigateGameCollectionDetailPage(collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity) {
private val _gameCollectionDetailDestination = MutableLiveData<Event<Pair<String, List<ExposureSource>>>>()
val gameCollectionDetailDestination: LiveData<Event<Pair<String, List<ExposureSource>>>> =
_gameCollectionDetailDestination
fun navigateGameCollectionDetailPage(
collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity,
exposureSourceList: List<ExposureSource>
) {
trackGameCollectSearchResultClick(collection)
_gameCollectionDetailDestination.value = Event(collection.id)
_gameCollectionDetailDestination.value = Event(collection.id to exposureSourceList)
}
private fun trackGameCollectSearchResultClick(collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity) {