Changed I18n to template

This commit is contained in:
2022-05-11 23:58:39 +08:00
parent e386e1fa42
commit 0e8d7bc733
6 changed files with 192 additions and 25 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -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() {

View File

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