Merge branch 'feat/GHZSCY-5891' into 'dev'
feat: 新增页面分流器—客户端 https://jira.shanqu.cc/browse/GHZSCY-5891 See merge request halo/android/assistant-android!1876
This commit is contained in:
@ -0,0 +1,52 @@
|
||||
package com.gh.common.prioritychain
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.FrameLayout
|
||||
import com.airbnb.lottie.LottieAnimationView
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.databinding.LayoutCommunityHomeVideoGuideBinding
|
||||
|
||||
class CommunityHomeGuideHandler(
|
||||
priority: Int,
|
||||
private val context: Context,
|
||||
private val decorView: FrameLayout?,
|
||||
private val videoLottie: LottieAnimationView?
|
||||
) : PriorityChainHandler(priority) {
|
||||
|
||||
init {
|
||||
updateStatus(STATUS_VALID)
|
||||
}
|
||||
|
||||
override fun onProcess(): Boolean {
|
||||
return if (SPUtils.getBoolean(Constants.SP_SHOW_COMMUNITY_HOME_VIDEO_GUIDE, true)) {
|
||||
showHomeVideoGuide(context, decorView, videoLottie)
|
||||
processNext()
|
||||
true
|
||||
} else {
|
||||
processNext()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun showHomeVideoGuide(context: Context, decorView: FrameLayout?, videoLottie: LottieAnimationView?) {
|
||||
val guideLayoutBinding = LayoutCommunityHomeVideoGuideBinding.inflate(
|
||||
LayoutInflater.from(context),
|
||||
decorView,
|
||||
true
|
||||
)
|
||||
guideLayoutBinding.root.setOnClickListener { view ->
|
||||
decorView?.removeView(view)
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_COMMUNITY_HOME_VIDEO_GUIDE, false)
|
||||
|
||||
videoLottie?.playAnimation()
|
||||
SPUtils.setLong(
|
||||
Constants.SP_COMMUNITY_HOME_VIDEO_LOTTIE_LAST_PLAY_TIME,
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -57,10 +57,6 @@ object HomeBottomBarHelper {
|
||||
return BottomTab(name = "我的光环", jsCode = animationCode, iconSelector = R.drawable.selector_ic_user, link = LinkEntity(type = TYPE_MY_HALO))
|
||||
}
|
||||
|
||||
fun isDefaultHomeBottomTabDataExist(): Boolean {
|
||||
return SPUtils.getString(KEY_HOME_BOTTOM_TAB).isNotEmpty()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getDefaultHomeBottomTabData(): List<BottomTab> {
|
||||
try {
|
||||
|
||||
@ -2716,4 +2716,52 @@ object NewFlatLogUtils {
|
||||
parseAndPutMeta()(this)
|
||||
}.let(::log)
|
||||
}
|
||||
|
||||
// 用户访问分流器
|
||||
fun logByPassBrowsing(
|
||||
source: String,
|
||||
bypassName: String,
|
||||
bypassId: String,
|
||||
branchId: String,
|
||||
branchName: String,
|
||||
inProcessTime: Int,
|
||||
bypassVisitTime: Int,
|
||||
linkType: String,
|
||||
linkId: String,
|
||||
linkText: String,
|
||||
bypassStatus: Int
|
||||
) {
|
||||
json {
|
||||
KEY_EVENT to "BypassBrowsing"
|
||||
"source" to source
|
||||
"bypass_name" to bypassName
|
||||
"bypass_id" to bypassId
|
||||
"branch_id" to branchId
|
||||
"branch_name" to branchName
|
||||
"inprocess_time" to inProcessTime
|
||||
"bypass_visit_time" to bypassVisitTime
|
||||
"link_type" to linkType
|
||||
"link_id" to linkId
|
||||
"link_text" to linkText
|
||||
"bypass_status" to bypassStatus
|
||||
parseAndPutMeta()(this)
|
||||
}.let(::log)
|
||||
}
|
||||
|
||||
// 分流失败
|
||||
fun logFailByPass(
|
||||
source: String,
|
||||
bypassName: String,
|
||||
bypassId: String,
|
||||
defeatedReason: String
|
||||
) {
|
||||
json {
|
||||
KEY_EVENT to "FailBypass"
|
||||
"source" to source
|
||||
"bypass_name" to bypassName
|
||||
"bypass_id" to bypassId
|
||||
"defeated_reason" to defeatedReason
|
||||
parseAndPutMeta()(this)
|
||||
}.let(::log)
|
||||
}
|
||||
}
|
||||
@ -82,6 +82,7 @@ object ViewPagerFragmentHelper {
|
||||
const val TYPE_TOOLKIT = "toolkit" // 工具箱
|
||||
|
||||
fun createFragment(parentFragment: Fragment?, bundle: Bundle, linkEntity: LinkEntity, isTabWrapper: Boolean): Fragment {
|
||||
val superiorChain = if (parentFragment is ISuperiorChain) parentFragment else null
|
||||
return when (linkEntity.type) {
|
||||
// 游戏详情页
|
||||
TYPE_GAME -> {
|
||||
@ -90,11 +91,12 @@ object ViewPagerFragmentHelper {
|
||||
}
|
||||
// 我的光环
|
||||
TYPE_MY_HALO -> {
|
||||
val superiorChain = if (parentFragment is ISuperiorChain) parentFragment else null
|
||||
HaloPersonalFragment().setSuperiorChain(superiorChain).with(bundle)
|
||||
}
|
||||
// 社区首页
|
||||
TYPE_COMMUNITY_HOME -> CommunityHomeFragment().with(bundle)
|
||||
TYPE_COMMUNITY_HOME -> {
|
||||
CommunityHomeFragment().setSuperiorChain(superiorChain).with(bundle)
|
||||
}
|
||||
// 视频信息流
|
||||
TYPE_VIDEO_STREAM -> {
|
||||
bundle.putBoolean(EntranceConsts.KEY_IS_HOME_VIDEO, true)
|
||||
@ -148,11 +150,11 @@ object ViewPagerFragmentHelper {
|
||||
NewQuestionDetailFragment().with(bundle)
|
||||
}
|
||||
// 其他原来带Toolbar的Fragment
|
||||
else -> createToolbarWrapperFragment(bundle, linkEntity, isTabWrapper)
|
||||
else -> createToolbarWrapperFragment(parentFragment, bundle, linkEntity, isTabWrapper)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createToolbarWrapperFragment(bundle: Bundle, entity: LinkEntity, isTabWrapper: Boolean): Fragment {
|
||||
private fun createToolbarWrapperFragment(parentFragment: Fragment?, bundle: Bundle, entity: LinkEntity, isTabWrapper: Boolean): Fragment {
|
||||
var className = ReloadFragment::class.java.name
|
||||
|
||||
when (entity.type) {
|
||||
|
||||
@ -138,7 +138,6 @@ import io.reactivex.functions.Function;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function0;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.HttpException;
|
||||
|
||||
@ -59,6 +59,9 @@ class SplashScreenActivity : BaseActivity() {
|
||||
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
mIsNewForThisVersion = HaloApp.getInstance().isNewForThisVersion
|
||||
HaloApp.getInstance().isBrandNewInstall = SPUtils.getBoolean(Constants.SP_BRAND_NEW_USER, true)
|
||||
if (HaloApp.getInstance().isBrandNewInstall) {
|
||||
SPUtils.setLong(Constants.SP_BRAND_NEW_FIRST_LAUNCH_TIME, System.currentTimeMillis())
|
||||
}
|
||||
|
||||
// 用户不是新版本,但应用最后更新时间不是上次的时间代表用户重新安装了当前版本
|
||||
if (!mIsNewForThisVersion) {
|
||||
|
||||
@ -26,7 +26,8 @@ data class BottomTab(
|
||||
@SerializedName("is_default_page")
|
||||
var default: Boolean = false, // 是否为默认显示页
|
||||
var guide: Guide? = null, // 引导文案
|
||||
var isTransparentStyle: Boolean = false // 本地字段,透明底部Tab
|
||||
var diverter: DiverterEntity? = null, // 分流器
|
||||
var isTransparentStyle: Boolean = false, // 本地字段,透明底部Tab
|
||||
) : Parcelable {
|
||||
@Parcelize
|
||||
data class SearchStyle(
|
||||
|
||||
31
app/src/main/java/com/gh/gamecenter/entity/DiverterData.kt
Normal file
31
app/src/main/java/com/gh/gamecenter/entity/DiverterData.kt
Normal file
@ -0,0 +1,31 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
class DiverterData(
|
||||
@SerializedName("diverter_id")
|
||||
val diverterId: String = "",
|
||||
@SerializedName("diverter_name")
|
||||
val diverterName: String = "",
|
||||
@SerializedName("branch_id")
|
||||
val branchId: String = "",
|
||||
@SerializedName("branch_name")
|
||||
val branchName: String = "",
|
||||
@SerializedName("branch_type")
|
||||
val branchType: String = "",
|
||||
@SerializedName("inprocess_time")
|
||||
val inprocessTime: Int = 0,
|
||||
@SerializedName("bypass_visit_time")
|
||||
val bypassVisitTime: Int = 0,
|
||||
@SerializedName("link_id")
|
||||
val linkId: String = "",
|
||||
@SerializedName("link_type")
|
||||
val linkType: String = "",
|
||||
@SerializedName("link_text")
|
||||
val linkText: String = "",
|
||||
@SerializedName("bypass_status")
|
||||
val bypassStatus: Int = 0,
|
||||
): Parcelable
|
||||
15
app/src/main/java/com/gh/gamecenter/entity/DiverterEntity.kt
Normal file
15
app/src/main/java/com/gh/gamecenter/entity/DiverterEntity.kt
Normal file
@ -0,0 +1,15 @@
|
||||
package com.gh.gamecenter.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
class DiverterEntity(
|
||||
@SerializedName("module_id")
|
||||
val moduleId: String = "",
|
||||
@SerializedName("module_index")
|
||||
val moduleIndex: Int = -1,
|
||||
@SerializedName("diverter_data")
|
||||
val diverterData: DiverterData = DiverterData()
|
||||
): Parcelable
|
||||
@ -23,6 +23,9 @@ import com.airbnb.lottie.SimpleColorFilter
|
||||
import com.airbnb.lottie.model.KeyPath
|
||||
import com.airbnb.lottie.value.LottieValueCallback
|
||||
import com.gh.common.browse.BrowseTimer
|
||||
import com.gh.common.iinterface.ISuperiorChain
|
||||
import com.gh.common.prioritychain.CommunityHomeGuideHandler
|
||||
import com.gh.common.prioritychain.PriorityChain
|
||||
import com.gh.common.util.DirectUtils
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.common.util.NewLogUtils
|
||||
@ -42,7 +45,6 @@ import com.gh.gamecenter.core.utils.MtaHelper
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.core.utils.TimeUtils
|
||||
import com.gh.gamecenter.databinding.FragmentCommunityHomeBinding
|
||||
import com.gh.gamecenter.databinding.LayoutCommunityHomeVideoGuideBinding
|
||||
import com.gh.gamecenter.databinding.TabItemCommunityBinding
|
||||
import com.gh.gamecenter.eventbus.EBSkip
|
||||
import com.gh.gamecenter.eventbus.EBTypeChange
|
||||
@ -81,6 +83,8 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
private var mNavigationBitmap: Bitmap? = null
|
||||
private var mShowVideo = true
|
||||
private var mBottomTabId = ""
|
||||
private val mPriorityChain by lazy { PriorityChain() }
|
||||
private var mSuperiorChain: ISuperiorChain? = null
|
||||
|
||||
private val browseTimer = BrowseTimer()
|
||||
.withResult {
|
||||
@ -156,6 +160,12 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
})
|
||||
}
|
||||
|
||||
private fun addHomeVideoGuideHandler() {
|
||||
val decorView = activity?.window?.decorView as? FrameLayout
|
||||
val communityHomeGuideHandler = CommunityHomeGuideHandler(21, requireContext(), decorView, mBinding?.videoLottie)
|
||||
mPriorityChain.addHandler(communityHomeGuideHandler)
|
||||
}
|
||||
|
||||
override fun initRealView() {
|
||||
super.initRealView()
|
||||
|
||||
@ -166,24 +176,7 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
mMainWrapperViewModel?.bottomTabListLiveData?.observe(this) { tabList ->
|
||||
mBinding?.videoAndSearchContainer?.goneIf(!mShowVideo) {
|
||||
val decorView = requireActivity().window.decorView as? FrameLayout
|
||||
|
||||
if (SPUtils.getBoolean(Constants.SP_SHOW_COMMUNITY_HOME_VIDEO_GUIDE, true)) {
|
||||
val guideLayoutBinding = LayoutCommunityHomeVideoGuideBinding.inflate(
|
||||
LayoutInflater.from(requireContext()),
|
||||
decorView,
|
||||
true
|
||||
)
|
||||
guideLayoutBinding.root.setOnClickListener { view ->
|
||||
decorView?.removeView(view)
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_COMMUNITY_HOME_VIDEO_GUIDE, false)
|
||||
|
||||
mBinding?.videoLottie?.playAnimation()
|
||||
SPUtils.setLong(
|
||||
Constants.SP_COMMUNITY_HOME_VIDEO_LOTTIE_LAST_PLAY_TIME,
|
||||
System.currentTimeMillis()
|
||||
)
|
||||
}
|
||||
}
|
||||
addHomeVideoGuideHandler()
|
||||
|
||||
// 每日首次进入社区tab视频lottie播放3次
|
||||
val lastPlayTime = SPUtils.getLong(Constants.SP_COMMUNITY_HOME_VIDEO_LOTTIE_LAST_PLAY_TIME, 0L) / 1000
|
||||
@ -285,6 +278,14 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
DisplayUtils.transparentStatusBar(requireActivity())
|
||||
DisplayUtils.setLightStatusBar(requireActivity(), !mIsDarkModeOn)
|
||||
NewLogUtils.logCommunityHomeEvent("view_community")
|
||||
|
||||
mSuperiorChain?.registerInferiorChain(mPriorityChain)
|
||||
}
|
||||
|
||||
override fun onFragmentPause() {
|
||||
super.onFragmentPause()
|
||||
|
||||
mSuperiorChain?.unregisterInferiorChain(mPriorityChain)
|
||||
}
|
||||
|
||||
fun setCurrentItem(index: Int) {
|
||||
@ -836,6 +837,11 @@ class CommunityHomeFragment : LazyFragment() {
|
||||
|
||||
fun getTopBgView() = mBinding?.topBg
|
||||
|
||||
fun setSuperiorChain(superiorChain: ISuperiorChain?): CommunityHomeFragment {
|
||||
this.mSuperiorChain = superiorChain
|
||||
return this
|
||||
}
|
||||
|
||||
companion object {
|
||||
var TAB_SELECTED_COLOR: Int = R.color.text_primary
|
||||
var TAB_DEFAULT_COLOR: Int = R.color.community_forum_more
|
||||
|
||||
@ -23,7 +23,7 @@ class ReloadFragment: BaseLazyFragment() {
|
||||
super.onCreate(savedInstanceState)
|
||||
mBinding.reuseLoading.root.visibility = View.VISIBLE
|
||||
mBinding.reuseNoConnection.connectionReloadTv.setOnClickListener {
|
||||
MainWrapperRepository.getInstance().getDataUnion()
|
||||
MainWrapperRepository.getInstance().init()
|
||||
mBinding.reuseNoConnection.root.visibility = View.GONE
|
||||
mBinding.reuseLoading.root.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ import com.gh.gamecenter.entity.DeviceDialogEntity;
|
||||
import com.gh.gamecenter.entity.DialogEntity;
|
||||
import com.gh.gamecenter.entity.DiscoveryGameCardEntity;
|
||||
import com.gh.gamecenter.entity.DiscoveryGameCardLabel;
|
||||
import com.gh.gamecenter.entity.DiverterEntity;
|
||||
import com.gh.gamecenter.entity.FollowCommonContentCollection;
|
||||
import com.gh.gamecenter.entity.FollowDynamicEntity;
|
||||
import com.gh.gamecenter.entity.FollowUserEntity;
|
||||
@ -107,6 +108,7 @@ import com.gh.gamecenter.feature.entity.BackgroundImageEntity;
|
||||
import com.gh.gamecenter.feature.entity.CommentEntity;
|
||||
import com.gh.gamecenter.feature.entity.CommentnumEntity;
|
||||
import com.gh.gamecenter.feature.entity.ConcernEntity;
|
||||
import com.gh.gamecenter.feature.entity.FloatingWindowEntity;
|
||||
import com.gh.gamecenter.feature.entity.ForumVideoEntity;
|
||||
import com.gh.gamecenter.feature.entity.GameEntity;
|
||||
import com.gh.gamecenter.feature.entity.LibaoEntity;
|
||||
@ -126,7 +128,6 @@ import com.gh.gamecenter.feature.entity.SimulatorEntity;
|
||||
import com.gh.gamecenter.feature.entity.UserEntity;
|
||||
import com.gh.gamecenter.feature.entity.ViewsEntity;
|
||||
import com.gh.gamecenter.feature.entity.WXSubscribeMsgConfig;
|
||||
import com.gh.gamecenter.feature.entity.FloatingWindowEntity;
|
||||
import com.gh.gamecenter.gamedetail.entity.BigEvent;
|
||||
import com.gh.gamecenter.gamedetail.entity.NewGameDetailEntity;
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageData;
|
||||
@ -3358,7 +3359,7 @@ public interface ApiService {
|
||||
* 页面数据聚合[底部tab+多tab导航页+默认数据]
|
||||
*/
|
||||
@GET("app/data_union")
|
||||
Single<DataUnionEntity> getDataUnion();
|
||||
Single<DataUnionEntity> getDataUnion(@Query("diverter") String diverter);
|
||||
|
||||
/**
|
||||
* 底部tab
|
||||
@ -3390,4 +3391,16 @@ public interface ApiService {
|
||||
*/
|
||||
@GET("game_lists/hot_columns")
|
||||
Single<List<SubjectEntity>> getHotColumns();
|
||||
|
||||
/**
|
||||
* 分流器列表信息
|
||||
*/
|
||||
@GET("app/{module}/diverter")
|
||||
Single<List<DiverterEntity>> getDiverterList(@Header("Install-First-Access") String isInstallFirstAccess, @Path("module") String module);
|
||||
|
||||
/**
|
||||
* 访问分流页面,更新分流访问次数
|
||||
*/
|
||||
@PATCH("app/{module}/diverter_visit_time")
|
||||
Single<ResponseBody> patchDiverterVisitTime(@Path("module") String module, @Body RequestBody body);
|
||||
}
|
||||
@ -9,20 +9,18 @@ import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import com.gh.gamecenter.R
|
||||
import com.gh.gamecenter.common.base.fragment.LazyFragment
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.constant.EntranceConsts
|
||||
import com.gh.gamecenter.common.utils.*
|
||||
import com.gh.gamecenter.common.view.BugFixedPopupWindow
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.core.utils.doOnEnd
|
||||
import com.gh.gamecenter.core.utils.doOnStart
|
||||
import com.gh.gamecenter.databinding.FragmentGameServerTestV2Binding
|
||||
import com.gh.gamecenter.databinding.LayoutGameServerTestV2SettingBinding
|
||||
import com.gh.gamecenter.databinding.LayoutGameServerTestV2SettingGuideBinding
|
||||
import com.gh.gamecenter.feature.entity.PageLocation
|
||||
import com.gh.gamecenter.mygame.MyGameActivity
|
||||
|
||||
@ -70,7 +68,7 @@ class GameServerTestV2Fragment : LazyFragment() {
|
||||
if (SPUtils.getBoolean(Constants.SP_SHOW_GAME_SERVER_TEST_V2_SETTING_GUIDE, true)) {
|
||||
mBaseHandler.post {
|
||||
showSettingView {
|
||||
showGuidePopupWindow()
|
||||
showGuide()
|
||||
}
|
||||
}
|
||||
SPUtils.setBoolean(Constants.SP_SHOW_GAME_SERVER_TEST_V2_SETTING_GUIDE, false)
|
||||
@ -293,6 +291,19 @@ class GameServerTestV2Fragment : LazyFragment() {
|
||||
}.start()
|
||||
}
|
||||
|
||||
private fun showGuide() {
|
||||
mBinding?.settingGuideContainer?.setOnClickListener {
|
||||
dismissGuide()
|
||||
}
|
||||
mBinding?.settingGuideContainer?.isVisible = true
|
||||
}
|
||||
|
||||
private fun dismissGuide() {
|
||||
mBinding?.settingGuideIv?.animate()?.alpha(0F)?.setDuration(200L)?.doOnEnd {
|
||||
mBinding?.settingGuideContainer?.isVisible = false
|
||||
}?.start()
|
||||
}
|
||||
|
||||
private fun getItemTextView(type: String): TextView {
|
||||
return TextView(requireContext()).apply {
|
||||
text = type
|
||||
@ -332,22 +343,11 @@ class GameServerTestV2Fragment : LazyFragment() {
|
||||
.commitAllowingStateLoss()
|
||||
}
|
||||
|
||||
private fun showGuidePopupWindow(): PopupWindow {
|
||||
val guideBinding = LayoutGameServerTestV2SettingGuideBinding.inflate(layoutInflater)
|
||||
return BugFixedPopupWindow(
|
||||
guideBinding.root,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT,
|
||||
FrameLayout.LayoutParams.WRAP_CONTENT
|
||||
).apply {
|
||||
isFocusable = true
|
||||
isTouchable = true
|
||||
isOutsideTouchable = true
|
||||
animationStyle = R.style.popup_window_ease_in_and_out_anim_style
|
||||
showAsDropDown(mBinding?.optionIv, 0, (-4F).dip2px())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed(): Boolean {
|
||||
if (mBinding?.settingGuideContainer?.isVisible == true) {
|
||||
dismissGuide()
|
||||
return true
|
||||
}
|
||||
if (mSettingBinding != null) {
|
||||
dismissSettingView()
|
||||
return true
|
||||
|
||||
@ -87,6 +87,11 @@ abstract class BaseBottomTabFragment<T : ViewBinding> : ToolbarFragment() {
|
||||
protected fun initViewPager() {
|
||||
mViewPager?.run {
|
||||
isUserInputEnabled = false
|
||||
// 去掉默认动画
|
||||
setPageTransformer { page, _ ->
|
||||
page.translationX = 0F
|
||||
page.alpha = 1F
|
||||
}
|
||||
adapter = provideAdapter()
|
||||
registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
|
||||
|
||||
@ -14,32 +14,45 @@ import com.gh.gamecenter.fragment.ReloadFragment
|
||||
|
||||
class MainFragmentStateAdapter(private val mFragment: Fragment) : BaseDiffFragmentStateAdapter<BottomTab>(mFragment) {
|
||||
override fun createFragment(data: BottomTab?, position: Int): Fragment {
|
||||
if (data != null) {
|
||||
val bundle = Bundle()
|
||||
val superiorChain = if (mFragment is ISuperiorChain) mFragment else null
|
||||
mFragment.arguments?.let { bundle.putAll(it) }
|
||||
if (data.link == null) return ReloadFragment()
|
||||
bundle.putBoolean(EntranceConsts.KEY_IS_HOME, true)
|
||||
bundle.putString(EntranceConsts.KEY_BOTTOM_TAB_ID, data.id)
|
||||
bundle.putString(EntranceConsts.KEY_BOTTOM_TAB_NAME, data.name)
|
||||
bundle.putInt(EntranceConsts.KEY_POSITION, position)
|
||||
bundle.putParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST, arrayListOf(ExposureSource("底部tab", data.name)))
|
||||
bundle.putBoolean(EntranceConsts.KEY_IS_FROM_MAIN_WRAPPER, true)
|
||||
return when (data.link.type) {
|
||||
if (data == null) return ReloadFragment()
|
||||
|
||||
val bundle = Bundle()
|
||||
val superiorChain = if (mFragment is ISuperiorChain) mFragment else null
|
||||
mFragment.arguments?.let { bundle.putAll(it) }
|
||||
bundle.putBoolean(EntranceConsts.KEY_IS_HOME, true)
|
||||
bundle.putString(EntranceConsts.KEY_BOTTOM_TAB_ID, data.id)
|
||||
bundle.putString(EntranceConsts.KEY_BOTTOM_TAB_NAME, data.name)
|
||||
bundle.putInt(EntranceConsts.KEY_POSITION, position)
|
||||
|
||||
val exposureSourceList = arrayListOf(ExposureSource("底部tab", data.name))
|
||||
data.diverter?.let {
|
||||
exposureSourceList.add(
|
||||
ExposureSource(
|
||||
"分流器",
|
||||
"${it.diverterData.diverterName}+${it.diverterData.diverterId}"
|
||||
)
|
||||
)
|
||||
}
|
||||
bundle.putParcelableArrayList(EntranceConsts.KEY_EXPOSURE_SOURCE_LIST, exposureSourceList)
|
||||
bundle.putBoolean(EntranceConsts.KEY_IS_FROM_MAIN_WRAPPER, true)
|
||||
return if (data.link == null) {
|
||||
ReloadFragment()
|
||||
} else {
|
||||
when (data.link!!.type) {
|
||||
ViewPagerFragmentHelper.TYPE_CUSTOM_PAGE -> {
|
||||
bundle.putParcelable(LinkEntity::class.java.simpleName, data.link)
|
||||
SearchToolbarTabWrapperFragment().setSuperiorChain(superiorChain).apply { arguments = bundle }
|
||||
}
|
||||
|
||||
ViewPagerFragmentHelper.TYPE_MULTI_TAB_NAV -> {
|
||||
bundle.putParcelable(BottomTab.SearchStyle::class.java.simpleName, data.searchStyle)
|
||||
bundle.putString(EntranceConsts.KEY_MULTI_TAB_NAV_ID, data.link.link)
|
||||
bundle.putString(EntranceConsts.KEY_MULTI_TAB_NAV_NAME, data.link.text)
|
||||
bundle.putString(EntranceConsts.KEY_MULTI_TAB_NAV_ID, data.link!!.link)
|
||||
bundle.putString(EntranceConsts.KEY_MULTI_TAB_NAV_NAME, data.link!!.text)
|
||||
SearchToolbarTabWrapperFragment().setSuperiorChain(superiorChain).apply { arguments = bundle }
|
||||
}
|
||||
else -> ViewPagerFragmentHelper.createFragment(mFragment, bundle, data.link, false)
|
||||
|
||||
else -> ViewPagerFragmentHelper.createFragment(mFragment, bundle, data.link!!, false)
|
||||
}
|
||||
} else {
|
||||
return ReloadFragment()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -80,8 +80,11 @@ class MainWrapperFragment : BaseBottomTabFragment<PieceBottomTabBinding>(), OnBa
|
||||
initBottomTab(mBottomTabList)
|
||||
showBottomTabGuideIfExists()
|
||||
mAdapter.submitList(mBottomTabList)
|
||||
val defaultBottomTabIndex = mViewModel!!.defaultBottomTabIndex
|
||||
val defaultBottomTab = mBottomTabList.getOrNull(defaultBottomTabIndex) ?: return@observe
|
||||
mViewPager?.doOnNextLayout {
|
||||
setCurrentItem(mViewModel!!.defaultBottomTabIndex)
|
||||
mViewModel?.handleBypassVisit(defaultBottomTab)
|
||||
setCurrentItem(defaultBottomTabIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -213,6 +216,9 @@ class MainWrapperFragment : BaseBottomTabFragment<PieceBottomTabBinding>(), OnBa
|
||||
if (bottomTab?.guide != null) {
|
||||
dismissBottomTabGuide()
|
||||
}
|
||||
bottomTab?.let {
|
||||
mViewModel?.handleBypassVisit(it)
|
||||
}
|
||||
playTabAnimation(toCheck)
|
||||
changeBottomTabStyle(toCheck)
|
||||
EventBus.getDefault().post(EBReuse(Constants.FINISH_PULL_DOWN_PUSH))
|
||||
|
||||
@ -3,14 +3,19 @@ package com.gh.gamecenter.wrapper
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.gh.common.util.HomeBottomBarHelper
|
||||
import com.gh.common.util.HomeBottomBarHelper.isDefaultHomeBottomTabDataExist
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.common.util.ViewPagerFragmentHelper
|
||||
import com.gh.gamecenter.common.constant.Constants
|
||||
import com.gh.gamecenter.common.entity.LaunchRedirect
|
||||
import com.gh.gamecenter.common.retrofit.BiResponse
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.core.utils.GsonUtils
|
||||
import com.gh.gamecenter.core.utils.SPUtils
|
||||
import com.gh.gamecenter.core.utils.SingletonHolder
|
||||
import com.gh.gamecenter.core.utils.TimeUtils
|
||||
import com.gh.gamecenter.entity.BottomTab
|
||||
import com.gh.gamecenter.entity.DataUnionEntity
|
||||
import com.gh.gamecenter.entity.DiverterEntity
|
||||
import com.gh.gamecenter.entity.MultiTabNav
|
||||
import com.gh.gamecenter.home.custom.model.CustomPageData
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
@ -21,6 +26,8 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.concurrent.TimeoutException
|
||||
|
||||
class MainWrapperRepository {
|
||||
private val mNewApi = RetrofitManager.getInstance().newApi
|
||||
@ -46,9 +53,17 @@ class MainWrapperRepository {
|
||||
val customPageLiveData = MutableLiveData<CustomPageData?>()
|
||||
val errorLiveData = MutableLiveData<Exception>()
|
||||
|
||||
val diverterList = arrayListOf<DiverterEntity>()
|
||||
|
||||
private val mTabSelectEventFlow = MutableSharedFlow<MainSelectedEvent>()
|
||||
val tabSelectEventFlow = mTabSelectEventFlow as SharedFlow<MainSelectedEvent>
|
||||
|
||||
fun init() {
|
||||
// 若 timeout 后数据未加载完成,则即便还没有回调也使用默认数据生成底部 tab
|
||||
emitDefaultTabDataAfterTimeout()
|
||||
getBypassList()
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送首次启动跳转事件的选中事件
|
||||
*/
|
||||
@ -133,16 +148,37 @@ class MainWrapperRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun getBypassList() {
|
||||
val isInstallFirstAccess = TimeUtils.isToday(SPUtils.getLong(Constants.SP_BRAND_NEW_FIRST_LAUNCH_TIME) / 1000).toString()
|
||||
mNewApi.getDiverterList(isInstallFirstAccess, BYPASS_TYPE_BOTTOM_TAB)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.timeout(BYPASS_TIME_OUT, TimeUnit.MILLISECONDS)
|
||||
.subscribe(object : BiResponse<List<DiverterEntity>>() {
|
||||
override fun onSuccess(data: List<DiverterEntity>) {
|
||||
diverterList.clear()
|
||||
diverterList.addAll(data)
|
||||
getDataUnion()
|
||||
}
|
||||
|
||||
override fun onFailure(exception: Exception) {
|
||||
super.onFailure(exception)
|
||||
getDataUnion()
|
||||
|
||||
val reasonString = if (exception is TimeoutException) "分流判断超时" else "分流页面返回为空"
|
||||
SensorsBridge.trackFailByPass("底部tab", "", "", reasonString)
|
||||
NewFlatLogUtils.logFailByPass("底部tab", "", "", reasonString)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
fun getDataUnion() {
|
||||
// 若历史 tab 数据存在,优先使用作为占位
|
||||
if (isDefaultHomeBottomTabDataExist()) {
|
||||
processBottomTabData(emptyList())
|
||||
} else {
|
||||
// 若 timeout 后数据未加载完成,则即便还没回调 onFailure 也生成两个底部 tab
|
||||
emitDefaultTabDataAfterTimeout()
|
||||
var diverter = ""
|
||||
diverterList.forEach {
|
||||
diverter += "${it.moduleIndex}:${it.diverterData.branchId},"
|
||||
}
|
||||
mNewApi.dataUnion
|
||||
mNewApi.getDataUnion(diverter)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe(object : BiResponse<DataUnionEntity>() {
|
||||
override fun onSuccess(data: DataUnionEntity) {
|
||||
@ -163,7 +199,9 @@ class MainWrapperRepository {
|
||||
|
||||
private fun processBottomTabData(bottomTabList: List<BottomTab>) {
|
||||
if (bottomTabList.isNotEmpty()) {
|
||||
HomeBottomBarHelper.updateDefaultHomeBottomTabData(bottomTabList)
|
||||
diverterList.forEach {
|
||||
bottomTabList.getOrNull(it.moduleIndex)?.diverter = it
|
||||
}
|
||||
|
||||
var preSelectedTab: BottomTab? = null
|
||||
|
||||
@ -206,11 +244,16 @@ class MainWrapperRepository {
|
||||
}
|
||||
}
|
||||
|
||||
HomeBottomBarHelper.updateDefaultHomeBottomTabData(bottomTabList)
|
||||
bottomTabListLiveData.postValue(bottomTabList)
|
||||
defaultNavId = bottomTabList.find { it.link?.type == ViewPagerFragmentHelper.TYPE_MULTI_TAB_NAV && it.default }?.link?.link ?: ""
|
||||
defaultCustomPageId = bottomTabList.find { it.link?.type == ViewPagerFragmentHelper.TYPE_CUSTOM_PAGE && it.default }?.link?.link ?: ""
|
||||
} else {
|
||||
HomeBottomBarHelper.getDefaultHomeBottomTabData().run {
|
||||
val defaultIndex = indexOfFirst { it.default }
|
||||
if (defaultIndex != -1) {
|
||||
defaultBottomTabIndex = defaultIndex
|
||||
}
|
||||
bottomTabListLiveData.postValue(this)
|
||||
defaultNavId = find { it.link?.type == ViewPagerFragmentHelper.TYPE_MULTI_TAB_NAV && it.default }?.link?.link ?: ""
|
||||
defaultCustomPageId = find { it.link?.type == ViewPagerFragmentHelper.TYPE_CUSTOM_PAGE && it.default }?.link?.link ?: ""
|
||||
@ -248,7 +291,10 @@ class MainWrapperRepository {
|
||||
}
|
||||
}
|
||||
|
||||
companion object : SingletonHolder<MainWrapperRepository>({ MainWrapperRepository() })
|
||||
companion object : SingletonHolder<MainWrapperRepository>({ MainWrapperRepository() }) {
|
||||
private const val BYPASS_TIME_OUT = 1000L
|
||||
const val BYPASS_TYPE_BOTTOM_TAB = "bottom_tab"
|
||||
}
|
||||
}
|
||||
|
||||
sealed class MainSelectedEvent {
|
||||
|
||||
@ -1,15 +1,22 @@
|
||||
package com.gh.gamecenter.wrapper
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.*
|
||||
import com.gh.common.util.CheckLoginUtils
|
||||
import com.gh.common.util.NewFlatLogUtils
|
||||
import com.gh.common.util.RealNameHelper
|
||||
import com.gh.gamecenter.common.retrofit.Response
|
||||
import com.gh.gamecenter.common.utils.SensorsBridge
|
||||
import com.gh.gamecenter.common.utils.singleToMain
|
||||
import com.gh.gamecenter.common.utils.toRequestBody
|
||||
import com.gh.gamecenter.entity.BottomTab
|
||||
import com.gh.gamecenter.entity.DiverterEntity
|
||||
import com.gh.gamecenter.feature.entity.GameEntity
|
||||
import com.gh.gamecenter.livedata.Event
|
||||
import com.gh.gamecenter.login.user.UserManager
|
||||
import com.gh.gamecenter.retrofit.RetrofitManager
|
||||
import com.lightgame.utils.Utils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.flow.map
|
||||
@ -23,6 +30,7 @@ import retrofit2.HttpException
|
||||
class MainWrapperViewModel(application: Application, private val mRepository: MainWrapperRepository) :
|
||||
AndroidViewModel(application) {
|
||||
private val mApi = RetrofitManager.getInstance().api
|
||||
private val mNewApi = RetrofitManager.getInstance().newApi
|
||||
|
||||
val defaultBottomTabIndex
|
||||
get() = mRepository.defaultBottomTabIndex
|
||||
@ -45,6 +53,8 @@ class MainWrapperViewModel(application: Application, private val mRepository: Ma
|
||||
|
||||
val bottomDoubleTabAction = MutableLiveData<BottomTab>()
|
||||
|
||||
private val byPassVisitBottomTabIdSet = hashSetOf<String>()
|
||||
|
||||
/**
|
||||
* 请求各种弹窗的数据
|
||||
*/
|
||||
@ -91,6 +101,58 @@ class MainWrapperViewModel(application: Application, private val mRepository: Ma
|
||||
})
|
||||
}
|
||||
|
||||
fun handleBypassVisit(bottomTab: BottomTab) {
|
||||
if (byPassVisitBottomTabIdSet.contains(bottomTab.id)) return
|
||||
|
||||
bottomTab.diverter?.let {
|
||||
val source = "底部tab:${bottomTab.name}"
|
||||
SensorsBridge.trackByPassBrowsing(
|
||||
source,
|
||||
it.diverterData.diverterName,
|
||||
it.diverterData.diverterId,
|
||||
it.diverterData.branchId,
|
||||
it.diverterData.branchName,
|
||||
it.diverterData.inprocessTime,
|
||||
it.diverterData.bypassVisitTime,
|
||||
it.diverterData.linkType,
|
||||
it.diverterData.linkId,
|
||||
it.diverterData.linkText,
|
||||
it.diverterData.bypassStatus,
|
||||
)
|
||||
NewFlatLogUtils.logByPassBrowsing(
|
||||
source,
|
||||
it.diverterData.diverterName,
|
||||
it.diverterData.diverterId,
|
||||
it.diverterData.branchId,
|
||||
it.diverterData.branchName,
|
||||
it.diverterData.inprocessTime,
|
||||
it.diverterData.bypassVisitTime,
|
||||
it.diverterData.linkType,
|
||||
it.diverterData.linkId,
|
||||
it.diverterData.linkText,
|
||||
it.diverterData.bypassStatus,
|
||||
)
|
||||
patchBypassVisitTime(it)
|
||||
byPassVisitBottomTabIdSet.add(bottomTab.id)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private fun patchBypassVisitTime(diverterEntity: DiverterEntity) {
|
||||
val data = mapOf(
|
||||
"module_id" to diverterEntity.moduleId,
|
||||
"diverter_id" to diverterEntity.diverterData.diverterId,
|
||||
"branch_type" to diverterEntity.diverterData.branchType
|
||||
)
|
||||
mNewApi.patchDiverterVisitTime(MainWrapperRepository.BYPASS_TYPE_BOTTOM_TAB, data.toRequestBody())
|
||||
.compose(singleToMain())
|
||||
.subscribe({
|
||||
Utils.log(TAG, "patchDiverterVisitTime onSuccess: ${it.string()}")
|
||||
}, {
|
||||
Utils.log(TAG, "patchDiverterVisitTime onError: ${it.message}")
|
||||
})
|
||||
}
|
||||
|
||||
class Factory(
|
||||
private val mApplication: Application,
|
||||
) : ViewModelProvider.NewInstanceFactory() {
|
||||
@ -100,6 +162,7 @@ class MainWrapperViewModel(application: Application, private val mRepository: Ma
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "MainWrapperViewModel"
|
||||
const val SHOULD_SHOW_OPENING_DIALOG = "show_opening_dialog"
|
||||
}
|
||||
}
|
||||
@ -369,7 +369,7 @@ public class HaloApp extends MultiDexApplication {
|
||||
|
||||
GlobalPriorityChainHelper.INSTANCE.preStart(isNewForThisVersion);
|
||||
|
||||
MainWrapperRepository.Companion.getInstance().getDataUnion();
|
||||
MainWrapperRepository.Companion.getInstance().init();
|
||||
|
||||
// QQ小游戏开放互联初始化
|
||||
IQGameProvider provider = (IQGameProvider) ARouter
|
||||
|
||||
Reference in New Issue
Block a user