Просмотр исходного кода

fix: 修复主页阅读及设置迁移问题

HapeLee 3 месяцев назад
Родитель
Сommit
6a1d1e4cf7

+ 23 - 8
app/src/main/java/io/legado/app/help/config/AppConfig.kt

@@ -5,6 +5,7 @@ import io.legado.app.BuildConfig
 import io.legado.app.constant.PreferKey
 import io.legado.app.data.appDb
 import io.legado.app.data.repository.ReadPreferences
+import io.legado.app.data.repository.SettingsRepository
 import io.legado.app.ui.config.backupConfig.BackupConfig
 import io.legado.app.ui.config.bookshelfConfig.BookshelfConfig
 import io.legado.app.ui.config.coverConfig.CoverConfig
@@ -24,10 +25,16 @@ import io.legado.app.utils.putPrefInt
 import io.legado.app.utils.putPrefString
 import io.legado.app.utils.sysConfiguration
 import io.legado.app.utils.toastOnUi
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.runBlocking
+import org.koin.java.KoinJavaComponent.get
 import splitties.init.appCtx
 
 @Suppress("MemberVisibilityCanBePrivate", "ConstPropertyName")
 object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
+    private val settingsRepository: SettingsRepository by lazy {
+        get(SettingsRepository::class.java)
+    }
     val isCronet get() = DownloadCacheConfig.cronetEnable
     val useAntiAlias get() = OtherConfig.antiAlias
     val userAgent: String get() = DownloadCacheConfig.userAgent
@@ -290,16 +297,20 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
         }
 
     var bookExportFileName: String?
-        get() = appCtx.getPrefString(PreferKey.bookExportFileName)
+        get() = runBlocking {
+            settingsRepository.getString(PreferKey.bookExportFileName).first().ifEmpty { null }
+        }
         set(value) {
-            appCtx.putPrefString(PreferKey.bookExportFileName, value)
+            runBlocking { DsSync.putString(PreferKey.bookExportFileName, value) }
         }
 
     // 保存 自定义导出章节模式 文件名js表达式
     var episodeExportFileName: String?
-        get() = appCtx.getPrefString(PreferKey.episodeExportFileName, "")
+        get() = runBlocking {
+            settingsRepository.getString(PreferKey.episodeExportFileName).first()
+        }
         set(value) {
-            appCtx.putPrefString(PreferKey.episodeExportFileName, value)
+            runBlocking { DsSync.putString(PreferKey.episodeExportFileName, value) }
         }
 
     var bookImportFileName: String?
@@ -504,12 +515,16 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
             appCtx.putPrefInt(PreferKey.batchChangeSourceDelay, value)
         }
 
-    val importKeepName get() = appCtx.getPrefBoolean(PreferKey.importKeepName)
-    val importKeepGroup get() = appCtx.getPrefBoolean(PreferKey.importKeepGroup)
+    var importKeepName: Boolean
+        get() = runBlocking { settingsRepository.getBoolean(PreferKey.importKeepName).first() }
+        set(value) { runBlocking { DsSync.putBoolean(PreferKey.importKeepName, value) } }
+    var importKeepGroup: Boolean
+        get() = runBlocking { settingsRepository.getBoolean(PreferKey.importKeepGroup).first() }
+        set(value) { runBlocking { DsSync.putBoolean(PreferKey.importKeepGroup, value) } }
     var importKeepEnable: Boolean
-        get() = appCtx.getPrefBoolean(PreferKey.importKeepEnable, false)
+        get() = runBlocking { settingsRepository.getBoolean(PreferKey.importKeepEnable).first() }
         set(value) {
-            appCtx.putPrefBoolean(PreferKey.importKeepEnable, value)
+            runBlocking { DsSync.putBoolean(PreferKey.importKeepEnable, value) }
         }
 
     var previewImageByClick: Boolean

+ 3 - 2
app/src/main/java/io/legado/app/service/AudioPlayService.kt

@@ -404,11 +404,12 @@ class AudioPlayService : BaseService(),
         postEvent(EventBus.AUDIO_DS, timeMinute)
         upAudioPlayNotification()
         dsJob?.cancel()
