添加切换源时重启app功能

This commit is contained in:
cyh 2025-04-25 13:41:12 +08:00
parent f9a87d3553
commit c49627cba7
12 changed files with 678 additions and 266 deletions

View File

@ -79,6 +79,8 @@ dependencies {
// https://mvnrepository.com/artifact/com.tencent/mmkv-static
implementation("com.tencent:mmkv-static:1.2.10")
implementation ("com.jakewharton:process-phoenix:3.0.0")
implementation("com.afollestad.material-dialogs:core:3.2.1")
//Retrofit 网络请求库
api("com.squareup.retrofit2:retrofit:2.9.0")
@ -95,7 +97,7 @@ dependencies {
// api("com.google.code.gson:gson:2.10.1")
api("org.yaml:snakeyaml:1.29")
// https://mvnrepository.com/artifact/com.al\ipay.sdk/alipaysdk-android
// https://mvnrepository.com/artifact/com.alipay.sdk/alipaysdk-android
implementation("com.alipay.sdk:alipaysdk-android:15.8.17")
// https://mvnrepository.com/artifact/com.journeyapps/zxing-android-embedded
// implementation("com.journeyapps:zxing-android-embedded:3.6.0")

View File

@ -15,6 +15,7 @@ import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.widget.AppCompatImageView
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
@ -37,10 +38,12 @@ import com.yingmao.clash.remote.Resource
import com.cncat.vpn.service.model.Profile
import com.cncat.vpn.service.remote.IProfileManager
import com.cncat.vpn.service.remote.IRemoteService
import com.yingmao.clash.app.MainApplication
import com.yingmao.clash.util.Utils
import com.yingmao.clash.view.RxToast
import com.yingmao.clash.view.adapter.NodeListAdapter
import com.yingmao.clash.view.dialog.DialogDoMainChoose
import com.yingmao.clash.view.dialog.DialogSureRestartChoose
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope
@ -322,10 +325,12 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
showLoading("正在获取...", this@ChangeNodeActivity)
startTimer()
updateProfile(false)
}
private fun changeSubUrl(originalUrl: String, newUrl: String) {
nowSubUrl = originalUrl.replace(Regex("https://[^/]+/"), "$newUrl/")
MMKV.defaultMMKV().encode(BZYConstants.PROFILE_SUB_URL, nowSubUrl)
}
val reloadLock = Semaphore(10)
@ -341,7 +346,8 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
testRuning = true
updateMoreBar("测速中")
launch(Dispatchers.IO) {
var group = reloadLock.withPermit { UIMainActivity.clashBinder?.let { cb ->
var group = reloadLock.withPermit {
UIMainActivity.clashBinder?.let { cb ->
var names = cb.queryProxyGroupNames(false)
if (names.isNotEmpty()) {
cb.healthCheck(names[0])
@ -510,11 +516,13 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
}
}
}
var dialogDoMainChoose: DialogDoMainChoose? = null
private fun showDomainList() {
try {
SplashHelper(changeNodeVM).getHostWithFallback { success ->
MainScope().launch {
if (success) {
if (dialogDoMainChoose == null) {
dialogDoMainChoose = DialogDoMainChoose(this@ChangeNodeActivity)
@ -523,20 +531,36 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
dialogDoMainChoose?.setOnTryButtonListener(object :
DialogDoMainChoose.OnTryButtonListener {
override fun tryButton() {
var currentHost = MMKV.defaultMMKV()
.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, "")
// com.cncat.vpn.common.log.Log.d("tryButton currentHost==>${currentHost}")
var oldUrl = nowSubUrl
currentHost?.let { changeSubUrl(oldUrl, it) }
saveSubUrl()
doProfile()
dialogDoMainChoose?.dismiss()
}
override fun cancel() {
com.cncat.vpn.common.log.Log.d("tryButton CHECK_LOGIN cancel")
dialogDoMainChoose?.dismiss()
}
})
dialogDoMainChoose?.setOnListItemListener(object :
DialogDoMainChoose.OnListItemListener {
override fun listItemClick() {
saveSubUrl()
MainApplication.restartApp(this@ChangeNodeActivity, object :
MainApplication.OnRestartButtonListener {
override fun enterButton() {
}
override fun cancelButton() {
doProfile()
dialogDoMainChoose?.dismiss()
}
})
}
})
dialogDoMainChoose?.show()
}
}
@ -548,6 +572,14 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
}
}
private fun saveSubUrl() {
var currentHost = MMKV.defaultMMKV()
.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, "")
// com.cncat.vpn.common.log.Log.d("tryButton currentHost==>${currentHost}")
var oldUrl = nowSubUrl
currentHost?.let { changeSubUrl(oldUrl, it) }
}
private fun stopTimer() {
timerTask?.cancel()
timer?.purge()

View File

@ -31,6 +31,7 @@ import com.stripe.android.model.StripeIntent
import com.tencent.mmkv.MMKV
import com.yingmao.clash.BuildConfig
import com.yingmao.clash.R
import com.yingmao.clash.app.MainApplication
import com.yingmao.clash.base.BaseActivity
import com.yingmao.clash.conf.BZYConstants
import com.yingmao.clash.entity.CheckLoginRsp
@ -49,6 +50,7 @@ import com.yingmao.clash.util.PayUtils
import com.yingmao.clash.util.ThreadUtils
import com.yingmao.clash.view.RxToast
import com.yingmao.clash.view.dialog.DialogDoMainChoose
import com.yingmao.clash.view.dialog.DialogSureRestartChoose
import com.yingmao.clash.view.dialog.RxDialogShapeLoading
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
@ -75,6 +77,7 @@ class MemberRechargeActivity: BaseActivity() {
private lateinit var rxDialogShapeLoading: RxDialogShapeLoading
private var outTradeNo = ""
private var selectedGradeID: Int = 0
//stripePay 支付
private var paymentIntentClientSecret: String = ""
private val stripe: Stripe by lazy {
@ -100,13 +103,15 @@ class MemberRechargeActivity: BaseActivity() {
} else {
userIdentity.text = resources.getString(R.string.VIPMember)
}
userIdentityNumber.text = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME)
userIdentityNumber.text =
MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME)
viewModel = ViewModelProvider(this)[RechargeViewModel::class.java]
observe(this, viewModel)
//获取充值列表
val username = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME,"")!!
val username =
MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME, "")!!
val phToken = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_PH_TOKEN, "")!!
val userId = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_USER_ID)!!
viewModel.getPhRechargeInfo(username, phToken, userId)
@ -126,7 +131,8 @@ class MemberRechargeActivity: BaseActivity() {
swipeLayout.setColorSchemeColors(Color.rgb(47, 223, 189))
swipeLayout.setOnRefreshListener {
selectedGrade = null
val username = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME,"")!!
val username =
MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME, "")!!
val phToken = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_PH_TOKEN, "")!!
//获取充值列表
val userId = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_USER_ID)!!
@ -166,6 +172,7 @@ class MemberRechargeActivity: BaseActivity() {
}
}
@SuppressLint("SimpleDateFormat")
fun setExpireDate(validPeriod: Long) {
val isExpire = checkExpire()
@ -240,10 +247,12 @@ class MemberRechargeActivity: BaseActivity() {
Logger.d("获取充值续费信息")
swipeLayout.isRefreshing = true
}
HttpReqType.PAY -> {
Logger.d("支付获取订单号")
showLoadingDialog(resources.getString(R.string.GeneratingOrder))
}
else -> {
}
@ -265,6 +274,7 @@ class MemberRechargeActivity: BaseActivity() {
}
}
}
HttpReqType.PAY -> {
hideLoadingDialog()
Logger.d("生成订单请求成功")
@ -281,6 +291,7 @@ class MemberRechargeActivity: BaseActivity() {
}
}
}
HttpReqType.unionPay -> {
(httpStatus.rsp as PayRsp).let { rsp ->
if (rsp.code != "1000") {
@ -292,6 +303,7 @@ class MemberRechargeActivity: BaseActivity() {
}
}
}
HttpReqType.StripeType -> {
(httpStatus.rsp as PayUploadParamData).let {
if (it.data != null) {
@ -303,6 +315,7 @@ class MemberRechargeActivity: BaseActivity() {
}
}
}
HttpReqType.StripeWeChat -> {
(httpStatus.rsp as PayUploadParamData).let {
if (it.data != null) {
@ -311,7 +324,8 @@ class MemberRechargeActivity: BaseActivity() {
BZYConstants.MMKV_KEY_CURRENT_HOST,
BuildConfig.service_url
)!!
val payUrl=serviceUrl+"/78zccgy0nsgknh9n4/iiii.html?s=${it.data.clientSecret.toString()}"
val payUrl =
serviceUrl + "/78zccgy0nsgknh9n4/iiii.html?s=${it.data.clientSecret.toString()}"
val uri = Uri.parse(payUrl)
val intent = Intent(Intent.ACTION_VIEW)
intent.setData(uri)
@ -322,6 +336,7 @@ class MemberRechargeActivity: BaseActivity() {
}
}
}
HttpReqType.CHECK_LOGIN -> {
Logger.d("支付成功更新有效期")
val checkLoginRsp = httpStatus.rsp
@ -337,6 +352,7 @@ class MemberRechargeActivity: BaseActivity() {
}
}
}
else -> {
}
@ -356,10 +372,12 @@ class MemberRechargeActivity: BaseActivity() {
Logger.d("获取支付订单号异常${httpStatus.msg}")
RxToast.error(resources.getString(R.string.DataPayNumber))
}
HttpReqType.unionPay -> {
Logger.d("OrderGenerationFailed${httpStatus.msg}")
RxToast.error(resources.getString(R.string.OrderGenerationFailed))
}
HttpReqType.StripeType -> {
hideLoading()
RxToast.error(resources.getString(R.string.NoPaymentReceipt))
@ -370,6 +388,7 @@ class MemberRechargeActivity: BaseActivity() {
}
}
}
var dialogDoMainChoose: DialogDoMainChoose? = null
private fun showDomainList() {
try {
@ -392,6 +411,8 @@ class MemberRechargeActivity: BaseActivity() {
val userId = MMKV.defaultMMKV()
.decodeString(BZYConstants.MMKV_KEY_USER_ID)!!
viewModel.getPhRechargeInfo(username, phToken, userId)
dialogDoMainChoose?.dismiss()
}
override fun cancel() {
@ -399,6 +420,32 @@ class MemberRechargeActivity: BaseActivity() {
dialogDoMainChoose?.dismiss()
}
})
dialogDoMainChoose?.setOnListItemListener(object :
DialogDoMainChoose.OnListItemListener {
override fun listItemClick() {
MainApplication.restartApp(this@MemberRechargeActivity, object :
MainApplication.OnRestartButtonListener {
override fun enterButton() {
}
override fun cancelButton() {
val username = MMKV.defaultMMKV()
.decodeString(
BZYConstants.MMKV_KEY_REMEMBER_USERNAME,
""
)!!
val phToken = MMKV.defaultMMKV()
.decodeString(BZYConstants.MMKV_KEY_PH_TOKEN, "")!!
val userId = MMKV.defaultMMKV()
.decodeString(BZYConstants.MMKV_KEY_USER_ID)!!
viewModel.getPhRechargeInfo(username, phToken, userId)
dialogDoMainChoose?.dismiss()
}
})
}
})
dialogDoMainChoose?.show()
}
}
@ -409,6 +456,7 @@ class MemberRechargeActivity: BaseActivity() {
e.printStackTrace()
}
}
private fun showLoadingDialog(content: String) {
apply {
if (!::rxDialogShapeLoading.isInitialized) {
@ -421,14 +469,17 @@ class MemberRechargeActivity: BaseActivity() {
}
}
}
private fun hideLoadingDialog() {
if (::rxDialogShapeLoading.isInitialized && rxDialogShapeLoading.isShowing) {
rxDialogShapeLoading.cancel()
}
}
private fun initAdapter(recharge: RechargeInfo) {
val rechargeListAdapter = VIPRechargeAdapter()
rvRechargeList.layoutManager =GridLayoutManager(CommonUtils.getApp(), 2, GridLayoutManager.VERTICAL, false)
rvRechargeList.layoutManager =
GridLayoutManager(CommonUtils.getApp(), 2, GridLayoutManager.VERTICAL, false)
rechargeListAdapter.setCloudServiceList(recharge, this@MemberRechargeActivity)
rvRechargeList.adapter = rechargeListAdapter
rechargeListAdapter.setListener(object : VIPRechargeAdapter.VIPRechargeItemClickListener {
@ -441,12 +492,14 @@ class MemberRechargeActivity: BaseActivity() {
selectedGradeID = selectedGrade!!.id!!
}
val decimalFormat = DecimalFormat("#0.00")
tvPay.text =resources.getString(R.string.ActivateVIP)+"(¥${decimalFormat.format(amount)}"
tvPay.text =
resources.getString(R.string.ActivateVIP) + "(¥${decimalFormat.format(amount)}"
}
}
})
}
@OptIn(DelicateCoroutinesApi::class)
private fun startCheckout() {
GlobalScope.launch {
@ -466,12 +519,14 @@ class MemberRechargeActivity: BaseActivity() {
RxToast.info(getString(R.string.PaymentCompleted))
}
}
StripeIntent.Status.RequiresAction -> {
Log.i("startCheckoutRequiresAction")
ThreadUtils.runOnUiThread {
RxToast.info(getString(R.string.PaymentCancellation))
}
}
else -> {
Log.i("startCheckout status::${paymentIntent.status}")
}
@ -487,6 +542,7 @@ class MemberRechargeActivity: BaseActivity() {
)
}
}
private fun orderPayment(data: Trade) {
Log.i("PayGradeIDTEST:${selectedGradeID}")
if (data.payType != null) {
@ -502,7 +558,8 @@ class MemberRechargeActivity: BaseActivity() {
)
for (index in data.payType!!) {
if (index.payModel == 10) {
findViewById<LinearLayout>(R.id.llAggregatePayment).visibility= View.VISIBLE
findViewById<LinearLayout>(R.id.llAggregatePayment).visibility =
View.VISIBLE
val JUhePay = findViewById<TextView>(R.id.JUhePay)
JUhePay.visibility = View.VISIBLE
JUhePay.text = index.payChannel
@ -537,12 +594,14 @@ class MemberRechargeActivity: BaseActivity() {
dismiss()
}
} else if (index.payModel == 11) {
findViewById<LinearLayout>(R.id.llQuickPayment).visibility= View.VISIBLE
findViewById<LinearLayout>(R.id.llQuickPayment).visibility =
View.VISIBLE
val KJPay = findViewById<TextView>(R.id.KJPay)
KJPay.visibility = View.VISIBLE
KJPay.text = index.payChannel
if (index.payType == 1) {
val ivQuickPayment=findViewById<AppCompatImageView>(R.id.ivQuickPayment)
val ivQuickPayment =
findViewById<AppCompatImageView>(R.id.ivQuickPayment)
ivQuickPayment.visibility = View.VISIBLE
ivQuickPayment.setOnClickListener {
val payModel = index.payModel
@ -557,7 +616,8 @@ class MemberRechargeActivity: BaseActivity() {
}
}
} else if (index.payType == 2) {
val ivQPWechatPay=findViewById<AppCompatImageView>(R.id.ivQPWechatPay)
val ivQPWechatPay =
findViewById<AppCompatImageView>(R.id.ivQPWechatPay)
ivQPWechatPay.visibility = View.VISIBLE
ivQPWechatPay.setOnClickListener {
val payModel = index.payModel
@ -576,8 +636,10 @@ class MemberRechargeActivity: BaseActivity() {
findViewById<LinearLayout>(R.id.llStripe).visibility = View.VISIBLE
findViewById<LinearLayout>(R.id.llStripePay).visibility = View.VISIBLE
findViewById<TextView>(R.id.tvStripePay).visibility = View.VISIBLE
findViewById<AppCompatImageView>(R.id.ivStripeAlipay).visibility= View.VISIBLE
val stripeWechatPay=findViewById<AppCompatImageView>(R.id.ivStripeWechatPay)
findViewById<AppCompatImageView>(R.id.ivStripeAlipay).visibility =
View.VISIBLE
val stripeWechatPay =
findViewById<AppCompatImageView>(R.id.ivStripeWechatPay)
stripeWechatPay.visibility = View.VISIBLE
findViewById<AppCompatImageView>(R.id.ivStripeAlipay).setOnClickListener {
if (selectedGradeID != 0) {
@ -586,7 +648,10 @@ class MemberRechargeActivity: BaseActivity() {
return@setOnClickListener
}
dismiss()
showLoading(resources.getString(R.string.PaymentIn),this@MemberRechargeActivity)
showLoading(
resources.getString(R.string.PaymentIn),
this@MemberRechargeActivity
)
Log.i("PayGradeID:${selectedGradeID}")
viewModel.getPayClientSecret(selectedGradeID)
} else {
@ -605,18 +670,21 @@ class MemberRechargeActivity: BaseActivity() {
}
}
}
getCustomView().findViewById<AppCompatImageView>(R.id.ivBack).setOnClickListener {
getCustomView().findViewById<AppCompatImageView>(R.id.ivBack)
.setOnClickListener {
dismiss()
}
}
}
}
}
override fun onRestart() {
super.onRestart()
android.util.Log.e("MemberRechargeActivity", " onRestart 重新可见之后刷新有效期")
viewModel.checkLogin()
}
override fun onBackPressed() {
val intent = Intent()
this.setResult(1000, intent)

View File

@ -1,6 +1,7 @@
package com.yingmao.clash.app
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Application
import android.app.NotificationChannel
import android.app.NotificationManager
@ -9,6 +10,7 @@ import android.content.Intent
import android.content.res.Configuration
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat.getString
import androidx.core.content.getSystemService
import com.cncat.vpn.common.Global
import com.cncat.vpn.common.compat.currentProcessName
@ -16,6 +18,7 @@ import com.cncat.vpn.common.log.Log
import com.github.gzuliyujiang.oaid.DeviceID
import com.github.gzuliyujiang.oaid.DeviceIdentifier
import com.github.gzuliyujiang.oaid.IGetter
import com.jakewharton.processphoenix.ProcessPhoenix
import com.orhanobut.logger.Logger
import com.stripe.android.PaymentConfiguration
import com.tencent.mmkv.MMKV
@ -25,6 +28,12 @@ import com.yingmao.clash.conf.BZYConstants
import com.yingmao.clash.entity.UserData
import com.yingmao.clash.util.CrashCatchHandler
import com.yingmao.clash.util.clashDir
import com.yingmao.clash.view.RxToast
import com.yingmao.clash.view.dialog.DialogDoMainChoose
import com.yingmao.clash.view.dialog.DialogSureRestartChoose
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.io.File
import java.io.FileOutputStream
import java.util.Locale
@ -53,8 +62,39 @@ class MainApplication : Application() {
Log.d("setUserInfo")
userBean = bean
}
fun restartApp(activity: Activity,listener:OnRestartButtonListener) {
var dialogDoMainChoose = DialogSureRestartChoose(activity)
if (!dialogDoMainChoose.isShowing) {
dialogDoMainChoose.setOnTryButtonListener(object :
DialogSureRestartChoose.OnTryButtonListener {
override fun tryButton() {
MainScope().launch {
delay(500)
ProcessPhoenix.triggerRebirth(mApp)
}
listener.enterButton()
dialogDoMainChoose.dismiss()
}
override fun cancel() {
listener.cancelButton()
dialogDoMainChoose.dismiss()
}
})
dialogDoMainChoose.show()
}
}
}
interface OnRestartButtonListener{
fun enterButton()
fun cancelButton()
}
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
}
@ -103,7 +143,6 @@ class MainApplication : Application() {
}
//openinstall
// OpenInstall.init(applicationContext);
PaymentConfiguration.init(

View File

@ -1,6 +1,8 @@
package com.yingmao.clash.fragment.setting
import android.annotation.SuppressLint
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
@ -9,6 +11,8 @@ import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.os.Handler
import android.os.Looper
import android.provider.Settings
import android.text.TextUtils
import android.view.View
@ -39,6 +43,7 @@ import com.google.gson.Gson
import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
import com.jakewharton.processphoenix.ProcessPhoenix
import com.orhanobut.logger.Logger
import com.tencent.mmkv.MMKV
import com.yingmao.clash.BuildConfig
@ -77,6 +82,7 @@ import com.yingmao.clash.view.RxToast
import com.yingmao.clash.view.adapter.LanguageAdapter
import com.yingmao.clash.view.dialog.DialogDoMainChoose
import com.yingmao.clash.view.dialog.DialogNotice
import com.yingmao.clash.view.dialog.DialogSureRestartChoose
import com.yingmao.clash.view.dialog.RxDialogShapeLoading
import com.yingmao.clash.vm.MainAtyVM
import com.yingmao.clash.webview.BZYWebViewKeFu
@ -91,6 +97,7 @@ import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.UUID
import kotlin.system.exitProcess
class SettingFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatchers.IO) {
@ -131,7 +138,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
backIv: ImageView,
moreIv: TextView,
titleTv: TextView,
container: FrameLayout
container: FrameLayout,
) {
titleBarRl.visibility = View.GONE
titleTv.visibility = View.GONE
@ -145,48 +152,77 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
@SuppressLint("SetTextI18n")
private fun initLanguage(view: View) {
userIdentityNumberCopy.text = requireActivity().resources.getString(R.string.copy)
view.findViewById<TextView>(R.id.expirationTimeStr).text = requireActivity().resources.getString(R.string.expire_date)
view.findViewById<TextView>(R.id.tvVip).text = requireActivity().resources.getString(R.string.vip_recharge)
view.findViewById<TextView>(R.id.tvVipStr).text = requireActivity().resources.getString(R.string.RechargeDiscount)
view.findViewById<TextView>(R.id.tvNotice).text = requireActivity().resources.getString(R.string.notice)
view.findViewById<TextView>(R.id.tvNoticeStr).text = requireActivity().resources.getString(R.string.newNotice)
view.findViewById<TextView>(R.id.expirationTimeStr).text =
requireActivity().resources.getString(R.string.expire_date)
view.findViewById<TextView>(R.id.tvVip).text =
requireActivity().resources.getString(R.string.vip_recharge)
view.findViewById<TextView>(R.id.tvVipStr).text =
requireActivity().resources.getString(R.string.RechargeDiscount)
view.findViewById<TextView>(R.id.tvNotice).text =
requireActivity().resources.getString(R.string.notice)
view.findViewById<TextView>(R.id.tvNoticeStr).text =
requireActivity().resources.getString(R.string.newNotice)
view.findViewById<TextView>(R.id.tvChangePsw).text = requireActivity().resources.getString(R.string.change_password)
view.findViewById<TextView>(R.id.tvChangePswStr).text = requireActivity().resources.getString(R.string.change_password)
view.findViewById<TextView>(R.id.tvFDS).text = requireActivity().resources.getString(R.string.PreventLoss)
view.findViewById<TextView>(R.id.tvFDSStr).text = requireActivity().resources.getString(R.string.PreventLoss)
view.findViewById<TextView>(R.id.tvChangePsw).text =
requireActivity().resources.getString(R.string.change_password)
view.findViewById<TextView>(R.id.tvChangePswStr).text =
requireActivity().resources.getString(R.string.change_password)
view.findViewById<TextView>(R.id.tvFDS).text =
requireActivity().resources.getString(R.string.PreventLoss)
view.findViewById<TextView>(R.id.tvFDSStr).text =
requireActivity().resources.getString(R.string.PreventLoss)
view.findViewById<TextView>(R.id.tvShare).text = requireActivity().resources.getString(R.string.share)
view.findViewById<TextView>(R.id.tvShareStr).text = requireActivity().resources.getString(R.string.SharingDuration)
view.findViewById<TextView>(R.id.tvkefu).text = requireActivity().resources.getString(R.string.kefu)
view.findViewById<TextView>(R.id.tvShare).text =
requireActivity().resources.getString(R.string.share)
view.findViewById<TextView>(R.id.tvShareStr).text =
requireActivity().resources.getString(R.string.SharingDuration)
view.findViewById<TextView>(R.id.tvkefu).text =
requireActivity().resources.getString(R.string.kefu)
view.findViewById<TextView>(R.id.tvInit).text = requireActivity().resources.getString(R.string.InitializationRepair)
view.findViewById<TextView>(R.id.tvInitStr).text = requireActivity().resources.getString(R.string.InitializationRepairStr)
view.findViewById<TextView>(R.id.tvExit).text = requireActivity().resources.getString(R.string.exit)
view.findViewById<TextView>(R.id.tvExitStr).text = requireActivity().resources.getString(R.string.exitTxt)
view.findViewById<TextView>(R.id.tvInit).text =
requireActivity().resources.getString(R.string.InitializationRepair)
view.findViewById<TextView>(R.id.tvInitStr).text =
requireActivity().resources.getString(R.string.InitializationRepairStr)
view.findViewById<TextView>(R.id.tvExit).text =
requireActivity().resources.getString(R.string.exit)
view.findViewById<TextView>(R.id.tvExitStr).text =
requireActivity().resources.getString(R.string.exitTxt)
view.findViewById<TextView>(R.id.tvTermsService).text = requireActivity().resources.getString(R.string.ServiceTerms)
view.findViewById<TextView>(R.id.tvTermsServiceStr).text = requireActivity().resources.getString(R.string.TermsOfService)
view.findViewById<TextView>(R.id.tvPrivacyPolicy).text = requireActivity().resources.getString(R.string.PrivacyPolicy)
view.findViewById<TextView>(R.id.tvPrivacyPolicyStr).text = requireActivity().resources.getString(R.string.PrivacyOfPolicy)
view.findViewById<TextView>(R.id.tvTermsService).text =
requireActivity().resources.getString(R.string.ServiceTerms)
view.findViewById<TextView>(R.id.tvTermsServiceStr).text =
requireActivity().resources.getString(R.string.TermsOfService)
view.findViewById<TextView>(R.id.tvPrivacyPolicy).text =
requireActivity().resources.getString(R.string.PrivacyPolicy)
view.findViewById<TextView>(R.id.tvPrivacyPolicyStr).text =
requireActivity().resources.getString(R.string.PrivacyOfPolicy)
view.findViewById<TextView>(R.id.tvUploadErrorLog).text = requireActivity().resources.getString(R.string.UploadErrorLog)
view.findViewById<TextView>(R.id.tvUploadErrorLogStr).text = requireActivity().resources.getString(R.string.UploadErrorLog)
view.findViewById<TextView>(R.id.tvSubApplicationProxy).text = requireActivity().resources.getString(R.string.source_switch)
view.findViewById<TextView>(R.id.tvSubApplicationProxyStr).text = requireActivity().resources.getString(R.string.source_switch_str)
view.findViewById<TextView>(R.id.tvUploadErrorLog).text =
requireActivity().resources.getString(R.string.UploadErrorLog)
view.findViewById<TextView>(R.id.tvUploadErrorLogStr).text =
requireActivity().resources.getString(R.string.UploadErrorLog)
view.findViewById<TextView>(R.id.tvSubApplicationProxy).text =
requireActivity().resources.getString(R.string.source_switch)
view.findViewById<TextView>(R.id.tvSubApplicationProxyStr).text =
requireActivity().resources.getString(R.string.source_switch_str)
view.findViewById<TextView>(R.id.tvLanguageSwitching).text = requireActivity().resources.getString(R.string.LanguageSwitching)
view.findViewById<TextView>(R.id.tvLanguageSwitchingStr).text = requireActivity().resources.getString(R.string.LanguageSwitchingStr)
view.findViewById<TextView>(R.id.tvTelegram).text = requireActivity().resources.getString(R.string.telegram)
view.findViewById<TextView>(R.id.tvTelegramStr).text = requireActivity().resources.getString(R.string.TelegramStr)
view.findViewById<TextView>(R.id.tvLanguageSwitching).text =
requireActivity().resources.getString(R.string.LanguageSwitching)
view.findViewById<TextView>(R.id.tvLanguageSwitchingStr).text =
requireActivity().resources.getString(R.string.LanguageSwitchingStr)
view.findViewById<TextView>(R.id.tvTelegram).text =
requireActivity().resources.getString(R.string.telegram)
view.findViewById<TextView>(R.id.tvTelegramStr).text =
requireActivity().resources.getString(R.string.TelegramStr)
tvSignIn.text = requireActivity().resources.getString(R.string.SignIn)
tvExitLog.text = requireActivity().resources.getString(R.string.exit)
tvVersion.text=requireActivity().resources.getString(R.string.edition) + "${BuildConfig.VERSION_NAME}." + BuildConfig.productId
tvVersion.text =
requireActivity().resources.getString(R.string.edition) + "${BuildConfig.VERSION_NAME}." + BuildConfig.productId
}
private fun initView(view: View) {
@ -221,18 +257,21 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
} else {
userIdentity.text = requireActivity().resources.getString(R.string.VIPMember)
}
userIdentityNumber.text = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME)
userIdentityNumber.text =
MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME)
userIdentityNumber.setOnClickListener {
val userName = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME)
val clipboardManager = requireActivity().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clipboardManager =
requireActivity().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clipData = ClipData.newPlainText("text", userName)
clipboardManager.setPrimaryClip(clipData)
RxToast.info(resources.getString(R.string.CopyToClipboard))
}
userIdentityNumberCopy.setOnClickListener {
val userName = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME)
val clipboardManager = requireActivity().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clipboardManager =
requireActivity().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clipData = ClipData.newPlainText("text", userName)
clipboardManager.setPrimaryClip(clipData)
RxToast.info(resources.getString(R.string.CopyToClipboard))
@ -310,7 +349,10 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
clUploadErrorLog.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (Environment.isExternalStorageManager()) {
showLoading(resources.getString(R.string.UploadingInProgress), requireActivity())
showLoading(
resources.getString(R.string.UploadingInProgress),
requireActivity()
)
// 已授予权限
val directory: File? = requireActivity().getExternalFilesDir("CrashLog")
if (directory != null) {
@ -438,11 +480,14 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
intent.setData(uri)
startActivity(intent)
}
tvExitLog.setOnClickListener {
cleanUserInfo()
}
}
var dialogDoMainChoose: DialogDoMainChoose? = null
private fun showDomainList() {
try {
@ -456,25 +501,42 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
dialogDoMainChoose?.setOnTryButtonListener(object :
DialogDoMainChoose.OnTryButtonListener {
override fun tryButton() {
RxToast.info(getString(R.string.StorageSuccessful))
RxToast.info(getString(R.string.ModificationFailed))
dialogDoMainChoose?.dismiss()
}
override fun cancel() {
dialogDoMainChoose?.dismiss()
}
})
dialogDoMainChoose?.setOnListItemListener(object :
DialogDoMainChoose.OnListItemListener {
override fun listItemClick() {
RxToast.info(getString(R.string.StorageSuccessful))
MainApplication.restartApp(requireActivity(),object:MainApplication.OnRestartButtonListener{
override fun enterButton() {
}
override fun cancelButton() {
dialogDoMainChoose?.dismiss()
}
})
}
})
dialogDoMainChoose?.show()
}
}
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
@SuppressLint("SimpleDateFormat")
fun setExpireDate() {
val isExpire = checkExpire()
@ -547,6 +609,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
}
return true
}
private fun cleanUserInfo() {
MMKV.defaultMMKV().removeValueForKey(BZYConstants.MMKV_KEY_PH_TOKEN)
MMKV.defaultMMKV().removeValueForKey(BZYConstants.MMKV_KEY_TOKEN)
@ -564,6 +627,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
startActivity(Intent(CommonUtils.getApp(), LoginActivity::class.java))
requireActivity().finish()
}
private fun cleanProfile() {
launch(Dispatchers.IO) {
profileBinder?.let { pm ->
@ -576,18 +640,21 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
}
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
Logger.d("onActivityCreated")
mainAtyVM = ViewModelProvider(this)[MainAtyVM::class.java]
observe(this, mainAtyVM)
}
private fun stopUpLoadTimer() {
if (activity != null) {
val uiMainActivity = activity as UIMainActivity
uiMainActivity.stopUploadTimer()
}
}
private fun goNewRecharge() {
if (activity != null) {
val uiMainActivity = activity as UIMainActivity
@ -619,11 +686,13 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
RxToast.error(resources.getString(R.string.CheckFailed) + "${data.message}")
}
}
HttpReqType.CHECK_LOGIN -> {
(httpStatus.rsp as CheckLoginRsp).let { checkLoginRsp ->
if (checkLoginRsp.code == 0) {
val mmkv = MMKV.defaultMMKV()
val oldExpireTime = mmkv.decodeLong(BZYConstants.MMKV_KEY_VPN_VALID_PERIOD, 0)
val oldExpireTime =
mmkv.decodeLong(BZYConstants.MMKV_KEY_VPN_VALID_PERIOD, 0)
if (checkLoginRsp.data != null) {
val nowExpireTime = checkLoginRsp.data.vpnExpireTime
if (nowExpireTime > oldExpireTime) {
@ -631,7 +700,8 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
mmkv.encode(BZYConstants.MMKV_KEY_VPN_EXPIRED, expired ?: true)
mmkv.encode(BZYConstants.MMKV_KEY_VPN_VALID_PERIOD, nowExpireTime)
setExpireDate()
fragments.filterIsInstance<HomeFragment>().forEach { it.setExpireDate() }
fragments.filterIsInstance<HomeFragment>()
.forEach { it.setExpireDate() }
mainAtyVM.getAirNodes()
RxToast.info(resources.getString(R.string.SuccessfullyUpdatedUserInformation))
}
@ -689,30 +759,37 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
hideLoading()
}
}
else -> {
}
}
}
override fun httpFailure(httpStatus: HttpStatus.Failure) {
when (httpStatus.reqType) {
HttpReqType.VIPSIGN -> {
RxToast.error(resources.getString(R.string.CheckFailed) + httpStatus.msg)
}
HttpReqType.GET_AIRNODES -> {
Logger.e("获取节点异常:${httpStatus.msg}")
}
HttpReqType.CHECK_LOGIN -> {
RxToast.error(resources.getString(R.string.QueryFailed))
}
HttpReqType.UploadParameters -> {
hideLoading()
}
else -> {
}
}
}
private suspend fun setSub2(url: String) {
profileBinder?.let { pm ->
pm.queryAll().forEach { itemPro ->
@ -753,6 +830,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
}
}
}
fun showLoading(str: String, context: Context) {
val message = if (TextUtils.isEmpty(str)) "进行中..." else str
if (baseLoading == null) {
@ -769,6 +847,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
baseLoading?.cancel()
}
}
private fun startTimer() {
getNodeTimeOutNum = 5
timerJob = launch {
@ -780,6 +859,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
errInit()
}
}
private fun errInit() {
requireActivity().runOnUiThread {
hideLoading()
@ -830,6 +910,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
}
}
private fun finishInit() {
timerJob?.cancel()
@ -839,6 +920,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
}
}
private fun checkPermission() {
XXPermissions.with(this)
// 申请单个权限
@ -847,7 +929,10 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
.request(object : OnPermissionCallback {
override fun onGranted(permissions: MutableList<String>, allGranted: Boolean) {
if (!allGranted) {
showLoading(resources.getString(R.string.UploadingInProgress), requireActivity())
showLoading(
resources.getString(R.string.UploadingInProgress),
requireActivity()
)
val directory: File? = requireActivity().getExternalFilesDir("CrashLog")
if (directory != null) {
val allFilePath = getAllFilePath(directory.path)
@ -864,6 +949,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
return
}
}
override fun onDenied(permissions: MutableList<String>, doNotAskAgain: Boolean) {
if (doNotAskAgain) {
RxToast.error(resources.getString(R.string.ReadPermissionsDenied))
@ -877,6 +963,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
}
})
}
private fun showBottomDialog(data: List<LanguageInfoEntity>) {
//1、使用Dialog、设置style
val bottomSheetDialog = BottomSheetDialog(requireActivity(), R.style.BottomSheetDialog)
@ -887,7 +974,8 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
//设置点击dialog外部不消失
//bottomSheetDialog.setCanceledOnTouchOutside(false);
bottomSheetDialog.show()
bottomView.findViewById<View>(R.id.IVClose).setOnClickListener { bottomSheetDialog.dismiss() }
bottomView.findViewById<View>(R.id.IVClose)
.setOnClickListener { bottomSheetDialog.dismiss() }
val abRecharge = bottomSheetDialog.findViewById<RecyclerView>(R.id.RvLanguage)
abRecharge!!.layoutManager = LinearLayoutManager(requireActivity())
val languageAdapter = LanguageAdapter()
@ -906,12 +994,14 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
updateActivity("Chinese-CN", Locale.CHINA)
RxToast.success("切换为简体中文!")
}
2 -> {
languageItem.isChoose = true
config.locale = Locale("zh", "HK")
updateActivity("Chinese-HK", Locale("zh", "HK"))
RxToast.success("切換爲中文繁體!")
}
3 -> {
languageItem.isChoose = true
config.locale = Locale.ENGLISH
@ -926,6 +1016,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
})
}
fun updateActivity(language: String, locale: Locale) {
MMKV.defaultMMKV().encode(BZYConstants.languageInfo, language)
val resources = this.resources
@ -939,6 +1030,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
startActivity(intent)
requireActivity().finish()
}
private fun uploadForAliOss(data: ParamData, filePath: List<String>, dirStr: String) {
val endpoint = "oss-cn-hongkong.aliyuncs.com"
val accessKeyId = data.credentials?.accessKeyId
@ -983,7 +1075,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
override fun onFailure(
request: PutObjectRequest?,
clientExcepion: ClientException,
serviceException: ServiceException
serviceException: ServiceException,
) {
requireActivity().runOnUiThread {
hideLoading()

View File

@ -41,6 +41,8 @@ open class DialogDoMainChoose : RxDialog {
private set
lateinit var onTryListener: OnTryButtonListener
lateinit var onDomainListItemListener: OnListItemListener
constructor(context: Context?, themeResId: Int) : super(context!!, themeResId) {
initView()
}
@ -110,6 +112,9 @@ open class DialogDoMainChoose : RxDialog {
fun setOnTryButtonListener(listener: OnTryButtonListener) {
this.onTryListener = listener
}
fun setOnListItemListener(listener: OnListItemListener) {
this.onDomainListItemListener = listener
}
var domainListAdapter: DomainListAdapter = DomainListAdapter(R.layout.domain_list_item_layout)
private fun initAdapter() {
@ -134,7 +139,7 @@ open class DialogDoMainChoose : RxDialog {
if (domainListAdapter.selectedPosition == position) -1 else position
domainListAdapter.notifyItemChanged(position)
this.onTryListener.tryButton()
this.onDomainListItemListener.listItemClick()
}
}
}
@ -148,5 +153,8 @@ open class DialogDoMainChoose : RxDialog {
fun tryButton()
fun cancel()
}
interface OnListItemListener {
fun listItemClick()
}
}

View File

@ -0,0 +1,95 @@
package com.yingmao.clash.view.dialog
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter.base.BaseQuickAdapter
import com.cncat.vpn.common.log.Log
import com.tencent.mmkv.MMKV
import com.yingmao.clash.R
import com.yingmao.clash.act.UIMainActivity
import com.yingmao.clash.conf.BZYConstants
import com.yingmao.clash.entity.DomainItemBean
import com.yingmao.clash.view.adapter.DomainListAdapter
import com.yingmao.clash.view.dialog.DialogDoMainChoose.OnTryButtonListener
/**
* @author tamsiree
* @date 2016/7/19
* 确认 取消 Dialog
*/
open class DialogSureRestartChoose : RxDialog {
lateinit var titleView: TextView
private set
lateinit var but_try: TextView
private set
lateinit var but_cancel: TextView
private set
lateinit var domainRecyclerView: RecyclerView
private set
lateinit var onTryListener: OnTryButtonListener
constructor(context: Context?, themeResId: Int) : super(context!!, themeResId) {
initView()
}
constructor(
context: Context?,
cancelable: Boolean,
cancelListener: DialogInterface.OnCancelListener?,
) : super(context!!, cancelable, cancelListener) {
initView()
}
constructor(context: Context?) : super(context!!) {
initView()
}
constructor(context: Activity?) : super(context!!) {
initView()
}
constructor(context: Context?, alpha: Float, gravity: Int) : super(context, alpha, gravity) {
initView()
}
fun setOnTryButtonListener(listener: OnTryButtonListener) {
this.onTryListener = listener
}
private fun initView() {
val dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_app_restart_choose, null)
titleView = dialogView.findViewById(R.id.tv_title)
but_try = dialogView.findViewById(R.id.but_try)
but_cancel = dialogView.findViewById(R.id.but_cancel)
but_try.setOnClickListener {
onTryListener.tryButton()
}
but_cancel.setOnClickListener { onTryListener.cancel() }
setContentView(dialogView)
setCancelable(false)
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
}
interface OnTryButtonListener {
fun tryButton()
fun cancel()
}
}

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@drawable/activity_bg"
android:gravity="center"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.8"
tools:ignore="MissingConstraints">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="10dp"
android:gravity="center"
android:text="@string/sure_restart"
android:textColor="@color/blue_4072FE"
android:textSize="16sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_margin="15dp"
android:layout_height="wrap_content">
<TextView
android:id="@+id/but_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/activity_close_bg"
android:layout_weight="1"
android:gravity="center"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:text="@string/cancel">
</TextView>
<TextView
android:id="@+id/but_try"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/activity_jump_bg"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:gravity="center"
android:text="@string/restart"
android:paddingTop="5dp"
android:paddingBottom="5dp">
</TextView>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -3,7 +3,7 @@
<string name="app_name_backcn">波斯猫回国加速器</string>
<string name="app_name_gz">影猫</string>
<string name="app_name_gz2">影猫加速器</string>
<string name="app_name_taizi">太子加速器</string>
<string name="app_name_taizi">太子</string>
<string name="file">file</string>
<string name="rule">rule</string>
<string name="proxy">proxy</string>
@ -348,4 +348,6 @@ Service Description\n
<string name="everyDay">每天</string>
<string name="PopularApplications">Popular applications</string>
<string name="PopularApplicationsStr">Popular Application Navigation</string>
<string name="sure_restart">Suggest restarting</string>
<string name="restart">Restart</string>
</resources>

View File

@ -3,7 +3,7 @@
<string name="app_name_backcn">波斯貓回國加速器</string>
<string name="app_name_gz">影貓</string>
<string name="app_name_gz2">影貓加速器</string>
<string name="app_name_taizi">太子加速器</string>
<string name="app_name_taizi">太子</string>
<string name="file">文件</string>
<string name="rule">規則</string>
<string name="proxy">代理</string>
@ -338,4 +338,6 @@
<string name="everyDay">每天</string>
<string name="PopularApplications">熱門應用</string>
<string name="PopularApplicationsStr">熱門應用導航</string>
<string name="sure_restart">"建議重啓 "</string>
<string name="restart">"重啓 "</string>
</resources>

View File

@ -4,7 +4,7 @@
<string name="app_name_gz">影貓</string>
<string name="app_name_gz2">影貓加速器</string>
<string name="app_name_taizi">太子加速器</string>
<string name="app_name_taizi">太子</string>
<string name="file">文件</string>
<string name="rule">規則</string>
<string name="proxy">代理</string>
@ -337,4 +337,6 @@
<string name="everyDay">每天</string>
<string name="PopularApplications">熱門應用</string>
<string name="PopularApplicationsStr">熱門應用導航</string>
<string name="sure_restart">"建議重啓 "</string>
<string name="restart">"重啓 "</string>
</resources>

View File

@ -3,7 +3,7 @@
<string name="app_name_backcn">波斯猫回国加速器</string>
<string name="app_name_gz">影猫</string>
<string name="app_name_gz2">影猫加速器</string>
<string name="app_name_taizi">太子加速器</string>
<string name="app_name_taizi">太子</string>
<string name="file">文件</string>
<string name="rule">规则</string>
<string name="proxy">代理</string>
@ -356,4 +356,6 @@
<string name="everyDay">每天</string>
<string name="PopularApplications">热门应用</string>
<string name="PopularApplicationsStr">热门应用导航</string>
<string name="sure_restart">建议重启</string>
<string name="restart">重启</string>
</resources>