mirror of
https://github.com/KitsunePie/AppErrorsTracking.git
synced 2025-09-01 16:55:18 +08:00
Changed I18n to template
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
package com.fankes.apperrorstracking.application
|
||||
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import com.fankes.apperrorstracking.locale.LocaleString
|
||||
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication
|
||||
|
||||
class AppErrorsApplication : ModuleApplication() {
|
||||
@@ -30,5 +31,7 @@ class AppErrorsApplication : ModuleApplication() {
|
||||
super.onCreate()
|
||||
/** 跟随系统夜间模式 */
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
/** 绑定 I18n */
|
||||
LocaleString.bind(instance = this)
|
||||
}
|
||||
}
|
@@ -22,6 +22,7 @@
|
||||
package com.fankes.apperrorstracking.hook
|
||||
|
||||
import com.fankes.apperrorstracking.hook.entity.FrameworkHooker
|
||||
import com.fankes.apperrorstracking.locale.LocaleString
|
||||
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
|
||||
import com.highcapable.yukihookapi.hook.factory.configs
|
||||
import com.highcapable.yukihookapi.hook.factory.encase
|
||||
@@ -35,5 +36,10 @@ class HookEntry : IYukiHookXposedInit {
|
||||
isDebug = false
|
||||
}
|
||||
|
||||
override fun onHook() = encase { loadSystem(FrameworkHooker) }
|
||||
override fun onHook() = encase {
|
||||
loadSystem {
|
||||
LocaleString.bind(instance = this)
|
||||
loadHooker(FrameworkHooker)
|
||||
}
|
||||
}
|
||||
}
|
@@ -42,6 +42,7 @@ import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import com.fankes.apperrorstracking.R
|
||||
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
|
||||
import com.fankes.apperrorstracking.locale.LocaleString
|
||||
import com.fankes.apperrorstracking.ui.activity.AppErrorsDetailActivity
|
||||
import com.fankes.apperrorstracking.utils.drawable.drawabletoolbox.DrawableBuilder
|
||||
import com.fankes.apperrorstracking.utils.factory.*
|
||||
@@ -129,14 +130,6 @@ object FrameworkHooker : YukiBaseHooker() {
|
||||
private fun lastAppErrorsInfo(packageName: String) =
|
||||
appErrorsRecords.takeIf { it.isNotEmpty() }?.filter { it.packageName == packageName }?.get(0)
|
||||
|
||||
/**
|
||||
* 获取 I18n 字符串
|
||||
* @param resId 模块资源 Id
|
||||
* @param objArrs 格式化数组
|
||||
* @return [String]
|
||||
*/
|
||||
private fun string(resId: Int, vararg objArrs: Any) = moduleAppResources.getString(resId, *objArrs)
|
||||
|
||||
/**
|
||||
* 创建对话框按钮
|
||||
* @param context 实例
|
||||
@@ -252,30 +245,30 @@ object FrameworkHooker : YukiBaseHooker() {
|
||||
android.R.style.Theme_Material_Dialog
|
||||
else android.R.style.Theme_Material_Light_Dialog
|
||||
).create().apply {
|
||||
setTitle(string(if (isRepeating) R.string.aerr_repeated_title else R.string.aerr_title, appName))
|
||||
setTitle(if (isRepeating) LocaleString.aerrRepeatedTitle(appName) else LocaleString.aerrTitle(appName))
|
||||
setView(LinearLayout(context).apply {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
/** 应用信息按钮 */
|
||||
val appInfoButton =
|
||||
createButtonItem(context, R.drawable.ic_baseline_info, string(R.string.app_info)) {
|
||||
createButtonItem(context, R.drawable.ic_baseline_info, LocaleString.appInfo) {
|
||||
cancel()
|
||||
context.openSelfSetting(packageName)
|
||||
}
|
||||
|
||||
/** 关闭应用按钮 */
|
||||
val closeAppButton =
|
||||
createButtonItem(context, R.drawable.ic_baseline_close, string(R.string.close_app)) { cancel() }
|
||||
createButtonItem(context, R.drawable.ic_baseline_close, LocaleString.closeApp) { cancel() }
|
||||
|
||||
/** 重新打开按钮 */
|
||||
val reOpenButton =
|
||||
createButtonItem(context, R.drawable.ic_baseline_refresh, string(R.string.reopen_app)) {
|
||||
createButtonItem(context, R.drawable.ic_baseline_refresh, LocaleString.reopenApp) {
|
||||
cancel()
|
||||
context.openApp(packageName)
|
||||
}
|
||||
|
||||
/** 错误详情按钮 */
|
||||
val errorDetailButton =
|
||||
createButtonItem(context, R.drawable.ic_baseline_bug_report, string(R.string.error_detail)) {
|
||||
createButtonItem(context, R.drawable.ic_baseline_bug_report, LocaleString.errorDetail) {
|
||||
cancel()
|
||||
lastAppErrorsInfo(packageName)?.let { AppErrorsDetailActivity.start(context, it, isOutSide = true) }
|
||||
?: context.toast(msg = "Invalid AppErrorsInfo")
|
||||
@@ -283,18 +276,18 @@ object FrameworkHooker : YukiBaseHooker() {
|
||||
|
||||
/** 忽略按钮 - 直到解锁 */
|
||||
val ignoredUntilUnlockButton =
|
||||
createButtonItem(context, R.drawable.ic_baseline_eject, string(R.string.ignore_if_unlock)) {
|
||||
createButtonItem(context, R.drawable.ic_baseline_eject, LocaleString.ignoreIfUnlock) {
|
||||
cancel()
|
||||
ignoredErrorsIfUnlockApps.add(packageName)
|
||||
context.toast(string(R.string.ignore_if_unlock_tip, appName))
|
||||
context.toast(LocaleString.ignoreIfUnlockTip(appName))
|
||||
}
|
||||
|
||||
/** 忽略按钮 - 直到重启 */
|
||||
val ignoredUntilRestartButton =
|
||||
createButtonItem(context, R.drawable.ic_baseline_eject, string(R.string.ignore_if_restart)) {
|
||||
createButtonItem(context, R.drawable.ic_baseline_eject, LocaleString.ignoreIfRestart) {
|
||||
cancel()
|
||||
ignoredErrorsIfRestartApps.add(packageName)
|
||||
context.toast(string(R.string.ignore_if_restart_tip, appName))
|
||||
context.toast(LocaleString.ignoreIfRestartTip(appName))
|
||||
}
|
||||
/** 判断进程是否为 APP */
|
||||
if (isApp) {
|
||||
|
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* AppErrorsTracking - Added more features to app's crash dialog, fixed custom rom deleted dialog, the best experience to Android developer.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/KitsunePie/AppErrorsTracking
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/5/11.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate", "StaticFieldLeak", "unused")
|
||||
|
||||
package com.fankes.apperrorstracking.locale
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import com.fankes.apperrorstracking.R
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
|
||||
/**
|
||||
* I18n 字符串实例
|
||||
*/
|
||||
object LocaleString {
|
||||
|
||||
/** 当前的 [Context] */
|
||||
private var baseContext: Context? = null
|
||||
|
||||
/** 当前的 [PackageParam] */
|
||||
private var basePackageParam: PackageParam? = null
|
||||
|
||||
/** 当前的 [Resources] */
|
||||
private var baseResources: Resources? = null
|
||||
|
||||
/**
|
||||
* 当前的 [Resources]
|
||||
* @return [Resources]
|
||||
* @throws IllegalStateException 如果 [LocaleString] 没有被绑定
|
||||
*/
|
||||
private val resources
|
||||
get() = baseContext?.resources ?: basePackageParam?.moduleAppResources ?: baseResources
|
||||
?: error("LocaleString must bind an instance first")
|
||||
|
||||
/**
|
||||
* 绑定并初始化
|
||||
* @param instance 可以是 [Context]、[PackageParam]、[Resources]
|
||||
*/
|
||||
fun bind(instance: Any) {
|
||||
when (instance) {
|
||||
is Context -> baseContext = instance
|
||||
is PackageParam -> basePackageParam = instance
|
||||
is Resources -> baseResources = instance
|
||||
else -> error("LocaleString bind an unknown instance")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据资源 Id 获取字符串
|
||||
* @param objArrs 格式化实例
|
||||
* @return [String]
|
||||
*/
|
||||
private fun Int.bind(vararg objArrs: Any) = resources.getString(this, *objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val copied get() = copied()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun copied(vararg objArrs: Any) = R.string.copied.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val copyFail get() = copyFail()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun copyFail(vararg objArrs: Any) = R.string.copy_fail.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val printToLogcatSuccess get() = printToLogcatSuccess()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun printToLogcatSuccess(vararg objArrs: Any) = R.string.print_to_logcat_success.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val outputStackSuccess get() = outputStackSuccess()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun outputStackSuccess(vararg objArrs: Any) = R.string.output_stack_success.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val outputStackFail get() = outputStackFail()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun outputStackFail(vararg objArrs: Any) = R.string.output_stack_fail.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val aerrTitle get() = aerrTitle()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun aerrTitle(vararg objArrs: Any) = R.string.aerr_title.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val aerrRepeatedTitle get() = aerrRepeatedTitle()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun aerrRepeatedTitle(vararg objArrs: Any) = R.string.aerr_repeated_title.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val appInfo get() = appInfo()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun appInfo(vararg objArrs: Any) = R.string.app_info.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val closeApp get() = closeApp()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun closeApp(vararg objArrs: Any) = R.string.close_app.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val reopenApp get() = reopenApp()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun reopenApp(vararg objArrs: Any) = R.string.reopen_app.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val errorDetail get() = errorDetail()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun errorDetail(vararg objArrs: Any) = R.string.error_detail.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val ignoreIfUnlock get() = ignoreIfUnlock()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun ignoreIfUnlock(vararg objArrs: Any) = R.string.ignore_if_unlock.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val ignoreIfRestart get() = ignoreIfRestart()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun ignoreIfRestart(vararg objArrs: Any) = R.string.ignore_if_restart.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val ignoreIfUnlockTip get() = ignoreIfUnlockTip()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun ignoreIfUnlockTip(vararg objArrs: Any) = R.string.ignore_if_unlock_tip.bind(*objArrs)
|
||||
|
||||
/** @string Automatic generated */
|
||||
val ignoreIfRestartTip get() = ignoreIfRestartTip()
|
||||
|
||||
/** @string Automatic generated */
|
||||
fun ignoreIfRestartTip(vararg objArrs: Any) = R.string.ignore_if_restart_tip.bind(*objArrs)
|
||||
}
|
@@ -33,6 +33,7 @@ import com.fankes.apperrorstracking.R
|
||||
import com.fankes.apperrorstracking.bean.AppErrorsInfoBean
|
||||
import com.fankes.apperrorstracking.databinding.ActivityAppErrorsDetailBinding
|
||||
import com.fankes.apperrorstracking.hook.entity.FrameworkHooker
|
||||
import com.fankes.apperrorstracking.locale.LocaleString
|
||||
import com.fankes.apperrorstracking.ui.activity.base.BaseActivity
|
||||
import com.fankes.apperrorstracking.utils.factory.*
|
||||
import com.highcapable.yukihookapi.hook.log.loggerE
|
||||
@@ -55,7 +56,8 @@ class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
|
||||
fun start(context: Context, appErrorsInfo: AppErrorsInfoBean, isOutSide: Boolean = false) {
|
||||
runCatching {
|
||||
context.startActivity((if (isOutSide) Intent() else Intent(context, AppErrorsDetailActivity::class.java)).apply {
|
||||
if (context !is Activity) flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
flags = if (context !is Activity) Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
else Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
if (isOutSide) component = ComponentName(BuildConfig.APPLICATION_ID, AppErrorsDetailActivity::class.java.name)
|
||||
putExtra(FrameworkHooker.APP_ERRORS_INFO, appErrorsInfo)
|
||||
})
|
||||
@@ -76,7 +78,7 @@ class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
|
||||
binding.titleBackIcon.setOnClickListener { onBackPressed() }
|
||||
binding.printIcon.setOnClickListener {
|
||||
loggerE(msg = createStack())
|
||||
toast(getString(R.string.print_to_logcat_success))
|
||||
toast(LocaleString.printToLogcatSuccess)
|
||||
}
|
||||
binding.copyIcon.setOnClickListener { copyToClipboard(appErrorsInfo.stackTrace) }
|
||||
binding.exportIcon.setOnClickListener {
|
||||
@@ -115,9 +117,9 @@ class AppErrorsDetailActivity : BaseActivity<ActivityAppErrorsDetailBinding>() {
|
||||
if (requestCode == WRITE_REQUEST_CODE && resultCode == Activity.RESULT_OK) runCatching {
|
||||
data?.data?.let {
|
||||
contentResolver?.openOutputStream(it)?.apply { write(stackTrace.toByteArray()) }?.close()
|
||||
toast(getString(R.string.output_stack_success))
|
||||
} ?: toast(getString(R.string.output_stack_fail))
|
||||
}.onFailure { toast(getString(R.string.output_stack_fail)) }
|
||||
toast(LocaleString.outputStackSuccess)
|
||||
} ?: toast(LocaleString.outputStackFail)
|
||||
}.onFailure { toast(LocaleString.outputStackFail) }
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
|
@@ -35,7 +35,7 @@ import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.provider.Settings
|
||||
import android.widget.Toast
|
||||
import com.fankes.apperrorstracking.R
|
||||
import com.fankes.apperrorstracking.locale.LocaleString
|
||||
|
||||
/**
|
||||
* 系统深色模式是否开启
|
||||
@@ -109,7 +109,7 @@ fun Context.copyToClipboard(content: String) = runCatching {
|
||||
(getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).apply {
|
||||
setPrimaryClip(ClipData.newPlainText(null, content))
|
||||
(primaryClip?.getItemAt(0)?.text ?: "").also {
|
||||
if (it != content) toast(getString(R.string.copy_fail)) else toast(getString(R.string.copied))
|
||||
if (it != content) toast(LocaleString.copyFail) else toast(LocaleString.copied)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user