更新界面

增加首次进入引导界面
This commit is contained in:
HapeLee
2025-08-27 03:04:46 +08:00
parent ab98072ec3
commit 50abb9b552
33 changed files with 684 additions and 307 deletions
+3 -1
View File
@@ -133,10 +133,12 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".ui.welcome.WelcomeActivity"
android:exported="false" />
<!-- 阅读界面 --> <!-- 阅读界面 -->
<activity <activity
android:name=".ui.book.read.ReadBookActivity" android:name=".ui.book.read.ReadBookActivity"
android:enableOnBackInvokedCallback="true" android:enableOnBackInvokedCallback="true"
android:exported="true" android:exported="true"
android:launchMode="singleTask"> android:launchMode="singleTask">
-2
View File
@@ -1,5 +1,3 @@
# 免责声明(Disclaimer
* 阅读是一款解析指定规则并获取内容的工具,为广大网络文学爱好者提供一种方便、快捷舒适的试读体验。 * 阅读是一款解析指定规则并获取内容的工具,为广大网络文学爱好者提供一种方便、快捷舒适的试读体验。
* 当您搜索一本书的时,阅读会您所使用的规则将该书的书名以关键词的形式提交到各个第三方网络文学网站。 * 当您搜索一本书的时,阅读会您所使用的规则将该书的书名以关键词的形式提交到各个第三方网络文学网站。
各第三方网站返回的内容与阅读无关,阅读对其概不负责,亦不承担任何法律责任。 各第三方网站返回的内容与阅读无关,阅读对其概不负责,亦不承担任何法律责任。
@@ -204,7 +204,7 @@ object PreferKey {
const val mangaClickActionBL = "mangaClickActionBottomLeft" const val mangaClickActionBL = "mangaClickActionBottomLeft"
const val mangaClickActionBC = "mangaClickActionBottomCenter" const val mangaClickActionBC = "mangaClickActionBottomCenter"
const val mangaClickActionBR = "mangaClickActionBottomRight" const val mangaClickActionBR = "mangaClickActionBottomRight"
const val isFirstLaunch = "isFirstLaunch"
const val permissionChecked = "permissionChecked" const val permissionChecked = "permissionChecked"
const val notificationsPost = "notificationsPost" const val notificationsPost = "notificationsPost"
const val ignoreBatteryPermission = "ignoreBatteryPermission" const val ignoreBatteryPermission = "ignoreBatteryPermission"
@@ -149,6 +149,12 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
} }
} }
var isFirstLaunch: Boolean
get() = appCtx.getPrefBoolean(PreferKey.isFirstLaunch, true)
set(value) {
appCtx.putPrefBoolean(PreferKey.isFirstLaunch, value)
}
var showUnread: Boolean var showUnread: Boolean
get() = appCtx.getPrefBoolean(PreferKey.showUnread, true) get() = appCtx.getPrefBoolean(PreferKey.showUnread, true)
set(value) { set(value) {
@@ -24,7 +24,7 @@ class ThemeCardPreference(context: Context, attrs: AttributeSet) : Preference(co
private var entries: Array<CharSequence> = context.resources.getTextArray(R.array.themes_item) private var entries: Array<CharSequence> = context.resources.getTextArray(R.array.themes_item)
private var entryValues: Array<CharSequence> = context.resources.getTextArray(R.array.themes_value).takeIf { it.isNotEmpty() } private var entryValues: Array<CharSequence> = context.resources.getTextArray(R.array.themes_value).takeIf { it.isNotEmpty() }
?: arrayOf("0") ?: arrayOf("0")
private var currentValue: String? = null private var currentValue = "0"
init { init {
layoutResource = R.layout.preference_theme_card layoutResource = R.layout.preference_theme_card
@@ -2,9 +2,6 @@ package io.legato.kazusa.lib.prefs
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.preference.PreferenceViewHolder import androidx.preference.PreferenceViewHolder
import com.google.android.material.button.MaterialButtonToggleGroup import com.google.android.material.button.MaterialButtonToggleGroup
import io.legato.kazusa.R import io.legato.kazusa.R
@@ -13,7 +10,7 @@ import io.legato.kazusa.help.config.ThemeConfig
class ThemeModePreference(context: Context, attrs: AttributeSet) : Preference(context, attrs) { class ThemeModePreference(context: Context, attrs: AttributeSet) : Preference(context, attrs) {
private var currentValue: String? = null private var currentValue: String = "0"
init { init {
layoutResource = R.layout.view_pref layoutResource = R.layout.view_pref
@@ -23,17 +20,21 @@ class ThemeModePreference(context: Context, attrs: AttributeSet) : Preference(co
override fun onBindViewHolder(holder: PreferenceViewHolder) { override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder) super.onBindViewHolder(holder)
val toggleGroup = holder.itemView.findViewById<View>(R.id.theme_toggle_group) val toggleGroup =
if (toggleGroup == null) { holder.itemView.findViewById<MaterialButtonToggleGroup>(R.id.theme_toggle_group)
val rootView = holder.itemView as ViewGroup ?: return
val inflater = LayoutInflater.from(context)
val themeToggleView = inflater.inflate(R.layout.view_theme_mode, rootView, false)
rootView.addView(themeToggleView)
setupToggleGroup(themeToggleView.findViewById(R.id.theme_toggle_group)) // 根据 currentValue 设置选中
when (currentValue) {
"0" -> toggleGroup.check(R.id.btn_system)
"1" -> toggleGroup.check(R.id.btn_light)
"2" -> toggleGroup.check(R.id.btn_dark)
} }
setupToggleGroup(toggleGroup)
} }
private fun setupToggleGroup(toggleGroup: MaterialButtonToggleGroup) { private fun setupToggleGroup(toggleGroup: MaterialButtonToggleGroup) {
when (currentValue) { when (currentValue) {
@@ -65,8 +66,4 @@ class ThemeModePreference(context: Context, attrs: AttributeSet) : Preference(co
currentValue = getPersistedString(defaultValue as? String ?: "0") currentValue = getPersistedString(defaultValue as? String ?: "0")
} }
override fun shouldDisableDependents(): Boolean {
return currentValue == null || super.shouldDisableDependents()
}
} }
@@ -1,22 +1,21 @@
package io.legato.kazusa.ui.book.read.config package io.legato.kazusa.ui.book.read.config
//import io.legado.app.lib.theme.bottomBackground
//import io.legado.app.lib.theme.getPrimaryTextColor
//import io.legado.app.lib.theme.getSecondaryTextColor
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.DialogInterface import android.content.DialogInterface
import android.graphics.Color import android.graphics.Color
import android.graphics.PorterDuff import android.graphics.PorterDuff
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.Gravity
import android.view.View import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.appcompat.widget.TooltipCompat import androidx.appcompat.widget.TooltipCompat
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import com.google.android.material.slider.Slider import com.google.android.material.slider.Slider
import com.jaredrummler.android.colorpicker.ColorPickerDialog import com.jaredrummler.android.colorpicker.ColorPickerDialog
import io.legato.kazusa.R import io.legato.kazusa.R
import io.legato.kazusa.base.BaseBottomSheetDialogFragment import io.legato.kazusa.base.BaseBottomSheetDialogFragment
import io.legato.kazusa.base.BaseDialogFragment
import io.legato.kazusa.constant.AppLog import io.legato.kazusa.constant.AppLog
import io.legato.kazusa.constant.EventBus import io.legato.kazusa.constant.EventBus
import io.legato.kazusa.databinding.DialogEditTextBinding import io.legato.kazusa.databinding.DialogEditTextBinding
@@ -29,9 +28,6 @@ import io.legato.kazusa.help.http.okHttpClient
import io.legato.kazusa.lib.dialogs.SelectItem import io.legato.kazusa.lib.dialogs.SelectItem
import io.legato.kazusa.lib.dialogs.alert import io.legato.kazusa.lib.dialogs.alert
import io.legato.kazusa.lib.dialogs.selector import io.legato.kazusa.lib.dialogs.selector
//import io.legado.app.lib.theme.bottomBackground
//import io.legado.app.lib.theme.getPrimaryTextColor
//import io.legado.app.lib.theme.getSecondaryTextColor
import io.legato.kazusa.ui.book.read.ReadBookActivity import io.legato.kazusa.ui.book.read.ReadBookActivity
import io.legato.kazusa.ui.file.HandleFileContract import io.legato.kazusa.ui.file.HandleFileContract
import io.legato.kazusa.utils.FileUtils import io.legato.kazusa.utils.FileUtils
@@ -116,22 +112,6 @@ class BgTextConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_read_bg
} }
private fun initView() = binding.run { private fun initView() = binding.run {
// val bg = requireContext().bottomBackground
// val isLight = ColorUtils.isColorLight(bg)
// primaryTextColor = requireContext().getPrimaryTextColor(isLight)
// secondaryTextColor = requireContext().getSecondaryTextColor(isLight)
// rootView.setBackgroundColor(bg)
// tvNameTitle.setTextColor(primaryTextColor)
// tvName.setTextColor(secondaryTextColor)
// ivEdit.setColorFilter(secondaryTextColor, PorterDuff.Mode.SRC_IN)
// tvRestore.setTextColor(primaryTextColor)
// swDarkStatusIcon.setTextColor(primaryTextColor)
// swUnderline.setTextColor(primaryTextColor)
// ivImport.setColorFilter(primaryTextColor, PorterDuff.Mode.SRC_IN)
// ivExport.setColorFilter(primaryTextColor, PorterDuff.Mode.SRC_IN)
// ivDelete.setColorFilter(primaryTextColor, PorterDuff.Mode.SRC_IN)
// tvBgAlpha.setTextColor(primaryTextColor)
// tvBgImage.setTextColor(primaryTextColor)
recyclerView.adapter = adapter recyclerView.adapter = adapter
adapter.addHeaderView { adapter.addHeaderView {
ItemBgImageBinding.inflate(layoutInflater, it, false).apply { ItemBgImageBinding.inflate(layoutInflater, it, false).apply {
@@ -230,14 +230,14 @@ class ReadStyleDialog : BaseBottomSheetDialogFragment(R.layout.dialog_read_book_
llStyle.gravity = Gravity.TOP llStyle.gravity = Gravity.TOP
cdStyle.cardElevation = 1f.dpToPx() cdStyle.cardElevation = 1f.dpToPx()
cdStyle.radius = 16f.dpToPx() cdStyle.radius = 16f.dpToPx()
cdStyle.strokeWidth = 2 cdStyle.strokeWidth = 1.dpToPx()
cdStyle.strokeColor = item.curTextColor() //cdStyle.strokeColor = item.curTextColor()
//tvStyle.setTextBold(true) //tvStyle.setTextBold(true)
} else { } else {
cdStyle.cardElevation = 2f.dpToPx() cdStyle.cardElevation = 2f.dpToPx()
cdStyle.radius = 32f.dpToPx() cdStyle.radius = 32f.dpToPx()
cdStyle.strokeWidth = 0 cdStyle.strokeWidth = 0
cdStyle.strokeColor = item.curTextColor() //cdStyle.strokeColor = item.curTextColor()
//tvStyle.setTextBold(false) //tvStyle.setTextBold(false)
} }
} }
@@ -1,14 +1,12 @@
package io.legato.kazusa.ui.config package io.legato.kazusa.ui.config
//import io.legado.app.lib.theme.primaryColor
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.widget.SeekBar import android.widget.SeekBar
import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import io.legato.kazusa.R import io.legato.kazusa.R
@@ -23,10 +21,8 @@ import io.legato.kazusa.help.config.ThemeConfig
import io.legato.kazusa.lib.dialogs.alert import io.legato.kazusa.lib.dialogs.alert
import io.legato.kazusa.lib.dialogs.selector import io.legato.kazusa.lib.dialogs.selector
import io.legato.kazusa.lib.prefs.ColorPreference import io.legato.kazusa.lib.prefs.ColorPreference
import io.legato.kazusa.lib.prefs.NameListPreference
import io.legato.kazusa.lib.prefs.ThemeCardPreference import io.legato.kazusa.lib.prefs.ThemeCardPreference
import io.legato.kazusa.lib.prefs.ThemeModePreference import io.legato.kazusa.lib.prefs.ThemeModePreference
//import io.legado.app.lib.theme.primaryColor
import io.legato.kazusa.ui.widget.number.NumberPickerDialog import io.legato.kazusa.ui.widget.number.NumberPickerDialog
import io.legato.kazusa.ui.widget.seekbar.SeekBarChangeListener import io.legato.kazusa.ui.widget.seekbar.SeekBarChangeListener
import io.legato.kazusa.utils.ColorUtils import io.legato.kazusa.utils.ColorUtils
@@ -72,9 +68,6 @@ class ThemeConfigFragment : PreferenceFragmentCompat(),
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_config_theme) addPreferencesFromResource(R.xml.pref_config_theme)
if (Build.VERSION.SDK_INT < 26) {
preferenceScreen.removePreferenceRecursively(PreferKey.launcherIcon)
}
upPreferenceSummary(PreferKey.bgImage, getPrefString(PreferKey.bgImage)) upPreferenceSummary(PreferKey.bgImage, getPrefString(PreferKey.bgImage))
upPreferenceSummary(PreferKey.bgImageN, getPrefString(PreferKey.bgImageN)) upPreferenceSummary(PreferKey.bgImageN, getPrefString(PreferKey.bgImageN))
@@ -26,7 +26,6 @@ import io.legato.kazusa.constant.AppConst.appInfo
import io.legato.kazusa.constant.EventBus import io.legato.kazusa.constant.EventBus
import io.legato.kazusa.constant.PreferKey import io.legato.kazusa.constant.PreferKey
import io.legato.kazusa.databinding.ActivityMainBinding import io.legato.kazusa.databinding.ActivityMainBinding
import io.legato.kazusa.databinding.DialogEditTextBinding
import io.legato.kazusa.help.AppWebDav import io.legato.kazusa.help.AppWebDav
import io.legato.kazusa.help.book.BookHelp import io.legato.kazusa.help.book.BookHelp
import io.legato.kazusa.help.config.AppConfig import io.legato.kazusa.help.config.AppConfig
@@ -43,6 +42,7 @@ import io.legato.kazusa.ui.main.bookshelf.books.BookshelfFragment3
import io.legato.kazusa.ui.main.explore.ExploreFragment import io.legato.kazusa.ui.main.explore.ExploreFragment
import io.legato.kazusa.ui.main.my.MyFragment import io.legato.kazusa.ui.main.my.MyFragment
import io.legato.kazusa.ui.main.rss.RssFragment import io.legato.kazusa.ui.main.rss.RssFragment
import io.legato.kazusa.ui.welcome.WelcomeActivity
import io.legato.kazusa.ui.widget.dialog.TextDialog import io.legato.kazusa.ui.widget.dialog.TextDialog
import io.legato.kazusa.utils.gone import io.legato.kazusa.utils.gone
import io.legato.kazusa.utils.hideSoftInput import io.legato.kazusa.utils.hideSoftInput
@@ -51,6 +51,7 @@ import io.legato.kazusa.utils.observeEvent
import io.legato.kazusa.utils.setNavigationBarColorAuto import io.legato.kazusa.utils.setNavigationBarColorAuto
import io.legato.kazusa.utils.shouldHideSoftInput import io.legato.kazusa.utils.shouldHideSoftInput
import io.legato.kazusa.utils.showDialogFragment import io.legato.kazusa.utils.showDialogFragment
import io.legato.kazusa.utils.startActivity
import io.legato.kazusa.utils.themeColor import io.legato.kazusa.utils.themeColor
import io.legato.kazusa.utils.toastOnUi import io.legato.kazusa.utils.toastOnUi
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
@@ -100,6 +101,12 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (AppConfig.isFirstLaunch) {
startActivity<WelcomeActivity>()
finish()
return
}
onBackPressedDispatcher.addCallback(this) { onBackPressedDispatcher.addCallback(this) {
if (pagePosition != 0) { if (pagePosition != 0) {
binding.viewPagerMain.currentItem = 0 binding.viewPagerMain.currentItem = 0
@@ -145,12 +152,9 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
override fun onPostCreate(savedInstanceState: Bundle?) { override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState) super.onPostCreate(savedInstanceState)
lifecycleScope.launch { lifecycleScope.launch {
//隐私协议
if (!privacyPolicy()) return@launch
//版本更新 //版本更新
upVersion() upVersion()
//设置本地密码 //设置本地密码
setLocalPassword()
notifyAppCrash() notifyAppCrash()
//备份同步 //备份同步
backupSync() backupSync()
@@ -217,27 +221,6 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
window.setNavigationBarColorAuto(themeColor(com.google.android.material.R.attr.colorSurfaceContainer)) window.setNavigationBarColorAuto(themeColor(com.google.android.material.R.attr.colorSurfaceContainer))
} }
/**
* 用户隐私与协议
*/
private suspend fun privacyPolicy(): Boolean = suspendCoroutine { block ->
if (LocalConfig.privacyPolicyOk) {
block.resume(true)
return@suspendCoroutine
}
val privacyPolicy = String(assets.open("privacyPolicy.md").readBytes())
alert(getString(R.string.privacy_policy), privacyPolicy) {
positiveButton(R.string.agree) {
LocalConfig.privacyPolicyOk = true
block.resume(true)
}
negativeButton(R.string.refuse) {
finish()
block.resume(false)
}
}
}
/** /**
* 版本更新日志 * 版本更新日志
*/ */
@@ -269,29 +252,6 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
/** /**
* 设置本地密码 * 设置本地密码
*/ */
private suspend fun setLocalPassword() = suspendCoroutine { block ->
if (LocalConfig.password != null) {
block.resume(null)
return@suspendCoroutine
}
alert(R.string.set_local_password, R.string.set_local_password_summary) {
val editTextBinding = DialogEditTextBinding.inflate(layoutInflater).apply {
editView.hint = "password"
}
customView {
editTextBinding.root
}
onDismiss {
block.resume(null)
}
okButton {
LocalConfig.password = editTextBinding.editView.text.toString()
}
cancelButton {
LocalConfig.password = ""
}
}
}
private fun notifyAppCrash() { private fun notifyAppCrash() {
if (!LocalConfig.appCrash || BuildConfig.DEBUG) { if (!LocalConfig.appCrash || BuildConfig.DEBUG) {
@@ -0,0 +1,23 @@
package io.legato.kazusa.ui.welcome
import android.os.Bundle
import android.view.View
import io.legato.kazusa.R
import io.legato.kazusa.base.BaseFragment
import io.legato.kazusa.databinding.FragmentPrivacyBinding
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
class PrivacyFragment : BaseFragment(R.layout.fragment_privacy) {
private val binding by viewBinding(FragmentPrivacyBinding::bind)
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
binding.tvPrivacy.text =
String(requireContext().assets.open("privacyPolicy.md").readBytes())
binding.tvDisclaimer.text =
String(requireContext().assets.open("disclaimer.md").readBytes())
}
}
@@ -0,0 +1,27 @@
package io.legato.kazusa.ui.welcome
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
import io.legato.kazusa.R
import io.legato.kazusa.constant.PreferKey
import io.legato.kazusa.lib.prefs.ThemeCardPreference
import io.legato.kazusa.lib.prefs.ThemeModePreference
class ThemeFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.pref_strat_theme, rootKey)
findPreference<ThemeModePreference>(PreferKey.themeMode)?.let {
it.setOnPreferenceChangeListener { _, _ ->
true
}
}
findPreference<ThemeCardPreference>(PreferKey.themePref)?.let {
it.setOnPreferenceChangeListener { _, _ ->
true
}
}
}
}
@@ -0,0 +1,204 @@
package io.legato.kazusa.ui.welcome
import android.content.Context
import android.os.Bundle
import android.text.InputType
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ArrayAdapter
import androidx.core.content.edit
import androidx.core.widget.doAfterTextChanged
import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager
import io.legato.kazusa.R
import io.legato.kazusa.base.BaseFragment
import io.legato.kazusa.constant.AppLog
import io.legato.kazusa.constant.PreferKey
import io.legato.kazusa.databinding.FragmentWebdavAuthBinding
import io.legato.kazusa.exception.NoStackTraceException
import io.legato.kazusa.help.AppWebDav
import io.legato.kazusa.help.AppWebDav.testWebDav
import io.legato.kazusa.help.config.LocalConfig
import io.legato.kazusa.help.coroutine.Coroutine
import io.legato.kazusa.help.storage.Restore
import io.legato.kazusa.lib.dialogs.alert
import io.legato.kazusa.lib.dialogs.selector
import io.legato.kazusa.ui.file.HandleFileContract
import io.legato.kazusa.ui.widget.dialog.WaitDialog
import io.legato.kazusa.utils.toastOnUi
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.Job
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import splitties.init.appCtx
import kotlin.coroutines.coroutineContext
class WebDavFragment : BaseFragment(R.layout.fragment_webdav_auth) {
private var _binding: FragmentWebdavAuthBinding? = null
private val binding get() = _binding!!
private var restoreJob: Job? = null
private val waitDialog by lazy { WaitDialog(requireContext()) }
private val restoreDoc = registerForActivityResult(HandleFileContract()) {
it.uri?.let { uri ->
waitDialog.setText("恢复中…")
waitDialog.show()
val task = Coroutine.async {
Restore.restore(appCtx, uri)
}.onFinally {
waitDialog.dismiss()
}
waitDialog.setOnCancelListener {
task.cancel()
}
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentWebdavAuthBinding.inflate(inflater, container, false)
return binding.root
}
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
val prefs = PreferenceManager.getDefaultSharedPreferences(requireContext())
val urls = listOf(
"https://dav.jianguoyun.com/dav/",
"https://webdav.aliyundrive.com/",
"https://dav.example.com/"
)
val adapter = ArrayAdapter(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
urls
)
binding.editUrl.setAdapter(adapter)
binding.editAccount.setText(prefs.getString(PreferKey.webDavAccount, ""))
binding.editPassword.setText(prefs.getString(PreferKey.webDavPassword, ""))
binding.editPassword.inputType =
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
binding.etPassword.setText(LocalConfig.password ?: "")
binding.etPassword.doAfterTextChanged {
LocalConfig.password = it.toString()
}
binding.btnCheck.setOnClickListener {
saveWebDavConfig()
lifecycleScope.launch {
testWebDav()
}
}
binding.btnRestore.setOnClickListener {
restore()
}
}
fun saveWebDavConfig(onSaved: (() -> Unit)? = null) {
val url = binding.editUrl.text.toString()
val account = binding.editAccount.text.toString()
val password = binding.editPassword.text.toString()
PreferenceManager.getDefaultSharedPreferences(requireContext()).edit {
putString(PreferKey.webDavUrl, url)
putString(PreferKey.webDavAccount, account)
putString(PreferKey.webDavPassword, password)
}
onSaved?.invoke()
}
fun restore() {
waitDialog.setText(R.string.loading)
waitDialog.setOnCancelListener {
restoreJob?.cancel()
}
waitDialog.show()
Coroutine.async {
restoreJob = coroutineContext[Job]
showRestoreDialog(requireContext())
}.onError {
AppLog.put("恢复备份出错WebDavError\n${it.localizedMessage}", it)
if (context == null) {
return@onError
}
alert {
setTitle(R.string.restore)
setMessage("WebDavError\n${it.localizedMessage}\n将从本地备份恢复。")
okButton {
restoreFromLocal()
}
cancelButton()
}
}.onFinally {
waitDialog.dismiss()
}
}
private suspend fun showRestoreDialog(context: Context) {
val names = withContext(IO) { AppWebDav.getBackupNames() }
if (AppWebDav.isJianGuoYun && names.size > 700) {
context.toastOnUi("由于坚果云限制列出文件数量,部分备份可能未显示,请及时清理旧备份")
}
if (names.isNotEmpty()) {
coroutineContext.ensureActive()
withContext(Main) {
context.selector(
title = context.getString(R.string.select_restore_file),
items = names
) { _, index ->
if (index in names.indices) {
restoreWebDav(names[index])
}
}
}
} else {
throw NoStackTraceException("Web dav no back up file")
}
}
private fun restoreWebDav(name: String) {
waitDialog.setText("恢复中…")
waitDialog.show()
val task = Coroutine.async {
AppWebDav.restoreWebDav(name)
}.onError {
AppLog.put("WebDav恢复出错\n${it.localizedMessage}", it)
appCtx.toastOnUi("WebDav恢复出错\n${it.localizedMessage}")
}.onFinally {
waitDialog.dismiss()
}
waitDialog.setOnCancelListener {
task.cancel()
}
}
private fun restoreFromLocal() {
restoreDoc.launch {
title = getString(R.string.select_restore_file)
mode = HandleFileContract.FILE
allowExtensions = arrayOf("zip")
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
@@ -1,86 +1,101 @@
package io.legato.kazusa.ui.welcome package io.legato.kazusa.ui.welcome
import android.content.Intent
import android.graphics.drawable.BitmapDrawable
import android.os.Bundle import android.os.Bundle
import androidx.core.view.postDelayed import androidx.activity.addCallback
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import io.legato.kazusa.base.BaseActivity import io.legato.kazusa.base.BaseActivity
import io.legato.kazusa.constant.PreferKey
import io.legato.kazusa.constant.Theme
import io.legato.kazusa.databinding.ActivityWelcomeBinding import io.legato.kazusa.databinding.ActivityWelcomeBinding
import io.legato.kazusa.help.config.ThemeConfig import io.legato.kazusa.help.config.AppConfig
//import io.legado.app.lib.theme.accentColor import io.legato.kazusa.help.config.LocalConfig
//import io.legado.app.lib.theme.backgroundColor
import io.legato.kazusa.ui.book.read.ReadBookActivity
import io.legato.kazusa.ui.main.MainActivity import io.legato.kazusa.ui.main.MainActivity
import io.legato.kazusa.utils.* import io.legato.kazusa.utils.startActivity
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
open class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() { class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() {
override val binding by viewBinding(ActivityWelcomeBinding::inflate) override val binding by viewBinding(ActivityWelcomeBinding::inflate)
private val pages = listOf(
PrivacyFragment(),
WebDavFragment(),
ThemeFragment()
)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
// binding.ivBook.setColorFilter(accentColor)
// binding.vwTitleLine.setBackgroundColor(accentColor)
// 避免从桌面启动程序后,会重新实例化入口类的activity
if (intent.flags and Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT != 0) {
finish()
} else {
binding.root.postDelayed(100) { startMainActivity() }
}
}
// override fun setupSystemBar() { onBackPressedDispatcher.addCallback(this) {
// fullScreen() val current = binding.viewPager.currentItem
// //setStatusBarColorAuto(backgroundColor, true, fullScreen) if (current > 0) {
// upNavigationBarColor() binding.viewPager.currentItem = current - 1
// } } else {
finish()
override fun upBackgroundImage() { }
if (getPrefBoolean(PreferKey.customWelcome)) { }
kotlin.runCatching {
when (ThemeConfig.getTheme()) { updateProgress(0)
Theme.Dark -> getPrefString(PreferKey.welcomeImageDark)?.let { path ->
val size = windowManager.windowSize binding.viewPager.adapter = object : FragmentStateAdapter(this) {
BitmapUtils.decodeBitmap(path, size.widthPixels, size.heightPixels).let { override fun getItemCount() = pages.size
binding.tvLegado.visible(getPrefBoolean(PreferKey.welcomeShowTextDark)) override fun createFragment(position: Int) = pages[position]
binding.ivBook.visible(getPrefBoolean(PreferKey.welcomeShowIconDark)) }
binding.tvGzh.visible(getPrefBoolean(PreferKey.welcomeShowTextDark))
window.decorView.background = BitmapDrawable(resources, it) binding.viewPager.isUserInputEnabled = false
return
} binding.viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
} override fun onPageSelected(position: Int) {
else -> getPrefString(PreferKey.welcomeImage)?.let { path -> super.onPageSelected(position)
val size = windowManager.windowSize binding.btnNext.text = when (position) {
BitmapUtils.decodeBitmap(path, size.widthPixels, size.heightPixels).let { 0 -> "阅读并同意" // PrivacyFragment
binding.tvLegado.visible(getPrefBoolean(PreferKey.welcomeShowText)) pages.lastIndex -> "完成"
binding.ivBook.visible(getPrefBoolean(PreferKey.welcomeShowIcon)) else -> "下一步"
binding.tvGzh.visible(getPrefBoolean(PreferKey.welcomeShowText)) }
window.decorView.background = BitmapDrawable(resources, it) binding.tvTitle.text = when (position) {
return 0 -> "欢迎!" // PrivacyFragment
} 1 -> "备份与恢复"
} else -> "主题样式"
}
binding.tvSummary.text = when (position) {
0 -> "请先阅读应用的服务条款与用户协议。"
1 -> "此处可设置云同步与恢复应用备份。"
else -> "在这里设置您喜爱的样式。"
} }
updateProgress(position)
}
})
// 初始化按钮文字
binding.btnNext.text = "阅读并同意"
binding.btnNext.setOnClickListener {
val current = binding.viewPager.currentItem
when (current) {
0 -> {
LocalConfig.privacyPolicyOk = true
binding.viewPager.currentItem = 1
}
pages.lastIndex -> {
updateProgress(2)
finishSetup()
}
else -> binding.viewPager.currentItem = current + 1
} }
} }
super.upBackgroundImage()
} }
private fun startMainActivity() { private fun updateProgress(position: Int) {
val progressMax = pages.size
val progress = (position * 100 / progressMax)
binding.progressBar.setProgress(progress, true)
}
private fun finishSetup() {
AppConfig.isFirstLaunch = false
startActivity<MainActivity>() startActivity<MainActivity>()
if (getPrefBoolean(PreferKey.defaultToRead)) {
startActivity<ReadBookActivity>()
}
finish() finish()
} }
} }
class Launcher1 : WelcomeActivity()
class Launcher2 : WelcomeActivity()
class Launcher3 : WelcomeActivity()
class Launcher4 : WelcomeActivity()
class Launcher5 : WelcomeActivity()
class Launcher6 : WelcomeActivity()
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorPrimaryContainer" android:state_checked="true" />
<item android:color="?attr/colorSurfaceContainerLow" />
</selector>
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorPrimaryContainer" android:state_checked="true" />
<item android:color="?attr/colorOutlineVariant" />
</selector>
@@ -33,6 +33,8 @@
android:id="@+id/refresh_progress_bar" android:id="@+id/refresh_progress_bar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:waveAmplitude="8dp"
app:wavelength="80dp"
android:indeterminate="true" android:indeterminate="true"
android:visibility="gone"> android:visibility="gone">
+54 -60
View File
@@ -1,82 +1,76 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="center_horizontal"> android:animateLayoutChanges="true"
android:fitsSystemWindows="true">
<androidx.constraintlayout.widget.ConstraintLayout <LinearLayout
android:id="@+id/tv_legado" android:id="@+id/ll_info"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintVertical_bias="0.4" android:orientation="vertical"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent">
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/iv_book">
<View <ImageView
android:id="@+id/vw_title_line" android:layout_width="56dp"
android:layout_width="6dp" android:layout_height="wrap_content"
android:layout_height="0dp" android:layout_marginStart="16dp"
android:background="@color/md_theme_primary" android:layout_marginTop="48dp"
app:layout_constraintTop_toTopOf="@+id/tv_title" android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="@+id/tv_title" android:src="@drawable/ic_launcher_foreground" />
app:layout_constraintLeft_toLeftOf="parent" />
<io.legato.kazusa.ui.widget.text.AccentTextView <TextView
android:id="@+id/tv_title" android:id="@+id/tv_title"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="6dp" android:layout_marginHorizontal="16dp"
android:ems="1" android:text="欢迎!"
android:text="阅读" android:textSize="36sp"
android:textSize="49sp" android:textStyle="bold" />
app:layout_constraintRight_toLeftOf="@+id/tv_sub_title"
app:layout_constraintLeft_toRightOf="@+id/vw_title_line"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="HardcodedText,RtlHardcoded" />
<io.legato.kazusa.ui.widget.text.AccentTextView <TextView
android:id="@+id/tv_sub_title" android:id="@+id/tv_summary"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:layout_marginLeft="6dp"
android:ems="1"
android:text="享受美好时光"
android:textSize="16sp" android:textSize="16sp"
app:layout_constraintTop_toTopOf="@+id/tv_title" android:layout_marginHorizontal="16dp"
app:layout_constraintLeft_toRightOf="@id/tv_title" android:layout_marginTop="8dp"
tools:ignore="HardcodedText,RtlHardcoded" /> android:layout_marginBottom="16dp"
android:text="请先阅读应用的服务条款与用户协议。"
android:textStyle="bold" />
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:indicatorColor="?attr/colorSecondary"
app:waveAmplitude="4dp"
app:waveSpeed="32dp"
app:wavelength="80dp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> <androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:layout_weight="1"
app:layout_constraintBottom_toTopOf="@id/btnNext"
app:layout_constraintTop_toBottomOf="@id/ll_info" />
<ImageView <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/iv_book" android:id="@+id/btnNext"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_marginBottom="32dp"
android:src="@drawable/icon_read_book"
android:scaleType="fitCenter"
android:contentDescription="@string/welcome"
app:layout_constraintBottom_toTopOf="@+id/tv_gzh"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<io.legato.kazusa.ui.widget.text.AccentTextView
android:id="@+id/tv_gzh"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="关注公众号[开源阅读]\n看文章点广告支持作者" android:layout_gravity="end"
android:layout_marginBottom="32dp" android:layout_margin="16dp"
android:gravity="center_horizontal" android:text="@string/text"
app:icon="@drawable/ic_arrow_right"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintEnd_toEndOf="parent" />
app:layout_constraintRight_toRightOf="parent"
tools:ignore="HardcodedText" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
+59 -55
View File
@@ -50,66 +50,70 @@
app:layout_constraintTop_toBottomOf="@id/tv_name_title" app:layout_constraintTop_toBottomOf="@id/tv_name_title"
tools:text="文字" /> tools:text="文字" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButtonGroup
android:id="@+id/iv_edit" android:id="@+id/mbg_1"
style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:contentDescription="@string/edit"
app:iconGravity="textStart"
app:icon="@drawable/ic_edit"
app:layout_constraintBottom_toBottomOf="@id/tv_name" app:layout_constraintBottom_toBottomOf="@id/tv_name"
app:layout_constraintEnd_toStartOf="@id/iv_delete"
app:layout_constraintTop_toTopOf="@id/tv_name" />
<com.google.android.material.button.MaterialButton
android:id="@+id/iv_delete"
style="@style/Widget.Material3Expressive.Button.IconButton.Outlined"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/delete"
app:icon="@drawable/ic_clear_all"
app:layout_constraintBottom_toBottomOf="@id/iv_edit"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/iv_edit" app:layout_constraintTop_toTopOf="@id/tv_name">
tools:ignore="UnusedAttribute" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/tv_restore" android:id="@+id/iv_edit"
android:layout_width="wrap_content" style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
style="@style/Widget.Material3Expressive.Button.OutlinedButton" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="8dp" android:contentDescription="@string/edit"
android:text="@string/restore" app:icon="@drawable/ic_edit"
app:icon="@drawable/ic_restore" app:iconGravity="textStart" />
app:layout_constraintEnd_toStartOf="@id/iv_import"
app:layout_constraintTop_toBottomOf="@id/iv_edit" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/iv_import" android:id="@+id/iv_delete"
style="@style/Widget.Material3Expressive.Button.OutlinedButton" style="@style/Widget.Material3Expressive.Button.IconButton.Outlined"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/delete"
app:icon="@drawable/ic_clear_all"
tools:ignore="UnusedAttribute" />
</com.google.android.material.button.MaterialButtonGroup>
<com.google.android.material.button.MaterialButtonGroup
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="8dp" android:layout_marginEnd="2dp"
android:contentDescription="@string/import_str"
android:text="@string/import_str"
app:icon="@drawable/ic_import"
app:layout_constraintBottom_toBottomOf="@id/tv_restore"
app:layout_constraintEnd_toStartOf="@id/iv_export"
app:layout_constraintTop_toTopOf="@id/tv_restore" />
<com.google.android.material.button.MaterialButton
android:id="@+id/iv_export"
style="@style/Widget.Material3Expressive.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/import_str"
android:text="@string/export_str"
app:icon="@drawable/ic_export"
app:layout_constraintBottom_toBottomOf="@id/iv_import"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/iv_import" /> app:layout_constraintTop_toBottomOf="@id/mbg_1">
<com.google.android.material.button.MaterialButton
android:id="@+id/tv_restore"
style="@style/Widget.Material3Expressive.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/restore"
app:icon="@drawable/ic_restore" />
<com.google.android.material.button.MaterialButton
android:id="@+id/iv_import"
style="@style/Widget.Material3Expressive.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/import_str"
android:text="@string/import_str"
app:icon="@drawable/ic_import" />
<com.google.android.material.button.MaterialButton
android:id="@+id/iv_export"
style="@style/Widget.Material3Expressive.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/import_str"
android:text="@string/export_str"
app:icon="@drawable/ic_export" />
</com.google.android.material.button.MaterialButtonGroup>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
@@ -129,7 +133,7 @@
android:text="@string/text_underline" android:text="@string/text_underline"
tools:ignore="TouchTargetSizeCheck" /> tools:ignore="TouchTargetSizeCheck" />
<LinearLayout <com.google.android.material.button.MaterialButtonGroup
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center_vertical" android:gravity="center_vertical"
@@ -141,7 +145,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
style="@style/Widget.Material3Expressive.Button.TonalButton" style="@style/Widget.Material3Expressive.Button.TonalButton"
android:layout_marginEnd="16dp" android:layout_marginEnd="8dp"
android:layout_weight="1" android:layout_weight="1"
app:icon="@drawable/ic_palette" app:icon="@drawable/ic_palette"
android:text="@string/text_color" android:text="@string/text_color"
@@ -159,7 +163,7 @@
android:text="@string/bg_color" android:text="@string/bg_color"
app:cornerRadius="12dp" /> app:cornerRadius="12dp" />
</LinearLayout> </com.google.android.material.button.MaterialButtonGroup>
<TextView <TextView
android:id="@+id/tv_bg_alpha" android:id="@+id/tv_bg_alpha"
@@ -189,7 +193,7 @@
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:paddingVertical="8dp" android:paddingVertical="8dp"
android:layout_height="100dp" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_bg_image" /> tools:listitem="@layout/item_bg_image" />
@@ -272,45 +272,37 @@
<com.google.android.material.chip.Chip <com.google.android.material.chip.Chip
android:id="@+id/rb_anim0" android:id="@+id/rb_anim0"
style="@style/Widget.Material3.Chip.Filter"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:checkable="true"
android:text="@string/page_anim_cover" /> android:text="@string/page_anim_cover" />
<!-- 滑动动画 Chip -->
<com.google.android.material.chip.Chip <com.google.android.material.chip.Chip
android:id="@+id/rb_anim1" android:id="@+id/rb_anim1"
style="@style/Widget.Material3.Chip.Filter"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="4dp" android:checkable="true"
android:text="@string/page_anim_slide" /> android:text="@string/page_anim_slide" />
<!-- 仿真翻页 Chip -->
<com.google.android.material.chip.Chip <com.google.android.material.chip.Chip
android:id="@+id/rb_simulation_anim" android:id="@+id/rb_simulation_anim"
style="@style/Widget.Material3.Chip.Filter"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="4dp" android:checkable="true"
android:text="@string/page_anim_simulation" /> android:text="@string/page_anim_simulation" />
<!-- 滚动动画 Chip -->
<com.google.android.material.chip.Chip <com.google.android.material.chip.Chip
android:id="@+id/rb_scroll_anim" android:id="@+id/rb_scroll_anim"
style="@style/Widget.Material3.Chip.Filter"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="4dp" android:checkable="true"
android:text="@string/page_anim_scroll" /> android:text="@string/page_anim_scroll" />
<!-- 无动画 Chip -->
<com.google.android.material.chip.Chip <com.google.android.material.chip.Chip
android:id="@+id/rb_no_anim" android:id="@+id/rb_no_anim"
style="@style/Widget.Material3.Chip.Filter"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="4dp" android:checkable="true"
android:text="@string/page_anim_none" /> android:text="@string/page_anim_none" />
</com.google.android.material.chip.ChipGroup> </com.google.android.material.chip.ChipGroup>
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingHorizontal="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="@string/privacy_policy"
android:textColor="?attr/colorSecondary"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvPrivacy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/text" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="@string/disclaimer"
android:textColor="?attr/colorSecondary"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvDisclaimer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
@@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingHorizontal="16dp">
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.Dense.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:hint="@string/web_dav_url">
<com.google.android.material.textfield.MaterialAutoCompleteTextView
android:id="@+id/editUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:imeOptions="actionDone"
android:inputType="textUri" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:hint="@string/web_dav_account">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editAccount"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/set_local_password" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:hint="@string/web_dav_pw"
app:endIconMode="password_toggle">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/set_local_password" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/btnRestore"
style="@style/Widget.Material3Expressive.Button.OutlinedButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_weight="2"
android:text="获取备份" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnCheck"
style="@style/Widget.Material3Expressive.Button.TonalButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/action_save" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/set_local_password_summary"
android:textSize="12sp" />
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/set_local_password">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
@@ -7,6 +7,7 @@
android:orientation="vertical"> android:orientation="vertical">
<com.google.android.material.card.MaterialCardView <com.google.android.material.card.MaterialCardView
android:id="@+id/cd_image"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1"> android:layout_weight="1">
@@ -104,6 +104,8 @@
style="@style/Widget.Material3.LinearProgressIndicator" style="@style/Widget.Material3.LinearProgressIndicator"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:waveAmplitude="8dp"
app:wavelength="80dp"
android:layout_marginTop="2dp" android:layout_marginTop="2dp"
android:visibility="gone" android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/iv_download" /> app:layout_constraintTop_toBottomOf="@id/iv_download" />
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/ll_style" android:id="@+id/ll_style"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -9,6 +10,8 @@
android:id="@+id/cd_style" android:id="@+id/cd_style"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
app:strokeColor="?attr/colorOutlineVariant"
app:strokeWidth="2dp"
android:layout_margin="4dp" android:layout_margin="4dp"
android:foreground="?android:attr/selectableItemBackground"> android:foreground="?android:attr/selectableItemBackground">
+1
View File
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/widget_frame"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
+5 -5
View File
@@ -4,16 +4,16 @@
android:id="@+id/theme_toggle_group" android:id="@+id/theme_toggle_group"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:spacing="2dp"
app:innerCornerSize="8dp"
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
android:layout_marginVertical="8dp" android:layout_marginVertical="8dp"
android:gravity="center"
app:singleSelection="true" app:singleSelection="true"
app:selectionRequired="true"> app:selectionRequired="true">
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/btn_system" android:id="@+id/btn_system"
style="@style/Widget.Material3Expressive.Button" style="@style/Widget.Material3Expressive.Button.OutlinedButton"
app:checkedIcon="@drawable/ic_check" app:checkedIcon="@drawable/ic_check"
android:checkable="true" android:checkable="true"
android:layout_width="0dp" android:layout_width="0dp"
@@ -23,7 +23,7 @@
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/btn_light" android:id="@+id/btn_light"
style="@style/Widget.Material3Expressive.Button" style="@style/Widget.Material3Expressive.Button.OutlinedButton"
app:checkedIcon="@drawable/ic_check" app:checkedIcon="@drawable/ic_check"
android:checkable="true" android:checkable="true"
android:layout_width="0dp" android:layout_width="0dp"
@@ -33,7 +33,7 @@
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/btn_dark" android:id="@+id/btn_dark"
style="@style/Widget.Material3Expressive.Button" style="@style/Widget.Material3Expressive.Button.OutlinedButton"
app:checkedIcon="@drawable/ic_check" app:checkedIcon="@drawable/ic_check"
android:checkable="true" android:checkable="true"
android:layout_width="0dp" android:layout_width="0dp"
+1
View File
@@ -5,6 +5,7 @@
<item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowLightStatusBar">false</item> <item name="android:windowLightStatusBar">false</item>
<item name="tabStyle">@style/Widget.App.TabLayout</item> <item name="tabStyle">@style/Widget.App.TabLayout</item>
<item name="chipStyle">@style/Widget.MyApp.Chip.Assist</item>
<item name="popupMenuBackground">@drawable/popup_background</item> <item name="popupMenuBackground">@drawable/popup_background</item>
<item name="alertDialogTheme">@style/AppTheme.AlertDialog</item> <item name="alertDialogTheme">@style/AppTheme.AlertDialog</item>
</style> </style>
+1 -1
View File
@@ -25,7 +25,7 @@
<dimen name="fastscroll_bubble_padding">16dp</dimen> <dimen name="fastscroll_bubble_padding">16dp</dimen>
<dimen name="fastscroll_handle_height">48dp</dimen> <dimen name="fastscroll_handle_height">48dp</dimen>
<dimen name="fastscroll_handle_width">16dp</dimen> <dimen name="fastscroll_handle_width">12dp</dimen>
<dimen name="fastscroll_handle_radius">8dp</dimen> <dimen name="fastscroll_handle_radius">8dp</dimen>
<dimen name="fastscroll_track_width">8dp</dimen> <dimen name="fastscroll_track_width">8dp</dimen>
+5
View File
@@ -32,6 +32,11 @@
<item name="android:layout" tools:ignore="PrivateResource">@layout/m3_alert_dialog</item> <item name="android:layout" tools:ignore="PrivateResource">@layout/m3_alert_dialog</item>
</style> </style>
<style name="Widget.MyApp.Chip.Assist" parent="Widget.Material3.Chip.Assist">
<item name="chipBackgroundColor">@color/chip_background_selector</item>
<item name="chipStrokeColor">@color/chip_stroke_selector</item>
</style>
<style name="TextActionMenuAnimation"> <style name="TextActionMenuAnimation">
<item name="android:windowEnterAnimation">@anim/popup_enter</item> <item name="android:windowEnterAnimation">@anim/popup_enter</item>
<item name="android:windowExitAnimation">@anim/popup_exit</item> <item name="android:windowExitAnimation">@anim/popup_exit</item>
+1
View File
@@ -6,6 +6,7 @@
<item name="android:windowDrawsSystemBarBackgrounds">true</item> <item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowLightStatusBar">true</item> <item name="android:windowLightStatusBar">true</item>
<item name="tabStyle">@style/Widget.App.TabLayout</item> <item name="tabStyle">@style/Widget.App.TabLayout</item>
<item name="chipStyle">@style/Widget.MyApp.Chip.Assist</item>
<item name="popupMenuBackground">@drawable/popup_background</item> <item name="popupMenuBackground">@drawable/popup_background</item>
<item name="alertDialogTheme">@style/AppTheme.AlertDialog</item> <item name="alertDialogTheme">@style/AppTheme.AlertDialog</item>
</style> </style>
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<io.legato.kazusa.lib.prefs.ThemeModePreference
android:defaultValue="0"
android:entries="@array/theme_mode"
android:entryValues="@array/theme_mode_v"
android:key="themeMode" />
<io.legato.kazusa.lib.prefs.ThemeCardPreference
android:defaultValue="0"
android:entries="@array/themes_item"
android:entryValues="@array/themes_value"
android:key="app_theme" />
</androidx.preference.PreferenceScreen>
+8 -8
View File
@@ -1,17 +1,17 @@
[versions] [versions]
datastorePreferences = "1.1.7" datastorePreferences = "1.1.7"
kotlin = "2.1.21" kotlin = "2.2.10"
ksp = "2.1.21-2.0.1" ksp = "2.1.21-2.0.1"
agp = "8.12.0" agp = "8.12.1"
appcompat = "1.7.1" appcompat = "1.7.1"
colorpicker = "1.1.0" colorpicker = "1.1.0"
commonsText = "1.13.1" commonsText = "1.14.0"
constraintlayout = "2.2.1" constraintlayout = "2.2.1"
core = "1.16.0" core = "1.17.0"
firebaseBom = "34.0.0" firebaseBom = "34.1.0"
flexbox = "3.0.0" flexbox = "3.0.0"
fragment = "1.8.8" fragment = "1.8.9"
#不要更新版本 #不要更新版本
hutool = "5.8.22" hutool = "5.8.22"
@@ -28,7 +28,7 @@ jsoupxpath = "2.5.3"
coroutines = "1.10.2" coroutines = "1.10.2"
liveeventbus = "1.8.14" liveeventbus = "1.8.14"
markwon = "4.6.2" markwon = "4.6.2"
material = "1.14.0-alpha03" material = "1.14.0-alpha04"
media = "1.7.0" media = "1.7.0"
media3 = "1.7.1" media3 = "1.7.1"
nanoHttpd = "2.3.1" nanoHttpd = "2.3.1"
@@ -52,7 +52,7 @@ viewpager2 = "1.0.0"
webkit = "1.14.0" webkit = "1.14.0"
collection = "1.5.0" collection = "1.5.0"
zxingLite = "3.2.0" zxingLite = "3.3.0"
[libraries] [libraries]