Kaynağa Gözat

[优化] 界面优化

HapeLee 7 ay önce
ebeveyn
işleme
1d585ecec9
41 değiştirilmiş dosya ile 1040 ekleme ve 450 silme
  1. 0 10
      app/src/main/AndroidManifest.xml
  2. 2 0
      app/src/main/java/io/legado/app/di/appModule.kt
  3. 2 1
      app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt
  4. 0 1
      app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt
  5. 0 163
      app/src/main/java/io/legado/app/ui/book/import/BaseImportBookActivity.kt
  6. 497 0
      app/src/main/java/io/legado/app/ui/book/import/local/ImportBookScreen.kt
  7. 3 3
      app/src/main/java/io/legado/app/ui/book/info/edit/BookInfoEditScreen.kt
  8. 134 55
      app/src/main/java/io/legado/app/ui/book/readRecord/ReadRecordScreen.kt
  9. 2 2
      app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt
  10. 1 1
      app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt
  11. 4 3
      app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt
  12. 1 1
      app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt
  13. 2 2
      app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt
  14. 41 0
      app/src/main/java/io/legado/app/ui/main/MainActivity.kt
  15. 6 2
      app/src/main/java/io/legado/app/ui/main/MainScreen.kt
  16. 32 15
      app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfScreen.kt
  17. 2 1
      app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt
  18. 4 1
      app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt
  19. 3 2
      app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt
  20. 3 1
      app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt
  21. 29 47
      app/src/main/java/io/legado/app/ui/replace/edit/ReplaceEditScreen.kt
  22. 3 2
      app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt
  23. 2 1
      app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt
  24. 1 1
      app/src/main/java/io/legado/app/ui/theme/AdaptivePadding.kt
  25. 2 1
      app/src/main/java/io/legado/app/ui/widget/CollapsibleHeader.kt
  26. 35 0
      app/src/main/java/io/legado/app/ui/widget/components/AppRadioButtom.kt
  27. 3 2
      app/src/main/java/io/legado/app/ui/widget/components/GroupManageBottomSheet.kt
  28. 4 4
      app/src/main/java/io/legado/app/ui/widget/components/ValueStepper.kt
  29. 15 15
      app/src/main/java/io/legado/app/ui/widget/components/button/MediumIconButton.kt
  30. 12 13
      app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt
  31. 3 3
      app/src/main/java/io/legado/app/ui/widget/components/button/SmallTextButton.kt
  32. 87 0
      app/src/main/java/io/legado/app/ui/widget/components/button/ToggleChip.kt
  33. 3 2
      app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt
  34. 30 33
      app/src/main/java/io/legado/app/ui/widget/components/heatmap/HeatmapCalendarComponents.kt
  35. 3 4
      app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/AppModalBottomSheet.kt
  36. 1 2
      app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/OptionSheet.kt
  37. 42 32
      app/src/main/java/io/legado/app/ui/widget/components/rules/RuleEditSheet.kt
  38. 5 5
      app/src/main/java/io/legado/app/ui/widget/components/settingItem/InputSettingItem.kt
  39. 13 12
      app/src/main/java/io/legado/app/ui/widget/components/settingItem/SliderSettingItem.kt
  40. 3 2
      app/src/main/java/io/legado/app/ui/widget/components/swipe/SwipeActionContainer.kt
  41. 5 5
      gradle/libs.versions.toml

+ 0 - 10
app/src/main/AndroidManifest.xml

@@ -274,16 +274,6 @@
             android:configChanges="orientation|screenSize"
             android:configChanges="orientation|screenSize"
             android:hardwareAccelerated="true"
             android:hardwareAccelerated="true"
             android:launchMode="singleTop" />
             android:launchMode="singleTop" />
-        <!-- 导入书籍 -->
-        <activity
-            android:name=".ui.book.import.local.ImportBookActivity"
-            android:enableOnBackInvokedCallback="true"
-            android:launchMode="singleTop" />
-        <!-- 添加远程 -->
-        <activity
-            android:name=".ui.book.import.remote.RemoteBookActivity"
-            android:enableOnBackInvokedCallback="true"
-            android:launchMode="singleTop" />
         <!-- 发现界面 -->
         <!-- 发现界面 -->
         <activity
         <activity
             android:name=".ui.book.explore.ExploreShowActivity"
             android:name=".ui.book.explore.ExploreShowActivity"

+ 2 - 0
app/src/main/java/io/legado/app/di/appModule.kt

@@ -22,6 +22,7 @@ import io.legado.app.help.http.okHttpClientManga
 import io.legado.app.ui.book.bookmark.AllBookmarkViewModel
 import io.legado.app.ui.book.bookmark.AllBookmarkViewModel
 import io.legado.app.ui.book.explore.ExploreShowViewModel
 import io.legado.app.ui.book.explore.ExploreShowViewModel
 import io.legado.app.ui.book.group.GroupViewModel
 import io.legado.app.ui.book.group.GroupViewModel
+import io.legado.app.ui.book.import.local.ImportBookViewModel
 import io.legado.app.ui.book.import.remote.RemoteBookViewModel
 import io.legado.app.ui.book.import.remote.RemoteBookViewModel
 import io.legado.app.ui.book.info.BookInfoViewModel
 import io.legado.app.ui.book.info.BookInfoViewModel
 import io.legado.app.ui.book.readRecord.ReadRecordViewModel
 import io.legado.app.ui.book.readRecord.ReadRecordViewModel
@@ -97,6 +98,7 @@ val appModule = module {
     viewModelOf(::ThemeConfigViewModel)
     viewModelOf(::ThemeConfigViewModel)
     viewModelOf(::BackupConfigViewModel)
     viewModelOf(::BackupConfigViewModel)
     viewModelOf(::TocViewModel)
     viewModelOf(::TocViewModel)
+    viewModelOf(::ImportBookViewModel)
     viewModelOf(::RemoteBookViewModel)
     viewModelOf(::RemoteBookViewModel)
     viewModelOf(::BookInfoViewModel)
     viewModelOf(::BookInfoViewModel)
     viewModelOf(::ExploreViewModel)
     viewModelOf(::ExploreViewModel)

+ 2 - 1
app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkScreen.kt

@@ -49,6 +49,7 @@ import androidx.compose.ui.unit.dp
 import io.legado.app.data.entities.Bookmark
 import io.legado.app.data.entities.Bookmark
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.ThemeResolver
 import io.legado.app.ui.theme.ThemeResolver
+import io.legado.app.ui.theme.adaptiveContentPadding
 import io.legado.app.ui.theme.adaptiveContentPaddingOnlyVertical
 import io.legado.app.ui.theme.adaptiveContentPaddingOnlyVertical
 import io.legado.app.ui.theme.adaptiveHorizontalPadding
 import io.legado.app.ui.theme.adaptiveHorizontalPadding
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.AppScaffold
@@ -242,7 +243,7 @@ fun AllBookmarkScreen(
                             FastScrollLazyColumn(
                             FastScrollLazyColumn(
                                 state = listState,
                                 state = listState,
                                 modifier = Modifier.fillMaxSize(),
                                 modifier = Modifier.fillMaxSize(),
-                                contentPadding = adaptiveContentPaddingOnlyVertical(
+                                contentPadding = adaptiveContentPadding(
                                     top = paddingValues.calculateTopPadding(),
                                     top = paddingValues.calculateTopPadding(),
                                     bottom = 120.dp
                                     bottom = 120.dp
                                 )
                                 )

+ 0 - 1
app/src/main/java/io/legado/app/ui/book/explore/ExploreShowScreen.kt

@@ -235,7 +235,6 @@ fun ExploreShowScreen(
 
 
     AppModalBottomSheet(
     AppModalBottomSheet(
         show = showKindSheet,
         show = showKindSheet,
-        containerColor = LegadoTheme.colorScheme.surface,
         onDismissRequest = { showKindSheet = false }
         onDismissRequest = { showKindSheet = false }
     ) {
     ) {
 
 

+ 0 - 163
app/src/main/java/io/legado/app/ui/book/import/BaseImportBookActivity.kt

@@ -1,163 +0,0 @@
-package io.legado.app.ui.book.import
-
-import android.os.Bundle
-import android.view.MotionEvent
-import androidx.appcompat.widget.SearchView
-import androidx.lifecycle.ViewModel
-import io.legado.app.R
-import io.legado.app.base.VMBaseActivity
-import io.legado.app.constant.AppPattern
-import io.legado.app.data.appDb
-import io.legado.app.data.entities.Book
-import io.legado.app.databinding.ActivityImportBookBinding
-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.theme.primaryTextColor
-import io.legado.app.model.localBook.LocalBook
-import io.legado.app.ui.file.HandleFileContract
-import io.legado.app.utils.ArchiveUtils
-import io.legado.app.utils.FileDoc
-import io.legado.app.utils.hideSoftInput
-import io.legado.app.utils.shouldHideSoftInput
-import io.legado.app.utils.startActivityForBook
-import io.legado.app.utils.toastOnUi
-import io.legado.app.utils.viewbindingdelegate.viewBinding
-import kotlin.coroutines.resume
-import kotlin.coroutines.suspendCoroutine
-
-abstract class BaseImportBookActivity<VM : ViewModel> :
-    VMBaseActivity<ActivityImportBookBinding, VM>() {
-
-    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<String>) {
-        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
-            }
-        })
-    }
-
-}

+ 497 - 0
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<String>,
+    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
+                )
+            }
+        }
+    }
+}

+ 3 - 3
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(
                     MediumOutlinedIconButton(
                         onClick = { selectCover.launch() },
                         onClick = { selectCover.launch() },
-                        icon = Icons.Default.FolderOpen
+                        imageVector = Icons.Default.FolderOpen
                     )
                     )
                     MediumOutlinedIconButton(
                     MediumOutlinedIconButton(
                         onClick = { viewModel.resetCover() },
                         onClick = { viewModel.resetCover() },
-                        icon = Icons.Default.Replay
+                        imageVector = Icons.Default.Replay
                     )
                     )
                 }
                 }
                 Spacer(modifier = Modifier.height(4.dp))
                 Spacer(modifier = Modifier.height(4.dp))

