再次优化加载性能

This commit is contained in:
BBIT-Kai
2026-05-28 17:15:17 +08:00
parent 4eeeaaa3bc
commit c7fd095c98
5 changed files with 224 additions and 90 deletions
@@ -240,6 +240,7 @@ fun <T : Any> MyRefreshTableForCard(
) {
val state = rememberPullToRefreshState()
val pagerSate = info.loadState.append
val refreshState = info.loadState.refresh
LaunchedEffect(pagerSate) {
if (pagerSate is LoadState.NotLoading) {
onFinishRefresh()
@@ -272,6 +273,7 @@ fun <T : Any> MyRefreshTableForCard(
}
}
) {
Box(modifier = M.fillMaxSize()) {
LazyVerticalGrid(
modifier = M.fillMaxSize(),
columns = GridCells.Fixed(columns),
@@ -299,6 +301,12 @@ fun <T : Any> MyRefreshTableForCard(
}
}
}
if (refreshState is LoadState.Loading && info.itemCount == 0) {
Box(modifier = M.fillMaxSize(), contentAlignment = Alignment.Center) {
ListLoading()
}
}
}
}
}
}
@@ -512,6 +520,7 @@ fun <T : Any> MyRefreshTable(
val listState: LazyListState = rememberLazyListState()
val state = rememberPullToRefreshState()
val pagerSate = info.loadState.append
val refreshState = info.loadState.refresh
LaunchedEffect(pagerSate) {
if (pagerSate is LoadState.NotLoading) {
onFinishRefresh()
@@ -553,6 +562,7 @@ fun <T : Any> MyRefreshTable(
}
}
) {
Box(modifier = M.fillMaxSize()) {
var selectIndex by rememberSaveable { mutableStateOf(-1) }
LazyColumn(state = listState) {
items(
@@ -648,6 +658,12 @@ fun <T : Any> MyRefreshTable(
}
}
}
if (refreshState is LoadState.Loading && info.itemCount == 0) {
Box(modifier = M.fillMaxSize(), contentAlignment = Alignment.Center) {
ListLoading()
}
}
}
}
}
@@ -54,11 +54,12 @@ open class BaseViewModel : ViewModel() {
onUI: (T) -> Unit,
) {
viewModelScope.launch {
val result = kotlin.runCatching {
withContext(Dispatchers.IO) {
if (showDialog) {
Toasty.showLoadingDialog(loadingTips)
}
val result = kotlin.runCatching {
withContext(Dispatchers.IO) {
onIO()
}
}
@@ -67,7 +68,6 @@ open class BaseViewModel : ViewModel() {
hideLoadingDialog()
}
withContext(Dispatchers.Main) {
result.onSuccess { data ->
onUI(data)
}.onFailure { exception ->
@@ -96,7 +96,6 @@ open class BaseViewModel : ViewModel() {
}
}
}
}
fun <T> doInIoThread(
@@ -20,12 +20,13 @@ import androidx.navigation.compose.rememberNavController
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import com.bbitcn.f8.pad.M
@@ -47,8 +48,8 @@ import com.bbitcn.f8.pad.ui.screen.mainFunc.UserScreen
import com.bbitcn.f8.pad.ui.screen.view.Toasty
import com.bbitcn.f8.pad.ui.viewmodel.UpdateViewModel
import com.cyberecho.ui.screen.ChatDialog
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.xutils.db.annotation.Column
@Preview(showBackground = true, widthDp = 1280)
@Composable
@@ -74,9 +75,43 @@ fun MainScreen(
}
Box(modifier = M.fillMaxWidth(), contentAlignment = Alignment.BottomStart) {
var selectedPage by rememberSaveable { mutableStateOf(0) }
var contentPage by rememberSaveable { mutableStateOf(0) }
var isSwitchingPage by remember { mutableStateOf(false) }
val cachedPages = remember { mutableStateListOf<Int>() }
val coroutineScope = rememberCoroutineScope()
val menu by mainViewModel.menu.collectAsState()
LaunchedEffect(menu, selectedPage) {
if (menu.isEmpty()) {
contentPage = 0
isSwitchingPage = false
cachedPages.clear()
return@LaunchedEffect
}
val safeSelectedPage = selectedPage.coerceIn(0, menu.lastIndex)
if (safeSelectedPage != selectedPage) {
selectedPage = safeSelectedPage
return@LaunchedEffect
}
cachedPages.removeAll { it !in menu.indices }
if (cachedPages.isEmpty()) {
cachedPages.add(safeSelectedPage)
}
if (contentPage != safeSelectedPage && safeSelectedPage !in cachedPages) {
isSwitchingPage = true
withFrameNanos { }
delay(180)
cachedPages.add(safeSelectedPage)
contentPage = safeSelectedPage
isSwitchingPage = false
} else if (contentPage != safeSelectedPage) {
contentPage = safeSelectedPage
isSwitchingPage = false
}
}
Row(modifier = M.fillMaxWidth()) {
NavigationRail(
containerColor = MyColors.Black,
@@ -99,37 +134,39 @@ fun MainScreen(
)
},
selected = selectedPage == index,
onClick = { selectedPage = index }
onClick = {
if (selectedPage != index) {
selectedPage = index
isSwitchingPage = index !in cachedPages
if (index in cachedPages) {
contentPage = index
}
}
}
)
}
}
Box {
var index = -1
if (menu.isNotEmpty()) {
index = menu[selectedPage].index
}
when (index) {
-1 -> {
Box(modifier = M.fillMaxSize(), contentAlignment = Alignment.Center) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text("正在加载菜单,如长时间未响应请点击重新加载")
MyButton(text = "刷新菜单") {
mainViewModel.refreshMenuPermission()
Box(modifier = M.weight(1f).fillMaxSize()) {
val selectedMenu = menu.getOrNull(selectedPage)
if (isSwitchingPage && selectedMenu != null && selectedPage !in cachedPages) {
MainPageLoading(selectedMenu.title)
} else {
cachedPages.forEach { page ->
key(page) {
val pageIndex = menu.getOrNull(page)?.index ?: -1
MainPageHost(visible = page == contentPage) {
MainPageContent(
index = pageIndex,
navController = navController,
drawerViewModel = drawerViewModel,
updateViewModel = updateViewModel,
topInfoViewmodel = topInfoViewmodel,
mainViewModel = mainViewModel
)
}
}
}
}
0 -> HomeScreen(navController)
1 -> UserScreen(navController)
2 -> PurchaseScreen(navController, drawerViewModel = drawerViewModel)
3 -> FundsScreen(navController, drawerViewModel = drawerViewModel)
4 -> StatisticsScreen(drawerViewModel = drawerViewModel)
5 -> DryCoonScreen(navController, drawerViewModel)
6 -> SettingScreen(navController, updateViewModel = updateViewModel, topInfoViewmodel = topInfoViewmodel){
mainViewModel.refreshMenuPermission()
}
}
}
}
Column(
@@ -208,3 +245,69 @@ fun MainScreen(
val chatDialogData by mainViewModel.chatDialogData.collectAsState()
ChatDialog(chatDialogData)
}
@Composable
private fun MainPageLoading(title: String) {
Box(modifier = M.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(
text = "正在加载$title...",
color = MyColors.Gray,
fontSize = MaterialTheme.typography.bodyLarge.fontSize
)
}
}
@Composable
private fun MainPageHost(
visible: Boolean,
content: @Composable () -> Unit
) {
Box(
modifier = if (visible) {
M
.fillMaxSize()
.alpha(1f)
.zIndex(1f)
} else {
M
.size(0.dp)
.alpha(0f)
.zIndex(0f)
}
) {
content()
}
}
@Composable
private fun MainPageContent(
index: Int,
navController: NavHostController,
drawerViewModel: DrawerViewModel,
updateViewModel: UpdateViewModel,
topInfoViewmodel: TopInfoViewModel,
mainViewModel: MainViewModel
) {
when (index) {
-1 -> {
Box(modifier = M.fillMaxSize(), contentAlignment = Alignment.Center) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text("正在加载菜单,如长时间未响应请点击重新加载")
MyButton(text = "刷新菜单") {
mainViewModel.refreshMenuPermission()
}
}
}
}
0 -> HomeScreen(navController)
1 -> UserScreen(navController)
2 -> PurchaseScreen(navController, drawerViewModel = drawerViewModel)
3 -> FundsScreen(navController, drawerViewModel = drawerViewModel)
4 -> StatisticsScreen(drawerViewModel = drawerViewModel)
5 -> DryCoonScreen(navController, drawerViewModel)
6 -> SettingScreen(navController, updateViewModel = updateViewModel, topInfoViewmodel = topInfoViewmodel) {
mainViewModel.refreshMenuPermission()
}
}
}
@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -45,6 +46,7 @@ import com.bbitcn.f8.pad.ui.screen.view.Toasty
import com.bbitcn.f8.pad.ui.screen.view.common.DatePickerRange
import com.bbitcn.f8.pad.ui.screen.view.drawer.DrawerViewModel
import com.bbitcn.f8.pad.ui.theme.MyColors
import kotlinx.coroutines.delay
import java.text.SimpleDateFormat
import java.time.LocalDate
import java.util.Locale
@@ -69,8 +71,18 @@ fun StatisticsScreen(
val ticketMoreDialogData by remember { mutableStateOf(TicketMoreDialogData()) }
var curType by remember { mutableStateOf(StatisticsResponse.Data()) }
var queryInput by rememberSaveable { mutableStateOf("") }
var queryInputInitialized by rememberSaveable { mutableStateOf(false) }
val pager = statisticsViewModel.statisticsPager.collectAsLazyPagingItems()
val dateRangeSelectDialogData by statisticsViewModel.dateRangeSelectDialogData.collectAsState()
LaunchedEffect(queryInput) {
if (!queryInputInitialized) {
queryInputInitialized = true
return@LaunchedEffect
}
delay(350)
statisticsViewModel.updateParamsLike(queryInput)
pager.refresh()
}
MainFuncFrame {
MyCard(colors = MyColors.LightLightBlueGreen) {
Row(
@@ -79,10 +91,12 @@ fun StatisticsScreen(
.padding(10.dp)
) {
StatisticsLeft(modifier = M.weight(2f), statisticsViewModel, curType, pager) {
if (curType.sgtypesysid != it.sgtypesysid) {
curType = it
statisticsViewModel.updateParamsCocoonType(it.sgtypesysid)
pager.refresh()
}
}
StatisticsMain(
modifier = M.weight(8f),
statisticsViewModel,
@@ -90,8 +104,6 @@ fun StatisticsScreen(
queryInput,
{
queryInput = it
statisticsViewModel.updateParamsLike(queryInput)
pager.refresh()
},
curType.name,
{
@@ -119,6 +131,7 @@ fun StatisticsLeft(
) {
val daysInfo by statisticsViewModel.daysInfo.collectAsState()
val statistics by statisticsViewModel.statistics.collectAsState()
val dayFormat = remember { SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) }
Column(
modifier = modifier
@@ -131,11 +144,13 @@ fun StatisticsLeft(
statisticsViewModel.calDate = it
statisticsViewModel.getDaysInfo(it.year.toString(), it.monthValue.toString())
}) { start, end ->
val dateStart = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).parse(start)
val dateEnd = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).parse(end)
val dateStart = dayFormat.parse(start)
val dateEnd = dayFormat.parse(end)
if (dateStart != null && dateEnd != null) {
statisticsViewModel.refreshDateRange(dateStart to dateEnd)
pager.refresh()
}
}
val dateRange by statisticsViewModel.dateRange.collectAsState()
DateRangePickTextFiled(M.fillMaxWidth(), dateRange = dateRange) {
statisticsViewModel.showDateRangeSelectDialog {
@@ -67,6 +67,7 @@ fun DatePickerRange(
// 处理拖动选择日期范围
var selectedStartDay by remember { mutableStateOf(-1) }
var selectedEndDay by remember { mutableStateOf(-1) }
val importantDaySet = remember(importantDateInfoList) { importantDateInfoList.toSet() }
val onClickChangeDate: (date: LocalDate) -> Unit = { date ->
currentDate = date
@@ -158,7 +159,7 @@ fun DatePickerRange(
items(currentDate.lengthOfMonth() + 1) { day ->
CalendarDay(
day,
importantDateInfoList.contains(day),
importantDaySet.contains(day),
rangeType = if (day == selectedStartDay)
if (selectedEndDay == -1
|| selectedEndDay == selectedStartDay