修复初始化界面备份失败与NPE问题

This commit is contained in:
HapeLee committed 2025-08-27 14:14:09 +08:00
1 parent 98c2aa6d2b
commit 9b1c155f77
6 files changed
+143 -89

No files matched your search

+3 -1
View File
@@ -135,7 +135,9 @@
</activity> </activity>
<activity <activity
android:name=".ui.welcome.WelcomeActivity" android:name=".ui.welcome.WelcomeActivity"
android:exported="false" /> android:enableOnBackInvokedCallback="true"
android:exported="false"
android:windowSoftInputMode="adjustPan|stateHidden" />
<!-- 阅读界面 --> <!-- 阅读界面 -->
<activity <activity
android:name=".ui.book.read.ReadBookActivity" android:name=".ui.book.read.ReadBookActivity"
@@ -2,6 +2,7 @@ package io.legato.kazusa.help.storage
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import androidx.core.content.edit
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import io.legato.kazusa.BuildConfig import io.legato.kazusa.BuildConfig
import io.legato.kazusa.R import io.legato.kazusa.R
@@ -231,36 +232,36 @@ object Restore {
} }
//AppWebDav.downBgs() //AppWebDav.downBgs()
appCtx.getSharedPreferences(path, "config")?.all?.let { map -> appCtx.getSharedPreferences(path, "config")?.all?.let { map ->
val edit = appCtx.defaultSharedPreferences.edit() appCtx.defaultSharedPreferences.edit {
map.forEach { (key, value) -> map.forEach { (key, value) ->
if (BackupConfig.keyIsNotIgnore(key)) { if (BackupConfig.keyIsNotIgnore(key)) {
when (key) { when (key) {
PreferKey.webDavPassword -> { PreferKey.webDavPassword -> {
kotlin.runCatching { kotlin.runCatching {
aes.decryptStr(value.toString()) aes.decryptStr(value.toString())
}.getOrNull()?.let { }.getOrNull()?.let {
edit.putString(key, it) putString(key, it)
} ?: let { } ?: let {
if (appCtx.getPrefString(PreferKey.webDavPassword) if (appCtx.getPrefString(PreferKey.webDavPassword)
.isNullOrBlank() .isNullOrBlank()
) { ) {
edit.putString(key, value.toString()) putString(key, value.toString())
}
} }
} }
}
else -> when (value) { else -> when (value) {
is Int -> edit.putInt(key, value) is Int -> putInt(key, value)
is Boolean -> edit.putBoolean(key, value) is Boolean -> putBoolean(key, value)
is Long -> edit.putLong(key, value) is Long -> putLong(key, value)
is Float -> edit.putFloat(key, value) is Float -> putFloat(key, value)
is String -> edit.putString(key, value) is String -> putString(key, value)
}
} }
} }
} }
} }
edit.apply()
} }
ReadBookConfig.apply { ReadBookConfig.apply {
comicStyleSelect = appCtx.getPrefInt(PreferKey.comicStyleSelect) comicStyleSelect = appCtx.getPrefInt(PreferKey.comicStyleSelect)
@@ -26,7 +26,9 @@ 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.ui.file.HandleFileContract import io.legato.kazusa.ui.file.HandleFileContract
import io.legato.kazusa.ui.widget.dialog.WaitDialog import io.legato.kazusa.ui.widget.dialog.WaitDialog
import io.legato.kazusa.utils.gone
import io.legato.kazusa.utils.toastOnUi import io.legato.kazusa.utils.toastOnUi
import io.legato.kazusa.utils.visible
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@@ -43,12 +45,6 @@ class WebDavFragment : BaseFragment(R.layout.fragment_webdav_auth) {
private var restoreJob: Job? = null private var restoreJob: Job? = null
private val waitDialog by lazy { WaitDialog(requireContext()) } private val waitDialog by lazy { WaitDialog(requireContext()) }
interface WebDavActions {
fun onSaveWebDavConfig()
}
var listener: WebDavActions? = null
private val restoreDoc = registerForActivityResult(HandleFileContract()) { private val restoreDoc = registerForActivityResult(HandleFileContract()) {
it.uri?.let { uri -> it.uri?.let { uri ->
waitDialog.setText("恢复中…") waitDialog.setText("恢复中…")
@@ -102,28 +98,44 @@ class WebDavFragment : BaseFragment(R.layout.fragment_webdav_auth) {
} }
binding.btnCheck.setOnClickListener { binding.btnCheck.setOnClickListener {
saveWebDavConfig() val config = WebDavConfig(
url = binding.editUrl.text.toString(),
account = binding.editAccount.text.toString(),
password = binding.editPassword.text.toString()
)
saveWebDavConfig(config)
lifecycleScope.launch { lifecycleScope.launch {
testWebDav() testWebDav()
} }
} }
binding.btnRestore.setOnClickListener { binding.btnRestore.setOnClickListener {
restore() val config = WebDavConfig(
url = binding.editUrl.text.toString(),
account = binding.editAccount.text.toString(),
password = binding.editPassword.text.toString()
)
lifecycleScope.launch {
try {
binding.progressRestore.visible()
binding.btnRestore.text = ""
saveWebDavConfig(config)
AppWebDav.upConfig()
restore()
} finally {
binding.progressRestore.gone()
binding.btnRestore.text = "获取备份"
}
}
} }
} }
fun saveWebDavConfig(onSaved: (() -> Unit)? = null) { fun saveWebDavConfig(config: WebDavConfig, 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 { PreferenceManager.getDefaultSharedPreferences(requireContext()).edit {
putString(PreferKey.webDavUrl, url) putString(PreferKey.webDavUrl, config.url)
putString(PreferKey.webDavAccount, account) putString(PreferKey.webDavAccount, config.account)
putString(PreferKey.webDavPassword, password) putString(PreferKey.webDavPassword, config.password)
} }
onSaved?.invoke() onSaved?.invoke()
@@ -205,6 +217,14 @@ class WebDavFragment : BaseFragment(R.layout.fragment_webdav_auth) {
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
waitDialog.dismiss() // 确保释放
_binding = null _binding = null
} }
} }
data class WebDavConfig(
val url: String,
val account: String,
val password: String
)
@@ -17,8 +17,6 @@ class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() {
override val binding by viewBinding(ActivityWelcomeBinding::inflate) override val binding by viewBinding(ActivityWelcomeBinding::inflate)
private val webDavFragment: WebDavFragment
get() = pages[1] as WebDavFragment
private val pages = listOf( private val pages = listOf(
PrivacyFragment(), PrivacyFragment(),
WebDavFragment(), WebDavFragment(),
@@ -71,13 +69,6 @@ class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() {
// 初始化按钮文字 // 初始化按钮文字
binding.btnNext.text = "阅读并同意" binding.btnNext.text = "阅读并同意"
(webDavFragment).listener = object : WebDavFragment.WebDavActions {
override fun onSaveWebDavConfig() {
webDavFragment.saveWebDavConfig()
}
}
binding.btnNext.setOnClickListener { binding.btnNext.setOnClickListener {
val current = binding.viewPager.currentItem val current = binding.viewPager.currentItem
when (current) { when (current) {
@@ -92,7 +83,6 @@ class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() {
} }
else -> { else -> {
webDavFragment.listener?.onSaveWebDavConfig()
binding.viewPager.currentItem = current + 1 binding.viewPager.currentItem = current + 1
} }
} }
+52 -32
View File
@@ -1,45 +1,65 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:orientation="vertical"
android:paddingHorizontal="16dp"> android:paddingHorizontal="16dp"
android:paddingBottom="8dp">
<LinearLayout <androidx.core.widget.NestedScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:orientation="vertical"> app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="8dp" android:orientation="vertical">
android:text="@string/privacy_policy"
android:textColor="?attr/colorSecondary"
android:textSize="16sp"
android:textStyle="bold" />
<TextView <TextView
android:id="@+id/tvPrivacy" android:layout_width="match_parent"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:layout_marginBottom="8dp"
android:layout_marginBottom="16dp" android:text="@string/privacy_policy"
android:text="@string/text" /> android:textColor="?attr/colorSecondary"
android:textSize="16sp"
android:textStyle="bold" />
<TextView <TextView
android:layout_width="match_parent" android:id="@+id/tvPrivacy"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:layout_marginBottom="8dp" android:layout_height="wrap_content"
android:text="@string/disclaimer" android:layout_marginBottom="16dp"
android:textColor="?attr/colorSecondary" android:text="@string/text" />
android:textSize="16sp"
android:textStyle="bold" />
<TextView <TextView
android:id="@+id/tvDisclaimer" android:layout_width="match_parent"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:layout_marginBottom="8dp"
android:text="@string/text" /> android:text="@string/disclaimer"
</LinearLayout> android:textColor="?attr/colorSecondary"
android:textSize="16sp"
android:textStyle="bold" />
</androidx.core.widget.NestedScrollView> <TextView
android:id="@+id/tvDisclaimer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<ImageView
android:layout_width="match_parent"
android:layout_height="60dp"
android:src="@drawable/bg_gradient_mask"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -56,20 +56,41 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal"> android:orientation="horizontal">
<com.google.android.material.button.MaterialButton <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/btnRestore" android:layout_width="wrap_content"
style="@style/Widget.Material3Expressive.Button.OutlinedButton"
android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="16dp" android:layout_marginEnd="8dp"
android:layout_weight="2" android:layout_weight="1">
android:text="获取备份" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnRestore"
style="@style/Widget.Material3Expressive.Button.OutlinedButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="获取备份"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.loadingindicator.LoadingIndicator
android:id="@+id/progressRestore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/btnCheck" android:id="@+id/btnCheck"
style="@style/Widget.Material3Expressive.Button.TonalButton" style="@style/Widget.Material3Expressive.Button.TonalButton"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_weight="1" android:layout_weight="1"
android:text="@string/action_save" /> android:text="@string/action_save" />