+ 134 - 55
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.ReadRecord
 import io.legado.app.data.entities.readRecord.ReadRecordDetail
 import io.legado.app.data.entities.readRecord.ReadRecordDetail
 import io.legado.app.ui.theme.LegadoTheme
 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.theme.adaptiveHorizontalPadding
 import io.legado.app.ui.widget.CollapsibleHeader
 import io.legado.app.ui.widget.CollapsibleHeader
 import io.legado.app.ui.widget.components.AppScaffold
 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.AppIconButton
 import io.legado.app.ui.widget.components.button.TopBarNavigationButton
 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.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.checkBox.CheckboxItem
 import io.legado.app.ui.widget.components.cover.Cover
 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.HeatmapConfig
 import io.legado.app.ui.widget.components.heatmap.HeatmapLegend
 import io.legado.app.ui.widget.components.heatmap.HeatmapLegend
 import io.legado.app.ui.widget.components.heatmap.HeatmapMode
 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.rememberDaysInRange
 import io.legado.app.ui.widget.components.heatmap.rememberWeeks
 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.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.modalBottomSheet.AppModalBottomSheet
 import io.legado.app.ui.widget.components.swipe.SwipeAction
 import io.legado.app.ui.widget.components.swipe.SwipeAction
 import io.legado.app.ui.widget.components.swipe.SwipeActionContainer
 import io.legado.app.ui.widget.components.swipe.SwipeActionContainer
