登录,注册和节点添加备用源

This commit is contained in:
cyh 2025-03-14 16:47:17 +08:00
parent 7b3351ebfd
commit a417929817
13 changed files with 470 additions and 242 deletions

View File

@ -42,6 +42,7 @@ import com.yingmao.clash.view.adapter.NodeListAdapter
import com.yingmao.clash.view.dialog.DialogDoMainChoose
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Semaphore
@ -165,10 +166,12 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
override fun onReceive(context: Context?, intent: Intent?) {
when (intent?.action) {
Intents.ACTION_NODE_LIST -> {
Log.d("ACTION_NODE_LIST ACTION_NODE_LIST")
// val parcelableArrayListExtra = intent.getParcelableArrayListExtra<Map<String,Any>>("")
hideLoading()
// stopTimer()
timerJob?.cancel()
dialogDoMainChoose?.dismiss()
// var json = intent.getStringExtra("node_list")
// Log.d("onReceive: $json")
// currNodeJsonA = json
@ -177,6 +180,9 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
if (TextUtils.isEmpty(json)) {
return
}
//缓存订阅地址
NewMainActivity.subUrl=nowSubUrl
MMKV.defaultMMKV().encode(BZYConstants.PROFILE_SUB_URL, nowSubUrl)
//缓存节点
MMKV.defaultMMKV().encode(BZYConstants.NODE_All_ITEM_NAME_KEY, json)
currentNode = getNodesInfo(json)
@ -212,42 +218,67 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
var is_runing = false
private var timer: Timer? = null
private var timerTask: TimerTask? = null
var nowSubUrl: String = ""
private fun updateProfile(isDelete: Boolean) {
// showLoading("正在获取...", this@ChangeNodeActivity)
launch(Dispatchers.IO) {
NewMainActivity.profileBinder?.let { profileManager ->
var pro = profileManager.queryAll().find {
it.name == Conf.getClashConfName(this@ChangeNodeActivity.applicationContext)
}
try {
if (pro == null) {
//为空的情况下选择第一个
profileManager.queryAll().forEach { profile ->
pro = profile
return@forEach
launch(Dispatchers.IO) {
NewMainActivity.profileBinder?.let { profileManager ->
var mProfile = profileManager.queryAll().find {
it.name == Conf.getClashConfName(this@ChangeNodeActivity.applicationContext)
}
if (mProfile == null) {
//为空的情况下选择第一个
profileManager.queryAll().forEach { profile ->
mProfile = profile
return@forEach
}
}
mProfile?.let { profile ->
uuid = profile.uuid
Log.d("ChangeNode22 uuid==>${profile.uuid}")
if (isDelete) {
Log.d("gogogogogo isDelete")
profileManager.delete(profile.uuid)
MMKV.defaultMMKV()
.removeValueForKey(BZYConstants.NODE_All_ITEM_NAME_KEY)
// setSub2(profileManager, NewMainActivity.subUrl)
setSub2(profileManager, nowSubUrl)
} else {
Log.d("gogogogogo update")
profileManager.setActive(profile)
delay(500)
if (!TextUtils.isEmpty(profile.source)) {
Log.d("updateProfile pro.source==>${profile.source}, url==>${nowSubUrl}")
if (profile.source != nowSubUrl) {
Log.d("updateProfile patch")
profileManager.patch(
profile.uuid,
profile.name,
nowSubUrl,
1800000L
)
Log.d("updateProfile patch 1")
profileManager.commit(profile.uuid) { status ->
Log.d("updateProfile updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress)
}
Log.d("updateProfile patch 2")
}
}
Log.d("updateProfile go update")
profileManager.update(profile.uuid)
}
Log.d("gogogogogo end")
}
}
pro?.uuid?.let { pu ->
uuid = pu
com.cncat.vpn.common.log.Log.d("ChangeNode22 uuid==>$pu")
com.cncat.vpn.common.log.Log.d("gogogogogo")
if (isDelete) {
com.cncat.vpn.common.log.Log.d("gogogogogo isDelete")
profileManager.delete(pu)
// setSub2(profileManager, NewMainActivity.subUrl)
setSub2(profileManager, NewMainActivity.subUrl)
} else {
com.cncat.vpn.common.log.Log.d("gogogogogo update")
profileManager.setActive(pro!!)
delay(500)
profileManager.update(pu)
}
com.cncat.vpn.common.log.Log.d("gogogogogo end")
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
@ -273,19 +304,27 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
override fun onStart() {
super.onStart()
NewMainActivity.subUrl?.let {
nowSubUrl = it
}
doProfile()
}
fun doProfile() {
if (TextUtils.isEmpty(cacheNodeStr)) {
showLoading("正在获取...", this@ChangeNodeActivity)
startTimer()
}
showLoading("正在获取...", this@ChangeNodeActivity)
startTimer()
updateProfile(false)
}
private fun changeSubUrl(originalUrl: String, newUrl: String) {
nowSubUrl = originalUrl.replace(Regex("https://[^/]+/"), "$newUrl/")
}
val reloadLock = Semaphore(10)
private fun setPing() {
if (!NewAccFragment.clashRunning) {
@ -452,44 +491,55 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
private fun startTimer() {
GetNodeTimeOutNum = 10
timerJob = launch {
repeat(10) {
repeat(11) {
Log.d("GetNodeTimeOutNum==>$GetNodeTimeOutNum")
if (GetNodeTimeOutNum >= 5) {
GetNodeTimeOutNum--
} else {
//超时后删除配置文件重新创建
if (GetNodeTimeOutNum == 0) {
hideLoading()
Log.d("isCreate==>$isCreate")
if (!isCreate) {
isCreate = true
showLoading("获取节点超时,正在重新配置...", this@ChangeNodeActivity)
createProfile()
} else {
Log.d("stopTimer...")
RxToast.error("获取节点失败...请尝试切换其他地址")
delay(1000)
this@ChangeNodeActivity.finish()
}
Log.d("stopTimer...")
RxToast.error("获取节点失败...请尝试切换其他地址")
showDomainList()
timerJob?.cancel()
// delay(1000)
// this@ChangeNodeActivity.finish()
}
GetNodeTimeOutNum--
delay(1000)
}
}
}
var dialogDoMainChoose:DialogDoMainChoose? =null
private fun showDomainList() {
try {
SplashHelper(changeNodeVM).getHostWithFallback { success ->
MainScope().launch {
if (success) {
if (dialogDoMainChoose==null) {
dialogDoMainChoose = DialogDoMainChoose(this@ChangeNodeActivity)
}
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) }
doProfile()
}
val dialogDoMainChoose = DialogDoMainChoose(this@ChangeNodeActivity)
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}")
doProfile()
override fun cancel() {
com.cncat.vpn.common.log.Log.d("tryButton CHECK_LOGIN cancel")
dialogDoMainChoose?.dismiss()
}
})
dialogDoMainChoose?.show()
}
}
}
})
dialogDoMainChoose.show()
}
} catch (e: Exception) {
e.printStackTrace()
}

View File

@ -35,10 +35,15 @@ import com.yingmao.clash.util.CommonUtils
import com.yingmao.clash.util.Utils
import com.yingmao.clash.view.PasswordTransformationMethodBigDot
import com.yingmao.clash.view.RxToast
import com.yingmao.clash.view.dialog.DialogDoMainChoose
import com.yingmao.clash.vm.LoginAtyVM
import com.yingmao.clash.vm.SplashAtyVM
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
class LoginActivity : BaseActivity(), View.OnClickListener {
private lateinit var loginViewMode: LoginAtyVM
private lateinit var splashAtyVM: SplashAtyVM
private lateinit var usernameEt: EditText
private lateinit var passwordEt: EditText
private lateinit var usernameErrorTv: TextView
@ -64,6 +69,7 @@ class LoginActivity : BaseActivity(), View.OnClickListener {
//点击输入框外边隐藏输入法 必须在setContentView之后调用
setupUI(findViewById<ViewGroup>(android.R.id.content).getChildAt(0))
loginViewMode = ViewModelProvider(this).get(LoginAtyVM::class.java)
splashAtyVM = ViewModelProvider(this).get(SplashAtyVM::class.java)
observe(this, loginViewMode)
initViews()
}
@ -146,18 +152,49 @@ class LoginActivity : BaseActivity(), View.OnClickListener {
}
}
}
var dialogDoMainChoose: DialogDoMainChoose? = null
override fun httpFailure(httpStatus: HttpStatus.Failure) {
super.httpFailure(httpStatus)
if (httpStatus.reqType == HttpReqType.LOGIN) {
if (super.switchServer()) {
loginViewMode.login(username_encrypt, password_encrypt)
} else {
if (::rxDialogShapeLoading.isInitialized && rxDialogShapeLoading.isShowing) {
rxDialogShapeLoading.cancel()
SplashHelper(splashAtyVM).getHostWithFallback { success ->
MainScope().launch {
if (success) {
if (dialogDoMainChoose==null) {
dialogDoMainChoose = DialogDoMainChoose(this@LoginActivity)
}
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 CHECK_LOGIN currentHost==>${currentHost}")
loginViewMode.login(username_encrypt, password_encrypt)
}
override fun cancel() {
com.cncat.vpn.common.log.Log.d("tryButton CHECK_LOGIN cancel")
dialogDoMainChoose?.dismiss()
}
})
dialogDoMainChoose?.show()
}
}else{
if (::rxDialogShapeLoading.isInitialized && rxDialogShapeLoading.isShowing) {
rxDialogShapeLoading.cancel()
}
RxToast.error(resources.getString(R.string.LoginException))
}
}
RxToast.error(resources.getString(R.string.LoginException))
}
// if (super.switchServer()) {
// loginViewMode.login(username_encrypt, password_encrypt)
// } else {
// if (::rxDialogShapeLoading.isInitialized && rxDialogShapeLoading.isShowing) {
// rxDialogShapeLoading.cancel()
// }
// RxToast.error(resources.getString(R.string.LoginException))
// }
} else if (httpStatus.reqType == HttpReqType.CHECK_LOGIN) {
if (::rxDialogShapeLoading.isInitialized && rxDialogShapeLoading.isShowing) {
rxDialogShapeLoading.cancel()

View File

@ -524,13 +524,25 @@ class NewMainActivity : BaseActivity() {
}
data.data?.let { url ->
android.util.Log.e("Data", "机场URL=${url}")
// var url2="https://www.otcopusapp.cc/lx3af288h5i8pz380/api/v1/client/subscribe?token=d6bc98c7ea53099fa5bd1a3ea415ebb6"
// var url2="https://api.ymvpnpro11.cc:8700/7air2vr7ikiqzgvxz/api/v1/client/subscribe?token=5af82930d222840cbc2dec572b21d6c6"
if (url.isNotEmpty()) {
//todo 判断订阅地址是否修改过,未修改就用接口返回的地址反之使用本地修改的地址
var pro_sub_url =
MMKV.defaultMMKV().decodeString(BZYConstants.PROFILE_SUB_URL, "")
if (!TextUtils.isEmpty(pro_sub_url)){
if (pro_sub_url == url) {
subUrl = url
} else {
subUrl = pro_sub_url
}
}else{
subUrl = url
}
subUrl = url
lifecycleScope.launch(Dispatchers.IO) {
// setSub(url)
setSub2(url)
subUrl?.let { setSub2(it) }
}
}
}
@ -648,7 +660,7 @@ class NewMainActivity : BaseActivity() {
MMKV.defaultMMKV().removeValueForKey(BZYConstants.MMKV_KEY_CURRENT_NODE)
MMKV.defaultMMKV().removeValueForKey(BZYConstants.NODE_SELECTED_NAME_KEY)
MMKV.defaultMMKV().removeValueForKey(BZYConstants.MMKV_KEY_VPN_UserCommand)
MMKV.defaultMMKV().removeValueForKey(BZYConstants.NODE_All_ITEM_NAME_KEY)
Log.d("cleanUserInfo clashRunning==>${clashRunning}")
if (clashRunning) {
fragments.filterIsInstance<NewAccFragment>().forEach { it.stopClash() }

View File

@ -0,0 +1,51 @@
package com.yingmao.clash.act
import android.util.Log
import com.yingmao.clash.base.PublicViewMode
import com.yingmao.clash.listener.AsyncCallback
import com.yingmao.clash.vm.SplashAtyVM
class SplashHelper(private val splashAtyVM: PublicViewMode) {
fun getHostWithFallback(callback: (Boolean) -> Unit) {
tryGetHost(
{ splashAtyVM.getHostByGithub(it) },
{ splashAtyVM.getHostByAWS(it) },
{ splashAtyVM.getHost(it) },
callback
)
}
private fun tryGetHost(
first: (AsyncCallback) -> Unit,
second: (AsyncCallback) -> Unit,
third: (AsyncCallback) -> Unit,
callback: (Boolean) -> Unit
) {
first(createCallback("getHostByGithub method success", "getHostByGithub method failed", callback) {
second(createCallback("getHostByAWS method success", "getHostByAWS method failed", callback) {
third(createCallback("getHost method success", "getHost methods failed", callback) {
callback(false) // 所有方法都失败
})
})
})
}
private fun createCallback(
successLog: String,
errorLog: String,
callback: (Boolean) -> Unit,
onFailure: () -> Unit
): AsyncCallback {
return object : AsyncCallback {
override suspend fun suc() {
Log.e("data", successLog)
callback(true) // 成功时回调
}
override fun err() {
Log.e("data", errorLog)
onFailure() // 失败时尝试下一个方法
}
}
}
}

View File

@ -174,46 +174,55 @@ class SplashActivity : BaseActivity() {
if (BuildConfig.is_back_cn == true) { //没有备用域名所以无需调用getHost
isNeedRegister()
} else {
splashAtyVM.getHostByGithub(object : AsyncCallback {
override suspend fun suc() {
Log.e("data", "getHostByGithub suc")
MainScope().launch {
SplashHelper(splashAtyVM).getHostWithFallback { success ->
MainScope().launch {
if (success) {
isNeedRegister()
} else {
isNeedRegister()
}
}
override fun err() {
Log.e("data", "getHostByGithub err")
splashAtyVM.getHostByAWS(object : AsyncCallback {
override suspend fun suc() {
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()
}
}
})
}
})
}
})
}
// splashAtyVM.getHostByGithub(object : AsyncCallback {
// override suspend fun suc() {
// Log.e("data", "getHostByGithub suc")
// MainScope().launch {
// isNeedRegister()
// }
// }
//
// override fun err() {
// Log.e("data", "getHostByGithub err")
// splashAtyVM.getHostByAWS(object : AsyncCallback {
// override suspend fun suc() {
// 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()
// }
// }
// })
// }
// })
// }
// })
}
}
}
@ -488,6 +497,7 @@ class SplashActivity : BaseActivity() {
override fun httpSuccess(httpStatus: HttpStatus.Success) {
when (httpStatus.reqType) {
HttpReqType.REGISTER -> {
dialogDoMainChoose?.dismiss()
with(httpStatus.rsp as RegisterRsp) {
if (code == "10000" || code == "200") {
if (data != null) {
@ -591,6 +601,7 @@ class SplashActivity : BaseActivity() {
}
HttpReqType.CHECK_LOGIN -> {
dialogDoMainChoose?.dismiss()
(httpStatus.rsp as CheckLoginRsp).let { checkLoginRsp ->
if (checkLoginRsp.code == 0) {
com.cncat.vpn.common.log.Log.d("splash CHECK_LOGIN==>")
@ -621,25 +632,36 @@ class SplashActivity : BaseActivity() {
}
}
var dialogDoMainChoose: DialogDoMainChoose? = null
override fun httpFailure(httpStatus: HttpStatus.Failure) {
when (httpStatus.reqType) {
HttpReqType.REGISTER -> {
rlPb.visibility=View.GONE
rlPb.visibility = View.GONE
com.cncat.vpn.common.log.Log.d("httpFailure HttpReqType.REGISTER")
try {
RxToast.error("检测到网络异常,请尝试切换其他地址.")
val dialogDoMainChoose = DialogDoMainChoose(this@SplashActivity)
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}")
doRegisterByEncryption()
}
})
dialogDoMainChoose.show()
if (dialogDoMainChoose==null) {
dialogDoMainChoose = DialogDoMainChoose(this@SplashActivity)
}
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}")
doRegisterByEncryption()
}
override fun cancel() {
com.cncat.vpn.common.log.Log.d("tryButton REGISTER cancel")
dialogDoMainChoose?.dismiss()
dialogDoMainChoose=null
}
})
dialogDoMainChoose?.show()
}
} catch (e: Exception) {
e.printStackTrace()
}
@ -682,11 +704,45 @@ class SplashActivity : BaseActivity() {
HttpReqType.CHECK_LOGIN -> {
com.cncat.vpn.common.log.Log.d("httpFailure HttpReqType.CHECK_LOGIN")
if (super.switchServer()) {
splashAtyVM.checkLogin()
} else {
try {
RxToast.error("检测到网络异常,请尝试切换其他地址.")
SplashHelper(splashAtyVM).getHostWithFallback { success ->
MainScope().launch {
if (success) {
if (dialogDoMainChoose==null) {
dialogDoMainChoose = DialogDoMainChoose(this@SplashActivity)
}
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 CHECK_LOGIN currentHost==>${currentHost}")
splashAtyVM.checkLogin()
}
override fun cancel() {
com.cncat.vpn.common.log.Log.d("tryButton CHECK_LOGIN cancel")
dialogDoMainChoose?.dismiss()
}
})
dialogDoMainChoose?.show()
}
}
}
}
} catch (e: Exception) {
e.printStackTrace()
toLoginPage()
}
// if (super.switchServer()) {
// splashAtyVM.checkLogin()
// } else {
// toLoginPage()
// }
}
else -> {}

View File

@ -1,10 +1,17 @@
package com.yingmao.clash.base
import android.text.TextUtils
import com.yingmao.clash.net.http.HttpApi
import com.yingmao.clash.net.http.NetService
import com.orhanobut.logger.Logger
import com.tencent.mmkv.MMKV
import com.yingmao.clash.BuildConfig
import com.yingmao.clash.conf.BZYConstants
import com.yingmao.clash.entity.DomainRsp
import com.yingmao.clash.listener.AsyncCallback
import com.yingmao.clash.net.http.HttpReqType
import com.yingmao.clash.util.AESUtil
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.util.ArrayList
@ -17,6 +24,95 @@ open class PublicViewMode: BaseViewMode() {
// return acls.size > 3
// }
fun getHost(callback: AsyncCallback) {
val rt =
NetService.instances.createFreeBaseUrl("https://yingmao.oss-cn-hongkong.aliyuncs.com/")
doAsyncNoNeedReturn(HttpReqType.GET_HOST) {
try { //TODO bug 会引起崩溃
var host = if (BuildConfig.is_ym) {
rt.getHost()
} else if (BuildConfig.is_tz) {
rt.getHostTZ()
} else {
rt.getHostDef()
}
// Log.e("data", "2:$host")
if (!TextUtils.isEmpty(host)) {
host = AESUtil.decrypt(host)
val hostSet = host.split("+").toSet()
MMKV.defaultMMKV().encode(BZYConstants.MMKV_KEY_ROUTER_HOST, hostSet)
}
// Log.e("data", "22:$host")
callback.suc()
} catch (e: Exception) {
e.printStackTrace()
callback.err()
}
}
}
fun getHostByGithub(callback: AsyncCallback) {
val rt = NetService.instances.createFreeBaseUrl("https://raw.githubusercontent1.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.getHostAWS()
}
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 getServiceAclAndSet(){
val httpApi = NetService.instances.createHttpsEncodeStr(HttpApi::class.java)
GlobalScope.launch {

View File

@ -63,8 +63,10 @@ class BZYConstants {
const val MMKV_KEY_IS_REGISTER = "is_register"
//节点
const val NODE_SELECTED_NAME_KEY = "node_select_name_key"
//节点列表
const val NODE_All_ITEM_NAME_KEY = "NODE_All_ITEM_NAME_KEY"
//订阅地址
const val PROFILE_SUB_URL = "PROFILE_SUB_URL"
//服务器模式根据手机ip切换后台地址
const val MMKV_KEY_SERVICE_TYPE = "SERVICE_TYPE"

View File

@ -69,6 +69,7 @@ class NetService private constructor() : INetService {
}
var httpClient: OkHttpClient? = null;
var downHttpClient: OkHttpClient? = null;
override fun httpsClient(connTO:Long,readTO:Long,writeTO:Long): OkHttpClient {
@ -330,12 +331,12 @@ class NetService private constructor() : INetService {
}
fun downloadFile(url: String, downLoadListener: DownLoadListener) {
if (httpClient == null) {
httpClient = httpsClient(Down_ConnectTimeOut, Down_ReadTimeOut, Down_WriteTimeOut);
if (downHttpClient == null) {
downHttpClient = httpsClient(Down_ConnectTimeOut, Down_ReadTimeOut, Down_WriteTimeOut);
}
val request = Request.Builder().get().url(url).build()
httpClient?.let { hc ->
downHttpClient?.let { hc ->
val call = hc.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {

View File

@ -37,8 +37,10 @@ class DomainListAdapter(layoutResId: Int) :
domainSelectedTv.visibility = View.INVISIBLE
}
val addressName = holder.getView<TextView>(R.id.domain_list_item_tv_address_name)
// addressName.text = item.address
addressName.text = "地址${addressIndex}"
if (!TextUtils.isEmpty(item.address)) {
addressName.text = item.address.replace(Regex("https://"), "")
}
// addressName.text = "地址${addressIndex}"
addressIndex++
}

View File

@ -9,8 +9,6 @@ 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
@ -20,16 +18,10 @@ 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
@ -41,10 +33,11 @@ open class DialogDoMainChoose : RxDialog {
private set
lateinit var but_try: Button
private set
lateinit var domainRecyclerView: RecyclerView
lateinit var but_cancel: Button
private set
lateinit var onTryListener: OnTryButtonListener
lateinit var domainRecyclerView: RecyclerView
private set
lateinit var onTryListener: OnTryButtonListener
constructor(context: Context?, themeResId: Int) : super(context!!, themeResId) {
initView()
@ -75,11 +68,13 @@ open class DialogDoMainChoose : RxDialog {
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)
but_cancel = dialogView.findViewById(R.id.but_cancel)
domainRecyclerView = dialogView.findViewById(R.id.domian_list)
but_try.setOnClickListener {
onTryListener.tryButton()
}
but_cancel.setOnClickListener { onTryListener.cancel() }
initAdapter()
setContentView(dialogView)
setCancelable(false)
@ -133,6 +128,7 @@ open class DialogDoMainChoose : RxDialog {
interface OnTryButtonListener {
fun tryButton()
fun cancel()
}
}

View File

@ -64,94 +64,6 @@ class SplashAtyVM : PublicViewMode() {
}
}
fun getHost(callback: AsyncCallback) {
val rt =
NetService.instances.createFreeBaseUrl("https://yingmao.oss-cn-hongkong.aliyuncs.com/")
doAsyncNoNeedReturn(HttpReqType.GET_HOST) {
try { //TODO bug 会引起崩溃
var host = if (BuildConfig.is_ym) {
rt.getHost()
} else if (BuildConfig.is_tz) {
rt.getHostTZ()
} else {
rt.getHostDef()
}
// Log.e("data", "2:$host")
if (!TextUtils.isEmpty(host)) {
host = AESUtil.decrypt(host)
val hostSet = host.split("+").toSet()
MMKV.defaultMMKV().encode(BZYConstants.MMKV_KEY_ROUTER_HOST, hostSet)
}
// Log.e("data", "22:$host")
callback.suc()
} catch (e: Exception) {
e.printStackTrace()
callback.err()
}
}
}
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()
}
}
}

View File

@ -14,13 +14,13 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@drawable/shape_round_white"
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"
android:gravity="center"
tools:ignore="MissingConstraints">
<TextView
@ -35,19 +35,14 @@
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:layout_marginBottom="15dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
@ -57,7 +52,25 @@
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_margin="15dp"
android:layout_height="wrap_content">
<Button
android:id="@+id/but_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel">
</Button>
<Button
android:layout_alignParentRight="true"
android:id="@+id/but_try"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/Resend">
</Button>
</RelativeLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -3,8 +3,8 @@
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:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@drawable/node_list_item_bg_selector"
android:clickable="true"
android:focusable="true">
@ -24,7 +24,7 @@
android:text="@string/selected"
android:visibility="invisible"
android:layout_width="wrap_content"
android:textColor="@color/white"
android:textColor="@color/green"
android:layout_centerVertical="true"
android:paddingRight="10dp"
android:layout_toLeftOf="@+id/domain_item_checked"