feat:游戏搜索页面新增分类导航—客户端 https://jira.shanqu.cc/browse/GHZSCY-5585

This commit is contained in:
张晨
2024-09-10 09:18:36 +08:00
parent 4191dbc4f0
commit d32d00a4fa
47 changed files with 1854 additions and 285 deletions

View File

@ -0,0 +1,36 @@
package com.gh.common.provider
import android.content.Context
import androidx.fragment.app.Fragment
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.alibaba.android.arouter.facade.annotation.Route
import com.gh.gamecenter.common.constant.RouteConsts
import com.gh.gamecenter.core.provider.ISearchTabUtilsProvider
import com.gh.gamecenter.search.viewmodel.SearchTabViewModel
@Route(path = RouteConsts.provider.searchTabUtils, name = "SearchTabUtils暴露服务")
class SearchTabUtilsProviderImpl : ISearchTabUtilsProvider {
override fun obtainParentViewModel(fragment: Fragment): ViewModel {
val store = (fragment.parentFragment ?: fragment).viewModelStore
val factory = fragment.defaultViewModelProviderFactory
return ViewModelProvider(
store,
factory
).get(SearchTabViewModel::class.java)
}
override fun getKeyAndTypeLiveData(viewModel: ViewModel?): LiveData<Pair<String, String>>? =
if (viewModel is SearchTabViewModel) {
viewModel.searchKeyAndType
} else {
null
}
override fun init(context: Context?) {
// no implement
}
}

View File

@ -78,6 +78,7 @@ import com.gh.gamecenter.qa.questions.newdetail.NewQuestionDetailActivity
import com.gh.gamecenter.qa.subject.CommunitySubjectActivity
import com.gh.gamecenter.qa.video.detail.ForumVideoDetailActivity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.servers.GameServerTestActivity
import com.gh.gamecenter.servers.GameServersActivity
import com.gh.gamecenter.servers.gametest2.GameServerTestV2Activity

View File

