From 7ec9bf08e2572ab8a75db0336e2af960dfd110c2 Mon Sep 17 00:00:00 2001 From: chenjuntao Date: Mon, 22 Jan 2024 17:31:54 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20APP=E5=86=85=E5=AE=B9=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E9=87=8D=E6=9E=84-=E9=99=84=E5=B1=9E=E9=9C=80=E6=B1=82:?= =?UTF-8?q?=E5=BC=B9=E7=AA=97=E9=A1=BA=E5=BA=8F=20https://jira.shanqu.cc/b?= =?UTF-8?q?rowse/GHZS-4086?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AccelerateNotificationHandler.kt | 2 +- .../CustomFloatingWindowHandler.kt | 2 +- .../prioritychain/FloatingWindowHandler.kt | 2 +- .../GlobalPriorityChainHelper.kt | 13 +- .../common/prioritychain/HomePushHandler.kt | 2 +- .../prioritychain/LaunchRedirectHandler.kt | 15 ++- .../gh/common/prioritychain/PriorityChain.kt | 7 +- .../prioritychain/PriorityChainHandler.kt | 17 ++- .../PrivacyPolicyDialogHandler.kt | 2 +- .../prioritychain/ReserveDialogHandler.kt | 2 +- .../prioritychain/UpdateDialogHandler.kt | 2 +- .../prioritychain/WelcomeDialogHandler.kt | 2 +- .../java/com/gh/common/util/DirectUtils.kt | 6 +- .../com/gh/gamecenter/entity/BottomTab.kt | 2 +- .../com/gh/gamecenter/entity/MultiTabNav.kt | 2 +- .../gamecenter/wrapper/MainWrapperFragment.kt | 11 ++ .../wrapper/MainWrapperRepository.kt | 114 +++++++++++++++++- .../wrapper/MainWrapperViewModel.kt | 21 ++-- .../SearchToolbarTabWrapperFragment.kt | 13 +- .../SearchToolbarTabWrapperViewModel.kt | 31 ++++- .../gamecenter/wrapper/TabWrapperViewModel.kt | 16 ++- .../main/java/com/halo/assistant/HaloApp.java | 3 + .../common/entity/LaunchRedirect.kt | 8 +- module_core/build.gradle | 1 + 24 files changed, 250 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/com/gh/common/prioritychain/AccelerateNotificationHandler.kt b/app/src/main/java/com/gh/common/prioritychain/AccelerateNotificationHandler.kt index f8eb37a2de..5683c92f5a 100644 --- a/app/src/main/java/com/gh/common/prioritychain/AccelerateNotificationHandler.kt +++ b/app/src/main/java/com/gh/common/prioritychain/AccelerateNotificationHandler.kt @@ -42,7 +42,7 @@ class AccelerateNotificationHandler(priority: Int) : PriorityChainHandler(priori processNext() } else { updateStatus(STATUS_VALID) - onProcess() + process() } } else { if (gameEntityList == null) { diff --git a/app/src/main/java/com/gh/common/prioritychain/CustomFloatingWindowHandler.kt b/app/src/main/java/com/gh/common/prioritychain/CustomFloatingWindowHandler.kt index 3d8bffabac..d3b85942f5 100644 --- a/app/src/main/java/com/gh/common/prioritychain/CustomFloatingWindowHandler.kt +++ b/app/src/main/java/com/gh/common/prioritychain/CustomFloatingWindowHandler.kt @@ -30,7 +30,7 @@ class CustomFloatingWindowHandler(priority: Int) : PriorityChainHandler(priority if (getStatus() == STATUS_PENDING) { if (data.isNotEmpty()) { updateStatus(STATUS_VALID) - onProcess() + process() } else { processNext() } diff --git a/app/src/main/java/com/gh/common/prioritychain/FloatingWindowHandler.kt b/app/src/main/java/com/gh/common/prioritychain/FloatingWindowHandler.kt index 4e392b2446..dd6ac401cf 100644 --- a/app/src/main/java/com/gh/common/prioritychain/FloatingWindowHandler.kt +++ b/app/src/main/java/com/gh/common/prioritychain/FloatingWindowHandler.kt @@ -42,7 +42,7 @@ class FloatingWindowHandler(priority: Int) : PriorityChainHandler(priority) { if (getStatus() == STATUS_PENDING) { if (!mWindowList.isNullOrEmpty()) { updateStatus(STATUS_VALID) - onProcess() + process() } else { processNext() } diff --git a/app/src/main/java/com/gh/common/prioritychain/GlobalPriorityChainHelper.kt b/app/src/main/java/com/gh/common/prioritychain/GlobalPriorityChainHelper.kt index 95e8bd782d..1db9f8e82c 100644 --- a/app/src/main/java/com/gh/common/prioritychain/GlobalPriorityChainHelper.kt +++ b/app/src/main/java/com/gh/common/prioritychain/GlobalPriorityChainHelper.kt @@ -45,11 +45,9 @@ object GlobalPriorityChainHelper : ISuperiorChain { } /** - * 启动优先级弹窗管理链的执行 + * 预启动所有的优先级弹窗管理链 */ - fun start() { - if (!mainChain.isHandlerQueueEmpty()) return - + fun preStart() { val launchRedirectHandler = LaunchRedirectHandler(-101) val updateDialogHandler = UpdateDialogHandler(-100) val privacyPolicyDialogHandler = PrivacyPolicyDialogHandler(-99) @@ -68,6 +66,13 @@ object GlobalPriorityChainHelper : ISuperiorChain { updateDialogHandler.doPreProcess() requestOpeningDialogData(welcomeDialogHandler, privacyPolicyDialogHandler) requestReserveDialogData(reserveDialogHandler) + } + + /** + * 启动优先级弹窗管理链的执行 + */ + fun start() { + if (mainChain.isHandlerQueueEmpty()) return mainChain.start() diff --git a/app/src/main/java/com/gh/common/prioritychain/HomePushHandler.kt b/app/src/main/java/com/gh/common/prioritychain/HomePushHandler.kt index 753fb5007a..0af19a8aa1 100644 --- a/app/src/main/java/com/gh/common/prioritychain/HomePushHandler.kt +++ b/app/src/main/java/com/gh/common/prioritychain/HomePushHandler.kt @@ -15,7 +15,7 @@ class HomePushHandler(priority: Int): PriorityChainHandler(priority) { if (getStatus() == STATUS_PENDING) { if (shouldShow && smartRefreshFragment != null) { updateStatus(STATUS_VALID) - onProcess() + process() } else { processNext() } diff --git a/app/src/main/java/com/gh/common/prioritychain/LaunchRedirectHandler.kt b/app/src/main/java/com/gh/common/prioritychain/LaunchRedirectHandler.kt index 9d2ebfcba5..5f43413ac2 100644 --- a/app/src/main/java/com/gh/common/prioritychain/LaunchRedirectHandler.kt +++ b/app/src/main/java/com/gh/common/prioritychain/LaunchRedirectHandler.kt @@ -10,6 +10,7 @@ import com.gh.gamecenter.common.utils.singleToMain import com.gh.gamecenter.core.AppExecutor import com.gh.gamecenter.core.utils.CurrentActivityHolder import com.gh.gamecenter.retrofit.RetrofitManager +import com.gh.gamecenter.wrapper.MainWrapperRepository import com.halo.assistant.HaloApp /** @@ -21,6 +22,7 @@ class LaunchRedirectHandler(priority: Int) : PriorityChainHandler(priority) { @SuppressLint("CheckResult") fun doPreProcess() { +// if (true) { if (HaloApp.getInstance().isBrandNewInstall) { RetrofitManager.getInstance().newApi .getLaunchRedirect(BuildConfig.VERSION_NAME, HaloApp.getInstance().channel) @@ -29,9 +31,20 @@ class LaunchRedirectHandler(priority: Int) : PriorityChainHandler(priority) { override fun onSuccess(data: LaunchRedirectWrapper) { launchData = data.launchRedirect + if (launchData == null) { + updateStatus(STATUS_INVALID) + processNext() + return + } + + // 提前设置 tab default 避免首页数据加载完成,tab 选中会闪烁 + if (launchData?.type == "bottom_tab") { + MainWrapperRepository.getInstance().sendSelectMainTabEvent(launchData!!) + } + if (getStatus() == STATUS_PENDING) { updateStatus(STATUS_VALID) - onProcess() + process() } else { updateStatus(STATUS_VALID) } diff --git a/app/src/main/java/com/gh/common/prioritychain/PriorityChain.kt b/app/src/main/java/com/gh/common/prioritychain/PriorityChain.kt index c4b6516ba1..41dd5c7f5e 100644 --- a/app/src/main/java/com/gh/common/prioritychain/PriorityChain.kt +++ b/app/src/main/java/com/gh/common/prioritychain/PriorityChain.kt @@ -21,7 +21,10 @@ class PriorityChain(private val completeCallback: (() -> Unit)? = null) { * 启动队列中的 handler */ fun start() { - handlerQueue.peek()?.process(handlerQueue) + handlerQueue.peek()?.let { + it.injectQueue(handlerQueue) + it.process() + } } /** @@ -33,7 +36,7 @@ class PriorityChain(private val completeCallback: (() -> Unit)? = null) { if (handler?.getStatus() == PriorityChainHandler.STATUS_HANDLING) { Utils.log(PriorityChainHandler.TAG, "${handler.javaClass.simpleName} 处于执行中状态,不用恢复") } else { - handler?.onProcess() + handler?.process() } } diff --git a/app/src/main/java/com/gh/common/prioritychain/PriorityChainHandler.kt b/app/src/main/java/com/gh/common/prioritychain/PriorityChainHandler.kt index 891e0da394..cebb09330c 100644 --- a/app/src/main/java/com/gh/common/prioritychain/PriorityChainHandler.kt +++ b/app/src/main/java/com/gh/common/prioritychain/PriorityChainHandler.kt @@ -30,15 +30,23 @@ abstract class PriorityChainHandler(private val mPriority: Int) : Comparable) { + fun injectQueue(queue: Queue) { + this.queue = queue + } + + fun process() { Utils.log(TAG, "${javaClass.simpleName} process $status") - this.queue = queue // 若当前 handler 未经处理,将其状态改为 pending if (status == STATUS_UNKNOWN) { updateStatus(STATUS_PENDING) } + if (status == STATUS_HANDLING) { + Utils.log(TAG, "${javaClass.simpleName} 已经处于执行中状态,不用再次执行") + return + } + val isHandling = onProcess() if (isHandling) { @@ -62,7 +70,10 @@ abstract class PriorityChainHandler(private val mPriority: Int) : Comparable { - // TODO 通知首页选中具体指定 tab val intent = Intent(context, MainActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_CLEAR_TOP } context.startActivity(intent) + + if (linkEntity is LaunchRedirect) { + MainWrapperRepository.getInstance().sendSelectMainTabEvent(linkEntity) + } } "" -> { diff --git a/app/src/main/java/com/gh/gamecenter/entity/BottomTab.kt b/app/src/main/java/com/gh/gamecenter/entity/BottomTab.kt index ec32226e41..be1399705f 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/BottomTab.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/BottomTab.kt @@ -23,7 +23,7 @@ data class BottomTab( @SerializedName("search_style") val searchStyle: SearchStyle = SearchStyle(), // 搜索样式 @SerializedName("is_default_page") - val default: Boolean = false, // 是否为默认显示页 + var default: Boolean = false, // 是否为默认显示页 var isTransparentStyle: Boolean = false // 本地字段,透明底部Tab ): Parcelable { @Parcelize diff --git a/app/src/main/java/com/gh/gamecenter/entity/MultiTabNav.kt b/app/src/main/java/com/gh/gamecenter/entity/MultiTabNav.kt index 40eb368db2..48aba480ad 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/MultiTabNav.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/MultiTabNav.kt @@ -18,7 +18,7 @@ data class MultiTabNav( @SerializedName("tab_show_img") var showImgOnSelected: Boolean? = false, // 选中时是否显示图片 @SerializedName("is_default_page") - val default: Boolean = false, // 是否为默认显示页 + var default: Boolean = false, // 是否为默认显示页 val link: LinkEntity? = null, // 通用链接 // 本地字段 diff --git a/app/src/main/java/com/gh/gamecenter/wrapper/MainWrapperFragment.kt b/app/src/main/java/com/gh/gamecenter/wrapper/MainWrapperFragment.kt index 37aae89dc9..a7217c854c 100644 --- a/app/src/main/java/com/gh/gamecenter/wrapper/MainWrapperFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/wrapper/MainWrapperFragment.kt @@ -66,6 +66,17 @@ class MainWrapperFragment : BaseBottomTabFragment(), OnBa } } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + mViewModel?.tabSelectedLiveData?.observe(viewLifecycleOwner) { + val selectedTab = it.getContentWithHandled() + if (selectedTab is MainSelectedEvent.SelectedTab && selectedTab.bottomTabIndex != -1) { + setCurrentItem(selectedTab.bottomTabIndex) + } + } + } + fun setCurrentItem(page: Int) { if (page < mBottomTabList.size) { mViewPager?.setCurrentItem(page, false) diff --git a/app/src/main/java/com/gh/gamecenter/wrapper/MainWrapperRepository.kt b/app/src/main/java/com/gh/gamecenter/wrapper/MainWrapperRepository.kt index 841e2ba6cc..4e93045db6 100644 --- a/app/src/main/java/com/gh/gamecenter/wrapper/MainWrapperRepository.kt +++ b/app/src/main/java/com/gh/gamecenter/wrapper/MainWrapperRepository.kt @@ -3,6 +3,7 @@ package com.gh.gamecenter.wrapper import android.annotation.SuppressLint import androidx.lifecycle.MutableLiveData import com.gh.common.util.HomeBottomBarHelper +import com.gh.gamecenter.common.entity.LaunchRedirect import com.gh.gamecenter.common.retrofit.BiResponse import com.gh.gamecenter.common.utils.singleToMain import com.gh.gamecenter.core.utils.SingletonHolder @@ -10,9 +11,18 @@ import com.gh.gamecenter.entity.* import com.gh.gamecenter.home.custom.model.CustomPageData import com.gh.gamecenter.home.custom.model.CustomPageItem import com.gh.gamecenter.retrofit.RetrofitManager +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.launch class MainWrapperRepository { private val mNewApi = RetrofitManager.getInstance().newApi + private var mIsMainDataReceived = false // 首页数据是否已加载 + + private var mHighPrioritySelectedBottomTabId = "" // 首页底部 tab 选中的id (优先级比 default 高) + private var mHighPrioritySelectedTopTabId = "" // 首页顶部 tab 选中的id (优先级比 default 高) var defaultNavId = "" var defaultCustomPageId = "" @@ -23,12 +33,60 @@ class MainWrapperRepository { val customPageLiveData = MutableLiveData() val errorLiveData = MutableLiveData() + private val mTabSelectEventFlow = MutableSharedFlow() + val tabSelectEventFlow = mTabSelectEventFlow as SharedFlow + + /** + * 发送首页子页面选中事件 + */ + fun sendSelectMainTabEvent(launchRedirect: LaunchRedirect) { + if (!mIsMainDataReceived) { + mHighPrioritySelectedBottomTabId = launchRedirect.link ?: "" + mHighPrioritySelectedTopTabId = launchRedirect.topTabLink?.link ?: "" + } else { + CoroutineScope(SupervisorJob()).launch { + val bottomTabIndex = bottomTabListLiveData.value?.indexOfFirst { + it.id == launchRedirect.link + } ?: -1 + val topTabIndex = multiTabNavLiveData.value?.linkMultiTabNav?.indexOfFirst { + it.id == launchRedirect.topTabLink?.link + } ?: -1 + mTabSelectEventFlow.emit( + MainSelectedEvent.SelectedTab( + bottomTabIndex = bottomTabIndex, + navTabId = launchRedirect.navTabLink?.link ?: "", + topTabIndex = topTabIndex, + topTabId = launchRedirect.topTabLink?.link ?: "" + ) + ) + } + } + } + + /** + * 发送首页子页面选中事件 + * @param bottomTabIndex 底部 tab 选中的 index + * @param topTabIndex 顶部 tab 选中的 index + */ + fun sendSelectMainTabEvent(bottomTabIndex: Int, topTabIndex: Int) { + CoroutineScope(SupervisorJob()).launch { + mTabSelectEventFlow.emit( + MainSelectedEvent.SelectedTab( + bottomTabIndex = bottomTabIndex, + topTabIndex = topTabIndex + ) + ) + } + } + @SuppressLint("CheckResult") fun getDataUnion() { mNewApi.dataUnion .compose(singleToMain()) .subscribe(object : BiResponse() { override fun onSuccess(data: DataUnionEntity) { + mIsMainDataReceived = true + processBottomTabData(data.bottomTab) processMultiTabData(data.multiTabNav) customPageLiveData.postValue(data.customPage?.apply { @@ -59,6 +117,23 @@ class MainWrapperRepository { private fun processBottomTabData(bottomTabList: List) { if (bottomTabList.isNotEmpty()) { + HomeBottomBarHelper.updateDefaultHomeBottomTabData(bottomTabList) + + // 如果有优先级更高的选中 tab id,则将优先级更高的选中 tab 设置为 default + if (mHighPrioritySelectedBottomTabId.isNotEmpty()) { + val selectedTab = bottomTabList.firstOrNull { + it.id == mHighPrioritySelectedBottomTabId + } + + // 将优先级更高的选中 tab 设置为 default + if (selectedTab != null) { + bottomTabList.forEach { it.default = false } + selectedTab.default = true + } + + mHighPrioritySelectedBottomTabId = "" + } + bottomTabList.forEachIndexed { index, bottomTab -> if (bottomTab.default) { defaultBottomTabIndex = index @@ -67,7 +142,7 @@ class MainWrapperRepository { bottomTab.isTransparentStyle = true } } - HomeBottomBarHelper.updateDefaultHomeBottomTabData(bottomTabList) + bottomTabListLiveData.postValue(bottomTabList) defaultNavId = bottomTabList.find { it.link?.type == "multi_tab_nav" && it.default }?.link?.link ?: "" defaultCustomPageId = bottomTabList.find { it.link?.type == "custom_page" && it.default }?.link?.link ?: "" @@ -81,12 +156,45 @@ class MainWrapperRepository { } private fun processMultiTabData(multiTabNav: MultiTabNav?) { - defaultCustomPageId = multiTabNav?.linkMultiTabNav?.find { it.link?.type == "custom_page" && it.default }?.link?.link ?: "" + // 如果有优先级更高的选中 tab id,则将优先级更高的选中 tab 设置为 default + if (mHighPrioritySelectedTopTabId.isNotEmpty()) { + val selectedTab = multiTabNav?.linkMultiTabNav?.firstOrNull { + it.link?.link == mHighPrioritySelectedTopTabId + } + + // 将优先级更高的选中 tab 设置为 default + if (selectedTab != null) { + multiTabNav.linkMultiTabNav.forEach { it.default = false } + selectedTab.default = true + } + + mHighPrioritySelectedTopTabId = "" + } + + defaultCustomPageId = + multiTabNav?.linkMultiTabNav?.find { it.link?.type == "custom_page" && it.default }?.link?.link ?: "" multiTabNavLiveData.postValue(multiTabNav) } - companion object : SingletonHolder({ MainWrapperRepository() }) { const val TYPE_TAB_VIDEO = "video_stream" } +} + +sealed class MainSelectedEvent { + + /** + * 首页子页面选中 + * @param bottomTabIndex 首页底部 tab 选中的 index + * @param navTabId 首页顶部 tab 的 id + * @param topTabIndex 首页顶部 tab 选中的 index + * @param topTabId 首页顶部 tab 的 id + */ + data class SelectedTab( + val bottomTabIndex: Int = -1, + val navTabId: String = "", + val topTabIndex: Int = -1, + val topTabId: String = "" + ) : MainSelectedEvent() + } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/wrapper/MainWrapperViewModel.kt b/app/src/main/java/com/gh/gamecenter/wrapper/MainWrapperViewModel.kt index 1ef02f11e7..b8e15a101c 100644 --- a/app/src/main/java/com/gh/gamecenter/wrapper/MainWrapperViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/wrapper/MainWrapperViewModel.kt @@ -1,22 +1,17 @@ package com.gh.gamecenter.wrapper import android.app.Application -import androidx.lifecycle.AndroidViewModel -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import com.alibaba.android.arouter.launcher.ARouter +import androidx.lifecycle.* import com.gh.common.util.CheckLoginUtils -import com.gh.gamecenter.common.constant.RouteConsts import com.gh.gamecenter.common.retrofit.Response -import com.gh.gamecenter.core.provider.IFloatingWindowProvider import com.gh.gamecenter.feature.entity.GameEntity -import com.gh.gamecenter.feature.entity.WelcomeDialogEntity -import com.gh.gamecenter.floatingwindow.FloatingWindowEntity +import com.gh.gamecenter.livedata.Event import com.gh.gamecenter.login.user.UserManager import com.gh.gamecenter.retrofit.RetrofitManager import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.transformWhile import okhttp3.MediaType import okhttp3.RequestBody import okhttp3.ResponseBody @@ -35,6 +30,14 @@ class MainWrapperViewModel(application: Application, private val mRepository: Ma val accelerateNotificationPopup = MutableLiveData?>() + val tabSelectedLiveData = mRepository.tabSelectEventFlow + .map { it as? MainSelectedEvent.SelectedTab } + .transformWhile { originalEvent -> + emit(Event(originalEvent)) + true + } + .asLiveData() + /** * 请求各种弹窗的数据 */ diff --git a/app/src/main/java/com/gh/gamecenter/wrapper/SearchToolbarTabWrapperFragment.kt b/app/src/main/java/com/gh/gamecenter/wrapper/SearchToolbarTabWrapperFragment.kt index 32fc627190..7116ff43eb 100644 --- a/app/src/main/java/com/gh/gamecenter/wrapper/SearchToolbarTabWrapperFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/wrapper/SearchToolbarTabWrapperFragment.kt @@ -458,6 +458,15 @@ class SearchToolbarTabWrapperFragment : BaseTabWrapperFragment(), ISmartRefresh, } initNoTabViewPager() } + + mViewModel.tabSelectLiveData.observe(viewLifecycleOwner) { + val selectTab = it.getContentWithHandled() + if (selectTab is MainSelectedEvent.SelectedTab) { + if (selectTab.topTabIndex != -1) { + mViewPager?.setCurrentItem(selectTab.topTabIndex, false) + } + } + } } override fun hideTab() { @@ -1074,7 +1083,9 @@ class SearchToolbarTabWrapperFragment : BaseTabWrapperFragment(), ISmartRefresh, @Subscribe(threadMode = ThreadMode.MAIN) fun onEventMainThread(status: EBDownloadStatus) { - setDownloadHint(mPackageViewModel.filterSameUpdateLiveData.value!!) + mPackageViewModel.filterSameUpdateLiveData.value?.let { + setDownloadHint(it) + } // 下载被删除事件 if ("delete" == status.status) { if (status.gameId == mPullDownPush?.game?.id) { diff --git a/app/src/main/java/com/gh/gamecenter/wrapper/SearchToolbarTabWrapperViewModel.kt b/app/src/main/java/com/gh/gamecenter/wrapper/SearchToolbarTabWrapperViewModel.kt index 7bf334b5f5..dcdf82f219 100644 --- a/app/src/main/java/com/gh/gamecenter/wrapper/SearchToolbarTabWrapperViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/wrapper/SearchToolbarTabWrapperViewModel.kt @@ -1,11 +1,12 @@ package com.gh.gamecenter.wrapper import android.app.Application -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.* import com.gh.gamecenter.common.utils.safelyGetInRelease import com.gh.gamecenter.entity.MultiTabNav +import com.gh.gamecenter.livedata.Event import com.halo.assistant.HaloApp +import kotlinx.coroutines.flow.* class SearchToolbarTabWrapperViewModel( application: Application, @@ -16,9 +17,31 @@ class SearchToolbarTabWrapperViewModel( var noTabStyle = MultiTabNav.LinkMultiTabNav.TabStyle() var appBarOffset = 0 - fun isTabCustomPage(position: Int) = tabListLiveData.value?.safelyGetInRelease(position)?.link?.type == "custom_page" || noTabLinkId.isNotEmpty() + val tabSelectLiveData = + repository.tabSelectEventFlow + .map { it as? MainSelectedEvent.SelectedTab } + .transformWhile { originalEvent -> + if (originalEvent?.navTabId == multiTabNavId) { + if (originalEvent.topTabIndex == -1 && originalEvent.topTabId.isNotEmpty()) { + multiTabLoadedFlow.receiveAsFlow().collect { tabList -> + val newTopTabIndex = tabList.indexOfFirst { + it.id == originalEvent.topTabId + } + emit(Event(MainSelectedEvent.SelectedTab(topTabIndex = newTopTabIndex))) + } + } else { + emit(Event(originalEvent)) + } + } + true + } + .asLiveData() - fun getCustomPageTabEntity(pageId: String): MultiTabNav.LinkMultiTabNav? = tabListLiveData.value?.find { it.link?.type == "custom_page" && it.link.link == pageId } + fun isTabCustomPage(position: Int) = + tabListLiveData.value?.safelyGetInRelease(position)?.link?.type == "custom_page" || noTabLinkId.isNotEmpty() + + fun getCustomPageTabEntity(pageId: String): MultiTabNav.LinkMultiTabNav? = + tabListLiveData.value?.find { it.link?.type == "custom_page" && it.link.link == pageId } fun enableSlideBackgroundColor(pageId: String, isSlideBackgroundColorEnable: Boolean) { if (multiTabNavId.isNotEmpty()) { diff --git a/app/src/main/java/com/gh/gamecenter/wrapper/TabWrapperViewModel.kt b/app/src/main/java/com/gh/gamecenter/wrapper/TabWrapperViewModel.kt index 21b53f2dec..b1c85e1094 100644 --- a/app/src/main/java/com/gh/gamecenter/wrapper/TabWrapperViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/wrapper/TabWrapperViewModel.kt @@ -2,16 +2,16 @@ package com.gh.gamecenter.wrapper import android.annotation.SuppressLint import android.app.Application -import androidx.lifecycle.AndroidViewModel -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.* import com.gh.gamecenter.R import com.gh.gamecenter.common.utils.singleToMain import com.gh.gamecenter.common.utils.toColor import com.gh.gamecenter.entity.MultiTabNav import com.gh.gamecenter.retrofit.RetrofitManager import com.halo.assistant.HaloApp +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch open class TabWrapperViewModel( application: Application, @@ -25,6 +25,8 @@ open class TabWrapperViewModel( val tabListLiveData = MutableLiveData>() val errorLiveData = MutableLiveData() + internal var multiTabLoadedFlow: Channel> = Channel(Channel.CONFLATED) + init { val isDefaultPage = repository.defaultNavId.isNotEmpty() && repository.defaultNavId == mMultiTabNavId && repository.multiTabNavLiveData.value != null @@ -64,6 +66,12 @@ open class TabWrapperViewModel( } } tabListLiveData.postValue(tabList) + + // 延迟 10ms,让 viewPager 先 setAdapter 再触发页面选中 + viewModelScope.launch { + delay(10L) + multiTabLoadedFlow.send(tabList) + } } class Factory(private val mMultiTabNavId: String) : ViewModelProvider.NewInstanceFactory() { diff --git a/app/src/main/java/com/halo/assistant/HaloApp.java b/app/src/main/java/com/halo/assistant/HaloApp.java index aaf5218f6a..1e1038475b 100644 --- a/app/src/main/java/com/halo/assistant/HaloApp.java +++ b/app/src/main/java/com/halo/assistant/HaloApp.java @@ -30,6 +30,7 @@ import com.gh.ad.AdDelegateHelper; import com.gh.base.GlobalActivityLifecycleObserver; import com.gh.common.FixedRateJobHelper; import com.gh.common.filter.RegionSettingHelper; +import com.gh.common.prioritychain.GlobalPriorityChainHelper; import com.gh.common.util.ActivationHelper; import com.gh.common.util.DataUtils; import com.gh.common.util.DeviceTokenUtils; @@ -334,6 +335,8 @@ public class HaloApp extends MultiDexApplication { // 必须放在外面,否则不能及时刷新用户数据 UserRepository.getInstance().getLoginUserInfo(); + GlobalPriorityChainHelper.INSTANCE.preStart(); + MainWrapperRepository.Companion.getInstance().getDataUnion(); AppExecutor.getUiExecutor().executeWithDelay(() -> { diff --git a/module_common/src/main/java/com/gh/gamecenter/common/entity/LaunchRedirect.kt b/module_common/src/main/java/com/gh/gamecenter/common/entity/LaunchRedirect.kt index 720e71cea7..28a43b67b9 100644 --- a/module_common/src/main/java/com/gh/gamecenter/common/entity/LaunchRedirect.kt +++ b/module_common/src/main/java/com/gh/gamecenter/common/entity/LaunchRedirect.kt @@ -4,12 +4,12 @@ import com.google.gson.annotations.SerializedName class LaunchRedirectWrapper( @SerializedName("link") - val launchRedirect: LaunchRedirect + val launchRedirect: LaunchRedirect? = null, ) class LaunchRedirect( @SerializedName("multi_tab_nav_link") - val tabNavLink: LinkEntity, - @SerializedName("multi_tab_detail") - val tabDetail: LinkEntity + val navTabLink: LinkEntity? = null, + @SerializedName("multi_tab_link") + val topTabLink: LinkEntity? = null, ) : LinkEntity() \ No newline at end of file diff --git a/module_core/build.gradle b/module_core/build.gradle index 9bdf743a27..72cde089b4 100644 --- a/module_core/build.gradle +++ b/module_core/build.gradle @@ -61,6 +61,7 @@ dependencies { api "com.squareup.retrofit2:retrofit:${retrofit}" api "com.squareup.retrofit2:converter-gson:${retrofit}" // include gson 2.7 api "com.squareup.retrofit2:adapter-rxjava2:${retrofit}" + api "androidx.lifecycle:lifecycle-runtime-ktx:$lifeCycle" api "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifeCycle" api "androidx.lifecycle:lifecycle-livedata-ktx:$lifeCycle" api "androidx.lifecycle:lifecycle-common-java8:$lifeCycle"