[修复] 修复偶现的主页面崩溃问题

This commit is contained in:
HapeLee
2026-03-25 01:38:10 +08:00
parent f16bec9dc7
commit 46a11de976
@@ -1,5 +1,7 @@
package io.legado.app.ui.main
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -8,10 +10,12 @@ import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.MenuOpen
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Menu
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.Badge
@@ -33,11 +37,16 @@ import androidx.compose.material3.WideNavigationRailValue
import androidx.compose.material3.rememberWideNavigationRailState
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
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -48,18 +57,24 @@ import io.legado.app.ui.book.info.BookInfoActivity
import io.legado.app.ui.book.search.SearchActivity
import io.legado.app.ui.config.mainConfig.MainConfig
import io.legado.app.ui.main.bookshelf.BookshelfScreen
import io.legado.app.ui.main.bookshelf.BookshelfViewModel
import io.legado.app.ui.main.explore.ExploreScreen
import io.legado.app.ui.main.my.MyScreen
import io.legado.app.ui.main.rss.RssScreen
import io.legado.app.ui.theme.regularHazeEffect
import io.legado.app.ui.widget.components.AppScaffold
import io.legado.app.ui.widget.components.GlassDefaults
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
import io.legado.app.utils.startActivity
import io.legado.app.utils.startActivityForBook
import kotlinx.coroutines.launch
import org.koin.androidx.compose.koinViewModel
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@OptIn(
ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class,
ExperimentalFoundationApi::class
)
@Composable
fun MainScreen(
viewModel: MainViewModel = koinViewModel(),
@@ -69,6 +84,9 @@ fun MainScreen(
val uiState by viewModel.state.collectAsStateWithLifecycle()
val coroutineScope = rememberCoroutineScope()
val bookshelfViewModel: BookshelfViewModel = koinViewModel()
val bookshelfUiState by bookshelfViewModel.uiState.collectAsState()
val hazeState = remember { HazeState() }
val destinations = remember(MainConfig.showDiscovery, MainConfig.showRSS) {
MainDestination.mainDestinations.filter {
@@ -139,6 +157,9 @@ fun MainScreen(
val labelVisibilityMode = MainConfig.labelVisibilityMode
destinations.forEachIndexed { index, destination ->
val selected = pagerState.targetPage == index
var showGroupMenu by remember { mutableStateOf(false) }
val haptic = LocalHapticFeedback.current
WideNavigationRailItem(
railExpanded = navState.targetValue == WideNavigationRailValue.Expanded,
selected = selected,
@@ -148,7 +169,57 @@ fun MainScreen(
}
},
icon = {
NavigationIcon(destination, selected, uiState.upBooksCount)
Box {
NavigationIcon(
destination = destination,
selected = selected,
upBooksCount = uiState.upBooksCount,
modifier = if (destination == MainDestination.Bookshelf) {
Modifier.combinedClickable(
onClick = {
coroutineScope.launch {
pagerState.animateScrollToPage(index)
}
},
onLongClick = {
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
showGroupMenu = true
}
)
} else Modifier
)
if (destination == MainDestination.Bookshelf && showGroupMenu) {
RoundDropdownMenu(
expanded = showGroupMenu,
onDismissRequest = { showGroupMenu = false }
) { dismiss ->
bookshelfUiState.groups.forEachIndexed { groupIndex, group ->
RoundDropdownMenuItem(
text = { Text(group.groupName) },
onClick = {
coroutineScope.launch {
if (pagerState.currentPage != index) {
pagerState.scrollToPage(index)
}
bookshelfViewModel.changeGroup(group.groupId)
dismiss()
}
},
trailingIcon = {
if (bookshelfUiState.selectedGroupIndex == groupIndex) {
Icon(
Icons.Default.Check,
null,
modifier = Modifier.size(18.dp)
)
}
}
)
}
}
}
}
},
label = if (labelVisibilityMode != "unlabeled") {
{ Text(stringResource(destination.labelId)) }
@@ -181,6 +252,9 @@ fun MainScreen(
}
destinations.forEachIndexed { index, destination ->
val selected = pagerState.targetPage == index
var showGroupMenu by remember { mutableStateOf(false) }
val haptic = LocalHapticFeedback.current
NavigationBarItem(
selected = selected,
onClick = {
@@ -189,7 +263,61 @@ fun MainScreen(
}
},
icon = {
NavigationIcon(destination, selected, uiState.upBooksCount)
Box {
NavigationIcon(
destination = destination,
selected = selected,
upBooksCount = uiState.upBooksCount,
modifier = if (destination == MainDestination.Bookshelf) {
Modifier.combinedClickable(
onClick = {
coroutineScope.launch {
pagerState.animateScrollToPage(index)
}
},
onLongClick = {
haptic.performHapticFeedback(
HapticFeedbackType.LongPress
)
showGroupMenu = true
}
)
} else Modifier
)
if (destination == MainDestination.Bookshelf && showGroupMenu) {
RoundDropdownMenu(
expanded = showGroupMenu,
onDismissRequest = { showGroupMenu = false }
) { dismiss ->
bookshelfUiState.groups.forEachIndexed { groupIndex, group ->
RoundDropdownMenuItem(
text = { Text(group.groupName) },
onClick = {
coroutineScope.launch {
if (pagerState.currentPage != index) {
pagerState.scrollToPage(index)
}
bookshelfViewModel.changeGroup(
group.groupId
)
dismiss()
}
},
trailingIcon = {
if (bookshelfUiState.selectedGroupIndex == groupIndex) {
Icon(
Icons.Default.Check,
null,
modifier = Modifier.size(18.dp)
)
}
}
)
}
}
}
}
},
colors = NavigationBarItemDefaults.colors(
indicatorColor = GlassDefaults.glassColor(
@@ -215,7 +343,8 @@ fun MainScreen(
userScrollEnabled = true,
beyondViewportPageCount = 3
) { page ->
when (destinations[page]) {
val destination = destinations.getOrNull(page) ?: return@HorizontalPager
when (destination) {
MainDestination.Bookshelf -> BookshelfScreen(
onBookClick = { book ->
context.startActivityForBook(book)
@@ -248,14 +377,17 @@ fun MainScreen(
private fun NavigationIcon(
destination: MainDestination,
selected: Boolean,
upBooksCount: Int
upBooksCount: Int,
modifier: Modifier = Modifier
) {
val icon = if (selected) destination.selectedIcon else destination.icon
if (destination == MainDestination.Bookshelf && upBooksCount > 0) {
BadgedBox(badge = { Badge { Text(upBooksCount.toString()) } }) {
Box(modifier = modifier) {
if (destination == MainDestination.Bookshelf && upBooksCount > 0) {
BadgedBox(badge = { Badge { Text(upBooksCount.toString()) } }) {
Icon(icon, contentDescription = null)
}
} else {
Icon(icon, contentDescription = null)
}
} else {
Icon(icon, contentDescription = null)
}
}