@ -661,12 +661,14 @@ object NewFlatLogUtils {
@JvmStatic
fun logSearchBbs(
searchType: String,
searchKey: String
searchKey: String,
location: String
) {
json {
KEY_EVENT to "search_bbs"
"search_type" to searchType
"key" to searchKey
KEY_LOCATION to location
parseAndPutMeta()()
}.let(::log)
}
@ -678,7 +680,8 @@ object NewFlatLogUtils {
bbsId: String,
sequence: Int,
name: String,
button: String
button: String,
location: String
) {
json {
KEY_EVENT to "search_bbs_click"
@ -688,6 +691,7 @@ object NewFlatLogUtils {
"sequence" to sequence
"name" to name
"button" to button
KEY_LOCATION to location
parseAndPutMeta()()
}.let(::log)
}
@ -695,12 +699,14 @@ object NewFlatLogUtils {
@JvmStatic
fun logSearchUser(
searchType: String,
searchKey: String
searchKey: String,
location: String
) {
json {
KEY_EVENT to "search_user"
"search_type" to searchType
"key" to searchKey
KEY_LOCATION to location
parseAndPutMeta()()
}.let(::log)
}
@ -711,7 +717,8 @@ object NewFlatLogUtils {
searchKey: String,
userId: String,
name: String,
sequence: Int
sequence: Int,
location: String
) {
json {
KEY_EVENT to "search_user_click"
@ -720,6 +727,7 @@ object NewFlatLogUtils {
"user_id" to userId
"name" to name
"sequence" to sequence
KEY_LOCATION to location
parseAndPutMeta()()
}.let(::log)
}
@ -1344,7 +1352,13 @@ object NewFlatLogUtils {
}
// 上传存档弹窗点击事件
fun logCloudArchiveUploadDialogClick(gameId: String, gameName: String, cloudSaveId: String, cloudSaveName: String, isSuccess: Boolean) {
fun logCloudArchiveUploadDialogClick(
gameId: String,
gameName: String,
cloudSaveId: String,
cloudSaveName: String,
isSuccess: Boolean
) {
val json = json {
KEY_EVENT to "cloud_save_upload_dialog_click"
KEY_GAME_ID to gameId

View File

@ -22,6 +22,7 @@ import com.gh.gamecenter.common.utils.*
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
@ -52,7 +53,11 @@ open class SearchActivity : BaseActivity() {
private var mPublishSubject: PublishSubject<String>? = null
private var mSourceEntrance: String = ""
/**
* 神策的 SourceEntrance 字段相当于 火山云的 location
* 如果有火山云埋点需要上传 location 字段,那么直接使用此字段的值就行
*/
protected var mSourceEntrance: String = ""
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
@ -117,27 +122,10 @@ open class SearchActivity : BaseActivity() {
updateDisplayType(DEFAULT)
}
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) ?: ""
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.trackSearchPageShow(
SensorsBridge.trackGameSearchPageShow(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
intent.getStringExtra(EntranceConsts.KEY_SOURCE_ENTRANCE) ?: "",
bottomTab,
multiTabId,
multiTabName,
customPageId,
customPageName,
searchBoxPattern
mSourceEntrance
)
}
@ -206,12 +194,12 @@ open class SearchActivity : BaseActivity() {
updateDisplayType(GAME_DIGEST)
LogUtils.uploadSearchGame("searching", "搜索页", key, "自动搜索")
SensorsBridge.trackSearchButtonClick(
SensorsBridge.trackGameSearchPageButtonClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
mSourceEntrance,
key ?: "",
TRACK_SEARCH_TYPE_INPUT,
mSourceEntrance
TRACK_SEARCH_TYPE_AUTO
)
}
}
@ -239,14 +227,13 @@ open class SearchActivity : BaseActivity() {
updateDisplayType(GAME_DETAIL)
LogUtils.uploadSearchGame("searching", "搜索页", key, "默认搜索")
SensorsBridge.trackSearchButtonClick(
SensorsBridge.trackGameSearchPageButtonClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
mSourceEntrance,
key ?: "",
TRACK_SEARCH_TYPE_DEFAULT,
mSourceEntrance
TRACK_SEARCH_TYPE_DEFAULT
)
// MtaHelper.onEvent("游戏搜索", "默认搜索", key)
}
protected open fun handleHotSearch(key: String?) {
@ -263,14 +250,13 @@ open class SearchActivity : BaseActivity() {
updateDisplayType(GAME_DETAIL)
LogUtils.uploadSearchGame("searching", "搜索页", key, "历史搜索")
SensorsBridge.trackSearchButtonClick(
SensorsBridge.trackGameSearchPageButtonClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
mSourceEntrance,
key ?: "",
TRACK_SEARCH_TYPE_HISTORY,
mSourceEntrance
TRACK_SEARCH_TYPE_HISTORY
)
// MtaHelper.onEvent("游戏搜索", "历史搜索", key)
}
protected open fun handleManualSearch() {
@ -284,16 +270,16 @@ open class SearchActivity : BaseActivity() {
} else if (newSearchKey != mSearchKey || mDisplayType != GAME_DETAIL) {
mSearchKey = newSearchKey
if (!TextUtils.isEmpty(mSearchKey)) {
SensorsBridge.trackSearchButtonClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
newSearchKey,
TRACK_SEARCH_TYPE_INPUT,
mSourceEntrance
)
mDao.add(mSearchKey)
updateDisplayType(GAME_DETAIL)
SensorsBridge.trackGameSearchPageButtonClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
mSourceEntrance,
newSearchKey,
TRACK_SEARCH_TYPE_INPUT
)
} else {
toast("请输入搜索内容")
}
@ -415,13 +401,15 @@ open class SearchActivity : BaseActivity() {
private const val KEY_SEARCH_IMMEDIATELY = "search_immediately"
private const val HINT_TEXT = "搜索游戏..."
const val TRACK_SEARCH_TYPE_AUTO = "自动搜索"
const val TRACK_SEARCH_TYPE_INPUT = "输入搜索"
const val TRACK_SEARCH_TYPE_DEFAULT = "默认搜索"
const val TRACK_SEARCH_TYPE_HISTORY = "历史搜索"
@JvmStatic
fun toTrackSearchType(type: String) = when (type) {
SearchType.AUTO.value, SearchType.MANUAL.value -> TRACK_SEARCH_TYPE_INPUT
SearchType.AUTO.value -> TRACK_SEARCH_TYPE_AUTO
SearchType.MANUAL.value -> TRACK_SEARCH_TYPE_INPUT
SearchType.HISTORY.value -> TRACK_SEARCH_TYPE_HISTORY
else -> TRACK_SEARCH_TYPE_DEFAULT
}
@ -433,7 +421,8 @@ open class SearchActivity : BaseActivity() {
hint: String,
entrance: String,
sourceEntrance: String
): Intent = getIntent(context, searchImmediately, hint, entrance, sourceEntrance, "", "", "", "", "", "")
): Intent =
getIntent(context, searchImmediately, hint, entrance, sourceEntrance, "", "", "", "", "", "")
@JvmStatic
fun getIntent(
@ -449,7 +438,7 @@ open class SearchActivity : BaseActivity() {
customPageName: String = "",
searchBoxPattern: String = ""
): Intent {
val intent = Intent(context, SearchActivity::class.java)
val intent = Intent(context, SearchTabActivity::class.java)
intent.putExtra(KEY_SEARCH_IMMEDIATELY, searchImmediately)
intent.putExtra(EntranceConsts.KEY_HINT, hint)
intent.putExtra(EntranceConsts.KEY_ENTRANCE, entrance)

View File

@ -78,9 +78,6 @@ class AmwaySearchActivity : SearchActivity() {
transaction.commitAllowingStateLoss()
}
// 安利墙搜索页不需要神策埋点
override fun trackSearchPageShow() = Unit
companion object {
fun getIntent(context: Context): Intent {
val intent = Intent(context, AmwaySearchActivity::class.java)

View File

@ -1,7 +1,9 @@
package com.gh.gamecenter.forum.search
import android.os.Bundle
import android.view.View
import androidx.core.content.ContextCompat
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.NewFlatLogUtils
import com.gh.common.util.NewLogUtils
@ -24,12 +26,19 @@ import com.gh.gamecenter.feature.entity.AnswerEntity
import com.gh.gamecenter.forum.home.ForumScrollCalculatorHelper
import com.gh.gamecenter.forum.search.CommunitySearchEventListener.Companion.SEARCH_BUTTON_VIEW_CONTENT_DETAIL
import com.gh.gamecenter.forum.search.ForumOrUserSearchActivity.Companion.LOCATION_COMMUNITY
import com.gh.gamecenter.search.viewmodel.SearchTabViewModel
import com.gh.gamecenter.video.detail.CustomManager
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
class ForumContentSearchListFragment : LazyListFragment<AnswerEntity, ForumContentSearchListViewModel>(),
CommunitySearchEventListener {
private val parentTabViewModel by viewModels<SearchTabViewModel>(
ownerProducer = {
parentFragment ?: this
}
)
private var mBbsId = ""
private var mSearchKey = ""
private var mSearchType = SearchType.DEFAULT.value
@ -42,6 +51,8 @@ class ForumContentSearchListFragment : LazyListFragment<AnswerEntity, ForumConte
private var mListReachTop = true
private var mIsAutoLoad = true
override fun provideListAdapter(): ListAdapter<*> {
return mAdapter
?: ForumContentSearchListAdapter(
@ -79,6 +90,11 @@ class ForumContentSearchListFragment : LazyListFragment<AnswerEntity, ForumConte
mListViewModel?.updateSearchKeyAndType(mSearchKey, mSearchType)
}
override fun onCreate(savedInstanceState: Bundle?) {
mIsAutoLoad = arguments?.getBoolean(EntranceConsts.KEY_IS_AUTO_LOAD, true) ?: true
super.onCreate(savedInstanceState)
}
override fun onFragmentResume() {
resumeVideo()
super.onFragmentResume()
@ -235,7 +251,12 @@ class ForumContentSearchListFragment : LazyListFragment<AnswerEntity, ForumConte
override fun initRealView() {
super.initRealView()
mListViewModel?.updateSearchKeyAndType(mSearchKey, mSearchType)
if (mIsAutoLoad) {
mListViewModel?.updateSearchKeyAndType(mSearchKey, mSearchType)
}
parentTabViewModel.searchKeyAndType.observe(viewLifecycleOwner) { (key, type) ->
setSearchKeyAndType(key, type)
}
}
override fun getItemDecoration(): RecyclerView.ItemDecoration? {
@ -260,13 +281,16 @@ class ForumContentSearchListFragment : LazyListFragment<AnswerEntity, ForumConte
}
override fun onItemClick(contentId: String?, itemType: String?, title: String?, sequence: Int) {
SensorsBridge.trackSearchResultClick(
SensorsBridge.trackArticleSearchResultClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
mListViewModel.sourceEntrance,
mSearchKey,
SearchActivity.toTrackSearchType(mSearchType),
mListViewModel.sourceEntrance
contentId ?: "",
title ?: ""
)
NewFlatLogUtils.logSearchContentClick(
mLocation,
mBbsId,

View File

@ -89,13 +89,13 @@ class ForumContentSearchListViewModel(application: Application, val bbsId: Strin
mResultLiveData.postValue(it)
if (mPage == 1) {
SensorsBridge.trackSearchResultReturn(
SensorsBridge.trackArticleSearchResultReturn(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
sourceEntrance,
searchKey,
SearchActivity.toTrackSearchType(searchType),
it.isNotEmpty(),
sourceEntrance
it.isNotEmpty()
)
}
}

View File

@ -11,9 +11,7 @@ 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.common.utils.showKeyBoard
import com.gh.gamecenter.common.utils.toColor
import com.gh.gamecenter.db.ISearchHistoryDao
@ -28,7 +26,6 @@ class ForumOrUserSearchActivity : SearchActivity() {
private var mBbsId = ""
private var mLocation = ""
private var mSourceEntrance = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -68,13 +65,6 @@ class ForumOrUserSearchActivity : SearchActivity() {
override fun handleAutoSearch(key: String?) {
mSearchKey = key
updateDisplayType(DisplayType.FORUM_OR_USER)
SensorsBridge.trackSearchButtonClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
key ?: "",
TRACK_SEARCH_TYPE_INPUT,
mSourceEntrance
)
}
override fun handleHistorySearch(key: String?) {
@ -82,13 +72,6 @@ class ForumOrUserSearchActivity : SearchActivity() {
searchEt.setText(key)
searchEt.setSelection(searchEt.text.length)
updateDisplayType(DisplayType.FORUM_OR_USER)
SensorsBridge.trackSearchButtonClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
key ?: "",
TRACK_SEARCH_TYPE_HISTORY,
mSourceEntrance
)
}
private fun handleOtherSearch(type: SearchType) {
@ -103,13 +86,6 @@ class ForumOrUserSearchActivity : SearchActivity() {
} else {
TRACK_SEARCH_TYPE_DEFAULT
}
SensorsBridge.trackSearchButtonClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
newSearchKey,
searchType,
mSourceEntrance
)
} else {
toast("请先输入搜索内容再搜索~")
}

View File

@ -1,7 +1,9 @@
package com.gh.gamecenter.forum.search
import android.os.Bundle
import android.view.View
import androidx.core.content.ContextCompat
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.R
@ -15,31 +17,39 @@ import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.entity.FollowersOrFansEntity
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.search.viewmodel.SearchTabViewModel
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class UserSearchListFragment : LazyListFragment<FollowersOrFansEntity, UserSearchListViewModel>() {
private val parentTabViewModel by viewModels<SearchTabViewModel>(
ownerProducer = { parentFragment ?: this }
)
private var mSearchKey = ""
private var mAdapter: UserSearchListAdapter? = null
private var mSearchType = SearchType.DEFAULT.value
private var mIsAutoLoad = true
override fun provideListAdapter(): ListAdapter<*> {
return mAdapter
?: UserSearchListAdapter(requireContext(), mEntrance, mListViewModel) { userId, name, position ->
SensorsBridge.trackSearchResultClick(
SensorsBridge.trackUserSearchResultClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
mSearchKey,
SearchActivity.toTrackSearchType(mSearchType),
mListViewModel.sourceEntrance
mListViewModel.sourceEntrance,
userId
)
NewFlatLogUtils.logSearchUserClick(
SearchType.fromString(mSearchType).toChinese(),
mSearchKey,
userId,
name,
position + 1
position + 1,
mListViewModel.sourceEntrance
)
}.apply { mAdapter = this }
}
@ -54,6 +64,11 @@ class UserSearchListFragment : LazyListFragment<FollowersOrFansEntity, UserSearc
override fun isAutomaticLoad(): Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
mIsAutoLoad = arguments?.getBoolean(EntranceConsts.KEY_IS_AUTO_LOAD, true) ?: true
super.onCreate(savedInstanceState)
}
fun setSearchKeyAndType(searchKey: String, searchType: String) {
mSearchKey = searchKey
mSearchType = searchType
@ -69,7 +84,13 @@ class UserSearchListFragment : LazyListFragment<FollowersOrFansEntity, UserSearc
override fun initRealView() {
super.initRealView()
mListViewModel?.updateSearchKeyAndType(mSearchKey, mSearchType)
if (mIsAutoLoad) {
mListViewModel?.updateSearchKeyAndType(mSearchKey, mSearchType)
}
parentTabViewModel.searchKeyAndType.observe(viewLifecycleOwner) { (key, type) ->
setSearchKeyAndType(key, type)
}
}
override fun getItemDecoration(): RecyclerView.ItemDecoration? = null

View File

@ -34,7 +34,8 @@ class UserSearchListViewModel(application: Application) :
if (page == 1) {
NewFlatLogUtils.logSearchUser(
SearchType.fromString(searchType).toChinese(),
searchKey
searchKey,
sourceEntrance
)
}
return RetrofitManager.getInstance().api.searchUsers(searchKey, page)
@ -44,13 +45,13 @@ class UserSearchListViewModel(application: Application) :
mResultLiveData.addSource(mListLiveData) {
mResultLiveData.postValue(it)
if (page == 1) {
SensorsBridge.trackSearchResultReturn(
SensorsBridge.trackUserSearchResultReturn(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
sourceEntrance,
searchKey,
SearchActivity.toTrackSearchType(searchType),
it.isNotEmpty(),
sourceEntrance
it.isNotEmpty()
)
}
}

View File

@ -86,6 +86,7 @@ import com.gh.gamecenter.home.video.ScrollCalculatorHelper
import com.gh.gamecenter.login.user.UserViewModel
import com.gh.gamecenter.newsdetail.NewsDetailActivity
import com.gh.gamecenter.packagehelper.PackageViewModel
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.simulatorgame.SimulatorGameActivity
import com.gh.gamecenter.tag.TagsActivity
import com.gh.gamecenter.video.detail.CustomManager

View File

@ -220,7 +220,9 @@ class CustomPageData(
@SerializedName("stamp")
private val _stamp: String? = null,
@SerializedName("style")
private val _style: String? = null
private val _style: String? = null,
@SerializedName("tags")
private val _tags: List<TagInfoEntity>? = null
) {
val id: String
@ -269,6 +271,9 @@ class CustomPageData(
@IgnoredOnParcel
private var filteredGames: List<GameEntity>? = null
val tags: List<TagInfoEntity>
get() = _tags ?: emptyList()
data class User(
@SerializedName("_id")
private val _id: String? = null,

View File

@ -14,18 +14,13 @@ import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.base.adapter.FragmentAdapter
import com.gh.common.util.*
import com.gh.gamecenter.R
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.SearchActivity.Companion.TRACK_SEARCH_TYPE_INPUT
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.doOnPageSelected
import com.gh.gamecenter.core.utils.DisplayUtils
import com.gh.gamecenter.core.utils.doOnEnd
import com.gh.gamecenter.databinding.DialogChooseForumBinding
import com.gh.gamecenter.common.entity.CommunityEntity
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.forum.detail.ForumDetailFragment.Companion.SOURCE_ENTRANCE
/**
* 选择论坛
@ -57,13 +52,6 @@ class ChooseForumActivity : BaseActivity() {
} else {
switchUI(true)
mSearchResultFragment?.setSearchKeyAndType(searchKey, SearchType.MANUAL.value)
SensorsBridge.trackSearchButtonClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
searchKey,
TRACK_SEARCH_TYPE_INPUT,
sourceEntrance
)
}
}
binding.searchEt.setOnTouchListener { _, event ->
@ -82,12 +70,6 @@ class ChooseForumActivity : BaseActivity() {
binding.maskView.setOnClickListener { binding.closeIv.performClick() }
binding.forumContainer.translationY = (DisplayUtils.getScreenHeight()).toFloat()
binding.forumContainer.animate().translationY(0f).setDuration(300).start()
SensorsBridge.trackSearchPageShow(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
SOURCE_ENTRANCE
)
}
private fun initViewPager() {

View File

@ -1,8 +1,10 @@
package com.gh.gamecenter.qa.dialog
import android.os.Bundle
import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.NewFlatLogUtils
import com.gh.common.util.NewLogUtils
@ -18,9 +20,14 @@ import com.gh.gamecenter.common.utils.viewModelProvider
import com.gh.gamecenter.core.utils.HtmlUtils
import com.gh.gamecenter.entity.ForumEntity
import com.gh.gamecenter.forum.detail.ForumDetailActivity
import com.gh.gamecenter.search.viewmodel.SearchTabViewModel
class ChooseForumContainerFragment : LazyListFragment<ForumEntity, ChooseForumContainerViewModel>() {
private val parentTabViewModel by viewModels<SearchTabViewModel>(
ownerProducer = { parentFragment ?: this }
)
private var mAdapter: ChooseForumContainerAdapter? = null
private var type: String = ""
private var mSearchKey: String = ""
@ -29,6 +36,13 @@ class ChooseForumContainerFragment : LazyListFragment<ForumEntity, ChooseForumCo
private var mSearchType = SearchType.DEFAULT.value
private var entrance = ""
private var mIsAutoLoad = true
override fun onCreate(savedInstanceState: Bundle?) {
mIsAutoLoad = arguments?.getBoolean(EntranceConsts.KEY_IS_AUTO_LOAD, true) ?: true
super.onCreate(savedInstanceState)
}
override fun onFragmentFirstVisible() {
type = arguments?.getString(EntranceConsts.KEY_CHOOSE_FORUM_TYPE) ?: ""
entrance =
@ -46,17 +60,27 @@ class ChooseForumContainerFragment : LazyListFragment<ForumEntity, ChooseForumCo
childClick = { position, forumEntity, button ->
NewFlatLogUtils.logSearchBbsClick(
mSearchType, mSearchKey, forumEntity.id, position + 1, HtmlUtils.stripHtml(forumEntity.name), button
mSearchType,
mSearchKey,
forumEntity.id,
position + 1,
HtmlUtils.stripHtml(forumEntity.name),
button,
mListViewModel.sourceEntrance
)
SensorsBridge.trackForumSearchResultClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
mListViewModel.sourceEntrance,
mListViewModel.searchKey,
SearchActivity.toTrackSearchType(mSearchType),
forumEntity.id,
HtmlUtils.stripHtml(forumEntity.name),
forumEntity.typeChinese
)
}
) { enity, position ->
SensorsBridge.trackSearchResultClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
mSearchKey,
SearchActivity.toTrackSearchType(mSearchType),
mListViewModel.sourceEntrance
)
if (requireActivity() is ChooseForumActivity) {
(requireActivity() as ChooseForumActivity).chooseSuccess(enity)
val bbsType = if (enity.type == "game_bbs") "游戏论坛" else "综合论坛"
@ -82,9 +106,13 @@ class ChooseForumContainerFragment : LazyListFragment<ForumEntity, ChooseForumCo
override fun initRealView() {
super.initRealView()
if (type == ChooseForumType.SEARCH.value) {
if (mIsAutoLoad && type == ChooseForumType.SEARCH.value) {
mListViewModel?.setSearchKeyAndRefresh(mSearchKey, mSearchType)
}
parentTabViewModel.searchKeyAndType.observe(viewLifecycleOwner, { (key, type) ->
setSearchKeyAndType(key, type)
})
}
override fun onChanged(ts: MutableList<ForumEntity>?) {

View File

@ -1,6 +1,5 @@
package com.gh.gamecenter.qa.dialog
import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
@ -13,7 +12,6 @@ import com.gh.gamecenter.common.baselist.LoadType
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.entity.ForumEntity
import com.gh.gamecenter.forum.search.ForumOrUserSearchActivity.Companion.LOCATION_COMMUNITY
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.retrofit.service.ApiService
@ -29,7 +27,7 @@ class ChooseForumContainerViewModel(
val type: String,
var searchKey: String,
var searchType: String,
var sourceEntrance: String
var sourceEntrance: String // 神策sourceEntrance 相当火山云 location
) :
ListViewModel<ForumEntity, ForumEntity>(application) {
@ -47,7 +45,7 @@ class ChooseForumContainerViewModel(
override fun provideDataObservable(page: Int): Observable<MutableList<ForumEntity>> {
mPage = page
if (mPage == 1 && type == ChooseForumContainerFragment.ChooseForumType.SEARCH.value) {
NewFlatLogUtils.logSearchBbs(SearchType.fromString(searchType).toChinese(), searchKey)
NewFlatLogUtils.logSearchBbs(SearchType.fromString(searchType).toChinese(), searchKey, sourceEntrance)
}
return when (type) {
ChooseForumContainerFragment.ChooseForumType.ATTENTION.value -> {
@ -74,13 +72,13 @@ class ChooseForumContainerViewModel(
mResultLiveData.addSource<List<ForumEntity>>(mListLiveData) {
mResultLiveData.postValue(it)
if (mPage == 1) {
SensorsBridge.trackSearchResultReturn(
SensorsBridge.trackForumSearchResultReturn(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
sourceEntrance,
searchKey,
SearchActivity.toTrackSearchType(searchType),
it.isNotEmpty(),
sourceEntrance
it.isNotEmpty()
)
}
}
@ -119,7 +117,13 @@ class ChooseForumContainerViewModel(
class Factory(val type: String, val searchKey: String, val searchType: String, private val sourceEntrance: String) :
ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return ChooseForumContainerViewModel(HaloApp.getInstance().application, type, searchKey, searchType, sourceEntrance) as T
return ChooseForumContainerViewModel(
HaloApp.getInstance().application,
type,
searchKey,
searchType,
sourceEntrance
) as T
}
}
}

View File

@ -3403,4 +3403,10 @@ public interface ApiService {
*/
@PATCH("app/{module}/diverter_visit_time")
Single<ResponseBody> patchDiverterVisitTime(@Path("module") String module, @Body RequestBody body);
/**
* 游戏单搜索(复用 游戏单合集-内容列表 (适用于刷新轮换) 接口实体)
*/
@GET("game_lists/search")
Single<List<CustomPageData.LinkColumnCollection.CustomSubjectEntity>> searchGameList(@Query("keyword") String keyword, @Query("page") int page);
}

View File

@ -11,8 +11,8 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.gh.common.databind.BindingAdapters
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.exposure.ExposureSource
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.HtmlUtils
@ -24,6 +24,7 @@ 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.feature.game.GameItemViewHolder
import com.gh.gamecenter.SearchType
import com.gh.gamecenter.search.SearchGameResultAdapter.Companion.setItemCLick
import com.gh.gamecenter.search.SearchGameResultAdapter.Companion.showContentTag
import com.lzf.easyfloat.utils.DisplayUtils
@ -51,7 +52,7 @@ class SearchGameFirstItemViewHolder(
game?.let {
val link = bannerItem.link ?: return@let
// 阿里云埋点
com.gh.common.util.NewFlatLogUtils.logGameSearchFirstGameBannerClick(
NewFlatLogUtils.logGameSearchFirstGameBannerClick(
it.id,
HtmlUtils.stripHtml(it.name),
position + 1,
@ -86,7 +87,7 @@ class SearchGameFirstItemViewHolder(
game?.let {
val link = cardItem.link ?: return@let
// 阿里云埋点
com.gh.common.util.NewFlatLogUtils.logGameSearchFirstGameCardClick(
NewFlatLogUtils.logGameSearchFirstGameCardClick(
it.id,
HtmlUtils.stripHtml(it.name),
cardItem.cardName,

View File

@ -17,11 +17,9 @@ import com.gh.common.util.LogUtils
import com.gh.common.util.NewLogUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.SearchType
import com.gh.gamecenter.adapter.viewholder.GameViewHolder
import com.gh.gamecenter.adapter.viewholder.SearchHistoryViewHolder
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.baselist.ListAdapter
import com.gh.gamecenter.common.constant.Constants
import com.gh.gamecenter.common.constant.ItemViewType
@ -418,13 +416,6 @@ class SearchGameIndexAdapter(
gameEntity.adSpaceId,
gameEntity.gameAdSourceId
)
SensorsBridge.trackSearchResultClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
key,
SearchActivity.toTrackSearchType(type),
sourceEntrance
)
}
@ -527,14 +518,6 @@ class SearchGameIndexAdapter(
gameEntity.adSpaceId,
gameEntity.gameAdSourceId
)
SensorsBridge.trackSearchResultClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
key,
SearchActivity.toTrackSearchType(type),
sourceEntrance
)
}
}
}

View File

@ -7,8 +7,6 @@ import androidx.recyclerview.widget.RecyclerView
import com.gh.common.util.DirectUtils
import com.gh.common.util.NewFlatLogUtils
import com.gh.gamecenter.R
import com.gh.gamecenter.SearchActivity.Companion.toTrackSearchType
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.exposure.ExposureSource
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.view.DrawableView
@ -89,14 +87,6 @@ class SearchSubjectItemViewHolder(var binding: SearchSubjectItemBinding) : Recyc
subjectRv.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
subjectRv.adapter = SearchSubjectAdapter(context, entity.getFilterGame(), "($type-专题)") {
dao?.add(key)
SensorsBridge.trackSearchButtonClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
key,
toTrackSearchType(type),
sourceEntrance
)
if (itemData.adConfig != null) {
NewFlatLogUtils.logClickGameAd(
itemData.adConfig.id,

View File

@ -0,0 +1,20 @@
package com.gh.gamecenter.search
import com.gh.gamecenter.home.custom.model.CustomPageData
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.retrofit.service.ApiService
import io.reactivex.Single
class SearchGameListRepository private constructor(private val newApi: ApiService) {
fun searchGameList(
key: String,
page: Int
): Single<MutableList<CustomPageData.LinkColumnCollection.CustomSubjectEntity>> = newApi.searchGameList(key, page)
companion object {
fun newInstance() =
SearchGameListRepository(RetrofitManager.getInstance().newApi)
}
}

View File

@ -185,7 +185,13 @@ class SearchGameResultAdapter(
}
bottomDivider.visibility = View.VISIBLE
}
holder.bindSubjectItem(mContext, mEntityList[position], SearchType.fromString(type).toChinese(), key, sourceEntrance = sourceEntrance)
holder.bindSubjectItem(
mContext,
mEntityList[position],
SearchType.fromString(type).toChinese(),
key,
sourceEntrance = sourceEntrance
)
}
is SearchGameFirstItemViewHolder -> {
@ -688,6 +694,16 @@ class SearchGameResultAdapter(
}
if (gameEntity.isMiniGame()) {
SensorsBridge.trackMiniGameSearchResultClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
sourceEntrance,
key,
SearchActivity.toTrackSearchType(type),
gameEntity.id,
gameEntity.name ?: "",
gameEntity.categoryChinese
)
MiniGameItemHelper.launchMiniGame(gameEntity.miniGameAppId, gameEntity.miniGameType)
MiniGameItemHelper.trackMiniGameClick(
gameEntity = gameEntity,
@ -695,6 +711,16 @@ class SearchGameResultAdapter(
searchContent = key,
)
} else {
SensorsBridge.trackGameSearchResultClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
sourceEntrance,
key,
SearchActivity.toTrackSearchType(type),
gameEntity.id,
gameEntity.name ?: "",
gameEntity.categoryChinese
)
GameDetailActivity.startGameDetailActivity(
context, gameEntity,
StringUtils.buildString(
@ -730,14 +756,6 @@ class SearchGameResultAdapter(
gameEntity.name ?: ""
)
}
SensorsBridge.trackSearchResultClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
key,
SearchActivity.toTrackSearchType(type),
sourceEntrance
)
}

View File

@ -11,6 +11,8 @@ import android.view.animation.Animation
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.*
@ -18,8 +20,6 @@ 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
@ -33,6 +33,9 @@ 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
import com.lightgame.download.DownloadEntity
@ -42,6 +45,10 @@ import org.greenrobot.eventbus.ThreadMode
open class SearchGameResultFragment : ListFragment<GameEntity, SearchGameResultViewModel>() {
private val parentTabViewModel by viewModels<SearchTabViewModel>(
ownerProducer = { parentFragment ?: this }
)
private var mAdapter: SearchGameResultAdapter? = null
private var mExposureListener: ExposureListener? = null
private lateinit var mShowAction: Animation
@ -53,6 +60,7 @@ open class SearchGameResultFragment : ListFragment<GameEntity, SearchGameResultV
private var mType: String = ""
private var mLoadingAnimation = false
private var mScrollIng = false
private var mIsAutoLoad = true
private val dataWatcher = object : DataWatcher() {
override fun onDataChanged(downloadEntity: DownloadEntity) {
@ -68,6 +76,10 @@ open class SearchGameResultFragment : ListFragment<GameEntity, SearchGameResultV
}
}
override fun isAutomaticLoad(): Boolean {
return mIsAutoLoad
}
override fun getLayoutId() = 0
override fun getInflatedLayout() = mBinding.root
@ -105,7 +117,7 @@ open class SearchGameResultFragment : ListFragment<GameEntity, SearchGameResultV
mKey = savedInstanceState.getString(EntranceConsts.KEY_SEARCHKEY) ?: ""
mType = savedInstanceState.getString(SearchActivity.KEY_SEARCH_TYPE) ?: ""
}
mIsAutoLoad = arguments?.getBoolean(EntranceConsts.KEY_IS_AUTO_LOAD, true) ?: true
super.onCreate(savedInstanceState)
mListRefresh?.isEnabled = false
mBinding.reuseNoneData.reuseNoneDataDescTv.visibility = View.VISIBLE
@ -170,6 +182,10 @@ open class SearchGameResultFragment : ListFragment<GameEntity, SearchGameResultV
})
initAnimation()
parentTabViewModel.searchKeyAndType.observe(viewLifecycleOwner) { (key, type) ->
setParams(key, type)
}
}
private fun handleCloseMenuVisibility(recyclerView: RecyclerView) {
@ -251,6 +267,7 @@ open class SearchGameResultFragment : ListFragment<GameEntity, SearchGameResultV
outState.putString(EntranceConsts.KEY_SEARCHKEY, mKey)
outState.putString(SearchActivity.KEY_SEARCH_TYPE, mType)
outState.putBoolean(EntranceConsts.KEY_IS_AUTO_LOAD, mIsAutoLoad)
}
private fun showOpenMenuView() {

View File

@ -7,7 +7,6 @@ import androidx.lifecycle.ViewModelProvider
import com.gh.ad.AdDelegateHelper
import com.gh.common.filter.RegionSettingHelper
import com.gh.common.util.PackageHelper
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.baselist.LoadParams
@ -21,7 +20,9 @@ import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.entity.AdConfig
import com.gh.gamecenter.entity.SearchSubjectEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.minigame.MiniGameSearchResultRepository
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.SearchActivity
import io.reactivex.Observable
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
@ -57,6 +58,10 @@ class SearchGameResultViewModel(
mSearchSubjects.clear()
}
override fun loadData() {
super.loadData()
}
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) { list ->
mGameEntityList = ArrayList(list)
@ -295,14 +300,27 @@ class SearchGameResultViewModel(
private fun postResultList(resultList: ArrayList<SearchItemData>, list: List<GameEntity>) {
mResultLiveData.postValue(resultList)
if (mPage == 1) {
SensorsBridge.trackSearchResultReturn(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
mSearchKey ?: "",
SearchActivity.toTrackSearchType(mSearchType),
list.isNotEmpty(),
sourceEntrance
)
if (repository is MiniGameSearchResultRepository) {
SensorsBridge.trackMiniGameSearchResultReturn(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
sourceEntrance,
mSearchKey ?: "",
SearchActivity.toTrackSearchType(mSearchType),
list.isNotEmpty()
)
} else {
SensorsBridge.trackGameSearchResultReturn(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
sourceEntrance,
mSearchKey ?: "",
SearchActivity.toTrackSearchType(mSearchType),
list.isNotEmpty()
)
}
}
}
@ -355,7 +373,14 @@ class SearchGameResultViewModel(
private val mSourceEntrance: String
) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return SearchGameResultViewModel(mApplication, mSearchKey, mIsManuallySearch, repository, mSearchType, mSourceEntrance) as T
return SearchGameResultViewModel(
mApplication,
mSearchKey,
mIsManuallySearch,
repository,
mSearchType,
mSourceEntrance
) as T
}
}

View File

@ -0,0 +1,39 @@
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
class SearchTabActivity : SearchActivity() {
private val viewModel by viewModels<SearchTabActivityViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.loadTabs()
}
override fun updateDisplayType(type: DisplayType) {
viewModel.updateSearchKeyAndType(mSearchKey, mSearchType.value)
val lastDisplayType = mDisplayType
mDisplayType = type
// 如果上一次展示的是SearchTabFragment并且当前需要展示的也是SearchTabFragment则无需重复显示
if (lastDisplayType != DisplayType.DEFAULT && 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()
}
}
}

View File

@ -0,0 +1,15 @@
package com.gh.gamecenter.search
import com.gh.common.constant.Config
import com.gh.gamecenter.feature.entity.SettingsEntity
class SearchTabRepository private constructor() {
fun getSearchTabs(): List<SettingsEntity.Search.Navigation> =
Config.getNewApiSettingsEntity()?.search?.navigations ?: emptyList()
companion object {
fun newInstance() = SearchTabRepository()
}
}

View File

@ -0,0 +1,145 @@
package com.gh.gamecenter.search.adapter
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.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.utils.toBinding
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
) : ListAdapter<CustomPageData.LinkColumnCollection.CustomSubjectEntity, ViewHolder>(
createDiffUtil()
) {
private var _recyclerView: RecyclerView? = null
private var _loadStatus = LoadStatus.INIT
fun updateStatus(loadStatus: LoadStatus) {
_loadStatus = loadStatus
if (itemCount > 0) {
_recyclerView?.post {
notifyItemChanged(itemCount - 1)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return if (viewType == ITEM_TYPE_CONTENT) {
SearchGameListViewHolder(parent.toBinding(), object : SearchGameListViewHolder.SearchGameListListener {
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 navigateGameCollectionDetailPage(collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity) {
viewModel.navigateGameCollectionDetailPage(collection)
}
})
} else {
SearchGameListFooterViewHolder(parent.toBinding(), object : SearchGameListFooterViewHolder.FooterListener {
override fun loadMore() {
viewModel.onLoadMore()
}
override fun retry() {
viewModel.retry()
}
override fun toTop() {
_recyclerView?.scrollToPosition(0)
}
})
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
when (holder) {
is SearchGameListViewHolder -> {
holder.bind(getItem(position))
}
is SearchGameListFooterViewHolder -> {
holder.bind(_loadStatus)
}
}
}
override fun getItemCount(): Int {
val dataCount = super.getItemCount()
return if (dataCount > 0) {
dataCount + 1
} else {
0
}
}
override fun getItemViewType(position: Int): Int {
return if (position < itemCount - 1) {
ITEM_TYPE_CONTENT
} else {
ITEM_TYPE_FOOTER
}
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
_recyclerView = recyclerView
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
_recyclerView = null
}
companion object {
private const val ITEM_TYPE_CONTENT = 0
private const val ITEM_TYPE_FOOTER = 1
fun createDiffUtil() =
object : DiffUtil.ItemCallback<CustomPageData.LinkColumnCollection.CustomSubjectEntity>() {
override fun areItemsTheSame(
oldItem: CustomPageData.LinkColumnCollection.CustomSubjectEntity,
newItem: CustomPageData.LinkColumnCollection.CustomSubjectEntity
): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(
oldItem: CustomPageData.LinkColumnCollection.CustomSubjectEntity,
newItem: CustomPageData.LinkColumnCollection.CustomSubjectEntity
): Boolean {
return oldItem.id == newItem.id
&& oldItem.user == newItem.user
&& oldItem.count == newItem.count
&& oldItem.games.size == newItem.games.size
&& oldItem.adIconActive == newItem.adIconActive
&& oldItem.intro == newItem.intro
&& oldItem.title == newItem.title
&& oldItem.image == newItem.image
&& oldItem.tags.size == newItem.tags.size
}
}
}
}

View File

@ -0,0 +1,72 @@
package com.gh.gamecenter.search.adapter
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.gh.gamecenter.SearchActivity
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.feature.entity.SettingsEntity
import com.gh.gamecenter.feedback.view.qa.HelpContentFragment
import com.gh.gamecenter.forum.search.ForumContentSearchListFragment
import com.gh.gamecenter.forum.search.UserSearchListFragment
import com.gh.gamecenter.minigame.MiniGameSearchResultFragment
import com.gh.gamecenter.qa.dialog.ChooseForumContainerFragment
import com.gh.gamecenter.search.SearchGameResultFragment
import com.gh.gamecenter.search.fragment.SearchGameListFragment
class SearchTabAdapter(
private val location: String,
private val searchType: String?,
private val tabs: List<SettingsEntity.Search.Navigation>,
private val fragment: Fragment
) : FragmentStateAdapter(fragment) {
override fun getItemCount() = tabs.size
override fun createFragment(position: Int): Fragment {
val navigation = tabs[position]
val bundle = Bundle().apply {
putBoolean(EntranceConsts.KEY_IS_AUTO_LOAD, false)
putString(EntranceConsts.KEY_LOCATION, location)
}
val fragment = when (navigation.type) {
SEARCH_TYPE_GAME -> SearchGameResultFragment()
SEARCH_TYPE_BBS -> ChooseForumContainerFragment.getInstance(ChooseForumContainerFragment.ChooseForumType.SEARCH)
SEARCH_TYPE_BBS_CONTENT -> ForumContentSearchListFragment()
SEARCH_TYPE_USER -> UserSearchListFragment()
SEARCH_TYPE_MINI_GAME -> MiniGameSearchResultFragment()
SEARCH_TYPE_QA -> HelpContentFragment().apply {
arguments = Bundle().apply {
putString(EntranceConsts.KEY_SEARCH_TYPE, SearchActivity.toTrackSearchType(searchType ?: ""))
}
}
SEARCH_TYPE_GAME_LIST -> SearchGameListFragment()
else -> SearchGameResultFragment()
}.also {
if (it.arguments != null) {
it.arguments?.putAll(bundle)
} else {
it.arguments = bundle
}
}
return fragment
}
companion object {
private const val SEARCH_TYPE_GAME = "game"
private const val SEARCH_TYPE_BBS = "bbs"
private const val SEARCH_TYPE_BBS_CONTENT = "bbs_content"
private const val SEARCH_TYPE_USER = "user"
private const val SEARCH_TYPE_QA = "qa"
private const val SEARCH_TYPE_MINI_GAME = "mini_game"
private const val SEARCH_TYPE_GAME_LIST = "game_list"
}
}

View File

@ -0,0 +1,118 @@
package com.gh.gamecenter.search.fragment
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.View
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import com.gh.common.util.DirectUtils
import com.gh.gamecenter.GameDetailActivity
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.activity.BaseActivity
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.view.FixLinearLayoutManager
import com.gh.gamecenter.databinding.FragmentSearchGameListBinding
import com.gh.gamecenter.gamecollection.detail.GameCollectionDetailActivity
import com.gh.gamecenter.livedata.EventObserver
import com.gh.gamecenter.search.adapter.SearchGameListAdapter
import com.gh.gamecenter.search.viewmodel.SearchGameListViewModel
import com.gh.gamecenter.search.viewmodel.SearchTabViewModel
class SearchGameListFragment : LazyFragment() {
private val viewModel by viewModels<SearchGameListViewModel>()
private val parentViewModel by viewModels<SearchTabViewModel>(
ownerProducer = { parentFragment ?: this }
)
private var searchKey = ""
private var location: String = ""
private lateinit var binding: FragmentSearchGameListBinding
private val adapter by lazy(LazyThreadSafetyMode.NONE) {
SearchGameListAdapter(viewModel)
}
override fun onCreate(savedInstanceState: Bundle?) {
searchKey = arguments?.getString(EntranceConsts.KEY_SEARCHKEY, "") ?: ""
location = arguments?.getString(EntranceConsts.KEY_LOCATION, "") ?: ""
super.onCreate(savedInstanceState)
}
override fun getRealLayoutId(): Int = R.layout.fragment_search_game_list
override fun onRealLayoutInflated(inflatedView: View) {
binding = FragmentSearchGameListBinding.bind(inflatedView)
}
@SuppressLint("NotifyDataSetChanged")
override fun initRealView() {
super.initRealView()
parentViewModel.searchKeyAndType.observe(viewLifecycleOwner, Observer { (key, type) ->
// 清空上一次的搜索结果
adapter.submitList(null)
// 上面调用了 adapter.submitList(null) ,这里为什么还要调用 notifyDataSetChanged 呢?
// 因为adapter.submitList(null)最终调用的adapter.notifyItemRangeRemoved()方法更新RecyclerView
// 此方法不会立马清空RecyclerView 的内容而是在postOnAnimation执行相关的移除工作这里为了让RecyclerView的内容立马清空需要再次调用adapter.notifyDataSetChanged()
adapter.notifyDataSetChanged()
viewModel.loadFirstData(key, type, location)
})
binding.rvGameList.layoutManager = FixLinearLayoutManager(context)
binding.rvGameList.adapter = adapter
binding.reuseNoData.reuseResetLoadTv.setOnClickListener {
viewModel.retry()
}
binding.reuseNoConnection.connectionReloadTv.setOnClickListener {
viewModel.retry()
}
with(viewModel) {
loadStatus.observe(viewLifecycleOwner) {
binding.rvGameList.goneIf(it == LoadStatus.INIT_LOADING || it == LoadStatus.INIT_FAILED || it == LoadStatus.INIT_EMPTY)
binding.reuseNoConnection.root.goneIf(it != LoadStatus.INIT_FAILED)
binding.reuseLoading.root.goneIf(it != LoadStatus.INIT_LOADING)
binding.reuseNoData.root.goneIf(it != LoadStatus.INIT_EMPTY)
adapter.updateStatus(it)
}
dataList.observe(viewLifecycleOwner, Observer {
adapter.submitList(it)
})
gameDetailDestination.observe(viewLifecycleOwner, EventObserver {
GameDetailActivity.startGameDetailActivity(
requireContext(),
it,
BaseActivity.mergeEntranceAndPath(location, "游戏单搜索"),
null
)
})
homeDestination.observe(viewLifecycleOwner, EventObserver {
DirectUtils.directToHomeActivity(
requireContext(),
it,
0,
location,
"游戏单搜索"
)
})
gameCollectionDetailDestination.observe(viewLifecycleOwner, EventObserver {
startActivity(
GameCollectionDetailActivity.getIntent(
requireContext(),
it,
isFromSquare = false,
)
)
})
}
}
}

View File

@ -0,0 +1,138 @@
package com.gh.gamecenter.search.fragment
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import com.gh.gamecenter.R
import com.gh.gamecenter.common.base.fragment.BaseFragment
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.utils.goneIf
import com.gh.gamecenter.databinding.FragmentSearchTabBinding
import com.gh.gamecenter.feature.entity.SettingsEntity
import com.gh.gamecenter.search.SearchGameResultFragment
import com.gh.gamecenter.search.adapter.SearchTabAdapter
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>() {
private lateinit var binding: FragmentSearchTabBinding
private val activityViewModel by activityViewModels<SearchTabActivityViewModel>()
private val viewModel by viewModels<SearchTabViewModel>()
private lateinit var adapter: SearchTabAdapter
private var location = ""
private var _key: String? = null
private var _searchType: String? = null
override fun getLayoutId(): Int = 0
override fun getInflatedLayout() =
FragmentSearchTabBinding.inflate(LayoutInflater.from(context))
.also {
binding = it
}.root
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
location = arguments?.getString(EntranceConsts.KEY_LOCATION) ?: ""
with(activityViewModel) {
searchKeyAndType.observe(this@SearchTabFragment) { (key, type) ->
if (key != null) {
_key = key
_searchType = type
viewModel.updateSearchKeyAndType(key, type)
}
}
}
}
override fun initView(view: View?) {
super.initView(view)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
with(activityViewModel) {
tabs.observe(viewLifecycleOwner) {
if (it.size > 1) {
initTabs(it)
} else {
initSingleFragment()
}
}
}
}
private fun initTabs(tabs: List<SettingsEntity.Search.Navigation>) {
binding.gTabs.goneIf(false)
binding.flContainer.goneIf(true)
binding.tabLayout.addOnTabSelectedListener(object : OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
viewModel.trackGameSearchPageTabClick(location, tab.text?.toString(), tab.position)
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
}
override fun onTabReselected(tab: TabLayout.Tab?) {
}
})
if (tabs.size > 5) {
binding.tabLayout.tabMode = TabLayout.MODE_SCROLLABLE
} else {
binding.tabLayout.tabMode = TabLayout.MODE_FIXED
}
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()
}
private fun initSingleFragment() {
binding.gTabs.goneIf(true)
binding.flContainer.goneIf(false)
val transaction = childFragmentManager.beginTransaction()
val fragment = childFragmentManager.findFragmentByTag(SearchGameResultFragment::class.java.name)
?: SearchGameResultFragment().apply {
arguments = Bundle().apply {
putBoolean(EntranceConsts.KEY_IS_AUTO_LOAD, false)
}
}
transaction.replace(R.id.fl_container, fragment, SearchGameResultFragment::class.java.name)
transaction.commitAllowingStateLoss()
}
companion object {
fun newInstance(location: String) =
SearchTabFragment().apply {
arguments = Bundle().apply {
putString(EntranceConsts.KEY_LOCATION, location)
}
}
}
}

View File

@ -0,0 +1,60 @@
package com.gh.gamecenter.search.viewholder
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.gh.gamecenter.common.R
import com.gh.gamecenter.common.baselist.LoadStatus
import com.gh.gamecenter.common.databinding.RefreshFooterviewBinding
import com.gh.gamecenter.common.utils.goneIf
class SearchGameListFooterViewHolder(
val binding: RefreshFooterviewBinding,
private val listener: FooterListener
) : ViewHolder(binding.root) {
private var _loadStatus = LoadStatus.INIT
fun bind(loadStatus: LoadStatus) {
if (_loadStatus == loadStatus) return
_loadStatus = loadStatus
when (loadStatus) {
LoadStatus.LIST_LOADING -> {
binding.footerviewLoading.goneIf(false)
binding.footerviewHint.goneIf(false)
binding.footerviewHint.setText(R.string.loading)
}
LoadStatus.LIST_FAILED -> {
binding.footerviewLoading.goneIf(true)
binding.footerviewHint.goneIf(false)
binding.footerviewHint.setText(R.string.loading_failed_retry)
}
LoadStatus.LIST_OVER -> {
binding.footerviewLoading.goneIf(true)
binding.footerviewHint.goneIf(false)
binding.footerviewHint.setText(R.string.load_over_hint)
}
LoadStatus.LIST_LOADED, LoadStatus.INIT_LOADED -> listener.loadMore()
else -> Unit
}
itemView.setOnClickListener {
when (loadStatus) {
LoadStatus.LIST_FAILED -> listener.retry()
LoadStatus.LIST_OVER -> listener.toTop()
else -> Unit
}
}
}
interface FooterListener {
fun loadMore()
fun retry()
fun toTop()
}
}

View File

@ -0,0 +1,119 @@
package com.gh.gamecenter.search.viewholder
import android.content.Context
import android.graphics.Color
import android.view.View
import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import android.widget.LinearLayout
import android.widget.TextView
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.common.utils.*
import com.gh.gamecenter.databinding.GameCollectionSquareItemBinding
import com.gh.gamecenter.home.custom.model.CustomPageData
class SearchGameListViewHolder(
val binding: GameCollectionSquareItemBinding,
private val listener: SearchGameListListener
) : ViewHolder(binding.root) {
private val context: Context
get() = binding.root.context
private val posterWidth by lazy(LazyThreadSafetyMode.NONE) {
context.resources.displayMetrics.widthPixels - 32F.dip2px()
}
fun bind(item: CustomPageData.LinkColumnCollection.CustomSubjectEntity) {
with(binding) {
root.updateLayoutParams {
if (this is MarginLayoutParams) {
topMargin = 16F.dip2px()
}
}
poster.setTag(ImageUtils.TAG_TARGET_WIDTH, posterWidth)
ImageUtils.display(poster, item.image)
ImageUtils.display(userIv, item.user.icon)
titleTv.text = item.title.fromHtml()
item.games.take(3).forEachIndexed { index, game ->
when (index) {
0 -> iconIvOne.displayGameIcon(game)
1 -> iconIvTwo.displayGameIcon(game)
2 -> iconIvThree.displayGameIcon(game)
}
}
item.games.size.let {
iconIvOne.goneIf(it == 0)
iconIvTwo.goneIf(it < 2)
iconIvThree.goneIf(it < 3)
}
countTv.goneIf(item.count.game < 4 || item.games.isEmpty())
countTv.text = "+ ${item.count.game - 3}"
hotTv.text = if (item.count.hot > 10000) "10000+" else item.count.hot.toString()
userTv.text = item.user.name
playedGameProgress.max = item.count.game
playedGameProgress.progress = item.count.gamePlayed ?: 0
playedGameTv.text =
"玩过 ${item.count.gamePlayed} / ${item.count.game}"
stampIv.goneIf(item.stamp.isEmpty())
stampIv.setBackgroundResource(if (item.stamp == "official") R.drawable.ic_official else R.drawable.ic_chosen)
tagContainer.removeAllViews()
tagContainer.visibleIf(!CheckLoginUtils.isLogin() || item.count.game == 0) {
item.tags.forEachIndexed { index, tag ->
// 添加分隔线
if (index != 0) tagContainer.addView(View(context).apply {
layoutParams = ViewGroup.LayoutParams(1F.dip2px(), 14F.dip2px())
setBackgroundColor(Color.parseColor("#33FFFFFF"))
})
// 添加标签
tagContainer.addView(TextView(context).apply {
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
setPadding(if (index == 0) 0 else 6F.dip2px(), 0, 6F.dip2px(), 0)
text = tag.name
setTextColor(R.color.white.toColor())
textSize = 10F
})
}
}
playedGamesContainer.visibleIf(CheckLoginUtils.isLogin() && item.count.game != 0)
adLabelTv.goneIf(!item.adIconActive)
arrayOf(iconIvOne, iconIvTwo, iconIvThree).forEachIndexed { index, ivIcon ->
ivIcon.setOnClickListener {
val game = item.games.getOrNull(index)
game?.id?.let { gameId ->
listener.navigateToGameDetailPage(gameId, item)
}
}
}
userContainer.setOnClickListener {
listener.navigateToHomePage(item.user.id, item)
}
root.setOnClickListener {
listener.navigateGameCollectionDetailPage(item)
}
}
}
interface SearchGameListListener {
fun navigateToGameDetailPage(
gameId: String,
collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity
)
fun navigateToHomePage(userId: String, collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity)
fun navigateGameCollectionDetailPage(collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity)
}
}

View File

@ -0,0 +1,141 @@
package com.gh.gamecenter.search.viewmodel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
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.retrofit.BiResponse
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.common.utils.singleToMain
import com.gh.gamecenter.home.custom.model.CustomPageData
import com.gh.gamecenter.livedata.Event
import com.gh.gamecenter.search.SearchGameListRepository
import io.reactivex.disposables.CompositeDisposable
class SearchGameListViewModel : ViewModel() {
private val repository = SearchGameListRepository.newInstance()
private val compositeDisposable = CompositeDisposable()
private var page = 1
private var key = ""
private var type = ""
private var location = ""
private val _loadStatus = MutableLiveData<LoadStatus>()
val loadStatus: LiveData<LoadStatus> = _loadStatus
private val _dataList = MutableLiveData<List<CustomPageData.LinkColumnCollection.CustomSubjectEntity>?>()
val dataList: LiveData<List<CustomPageData.LinkColumnCollection.CustomSubjectEntity>?> = _dataList
fun loadFirstData(key: String, type: String, location: String) {
this.key = key
this.type = type
this.location = location
page = 1
_loadStatus.value = LoadStatus.INIT_LOADING
searchGameList()
}
fun onLoadMore() {
page++
_loadStatus.value = LoadStatus.LIST_LOADING
searchGameList()
}
fun retry() {
_loadStatus.value = if (page == 1) {
LoadStatus.INIT_LOADING
} else {
LoadStatus.LIST_LOADED
}
searchGameList()
}
private fun searchGameList() {
repository.searchGameList(key, page)
.compose(singleToMain())
.subscribe(object : BiResponse<List<CustomPageData.LinkColumnCollection.CustomSubjectEntity>>() {
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
}
SensorsBridge.trackGameCollectSearchResultReturn(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
location,
key,
SearchActivity.toTrackSearchType(type),
data.isNotEmpty()
)
} else {
addData(data)
_loadStatus.value = if (data.isEmpty()) {
LoadStatus.LIST_OVER
} else {
LoadStatus.LIST_LOADED
}
}
}
override fun onFailure(exception: Exception) {
_loadStatus.value = if (page == 1) {
LoadStatus.INIT_FAILED
} else {
LoadStatus.LIST_FAILED
}
}
}).let(compositeDisposable::add)
}
private fun addData(newData: List<CustomPageData.LinkColumnCollection.CustomSubjectEntity>) {
val oldData = dataList.value
_dataList.value = if (oldData == null) {
newData
} else {
oldData + newData
}
}
private val _gameDetailDestination = MutableLiveData<Event<String>>()
val gameDetailDestination: LiveData<Event<String>> = _gameDetailDestination
fun navigateToGameDetailPage(gameId: String, collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity) {
trackGameCollectSearchResultClick(collection)
_gameDetailDestination.value = Event(gameId)
}
private val _homeDestination = MutableLiveData<Event<String>>()
val homeDestination: LiveData<Event<String>> = _homeDestination
fun navigateToHomePage(userId: String, collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity) {
trackGameCollectSearchResultClick(collection)
_homeDestination.value = Event(userId)
}
private val _gameCollectionDetailDestination = MutableLiveData<Event<String>>()
val gameCollectionDetailDestination: LiveData<Event<String>> = _gameCollectionDetailDestination
fun navigateGameCollectionDetailPage(collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity) {
trackGameCollectSearchResultClick(collection)
_gameCollectionDetailDestination.value = Event(collection.id)
}
private fun trackGameCollectSearchResultClick(collection: CustomPageData.LinkColumnCollection.CustomSubjectEntity) {
SensorsBridge.trackGameCollectSearchResultClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
key,
SearchActivity.toTrackSearchType(type),
location,
collection.id,
collection.title
)
}
}

View File

@ -0,0 +1,26 @@
package com.gh.gamecenter.search.viewmodel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.gh.gamecenter.feature.entity.SettingsEntity
import com.gh.gamecenter.search.SearchTabRepository
class SearchTabActivityViewModel : ViewModel() {
private val repository = SearchTabRepository.newInstance()
private val _searchKeyAndType = MutableLiveData<Pair<String?, String>>()
val searchKeyAndType: LiveData<Pair<String?, String>> = _searchKeyAndType
fun updateSearchKeyAndType(key: String?, type: String) {
_searchKeyAndType.value = key to type
}
private val _tabs = MutableLiveData<List<SettingsEntity.Search.Navigation>>()
val tabs: LiveData<List<SettingsEntity.Search.Navigation>> = _tabs
fun loadTabs() {
_tabs.value = repository.getSearchTabs()
}
}

View File

@ -0,0 +1,29 @@
package com.gh.gamecenter.search.viewmodel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.gh.gamecenter.common.base.GlobalActivityManager
import com.gh.gamecenter.common.utils.SensorsBridge
import io.reactivex.disposables.CompositeDisposable
class SearchTabViewModel : ViewModel() {
private val _searchKeyAndType = MutableLiveData<Pair<String, String>>()
val searchKeyAndType: LiveData<Pair<String, String>> = _searchKeyAndType
fun updateSearchKeyAndType(key: String, type: String) {
_searchKeyAndType.value = key to type
}
fun trackGameSearchPageTabClick(location: String, text: String?, position: Int) {
SensorsBridge.trackGameSearchPageTabClick(
GlobalActivityManager.getCurrentPageEntity().pageId,
GlobalActivityManager.getCurrentPageEntity().pageName,
location,
searchKeyAndType.value?.first ?: "",
searchKeyAndType.value?.second ?: "",
text ?: "",
position
)
}
}

View File

@ -1,11 +1,9 @@
package com.gh.gamecenter.vote
import android.annotation.SuppressLint
import android.app.Application
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.gh.gamecenter.SearchType
import com.gh.gamecenter.common.baselist.ListViewModel
import com.gh.gamecenter.common.baselist.LoadType
import com.gh.gamecenter.common.retrofit.ApiResponse