[修复] 修复偶现的主页面崩溃问题
This commit is contained in:
1 file changed
+141
-9
@@ -1,5 +1,7 @@
|
|||||||
package io.legado.app.ui.main
|
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.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
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.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.MenuOpen
|
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.Menu
|
||||||
import androidx.compose.material.icons.filled.Search
|
import androidx.compose.material.icons.filled.Search
|
||||||
import androidx.compose.material3.Badge
|
import androidx.compose.material3.Badge
|
||||||
@@ -33,11 +37,16 @@ import androidx.compose.material3.WideNavigationRailValue
|
|||||||
import androidx.compose.material3.rememberWideNavigationRailState
|
import androidx.compose.material3.rememberWideNavigationRailState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
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.book.search.SearchActivity
|
||||||
import io.legado.app.ui.config.mainConfig.MainConfig
|
import io.legado.app.ui.config.mainConfig.MainConfig
|
||||||
import io.legado.app.ui.main.bookshelf.BookshelfScreen
|
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.explore.ExploreScreen
|
||||||
import io.legado.app.ui.main.my.MyScreen
|
import io.legado.app.ui.main.my.MyScreen
|
||||||
import io.legado.app.ui.main.rss.RssScreen
|
import io.legado.app.ui.main.rss.RssScreen
|
||||||
import io.legado.app.ui.theme.regularHazeEffect
|
import io.legado.app.ui.theme.regularHazeEffect
|
||||||
import io.legado.app.ui.widget.components.AppScaffold
|
import io.legado.app.ui.widget.components.AppScaffold
|
||||||
import io.legado.app.ui.widget.components.GlassDefaults
|
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.startActivity
|
||||||
import io.legado.app.utils.startActivityForBook
|
import io.legado.app.utils.startActivityForBook
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.androidx.compose.koinViewModel
|
import org.koin.androidx.compose.koinViewModel
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
@OptIn(
|
||||||
|
ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class,
|
||||||
|
ExperimentalFoundationApi::class
|
||||||
|
)
|
||||||
@Composable
|
@Composable
|
||||||
fun MainScreen(
|
fun MainScreen(
|
||||||
viewModel: MainViewModel = koinViewModel(),
|
viewModel: MainViewModel = koinViewModel(),
|
||||||
@@ -69,6 +84,9 @@ fun MainScreen(
|
|||||||
val uiState by viewModel.state.collectAsStateWithLifecycle()
|
val uiState by viewModel.state.collectAsStateWithLifecycle()
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
val bookshelfViewModel: BookshelfViewModel = koinViewModel()
|
||||||
|
val bookshelfUiState by bookshelfViewModel.uiState.collectAsState()
|
||||||
|
|
||||||
val hazeState = remember { HazeState() }
|
val hazeState = remember { HazeState() }
|
||||||
val destinations = remember(MainConfig.showDiscovery, MainConfig.showRSS) {
|
val destinations = remember(MainConfig.showDiscovery, MainConfig.showRSS) {
|
||||||
MainDestination.mainDestinations.filter {
|
MainDestination.mainDestinations.filter {
|
||||||
@@ -139,6 +157,9 @@ fun MainScreen(
|
|||||||
val labelVisibilityMode = MainConfig.labelVisibilityMode
|
val labelVisibilityMode = MainConfig.labelVisibilityMode
|
||||||
destinations.forEachIndexed { index, destination ->
|
destinations.forEachIndexed { index, destination ->
|
||||||
val selected = pagerState.targetPage == index
|
val selected = pagerState.targetPage == index
|
||||||
|
var showGroupMenu by remember { mutableStateOf(false) }
|
||||||
|
val haptic = LocalHapticFeedback.current
|
||||||
|
|
||||||
WideNavigationRailItem(
|
WideNavigationRailItem(
|
||||||
railExpanded = navState.targetValue == WideNavigationRailValue.Expanded,
|
railExpanded = navState.targetValue == WideNavigationRailValue.Expanded,
|
||||||
selected = selected,
|
selected = selected,
|
||||||
@@ -148,7 +169,57 @@ fun MainScreen(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
icon = {
|
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") {
|
label = if (labelVisibilityMode != "unlabeled") {
|
||||||
{ Text(stringResource(destination.labelId)) }
|
{ Text(stringResource(destination.labelId)) }
|
||||||
@@ -181,6 +252,9 @@ fun MainScreen(
|
|||||||
}
|
}
|
||||||
destinations.forEachIndexed { index, destination ->
|
destinations.forEachIndexed { index, destination ->
|
||||||
val selected = pagerState.targetPage == index
|
val selected = pagerState.targetPage == index
|
||||||
|
var showGroupMenu by remember { mutableStateOf(false) }
|
||||||
|
val haptic = LocalHapticFeedback.current
|
||||||
|
|
||||||
NavigationBarItem(
|
NavigationBarItem(
|
||||||
selected = selected,
|
selected = selected,
|
||||||
onClick = {
|
onClick = {
|
||||||
@@ -189,7 +263,61 @@ fun MainScreen(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
icon = {
|
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(
|
colors = NavigationBarItemDefaults.colors(
|
||||||
indicatorColor = GlassDefaults.glassColor(
|
indicatorColor = GlassDefaults.glassColor(
|
||||||
@@ -215,7 +343,8 @@ fun MainScreen(
|
|||||||
userScrollEnabled = true,
|
userScrollEnabled = true,
|
||||||
beyondViewportPageCount = 3
|
beyondViewportPageCount = 3
|
||||||
) { page ->
|
) { page ->
|
||||||
when (destinations[page]) {
|
val destination = destinations.getOrNull(page) ?: return@HorizontalPager
|
||||||
|
when (destination) {
|
||||||
MainDestination.Bookshelf -> BookshelfScreen(
|
MainDestination.Bookshelf -> BookshelfScreen(
|
||||||
onBookClick = { book ->
|
onBookClick = { book ->
|
||||||
context.startActivityForBook(book)
|
context.startActivityForBook(book)
|
||||||
@@ -248,14 +377,17 @@ fun MainScreen(
|
|||||||
private fun NavigationIcon(
|
private fun NavigationIcon(
|
||||||
destination: MainDestination,
|
destination: MainDestination,
|
||||||
selected: Boolean,
|
selected: Boolean,
|
||||||
upBooksCount: Int
|
upBooksCount: Int,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val icon = if (selected) destination.selectedIcon else destination.icon
|
val icon = if (selected) destination.selectedIcon else destination.icon
|
||||||
if (destination == MainDestination.Bookshelf && upBooksCount > 0) {
|
Box(modifier = modifier) {
|
||||||
BadgedBox(badge = { Badge { Text(upBooksCount.toString()) } }) {
|
if (destination == MainDestination.Bookshelf && upBooksCount > 0) {
|
||||||
|
BadgedBox(badge = { Badge { Text(upBooksCount.toString()) } }) {
|
||||||
|
Icon(icon, contentDescription = null)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
Icon(icon, contentDescription = null)
|
Icon(icon, contentDescription = null)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Icon(icon, contentDescription = null)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user