From a3e0c2dd34f80edafaba071066b2c31751b9e3cc Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 3 Apr 2023 17:36:55 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/legado/app/ui/about/AboutFragment.kt | 19 +-- .../io/legado/app/ui/about/CrashLogsDialog.kt | 150 ++++++++++++++++++ app/src/main/res/menu/crash_log.xml | 12 ++ 3 files changed, 163 insertions(+), 18 deletions(-) create mode 100644 app/src/main/java/io/legado/app/ui/about/CrashLogsDialog.kt create mode 100644 app/src/main/res/menu/crash_log.xml diff --git a/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt b/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt index 03df183e9..c7c8ea659 100644 --- a/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt +++ b/app/src/main/java/io/legado/app/ui/about/AboutFragment.kt @@ -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() "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() - 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())) - } - } - } - } - } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/about/CrashLogsDialog.kt b/app/src/main/java/io/legado/app/ui/about/CrashLogsDialog.kt new file mode 100644 index 000000000..aaa06f25f --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/about/CrashLogsDialog.kt @@ -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() + 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(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 + ) { + binding.textView.text = item.name + } + + } + + class CrashViewModel(application: Application) : BaseViewModel(application) { + + val logLiveData = MutableLiveData>() + + fun initData() { + execute { + val list = arrayListOf() + 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() + } + } + + } + +} \ No newline at end of file diff --git a/app/src/main/res/menu/crash_log.xml b/app/src/main/res/menu/crash_log.xml new file mode 100644 index 000000000..3d17348bb --- /dev/null +++ b/app/src/main/res/menu/crash_log.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file