添加切换源时重启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
@ -119,7 +122,7 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
@SuppressLint("SetTextI18n")
private fun initViews() {
aiBack=findViewById(R.id.aiBack)
aiBack = findViewById(R.id.aiBack)
aiBack.setOnClickListener {
onBackPressed()
}
@ -186,7 +189,7 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
return
}
//缓存订阅地址
UIMainActivity.subUrl=nowSubUrl
UIMainActivity.subUrl = nowSubUrl
MMKV.defaultMMKV().encode(BZYConstants.PROFILE_SUB_URL, nowSubUrl)
//缓存节点
MMKV.defaultMMKV().encode(BZYConstants.NODE_All_ITEM_NAME_KEY, json)
@ -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])
@ -435,7 +441,7 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
uuid?.let { uu ->
pro.delete(uu)
delay(500)
setSub2(pro, UIMainActivity.subUrl)
setSub2(pro, UIMainActivity.subUrl)
}
}
}
@ -510,33 +516,51 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
}
}
}
var dialogDoMainChoose:DialogDoMainChoose? =null
var dialogDoMainChoose: DialogDoMainChoose? = null
private fun showDomainList() {
try {
SplashHelper(changeNodeVM).getHostWithFallback { success ->
MainScope().launch {
if (success) {
if (dialogDoMainChoose==null) {
if (dialogDoMainChoose == null) {
dialogDoMainChoose = DialogDoMainChoose(this@ChangeNodeActivity)
}
if (dialogDoMainChoose?.isShowing==false) {
if (dialogDoMainChoose?.isShowing == false) {
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
@ -58,23 +60,24 @@ import java.text.DecimalFormat
import java.text.SimpleDateFormat
import java.util.Locale
class MemberRechargeActivity: BaseActivity() {
private lateinit var aiBack: AppCompatImageView
private lateinit var userIdentity: TextView
private lateinit var userIdentityNumber: TextView
private lateinit var expirationTime: TextView
private lateinit var userIdentityNumberCopy: TextView
class MemberRechargeActivity : BaseActivity() {
private lateinit var aiBack: AppCompatImageView
private lateinit var userIdentity: TextView
private lateinit var userIdentityNumber: TextView
private lateinit var expirationTime: TextView
private lateinit var userIdentityNumberCopy: TextView
private lateinit var viewModel: RechargeViewModel
private lateinit var swipeLayout: SwipeRefreshLayout
private lateinit var rvRechargeList:RecyclerView
private lateinit var tvPay:TextView
private lateinit var tvRechargeRecord:TextView
private lateinit var swipeLayout: SwipeRefreshLayout
private lateinit var rvRechargeList: RecyclerView
private lateinit var tvPay: TextView
private lateinit var tvRechargeRecord: TextView
private var selectedGrade: Grade? = null
private lateinit var rxDialogShapeLoading: RxDialogShapeLoading
private var outTradeNo = ""
private var selectedGradeID :Int=0
private var selectedGradeID: Int = 0
//stripePay 支付
private var paymentIntentClientSecret: String = ""
private val stripe: Stripe by lazy {
@ -95,60 +98,63 @@ class MemberRechargeActivity: BaseActivity() {
private fun initData() {
val validPeriod = MMKV.defaultMMKV().decodeLong(BZYConstants.MMKV_KEY_VPN_VALID_PERIOD)
setExpireDate(validPeriod)
if(checkExpire()){
userIdentity.text=resources.getString(R.string.TemporaryUser)
}else{
userIdentity.text=resources.getString(R.string.VIPMember)
if (checkExpire()) {
userIdentity.text = resources.getString(R.string.TemporaryUser)
} 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 phToken = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_PH_TOKEN,"")!!
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)
}
private fun initView() {
aiBack=findViewById(R.id.aiBack)
userIdentity=findViewById(R.id.userIdentity)
userIdentityNumber=findViewById(R.id.userIdentityNumber)
expirationTime=findViewById(R.id.expirationTime)
userIdentityNumberCopy=findViewById(R.id.userIdentityNumberCopy)
swipeLayout=findViewById(R.id.swipeLayout)
rvRechargeList=findViewById(R.id.rvRechargeList)
tvPay=findViewById(R.id.tvPay)
tvRechargeRecord=findViewById(R.id.tvRechargeRecord)
aiBack = findViewById(R.id.aiBack)
userIdentity = findViewById(R.id.userIdentity)
userIdentityNumber = findViewById(R.id.userIdentityNumber)
expirationTime = findViewById(R.id.expirationTime)
userIdentityNumberCopy = findViewById(R.id.userIdentityNumberCopy)
swipeLayout = findViewById(R.id.swipeLayout)
rvRechargeList = findViewById(R.id.rvRechargeList)
tvPay = findViewById(R.id.tvPay)
tvRechargeRecord = findViewById(R.id.tvRechargeRecord)
swipeLayout.setColorSchemeColors(Color.rgb(47, 223, 189))
swipeLayout.setOnRefreshListener {
selectedGrade = null
val username = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME,"")!!
val phToken = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_PH_TOKEN,"")!!
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)
}
aiBack.setOnClickListener {
val intent=Intent()
this.setResult(1000,intent)
val intent = Intent()
this.setResult(1000, intent)
finish() // 关闭当前 Activity
}
userIdentityNumberCopy.setOnClickListener {
val userName = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME)
val clipboardManager =getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clipboardManager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clipData = ClipData.newPlainText("text", userName)
clipboardManager.setPrimaryClip(clipData)
RxToast.info(resources.getString(R.string.CopyToClipboard))
}
userIdentityNumber.setOnClickListener {
val userName = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME)
val clipboardManager =getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clipboardManager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clipData = ClipData.newPlainText("text", userName)
clipboardManager.setPrimaryClip(clipData)
RxToast.info(resources.getString(R.string.CopyToClipboard))
@ -166,8 +172,9 @@ class MemberRechargeActivity: BaseActivity() {
}
}
@SuppressLint("SimpleDateFormat")
fun setExpireDate(validPeriod:Long) {
fun setExpireDate(validPeriod: Long) {
val isExpire = checkExpire()
var endTimeInfo = "--"
if (isExpire) {
@ -240,11 +247,13 @@ class MemberRechargeActivity: BaseActivity() {
Logger.d("获取充值续费信息")
swipeLayout.isRefreshing = true
}
HttpReqType.PAY -> {
Logger.d("支付获取订单号")
showLoadingDialog(resources.getString(R.string.GeneratingOrder))
}
else->{
else -> {
}
}
@ -257,7 +266,7 @@ class MemberRechargeActivity: BaseActivity() {
swipeLayout.isRefreshing = false
(httpStatus.rsp as RechargeInfoRsp).let { it ->
if (it.code != "1000") {
RxToast.error(if (it.message.isNullOrBlank())resources.getString(R.string.FailedRechargeList)+ "${it.code}" else "${it.code}:${it.message}")
RxToast.error(if (it.message.isNullOrBlank()) resources.getString(R.string.FailedRechargeList) + "${it.code}" else "${it.code}:${it.message}")
} else {
it.data?.let { rechargeInfo ->
initAdapter(rechargeInfo)
@ -265,14 +274,15 @@ class MemberRechargeActivity: BaseActivity() {
}
}
}
HttpReqType.PAY -> {
hideLoadingDialog()
Logger.d("生成订单请求成功")
(httpStatus.rsp as PayRsp).let { rsp ->
if (rsp.code != "1000") {
RxToast.error(if (rsp.message.isNullOrBlank()) resources.getString(R.string.OrderGenerationFailed)+"${rsp.code}" else "${rsp.code}:${rsp.message}")
RxToast.error(if (rsp.message.isNullOrBlank()) resources.getString(R.string.OrderGenerationFailed) + "${rsp.code}" else "${rsp.code}:${rsp.message}")
} else {
let {
let {
outTradeNo = rsp.data?.outTradeNo!!
val newUrl = rsp.data.payUrl.toString()
orderPayment(rsp.data)
@ -281,10 +291,11 @@ class MemberRechargeActivity: BaseActivity() {
}
}
}
HttpReqType.unionPay -> {
(httpStatus.rsp as PayRsp).let { rsp ->
if (rsp.code != "1000") {
RxToast.error(if (rsp.message.isNullOrBlank()) resources.getString(R.string.OrderGenerationFailed)+"${rsp.code}" else "${rsp.code}:${rsp.message}")
RxToast.error(if (rsp.message.isNullOrBlank()) resources.getString(R.string.OrderGenerationFailed) + "${rsp.code}" else "${rsp.code}:${rsp.message}")
} else {
if (rsp.data != null) {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(rsp.data.payUrl)))
@ -292,42 +303,46 @@ class MemberRechargeActivity: BaseActivity() {
}
}
}
HttpReqType.StripeType ->{
HttpReqType.StripeType -> {
(httpStatus.rsp as PayUploadParamData).let {
if(it.data!=null){
paymentIntentClientSecret= it.data.clientSecret.toString()
if (it.data != null) {
paymentIntentClientSecret = it.data.clientSecret.toString()
startCheckout()
}else{
} else {
hideLoading()
RxToast.info(getString(R.string.NoPaymentReceipt))
}
}
}
HttpReqType.StripeWeChat ->{
HttpReqType.StripeWeChat -> {
(httpStatus.rsp as PayUploadParamData).let {
if(it.data!=null){
paymentIntentClientSecret= it.data.clientSecret.toString()
if (it.data != null) {
paymentIntentClientSecret = it.data.clientSecret.toString()
val serviceUrl = MMKV.defaultMMKV().decodeString(
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)
startActivity(intent)
}else{
} else {
hideLoading()
RxToast.info(getString(R.string.NoPaymentReceipt))
}
}
}
HttpReqType.CHECK_LOGIN -> {
Logger.d("支付成功更新有效期")
val checkLoginRsp = httpStatus.rsp
if (checkLoginRsp is CheckLoginRsp) {
if (checkLoginRsp.code == 0) {
if(checkLoginRsp.data!=null){
if (checkLoginRsp.data != null) {
val vpnExpireTime = checkLoginRsp.data.vpnExpireTime
setExpireDate(vpnExpireTime)
}
@ -337,7 +352,8 @@ class MemberRechargeActivity: BaseActivity() {
}
}
}
else->{
else -> {
}
}
@ -356,20 +372,23 @@ 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))
}
else->{
else -> {
}
}
}
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,32 +469,37 @@ 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)
rechargeListAdapter.setCloudServiceList(recharge,this@MemberRechargeActivity)
rvRechargeList.adapter=rechargeListAdapter
rechargeListAdapter.setListener(object :VIPRechargeAdapter.VIPRechargeItemClickListener{
rvRechargeList.layoutManager =
GridLayoutManager(CommonUtils.getApp(), 2, GridLayoutManager.VERTICAL, false)
rechargeListAdapter.setCloudServiceList(recharge, this@MemberRechargeActivity)
rvRechargeList.adapter = rechargeListAdapter
rechargeListAdapter.setListener(object : VIPRechargeAdapter.VIPRechargeItemClickListener {
@SuppressLint("SetTextI18n")
override fun onItemClick(noteItem: Grade?) {
selectedGrade=noteItem
selectedGrade = noteItem
val amount = selectedGrade!!.amount?.toFloat()
if (amount != null) {
if(selectedGrade!!.id!=null){
if (selectedGrade!!.id != null) {
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,9 +542,10 @@ class MemberRechargeActivity: BaseActivity() {
)
}
}
private fun orderPayment(data: Trade) {
Log.i("PayGradeIDTEST:${selectedGradeID}")
if(data.payType!=null){
if (data.payType != null) {
let {
MaterialDialog(it).show {
this.cancelable(true)
@ -500,18 +556,19 @@ class MemberRechargeActivity: BaseActivity() {
noVerticalPadding = true,
horizontalPadding = false
)
for (index in data.payType!!){
if(index.payModel==10){
findViewById<LinearLayout>(R.id.llAggregatePayment).visibility= View.VISIBLE
val JUhePay=findViewById<TextView>(R.id.JUhePay)
JUhePay.visibility= View.VISIBLE
for (index in data.payType!!) {
if (index.payModel == 10) {
findViewById<LinearLayout>(R.id.llAggregatePayment).visibility =
View.VISIBLE
val JUhePay = findViewById<TextView>(R.id.JUhePay)
JUhePay.visibility = View.VISIBLE
JUhePay.text = index.payChannel
if(index.payType==1){
val ivAlipay =findViewById<AppCompatImageView>(R.id.ivAlipay)
ivAlipay.visibility= View.VISIBLE
if (index.payType == 1) {
val ivAlipay = findViewById<AppCompatImageView>(R.id.ivAlipay)
ivAlipay.visibility = View.VISIBLE
ivAlipay.setOnClickListener {
val payModel = index.payModel
val payType =index.payType
val payType = index.payType
val payParam = index.payParam
if (payModel != null && payType != null && payParam != null) {
viewModel.orderPayment(data, payModel, payType, payParam)
@ -520,13 +577,13 @@ class MemberRechargeActivity: BaseActivity() {
}
}
dismiss()
}else if(index.payType==2){
val ivWechatPay= findViewById<AppCompatImageView>(R.id.ivWechatPay)
ivWechatPay.visibility= View.VISIBLE
} else if (index.payType == 2) {
val ivWechatPay = findViewById<AppCompatImageView>(R.id.ivWechatPay)
ivWechatPay.visibility = View.VISIBLE
ivWechatPay.setOnClickListener {
val payModel = index.payModel
val payType =index.payType
val payParam =index.payParam
val payType = index.payType
val payParam = index.payParam
if (payModel != null && payType != null && payParam != null) {
viewModel.orderPayment(data, payModel, payType, payParam)
} else {
@ -536,18 +593,20 @@ class MemberRechargeActivity: BaseActivity() {
}
dismiss()
}
}else if(index.payModel==11){
findViewById<LinearLayout>(R.id.llQuickPayment).visibility= View.VISIBLE
val KJPay=findViewById<TextView>(R.id.KJPay)
KJPay.visibility= View.VISIBLE
} else if (index.payModel == 11) {
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)
ivQuickPayment.visibility= View.VISIBLE
if (index.payType == 1) {
val ivQuickPayment =
findViewById<AppCompatImageView>(R.id.ivQuickPayment)
ivQuickPayment.visibility = View.VISIBLE
ivQuickPayment.setOnClickListener {
val payModel =index.payModel
val payType =index.payType
val payParam =index.payParam
val payModel = index.payModel
val payType = index.payType
val payParam = index.payParam
if (payModel != null && payType != null && payParam != null) {
viewModel.orderPayment(data, payModel, payType, payParam)
dismiss()
@ -556,13 +615,14 @@ class MemberRechargeActivity: BaseActivity() {
dismiss()
}
}
}else if(index.payType==2){
val ivQPWechatPay=findViewById<AppCompatImageView>(R.id.ivQPWechatPay)
ivQPWechatPay.visibility= View.VISIBLE
} else if (index.payType == 2) {
val ivQPWechatPay =
findViewById<AppCompatImageView>(R.id.ivQPWechatPay)
ivQPWechatPay.visibility = View.VISIBLE
ivQPWechatPay.setOnClickListener {
val payModel =index.payModel
val payType =index.payType
val payParam =index.payParam
val payModel = index.payModel
val payType = index.payType
val payParam = index.payParam
if (payModel != null && payType != null && payParam != null) {
viewModel.orderPayment(data, payModel, payType, payParam)
dismiss()
@ -572,54 +632,62 @@ class MemberRechargeActivity: BaseActivity() {
}
}
}
}else if(index.payModel==7){
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)
stripeWechatPay.visibility= View.VISIBLE
} else if (index.payModel == 7) {
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)
stripeWechatPay.visibility = View.VISIBLE
findViewById<AppCompatImageView>(R.id.ivStripeAlipay).setOnClickListener {
if(selectedGradeID!=0){
if(!PayUtils.isAlipayInstalled(this@MemberRechargeActivity)){
if (selectedGradeID != 0) {
if (!PayUtils.isAlipayInstalled(this@MemberRechargeActivity)) {
RxToast.error(resources.getString(R.string.AlipayNotInstalled))
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{
} else {
dismiss()
RxToast.info(getString(R.string.NoPaymentReceipt))
}
}
stripeWechatPay.setOnClickListener {
if(selectedGradeID!=0){
if (selectedGradeID != 0) {
viewModel.getWeChatPayClientSecret(selectedGradeID)
dismiss()
}else{
} else {
dismiss()
RxToast.info(getString(R.string.NoPaymentReceipt))
}
}
}
}
getCustomView().findViewById<AppCompatImageView>(R.id.ivBack).setOnClickListener {
dismiss()
}
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)
val intent = Intent()
this.setResult(1000, intent)
finish() // 关闭当前 Activity
super.onBackPressed()
}

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)
}
@ -86,7 +126,7 @@ class MainApplication : Application() {
val crashCatchHandler: CrashCatchHandler = CrashCatchHandler.getInstance() //获得单例
crashCatchHandler.init(applicationContext) //初始化,传入context
if (DeviceID.supportedOAID(applicationContext)){
if (DeviceID.supportedOAID(applicationContext)) {
// 获取OAID/AAID异步回调
DeviceID.getOAID(applicationContext, object : IGetter {
override fun onOAIDGetComplete(result: String) {
@ -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,36 +97,37 @@ 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) {
private lateinit var clTopUp: ConstraintLayout
private lateinit var userIdentity: TextView
private lateinit var userIdentityNumber: TextView
private lateinit var expirationTime: TextView
private lateinit var userIdentityNumberCopy: TextView
private lateinit var clNotice:ConstraintLayout
private lateinit var clTermsService:ConstraintLayout
private lateinit var clPrivacyPolicy:ConstraintLayout
private lateinit var clShare:ConstraintLayout
private lateinit var clCustomerService:ConstraintLayout
private lateinit var clPreventLoss:ConstraintLayout
private lateinit var clExit:ConstraintLayout
private lateinit var clChangePsw:ConstraintLayout
private lateinit var initializationRepair:ConstraintLayout
class SettingFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatchers.IO) {
private lateinit var clTopUp: ConstraintLayout
private lateinit var userIdentity: TextView
private lateinit var userIdentityNumber: TextView
private lateinit var expirationTime: TextView
private lateinit var userIdentityNumberCopy: TextView
private lateinit var clNotice: ConstraintLayout
private lateinit var clTermsService: ConstraintLayout
private lateinit var clPrivacyPolicy: ConstraintLayout
private lateinit var clShare: ConstraintLayout
private lateinit var clCustomerService: ConstraintLayout
private lateinit var clPreventLoss: ConstraintLayout
private lateinit var clExit: ConstraintLayout
private lateinit var clChangePsw: ConstraintLayout
private lateinit var initializationRepair: ConstraintLayout
private lateinit var clUploadErrorLog:ConstraintLayout
private lateinit var clUploadErrorLog: ConstraintLayout
private lateinit var clSubApplicationProxy:ConstraintLayout
private lateinit var clApplicationLanguage:ConstraintLayout
private lateinit var clTelegraph:ConstraintLayout
private lateinit var clFire:ConstraintLayout
private lateinit var clSubApplicationProxy: ConstraintLayout
private lateinit var clApplicationLanguage: ConstraintLayout
private lateinit var clTelegraph: ConstraintLayout
private lateinit var clFire: ConstraintLayout
private lateinit var tvExitLog:TextView
private lateinit var tvExitLog: TextView
private lateinit var tvSignIn:TextView
private lateinit var tvSignIn: TextView
private lateinit var tvVersion:TextView
private lateinit var tvVersion: TextView
private var baseLoading: RxDialogShapeLoading? = null
private val fragments = arrayListOf<Fragment>()
private lateinit var mainAtyVM: MainAtyVM
@ -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,94 +152,126 @@ 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
tvExitLog.text = requireActivity().resources.getString(R.string.exit)
tvVersion.text =
requireActivity().resources.getString(R.string.edition) + "${BuildConfig.VERSION_NAME}." + BuildConfig.productId
}
private fun initView(view: View) {
clTopUp=view.findViewById(R.id.clTopUp)
userIdentity=view.findViewById(R.id.userIdentity)
userIdentityNumber=view.findViewById(R.id.userIdentityNumber)
expirationTime=view.findViewById(R.id.expirationTime)
userIdentityNumberCopy=view.findViewById(R.id.userIdentityNumberCopy)
clNotice=view.findViewById(R.id.clNotice)
clTermsService=view.findViewById(R.id.clTermsService)
clPrivacyPolicy=view.findViewById(R.id.clPrivacyPolicy)
clShare=view.findViewById(R.id.clShare)
clCustomerService=view.findViewById(R.id.clCustomerService)
clPreventLoss=view.findViewById(R.id.clFDS)
clExit=view.findViewById(R.id.clExit)
clChangePsw=view.findViewById(R.id.clChangePsw)
initializationRepair=view.findViewById(R.id.clInitializationRepair)
tvSignIn=view.findViewById(R.id.tvSignIn)
clTopUp = view.findViewById(R.id.clTopUp)
userIdentity = view.findViewById(R.id.userIdentity)
userIdentityNumber = view.findViewById(R.id.userIdentityNumber)
expirationTime = view.findViewById(R.id.expirationTime)
userIdentityNumberCopy = view.findViewById(R.id.userIdentityNumberCopy)
clNotice = view.findViewById(R.id.clNotice)
clTermsService = view.findViewById(R.id.clTermsService)
clPrivacyPolicy = view.findViewById(R.id.clPrivacyPolicy)
clShare = view.findViewById(R.id.clShare)
clCustomerService = view.findViewById(R.id.clCustomerService)
clPreventLoss = view.findViewById(R.id.clFDS)
clExit = view.findViewById(R.id.clExit)
clChangePsw = view.findViewById(R.id.clChangePsw)
initializationRepair = view.findViewById(R.id.clInitializationRepair)
tvSignIn = view.findViewById(R.id.tvSignIn)
clUploadErrorLog=view.findViewById(R.id.clUploadErrorLog)
clSubApplicationProxy=view.findViewById(R.id.clSubApplicationProxy)
clApplicationLanguage=view.findViewById(R.id.clApplicationLanguage)
clTelegraph=view.findViewById(R.id.clTelegraph)
tvExitLog=view.findViewById(R.id.tvExitLog)
tvVersion=view.findViewById(R.id.tvVersion)
clFire=view.findViewById(R.id.clFire)
clUploadErrorLog = view.findViewById(R.id.clUploadErrorLog)
clSubApplicationProxy = view.findViewById(R.id.clSubApplicationProxy)
clApplicationLanguage = view.findViewById(R.id.clApplicationLanguage)
clTelegraph = view.findViewById(R.id.clTelegraph)
tvExitLog = view.findViewById(R.id.tvExitLog)
tvVersion = view.findViewById(R.id.tvVersion)
clFire = view.findViewById(R.id.clFire)
setExpireDate()
if(checkExpire()){
userIdentity.text=requireActivity().resources.getString(R.string.TemporaryUser)
}else{
userIdentity.text=requireActivity().resources.getString(R.string.VIPMember)
if (checkExpire()) {
userIdentity.text = requireActivity().resources.getString(R.string.TemporaryUser)
} 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))
@ -284,7 +323,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
startActivity(intent)
}
initializationRepair.setOnClickListener {
if (TextUtils.isEmpty(subUrl)){
if (TextUtils.isEmpty(subUrl)) {
return@setOnClickListener
}
showLoading(resources.getString(R.string.UnderRepair), requireActivity())
@ -298,7 +337,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
delay(1000)
if (subUrl?.isNotEmpty() == true) {
startTimer()
setSub2(subUrl!!,pm)
setSub2(subUrl!!, pm)
}
}
}
@ -308,9 +347,12 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
mainAtyVM.vipSign()
}
clUploadErrorLog.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){
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) {
@ -332,7 +374,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
startActivity(intent)
hideLoading()
}
}else{
} else {
checkPermission()
}
}
@ -438,43 +480,63 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
intent.setData(uri)
startActivity(intent)
}
tvExitLog.setOnClickListener {
cleanUserInfo()
}
}
var dialogDoMainChoose:DialogDoMainChoose? =null
var dialogDoMainChoose: DialogDoMainChoose? = null
private fun showDomainList() {
try {
SplashHelper(mainAtyVM).getHostWithFallback { success ->
MainScope().launch {
if (success) {
if (dialogDoMainChoose==null) {
if (dialogDoMainChoose == null) {
dialogDoMainChoose = DialogDoMainChoose(activity)
}
if (dialogDoMainChoose?.isShowing==false) {
if (dialogDoMainChoose?.isShowing == false) {
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
@ -600,9 +667,9 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
}
override fun httpSuccess(httpStatus: HttpStatus.Success) {
when(httpStatus.reqType){
when (httpStatus.reqType) {
HttpReqType.VIPSIGN->{
HttpReqType.VIPSIGN -> {
val data = httpStatus.rsp as VipSignRsp
if (data.code == "1000") {
var gifMins = 30
@ -619,19 +686,22 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
RxToast.error(resources.getString(R.string.CheckFailed) + "${data.message}")
}
}
HttpReqType.CHECK_LOGIN->{
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)
if(checkLoginRsp.data!=null){
val oldExpireTime =
mmkv.decodeLong(BZYConstants.MMKV_KEY_VPN_VALID_PERIOD, 0)
if (checkLoginRsp.data != null) {
val nowExpireTime = checkLoginRsp.data.vpnExpireTime
if (nowExpireTime > oldExpireTime) {
val expired = checkLoginRsp.data.expired
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))
}
@ -643,7 +713,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
}
}
HttpReqType.GET_AIRNODES->{
HttpReqType.GET_AIRNODES -> {
val data = httpStatus.rsp as SubscriptionRsp
if (data.code != "1000") {
RxToast.error(resources.getString(R.string.NodeAcquisitionFailed) + "${data.msg}")
@ -660,7 +730,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
}
}
HttpReqType.UploadParameters->{
HttpReqType.UploadParameters -> {
val upLoadData = httpStatus.rsp as UploadParamData
if (upLoadData.code == 1000) {
val directory: File? = requireActivity().getExternalFilesDir("CrashLog")
@ -685,35 +755,42 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
}
}
}else{
} else {
hideLoading()
}
}
else->{
else -> {
}
}
}
override fun httpFailure(httpStatus: HttpStatus.Failure) {
when(httpStatus.reqType){
HttpReqType.VIPSIGN->{
when (httpStatus.reqType) {
HttpReqType.VIPSIGN -> {
RxToast.error(resources.getString(R.string.CheckFailed) + httpStatus.msg)
}
HttpReqType.GET_AIRNODES->{
HttpReqType.GET_AIRNODES -> {
Logger.e("获取节点异常:${httpStatus.msg}")
}
HttpReqType.CHECK_LOGIN->{
HttpReqType.CHECK_LOGIN -> {
RxToast.error(resources.getString(R.string.QueryFailed))
}
HttpReqType.UploadParameters->{
HttpReqType.UploadParameters -> {
hideLoading()
}
else->{
else -> {
}
}
}
private suspend fun setSub2(url: String) {
private suspend fun setSub2(url: String) {
profileBinder?.let { pm ->
pm.queryAll().forEach { itemPro ->
if (itemPro.name != Conf.getClashConfName(requireActivity().applicationContext)) {
@ -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,7 +859,8 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
errInit()
}
}
private fun errInit(){
private fun errInit() {
requireActivity().runOnUiThread {
hideLoading()
RxToast.error(resources.getString(R.string.FixTimeout))
@ -801,7 +881,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
val actName = it.name
Log.d("new main actname==>" + actName)
pm.setActive(it)
newUuid = pro.uuid.toString();
newUuid = pro.uuid.toString();
isSubed = true
Log.d("setSub2 setActive end")
finishInit()
@ -830,6 +910,7 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
}
}
private fun finishInit() {
timerJob?.cancel()
@ -839,16 +920,20 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
}
}
private fun checkPermission() {
XXPermissions.with(this)
// 申请单个权限
.permission(Permission.MANAGE_EXTERNAL_STORAGE)
.permission(Permission.Group.STORAGE)
.request(object: OnPermissionCallback {
.request(object : OnPermissionCallback {
override fun onGranted(permissions: MutableList<String>, allGranted: Boolean) {
if (!allGranted) {
showLoading(resources.getString(R.string.UploadingInProgress), requireActivity())
val directory: File? =requireActivity().getExternalFilesDir("CrashLog")
showLoading(
resources.getString(R.string.UploadingInProgress),
requireActivity()
)
val directory: File? = requireActivity().getExternalFilesDir("CrashLog")
if (directory != null) {
val allFilePath = getAllFilePath(directory.path)
if (allFilePath.isNotEmpty()) {
@ -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,35 +974,38 @@ 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())
abRecharge!!.layoutManager = LinearLayoutManager(requireActivity())
val languageAdapter = LanguageAdapter()
languageAdapter.notifyAdapter(data, requireActivity())
abRecharge.adapter=languageAdapter
abRecharge.adapter = languageAdapter
val config = resources.configuration
languageAdapter.setListener(object: LanguageAdapter.onItemClickListener{
languageAdapter.setListener(object : LanguageAdapter.onItemClickListener {
override fun onItemClick(languageInfoList: List<LanguageInfoEntity>, isPosition: Int) {
val languageItem = languageInfoList[isPosition]
if(!languageItem.isChoose){
when(languageItem.id){
1->{
languageItem.isChoose=true
if (!languageItem.isChoose) {
when (languageItem.id) {
1 -> {
languageItem.isChoose = true
config.locale = Locale.CHINA
updateActivity("Chinese-CN", Locale.CHINA)
RxToast.success("切换为简体中文!")
}
2->{
languageItem.isChoose=true
config.locale = Locale("zh","HK")
updateActivity("Chinese-HK", Locale("zh","HK"))
2 -> {
languageItem.isChoose = true
config.locale = Locale("zh", "HK")
updateActivity("Chinese-HK", Locale("zh", "HK"))
RxToast.success("切換爲中文繁體!")
}
3->{
languageItem.isChoose=true
3 -> {
languageItem.isChoose = true
config.locale = Locale.ENGLISH
updateActivity("English",Locale.ENGLISH)
updateActivity("English", Locale.ENGLISH)
RxToast.success("Switch to English")
}
}
@ -926,19 +1016,21 @@ class SettingFragment: BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
})
}
fun updateActivity(language:String,locale: Locale){
fun updateActivity(language: String, locale: Locale) {
MMKV.defaultMMKV().encode(BZYConstants.languageInfo, language)
val resources =this.resources
val resources = this.resources
val metrics = resources.displayMetrics
val config = resources.configuration
config.locale=locale
resources.updateConfiguration(config,metrics)
config.locale = locale
resources.updateConfiguration(config, metrics)
//设置好选择的语言以后需要清除任务栈中的所有activity打开首页确保以后进入的页面都是当前选择的语言
val intent = Intent(requireActivity(), SplashActivity::class.java)
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
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>