This commit is contained in:
kunfei 2023-04-03 17:36:55 +08:00
parent bd2581954a
commit a3e0c2dd34
3 changed files with 163 additions and 18 deletions

View File

@ -13,7 +13,6 @@ import io.legado.app.constant.AppConst
import io.legado.app.constant.AppConst.appInfo
import io.legado.app.help.AppUpdate
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.dialogs.selector
import io.legado.app.lib.prefs.PreferenceCategory
import io.legado.app.ui.widget.dialog.TextDialog
import io.legado.app.ui.widget.dialog.WaitDialog
@ -75,7 +74,7 @@ class AboutFragment : PreferenceFragmentCompat() {
"privacyPolicy" -> showMdFile(getString(R.string.privacy_policy), "privacyPolicy.md")
"qq" -> showQqGroups()
"gzGzh" -> requireContext().sendToClip(getString(R.string.legado_gzh))
"crashLog" -> showCrashLogs()
"crashLog" -> showDialogFragment<CrashLogsDialog>()
"qqChannel" -> context?.openUrl(qqChannel)
"tg" -> openUrl(R.string.tg_url)
"discord" -> openUrl(R.string.discord_url)
@ -152,20 +151,4 @@ class AboutFragment : PreferenceFragmentCompat() {
return false
}
private fun showCrashLogs() {
context?.externalCacheDir?.let { exCacheDir ->
val crashDir = exCacheDir.getFile("crash")
val crashLogs = crashDir.listFiles()
val crashLogNames = arrayListOf<String>()
crashLogs?.forEach {
crashLogNames.add(it.name)
}
context?.selector(R.string.crash_log, crashLogNames) { _, select ->
crashLogs?.getOrNull(select)?.let { logFile ->
showDialogFragment(TextDialog("Crash log", logFile.readText()))
}
}
}
}
}

View File

@ -0,0 +1,150 @@
package io.legado.app.ui.about
import android.app.Application
import android.net.Uri
import android.os.Bundle
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.viewModels
import androidx.lifecycle.MutableLiveData
import androidx.recyclerview.widget.LinearLayoutManager
import io.legado.app.R
import io.legado.app.base.BaseDialogFragment
import io.legado.app.base.BaseViewModel
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.Item1lineTextBinding
import io.legado.app.help.config.AppConfig
import io.legado.app.lib.theme.primaryColor
import io.legado.app.ui.widget.dialog.TextDialog
import io.legado.app.utils.*
import io.legado.app.utils.viewbindingdelegate.viewBinding
import kotlinx.coroutines.isActive
import java.io.FileFilter
class CrashLogsDialog : BaseDialogFragment(R.layout.dialog_recycler_view),
Toolbar.OnMenuItemClickListener {
private val binding by viewBinding(DialogRecyclerViewBinding::bind)
private val viewModel by viewModels<CrashViewModel>()
private val adapter by lazy { LogAdapter() }
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
binding.toolBar.setBackgroundColor(primaryColor)
binding.toolBar.setTitle(R.string.crash_log)
binding.toolBar.inflateMenu(R.menu.crash_log)
binding.toolBar.setOnMenuItemClickListener(this)
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
binding.recyclerView.adapter = adapter
viewModel.logLiveData.observe(viewLifecycleOwner) {
adapter.setItems(it)
}
viewModel.initData()
}
override fun onMenuItemClick(item: MenuItem): Boolean {
when (item.itemId) {
R.id.menu_clear -> viewModel.clearCrashLog()
}
return true
}
private fun showLogFile(fileDoc: FileDoc) {
viewModel.readFile(fileDoc) {
if (isActive) {
showDialogFragment(TextDialog(fileDoc.name, it))
}
}
}
inner class LogAdapter : RecyclerAdapter<FileDoc, Item1lineTextBinding>(requireContext()) {
override fun getViewBinding(parent: ViewGroup): Item1lineTextBinding {
return Item1lineTextBinding.inflate(inflater, parent, false)
}
override fun registerListener(holder: ItemViewHolder, binding: Item1lineTextBinding) {
binding.root.setOnClickListener {
getItemByLayoutPosition(holder.layoutPosition)?.let { item ->
showLogFile(item)
}
}
}
override fun convert(
holder: ItemViewHolder,
binding: Item1lineTextBinding,
item: FileDoc,
payloads: MutableList<Any>
) {
binding.textView.text = item.name
}
}
class CrashViewModel(application: Application) : BaseViewModel(application) {
val logLiveData = MutableLiveData<List<FileDoc>>()
fun initData() {
execute {
val list = arrayListOf<FileDoc>()
context.externalCacheDir
?.getFile("crash")
?.listFiles(FileFilter { it.isFile })
?.forEach {
list.add(FileDoc.fromFile(it))
}
val backupPath = AppConfig.backupPath
if (!backupPath.isNullOrEmpty()) {
val uri = Uri.parse(backupPath)
FileDoc.fromUri(uri, true).list {
!it.isDir
}?.let {
list.addAll(it)
}
}
return@execute list.sortedByDescending { it.name }
}.onSuccess {
logLiveData.postValue(it)
}
}
fun readFile(fileDoc: FileDoc, success: (String) -> Unit) {
execute {
String(fileDoc.readBytes())
}.onSuccess {
success.invoke(it)
}.onError {
context.toastOnUi(it.localizedMessage)
}
}
fun clearCrashLog() {
execute {
context.externalCacheDir
?.getFile("crash")
?.let {
FileUtils.delete(it, false)
}
val backupPath = AppConfig.backupPath
if (!backupPath.isNullOrEmpty()) {
val uri = Uri.parse(backupPath)
FileDoc.fromUri(uri, true).list()?.let {
}
}
}.onError {
context.toastOnUi(it.localizedMessage)
}.onFinally {
initData()
}
}
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="AlwaysShowAction">
<item
android:id="@+id/menu_clear"
android:title="@string/clear"
app:showAsAction="always" />
</menu>