kunfei 3 лет назад
Родитель
Сommit
c8bfe5c6ce

+ 1 - 18
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<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()))
-                }
-            }
-        }
-    }
-
 }

+ 150 - 0
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<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()
+            }
+        }
+
+    }
+
+}

+ 12 - 0
app/src/main/res/menu/crash_log.xml

@@ -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>