+        if (timeMinute <= 0) return
         dsJob = lifecycleScope.launch {
             while (isActive) {
                 delay(60000)
                 if (!pause) {
-                    if (timeMinute >= 0) {
+                    if (timeMinute > 0) {
                         timeMinute--
                     }
                     if (timeMinute == 0) {
@@ -684,4 +685,4 @@ class AudioPlayService : BaseService(),
         audioManager.abandonAudioFocus(this)
     }
 
-}
+}

+ 2 - 1
app/src/main/java/io/legado/app/service/BaseReadAloudService.kt

@@ -424,11 +424,12 @@ abstract class BaseReadAloudService : BaseService(),
         postEvent(EventBus.READ_ALOUD_DS, timeMinute)
         upReadAloudNotification()
         dsJob?.cancel()
+        if (timeMinute <= 0) return
         dsJob = lifecycleScope.launch {
             while (isActive) {
                 delay(60000)
                 if (!pause) {
-                    if (timeMinute >= 0) {
+                    if (timeMinute > 0) {
                         timeMinute--
                     }
                     if (timeMinute == 0) {

+ 3 - 4
app/src/main/java/io/legado/app/ui/association/ImportBookSourceDialog.kt

@@ -14,7 +14,6 @@ import io.legado.app.R
 import io.legado.app.base.BaseBottomSheetDialogFragment
 import io.legado.app.base.adapter.ItemViewHolder
 import io.legado.app.base.adapter.RecyclerAdapter
-import io.legado.app.constant.PreferKey
 import io.legado.app.data.appDb
 import io.legado.app.data.entities.BookSource
 import io.legado.app.databinding.DialogCustomGroupBinding
@@ -173,12 +172,12 @@ class ImportBookSourceDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_r
 
             R.id.menu_keep_original_name -> {
                 item.isChecked = !item.isChecked
-                putPrefBoolean(PreferKey.importKeepName, item.isChecked)
+                AppConfig.importKeepName = item.isChecked
             }
 
             R.id.menu_keep_group -> {
                 item.isChecked = !item.isChecked
-                putPrefBoolean(PreferKey.importKeepGroup, item.isChecked)
+                AppConfig.importKeepGroup = item.isChecked
             }
 
             R.id.menu_keep_enable -> {
@@ -280,4 +279,4 @@ class ImportBookSourceDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_r
 
     }
 
-}
+}

+ 3 - 4
app/src/main/java/io/legado/app/ui/association/ImportRssSourceDialog.kt

@@ -14,7 +14,6 @@ import io.legado.app.R
 import io.legado.app.base.BaseDialogFragment
 import io.legado.app.base.adapter.ItemViewHolder
 import io.legado.app.base.adapter.RecyclerAdapter
-import io.legado.app.constant.PreferKey
 import io.legado.app.data.appDb
 import io.legado.app.data.entities.RssSource
 import io.legado.app.databinding.DialogCustomGroupBinding
@@ -153,12 +152,12 @@ class ImportRssSourceDialog() : BaseDialogFragment(R.layout.dialog_recycler_view
             R.id.menu_new_group -> alertCustomGroup(item)
             R.id.menu_keep_original_name -> {
                 item.isChecked = !item.isChecked
-                putPrefBoolean(PreferKey.importKeepName, item.isChecked)
+                AppConfig.importKeepName = item.isChecked
             }
 
             R.id.menu_keep_group -> {
                 item.isChecked = !item.isChecked
-                putPrefBoolean(PreferKey.importKeepGroup, item.isChecked)
+                AppConfig.importKeepGroup = item.isChecked
             }
 
             R.id.menu_keep_enable -> {
@@ -259,4 +258,4 @@ class ImportRssSourceDialog() : BaseDialogFragment(R.layout.dialog_recycler_view
         }
     }
 
-}
+}

+ 1 - 1
app/src/main/java/io/legado/app/ui/book/audio/AudioPlayActivity.kt

@@ -399,7 +399,7 @@ class AudioPlayActivity :
                 valueFrom = 0f
                 valueTo = 180f
                 stepSize = 1f
-                value = AudioPlayService.timeMinute.toFloat()
+                value = AudioPlayService.timeMinute.coerceIn(0, 180).toFloat()
 
                 addOnChangeListener { _, newValue, fromUser ->
                     if (fromUser) AudioPlay.setTimer(newValue.toInt())

+ 1 - 0
app/src/main/java/io/legado/app/ui/book/info/BookInfoContract.kt

@@ -22,6 +22,7 @@ data class HighlightedTag(
 data class BookInfoUiState(
     val book: BookInfoBookUi? = null,
     val hasChapters: Boolean = false,
+    val tocLoadFailed: Boolean = false,
     val webFiles: List<BookInfoWebFile> = emptyList(),
     val highlightedTags: List<HighlightedTag> = emptyList(),
     val kindLabels: List<String> = emptyList(),

+ 3 - 3
app/src/main/java/io/legado/app/ui/book/info/BookInfoScreen.kt

@@ -317,7 +317,7 @@ private fun BookInfoScreenContent(
                                 }
                                 BookInfoSummary(
                                     book = book,
-                                    hasChapters = state.hasChapters,
+                                    tocLoadFailed = state.tocLoadFailed,
                                     onRemarkClick = { onIntent(BookInfoIntent.RemarkClick) },
                                 )
                             }
@@ -1100,7 +1100,7 @@ private fun BookInfoActionCard(
 @Composable
 private fun BookInfoSummary(
     book: BookInfoBookUi,
-    hasChapters: Boolean,
+    tocLoadFailed: Boolean,
     onRemarkClick: () -> Unit,
 ) {
     Column(
@@ -1140,7 +1140,7 @@ private fun BookInfoSummary(
                 style = LegadoTheme.typography.labelMedium,
                 color = LegadoTheme.colorScheme.secondary,
             )
-            if (!hasChapters) {
+            if (tocLoadFailed) {
                 AppText(
                     text = " · ",
                     color = LegadoTheme.colorScheme.secondary

+ 6 - 0
app/src/main/java/io/legado/app/ui/book/info/BookInfoViewModel.kt

@@ -138,6 +138,7 @@ class BookInfoViewModel(
             observeReadRecordIfNeeded(value)
         }
     private var currentChapterList: List<BookChapter> = emptyList()
+    private var tocLoadFailed = false
     private var currentWebFiles: List<BookInfoWebFile> = emptyList()
     private var currentRelatedBooks: List<RelatedBooksUi> = emptyList()
     private var currentHighlightedTags: List<HighlightedTag> = emptyList()
@@ -830,6 +831,7 @@ class BookInfoViewModel(
     private fun upBook(book: Book, source: BookSource?) {
         currentBook = book
         currentChapterList = emptyList()
+        tocLoadFailed = false
         currentWebFiles = emptyList()
         currentRelatedBooks = emptyList()
         currentKindLabels = emptyList()
@@ -913,6 +915,7 @@ class BookInfoViewModel(
         scope: CoroutineScope = viewModelScope,
         showLoading: Boolean = true,
     ) {
+        tocLoadFailed = false
         syncUiState(isTocLoading = showLoading)
         if (book.isLocal) {
             execute(scope) {
@@ -928,6 +931,7 @@ class BookInfoViewModel(
                 syncUiState(isTocLoading = false)
             }.onError {
                 currentChapterList = emptyList()
+                tocLoadFailed = true
                 syncUiState(isTocLoading = false)
             }
         } else {
@@ -954,6 +958,7 @@ class BookInfoViewModel(
                     syncUiState(isTocLoading = false)
                 }.onError {
                     currentChapterList = emptyList()
+                    tocLoadFailed = true
                     syncUiState(isTocLoading = false)
                     AppLog.put("获取目录失败\n${it.localizedMessage}", it)
                 }
@@ -1359,6 +1364,7 @@ class BookInfoViewModel(
             it.copy(
                 book = currentBook?.toBookInfoBookUi(),
                 hasChapters = currentChapterList.isNotEmpty(),
+                tocLoadFailed = tocLoadFailed,
                 webFiles = currentWebFiles,
                 relatedBooks = currentRelatedBooks.toImmutableList(),
                 highlightedTags = currentHighlightedTags,

+ 4 - 3
app/src/main/java/io/legado/app/ui/book/read/page/provider/TextChapterLayout.kt

@@ -146,6 +146,7 @@ class TextChapterLayout(
     private val textFullJustify = ReadBookConfig.textFullJustify
     private val adaptSpecialStyle = ReadConfig.adaptSpecialStyle
     private val pageAnim = book.getPageAnim()
+    private val isSingleImageStyle = book.getImageStyle().equals(Book.imgStyleSingle, true)
     private val titleSegType = ReadBookConfig.titleSegType
     private val titleSegDistance = ReadBookConfig.titleSegDistance
     private val titleSegFlag = ReadBookConfig.titleSegFlag
@@ -271,7 +272,6 @@ class TextChapterLayout(
     ) {
         val contents = bookContent.textList
         val imageStyle = book.getImageStyle()
-        val isSingleImageStyle = imageStyle.equals(Book.imgStyleSingle, true)
         val isTextImageStyle = imageStyle.equals(Book.imgStyleText, true)
 
         val allTitleSegments = if (titleMode != 2 || bookChapter.isVolume || contents.isEmpty()) {
@@ -1037,8 +1037,9 @@ class TextChapterLayout(
             val textPage = pendingTextPage
             textPage.addLine(textLine)
             durY += textHeight * if (isTitle) titleLineSpacingExtra else lineSpacingExtra
-            if (textPage.height < durY) {
-                textPage.height = durY
+            val pageHeight = if (isSingleImageStyle) visibleHeight.toFloat() else durY
+            if (textPage.height < pageHeight) {
+                textPage.height = pageHeight
             }
         }
         durY += textHeight * paragraphSpacing / 10f

+ 71 - 1
app/src/main/java/io/legado/app/ui/main/MainScreen.kt

@@ -86,9 +86,14 @@ import io.legado.app.ui.main.my.MyScreen
 import io.legado.app.ui.main.my.PrefClickEvent
 import io.legado.app.ui.main.rss.RssScreen
 import io.legado.app.ui.theme.LegadoTheme
+import io.legado.app.ui.theme.ThemeResolver
 import io.legado.app.ui.widget.components.AppScaffold
 import io.legado.app.ui.widget.components.FloatingBottomBar
 import io.legado.app.ui.widget.components.FloatingBottomBarItem
+import top.yukonga.miuix.kmp.basic.NavigationRail as MiuixNavigationRail
+import top.yukonga.miuix.kmp.basic.NavigationRailItem as MiuixNavigationRailItem
+import top.yukonga.miuix.kmp.basic.NavigationRailValue
+import top.yukonga.miuix.kmp.basic.rememberNavigationRailState
 import io.legado.app.ui.widget.components.GlassDefaults
 import io.legado.app.ui.widget.components.icon.AppIcon
 import io.legado.app.ui.widget.components.icon.AppIcons
@@ -250,7 +255,72 @@ fun MainScreen(
 
     Row(modifier = Modifier.fillMaxSize()) {
         if (useRail && mainUiState.showBottomView) {
-            WideNavigationRail(
+            if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) {
+                val miuixNavState = rememberNavigationRailState(
+                    initialValue = if (mainUiState.navExtended) {
+                        NavigationRailValue.Expanded
+                    } else {
+                        NavigationRailValue.Collapsed
+                    }
+                )
+                LaunchedEffect(miuixNavState.currentValue) {
+                    viewModel.setNavExtended(miuixNavState.isExpanded)
+                }
+                MiuixNavigationRail(
+                    state = miuixNavState,
+                    header = {
+                        ExtendedFloatingActionButton(
+                            onClick = { onNavigateToSearch(null) },
+                            expanded = miuixNavState.isExpanded,
+                            icon = { AppIcon(Icons.Default.Search, contentDescription = null) },
+                            text = { AppText(stringResource(R.string.search)) }
+                        )
+                    }
+                ) {
+                    destinations.forEachIndexed { index, destination ->
+                        val selected = pagerState.targetPage == index
+                        var showGroupMenu by remember { mutableStateOf(false) }
+                        val haptic = LocalHapticFeedback.current
+                        val destinationLabel = stringResource(destination.labelId)
+                        Box {
+                            MiuixNavigationRailItem(
+                                modifier = Modifier
+                                    .semantics(mergeDescendants = true) {
+                                        contentDescription = destinationLabel
+                                    }
+                                    .then(
+                                        if (destination == MainDestination.Bookshelf) {
+                                            Modifier.combinedClickable(
+                                                interactionSource = remember { MutableInteractionSource() },
+                                                indication = null,
+                                                onClick = { handleMainDestinationClick(index, destination) },
+                                                onLongClick = {
+                                                    haptic.performHapticFeedback(HapticFeedbackType.LongPress)
+                                                    showGroupMenu = true
+                                                }
+                                            )
+                                        } else Modifier
+                                    ),
+                                selected = selected,
+                                onClick = { handleMainDestinationClick(index, destination) },
+                                icon = AppIcons.mainDestination(destination, selected),
+                                label = destinationLabel,
+                            )
+                            if (destination == MainDestination.Bookshelf && showGroupMenu) {
+                                BookshelfRailGroupMenu(
+                                    expanded = showGroupMenu,
+                                    onDismissRequest = { showGroupMenu = false },
+                                    onBeforeSelectGroup = {
+                                        if (pagerState.currentPage != index) {
+                                            pagerState.scrollToPage(index)
+                                        }
+                                    }
+                                )
+                            }
+                        }
+                    }
+                }
+            } else WideNavigationRail(
                 state = navState,
                 header = {
                     val expanded = navState.targetValue == WideNavigationRailValue.Expanded