package com.example.myapplication import android.os.Bundle import android.view.View import android.widget.Toast import androidx.activity.OnBackPressedCallback import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.lifecycleScope import androidx.navigation.NavController import androidx.navigation.fragment.NavHostFragment import com.example.myapplication.network.AuthEvent import com.example.myapplication.network.AuthEventBus import com.example.myapplication.utils.EncryptedSharedPreferencesUtil import com.google.android.material.bottomnavigation.BottomNavigationView import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch class MainActivity : AppCompatActivity() { private lateinit var bottomNav: BottomNavigationView private val TAB_HOME = "tab_home" private val TAB_SHOP = "tab_shop" private val TAB_MINE = "tab_mine" private val GLOBAL_HOST = "global_host" private var currentTabTag = TAB_HOME private var pendingTabAfterLogin: String? = null private val protectedTabs = setOf( R.id.shop_graph, R.id.mine_graph ) private val tabMap by lazy { mapOf( R.id.home_graph to TAB_HOME, R.id.shop_graph to TAB_SHOP, R.id.mine_graph to TAB_MINE ) } private lateinit var homeHost: NavHostFragment private lateinit var shopHost: NavHostFragment private lateinit var mineHost: NavHostFragment private lateinit var globalHost: NavHostFragment private var lastGlobalDestId: Int = R.id.globalEmptyFragment private val currentTabHost: NavHostFragment get() = when (currentTabTag) { TAB_SHOP -> shopHost TAB_MINE -> mineHost else -> homeHost } private val currentTabNavController: NavController get() = currentTabHost.navController private val globalNavController: NavController get() = globalHost.navController override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) bottomNav = findViewById(R.id.bottom_nav) bottomNav.itemIconTintList = null bottomNav.setOnItemReselectedListener { /* ignore */ } // 1) 恢复当前tab currentTabTag = savedInstanceState?.getString("current_tab_tag") ?: TAB_HOME // 2) 初始化/找回 3个Tab host + global host initHosts() // 3) 底栏点击:show/hide 切 tab(带登录拦截 + 防 stateSaved) bottomNav.setOnItemSelectedListener { item -> val tabTag = tabMap[item.itemId] ?: return@setOnItemSelectedListener false // 登录拦截:未登录点受保护tab => 打开全局login if (!isLoggedIn() && item.itemId in protectedTabs) { // 强制回到当前tab的选中状态,避免底栏短暂闪一下 bottomNav.selectedItemId = when (currentTabTag) { TAB_SHOP -> R.id.shop_graph TAB_MINE -> R.id.mine_graph else -> R.id.home_graph } pendingTabAfterLogin = tabTag // 记录目标tab openGlobal(R.id.loginFragment) return@setOnItemSelectedListener false } switchTab(tabTag) true } // 4) token过期:走全局 overlay,且避免重复打开 lifecycleScope.launch { AuthEventBus.events.collectLatest { event -> when (event) { is AuthEvent.TokenExpired -> { pendingTabAfterLogin = null // 已经在login就别重复 if (!isGlobalVisible() || globalNavController.currentDestination?.id != R.id.loginFragment) { openGlobal(R.id.loginFragment) } } is AuthEvent.GenericError -> { Toast.makeText(this@MainActivity, event.message, Toast.LENGTH_SHORT).show() } // 登录成功事件处理 is AuthEvent.LoginSuccess -> { // 关闭 global overlay:回到 empty globalNavController.popBackStack(R.id.globalEmptyFragment, false) // 如果之前想去商城/我的,登录成功后自动切过去 pendingTabAfterLogin?.let { tag -> switchTab(tag) bottomNav.selectedItemId = when (tag) { TAB_SHOP -> R.id.shop_graph TAB_MINE -> R.id.mine_graph else -> R.id.home_graph } } pendingTabAfterLogin = null } // 登出事件处理 is AuthEvent.Logout -> { pendingTabAfterLogin = event.returnTabTag // ✅ 用户没登录按返回,应回首页,所以先切到首页 switchTab(TAB_HOME, force = true) bottomNav.post { bottomNav.selectedItemId = R.id.home_graph openGlobal(R.id.loginFragment) // ✅ 退出登录后立刻打开登录页 } } // 打开全局页面事件处理 is AuthEvent.OpenGlobalPage -> { // 打开指定的全局页面 openGlobal(event.destinationId, event.bundle) } } } } // 5) intent跳转(充值等)统一走全局 overlay handleNavigationFromIntent() // 6) 返回键规则:优先关闭global,其次pop当前tab setupBackPress() // 7) 初始选中正确tab(不会触发二次创建) bottomNav.post { bottomNav.selectedItemId = when (currentTabTag) { TAB_SHOP -> R.id.shop_graph TAB_MINE -> R.id.mine_graph else -> R.id.home_graph } } } private fun initHosts() { val fm = supportFragmentManager homeHost = fm.findFragmentByTag(TAB_HOME) as? NavHostFragment ?: NavHostFragment.create(R.navigation.home_graph) shopHost = fm.findFragmentByTag(TAB_SHOP) as? NavHostFragment ?: NavHostFragment.create(R.navigation.shop_graph) mineHost = fm.findFragmentByTag(TAB_MINE) as? NavHostFragment ?: NavHostFragment.create(R.navigation.mine_graph) globalHost = fm.findFragmentByTag(GLOBAL_HOST) as? NavHostFragment ?: NavHostFragment.create(R.navigation.global_graph) // 第一次创建时 add;后续进程重建会自动恢复,无需重复 add if (fm.findFragmentByTag(TAB_HOME) == null) { fm.beginTransaction() .setReorderingAllowed(true) .add(R.id.tab_container, homeHost, TAB_HOME) .add(R.id.tab_container, shopHost, TAB_SHOP).hide(shopHost) .add(R.id.tab_container, mineHost, TAB_MINE).hide(mineHost) .commitNow() } if (fm.findFragmentByTag(GLOBAL_HOST) == null) { fm.beginTransaction() .setReorderingAllowed(true) .add(R.id.global_container, globalHost, GLOBAL_HOST) .commitNow() } // 确保当前tab可见 switchTab(currentTabTag, force = true) // 绑定全局导航可见性监听 bindGlobalVisibility() // 绑定底部导航栏可见性监听 bindBottomNavVisibilityForTabs() } private fun bindGlobalVisibility() { globalNavController.addOnDestinationChangedListener { _, dest, _ -> val isEmpty = dest.id == R.id.globalEmptyFragment findViewById(R.id.global_container).visibility = if (isEmpty) View.GONE else View.VISIBLE bottomNav.visibility = if (isEmpty) View.VISIBLE else View.GONE // ✅ 只在"刚从某个全局页关闭回 empty"时触发回退逻辑 val justClosedOverlay = (dest.id == R.id.globalEmptyFragment && lastGlobalDestId != R.id.globalEmptyFragment) lastGlobalDestId = dest.id if (justClosedOverlay) { val currentTabGraphId = when (currentTabTag) { TAB_SHOP -> R.id.shop_graph TAB_MINE -> R.id.mine_graph else -> R.id.home_graph } // 未登录且当前处在受保护tab:强制回首页 if (!isLoggedIn() && currentTabGraphId in protectedTabs) { switchTab(TAB_HOME, force = true) bottomNav.selectedItemId = R.id.home_graph } // ✅ 只有"没登录就关闭登录页"才清 pending if (!isLoggedIn()) { pendingTabAfterLogin = null } } } } private fun switchTab(targetTag: String, force: Boolean = false) { if (!force && targetTag == currentTabTag) return val fm = supportFragmentManager if (fm.isStateSaved) return // ✅ 防崩:stateSaved 时不做事务 currentTabTag = targetTag fm.beginTransaction() .setReorderingAllowed(true) .hide(homeHost) .hide(shopHost) .hide(mineHost) .also { ft -> when (targetTag) { TAB_SHOP -> ft.show(shopHost) TAB_MINE -> ft.show(mineHost) else -> ft.show(homeHost) } } .commit() } /** 打开全局页(login/recharge等) */ private fun openGlobal(destId: Int, bundle: Bundle? = null) { val fm = supportFragmentManager if (fm.isStateSaved) return // ✅ 防崩 try { if (bundle != null) { globalNavController.navigate(destId, bundle) } else { globalNavController.navigate(destId) } } catch (e: IllegalArgumentException) { // 可选:防止偶发重复 navigate 崩溃 e.printStackTrace() } } /** 关闭全局页:pop到 empty */ private fun bindBottomNavVisibilityForTabs() { fun shouldHideBottomNav(destId: Int): Boolean { return destId in setOf( R.id.searchFragment, R.id.searchResultFragment, R.id.MySkin // 你还有其他需要全屏的页,也加在这里 ) } val listener = NavController.OnDestinationChangedListener { _, dest, _ -> // 只要 global overlay 打开了,仍然以 overlay 为准(你已有逻辑) if (isGlobalVisible()) return@OnDestinationChangedListener bottomNav.visibility = if (shouldHideBottomNav(dest.id)) View.GONE else View.VISIBLE } homeHost.navController.addOnDestinationChangedListener(listener) shopHost.navController.addOnDestinationChangedListener(listener) mineHost.navController.addOnDestinationChangedListener(listener) } private fun closeGlobalIfPossible(): Boolean { if (!isGlobalVisible()) return false val popped = globalNavController.popBackStack() val stillVisible = globalNavController.currentDestination?.id != R.id.globalEmptyFragment return popped || stillVisible } private fun isGlobalVisible(): Boolean { return findViewById(R.id.global_container).visibility == View.VISIBLE } private fun setupBackPress() { onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { // 1) 优先关 global if (closeGlobalIfPossible()) return // 2) 再 pop 当前tab val popped = currentTabNavController.popBackStack() if (popped) return // 3) 当前tab到根了:如果不是home,切回home;否则退出 if (currentTabTag != TAB_HOME) { bottomNav.post { bottomNav.selectedItemId = R.id.home_graph } switchTab(TAB_HOME) } else { finish() } } }) } private fun handleNavigationFromIntent() { val navigateTo = intent.getStringExtra("navigate_to") if (navigateTo == "recharge_fragment") { bottomNav.post { if (!isLoggedIn()) { openGlobal(R.id.loginFragment) return@post } openGlobal(R.id.rechargeFragment) } } } private fun isLoggedIn(): Boolean { return EncryptedSharedPreferencesUtil.contains(this, "user") } override fun onSaveInstanceState(outState: Bundle) { outState.putString("current_tab_tag", currentTabTag) super.onSaveInstanceState(outState) } }