优化
This commit is contained in:
@@ -114,7 +114,7 @@ object AppWebDav {
|
|||||||
webDav.downloadTo(Backup.zipFilePath, true)
|
webDav.downloadTo(Backup.zipFilePath, true)
|
||||||
FileUtils.delete(Backup.backupPath)
|
FileUtils.delete(Backup.backupPath)
|
||||||
ZipUtils.unZipToPath(File(Backup.zipFilePath), Backup.backupPath)
|
ZipUtils.unZipToPath(File(Backup.zipFilePath), Backup.backupPath)
|
||||||
Restore.restore(Backup.backupPath)
|
Restore.restoreLocked(Backup.backupPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -207,7 +207,11 @@ object Backup {
|
|||||||
copyBackup(File(path), backupFileName)
|
copyBackup(File(path), backupFileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AppWebDav.backUpWebDav(zipFileName)
|
try {
|
||||||
|
AppWebDav.backUpWebDav(zipFileName)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
AppLog.put("上传备份至webdav失败\n$e", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FileUtils.delete(backupPath)
|
FileUtils.delete(backupPath)
|
||||||
FileUtils.delete(zipFilePath)
|
FileUtils.delete(zipFilePath)
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ import io.legado.app.utils.openInputStream
|
|||||||
import io.legado.app.utils.toastOnUi
|
import io.legado.app.utils.toastOnUi
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -59,6 +61,8 @@ import java.io.FileInputStream
|
|||||||
*/
|
*/
|
||||||
object Restore {
|
object Restore {
|
||||||
|
|
||||||
|
private val mutex = Mutex()
|
||||||
|
|
||||||
private const val TAG = "Restore"
|
private const val TAG = "Restore"
|
||||||
|
|
||||||
suspend fun restore(context: Context, uri: Uri) {
|
suspend fun restore(context: Context, uri: Uri) {
|
||||||
@@ -77,7 +81,7 @@ object Restore {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
restore(Backup.backupPath)
|
restoreLocked(Backup.backupPath)
|
||||||
LocalConfig.lastBackup = System.currentTimeMillis()
|
LocalConfig.lastBackup = System.currentTimeMillis()
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
appCtx.toastOnUi("恢复备份出错\n${it.localizedMessage}")
|
appCtx.toastOnUi("恢复备份出错\n${it.localizedMessage}")
|
||||||
@@ -85,7 +89,13 @@ object Restore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun restore(path: String) {
|
suspend fun restoreLocked(path: String) {
|
||||||
|
mutex.withLock {
|
||||||
|
restore(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun restore(path: String) {
|
||||||
val aes = BackupAES()
|
val aes = BackupAES()
|
||||||
fileToListT<Book>(path, "bookshelf.json")?.let {
|
fileToListT<Book>(path, "bookshelf.json")?.let {
|
||||||
it.forEach { book ->
|
it.forEach { book ->
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ package io.legado.app.lib.prefs
|
|||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.view.forEach
|
||||||
import androidx.preference.ListPreferenceDialogFragmentCompat
|
import androidx.preference.ListPreferenceDialogFragmentCompat
|
||||||
import androidx.preference.PreferenceDialogFragmentCompat
|
import androidx.preference.PreferenceDialogFragmentCompat
|
||||||
import io.legado.app.lib.theme.accentColor
|
import io.legado.app.lib.theme.accentColor
|
||||||
import io.legado.app.lib.theme.filletBackground
|
import io.legado.app.lib.theme.filletBackground
|
||||||
|
import io.legado.app.utils.applyTint
|
||||||
|
|
||||||
class ListPreferenceDialog : ListPreferenceDialogFragmentCompat() {
|
class ListPreferenceDialog : ListPreferenceDialogFragmentCompat() {
|
||||||
|
|
||||||
@@ -30,6 +32,9 @@ class ListPreferenceDialog : ListPreferenceDialogFragmentCompat() {
|
|||||||
getButton(AlertDialog.BUTTON_NEGATIVE)?.setTextColor(accentColor)
|
getButton(AlertDialog.BUTTON_NEGATIVE)?.setTextColor(accentColor)
|
||||||
getButton(AlertDialog.BUTTON_POSITIVE)?.setTextColor(accentColor)
|
getButton(AlertDialog.BUTTON_POSITIVE)?.setTextColor(accentColor)
|
||||||
getButton(AlertDialog.BUTTON_NEUTRAL)?.setTextColor(accentColor)
|
getButton(AlertDialog.BUTTON_NEUTRAL)?.setTextColor(accentColor)
|
||||||
|
listView?.forEach {
|
||||||
|
it.applyTint(accentColor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dialog
|
return dialog
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ package io.legado.app.lib.prefs
|
|||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.view.forEach
|
||||||
import androidx.preference.MultiSelectListPreferenceDialogFragmentCompat
|
import androidx.preference.MultiSelectListPreferenceDialogFragmentCompat
|
||||||
import androidx.preference.PreferenceDialogFragmentCompat
|
import androidx.preference.PreferenceDialogFragmentCompat
|
||||||
import io.legado.app.lib.theme.accentColor
|
import io.legado.app.lib.theme.accentColor
|
||||||
import io.legado.app.lib.theme.filletBackground
|
import io.legado.app.lib.theme.filletBackground
|
||||||
|
import io.legado.app.utils.applyTint
|
||||||
|
|
||||||
class MultiSelectListPreferenceDialog : MultiSelectListPreferenceDialogFragmentCompat() {
|
class MultiSelectListPreferenceDialog : MultiSelectListPreferenceDialogFragmentCompat() {
|
||||||
|
|
||||||
@@ -32,6 +34,9 @@ class MultiSelectListPreferenceDialog : MultiSelectListPreferenceDialogFragmentC
|
|||||||
getButton(AlertDialog.BUTTON_NEGATIVE)?.setTextColor(accentColor)
|
getButton(AlertDialog.BUTTON_NEGATIVE)?.setTextColor(accentColor)
|
||||||
getButton(AlertDialog.BUTTON_POSITIVE)?.setTextColor(accentColor)
|
getButton(AlertDialog.BUTTON_POSITIVE)?.setTextColor(accentColor)
|
||||||
getButton(AlertDialog.BUTTON_NEUTRAL)?.setTextColor(accentColor)
|
getButton(AlertDialog.BUTTON_NEUTRAL)?.setTextColor(accentColor)
|
||||||
|
listView?.forEach {
|
||||||
|
it.applyTint(accentColor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dialog
|
return dialog
|
||||||
|
|||||||
@@ -7,7 +7,16 @@ import android.graphics.PorterDuff
|
|||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.graphics.drawable.RippleDrawable
|
import android.graphics.drawable.RippleDrawable
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.*
|
import android.widget.Button
|
||||||
|
import android.widget.CheckBox
|
||||||
|
import android.widget.CheckedTextView
|
||||||
|
import android.widget.EditText
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.ProgressBar
|
||||||
|
import android.widget.RadioButton
|
||||||
|
import android.widget.SeekBar
|
||||||
|
import android.widget.Switch
|
||||||
|
import android.widget.TextView
|
||||||
import androidx.annotation.CheckResult
|
import androidx.annotation.CheckResult
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
import androidx.appcompat.widget.AppCompatEditText
|
import androidx.appcompat.widget.AppCompatEditText
|
||||||
@@ -15,6 +24,7 @@ import androidx.appcompat.widget.SearchView
|
|||||||
import androidx.appcompat.widget.SwitchCompat
|
import androidx.appcompat.widget.SwitchCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.graphics.drawable.DrawableCompat
|
import androidx.core.graphics.drawable.DrawableCompat
|
||||||
|
import androidx.core.widget.TextViewCompat
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.utils.ColorUtils
|
import io.legado.app.utils.ColorUtils
|
||||||
@@ -144,6 +154,7 @@ object TintHelper {
|
|||||||
is ProgressBar -> setTint(view, color)
|
is ProgressBar -> setTint(view, color)
|
||||||
is AppCompatEditText -> setTint(view, color, isDark)
|
is AppCompatEditText -> setTint(view, color, isDark)
|
||||||
is CheckBox -> setTint(view, color, isDark)
|
is CheckBox -> setTint(view, color, isDark)
|
||||||
|
is CheckedTextView -> setTint(view, color, isDark)
|
||||||
is ImageView -> setTint(view, color)
|
is ImageView -> setTint(view, color)
|
||||||
is Switch -> setTint(view, color, isDark)
|
is Switch -> setTint(view, color, isDark)
|
||||||
is SwitchCompat -> setTint(view, color, isDark)
|
is SwitchCompat -> setTint(view, color, isDark)
|
||||||
@@ -299,6 +310,29 @@ object TintHelper {
|
|||||||
box.buttonTintList = sl
|
box.buttonTintList = sl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("PrivateResource")
|
||||||
|
fun setTint(checkedTextView: CheckedTextView, @ColorInt color: Int, useDarker: Boolean) {
|
||||||
|
val sl = ColorStateList(
|
||||||
|
arrayOf(
|
||||||
|
intArrayOf(-android.R.attr.state_enabled),
|
||||||
|
intArrayOf(android.R.attr.state_enabled, -android.R.attr.state_checked),
|
||||||
|
intArrayOf(android.R.attr.state_enabled, android.R.attr.state_checked)
|
||||||
|
), intArrayOf(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
checkedTextView.context,
|
||||||
|
if (useDarker) R.color.ate_control_disabled_dark else R.color.ate_control_disabled_light
|
||||||
|
),
|
||||||
|
ContextCompat.getColor(
|
||||||
|
checkedTextView.context,
|
||||||
|
if (useDarker) R.color.ate_control_normal_dark else R.color.ate_control_normal_light
|
||||||
|
),
|
||||||
|
color
|
||||||
|
)
|
||||||
|
)
|
||||||
|
checkedTextView.checkMarkTintList = sl
|
||||||
|
TextViewCompat.setCompoundDrawableTintList(checkedTextView, sl)
|
||||||
|
}
|
||||||
|
|
||||||
fun setTint(image: ImageView, @ColorInt color: Int) {
|
fun setTint(image: ImageView, @ColorInt color: Int) {
|
||||||
image.setColorFilter(color, PorterDuff.Mode.SRC_ATOP)
|
image.setColorFilter(color, PorterDuff.Mode.SRC_ATOP)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ package io.legado.app.utils
|
|||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.view.forEach
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import io.legado.app.lib.theme.Selector
|
import io.legado.app.lib.theme.Selector
|
||||||
import io.legado.app.lib.theme.ThemeStore
|
import io.legado.app.lib.theme.ThemeStore
|
||||||
|
import io.legado.app.lib.theme.accentColor
|
||||||
import io.legado.app.lib.theme.filletBackground
|
import io.legado.app.lib.theme.filletBackground
|
||||||
import splitties.systemservices.windowManager
|
import splitties.systemservices.windowManager
|
||||||
|
|
||||||
@@ -24,6 +26,11 @@ fun AlertDialog.applyTint(): AlertDialog {
|
|||||||
if (getButton(AlertDialog.BUTTON_NEUTRAL) != null) {
|
if (getButton(AlertDialog.BUTTON_NEUTRAL) != null) {
|
||||||
getButton(AlertDialog.BUTTON_NEUTRAL).setTextColor(colorStateList)
|
getButton(AlertDialog.BUTTON_NEUTRAL).setTextColor(colorStateList)
|
||||||
}
|
}
|
||||||
|
window?.decorView?.post {
|
||||||
|
listView?.forEach {
|
||||||
|
it.applyTint(context.accentColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,9 +153,10 @@ object UrlUtil {
|
|||||||
/* 获取合法的文件后缀 */
|
/* 获取合法的文件后缀 */
|
||||||
fun getSuffix(str: String, default: String? = null): String {
|
fun getSuffix(str: String, default: String? = null): String {
|
||||||
val suffix = CustomUrl(str).getUrl()
|
val suffix = CustomUrl(str).getUrl()
|
||||||
.substringAfterLast(".", "")
|
.substringAfterLast("/")
|
||||||
.substringBefore("?")
|
.substringBefore("?")
|
||||||
.substringBefore("/")
|
.substringBefore("#")
|
||||||
|
.substringAfterLast(".", "")
|
||||||
//检查截取的后缀字符是否合法 [a-zA-Z0-9]
|
//检查截取的后缀字符是否合法 [a-zA-Z0-9]
|
||||||
return if (suffix.length > 5 || !suffix.matches(fileSuffixRegex)) {
|
return if (suffix.length > 5 || !suffix.matches(fileSuffixRegex)) {
|
||||||
AppLog.put("Cannot find legal suffix:\n target: $str\n suffix: $suffix")
|
AppLog.put("Cannot find legal suffix:\n target: $str\n suffix: $suffix")
|
||||||
|
|||||||
Reference in New Issue
Block a user