@@ -22,7 +22,6 @@ import com.omarea.common.shared.FilePathResolver
2222import com.omarea.common.shell.KeepShellPublic
2323import com.omarea.common.ui.DialogHelper
2424import com.omarea.common.ui.ProgressBarDialog
25- import com.omarea.common.ui.ThemeMode
2625import com.omarea.krscript.config.PageConfigReader
2726import com.omarea.krscript.config.PageConfigSh
2827import com.omarea.krscript.model.*
@@ -32,9 +31,6 @@ import com.tool.tree.databinding.ActivityMainBinding
3231import com.tool.tree.ui.MainPagerAdapter
3332import com.tool.tree.ui.TabIconHelper
3433import kotlinx.coroutines.Dispatchers
35- import kotlinx.coroutines.async
36- import kotlinx.coroutines.awaitAll
37- import kotlinx.coroutines.coroutineScope
3834import kotlinx.coroutines.isActive
3935import kotlinx.coroutines.launch
4036import kotlinx.coroutines.withContext
@@ -51,11 +47,6 @@ class MainActivity : AppCompatActivity() {
5147
5248 private val ACTION_FILE_PATH_CHOOSER = 65400
5349 private lateinit var adapter: MainPagerAdapter
54- // Lưu icon tương ứng theo đúng vị trí tab THỰC TẾ đã được thêm vào adapter
55- // (vì một số tab có thể bị bỏ qua nếu không có dữ liệu, nên không thể dùng vị trí cố định 0..3 nữa)
56- private val tabIcons = ArrayList <Int >()
57- // 0 = favorites, 1 = pages, 2 = tab3, 3 = tab4 -> loại tab theo đúng thứ tự đã hiển thị thực tế
58- private val tabSlotOrder = ArrayList <Int >()
5950
6051 override fun onCreate (savedInstanceState : Bundle ? ) {
6152 super .onCreate(savedInstanceState)
@@ -91,97 +82,58 @@ class MainActivity : AppCompatActivity() {
9182 }
9283 }
9384
94- // Thêm tab vào adapter nếu có dữ liệu. Icon/slot phải được ghi trước khi gọi adapter.addFragment
95- // vì TabLayoutMediator sẽ đọc lại tabIcons ngay khi adapter báo có thay đổi.
96- private fun addTabIfPresent (slot : Int , items : ArrayList <NodeInfoBase >? , titleRes : Int , iconRes : Int , config : PageNode , isFav : Boolean , theme : ThemeMode ) {
97- items?.takeIf { it.isNotEmpty() }?.let { data ->
98- tabIcons.add(iconRes)
99- tabSlotOrder.add(slot)
100- val fragment = ActionListFragment .create(data, getKrScriptActionHandler(config, isFav), null , theme)
101- adapter.addFragment(fragment, getString(titleRes))
102- }
103- }
104-
10585 private fun loadTabs () {
10686 progressBarDialog.showDialog(getString(R .string.please_wait))
107- tabIcons.clear()
108- tabSlotOrder.clear()
109-
87+
11088 lifecycleScope.launch(Dispatchers .IO ) {
111- // GIAI ĐOẠN 1: ưu tiên load 2 tab đầu (favorites, pages) trước, song song với nhau
112- val (favorites, pages) = coroutineScope {
113- val favoritesDeferred = async { getItems(krScriptConfig.favoriteConfig) }
114- val pagesDeferred = async { getItems(krScriptConfig.pageListConfig) }
115- listOf (favoritesDeferred, pagesDeferred).awaitAll()
116- }
89+ val favorites = getItems(krScriptConfig.favoriteConfig)
90+ val pages = getItems(krScriptConfig.pageListConfig)
91+ val tab3Items = getItems(krScriptConfig.customTab3Config)
92+ val tab4Items = getItems(krScriptConfig.customTab4Config)
11793
11894 if (! isActive) return @launch
11995
12096 withContext(Dispatchers .Main ) {
121- // Ẩn dialog chờ và hiển thị ngay 2 tab đầu, không cần đợi 2 tab sau
12297 progressBarDialog.hideDialog()
12398 val theme = ThemeModeState .getThemeMode()
12499
125- addTabIfPresent(0 , favorites, R .string.tab_favorites, R .drawable.tab_favorites, krScriptConfig.favoriteConfig, true , theme)
126- addTabIfPresent(1 , pages, R .string.tab_pages, R .drawable.tab_pages, krScriptConfig.pageListConfig, false , theme)
127-
128- setupTabs()
129- }
130-
131- // GIAI ĐOẠN 2: load ngầm 2 tab còn lại (tab3, tab4), không chặn UI của 2 tab đầu
132- val (tab3Items, tab4Items) = coroutineScope {
133- val tab3Deferred = async { getItems(krScriptConfig.customTab3Config) }
134- val tab4Deferred = async { getItems(krScriptConfig.customTab4Config) }
135- listOf (tab3Deferred, tab4Deferred).awaitAll()
136- }
100+ fun updateTab (pos : Int , items : ArrayList <NodeInfoBase >? , titleRes : Int , config : PageNode , isFav : Boolean ) {
101+ items?.takeIf { it.isNotEmpty() }?.let { data ->
102+ val fragment = ActionListFragment .create(data, getKrScriptActionHandler(config, isFav), null , theme)
103+ if (adapter.getFragment(pos) == null ) {
104+ adapter.addFragment(fragment, getString(titleRes))
105+ } else {
106+ adapter.replaceFragment(pos, fragment)
107+ }
108+ }
109+ }
137110
138- if (! isActive) return @launch
111+ updateTab(0 , favorites, R .string.tab_favorites, krScriptConfig.favoriteConfig, true )
112+ updateTab(1 , pages, R .string.tab_pages, krScriptConfig.pageListConfig, false )
113+ updateTab(2 , tab3Items, R .string.tab_custom3, krScriptConfig.customTab3Config, false )
114+ updateTab(3 , tab4Items, R .string.tab_custom4, krScriptConfig.customTab4Config, false )
139115
140- withContext(Dispatchers .Main ) {
141- val theme = ThemeModeState .getThemeMode()
142- addTabIfPresent(2 , tab3Items, R .string.tab_custom3, R .drawable.tab_custom3, krScriptConfig.customTab3Config, false , theme)
143- addTabIfPresent(3 , tab4Items, R .string.tab_custom4, R .drawable.tab_custom4, krScriptConfig.customTab4Config, false , theme)
116+ setupTabs()
144117 }
145118 }
146119 }
147120
148121 private fun reloadTabs () {
149122 lifecycleScope.launch(Dispatchers .IO ) {
150- // Chạy song song thay vì tuần tự - giảm thời gian chờ khi reload
151- val (favorites, pages, tab3Items, tab4Items) = coroutineScope {
152- val favoritesDeferred = async { getItems(krScriptConfig.favoriteConfig) }
153- val pagesDeferred = async { getItems(krScriptConfig.pageListConfig) }
154- val tab3Deferred = async { getItems(krScriptConfig.customTab3Config) }
155- val tab4Deferred = async { getItems(krScriptConfig.customTab4Config) }
156- listOf (favoritesDeferred, pagesDeferred, tab3Deferred, tab4Deferred).awaitAll()
157- }
123+ val favorites = getItems(krScriptConfig.favoriteConfig)
124+ val pages = getItems(krScriptConfig.pageListConfig)
125+ val tab3Items = getItems(krScriptConfig.customTab3Config)
126+ val tab4Items = getItems(krScriptConfig.customTab4Config)
158127
159128 if (! isActive) return @launch
160129
161130 withContext(Dispatchers .Main ) {
162131 val theme = ThemeModeState .getThemeMode()
163-
164- // Nếu số tab hiện có không còn khớp với dữ liệu mới (tab bị thêm/bớt do có/không có dữ liệu)
165- // thì load lại toàn bộ để đảm bảo tab rỗng không bị hiển thị và icon luôn đúng vị trí.
166- val newItemsBySlot = mapOf (0 to favorites, 1 to pages, 2 to tab3Items, 3 to tab4Items)
167- val newNonEmptySlots = newItemsBySlot.filterValues { ! it.isNullOrEmpty() }.keys
168- if (newNonEmptySlots != tabSlotOrder.toSet()) {
169- loadTabs()
170- return @withContext
171- }
172-
173- fun configFor (slot : Int ) = when (slot) {
174- 0 -> krScriptConfig.favoriteConfig to true
175- 1 -> krScriptConfig.pageListConfig to false
176- 2 -> krScriptConfig.customTab3Config to false
177- else -> krScriptConfig.customTab4Config to false
178- }
179-
180- tabSlotOrder.forEachIndexed { position, slot ->
181- val items = newItemsBySlot[slot] ? : return @forEachIndexed
182- val (config, isFav) = configFor(slot)
183- (adapter.getFragment(position) as ? ActionListFragment )?.updateData(items, getKrScriptActionHandler(config, isFav), theme)
184- }
132+
133+ favorites?.let { (adapter.getFragment(0 ) as ? ActionListFragment )?.updateData(it, getKrScriptActionHandler(krScriptConfig.favoriteConfig, true ), theme) }
134+ pages?.let { (adapter.getFragment(1 ) as ? ActionListFragment )?.updateData(it, getKrScriptActionHandler(krScriptConfig.pageListConfig, false ), theme) }
135+ tab3Items?.let { (adapter.getFragment(2 ) as ? ActionListFragment )?.updateData(it, getKrScriptActionHandler(krScriptConfig.customTab3Config, false ), theme) }
136+ tab4Items?.let { (adapter.getFragment(3 ) as ? ActionListFragment )?.updateData(it, getKrScriptActionHandler(krScriptConfig.customTab4Config, false ), theme) }
185137 }
186138 }
187139 }
@@ -192,7 +144,13 @@ class MainActivity : AppCompatActivity() {
192144 // Kết nối TabLayout và ViewPager2
193145 TabLayoutMediator (binding.tabLayout, binding.viewPager) { tab, position ->
194146 val title = adapter.getTitle(position)
195- val iconRes = tabIcons.getOrElse(position) { R .drawable.tab_home }
147+ val iconRes = when (position) {
148+ 0 -> R .drawable.tab_favorites
149+ 1 -> R .drawable.tab_pages
150+ 2 -> R .drawable.tab_custom3
151+ 3 -> R .drawable.tab_custom4
152+ else -> R .drawable.tab_home
153+ }
196154 tab.customView = tabHelper.createTabView(title, getDrawable(iconRes)!! , position == binding.viewPager.currentItem)
197155 }.attach()
198156
0 commit comments