feat: 搜索业务-新增搜索发现取代热门标签—客户端 https://jira.shanqu.cc/browse/GHZSCY-5572

This commit is contained in:
曾祥俊
2024-12-09 10:27:39 +08:00
parent 44d93b7527
commit 1002d02f12
12 changed files with 296 additions and 53 deletions

View File

@ -191,6 +191,7 @@ open class SearchActivity : BaseActivity() {
when (type) {
SearchType.AUTO -> handleAutoSearch(key)
SearchType.DEFAULT -> handleDefaultSearch(key)
SearchType.DISCOVERY -> handleDiscoverySearch(key)
SearchType.RANK -> handleRankSearch(key)
SearchType.HOT -> handleHotSearch(key)
SearchType.HISTORY -> handleHistorySearch(key)
@ -244,6 +245,22 @@ open class SearchActivity : BaseActivity() {
)
}
protected open fun handleDiscoverySearch(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_DISCOVERY,
mSourceEntrance
)
}
protected open fun handleDefaultSearch(key: String?) {
mSearchKey = key
searchEt.setText(key)
@ -391,6 +408,7 @@ open class SearchActivity : BaseActivity() {
SearchType.HISTORY.value -> search(SearchType.HISTORY, search.key)
SearchType.HOT.value -> search(SearchType.HOT, search.key)
SearchType.RANK.value -> search(SearchType.RANK, search.key)
SearchType.DISCOVERY.value -> search(SearchType.DISCOVERY, search.key)
"click" -> DataCollectionUtils.uploadSearchClick(
this, mSearchKey, mSearchType.value, "搜索页面",
@ -435,6 +453,7 @@ open class SearchActivity : BaseActivity() {
const val TRACK_SEARCH_TYPE_DEFAULT = "默认搜索"
const val TRACK_SEARCH_TYPE_HISTORY = "历史搜索"
const val TRACK_SEARCH_TYPE_RANK = "榜单搜索"
const val TRACK_SEARCH_TYPE_DISCOVERY = "搜索发现"
@JvmStatic
fun toTrackSearchType(type: String) = when (type) {
@ -442,6 +461,7 @@ open class SearchActivity : BaseActivity() {
SearchType.MANUAL.value -> TRACK_SEARCH_TYPE_INPUT
SearchType.HISTORY.value -> TRACK_SEARCH_TYPE_HISTORY
SearchType.RANK.value -> TRACK_SEARCH_TYPE_RANK
SearchType.DISCOVERY.value -> TRACK_SEARCH_TYPE_DISCOVERY
else -> TRACK_SEARCH_TYPE_DEFAULT
}
@ -491,7 +511,8 @@ enum class SearchType(var value: String) {
HISTORY("history"),
MANUAL("initiative"),
HOT("remen"),
RANK("rank");
RANK("rank"),
DISCOVERY("dicovery");
fun toChinese() = when (this) {
AUTO -> "自动搜索"
@ -500,6 +521,7 @@ enum class SearchType(var value: String) {
MANUAL -> "主动搜索"
HOT -> "热门搜索"
RANK -> "榜单搜索"
DISCOVERY -> "搜索发现"
}
companion object {

View File

@ -39,8 +39,8 @@ class ForumOrUserSearchDefaultFragment : SearchDefaultFragment() {
override fun initView() {
mBinding = FragmentSearchDefaultBinding.bind(mCachedView)
mBinding.hotTagHeadContainer.root.visibility = View.GONE
mBinding.hotTagFlexContainer.visibility = View.GONE
mBinding.hotAndDiscoveryTagHeadContainer.root.visibility = View.GONE
mBinding.hotAndDiscoveryTagFlexContainer.visibility = View.GONE
if (mEntrance == "论坛首页" || mEntrance == "搜索栏") {
mBinding.hotHeadContainer.headTitle.text = "热门论坛"
mViewModel.getForumSearchHotContent()

View File

@ -1,10 +1,9 @@
package com.gh.gamecenter.search
import android.graphics.Color
import android.graphics.LinearGradient
import android.graphics.Shader
import android.graphics.Typeface
import android.graphics.*
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RoundRectShape
import android.os.Bundle
import android.text.TextUtils
import android.view.Gravity
@ -14,6 +13,7 @@ import android.widget.CheckedTextView
import android.widget.TextView
import androidx.appcompat.content.res.AppCompatResources
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.viewpager.widget.PagerAdapter
import com.gh.common.constant.Config
import com.gh.common.exposure.ExposureManager
@ -22,6 +22,7 @@ import com.gh.common.util.DirectUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.SearchType
import com.gh.gamecenter.common.base.fragment.BaseFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.exposure.ExposureSource
@ -35,6 +36,7 @@ import com.gh.gamecenter.databinding.TabItemSearchDefaultRankBinding
import com.gh.gamecenter.db.ISearchHistoryDao
import com.gh.gamecenter.db.SearchHistoryDao
import com.gh.gamecenter.eventbus.EBSearch
import com.gh.gamecenter.feature.entity.DiscoveryTagEntity
import com.gh.gamecenter.feature.entity.HotTagEntity
import com.gh.gamecenter.feature.entity.SettingsEntity
import com.gh.gamecenter.feature.exposure.ExposureEvent
@ -48,6 +50,7 @@ import org.json.JSONObject
open class SearchDefaultFragment : BaseFragment<Any>() {
private var mHotTagList: List<HotTagEntity>? = null
private var mDiscoveryTagList: List<DiscoveryTagEntity>? = null
protected var mRankList: List<SettingsEntity.Search.RankList>? = null
protected lateinit var mBinding: FragmentSearchDefaultBinding
@ -64,10 +67,11 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
// FlexboxLayout:maxLine 不符合需求
protected val mFlexMaxHeight = DisplayUtils.dip2px(57F)
protected val mHotAndDiscoveryFlexMaxHeight = DisplayUtils.dip2px(88F)
private val mDao by lazy { provideDao() }
private val mHotTagClickListener: (Int) -> Unit = {
val tag = mHotTagList!![it]
private val mHotTagClickListener: (HotTagEntity) -> Unit = { tag ->
NewFlatLogUtils.logSearchHotTagClick(
tag.name ?: "",
tag.type ?: "",
@ -90,6 +94,29 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
DirectUtils.directToLinkPage(requireContext(), tag, "(搜索-${tag.name})", "", exposureEvent) // 不需要path
}
private val mDiscoveryTagClickListener: (DiscoveryTagEntity, Int) -> Unit = { tag, position ->
val keyword = tag.keyword
if (keyword.isNotEmpty()) {
PageSwitchDataHelper.pushCurrentPageData(
hashMapOf(
Pair(PageSwitchDataHelper.PAGE_BUSINESS_TYPE, "游戏搜索-搜索发现"),
Pair(PageSwitchDataHelper.PAGE_BUSINESS_ID, tag.id ?: ""),
Pair(PageSwitchDataHelper.PAGE_BUSINESS_NAME, tag.text ?: " ")
)
)
SensorsBridge.trackEvent("SearchLabelClick", "label_name", tag.text ?: "", "label_id", tag.id ?: "")
SensorsBridge.trackSearchDiscoveryClick(
labelName = tag.text ?: "",
labelId = tag.id ?: "",
searchContent = keyword,
position = position
)
mViewModel?.add(keyword)
EventBus.getDefault().post(EBSearch(SearchType.DISCOVERY.value, keyword))
Util_System_Keyboard.hideSoftKeyboardByIBinder(context, mBinding.historyFlex.windowToken)
}
}
override fun getLayoutId(): Int {
return R.layout.fragment_search_default
}
@ -141,15 +168,23 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
mViewModel?.isExistRankList = mRankList?.isNotEmpty() == true
mHotTagList = Config.getSettings()?.search?.hotTag
mViewModel?.isExistHotTag = mHotTagList?.isNotEmpty() == true
mDiscoveryTagList = Config.getSettings()?.search?.discoveryTag
mViewModel?.isExistHotAndDiscoveryTag =
mHotTagList?.isNotEmpty() == true || mDiscoveryTagList?.isNotEmpty() == true
updateHistorySearchView(null)
mViewModel?.historySearchLiveData?.observe(viewLifecycleOwner) {
updateHistorySearchView(it)
}
mBinding.hotTagFlexContainer.setLimitHeight(mFlexMaxHeight)
createFlexContent(mBinding.hotTagFlex, getTagListString(), true, clickListener = mHotTagClickListener)
mBinding.hotAndDiscoveryTagFlexContainer.setLimitHeight(mHotAndDiscoveryFlexMaxHeight)
createHotAndDiscoveryFlexContent(
mBinding.hotAndDiscoveryTagFlex,
getHotTagList(),
getDiscoveryTagList(),
hotTagClickListener = mHotTagClickListener,
discoveryTagClickListener = mDiscoveryTagClickListener
)
initHeadView()
initRankViewPager()
}
@ -181,9 +216,9 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
mBinding.hotHeadContainer.headTitle.text = getString(R.string.search_hot)
mBinding.hotHeadContainer.headTitle.textSize = 16F
mBinding.hotHeadContainer.headActionTv.visibility = View.GONE
mBinding.hotTagHeadContainer.headTitle.text = getString(R.string.search_hot_tag)
mBinding.hotTagHeadContainer.headTitle.textSize = 16F
mBinding.hotTagHeadContainer.headActionTv.visibility = View.GONE
mBinding.hotAndDiscoveryTagHeadContainer.headTitle.text = getString(R.string.search_discovery_tag)
mBinding.hotAndDiscoveryTagHeadContainer.headTitle.textSize = 16F
mBinding.hotAndDiscoveryTagHeadContainer.headActionTv.visibility = View.GONE
}
protected open fun initRankViewPager() {
@ -318,8 +353,8 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
mBinding.historyHeadContainer.root.visibility =
if (mViewModel?.isExistHistory == true) View.VISIBLE else View.GONE
mBinding.historyFlex.visibility = if (mViewModel?.isExistHistory == true) View.VISIBLE else View.GONE
mBinding.hotTagHeadContainer.root.layoutParams =
(mBinding.hotTagHeadContainer.root.layoutParams as ConstraintLayout.LayoutParams).apply {
mBinding.hotAndDiscoveryTagHeadContainer.root.layoutParams =
(mBinding.hotAndDiscoveryTagHeadContainer.root.layoutParams as ConstraintLayout.LayoutParams).apply {
setMargins(
0,
if (mViewModel?.isExistHistory == true) 16F.dip2px() else 0,
@ -331,14 +366,15 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
(mBinding.hotHeadContainer.root.layoutParams as ConstraintLayout.LayoutParams).apply {
setMargins(
0,
if (mViewModel?.isExistHistory == false && mViewModel?.isExistHotTag == false) 16F.dip2px() else 0,
if (mViewModel?.isExistHistory == false && mViewModel?.isExistHotAndDiscoveryTag == false) 16F.dip2px() else 0,
0,
0
)
}
mBinding.hotTagHeadContainer.root.visibility =
if (mViewModel?.isExistHotTag == true) View.VISIBLE else View.GONE
mBinding.hotTagFlex.visibility = if (mViewModel?.isExistHotTag == true) View.VISIBLE else View.GONE
mBinding.hotAndDiscoveryTagHeadContainer.root.visibility =
if (mViewModel?.isExistHotAndDiscoveryTag == true) View.VISIBLE else View.GONE
mBinding.hotAndDiscoveryTagFlex.visibility =
if (mViewModel?.isExistHotAndDiscoveryTag == true) View.VISIBLE else View.GONE
mBinding.hotHeadContainer.root.visibility =
if (mViewModel?.isExistHotSearch == true) View.VISIBLE else View.GONE
mBinding.hotList.visibility = if (mViewModel?.isExistHotSearch == true) View.VISIBLE else View.GONE
@ -361,20 +397,31 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
}
}
private fun getTagListString(): List<String> {
val list = ArrayList<String>()
private fun getHotTagList(): List<HotTagEntity> {
val list = ArrayList<HotTagEntity>()
if (mHotTagList != null) {
for (entity in mHotTagList!!) {
entity.name?.let { list.add(it) }
if (list.size == 8) break // 最多显示8个热门标签
entity.name?.let { list.add(entity) }
}
}
return list
}
private fun getDiscoveryTagList(): List<DiscoveryTagEntity> {
val list = ArrayList<DiscoveryTagEntity>()
if (mDiscoveryTagList != null) {
for (entity in mDiscoveryTagList!!) {
entity.text?.let { list.add(entity) }
}
}
return list
}
fun createFlexContent(
flexView: FlexboxLayout,
contentList: List<String>?,
isHotTag: Boolean = false,
clickListener: (Int) -> Unit
) {
@ -388,16 +435,12 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
val params = FlexboxLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 24F.dip2px())
flexCell.layoutParams = params
if (isHotTag && !mHotTagList.isNullOrEmpty() && mHotTagList!![index].isGuessSearch) {
createSmartHotTagStyle(flexCell, contentList[index])
} else {
flexCell.setSingleLine()
flexCell.ellipsize = TextUtils.TruncateAt.END
flexCell.gravity = Gravity.CENTER
flexCell.textSize = 12F
flexCell.text = StringUtils.shrinkStringWithDot(contentList[index], 6)
flexCell.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()))
}
flexCell.setSingleLine()
flexCell.ellipsize = TextUtils.TruncateAt.END
flexCell.gravity = Gravity.CENTER
flexCell.textSize = 12F
flexCell.text = StringUtils.shrinkStringWithDot(contentList[index], 6)
flexCell.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()))
flexCell.setPadding(8F.dip2px(), 0, 8F.dip2px(), 0)
flexCell.background = if (mIsDarkModeOn) GradientDrawable().apply {
setStroke(0.5F.dip2px(), Color.parseColor("#21FFFFFF"))
@ -409,16 +452,84 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
}
}
private fun createSmartHotTagStyle(flexCell: TextView, name: String) {
flexCell.setDrawableStart(R.drawable.ic_smart_search)
private fun createHotAndDiscoveryFlexContent(
flexView: FlexboxLayout,
hotTagList: List<HotTagEntity>,
discoveryTagList: List<DiscoveryTagEntity>,
hotTagClickListener: (HotTagEntity) -> Unit,
discoveryTagClickListener: (DiscoveryTagEntity, Int) -> Unit
) {
if (hotTagList.isEmpty() && discoveryTagList.isEmpty()) return
flexView.removeAllViews()
createHotFlexContent(flexView, hotTagList, hotTagClickListener)
createDiscoveryFlexContent(flexView, discoveryTagList, discoveryTagClickListener)
}
private fun createHotFlexContent(
flexView: FlexboxLayout,
contentList: List<HotTagEntity>?,
clickListener: (HotTagEntity) -> Unit
) {
if (contentList.isNullOrEmpty()) return
for (index in 0 until contentList.count()) {
val flexCell = TextView(context)
flexView.addView(flexCell)
flexCell.layoutParams = FlexboxLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, 24F.dip2px()
)
createSmartHotTagStyle(flexCell, contentList[index])
flexCell.setOnClickListener {
clickListener.invoke(contentList[index])
}
}
}
private fun createDiscoveryFlexContent(
flexView: FlexboxLayout,
contentList: List<DiscoveryTagEntity>?,
clickListener: (DiscoveryTagEntity, Int) -> Unit
) {
if (contentList.isNullOrEmpty()) return
for (index in 0 until contentList.count()) {
val flexCell = TextView(context)
flexView.addView(flexCell)
flexCell.layoutParams = FlexboxLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, 24F.dip2px()
)
createSmartDiscoverTagStyle(flexCell, contentList[index])
flexCell.setPadding(8F.dip2px(), 0, 8F.dip2px(), 0)
flexCell.background = if (mIsDarkModeOn) GradientDrawable().apply {
setStroke(0.5F.dip2px(), Color.parseColor("#21FFFFFF"))
cornerRadius = 999F
} else DrawableView.getStrokeDrawable(com.gh.gamecenter.common.R.color.text_dddddd, 0.5F)
flexCell.setOnClickListener {
clickListener.invoke(contentList[index], index)
}
}
}
private fun createSmartHotTagStyle(flexCell: TextView, entity: HotTagEntity) {
flexCell.compoundDrawablePadding = 4F.dip2px()
flexCell.gravity = Gravity.CENTER_VERTICAL
flexCell.typeface = Typeface.DEFAULT_BOLD
flexCell.textSize = 12F
flexCell.text = StringUtils.shrinkStringWithDot(name, 6)
flexCell.setTextColor(Color.WHITE)
flexCell.text = StringUtils.shrinkStringWithDot(entity.name, 6)
flexCell.setPadding(8F.dip2px(), 0, 8F.dip2px(), 0)
val colors =
intArrayOf(com.gh.gamecenter.common.R.color.text_FFB749.toColor(requireContext()), com.gh.gamecenter.common.R.color.text_FF6D3C.toColor(requireContext()))
intArrayOf(
com.gh.gamecenter.common.R.color.text_FFB749.toColor(requireContext()),
com.gh.gamecenter.common.R.color.text_FF6D3C.toColor(requireContext())
)
val position = floatArrayOf(0F, 1F)
val linearGradient = LinearGradient(
0F,
@ -429,10 +540,53 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
position,
Shader.TileMode.CLAMP
)
flexCell.paint.shader = linearGradient
val shapeRadius = floatArrayOf(999F, 999F, 999F, 999F, 999F, 999F, 999F, 999F)
val strokeWidth = 0.5F.dip2px().toFloat()
val shape = RoundRectShape(shapeRadius, RectF(strokeWidth, strokeWidth, strokeWidth, strokeWidth), shapeRadius)
flexCell.background = ShapeDrawable(shape).apply {
paint.shader = linearGradient
}
if (entity.isGuessSearch) {
flexCell.setTextColor(Color.WHITE)
flexCell.typeface = Typeface.DEFAULT_BOLD
flexCell.setDrawableStart(R.drawable.ic_smart_search)
flexCell.paint.shader = linearGradient
} else {
flexCell.setTextColor(
ContextCompat.getColor(
requireContext(),
com.gh.gamecenter.common.R.color.text_secondary
)
)
}
flexCell.invalidate()
}
private fun createSmartDiscoverTagStyle(flexCell: TextView, entity: DiscoveryTagEntity) {
val labelIcon = when (entity.recommendType) {
"hot" -> R.drawable.ic_search_hot
"new" -> R.drawable.ic_search_new
"surge", "rise" -> R.drawable.ic_search_rise
"update" -> R.drawable.ic_search_update
else -> -1
}
if (labelIcon != -1) {
flexCell.setDrawableEnd(labelIcon.toDrawable())
flexCell.compoundDrawablePadding = 4F.dip2px()
}
flexCell.setSingleLine()
flexCell.ellipsize = TextUtils.TruncateAt.END
flexCell.gravity = Gravity.CENTER
flexCell.textSize = 12F
flexCell.text = entity.text
flexCell.setTextColor(com.gh.gamecenter.common.R.color.text_secondary.toColor(requireContext()))
flexCell.setPadding(8F.dip2px(), 0, 8F.dip2px(), 0)
flexCell.background = if (mIsDarkModeOn) GradientDrawable().apply {
setStroke(0.5F.dip2px(), Color.parseColor("#21FFFFFF"))
cornerRadius = 999F
} else DrawableView.getStrokeDrawable(com.gh.gamecenter.common.R.color.text_dddddd, 0.5F)
}
private fun postExposureEvent(index: Int) {
mRankList?.safelyGetInRelease(index)?.content?.forEach {
if (it.link.type == "game") {
@ -451,7 +605,13 @@ open class SearchDefaultFragment : BaseFragment<Any>() {
notifyItemRangeChanged(0, itemCount)
}
mViewModel?.historySearchLiveData?.value?.let { updateHistorySearchView(it) }
createFlexContent(mBinding.hotTagFlex, getTagListString(), true, clickListener = mHotTagClickListener)
createHotAndDiscoveryFlexContent(
mBinding.hotAndDiscoveryTagFlex,
getHotTagList(),
getDiscoveryTagList(),
hotTagClickListener = mHotTagClickListener,
discoveryTagClickListener = mDiscoveryTagClickListener
)
}
protected open fun provideDao(): ISearchHistoryDao =

View File

@ -11,7 +11,7 @@ class SearchDefaultViewModel(private val dao: ISearchHistoryDao) : ViewModel() {
it
}
var isExistHotSearch: Boolean = false
var isExistHotTag: Boolean = false
var isExistHotAndDiscoveryTag: Boolean = false
var isExistHistory: Boolean = false
var isExistRankList: Boolean = false