更新关于界面
搜索书籍界面切换至SearchBar与SearchView
This commit is contained in:
1 parent
3db111e87d
commit
ccaf8973fe
18 files changed
+798
-490
No files matched your search
@@ -1,53 +1,97 @@
|
||||
package io.legato.kazusa.ui.about
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.util.TypedValue
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.base.BaseActivity
|
||||
import io.legato.kazusa.databinding.ActivityAboutBinding
|
||||
//import io.legado.app.lib.theme.accentColor
|
||||
//import io.legado.app.lib.theme.filletBackground
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.net.toUri
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.base.BaseActivity
|
||||
import io.legato.kazusa.constant.AppLog
|
||||
import io.legato.kazusa.databinding.ActivityAboutBinding
|
||||
import io.legato.kazusa.help.CrashHandler
|
||||
import io.legato.kazusa.help.config.AppConfig
|
||||
import io.legato.kazusa.help.coroutine.Coroutine
|
||||
import io.legato.kazusa.help.update.AppUpdate
|
||||
import io.legato.kazusa.ui.widget.dialog.TextDialog
|
||||
import io.legato.kazusa.ui.widget.dialog.WaitDialog
|
||||
import io.legato.kazusa.utils.FileDoc
|
||||
import io.legato.kazusa.utils.compress.ZipUtils
|
||||
import io.legato.kazusa.utils.createFileIfNotExist
|
||||
import io.legato.kazusa.utils.createFolderIfNotExist
|
||||
import io.legato.kazusa.utils.delete
|
||||
import io.legato.kazusa.utils.externalCache
|
||||
import io.legato.kazusa.utils.find
|
||||
import io.legato.kazusa.utils.list
|
||||
import io.legato.kazusa.utils.openInputStream
|
||||
import io.legato.kazusa.utils.openOutputStream
|
||||
import io.legato.kazusa.utils.openUrl
|
||||
import io.legato.kazusa.utils.share
|
||||
import io.legato.kazusa.utils.showDialogFragment
|
||||
import io.legato.kazusa.utils.toastOnUi
|
||||
import io.legato.kazusa.utils.viewbindingdelegate.viewBinding
|
||||
import kotlinx.coroutines.delay
|
||||
import splitties.init.appCtx
|
||||
import java.io.File
|
||||
|
||||
|
||||
class AboutActivity : BaseActivity<ActivityAboutBinding>() {
|
||||
|
||||
override val binding by viewBinding(ActivityAboutBinding::inflate)
|
||||
|
||||
private val waitDialog by lazy {
|
||||
WaitDialog(this).setText(R.string.checking_update)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setSupportActionBar(binding.topBar)
|
||||
|
||||
val fTag = "aboutFragment"
|
||||
var aboutFragment = supportFragmentManager.findFragmentByTag(fTag)
|
||||
if (aboutFragment == null) aboutFragment = AboutFragment()
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.fl_fragment, aboutFragment, fTag)
|
||||
.commit()
|
||||
binding.tvAppSummary.post {
|
||||
kotlin.runCatching {
|
||||
val typedValue = TypedValue()
|
||||
val context = binding.root.context
|
||||
context.theme.resolveAttribute(
|
||||
androidx.appcompat.R.attr.colorPrimary,
|
||||
typedValue,
|
||||
true
|
||||
)
|
||||
val accentColor = typedValue.data
|
||||
val spannableString = SpannableString(binding.tvAppSummary.text)
|
||||
val gzh = getString(R.string.legado_gzh)
|
||||
val start = spannableString.indexOf(gzh)
|
||||
spannableString.setSpan(
|
||||
accentColor, start, start + gzh.length,
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||
)
|
||||
binding.tvAppSummary.text = spannableString
|
||||
}
|
||||
binding.btnUpdate.setOnClickListener {
|
||||
checkUpdate()
|
||||
}
|
||||
|
||||
binding.btnGithub.setOnClickListener {
|
||||
openUrl(R.string.github_url)
|
||||
}
|
||||
|
||||
binding.btnWeb.setOnClickListener {
|
||||
openUrl(R.string.legado_url)
|
||||
}
|
||||
|
||||
binding.llContributors.setOnClickListener {
|
||||
openUrl(R.string.contributors_url)
|
||||
}
|
||||
|
||||
binding.llUpdateLog.setOnClickListener {
|
||||
showMdFile(getString(R.string.update_log), "updateLog.md")
|
||||
}
|
||||
|
||||
binding.llPrivacyPolicy.setOnClickListener {
|
||||
showMdFile(getString(R.string.privacy_policy), "privacyPolicy.md")
|
||||
}
|
||||
|
||||
binding.llLicense.setOnClickListener {
|
||||
showMdFile(getString(R.string.license), "LICENSE.md")
|
||||
}
|
||||
|
||||
binding.llDisclaimer.setOnClickListener {
|
||||
showMdFile(getString(R.string.disclaimer), "disclaimer.md")
|
||||
}
|
||||
|
||||
binding.llCrashLog.setOnClickListener {
|
||||
showDialogFragment<CrashLogsDialog>()
|
||||
}
|
||||
|
||||
binding.llSaveLog.setOnClickListener {
|
||||
saveLog()
|
||||
}
|
||||
|
||||
binding.llCreateHeapDump.setOnClickListener {
|
||||
createHeapDump()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +102,6 @@ class AboutActivity : BaseActivity<ActivityAboutBinding>() {
|
||||
|
||||
override fun onCompatOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.menu_scoring -> openUrl("market://details?id=$packageName")
|
||||
R.id.menu_share_it -> share(
|
||||
getString(R.string.app_share_description),
|
||||
getString(R.string.app_name)
|
||||
@@ -67,4 +110,118 @@ class AboutActivity : BaseActivity<ActivityAboutBinding>() {
|
||||
return super.onCompatOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
private fun showMdFile(title: String, fileName: String) {
|
||||
val mdText = String(this.assets.open(fileName).readBytes())
|
||||
showDialogFragment(TextDialog(title, mdText, TextDialog.Mode.MD))
|
||||
}
|
||||
|
||||
private fun checkUpdate() {
|
||||
waitDialog.show()
|
||||
AppUpdate.gitHubUpdate?.run {
|
||||
check(lifecycleScope)
|
||||
.onSuccess {
|
||||
showDialogFragment(UpdateDialog(it))
|
||||
}.onError {
|
||||
appCtx.toastOnUi("${getString(R.string.check_update)}\n${it.localizedMessage}")
|
||||
}.onFinally {
|
||||
waitDialog.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun openUrl(@StringRes addressID: Int) {
|
||||
this.openUrl(getString(addressID))
|
||||
}
|
||||
|
||||
private fun saveLog() {
|
||||
Coroutine.async {
|
||||
val backupPath = AppConfig.backupPath ?: let {
|
||||
appCtx.toastOnUi("未设置备份目录")
|
||||
return@async
|
||||
}
|
||||
if (!AppConfig.recordLog) {
|
||||
appCtx.toastOnUi("未开启日志记录,请去其他设置里打开记录日志")
|
||||
delay(3000)
|
||||
}
|
||||
val doc = FileDoc.fromUri(backupPath.toUri(), true)
|
||||
copyLogs(doc)
|
||||
copyHeapDump(doc)
|
||||
appCtx.toastOnUi("已保存至备份目录")
|
||||
}.onError {
|
||||
AppLog.put("保存日志出错\n${it.localizedMessage}", it, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createHeapDump() {
|
||||
Coroutine.async {
|
||||
val backupPath = AppConfig.backupPath ?: let {
|
||||
appCtx.toastOnUi("未设置备份目录")
|
||||
return@async
|
||||
}
|
||||
if (!AppConfig.recordHeapDump) {
|
||||
appCtx.toastOnUi("未开启堆转储记录,请去其他设置里打开记录堆转储")
|
||||
delay(3000)
|
||||
}
|
||||
appCtx.toastOnUi("开始创建堆转储")
|
||||
System.gc()
|
||||
CrashHandler.doHeapDump(true)
|
||||
val doc = FileDoc.fromUri(backupPath.toUri(), true)
|
||||
if (!copyHeapDump(doc)) {
|
||||
appCtx.toastOnUi("未找到堆转储文件")
|
||||
} else {
|
||||
appCtx.toastOnUi("已保存至备份目录")
|
||||
}
|
||||
}.onError {
|
||||
AppLog.put("保存堆转储失败\n${it.localizedMessage}", it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyLogs(doc: FileDoc) {
|
||||
val cacheDir = appCtx.externalCache
|
||||
val logFiles = File(cacheDir, "logs")
|
||||
val crashFiles = File(cacheDir, "crash")
|
||||
val logcatFile = File(cacheDir, "logcat.txt")
|
||||
|
||||
dumpLogcat(logcatFile)
|
||||
|
||||
val zipFile = File(cacheDir, "logs.zip")
|
||||
ZipUtils.zipFiles(arrayListOf(logFiles, crashFiles, logcatFile), zipFile)
|
||||
|
||||
doc.find("logs.zip")?.delete()
|
||||
|
||||
zipFile.inputStream().use { input ->
|
||||
doc.createFileIfNotExist("logs.zip").openOutputStream().getOrNull()
|
||||
?.use {
|
||||
input.copyTo(it)
|
||||
}
|
||||
}
|
||||
zipFile.delete()
|
||||
}
|
||||
|
||||
private fun copyHeapDump(doc: FileDoc): Boolean {
|
||||
val heapFile = FileDoc.fromFile(File(appCtx.externalCache, "heapDump")).list()
|
||||
?.firstOrNull() ?: return false
|
||||
doc.find("heapDump")?.delete()
|
||||
val heapDumpDoc = doc.createFolderIfNotExist("heapDump")
|
||||
heapFile.openInputStream().getOrNull()?.use { input ->
|
||||
heapDumpDoc.createFileIfNotExist(heapFile.name).openOutputStream().getOrNull()
|
||||
?.use {
|
||||
input.copyTo(it)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun dumpLogcat(file: File) {
|
||||
try {
|
||||
val process = Runtime.getRuntime().exec("logcat -d")
|
||||
file.outputStream().use {
|
||||
process.inputStream.copyTo(it)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
AppLog.put("保存Logcat失败\n$e", e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
package io.legato.kazusa.ui.about
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import io.legato.kazusa.R
|
||||
import io.legato.kazusa.constant.AppConst.appInfo
|
||||
import io.legato.kazusa.constant.AppLog
|
||||
import io.legato.kazusa.help.CrashHandler
|
||||
import io.legato.kazusa.help.config.AppConfig
|
||||
import io.legato.kazusa.help.coroutine.Coroutine
|
||||
import io.legato.kazusa.help.update.AppUpdate
|
||||
import io.legato.kazusa.ui.widget.dialog.TextDialog
|
||||
import io.legato.kazusa.ui.widget.dialog.WaitDialog
|
||||
import io.legato.kazusa.utils.FileDoc
|
||||
import io.legato.kazusa.utils.compress.ZipUtils
|
||||
import io.legato.kazusa.utils.createFileIfNotExist
|
||||
import io.legato.kazusa.utils.createFolderIfNotExist
|
||||
import io.legato.kazusa.utils.delete
|
||||
import io.legato.kazusa.utils.externalCache
|
||||
import io.legato.kazusa.utils.find
|
||||
import io.legato.kazusa.utils.list
|
||||
import io.legato.kazusa.utils.openInputStream
|
||||
import io.legato.kazusa.utils.openOutputStream
|
||||
import io.legato.kazusa.utils.openUrl
|
||||
import io.legato.kazusa.utils.sendMail
|
||||
import io.legato.kazusa.utils.sendToClip
|
||||
import io.legato.kazusa.utils.showDialogFragment
|
||||
import io.legato.kazusa.utils.toastOnUi
|
||||
import kotlinx.coroutines.delay
|
||||
import splitties.init.appCtx
|
||||
import java.io.File
|
||||
import androidx.core.net.toUri
|
||||
|
||||
class AboutFragment : PreferenceFragmentCompat() {
|
||||
|
||||
private val waitDialog by lazy {
|
||||
WaitDialog(requireContext())
|
||||
}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.about)
|
||||
findPreference<Preference>("update_log")?.summary =
|
||||
"${getString(R.string.version)} ${appInfo.versionName}"
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
listView.overScrollMode = View.OVER_SCROLL_NEVER
|
||||
}
|
||||
|
||||
override fun onPreferenceTreeClick(preference: Preference): Boolean {
|
||||
when (preference.key) {
|
||||
"contributors" -> openUrl(R.string.contributors_url)
|
||||
"update_log" -> showMdFile(getString(R.string.update_log), "updateLog.md")
|
||||
"check_update" -> checkUpdate()
|
||||
"mail" -> requireContext().sendMail(getString(R.string.email))
|
||||
"license" -> showMdFile(getString(R.string.license), "LICENSE.md")
|
||||
"disclaimer" -> showMdFile(getString(R.string.disclaimer), "disclaimer.md")
|
||||
"privacyPolicy" -> showMdFile(getString(R.string.privacy_policy), "privacyPolicy.md")
|
||||
"gzGzh" -> requireContext().sendToClip(getString(R.string.legado_gzh))
|
||||
"crashLog" -> showDialogFragment<CrashLogsDialog>()
|
||||
"saveLog" -> saveLog()
|
||||
"createHeapDump" -> createHeapDump()
|
||||
}
|
||||
return super.onPreferenceTreeClick(preference)
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun openUrl(@StringRes addressID: Int) {
|
||||
requireContext().openUrl(getString(addressID))
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示md文件
|
||||
*/
|
||||
private fun showMdFile(title: String, fileName: String) {
|
||||
val mdText = String(requireContext().assets.open(fileName).readBytes())
|
||||
showDialogFragment(TextDialog(title, mdText, TextDialog.Mode.MD))
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测更新
|
||||
*/
|
||||
private fun checkUpdate() {
|
||||
waitDialog.show()
|
||||
AppUpdate.gitHubUpdate?.run {
|
||||
check(lifecycleScope)
|
||||
.onSuccess {
|
||||
showDialogFragment(
|
||||
UpdateDialog(it)
|
||||
)
|
||||
}.onError {
|
||||
appCtx.toastOnUi("${getString(R.string.check_update)}\n${it.localizedMessage}")
|
||||
}.onFinally {
|
||||
waitDialog.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// /**
|
||||
// * 加入qq群
|
||||
// */
|
||||
// private fun joinQQGroup(key: String): Boolean {
|
||||
// val intent = Intent()
|
||||
// intent.data =
|
||||
// "mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3D$key".toUri()
|
||||
// // 此Flag可根据具体产品需要自定义,如设置,则在加群界面按返回,返回手Q主界面,不设置,按返回会返回到呼起产品界面
|
||||
// // intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
// kotlin.runCatching {
|
||||
// startActivity(intent)
|
||||
// return true
|
||||
// }.onFailure {
|
||||
// toastOnUi("添加失败,请手动添加")
|
||||
// }
|
||||
// return false
|
||||
// }
|
||||
|
||||
private fun saveLog() {
|
||||
Coroutine.async {
|
||||
val backupPath = AppConfig.backupPath ?: let {
|
||||
appCtx.toastOnUi("未设置备份目录")
|
||||
return@async
|
||||
}
|
||||
if (!AppConfig.recordLog) {
|
||||
appCtx.toastOnUi("未开启日志记录,请去其他设置里打开记录日志")
|
||||
delay(3000)
|
||||
}
|
||||
val doc = FileDoc.fromUri(backupPath.toUri(), true)
|
||||
copyLogs(doc)
|
||||
copyHeapDump(doc)
|
||||
appCtx.toastOnUi("已保存至备份目录")
|
||||
}.onError {
|
||||
AppLog.put("保存日志出错\n${it.localizedMessage}", it, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createHeapDump() {
|
||||
Coroutine.async {
|
||||
val backupPath = AppConfig.backupPath ?: let {
|
||||
appCtx.toastOnUi("未设置备份目录")
|
||||
return@async
|
||||
}
|
||||
if (!AppConfig.recordHeapDump) {
|
||||
appCtx.toastOnUi("未开启堆转储记录,请去其他设置里打开记录堆转储")
|
||||
delay(3000)
|
||||
}
|
||||
appCtx.toastOnUi("开始创建堆转储")
|
||||
System.gc()
|
||||
CrashHandler.doHeapDump(true)
|
||||
val doc = FileDoc.fromUri(backupPath.toUri(), true)
|
||||
if (!copyHeapDump(doc)) {
|
||||
appCtx.toastOnUi("未找到堆转储文件")
|
||||
} else {
|
||||
appCtx.toastOnUi("已保存至备份目录")
|
||||
}
|
||||
}.onError {
|
||||
AppLog.put("保存堆转储失败\n${it.localizedMessage}", it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyLogs(doc: FileDoc) {
|
||||
val cacheDir = appCtx.externalCache
|
||||
val logFiles = File(cacheDir, "logs")
|
||||
val crashFiles = File(cacheDir, "crash")
|
||||
val logcatFile = File(cacheDir, "logcat.txt")
|
||||
|
||||
dumpLogcat(logcatFile)
|
||||
|
||||
val zipFile = File(cacheDir, "logs.zip")
|
||||
ZipUtils.zipFiles(arrayListOf(logFiles, crashFiles, logcatFile), zipFile)
|
||||
|
||||
doc.find("logs.zip")?.delete()
|
||||
|
||||
zipFile.inputStream().use { input ->
|
||||
doc.createFileIfNotExist("logs.zip").openOutputStream().getOrNull()
|
||||
?.use {
|
||||
input.copyTo(it)
|
||||
}
|
||||
}
|
||||
zipFile.delete()
|
||||
}
|
||||
|
||||
private fun copyHeapDump(doc: FileDoc): Boolean {
|
||||
val heapFile = FileDoc.fromFile(File(appCtx.externalCache, "heapDump")).list()
|
||||
?.firstOrNull() ?: return false
|
||||
doc.find("heapDump")?.delete()
|
||||
val heapDumpDoc = doc.createFolderIfNotExist("heapDump")
|
||||
heapFile.openInputStream().getOrNull()?.use { input ->
|
||||
heapDumpDoc.createFileIfNotExist(heapFile.name).openOutputStream().getOrNull()
|
||||
?.use {
|
||||
input.copyTo(it)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun dumpLogcat(file: File) {
|
||||
try {
|
||||
val process = Runtime.getRuntime().exec("logcat -d")
|
||||
file.outputStream().use {
|
||||
process.inputStream.copyTo(it)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
AppLog.put("保存Logcat失败\n$e", e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user