[优化] 一些主题优化
This commit is contained in:
@@ -10,7 +10,6 @@ import android.content.res.Configuration
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Build
|
||||
import androidx.core.graphics.scale
|
||||
import coil.ImageLoader
|
||||
import com.github.liuyueyi.quick.transfer.constants.TransType
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import com.google.android.material.color.DynamicColorsOptions
|
||||
@@ -44,9 +43,9 @@ import io.legado.app.help.LifecycleHelp
|
||||
import io.legado.app.help.RuleBigDataHelp
|
||||
import io.legado.app.help.book.BookHelp
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.config.OldThemeConfig
|
||||
import io.legado.app.help.config.OldThemeConfig.applyDayNightInit
|
||||
import io.legado.app.help.config.ReadBookConfig
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.help.config.ThemeConfig.applyDayNightInit
|
||||
import io.legado.app.help.coroutine.Coroutine
|
||||
import io.legado.app.help.http.Cronet
|
||||
import io.legado.app.help.http.ObsoleteUrlFactory
|
||||
@@ -155,7 +154,7 @@ class App : Application() {
|
||||
BookHelp.clearInvalidCache()
|
||||
Backup.clearCache()
|
||||
ReadBookConfig.clearBgAndCache()
|
||||
ThemeConfig.clearBg()
|
||||
OldThemeConfig.clearBg()
|
||||
//初始化简繁转换引擎
|
||||
when (AppConfig.chineseConverterType) {
|
||||
1 -> {
|
||||
|
||||
@@ -27,9 +27,8 @@ import io.legado.app.constant.EventBus
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.constant.Theme
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.help.config.OldThemeConfig
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.ui.theme.ThemeSyncer
|
||||
import io.legado.app.utils.applyOpenTint
|
||||
import io.legado.app.utils.applyTint
|
||||
import io.legado.app.utils.disableAutoFill
|
||||
@@ -232,7 +231,7 @@ abstract class BaseActivity<VB : ViewBinding>(
|
||||
open fun upBackgroundImage() {
|
||||
if (imageBg) {
|
||||
try {
|
||||
ThemeConfig.getBgImage(this, windowManager.windowSize)?.let {
|
||||
OldThemeConfig.getBgImage(this, windowManager.windowSize)?.let {
|
||||
window.decorView.background = it.toDrawable(resources)
|
||||
}
|
||||
} catch (e: OutOfMemoryError) {
|
||||
@@ -245,7 +244,6 @@ abstract class BaseActivity<VB : ViewBinding>(
|
||||
|
||||
open fun observeLiveBus() {
|
||||
observeEvent<String>(EventBus.RECREATE) {
|
||||
ThemeSyncer.syncAll()
|
||||
recreate()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,8 @@ import androidx.core.graphics.drawable.toDrawable
|
||||
import androidx.core.view.WindowCompat
|
||||
import io.legado.app.constant.EventBus
|
||||
import io.legado.app.constant.Theme
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.help.config.OldThemeConfig
|
||||
import io.legado.app.ui.theme.AppTheme
|
||||
import io.legado.app.ui.theme.ThemeSyncer
|
||||
import io.legado.app.utils.disableAutoFill
|
||||
import io.legado.app.utils.fullScreen
|
||||
import io.legado.app.utils.observeEvent
|
||||
@@ -66,7 +65,7 @@ abstract class BaseComposeActivity(
|
||||
|
||||
open fun upBackgroundImage() {
|
||||
try {
|
||||
ThemeConfig.getBgImage(this, windowManager.windowSize)?.let {
|
||||
OldThemeConfig.getBgImage(this, windowManager.windowSize)?.let {
|
||||
window.setBackgroundDrawable(it.toDrawable(resources))
|
||||
}
|
||||
} catch (_: Exception) {}
|
||||
@@ -74,7 +73,6 @@ abstract class BaseComposeActivity(
|
||||
|
||||
open fun observeLiveBus() {
|
||||
observeEvent<String>(EventBus.RECREATE) {
|
||||
ThemeSyncer.syncAll()
|
||||
recreate()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,6 +181,7 @@ object PreferKey {
|
||||
const val composeEngine = "composeEngine"
|
||||
const val containerOpacity = "containerOpacity"
|
||||
const val enableBlur = "enableBlur"
|
||||
const val enableProgressiveBlur = "enableProgressiveBlur"
|
||||
const val cBackground = "colorBackground"
|
||||
const val cBBackground = "colorBottomBackground"
|
||||
const val bgImage = "backgroundImage"
|
||||
|
||||
@@ -8,8 +8,8 @@ import io.legado.app.data.entities.KeyboardAssist
|
||||
import io.legado.app.data.entities.RssSource
|
||||
import io.legado.app.data.entities.TxtTocRule
|
||||
import io.legado.app.help.config.LocalConfig
|
||||
import io.legado.app.help.config.OldThemeConfig
|
||||
import io.legado.app.help.config.ReadBookConfig
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.help.coroutine.Coroutine
|
||||
import io.legado.app.model.BookCover
|
||||
import io.legado.app.utils.GSON
|
||||
@@ -70,12 +70,12 @@ object DefaultData {
|
||||
GSON.fromJsonArray<TxtTocRule>(json).getOrNull() ?: emptyList()
|
||||
}
|
||||
|
||||
val themeConfigs: List<ThemeConfig.Config> by lazy {
|
||||
val themeConfigs: List<OldThemeConfig.Config> by lazy {
|
||||
val json = String(
|
||||
appCtx.assets.open("defaultData${File.separator}${ThemeConfig.configFileName}")
|
||||
appCtx.assets.open("defaultData${File.separator}${OldThemeConfig.configFileName}")
|
||||
.readBytes()
|
||||
)
|
||||
GSON.fromJsonArray<ThemeConfig.Config>(json).getOrNull() ?: emptyList()
|
||||
GSON.fromJsonArray<OldThemeConfig.Config>(json).getOrNull() ?: emptyList()
|
||||
}
|
||||
|
||||
val rssSources: List<RssSource> by lazy {
|
||||
|
||||
@@ -15,8 +15,8 @@ import io.legado.app.constant.AppPattern
|
||||
import io.legado.app.data.entities.BaseSource
|
||||
import io.legado.app.exception.NoStackTraceException
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.config.OldThemeConfig
|
||||
import io.legado.app.help.config.ReadBookConfig
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.help.http.BackstageWebView
|
||||
import io.legado.app.help.http.CookieManager.cookieJarHeader
|
||||
import io.legado.app.help.http.CookieStore
|
||||
@@ -1203,12 +1203,12 @@ interface JsExtensions : JsEncodeUtils {
|
||||
*/
|
||||
@JavascriptInterface
|
||||
fun getThemeConfig(): String {
|
||||
val themeConfig = ThemeConfig.getDurConfig(appCtx)
|
||||
val themeConfig = OldThemeConfig.getDurConfig(appCtx)
|
||||
return GSON.toJson(themeConfig)
|
||||
}
|
||||
|
||||
fun getThemeConfigMap(): Map<String, Any?> {
|
||||
return ThemeConfig.getDurConfig(appCtx).toMap()
|
||||
return OldThemeConfig.getDurConfig(appCtx).toMap()
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -32,7 +32,7 @@ import splitties.init.appCtx
|
||||
import java.io.File
|
||||
|
||||
@Keep
|
||||
object ThemeConfig {
|
||||
object OldThemeConfig {
|
||||
const val configFileName = "themeConfig.json"
|
||||
val configFilePath = FileUtils.getPath(appCtx.filesDir, configFileName)
|
||||
|
||||
@@ -13,8 +13,8 @@ import io.legado.app.help.AppWebDav
|
||||
import io.legado.app.help.DirectLinkUpload
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.config.LocalConfig
|
||||
import io.legado.app.help.config.OldThemeConfig
|
||||
import io.legado.app.help.config.ReadBookConfig
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.help.coroutine.Coroutine
|
||||
import io.legado.app.model.BookCover
|
||||
import io.legado.app.utils.FileUtils
|
||||
@@ -82,7 +82,7 @@ object Backup {
|
||||
DirectLinkUpload.ruleFileName,
|
||||
ReadBookConfig.configFileName,
|
||||
ReadBookConfig.shareConfigFileName,
|
||||
ThemeConfig.configFileName,
|
||||
OldThemeConfig.configFileName,
|
||||
BookCover.configFileName,
|
||||
"config.xml"
|
||||
)
|
||||
@@ -169,8 +169,8 @@ object Backup {
|
||||
FileUtils.createFileIfNotExist(backupPath + File.separator + ReadBookConfig.shareConfigFileName)
|
||||
.writeText(it)
|
||||
}
|
||||
GSON.toJson(ThemeConfig.configList).let {
|
||||
FileUtils.createFileIfNotExist(backupPath + File.separator + ThemeConfig.configFileName)
|
||||
GSON.toJson(OldThemeConfig.configList).let {
|
||||
FileUtils.createFileIfNotExist(backupPath + File.separator + OldThemeConfig.configFileName)
|
||||
.writeText(it)
|
||||
}
|
||||
DirectLinkUpload.getConfig()?.let {
|
||||
|
||||
@@ -33,8 +33,8 @@ import io.legado.app.help.LauncherIconHelp
|
||||
import io.legado.app.help.book.isLocal
|
||||
import io.legado.app.help.book.upType
|
||||
import io.legado.app.help.config.LocalConfig
|
||||
import io.legado.app.help.config.OldThemeConfig
|
||||
import io.legado.app.help.config.ReadBookConfig
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.model.BookCover
|
||||
import io.legado.app.model.localBook.LocalBook
|
||||
import io.legado.app.utils.ACache
|
||||
@@ -216,12 +216,12 @@ object Restore {
|
||||
AppLog.put("恢复直链上传出错\n${it.localizedMessage}", it)
|
||||
}
|
||||
//恢复主题配置
|
||||
File(path, ThemeConfig.configFileName).takeIf {
|
||||
File(path, OldThemeConfig.configFileName).takeIf {
|
||||
it.exists()
|
||||
}?.runCatching {
|
||||
FileUtils.delete(ThemeConfig.configFilePath)
|
||||
copyTo(File(ThemeConfig.configFilePath))
|
||||
ThemeConfig.upConfig()
|
||||
FileUtils.delete(OldThemeConfig.configFilePath)
|
||||
copyTo(File(OldThemeConfig.configFilePath))
|
||||
OldThemeConfig.upConfig()
|
||||
}?.onFailure {
|
||||
AppLog.put("恢复主题出错\n${it.localizedMessage}", it)
|
||||
}
|
||||
@@ -301,7 +301,7 @@ object Restore {
|
||||
if (!BuildConfig.DEBUG) {
|
||||
LauncherIconHelp.changeIcon(appCtx.getPrefString(PreferKey.launcherIcon))
|
||||
}
|
||||
ThemeConfig.applyDayNight(appCtx)
|
||||
OldThemeConfig.applyDayNight(appCtx)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import io.legado.app.constant.EventBus
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
import io.legado.app.ui.theme.ThemeSyncer
|
||||
import io.legado.app.ui.config.themeConfig.ThemeConfig
|
||||
import io.legado.app.utils.getPrefString
|
||||
import io.legado.app.utils.postEvent
|
||||
import io.legado.app.utils.restart
|
||||
@@ -91,13 +91,13 @@ class ThemeCardPreference(context: Context, attrs: AttributeSet) : Preference(co
|
||||
return@setOnClickListener
|
||||
} else {
|
||||
AppConfig.containerOpacity = 0
|
||||
ThemeSyncer.syncContainerOpacity()
|
||||
}
|
||||
}
|
||||
val oldValue = currentValue
|
||||
currentValue = value
|
||||
persistString(value)
|
||||
callChangeListener(value)
|
||||
ThemeConfig.appTheme = value
|
||||
notifyDataSetChanged()
|
||||
val isDynamicSwitch = (oldValue == "12" || value == "12")
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
|
||||
@@ -7,7 +7,7 @@ import android.util.AttributeSet
|
||||
import androidx.preference.PreferenceViewHolder
|
||||
import com.google.android.material.button.MaterialButtonToggleGroup
|
||||
import io.legado.app.R
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.help.config.OldThemeConfig
|
||||
|
||||
|
||||
class ThemeModePreference(context: Context, attrs: AttributeSet) : Preference(context, attrs) {
|
||||
@@ -59,7 +59,7 @@ class ThemeModePreference(context: Context, attrs: AttributeSet) : Preference(co
|
||||
persistString(newValue)
|
||||
callChangeListener(newValue)
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
ThemeConfig.applyDayNight(context)
|
||||
OldThemeConfig.applyDayNight(context)
|
||||
}, 300)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ import io.legado.app.R
|
||||
import io.legado.app.constant.AppConst.appInfo
|
||||
import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
|
||||
import io.legado.app.ui.widget.components.SplicedColumnGroup
|
||||
import io.legado.app.ui.widget.components.button.SmallTopBarButton
|
||||
import io.legado.app.ui.widget.components.button.TopbarNavigationButton
|
||||
import io.legado.app.ui.widget.components.card.TextCard
|
||||
import io.legado.app.ui.widget.components.settingItem.SettingItem
|
||||
|
||||
@@ -61,7 +61,7 @@ fun AboutScreen(
|
||||
GlassMediumFlexibleTopAppBar(
|
||||
title = { Text(stringResource(R.string.about)) },
|
||||
navigationIcon = {
|
||||
SmallTopBarButton(onClick = onBack)
|
||||
TopbarNavigationButton(onClick = onBack)
|
||||
},
|
||||
scrollBehavior = scrollBehavior
|
||||
)
|
||||
|
||||
@@ -14,7 +14,7 @@ import io.legado.app.base.adapter.ItemViewHolder
|
||||
import io.legado.app.base.adapter.RecyclerAdapter
|
||||
import io.legado.app.databinding.DialogRecyclerViewBinding
|
||||
import io.legado.app.databinding.ItemSourceImportBinding
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.help.config.OldThemeConfig
|
||||
//import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.ui.widget.dialog.CodeDialog
|
||||
import io.legado.app.ui.widget.dialog.WaitDialog
|
||||
@@ -126,7 +126,7 @@ class ImportThemeDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_recycl
|
||||
}
|
||||
|
||||
inner class SourcesAdapter(context: Context) :
|
||||
RecyclerAdapter<ThemeConfig.Config, ItemSourceImportBinding>(context) {
|
||||
RecyclerAdapter<OldThemeConfig.Config, ItemSourceImportBinding>(context) {
|
||||
|
||||
override fun getViewBinding(parent: ViewGroup): ItemSourceImportBinding {
|
||||
return ItemSourceImportBinding.inflate(inflater, parent, false)
|
||||
@@ -135,7 +135,7 @@ class ImportThemeDialog() : BaseBottomSheetDialogFragment(R.layout.dialog_recycl
|
||||
override fun convert(
|
||||
holder: ItemViewHolder,
|
||||
binding: ItemSourceImportBinding,
|
||||
item: ThemeConfig.Config,
|
||||
item: OldThemeConfig.Config,
|
||||
payloads: MutableList<Any>
|
||||
) {
|
||||
binding.apply {
|
||||
|
||||
@@ -8,12 +8,19 @@ import io.legado.app.base.BaseViewModel
|
||||
import io.legado.app.constant.AppConst
|
||||
import io.legado.app.constant.AppLog
|
||||
import io.legado.app.exception.NoStackTraceException
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.help.config.OldThemeConfig
|
||||
import io.legado.app.help.http.decompressed
|
||||
import io.legado.app.help.http.newCallResponseBody
|
||||
import io.legado.app.help.http.okHttpClient
|
||||
import io.legado.app.help.http.text
|
||||
import io.legado.app.utils.*
|
||||
import io.legado.app.utils.GSON
|
||||
import io.legado.app.utils.fromJsonArray
|
||||
import io.legado.app.utils.fromJsonObject
|
||||
import io.legado.app.utils.isAbsUrl
|
||||
import io.legado.app.utils.isJsonArray
|
||||
import io.legado.app.utils.isJsonObject
|
||||
import io.legado.app.utils.isUri
|
||||
import io.legado.app.utils.readText
|
||||
import splitties.init.appCtx
|
||||
|
||||
class ImportThemeViewModel(app: Application) : BaseViewModel(app) {
|
||||
@@ -21,8 +28,8 @@ class ImportThemeViewModel(app: Application) : BaseViewModel(app) {
|
||||
val errorLiveData = MutableLiveData<String>()
|
||||
val successLiveData = MutableLiveData<Int>()
|
||||
|
||||
val allSources = arrayListOf<ThemeConfig.Config>()
|
||||
val checkSources = arrayListOf<ThemeConfig.Config?>()
|
||||
val allSources = arrayListOf<OldThemeConfig.Config>()
|
||||
val checkSources = arrayListOf<OldThemeConfig.Config?>()
|
||||
val selectStatus = arrayListOf<Boolean>()
|
||||
|
||||
val isSelectAll: Boolean
|
||||
@@ -50,7 +57,7 @@ class ImportThemeViewModel(app: Application) : BaseViewModel(app) {
|
||||
execute {
|
||||
selectStatus.forEachIndexed { index, b ->
|
||||
if (b) {
|
||||
ThemeConfig.addConfig(allSources[index])
|
||||
OldThemeConfig.addConfig(allSources[index])
|
||||
}
|
||||
}
|
||||
}.onFinally {
|
||||
@@ -72,11 +79,12 @@ class ImportThemeViewModel(app: Application) : BaseViewModel(app) {
|
||||
private suspend fun importSourceAwait(text: String) {
|
||||
when {
|
||||
text.isJsonObject() -> {
|
||||
GSON.fromJsonObject<ThemeConfig.Config>(text).getOrThrow().let {
|
||||
GSON.fromJsonObject<OldThemeConfig.Config>(text).getOrThrow().let {
|
||||
allSources.add(it)
|
||||
}
|
||||
}
|
||||
text.isJsonArray() -> GSON.fromJsonArray<ThemeConfig.Config>(text).getOrThrow()
|
||||
|
||||
text.isJsonArray() -> GSON.fromJsonArray<OldThemeConfig.Config>(text).getOrThrow()
|
||||
.let { items ->
|
||||
allSources.addAll(items)
|
||||
}
|
||||
@@ -106,7 +114,7 @@ class ImportThemeViewModel(app: Application) : BaseViewModel(app) {
|
||||
private fun comparisonSource() {
|
||||
execute {
|
||||
allSources.forEach { config ->
|
||||
val source = ThemeConfig.configList.find {
|
||||
val source = OldThemeConfig.configList.find {
|
||||
it.themeName == config.themeName
|
||||
}
|
||||
checkSources.add(source)
|
||||
|
||||
@@ -22,8 +22,6 @@ import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.filled.UnfoldLess
|
||||
import androidx.compose.material.icons.filled.UnfoldMore
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.Icon
|
||||
@@ -48,9 +46,11 @@ import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
|
||||
import io.legado.app.ui.widget.components.SearchBarSection
|
||||
import io.legado.app.ui.widget.components.bookmark.BookmarkEditSheet
|
||||
import io.legado.app.ui.widget.components.bookmark.BookmarkItem
|
||||
import io.legado.app.ui.widget.components.button.SmallTopBarButton
|
||||
import io.legado.app.ui.widget.components.button.TopbarNavigationButton
|
||||
import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
|
||||
import io.legado.app.ui.widget.components.lazylist.Scroller
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class,
|
||||
@@ -105,7 +105,7 @@ fun AllBookmarkScreen(
|
||||
},
|
||||
scrollBehavior = scrollBehavior,
|
||||
navigationIcon = {
|
||||
SmallTopBarButton(onClick = onBack)
|
||||
TopbarNavigationButton(onClick = onBack)
|
||||
},
|
||||
actions = {
|
||||
if (bookmarksGrouped.isNotEmpty()) {
|
||||
@@ -127,11 +127,11 @@ fun AllBookmarkScreen(
|
||||
IconButton(onClick = { showMenu = true }) {
|
||||
Icon(Icons.Default.MoreVert, contentDescription = "Menu")
|
||||
}
|
||||
DropdownMenu(
|
||||
RoundDropdownMenu(
|
||||
expanded = showMenu,
|
||||
onDismissRequest = { showMenu = false }
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
RoundDropdownMenuItem(
|
||||
text = { Text("导出 JSON") },
|
||||
onClick = {
|
||||
showMenu = false
|
||||
@@ -139,7 +139,7 @@ fun AllBookmarkScreen(
|
||||
exportLauncher.launch(null)
|
||||
}
|
||||
)
|
||||
DropdownMenuItem(
|
||||
RoundDropdownMenuItem(
|
||||
text = { Text("导出 Markdown") },
|
||||
onClick = {
|
||||
showMenu = false
|
||||
|
||||
@@ -53,6 +53,7 @@ class ExploreShowViewModel(
|
||||
private val _rawBooks = MutableStateFlow<List<SearchBook>>(emptyList())
|
||||
private val _filterState = MutableStateFlow(BookFilterState.fromId(AppConfig.exploreFilterState))
|
||||
private val _isLoading = MutableStateFlow(false)
|
||||
private val _isRefreshing = MutableStateFlow(false)
|
||||
private val _errorMsg = MutableStateFlow<String?>(null)
|
||||
private var bookSource: BookSource? = null
|
||||
private var exploreUrl: String? = null
|
||||
@@ -68,10 +69,14 @@ class ExploreShowViewModel(
|
||||
private val _gridCount = MutableStateFlow(appCtx.exploreLayoutGrid)
|
||||
val gridCount = _gridCount.asStateFlow()
|
||||
val isEnd: StateFlow<Boolean> = _isEndStateFlow.asStateFlow()
|
||||
|
||||
val isRefreshing = _isRefreshing.asStateFlow()
|
||||
|
||||
fun saveGridCount(value: Int) {
|
||||
appCtx.exploreLayoutGrid = value
|
||||
_gridCount.value = value
|
||||
}
|
||||
|
||||
val uiBooks = combine(
|
||||
_rawBooks,
|
||||
_filterState,
|
||||
|
||||
@@ -50,8 +50,8 @@ import io.legado.app.R
|
||||
import io.legado.app.ui.book.changecover.ChangeCoverDialog
|
||||
import io.legado.app.ui.widget.components.Cover
|
||||
import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
|
||||
import io.legado.app.ui.widget.components.button.SmallTopBarButton
|
||||
import io.legado.app.ui.widget.components.button.TopBarButtonVariant
|
||||
import io.legado.app.ui.widget.components.button.TopbarNavigationButton
|
||||
import io.legado.app.utils.SelectImageContract
|
||||
import io.legado.app.utils.launch
|
||||
import io.legado.app.utils.showDialogFragment
|
||||
@@ -72,13 +72,13 @@ fun BookInfoEditScreen(
|
||||
GlassMediumFlexibleTopAppBar(
|
||||
title = { Text(text = stringResource(id = R.string.book_info_edit)) },
|
||||
navigationIcon = {
|
||||
SmallTopBarButton(
|
||||
TopbarNavigationButton(
|
||||
onClick = onBack,
|
||||
style = TopBarButtonVariant.Outlined
|
||||
)
|
||||
},
|
||||
actions = {
|
||||
SmallTopBarButton(
|
||||
TopbarNavigationButton(
|
||||
onClick = { viewModel.save(onSave) },
|
||||
imageVector = Icons.Default.Save
|
||||
)
|
||||
|
||||
@@ -33,8 +33,8 @@ import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.databinding.ViewReadMenuBinding
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.config.LocalConfig
|
||||
import io.legado.app.help.config.OldThemeConfig
|
||||
import io.legado.app.help.config.ReadBookConfig
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.help.coroutine.Coroutine
|
||||
import io.legado.app.help.source.getSourceType
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
@@ -693,7 +693,7 @@ class ReadMenu @JvmOverloads constructor(
|
||||
description = context.getString(R.string.day_night_switch),
|
||||
onClick = {
|
||||
AppConfig.isNightTheme = !AppConfig.isNightTheme
|
||||
ThemeConfig.applyDayNight(context)
|
||||
OldThemeConfig.applyDayNight(context)
|
||||
buttonMap["theme"]?.setIconResource(
|
||||
if (AppConfig.isNightTheme) R.drawable.ic_daytime else R.drawable.ic_brightness
|
||||
)
|
||||
|
||||
@@ -15,8 +15,8 @@ import io.legado.app.constant.EventBus
|
||||
import io.legado.app.databinding.DialogReadBookStyleBinding
|
||||
import io.legado.app.databinding.ItemReadStyleBinding
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.config.OldThemeConfig
|
||||
import io.legado.app.help.config.ReadBookConfig
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
import io.legado.app.model.ReadBook
|
||||
import io.legado.app.ui.book.read.ReadBookActivity
|
||||
@@ -121,7 +121,7 @@ class ReadStyleDialog : BaseBottomSheetDialogFragment(R.layout.dialog_read_book_
|
||||
}
|
||||
tvDayNight.setOnClickListener {
|
||||
AppConfig.isNightTheme = !AppConfig.isNightTheme
|
||||
ThemeConfig.applyDayNight(requireContext())
|
||||
OldThemeConfig.applyDayNight(requireContext())
|
||||
}
|
||||
// rgPageAnim.setOnCheckedChangeListener { _, checkedId ->
|
||||
// ReadBook.book?.setPageAnim(-1)
|
||||
|
||||
@@ -47,6 +47,7 @@ import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
@@ -87,7 +88,7 @@ import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
|
||||
import io.legado.app.ui.widget.components.SearchBarSection
|
||||
import io.legado.app.ui.widget.components.SectionHeader
|
||||
import io.legado.app.ui.widget.components.button.AlertButton
|
||||
import io.legado.app.ui.widget.components.button.SmallTopBarButton
|
||||
import io.legado.app.ui.widget.components.button.TopbarNavigationButton
|
||||
import io.legado.app.ui.widget.components.heatmap.HeatmapCalendarTopBar
|
||||
import io.legado.app.ui.widget.components.heatmap.HeatmapConfig
|
||||
import io.legado.app.ui.widget.components.heatmap.HeatmapLegend
|
||||
@@ -98,6 +99,7 @@ import io.legado.app.ui.widget.components.heatmap.WeekdayLabelsColumn
|
||||
import io.legado.app.ui.widget.components.heatmap.rememberDateRange
|
||||
import io.legado.app.ui.widget.components.heatmap.rememberDaysInRange
|
||||
import io.legado.app.ui.widget.components.heatmap.rememberWeeks
|
||||
import io.legado.app.ui.widget.components.modalBottomSheet.GlassModalBottomSheet
|
||||
import io.legado.app.ui.widget.components.swipe.SwipeAction
|
||||
import io.legado.app.ui.widget.components.swipe.SwipeActionContainer
|
||||
import io.legado.app.utils.StringUtils.formatFriendlyDate
|
||||
@@ -163,7 +165,7 @@ fun ReadRecordScreen(
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
SmallTopBarButton(onClick = onBackClick)
|
||||
TopbarNavigationButton(onClick = onBackClick)
|
||||
},
|
||||
actions = {
|
||||
IconButton(onClick = {
|
||||
@@ -318,8 +320,8 @@ fun ReadRecordScreen(
|
||||
|
||||
if (showCalendar) {
|
||||
val sheetState =
|
||||
androidx.compose.material3.rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
androidx.compose.material3.ModalBottomSheet(
|
||||
rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
GlassModalBottomSheet(
|
||||
onDismissRequest = { showCalendar = false },
|
||||
sheetState = sheetState
|
||||
) {
|
||||
|
||||
@@ -58,7 +58,7 @@ import io.legado.app.ui.widget.components.EmptyMessageView
|
||||
import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
|
||||
import io.legado.app.ui.widget.components.SearchBarSection
|
||||
import io.legado.app.ui.widget.components.button.AnimatedActionButton
|
||||
import io.legado.app.ui.widget.components.button.SmallTopBarButton
|
||||
import io.legado.app.ui.widget.components.button.TopbarNavigationButton
|
||||
import io.legado.app.ui.widget.components.card.TextCard
|
||||
import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
@@ -141,7 +141,7 @@ fun SearchContentScreen(
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
SmallTopBarButton(onClick = onBack)
|
||||
TopbarNavigationButton(onClick = onBack)
|
||||
},
|
||||
actions = {
|
||||
Row(
|
||||
|
||||
@@ -294,33 +294,33 @@ fun TocScreen(
|
||||
when (pagerState.currentPage) {
|
||||
0 -> {
|
||||
RoundDropdownMenuItem(
|
||||
text = "使用替换规则",
|
||||
text = { Text("使用替换规则") },
|
||||
trailingIcon = {
|
||||
Checkbox(checked = useReplace, onCheckedChange = null)
|
||||
},
|
||||
onClick = { viewModel.toggleUseReplace() }
|
||||
)
|
||||
RoundDropdownMenuItem(
|
||||
text = "显示字数",
|
||||
text = { Text("显示字数") },
|
||||
trailingIcon = {
|
||||
Checkbox(checked = showWordCount, onCheckedChange = null)
|
||||
},
|
||||
onClick = { viewModel.toggleShowWordCount() }
|
||||
)
|
||||
RoundDropdownMenuItem(
|
||||
text = "反转目录",
|
||||
text = { Text("反转目录") },
|
||||
onClick = { viewModel.reverseToc() }
|
||||
)
|
||||
PillDivider()
|
||||
RoundDropdownMenuItem(
|
||||
text = "替换规则",
|
||||
text = { Text("替换规则") },
|
||||
onClick = {
|
||||
onOpenReplaceRule(null)
|
||||
dismiss()
|
||||
}
|
||||
)
|
||||
RoundDropdownMenuItem(
|
||||
text = "新建替换规则",
|
||||
text = { Text("新建替换规则") },
|
||||
onClick = {
|
||||
val scopes = mutableListOf<String>()
|
||||
book?.name?.let { scopes.add(it) }
|
||||
@@ -340,7 +340,7 @@ fun TocScreen(
|
||||
if (book?.isLocal == true) {
|
||||
PillHeaderDivider(title = "本地书籍选项")
|
||||
RoundDropdownMenuItem(
|
||||
text = "本地书籍目录规则",
|
||||
text = { Text("本地书籍目录规则") },
|
||||
onClick = {
|
||||
val intent =
|
||||
Intent(context, TxtTocRuleActivity::class.java).apply {
|
||||
@@ -351,7 +351,7 @@ fun TocScreen(
|
||||
}
|
||||
)
|
||||
RoundDropdownMenuItem(
|
||||
text = "拆分超长章节",
|
||||
text = { Text("拆分超长章节") },
|
||||
trailingIcon = {
|
||||
Checkbox(
|
||||
checked = viewModel.isSplitLongChapter,
|
||||
@@ -368,7 +368,7 @@ fun TocScreen(
|
||||
|
||||
else -> {
|
||||
RoundDropdownMenuItem(
|
||||
text = "导出书签为JSON",
|
||||
text = { Text("导出书签为JSON") },
|
||||
onClick = {
|
||||
val dateFormat = SimpleDateFormat(
|
||||
"yyyyMMdd_HHmm",
|
||||
@@ -380,7 +380,7 @@ fun TocScreen(
|
||||
}
|
||||
)
|
||||
RoundDropdownMenuItem(
|
||||
text = "导出书签为MarkDown",
|
||||
text = { Text("导出书签为MarkDown") },
|
||||
onClick = {
|
||||
val dateFormat = SimpleDateFormat(
|
||||
"yyyyMMdd_HHmm",
|
||||
@@ -445,13 +445,13 @@ fun TocScreen(
|
||||
onDismissRequest = { showVolumeMenu = false }
|
||||
) {
|
||||
RoundDropdownMenuItem(
|
||||
text = "展开所有卷",
|
||||
text = { Text("展开所有卷") },
|
||||
onClick = {
|
||||
viewModel.expandAllVolumes(); showVolumeMenu = false
|
||||
}
|
||||
)
|
||||
RoundDropdownMenuItem(
|
||||
text = "收起所有卷",
|
||||
text = { Text("收起所有卷") },
|
||||
onClick = {
|
||||
viewModel.collapseAllVolumes(); showVolumeMenu = false
|
||||
}
|
||||
@@ -463,7 +463,7 @@ fun TocScreen(
|
||||
PillHeaderDivider(title = "快速跳转")
|
||||
volumeItems.forEach { uiItem ->
|
||||
RoundDropdownMenuItem(
|
||||
text = uiItem.title,
|
||||
text = { Text(uiItem.title) },
|
||||
onClick = {
|
||||
scope.launch {
|
||||
val targetIndex =
|
||||
|
||||
@@ -22,7 +22,7 @@ import io.legado.app.databinding.DialogEditTextBinding
|
||||
import io.legado.app.databinding.DialogImageBlurringBinding
|
||||
import io.legado.app.help.LauncherIconHelp
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.help.config.OldThemeConfig
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
import io.legado.app.lib.dialogs.selector
|
||||
import io.legado.app.lib.prefs.ColorPreference
|
||||
@@ -32,7 +32,7 @@ import io.legado.app.lib.prefs.ThemeCardPreference
|
||||
import io.legado.app.lib.prefs.ThemeModePreference
|
||||
import io.legado.app.lib.theme.ThemeStore
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.ui.theme.ThemeSyncer
|
||||
import io.legado.app.ui.config.themeConfig.ThemeConfig
|
||||
import io.legado.app.ui.widget.number.NumberPickerDialog
|
||||
import io.legado.app.ui.widget.seekbar.SeekBarChangeListener
|
||||
import io.legado.app.utils.ColorUtils
|
||||
@@ -181,13 +181,20 @@ class ThemeConfigFragment : PreferenceFragmentCompat(),
|
||||
}
|
||||
|
||||
|
||||
PreferKey.paletteStyle, PreferKey.pureBlack, PreferKey.enableBlur, PreferKey.swipeAnimation -> {
|
||||
ThemeSyncer.syncAll()
|
||||
PreferKey.paletteStyle, PreferKey.pureBlack, PreferKey.swipeAnimation -> {
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
recreateActivities()
|
||||
}, 100)
|
||||
}
|
||||
|
||||
PreferKey.enableBlur -> {
|
||||
ThemeConfig.enableBlur = PreferKey.enableBlur.toBoolean()
|
||||
}
|
||||
|
||||
PreferKey.enableProgressiveBlur -> {
|
||||
ThemeConfig.enableProgressiveBlur = PreferKey.enableProgressiveBlur.toBoolean()
|
||||
}
|
||||
|
||||
PreferKey.customMode -> handleRestartRequired()
|
||||
|
||||
PreferKey.isPredictiveBackEnabled -> {
|
||||
@@ -263,17 +270,15 @@ class ThemeConfigFragment : PreferenceFragmentCompat(),
|
||||
.setTitle(getString(R.string.container_opacity))
|
||||
.setMaxValue(100)
|
||||
.setMinValue(0)
|
||||
.setValue(AppConfig.containerOpacity)
|
||||
.setValue(ThemeConfig.containerOpacity)
|
||||
.setCustomButton((R.string.btn_default_s)) {
|
||||
AppConfig.containerOpacity = 100
|
||||
ThemeSyncer.syncContainerOpacity()
|
||||
ThemeConfig.containerOpacity = 100
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
upPreferenceSummary(PreferKey.containerOpacity)
|
||||
}, 100)
|
||||
}
|
||||
.show {
|
||||
AppConfig.containerOpacity = it
|
||||
ThemeSyncer.syncContainerOpacity()
|
||||
ThemeConfig.containerOpacity = it
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
upPreferenceSummary(PreferKey.containerOpacity)
|
||||
}, 100)
|
||||
@@ -305,11 +310,11 @@ class ThemeConfigFragment : PreferenceFragmentCompat(),
|
||||
alertBinding.editView.text?.toString()?.let { themeName ->
|
||||
when (key) {
|
||||
"saveDayTheme" -> {
|
||||
ThemeConfig.saveDayTheme(requireContext(), themeName)
|
||||
OldThemeConfig.saveDayTheme(requireContext(), themeName)
|
||||
}
|
||||
|
||||
"saveNightTheme" -> {
|
||||
ThemeConfig.saveNightTheme(requireContext(), themeName)
|
||||
OldThemeConfig.saveNightTheme(requireContext(), themeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package io.legado.app.ui.config
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@@ -15,11 +14,10 @@ import io.legado.app.base.adapter.ItemViewHolder
|
||||
import io.legado.app.base.adapter.RecyclerAdapter
|
||||
import io.legado.app.databinding.DialogRecyclerViewBinding
|
||||
import io.legado.app.databinding.ItemThemeConfigBinding
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.help.config.OldThemeConfig
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
//import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.ui.widget.recycler.VerticalDivider
|
||||
import io.legado.app.utils.*
|
||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
|
||||
@@ -54,14 +52,14 @@ class ThemeListDialog : BaseBottomSheetDialogFragment(R.layout.dialog_recycler_v
|
||||
}
|
||||
|
||||
fun initData() {
|
||||
adapter.setItems(ThemeConfig.configList)
|
||||
adapter.setItems(OldThemeConfig.configList)
|
||||
}
|
||||
|
||||
override fun onMenuItemClick(item: MenuItem?): Boolean {
|
||||
when (item?.itemId) {
|
||||
R.id.menu_import -> {
|
||||
requireContext().getClipText()?.let {
|
||||
if (ThemeConfig.addConfig(it)) {
|
||||
if (OldThemeConfig.addConfig(it)) {
|
||||
initData()
|
||||
} else {
|
||||
toastOnUi("格式不对,添加失败")
|
||||
@@ -75,7 +73,7 @@ class ThemeListDialog : BaseBottomSheetDialogFragment(R.layout.dialog_recycler_v
|
||||
fun delete(index: Int) {
|
||||
alert(R.string.delete, R.string.sure_del) {
|
||||
yesButton {
|
||||
ThemeConfig.delConfig(index)
|
||||
OldThemeConfig.delConfig(index)
|
||||
initData()
|
||||
}
|
||||
noButton()
|
||||
@@ -83,12 +81,12 @@ class ThemeListDialog : BaseBottomSheetDialogFragment(R.layout.dialog_recycler_v
|
||||
}
|
||||
|
||||
fun share(index: Int) {
|
||||
val json = GSON.toJson(ThemeConfig.configList[index])
|
||||
val json = GSON.toJson(OldThemeConfig.configList[index])
|
||||
requireContext().share(json, "主题分享")
|
||||
}
|
||||
|
||||
inner class Adapter(context: Context) :
|
||||
RecyclerAdapter<ThemeConfig.Config, ItemThemeConfigBinding>(context) {
|
||||
RecyclerAdapter<OldThemeConfig.Config, ItemThemeConfigBinding>(context) {
|
||||
|
||||
override fun getViewBinding(parent: ViewGroup): ItemThemeConfigBinding {
|
||||
return ItemThemeConfigBinding.inflate(inflater, parent, false)
|
||||
@@ -97,7 +95,7 @@ class ThemeListDialog : BaseBottomSheetDialogFragment(R.layout.dialog_recycler_v
|
||||
override fun convert(
|
||||
holder: ItemViewHolder,
|
||||
binding: ItemThemeConfigBinding,
|
||||
item: ThemeConfig.Config,
|
||||
item: OldThemeConfig.Config,
|
||||
payloads: MutableList<Any>
|
||||
) {
|
||||
binding.apply {
|
||||
@@ -113,7 +111,10 @@ class ThemeListDialog : BaseBottomSheetDialogFragment(R.layout.dialog_recycler_v
|
||||
override fun registerListener(holder: ItemViewHolder, binding: ItemThemeConfigBinding) {
|
||||
binding.apply {
|
||||
root.setOnClickListener {
|
||||
ThemeConfig.applyConfig(context, ThemeConfig.configList[holder.layoutPosition])
|
||||
OldThemeConfig.applyConfig(
|
||||
context,
|
||||
OldThemeConfig.configList[holder.layoutPosition]
|
||||
)
|
||||
}
|
||||
ivShare.setOnClickListener {
|
||||
share(holder.layoutPosition)
|
||||
|
||||
@@ -34,7 +34,7 @@ import io.legado.app.R
|
||||
import io.legado.app.service.WebService
|
||||
import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
|
||||
import io.legado.app.ui.widget.components.SplicedColumnGroup
|
||||
import io.legado.app.ui.widget.components.button.SmallTopBarButton
|
||||
import io.legado.app.ui.widget.components.button.TopbarNavigationButton
|
||||
import io.legado.app.ui.widget.components.exportComponents.FilePickerSheet
|
||||
import io.legado.app.ui.widget.components.settingItem.ClickableSettingItem
|
||||
import io.legado.app.ui.widget.components.settingItem.DropdownListSettingItem
|
||||
@@ -89,7 +89,7 @@ fun OtherConfigScreen(
|
||||
},
|
||||
scrollBehavior = scrollBehavior,
|
||||
navigationIcon = {
|
||||
SmallTopBarButton(onClick = onBackClick)
|
||||
TopbarNavigationButton(onClick = onBackClick)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package io.legado.app.ui.config.themeConfig
|
||||
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.ui.config.prefDelegate
|
||||
|
||||
object ThemeConfig {
|
||||
|
||||
var containerOpacity by prefDelegate(PreferKey.containerOpacity, 100)
|
||||
|
||||
var enableBlur by prefDelegate(PreferKey.enableBlur, false)
|
||||
|
||||
var enableProgressiveBlur by prefDelegate(PreferKey.enableProgressiveBlur, true)
|
||||
|
||||
var paletteStyle by prefDelegate(PreferKey.paletteStyle, "tonalSpot")
|
||||
|
||||
var appTheme by prefDelegate(PreferKey.appTheme, "0")
|
||||
|
||||
var isPureBlack by prefDelegate(PreferKey.pureBlack, false)
|
||||
|
||||
var bgImageLight by prefDelegate<String?>(PreferKey.bgImage, null)
|
||||
|
||||
var bgImageDark by prefDelegate<String?>(PreferKey.bgImageN, null)
|
||||
|
||||
fun hasImageBg(isDark: Boolean): Boolean {
|
||||
return if (isDark) {
|
||||
!bgImageDark.isNullOrEmpty()
|
||||
} else {
|
||||
!bgImageLight.isNullOrEmpty()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,7 @@ import io.legado.app.ui.widget.components.importComponents.BaseImportUiState
|
||||
import io.legado.app.ui.widget.components.importComponents.BatchImportDialog
|
||||
import io.legado.app.ui.widget.components.importComponents.SourceInputDialog
|
||||
import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
|
||||
import io.legado.app.ui.widget.components.rules.RuleListScaffold
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
@@ -387,35 +388,35 @@ fun ReplaceRuleScreen(
|
||||
},
|
||||
snackbarHostState = snackbarHostState,
|
||||
dropDownMenuContent = { dismiss ->
|
||||
DropdownMenuItem(
|
||||
RoundDropdownMenuItem(
|
||||
text = { Text("在线导入") },
|
||||
onClick = {
|
||||
dismiss()
|
||||
showUrlInput = true // 触发输入框
|
||||
}
|
||||
)
|
||||
DropdownMenuItem(
|
||||
RoundDropdownMenuItem(
|
||||
text = { Text("本地导入") },
|
||||
onClick = { importDoc.launch(arrayOf("text/plain", "application/json")); dismiss() }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
RoundDropdownMenuItem(
|
||||
text = { Text("分组管理") },
|
||||
onClick = { showGroupManageSheet = true; dismiss() }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
RoundDropdownMenuItem(
|
||||
text = { Text("帮助") },
|
||||
onClick = { /*TODO*/ dismiss() }
|
||||
)
|
||||
HorizontalDivider()
|
||||
DropdownMenuItem(
|
||||
RoundDropdownMenuItem(
|
||||
text = { Text("旧的在前") },
|
||||
onClick = { viewModel.setSortMode("asc"); dismiss() }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
RoundDropdownMenuItem(
|
||||
text = { Text("新的在前") },
|
||||
onClick = { viewModel.setSortMode("desc"); dismiss() }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
RoundDropdownMenuItem(
|
||||
text = { Text("名称升序") },
|
||||
onClick = {
|
||||
viewModel.setSortMode("name_asc")
|
||||
@@ -425,7 +426,7 @@ fun ReplaceRuleScreen(
|
||||
}
|
||||
}
|
||||
)
|
||||
DropdownMenuItem(
|
||||
RoundDropdownMenuItem(
|
||||
text = { Text("名称降序") },
|
||||
onClick = {
|
||||
viewModel.setSortMode("name_desc")
|
||||
|
||||
@@ -81,7 +81,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
|
||||
import io.legado.app.ui.widget.components.button.AlertButton
|
||||
import io.legado.app.ui.widget.components.button.SmallTopBarButton
|
||||
import io.legado.app.ui.widget.components.button.TopbarNavigationButton
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
|
||||
@Composable
|
||||
@@ -121,7 +121,7 @@ fun ReplaceEditScreen(
|
||||
GlassMediumFlexibleTopAppBar(
|
||||
title = { Text(if (state.id > 0) "编辑替换规则" else "新增替换规则") },
|
||||
navigationIcon = {
|
||||
SmallTopBarButton(onClick = onBack)
|
||||
TopbarNavigationButton(onClick = onBack)
|
||||
},
|
||||
actions = {
|
||||
AnimatedVisibility(
|
||||
|
||||
@@ -7,8 +7,9 @@ import androidx.compose.material3.MotionScheme
|
||||
import androidx.compose.material3.Shapes
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import io.legado.app.ui.config.themeConfig.ThemeConfig
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
@@ -16,18 +17,23 @@ fun AppTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val appThemeMode by ThemeState.themeMode.collectAsState()
|
||||
val isPureBlack by ThemeState.isPureBlack.collectAsState()
|
||||
val hasImageBg by ThemeState.hasImageBg.collectAsState()
|
||||
val paletteStyle by ThemeState.paletteStyle.collectAsState()
|
||||
val context = LocalContext.current
|
||||
val appThemeMode = ThemeResolver.resolveThemeMode(ThemeConfig.appTheme)
|
||||
val isPureBlack = ThemeConfig.isPureBlack
|
||||
val hasImageBg = ThemeConfig.hasImageBg(darkTheme)
|
||||
val paletteStyle = ThemeConfig.paletteStyle
|
||||
|
||||
val colorScheme = ThemeManager.getColorScheme(
|
||||
mode = appThemeMode,
|
||||
darkTheme = darkTheme,
|
||||
isAmoled = isPureBlack,
|
||||
isImageBg = hasImageBg,
|
||||
paletteStyle = paletteStyle
|
||||
)
|
||||
val colorScheme =
|
||||
remember(context, appThemeMode, darkTheme, isPureBlack, hasImageBg, paletteStyle) {
|
||||
ThemeManager.getColorScheme(
|
||||
context = context,
|
||||
mode = appThemeMode,
|
||||
darkTheme = darkTheme,
|
||||
isAmoled = isPureBlack,
|
||||
isImageBg = hasImageBg,
|
||||
paletteStyle = paletteStyle
|
||||
)
|
||||
}
|
||||
|
||||
MaterialExpressiveTheme(
|
||||
colorScheme = colorScheme,
|
||||
@@ -36,5 +42,4 @@ fun AppTheme(
|
||||
shapes = Shapes(),
|
||||
content = content
|
||||
)
|
||||
|
||||
}
|
||||
@@ -1,15 +1,11 @@
|
||||
package io.legado.app.ui.theme
|
||||
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
|
||||
abstract class BaseColorScheme {
|
||||
abstract val lightScheme: ColorScheme
|
||||
abstract val darkScheme: ColorScheme
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun getColorScheme(darkTheme: Boolean): ColorScheme {
|
||||
return if (darkTheme) darkScheme else lightScheme
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package io.legado.app.ui.theme
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import io.legado.app.ui.config.themeConfig.ThemeConfig
|
||||
import io.legado.app.ui.theme.ThemeManager.getColorScheme
|
||||
|
||||
@Composable
|
||||
fun rememberOpaqueColorScheme(): ColorScheme {
|
||||
val context = LocalContext.current
|
||||
val isDark = isSystemInDarkTheme()
|
||||
val appThemeMode = ThemeResolver.resolveThemeMode(ThemeConfig.appTheme)
|
||||
val isPureBlack = ThemeConfig.isPureBlack
|
||||
val hasImageBg = ThemeConfig.hasImageBg(isDark)
|
||||
val paletteStyle = ThemeConfig.paletteStyle
|
||||
|
||||
return remember(context, appThemeMode, isDark, isPureBlack, hasImageBg, paletteStyle) {
|
||||
getColorScheme(
|
||||
context = context,
|
||||
mode = appThemeMode,
|
||||
darkTheme = isDark,
|
||||
isAmoled = isPureBlack,
|
||||
isImageBg = hasImageBg,
|
||||
paletteStyle = paletteStyle,
|
||||
forceOpaque = true
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
package io.legado.app.ui.theme
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.ui.theme.ThemeResolver.resolvePaletteStyle
|
||||
import io.legado.app.ui.theme.colorScheme.AugustColorScheme
|
||||
@@ -40,16 +38,17 @@ object ThemeManager {
|
||||
AppThemeMode.Transparent to TransparentColorScheme,
|
||||
)
|
||||
|
||||
@Composable
|
||||
|
||||
fun getColorScheme(
|
||||
context: Context,
|
||||
mode: AppThemeMode,
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
darkTheme: Boolean,
|
||||
isAmoled: Boolean,
|
||||
isImageBg: Boolean,
|
||||
paletteStyle: String?,
|
||||
forceOpaque: Boolean = false
|
||||
): ColorScheme {
|
||||
val context = LocalContext.current
|
||||
|
||||
val style = resolvePaletteStyle(paletteStyle)
|
||||
val actualMode = if (forceOpaque && mode == AppThemeMode.Transparent) {
|
||||
AppThemeMode.WH
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
package io.legado.app.ui.theme
|
||||
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.utils.getPrefBoolean
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import splitties.init.appCtx
|
||||
|
||||
object ThemeState {
|
||||
|
||||
private val _themeMode =
|
||||
MutableStateFlow(ThemeResolver.resolveThemeMode(AppConfig.AppTheme.toString()))
|
||||
val themeMode: StateFlow<AppThemeMode> = _themeMode.asStateFlow()
|
||||
|
||||
private val _isPureBlack =
|
||||
MutableStateFlow(appCtx.getPrefBoolean(PreferKey.pureBlack, false))
|
||||
val isPureBlack: StateFlow<Boolean> = _isPureBlack.asStateFlow()
|
||||
|
||||
private val _hasImageBg =
|
||||
MutableStateFlow(AppConfig.hasImageBg)
|
||||
val hasImageBg: StateFlow<Boolean> = _hasImageBg.asStateFlow()
|
||||
|
||||
private val _paletteStyle =
|
||||
MutableStateFlow(AppConfig.paletteStyle)
|
||||
val paletteStyle: StateFlow<String?> = _paletteStyle.asStateFlow()
|
||||
|
||||
private val _enableBlur =
|
||||
MutableStateFlow(AppConfig.enableBlur)
|
||||
val enableBlur: StateFlow<Boolean> = _enableBlur.asStateFlow()
|
||||
|
||||
private val _containerOpacity =
|
||||
MutableStateFlow(AppConfig.containerOpacity)
|
||||
val containerOpacity: StateFlow<Int> = _containerOpacity
|
||||
|
||||
fun updateThemeMode(newMode: AppThemeMode) {
|
||||
if (_themeMode.value != newMode) {
|
||||
_themeMode.value = newMode
|
||||
}
|
||||
}
|
||||
|
||||
fun updatePureBlack(enabled: Boolean) {
|
||||
if (_isPureBlack.value != enabled) {
|
||||
_isPureBlack.value = enabled
|
||||
}
|
||||
}
|
||||
|
||||
fun updateImageBg(enabled: Boolean) {
|
||||
if (_hasImageBg.value != enabled) {
|
||||
_hasImageBg.value = enabled
|
||||
}
|
||||
}
|
||||
|
||||
fun updatePaletteStyle(style: String?) {
|
||||
if (_paletteStyle.value != style) {
|
||||
_paletteStyle.value = style
|
||||
}
|
||||
}
|
||||
|
||||
fun updateEnableBlur(enabled: Boolean) {
|
||||
if (_enableBlur.value != enabled) {
|
||||
_enableBlur.value = enabled
|
||||
}
|
||||
}
|
||||
|
||||
fun updateContainerOpacity(opacity: Int) {
|
||||
if (_containerOpacity.value != opacity) {
|
||||
_containerOpacity.value = opacity
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package io.legado.app.ui.theme
|
||||
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.utils.getPrefBoolean
|
||||
import splitties.init.appCtx
|
||||
|
||||
object ThemeSyncer {
|
||||
|
||||
fun syncAll() {
|
||||
syncThemeMode()
|
||||
syncPureBlack()
|
||||
syncImageBg()
|
||||
syncPaletteStyle()
|
||||
syncEnableBlur()
|
||||
syncContainerOpacity()
|
||||
}
|
||||
|
||||
fun syncThemeMode() {
|
||||
ThemeState.updateThemeMode(
|
||||
ThemeResolver.resolveThemeMode(AppConfig.AppTheme.toString())
|
||||
)
|
||||
}
|
||||
|
||||
fun syncPureBlack() {
|
||||
ThemeState.updatePureBlack(appCtx.getPrefBoolean(PreferKey.pureBlack, false))
|
||||
}
|
||||
|
||||
fun syncImageBg() {
|
||||
ThemeState.updateImageBg(AppConfig.hasImageBg)
|
||||
}
|
||||
|
||||
fun syncPaletteStyle() {
|
||||
ThemeState.updatePaletteStyle(AppConfig.paletteStyle)
|
||||
}
|
||||
|
||||
fun syncEnableBlur() {
|
||||
ThemeState.updateEnableBlur(AppConfig.enableBlur)
|
||||
}
|
||||
|
||||
fun syncContainerOpacity() {
|
||||
ThemeState.updateContainerOpacity(AppConfig.containerOpacity)
|
||||
}
|
||||
|
||||
}
|
||||
+44
-27
@@ -5,14 +5,13 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.MediumFlexibleTopAppBar
|
||||
import androidx.compose.material3.TopAppBarColors
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import io.legado.app.ui.theme.ThemeState
|
||||
import io.legado.app.ui.config.themeConfig.ThemeConfig
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
@@ -22,30 +21,9 @@ fun GlassMediumFlexibleTopAppBar(
|
||||
subtitle: (@Composable () -> Unit)? = null,
|
||||
scrollBehavior: TopAppBarScrollBehavior? = null,
|
||||
navigationIcon: @Composable () -> Unit = {},
|
||||
actions: @Composable RowScope.() -> Unit = {}
|
||||
actions: @Composable RowScope.() -> Unit = {},
|
||||
colors: TopAppBarColors = GlassTopAppBarDefaults.glassColors()
|
||||
) {
|
||||
val opacityValue by ThemeState.containerOpacity.collectAsState()
|
||||
val enableBlur by ThemeState.enableBlur.collectAsState()
|
||||
|
||||
val alpha = opacityValue / 100f
|
||||
|
||||
val containerColor = if (enableBlur) {
|
||||
Color.Transparent
|
||||
} else {
|
||||
MaterialTheme.colorScheme.surface.copy(alpha = alpha)
|
||||
}
|
||||
|
||||
val scrolledContainerColor = if (enableBlur) {
|
||||
Color.Transparent
|
||||
} else {
|
||||
MaterialTheme.colorScheme.surfaceContainer.copy(alpha = alpha)
|
||||
}
|
||||
|
||||
val appBarColors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = containerColor,
|
||||
scrolledContainerColor = scrolledContainerColor
|
||||
)
|
||||
|
||||
MediumFlexibleTopAppBar(
|
||||
modifier = modifier,
|
||||
title = title,
|
||||
@@ -53,7 +31,46 @@ fun GlassMediumFlexibleTopAppBar(
|
||||
navigationIcon = navigationIcon,
|
||||
actions = actions,
|
||||
scrollBehavior = scrollBehavior,
|
||||
colors = appBarColors
|
||||
colors = colors
|
||||
)
|
||||
}
|
||||
|
||||
object GlassTopAppBarDefaults {
|
||||
|
||||
@Composable
|
||||
fun glassColors(): TopAppBarColors {
|
||||
val alpha = ThemeConfig.containerOpacity / 100f
|
||||
val enableBlur = ThemeConfig.enableBlur
|
||||
|
||||
val containerColor = if (enableBlur) {
|
||||
MaterialTheme.colorScheme.surface
|
||||
} else {
|
||||
MaterialTheme.colorScheme.surface.copy(alpha = alpha)
|
||||
}
|
||||
|
||||
val scrolledContainerColor = if (enableBlur) {
|
||||
MaterialTheme.colorScheme.surface.copy(alpha = 0f)
|
||||
} else {
|
||||
MaterialTheme.colorScheme.surfaceContainer
|
||||
}
|
||||
|
||||
return TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = containerColor,
|
||||
scrolledContainerColor = scrolledContainerColor
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun controlContainerColor(): Color {
|
||||
val enableBlur = ThemeConfig.enableBlur
|
||||
val baseColor = MaterialTheme.colorScheme.surfaceContainerHigh
|
||||
|
||||
return if (enableBlur) {
|
||||
val alpha = 0.6f
|
||||
baseColor.copy(alpha = alpha)
|
||||
} else {
|
||||
baseColor.copy(alpha = ThemeConfig.containerOpacity / 100f)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+48
-9
@@ -17,31 +17,26 @@ import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedIconButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.legado.app.ui.theme.ThemeState
|
||||
import io.legado.app.ui.config.themeConfig.ThemeConfig
|
||||
import io.legado.app.ui.widget.components.GlassTopAppBarDefaults
|
||||
|
||||
enum class TopBarButtonVariant {
|
||||
Filled, Outlined, Icon
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SmallTopBarButton(
|
||||
fun TopBarButton(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
imageVector: ImageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||
contentDescription: String? = null,
|
||||
style: TopBarButtonVariant = TopBarButtonVariant.Filled
|
||||
) {
|
||||
val themeOpacity by ThemeState.containerOpacity.collectAsState()
|
||||
val baseColor = MaterialTheme.colorScheme.surfaceContainerHigh
|
||||
val glassColor = baseColor.copy(alpha = (themeOpacity / 100f).coerceAtLeast(0.6f))
|
||||
|
||||
val commonModifier = modifier
|
||||
.padding(horizontal = 12.dp)
|
||||
.size(36.dp)
|
||||
|
||||
when (style) {
|
||||
@@ -50,7 +45,7 @@ fun SmallTopBarButton(
|
||||
onClick = onClick,
|
||||
modifier = commonModifier,
|
||||
colors = IconButtonDefaults.filledTonalIconButtonColors(
|
||||
containerColor = glassColor,
|
||||
containerColor = GlassTopAppBarDefaults.controlContainerColor(),
|
||||
contentColor = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
) {
|
||||
@@ -79,6 +74,50 @@ fun SmallTopBarButton(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TopbarNavigationButton(
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
imageVector: ImageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||
contentDescription: String? = "返回",
|
||||
style: TopBarButtonVariant = TopBarButtonVariant.Filled
|
||||
) {
|
||||
TopBarButton(
|
||||
onClick = onClick,
|
||||
imageVector = imageVector,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier.padding(start = 12.dp, end = 4.dp),
|
||||
style = style
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TopBarActionButton(
|
||||
onClick: () -> Unit,
|
||||
imageVector: ImageVector,
|
||||
contentDescription: String?,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val enableProgressive = ThemeConfig.enableProgressiveBlur
|
||||
|
||||
if (enableProgressive) {
|
||||
TopBarButton(
|
||||
onClick = onClick,
|
||||
imageVector = imageVector,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier.padding(end = 12.dp),
|
||||
style = TopBarButtonVariant.Filled
|
||||
)
|
||||
} else {
|
||||
IconButton(onClick = onClick) {
|
||||
Icon(
|
||||
imageVector = imageVector,
|
||||
contentDescription = contentDescription
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SmallIcon(imageVector: ImageVector, contentDescription: String?) {
|
||||
AnimatedContent(
|
||||
@@ -7,12 +7,10 @@ import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CardElevation
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import io.legado.app.ui.theme.ThemeState
|
||||
import io.legado.app.ui.config.themeConfig.ThemeConfig
|
||||
|
||||
@Composable
|
||||
fun GlassCard(
|
||||
@@ -24,7 +22,7 @@ fun GlassCard(
|
||||
border: BorderStroke? = null,
|
||||
content: @Composable ColumnScope.() -> Unit
|
||||
) {
|
||||
val opacity by ThemeState.containerOpacity.collectAsState()
|
||||
val opacity = ThemeConfig.containerOpacity
|
||||
val cardColors = CardDefaults.cardColors(
|
||||
containerColor = color.copy(alpha = opacity / 100f)
|
||||
)
|
||||
|
||||
@@ -4,13 +4,21 @@ import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.MaterialExpressiveTheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.MotionScheme
|
||||
import androidx.compose.material3.Shapes
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.legado.app.ui.theme.rememberOpaqueColorScheme
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
fun RoundDropdownMenu(
|
||||
expanded: Boolean,
|
||||
@@ -21,17 +29,27 @@ fun RoundDropdownMenu(
|
||||
verticalSpacing: Dp = 8.dp,
|
||||
content: @Composable ColumnScope.(dismiss: () -> Unit) -> Unit
|
||||
) {
|
||||
val colorScheme = rememberOpaqueColorScheme()
|
||||
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = onDismissRequest,
|
||||
modifier = modifier,
|
||||
shape = shape,
|
||||
shadowElevation = shadowElevation
|
||||
shadowElevation = shadowElevation,
|
||||
containerColor = colorScheme.surfaceContainerLow
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(verticalSpacing)
|
||||
MaterialExpressiveTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography(),
|
||||
motionScheme = MotionScheme.expressive(),
|
||||
shapes = Shapes()
|
||||
) {
|
||||
content(onDismissRequest)
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(verticalSpacing)
|
||||
) {
|
||||
content(onDismissRequest)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-5
@@ -4,26 +4,28 @@ import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.legado.app.ui.theme.rememberOpaqueColorScheme
|
||||
|
||||
@Composable
|
||||
fun RoundDropdownMenuItem(
|
||||
modifier: Modifier = Modifier,
|
||||
text: String,
|
||||
text: @Composable () -> Unit,
|
||||
onClick: () -> Unit,
|
||||
trailingIcon: @Composable (() -> Unit)? = null,
|
||||
) {
|
||||
val colorScheme = rememberOpaqueColorScheme()
|
||||
|
||||
DropdownMenuItem(
|
||||
modifier = modifier
|
||||
.padding(horizontal = 8.dp)
|
||||
.clip(MaterialTheme.shapes.small)
|
||||
.background(MaterialTheme.colorScheme.surface),
|
||||
text = { Text(text) },
|
||||
.background(colorScheme.surface),
|
||||
text = text,
|
||||
trailingIcon = trailingIcon,
|
||||
onClick = onClick,
|
||||
onClick = onClick
|
||||
)
|
||||
}
|
||||
+2
-16
@@ -15,12 +15,9 @@ import androidx.compose.material3.SheetState
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import io.legado.app.ui.theme.ThemeManager
|
||||
import io.legado.app.ui.theme.ThemeState
|
||||
import io.legado.app.ui.theme.rememberOpaqueColorScheme
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
@@ -31,18 +28,7 @@ fun GlassModalBottomSheet(
|
||||
containerColor: (ColorScheme) -> Color = { it.surfaceContainerLow },
|
||||
content: @Composable ColumnScope.() -> Unit
|
||||
) {
|
||||
val themeMode by ThemeState.themeMode.collectAsState()
|
||||
val isPureBlack by ThemeState.isPureBlack.collectAsState()
|
||||
val hasImageBg by ThemeState.hasImageBg.collectAsState()
|
||||
val paletteStyle by ThemeState.paletteStyle.collectAsState()
|
||||
|
||||
val colorScheme = ThemeManager.getColorScheme(
|
||||
mode = themeMode,
|
||||
isAmoled = isPureBlack,
|
||||
isImageBg = hasImageBg,
|
||||
forceOpaque = true,
|
||||
paletteStyle = paletteStyle
|
||||
)
|
||||
val colorScheme = rememberOpaqueColorScheme()
|
||||
|
||||
ModalBottomSheet(
|
||||
onDismissRequest = onDismissRequest,
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.SwipeToDismissBox
|
||||
import androidx.compose.material3.SwipeToDismissBoxState
|
||||
import androidx.compose.material3.SwipeToDismissBoxValue
|
||||
import androidx.compose.material3.contentColorFor
|
||||
import androidx.compose.material3.rememberSwipeToDismissBoxState
|
||||
@@ -79,8 +80,8 @@ fun SwipeActionContainer(
|
||||
SwipeToDismissBoxValue.StartToEnd -> {
|
||||
startAction?.let { action ->
|
||||
SwipeBackground(
|
||||
dismissState = dismissState,
|
||||
action = action,
|
||||
progress = progress,
|
||||
alignStart = true
|
||||
)
|
||||
}
|
||||
@@ -89,8 +90,8 @@ fun SwipeActionContainer(
|
||||
SwipeToDismissBoxValue.EndToStart -> {
|
||||
endAction?.let { action ->
|
||||
SwipeBackground(
|
||||
dismissState = dismissState,
|
||||
action = action,
|
||||
progress = progress,
|
||||
alignStart = false
|
||||
)
|
||||
}
|
||||
@@ -114,10 +115,13 @@ fun SwipeActionContainer(
|
||||
@Composable
|
||||
private fun SwipeBackground(
|
||||
action: SwipeAction,
|
||||
progress: Float,
|
||||
dismissState: SwipeToDismissBoxState,
|
||||
alignStart: Boolean
|
||||
) {
|
||||
val isThresholdReached = progress > 0.6f
|
||||
val isThresholdReached = dismissState.targetValue == if (alignStart)
|
||||
SwipeToDismissBoxValue.StartToEnd
|
||||
else
|
||||
SwipeToDismissBoxValue.EndToStart
|
||||
|
||||
val backgroundColor by animateColorAsState(
|
||||
targetValue = if (isThresholdReached)
|
||||
@@ -128,8 +132,8 @@ private fun SwipeBackground(
|
||||
)
|
||||
|
||||
val iconScale by animateFloatAsState(
|
||||
targetValue = if (isThresholdReached) 1.3f
|
||||
else progress.coerceIn(0.5f, 1f),
|
||||
targetValue = if (isThresholdReached) 1.2f
|
||||
else 1f,
|
||||
label = "iconScale"
|
||||
)
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ import io.legado.app.ui.widget.components.AdaptiveAnimatedText
|
||||
import io.legado.app.ui.widget.components.AnimatedTextLine
|
||||
import io.legado.app.ui.widget.components.GlassMediumFlexibleTopAppBar
|
||||
import io.legado.app.ui.widget.components.SearchBarSection
|
||||
import io.legado.app.ui.widget.components.button.SmallTopBarButton
|
||||
import io.legado.app.ui.widget.components.button.TopbarNavigationButton
|
||||
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenu
|
||||
import io.legado.app.ui.widget.components.rules.RuleActionState
|
||||
|
||||
@@ -75,7 +75,7 @@ fun <T> DynamicTopAppBar(
|
||||
{ AnimatedTextLine(text = it) }
|
||||
},
|
||||
navigationIcon = {
|
||||
SmallTopBarButton(
|
||||
TopbarNavigationButton(
|
||||
onClick = { if (isSelecting) onClearSelection() else onBackClick() },
|
||||
imageVector = if (isSelecting) Icons.Default.Close else Icons.AutoMirrored.Filled.ArrowBack,
|
||||
contentDescription = if (isSelecting) "取消选择" else "返回"
|
||||
|
||||
Reference in New Issue
Block a user