@@ -118,6 +124,7 @@ fun ReadRecordScreen(
     val displayMode by viewModel.displayMode.collectAsState()
     val displayMode by viewModel.displayMode.collectAsState()
     var showSearch by remember { mutableStateOf(false) }
     var showSearch by remember { mutableStateOf(false) }
     var showCalendar by remember { mutableStateOf(false) }
     var showCalendar by remember { mutableStateOf(false) }
+    var heatmapMode by remember { mutableStateOf(HeatmapMode.COUNT) }
     val listState = rememberLazyListState()
     val listState = rememberLazyListState()
     val scrollBehavior = GlassTopAppBarDefaults.defaultScrollBehavior()
     val scrollBehavior = GlassTopAppBarDefaults.defaultScrollBehavior()
 
 
@@ -131,6 +138,36 @@ fun ReadRecordScreen(
             pendingDeleteAction = action
             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) {
     LaunchedEffect(state.searchKey) {
         if (state.searchKey.isNullOrBlank()) {
         if (state.searchKey.isNullOrBlank()) {
@@ -198,41 +235,52 @@ fun ReadRecordScreen(
             }
             }
         }
         }
     ) { padding ->
     ) { 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(
                         LazyColumn(
                             state = listState,
                             state = listState,
-                            modifier = Modifier
-                                .nestedScroll(scrollBehavior.nestedScrollConnection)
+                            modifier = Modifier.fillMaxSize(),
+                            contentPadding = adaptiveContentPaddingOnlyVertical(
+                                top = padding.calculateTopPadding(),
+                                bottom = padding.calculateBottomPadding() + 16.dp
+                            )
                         ) {
                         ) {
                             item(key = "summary_card") {
                             item(key = "summary_card") {
                                 SummarySection(state, viewModel)
                                 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(
     AppModalBottomSheet(
         show = showCalendar,
         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(
         HeatmapCalendarSection(
             dailyReadCounts = state.dailyReadCounts,
             dailyReadCounts = state.dailyReadCounts,
             dailyReadTimes = state.dailyReadTimes,
             dailyReadTimes = state.dailyReadTimes,
+            currentMode = heatmapMode,
             selectedDate = state.selectedDate,
             selectedDate = state.selectedDate,
             onDateSelected = { date ->
             onDateSelected = { date ->
                 viewModel.setSelectedDate(date)
                 viewModel.setSelectedDate(date)
                 showCalendar = false
                 showCalendar = false
-            },
-            onClearDate = {
-                viewModel.setSelectedDate(null)
-                showCalendar = false
             }
             }
         )
         )
     }
     }
@@ -404,13 +490,11 @@ fun HeatmapCalendarSection(
     modifier: Modifier = Modifier,
     modifier: Modifier = Modifier,
     dailyReadCounts: Map<LocalDate, Int>,
     dailyReadCounts: Map<LocalDate, Int>,
     dailyReadTimes: Map<LocalDate, Long>,
     dailyReadTimes: Map<LocalDate, Long>,
+    currentMode: HeatmapMode,
     selectedDate: LocalDate?,
     selectedDate: LocalDate?,
     onDateSelected: (LocalDate) -> Unit,
     onDateSelected: (LocalDate) -> Unit,
-    onClearDate: () -> Unit,
     config: HeatmapConfig = HeatmapConfig()
     config: HeatmapConfig = HeatmapConfig()
 ) {
 ) {
-    var currentMode by remember { mutableStateOf(HeatmapMode.COUNT) }
-
     val (startDate, endDate) = rememberDateRange(dailyReadCounts, dailyReadTimes)
     val (startDate, endDate) = rememberDateRange(dailyReadCounts, dailyReadTimes)
     val days = rememberDaysInRange(startDate, endDate)
     val days = rememberDaysInRange(startDate, endDate)
     val weeks = rememberWeeks(days, startDate)
     val weeks = rememberWeeks(days, startDate)
@@ -452,14 +536,6 @@ fun HeatmapCalendarSection(
             .padding(horizontal = 16.dp, vertical = 8.dp)
             .padding(horizontal = 16.dp, vertical = 8.dp)
             .padding(bottom = 32.dp)
             .padding(bottom = 32.dp)
     ) {
     ) {
-        HeatmapCalendarTopBar(
-            currentMode = currentMode,
-            onModeChanged = { currentMode = it },
-            onClearDate = onClearDate
-        )
-
-        Spacer(modifier = Modifier.height(8.dp))
-
         Row(modifier = Modifier.fillMaxWidth()) {
         Row(modifier = Modifier.fillMaxWidth()) {
             WeekdayLabelsColumn(
             WeekdayLabelsColumn(
                 cellSize = config.cellSize,
                 cellSize = config.cellSize,
@@ -543,10 +619,13 @@ fun LazyListScope.renderListByMode(
     when (displayMode) {
     when (displayMode) {
         DisplayMode.AGGREGATE -> {
         DisplayMode.AGGREGATE -> {
             state.groupedRecords.forEach { (date, details) ->
             state.groupedRecords.forEach { (date, details) ->
-                stickyHeader(key = "header_$date") {
+                item(key = "header_$date") {
                     DateHeader(date, details.sumOf { it.readTime })
                     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(
                     SwipeActionContainer(
                         modifier = Modifier.animateItem(),
                         modifier = Modifier.animateItem(),
                         startAction = SwipeAction(
                         startAction = SwipeAction(
@@ -568,8 +647,8 @@ fun LazyListScope.renderListByMode(
 
 
         DisplayMode.TIMELINE -> {
         DisplayMode.TIMELINE -> {
             state.timelineRecords.forEach { (date, sessions) ->
             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(
                     SwipeActionContainer(
                         modifier = Modifier.animateItem(),
                         modifier = Modifier.animateItem(),
                         startAction = SwipeAction(
                         startAction = SwipeAction(
@@ -637,7 +716,7 @@ fun LatestReadItem(
         modifier = modifier
         modifier = modifier
             .fillMaxWidth()
             .fillMaxWidth()
             .clickable(onClick = onClick)
             .clickable(onClick = onClick)
-            .padding(horizontal = 16.dp, vertical = 8.dp),
+            .adaptiveHorizontalPadding(vertical = 8.dp),
         verticalAlignment = Alignment.CenterVertically
         verticalAlignment = Alignment.CenterVertically
     ) {
     ) {
         Cover(coverPath)
         Cover(coverPath)
@@ -798,7 +877,7 @@ fun ReadRecordItem(
         modifier = modifier
         modifier = modifier
             .fillMaxWidth()
             .fillMaxWidth()
             .clickable(onClick = onClick)
             .clickable(onClick = onClick)
-            .padding(horizontal = 16.dp, vertical = 8.dp),
+            .adaptiveHorizontalPadding(vertical = 8.dp),
         verticalAlignment = Alignment.CenterVertically
         verticalAlignment = Alignment.CenterVertically
     ) {
     ) {
         Cover(coverPath)
         Cover(coverPath)
@@ -877,7 +956,7 @@ fun ReadingSummaryCard(
         onClick = onClick,
         onClick = onClick,
         modifier = Modifier
         modifier = Modifier
             .fillMaxWidth()
             .fillMaxWidth()
-            .padding(horizontal = 16.dp, vertical = 8.dp),
+            .adaptiveHorizontalPadding(vertical = 8.dp),
         containerColor = LegadoTheme.colorScheme.surfaceContainer
         containerColor = LegadoTheme.colorScheme.surfaceContainer
     ) {
     ) {
         Row(
         Row(

+ 2 - 2
app/src/main/java/io/legado/app/ui/book/searchContent/SearchContentScreen.kt

@@ -345,7 +345,7 @@ fun SearchHistoryList(
                         trailingContent = {
                         trailingContent = {
                             SmallIconButton(
                             SmallIconButton(
                                 onClick = { onDeleteHistory(item) },
                                 onClick = { onDeleteHistory(item) },
-                                icon = Icons.Default.Close,
+                                imageVector = Icons.Default.Close,
                                 contentDescription = "删除"
                                 contentDescription = "删除"
                             )
                             )
                         },
                         },
@@ -366,7 +366,7 @@ fun SearchHistoryList(
                         MediumOutlinedButton(
                         MediumOutlinedButton(
                             onClick = onClearHistory,
                             onClick = onClearHistory,
                             modifier = Modifier.fillMaxWidth(0.6f),
                             modifier = Modifier.fillMaxWidth(0.6f),
-                            icon = Icons.Outlined.DeleteSweep,
+                            imageVector = Icons.Outlined.DeleteSweep,
                             text = "清除搜索历史"
                             text = "清除搜索历史"
                         )
                         )
                     }
                     }

+ 1 - 1
app/src/main/java/io/legado/app/ui/book/toc/TocScreen.kt

@@ -469,7 +469,7 @@ fun TocScreen(
                                 SmallOutlinedIconToggleButton(
                                 SmallOutlinedIconToggleButton(
                                     checked = showVolumeMenu,
                                     checked = showVolumeMenu,
                                     onCheckedChange = { showVolumeMenu = it },
                                     onCheckedChange = { showVolumeMenu = it },
-                                    icon = Icons.AutoMirrored.Filled.FormatListBulleted,
+                                    imageVector = Icons.AutoMirrored.Filled.FormatListBulleted,
                                     contentDescription = "卷管理"
                                     contentDescription = "卷管理"
                                 )
                                 )
                                 RoundDropdownMenu(
                                 RoundDropdownMenu(

+ 4 - 3
app/src/main/java/io/legado/app/ui/book/toc/rule/TxtRuleScreen.kt

@@ -204,7 +204,7 @@ fun TxtRuleScreen(
     }
     }
 
 
     AppAlertDialog(
     AppAlertDialog(
-        data = showDeleteRuleDialog, // 传入 nullable 的 rule 对象
+        data = showDeleteRuleDialog, // 传入 nullable �rule 对象
         onDismissRequest = { showDeleteRuleDialog = null },
         onDismissRequest = { showDeleteRuleDialog = null },
         title = stringResource(R.string.delete),
         title = stringResource(R.string.delete),
         confirmText = stringResource(R.string.ok),
         confirmText = stringResource(R.string.ok),
@@ -228,7 +228,7 @@ fun TxtRuleScreen(
             editingRule = null
             editingRule = null
         },
         },
         onSave = { updatedRule ->
         onSave = { updatedRule ->
-            //TODO:我很想把他改为自增主键,但为了兼容性日��说
+            //TODO:我很想把他改为自增主键,但为了兼容性日���
             if (editingRule == null) {
             if (editingRule == null) {
                 viewModel.insert(updatedRule)
                 viewModel.insert(updatedRule)
             } else {
             } else {
@@ -346,7 +346,7 @@ fun TxtRuleScreen(
                         trailingAction = {
                         trailingAction = {
                             SmallIconButton(
                             SmallIconButton(
                                 onClick = { showDeleteRuleDialog = item.rule },
                                 onClick = { showDeleteRuleDialog = item.rule },
-                                icon = Icons.Default.Delete
+                                imageVector = Icons.Default.Delete
                             )
                             )
                         }
                         }
                     )
                     )
@@ -368,3 +368,4 @@ fun TxtRuleScreen(
         }
         }
     }
     }
 }
 }
+

+ 1 - 1
app/src/main/java/io/legado/app/ui/config/otherConfig/DirectLinkUploadBottomSheet.kt

@@ -68,7 +68,7 @@ fun DirectLinkUploadBottomSheet(
         endAction = {
         endAction = {
             MediumIconButton(
             MediumIconButton(
                 onClick = { showMenu = true },
                 onClick = { showMenu = true },
-                icon = Icons.Default.MoreVert
+                imageVector = Icons.Default.MoreVert
             )
             )
             RoundDropdownMenu(
             RoundDropdownMenu(
                 expanded = showMenu,
                 expanded = showMenu,

+ 2 - 2
app/src/main/java/io/legado/app/ui/dict/rule/DictRuleScreen.kt

@@ -320,7 +320,7 @@ fun DictRuleScreen(
                         trailingAction = {
                         trailingAction = {
                             SmallIconButton(
                             SmallIconButton(
                                 onClick = { showDeleteRuleDialog = item.rule },
                                 onClick = { showDeleteRuleDialog = item.rule },
-                                icon = Icons.Default.Delete
+                                imageVector = Icons.Default.Delete
                             )
                             )
                         }
                         }
                     )
                     )
@@ -341,4 +341,4 @@ fun DictRuleScreen(
             }
             }
         }
         }
     }
     }
-}
+}

+ 41 - 0
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.service.WebService
 import io.legado.app.ui.about.CrashLogsDialog
 import io.legado.app.ui.about.CrashLogsDialog
 import io.legado.app.ui.about.UpdateDialog
 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.book.read.ReadBookActivity
 import io.legado.app.ui.config.ConfigNavScreen
 import io.legado.app.ui.config.ConfigNavScreen
 import io.legado.app.ui.config.ConfigTag
 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_COVER = "settings/cover"
         private const val ROUTE_SETTINGS_THEME = "settings/theme"
         private const val ROUTE_SETTINGS_THEME = "settings/theme"
         private const val ROUTE_SETTINGS_BACKUP = "settings/backup"
         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 {
         fun createIntent(context: Context, configTag: String? = null): Intent {
             return Intent(context, MainActivity::class.java).apply {
             return Intent(context, MainActivity::class.java).apply {
@@ -120,6 +124,12 @@ open class MainActivity : BaseComposeActivity() {
     @Serializable
     @Serializable
     private data object MainRouteSettingsBackup : MainRoute
     private data object MainRouteSettingsBackup : MainRoute
 
 
+    @Serializable
+    private data object MainRouteImportLocal : MainRoute
+
+    @Serializable
+    private data object MainRouteImportRemote : MainRoute
+
     override fun onCreate(savedInstanceState: Bundle?) {
     override fun onCreate(savedInstanceState: Bundle?) {
         installSplashScreen()
         installSplashScreen()
         super.onCreate(savedInstanceState)
         super.onCreate(savedInstanceState)
@@ -260,6 +270,12 @@ open class MainActivity : BaseComposeActivity() {
                         useRail = useRail,
                         useRail = useRail,
                         onOpenSettings = {
                         onOpenSettings = {
                             navigateToRoute(backStack, MainRouteSettings)
                             navigateToRoute(backStack, MainRouteSettings)
+                        },
+                        onNavigateToRemoteImport = {
+                            navigateToRoute(backStack, MainRouteImportRemote)
+                        },
+                        onNavigateToLocalImport = {
+                            navigateToRoute(backStack, MainRouteImportLocal)
                         }
                         }
                     )
                     )
                 }
                 }
@@ -294,6 +310,18 @@ open class MainActivity : BaseComposeActivity() {
                 entry<MainRouteSettingsBackup> {
                 entry<MainRouteSettingsBackup> {
                     BackupConfigScreen(onBackClick = { navigateBack(backStack) })
                     BackupConfigScreen(onBackClick = { navigateBack(backStack) })
                 }
                 }
+
+                entry<MainRouteImportLocal> {
+                    ImportBookScreen(
+                        onBackClick = { navigateBack(backStack) }
+                    )
+                }
+
+                entry<MainRouteImportRemote> {
+                    RemoteBookScreen(
+                        onBackClick = { navigateBack(backStack) }
+                    )
+                }
             }
             }
         )
         )
     }
     }
@@ -328,6 +356,17 @@ open class MainActivity : BaseComposeActivity() {
                 backStack.add(MainRouteSettings)
                 backStack.add(MainRouteSettings)
                 backStack.add(route)
                 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/cover" -> MainRouteSettingsCover
             "settings/theme" -> MainRouteSettingsTheme
             "settings/theme" -> MainRouteSettingsTheme
             "settings/backup" -> MainRouteSettingsBackup
             "settings/backup" -> MainRouteSettingsBackup
+            "import/local" -> MainRouteImportLocal
+            "import/remote" -> MainRouteImportRemote
             else -> MainRouteHome
             else -> MainRouteHome
         }
         }
     }
     }

+ 6 - 2
app/src/main/java/io/legado/app/ui/main/MainScreen.kt

@@ -89,7 +89,9 @@ import org.koin.androidx.compose.koinViewModel
 fun MainScreen(
 fun MainScreen(
     viewModel: MainViewModel = koinViewModel(),
     viewModel: MainViewModel = koinViewModel(),
     useRail: Boolean,
     useRail: Boolean,
-    onOpenSettings: () -> Unit
+    onOpenSettings: () -> Unit,
+    onNavigateToRemoteImport: () -> Unit,
+    onNavigateToLocalImport: () -> Unit
 ) {
 ) {
     val context = LocalContext.current
     val context = LocalContext.current
     val coroutineScope = rememberCoroutineScope()
     val coroutineScope = rememberCoroutineScope()
@@ -373,7 +375,9 @@ fun MainScreen(
                                     putExtra("author", book.author)
                                     putExtra("author", book.author)
                                     putExtra("bookUrl", book.bookUrl)
                                     putExtra("bookUrl", book.bookUrl)
                                 }
                                 }
-                            }
+                            },
+                            onNavigateToRemoteImport = onNavigateToRemoteImport,
+                            onNavigateToLocalImport = onNavigateToLocalImport
                         )
                         )
 
 
                         MainDestination.Explore -> ExploreScreen()
                         MainDestination.Explore -> ExploreScreen()

+ 32 - 15
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.base.BaseRuleEvent
 import io.legado.app.ui.about.AppLogSheet
 import io.legado.app.ui.about.AppLogSheet
 import io.legado.app.ui.book.cache.CacheActivity
 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.manage.BookshelfManageActivity
 import io.legado.app.ui.book.search.SearchActivity
 import io.legado.app.ui.book.search.SearchActivity
 import io.legado.app.ui.config.bookshelfConfig.BookshelfConfig
 import io.legado.app.ui.config.bookshelfConfig.BookshelfConfig
 import io.legado.app.ui.theme.LegadoTheme
 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.adaptiveContentPadding
 import io.legado.app.ui.theme.adaptiveHorizontalPadding
 import io.legado.app.ui.theme.adaptiveHorizontalPadding
 import io.legado.app.ui.widget.components.button.SmallOutlinedIconToggleButton
 import io.legado.app.ui.widget.components.button.SmallOutlinedIconToggleButton
@@ -100,7 +99,9 @@ import org.koin.androidx.compose.koinViewModel
 fun BookshelfScreen(
 fun BookshelfScreen(
     viewModel: BookshelfViewModel = koinViewModel(),
     viewModel: BookshelfViewModel = koinViewModel(),
     onBookClick: (BookShelfItem) -> Unit,
     onBookClick: (BookShelfItem) -> Unit,
-    onBookLongClick: (BookShelfItem) -> Unit
+    onBookLongClick: (BookShelfItem) -> Unit,
+    onNavigateToRemoteImport: () -> Unit,
+    onNavigateToLocalImport: () -> Unit
 ) {
 ) {
     val context = LocalContext.current
     val context = LocalContext.current
     val uiState by viewModel.uiState.collectAsState()
     val uiState by viewModel.uiState.collectAsState()
@@ -196,7 +197,7 @@ fun BookshelfScreen(
     }
     }
 
 
     val bookGroupStyle = BookshelfConfig.bookGroupStyle
     val bookGroupStyle = BookshelfConfig.bookGroupStyle
-    // 控制是否处于“文件夹列表”根视图,还是“文件夹内部”书籍视图
+    // 控制是否处于“文件夹列表”根视图,还是“文件夹内部”书籍视��?
     var isInFolderRoot by remember(bookGroupStyle) { mutableStateOf(bookGroupStyle == 2) }
     var isInFolderRoot by remember(bookGroupStyle) { mutableStateOf(bookGroupStyle == 2) }
     val baseTitle = when {
     val baseTitle = when {
         bookGroupStyle == 1 -> {
         bookGroupStyle == 1 -> {
@@ -232,6 +233,10 @@ fun BookshelfScreen(
         if (isLandscape) BookshelfConfig.bookshelfLayoutGridLandscape else BookshelfConfig.bookshelfLayoutGridPortrait
         if (isLandscape) BookshelfConfig.bookshelfLayoutGridLandscape else BookshelfConfig.bookshelfLayoutGridPortrait
     val bookshelfLayoutList =
     val bookshelfLayoutList =
         if (isLandscape) BookshelfConfig.bookshelfLayoutListLandscape else BookshelfConfig.bookshelfLayoutListPortrait
         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(
     ListScaffold(
         title = title,
         title = title,
@@ -242,12 +247,12 @@ fun BookshelfScreen(
         dropDownMenuContent = { dismiss ->
         dropDownMenuContent = { dismiss ->
             RoundDropdownMenuItem(
             RoundDropdownMenuItem(
                 text = stringResource(R.string.add_remote_book),
                 text = stringResource(R.string.add_remote_book),
-                onClick = { context.startActivity<RemoteBookActivity>(); dismiss() },
+                onClick = { onNavigateToRemoteImport(); dismiss() },
                 leadingIcon = { Icon(Icons.Default.Wifi, null) }
                 leadingIcon = { Icon(Icons.Default.Wifi, null) }
             )
             )
             RoundDropdownMenuItem(
             RoundDropdownMenuItem(
                 text = stringResource(R.string.book_local),
                 text = stringResource(R.string.book_local),
-                onClick = { context.startActivity<ImportBookActivity>(); dismiss() },
+                onClick = { onNavigateToLocalImport(); dismiss() },
                 leadingIcon = { Icon(Icons.Default.Save, null) }
                 leadingIcon = { Icon(Icons.Default.Save, null) }
             )
             )
             RoundDropdownMenuItem(
             RoundDropdownMenuItem(
@@ -345,7 +350,7 @@ fun BookshelfScreen(
                                 SmallOutlinedIconToggleButton(
                                 SmallOutlinedIconToggleButton(
                                     checked = showGroupMenu,
                                     checked = showGroupMenu,
                                     onCheckedChange = { showGroupMenu = it },
                                     onCheckedChange = { showGroupMenu = it },
-                                    icon = Icons.AutoMirrored.Filled.FormatListBulleted,
+                                    imageVector = Icons.AutoMirrored.Filled.FormatListBulleted,
                                     contentDescription = stringResource(R.string.group_manage)
                                     contentDescription = stringResource(R.string.group_manage)
                                 )
                                 )
                                 RoundDropdownMenu(
                                 RoundDropdownMenu(
@@ -407,15 +412,19 @@ fun BookshelfScreen(
                 if (bookGroupStyle == 2 && isRoot) {
                 if (bookGroupStyle == 2 && isRoot) {
                     val folderColumns =
                     val folderColumns =
                         if (bookshelfLayoutMode == 0) bookshelfLayoutList else bookshelfLayoutGrid
                         if (bookshelfLayoutMode == 0) bookshelfLayoutList else bookshelfLayoutGrid
+                    val isGridMode = bookshelfLayoutMode != 0
                     FastScrollLazyVerticalGrid(
                     FastScrollLazyVerticalGrid(
                         columns = GridCells.Fixed(folderColumns.coerceAtLeast(1)),
                         columns = GridCells.Fixed(folderColumns.coerceAtLeast(1)),
-                        modifier = Modifier.fillMaxSize(),
+                        modifier = Modifier
+                            .fillMaxSize()
+                            .padding(horizontal = if (isGridMode) gridInnerHorizontalPadding else 0.dp),
                         contentPadding = adaptiveContentPadding(
                         contentPadding = adaptiveContentPadding(
                             top = paddingValues.calculateTopPadding(),
                             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
                         showFastScroll = BookshelfConfig.showBookshelfFastScroller
                     ) {
                     ) {
                         itemsIndexed(
                         itemsIndexed(
@@ -592,16 +601,23 @@ fun BookshelfPage(
     onBookLongClick: (BookShelfItem) -> Unit
     onBookLongClick: (BookShelfItem) -> Unit
 ) {
 ) {
     val columns = if (bookshelfLayoutMode == 0) bookshelfLayoutList else bookshelfLayoutGrid
     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(
     FastScrollLazyVerticalGrid(
         columns = GridCells.Fixed(columns.coerceAtLeast(1)),
         columns = GridCells.Fixed(columns.coerceAtLeast(1)),
-        modifier = Modifier.fillMaxSize(),
+        modifier = Modifier
+            .fillMaxSize()
+            .padding(horizontal = if (isGridMode) gridInnerHorizontalPadding else 0.dp),
         contentPadding = adaptiveContentPadding(
         contentPadding = adaptiveContentPadding(
             top = paddingValues.calculateTopPadding(),
             top = paddingValues.calculateTopPadding(),
             bottom = 120.dp,
             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
         showFastScroll = BookshelfConfig.showBookshelfFastScroller
     ) {
     ) {
         items(books, key = { it.bookUrl }) { book ->
         items(books, key = { it.bookUrl }) { book ->
@@ -621,3 +637,4 @@ fun BookshelfPage(
         }
         }
     }
     }
 }
 }
+

+ 2 - 1
app/src/main/java/io/legado/app/ui/main/bookshelf/GroupManageSheet.kt

@@ -83,7 +83,7 @@ fun GroupManageSheet(
                         editingGroup = null
                         editingGroup = null
                         isEditing = true
                         isEditing = true
                     },
                     },
-                    icon = Icons.Default.Add
+                    imageVector = Icons.Default.Add
                 )
                 )
             }
             }
         }
         }
@@ -130,3 +130,4 @@ fun GroupManageSheet(
         }
         }
     }
     }
 }
 }
+

+ 4 - 1
app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt

@@ -249,8 +249,11 @@ fun ExploreScreen(
                 TextCard(
                 TextCard(
                     text = item.bookSourceName,
                     text = item.bookSourceName,
                     textStyle = LegadoTheme.typography.labelLarge,
                     textStyle = LegadoTheme.typography.labelLarge,
+                    backgroundColor = LegadoTheme.colorScheme.cardContainer,
+                    contentColor = LegadoTheme.colorScheme.onCardContainer,
+                    cornerRadius = 8.dp,
                     horizontalPadding = 8.dp,
                     horizontalPadding = 8.dp,
-                    verticalPadding = 6.dp,
+                    verticalPadding = 8.dp,
                     onClick = {
                     onClick = {
                         scope.launch {
                         scope.launch {
                             val index =
                             val index =

+ 3 - 2
app/src/main/java/io/legado/app/ui/main/my/MyScreen.kt

@@ -235,7 +235,7 @@ fun WebServiceSettingBlock(
             ) {
             ) {
                 SmallTextButton(
                 SmallTextButton(
                     text = "复制地址",
                     text = "复制地址",
-                    icon = Icons.Default.ContentCopy,
+                    imageVector = Icons.Default.ContentCopy,
                     onClick = {
                     onClick = {
                         onNavigate(PrefClickEvent.CopyUrl(uiState.webServiceAddress))
                         onNavigate(PrefClickEvent.CopyUrl(uiState.webServiceAddress))
                     }
                     }
@@ -245,7 +245,7 @@ fun WebServiceSettingBlock(
 
 
                 SmallTextButton(
                 SmallTextButton(
                     text = "浏览器打开",
                     text = "浏览器打开",
-                    icon = Icons.Default.OpenInBrowser,
+                    imageVector = Icons.Default.OpenInBrowser,
                     onClick = {
                     onClick = {
                         onNavigate(PrefClickEvent.OpenUrl(uiState.webServiceAddress))
                         onNavigate(PrefClickEvent.OpenUrl(uiState.webServiceAddress))
                     }
                     }
@@ -254,3 +254,4 @@ fun WebServiceSettingBlock(
         }
         }
     }
     }
 }
 }
+

+ 3 - 1
app/src/main/java/io/legado/app/ui/replace/ReplaceRuleActivity.kt

@@ -143,7 +143,9 @@ class ReplaceRuleActivity : BaseComposeActivity() {
                     }
                     }
 
 
                     entry<ReplaceEditRoute> { route ->
                     entry<ReplaceEditRoute> { route ->
-                        val viewModel: ReplaceEditViewModel = koinViewModel { parametersOf(route) }
+                        val viewModel: ReplaceEditViewModel = koinViewModel(
+                            key = "replace_edit_${System.identityHashCode(route)}"
+                        ) { parametersOf(route) }
 
 
                         ReplaceEditScreen(
                         ReplaceEditScreen(
                             viewModel = viewModel,
                             viewModel = viewModel,

+ 29 - 47
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.ExposedDropdownMenuAnchorType
 import androidx.compose.material3.ExposedDropdownMenuBox
 import androidx.compose.material3.ExposedDropdownMenuBox
 import androidx.compose.material3.ExposedDropdownMenuDefaults
 import androidx.compose.material3.ExposedDropdownMenuDefaults
-import androidx.compose.material3.FilterChip
-import androidx.compose.material3.FilterChipDefaults
 import io.legado.app.ui.widget.components.AppFloatingActionButton
 import io.legado.app.ui.widget.components.AppFloatingActionButton
 import androidx.compose.material3.Icon
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.OutlinedTextField
 import androidx.compose.material3.OutlinedTextField
+import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.material3.TextButton
 import androidx.compose.material3.animateFloatingActionButton
 import androidx.compose.material3.animateFloatingActionButton
 import androidx.compose.runtime.Composable
 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.AppTextField
 import io.legado.app.ui.widget.components.alert.AppAlertDialog
 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.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.button.TopBarNavigationButton
 import io.legado.app.ui.widget.components.checkBox.CheckboxItem
 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.RoundDropdownMenu
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
 import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
 import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.ui.widget.components.text.AppText
@@ -115,15 +117,19 @@ fun ReplaceEditScreen(
                         enter = fadeIn(),
                         enter = fadeIn(),
                         exit = fadeOut()
                         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(
                     RoundDropdownMenu(
                         expanded = showMenu,
                         expanded = showMenu,
                         onDismissRequest = { showMenu = false }
                         onDismissRequest = { showMenu = false }
@@ -158,7 +164,7 @@ fun ReplaceEditScreen(
                 onClick = { viewModel.save(onSaveSuccess) },
                 onClick = { viewModel.save(onSaveSuccess) },
                 tooltipText = "添加"
                 tooltipText = "添加"
             ) {
             ) {
-                Icon(Icons.Default.Save, contentDescription = "保存")
+                AppIcon(Icons.Default.Save, contentDescription = "保存")
             }
             }
         }, contentWindowInsets = WindowInsets(0, 0, 0, 0)
         }, contentWindowInsets = WindowInsets(0, 0, 0, 0)
     ) { innerPadding ->
     ) { innerPadding ->
@@ -242,53 +248,29 @@ fun ReplaceEditScreen(
                     verticalAlignment = Alignment.CenterVertically,
                     verticalAlignment = Alignment.CenterVertically,
                     horizontalArrangement = Arrangement.Start
                     horizontalArrangement = Arrangement.Start
                 ) {
                 ) {
-                    FilterChip(
+                    ToggleChip(
+                        label = "标题",
                         selected = state.scopeTitle,
                         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))
                     Spacer(Modifier.width(8.dp))
 
 
-                    FilterChip(
+                    ToggleChip(
+                        label = "内容",
                         selected = state.scopeContent,
                         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))
                     Spacer(Modifier.weight(1f))
 
 
-                    FilterChip(
+                    ToggleChip(
+                        label = "使用正则",
                         selected = state.isRegex,
                         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) }
                     )
                     )
 
 
                 }
                 }

+ 3 - 2
app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesScreen.kt

@@ -203,7 +203,7 @@ fun RssFavoritesScreen(
                     SelectionItemCard(
                     SelectionItemCard(
                         title = rssStar.title,
                         title = rssStar.title,
                         subtitle = if (rssStar.group.isNotBlank()) {
                         subtitle = if (rssStar.group.isNotBlank()) {
-                            "${rssStar.group} • ${rssStar.pubDate ?: ""}"
+                            "${rssStar.group} �${rssStar.pubDate ?: ""}"
                         } else {
                         } else {
                             rssStar.pubDate
                             rssStar.pubDate
                         },
                         },
@@ -232,7 +232,7 @@ fun RssFavoritesScreen(
                             }
                             }
                             SmallIconButton(
                             SmallIconButton(
                                 onClick = openAction,
                                 onClick = openAction,
-                                icon = Icons.AutoMirrored.Filled.OpenInNew,
+                                imageVector = Icons.AutoMirrored.Filled.OpenInNew,
                                 contentDescription = "Open"
                                 contentDescription = "Open"
                             )
                             )
                         },
                         },
@@ -258,3 +258,4 @@ fun RssFavoritesScreen(
         }
         }
     }
     }
 }
 }
+

+ 2 - 1
app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceScreen.kt

@@ -365,7 +365,7 @@ fun RssSourceScreen(
                         trailingAction = {
                         trailingAction = {
                             SmallIconButton(
                             SmallIconButton(
                                 onClick = { showDeleteRuleDialog = item.source },
                                 onClick = { showDeleteRuleDialog = item.source },
-                                icon = Icons.Default.Delete
+                                imageVector = Icons.Default.Delete
                             )
                             )
                         }
                         }
                     )
                     )
@@ -387,3 +387,4 @@ fun RssSourceScreen(
         }
         }
     }
     }
 }
 }
+

+ 1 - 1
app/src/main/java/io/legado/app/ui/theme/AdaptivePadding.kt

@@ -63,7 +63,7 @@ fun adaptiveContentPadding(
     bottom: Dp,
     bottom: Dp,
     horizontal: Dp
     horizontal: Dp
 ): PaddingValues {
 ): 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(
     return PaddingValues(
         top = adjustedTop,
         top = adjustedTop,
         bottom = bottom,
         bottom = bottom,

+ 2 - 1
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.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.dp
 import io.legado.app.ui.theme.LegadoTheme
 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.card.GlassCard
 import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.ui.widget.components.text.AppText
 
 
@@ -37,7 +38,7 @@ fun CollapsibleHeader(
     GlassCard(
     GlassCard(
         modifier = modifier
         modifier = modifier
             .fillMaxWidth()
             .fillMaxWidth()
-            .padding(start = 16.dp, top = 4.dp, end = 16.dp),
+            .adaptiveHorizontalPadding(vertical = 4.dp),
         shape = MaterialTheme.shapes.medium,
         shape = MaterialTheme.shapes.medium,
         containerColor = LegadoTheme.colorScheme.surfaceContainer,
         containerColor = LegadoTheme.colorScheme.surfaceContainer,
         onClick = onToggle
         onClick = onToggle

+ 35 - 0
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
+        )
+    }
+}

+ 3 - 2
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.Arrangement
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.PaddingValues
@@ -120,7 +120,7 @@ private fun GroupItem(
             ) {
             ) {
                 SmallTextButton(
                 SmallTextButton(
                     text = stringResource(id = R.string.ok),
                     text = stringResource(id = R.string.ok),
-                    icon = Icons.Default.Check,
+                    imageVector = Icons.Default.Check,
                     onClick = {
                     onClick = {
                         onUpdateGroup(group, state.text.toString())
                         onUpdateGroup(group, state.text.toString())
                         expanded = false
                         expanded = false
@@ -130,3 +130,4 @@ private fun GroupItem(
         }
         }
     )
     )
 }
 }
+

+ 4 - 4
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.Arrangement
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.Row
@@ -31,7 +31,7 @@ fun ValueStepper(
                 val newValue = (value.toInt() - 1).toFloat().coerceIn(valueRange)
                 val newValue = (value.toInt() - 1).toFloat().coerceIn(valueRange)
                 onValueChange(newValue)
                 onValueChange(newValue)
             },
             },
-            icon = Icons.Default.Remove
+            imageVector = Icons.Default.Remove
         )
         )
         TextCard(
         TextCard(
             cornerRadius = 8.dp,
             cornerRadius = 8.dp,
@@ -46,7 +46,7 @@ fun ValueStepper(
                 val newValue = (value.toInt() + 1).toFloat().coerceIn(valueRange)
                 val newValue = (value.toInt() + 1).toFloat().coerceIn(valueRange)
                 onValueChange(newValue)
                 onValueChange(newValue)
             },
             },
-            icon = Icons.Default.Add
+            imageVector = Icons.Default.Add
         )
         )
     }
     }
-}
+}

+ 15 - 15
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
 @Composable
 fun MediumIconButton(
 fun MediumIconButton(
     onClick: () -> Unit,
     onClick: () -> Unit,
-    icon: ImageVector,
+    imageVector: ImageVector,
     modifier: Modifier = Modifier,
     modifier: Modifier = Modifier,
     contentDescription: String? = null
     contentDescription: String? = null
 ) {
 ) {
@@ -51,7 +51,7 @@ fun MediumIconButton(
             modifier = modifier
             modifier = modifier
         ) {
         ) {
             MiuixIcon(
             MiuixIcon(
-                imageVector = icon,
+                imageVector = imageVector,
                 contentDescription = contentDescription
                 contentDescription = contentDescription
             )
             )
         }
         }
@@ -61,7 +61,7 @@ fun MediumIconButton(
             modifier = modifier
             modifier = modifier
         ) {
         ) {
             Icon(
             Icon(
-                imageVector = icon,
+                imageVector = imageVector,
                 contentDescription = contentDescription
                 contentDescription = contentDescription
             )
             )
         }
         }
@@ -71,7 +71,7 @@ fun MediumIconButton(
 @Composable
 @Composable
 fun MediumOutlinedIconButton(
 fun MediumOutlinedIconButton(
     onClick: () -> Unit,
     onClick: () -> Unit,
-    icon: ImageVector,
+    imageVector: ImageVector,
     modifier: Modifier = Modifier,
     modifier: Modifier = Modifier,
     contentDescription: String? = null
     contentDescription: String? = null
 ) {
 ) {
@@ -83,7 +83,7 @@ fun MediumOutlinedIconButton(
             backgroundColor = LegadoTheme.colorScheme.surfaceContainerHigh
             backgroundColor = LegadoTheme.colorScheme.surfaceContainerHigh
         ) {
         ) {
             MiuixIcon(
             MiuixIcon(
-                imageVector = icon,
+                imageVector = imageVector,
                 contentDescription = contentDescription
                 contentDescription = contentDescription
             )
             )
         }
         }
@@ -93,7 +93,7 @@ fun MediumOutlinedIconButton(
             border = ButtonDefaults.outlinedButtonBorder()
             border = ButtonDefaults.outlinedButtonBorder()
         ) {
         ) {
             Icon(
             Icon(
-                imageVector = icon,
+                imageVector = imageVector,
                 contentDescription = contentDescription
                 contentDescription = contentDescription
             )
             )
         }
         }
@@ -103,7 +103,7 @@ fun MediumOutlinedIconButton(
 @Composable
 @Composable
 fun MediumOutlinedButton(
 fun MediumOutlinedButton(
     onClick: () -> Unit,
     onClick: () -> Unit,
-    icon: ImageVector,
+    imageVector: ImageVector,
     text: String,
     text: String,
     modifier: Modifier = Modifier,
     modifier: Modifier = Modifier,
     contentDescription: String? = null
     contentDescription: String? = null
@@ -120,7 +120,7 @@ fun MediumOutlinedButton(
                 horizontalArrangement = Arrangement.spacedBy(8.dp)
                 horizontalArrangement = Arrangement.spacedBy(8.dp)
             ) {
             ) {
                 MiuixIcon(
                 MiuixIcon(
-                    imageVector = icon,
+                    imageVector = imageVector,
                     contentDescription = contentDescription
                     contentDescription = contentDescription
                 )
                 )
                 MiuixText(text = text)
                 MiuixText(text = text)
@@ -136,7 +136,7 @@ fun MediumOutlinedButton(
                 horizontalArrangement = Arrangement.spacedBy(8.dp)
                 horizontalArrangement = Arrangement.spacedBy(8.dp)
             ) {
             ) {
                 Icon(
                 Icon(
-                    imageVector = icon,
+                    imageVector = imageVector,
                     contentDescription = contentDescription
                     contentDescription = contentDescription
                 )
                 )
                 Text(text = text)
                 Text(text = text)
@@ -148,7 +148,7 @@ fun MediumOutlinedButton(
 @Composable
 @Composable
 fun MediumTonalIconButton(
 fun MediumTonalIconButton(
     onClick: () -> Unit,
     onClick: () -> Unit,
-    icon: ImageVector,
+    imageVector: ImageVector,
     modifier: Modifier = Modifier,
     modifier: Modifier = Modifier,
     contentDescription: String? = null
     contentDescription: String? = null
 ) {
 ) {
@@ -161,7 +161,7 @@ fun MediumTonalIconButton(
             backgroundColor = LegadoTheme.colorScheme.surfaceContainer
             backgroundColor = LegadoTheme.colorScheme.surfaceContainer
         ) {
         ) {
             MiuixIcon(
             MiuixIcon(
-                imageVector = icon,
+                imageVector = imageVector,
                 contentDescription = contentDescription
                 contentDescription = contentDescription
             )
             )
         }
         }
@@ -172,7 +172,7 @@ fun MediumTonalIconButton(
             colors = IconButtonDefaults.filledTonalIconButtonColors()
             colors = IconButtonDefaults.filledTonalIconButtonColors()
         ) {
         ) {
             Icon(
             Icon(
-                imageVector = icon,
+                imageVector = imageVector,
                 contentDescription = contentDescription
                 contentDescription = contentDescription
             )
             )
         }
         }
@@ -183,7 +183,7 @@ fun MediumTonalIconButton(
 fun MediumOutlinedIconToggleButton(
 fun MediumOutlinedIconToggleButton(
     checked: Boolean,
     checked: Boolean,
     onCheckedChange: (Boolean) -> Unit,
     onCheckedChange: (Boolean) -> Unit,
-    icon: ImageVector,
+    imageVector: ImageVector,
     modifier: Modifier = Modifier,
     modifier: Modifier = Modifier,
     contentDescription: String? = null
     contentDescription: String? = null
 ) {
 ) {
@@ -208,7 +208,7 @@ fun MediumOutlinedIconToggleButton(
             backgroundColor = containerColor
             backgroundColor = containerColor
         ) {
         ) {
             MiuixIcon(
             MiuixIcon(
-                imageVector = icon,
+                imageVector = imageVector,
                 contentDescription = contentDescription,
                 contentDescription = contentDescription,
                 tint = iconTint
                 tint = iconTint
             )
             )
@@ -220,7 +220,7 @@ fun MediumOutlinedIconToggleButton(
             modifier = modifier
             modifier = modifier
         ) {
         ) {
             Icon(
             Icon(
-                imageVector = icon,
+                imageVector = imageVector,
                 contentDescription = contentDescription
                 contentDescription = contentDescription
             )
             )
         }
         }

+ 12 - 13
app/src/main/java/io/legado/app/ui/widget/components/button/SmallIconButton.kt

@@ -64,7 +64,7 @@ private fun SmallNoMinTouchTarget(content: @Composable () -> Unit) {
 @Composable
 @Composable
 fun SmallIconButton(
 fun SmallIconButton(
     onClick: () -> Unit,
     onClick: () -> Unit,
-    icon: ImageVector,
+    imageVector: ImageVector,
     contentDescription: String? = null
     contentDescription: String? = null
 ) {
 ) {
     if (ThemeResolver.isMiuixEngine(composeEngine)) {
     if (ThemeResolver.isMiuixEngine(composeEngine)) {
@@ -72,7 +72,7 @@ fun SmallIconButton(
             onClick = onClick
             onClick = onClick
         ) {
         ) {
             MiuixIcon(
             MiuixIcon(
-                imageVector = icon,
+                imageVector = imageVector,
                 contentDescription = contentDescription
                 contentDescription = contentDescription
             )
             )
         }
         }
@@ -84,7 +84,7 @@ fun SmallIconButton(
                 shape = IconButtonDefaults.extraSmallRoundShape,
                 shape = IconButtonDefaults.extraSmallRoundShape,
             ) {
             ) {
                 Icon(
                 Icon(
-                    imageVector = icon,
+                    imageVector = imageVector,
                     contentDescription = contentDescription,
                     contentDescription = contentDescription,
                     modifier = Modifier.size(smallIconSize),
                     modifier = Modifier.size(smallIconSize),
                 )
                 )
@@ -97,11 +97,10 @@ fun SmallIconButton(
 @Composable
 @Composable
 fun SmallOutlinedIconButton(
 fun SmallOutlinedIconButton(
     onClick: () -> Unit,
     onClick: () -> Unit,
-    icon: ImageVector,
+    imageVector: ImageVector,
     modifier: Modifier = Modifier,
     modifier: Modifier = Modifier,
     contentDescription: String? = null
     contentDescription: String? = null
 ) {
 ) {
-
     val isMiuix = ThemeResolver.isMiuixEngine(composeEngine)
     val isMiuix = ThemeResolver.isMiuixEngine(composeEngine)
     if (isMiuix) {
     if (isMiuix) {
         MiuixIconButton(
         MiuixIconButton(
@@ -110,7 +109,7 @@ fun SmallOutlinedIconButton(
             backgroundColor = LegadoTheme.colorScheme.surfaceContainer
             backgroundColor = LegadoTheme.colorScheme.surfaceContainer
         ) {
         ) {
             MiuixIcon(
             MiuixIcon(
-                imageVector = icon,
+                imageVector = imageVector,
                 contentDescription = contentDescription,
                 contentDescription = contentDescription,
                 modifier = Modifier.size(SmallMiuixIconSize)
                 modifier = Modifier.size(SmallMiuixIconSize)
             )
             )
@@ -124,7 +123,7 @@ fun SmallOutlinedIconButton(
                 border = ButtonDefaults.outlinedButtonBorder()
                 border = ButtonDefaults.outlinedButtonBorder()
             ) {
             ) {
                 Icon(
                 Icon(
-                    imageVector = icon,
+                    imageVector = imageVector,
                     contentDescription = contentDescription,
                     contentDescription = contentDescription,
                     modifier = Modifier.size(smallIconSize)
                     modifier = Modifier.size(smallIconSize)
                 )
                 )
@@ -137,7 +136,7 @@ fun SmallOutlinedIconButton(
 @Composable
 @Composable
 fun SmallTonalIconButton(
 fun SmallTonalIconButton(
     onClick: () -> Unit,
     onClick: () -> Unit,
-    icon: ImageVector,
+    imageVector: ImageVector,
     modifier: Modifier = Modifier,
     modifier: Modifier = Modifier,
     contentDescription: String? = null
     contentDescription: String? = null
 ) {
 ) {
@@ -150,7 +149,7 @@ fun SmallTonalIconButton(
             backgroundColor = LegadoTheme.colorScheme.surfaceContainer
             backgroundColor = LegadoTheme.colorScheme.surfaceContainer
         ) {
         ) {
             MiuixIcon(
             MiuixIcon(
-                imageVector = icon,
+                imageVector = imageVector,
                 contentDescription = contentDescription,
                 contentDescription = contentDescription,
                 modifier = Modifier.size(SmallMiuixIconSize)
                 modifier = Modifier.size(SmallMiuixIconSize)
             )
             )
@@ -164,7 +163,7 @@ fun SmallTonalIconButton(
                 colors = IconButtonDefaults.filledTonalIconButtonColors()
                 colors = IconButtonDefaults.filledTonalIconButtonColors()
             ) {
             ) {
                 Icon(
                 Icon(
-                    imageVector = icon,
+                    imageVector = imageVector,
                     contentDescription = contentDescription,
                     contentDescription = contentDescription,
                     modifier = Modifier.size(smallIconSize)
                     modifier = Modifier.size(smallIconSize)
                 )
                 )
@@ -178,7 +177,7 @@ fun SmallTonalIconButton(
 fun SmallOutlinedIconToggleButton(
 fun SmallOutlinedIconToggleButton(
     checked: Boolean,
     checked: Boolean,
     onCheckedChange: (Boolean) -> Unit,
     onCheckedChange: (Boolean) -> Unit,
-    icon: ImageVector,
+    imageVector: ImageVector,
     modifier: Modifier = Modifier,
     modifier: Modifier = Modifier,
     contentDescription: String? = null
     contentDescription: String? = null
 ) {
 ) {
@@ -205,7 +204,7 @@ fun SmallOutlinedIconToggleButton(
             backgroundColor = containerColor
             backgroundColor = containerColor
         ) {
         ) {
             MiuixIcon(
             MiuixIcon(
-                imageVector = icon,
+                imageVector = imageVector,
                 contentDescription = contentDescription,
                 contentDescription = contentDescription,
                 tint = iconTint,
                 tint = iconTint,
                 modifier = Modifier.size(SmallMiuixIconSize)
                 modifier = Modifier.size(SmallMiuixIconSize)
@@ -233,7 +232,7 @@ fun SmallOutlinedIconToggleButton(
                 shapes = toggleShapes
                 shapes = toggleShapes
             ) {
             ) {
                 Icon(
                 Icon(
-                    imageVector = icon,
+                    imageVector = imageVector,
                     contentDescription = contentDescription,
                     contentDescription = contentDescription,
                     modifier = Modifier.size(smallIconSize),
                     modifier = Modifier.size(smallIconSize),
                 )
                 )

+ 3 - 3
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
 @Composable
 fun SmallTextButton(
 fun SmallTextButton(
     text: String,
     text: String,
-    icon: ImageVector,
+    imageVector: ImageVector,
     modifier: Modifier = Modifier,
     modifier: Modifier = Modifier,
     onClick: () -> Unit
     onClick: () -> Unit
 ) {
 ) {
@@ -44,7 +44,7 @@ fun SmallTextButton(
             shape = MaterialTheme.shapes.small
             shape = MaterialTheme.shapes.small
         ) {
         ) {
             Icon(
             Icon(
-                imageVector = icon,
+                imageVector = imageVector,
                 contentDescription = null,
                 contentDescription = null,
                 modifier = Modifier.size(16.dp)
                 modifier = Modifier.size(16.dp)
             )
             )
@@ -55,4 +55,4 @@ fun SmallTextButton(
             )
             )
         }
         }
     }
     }
-}
+}

+ 87 - 0
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
+        )
+    }
+}

+ 3 - 2
app/src/main/java/io/legado/app/ui/widget/components/card/SelectionItemCard.kt

@@ -181,7 +181,7 @@ fun SelectionItemCard(
                 if (onClickEdit != null) {
                 if (onClickEdit != null) {
                     SmallIconButton(
                     SmallIconButton(
                         onClick = onClickEdit,
                         onClick = onClickEdit,
-                        icon = Icons.Default.Edit,
+                        imageVector = Icons.Default.Edit,
                         contentDescription = "Edit"
                         contentDescription = "Edit"
                     )
                     )
                 }
                 }
@@ -194,7 +194,7 @@ fun SelectionItemCard(
                     Box {
                     Box {
                         SmallIconButton(
                         SmallIconButton(
                             onClick = { showMenu = true },
                             onClick = { showMenu = true },
-                            icon = Icons.Default.MoreVert,
+                            imageVector = Icons.Default.MoreVert,
                             contentDescription = "More"
                             contentDescription = "More"
                         )
                         )
                         RoundDropdownMenu(
                         RoundDropdownMenu(
@@ -272,3 +272,4 @@ fun LazyItemScope.ReorderableSelectionItem(
         )
         )
     }
     }
 }
 }
+

+ 30 - 33
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.AccessTime
 import androidx.compose.material.icons.filled.FormatListNumbered
 import androidx.compose.material.icons.filled.FormatListNumbered
 import androidx.compose.material.icons.outlined.Delete
 import androidx.compose.material.icons.outlined.Delete
-import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Alignment
@@ -43,43 +42,41 @@ import io.legado.app.ui.widget.components.text.AppText
 import java.time.LocalDate
 import java.time.LocalDate
 
 
 /**
 /**
- * 热力图日历顶部操作栏
+ * 热力图日历弹窗标题
+ */
+const val HEATMAP_CALENDAR_TITLE = "时间线"
+
+/**
+ * 热力图日历弹窗左侧操作
  */
  */
-@OptIn(ExperimentalMaterial3ExpressiveApi::class)
 @Composable
 @Composable
-fun HeatmapCalendarTopBar(
+fun HeatmapCalendarStartAction(
     currentMode: HeatmapMode,
     currentMode: HeatmapMode,
     onModeChanged: (HeatmapMode) -> Unit,
     onModeChanged: (HeatmapMode) -> Unit,
-    onClearDate: () -> Unit,
-    modifier: Modifier = Modifier
 ) {
 ) {
-    Row(
-        modifier = modifier.fillMaxWidth(),
-        horizontalArrangement = Arrangement.SpaceBetween,
-        verticalAlignment = Alignment.CenterVertically
-    ) {
-        AppText("时间线", style = LegadoTheme.typography.titleMedium)
-
-        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))
+    MediumAnimatedActionButton(
+        checked = currentMode == HeatmapMode.TIME,
+        onCheckedChange = {
+            onModeChanged(if (it) HeatmapMode.TIME else HeatmapMode.COUNT)
+        },
+        iconChecked = Icons.Default.AccessTime,
+        iconUnchecked = Icons.Default.FormatListNumbered,
+        activeText = "按时长",
+        inactiveText = "按次数"
+    )
+}
 
 
-            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
             color = Color.Gray
         )
         )
     }
     }
-}
+}

+ 3 - 4
app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/AppModalBottomSheet.kt

@@ -41,7 +41,6 @@ fun AppModalBottomSheet(
     title: String? = null,
     title: String? = null,
     startAction: @Composable (() -> Unit)? = null,
     startAction: @Composable (() -> Unit)? = null,
     endAction: @Composable (() -> Unit)? = null,
     endAction: @Composable (() -> Unit)? = null,
-    containerColor: Color = LegadoTheme.colorScheme.surfaceContainer,
     content: @Composable ColumnScope.() -> Unit
     content: @Composable ColumnScope.() -> Unit
 ) {
 ) {
     if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) {
     if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) {
@@ -52,14 +51,15 @@ fun AppModalBottomSheet(
             startAction = startAction,
             startAction = startAction,
             endAction = endAction,
             endAction = endAction,
             insideMargin = DpSize(16.dp, 12.dp),
             insideMargin = DpSize(16.dp, 12.dp),
-            backgroundColor = containerColor,
             onDismissRequest = onDismissRequest,
             onDismissRequest = onDismissRequest,
             onDismissFinished = onDismissRequest,
             onDismissFinished = onDismissRequest,
             enableWindowDim = true,
             enableWindowDim = true,
             allowDismiss = true
             allowDismiss = true
         ) {
         ) {
             Column(
             Column(
-                modifier = Modifier.fillMaxWidth(),
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .animateContentSize(),
                 content = content
                 content = content
             )
             )
         }
         }
@@ -75,7 +75,6 @@ fun AppModalBottomSheet(
             ModalBottomSheet(
             ModalBottomSheet(
                 onDismissRequest = onDismissRequest,
                 onDismissRequest = onDismissRequest,
                 sheetState = sheetState,
                 sheetState = sheetState,
-                containerColor = containerColor,
                 contentColor = colorScheme.onSurface,
                 contentColor = colorScheme.onSurface,
                 dragHandle = { BottomSheetDefaults.DragHandle() }
                 dragHandle = { BottomSheetDefaults.DragHandle() }
             ) {
             ) {

+ 1 - 2
app/src/main/java/io/legado/app/ui/widget/components/modalBottomSheet/OptionSheet.kt

@@ -32,8 +32,7 @@ fun OptionSheet(
     AppModalBottomSheet(
     AppModalBottomSheet(
         show = show,
         show = show,
         title = title,
         title = title,
-        onDismissRequest = onDismissRequest,
-        containerColor = LegadoTheme.colorScheme.surface
+        onDismissRequest = onDismissRequest
     ) {
     ) {
         Column(
         Column(
             modifier = Modifier
             modifier = Modifier

+ 42 - 32
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.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.theme.LegadoTheme
 import io.legado.app.ui.widget.components.AppFloatingActionButton
 import io.legado.app.ui.widget.components.AppFloatingActionButton
 import io.legado.app.ui.widget.components.AppTextField
 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.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.modalBottomSheet.AppModalBottomSheet
 import io.legado.app.ui.widget.components.text.AppText
 import io.legado.app.ui.widget.components.text.AppText
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.launch
 
 
 /**
 /**
- * 通用编辑数据包装,用于适配不同的规则实体
+ * 通用编辑数据包装,用于适配不同的规则
  */
  */
 data class RuleEditFields(
 data class RuleEditFields(
     val name: String = "",
     val name: String = "",
@@ -80,41 +84,44 @@ fun <T> RuleEditSheet(
     AppModalBottomSheet(
     AppModalBottomSheet(
         title = title,
         title = title,
         startAction = {
         startAction = {
-            IconButton(onClick = onDismissRequest) {
-                Icon(
-                    Icons.Default.Close,
-                    contentDescription = stringResource(R.string.cancel)
-                )
-            }
+            MediumIconButton(
+                onClick = onDismissRequest,
+                imageVector = Icons.Default.Close,
+                contentDescription = "Close",
+            )
         },
         },
         endAction = {
         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
+                        }
+                    )
+                    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
                         }
                         }
-                        showMenu = false
-                    }
-                )
+                    )
+                }
             }
             }
         },
         },
         show = show,
         show = show,
@@ -132,6 +139,7 @@ fun <T> RuleEditSheet(
                     modifier = Modifier.fillMaxWidth(),
                     modifier = Modifier.fillMaxWidth(),
                     value = name,
                     value = name,
                     onValueChange = { name = it },
                     onValueChange = { name = it },
+                    backgroundColor = LegadoTheme.colorScheme.surface,
                     label = stringResource(R.string.name),
                     label = stringResource(R.string.name),
                     singleLine = true
                     singleLine = true
                 )
                 )
@@ -139,12 +147,14 @@ fun <T> RuleEditSheet(
                     modifier = Modifier.fillMaxWidth(),
                     modifier = Modifier.fillMaxWidth(),
                     value = rule1,
                     value = rule1,
                     onValueChange = { rule1 = it },
                     onValueChange = { rule1 = it },
+                    backgroundColor = LegadoTheme.colorScheme.surface,
                     label = label1
                     label = label1
                 )
                 )
                 AppTextField(
                 AppTextField(
                     modifier = Modifier.fillMaxWidth(),
                     modifier = Modifier.fillMaxWidth(),
                     value = rule2,
                     value = rule2,
                     onValueChange = { rule2 = it },
                     onValueChange = { rule2 = it },
+                    backgroundColor = LegadoTheme.colorScheme.surface,
                     label = label2,
                     label = label2,
                     minLines = 3
                     minLines = 3
                 )
                 )
@@ -160,4 +170,4 @@ fun <T> RuleEditSheet(
             }
             }
         }
         }
     }
     }
-}
+}

+ 5 - 5
app/src/main/java/io/legado/app/ui/widget/components/settingItem/InputSettingItem.kt

@@ -84,14 +84,14 @@ fun InputSettingItem(
                     ) {
                     ) {
                         SmallTextButton(
                         SmallTextButton(
                             text = "默认",
                             text = "默认",
-                            icon = Icons.Default.Replay,
+                            imageVector = Icons.Default.Replay,
                             onClick = {
                             onClick = {
                                 state.edit { replace(0, length, defaultValue.toString()) }
                                 state.edit { replace(0, length, defaultValue.toString()) }
                             }
                             }
                         )
                         )
                         SmallTextButton(
                         SmallTextButton(
                             text = "确认",
                             text = "确认",
-                            icon = Icons.Default.Check,
+                            imageVector = Icons.Default.Check,
                             onClick = {
                             onClick = {
                                 onConfirm(state.text.toString())
                                 onConfirm(state.text.toString())
                                 expanded = false
                                 expanded = false
@@ -133,14 +133,14 @@ fun InputSettingItem(
                 ) {
                 ) {
                     SmallTextButton(
                     SmallTextButton(
                         text = "默认",
                         text = "默认",
-                        icon = Icons.Default.Replay,
+                        imageVector = Icons.Default.Replay,
                         onClick = {
                         onClick = {
                             state.edit { replace(0, length, defaultValue.toString()) }
                             state.edit { replace(0, length, defaultValue.toString()) }
                         }
                         }
                     )
                     )
                     SmallTextButton(
                     SmallTextButton(
                         text = "确认",
                         text = "确认",
-                        icon = Icons.Default.Check,
+                        imageVector = Icons.Default.Check,
                         onClick = {
                         onClick = {
                             onConfirm(state.text.toString())
                             onConfirm(state.text.toString())
                             expanded = false
                             expanded = false
@@ -150,4 +150,4 @@ fun InputSettingItem(
             }
             }
         )
         )
     }
     }
-}
+}

+ 13 - 12
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.AnimatedContent
 import androidx.compose.animation.AnimatedVisibility
 import androidx.compose.animation.AnimatedVisibility
@@ -78,7 +78,7 @@ fun SliderSettingItem(
                             MiuixTextField(
                             MiuixTextField(
                                 state = textFieldState,
                                 state = textFieldState,
                                 lineLimits = TextFieldLineLimits.SingleLine,
                                 lineLimits = TextFieldLineLimits.SingleLine,
-                                label = "输入数值 (${valueRange.start.toInt()}-${valueRange.endInclusive.toInt()})",
+                                label = "杈撳叆鏁板€?(${valueRange.start.toInt()}-${valueRange.endInclusive.toInt()})",
                                 keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
                                 keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
                                 modifier = Modifier.fillMaxWidth(),
                                 modifier = Modifier.fillMaxWidth(),
                                 inputTransformation = {
                                 inputTransformation = {
@@ -120,16 +120,16 @@ fun SliderSettingItem(
                         horizontalArrangement = Arrangement.End
                         horizontalArrangement = Arrangement.End
                     ) {
                     ) {
                         SmallTextButton(
                         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 }
                             onClick = { isInputMode = !isInputMode }
                         )
                         )
 
 
                         Spacer(Modifier.width(8.dp))
                         Spacer(Modifier.width(8.dp))
 
 
                         SmallTextButton(
                         SmallTextButton(
-                            text = "默认",
-                            icon = Icons.Default.RestartAlt,
+                            text = "榛樿",
+                            imageVector = Icons.Default.RestartAlt,
                             onClick = {
                             onClick = {
                                 onValueChange(defaultValue)
                                 onValueChange(defaultValue)
                                 textFieldState.edit {
                                 textFieldState.edit {
@@ -163,7 +163,7 @@ fun SliderSettingItem(
                             TextField(
                             TextField(
                                 state = textFieldState,
                                 state = textFieldState,
                                 lineLimits = TextFieldLineLimits.SingleLine,
                                 lineLimits = TextFieldLineLimits.SingleLine,
-                                label = { AppText("输入数值 (${valueRange.start.toInt()}-${valueRange.endInclusive.toInt()})") },
+                                label = { AppText("杈撳叆鏁板€?(${valueRange.start.toInt()}-${valueRange.endInclusive.toInt()})") },
                                 keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
                                 keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
                                 modifier = Modifier
                                 modifier = Modifier
                                     .fillMaxWidth()
                                     .fillMaxWidth()
@@ -212,16 +212,16 @@ fun SliderSettingItem(
                     horizontalArrangement = Arrangement.End
                     horizontalArrangement = Arrangement.End
                 ) {
                 ) {
                     SmallTextButton(
                     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 }
                         onClick = { isInputMode = !isInputMode }
                     )
                     )
 
 
                     Spacer(Modifier.width(8.dp))
                     Spacer(Modifier.width(8.dp))
 
 
                     SmallTextButton(
                     SmallTextButton(
-                        text = "默认",
-                        icon = Icons.Default.RestartAlt,
+                        text = "榛樿",
+                        imageVector = Icons.Default.RestartAlt,
                         onClick = {
                         onClick = {
                             onValueChange(defaultValue)
                             onValueChange(defaultValue)
                             textFieldState.edit {
                             textFieldState.edit {
@@ -237,4 +237,5 @@ fun SliderSettingItem(
             }
             }
         )
         )
     }
     }
-}
+}
+

+ 3 - 2
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.hapticfeedback.HapticFeedbackType
 import androidx.compose.ui.platform.LocalHapticFeedback
 import androidx.compose.ui.platform.LocalHapticFeedback
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.dp
+import io.legado.app.ui.theme.LegadoTheme
 
 
 @OptIn(ExperimentalMaterial3Api::class)
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 @Composable
@@ -128,7 +129,7 @@ private fun SwipeBackground(
         targetValue = if (isThresholdReached)
         targetValue = if (isThresholdReached)
             action.background
             action.background
         else
         else
-            MaterialTheme.colorScheme.surfaceVariant,
+            LegadoTheme.colorScheme.surfaceVariant,
         label = "bgColor"
         label = "bgColor"
     )
     )
 
 
@@ -160,7 +161,7 @@ private fun SwipeBackground(
             tint = if (isThresholdReached)
             tint = if (isThresholdReached)
                 contentColorFor(action.background)
                 contentColorFor(action.background)
             else
             else
-                MaterialTheme.colorScheme.onSurfaceVariant
+                LegadoTheme.colorScheme.onSurfaceVariant
         )
         )
     }
     }
 }
 }

+ 5 - 5
gradle/libs.versions.toml

@@ -1,9 +1,9 @@
 [versions]
 [versions]
 
 
 accompanistWebview = "0.36.0"
 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"
 animation = "1.10.6"
 biometric = "1.4.0-alpha06"
 biometric = "1.4.0-alpha06"
 coilCompose = "2.7.0"
 coilCompose = "2.7.0"
@@ -46,8 +46,8 @@ liveeventbus = "1.8.14"
 navigation3 = "1.0.1"
 navigation3 = "1.0.1"
 markdownCompose = "0.5.0"
 markdownCompose = "0.5.0"
 markwon = "4.6.2"
 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"
 material3IconsExtended = "1.7.8"
 materialKolor = "4.1.1"
 materialKolor = "4.1.1"
 media = "1.7.1"
 media = "1.7.1"