优化
This commit is contained in:
4 files changed
+60
-26
No files matched your search
@@ -9,6 +9,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
|
import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
|
||||||
|
import io.legado.app.ui.widget.components.settingItem.CompactDropdownSettingItem
|
||||||
import io.legado.app.ui.widget.components.settingItem.DropdownListSettingItem
|
import io.legado.app.ui.widget.components.settingItem.DropdownListSettingItem
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -39,7 +40,7 @@ fun <T> HomepageLayoutSheet(
|
|||||||
title = stringResource(R.string.homepage_layout_settings),
|
title = stringResource(R.string.homepage_layout_settings),
|
||||||
) {
|
) {
|
||||||
Column {
|
Column {
|
||||||
DropdownListSettingItem(
|
CompactDropdownSettingItem(
|
||||||
title = stringResource(R.string.homepage_layout_mode),
|
title = stringResource(R.string.homepage_layout_mode),
|
||||||
selectedValue = layoutMode.toString(),
|
selectedValue = layoutMode.toString(),
|
||||||
displayEntries = arrayOf(
|
displayEntries = arrayOf(
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ import io.legado.app.ui.main.homepage.modules.GridRankingModule
|
|||||||
import io.legado.app.ui.main.homepage.modules.HomepageModuleSkeleton
|
import io.legado.app.ui.main.homepage.modules.HomepageModuleSkeleton
|
||||||
import io.legado.app.ui.main.homepage.modules.RankingModule
|
import io.legado.app.ui.main.homepage.modules.RankingModule
|
||||||
import io.legado.app.ui.main.homepage.modules.WaterfallItem
|
import io.legado.app.ui.main.homepage.modules.WaterfallItem
|
||||||
|
import io.legado.app.ui.config.themeConfig.ThemeConfig
|
||||||
import io.legado.app.ui.theme.LegadoTheme
|
import io.legado.app.ui.theme.LegadoTheme
|
||||||
|
import io.legado.app.ui.theme.adaptiveContentPaddingBookshelf
|
||||||
import io.legado.app.ui.widget.components.AppPullToRefresh
|
import io.legado.app.ui.widget.components.AppPullToRefresh
|
||||||
import io.legado.app.ui.widget.components.AppScaffold
|
import io.legado.app.ui.widget.components.AppScaffold
|
||||||
import io.legado.app.ui.widget.components.LoadMoreFooter
|
import io.legado.app.ui.widget.components.LoadMoreFooter
|
||||||
@@ -84,6 +86,7 @@ import io.legado.app.ui.widget.components.card.GlassCard
|
|||||||
import io.legado.app.ui.widget.components.icon.AppIcon
|
import io.legado.app.ui.widget.components.icon.AppIcon
|
||||||
import io.legado.app.ui.widget.components.tabRow.AppTabRow
|
import io.legado.app.ui.widget.components.tabRow.AppTabRow
|
||||||
import io.legado.app.ui.widget.components.EmptyMessage
|
import io.legado.app.ui.widget.components.EmptyMessage
|
||||||
|
import io.legado.app.ui.widget.components.icon.AppIcons
|
||||||
import io.legado.app.ui.widget.components.text.AppText
|
import io.legado.app.ui.widget.components.text.AppText
|
||||||
import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
|
import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
|
||||||
import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
|
import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
|
||||||
@@ -171,12 +174,12 @@ fun HomepageScreen(
|
|||||||
actions = {
|
actions = {
|
||||||
TopBarActionButton(
|
TopBarActionButton(
|
||||||
onClick = { viewModel.toggleConfigMode() },
|
onClick = { viewModel.toggleConfigMode() },
|
||||||
imageVector = Icons.Default.GridView,
|
imageVector = AppIcons.MoreCircle,
|
||||||
contentDescription = "Layout Settings",
|
contentDescription = "Layout Settings",
|
||||||
)
|
)
|
||||||
TopBarActionButton(
|
TopBarActionButton(
|
||||||
onClick = { viewModel.toggleManageMode() },
|
onClick = { viewModel.toggleManageMode() },
|
||||||
imageVector = Icons.Default.Settings,
|
imageVector = AppIcons.Settings,
|
||||||
contentDescription = "Manage Modules",
|
contentDescription = "Manage Modules",
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@@ -200,14 +203,14 @@ fun HomepageScreen(
|
|||||||
AppPullToRefresh(
|
AppPullToRefresh(
|
||||||
isRefreshing = uiState.isRefreshing,
|
isRefreshing = uiState.isRefreshing,
|
||||||
onRefresh = { viewModel.onRefresh() },
|
onRefresh = { viewModel.onRefresh() },
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxSize(),
|
||||||
.fillMaxSize()
|
|
||||||
.padding(paddingValues),
|
|
||||||
) {
|
) {
|
||||||
if (selectedSets.isEmpty()) {
|
if (selectedSets.isEmpty()) {
|
||||||
EmptyMessage(
|
EmptyMessage(
|
||||||
messageResId = R.string.homepage_no_source_sets_selected,
|
messageResId = R.string.homepage_no_source_sets_selected,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(paddingValues),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
HorizontalPager(
|
HorizontalPager(
|
||||||
@@ -231,6 +234,7 @@ fun HomepageScreen(
|
|||||||
modules = sourceModules,
|
modules = sourceModules,
|
||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
paddingValues = paddingValues,
|
||||||
onErrorClick = { errorMsg = it },
|
onErrorClick = { errorMsg = it },
|
||||||
sharedTransitionScope = sharedTransitionScope,
|
sharedTransitionScope = sharedTransitionScope,
|
||||||
animatedVisibilityScope = animatedVisibilityScope,
|
animatedVisibilityScope = animatedVisibilityScope,
|
||||||
@@ -344,6 +348,7 @@ private fun ModuleList(
|
|||||||
modules: List<HomepageModuleUi>,
|
modules: List<HomepageModuleUi>,
|
||||||
viewModel: HomepageViewModel,
|
viewModel: HomepageViewModel,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
paddingValues: PaddingValues = PaddingValues(0.dp),
|
||||||
gridState: LazyStaggeredGridState = rememberLazyStaggeredGridState(),
|
gridState: LazyStaggeredGridState = rememberLazyStaggeredGridState(),
|
||||||
sharedTransitionScope: SharedTransitionScope? = null,
|
sharedTransitionScope: SharedTransitionScope? = null,
|
||||||
animatedVisibilityScope: AnimatedVisibilityScope? = null,
|
animatedVisibilityScope: AnimatedVisibilityScope? = null,
|
||||||
@@ -381,7 +386,11 @@ private fun ModuleList(
|
|||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
verticalItemSpacing = 16.dp,
|
verticalItemSpacing = 16.dp,
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
contentPadding = PaddingValues(start = 16.dp, end = 16.dp, bottom = 80.dp),
|
contentPadding = adaptiveContentPaddingBookshelf(
|
||||||
|
top = paddingValues.calculateTopPadding(),
|
||||||
|
bottom = if (ThemeConfig.useFloatingBottomBar || ThemeConfig.enableBlur) 120.dp else 8.dp,
|
||||||
|
horizontal = 4.dp
|
||||||
|
),
|
||||||
) {
|
) {
|
||||||
processedModules.forEach { moduleUi ->
|
processedModules.forEach { moduleUi ->
|
||||||
// 1. 头部 (全宽)
|
// 1. 头部 (全宽)
|
||||||
|
|||||||
@@ -104,9 +104,6 @@ class HomepageViewModel(
|
|||||||
private val _layoutConfigCache = MutableStateFlow<Map<String, Map<String, String>>>(emptyMap())
|
private val _layoutConfigCache = MutableStateFlow<Map<String, Map<String, String>>>(emptyMap())
|
||||||
private val _pendingEnabled = MutableStateFlow<Map<String, Boolean>>(emptyMap())
|
private val _pendingEnabled = MutableStateFlow<Map<String, Boolean>>(emptyMap())
|
||||||
private val _pendingUserModules = MutableStateFlow<List<ModuleItem>>(emptyList())
|
private val _pendingUserModules = MutableStateFlow<List<ModuleItem>>(emptyList())
|
||||||
private val _exploreKindsCache =
|
|
||||||
MutableStateFlow<Map<String, List<Pair<String, String>>>>(emptyMap())
|
|
||||||
|
|
||||||
// 2. 数据库同步流
|
// 2. 数据库同步流
|
||||||
private val localModulesFlow = gateway.flowEnabled()
|
private val localModulesFlow = gateway.flowEnabled()
|
||||||
val allModulesCache =
|
val allModulesCache =
|
||||||
@@ -228,27 +225,44 @@ class HomepageViewModel(
|
|||||||
rawModulesFlow,
|
rawModulesFlow,
|
||||||
_bookshelf
|
_bookshelf
|
||||||
) { modules, bookshelf ->
|
) { modules, bookshelf ->
|
||||||
|
if (bookshelf.isEmpty()) {
|
||||||
modules.map { module ->
|
modules.map { module ->
|
||||||
val state = module.state
|
val state = module.state
|
||||||
if (state is ModuleLoadState.Loaded) {
|
if (state is ModuleLoadState.Loaded) {
|
||||||
module.copy(
|
module.copy(state = state.copy(
|
||||||
state = state.copy(
|
|
||||||
books = state.books.map { item ->
|
books = state.books.map { item ->
|
||||||
item.copy(
|
if (item.shelfState == BookShelfState.NOT_IN_SHELF) item
|
||||||
shelfState = resolveBookShelfStateUseCase.execute(
|
else item.copy(shelfState = BookShelfState.NOT_IN_SHELF)
|
||||||
name = item.book.name,
|
}.toImmutableList()
|
||||||
author = item.book.author,
|
))
|
||||||
url = item.book.bookUrl,
|
} else module
|
||||||
shelf = bookshelf
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}.toImmutableList()
|
}.toImmutableList()
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
module
|
val exactKeys = HashSet<Triple<String, String, String?>>(bookshelf.size)
|
||||||
|
val nameAuthorKeys = HashSet<Pair<String, String>>(bookshelf.size)
|
||||||
|
for (key in bookshelf) {
|
||||||
|
exactKeys.add(Triple(key.name, key.author, key.url))
|
||||||
|
nameAuthorKeys.add(key.name to key.author)
|
||||||
}
|
}
|
||||||
|
modules.map { module ->
|
||||||
|
val state = module.state
|
||||||
|
if (state is ModuleLoadState.Loaded) {
|
||||||
|
module.copy(state = state.copy(
|
||||||
|
books = state.books.map { item ->
|
||||||
|
val bookTriple = Triple(item.book.name, item.book.author, item.book.bookUrl)
|
||||||
|
val newShelfState = when {
|
||||||
|
bookTriple in exactKeys -> BookShelfState.IN_SHELF
|
||||||
|
(item.book.name to item.book.author) in nameAuthorKeys ->
|
||||||
|
BookShelfState.SAME_NAME_AUTHOR
|
||||||
|
else -> BookShelfState.NOT_IN_SHELF
|
||||||
|
}
|
||||||
|
if (item.shelfState == newShelfState) item
|
||||||
|
else item.copy(shelfState = newShelfState)
|
||||||
}.toImmutableList()
|
}.toImmutableList()
|
||||||
|
))
|
||||||
|
} else module
|
||||||
|
}.toImmutableList()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 最终 UI 状态
|
// 5. 最终 UI 状态
|
||||||
@@ -308,6 +322,10 @@ class HomepageViewModel(
|
|||||||
allModulesCache.collect { modules ->
|
allModulesCache.collect { modules ->
|
||||||
val dbIds = modules.map { it.id }.toSet()
|
val dbIds = modules.map { it.id }.toSet()
|
||||||
_pendingUserModules.update { pending -> pending.filter { it.id !in dbIds } }
|
_pendingUserModules.update { pending -> pending.filter { it.id !in dbIds } }
|
||||||
|
_moduleContentStates.update { states ->
|
||||||
|
if (states.keys.any { it !in dbIds }) states.filterKeys { it in dbIds }
|
||||||
|
else states
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,8 +632,7 @@ class HomepageViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSourceExploreKinds(sourceUrl: String): List<Pair<String, String>> =
|
fun getSourceExploreKinds(sourceUrl: String): List<Pair<String, String>> = emptyList()
|
||||||
_exploreKindsCache.value[sourceUrl].orEmpty()
|
|
||||||
|
|
||||||
fun updateModule(globalId: String, def: ModuleDef) {
|
fun updateModule(globalId: String, def: ModuleDef) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import androidx.compose.material.icons.filled.FilterList
|
|||||||
import androidx.compose.material.icons.filled.History
|
import androidx.compose.material.icons.filled.History
|
||||||
import androidx.compose.material.icons.filled.Home
|
import androidx.compose.material.icons.filled.Home
|
||||||
import androidx.compose.material.icons.filled.LocationSearching
|
import androidx.compose.material.icons.filled.LocationSearching
|
||||||
|
import androidx.compose.material.icons.filled.MoreHoriz
|
||||||
import androidx.compose.material.icons.filled.MoreVert
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
import androidx.compose.material.icons.filled.MyLocation
|
import androidx.compose.material.icons.filled.MyLocation
|
||||||
import androidx.compose.material.icons.filled.Person
|
import androidx.compose.material.icons.filled.Person
|
||||||
@@ -40,6 +41,7 @@ import top.yukonga.miuix.kmp.icon.extended.Edit
|
|||||||
import top.yukonga.miuix.kmp.icon.extended.Favorites
|
import top.yukonga.miuix.kmp.icon.extended.Favorites
|
||||||
import top.yukonga.miuix.kmp.icon.extended.Filter
|
import top.yukonga.miuix.kmp.icon.extended.Filter
|
||||||
import top.yukonga.miuix.kmp.icon.extended.More
|
import top.yukonga.miuix.kmp.icon.extended.More
|
||||||
|
import top.yukonga.miuix.kmp.icon.extended.MoreCircle
|
||||||
import top.yukonga.miuix.kmp.icon.extended.Notes
|
import top.yukonga.miuix.kmp.icon.extended.Notes
|
||||||
import top.yukonga.miuix.kmp.icon.extended.Pin
|
import top.yukonga.miuix.kmp.icon.extended.Pin
|
||||||
import top.yukonga.miuix.kmp.icon.extended.Refresh
|
import top.yukonga.miuix.kmp.icon.extended.Refresh
|
||||||
@@ -105,6 +107,11 @@ object AppIcons {
|
|||||||
@Composable
|
@Composable
|
||||||
get() = if (isMiuix) MiuixIcons.Refresh else Icons.Default.Replay
|
get() = if (isMiuix) MiuixIcons.Refresh else Icons.Default.Replay
|
||||||
|
|
||||||
|
val MoreCircle: ImageVector
|
||||||
|
@Composable
|
||||||
|
get() = if (isMiuix) MiuixIcons.MoreCircle else Icons.Default.MoreHoriz
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun mainDestination(destination: MainDestination, selected: Boolean): ImageVector {
|
fun mainDestination(destination: MainDestination, selected: Boolean): ImageVector {
|
||||||
return when (destination) {
|
return when (destination) {
|
||||||
|
|||||||
Reference in new issue
Block a user