修改备用源逻辑,改用手动选择方式

修改api请求的超时时间
This commit is contained in:
cyh 2025-03-13 18:56:04 +08:00
parent 6f2b108068
commit 7b3351ebfd
17 changed files with 521 additions and 89 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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