Merge branch 'feature-GHZS-5576' into 'dev'

feat: 搜索业务-热门榜单新增触发搜索的榜单类型—客户端 https://jira.shanqu.cc/browse/GHZSCY-5576

See merge request halo/android/assistant-android!1738
This commit is contained in:
曾祥俊
2024-08-29 10:43:47 +08:00
13 changed files with 202 additions and 111 deletions

View File

@ -550,6 +550,8 @@ object NewFlatLogUtils {
// 搜索-点击搜索榜单内容
@JvmStatic
fun logSearchClickRankDetail(
key: String,
rankType: String,
rankName: String,
rankSequence: String,
linkId: String,
@ -558,6 +560,8 @@ object NewFlatLogUtils {
) {
val json = json {
KEY_EVENT to "search_click_rank_detail"
"key" to key
"rank_type" to rankType
"rank_name" to rankName
"rank_sequence" to rankSequence
"link_id" to linkId

View File

@ -10,6 +10,8 @@ import android.view.inputmethod.EditorInfo
import android.widget.*
import androidx.core.widget.doAfterTextChanged
import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
import com.gh.common.util.*
import com.gh.common.util.LogUtils
import com.gh.gamecenter.DisplayType.*
@ -118,7 +120,7 @@ open class SearchActivity : BaseActivity() {
trackSearchPageShow()
}
protected open fun trackSearchPageShow(){
protected open fun trackSearchPageShow() {
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) ?: ""
@ -179,10 +181,11 @@ open class SearchActivity : BaseActivity() {
open fun search(type: SearchType, key: String?) {
mSearchType = type
mIsAutoSearchDisabled = true
// 自动搜索,默认搜索,热门搜索,历史搜索,主动搜索
// 自动搜索,默认搜索,热门搜索,历史搜索,主动搜索,榜单搜索
when (type) {
SearchType.AUTO -> handleAutoSearch(key)
SearchType.DEFAULT -> handleDefaultSearch(key)
SearchType.RANK -> handleRankSearch(key)
SearchType.HOT -> handleHotSearch(key)
SearchType.HISTORY -> handleHistorySearch(key)
SearchType.MANUAL -> handleManualSearch()
@ -213,6 +216,22 @@ open class SearchActivity : BaseActivity() {
}
}
protected open fun handleRankSearch(key: String?) {
mSearchKey = key
searchEt.setText(key)
searchEt.setSelection(searchEt.text.length)
updateDisplayType(GAME_DETAIL)
LogUtils.uploadSearchGame("searching", "搜索页", key, "榜单搜索")
SensorsBridge.trackSearchButtonClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
key ?: "",
TRACK_SEARCH_TYPE_DEFAULT,
mSourceEntrance
)
}
protected open fun handleDefaultSearch(key: String?) {
mSearchKey = key
searchEt.setText(key)
@ -286,38 +305,72 @@ open class SearchActivity : BaseActivity() {
protected open fun provideDao(): ISearchHistoryDao = SearchHistoryDao(this)
open fun updateDisplayType(type: DisplayType) {
val transaction = supportFragmentManager.beginTransaction()
when (type) {
DEFAULT -> {
val fragment = supportFragmentManager.findFragmentByTag(SearchDefaultFragment::class.java.name)
?: SearchDefaultFragment().apply {
arguments = Bundle().also { it.putBoolean(SearchDefaultFragment.KEY_IS_GAME_SEARCH, true) }
}
transaction.replace(R.id.search_result, fragment, SearchDefaultFragment::class.java.name)
val transaction = when (type) {
DEFAULT -> showFragment(
SearchDefaultFragment::class.java.name,
{ SearchDefaultFragment() }
) {
it.arguments = Bundle().also { bundle ->
bundle.putBoolean(SearchDefaultFragment.KEY_IS_GAME_SEARCH, true)
}
}
GAME_DIGEST -> {
val digestListFragment =
supportFragmentManager.findFragmentByTag(SearchGameIndexFragment::class.java.name) as? SearchGameIndexFragment
?: SearchGameIndexFragment()
digestListFragment.setParams(mSearchKey ?: "", mSearchType.value)
transaction.replace(R.id.search_result, digestListFragment, SearchGameIndexFragment::class.java.name)
GAME_DIGEST -> showFragment(
SearchGameIndexFragment::class.java.name,
{ SearchGameIndexFragment() }
) {
removeFragment(SearchGameResultFragment::class.java.name)
it.setParams(mSearchKey ?: "", mSearchType.value)
}
GAME_DETAIL -> {
val detailListFragment =
supportFragmentManager.findFragmentByTag(SearchGameResultFragment::class.java.name) as? SearchGameResultFragment
?: SearchGameResultFragment()
detailListFragment.setParams(mSearchKey ?: "", mSearchType.value)
transaction.replace(R.id.search_result, detailListFragment, SearchGameResultFragment::class.java.name)
GAME_DETAIL -> showFragment(
SearchGameResultFragment::class.java.name,
{ SearchGameResultFragment() }
) {
removeFragment(SearchGameIndexFragment::class.java.name)
it.setParams(mSearchKey ?: "", mSearchType.value)
}
else -> {
//do nothing
}
else -> null
}
mDisplayType = type
transaction.commitAllowingStateLoss()
transaction?.let {
mDisplayType = type
it.commitAllowingStateLoss()
}
}
protected fun <T : Fragment> showFragment(
tag: String,
onFragmentCreate: () -> T,
onFragmentCreated: ((T) -> Unit)? = null,
): FragmentTransaction {
val transaction = supportFragmentManager.beginTransaction()
var createNewFragment = false
var fragment = supportFragmentManager
.findFragmentByTag(tag)
if (fragment == null) {
createNewFragment = true
fragment = onFragmentCreate.invoke()
}
onFragmentCreated?.invoke(fragment as T)
if (createNewFragment) {
transaction.add(R.id.search_result, fragment, tag)
transaction.addToBackStack(null)
} else if (!fragment.isAdded) {
transaction.show(fragment)
transaction.addToBackStack(null)
}
return transaction
}
protected fun removeFragment(tag: String) {
val fragment = supportFragmentManager
.findFragmentByTag(tag) ?: return
supportFragmentManager
.beginTransaction()
.remove(fragment)
.commit()
supportFragmentManager.popBackStack()
}
@Subscribe(threadMode = ThreadMode.MAIN)
@ -325,6 +378,7 @@ open class SearchActivity : BaseActivity() {
when (search.type) {
SearchType.HISTORY.value -> search(SearchType.HISTORY, search.key)
SearchType.HOT.value -> search(SearchType.HOT, search.key)
SearchType.RANK.value -> search(SearchType.RANK, search.key)
"click" -> DataCollectionUtils.uploadSearchClick(
this, mSearchKey, mSearchType.value, "搜索页面",
@ -341,9 +395,8 @@ open class SearchActivity : BaseActivity() {
}
override fun handleBackPressed(): Boolean {
val fragment = supportFragmentManager.findFragmentByTag(SearchDefaultFragment::class.java.name)
if (fragment == null) {
updateDisplayType(DEFAULT)
if (supportFragmentManager.fragments.size == 1) {
finish()
return true
}
return super.handleBackPressed()
@ -417,7 +470,8 @@ enum class SearchType(var value: String) {
DEFAULT("default"),
HISTORY("history"),
MANUAL("initiative"),
HOT("remen");
HOT("remen"),
RANK("rank");
fun toChinese() = when (this) {
AUTO -> "自动搜索"
@ -425,6 +479,7 @@ enum class SearchType(var value: String) {
HISTORY -> "历史搜索"
MANUAL -> "主动搜索"
HOT -> "热门搜索"
RANK -> "榜单搜索"
}
companion object {

View File

@ -4,11 +4,10 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.DisplayType
import com.gh.gamecenter.R
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.SearchType
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.search.SearchDefaultFragment
@ -64,19 +63,16 @@ class AmwaySearchActivity : SearchActivity() {
}
override fun updateDisplayType(type: DisplayType) {
val transaction = supportFragmentManager.beginTransaction()
when (type) {
DisplayType.DEFAULT -> {
val fragment = supportFragmentManager.findFragmentByTag(SearchDefaultFragment::class.java.name)
?: AmwaySearchDefaultFragment()
transaction.replace(R.id.search_result, fragment, SearchDefaultFragment::class.java.name)
}
val transaction = when (type) {
DisplayType.DEFAULT -> showFragment(
SearchDefaultFragment::class.java.name,
{ AmwaySearchDefaultFragment() }
)
else -> {
val fragment = supportFragmentManager.findFragmentByTag(AmwaySearchListFragment::class.java.name)
?: AmwaySearchListFragment()
transaction.replace(R.id.search_result, fragment, AmwaySearchListFragment::class.java.name)
}
else -> showFragment(
AmwaySearchListFragment::class.java.name,
{ AmwaySearchListFragment() }
)
}
mDisplayType = type
transaction.commitAllowingStateLoss()

View File

@ -57,6 +57,7 @@ class AmwaySearchListFragment : ToolbarFragment() {
when (it) {
LoadStatus.INIT_LOADING -> {
hideError()
hideRvList()
showLoading()
hideNoDataHint()
}
@ -64,16 +65,19 @@ class AmwaySearchListFragment : ToolbarFragment() {
hideError()
hideLoading()
hideNoDataHint()
showRvList()
}
LoadStatus.INIT_FAILED -> {
hideLoading()
hideNoDataHint()
showError()
hideRvList()
}
LoadStatus.INIT_EMPTY -> {
showNoDataHint()
hideError()
hideLoading()
hideRvList()
}
else -> {
// do nothing
@ -82,6 +86,14 @@ class AmwaySearchListFragment : ToolbarFragment() {
}
}
private fun hideRvList() {
mBinding.recyclerView.visibility = View.GONE
}
private fun showRvList() {
mBinding.recyclerView.visibility = View.VISIBLE
}
private fun showLoading() {
mBinding.loadingContainer.visibility = View.VISIBLE
}

View File

@ -44,6 +44,7 @@ class AmwaySearchViewModel(application: Application) : AndroidViewModel(applicat
mTempSearchKey = searchKey
currentSearchKey = searchKey
loadStatus.postValue(LoadStatus.INIT_LOADING)
searchGames.postValue(emptyList())
RetrofitManager
.getInstance().api
.getSearchGame(Config.API_HOST + "games:search?keyword=" + searchKey + "&view=anliwall" + "&channel=" + HaloApp.getInstance().channel + "&version=" + BuildConfig.VERSION_NAME)

View File

@ -129,39 +129,40 @@ class ForumOrUserSearchActivity : SearchActivity() {
}
override fun updateDisplayType(type: DisplayType) {
val transaction = supportFragmentManager.beginTransaction()
when (type) {
DisplayType.DEFAULT -> {
val fragment = supportFragmentManager.findFragmentByTag(SearchDefaultFragment::class.java.name)
?: ForumOrUserSearchDefaultFragment()
fragment.arguments = intent.extras
transaction.replace(R.id.search_result, fragment, SearchDefaultFragment::class.java.name)
val key = searchEt.text.toString().trim { it <= ' ' }
if (key.isNotEmpty()) {
val stayTime = (System.currentTimeMillis() - startPageTime) / 1000
if (mEntrance != ForumDetailFragment.ENTRANCE) {
NewFlatLogUtils.logViewSearchList(stayTime, key)
} else {
NewFlatLogUtils.logViewBbsSearchList(stayTime, key, mBbsId)
val transaction = when (type) {
DisplayType.DEFAULT -> showFragment(
SearchDefaultFragment::class.java.name,
onFragmentCreate = { ForumOrUserSearchDefaultFragment() }
) { fragment ->
fragment.arguments = intent.extras
}.apply {
val key = searchEt.text.toString().trim { it <= ' ' }
if (key.isNotEmpty()) {
val stayTime = (System.currentTimeMillis() - startPageTime) / 1000
if (mEntrance != ForumDetailFragment.ENTRANCE) {
NewFlatLogUtils.logViewSearchList(stayTime, key)
} else {
NewFlatLogUtils.logViewBbsSearchList(stayTime, key, mBbsId)
}
}
}
}
else -> {
if (mEntrance != ForumDetailFragment.ENTRANCE) {
val fragment =
supportFragmentManager.findFragmentByTag(ForumOrUserSearchFragment::class.java.name) as? ForumOrUserSearchFragment
?: ForumOrUserSearchFragment()
fragment.setSearchKeyAndType(mSearchKey ?: "", mSearchType.value)
transaction.replace(R.id.search_result, fragment, ForumOrUserSearchFragment::class.java.name)
else -> if (mEntrance != ForumDetailFragment.ENTRANCE) {
showFragment(
ForumOrUserSearchFragment::class.java.name,
{ ForumOrUserSearchFragment() }
) { fragment ->
fragment.setSearchKeyAndType(mSearchKey ?: "", mSearchType.value)
}
} else {
val fragment =
supportFragmentManager.findFragmentByTag(ForumContentSearchListFragment::class.java.name) as? ForumContentSearchListFragment
?: ForumContentSearchListFragment()
fragment.setSearchKeyAndType(mSearchKey ?: "", mSearchType.value)
fragment.arguments = intent.extras
transaction.replace(R.id.search_result, fragment, ForumContentSearchListFragment::class.java.name)
}
showFragment(
ForumOrUserSearchFragment::class.java.name,
{ ForumContentSearchListFragment() }
) { fragment ->
fragment.setSearchKeyAndType(mSearchKey ?: "", mSearchType.value)
fragment.arguments = intent.extras
}
}.apply {
startPageTime = System.currentTimeMillis()
}
}

View File

@ -3,20 +3,12 @@ package com.gh.gamecenter.minigame
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import com.gh.gamecenter.DisplayType
import com.gh.gamecenter.R
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.SearchType
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.forum.search.ForumSearchDao
import com.gh.gamecenter.search.SearchDefaultFragment
import com.gh.gamecenter.search.SearchGameResultFragment
import com.lightgame.config.CommonDebug
import com.lightgame.listeners.OnBackPressedListener
/**
* 小游戏-搜索页面
@ -26,22 +18,21 @@ class MiniGameSearchActivity : SearchActivity() {
override fun provideDao(): ISearchHistoryDao = MiniGameSearchDao()
override fun updateDisplayType(type: DisplayType) {
val transaction = supportFragmentManager.beginTransaction()
when(type) {
DisplayType.DEFAULT -> {
val fragment = supportFragmentManager.findFragmentByTag(SearchDefaultFragment::class.java.name)
?: MiniGameSearchDefaultFragment().apply {
arguments = Bundle().also { it.putBoolean(SearchDefaultFragment.KEY_IS_GAME_SEARCH, true) }
}
transaction.replace(R.id.search_result, fragment, SearchDefaultFragment::class.java.name)
val transaction = when(type) {
DisplayType.DEFAULT -> showFragment(
SearchDefaultFragment::class.java.name,
{ MiniGameSearchDefaultFragment() }
) {
it.arguments = Bundle().also { bundle ->
bundle.putBoolean(SearchDefaultFragment.KEY_IS_GAME_SEARCH, true)
}
}
else -> {
val digestListFragment =
supportFragmentManager.findFragmentByTag(SearchGameResultFragment::class.java.name) as? MiniGameSearchResultFragment
?: MiniGameSearchResultFragment()
digestListFragment.setParams(mSearchKey ?: "", mSearchType.value)
transaction.replace(R.id.search_result, digestListFragment, SearchGameResultFragment::class.java.name)
else -> showFragment(
SearchGameResultFragment::class.java.name,
{ MiniGameSearchResultFragment() }
) {
it.setParams(mSearchKey ?: "", mSearchType.value)
}
}
mDisplayType = type

View File

@ -421,7 +421,14 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
protected open fun provideDao(): ISearchHistoryDao = SearchHistoryDao(requireContext().applicationContext)
protected open fun provideAdapter(pageRatio: Float): PagerAdapter =
SearchDefaultRankListAdapter(requireContext(), mRankList!!, pageRatio, mIsGameSearch, mSourceEntrance)
SearchDefaultRankListAdapter(
requireContext(),
mViewModel!!,
mRankList!!,
pageRatio,
mIsGameSearch,
mSourceEntrance
)
private fun provideViewModel(): SearchDefaultViewModel {
val factory = SearchDefaultViewModel.Factory(provideDao())

View File

@ -6,23 +6,27 @@ import android.view.ViewGroup
import com.gh.common.util.DirectUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.SearchType
import com.gh.gamecenter.common.base.BaseRecyclerViewHolder
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.databinding.SearchDefaultRankItemBinding
import com.gh.gamecenter.eventbus.EBSearch
import com.gh.gamecenter.feature.entity.SettingsEntity
import com.lightgame.adapter.BaseRecyclerAdapter
import com.lightgame.utils.Util_System_Keyboard
import org.greenrobot.eventbus.EventBus
import org.json.JSONException
import org.json.JSONObject
class SearchDefaultRankAdapter(
context: Context,
private val mViewModel: SearchDefaultViewModel,
private val mRankList: SettingsEntity.Search.RankList,
private val mIsGameSearch: Boolean,
private val mIsGameSearch: Boolean
) : BaseRecyclerAdapter<SearchDefaultRankAdapter.SearchDefaultRankItemViewHolder>(context) {
override fun getItemCount() = minOf(mRankList.content.size, 10)
override fun getItemCount() = minOf(mRankList.content.size, 20)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
SearchDefaultRankItemViewHolder(parent.toBinding())
@ -34,7 +38,8 @@ class SearchDefaultRankAdapter(
icon.goneIf(!mRankList.isShowIcon) {
icon.display(if (rank.link.type == "game") gameEntity?.icon else rank.icon)
}
name.text = if (rank.link.type == "game") gameEntity?.name else rank.name.ifBlank { rank.link.text }
val labelName = if (rank.link.type == "game") gameEntity?.name else rank.name.ifBlank { rank.link.text }
name.text = labelName
index.run {
typeface = Typeface.createFromAsset(mContext.assets, Constants.DIN_FONT_PATH)
text = (position + 1).toString()
@ -60,18 +65,31 @@ class SearchDefaultRankAdapter(
root.setOnClickListener {
val linkEntity = rank.link
DirectUtils.directToLinkPage(
mContext,
linkEntity,
"游戏搜索-搜索榜单",
"${mRankList.title}-${rank.name}",
rank.exposureEvent
)
if (linkEntity.type == "game_search") {
mViewModel.add(linkEntity.text ?: "")
EventBus.getDefault().post(EBSearch(SearchType.RANK.value, linkEntity.text))
} else {
DirectUtils.directToLinkPage(
mContext,
linkEntity,
"游戏搜索-搜索榜单",
"${mRankList.title}-${rank.name}",
rank.exposureEvent
)
}
Util_System_Keyboard.hideSoftKeyboardByIBinder(mContext, it.windowToken)
// 是否来源于游戏搜索
if (mIsGameSearch) {
val searchType = if (linkEntity.type == "game_search") {
SearchType.RANK.toChinese()
} else {
""
}
NewFlatLogUtils.logSearchClickRankDetail(
linkEntity.link ?: "",
searchType,
rank.name,
(position + 1).toString(),
linkEntity.link ?: "",
@ -89,6 +107,8 @@ class SearchDefaultRankAdapter(
val trackEvent = JSONObject()
try {
trackEvent.put("text", labelName)
trackEvent.put("search_content", linkEntity.link)
trackEvent.put("game_name", gameEntity?.name)
trackEvent.put("game_id", gameEntity?.id)
trackEvent.put("list_name", mRankList.title)

View File

@ -11,6 +11,7 @@ import com.gh.gamecenter.feature.entity.SettingsEntity
class SearchDefaultRankListAdapter(
private val mContext: Context,
private val mViewModel: SearchDefaultViewModel,
private val mRankList: List<SettingsEntity.Search.RankList>,
private val mPageWidth: Float,
private val mIsGameSearch: Boolean,
@ -31,7 +32,7 @@ class SearchDefaultRankListAdapter(
view!!.findViewById<RecyclerView>(R.id.rankContainer).run {
layoutManager = LinearLayoutManager(mContext)
adapter = SearchDefaultRankAdapter(mContext, mRankList[position], mIsGameSearch)
adapter = SearchDefaultRankAdapter(mContext, mViewModel, mRankList[position], mIsGameSearch)
}
return view
}

View File

@ -2,7 +2,8 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="@color/ui_background">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"

View File

@ -4,7 +4,8 @@
android:id="@+id/search_detail_ll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:orientation="vertical"
android:background="@color/ui_background">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/list_refresh"

View File

@ -7,8 +7,9 @@
<TextView
android:id="@+id/index"
android:layout_width="16dp"
android:layout_width="wrap_content"
android:layout_height="16dp"
android:minWidth="16dp"
android:gravity="center"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"