[优化] 优化界面

This commit is contained in:
HapeLee
2026-04-14 00:50:56 +08:00
parent 6a354acd29
commit 9410e9e0b5
13 changed files with 114 additions and 56 deletions
@@ -134,6 +134,7 @@ object PreferKey {
const val doublePageHorizontal = "doubleHorizontalPage"
const val readUrlOpenInBrowser = "readUrlInBrowser"
const val defaultBookTreeUri = "defaultBookTreeUri"
const val importBookPath = "importBookPath"
const val checkSource = "checkSource"
const val uploadRule = "uploadRule"
const val tocUiUseReplace = "tocUiUseReplace"
@@ -15,6 +15,7 @@ import io.legado.app.data.repository.ReadRecordRepository
import io.legado.app.data.repository.RemoteBookRepository
import io.legado.app.data.repository.SearchContentRepository
import io.legado.app.data.repository.UploadRepository
import io.legado.app.domain.usecase.ExploreKindUiUseCase
import io.legado.app.help.coil.CoverFetcher
import io.legado.app.help.coil.CoverInterceptor
import io.legado.app.help.http.okHttpClient
@@ -64,6 +65,7 @@ val appModule = module {
singleOf(::BookGroupRepository)
singleOf(::SearchContentRepository)
singleOf(::RemoteBookRepository)
singleOf(::ExploreKindUiUseCase)
single<UploadRepository> { DirectLinkUploadRepository() }
single<ExploreRepository> { ExploreRepositoryImpl(get()) }
@@ -1,6 +1,7 @@
package io.legado.app.help.source
import com.script.rhino.runScriptWithContext
import androidx.collection.LruCache
import io.legado.app.constant.BookSourceType
import io.legado.app.constant.BookType
import io.legado.app.data.entities.BookSource
@@ -8,6 +9,7 @@ import io.legado.app.data.entities.BookSourcePart
import io.legado.app.data.entities.rule.ExploreKind
import io.legado.app.utils.ACache
import io.legado.app.utils.GSON
import io.legado.app.utils.InfoMap
import io.legado.app.utils.MD5Utils
import io.legado.app.utils.fromJsonArray
import io.legado.app.utils.isJsonArray
@@ -25,6 +27,15 @@ import java.util.concurrent.ConcurrentHashMap
private val mutexMap by lazy { hashMapOf<String, Mutex>() }
private val exploreKindsMap by lazy { ConcurrentHashMap<String, List<ExploreKind>>() }
private val aCache by lazy { ACache.get("explore") }
private val exploreInfoMapList by lazy { LruCache<String, InfoMap>(99) }
fun getExploreInfoMap(sourceUrl: String): InfoMap {
return synchronized(exploreInfoMapList) {
exploreInfoMapList[sourceUrl] ?: InfoMap(sourceUrl).also {
exploreInfoMapList.put(sourceUrl, it)
}
}
}
private fun BookSource.getExploreKindsKey(): String {
return MD5Utils.md5Encode(bookSourceUrl + exploreUrl)
@@ -57,13 +68,16 @@ suspend fun BookSource.exploreKinds(): List<ExploreKind> {
) {
ruleStr = aCache.getAsString(exploreKindsKey)
if (ruleStr.isNullOrBlank()) {
val exploreInfoMap = getExploreInfoMap(bookSourceUrl)
val jsStr = if (exploreUrl.startsWith("@")) {
exploreUrl.substring(4)
} else {
exploreUrl.substring(4, exploreUrl.lastIndexOf("<"))
}
ruleStr = runScriptWithContext {
evalJS(jsStr).toString().trim()
evalJS(jsStr) {
put("infoMap", exploreInfoMap)
}.toString().trim()
}
aCache.put(exploreKindsKey, ruleStr)
}
@@ -304,6 +304,7 @@ fun RemoteBookScreen(
)
},
selectionActions = SelectionActions(
onClearSelection = { viewModel.clearSelection() },
onSelectAll = { viewModel.dispatch(RemoteBookIntent.SelectAll) },
onSelectInvert = { viewModel.dispatch(RemoteBookIntent.SelectInvert) },
primaryAction = ActionItem(
@@ -845,11 +845,14 @@ private fun BookInfoSummary(
) {
AppText(
text = stringResource(R.string.read_chapter_total, book.totalChapterNum),
style = LegadoTheme.typography.bodyMedium,
style = LegadoTheme.typography.labelMedium,
color = LegadoTheme.colorScheme.primary,
fontWeight = FontWeight.Bold,
)
AppText(text = "|", color = LegadoTheme.colorScheme.secondary)
AppText(
text = "|",
color = LegadoTheme.colorScheme.secondary
)
AppText(
text = if (book.durChapterIndex + 1 == book.totalChapterNum && book.totalChapterNum > 0) "已读完" else stringResource(R.string.read_chapter_index, book.durChapterIndex + 1),
style = LegadoTheme.typography.labelMedium,
@@ -13,8 +13,6 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import io.legado.app.ui.config.themeConfig.ThemeConfig
import top.yukonga.miuix.kmp.theme.MiuixTheme
import top.yukonga.miuix.kmp.theme.ThemeController
@@ -132,37 +130,7 @@ fun AppTheme(
MiuixTheme(controller = controller) {
val miuixStyles = MiuixTheme.textStyles
val legadoTypography = remember(miuixStyles) {
LegadoTypography(
headlineLarge = miuixStyles.title1,
headlineLargeEmphasized = miuixStyles.title1.emphasized(),
headlineMedium = miuixStyles.title2,
headlineMediumEmphasized = miuixStyles.title2.emphasized(),
headlineSmall = miuixStyles.title3,
headlineSmallEmphasized = miuixStyles.title3.emphasized(),
titleLarge = miuixStyles.headline1,
titleLargeEmphasized = miuixStyles.headline1.emphasized(),
titleMedium = miuixStyles.headline2,
titleMediumEmphasized = miuixStyles.headline2.emphasized(),
titleSmall = miuixStyles.subtitle,
titleSmallEmphasized = miuixStyles.subtitle.emphasized(),
bodyLarge = miuixStyles.paragraph,
bodyLargeEmphasized = miuixStyles.paragraph.emphasized(),
bodyMedium = miuixStyles.body1,
bodyMediumEmphasized = miuixStyles.body1.emphasized(),
bodySmall = miuixStyles.body2,
bodySmallEmphasized = miuixStyles.body2.emphasized(),
labelLarge = miuixStyles.button,
labelLargeEmphasized = miuixStyles.button.emphasized(),
labelMedium = miuixStyles.footnote1,
labelMediumEmphasized = miuixStyles.footnote1.emphasized(),
labelSmall = miuixStyles.footnote2,
labelSmallEmphasized = miuixStyles.footnote2.emphasized()
)
miuixStylesToM3Typography(miuixStyles).toLegadoTypography()
}
val miuixColorScheme = MiuixTheme.colorScheme
@@ -290,7 +258,3 @@ private fun Typography.toLegadoTypography(): LegadoTypography {
labelSmallEmphasized = labelSmallEmphasized
)
}
private fun TextStyle.emphasized(): TextStyle {
return copy(fontWeight = FontWeight.Medium)
}
@@ -3,6 +3,7 @@ package io.legado.app.ui.theme
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Typography
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import top.yukonga.miuix.kmp.theme.TextStyles
@@ -17,28 +18,34 @@ fun miuixStylesToM3Typography(miuixStyles: TextStyles): Typography {
displayMedium = miuixStyles.title2, // 24.sp
displaySmall = miuixStyles.title3, // 20.sp
headlineLarge = miuixStyles.title2, // 24.sp
headlineMedium = miuixStyles.title3, // 20.sp
headlineSmall = miuixStyles.title4, // 18.sp
headlineLarge = miuixStyles.title1, // 32.sp
headlineMedium = miuixStyles.title2, // 24.sp
headlineSmall = miuixStyles.title3, // 20.sp
titleLarge = miuixStyles.headline1, // 17.sp
titleLarge = miuixStyles.title4, // 18.sp
titleMedium = miuixStyles.headline2, // 16.sp
titleSmall = miuixStyles.subtitle, // 14.sp, Bold
bodyLarge = miuixStyles.paragraph, // 17.sp, lineHeight 1.2em (如果不需要行高也可以换成 main)
bodyLarge = miuixStyles.paragraph, // 17.sp
bodyMedium = miuixStyles.body1, // 16.sp
bodySmall = miuixStyles.body2, // 14.sp
bodySmall = miuixStyles.body2.copy(fontSize = 12.sp), // 12.sp
labelLarge = miuixStyles.button, // 17.sp
labelLarge = miuixStyles.footnote1.copy(fontSize = 14.sp), // 14.sp
labelMedium = miuixStyles.footnote1, // 13.sp
labelSmall = miuixStyles.footnote2, // 11.sp
labelSmall = miuixStyles.footnote2, // 11.sp
bodyLargeEmphasized = miuixStyles.paragraph.copy(fontWeight = FontWeight.Medium),
bodyMediumEmphasized = miuixStyles.body1.copy(fontWeight = FontWeight.Medium),
bodySmallEmphasized = miuixStyles.body2.copy(fontWeight = FontWeight.Medium),
bodySmallEmphasized = miuixStyles.body2.copy(
fontSize = 12.sp,
fontWeight = FontWeight.Medium
),
labelLargeEmphasized = miuixStyles.button.copy(fontWeight = FontWeight.Medium),
labelLargeEmphasized = miuixStyles.button.copy(
fontSize = 14.sp,
fontWeight = FontWeight.Medium
),
labelMediumEmphasized = miuixStyles.footnote1.copy(fontWeight = FontWeight.Medium),
labelSmallEmphasized = miuixStyles.footnote2.copy(fontWeight = FontWeight.Medium)
)
}
}
@@ -3,6 +3,7 @@ package io.legado.app.ui.widget.components
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
@@ -22,6 +23,7 @@ import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.dp
import io.legado.app.ui.theme.LegadoTheme
import io.legado.app.ui.theme.ThemeResolver
import io.legado.app.ui.widget.components.text.AppText
@@ -272,6 +274,61 @@ fun AppTextFieldSurface(
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppDenseTextField(
state: TextFieldState,
modifier: Modifier = Modifier,
enabled: Boolean = true,
readOnly: Boolean = false,
backgroundColor: Color = Color.Unspecified,
label: String? = null,
labelPosition: TextFieldLabelPosition = TextFieldLabelPosition.Attached(),
placeholder: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
prefix: @Composable (() -> Unit)? = null,
suffix: @Composable (() -> Unit)? = null,
supportingText: @Composable (() -> Unit)? = null,
isError: Boolean = false,
inputTransformation: InputTransformation? = null,
outputTransformation: OutputTransformation? = null,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
onKeyboardAction: KeyboardActionHandler? = null,
lineLimits: TextFieldLineLimits = TextFieldLineLimits.Default,
onTextLayout: (Density.(getResult: () -> TextLayoutResult?) -> Unit)? = null,
scrollState: ScrollState = rememberScrollState(),
shape: Shape = TextFieldDefaults.shape,
interactionSource: MutableInteractionSource? = null,
) {
AppTextField(
state = state,
modifier = modifier.heightIn(min = 48.dp),
enabled = enabled,
readOnly = readOnly,
backgroundColor = backgroundColor,
label = label,
labelPosition = labelPosition,
placeholder = placeholder,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
prefix = prefix,
suffix = suffix,
supportingText = supportingText,
isError = isError,
inputTransformation = inputTransformation,
outputTransformation = outputTransformation,
keyboardOptions = keyboardOptions,
onKeyboardAction = onKeyboardAction,
lineLimits = lineLimits,
onTextLayout = onTextLayout,
scrollState = scrollState,
shape = shape,
contentPadding = PaddingValues(top = 4.dp, bottom = 4.dp, start = 12.dp, end = 12.dp),
interactionSource = interactionSource
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppTextFieldSurface(
@@ -321,4 +378,4 @@ fun AppTextFieldSurface(
shape = shape,
interactionSource = interactionSource
)
}
}
@@ -79,7 +79,7 @@ fun SearchBarSection(
)
val searchTextField = @Composable {
AppTextField(
AppDenseTextField(
state = textFieldState,
modifier = modifier,
placeholder = { AppText(placeholder) },
@@ -106,4 +106,4 @@ fun SearchBarSection(
searchTextField()
}
}
}
}
@@ -31,6 +31,7 @@ import io.legado.app.ui.widget.components.text.AppText
data class SelectionActions(
val primaryAction: ActionItem,
val secondaryActions: List<ActionItem> = emptyList(),
val onClearSelection: (() -> Unit)? = null,
val onSelectAll: () -> Unit,
val onSelectInvert: () -> Unit,
)
@@ -113,4 +114,4 @@ fun SelectionBottomBar(
}
}
)
}
}
@@ -88,7 +88,7 @@ fun <T> ListScaffold(
onSearchToggle = onSearchToggle,
onSearchQueryChange = onSearchQueryChange,
searchPlaceholder = searchPlaceholder,
onClearSelection = { selectionActions?.onSelectInvert?.invoke() },
onClearSelection = { selectionActions?.onClearSelection?.invoke() },
topBarActions = topBarActions,
dropDownMenuContent = dropDownMenuContent,
bottomContent = bottomContent
@@ -101,6 +101,7 @@ fun <T> RuleListScaffold(
floatingActionButton = floatingActionButton,
snackbarHostState = snackbarHostState,
selectionActions = SelectionActions(
onClearSelection = onClearSelection,
onSelectAll = onSelectAll,
onSelectInvert = onSelectInvert,
primaryAction = ActionItem(
@@ -38,6 +38,13 @@ fun Uri.takePersistablePermissionSafely(
modeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
): Boolean {
if (!isContentScheme()) return false
kotlin.runCatching {
context.contentResolver.takePersistableUriPermission(this, modeFlags)
}.onSuccess {
return true
}.onFailure {
AppLog.put("持久化读写权限失败(组合模式): $this", it)
}
var granted = false
if (modeFlags and Intent.FLAG_GRANT_READ_URI_PERMISSION != 0) {
kotlin.runCatching {