Bladeren bron

代码优化

HapeLee 6 maanden geleden
bovenliggende
commit
dda4a27730

+ 10 - 1
.claude/settings.local.json

@@ -55,7 +55,16 @@
       "PowerShell(.\\\\gradlew.bat :app:compileAppDebugKotlin 2>&1 | Select-Object -Last 40)",
       "PowerShell(.\\\\gradlew.bat :app:compileAppDebugKotlin 2>&1 | Select-Object -Last 100)",
       "PowerShell(.\\\\gradlew.bat :app:compileAppDebugKotlin 2>&1 | Select-Object -Last 50)",
-      "Bash(python3 *)"
+      "Bash(python3 *)",
+      "WebFetch(domain:raw.githubusercontent.com)",
+      "Bash(xargs -I{} jar -tf {})",
+      "Bash(gh api *)",
+      "Bash(rustup show *)",
+      "PowerShell(rustup show *)",
+      "PowerShell(npm *)",
+      "PowerShell(gcc *)",
+      "Bash(gh repo *)",
+      "Bash(Test-Path *)"
     ]
   }
 }

+ 0 - 5
app/src/main/java/io/legado/app/constant/PreferKey.kt

@@ -210,11 +210,6 @@ object PreferKey {
     const val secondaryTextColor = "colorMD3OnPrimaryContainer"
     const val themeBackgroundColor = "colorMD3Background"
     const val labelContainerColor = "colorMD3SurfaceContainerLow"
-    const val enableContainerBorder = "enableContainerBorder"
-    const val containerBorderWidth = "containerBorderWidth"
-    const val containerBorderStyle = "containerBorderStyle"
-    const val containerBorderColor = "containerBorderColor"
-    const val containerBorderDashWidth = "containerBorderDashWidth"
     // 中间单线间隔设置
     const val enableItemDivider = "enableItemDivider"
     const val itemDividerWidth = "itemDividerWidth"

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

@@ -82,6 +82,7 @@ import io.legado.app.ui.book.toc.rule.TxtTocRuleViewModel
 import io.legado.app.ui.config.backupConfig.BackupConfigViewModel
 import io.legado.app.ui.config.bookshelfConfig.BookshelfManageScreenConfig
 import io.legado.app.ui.config.coverConfig.CoverConfigViewModel
+import io.legado.app.ui.config.downloadCacheConfig.DownloadCacheConfigViewModel
 import io.legado.app.ui.config.otherConfig.OtherConfigViewModel
 import io.legado.app.ui.config.readConfig.ReadConfigViewModel
 import io.legado.app.ui.config.themeConfig.ThemeConfigViewModel
@@ -189,6 +190,7 @@ val appModule = module {
     viewModelOf(::OtherConfigViewModel)
     viewModelOf(::ReadConfigViewModel)
     viewModelOf(::CoverConfigViewModel)
+    viewModelOf(::DownloadCacheConfigViewModel)
     viewModelOf(::ThemeConfigViewModel)
     viewModelOf(::BackupConfigViewModel)
     viewModelOf(::TocViewModel)

+ 21 - 6
app/src/main/java/io/legado/app/help/http/HttpHelper.kt

@@ -52,16 +52,12 @@ val cookieJar by lazy {
 }
 
 /**
- * 强制缓存拦截器,对于图片资源,如果没有缓存头,则强制缓存30天
+ * 强制缓存拦截器,对于封面请求(由CoverFetcher标记),强制缓存30天
  */
 private val cacheControlInterceptor = Interceptor { chain ->
     val request = chain.request()
     val response = chain.proceed(request)
-    val url = request.url.toString()
-    if (url.contains("image", true) || url.endsWith(".jpg") || url.endsWith(".png") || url.endsWith(
-            ".webp"
-        ) || url.endsWith(".jpeg")
-    ) {
+    if (request.tag() === io.legado.app.help.coil.CoverFetcher.COVER_REQUEST_TAG) {
         response.newBuilder()
             .header("Cache-Control", "public, max-age=2592000")
             .removeHeader("Pragma")
@@ -149,6 +145,7 @@ val okHttpClient: OkHttpClient by lazy {
 
 val okHttpClientManga by lazy {
     okHttpClient.newBuilder().run {
+        cache(Cache(File(appCtx.cacheDir, "manga_cache"), 100L * 1024L * 1024L))
         val interceptors = interceptors()
         interceptors.add(1) { chain ->
             val request = chain.request()
@@ -167,6 +164,24 @@ val okHttpClientManga by lazy {
     }
 }
 
+enum class HttpCacheType(val dirName: String, val maxSize: Long) {
+    COVER("http_cache", 100L * 1024 * 1024),
+    MANGA("manga_cache", 100L * 1024 * 1024),
+}
+
+fun getHttpCacheSize(type: HttpCacheType): Long {
+    val dir = File(appCtx.cacheDir, type.dirName)
+    if (!dir.exists()) return 0
+    return dir.walkTopDown().filter { it.isFile }.sumOf { it.length() }
+}
+
+fun clearHttpCache(type: HttpCacheType) {
+    when (type) {
+        HttpCacheType.COVER -> okHttpClient.cache?.delete()
+        HttpCacheType.MANGA -> okHttpClientManga.cache?.delete()
+    }
+}
+
 /**
  * 缓存代理okHttp
  */

+ 41 - 47
app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfig.kt

@@ -1,7 +1,7 @@
 package io.legado.app.ui.config.otherConfig
 
-import io.legado.app.BuildConfig
 import io.legado.app.constant.PreferKey
+import io.legado.app.ui.config.downloadCacheConfig.DownloadCacheConfig
 import io.legado.app.ui.config.prefDelegate
 
 object OtherConfig {
@@ -56,21 +56,6 @@ object OtherConfig {
         false
     )
 
-    var bitmapCacheSize by prefDelegate(
-        PreferKey.bitmapCacheSize,
-        50
-    )
-
-    var imageRetainNum by prefDelegate(
-        PreferKey.imageRetainNum,
-        0
-    )
-
-    var preDownloadNum by prefDelegate(
-        PreferKey.preDownloadNum,
-        10
-    )
-
     var replaceEnableDefault by prefDelegate(
         PreferKey.replaceEnableDefault,
         true
@@ -106,6 +91,18 @@ object OtherConfig {
         true
     )
 
+    var userAgent: String
+        get() = DownloadCacheConfig.userAgent
+        set(value) {
+            DownloadCacheConfig.userAgent = value
+        }
+
+    var cronetEnable: Boolean
+        get() = DownloadCacheConfig.cronetEnable
+        set(value) {
+            DownloadCacheConfig.cronetEnable = value
+        }
+
     var sharedElementEnterTransitionEnable by prefDelegate(
         PreferKey.sharedElementEnterTransitionEnable,
         false
@@ -116,19 +113,6 @@ object OtherConfig {
         true
     )
 
-    private var _userAgent by prefDelegate(
-        PreferKey.userAgent,
-        ""
-    )
-
-    var userAgent: String
-        get() = _userAgent.ifBlank {
-            defaultUserAgent
-        }
-        set(value) {
-            _userAgent = value
-        }
-
     var webServiceWakeLock by prefDelegate(
         PreferKey.webServiceWakeLock,
         false
@@ -145,25 +129,40 @@ object OtherConfig {
             _sourceEditMaxLine = value
         }
 
-    var cronetEnable by prefDelegate(
-        PreferKey.cronet,
-        false
-    )
-
     var webPort by prefDelegate(
         PreferKey.webPort,
         1122
     )
 
-    var threadCount by prefDelegate(
-        PreferKey.threadCount,
-        16
-    )
+    var threadCount: Int
+        get() = DownloadCacheConfig.threadCount
+        set(value) {
+            DownloadCacheConfig.threadCount = value
+        }
 
-    var cacheBookThreadCount by prefDelegate(
-        PreferKey.cacheBookThreadCount,
-        16
-    )
+    var cacheBookThreadCount: Int
+        get() = DownloadCacheConfig.cacheBookThreadCount
+        set(value) {
+            DownloadCacheConfig.cacheBookThreadCount = value
+        }
+
+    var preDownloadNum: Int
+        get() = DownloadCacheConfig.preDownloadNum
+        set(value) {
+            DownloadCacheConfig.preDownloadNum = value
+        }
+
+    var bitmapCacheSize: Int
+        get() = DownloadCacheConfig.bitmapCacheSize
+        set(value) {
+            DownloadCacheConfig.bitmapCacheSize = value
+        }
+
+    var imageRetainNum: Int
+        get() = DownloadCacheConfig.imageRetainNum
+        set(value) {
+            DownloadCacheConfig.imageRetainNum = value
+        }
 
     var processText by prefDelegate(
         PreferKey.processText,
@@ -180,9 +179,4 @@ object OtherConfig {
         false
     )
 
-    private val defaultUserAgent: String
-        get() = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
-                "AppleWebKit/537.36 (KHTML, like Gecko) " +
-                "Chrome/${BuildConfig.Cronet_Main_Version} Safari/537.36"
-
 }

+ 0 - 114
app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfigScreen.kt

@@ -21,7 +21,6 @@ import androidx.compose.ui.res.stringArrayResource
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
 import io.legado.app.R
-import io.legado.app.model.CacheBook
 import io.legado.app.service.WebService
 import io.legado.app.ui.theme.LegadoTheme
 import io.legado.app.ui.theme.adaptiveContentPadding
@@ -34,7 +33,6 @@ import io.legado.app.ui.widget.components.filePicker.FilePickerSheet
 import io.legado.app.ui.widget.components.settingItem.ClickableSettingItem
 import io.legado.app.ui.widget.components.settingItem.DropdownListSettingItem
 import io.legado.app.ui.widget.components.settingItem.InputSettingItem
-import io.legado.app.ui.widget.components.settingItem.SliderSettingItem
 import io.legado.app.ui.widget.components.settingItem.SwitchSettingItem
 import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
 import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
@@ -58,8 +56,6 @@ fun OtherConfigScreen(
 
     val scrollBehavior = GlassTopAppBarDefaults.defaultScrollBehavior()
 
-    var showClearCacheDialog by remember { mutableStateOf(false) }
-    var showShrinkDbDialog by remember { mutableStateOf(false) }
     var showClearWebViewDialog by remember { mutableStateOf(false) }
     var showPasswordDialog by remember { mutableStateOf(false) }
     var showCheckSourceSheet by remember { mutableStateOf(false) }
@@ -194,44 +190,6 @@ fun OtherConfigScreen(
                     onCheckedChange = { OtherConfig.antiAlias = it }
                 )
 
-                SliderSettingItem(
-                    title = stringResource(R.string.bitmap_cache_size),
-                    description = stringResource(
-                        R.string.bitmap_cache_size_summary,
-                        OtherConfig.bitmapCacheSize
-                    ),
-                    value = OtherConfig.bitmapCacheSize.toFloat(),
-                    defaultValue = 32f,
-                    valueRange = 1f..2047f,
-                    onValueChange = {
-                        viewModel.updateBitmapCacheSize(it.toInt())
-                    }
-                )
-
-                SliderSettingItem(
-                    title = stringResource(R.string.image_retain_number),
-                    description = stringResource(
-                        R.string.image_retain_number_summary,
-                        OtherConfig.imageRetainNum
-                    ),
-                    value = OtherConfig.imageRetainNum.toFloat(),
-                    defaultValue = 10f,
-                    valueRange = 0f..100f,
-                    onValueChange = { OtherConfig.imageRetainNum = it.toInt() }
-                )
-
-                SliderSettingItem(
-                    title = stringResource(R.string.pre_download),
-                    description = stringResource(
-                        R.string.pre_download_s,
-                        OtherConfig.preDownloadNum
-                    ),
-                    value = OtherConfig.preDownloadNum.toFloat(),
-                    defaultValue = 10f,
-                    valueRange = 0f..100f,
-                    onValueChange = { OtherConfig.preDownloadNum = it.toInt() }
-                )
-
                 SwitchSettingItem(
                     title = stringResource(R.string.replace_enable_default_t),
                     description = stringResource(R.string.replace_enable_default_s),
@@ -297,12 +255,6 @@ fun OtherConfigScreen(
                     onCheckedChange = { OtherConfig.delayBookLoadEnable = it }
                 )
 
-                InputSettingItem(
-                    title = stringResource(R.string.user_agent),
-                    value = OtherConfig.userAgent,
-                    onConfirm = { viewModel.saveUserAgent(it) }
-                )
-
                 SwitchSettingItem(
                     title = stringResource(R.string.web_service_wake_lock),
                     description = stringResource(R.string.web_service_wake_lock_summary),
@@ -328,13 +280,6 @@ fun OtherConfigScreen(
                     onClick = { showDirectLinkUploadSheet = true }
                 )
 
-                SwitchSettingItem(
-                    title = "Cronet",
-                    description = stringResource(R.string.pref_cronet_summary),
-                    checked = OtherConfig.cronetEnable,
-                    onCheckedChange = { OtherConfig.cronetEnable = it }
-                )
-
                 InputSettingItem(
                     title = stringResource(R.string.web_port_title),
                     value = OtherConfig.webPort.toString(),
@@ -347,47 +292,12 @@ fun OtherConfigScreen(
                     }
                 )
 
-                ClickableSettingItem(
-                    title = stringResource(R.string.clear_cache),
-                    description = stringResource(R.string.clear_cache_summary),
-                    onClick = { showClearCacheDialog = true }
-                )
-
                 ClickableSettingItem(
                     title = stringResource(R.string.clear_webview_data),
                     description = stringResource(R.string.clear_webview_data_summary),
                     onClick = { showClearWebViewDialog = true }
                 )
 
-                ClickableSettingItem(
-                    title = stringResource(R.string.shrink_database),
-                    description = stringResource(R.string.shrink_database_summary),
-                    onClick = { showShrinkDbDialog = true }
-                )
-
-                SliderSettingItem(
-                    title = stringResource(R.string.threads_num_title),
-                    description = stringResource(R.string.threads_num_summary),
-                    value = OtherConfig.threadCount.toFloat(),
-                    defaultValue = 8f,
-                    valueRange = 1f..256f,
-                    onValueChange = { OtherConfig.threadCount = it.toInt() }
-                )
-
-                SliderSettingItem(
-                    title = stringResource(R.string.cache_book_threads_num_title),
-                    description = stringResource(R.string.cache_book_threads_num_summary),
-                    value = OtherConfig.cacheBookThreadCount
-                        .coerceIn(1, CacheBook.maxDownloadConcurrency)
-                        .toFloat(),
-                    defaultValue = CacheBook.maxDownloadConcurrency.toFloat(),
-                    valueRange = 1f..CacheBook.maxDownloadConcurrency.toFloat(),
-                    onValueChange = {
-                        OtherConfig.cacheBookThreadCount =
-                            it.toInt().coerceIn(1, CacheBook.maxDownloadConcurrency)
-                    }
-                )
-
                 SwitchSettingItem(
                     title = stringResource(R.string.add_to_text_context_menu_t),
                     description = stringResource(R.string.add_to_text_context_menu_s),
@@ -437,30 +347,6 @@ fun OtherConfigScreen(
             onDismiss = { showDirectLinkUploadSheet = false }
         )
 
-        AppAlertDialog(
-            show = showClearCacheDialog,
-            onDismissRequest = { showClearCacheDialog = false },
-            title = stringResource(R.string.clear_cache),
-            text = stringResource(R.string.sure_del),
-            onConfirm = {
-                viewModel.clearCache(context)
-                showClearCacheDialog = false
-            },
-            onDismiss = { showClearCacheDialog = false }
-        )
-
-        AppAlertDialog(
-            show = showShrinkDbDialog,
-            onDismissRequest = { showShrinkDbDialog = false },
-            title = stringResource(R.string.shrink_database),
-            text = stringResource(R.string.sure),
-            onConfirm = {
-                viewModel.shrinkDatabase()
-                showShrinkDbDialog = false
-            },
-            onDismiss = { showShrinkDbDialog = false }
-        )
-
         AppAlertDialog(
             show = showClearWebViewDialog,
             onDismissRequest = { showClearWebViewDialog = false },

+ 4 - 29
app/src/main/java/io/legado/app/ui/config/otherConfig/OtherConfigViewModel.kt

@@ -9,14 +9,12 @@ import androidx.compose.runtime.setValue
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
 import io.legado.app.constant.PreferKey
-import io.legado.app.domain.usecase.ClearBookCacheUseCase
-import io.legado.app.domain.usecase.ShrinkDatabaseUseCase
 import io.legado.app.help.DirectLinkUpload
 import io.legado.app.help.config.AppConfig
 import io.legado.app.help.config.LocalConfig
 import io.legado.app.model.CheckSource
-import io.legado.app.model.ImageProvider
 import io.legado.app.receiver.SharedReceiverActivity
+import io.legado.app.ui.config.downloadCacheConfig.DownloadCacheConfig
 import io.legado.app.utils.FileUtils
 import io.legado.app.utils.putPrefString
 import io.legado.app.utils.restart
@@ -25,10 +23,7 @@ import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 import splitties.init.appCtx
 
-class OtherConfigViewModel(
-    private val clearBookCacheUseCase: ClearBookCacheUseCase,
-    private val shrinkDatabaseUseCase: ShrinkDatabaseUseCase
-) : ViewModel() {
+class OtherConfigViewModel : ViewModel() {
 
     private val packageManager = appCtx.packageManager
     private val componentName = ComponentName(
@@ -53,21 +48,6 @@ class OtherConfigViewModel(
         )
     }
 
-    fun clearCache(context: Context) {
-        viewModelScope.launch(Dispatchers.IO) {
-            clearBookCacheUseCase.executeAll()
-            FileUtils.delete(context.cacheDir.absolutePath)
-            context.externalCacheDir?.deleteRecursively()
-            context.cacheDir.deleteRecursively()
-        }
-    }
-
-    fun shrinkDatabase() {
-        viewModelScope.launch(Dispatchers.IO) {
-            shrinkDatabaseUseCase.execute()
-        }
-    }
-
     fun clearWebViewData(context: Context) {
         viewModelScope.launch(Dispatchers.IO) {
             FileUtils.delete(context.getDir("webview", Context.MODE_PRIVATE))
@@ -82,13 +62,8 @@ class OtherConfigViewModel(
     }
 
     fun saveUserAgent(input: String) {
-        OtherConfig.userAgent = input
-        AppConfig.userAgent = OtherConfig.userAgent
-    }
-
-    fun updateBitmapCacheSize(size: Int) {
-        AppConfig.bitmapCacheSize = size
-        ImageProvider.bitmapLruCache.resize(ImageProvider.cacheSize)
+        DownloadCacheConfig.userAgent = input
+        AppConfig.userAgent = DownloadCacheConfig.userAgent
     }
 
     fun updateLocalBookDir(path: String) {

+ 0 - 185
app/src/main/java/io/legado/app/ui/config/personalizationConfig/FontSelectScreen.kt

@@ -1,185 +0,0 @@
-package io.legado.app.ui.config.personalizationConfig
-
-import android.content.Intent
-import android.graphics.Typeface
-import android.net.Uri
-import androidx.activity.compose.rememberLauncherForActivityResult
-import androidx.activity.result.contract.ActivityResultContracts
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.lazy.grid.GridCells
-import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
-import androidx.compose.foundation.lazy.grid.items
-import androidx.compose.material3.Button
-import androidx.compose.material3.Card
-import androidx.compose.material3.CardDefaults
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.input.nestedscroll.nestedScroll
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.viewinterop.AndroidView
-import androidx.core.content.res.ResourcesCompat
-import io.legado.app.R
-import io.legado.app.constant.PreferKey
-import io.legado.app.help.loadFontFiles
-import io.legado.app.ui.config.themeConfig.ThemeConfig
-import io.legado.app.ui.theme.adaptiveContentPadding
-import io.legado.app.ui.widget.components.AppScaffold
-import io.legado.app.ui.widget.components.topbar.TopBarNavigationButton
-import io.legado.app.ui.widget.components.topbar.GlassMediumFlexibleTopAppBar
-import io.legado.app.ui.widget.components.topbar.GlassTopAppBarDefaults
-import io.legado.app.utils.FileDoc
-import io.legado.app.utils.getPrefString
-import io.legado.app.utils.putPrefString
-import io.legado.app.utils.takePersistablePermissionSafely
-
-@OptIn(ExperimentalMaterial3Api::class)
-@Composable
-fun FontSelectScreen(
-    onBackClick: () -> Unit
-) {
-    val scrollBehavior = GlassTopAppBarDefaults.defaultScrollBehavior()
-    val context = LocalContext.current
-    var fontItems by remember { mutableStateOf<List<FileDoc>>(emptyList()) }
-    var selectedFolderUri by remember { mutableStateOf<Uri?>(null) }
-
-    // 加载字体文件
-    fun loadFonts() {
-        fontItems = loadFontFiles(context, selectedFolderUri)
-    }
-
-    // 从偏好设置中加载保存的字体文件夹路径
-    remember {
-        val savedFontPath = context.getPrefString(PreferKey.fontFolder)
-        if (!savedFontPath.isNullOrEmpty()) {
-            selectedFolderUri = Uri.parse(savedFontPath)
-        }
-        loadFonts()
-    }
-
-    // 文件夹选择启动器
-    val selectFolderLauncher = rememberLauncherForActivityResult(
-        contract = ActivityResultContracts.OpenDocumentTree()
-    ) { uri ->
-        if (uri != null) {
-            selectedFolderUri = uri
-            // 获取持久化权限
-            uri.takePersistablePermissionSafely(context, Intent.FLAG_GRANT_READ_URI_PERMISSION)
-            // 保存选择的文件夹路径到偏好设置
-            context.putPrefString(PreferKey.fontFolder, uri.toString())
-            loadFonts()
-        }
-    }
-
-    AppScaffold(
-        modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
-        topBar = {
-            GlassMediumFlexibleTopAppBar(
-                title = stringResource(R.string.font_setting),
-                scrollBehavior = scrollBehavior,
-                navigationIcon = {
-                    TopBarNavigationButton(onClick = onBackClick)
-                }
-            )
-        }
-    ) { paddingValues ->
-        if (fontItems.isEmpty()) {
-            Box(
-                modifier = Modifier.fillMaxSize(),
-                contentAlignment = Alignment.Center
-            ) {
-                Column(
-                    horizontalAlignment = Alignment.CenterHorizontally,
-                    verticalArrangement = Arrangement.Center
-                ) {
-                    Text(
-                        text = "没有字体文件",
-                        style = MaterialTheme.typography.bodyLarge,
-                        modifier = Modifier.padding(bottom = 16.dp)
-                    )
-                    Button(onClick = { selectFolderLauncher.launch(null) }) {
-                        Text(text = stringResource(R.string.select_font))
-                    }
-                }
-            }
-        } else {
-            LazyVerticalGrid(
-                columns = GridCells.Fixed(2),
-                modifier = Modifier.fillMaxSize(),
-                contentPadding = adaptiveContentPadding(
-                    top = paddingValues.calculateTopPadding(),
-                    bottom = 120.dp
-                ),
-                verticalArrangement = Arrangement.spacedBy(16.dp),
-                horizontalArrangement = Arrangement.spacedBy(16.dp)
-            ) {
-                items(fontItems) {
-                    FontItem(it) {
-                        // 选择字体的逻辑
-                        ThemeConfig.appFontPath = it.uri.toString()
-                    }
-                }
-            }
-        }
-    }
-}
-
-@Composable
-fun FontItem(fontDoc: FileDoc, onFontSelected: (FileDoc) -> Unit) {
-    val context = LocalContext.current
-    
-    Card(
-        modifier = Modifier.fillMaxWidth().height(120.dp),
-        onClick = {
-            onFontSelected(fontDoc)
-        },
-        colors = CardDefaults.cardColors(
-            containerColor = MaterialTheme.colorScheme.surfaceVariant
-        )
-    ) {
-        // 使用AndroidView显示使用对应字体的文本
-        AndroidView(
-            factory = { ctx ->
-                android.widget.TextView(ctx).apply {
-                    text = fontDoc.name
-                    textSize = 16f
-                    // 设置垂直和水平居中
-                    gravity = android.view.Gravity.CENTER
-                    // 设置最大行数为2,超过省略
-                    maxLines = 2
-                    ellipsize = android.text.TextUtils.TruncateAt.END
-                    // 加载并设置字体
-                    runCatching {
-                        val typeface: Typeface? = if (fontDoc.uri.scheme == "content") {
-                            ctx.contentResolver.openFileDescriptor(fontDoc.uri, "r")?.use {
-                                Typeface.Builder(it.fileDescriptor).build()
-                            }
-                        } else {
-                            Typeface.createFromFile(fontDoc.uri.path!!)
-                        }
-                        this.typeface = typeface
-                    }.onFailure {
-                        // 字体加载失败,使用默认字体
-                    }
-                }
-            },
-            modifier = Modifier.fillMaxSize()
-        )
-    }
-}
-

+ 0 - 5
app/src/main/java/io/legado/app/ui/config/themeManage/EditThemeSheet.kt

@@ -276,11 +276,6 @@ fun EditThemeSheet(
                 valueRange = 0f..100f,
                 onValueChange = { data = data.copy(containerOpacity = it.toInt()) }
             )
-            CompactSwitchSettingItem(
-                title = "容器边框",
-                checked = data.enableContainerBorder,
-                onCheckedChange = { data = data.copy(enableContainerBorder = it) }
-            )
 
             Spacer(modifier = Modifier.height(8.dp))
 

+ 16 - 3
app/src/main/java/io/legado/app/ui/main/MainActivity.kt

@@ -62,9 +62,9 @@ import io.legado.app.ui.config.ConfigNavScreen
 import io.legado.app.ui.config.ConfigTag
 import io.legado.app.ui.config.backupConfig.BackupConfigScreen
 import io.legado.app.ui.config.coverConfig.CoverConfigScreen
+import io.legado.app.ui.config.downloadCacheConfig.DownloadCacheConfigScreen
 import io.legado.app.ui.config.themeConfig.ThemeConfig
 import io.legado.app.ui.config.otherConfig.OtherConfigScreen
-import io.legado.app.ui.config.personalizationConfig.FontSelectScreen
 import io.legado.app.ui.config.customTheme.CustomThemeScreen
 import io.legado.app.ui.config.readConfig.ReadConfigScreen
 import io.legado.app.ui.config.themeConfig.ThemeConfigScreen
@@ -105,6 +105,7 @@ open class MainActivity : BaseComposeActivity(), VariableDialog.Callback {
         private const val ROUTE_SETTINGS_THEME = "settings/theme"
         private const val ROUTE_SETTINGS_BACKUP = "settings/backup"
         private const val ROUTE_SETTINGS_CUSTOM_THEME = "settings/custom_theme"
+        private const val ROUTE_SETTINGS_DOWNLOAD_CACHE = "settings/download_cache"
         private const val ROUTE_IMPORT_LOCAL = "import/local"
         private const val ROUTE_IMPORT_REMOTE = "import/remote"
         private const val ROUTE_CACHE = "cache"
@@ -255,6 +256,7 @@ open class MainActivity : BaseComposeActivity(), VariableDialog.Callback {
                 ConfigTag.COVER_CONFIG -> ROUTE_SETTINGS_COVER
                 ConfigTag.THEME_CONFIG -> ROUTE_SETTINGS_THEME
                 ConfigTag.BACKUP_CONFIG -> ROUTE_SETTINGS_BACKUP
+                ConfigTag.DOWNLOAD_CACHE_CONFIG -> ROUTE_SETTINGS_DOWNLOAD_CACHE
                 else -> ROUTE_SETTINGS
             }
         }
@@ -294,6 +296,9 @@ open class MainActivity : BaseComposeActivity(), VariableDialog.Callback {
     @Serializable
     private data object MainRouteSettingsThemeManage : MainRoute
 
+    @Serializable
+    private data object MainRouteSettingsDownloadCache : MainRoute
+
     @Serializable
     private data object MainRouteImportLocal : MainRoute
 
@@ -551,7 +556,8 @@ open class MainActivity : BaseComposeActivity(), VariableDialog.Callback {
                         onNavigateToRead = { backStack.add(MainRouteSettingsRead) },
                         onNavigateToCover = { backStack.add(MainRouteSettingsCover) },
                         onNavigateToTheme = { backStack.add(MainRouteSettingsTheme) },
-                        onNavigateToBackup = { backStack.add(MainRouteSettingsBackup) }
+                        onNavigateToBackup = { backStack.add(MainRouteSettingsBackup) },
+                        onNavigateToDownloadCache = { backStack.add(MainRouteSettingsDownloadCache) }
                     )
                 }
 
@@ -579,6 +585,10 @@ open class MainActivity : BaseComposeActivity(), VariableDialog.Callback {
                     BackupConfigScreen(onBackClick = { navigateBack(backStack) })
                 }
 
+                entry<MainRouteSettingsDownloadCache> {
+                    DownloadCacheConfigScreen(onBackClick = { navigateBack(backStack) })
+                }
+
                 entry<MainRouteSettingsCustomTheme> {
                     CustomThemeScreen(
                         onBackClick = { navigateBack(backStack) }
@@ -832,7 +842,8 @@ open class MainActivity : BaseComposeActivity(), VariableDialog.Callback {
             MainRouteSettingsTheme,
             MainRouteSettingsBackup,
             MainRouteSettingsCustomTheme,
-            MainRouteSettingsThemeManage -> {
+            MainRouteSettingsThemeManage,
+            MainRouteSettingsDownloadCache -> {
                 backStack.clear()
                 backStack.add(MainRouteHome)
                 backStack.add(MainRouteSettings)
@@ -1095,6 +1106,7 @@ open class MainActivity : BaseComposeActivity(), VariableDialog.Callback {
             "settings/theme" -> MainRouteSettingsTheme
             "settings/backup" -> MainRouteSettingsBackup
             "settings/custom_theme" -> MainRouteSettingsCustomTheme
+            "settings/download_cache" -> MainRouteSettingsDownloadCache
             "import/local" -> MainRouteImportLocal
             "import/remote" -> MainRouteImportRemote
             ROUTE_MAIN -> MainRouteHome
@@ -1104,6 +1116,7 @@ open class MainActivity : BaseComposeActivity(), VariableDialog.Callback {
             ROUTE_SETTINGS_COVER -> MainRouteSettingsCover
             ROUTE_SETTINGS_THEME -> MainRouteSettingsTheme
             ROUTE_SETTINGS_BACKUP -> MainRouteSettingsBackup
+            ROUTE_SETTINGS_DOWNLOAD_CACHE -> MainRouteSettingsDownloadCache
             ROUTE_IMPORT_LOCAL -> MainRouteImportLocal
             ROUTE_IMPORT_REMOTE -> MainRouteImportRemote
             ROUTE_CACHE -> MainRouteCache(intent?.getLongExtra(EXTRA_CACHE_GROUP_ID, -1L) ?: -1L)

+ 0 - 22
app/src/main/java/io/legado/app/ui/main/explore/ExploreScreen.kt

@@ -5,7 +5,6 @@ import androidx.compose.animation.animateColorAsState
 import androidx.compose.animation.core.FastOutSlowInEasing
 import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.animation.core.tween
-import androidx.compose.foundation.BorderStroke
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.combinedClickable
 import androidx.compose.foundation.layout.Arrangement
@@ -285,22 +284,12 @@ fun ExploreScreen(
                     .align(Alignment.TopStart)
                     .padding(top = paddingValues.calculateTopPadding() + 4.dp, start = 8.dp)
             ) { item ->
-                val enableBorder = ThemeConfig.enableDeepPersonalization && ThemeConfig.enableContainerBorder
-                val borderWidth = ThemeConfig.containerBorderWidth.dp
-                val borderColor = if (ThemeConfig.containerBorderColor != 0) {
-                    Color(ThemeConfig.containerBorderColor)
-                } else {
-                    LegadoTheme.colorScheme.outline
-                }
                 TextCard(
                     text = item.bookSourceName,
                     textStyle = LegadoTheme.typography.labelMediumEmphasized,
                     cornerRadius = 12.dp,
                     horizontalPadding = 12.dp,
                     verticalPadding = 8.dp,
-                    border = if (enableBorder) {
-                        BorderStroke(borderWidth, borderColor)
-                    } else null,
                     onClick = {
                         scope.launch {
                             val index =
@@ -371,23 +360,12 @@ fun ExploreSourceHeader(
         label = "CardColor"
     )
 
-    val enableBorder = ThemeConfig.enableDeepPersonalization && ThemeConfig.enableContainerBorder
-    val borderWidth = ThemeConfig.containerBorderWidth.dp
-    val borderColor = if (ThemeConfig.containerBorderColor != 0) {
-        Color(ThemeConfig.containerBorderColor)
-    } else {
-        LegadoTheme.colorScheme.outline
-    }
-
     GlassCard(
         modifier = modifier
             .fillMaxWidth()
             .padding(vertical = 4.dp),
         cornerRadius = 12.dp,
         containerColor = containerColor,
-        border = if (enableBorder) {
-            BorderStroke(borderWidth, borderColor)
-        } else null
     ) {
         ListItem(
             modifier = Modifier

+ 8 - 0
app/src/main/res/values-zh-rCN/strings.xml

@@ -1483,4 +1483,12 @@
     <string name="search_source_progress"> · 进度 %1$d/%2$d</string>
     <string name="search_empty_scope_disable_precision">%1$s分组搜索结果为空,是否关闭精准搜索?</string>
     <string name="search_empty_scope_switch_all">%1$s分组搜索结果为空,是否切换到全部分组?</string>
+    <string name="download_cache_config">下载与缓存</string>
+    <string name="http_cache">HTTP缓存</string>
+    <string name="cover_cache">封面缓存</string>
+    <string name="manga_cache">漫画缓存</string>
+    <string name="cache_size_mb">%1$.1f MB</string>
+    <string name="download_setting">下载</string>
+    <string name="image_cache">图片缓存</string>
+    <string name="network">网络</string>
 </resources>

+ 8 - 0
app/src/main/res/values/strings.xml

@@ -1527,4 +1527,12 @@
     <string name="search_source_progress"> · Progress %1$d/%2$d</string>
     <string name="search_empty_scope_disable_precision">%1$s group search returned no results. Disable precise search?</string>
     <string name="search_empty_scope_switch_all">%1$s group search returned no results. Switch to all groups?</string>
+    <string name="download_cache_config">Download &amp; Cache</string>
+    <string name="http_cache">HTTP Cache</string>
+    <string name="cover_cache">Cover Cache</string>
+    <string name="manga_cache">Manga Cache</string>
+    <string name="cache_size_mb">%1$.1f MB</string>
+    <string name="download_setting">Download</string>
+    <string name="image_cache">Image Cache</string>
+    <string name="network">Network</string>
 </resources>