From 1d585ecec9786a3ed9678ff4ed6615a78bca64ba Mon Sep 17 00:00:00 2001
From: HapeLee <63206378+HapeLee@users.noreply.github.com>
Date: Sat, 11 Apr 2026 17:21:55 +0800
Subject: [PATCH] =?UTF-8?q?[=E4=BC=98=E5=8C=96]=20=E7=95=8C=E9=9D=A2?=
=?UTF-8?q?=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/src/main/AndroidManifest.xml | 10 -
.../main/java/io/legado/app/di/appModule.kt | 2 +
.../app/ui/book/bookmark/AllBookmarkScreen.kt | 3 +-
.../app/ui/book/explore/ExploreShowScreen.kt | 1 -
.../ui/book/import/BaseImportBookActivity.kt | 163 ------
.../ui/book/import/local/ImportBookScreen.kt | 497 ++++++++++++++++++
.../ui/book/info/edit/BookInfoEditScreen.kt | 6 +-
.../ui/book/readRecord/ReadRecordScreen.kt | 189 +++++--
.../book/searchContent/SearchContentScreen.kt | 4 +-
.../io/legado/app/ui/book/toc/TocScreen.kt | 2 +-
.../app/ui/book/toc/rule/TxtRuleScreen.kt | 7 +-
.../DirectLinkUploadBottomSheet.kt | 2 +-
.../legado/app/ui/dict/rule/DictRuleScreen.kt | 4 +-
.../io/legado/app/ui/main/MainActivity.kt | 41 ++
.../java/io/legado/app/ui/main/MainScreen.kt | 8 +-
.../app/ui/main/bookshelf/BookshelfScreen.kt | 47 +-
.../app/ui/main/bookshelf/GroupManageSheet.kt | 3 +-
.../app/ui/main/explore/ExploreScreen.kt | 5 +-
.../java/io/legado/app/ui/main/my/MyScreen.kt | 5 +-
.../app/ui/replace/ReplaceRuleActivity.kt | 4 +-
.../app/ui/replace/edit/ReplaceEditScreen.kt | 76 +--
.../ui/rss/favorites/RssFavoritesScreen.kt | 5 +-
.../ui/rss/source/manage/RssSourceScreen.kt | 3 +-
.../io/legado/app/ui/theme/AdaptivePadding.kt | 2 +-
.../legado/app/ui/widget/CollapsibleHeader.kt | 3 +-
.../ui/widget/components/AppRadioButtom.kt | 35 ++
.../components/GroupManageBottomSheet.kt | 5 +-
.../app/ui/widget/components/ValueStepper.kt | 8 +-
.../components/button/MediumIconButton.kt | 30 +-
.../components/button/SmallIconButton.kt | 25 +-
.../components/button/SmallTextButton.kt | 6 +-
.../ui/widget/components/button/ToggleChip.kt | 87 +++
.../components/card/SelectionItemCard.kt | 5 +-
.../heatmap/HeatmapCalendarComponents.kt | 63 ++-
.../modalBottomSheet/AppModalBottomSheet.kt | 7 +-
.../modalBottomSheet/OptionSheet.kt | 3 +-
.../widget/components/rules/RuleEditSheet.kt | 76 +--
.../settingItem/InputSettingItem.kt | 10 +-
.../settingItem/SliderSettingItem.kt | 25 +-
.../components/swipe/SwipeActionContainer.kt | 5 +-
gradle/libs.versions.toml | 10 +-
41 files changed, 1041 insertions(+), 451 deletions(-)
delete mode 100644 app/src/main/java/io/legado/app/ui/book/import/BaseImportBookActivity.kt
create mode 100644 app/src/main/java/io/legado/app/ui/book/import/local/ImportBookScreen.kt
create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/AppRadioButtom.kt
create mode 100644 app/src/main/java/io/legado/app/ui/widget/components/button/ToggleChip.kt
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 00ea91137..6d8a02238 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -274,16 +274,6 @@
android:configChanges="orientation|screenSize"
android:hardwareAccelerated="true"
android:launchMode="singleTop" />
-
-
-
-
:
- VMBaseActivity() {
-
- final override val binding by viewBinding(ActivityImportBookBinding::inflate)
-
- private var localBookTreeSelectListener: ((Boolean) -> Unit)? = null
- protected val searchView: SearchView by lazy {
- binding.titleBar.findViewById(R.id.search_view)
- }
-
- val localBookTreeSelect = registerForActivityResult(HandleFileContract()) {
- it.uri?.let { treeUri ->
- AppConfig.defaultBookTreeUri = treeUri.toString()
- localBookTreeSelectListener?.invoke(true)
- } ?: localBookTreeSelectListener?.invoke(false)
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- initSearchView()
- }
-
- /**
- * 设置书籍保存位置
- */
- protected suspend fun setBookStorage() = suspendCoroutine { block ->
- localBookTreeSelectListener = {
- localBookTreeSelectListener = null
- block.resume(it)
- }
- //测试书籍保存位置是否设置
- if (!AppConfig.defaultBookTreeUri.isNullOrBlank()) {
- localBookTreeSelectListener = null
- block.resume(true)
- return@suspendCoroutine
- }
- //测试读写??
- val storageHelp = String(assets.open("storageHelp.md").readBytes())
- val hint = getString(R.string.select_book_folder)
- alert(hint, storageHelp) {
- okButton {
- localBookTreeSelect.launch {
- title = hint
- }
- }
- cancelButton {
- localBookTreeSelectListener = null
- block.resume(false)
- }
- onCancelled {
- localBookTreeSelectListener = null
- block.resume(false)
- }
- }
- }
-
- abstract fun onSearchTextChange(newText: String?)
-
- protected fun startReadBook(book: Book) {
- startActivityForBook(book)
- }
-
- protected fun onArchiveFileClick(fileDoc: FileDoc) {
- val fileNames = ArchiveUtils.getArchiveFilesName(fileDoc) {
- it.matches(AppPattern.bookFileRegex)
- }
- if (fileNames.size == 1) {
- val name = fileNames[0]
- appDb.bookDao.getBookByFileName(name)?.let {
- startReadBook(it)
- } ?: showImportAlert(fileDoc, name)
- } else {
- showSelectBookReadAlert(fileDoc, fileNames)
- }
- }
-
- private fun showSelectBookReadAlert(fileDoc: FileDoc, fileNames: List) {
- if (fileNames.isEmpty()) {
- toastOnUi(R.string.unsupport_archivefile_entry)
- return
- }
- selector(
- R.string.start_read,
- fileNames
- ) { _, name, _ ->
- appDb.bookDao.getBookByFileName(name)?.let {
- startReadBook(it)
- } ?: showImportAlert(fileDoc, name)
- }
- }
-
- /* 添加压缩包内指定文件到书架 */
- private inline fun addArchiveToBookShelf(
- fileDoc: FileDoc,
- fileName: String,
- onSuccess: (Book) -> Unit
- ) {
- LocalBook.importArchiveFile(fileDoc.uri, fileName) {
- it.contains(fileName)
- }.firstOrNull()?.run {
- onSuccess.invoke(this)
- }
- }
-
- /* 提示是否重新导入所点击的压缩文件 */
- private fun showImportAlert(fileDoc: FileDoc, fileName: String) {
- alert(
- R.string.draw,
- R.string.no_book_found_bookshelf
- ) {
- okButton {
- addArchiveToBookShelf(fileDoc, fileName) {
- startReadBook(it)
- }
- }
- noButton()
- }
- }
-
- private fun initSearchView() {
- //searchView.applyTint(primaryTextColor)
- searchView.isSubmitButtonEnabled = true
- searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
- override fun onQueryTextSubmit(query: String?): Boolean {
- return false
- }
-
- override fun onQueryTextChange(newText: String?): Boolean {
- onSearchTextChange(newText)
- return false
- }
- })
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/io/legado/app/ui/book/import/local/ImportBookScreen.kt b/app/src/main/java/io/legado/app/ui/book/import/local/ImportBookScreen.kt
new file mode 100644
index 000000000..d76617c3d
--- /dev/null
+++ b/app/src/main/java/io/legado/app/ui/book/import/local/ImportBookScreen.kt
@@ -0,0 +1,497 @@
+package io.legado.app.ui.book.import.local
+
+import android.net.Uri
+import androidx.activity.compose.rememberLauncherForActivityResult
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.compose.animation.animateContentSize
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.lazy.itemsIndexed
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.filled.ArrowBack
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material.icons.filled.ChevronRight
+import androidx.compose.material.icons.filled.CloudDownload
+import androidx.compose.material.icons.filled.Delete
+import androidx.compose.material.icons.filled.Folder
+import androidx.compose.material.icons.filled.FolderOpen
+import androidx.compose.material.icons.outlined.Book
+import androidx.compose.material.icons.outlined.Description
+import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedTextField
+import androidx.compose.material3.pulltorefresh.PullToRefreshBox
+import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import androidx.core.net.toUri
+import androidx.documentfile.provider.DocumentFile
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import io.legado.app.R
+import io.legado.app.constant.AppConst
+import io.legado.app.constant.AppPattern
+import io.legado.app.data.appDb
+import io.legado.app.data.entities.Book
+import io.legado.app.help.config.AppConfig
+import io.legado.app.lib.dialogs.alert
+import io.legado.app.lib.dialogs.selector
+import io.legado.app.lib.permission.Permissions
+import io.legado.app.lib.permission.PermissionsCompat
+import io.legado.app.model.localBook.LocalBook
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.widget.components.ActionItem
+import io.legado.app.ui.widget.components.EmptyMessageView
+import io.legado.app.ui.widget.components.SelectionActions
+import io.legado.app.ui.widget.components.alert.AppAlertDialog
+import io.legado.app.ui.widget.components.button.SmallTonalIconButton
+import io.legado.app.ui.widget.components.button.TopBarActionButton
+import io.legado.app.ui.widget.components.card.GlassCard
+import io.legado.app.ui.widget.components.card.TextCard
+import io.legado.app.ui.widget.components.filePicker.FilePickerSheet
+import io.legado.app.ui.widget.components.list.ListScaffold
+import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
+import io.legado.app.ui.widget.components.text.AppText
+import io.legado.app.utils.ConvertUtils
+import io.legado.app.utils.ArchiveUtils
+import io.legado.app.utils.FileDoc
+import io.legado.app.utils.isContentScheme
+import io.legado.app.utils.isUri
+import io.legado.app.utils.startActivityForBook
+import io.legado.app.utils.takePersistablePermissionSafely
+import io.legado.app.utils.toastOnUi
+import org.koin.androidx.compose.koinViewModel
+import java.io.File
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+private fun ImportBookContent(
+ state: ImportBookUiState,
+ onBackClick: () -> Unit,
+ onSearchToggle: (Boolean) -> Unit,
+ onSearchQueryChange: (String) -> Unit,
+ onSelectFolder: () -> Unit,
+ onScanFolder: () -> Unit,
+ onImportFileName: () -> Unit,
+ onSortChange: (Int) -> Unit,
+ onNavigateBack: () -> Unit,
+ onNavigateToLevel: (Int) -> Unit,
+ onSelectAll: () -> Unit,
+ onSelectInvert: () -> Unit,
+ onAddToBookshelf: () -> Unit,
+ onDeleteSelection: () -> Unit,
+ onItemClick: (ImportBook) -> Unit
+) {
+ ListScaffold(
+ title = stringResource(R.string.local_book),
+ state = state,
+ onBackClick = onBackClick,
+ onSearchToggle = onSearchToggle,
+ onSearchQueryChange = onSearchQueryChange,
+ searchPlaceholder = stringResource(R.string.screen),
+ topBarActions = {
+ TopBarActionButton(
+ onClick = onSelectFolder,
+ imageVector = Icons.Default.FolderOpen,
+ contentDescription = stringResource(R.string.select_folder)
+ )
+ },
+ dropDownMenuContent = { dismiss ->
+ RoundDropdownMenuItem(
+ text = stringResource(R.string.sort_by_name),
+ onClick = {
+ onSortChange(0)
+ dismiss()
+ },
+ trailingIcon = {
+ if (state.sort == 0) {
+ Icon(Icons.Default.Check, null)
+ }
+ }
+ )
+ RoundDropdownMenuItem(
+ text = stringResource(R.string.sort_by_size),
+ onClick = {
+ onSortChange(1)
+ dismiss()
+ },
+ trailingIcon = {
+ if (state.sort == 1) {
+ Icon(Icons.Default.Check, null)
+ }
+ }
+ )
+ RoundDropdownMenuItem(
+ text = stringResource(R.string.sort_by_time),
+ onClick = {
+ onSortChange(2)
+ dismiss()
+ },
+ trailingIcon = {
+ if (state.sort == 2) {
+ Icon(Icons.Default.Check, null)
+ }
+ }
+ )
+ RoundDropdownMenuItem(
+ text = stringResource(R.string.scan_folder),
+ onClick = {
+ onScanFolder()
+ dismiss()
+ }
+ )
+ RoundDropdownMenuItem(
+ text = stringResource(R.string.import_file_name),
+ onClick = {
+ onImportFileName()
+ dismiss()
+ }
+ )
+ },
+ bottomContent = {
+ ImportPathNavigationBar(
+ pathNames = state.pathNames,
+ canGoBack = state.canGoBack,
+ onNavigateBack = onNavigateBack,
+ onNavigateToLevel = onNavigateToLevel
+ )
+ },
+ selectionActions = SelectionActions(
+ onSelectAll = onSelectAll,
+ onSelectInvert = onSelectInvert,
+ primaryAction = ActionItem(
+ text = stringResource(R.string.add_to_bookshelf),
+ icon = { Icon(Icons.Default.CloudDownload, null) },
+ onClick = onAddToBookshelf
+ ),
+ secondaryActions = listOf(
+ ActionItem(
+ text = stringResource(R.string.delete),
+ icon = { Icon(Icons.Default.Delete, null) },
+ onClick = onDeleteSelection
+ )
+ )
+ ),
+ onAddClick = null
+ ) { paddingValues ->
+ val refreshState = rememberPullToRefreshState()
+ PullToRefreshBox(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(paddingValues),
+ isRefreshing = state.isLoading,
+ state = refreshState,
+ onRefresh = onScanFolder
+ ) {
+ when {
+ state.items.isEmpty() && state.isLoading -> {
+ CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
+ }
+
+ state.items.isEmpty() -> {
+ EmptyMessageView(
+ modifier = Modifier.fillMaxSize(),
+ message = stringResource(R.string.empty_msg_import_book)
+ )
+ }
+
+ else -> {
+ LazyColumn(modifier = Modifier.fillMaxSize()) {
+ items(state.items, key = { it.selectionId }) { item ->
+ ImportBookItem(
+ modifier = Modifier.animateItem(),
+ item = item,
+ isSelected = item.selectionId in state.selectedIds,
+ onClick = { onItemClick(item) }
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun ImportBookScreen(
+ onBackClick: () -> Unit,
+ viewModel: ImportBookViewModel = koinViewModel()
+) {
+ val context = LocalContext.current
+ val uiState by viewModel.uiState.collectAsStateWithLifecycle()
+ var showFolderPicker by remember { mutableStateOf(false) }
+ var showImportFileNameDialog by remember { mutableStateOf(false) }
+ var fileNameJs by remember { mutableStateOf(AppConfig.bookImportFileName.orEmpty()) }
+ var pickerTarget by remember { mutableStateOf(ImportFolderPickTarget.IMPORT_FOLDER) }
+ val selectDocTree = rememberLauncherForActivityResult(
+ contract = ActivityResultContracts.OpenDocumentTree()
+ ) { uri ->
+ viewModel.dispatch(ImportBookIntent.FolderPicked(uri, pickerTarget))
+ }
+
+ LaunchedEffect(viewModel) {
+ viewModel.dispatch(ImportBookIntent.Initialize)
+ viewModel.effects.collect { effect ->
+ when (effect) {
+ is ImportBookEffect.RequestFolderPicker -> {
+ pickerTarget = effect.target
+ selectDocTree.launch(effect.initialUri)
+ }
+
+ is ImportBookEffect.OpenBook -> {
+ context.startActivityForBook(effect.book)
+ }
+
+ is ImportBookEffect.ShowArchiveEntries -> {
+ context.selector(R.string.start_read, effect.fileNames) { _, name, _ ->
+ viewModel.dispatch(
+ ImportBookIntent.ArchiveEntrySelected(effect.fileDoc, name)
+ )
+ }
+ }
+
+ is ImportBookEffect.ShowImportArchiveDialog -> {
+ context.alert(R.string.draw, R.string.no_book_found_bookshelf) {
+ okButton {
+ viewModel.dispatch(
+ ImportBookIntent.ImportArchiveConfirmed(
+ effect.fileDoc,
+ effect.fileName
+ )
+ )
+ }
+ noButton()
+ }
+ }
+
+ is ImportBookEffect.ShowToastRes -> {
+ context.toastOnUi(effect.resId)
+ }
+ }
+ }
+ }
+
+ FilePickerSheet(
+ show = showFolderPicker,
+ onDismissRequest = { showFolderPicker = false },
+ title = stringResource(R.string.select_folder),
+ onSelectSysDir = {
+ showFolderPicker = false
+ viewModel.dispatch(ImportBookIntent.SelectFolderClick)
+ }
+ )
+
+ AppAlertDialog(
+ show = showImportFileNameDialog,
+ onDismissRequest = { showImportFileNameDialog = false },
+ title = stringResource(R.string.import_file_name),
+ content = {
+ AppText("Use js to parse file name from src, then assign name/author.")
+ OutlinedTextField(
+ value = fileNameJs,
+ onValueChange = { fileNameJs = it },
+ label = { AppText("js") }
+ )
+ },
+ confirmText = stringResource(android.R.string.ok),
+ onConfirm = {
+ AppConfig.bookImportFileName = fileNameJs
+ showImportFileNameDialog = false
+ },
+ dismissText = stringResource(android.R.string.cancel),
+ onDismiss = { showImportFileNameDialog = false }
+ )
+
+ ImportBookContent(
+ state = uiState,
+ onBackClick = onBackClick,
+ onSearchToggle = { viewModel.dispatch(ImportBookIntent.SearchToggle(it)) },
+ onSearchQueryChange = { viewModel.dispatch(ImportBookIntent.SearchQueryChange(it)) },
+ onSelectFolder = { showFolderPicker = true },
+ onScanFolder = { viewModel.dispatch(ImportBookIntent.ScanFolder) },
+ onImportFileName = {
+ fileNameJs = AppConfig.bookImportFileName.orEmpty()
+ showImportFileNameDialog = true
+ },
+ onSortChange = { viewModel.dispatch(ImportBookIntent.SortChange(it)) },
+ onNavigateBack = { viewModel.dispatch(ImportBookIntent.NavigateBack) },
+ onNavigateToLevel = { viewModel.dispatch(ImportBookIntent.NavigateToLevel(it)) },
+ onSelectAll = { viewModel.dispatch(ImportBookIntent.SelectAll) },
+ onSelectInvert = { viewModel.dispatch(ImportBookIntent.SelectInvert) },
+ onAddToBookshelf = { viewModel.dispatch(ImportBookIntent.AddToBookshelf) },
+ onDeleteSelection = { viewModel.dispatch(ImportBookIntent.DeleteSelection) },
+ onItemClick = { viewModel.dispatch(ImportBookIntent.ItemClick(it)) }
+ )
+}
+
+@Composable
+private fun ImportPathNavigationBar(
+ pathNames: List,
+ canGoBack: Boolean,
+ onNavigateBack: () -> Unit,
+ onNavigateToLevel: (Int) -> Unit
+) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(start = 16.dp, end = 16.dp, bottom = 4.dp)
+ .animateContentSize(),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(8.dp)
+ ) {
+ GlassCard(
+ modifier = Modifier.weight(1f),
+ containerColor = LegadoTheme.colorScheme.surfaceContainer
+ ) {
+ LazyRow(
+ modifier = Modifier.fillMaxWidth(),
+ contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(4.dp)
+ ) {
+ itemsIndexed(pathNames) { index, name ->
+ val isLast = index == pathNames.lastIndex
+ AppText(
+ text = name,
+ style = LegadoTheme.typography.labelSmall,
+ fontWeight = if (isLast) FontWeight.SemiBold else FontWeight.Medium,
+ color = if (isLast) {
+ LegadoTheme.colorScheme.primary
+ } else {
+ LegadoTheme.colorScheme.onSurfaceVariant
+ },
+ modifier = Modifier
+ .clip(MaterialTheme.shapes.small)
+ .then(if (!isLast) Modifier.clickable { onNavigateToLevel(index) } else Modifier)
+ .padding(horizontal = 4.dp, vertical = 4.dp)
+ )
+ if (!isLast) {
+ Icon(
+ imageVector = Icons.Default.ChevronRight,
+ contentDescription = null,
+ modifier = Modifier.size(12.dp),
+ tint = LegadoTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f)
+ )
+ }
+ }
+ }
+ }
+
+ if (canGoBack) {
+ SmallTonalIconButton(
+ onClick = onNavigateBack,
+ imageVector = Icons.AutoMirrored.Filled.ArrowBack,
+ contentDescription = "back"
+ )
+ }
+ }
+}
+
+@Composable
+private fun ImportBookItem(
+ modifier: Modifier,
+ item: ImportBook,
+ isSelected: Boolean,
+ onClick: () -> Unit
+) {
+ val containerColor = if (isSelected) {
+ LegadoTheme.colorScheme.secondaryContainer
+ } else {
+ LegadoTheme.colorScheme.surfaceContainer
+ }
+
+ GlassCard(
+ modifier = modifier
+ .fillMaxWidth()
+ .padding(horizontal = 16.dp, vertical = 4.dp),
+ onClick = onClick,
+ containerColor = containerColor
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 16.dp, vertical = 12.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Icon(
+ imageVector = when {
+ item.isDir -> Icons.Default.Folder
+ item.isOnBookShelf -> Icons.Outlined.Book
+ else -> Icons.Outlined.Description
+ },
+ contentDescription = null,
+ modifier = Modifier.size(20.dp),
+ tint = if (item.isDir) {
+ LegadoTheme.colorScheme.primary
+ } else {
+ LegadoTheme.colorScheme.onSurfaceVariant
+ }
+ )
+
+ Spacer(modifier = Modifier.width(16.dp))
+
+ Column(modifier = Modifier.weight(1f)) {
+ AppText(
+ text = item.name,
+ style = LegadoTheme.typography.bodyMedium,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis
+ )
+
+ if (!item.isDir) {
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ TextCard(
+ text = item.name.substringAfterLast('.', "").uppercase(),
+ textStyle = LegadoTheme.typography.labelSmall,
+ horizontalPadding = 4.dp,
+ verticalPadding = 2.dp,
+ cornerRadius = 4.dp,
+ icon = null,
+ backgroundColor = LegadoTheme.colorScheme.surfaceContainerHighest
+ )
+ Spacer(modifier = Modifier.width(6.dp))
+ AppText(
+ text = "${ConvertUtils.formatFileSize(item.size)} - ${AppConst.dateFormat.format(item.lastModified)}",
+ style = LegadoTheme.typography.labelMedium,
+ color = LegadoTheme.colorScheme.onSurfaceVariant
+ )
+ }
+ }
+ }
+
+ if (!item.isDir && !item.isOnBookShelf) {
+ Spacer(modifier = Modifier.width(8.dp))
+ Icon(
+ imageVector = if (isSelected) Icons.Default.Check else Icons.Default.ChevronRight,
+ contentDescription = null,
+ tint = LegadoTheme.colorScheme.primary
+ )
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditScreen.kt b/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditScreen.kt
index 815f002a1..e53b377dd 100644
--- a/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditScreen.kt
+++ b/app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditScreen.kt
@@ -145,15 +145,15 @@ fun BookInfoEditContent(
)
)
},
- icon = Icons.Default.ImageSearch
+ imageVector = Icons.Default.ImageSearch
)
MediumOutlinedIconButton(
onClick = { selectCover.launch() },
- icon = Icons.Default.FolderOpen
+ imageVector = Icons.Default.FolderOpen
)
MediumOutlinedIconButton(
onClick = { viewModel.resetCover() },
- icon = Icons.Default.Replay
+ imageVector = Icons.Default.Replay
)
}
Spacer(modifier = Modifier.height(4.dp))
diff --git a/app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt b/app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt
index 163045988..318e45ed5 100644
--- a/app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt
+++ b/app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt
@@ -69,6 +69,8 @@ import cn.hutool.core.date.DateUtil
import io.legado.app.data.entities.readRecord.ReadRecord
import io.legado.app.data.entities.readRecord.ReadRecordDetail
import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.adaptiveContentPadding
+import io.legado.app.ui.theme.adaptiveContentPaddingOnlyVertical
import io.legado.app.ui.theme.adaptiveHorizontalPadding
import io.legado.app.ui.widget.CollapsibleHeader
import io.legado.app.ui.widget.components.AppScaffold
@@ -78,9 +80,12 @@ import io.legado.app.ui.widget.components.alert.AppAlertDialog
import io.legado.app.ui.widget.components.button.AppIconButton
import io.legado.app.ui.widget.components.button.TopBarNavigationButton
import io.legado.app.ui.widget.components.card.GlassCard
+import io.legado.app.ui.widget.components.card.TextCard
import io.legado.app.ui.widget.components.checkBox.CheckboxItem
import io.legado.app.ui.widget.components.cover.Cover
-import io.legado.app.ui.widget.components.heatmap.HeatmapCalendarTopBar
+import io.legado.app.ui.widget.components.heatmap.HEATMAP_CALENDAR_TITLE
+import io.legado.app.ui.widget.components.heatmap.HeatmapCalendarEndAction
+import io.legado.app.ui.widget.components.heatmap.HeatmapCalendarStartAction
import io.legado.app.ui.widget.components.heatmap.HeatmapConfig
import io.legado.app.ui.widget.components.heatmap.HeatmapLegend
import io.legado.app.ui.widget.components.heatmap.HeatmapMode
@@ -91,6 +96,7 @@ import io.legado.app.ui.widget.components.heatmap.rememberDateRange
import io.legado.app.ui.widget.components.heatmap.rememberDaysInRange
import io.legado.app.ui.widget.components.heatmap.rememberWeeks
import io.legado.app.ui.widget.components.icon.AppIcon
+import io.legado.app.ui.widget.components.list.TopFloatingStickyItem
import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
import io.legado.app.ui.widget.components.swipe.SwipeAction
import io.legado.app.ui.widget.components.swipe.SwipeActionContainer
@@ -118,6 +124,7 @@ fun ReadRecordScreen(
val displayMode by viewModel.displayMode.collectAsState()
var showSearch by remember { mutableStateOf(false) }
var showCalendar by remember { mutableStateOf(false) }
+ var heatmapMode by remember { mutableStateOf(HeatmapMode.COUNT) }
val listState = rememberLazyListState()
val scrollBehavior = GlassTopAppBarDefaults.defaultScrollBehavior()
@@ -131,6 +138,36 @@ fun ReadRecordScreen(
pendingDeleteAction = action
}
}
+ val stickyDate by remember(displayMode, listState) {
+ derivedStateOf {
+ if (displayMode == DisplayMode.LATEST) return@derivedStateOf null
+ val stickyKey = listState.layoutInfo.visibleItemsInfo
+ .firstOrNull { info ->
+ val key = info.key.toString()
+ key.startsWith("header_") ||
+ key.startsWith("timeline_header_") ||
+ key.startsWith("agg_item_") ||
+ key.startsWith("timeline_item_")
+ }?.key?.toString() ?: return@derivedStateOf null
+
+ when {
+ stickyKey.startsWith("header_") -> stickyKey.removePrefix("header_")
+ stickyKey.startsWith("timeline_header_") -> stickyKey.removePrefix("timeline_header_")
+ stickyKey.startsWith("agg_item_") -> stickyKey.removePrefix("agg_item_").substringBefore("|")
+ stickyKey.startsWith("timeline_item_") -> stickyKey.removePrefix("timeline_item_").substringBefore("|")
+ else -> null
+ }
+ }
+ }
+ val floatingDate by remember(stickyDate, listState, displayMode) {
+ derivedStateOf {
+ if (displayMode == DisplayMode.LATEST) return@derivedStateOf null
+ if (stickyDate == null) return@derivedStateOf null
+ val shouldStick = listState.firstVisibleItemIndex > 1 ||
+ listState.firstVisibleItemScrollOffset > 24
+ if (shouldStick) stickyDate else null
+ }
+ }
LaunchedEffect(state.searchKey) {
if (state.searchKey.isNullOrBlank()) {
@@ -198,41 +235,52 @@ fun ReadRecordScreen(
}
}
) { padding ->
- Column(modifier = Modifier
- .padding(padding)
- .fillMaxSize()) {
- val contentState = when {
- state.isLoading -> "LOADING"
- (displayMode == DisplayMode.AGGREGATE && state.groupedRecords.isEmpty()) ||
- (displayMode == DisplayMode.TIMELINE && state.timelineRecords.isEmpty()) ||
- (displayMode == DisplayMode.LATEST && state.latestRecords.isEmpty()) -> "EMPTY"
- else -> "CONTENT"
- }
- AnimatedContent(
- targetState = contentState,
- label = "MainContentAnimation"
- ) { targetState ->
- when (targetState) {
- "LOADING" -> {
- EmptyMessageView(
- modifier = Modifier.fillMaxSize(),
- message = "加载中",
- isLoading = true
- )
- }
+ val contentState = when {
+ state.isLoading -> "LOADING"
+ (displayMode == DisplayMode.AGGREGATE && state.groupedRecords.isEmpty()) ||
+ (displayMode == DisplayMode.TIMELINE && state.timelineRecords.isEmpty()) ||
+ (displayMode == DisplayMode.LATEST && state.latestRecords.isEmpty()) -> "EMPTY"
+ else -> "CONTENT"
+ }
+ AnimatedContent(
+ targetState = contentState,
+ label = "MainContentAnimation"
+ ) { targetState ->
+ when (targetState) {
+ "LOADING" -> {
+ EmptyMessageView(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(
+ top = padding.calculateTopPadding(),
+ bottom = padding.calculateBottomPadding()
+ ),
+ message = "加载中",
+ isLoading = true
+ )
+ }
- "EMPTY" -> {
- EmptyMessageView(
- modifier = Modifier.fillMaxSize(),
- message = "没有记录"
- )
- }
+ "EMPTY" -> {
+ EmptyMessageView(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(
+ top = padding.calculateTopPadding(),
+ bottom = padding.calculateBottomPadding()
+ ),
+ message = "没有记录"
+ )
+ }
- "CONTENT" -> {
+ "CONTENT" -> {
+ Box(modifier = Modifier.fillMaxSize()) {
LazyColumn(
state = listState,
- modifier = Modifier
- .nestedScroll(scrollBehavior.nestedScrollConnection)
+ modifier = Modifier.fillMaxSize(),
+ contentPadding = adaptiveContentPaddingOnlyVertical(
+ top = padding.calculateTopPadding(),
+ bottom = padding.calculateBottomPadding() + 16.dp
+ )
) {
item(key = "summary_card") {
SummarySection(state, viewModel)
@@ -255,6 +303,32 @@ fun ReadRecordScreen(
}
)
}
+
+ TopFloatingStickyItem(
+ item = floatingDate,
+ modifier = Modifier.padding(
+ top = padding.calculateTopPadding() + 4.dp,
+ start = 8.dp
+ )
+ ) { date ->
+ val text = buildString {
+ append(formatFriendlyDate(date))
+ if (displayMode == DisplayMode.AGGREGATE) {
+ val dailyTotal = state.groupedRecords[date]?.sumOf { it.readTime } ?: 0L
+ append(" · ")
+ append(formatDuring(dailyTotal))
+ }
+ }
+ TextCard(
+ text = text,
+ textStyle = LegadoTheme.typography.labelLarge,
+ backgroundColor = LegadoTheme.colorScheme.cardContainer,
+ contentColor = LegadoTheme.colorScheme.onCardContainer,
+ cornerRadius = 8.dp,
+ horizontalPadding = 8.dp,
+ verticalPadding = 8.dp
+ )
+ }
}
}
}
@@ -292,19 +366,31 @@ fun ReadRecordScreen(
AppModalBottomSheet(
show = showCalendar,
- onDismissRequest = { showCalendar = false }
+ onDismissRequest = { showCalendar = false },
+ title = HEATMAP_CALENDAR_TITLE,
+ startAction = {
+ HeatmapCalendarStartAction(
+ currentMode = heatmapMode,
+ onModeChanged = { heatmapMode = it }
+ )
+ },
+ endAction = {
+ HeatmapCalendarEndAction(
+ onClearDate = {
+ viewModel.setSelectedDate(null)
+ showCalendar = false
+ }
+ )
+ }
) {
HeatmapCalendarSection(
dailyReadCounts = state.dailyReadCounts,
dailyReadTimes = state.dailyReadTimes,
+ currentMode = heatmapMode,
selectedDate = state.selectedDate,
onDateSelected = { date ->
viewModel.setSelectedDate(date)
showCalendar = false
- },
- onClearDate = {
- viewModel.setSelectedDate(null)
- showCalendar = false
}
)
}
@@ -404,13 +490,11 @@ fun HeatmapCalendarSection(
modifier: Modifier = Modifier,
dailyReadCounts: Map,
dailyReadTimes: Map,
+ currentMode: HeatmapMode,
selectedDate: LocalDate?,
onDateSelected: (LocalDate) -> Unit,
- onClearDate: () -> Unit,
config: HeatmapConfig = HeatmapConfig()
) {
- var currentMode by remember { mutableStateOf(HeatmapMode.COUNT) }
-
val (startDate, endDate) = rememberDateRange(dailyReadCounts, dailyReadTimes)
val days = rememberDaysInRange(startDate, endDate)
val weeks = rememberWeeks(days, startDate)
@@ -452,14 +536,6 @@ fun HeatmapCalendarSection(
.padding(horizontal = 16.dp, vertical = 8.dp)
.padding(bottom = 32.dp)
) {
- HeatmapCalendarTopBar(
- currentMode = currentMode,
- onModeChanged = { currentMode = it },
- onClearDate = onClearDate
- )
-
- Spacer(modifier = Modifier.height(8.dp))
-
Row(modifier = Modifier.fillMaxWidth()) {
WeekdayLabelsColumn(
cellSize = config.cellSize,
@@ -543,10 +619,13 @@ fun LazyListScope.renderListByMode(
when (displayMode) {
DisplayMode.AGGREGATE -> {
state.groupedRecords.forEach { (date, details) ->
- stickyHeader(key = "header_$date") {
+ item(key = "header_$date") {
DateHeader(date, details.sumOf { it.readTime })
}
- items(items = details, key = { "${it.bookName}_${it.bookAuthor}_${it.date}" }) { detail ->
+ items(
+ items = details,
+ key = { "agg_item_${date}|${it.bookName}_${it.bookAuthor}_${it.date}" }
+ ) { detail ->
SwipeActionContainer(
modifier = Modifier.animateItem(),
startAction = SwipeAction(
@@ -568,8 +647,8 @@ fun LazyListScope.renderListByMode(
DisplayMode.TIMELINE -> {
state.timelineRecords.forEach { (date, sessions) ->
- stickyHeader(key = "timeline_header_$date") { DateHeader(date) }
- items(items = sessions, key = { it.id }) { session ->
+ item(key = "timeline_header_$date") { DateHeader(date) }
+ items(items = sessions, key = { "timeline_item_${date}|${it.id}" }) { session ->
SwipeActionContainer(
modifier = Modifier.animateItem(),
startAction = SwipeAction(
@@ -637,7 +716,7 @@ fun LatestReadItem(
modifier = modifier
.fillMaxWidth()
.clickable(onClick = onClick)
- .padding(horizontal = 16.dp, vertical = 8.dp),
+ .adaptiveHorizontalPadding(vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Cover(coverPath)
@@ -798,7 +877,7 @@ fun ReadRecordItem(
modifier = modifier
.fillMaxWidth()
.clickable(onClick = onClick)
- .padding(horizontal = 16.dp, vertical = 8.dp),
+ .adaptiveHorizontalPadding(vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Cover(coverPath)
@@ -877,7 +956,7 @@ fun ReadingSummaryCard(
onClick = onClick,
modifier = Modifier
.fillMaxWidth()
- .padding(horizontal = 16.dp, vertical = 8.dp),
+ .adaptiveHorizontalPadding(vertical = 8.dp),
containerColor = LegadoTheme.colorScheme.surfaceContainer
) {
Row(
diff --git a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt
index bdb453b58..ac90bcc8d 100644
--- a/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt
+++ b/app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt
@@ -345,7 +345,7 @@ fun SearchHistoryList(
trailingContent = {
SmallIconButton(
onClick = { onDeleteHistory(item) },
- icon = Icons.Default.Close,
+ imageVector = Icons.Default.Close,
contentDescription = "删除"
)
},
@@ -366,7 +366,7 @@ fun SearchHistoryList(
MediumOutlinedButton(
onClick = onClearHistory,
modifier = Modifier.fillMaxWidth(0.6f),
- icon = Icons.Outlined.DeleteSweep,
+ imageVector = Icons.Outlined.DeleteSweep,
text = "清除搜索历史"
)
}
diff --git a/app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt b/app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt
index 4321e0fee..b025d7903 100644
--- a/app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt
+++ b/app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt
@@ -469,7 +469,7 @@ fun TocScreen(
SmallOutlinedIconToggleButton(
checked = showVolumeMenu,
onCheckedChange = { showVolumeMenu = it },
- icon = Icons.AutoMirrored.Filled.FormatListBulleted,
+ imageVector = Icons.AutoMirrored.Filled.FormatListBulleted,
contentDescription = "卷管理"
)
RoundDropdownMenu(
diff --git a/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt b/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt
index 14fbfd54b..09d87006d 100644
--- a/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt
+++ b/app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt
@@ -204,7 +204,7 @@ fun TxtRuleScreen(
}
AppAlertDialog(
- data = showDeleteRuleDialog, // 传入 nullable 的 rule 对象
+ data = showDeleteRuleDialog, // 传入 nullable ?rule 对象
onDismissRequest = { showDeleteRuleDialog = null },
title = stringResource(R.string.delete),
confirmText = stringResource(R.string.ok),
@@ -228,7 +228,7 @@ fun TxtRuleScreen(
editingRule = null
},
onSave = { updatedRule ->
- //TODO:我很想把他改为自增主键,但为了兼容性日后再说
+ //TODO:我很想把他改为自增主键,但为了兼容性日后再?
if (editingRule == null) {
viewModel.insert(updatedRule)
} else {
@@ -346,7 +346,7 @@ fun TxtRuleScreen(
trailingAction = {
SmallIconButton(
onClick = { showDeleteRuleDialog = item.rule },
- icon = Icons.Default.Delete
+ imageVector = Icons.Default.Delete
)
}
)
@@ -368,3 +368,4 @@ fun TxtRuleScreen(
}
}
}
+
diff --git a/app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt b/app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt
index a0541c287..10f0ff114 100644
--- a/app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt
+++ b/app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt
@@ -68,7 +68,7 @@ fun DirectLinkUploadBottomSheet(
endAction = {
MediumIconButton(
onClick = { showMenu = true },
- icon = Icons.Default.MoreVert
+ imageVector = Icons.Default.MoreVert
)
RoundDropdownMenu(
expanded = showMenu,
diff --git a/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt b/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt
index 7dcff4ab9..79c276cd4 100644
--- a/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt
+++ b/app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt
@@ -320,7 +320,7 @@ fun DictRuleScreen(
trailingAction = {
SmallIconButton(
onClick = { showDeleteRuleDialog = item.rule },
- icon = Icons.Default.Delete
+ imageVector = Icons.Default.Delete
)
}
)
@@ -341,4 +341,4 @@ fun DictRuleScreen(
}
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt
index e7778a926..857c559df 100644
--- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt
+++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt
@@ -37,6 +37,8 @@ import io.legado.app.lib.dialogs.alert
import io.legado.app.service.WebService
import io.legado.app.ui.about.CrashLogsDialog
import io.legado.app.ui.about.UpdateDialog
+import io.legado.app.ui.book.import.local.ImportBookScreen
+import io.legado.app.ui.book.import.remote.RemoteBookScreen
import io.legado.app.ui.book.read.ReadBookActivity
import io.legado.app.ui.config.ConfigNavScreen
import io.legado.app.ui.config.ConfigTag
@@ -74,6 +76,8 @@ open class MainActivity : BaseComposeActivity() {
private const val ROUTE_SETTINGS_COVER = "settings/cover"
private const val ROUTE_SETTINGS_THEME = "settings/theme"
private const val ROUTE_SETTINGS_BACKUP = "settings/backup"
+ private const val ROUTE_IMPORT_LOCAL = "import/local"
+ private const val ROUTE_IMPORT_REMOTE = "import/remote"
fun createIntent(context: Context, configTag: String? = null): Intent {
return Intent(context, MainActivity::class.java).apply {
@@ -120,6 +124,12 @@ open class MainActivity : BaseComposeActivity() {
@Serializable
private data object MainRouteSettingsBackup : MainRoute
+ @Serializable
+ private data object MainRouteImportLocal : MainRoute
+
+ @Serializable
+ private data object MainRouteImportRemote : MainRoute
+
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
super.onCreate(savedInstanceState)
@@ -260,6 +270,12 @@ open class MainActivity : BaseComposeActivity() {
useRail = useRail,
onOpenSettings = {
navigateToRoute(backStack, MainRouteSettings)
+ },
+ onNavigateToRemoteImport = {
+ navigateToRoute(backStack, MainRouteImportRemote)
+ },
+ onNavigateToLocalImport = {
+ navigateToRoute(backStack, MainRouteImportLocal)
}
)
}
@@ -294,6 +310,18 @@ open class MainActivity : BaseComposeActivity() {
entry {
BackupConfigScreen(onBackClick = { navigateBack(backStack) })
}
+
+ entry {
+ ImportBookScreen(
+ onBackClick = { navigateBack(backStack) }
+ )
+ }
+
+ entry {
+ RemoteBookScreen(
+ onBackClick = { navigateBack(backStack) }
+ )
+ }
}
)
}
@@ -328,6 +356,17 @@ open class MainActivity : BaseComposeActivity() {
backStack.add(MainRouteSettings)
backStack.add(route)
}
+
+ MainRouteImportLocal,
+ MainRouteImportRemote -> {
+ if (currentRoute == MainRouteHome) {
+ backStack.add(route)
+ } else {
+ backStack.clear()
+ backStack.add(MainRouteHome)
+ backStack.add(route)
+ }
+ }
}
}
@@ -462,6 +501,8 @@ open class MainActivity : BaseComposeActivity() {
"settings/cover" -> MainRouteSettingsCover
"settings/theme" -> MainRouteSettingsTheme
"settings/backup" -> MainRouteSettingsBackup
+ "import/local" -> MainRouteImportLocal
+ "import/remote" -> MainRouteImportRemote
else -> MainRouteHome
}
}
diff --git a/app/src/main/java/io/legado/app/ui/main/MainScreen.kt b/app/src/main/java/io/legado/app/ui/main/MainScreen.kt
index 07f77abc4..8b630f537 100644
--- a/app/src/main/java/io/legado/app/ui/main/MainScreen.kt
+++ b/app/src/main/java/io/legado/app/ui/main/MainScreen.kt
@@ -89,7 +89,9 @@ import org.koin.androidx.compose.koinViewModel
fun MainScreen(
viewModel: MainViewModel = koinViewModel(),
useRail: Boolean,
- onOpenSettings: () -> Unit
+ onOpenSettings: () -> Unit,
+ onNavigateToRemoteImport: () -> Unit,
+ onNavigateToLocalImport: () -> Unit
) {
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
@@ -373,7 +375,9 @@ fun MainScreen(
putExtra("author", book.author)
putExtra("bookUrl", book.bookUrl)
}
- }
+ },
+ onNavigateToRemoteImport = onNavigateToRemoteImport,
+ onNavigateToLocalImport = onNavigateToLocalImport
)
MainDestination.Explore -> ExploreScreen()
diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt
index 2ba1dad70..5bb726c4e 100644
--- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt
+++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt
@@ -67,12 +67,11 @@ import io.legado.app.R
import io.legado.app.base.BaseRuleEvent
import io.legado.app.ui.about.AppLogSheet
import io.legado.app.ui.book.cache.CacheActivity
-import io.legado.app.ui.book.import.local.ImportBookActivity
-import io.legado.app.ui.book.import.remote.RemoteBookActivity
import io.legado.app.ui.book.manage.BookshelfManageActivity
import io.legado.app.ui.book.search.SearchActivity
import io.legado.app.ui.config.bookshelfConfig.BookshelfConfig
import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.ThemeResolver
import io.legado.app.ui.theme.adaptiveContentPadding
import io.legado.app.ui.theme.adaptiveHorizontalPadding
import io.legado.app.ui.widget.components.button.SmallOutlinedIconToggleButton
@@ -100,7 +99,9 @@ import org.koin.androidx.compose.koinViewModel
fun BookshelfScreen(
viewModel: BookshelfViewModel = koinViewModel(),
onBookClick: (BookShelfItem) -> Unit,
- onBookLongClick: (BookShelfItem) -> Unit
+ onBookLongClick: (BookShelfItem) -> Unit,
+ onNavigateToRemoteImport: () -> Unit,
+ onNavigateToLocalImport: () -> Unit
) {
val context = LocalContext.current
val uiState by viewModel.uiState.collectAsState()
@@ -196,7 +197,7 @@ fun BookshelfScreen(
}
val bookGroupStyle = BookshelfConfig.bookGroupStyle
- // 控制是否处于“文件夹列表”根视图,还是“文件夹内部”书籍视图
+ // 控制是否处于“文件夹列表”根视图,还是“文件夹内部”书籍视?
var isInFolderRoot by remember(bookGroupStyle) { mutableStateOf(bookGroupStyle == 2) }
val baseTitle = when {
bookGroupStyle == 1 -> {
@@ -232,6 +233,10 @@ fun BookshelfScreen(
if (isLandscape) BookshelfConfig.bookshelfLayoutGridLandscape else BookshelfConfig.bookshelfLayoutGridPortrait
val bookshelfLayoutList =
if (isLandscape) BookshelfConfig.bookshelfLayoutListLandscape else BookshelfConfig.bookshelfLayoutListPortrait
+ val totalHorizontalPadding =
+ if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) 12.dp else 16.dp
+ val gridContentHorizontalPadding = totalHorizontalPadding / 2
+ val gridInnerHorizontalPadding = totalHorizontalPadding / 2
ListScaffold(
title = title,
@@ -242,12 +247,12 @@ fun BookshelfScreen(
dropDownMenuContent = { dismiss ->
RoundDropdownMenuItem(
text = stringResource(R.string.add_remote_book),
- onClick = { context.startActivity(); dismiss() },
+ onClick = { onNavigateToRemoteImport(); dismiss() },
leadingIcon = { Icon(Icons.Default.Wifi, null) }
)
RoundDropdownMenuItem(
text = stringResource(R.string.book_local),
- onClick = { context.startActivity(); dismiss() },
+ onClick = { onNavigateToLocalImport(); dismiss() },
leadingIcon = { Icon(Icons.Default.Save, null) }
)
RoundDropdownMenuItem(
@@ -345,7 +350,7 @@ fun BookshelfScreen(
SmallOutlinedIconToggleButton(
checked = showGroupMenu,
onCheckedChange = { showGroupMenu = it },
- icon = Icons.AutoMirrored.Filled.FormatListBulleted,
+ imageVector = Icons.AutoMirrored.Filled.FormatListBulleted,
contentDescription = stringResource(R.string.group_manage)
)
RoundDropdownMenu(
@@ -407,15 +412,19 @@ fun BookshelfScreen(
if (bookGroupStyle == 2 && isRoot) {
val folderColumns =
if (bookshelfLayoutMode == 0) bookshelfLayoutList else bookshelfLayoutGrid
+ val isGridMode = bookshelfLayoutMode != 0
FastScrollLazyVerticalGrid(
columns = GridCells.Fixed(folderColumns.coerceAtLeast(1)),
- modifier = Modifier.fillMaxSize(),
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(horizontal = if (isGridMode) gridInnerHorizontalPadding else 0.dp),
contentPadding = adaptiveContentPadding(
top = paddingValues.calculateTopPadding(),
- bottom = 120.dp
+ bottom = 120.dp,
+ horizontal = if (isGridMode) gridContentHorizontalPadding else 0.dp
),
- verticalArrangement = Arrangement.spacedBy(if (bookshelfLayoutMode != 0) 8.dp else 0.dp),
- horizontalArrangement = Arrangement.spacedBy(if (bookshelfLayoutMode != 0) 8.dp else 0.dp),
+ verticalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp),
+ horizontalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp),
showFastScroll = BookshelfConfig.showBookshelfFastScroller
) {
itemsIndexed(
@@ -592,16 +601,23 @@ fun BookshelfPage(
onBookLongClick: (BookShelfItem) -> Unit
) {
val columns = if (bookshelfLayoutMode == 0) bookshelfLayoutList else bookshelfLayoutGrid
+ val isGridMode = bookshelfLayoutMode != 0
+ val totalHorizontalPadding =
+ if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) 12.dp else 16.dp
+ val gridContentHorizontalPadding = totalHorizontalPadding / 2
+ val gridInnerHorizontalPadding = totalHorizontalPadding / 2
FastScrollLazyVerticalGrid(
columns = GridCells.Fixed(columns.coerceAtLeast(1)),
- modifier = Modifier.fillMaxSize(),
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(horizontal = if (isGridMode) gridInnerHorizontalPadding else 0.dp),
contentPadding = adaptiveContentPadding(
top = paddingValues.calculateTopPadding(),
bottom = 120.dp,
- horizontal = if (bookshelfLayoutMode != 0) 12.dp else 0.dp
+ horizontal = if (isGridMode) gridContentHorizontalPadding else 0.dp
),
- verticalArrangement = Arrangement.spacedBy(if (bookshelfLayoutMode != 0) 8.dp else 0.dp),
- horizontalArrangement = Arrangement.spacedBy(if (bookshelfLayoutMode != 0) 8.dp else 0.dp),
+ verticalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp),
+ horizontalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp),
showFastScroll = BookshelfConfig.showBookshelfFastScroller
) {
items(books, key = { it.bookUrl }) { book ->
@@ -621,3 +637,4 @@ fun BookshelfPage(
}
}
}
+
diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt
index dadd56466..dbeec5e34 100644
--- a/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt
+++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt
@@ -83,7 +83,7 @@ fun GroupManageSheet(
editingGroup = null
isEditing = true
},
- icon = Icons.Default.Add
+ imageVector = Icons.Default.Add
)
}
}
@@ -130,3 +130,4 @@ fun GroupManageSheet(
}
}
}
+
diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt
index a99597bfd..846e9fe4d 100644
--- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt
+++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt
@@ -249,8 +249,11 @@ fun ExploreScreen(
TextCard(
text = item.bookSourceName,
textStyle = LegadoTheme.typography.labelLarge,
+ backgroundColor = LegadoTheme.colorScheme.cardContainer,
+ contentColor = LegadoTheme.colorScheme.onCardContainer,
+ cornerRadius = 8.dp,
horizontalPadding = 8.dp,
- verticalPadding = 6.dp,
+ verticalPadding = 8.dp,
onClick = {
scope.launch {
val index =
diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt b/app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt
index 992173b19..51c31f874 100644
--- a/app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt
+++ b/app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt
@@ -235,7 +235,7 @@ fun WebServiceSettingBlock(
) {
SmallTextButton(
text = "复制地址",
- icon = Icons.Default.ContentCopy,
+ imageVector = Icons.Default.ContentCopy,
onClick = {
onNavigate(PrefClickEvent.CopyUrl(uiState.webServiceAddress))
}
@@ -245,7 +245,7 @@ fun WebServiceSettingBlock(
SmallTextButton(
text = "浏览器打开",
- icon = Icons.Default.OpenInBrowser,
+ imageVector = Icons.Default.OpenInBrowser,
onClick = {
onNavigate(PrefClickEvent.OpenUrl(uiState.webServiceAddress))
}
@@ -254,3 +254,4 @@ fun WebServiceSettingBlock(
}
}
}
+
diff --git a/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt b/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt
index 48de8a0ba..73045b151 100644
--- a/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt
+++ b/app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt
@@ -143,7 +143,9 @@ class ReplaceRuleActivity : BaseComposeActivity() {
}
entry { route ->
- val viewModel: ReplaceEditViewModel = koinViewModel { parametersOf(route) }
+ val viewModel: ReplaceEditViewModel = koinViewModel(
+ key = "replace_edit_${System.identityHashCode(route)}"
+ ) { parametersOf(route) }
ReplaceEditScreen(
viewModel = viewModel,
diff --git a/app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditScreen.kt b/app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditScreen.kt
index 8ed4230e0..c668e6e2b 100644
--- a/app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditScreen.kt
+++ b/app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditScreen.kt
@@ -42,13 +42,12 @@ import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.ExposedDropdownMenuAnchorType
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
-import androidx.compose.material3.FilterChip
-import androidx.compose.material3.FilterChipDefaults
import io.legado.app.ui.widget.components.AppFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
+import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.animateFloatingActionButton
import androidx.compose.runtime.Composable
@@ -73,8 +72,11 @@ import io.legado.app.ui.widget.components.AppScaffold
import io.legado.app.ui.widget.components.AppTextField
import io.legado.app.ui.widget.components.alert.AppAlertDialog
import io.legado.app.ui.widget.components.button.AlertButton
+import io.legado.app.ui.widget.components.button.ToggleChip
+import io.legado.app.ui.widget.components.button.TopBarActionButton
import io.legado.app.ui.widget.components.button.TopBarNavigationButton
import io.legado.app.ui.widget.components.checkBox.CheckboxItem
+import io.legado.app.ui.widget.components.icon.AppIcon
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
import io.legado.app.ui.widget.components.text.AppText
@@ -115,15 +117,19 @@ fun ReplaceEditScreen(
enter = fadeIn(),
exit = fadeOut()
) {
- IconButton(onClick = {
- viewModel.save(onSaveSuccess)
- }) {
- Icon(Icons.Default.Save, contentDescription = "保存")
- }
- }
- IconButton(onClick = { showMenu = true }) {
- Icon(Icons.Default.MoreVert, contentDescription = "更多操作")
+ TopBarActionButton(
+ onClick = {
+ viewModel.save(onSaveSuccess)
+ },
+ imageVector = Icons.Default.Save,
+ contentDescription = "保存"
+ )
}
+ TopBarActionButton(
+ onClick = { showMenu = true },
+ imageVector = Icons.Default.MoreVert,
+ contentDescription = "更多操作"
+ )
RoundDropdownMenu(
expanded = showMenu,
onDismissRequest = { showMenu = false }
@@ -158,7 +164,7 @@ fun ReplaceEditScreen(
onClick = { viewModel.save(onSaveSuccess) },
tooltipText = "添加"
) {
- Icon(Icons.Default.Save, contentDescription = "保存")
+ AppIcon(Icons.Default.Save, contentDescription = "保存")
}
}, contentWindowInsets = WindowInsets(0, 0, 0, 0)
) { innerPadding ->
@@ -242,53 +248,29 @@ fun ReplaceEditScreen(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Start
) {
- FilterChip(
+ ToggleChip(
+ label = "标题",
selected = state.scopeTitle,
- onClick = { viewModel.onScopeTitleChange(!state.scopeTitle) },
- label = { AppText("标题") },
- leadingIcon = if (state.scopeTitle) {
- {
- Icon(
- Icons.Default.Check,
- contentDescription = "已选择",
- Modifier.size(FilterChipDefaults.IconSize)
- )
- }
- } else null
+ checkedContentDescription = "已选择",
+ onToggle = { viewModel.onScopeTitleChange(!state.scopeTitle) }
)
Spacer(Modifier.width(8.dp))
- FilterChip(
+ ToggleChip(
+ label = "内容",
selected = state.scopeContent,
- onClick = { viewModel.onScopeContentChange(!state.scopeContent) },
- label = { AppText("内容") },
- leadingIcon = if (state.scopeContent) {
- {
- Icon(
- Icons.Default.Check,
- contentDescription = "已选择",
- Modifier.size(FilterChipDefaults.IconSize)
- )
- }
- } else null
+ checkedContentDescription = "已选择",
+ onToggle = { viewModel.onScopeContentChange(!state.scopeContent) }
)
Spacer(Modifier.weight(1f))
- FilterChip(
+ ToggleChip(
+ label = "使用正则",
selected = state.isRegex,
- onClick = { viewModel.onRegexChange(!state.isRegex) },
- label = { AppText("使用正则") },
- leadingIcon = if (state.isRegex) {
- {
- Icon(
- Icons.Default.Check,
- contentDescription = "正则已启用",
- Modifier.size(FilterChipDefaults.IconSize)
- )
- }
- } else null
+ checkedContentDescription = "正则已启用",
+ onToggle = { viewModel.onRegexChange(!state.isRegex) }
)
}
diff --git a/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt b/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt
index 887fcc7d3..b32a8a4b1 100644
--- a/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt
+++ b/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt
@@ -203,7 +203,7 @@ fun RssFavoritesScreen(
SelectionItemCard(
title = rssStar.title,
subtitle = if (rssStar.group.isNotBlank()) {
- "${rssStar.group} • ${rssStar.pubDate ?: ""}"
+ "${rssStar.group} ?${rssStar.pubDate ?: ""}"
} else {
rssStar.pubDate
},
@@ -232,7 +232,7 @@ fun RssFavoritesScreen(
}
SmallIconButton(
onClick = openAction,
- icon = Icons.AutoMirrored.Filled.OpenInNew,
+ imageVector = Icons.AutoMirrored.Filled.OpenInNew,
contentDescription = "Open"
)
},
@@ -258,3 +258,4 @@ fun RssFavoritesScreen(
}
}
}
+
diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt
index bfb9d5ae3..fc7113ffd 100644
--- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt
+++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt
@@ -365,7 +365,7 @@ fun RssSourceScreen(
trailingAction = {
SmallIconButton(
onClick = { showDeleteRuleDialog = item.source },
- icon = Icons.Default.Delete
+ imageVector = Icons.Default.Delete
)
}
)
@@ -387,3 +387,4 @@ fun RssSourceScreen(
}
}
}
+
diff --git a/app/src/main/java/io/legado/app/ui/theme/AdaptivePadding.kt b/app/src/main/java/io/legado/app/ui/theme/AdaptivePadding.kt
index fd180eb87..7d282484a 100644
--- a/app/src/main/java/io/legado/app/ui/theme/AdaptivePadding.kt
+++ b/app/src/main/java/io/legado/app/ui/theme/AdaptivePadding.kt
@@ -63,7 +63,7 @@ fun adaptiveContentPadding(
bottom: Dp,
horizontal: Dp
): PaddingValues {
- val adjustedTop = if (ThemeResolver.isMiuixEngine(composeEngine)) top else top + 4.dp
+ val adjustedTop = if (ThemeResolver.isMiuixEngine(composeEngine)) top + 6.dp else top + 4.dp
return PaddingValues(
top = adjustedTop,
bottom = bottom,
diff --git a/app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt b/app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt
index 98e3879df..1bc32f113 100644
--- a/app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt
@@ -20,6 +20,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.adaptiveHorizontalPadding
import io.legado.app.ui.widget.components.card.GlassCard
import io.legado.app.ui.widget.components.text.AppText
@@ -37,7 +38,7 @@ fun CollapsibleHeader(
GlassCard(
modifier = modifier
.fillMaxWidth()
- .padding(start = 16.dp, top = 4.dp, end = 16.dp),
+ .adaptiveHorizontalPadding(vertical = 4.dp),
shape = MaterialTheme.shapes.medium,
containerColor = LegadoTheme.colorScheme.surfaceContainer,
onClick = onToggle
diff --git a/app/src/main/java/io/legado/app/ui/widget/components/AppRadioButtom.kt b/app/src/main/java/io/legado/app/ui/widget/components/AppRadioButtom.kt
new file mode 100644
index 000000000..5e83d9cdf
--- /dev/null
+++ b/app/src/main/java/io/legado/app/ui/widget/components/AppRadioButtom.kt
@@ -0,0 +1,35 @@
+package io.legado.app.ui.widget.components
+
+import androidx.compose.material3.Checkbox
+import androidx.compose.material3.RadioButton
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.state.ToggleableState
+import io.legado.app.ui.theme.LegadoTheme.composeEngine
+import io.legado.app.ui.theme.ThemeResolver
+import top.yukonga.miuix.kmp.basic.Checkbox
+import top.yukonga.miuix.kmp.basic.RadioButton as MiuixRadioButton
+
+@Composable
+fun AppRadioButton(
+ selected: Boolean,
+ onClick: (() -> Unit)?,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true
+) {
+ if (ThemeResolver.isMiuixEngine(composeEngine)) {
+ MiuixRadioButton(
+ selected = selected,
+ onClick = onClick,
+ modifier = modifier,
+ enabled = enabled
+ )
+ } else {
+ RadioButton(
+ selected = selected,
+ onClick = onClick,
+ modifier = modifier,
+ enabled = enabled
+ )
+ }
+}
diff --git a/app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt
index 7e8e6fdab..5c1f1dfcf 100644
--- a/app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt
@@ -1,4 +1,4 @@
-package io.legado.app.ui.widget.components
+package io.legado.app.ui.widget.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
@@ -120,7 +120,7 @@ private fun GroupItem(
) {
SmallTextButton(
text = stringResource(id = R.string.ok),
- icon = Icons.Default.Check,
+ imageVector = Icons.Default.Check,
onClick = {
onUpdateGroup(group, state.text.toString())
expanded = false
@@ -130,3 +130,4 @@ private fun GroupItem(
}
)
}
+
diff --git a/app/src/main/java/io/legado/app/ui/widget/components/ValueStepper.kt b/app/src/main/java/io/legado/app/ui/widget/components/ValueStepper.kt
index 3f0ca7038..c538322fa 100644
--- a/app/src/main/java/io/legado/app/ui/widget/components/ValueStepper.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/components/ValueStepper.kt
@@ -1,4 +1,4 @@
-package io.legado.app.ui.widget.components
+package io.legado.app.ui.widget.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
@@ -31,7 +31,7 @@ fun ValueStepper(
val newValue = (value.toInt() - 1).toFloat().coerceIn(valueRange)
onValueChange(newValue)
},
- icon = Icons.Default.Remove
+ imageVector = Icons.Default.Remove
)
TextCard(
cornerRadius = 8.dp,
@@ -46,7 +46,7 @@ fun ValueStepper(
val newValue = (value.toInt() + 1).toFloat().coerceIn(valueRange)
onValueChange(newValue)
},
- icon = Icons.Default.Add
+ imageVector = Icons.Default.Add
)
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/MediumIconButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/MediumIconButton.kt
index 9a56b606c..4aa076371 100644
--- a/app/src/main/java/io/legado/app/ui/widget/components/button/MediumIconButton.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/components/button/MediumIconButton.kt
@@ -41,7 +41,7 @@ import top.yukonga.miuix.kmp.basic.Text as MiuixText
@Composable
fun MediumIconButton(
onClick: () -> Unit,
- icon: ImageVector,
+ imageVector: ImageVector,
modifier: Modifier = Modifier,
contentDescription: String? = null
) {
@@ -51,7 +51,7 @@ fun MediumIconButton(
modifier = modifier
) {
MiuixIcon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription
)
}
@@ -61,7 +61,7 @@ fun MediumIconButton(
modifier = modifier
) {
Icon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription
)
}
@@ -71,7 +71,7 @@ fun MediumIconButton(
@Composable
fun MediumOutlinedIconButton(
onClick: () -> Unit,
- icon: ImageVector,
+ imageVector: ImageVector,
modifier: Modifier = Modifier,
contentDescription: String? = null
) {
@@ -83,7 +83,7 @@ fun MediumOutlinedIconButton(
backgroundColor = LegadoTheme.colorScheme.surfaceContainerHigh
) {
MiuixIcon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription
)
}
@@ -93,7 +93,7 @@ fun MediumOutlinedIconButton(
border = ButtonDefaults.outlinedButtonBorder()
) {
Icon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription
)
}
@@ -103,7 +103,7 @@ fun MediumOutlinedIconButton(
@Composable
fun MediumOutlinedButton(
onClick: () -> Unit,
- icon: ImageVector,
+ imageVector: ImageVector,
text: String,
modifier: Modifier = Modifier,
contentDescription: String? = null
@@ -120,7 +120,7 @@ fun MediumOutlinedButton(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
MiuixIcon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription
)
MiuixText(text = text)
@@ -136,7 +136,7 @@ fun MediumOutlinedButton(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Icon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription
)
Text(text = text)
@@ -148,7 +148,7 @@ fun MediumOutlinedButton(
@Composable
fun MediumTonalIconButton(
onClick: () -> Unit,
- icon: ImageVector,
+ imageVector: ImageVector,
modifier: Modifier = Modifier,
contentDescription: String? = null
) {
@@ -161,7 +161,7 @@ fun MediumTonalIconButton(
backgroundColor = LegadoTheme.colorScheme.surfaceContainer
) {
MiuixIcon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription
)
}
@@ -172,7 +172,7 @@ fun MediumTonalIconButton(
colors = IconButtonDefaults.filledTonalIconButtonColors()
) {
Icon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription
)
}
@@ -183,7 +183,7 @@ fun MediumTonalIconButton(
fun MediumOutlinedIconToggleButton(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
- icon: ImageVector,
+ imageVector: ImageVector,
modifier: Modifier = Modifier,
contentDescription: String? = null
) {
@@ -208,7 +208,7 @@ fun MediumOutlinedIconToggleButton(
backgroundColor = containerColor
) {
MiuixIcon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription,
tint = iconTint
)
@@ -220,7 +220,7 @@ fun MediumOutlinedIconToggleButton(
modifier = modifier
) {
Icon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription
)
}
diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt
index c7aafc470..166a92cb0 100644
--- a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt
@@ -64,7 +64,7 @@ private fun SmallNoMinTouchTarget(content: @Composable () -> Unit) {
@Composable
fun SmallIconButton(
onClick: () -> Unit,
- icon: ImageVector,
+ imageVector: ImageVector,
contentDescription: String? = null
) {
if (ThemeResolver.isMiuixEngine(composeEngine)) {
@@ -72,7 +72,7 @@ fun SmallIconButton(
onClick = onClick
) {
MiuixIcon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription
)
}
@@ -84,7 +84,7 @@ fun SmallIconButton(
shape = IconButtonDefaults.extraSmallRoundShape,
) {
Icon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription,
modifier = Modifier.size(smallIconSize),
)
@@ -97,11 +97,10 @@ fun SmallIconButton(
@Composable
fun SmallOutlinedIconButton(
onClick: () -> Unit,
- icon: ImageVector,
+ imageVector: ImageVector,
modifier: Modifier = Modifier,
contentDescription: String? = null
) {
-
val isMiuix = ThemeResolver.isMiuixEngine(composeEngine)
if (isMiuix) {
MiuixIconButton(
@@ -110,7 +109,7 @@ fun SmallOutlinedIconButton(
backgroundColor = LegadoTheme.colorScheme.surfaceContainer
) {
MiuixIcon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription,
modifier = Modifier.size(SmallMiuixIconSize)
)
@@ -124,7 +123,7 @@ fun SmallOutlinedIconButton(
border = ButtonDefaults.outlinedButtonBorder()
) {
Icon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription,
modifier = Modifier.size(smallIconSize)
)
@@ -137,7 +136,7 @@ fun SmallOutlinedIconButton(
@Composable
fun SmallTonalIconButton(
onClick: () -> Unit,
- icon: ImageVector,
+ imageVector: ImageVector,
modifier: Modifier = Modifier,
contentDescription: String? = null
) {
@@ -150,7 +149,7 @@ fun SmallTonalIconButton(
backgroundColor = LegadoTheme.colorScheme.surfaceContainer
) {
MiuixIcon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription,
modifier = Modifier.size(SmallMiuixIconSize)
)
@@ -164,7 +163,7 @@ fun SmallTonalIconButton(
colors = IconButtonDefaults.filledTonalIconButtonColors()
) {
Icon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription,
modifier = Modifier.size(smallIconSize)
)
@@ -178,7 +177,7 @@ fun SmallTonalIconButton(
fun SmallOutlinedIconToggleButton(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
- icon: ImageVector,
+ imageVector: ImageVector,
modifier: Modifier = Modifier,
contentDescription: String? = null
) {
@@ -205,7 +204,7 @@ fun SmallOutlinedIconToggleButton(
backgroundColor = containerColor
) {
MiuixIcon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription,
tint = iconTint,
modifier = Modifier.size(SmallMiuixIconSize)
@@ -233,7 +232,7 @@ fun SmallOutlinedIconToggleButton(
shapes = toggleShapes
) {
Icon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = contentDescription,
modifier = Modifier.size(smallIconSize),
)
diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt
index 9c3d49600..918f8f34c 100644
--- a/app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt
@@ -22,7 +22,7 @@ import top.yukonga.miuix.kmp.basic.Text as MiuixText
@Composable
fun SmallTextButton(
text: String,
- icon: ImageVector,
+ imageVector: ImageVector,
modifier: Modifier = Modifier,
onClick: () -> Unit
) {
@@ -44,7 +44,7 @@ fun SmallTextButton(
shape = MaterialTheme.shapes.small
) {
Icon(
- imageVector = icon,
+ imageVector = imageVector,
contentDescription = null,
modifier = Modifier.size(16.dp)
)
@@ -55,4 +55,4 @@ fun SmallTextButton(
)
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/legado/app/ui/widget/components/button/ToggleChip.kt b/app/src/main/java/io/legado/app/ui/widget/components/button/ToggleChip.kt
new file mode 100644
index 000000000..a4d2dee22
--- /dev/null
+++ b/app/src/main/java/io/legado/app/ui/widget/components/button/ToggleChip.kt
@@ -0,0 +1,87 @@
+package io.legado.app.ui.widget.components.button
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material3.FilterChip
+import androidx.compose.material3.FilterChipDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.LegadoTheme.composeEngine
+import io.legado.app.ui.theme.ThemeResolver
+import top.yukonga.miuix.kmp.basic.Icon as MiuixIcon
+import top.yukonga.miuix.kmp.basic.IconButton as MiuixIconButton
+import top.yukonga.miuix.kmp.basic.Text as MiuixText
+import top.yukonga.miuix.kmp.theme.MiuixTheme
+
+@Composable
+fun ToggleChip(
+ label: String,
+ selected: Boolean,
+ onToggle: () -> Unit,
+ modifier: Modifier = Modifier,
+ checkedContentDescription: String = "已选择"
+) {
+ if (ThemeResolver.isMiuixEngine(composeEngine)) {
+ MiuixIconButton(
+ onClick = onToggle,
+ modifier = modifier,
+ backgroundColor = if (selected) {
+ MiuixTheme.colorScheme.primaryContainer
+ } else {
+ MiuixTheme.colorScheme.surfaceContainer
+ }
+ ) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.Center,
+ modifier = Modifier.padding(horizontal = 8.dp, vertical = 6.dp)
+ ) {
+ AnimatedVisibility(visible = selected) {
+ Row(verticalAlignment = Alignment.CenterVertically) {
+ MiuixIcon(
+ imageVector = Icons.Default.Check,
+ contentDescription = checkedContentDescription,
+ modifier = Modifier.size(16.dp)
+ )
+ Spacer(Modifier.width(6.dp))
+ }
+ }
+
+ MiuixText(
+ text = label,
+ style = LegadoTheme.typography.labelSmall,
+ maxLines = 1,
+ softWrap = false
+ )
+ }
+ }
+ } else {
+ FilterChip(
+ selected = selected,
+ onClick = onToggle,
+ modifier = modifier,
+ label = { Text(label) },
+ leadingIcon = if (selected) {
+ {
+ Icon(
+ Icons.Default.Check,
+ contentDescription = checkedContentDescription,
+ Modifier.size(FilterChipDefaults.IconSize)
+ )
+ }
+ } else null
+ )
+ }
+}
diff --git a/app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt b/app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt
index 221416e7f..747ab58a8 100644
--- a/app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt
@@ -181,7 +181,7 @@ fun SelectionItemCard(
if (onClickEdit != null) {
SmallIconButton(
onClick = onClickEdit,
- icon = Icons.Default.Edit,
+ imageVector = Icons.Default.Edit,
contentDescription = "Edit"
)
}
@@ -194,7 +194,7 @@ fun SelectionItemCard(
Box {
SmallIconButton(
onClick = { showMenu = true },
- icon = Icons.Default.MoreVert,
+ imageVector = Icons.Default.MoreVert,
contentDescription = "More"
)
RoundDropdownMenu(
@@ -272,3 +272,4 @@ fun LazyItemScope.ReorderableSelectionItem(
)
}
}
+
diff --git a/app/src/main/java/io/legado/app/ui/widget/components/heatmap/HeatmapCalendarComponents.kt b/app/src/main/java/io/legado/app/ui/widget/components/heatmap/HeatmapCalendarComponents.kt
index b9e830bb7..0bef92c93 100644
--- a/app/src/main/java/io/legado/app/ui/widget/components/heatmap/HeatmapCalendarComponents.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/components/heatmap/HeatmapCalendarComponents.kt
@@ -19,7 +19,6 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccessTime
import androidx.compose.material.icons.filled.FormatListNumbered
import androidx.compose.material.icons.outlined.Delete
-import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@@ -43,43 +42,41 @@ import io.legado.app.ui.widget.components.text.AppText
import java.time.LocalDate
/**
- * 热力图日历顶部操作栏
+ * 热力图日历弹窗标题
+ */
+const val HEATMAP_CALENDAR_TITLE = "时间线"
+
+/**
+ * 热力图日历弹窗左侧操作
*/
-@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
-fun HeatmapCalendarTopBar(
+fun HeatmapCalendarStartAction(
currentMode: HeatmapMode,
onModeChanged: (HeatmapMode) -> Unit,
- onClearDate: () -> Unit,
- modifier: Modifier = Modifier
) {
- Row(
- modifier = modifier.fillMaxWidth(),
- horizontalArrangement = Arrangement.SpaceBetween,
- verticalAlignment = Alignment.CenterVertically
- ) {
- AppText("时间线", style = LegadoTheme.typography.titleMedium)
+ MediumAnimatedActionButton(
+ checked = currentMode == HeatmapMode.TIME,
+ onCheckedChange = {
+ onModeChanged(if (it) HeatmapMode.TIME else HeatmapMode.COUNT)
+ },
+ iconChecked = Icons.Default.AccessTime,
+ iconUnchecked = Icons.Default.FormatListNumbered,
+ activeText = "按时长",
+ inactiveText = "按次数"
+ )
+}
- Row(verticalAlignment = Alignment.CenterVertically) {
- MediumAnimatedActionButton(
- checked = currentMode == HeatmapMode.TIME,
- onCheckedChange = {
- onModeChanged(if (it) HeatmapMode.TIME else HeatmapMode.COUNT)
- },
- iconChecked = Icons.Default.AccessTime,
- iconUnchecked = Icons.Default.FormatListNumbered,
- activeText = "按时长",
- inactiveText = "按次数"
- )
-
- Spacer(modifier = Modifier.width(8.dp))
-
- MediumOutlinedIconButton(
- onClick = onClearDate,
- icon = Icons.Outlined.Delete,
- )
- }
- }
+/**
+ * 热力图日历弹窗右侧操作
+ */
+@Composable
+fun HeatmapCalendarEndAction(
+ onClearDate: () -> Unit
+) {
+ MediumOutlinedIconButton(
+ onClick = onClearDate,
+ imageVector = Icons.Outlined.Delete,
+ )
}
/**
@@ -296,4 +293,4 @@ fun HeatmapLegend(
color = Color.Gray
)
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/AppModalBottomSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/AppModalBottomSheet.kt
index 77a3ea7b8..cc42c9f1e 100644
--- a/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/AppModalBottomSheet.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/AppModalBottomSheet.kt
@@ -41,7 +41,6 @@ fun AppModalBottomSheet(
title: String? = null,
startAction: @Composable (() -> Unit)? = null,
endAction: @Composable (() -> Unit)? = null,
- containerColor: Color = LegadoTheme.colorScheme.surfaceContainer,
content: @Composable ColumnScope.() -> Unit
) {
if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) {
@@ -52,14 +51,15 @@ fun AppModalBottomSheet(
startAction = startAction,
endAction = endAction,
insideMargin = DpSize(16.dp, 12.dp),
- backgroundColor = containerColor,
onDismissRequest = onDismissRequest,
onDismissFinished = onDismissRequest,
enableWindowDim = true,
allowDismiss = true
) {
Column(
- modifier = Modifier.fillMaxWidth(),
+ modifier = Modifier
+ .fillMaxWidth()
+ .animateContentSize(),
content = content
)
}
@@ -75,7 +75,6 @@ fun AppModalBottomSheet(
ModalBottomSheet(
onDismissRequest = onDismissRequest,
sheetState = sheetState,
- containerColor = containerColor,
contentColor = colorScheme.onSurface,
dragHandle = { BottomSheetDefaults.DragHandle() }
) {
diff --git a/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/OptionSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/OptionSheet.kt
index 9f23196e8..439204cf4 100644
--- a/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/OptionSheet.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/OptionSheet.kt
@@ -32,8 +32,7 @@ fun OptionSheet(
AppModalBottomSheet(
show = show,
title = title,
- onDismissRequest = onDismissRequest,
- containerColor = LegadoTheme.colorScheme.surface
+ onDismissRequest = onDismissRequest
) {
Column(
modifier = Modifier
diff --git a/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt b/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt
index 798f7df89..5799f7bad 100644
--- a/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt
@@ -34,15 +34,19 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import io.legado.app.R
+import io.legado.app.ui.theme.LegadoTheme
import io.legado.app.ui.widget.components.AppFloatingActionButton
import io.legado.app.ui.widget.components.AppTextField
+import io.legado.app.ui.widget.components.button.MediumIconButton
import io.legado.app.ui.widget.components.icon.AppIcon
+import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
+import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
import io.legado.app.ui.widget.components.modalBottomSheet.AppModalBottomSheet
import io.legado.app.ui.widget.components.text.AppText
import kotlinx.coroutines.launch
/**
- * 通用编辑数据包装,用于适配不同的规则实体
+ * 通用编辑数据包装,用于适配不同的规则
*/
data class RuleEditFields(
val name: String = "",
@@ -80,41 +84,44 @@ fun RuleEditSheet(
AppModalBottomSheet(
title = title,
startAction = {
- IconButton(onClick = onDismissRequest) {
- Icon(
- Icons.Default.Close,
- contentDescription = stringResource(R.string.cancel)
- )
- }
+ MediumIconButton(
+ onClick = onDismissRequest,
+ imageVector = Icons.Default.Close,
+ contentDescription = "Close",
+ )
},
endAction = {
- IconButton(onClick = { showMenu = true }) {
- Icon(Icons.Default.MoreVert, contentDescription = "More")
- }
- DropdownMenu(expanded = showMenu, onDismissRequest = { showMenu = false }) {
- DropdownMenuItem(
- text = { AppText(stringResource(R.string.copy_rule)) },
- leadingIcon = { Icon(Icons.AutoMirrored.Filled.NoteAdd, null) },
- onClick = {
- onCopy(getCurrentEntity())
- showMenu = false
- }
+ Box{
+ MediumIconButton(
+ onClick = { showMenu = true },
+ imageVector = Icons.Default.MoreVert,
+ contentDescription = "More"
)
- DropdownMenuItem(
- text = { AppText(stringResource(R.string.paste_rule)) },
- leadingIcon = { Icon(Icons.Default.ContentPaste, null) },
- onClick = {
- scope.launch {
- onPaste()?.let { pasted ->
- val fields = toFields(pasted)
- name = fields.name
- rule1 = fields.rule1
- rule2 = fields.rule2
- }
+ RoundDropdownMenu(expanded = showMenu, onDismissRequest = { showMenu = false }) {
+ RoundDropdownMenuItem(
+ text = stringResource(R.string.copy_rule),
+ leadingIcon = { Icon(Icons.AutoMirrored.Filled.NoteAdd, null) },
+ onClick = {
+ onCopy(getCurrentEntity())
+ showMenu = false
}
- showMenu = false
- }
- )
+ )
+ RoundDropdownMenuItem(
+ text = stringResource(R.string.paste_rule),
+ leadingIcon = { Icon(Icons.Default.ContentPaste, null) },
+ onClick = {
+ scope.launch {
+ onPaste()?.let { pasted ->
+ val fields = toFields(pasted)
+ name = fields.name
+ rule1 = fields.rule1
+ rule2 = fields.rule2
+ }
+ }
+ showMenu = false
+ }
+ )
+ }
}
},
show = show,
@@ -132,6 +139,7 @@ fun RuleEditSheet(
modifier = Modifier.fillMaxWidth(),
value = name,
onValueChange = { name = it },
+ backgroundColor = LegadoTheme.colorScheme.surface,
label = stringResource(R.string.name),
singleLine = true
)
@@ -139,12 +147,14 @@ fun RuleEditSheet(
modifier = Modifier.fillMaxWidth(),
value = rule1,
onValueChange = { rule1 = it },
+ backgroundColor = LegadoTheme.colorScheme.surface,
label = label1
)
AppTextField(
modifier = Modifier.fillMaxWidth(),
value = rule2,
onValueChange = { rule2 = it },
+ backgroundColor = LegadoTheme.colorScheme.surface,
label = label2,
minLines = 3
)
@@ -160,4 +170,4 @@ fun RuleEditSheet(
}
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/InputSettingItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/InputSettingItem.kt
index 63ad5d893..eefe85ac7 100644
--- a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/InputSettingItem.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/InputSettingItem.kt
@@ -84,14 +84,14 @@ fun InputSettingItem(
) {
SmallTextButton(
text = "默认",
- icon = Icons.Default.Replay,
+ imageVector = Icons.Default.Replay,
onClick = {
state.edit { replace(0, length, defaultValue.toString()) }
}
)
SmallTextButton(
text = "确认",
- icon = Icons.Default.Check,
+ imageVector = Icons.Default.Check,
onClick = {
onConfirm(state.text.toString())
expanded = false
@@ -133,14 +133,14 @@ fun InputSettingItem(
) {
SmallTextButton(
text = "默认",
- icon = Icons.Default.Replay,
+ imageVector = Icons.Default.Replay,
onClick = {
state.edit { replace(0, length, defaultValue.toString()) }
}
)
SmallTextButton(
text = "确认",
- icon = Icons.Default.Check,
+ imageVector = Icons.Default.Check,
onClick = {
onConfirm(state.text.toString())
expanded = false
@@ -150,4 +150,4 @@ fun InputSettingItem(
}
)
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SliderSettingItem.kt b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SliderSettingItem.kt
index a1a08a3ad..833350d91 100644
--- a/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SliderSettingItem.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/components/settingItem/SliderSettingItem.kt
@@ -1,4 +1,4 @@
-package io.legado.app.ui.widget.components.settingItem
+package io.legado.app.ui.widget.components.settingItem
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
@@ -78,7 +78,7 @@ fun SliderSettingItem(
MiuixTextField(
state = textFieldState,
lineLimits = TextFieldLineLimits.SingleLine,
- label = "输入数值 (${valueRange.start.toInt()}-${valueRange.endInclusive.toInt()})",
+ label = "杈撳叆鏁板€?(${valueRange.start.toInt()}-${valueRange.endInclusive.toInt()})",
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
modifier = Modifier.fillMaxWidth(),
inputTransformation = {
@@ -120,16 +120,16 @@ fun SliderSettingItem(
horizontalArrangement = Arrangement.End
) {
SmallTextButton(
- text = if (isInputMode) "滑块" else "输入",
- icon = if (isInputMode) Icons.Default.LinearScale else Icons.Default.Edit,
+ text = if (isInputMode) "婊戝潡" else "杈撳叆",
+ imageVector = if (isInputMode) Icons.Default.LinearScale else Icons.Default.Edit,
onClick = { isInputMode = !isInputMode }
)
Spacer(Modifier.width(8.dp))
SmallTextButton(
- text = "默认",
- icon = Icons.Default.RestartAlt,
+ text = "榛樿",
+ imageVector = Icons.Default.RestartAlt,
onClick = {
onValueChange(defaultValue)
textFieldState.edit {
@@ -163,7 +163,7 @@ fun SliderSettingItem(
TextField(
state = textFieldState,
lineLimits = TextFieldLineLimits.SingleLine,
- label = { AppText("输入数值 (${valueRange.start.toInt()}-${valueRange.endInclusive.toInt()})") },
+ label = { AppText("杈撳叆鏁板€?(${valueRange.start.toInt()}-${valueRange.endInclusive.toInt()})") },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
modifier = Modifier
.fillMaxWidth()
@@ -212,16 +212,16 @@ fun SliderSettingItem(
horizontalArrangement = Arrangement.End
) {
SmallTextButton(
- text = if (isInputMode) "滑块" else "输入",
- icon = if (isInputMode) Icons.Default.LinearScale else Icons.Default.Edit,
+ text = if (isInputMode) "婊戝潡" else "杈撳叆",
+ imageVector = if (isInputMode) Icons.Default.LinearScale else Icons.Default.Edit,
onClick = { isInputMode = !isInputMode }
)
Spacer(Modifier.width(8.dp))
SmallTextButton(
- text = "默认",
- icon = Icons.Default.RestartAlt,
+ text = "榛樿",
+ imageVector = Icons.Default.RestartAlt,
onClick = {
onValueChange(defaultValue)
textFieldState.edit {
@@ -237,4 +237,5 @@ fun SliderSettingItem(
}
)
}
-}
\ No newline at end of file
+}
+
diff --git a/app/src/main/java/io/legado/app/ui/widget/components/swipe/SwipeActionContainer.kt b/app/src/main/java/io/legado/app/ui/widget/components/swipe/SwipeActionContainer.kt
index b388dced4..c204fa1b6 100644
--- a/app/src/main/java/io/legado/app/ui/widget/components/swipe/SwipeActionContainer.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/components/swipe/SwipeActionContainer.kt
@@ -27,6 +27,7 @@ import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -128,7 +129,7 @@ private fun SwipeBackground(
targetValue = if (isThresholdReached)
action.background
else
- MaterialTheme.colorScheme.surfaceVariant,
+ LegadoTheme.colorScheme.surfaceVariant,
label = "bgColor"
)
@@ -160,7 +161,7 @@ private fun SwipeBackground(
tint = if (isThresholdReached)
contentColorFor(action.background)
else
- MaterialTheme.colorScheme.onSurfaceVariant
+ LegadoTheme.colorScheme.onSurfaceVariant
)
}
}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index d0432698d..10cdac732 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,9 +1,9 @@
[versions]
accompanistWebview = "0.36.0"
-adaptive = "1.3.0-alpha09"
-adaptiveLayout = "1.3.0-alpha09"
-adaptiveNavigation = "1.3.0-alpha09"
+adaptive = "1.3.0-alpha10"
+adaptiveLayout = "1.3.0-alpha10"
+adaptiveNavigation = "1.3.0-alpha10"
animation = "1.10.6"
biometric = "1.4.0-alpha06"
coilCompose = "2.7.0"
@@ -46,8 +46,8 @@ liveeventbus = "1.8.14"
navigation3 = "1.0.1"
markdownCompose = "0.5.0"
markwon = "4.6.2"
-material = "1.14.0-alpha10"
-material3 = "1.5.0-alpha15"
+material = "1.14.0-beta01"
+material3 = "1.5.0-alpha17"
material3IconsExtended = "1.7.8"
materialKolor = "4.1.1"
media = "1.7.1"