parent
6f2b108068
commit
7b3351ebfd
|
|
@ -39,6 +39,7 @@ import com.cncat.vpn.service.remote.IRemoteService
|
||||||
import com.yingmao.clash.util.Utils
|
import com.yingmao.clash.util.Utils
|
||||||
import com.yingmao.clash.view.RxToast
|
import com.yingmao.clash.view.RxToast
|
||||||
import com.yingmao.clash.view.adapter.NodeListAdapter
|
import com.yingmao.clash.view.adapter.NodeListAdapter
|
||||||
|
import com.yingmao.clash.view.dialog.DialogDoMainChoose
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
@ -119,7 +120,7 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
||||||
swipeLayout = findViewById(R.id.swipeLayout)
|
swipeLayout = findViewById(R.id.swipeLayout)
|
||||||
initRefreshLayout()
|
initRefreshLayout()
|
||||||
nodeListRv = findViewById(R.id.rv_node_list)
|
nodeListRv = findViewById(R.id.rv_node_list)
|
||||||
var userTrafficTv:TextView = findViewById(R.id.node_user_traffic)
|
var userTrafficTv: TextView = findViewById(R.id.node_user_traffic)
|
||||||
|
|
||||||
findViewById<ImageView>(R.id.iv_back).setOnClickListener {
|
findViewById<ImageView>(R.id.iv_back).setOnClickListener {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
|
|
@ -272,14 +273,17 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
super.onStart()
|
super.onStart()
|
||||||
// getNodesStatus()
|
|
||||||
// changeNodeVM.getAirNodes()
|
doProfile()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun doProfile() {
|
||||||
if (TextUtils.isEmpty(cacheNodeStr)) {
|
if (TextUtils.isEmpty(cacheNodeStr)) {
|
||||||
showLoading("正在获取...", this@ChangeNodeActivity)
|
showLoading("正在获取...", this@ChangeNodeActivity)
|
||||||
startTimer()
|
startTimer()
|
||||||
}
|
}
|
||||||
updateProfile(false)
|
updateProfile(false)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val reloadLock = Semaphore(10)
|
val reloadLock = Semaphore(10)
|
||||||
|
|
@ -462,7 +466,7 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
||||||
createProfile()
|
createProfile()
|
||||||
} else {
|
} else {
|
||||||
Log.d("stopTimer...")
|
Log.d("stopTimer...")
|
||||||
RxToast.error("获取节点失败...")
|
RxToast.error("获取节点失败...请尝试切换其他地址")
|
||||||
delay(1000)
|
delay(1000)
|
||||||
this@ChangeNodeActivity.finish()
|
this@ChangeNodeActivity.finish()
|
||||||
}
|
}
|
||||||
|
|
@ -470,39 +474,25 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
||||||
delay(1000)
|
delay(1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// timer = Timer()
|
private fun showDomainList() {
|
||||||
// timerTask = object : TimerTask() {
|
try {
|
||||||
// override fun run() {
|
|
||||||
// if (GetNodeTimeOutNum >= 0) {
|
val dialogDoMainChoose = DialogDoMainChoose(this@ChangeNodeActivity)
|
||||||
// GetNodeTimeOutNum--
|
dialogDoMainChoose.setOnTryButtonListener(object :
|
||||||
// Log.d("GetNodeTimeOutNum==>$GetNodeTimeOutNum")
|
DialogDoMainChoose.OnTryButtonListener {
|
||||||
// } else {
|
override fun tryButton() {
|
||||||
// GetNodeTimeOutNum = 5
|
var currentHost = MMKV.defaultMMKV()
|
||||||
// //超时后删除配置文件重新创建
|
.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, "")
|
||||||
// launch {
|
com.cncat.vpn.common.log.Log.d("tryButton currentHost==>${currentHost}")
|
||||||
// hideLoading()
|
doProfile()
|
||||||
// }
|
}
|
||||||
// Log.d("isCreate==>$isCreate")
|
})
|
||||||
// if (!isCreate) {
|
dialogDoMainChoose.show()
|
||||||
// isCreate = true
|
} catch (e: Exception) {
|
||||||
//
|
e.printStackTrace()
|
||||||
// launch {
|
}
|
||||||
// showLoading("获取节点超时,正在重新配置...", this@ChangeNodeActivity)
|
|
||||||
// }
|
|
||||||
// createProfile()
|
|
||||||
// } else {
|
|
||||||
// Log.d("stopTimer...")
|
|
||||||
// stopTimer()
|
|
||||||
// launch {
|
|
||||||
// RxToast.error("获取节点失败...")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// timer!!.schedule(timerTask, 0, 1000)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun stopTimer() {
|
private fun stopTimer() {
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@ import com.cncat.vpn.service.remote.wrap
|
||||||
import com.yingmao.clash.util.AESUtil
|
import com.yingmao.clash.util.AESUtil
|
||||||
import com.yingmao.clash.util.Utils
|
import com.yingmao.clash.util.Utils
|
||||||
import com.yingmao.clash.view.RxToast
|
import com.yingmao.clash.view.RxToast
|
||||||
|
import com.yingmao.clash.view.dialog.DialogBandChoose
|
||||||
|
import com.yingmao.clash.view.dialog.DialogDoMainChoose
|
||||||
import com.yingmao.clash.view.dialog.RxDialogSureCancel
|
import com.yingmao.clash.view.dialog.RxDialogSureCancel
|
||||||
import com.yingmao.clash.vm.SplashAtyVM
|
import com.yingmao.clash.vm.SplashAtyVM
|
||||||
import kotlinx.coroutines.MainScope
|
import kotlinx.coroutines.MainScope
|
||||||
|
|
@ -80,9 +82,13 @@ class SplashActivity : BaseActivity() {
|
||||||
ll_action = findViewById(R.id.ll_action)
|
ll_action = findViewById(R.id.ll_action)
|
||||||
serStore.isYM = BuildConfig.is_ym
|
serStore.isYM = BuildConfig.is_ym
|
||||||
if (!BuildConfig.is_ym) {
|
if (!BuildConfig.is_ym) {
|
||||||
serStore.isBZY = true
|
if (BuildConfig.is_tz) {
|
||||||
|
serStore.isTZ = true
|
||||||
|
} else {
|
||||||
|
serStore.isBZY = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
serStore.isTZ = BuildConfig.is_tz
|
|
||||||
|
|
||||||
// mPermissions.add(Manifest.permission.READ_PHONE_STATE)
|
// mPermissions.add(Manifest.permission.READ_PHONE_STATE)
|
||||||
// mPermissions.add(Manifest.permission.INTERNET)
|
// mPermissions.add(Manifest.permission.INTERNET)
|
||||||
|
|
@ -142,7 +148,6 @@ class SplashActivity : BaseActivity() {
|
||||||
registerKey = cb.getRegisterKey(si)
|
registerKey = cb.getRegisterKey(si)
|
||||||
registerIV2 = cb.getRegisterKiv(si)
|
registerIV2 = cb.getRegisterKiv(si)
|
||||||
// com.cncat.vpn.common.log.Log.d("si==>${si}, ss1==>${ss1}, ss2==>${ss2}")
|
// com.cncat.vpn.common.log.Log.d("si==>${si}, ss1==>${ss1}, ss2==>${ss2}")
|
||||||
|
|
||||||
AESUtil.KEY2 = ss1
|
AESUtil.KEY2 = ss1
|
||||||
AESUtil.IV2 = ss2
|
AESUtil.IV2 = ss2
|
||||||
// 太子
|
// 太子
|
||||||
|
|
@ -151,29 +156,62 @@ class SplashActivity : BaseActivity() {
|
||||||
// 八爪鱼 2
|
// 八爪鱼 2
|
||||||
// com.cncat.vpn.common.log.Log.d("bzy2 encrypt:"+ AESUtil.byteArrayToHexStr(AESUtil.encrypt("")))
|
// com.cncat.vpn.common.log.Log.d("bzy2 encrypt:"+ AESUtil.byteArrayToHexStr(AESUtil.encrypt("")))
|
||||||
// 影猫
|
// 影猫
|
||||||
// com.cncat.vpn.common.log.Log.d("ym encrypt:"+ AESUtil.byteArrayToHexStr(AESUtil.encrypt("")))
|
com.cncat.vpn.common.log.Log.d(
|
||||||
|
"ym encrypt:" +
|
||||||
|
AESUtil.byteArrayToHexStr(
|
||||||
|
AESUtil.encrypt(
|
||||||
|
"https://yingmaohot.org+https://yingmao888.net+" +
|
||||||
|
"https://ymsohot.com+https://ma.wztgyh.com+https://ymapi.yingmaox.cc"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
val routerSet =
|
val routerSet =
|
||||||
MMKV.defaultMMKV().decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST)
|
MMKV.defaultMMKV().decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST)
|
||||||
if (routerSet != null && routerSet.size > 0) {
|
if (routerSet != null && routerSet.size > 0) {
|
||||||
isNeedRegister()
|
isNeedRegister()
|
||||||
} else {
|
} else {
|
||||||
|
rlPb.visibility = View.VISIBLE
|
||||||
if (BuildConfig.is_back_cn == true) { //没有备用域名所以无需调用getHost
|
if (BuildConfig.is_back_cn == true) { //没有备用域名所以无需调用getHost
|
||||||
isNeedRegister()
|
isNeedRegister()
|
||||||
} else {
|
} else {
|
||||||
splashAtyVM.getHost(object : AsyncCallback {
|
splashAtyVM.getHostByGithub(object : AsyncCallback {
|
||||||
override suspend fun suc() {
|
override suspend fun suc() {
|
||||||
Log.e("data", "getHost suc")
|
Log.e("data", "getHostByGithub suc")
|
||||||
MainScope().launch {
|
MainScope().launch {
|
||||||
isNeedRegister()
|
isNeedRegister()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun err() {
|
override fun err() {
|
||||||
Log.e("data", "getHost err")
|
Log.e("data", "getHostByGithub err")
|
||||||
//失败也注册
|
splashAtyVM.getHostByAWS(object : AsyncCallback {
|
||||||
MainScope().launch {
|
override suspend fun suc() {
|
||||||
isNeedRegister()
|
Log.e("data", "getHostByAWS suc")
|
||||||
}
|
MainScope().launch {
|
||||||
|
isNeedRegister()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun err() {
|
||||||
|
Log.e("data", "getHostByAWS err")
|
||||||
|
splashAtyVM.getHost(object : AsyncCallback {
|
||||||
|
override suspend fun suc() {
|
||||||
|
Log.e("data", "getHost suc")
|
||||||
|
MainScope().launch {
|
||||||
|
isNeedRegister()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun err() {
|
||||||
|
Log.e("data", "getHost err")
|
||||||
|
//全部失败后也调用
|
||||||
|
MainScope().launch {
|
||||||
|
isNeedRegister()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -586,24 +624,41 @@ class SplashActivity : BaseActivity() {
|
||||||
override fun httpFailure(httpStatus: HttpStatus.Failure) {
|
override fun httpFailure(httpStatus: HttpStatus.Failure) {
|
||||||
when (httpStatus.reqType) {
|
when (httpStatus.reqType) {
|
||||||
HttpReqType.REGISTER -> {
|
HttpReqType.REGISTER -> {
|
||||||
|
rlPb.visibility=View.GONE
|
||||||
|
|
||||||
com.cncat.vpn.common.log.Log.d("httpFailure HttpReqType.REGISTER")
|
com.cncat.vpn.common.log.Log.d("httpFailure HttpReqType.REGISTER")
|
||||||
if (super.switchServer()) {//切换服务器并直接重试
|
try {
|
||||||
// doRegister()
|
RxToast.error("检测到网络异常,请尝试切换其他地址.")
|
||||||
doRegisterByEncryption()
|
val dialogDoMainChoose = DialogDoMainChoose(this@SplashActivity)
|
||||||
} else {
|
dialogDoMainChoose.setOnTryButtonListener(object :
|
||||||
MaterialDialog(this@SplashActivity).show {
|
DialogDoMainChoose.OnTryButtonListener {
|
||||||
message(text = initErrMsg)
|
override fun tryButton() {
|
||||||
positiveButton(R.string.retry) {
|
var currentHost = MMKV.defaultMMKV()
|
||||||
// doRegister()
|
.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, "")
|
||||||
|
com.cncat.vpn.common.log.Log.d("tryButton currentHost==>${currentHost}")
|
||||||
doRegisterByEncryption()
|
doRegisterByEncryption()
|
||||||
}
|
}
|
||||||
negativeButton(R.string.cancel) {
|
})
|
||||||
it.dismiss()
|
dialogDoMainChoose.show()
|
||||||
finish()
|
} catch (e: Exception) {
|
||||||
}
|
e.printStackTrace()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// if (super.switchServer()) {//切换服务器并直接重试
|
||||||
|
//// doRegister()
|
||||||
|
// doRegisterByEncryption()
|
||||||
|
// } else {
|
||||||
|
// MaterialDialog(this@SplashActivity).show {
|
||||||
|
// message(text = initErrMsg)
|
||||||
|
// positiveButton(R.string.retry) {
|
||||||
|
//// doRegister()
|
||||||
|
// doRegisterByEncryption()
|
||||||
|
// }
|
||||||
|
// negativeButton(R.string.cancel) {
|
||||||
|
// it.dismiss()
|
||||||
|
// finish()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpReqType.LOGIN -> {
|
HttpReqType.LOGIN -> {
|
||||||
|
|
|
||||||
|
|
@ -285,11 +285,11 @@ open class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), Br
|
||||||
val iterator = it.iterator()
|
val iterator = it.iterator()
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
val newUrl = iterator.next()
|
val newUrl = iterator.next()
|
||||||
//Log.e("Data", "遍历备用的url:$newUrl")
|
Log.e("Data", "遍历备用的url:$newUrl")
|
||||||
if (newUrl == originalUrl) {
|
if (newUrl == originalUrl) {
|
||||||
iterator.remove()
|
iterator.remove()
|
||||||
} else {
|
} else {
|
||||||
//Log.e("Retry", "切换到新url:$newUrl")
|
Log.e("Retry", "切换到新url:$newUrl")
|
||||||
mmkv.encode(BZYConstants.MMKV_KEY_OLD_CURRENT_HOST, originalUrl)
|
mmkv.encode(BZYConstants.MMKV_KEY_OLD_CURRENT_HOST, originalUrl)
|
||||||
isChange = true
|
isChange = true
|
||||||
newUrlString = newUrl
|
newUrlString = newUrl
|
||||||
|
|
@ -297,7 +297,7 @@ open class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), Br
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mmkv.encode(BZYConstants.MMKV_KEY_ROUTER_HOST, routerHost)
|
// mmkv.encode(BZYConstants.MMKV_KEY_ROUTER_HOST, routerHost)
|
||||||
mmkv.encode(BZYConstants.MMKV_KEY_CURRENT_HOST, newUrlString)
|
mmkv.encode(BZYConstants.MMKV_KEY_CURRENT_HOST, newUrlString)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.yingmao.clash.entity
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class DomainItemBean(
|
||||||
|
val address: String,
|
||||||
|
|
||||||
|
) : Parcelable,Serializable
|
||||||
|
|
@ -163,6 +163,10 @@ interface HttpApi {
|
||||||
//影猫
|
//影猫
|
||||||
@GET("/host.txt")
|
@GET("/host.txt")
|
||||||
suspend fun getHost(): String
|
suspend fun getHost(): String
|
||||||
|
@GET("/host_ym.txt")
|
||||||
|
suspend fun getHostAWS(): String
|
||||||
|
@GET("/ym-source/ym/main/host_ym.txt")
|
||||||
|
suspend fun getHostGithub(): String
|
||||||
//八爪鱼
|
//八爪鱼
|
||||||
@GET("/hostdef.txt")
|
@GET("/hostdef.txt")
|
||||||
suspend fun getHostDef(): String
|
suspend fun getHostDef(): String
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,6 @@ import okhttp3.OkHttpClient
|
||||||
|
|
||||||
|
|
||||||
interface INetService{
|
interface INetService{
|
||||||
fun httpClient():OkHttpClient
|
fun httpClient(connTO:Long,readTO:Long,writeTO:Long):OkHttpClient
|
||||||
fun httpsClient():OkHttpClient
|
fun httpsClient(connTO:Long,readTO:Long,writeTO:Long):OkHttpClient
|
||||||
}
|
}
|
||||||
|
|
@ -42,9 +42,13 @@ import javax.net.ssl.*
|
||||||
class NetService private constructor() : INetService {
|
class NetService private constructor() : INetService {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val ConnectTimeOut = 15L
|
private const val ConnectTimeOut = 10L
|
||||||
private const val ReadTimeOut = 60L
|
private const val ReadTimeOut = 15L
|
||||||
private const val WriteTimeOut = 60L
|
private const val WriteTimeOut = 15L
|
||||||
|
|
||||||
|
private const val Down_ConnectTimeOut = 15L
|
||||||
|
private const val Down_ReadTimeOut = 60L
|
||||||
|
private const val Down_WriteTimeOut = 60L
|
||||||
|
|
||||||
// private var defaultUrl_domestic = getCurrentUrl()
|
// private var defaultUrl_domestic = getCurrentUrl()
|
||||||
val instances: NetService by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { NetService() }
|
val instances: NetService by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { NetService() }
|
||||||
|
|
@ -66,7 +70,7 @@ class NetService private constructor() : INetService {
|
||||||
|
|
||||||
var httpClient: OkHttpClient? = null;
|
var httpClient: OkHttpClient? = null;
|
||||||
|
|
||||||
override fun httpsClient(): OkHttpClient {
|
override fun httpsClient(connTO:Long,readTO:Long,writeTO:Long): OkHttpClient {
|
||||||
|
|
||||||
var loggingInterceptor = HttpLoggingInterceptor(
|
var loggingInterceptor = HttpLoggingInterceptor(
|
||||||
object : HttpLoggingInterceptor.Logger {
|
object : HttpLoggingInterceptor.Logger {
|
||||||
|
|
@ -80,10 +84,10 @@ class NetService private constructor() : INetService {
|
||||||
.retryOnConnectionFailure(true)
|
.retryOnConnectionFailure(true)
|
||||||
// .addInterceptor(RetryAndChangeIpInterceptor())
|
// .addInterceptor(RetryAndChangeIpInterceptor())
|
||||||
// .proxy(java.net.Proxy.NO_PROXY)
|
// .proxy(java.net.Proxy.NO_PROXY)
|
||||||
.connectTimeout(ConnectTimeOut, TimeUnit.SECONDS)
|
.connectTimeout(connTO, TimeUnit.SECONDS)
|
||||||
.writeTimeout(WriteTimeOut, TimeUnit.SECONDS)
|
.writeTimeout(readTO, TimeUnit.SECONDS)
|
||||||
.readTimeout(ReadTimeOut, TimeUnit.SECONDS)
|
.readTimeout(writeTO, TimeUnit.SECONDS)
|
||||||
.callTimeout(240, TimeUnit.SECONDS)
|
.callTimeout(120, TimeUnit.SECONDS)
|
||||||
// .sslSocketFactory(getSSLSocketFactory(), CustomTrustManager())//信任所有证书
|
// .sslSocketFactory(getSSLSocketFactory(), CustomTrustManager())//信任所有证书
|
||||||
.sslSocketFactory(getSSLSocketFactory(), trustAllCerts[0] as X509TrustManager)
|
.sslSocketFactory(getSSLSocketFactory(), trustAllCerts[0] as X509TrustManager)
|
||||||
.hostnameVerifier(getHostnameVerifier()!!)
|
.hostnameVerifier(getHostnameVerifier()!!)
|
||||||
|
|
@ -95,15 +99,15 @@ class NetService private constructor() : INetService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun httpClient(): OkHttpClient {
|
override fun httpClient(connTO:Long,readTO:Long,writeTO:Long): OkHttpClient {
|
||||||
|
|
||||||
return OkHttpClient.Builder()
|
return OkHttpClient.Builder()
|
||||||
// .retryOnConnectionFailure(true)
|
// .retryOnConnectionFailure(true)
|
||||||
// .addInterceptor(RetryAndChangeIpInterceptor())
|
// .addInterceptor(RetryAndChangeIpInterceptor())
|
||||||
.connectTimeout(ConnectTimeOut, TimeUnit.SECONDS)
|
.connectTimeout(connTO, TimeUnit.SECONDS)
|
||||||
.writeTimeout(WriteTimeOut, TimeUnit.SECONDS)
|
.writeTimeout(readTO, TimeUnit.SECONDS)
|
||||||
.readTimeout(ReadTimeOut, TimeUnit.SECONDS)
|
.readTimeout(writeTO, TimeUnit.SECONDS)
|
||||||
// .sslSocketFactory(getSSLSocketFactory(), trustAllCerts[0] as X509TrustManager)//信任所有证书
|
.sslSocketFactory(getSSLSocketFactory(), trustAllCerts[0] as X509TrustManager)//信任所有证书
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,7 +115,7 @@ class NetService private constructor() : INetService {
|
||||||
if (httpClient == null) {
|
if (httpClient == null) {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if (httpClient == null) {
|
if (httpClient == null) {
|
||||||
httpClient = httpClient()
|
httpClient = httpsClient(ConnectTimeOut, ReadTimeOut, WriteTimeOut)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -122,7 +126,7 @@ class NetService private constructor() : INetService {
|
||||||
//创建Retrofit构建器
|
//创建Retrofit构建器
|
||||||
val builder = Retrofit.Builder()
|
val builder = Retrofit.Builder()
|
||||||
if (httpClient == null) {
|
if (httpClient == null) {
|
||||||
httpClient = httpsClient();
|
httpClient = getClient()
|
||||||
}
|
}
|
||||||
builder.client(httpClient)
|
builder.client(httpClient)
|
||||||
builder.baseUrl(getCurrentUrl())
|
builder.baseUrl(getCurrentUrl())
|
||||||
|
|
@ -138,7 +142,7 @@ class NetService private constructor() : INetService {
|
||||||
//创建Retrofit构建器
|
//创建Retrofit构建器
|
||||||
val builder = Retrofit.Builder()
|
val builder = Retrofit.Builder()
|
||||||
if (httpClient == null) {
|
if (httpClient == null) {
|
||||||
httpClient = httpsClient();
|
httpClient = getClient()
|
||||||
}
|
}
|
||||||
builder.client(httpClient)
|
builder.client(httpClient)
|
||||||
//请求的服务器地址
|
//请求的服务器地址
|
||||||
|
|
@ -157,6 +161,12 @@ class NetService private constructor() : INetService {
|
||||||
.build() //创建Retrofit对象
|
.build() //创建Retrofit对象
|
||||||
return retrofit.create(HttpApi::class.java)
|
return retrofit.create(HttpApi::class.java)
|
||||||
}
|
}
|
||||||
|
fun createFreeBaseUrl2(): HttpApi {
|
||||||
|
val retrofit = Retrofit.Builder()
|
||||||
|
.addConverterFactory(ScalarsConverterFactory.create())//json解析器Gson
|
||||||
|
.build() //创建Retrofit对象
|
||||||
|
return retrofit.create(HttpApi::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* post请求,异步方式,提交数据,是在子线程中执行的,需要切换到主线程才能更新UI
|
* post请求,异步方式,提交数据,是在子线程中执行的,需要切换到主线程才能更新UI
|
||||||
|
|
@ -321,7 +331,7 @@ class NetService private constructor() : INetService {
|
||||||
|
|
||||||
fun downloadFile(url: String, downLoadListener: DownLoadListener) {
|
fun downloadFile(url: String, downLoadListener: DownLoadListener) {
|
||||||
if (httpClient == null) {
|
if (httpClient == null) {
|
||||||
httpClient = httpsClient();
|
httpClient = httpsClient(Down_ConnectTimeOut, Down_ReadTimeOut, Down_WriteTimeOut);
|
||||||
}
|
}
|
||||||
val request = Request.Builder().get().url(url).build()
|
val request = Request.Builder().get().url(url).build()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.yingmao.clash.view.adapter
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.text.TextUtils
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.RelativeLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.bumptech.glide.util.Util
|
||||||
|
|
||||||
|
import com.chad.library.adapter.base.BaseQuickAdapter
|
||||||
|
import com.chad.library.adapter.base.module.LoadMoreModule
|
||||||
|
import com.chad.library.adapter.base.viewholder.BaseViewHolder
|
||||||
|
|
||||||
|
import com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
import com.yingmao.clash.R
|
||||||
|
import com.yingmao.clash.entity.ClashNodebBean
|
||||||
|
import com.cncat.vpn.service.model.Profile
|
||||||
|
import com.yingmao.clash.entity.DomainItemBean
|
||||||
|
import com.yingmao.clash.util.Utils
|
||||||
|
|
||||||
|
class DomainListAdapter(layoutResId: Int) :
|
||||||
|
BaseQuickAdapter<DomainItemBean, BaseViewHolder>(layoutResId), LoadMoreModule {
|
||||||
|
|
||||||
|
var selectedPosition: Int = -1
|
||||||
|
|
||||||
|
var addressIndex=1
|
||||||
|
|
||||||
|
override fun convert(holder: BaseViewHolder, item: DomainItemBean) {
|
||||||
|
val domainSelectedTv = holder.getView<TextView>(R.id.domain_selected_tv)
|
||||||
|
val nodeCheckMrb = holder.getView<MaterialRadioButton>(R.id.domain_item_checked)
|
||||||
|
if (holder.layoutPosition == selectedPosition) {
|
||||||
|
nodeCheckMrb.isChecked = true
|
||||||
|
domainSelectedTv.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
nodeCheckMrb.isChecked = false
|
||||||
|
domainSelectedTv.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
val addressName = holder.getView<TextView>(R.id.domain_list_item_tv_address_name)
|
||||||
|
// addressName.text = item.address
|
||||||
|
addressName.text = "地址${addressIndex}"
|
||||||
|
addressIndex++
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
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.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
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.conf.BZYConstants
|
||||||
|
import com.yingmao.clash.conf.PayType
|
||||||
|
import com.yingmao.clash.entity.ClashNodebBean
|
||||||
|
import com.yingmao.clash.entity.DomainItemBean
|
||||||
|
import com.yingmao.clash.fragment.NewAccFragment.Companion.CHECK_NODE_RESULT_CODE
|
||||||
|
import com.yingmao.clash.view.adapter.DomainListAdapter
|
||||||
|
import com.yingmao.clash.view.adapter.NodeListAdapter
|
||||||
|
import com.yingmao.clash.view.dialog.DialogPayTypeChoose.OnPayTypeCheckedListener
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.util.HashSet
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author tamsiree
|
||||||
|
* @date 2016/7/19
|
||||||
|
* 确认 取消 Dialog
|
||||||
|
*/
|
||||||
|
open class DialogDoMainChoose : RxDialog {
|
||||||
|
lateinit var titleView: TextView
|
||||||
|
private set
|
||||||
|
lateinit var but_try: Button
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun initView() {
|
||||||
|
val dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_domain_choose, null)
|
||||||
|
titleView = dialogView.findViewById(R.id.tv_title)
|
||||||
|
but_try = dialogView.findViewById(R.id.but_try)
|
||||||
|
domainRecyclerView = dialogView.findViewById(R.id.domian_list)
|
||||||
|
|
||||||
|
but_try.setOnClickListener {
|
||||||
|
onTryListener.tryButton()
|
||||||
|
}
|
||||||
|
initAdapter()
|
||||||
|
setContentView(dialogView)
|
||||||
|
setCancelable(false)
|
||||||
|
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||||
|
|
||||||
|
var mmkv = MMKV.defaultMMKV()
|
||||||
|
val routerHost = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST, emptySet())
|
||||||
|
var domainList = routerHost?.mapTo(mutableListOf()) { DomainItemBean(it) }
|
||||||
|
setNewData(domainList)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
private fun setNewData(nodes: MutableList<DomainItemBean>?) {
|
||||||
|
if (nodes != null) {
|
||||||
|
domainListAdapter.setNewInstance(nodes)
|
||||||
|
var mmkv = MMKV.defaultMMKV()
|
||||||
|
|
||||||
|
var currentHost = mmkv.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, "")
|
||||||
|
Log.d("currentHost==>${currentHost}")
|
||||||
|
for ((index, node) in nodes.withIndex()) {
|
||||||
|
if (node.address == currentHost) {
|
||||||
|
domainListAdapter.selectedPosition = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
domainListAdapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setOnTryButtonListener(listener: OnTryButtonListener) {
|
||||||
|
this.onTryListener = listener
|
||||||
|
}
|
||||||
|
|
||||||
|
var domainListAdapter: DomainListAdapter = DomainListAdapter(R.layout.domain_list_item_layout)
|
||||||
|
private fun initAdapter() {
|
||||||
|
domainRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||||
|
domainRecyclerView.adapter = domainListAdapter
|
||||||
|
domainListAdapter.selectedPosition
|
||||||
|
domainListAdapter.setOnItemClickListener { baseQuickAdapter: BaseQuickAdapter<*, *>, view: View, position: Int ->
|
||||||
|
(baseQuickAdapter.getItem(position) as DomainItemBean).let { bean ->
|
||||||
|
MMKV.defaultMMKV().encode(BZYConstants.MMKV_KEY_CURRENT_HOST, bean.address)
|
||||||
|
domainListAdapter.notifyItemChanged(domainListAdapter.selectedPosition)
|
||||||
|
domainListAdapter.selectedPosition =
|
||||||
|
if (domainListAdapter.selectedPosition == position) -1 else position
|
||||||
|
domainListAdapter.notifyItemChanged(position)
|
||||||
|
this.onTryListener.tryButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OnTryButtonListener {
|
||||||
|
fun tryButton()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -38,7 +38,11 @@ open class DialogPayTypeChoose : RxDialog {
|
||||||
initView()
|
initView()
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(context: Context?, cancelable: Boolean, cancelListener: DialogInterface.OnCancelListener?) : super(context!!, cancelable, cancelListener) {
|
constructor(
|
||||||
|
context: Context?,
|
||||||
|
cancelable: Boolean,
|
||||||
|
cancelListener: DialogInterface.OnCancelListener?,
|
||||||
|
) : super(context!!, cancelable, cancelListener) {
|
||||||
initView()
|
initView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,12 +98,12 @@ open class DialogPayTypeChoose : RxDialog {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setOnPayTypeCheckedListener(onPayTypeCheckedListener : OnPayTypeCheckedListener){
|
fun setOnPayTypeCheckedListener(onPayTypeCheckedListener: OnPayTypeCheckedListener) {
|
||||||
this.onPayTypeCheckedListener = onPayTypeCheckedListener
|
this.onPayTypeCheckedListener = onPayTypeCheckedListener
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OnPayTypeCheckedListener{
|
interface OnPayTypeCheckedListener {
|
||||||
fun onPayTypeChecked(payType :String)
|
fun onPayTypeChecked(payType: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setTitle(titleStr: String) {
|
fun setTitle(titleStr: String) {
|
||||||
|
|
|
||||||
|
|
@ -69,10 +69,9 @@ class SplashAtyVM : PublicViewMode() {
|
||||||
NetService.instances.createFreeBaseUrl("https://yingmao.oss-cn-hongkong.aliyuncs.com/")
|
NetService.instances.createFreeBaseUrl("https://yingmao.oss-cn-hongkong.aliyuncs.com/")
|
||||||
doAsyncNoNeedReturn(HttpReqType.GET_HOST) {
|
doAsyncNoNeedReturn(HttpReqType.GET_HOST) {
|
||||||
try { //TODO bug 会引起崩溃
|
try { //TODO bug 会引起崩溃
|
||||||
|
|
||||||
|
|
||||||
var host = if (BuildConfig.is_ym) {
|
var host = if (BuildConfig.is_ym) {
|
||||||
rt.getHost()
|
rt.getHost()
|
||||||
|
|
||||||
} else if (BuildConfig.is_tz) {
|
} else if (BuildConfig.is_tz) {
|
||||||
rt.getHostTZ()
|
rt.getHostTZ()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -94,6 +93,68 @@ class SplashAtyVM : PublicViewMode() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getHostByGithub(callback: AsyncCallback) {
|
||||||
|
val rt = NetService.instances.createFreeBaseUrl("https://raw.githubusercontent.com/")
|
||||||
|
doAsyncNoNeedReturn(HttpReqType.GET_HOST) {
|
||||||
|
try {
|
||||||
|
val host = when {
|
||||||
|
BuildConfig.is_ym -> {
|
||||||
|
rt.getHostGithub()
|
||||||
|
}
|
||||||
|
BuildConfig.is_tz -> {
|
||||||
|
rt.getHostTZ()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
rt.getHostDef()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
host?.takeIf { it.isNotEmpty() }?.let {
|
||||||
|
com.cncat.vpn.common.log.Log.d("getHostByGithub host-->${it}")
|
||||||
|
val decryptedHost = AESUtil.decrypt(it)
|
||||||
|
com.cncat.vpn.common.log.Log.d("getHostByGithub decryptedHost-->${decryptedHost}")
|
||||||
|
val hostSet = decryptedHost.split("+").toSet()
|
||||||
|
MMKV.defaultMMKV().encode(BZYConstants.MMKV_KEY_ROUTER_HOST, hostSet)
|
||||||
|
}
|
||||||
|
callback.suc()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
callback.err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getHostByAWS(callback: AsyncCallback) {
|
||||||
|
val rt = NetService.instances.createFreeBaseUrl("https://yingmao2.s3.ap-east-1.amazonaws.com/")
|
||||||
|
doAsyncNoNeedReturn(HttpReqType.GET_HOST) {
|
||||||
|
try {
|
||||||
|
val host = when {
|
||||||
|
BuildConfig.is_ym -> {
|
||||||
|
rt.getHostGithub()
|
||||||
|
}
|
||||||
|
BuildConfig.is_tz -> {
|
||||||
|
rt.getHostTZ()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
rt.getHostDef()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
host?.takeIf { it.isNotEmpty() }?.let {
|
||||||
|
com.cncat.vpn.common.log.Log.d("getHostByAWS host-->${it}")
|
||||||
|
val decryptedHost = AESUtil.decrypt(it)
|
||||||
|
com.cncat.vpn.common.log.Log.d("getHostByAWS decryptedHost-->${decryptedHost}")
|
||||||
|
val hostSet = decryptedHost.split("+").toSet()
|
||||||
|
MMKV.defaultMMKV().encode(BZYConstants.MMKV_KEY_ROUTER_HOST, hostSet)
|
||||||
|
}
|
||||||
|
callback.suc()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
callback.err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun register(params: Map<String, String>) {
|
fun register(params: Map<String, String>) {
|
||||||
Log.e("data", "register ....")
|
Log.e("data", "register ....")
|
||||||
val httpApi = NetService.instances.createHttps(HttpApi::class.java)
|
val httpApi = NetService.instances.createHttps(HttpApi::class.java)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?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/shape_round_white"
|
||||||
|
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"
|
||||||
|
android:gravity="center"
|
||||||
|
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/domain_warn"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/but_try"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/Resend">
|
||||||
|
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/rg_pay_type"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="40dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/domian_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/rl_node_list_item"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="67dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:background="@drawable/node_list_item_bg_selector"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/domain_list_item_tv_address_name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_marginStart="15dp"
|
||||||
|
android:text="地址1"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/domain_selected_tv"
|
||||||
|
android:text="@string/selected"
|
||||||
|
android:visibility="invisible"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:paddingRight="10dp"
|
||||||
|
android:layout_toLeftOf="@+id/domain_item_checked"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
</TextView>
|
||||||
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
android:id="@+id/domain_item_checked"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:buttonTint="@color/white"
|
||||||
|
android:clickable="false" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
@ -279,4 +279,6 @@
|
||||||
<string name="AlipayNotInstalled">Alipay is not installed</string>
|
<string name="AlipayNotInstalled">Alipay is not installed</string>
|
||||||
<string name="quickPaymentMain">Quick payment (recommended)</string>
|
<string name="quickPaymentMain">Quick payment (recommended)</string>
|
||||||
<string name="aggregatePaymentBase">Aggregate payment (backup)</string>
|
<string name="aggregatePaymentBase">Aggregate payment (backup)</string>
|
||||||
|
<string name="domain_warn">The current request is abnormal. Please try selecting an available address</string>
|
||||||
|
<string name="selected">Selected</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -271,4 +271,6 @@
|
||||||
<string name="AlipayNotInstalled">支付寶未安裝</string>
|
<string name="AlipayNotInstalled">支付寶未安裝</string>
|
||||||
<string name="quickPaymentMain">快捷支付(推薦)</string>
|
<string name="quickPaymentMain">快捷支付(推薦)</string>
|
||||||
<string name="aggregatePaymentBase">聚合支付(備用)</string>
|
<string name="aggregatePaymentBase">聚合支付(備用)</string>
|
||||||
|
<string name="domain_warn">當前請求异常,請嘗試選擇可用地址</string>
|
||||||
|
<string name="selected">當前選擇</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -270,4 +270,6 @@
|
||||||
<string name="AlipayNotInstalled">支付寶未安裝</string>
|
<string name="AlipayNotInstalled">支付寶未安裝</string>
|
||||||
<string name="quickPaymentMain">快捷支付(推薦)</string>
|
<string name="quickPaymentMain">快捷支付(推薦)</string>
|
||||||
<string name="aggregatePaymentBase">聚合支付(備用)</string>
|
<string name="aggregatePaymentBase">聚合支付(備用)</string>
|
||||||
|
<string name="domain_warn">當前請求异常,請嘗試選擇可用地址</string>
|
||||||
|
<string name="selected">當前選擇</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -286,4 +286,6 @@
|
||||||
<string name="AlipayNotInstalled">支付宝未安装</string>
|
<string name="AlipayNotInstalled">支付宝未安装</string>
|
||||||
<string name="quickPaymentMain">快捷支付(推荐)</string>
|
<string name="quickPaymentMain">快捷支付(推荐)</string>
|
||||||
<string name="aggregatePaymentBase">聚合支付(备用)</string>
|
<string name="aggregatePaymentBase">聚合支付(备用)</string>
|
||||||
|
<string name="domain_warn">当前请求异常,请尝试选择可用地址</string>
|
||||||
|
<string name="selected">当前选择</string>
|
||||||
</resources>
|
</resources>
|
||||||
Loading…
Reference in New Issue