代码优化

This commit is contained in:
HapeLee
2026-05-14 15:37:26 +08:00
parent 4d3ae1e537
commit 7fda394d74
12 changed files with 301 additions and 147 deletions
@@ -3,9 +3,10 @@ package io.legado.app.help.rhino
import com.script.rhino.JavaObjectWrapFactory import com.script.rhino.JavaObjectWrapFactory
import org.mozilla.javascript.NativeJavaObject import org.mozilla.javascript.NativeJavaObject
import org.mozilla.javascript.Scriptable import org.mozilla.javascript.Scriptable
import org.mozilla.javascript.lc.type.TypeInfoFactory
class NativeBaseSource(scope: Scriptable?, javaObject: Any, staticType: Class<*>?) : class NativeBaseSource(scope: Scriptable?, javaObject: Any, staticType: Class<*>?) :
NativeJavaObject(scope, javaObject, staticType) { NativeJavaObject(scope, javaObject, staticType?.let { TypeInfoFactory.GLOBAL.create(it) }) {
override fun has(name: String, start: Scriptable): Boolean { override fun has(name: String, start: Scriptable): Boolean {
if (name != "setVariable" && name.length > 3 && name.startsWith("set")) { if (name != "setVariable" && name.length > 3 && name.startsWith("set")) {
@@ -2,6 +2,7 @@ package io.legado.app.ui.config
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
@@ -21,9 +22,14 @@ import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
interface PrefDelegate<T> : ReadWriteProperty<Any?, T> { interface PrefDelegate<T> : ReadWriteProperty<Any?, T> {
val state: State<T>
fun dispose() fun dispose()
} }
class PrefStateDelegate<T>(private val delegate: PrefDelegate<T>) : ReadWriteProperty<Any?, T> by delegate {
val state: State<T> get() = delegate.state
}
fun <T> prefDelegate( fun <T> prefDelegate(
key: String, key: String,
defaultValue: T, defaultValue: T,
@@ -32,6 +38,7 @@ fun <T> prefDelegate(
): PrefDelegate<T> { ): PrefDelegate<T> {
return object : PrefDelegate<T>, SharedPreferences.OnSharedPreferenceChangeListener, DefaultLifecycleObserver { return object : PrefDelegate<T>, SharedPreferences.OnSharedPreferenceChangeListener, DefaultLifecycleObserver {
private var _value: MutableState<T> = mutableStateOf(readInitialValue()) private var _value: MutableState<T> = mutableStateOf(readInitialValue())
override val state: State<T> get() = _value
init { init {
if (lifecycleOwner != null) { if (lifecycleOwner != null) {
@@ -98,4 +105,14 @@ fun <T> prefDelegate(
} }
} }
} }
}
fun <T> prefStateDelegate(
key: String,
defaultValue: T,
lifecycleOwner: LifecycleOwner? = null,
onValueChange: ((T) -> Unit)? = null
): PrefStateDelegate<T> {
val delegate = prefDelegate(key, defaultValue, lifecycleOwner, onValueChange)
return PrefStateDelegate(delegate)
} }
@@ -1,9 +1,10 @@
package io.legado.app.ui.config.bookshelfConfig package io.legado.app.ui.config.bookshelfConfig
import androidx.compose.runtime.State
import io.legado.app.constant.EventBus import io.legado.app.constant.EventBus
import io.legado.app.constant.PreferKey import io.legado.app.constant.PreferKey
import io.legado.app.data.entities.BookGroup import io.legado.app.data.entities.BookGroup
import io.legado.app.ui.config.prefDelegate import io.legado.app.ui.config.prefStateDelegate
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
/** /**
@@ -14,213 +15,295 @@ object BookshelfConfig {
/** /**
* 书架分组样式: 0: Tab, 1:隐藏Tab, 2:文件夹 * 书架分组样式: 0: Tab, 1:隐藏Tab, 2:文件夹
*/ */
var bookGroupStyle by prefDelegate(PreferKey.bookGroupStyle, 0) { private val _bookGroupStyle = prefStateDelegate(PreferKey.bookGroupStyle, 0) {
postEvent(EventBus.NOTIFY_MAIN, false) postEvent(EventBus.NOTIFY_MAIN, false)
} }
var bookGroupStyle by _bookGroupStyle
val bookGroupStyleState: State<Int> get() = _bookGroupStyle.state
/** /**
* 书架排序方式 * 书架排序方式
*/ */
var bookshelfSort by prefDelegate(PreferKey.bookshelfSort, 0) private val _bookshelfSort = prefStateDelegate(PreferKey.bookshelfSort, 0)
var bookshelfSort by _bookshelfSort
val bookshelfSortState: State<Int> get() = _bookshelfSort.state
/** /**
* 书架排序顺序 * 书架排序顺序
*/ */
var bookshelfSortOrder by prefDelegate(PreferKey.bookshelfSortOrder, 1) private val _bookshelfSortOrder = prefStateDelegate(PreferKey.bookshelfSortOrder, 1)
var bookshelfSortOrder by _bookshelfSortOrder
val bookshelfSortOrderState: State<Int> get() = _bookshelfSortOrder.state
/** /**
* 是否显示未读标志 * 是否显示未读标志
*/ */
var showUnread by prefDelegate(PreferKey.showUnread, true) private val _showUnread = prefStateDelegate(PreferKey.showUnread, true)
var showUnread by _showUnread
val showUnreadState: State<Boolean> get() = _showUnread.state
/** /**
* 是否显示新未读标志(小圆点) * 是否显示新未读标志(小圆点)
*/ */
var showUnreadNew by prefDelegate(PreferKey.showUnreadNew, true) private val _showUnreadNew = prefStateDelegate(PreferKey.showUnreadNew, true)
var showUnreadNew by _showUnreadNew
val showUnreadNewState: State<Boolean> get() = _showUnreadNew.state
/** /**
* 是否显示更新提示 * 是否显示更新提示
*/ */
var showTip by prefDelegate(PreferKey.showTip, false) private val _showTip = prefStateDelegate(PreferKey.showTip, false)
var showTip by _showTip
val showTipState: State<Boolean> get() = _showTip.state
/** /**
* 鏄惁鏄剧ず鍒嗙粍鍐呬功绫嶆暟閲? * 鏄惁鏄剧ず鍒嗙粍鍐呬功绫嶆暟閲?
*/ */
var showBookCount by prefDelegate(PreferKey.showBookCount, true) private val _showBookCount = prefStateDelegate(PreferKey.showBookCount, true)
var showBookCount by _showBookCount
val showBookCountState: State<Boolean> get() = _showBookCount.state
/** /**
* 是否在列表中显示最后更新时间 * 是否在列表中显示最后更新时间
*/ */
var showLastUpdateTime by prefDelegate(PreferKey.showLastUpdateTime, false) private val _showLastUpdateTime = prefStateDelegate(PreferKey.showLastUpdateTime, false)
var showLastUpdateTime by _showLastUpdateTime
val showLastUpdateTimeState: State<Boolean> get() = _showLastUpdateTime.state
/** /**
* 是否在列表中显示书籍简介 * 是否在列表中显示书籍简介
*/ */
var showBookIntro by prefDelegate(PreferKey.showBookIntro, false) private val _showBookIntro = prefStateDelegate(PreferKey.showBookIntro, false)
var showBookIntro by _showBookIntro
val showBookIntroState: State<Boolean> get() = _showBookIntro.state
/** /**
* 是否显示简介 * 是否显示简介
*/ */
var bookshelfShowIntro by prefDelegate(PreferKey.bookshelfShowIntro, true) private val _bookshelfShowIntro = prefStateDelegate(PreferKey.bookshelfShowIntro, true)
var bookshelfShowIntro by _bookshelfShowIntro
val bookshelfShowIntroState: State<Boolean> get() = _bookshelfShowIntro.state
/** /**
* 是否显示标签 * 是否显示标签
*/ */
var bookshelfShowTag by prefDelegate(PreferKey.bookshelfShowTag, true) private val _bookshelfShowTag = prefStateDelegate(PreferKey.bookshelfShowTag, true)
var bookshelfShowTag by _bookshelfShowTag
val bookshelfShowTagState: State<Boolean> get() = _bookshelfShowTag.state
/** /**
* 列表模式下简介显示行数 (0为显示全部) * 列表模式下简介显示行数 (0为显示全部)
*/ */
var bookshelfIntroMaxLines by prefDelegate(PreferKey.bookshelfIntroMaxLines, 0) private val _bookshelfIntroMaxLines = prefStateDelegate(PreferKey.bookshelfIntroMaxLines, 0)
var bookshelfIntroMaxLines by _bookshelfIntroMaxLines
val bookshelfIntroMaxLinesState: State<Int> get() = _bookshelfIntroMaxLines.state
/** /**
* 是否显示等待更新的书籍数量 * 是否显示等待更新的书籍数量
*/ */
var showWaitUpCount by prefDelegate(PreferKey.showWaitUpCount, false) private val _showWaitUpCount = prefStateDelegate(PreferKey.showWaitUpCount, false)
var showWaitUpCount by _showWaitUpCount
val showWaitUpCountState: State<Boolean> get() = _showWaitUpCount.state
/** /**
* 是否显示书架快速滚动条 * 是否显示书架快速滚动条
*/ */
var showBookshelfFastScroller by prefDelegate(PreferKey.showBookshelfFastScroller, false) private val _showBookshelfFastScroller = prefStateDelegate(PreferKey.showBookshelfFastScroller, false)
var showBookshelfFastScroller by _showBookshelfFastScroller
val showBookshelfFastScrollerState: State<Boolean> get() = _showBookshelfFastScroller.state
/** /**
* 是否在书架Tab处显示分类展开按钮 * 是否在书架Tab处显示分类展开按钮
*/ */
var shouldShowExpandButton by prefDelegate(PreferKey.shouldShowExpandButton, false) private val _shouldShowExpandButton = prefStateDelegate(PreferKey.shouldShowExpandButton, false)
var shouldShowExpandButton by _shouldShowExpandButton
val shouldShowExpandButtonState: State<Boolean> get() = _shouldShowExpandButton.state
/** /**
* 书架同时更新书籍数量限制 (0为无限制) * 书架同时更新书籍数量限制 (0为无限制)
*/ */
var bookshelfRefreshingLimit by prefDelegate(PreferKey.bookshelfRefreshingLimit, 0) private val _bookshelfRefreshingLimit = prefStateDelegate(PreferKey.bookshelfRefreshingLimit, 0)
var bookshelfRefreshingLimit by _bookshelfRefreshingLimit
val bookshelfRefreshingLimitState: State<Int> get() = _bookshelfRefreshingLimit.state
/** /**
* 竖屏书架布局模式: 0:列表, 1:网格 * 竖屏书架布局模式: 0:列表, 1:网格
*/ */
var bookshelfLayoutModePortrait by prefDelegate(PreferKey.bookshelfLayoutModePortrait, 1) private val _bookshelfLayoutModePortrait = prefStateDelegate(PreferKey.bookshelfLayoutModePortrait, 1)
var bookshelfLayoutModePortrait by _bookshelfLayoutModePortrait
val bookshelfLayoutModePortraitState: State<Int> get() = _bookshelfLayoutModePortrait.state
/** /**
* 竖屏书架网格列数 * 竖屏书架网格列数
*/ */
var bookshelfLayoutGridPortrait by prefDelegate(PreferKey.bookshelfLayoutGridPortrait, 3) private val _bookshelfLayoutGridPortrait = prefStateDelegate(PreferKey.bookshelfLayoutGridPortrait, 3)
var bookshelfLayoutGridPortrait by _bookshelfLayoutGridPortrait
val bookshelfLayoutGridPortraitState: State<Int> get() = _bookshelfLayoutGridPortrait.state
/** /**
* 横屏书架布局模式: 0:列表, 1:网格 * 横屏书架布局模式: 0:列表, 1:网格
*/ */
var bookshelfLayoutModeLandscape by prefDelegate(PreferKey.bookshelfLayoutModeLandscape, 1) private val _bookshelfLayoutModeLandscape = prefStateDelegate(PreferKey.bookshelfLayoutModeLandscape, 1)
var bookshelfLayoutModeLandscape by _bookshelfLayoutModeLandscape
val bookshelfLayoutModeLandscapeState: State<Int> get() = _bookshelfLayoutModeLandscape.state
/** /**
* 横屏书架网格列数 * 横屏书架网格列数
*/ */
var bookshelfLayoutGridLandscape by prefDelegate(PreferKey.bookshelfLayoutGridLandscape, 7) private val _bookshelfLayoutGridLandscape = prefStateDelegate(PreferKey.bookshelfLayoutGridLandscape, 7)
var bookshelfLayoutGridLandscape by _bookshelfLayoutGridLandscape
val bookshelfLayoutGridLandscapeState: State<Int> get() = _bookshelfLayoutGridLandscape.state
/** /**
* 竖屏书架列表列数 * 竖屏书架列表列数
*/ */
var bookshelfLayoutListPortrait by prefDelegate(PreferKey.bookshelfLayoutListPortrait, 1) private val _bookshelfLayoutListPortrait = prefStateDelegate(PreferKey.bookshelfLayoutListPortrait, 1)
var bookshelfLayoutListPortrait by _bookshelfLayoutListPortrait
val bookshelfLayoutListPortraitState: State<Int> get() = _bookshelfLayoutListPortrait.state
/** /**
* 横屏书架列表列数 * 横屏书架列表列数
*/ */
var bookshelfLayoutListLandscape by prefDelegate(PreferKey.bookshelfLayoutListLandscape, 1) private val _bookshelfLayoutListLandscape = prefStateDelegate(PreferKey.bookshelfLayoutListLandscape, 1)
var bookshelfLayoutListLandscape by _bookshelfLayoutListLandscape
val bookshelfLayoutListLandscapeState: State<Int> get() = _bookshelfLayoutListLandscape.state
/** /**
* 文件夹竖屏布局模式: 0:列表, 1:网格 * 文件夹竖屏布局模式: 0:列表, 1:网格
*/ */
var bookshelfFolderLayoutModePortrait by prefDelegate(PreferKey.bookshelfFolderLayoutModePortrait, 1) private val _bookshelfFolderLayoutModePortrait = prefStateDelegate(PreferKey.bookshelfFolderLayoutModePortrait, 1)
var bookshelfFolderLayoutModePortrait by _bookshelfFolderLayoutModePortrait
val bookshelfFolderLayoutModePortraitState: State<Int> get() = _bookshelfFolderLayoutModePortrait.state
/** /**
* 文件夹竖屏网格列数 * 文件夹竖屏网格列数
*/ */
var bookshelfFolderLayoutGridPortrait by prefDelegate(PreferKey.bookshelfFolderLayoutGridPortrait, 3) private val _bookshelfFolderLayoutGridPortrait = prefStateDelegate(PreferKey.bookshelfFolderLayoutGridPortrait, 3)
var bookshelfFolderLayoutGridPortrait by _bookshelfFolderLayoutGridPortrait
val bookshelfFolderLayoutGridPortraitState: State<Int> get() = _bookshelfFolderLayoutGridPortrait.state
/** /**
* 文件夹横屏布局模式: 0:列表, 1:网格 * 文件夹横屏布局模式: 0:列表, 1:网格
*/ */
var bookshelfFolderLayoutModeLandscape by prefDelegate(PreferKey.bookshelfFolderLayoutModeLandscape, 1) private val _bookshelfFolderLayoutModeLandscape = prefStateDelegate(PreferKey.bookshelfFolderLayoutModeLandscape, 1)
var bookshelfFolderLayoutModeLandscape by _bookshelfFolderLayoutModeLandscape
val bookshelfFolderLayoutModeLandscapeState: State<Int> get() = _bookshelfFolderLayoutModeLandscape.state
/** /**
* 文件夹横屏网格列数 * 文件夹横屏网格列数
*/ */
var bookshelfFolderLayoutGridLandscape by prefDelegate(PreferKey.bookshelfFolderLayoutGridLandscape, 7) private val _bookshelfFolderLayoutGridLandscape = prefStateDelegate(PreferKey.bookshelfFolderLayoutGridLandscape, 7)
var bookshelfFolderLayoutGridLandscape by _bookshelfFolderLayoutGridLandscape
val bookshelfFolderLayoutGridLandscapeState: State<Int> get() = _bookshelfFolderLayoutGridLandscape.state
/** /**
* 文件夹竖屏列表列数 * 文件夹竖屏列表列数
*/ */
var bookshelfFolderLayoutListPortrait by prefDelegate(PreferKey.bookshelfFolderLayoutListPortrait, 1) private val _bookshelfFolderLayoutListPortrait = prefStateDelegate(PreferKey.bookshelfFolderLayoutListPortrait, 1)
var bookshelfFolderLayoutListPortrait by _bookshelfFolderLayoutListPortrait
val bookshelfFolderLayoutListPortraitState: State<Int> get() = _bookshelfFolderLayoutListPortrait.state
/** /**
* 文件夹横屏列表列数 * 文件夹横屏列表列数
*/ */
var bookshelfFolderLayoutListLandscape by prefDelegate(PreferKey.bookshelfFolderLayoutListLandscape, 1) private val _bookshelfFolderLayoutListLandscape = prefStateDelegate(PreferKey.bookshelfFolderLayoutListLandscape, 1)
var bookshelfFolderLayoutListLandscape by _bookshelfFolderLayoutListLandscape
val bookshelfFolderLayoutListLandscapeState: State<Int> get() = _bookshelfFolderLayoutListLandscape.state
/** /**
* 网格模式布局样式: 0:标准, 1:紧凑, 2:仅封面 * 网格模式布局样式: 0:标准, 1:紧凑, 2:仅封面
*/ */
var bookshelfGridLayout by prefDelegate(PreferKey.bookshelfGridLayout, 0) private val _bookshelfGridLayout = prefStateDelegate(PreferKey.bookshelfGridLayout, 0)
var bookshelfGridLayout by _bookshelfGridLayout
val bookshelfGridLayoutState: State<Int> get() = _bookshelfGridLayout.state
/** /**
* 紧凑模式 * 紧凑模式
*/ */
var bookshelfLayoutCompact by prefDelegate(PreferKey.bookshelfLayoutCompact, false) private val _bookshelfLayoutCompact = prefStateDelegate(PreferKey.bookshelfLayoutCompact, false)
var bookshelfLayoutCompact by _bookshelfLayoutCompact
val bookshelfLayoutCompactState: State<Boolean> get() = _bookshelfLayoutCompact.state
/** /**
* 是否显示书架分隔线 * 是否显示书架分隔线
*/ */
var bookshelfShowDivider by prefDelegate(PreferKey.bookshelfShowDivider, true) private val _bookshelfShowDivider = prefStateDelegate(PreferKey.bookshelfShowDivider, true)
var bookshelfShowDivider by _bookshelfShowDivider
val bookshelfShowDividerState: State<Boolean> get() = _bookshelfShowDivider.state
/** /**
* 书架标题小字体 * 书架标题小字体
*/ */
var bookshelfTitleSmallFont by prefDelegate(PreferKey.bookshelfTitleSmallFont, false) private val _bookshelfTitleSmallFont = prefStateDelegate(PreferKey.bookshelfTitleSmallFont, false)
var bookshelfTitleSmallFont by _bookshelfTitleSmallFont
val bookshelfTitleSmallFontState: State<Boolean> get() = _bookshelfTitleSmallFont.state
/** /**
* 书架标题居中 * 书架标题居中
*/ */
var bookshelfTitleCenter by prefDelegate(PreferKey.bookshelfTitleCenter, true) private val _bookshelfTitleCenter = prefStateDelegate(PreferKey.bookshelfTitleCenter, true)
var bookshelfTitleCenter by _bookshelfTitleCenter
val bookshelfTitleCenterState: State<Boolean> get() = _bookshelfTitleCenter.state
/** /**
* 书架标题最大行数 * 书架标题最大行数
*/ */
var bookshelfTitleMaxLines by prefDelegate(PreferKey.bookshelfTitleMaxLines, 2) private val _bookshelfTitleMaxLines = prefStateDelegate(PreferKey.bookshelfTitleMaxLines, 2)
var bookshelfTitleMaxLines by _bookshelfTitleMaxLines
val bookshelfTitleMaxLinesState: State<Int> get() = _bookshelfTitleMaxLines.state
/** /**
* 书架封面阴影 * 书架封面阴影
*/ */
var bookshelfCoverShadow by prefDelegate(PreferKey.bookshelfCoverShadow, false) private val _bookshelfCoverShadow = prefStateDelegate(PreferKey.bookshelfCoverShadow, false)
var bookshelfCoverShadow by _bookshelfCoverShadow
val bookshelfCoverShadowState: State<Boolean> get() = _bookshelfCoverShadow.state
/** /**
* 书架卡片背景颜色 * 书架卡片背景颜色
*/ */
var bookshelfCardColor by prefDelegate(PreferKey.bookshelfCardColor, 0) { private val _bookshelfCardColor = prefStateDelegate(PreferKey.bookshelfCardColor, 0) {
postEvent(EventBus.NOTIFY_MAIN, false) postEvent(EventBus.NOTIFY_MAIN, false)
} }
var bookshelfCardColor by _bookshelfCardColor
val bookshelfCardColorState: State<Int> get() = _bookshelfCardColor.state
/** /**
* 文件夹在列表模式下的样式: 0: 默认, 2: 横排封面 * 文件夹在列表模式下的样式: 0: 默认, 2: 横排封面
*/ */
var bookshelfGroupListStyle by prefDelegate(PreferKey.bookshelfGroupListStyle, 0) private val _bookshelfGroupListStyle = prefStateDelegate(PreferKey.bookshelfGroupListStyle, 0)
var bookshelfGroupListStyle by _bookshelfGroupListStyle
val bookshelfGroupListStyleState: State<Int> get() = _bookshelfGroupListStyle.state
/** /**
* 文件夹在列表模式下横排封面的数量 * 文件夹在列表模式下横排封面的数量
*/ */
var bookshelfGroupCoverCount by prefDelegate(PreferKey.bookshelfGroupCoverCount, 4) private val _bookshelfGroupCoverCount = prefStateDelegate(PreferKey.bookshelfGroupCoverCount, 4)
var bookshelfGroupCoverCount by _bookshelfGroupCoverCount
val bookshelfGroupCoverCountState: State<Int> get() = _bookshelfGroupCoverCount.state
/** /**
* 书架搜索按钮是否直接跳转搜索页 * 书架搜索按钮是否直接跳转搜索页
*/ */
var bookshelfSearchActionDirectToSearch by prefDelegate( private val _bookshelfSearchActionDirectToSearch = prefStateDelegate(
PreferKey.bookshelfSearchActionDirectToSearch, PreferKey.bookshelfSearchActionDirectToSearch,
true true
) )
var bookshelfSearchActionDirectToSearch by _bookshelfSearchActionDirectToSearch
val bookshelfSearchActionDirectToSearchState: State<Boolean> get() = _bookshelfSearchActionDirectToSearch.state
/** /**
* 启动时自动刷新书架 * 启动时自动刷新书架
*/ */
var autoRefreshBook by prefDelegate(PreferKey.autoRefresh, false) private val _autoRefreshBook = prefStateDelegate(PreferKey.autoRefresh, false)
var autoRefreshBook by _autoRefreshBook
val autoRefreshBookState: State<Boolean> get() = _autoRefreshBook.state
/** /**
* 保存上次停留的分组Id * 保存上次停留的分组Id
*/ */
var saveTabPosition by prefDelegate(PreferKey.saveTabPosition, BookGroup.IdAll) private val _saveTabPosition = prefStateDelegate(PreferKey.saveTabPosition, BookGroup.IdAll)
var saveTabPosition by _saveTabPosition
val saveTabPositionState: State<Long> get() = _saveTabPosition.state
} }
@@ -56,6 +56,9 @@ import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTagsAsResourceId
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
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
@@ -241,7 +244,9 @@ fun MainScreen(
val haptic = LocalHapticFeedback.current val haptic = LocalHapticFeedback.current
WideNavigationRailItem( WideNavigationRailItem(
modifier = Modifier.testTag("nav_${destination.route}"), modifier = Modifier.semantics(mergeDescendants = true) {
contentDescription = "nav_${destination.route}"
},
railExpanded = navState.targetValue == WideNavigationRailValue.Expanded, railExpanded = navState.targetValue == WideNavigationRailValue.Expanded,
selected = selected, selected = selected,
onClick = { onClick = {
@@ -310,7 +315,9 @@ fun MainScreen(
MainDestination.My -> ThemeConfig.navIconMy MainDestination.My -> ThemeConfig.navIconMy
} }
AppNavigationBarItem( AppNavigationBarItem(
modifier = Modifier.testTag("nav_${destination.route}"), modifier = Modifier.semantics(mergeDescendants = true) {
contentDescription = "nav_${destination.route}"
},
selected = selected, selected = selected,
onClick = { onClick = {
coroutineScope.launch { pagerState.animateScrollToPage(index) } coroutineScope.launch { pagerState.animateScrollToPage(index) }
@@ -457,7 +464,11 @@ fun MainScreen(
pagerState.animateScrollToPage(index) pagerState.animateScrollToPage(index)
} }
}, },
modifier = Modifier.defaultMinSize(minWidth = 76.dp) modifier = Modifier
.defaultMinSize(minWidth = 76.dp)
.semantics(mergeDescendants = true) {
contentDescription = "nav_${destination.route}"
}
) { ) {
NavigationIcon( NavigationIcon(
destination = destination, destination = destination,
@@ -83,7 +83,11 @@ import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -123,6 +127,9 @@ 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.tabRow.AppTabRow import io.legado.app.ui.widget.components.tabRow.AppTabRow
import io.legado.app.ui.widget.components.text.AppText import io.legado.app.ui.widget.components.text.AppText
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.androidx.compose.koinViewModel import org.koin.androidx.compose.koinViewModel
@@ -321,32 +328,38 @@ fun BookshelfScreen(
val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
val bookshelfLayoutMode by remember { val bookshelfLayoutMode by remember {
derivedStateOf { derivedStateOf {
if (isLandscape) BookshelfConfig.bookshelfLayoutModeLandscape else BookshelfConfig.bookshelfLayoutModePortrait if (isLandscape) BookshelfConfig.bookshelfLayoutModeLandscapeState.value
else BookshelfConfig.bookshelfLayoutModePortraitState.value
} }
} }
val bookshelfLayoutGrid by remember { val bookshelfLayoutGrid by remember {
derivedStateOf { derivedStateOf {
if (isLandscape) BookshelfConfig.bookshelfLayoutGridLandscape else BookshelfConfig.bookshelfLayoutGridPortrait if (isLandscape) BookshelfConfig.bookshelfLayoutGridLandscapeState.value
else BookshelfConfig.bookshelfLayoutGridPortraitState.value
} }
} }
val bookshelfLayoutList by remember { val bookshelfLayoutList by remember {
derivedStateOf { derivedStateOf {
if (isLandscape) BookshelfConfig.bookshelfLayoutListLandscape else BookshelfConfig.bookshelfLayoutListPortrait if (isLandscape) BookshelfConfig.bookshelfLayoutListLandscapeState.value
else BookshelfConfig.bookshelfLayoutListPortraitState.value
} }
} }
val bookshelfFolderLayoutMode by remember { val bookshelfFolderLayoutMode by remember {
derivedStateOf { derivedStateOf {
if (isLandscape) BookshelfConfig.bookshelfFolderLayoutModeLandscape else BookshelfConfig.bookshelfFolderLayoutModePortrait if (isLandscape) BookshelfConfig.bookshelfFolderLayoutModeLandscapeState.value
else BookshelfConfig.bookshelfFolderLayoutModePortraitState.value
} }
} }
val bookshelfFolderLayoutGrid by remember { val bookshelfFolderLayoutGrid by remember {
derivedStateOf { derivedStateOf {
if (isLandscape) BookshelfConfig.bookshelfFolderLayoutGridLandscape else BookshelfConfig.bookshelfFolderLayoutGridPortrait if (isLandscape) BookshelfConfig.bookshelfFolderLayoutGridLandscapeState.value
else BookshelfConfig.bookshelfFolderLayoutGridPortraitState.value
} }
} }
val bookshelfFolderLayoutList by remember { val bookshelfFolderLayoutList by remember {
derivedStateOf { derivedStateOf {
if (isLandscape) BookshelfConfig.bookshelfFolderLayoutListLandscape else BookshelfConfig.bookshelfFolderLayoutListPortrait if (isLandscape) BookshelfConfig.bookshelfFolderLayoutListLandscapeState.value
else BookshelfConfig.bookshelfFolderLayoutListPortraitState.value
} }
} }
val currentMenuGroupId by remember { val currentMenuGroupId by remember {
@@ -388,7 +401,7 @@ fun BookshelfScreen(
backNavigationIcon = AppIcons.Close, backNavigationIcon = AppIcons.Close,
showSearchAction = true, showSearchAction = true,
onSearchToggle = { active -> onSearchToggle = { active ->
if (BookshelfConfig.bookshelfSearchActionDirectToSearch) { if (BookshelfConfig.bookshelfSearchActionDirectToSearchState.value) {
onNavigateToSearch(uiState.searchKey.trim()) onNavigateToSearch(uiState.searchKey.trim())
} else { } else {
viewModel.setSearchMode(active) viewModel.setSearchMode(active)
@@ -561,7 +574,8 @@ fun BookshelfScreen(
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) )
if (BookshelfConfig.shouldShowExpandButton) { val showExpandButton by BookshelfConfig.shouldShowExpandButtonState
if (showExpandButton) {
Box(modifier = Modifier) { Box(modifier = Modifier) {
SmallOutlinedIconToggleButton( SmallOutlinedIconToggleButton(
checked = showGroupMenu, checked = showGroupMenu,
@@ -716,12 +730,12 @@ fun BookshelfScreen(
), ),
verticalArrangement = Arrangement.spacedBy(if (isGridMode) 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), horizontalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp),
showFastScroll = BookshelfConfig.showBookshelfFastScroller showFastScroll = BookshelfConfig.showBookshelfFastScrollerState.value
) { ) {
itemsIndexed( itemsIndexed(
uiState.groups, uiState.groups,
key = { _, it -> it.groupId }) { index, group -> key = { _, it -> it.groupId }) { index, group ->
val countText = if (BookshelfConfig.showBookCount) { val countText = if (BookshelfConfig.showBookCountState.value) {
uiState.groupBookCounts[group.groupId]?.let { uiState.groupBookCounts[group.groupId]?.let {
stringResource(R.string.book_count, it) stringResource(R.string.book_count, it)
} }
@@ -734,11 +748,11 @@ fun BookshelfScreen(
previewBooks = uiState.groupPreviews[group.groupId] previewBooks = uiState.groupPreviews[group.groupId]
?: emptyList(), ?: emptyList(),
countText = countText, countText = countText,
isCompact = BookshelfConfig.bookshelfLayoutCompact, isCompact = BookshelfConfig.bookshelfLayoutCompactState.value,
titleSmallFont = BookshelfConfig.bookshelfTitleSmallFont, titleSmallFont = BookshelfConfig.bookshelfTitleSmallFontState.value,
titleCenter = BookshelfConfig.bookshelfTitleCenter, titleCenter = BookshelfConfig.bookshelfTitleCenterState.value,
titleMaxLines = BookshelfConfig.bookshelfTitleMaxLines, titleMaxLines = BookshelfConfig.bookshelfTitleMaxLinesState.value,
coverShadow = BookshelfConfig.bookshelfCoverShadow, coverShadow = BookshelfConfig.bookshelfCoverShadowState.value,
onClick = { onClick = {
scope.launch { pagerState.scrollToPage(index) } scope.launch { pagerState.scrollToPage(index) }
viewModel.setInFolderRoot(false) viewModel.setInFolderRoot(false)
@@ -754,11 +768,11 @@ fun BookshelfScreen(
previewBooks = uiState.groupPreviews[group.groupId] previewBooks = uiState.groupPreviews[group.groupId]
?: emptyList(), ?: emptyList(),
countText = countText, countText = countText,
gridStyle = BookshelfConfig.bookshelfGridLayout, gridStyle = BookshelfConfig.bookshelfGridLayoutState.value,
titleSmallFont = BookshelfConfig.bookshelfTitleSmallFont, titleSmallFont = BookshelfConfig.bookshelfTitleSmallFontState.value,
titleCenter = BookshelfConfig.bookshelfTitleCenter, titleCenter = BookshelfConfig.bookshelfTitleCenterState.value,
titleMaxLines = BookshelfConfig.bookshelfTitleMaxLines, titleMaxLines = BookshelfConfig.bookshelfTitleMaxLinesState.value,
coverShadow = BookshelfConfig.bookshelfCoverShadow, coverShadow = BookshelfConfig.bookshelfCoverShadowState.value,
onClick = { onClick = {
scope.launch { pagerState.scrollToPage(index) } scope.launch { pagerState.scrollToPage(index) }
viewModel.setInFolderRoot(false) viewModel.setInFolderRoot(false)
@@ -810,7 +824,7 @@ fun BookshelfScreen(
val isSelectedGroup = group.groupId == uiState.selectedGroupId val isSelectedGroup = group.groupId == uiState.selectedGroupId
val books = uiState.allGroupBooks[group.groupId] val books = uiState.allGroupBooks[group.groupId]
?: if (isSelectedGroup) uiState.items ?: if (isSelectedGroup) uiState.items
else emptyList() else persistentListOf()
val canReorderBooks = isEditMode && val canReorderBooks = isEditMode &&
!uiState.isSearch && !uiState.isSearch &&
(group.bookSort.takeIf { it >= 0 } (group.bookSort.takeIf { it >= 0 }
@@ -1155,17 +1169,17 @@ private data class BookshelfEditStickySummary(
@Composable @Composable
fun BookshelfPage( fun BookshelfPage(
paddingValues: PaddingValues, paddingValues: PaddingValues,
books: List<BookShelfItem>, books: ImmutableList<BookShelfItem>,
uiState: BookshelfUiState, uiState: BookshelfUiState,
selectedBookUrls: Set<String>, selectedBookUrls: ImmutableSet<String>,
canReorderBooks: Boolean, canReorderBooks: Boolean,
onToggleBookSelection: (BookShelfItem) -> Unit, onToggleBookSelection: (BookShelfItem) -> Unit,
draggingBooks: List<BookShelfItem>?, draggingBooks: ImmutableList<BookShelfItem>?,
pendingSavedBooks: List<BookShelfItem>?, pendingSavedBooks: ImmutableList<BookShelfItem>?,
onDragStarted: (List<BookShelfItem>) -> Unit, onDragStarted: (ImmutableList<BookShelfItem>) -> Unit,
onMoveBook: (fromIndex: Int, toIndex: Int, currentBooks: List<BookShelfItem>) -> Unit, onMoveBook: (fromIndex: Int, toIndex: Int, currentBooks: ImmutableList<BookShelfItem>) -> Unit,
onDragFinished: () -> Unit, onDragFinished: () -> Unit,
onSyncDragState: (books: List<BookShelfItem>, canReorderBooks: Boolean) -> Unit, onSyncDragState: (books: ImmutableList<BookShelfItem>, canReorderBooks: Boolean) -> Unit,
onGlobalSearch: () -> Unit, onGlobalSearch: () -> Unit,
onBookClick: (BookShelfItem) -> Unit, onBookClick: (BookShelfItem) -> Unit,
onBookLongClick: (BookShelfItem) -> Unit, onBookLongClick: (BookShelfItem) -> Unit,
@@ -1203,14 +1217,37 @@ fun BookshelfPage(
val configuration = LocalConfiguration.current val configuration = LocalConfiguration.current
val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
val bookshelfLayoutMode = val bookshelfLayoutMode by remember {
if (isLandscape) BookshelfConfig.bookshelfLayoutModeLandscape else BookshelfConfig.bookshelfLayoutModePortrait derivedStateOf {
val bookshelfLayoutGrid = if (isLandscape) BookshelfConfig.bookshelfLayoutModeLandscapeState.value
if (isLandscape) BookshelfConfig.bookshelfLayoutGridLandscape else BookshelfConfig.bookshelfLayoutGridPortrait else BookshelfConfig.bookshelfLayoutModePortraitState.value
val bookshelfLayoutList = }
if (isLandscape) BookshelfConfig.bookshelfLayoutListLandscape else BookshelfConfig.bookshelfLayoutListPortrait }
val columns = if (bookshelfLayoutMode == 0) bookshelfLayoutList else bookshelfLayoutGrid val bookshelfLayoutGrid by remember {
val isGridMode = bookshelfLayoutMode != 0 derivedStateOf {
if (isLandscape) BookshelfConfig.bookshelfLayoutGridLandscapeState.value
else BookshelfConfig.bookshelfLayoutGridPortraitState.value
}
}
val bookshelfLayoutList by remember {
derivedStateOf {
if (isLandscape) BookshelfConfig.bookshelfLayoutListLandscapeState.value
else BookshelfConfig.bookshelfLayoutListPortraitState.value
}
}
val columns by remember {
derivedStateOf {
if (bookshelfLayoutMode == 0) bookshelfLayoutList else bookshelfLayoutGrid
}
}
val isGridMode by remember { derivedStateOf { bookshelfLayoutMode != 0 } }
val bookItemGridStyle by BookshelfConfig.bookshelfGridLayoutState
val bookItemIsCompact by BookshelfConfig.bookshelfLayoutCompactState
val bookItemTitleSmallFont by BookshelfConfig.bookshelfTitleSmallFontState
val bookItemTitleCenter by BookshelfConfig.bookshelfTitleCenterState
val bookItemTitleMaxLines by BookshelfConfig.bookshelfTitleMaxLinesState
val bookItemCoverShadow by BookshelfConfig.bookshelfCoverShadowState
val showFastScroll by BookshelfConfig.showBookshelfFastScrollerState
val totalHorizontalPadding = val totalHorizontalPadding =
if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) 12.dp else 16.dp if (ThemeResolver.isMiuixEngine(LegadoTheme.composeEngine)) 12.dp else 16.dp
val gridContentHorizontalPadding = totalHorizontalPadding / 2 val gridContentHorizontalPadding = totalHorizontalPadding / 2
@@ -1247,7 +1284,7 @@ fun BookshelfPage(
state = gridState, state = gridState,
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.testTag("bookshelf_list") .semantics(mergeDescendants = true) { contentDescription = "bookshelf_list" }
.then( .then(
with(sharedTransitionScope) { with(sharedTransitionScope) {
if (this != null) Modifier.skipToLookaheadSize() else Modifier if (this != null) Modifier.skipToLookaheadSize() else Modifier
@@ -1260,7 +1297,7 @@ fun BookshelfPage(
), ),
verticalArrangement = Arrangement.spacedBy(if (isGridMode) 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), horizontalArrangement = Arrangement.spacedBy(if (isGridMode) 8.dp else 0.dp),
showFastScroll = BookshelfConfig.showBookshelfFastScroller showFastScroll = showFastScroll
) { ) {
items(displayBooks, key = { it.bookUrl }) { book -> items(displayBooks, key = { it.bookUrl }) { book ->
val isSelected = selectedBookUrls.contains(book.bookUrl) val isSelected = selectedBookUrls.contains(book.bookUrl)
@@ -1292,13 +1329,13 @@ fun BookshelfPage(
), ),
layoutMode = bookshelfLayoutMode, layoutMode = bookshelfLayoutMode,
isSelected = isSelected, isSelected = isSelected,
gridStyle = BookshelfConfig.bookshelfGridLayout, gridStyle = bookItemGridStyle,
isCompact = BookshelfConfig.bookshelfLayoutCompact, isCompact = bookItemIsCompact,
isUpdating = uiState.updatingBooks.contains(book.bookUrl), isUpdating = uiState.updatingBooks.contains(book.bookUrl),
titleSmallFont = BookshelfConfig.bookshelfTitleSmallFont, titleSmallFont = bookItemTitleSmallFont,
titleCenter = BookshelfConfig.bookshelfTitleCenter, titleCenter = bookItemTitleCenter,
titleMaxLines = BookshelfConfig.bookshelfTitleMaxLines, titleMaxLines = bookItemTitleMaxLines,
coverShadow = BookshelfConfig.bookshelfCoverShadow, coverShadow = bookItemCoverShadow,
isSearchMode = uiState.isSearch, isSearchMode = uiState.isSearch,
searchKey = uiState.searchKey, searchKey = uiState.searchKey,
sharedTransitionScope = sharedTransitionScope, sharedTransitionScope = sharedTransitionScope,
+2 -1
View File
@@ -21,7 +21,8 @@ android {
targetSdk = 37 targetSdk = 37
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "DEBUGGABLE"
}
targetProjectPath = ":app" targetProjectPath = ":app"
@@ -30,36 +30,41 @@ class BaselineProfileGenerator {
packageName = packageName, packageName = packageName,
includeInStartupProfile = true includeInStartupProfile = true
) { ) {
// 1. 启动应用
pressHome() pressHome()
startActivityAndWait() startActivityAndWait()
// 2. 等待书架加载 (我们在 BookshelfScreen 中添加了 ReportDrawnWhen) val bookshelfSelector = By.desc("bookshelf_list")
// 等待书架列表 testTag 出现 device.wait(Until.hasObject(bookshelfSelector), 10000)
device.wait(Until.hasObject(By.res(packageName, "bookshelf_list")), 10000)
// 3. 模拟滑动书架 (优化列表渲染性能) device.waitForIdle()
val bookshelf = device.findObject(By.res(packageName, "bookshelf_list")) Thread.sleep(2000)
bookshelf?.apply {
setGestureMargin(device.displayWidth / 10) val screenWidth = device.displayWidth
fling(Direction.DOWN) val screenHeight = device.displayHeight
device.waitForIdle() val startX = screenWidth / 2
fling(Direction.UP) val startY = (screenHeight * 0.75).toInt()
device.waitForIdle() val endY = (screenHeight * 0.25).toInt()
repeat(3) {
device.swipe(startX, startY, startX, endY, 25)
Thread.sleep(1000)
} }
// 4. 遍历主要 Tab (优化 Compose 导航和各页面初始化) repeat(2) {
val tabs = listOf("nav_explore", "nav_rss", "nav_my", "nav_bookshelf") device.swipe(startX, endY, startX, startY, 10)
for (tabTag in tabs) { Thread.sleep(1000)
val tab = device.findObject(By.res(packageName, tabTag)) }
// "nav_my"
/* val tabs = listOf("nav_explore", "nav_rss", "nav_bookshelf")
for (tabDesc in tabs) {
val tab = device.wait(Until.findObject(By.desc(tabDesc)), 5000)
if (tab != null) { if (tab != null) {
tab.click() val bounds = tab.visibleBounds
device.waitForIdle() device.click(bounds.centerX(), bounds.centerY())
// 稍微等待页面加载 Thread.sleep(3000)
Thread.sleep(500)
} }
} }*/
} }
} }
} }
@@ -44,21 +44,19 @@ class StartupBenchmarks {
val rule = MacrobenchmarkRule() val rule = MacrobenchmarkRule()
@Test @Test
fun startupCompilationNone() = fun startupCompilationNone() = benchmark(CompilationMode.None())
benchmark(CompilationMode.None())
@Test @Test
fun startupCompilationBaselineProfiles() = fun startupCompilationBaselineProfiles() =
benchmark(CompilationMode.Partial(BaselineProfileMode.Require)) benchmark(CompilationMode.Partial(BaselineProfileMode.Require))
private fun benchmark(compilationMode: CompilationMode) { private fun benchmark(compilationMode: CompilationMode) {
// The application id for the running build variant is read from the instrumentation arguments.
val packageName = InstrumentationRegistry.getArguments().getString("targetAppId") val packageName = InstrumentationRegistry.getArguments().getString("targetAppId")
?: "io.legado.app" ?: "io.legado.app"
rule.measureRepeated( rule.measureRepeated(
packageName = packageName, packageName = packageName,
metrics = listOf(StartupTimingMetric(), FrameTimingMetric()), metrics = listOf(StartupTimingMetric()),
compilationMode = compilationMode, compilationMode = compilationMode,
startupMode = StartupMode.COLD, startupMode = StartupMode.COLD,
iterations = 3, iterations = 3,
@@ -67,18 +65,6 @@ class StartupBenchmarks {
}, },
measureBlock = { measureBlock = {
startActivityAndWait() startActivityAndWait()
// 等待书架列表加载完成
// 我们在 BookshelfScreen 中添加了 testTag("bookshelf_list")
device.wait(Until.hasObject(By.res(packageName, "bookshelf_list")), 10000)
// 模拟交互:在书架上进行滑动,以确保 Profile 捕获到列表渲染和图片加载的路径
val bookshelfList = device.findObject(By.res(packageName, "bookshelf_list"))
bookshelfList?.apply {
setGestureMargin(device.displayWidth / 10)
fling(Direction.DOWN)
device.waitForIdle()
}
} }
) )
} }
+7 -7
View File
@@ -5,14 +5,14 @@ adaptive = "1.3.0-beta01"
adaptiveLayout = "1.3.0-beta01" adaptiveLayout = "1.3.0-beta01"
adaptiveNavigation = "1.3.0-beta01" adaptiveNavigation = "1.3.0-beta01"
animation = "1.11.1" animation = "1.11.1"
biometric = "1.4.0-alpha06" biometric = "1.4.0-alpha07"
coilCompose = "2.7.0" coilCompose = "2.7.0"
composeBom = "2026.05.00" composeBom = "2026.05.00"
constraintlayoutCompose = "1.1.1" constraintlayoutCompose = "1.1.1"
coreSplashscreen = "1.2.0" coreSplashscreen = "1.2.0"
datastorePreferences = "1.2.1" datastorePreferences = "1.2.1"
foundation = "1.11.1" foundation = "1.11.1"
kotlin = "2.3.10" kotlin = "2.3.21"
kotlinxSerialization = "1.11.0" kotlinxSerialization = "1.11.0"
kotlinxCoroutinesAndroid = "1.10.2" kotlinxCoroutinesAndroid = "1.10.2"
kotlinxSerializationJson = "1.11.0" kotlinxSerializationJson = "1.11.0"
@@ -35,8 +35,8 @@ hutool = "5.8.22"
libarchive = "1.1.6" libarchive = "1.1.6"
lifecycle = "2.10.0" lifecycle = "2.10.0"
glide = "5.0.7" glide = "5.0.7"
gson = "2.13.2" gson = "2.14.0"
jsonPath = "2.10.0" jsonPath = "3.0.0"
# issue #3811,不要更新版本,新版引入了一个破坏性变更(详见https://github.com/jhy/jsoup/pull/2017 # issue #3811,不要更新版本,新版引入了一个破坏性变更(详见https://github.com/jhy/jsoup/pull/2017
# 若要升级请确保相关代码不会受此变更影响(如AnalyzeByJSoup.kt、JsoupXpath库等) # 若要升级请确保相关代码不会受此变更影响(如AnalyzeByJSoup.kt、JsoupXpath库等)
jsoup = "1.16.2" jsoup = "1.16.2"
@@ -51,7 +51,7 @@ material = "1.14.0-rc01"
material3 = "1.5.0-alpha19" material3 = "1.5.0-alpha19"
material3IconsExtended = "1.7.8" material3IconsExtended = "1.7.8"
materialKolor = "4.1.1" materialKolor = "4.1.1"
media = "1.7.1" media = "1.8.0"
media3 = "1.8.0" media3 = "1.8.0"
nanoHttpd = "2.3.1" nanoHttpd = "2.3.1"
navigationCompose = "2.9.8" navigationCompose = "2.9.8"
@@ -62,7 +62,7 @@ protobufJavalite = "4.26.1"
quickChineseTransfer = "0.2.16" quickChineseTransfer = "0.2.16"
room = "2.8.4" room = "2.8.4"
splitties = "3.0.0" splitties = "3.0.0"
rhino = "1.8.1" rhino = "1.9.1"
desugar = "2.1.5" desugar = "2.1.5"
activity = "1.13.0" activity = "1.13.0"
@@ -77,7 +77,7 @@ viewpager2 = "1.1.0"
webkit = "1.16.0" webkit = "1.16.0"
collection = "1.6.0" collection = "1.6.0"
zxingLite = "3.3.0" zxingLite = "3.4.1"
koin-bom = "4.2.1" koin-bom = "4.2.1"
biometricKtx = "1.1.0" biometricKtx = "1.1.0"
@@ -2,9 +2,10 @@ package com.script.rhino
import org.mozilla.javascript.NativeJavaObject import org.mozilla.javascript.NativeJavaObject
import org.mozilla.javascript.Scriptable import org.mozilla.javascript.Scriptable
import org.mozilla.javascript.lc.type.TypeInfoFactory
class ReadOnlyJavaObject(scope: Scriptable?, javaObject: Any, staticType: Class<*>?) : class ReadOnlyJavaObject(scope: Scriptable?, javaObject: Any, staticType: Class<*>?) :
NativeJavaObject(scope, javaObject, staticType) { NativeJavaObject(scope, javaObject, staticType?.let { TypeInfoFactory.GLOBAL.create(it) }) {
override fun has(name: String, start: Scriptable): Boolean { override fun has(name: String, start: Scriptable): Boolean {
if (name.length > 3 && name.startsWith("set")) { if (name.length > 3 && name.startsWith("set")) {
@@ -1,20 +1,31 @@
package com.script.rhino package com.script.rhino
import org.mozilla.javascript.VMBridge import org.mozilla.javascript.Context
import org.mozilla.javascript.ContextFactory
object VMBridgeReflect { object VMBridgeReflect {
val instance: VMBridge by lazy {
VMBridge::class.java.getDeclaredField("instance").apply {
isAccessible = true
}.get(null) as VMBridge
}
val contextLocal: ThreadLocal<Any> by lazy { val contextLocal: ThreadLocal<Any> by lazy {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
instance::class.java.getDeclaredField("contextLocal").apply { try {
isAccessible = true // Rhino 1.9.1+ uses threadContextLocal directly in Context class
}.get(null) as ThreadLocal<Any> val field = Context::class.java.getDeclaredField("threadContextLocal")
field.isAccessible = true
field.get(null) as ThreadLocal<Any>
} catch (e: Exception) {
try {
// Fallback for some versions or custom builds
val factory = ContextFactory.getGlobal()
val field = ContextFactory::class.java.getDeclaredField("localContext")
field.isAccessible = true
field.get(factory) as ThreadLocal<Any>
} catch (e2: Exception) {
// Older versions used threadContextHelper (Object) which held a ThreadLocal
val field = Context::class.java.getDeclaredField("threadContextHelper")
field.isAccessible = true
field.get(null) as ThreadLocal<Any>
}
}
} }
} }
+1
View File
@@ -54,3 +54,4 @@ include ':app'
include ':modules:book' include ':modules:book'
include ':modules:rhino' include ':modules:rhino'
include ':baselineprofile' include ':baselineprofile'
project(':baselineprofile').projectDir = file('baselineProfile')