diff --git a/app/src/main/java/com/yingmao/clash/act/ChangeNodeActivity.kt b/app/src/main/java/com/yingmao/clash/act/ChangeNodeActivity.kt index 3a75f04..5892266 100644 --- a/app/src/main/java/com/yingmao/clash/act/ChangeNodeActivity.kt +++ b/app/src/main/java/com/yingmao/clash/act/ChangeNodeActivity.kt @@ -29,6 +29,7 @@ import com.yingmao.clash.R import com.yingmao.clash.base.BaseActivity import com.cncat.vpn.common.constants.Intents import com.cncat.vpn.common.log.Log +import com.cncat.vpn.service.ProfileManager import com.yingmao.clash.conf.BZYConstants import com.yingmao.clash.conf.Conf import com.yingmao.clash.entity.ClashNodebBean @@ -38,8 +39,11 @@ import com.yingmao.clash.remote.Resource import com.cncat.vpn.service.model.Profile import com.cncat.vpn.service.remote.IProfileManager import com.cncat.vpn.service.remote.IRemoteService +import com.cncat.vpn.service.remote.wrap +import com.yingmao.clash.BuildConfig import com.yingmao.clash.app.MainApplication import com.yingmao.clash.fragment.home.HomeFragment +import com.yingmao.clash.util.CommonUtils import com.yingmao.clash.util.Utils import com.yingmao.clash.view.RxToast import com.yingmao.clash.view.adapter.NodeListAdapter @@ -100,6 +104,8 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { private fun initData() { // clash = MainApplication.getApp()?.let { ClashManager(it) } +// profileBinder = +// MainApplication.getApp()?.let { ProfileManager(it).wrap() as IProfileManager } cacheNodeStr = MMKV.defaultMMKV().decodeString(BZYConstants.NODE_All_ITEM_NAME_KEY, ""); val intentFilter = IntentFilter(Intents.ACTION_NODE_LIST) @@ -233,14 +239,21 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { var nowSubUrl: String = "" private fun updateProfile(isDelete: Boolean) { // showLoading("正在获取...", this@ChangeNodeActivity) - try { - - launch(Dispatchers.IO) { UIMainActivity.profileBinder?.let { profileManager -> - var mProfile = profileManager.queryAll().find { - it.name == Conf.getClashConfName(this@ChangeNodeActivity.applicationContext) +// var mProfile = profileManager.queryAll().find { +// it.name == Conf.getClashConfName(this@ChangeNodeActivity.applicationContext) +// } + var mProfile: Profile? = null + Log.d("queryAll().size ==>${profileManager.queryAll().size}") + profileManager.queryAll().forEach { it_pf -> + var confName = + Conf.getClashConfName(this@ChangeNodeActivity.applicationContext) + Log.d(" it_pf.name ==>${it_pf.name}, confName==>${confName}") + if (confName == it_pf.name) { + mProfile = it_pf + } } if (mProfile == null) { @@ -256,16 +269,16 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { Log.d("ChangeNode22 uuid==>${profile.uuid}") if (isDelete) { Log.d("gogogogogo isDelete") - profileManager.delete(profile.uuid) +// profileManager.delete(profile.uuid) MMKV.defaultMMKV() .removeValueForKey(BZYConstants.NODE_All_ITEM_NAME_KEY) - setSub2(profileManager, nowSubUrl) + } else { Log.d("gogogogogo update") profileManager.setActive(profile) - delay(500) + Log.d("updateProfile pro.source==>${profile.source}, url==>${nowSubUrl}") if (!TextUtils.isEmpty(profile.source)) { -// Log.d("updateProfile pro.source==>${profile.source}, url==>${nowSubUrl}") + if (profile.source != nowSubUrl) { Log.d("updateProfile patch") profileManager.patch( @@ -280,6 +293,17 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { } Log.d("updateProfile patch 2") } + } else { + profileManager.patch( + profile.uuid, + profile.name, + nowSubUrl, + 1800000L + ) + Log.d("updateProfile patch new 1") + profileManager.commit(profile.uuid) { status -> + Log.d("updateProfile new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress) + } } Log.d("updateProfile go update") profileManager.update(profile.uuid) @@ -318,29 +342,35 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { UIMainActivity.subUrl?.let { nowSubUrl = it } - doProfile() + doProfile(false) } - fun doProfile() { + fun doProfile(isDelete: Boolean) { + Log.d("doProfile....") if (TextUtils.isEmpty(cacheNodeStr)) { } showLoading("正在获取...", this@ChangeNodeActivity) startTimer() - updateProfile(false) +// updateProfile(isDelete) + + launch(Dispatchers.IO) { + UIMainActivity.setSub2(nowSubUrl) + } } private fun changeSubUrl(originalUrl: String, newUrl: String) { if (!originalUrl.isNullOrEmpty() && !newUrl.isNullOrEmpty()) { nowSubUrl = originalUrl.replace(Regex("https://[^/]+/"), "$newUrl/") + UIMainActivity.subUrl = nowSubUrl MMKV.defaultMMKV().encode(BZYConstants.PROFILE_SUB_URL, nowSubUrl) } } private fun updateTestBut(str: String) { - nodeItemTest.text=str + nodeItemTest.text = str } val reloadLock = Semaphore(10) @@ -393,7 +423,6 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { } } - private fun setNewData(nodes: MutableList?) { runOnUiThread { if (nodes != null) { @@ -449,13 +478,25 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { } private fun createProfile() { + cleanProfile() launch(Dispatchers.IO) { UIMainActivity.profileBinder?.let { pro -> - uuid?.let { uu -> - pro.delete(uu) - delay(500) - setSub2(pro, UIMainActivity.subUrl) + createMyProfile(pro, nowSubUrl) + + } + + } + } + + private fun cleanProfile() { + launch(Dispatchers.IO) { + UIMainActivity.profileBinder?.let { pm -> + pm.queryAll().forEach { profile -> + Log.d("changeNode cleanProfile go delete name==>${profile.name}, uuid==>${profile.uuid}") + pm.delete(profile.uuid) } + } ?: let { + Log.d("changeNode profileBinder is null") } } } @@ -466,10 +507,6 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { com.cncat.vpn.common.log.Log.d("setSub2 url isEmpty") return } - - com.cncat.vpn.common.log.Log.d("setSub2 2") - - com.cncat.vpn.common.log.Log.d("setSub2 3") val pro = pm.queryAll().find { it.name == Conf.getClashConfName(this@ChangeNodeActivity.applicationContext) @@ -502,11 +539,40 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { "new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress ) } + // } } } } + suspend fun createMyProfile(pm: IProfileManager, url: String) { + var uuid: UUID = pm.create( + Profile.Type.Url, Conf.getClashConfName(this@ChangeNodeActivity.applicationContext) + ) + delay(500) + pm.queryByUUID(uuid)?.let { qPro -> + Log.d("createMyProfile url==>${url}") + pm.setActive(qPro) + pm.patch( + qPro.uuid, qPro.name, +// "https://mojie0201.xn--8stx8olrwkucjq3b.com/api/v1/client/subscribe?token=169110d2674c49604b7e5b5cea341579", +// "https://www.otcopusapp.cc/lx3af288h5i8pz380/api/v1/client/subscribe?token=d6bc98c7ea53099fa5bd1a3ea415ebb6", +// "https://reg.bazhuayujiasu.cc/api/v1/client/subscribe?token=7f0f025ab341bcec4822d2c90aadf8b0", + url, 1800000L + ) +// coroutineScope { + pm.commit(qPro.uuid) { status -> + android.util.Log.d( + Conf.TAG, + "new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress + ) + } + +// UIMainActivity.profileBinder = pm +// } + } + } + var isCreate: Boolean = false private var timerJob: Job? = null private fun startTimer() { @@ -514,15 +580,42 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { timerJob = launch { repeat(16) { Log.d("GetNodeTimeOutNum==>$GetNodeTimeOutNum") + if (GetNodeTimeOutNum == 0) { hideLoading() Log.d("stopTimer...") - RxToast.error("获取节点失败...请尝试切换其他地址") - showDomainList() - timerJob?.cancel() + RxToast.error("获取节点失败...正在切换其他地址") +// showDomainList() +// var mmkv = MMKV.defaultMMKV() +// var currentHost = mmkv.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, "") + if (setNewData()) { + timerJob?.cancel() +// cleanProfile() + MMKV.defaultMMKV() + .removeValueForKey(BZYConstants.NODE_All_ITEM_NAME_KEY) +// createProfile() + saveSubUrl() + + MainApplication.restartApp(this@ChangeNodeActivity, object : + MainApplication.OnRestartButtonListener { + + override fun enterButton() { + + } + + override fun cancelButton() { + doProfile(false) + } + + }) +// doProfile(false) +// isCreate=true + } else { + timerJob?.cancel() + RxToast.error("获取全部线路失败...请切换网络重试") + } // delay(1000) // this@ChangeNodeActivity.finish() - } GetNodeTimeOutNum-- delay(1000) @@ -545,7 +638,7 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { DialogDoMainChoose.OnTryButtonListener { override fun tryButton() { saveSubUrl() - doProfile() + doProfile(false) dialogDoMainChoose?.dismiss() } @@ -567,7 +660,7 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { } override fun cancelButton() { - doProfile() + doProfile(false) dialogDoMainChoose?.dismiss() } @@ -585,10 +678,90 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { } } + private fun setNewData(): Boolean { + var mmkv = MMKV.defaultMMKV() + val originalUrl = + mmkv.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, BuildConfig.service_url) + var newUrlString = originalUrl + var isChange = false + val routerHost = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST, HashSet()) + var switchFinshSet = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_Switch_Finsh_Set, HashSet()) + routerHost?.let { +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { +// if (!isNetworkAvailable(this@BaseActivity)){ +// return isChange +// } +// } + if (it.isEmpty()) { + android.util.Log.d(Conf.TAG, "routerHost isEmpty") + return isChange + } + com.cncat.vpn.common.log.Log.d("switchFinshSet.size==>${switchFinshSet?.size!!} , routerHost.size==>${routerHost.size}") + //次数已满 + if (switchFinshSet?.size!! >= routerHost.size) { + return isChange + } + android.util.Log.d(Conf.TAG, "routerHost not empty") + for (url in it) { +// com.cncat.vpn.common.log.Log.d("url==>$url") + + if (url == originalUrl) { + switchFinshSet?.add(url) + mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinshSet) + continue + } + + if (switchFinshSet?.contains(url) == true) { + continue + } else { + isChange = true + android.util.Log.e("Retry", "切换到新url:$url") + newUrlString = url + switchFinshSet?.add(newUrlString) + mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinshSet) +// mmkv.encode(BZYConstants.MMKV_KEY_OLD_CURRENT_HOST, newUrlString) + break + } + } + +// val iterator = it.iterator() +// while (iterator.hasNext()) { +// val newUrl = iterator.next() +// android.util.Log.e( +// "Data", +// "遍历备用的url:$newUrl, contains==>${switchFinshSet?.contains(newUrl)}" +// ) +// if (newUrl == originalUrl) { +// switchFinshSet?.add(newUrl) +// iterator.remove() +// continue +// } +// if (switchFinshSet?.contains(newUrl) == true) { +// iterator.remove() +// } else { +// android.util.Log.e("Retry", "切换到新url:$newUrl") +// newUrlString = newUrl +// iterator.remove() +// if (originalUrl != null) { +// switchFinshSet?.add(originalUrl) +// mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinshSet) +// mmkv.encode(BZYConstants.MMKV_KEY_OLD_CURRENT_HOST, originalUrl) +// } +// break +// } +// } +// mmkv.encode(BZYConstants.MMKV_KEY_ROUTER_HOST, routerHost) + + mmkv.encode(BZYConstants.MMKV_KEY_CURRENT_HOST, newUrlString) + + } + return isChange + } + private fun saveSubUrl() { var currentHost = MMKV.defaultMMKV() .decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, "") -// com.cncat.vpn.common.log.Log.d("tryButton currentHost==>${currentHost}") + com.cncat.vpn.common.log.Log.d("tryButton currentHost==>${currentHost}") var oldUrl = nowSubUrl currentHost?.let { changeSubUrl(oldUrl, it) } } diff --git a/app/src/main/java/com/yingmao/clash/act/MemberRechargeActivity.kt b/app/src/main/java/com/yingmao/clash/act/MemberRechargeActivity.kt index d39d215..082fc86 100644 --- a/app/src/main/java/com/yingmao/clash/act/MemberRechargeActivity.kt +++ b/app/src/main/java/com/yingmao/clash/act/MemberRechargeActivity.kt @@ -362,7 +362,19 @@ class MemberRechargeActivity : BaseActivity() { override fun httpFailure(httpStatus: HttpStatus.Failure) { when (httpStatus.reqType) { HttpReqType.GET_RECHARGE_INFO -> { - showDomainList() +// showDomainList() + if (super.switchServer2()) { + val username = + MMKV.defaultMMKV() + .decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME, "")!! + val phToken = + MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_PH_TOKEN, "")!! + val userId = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_USER_ID)!! + viewModel.getPhRechargeInfo(username, phToken, userId) + } else { +// super.switchFinshSet?.clear() + } + Logger.d("获取充值续费信息异常${httpStatus.msg}") swipeLayout.isRefreshing = false RxToast.error(resources.getString(R.string.DataError)) diff --git a/app/src/main/java/com/yingmao/clash/act/NewMainActivity.kt b/app/src/main/java/com/yingmao/clash/act/NewMainActivity.kt index 5d28f2b..1e4700d 100644 --- a/app/src/main/java/com/yingmao/clash/act/NewMainActivity.kt +++ b/app/src/main/java/com/yingmao/clash/act/NewMainActivity.kt @@ -128,8 +128,8 @@ class NewMainActivity : BaseActivity() { // private var profile: ProfileManager? = null // private var clashManager: ClashManager? = null - var clashBinder: IClashManager? = null - var profileBinder: IProfileManager? = null + private var clashBinder: IClashManager? = null + private var profileBinder: IProfileManager? = null var newMainActGlo: Boolean = false var isUpload: Boolean = false var hostsMem: ArrayList = ArrayList() @@ -1187,6 +1187,7 @@ class NewMainActivity : BaseActivity() { suspend fun createMyProfile(pm: IProfileManager, url: String) { + Log.d("createMyProfile") var uuid: UUID = pm.create( Profile.Type.Url, Conf.getClashConfName(this@NewMainActivity.applicationContext) ) diff --git a/app/src/main/java/com/yingmao/clash/act/SettingActivity.kt b/app/src/main/java/com/yingmao/clash/act/SettingActivity.kt index 158806d..c2d14b2 100644 --- a/app/src/main/java/com/yingmao/clash/act/SettingActivity.kt +++ b/app/src/main/java/com/yingmao/clash/act/SettingActivity.kt @@ -110,7 +110,7 @@ class SettingActivity : BaseActivity() { showLoading(resources.getString(R.string.UnderRepair), this@SettingActivity) launch(Dispatchers.IO) { - NewMainActivity.profileBinder?.let { pm -> + UIMainActivity.profileBinder?.let { pm -> pm.queryAll().forEach { profile -> Log.d("setting profile delete ==>${profile.name}") pm.delete(profile.uuid) diff --git a/app/src/main/java/com/yingmao/clash/act/SlpashHelper.kt b/app/src/main/java/com/yingmao/clash/act/SlpashHelper.kt index ce09ec0..dbaf4cf 100644 --- a/app/src/main/java/com/yingmao/clash/act/SlpashHelper.kt +++ b/app/src/main/java/com/yingmao/clash/act/SlpashHelper.kt @@ -21,9 +21,9 @@ class SplashHelper(private val splashAtyVM: PublicViewMode) { third: (AsyncCallback) -> Unit, callback: (Boolean) -> Unit ) { - first(createCallback("getHost method success", "getHostByGithub method failed", callback) { + first(createCallback("getHost method success", "getHost method failed", callback) { second(createCallback("getHostByAWS method success", "getHostByAWS method failed", callback) { - third(createCallback("getHost method success", "getHost methods failed", callback) { + third(createCallback("getHostByGithub method success", "getHostByGithub methods failed", callback) { callback(false) // 所有方法都失败 }) }) diff --git a/app/src/main/java/com/yingmao/clash/act/SplashActivity.kt b/app/src/main/java/com/yingmao/clash/act/SplashActivity.kt index 1e6ed9f..cd3db08 100644 --- a/app/src/main/java/com/yingmao/clash/act/SplashActivity.kt +++ b/app/src/main/java/com/yingmao/clash/act/SplashActivity.kt @@ -239,6 +239,11 @@ class SplashActivity : BaseActivity() { com.cncat.vpn.common.log.Log.d("si==>${si}, ss1==>${ss1}, ss2==>${ss2}") MainApplication.KEY2 = ss1 MainApplication.IV2 = ss2 + + +// val byteArrayToHexStr = +// AESUtil.byteArrayToHexStr(AESUtil.encrypt("https://api.kuaifei.net+https://api.wfvpnpro.com+https://wf.jimao.xyz+https://api.msljsqpro.com+https://api.mashanglianjsq.com")) +// android.util.Log.i("AAAAAAAAAAAAAAAA","data::"+byteArrayToHexStr+"::") // 太子 // com.cncat.vpn.common.log.Log.d("tz encrypt:"+ AESUtil.byteArrayToHexStr(AESUtil.encrypt(""))) // 八爪鱼 com.cncat.vpn.common.log.Log.d("bzy encrypt:"+ AESUtil.byteArrayToHexStr(AESUtil.encrypt(""))) @@ -817,6 +822,7 @@ class SplashActivity : BaseActivity() { val expired = checkLoginRsp.data?.expired val isPerfect = checkLoginRsp.data?.isPerfect val userCommand = checkLoginRsp.data?.userCommand + val logSwitch = checkLoginRsp.data?.logSwitch val mmkv = MMKV.defaultMMKV() mmkv.encode(BZYConstants.MMKV_KEY_VPN_EXPIRED, expired ?: true) mmkv.encode( @@ -825,11 +831,8 @@ class SplashActivity : BaseActivity() { ) mmkv.encode(BZYConstants.MMKV_KEY_IS_PERFECT, isPerfect ?: true) mmkv.encode(BZYConstants.MMKV_KEY_VPN_UserCommand, userCommand ?: "") - - + mmkv.encode(BZYConstants.MMKV_KEY_VPN_LogSwitch, logSwitch ?: "") toMainPage() - - } else { toLoginPage() } @@ -903,56 +906,56 @@ class SplashActivity : BaseActivity() { rlPb.visibility = View.GONE pb_web?.visibility = View.INVISIBLE com.cncat.vpn.common.log.Log.d("httpFailure HttpReqType.REGISTER") - try { - RxToast.error("检测到网络异常,请尝试切换其他地址.") - 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?.setOnListItemListener(object : - DialogDoMainChoose.OnListItemListener { - override fun listItemClick() { - doRegisterByEncryption() - dialogDoMainChoose?.dismiss() - } - - }) - dialogDoMainChoose?.show() - } - } 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() -// } +// try { +// RxToast.error("检测到网络异常,请尝试切换其他地址.") +// 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?.setOnListItemListener(object : +// DialogDoMainChoose.OnListItemListener { +// override fun listItemClick() { +// doRegisterByEncryption() +// dialogDoMainChoose?.dismiss() +// } +// +// }) +// dialogDoMainChoose?.show() +// } +// } catch (e: Exception) { +// e.printStackTrace() // } + if (super.switchServer2()) {//切换服务器并直接重试 +// 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 -> { diff --git a/app/src/main/java/com/yingmao/clash/act/UIMainActivity.kt b/app/src/main/java/com/yingmao/clash/act/UIMainActivity.kt index 43aa0d4..a5f0426 100644 --- a/app/src/main/java/com/yingmao/clash/act/UIMainActivity.kt +++ b/app/src/main/java/com/yingmao/clash/act/UIMainActivity.kt @@ -92,8 +92,9 @@ class UIMainActivity : BaseActivity() { private var timer: Timer? = null private var uTimerTask: TimerTask? = null private var newMainActGlo: Boolean = false - private var homeFragment:HomeFragment?=null - private var settingFragment:SettingFragment?=null + private var homeFragment: HomeFragment? = null + private var settingFragment: SettingFragment? = null + @SuppressLint("SimpleDateFormat") private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss") private var activityDialog: ActivityViewDialog? = null @@ -113,6 +114,69 @@ class UIMainActivity : BaseActivity() { var hostsMem: ArrayList = ArrayList() var isSubed = false var newMainActGlo: Boolean = false + public suspend fun setSub2(url: String) { + profileBinder?.let { pm -> + pm.queryAll().forEach { itemPro -> + Log.d("uimain setSub2 itemPro.name==${itemPro.name}") + if (itemPro.name != Conf.getClashConfName(MainApplication.getApp()?.applicationContext)) { + Log.d("setSub2 delete ==>${itemPro.name}") + pm.delete(itemPro.uuid) + } + } + var mProfile = pm.queryAll().find { + it.name == Conf.getClashConfName(MainApplication.getApp()?.applicationContext) + } + + mProfile?.let { + var actname = it.name + Log.d("new main actname==>" + actname) + Log.d("setSub2 pro 已存在 ==>") + pm.setActive(it) + delay(500) + //判断配置文件source + if (!TextUtils.isEmpty(mProfile.source)) { + Log.d("setSub2 pro.source==>${mProfile.source}, url==>${url}") + //订阅链接不同就更换 + if (mProfile.source != url) { + pm.patch( + mProfile.uuid, mProfile.name, + url, 1800000L + ) + pm.commit(mProfile.uuid) { status -> + android.util.Log.d( + Conf.TAG, + "new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress + ) + } + } + } + pm.update(it.uuid) + newUuid = mProfile.uuid.toString() + isSubbed = true + } ?: run { + Log.d("setSub2 go create") + val uuid: UUID = pm.create( + Profile.Type.Url, Conf.getClashConfName(MainApplication.getApp()?.applicationContext) + ) + delay(500) + pm.queryByUUID(uuid)?.let { qPro -> + pm.setActive(qPro) + pm.patch( + qPro.uuid, qPro.name, + url, 1800000L + ) + pm.commit(qPro.uuid) { status -> + android.util.Log.d( + Conf.TAG, + "new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress + ) + } + newUuid = qPro.uuid.toString() + isSubbed = true + } + } + } + } } override fun onCreate(savedInstanceState: Bundle?) { @@ -148,6 +212,7 @@ class UIMainActivity : BaseActivity() { if (homeFragment == null) homeFragment = HomeFragment() showFragment(homeFragment!!) } + R.id.navigation_setting -> { if (settingFragment == null) settingFragment = SettingFragment() showFragment(settingFragment!!) @@ -163,6 +228,7 @@ class UIMainActivity : BaseActivity() { transaction.replace(R.id.fragmentContainer, fragment) transaction.commit() } + private fun showFragment(fragment: Fragment) { val fragmentManager = supportFragmentManager val transaction = fragmentManager.beginTransaction() @@ -179,6 +245,7 @@ class UIMainActivity : BaseActivity() { } transaction.commit() } + override fun httpLoading(httpStatus: HttpStatus.Loading) { if (httpStatus.reqType == HttpReqType.HEARTBEAT) { Logger.d("心跳中") @@ -196,25 +263,26 @@ class UIMainActivity : BaseActivity() { } data.data.let { url -> android.util.Log.e("Data", "机场URL:=${url}") + var url2="https://api.ymvpnpro11.cc:8700/7air2vr7ikiqzgvxz/api/v1/client/subscribe?token=22f3d75079ec6fa546c1862c4354e448" // if (url.isNotEmpty()) { // subUrl = url // lifecycleScope.launch(Dispatchers.IO) { // setSub2(url) // } // } - if (url.isNotEmpty()) { + if (url2.isNotEmpty()) { //todo 判断订阅地址是否修改过,未修改就用接口返回的地址反之使用本地修改的地址 var pro_sub_url = MMKV.defaultMMKV().decodeString(BZYConstants.PROFILE_SUB_URL, "") // Log.d("pro_sub_url==>${pro_sub_url}") - if (!TextUtils.isEmpty(pro_sub_url)){ - if (pro_sub_url == url) { - subUrl = url + if (!TextUtils.isEmpty(pro_sub_url)) { + if (pro_sub_url == url2) { + subUrl = url2 } else { subUrl = pro_sub_url } - }else{ - subUrl = url + } else { + subUrl = url2 } lifecycleScope.launch(Dispatchers.IO) { // setSub(url) @@ -230,7 +298,7 @@ class UIMainActivity : BaseActivity() { if (data.code == 200) { if (data.data.data.list.isNotEmpty()) { data.data.data.list[0].redirectLink.let { - if(activityDialog==null){ + if (activityDialog == null) { activityDialog = ActivityViewDialog(this, data.data.data.list[0].redirectLink) activityDialog?.setOnDialogClickListener(object : @@ -263,8 +331,10 @@ class UIMainActivity : BaseActivity() { val expired = checkLoginRsp.data.expired mmkv.encode(BZYConstants.MMKV_KEY_VPN_EXPIRED, expired ?: true) mmkv.encode(BZYConstants.MMKV_KEY_VPN_VALID_PERIOD, nowExpireTime) - val hf = supportFragmentManager.findFragmentById(R.id.fragmentContainer) as? HomeFragment - val sf = supportFragmentManager.findFragmentById(R.id.fragmentContainer) as? SettingFragment + val hf = + supportFragmentManager.findFragmentById(R.id.fragmentContainer) as? HomeFragment + val sf = + supportFragmentManager.findFragmentById(R.id.fragmentContainer) as? SettingFragment hf?.setExpireDate() sf?.setExpireDate() checkPayResultDia?.dismiss() @@ -343,6 +413,7 @@ class UIMainActivity : BaseActivity() { } } } + private fun showLoadingDialog(msg: String) { payResultLoading = RxDialogShapeLoading(this) payResultLoading!!.setMessage(msg) @@ -356,7 +427,11 @@ class UIMainActivity : BaseActivity() { 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) + MMKV.defaultMMKV().removeValueForKey(BZYConstants.PROFILE_SUB_URL) + MMKV.defaultMMKV().removeValueForKey(BZYConstants.MMKV_KEY_Switch_Finsh_Set) Log.d("cleanUserInfo clashRunning==>${clashRunning}") + //清除源切换记录 + if (clashRunning) { fragments.filterIsInstance().forEach { it.stopClash() } } @@ -401,61 +476,7 @@ class UIMainActivity : BaseActivity() { } } - private suspend fun setSub2(url: String) { - profileBinder?.let { pm -> - pm.queryAll().forEach { itemPro -> - if (itemPro.name != Conf.getClashConfName(this@UIMainActivity.applicationContext)) { - pm.delete(itemPro.uuid) - } - } - val pro = pm.queryActive() - pro?.let { - pm.setActive(it) - delay(500) - //判断配置文件source - if (!TextUtils.isEmpty(pro.source)) { - Log.d("setSub2 pro.source==>${pro.source}, url==>${url}") - //订阅链接不同就更换 - if (pro.source != url) { - pm.patch( - pro.uuid, pro.name, - url, 1800000L - ) - pm.commit(pro.uuid) { status -> - android.util.Log.d( - Conf.TAG, - "new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress - ) - } - } - } - pm.update(it.uuid) - newUuid = pro.uuid.toString() - isSubbed = true - } ?: run { - val uuid: UUID = pm.create( - Profile.Type.Url, Conf.getClashConfName(this@UIMainActivity.applicationContext) - ) - delay(500) - pm.queryByUUID(uuid)?.let { qPro -> - pm.setActive(qPro) - pm.patch( - qPro.uuid, qPro.name, - url, 1800000L - ) - pm.commit(qPro.uuid) { status -> - android.util.Log.d( - Conf.TAG, - "new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress - ) - } - newUuid = qPro.uuid.toString() - isSubbed = true - } - } - } - } private fun startLog() { @@ -559,7 +580,7 @@ class UIMainActivity : BaseActivity() { override fun onDestroy() { if (activityDialog != null) { - if(activityDialog!!.isShowing){ + if (activityDialog!!.isShowing) { activityDialog!!.dismiss() } diff --git a/app/src/main/java/com/yingmao/clash/app/MainApplication.kt b/app/src/main/java/com/yingmao/clash/app/MainApplication.kt index e96d73c..5e33936 100644 --- a/app/src/main/java/com/yingmao/clash/app/MainApplication.kt +++ b/app/src/main/java/com/yingmao/clash/app/MainApplication.kt @@ -1,6 +1,5 @@ package com.yingmao.clash.app -import android.annotation.SuppressLint import android.app.Activity import android.app.Application import android.app.NotificationChannel @@ -10,7 +9,6 @@ import android.content.Intent import android.content.res.Configuration import android.os.Build import androidx.annotation.RequiresApi -import androidx.core.content.ContextCompat.getString import androidx.core.content.getSystemService import com.cncat.vpn.common.Global import com.cncat.vpn.common.compat.currentProcessName @@ -18,7 +16,6 @@ import com.cncat.vpn.common.log.Log import com.github.gzuliyujiang.oaid.DeviceID import com.github.gzuliyujiang.oaid.DeviceIdentifier import com.github.gzuliyujiang.oaid.IGetter - import com.jakewharton.processphoenix.ProcessPhoenix import com.orhanobut.logger.Logger import com.stripe.android.PaymentConfiguration @@ -29,14 +26,16 @@ import com.yingmao.clash.conf.BZYConstants import com.yingmao.clash.entity.UserData import com.yingmao.clash.util.CrashCatchHandler import com.yingmao.clash.util.clashDir -import com.yingmao.clash.view.RxToast -import com.yingmao.clash.view.dialog.DialogDoMainChoose import com.yingmao.clash.view.dialog.DialogSureRestartChoose import kotlinx.coroutines.MainScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import java.io.File import java.io.FileOutputStream +import java.io.PrintWriter +import java.io.StringWriter +import java.text.SimpleDateFormat +import java.util.Date import java.util.Locale @@ -154,10 +153,27 @@ class MainApplication : Application() { // if (privacyPolicyAgreed) { // } - +// Thread.setDefaultUncaughtExceptionHandler { thread, throwable -> +// logException(throwable) +// // 可选择上报到服务器或写入本地文件 +// } } + fun logException(e: Throwable) { + val log = StringWriter().also { e.printStackTrace(PrintWriter(it)) }.toString() + Log.d("MainApplication logException==>${log}") +// val directory: File? = applicationContext.getExternalFilesDir("CrashLog") +// if (directory != null) { +// if (!directory.isDirectory) { +// directory.delete() +// } +// if (!directory.exists()) { +// directory.mkdirs() +// } +// } +// File(directory, "crash_${System.currentTimeMillis()}.log").writeText(log) + } fun updateActivity(language: String, locale: Locale) { MMKV.defaultMMKV().encode(BZYConstants.languageInfo, language) val resources = this.resources diff --git a/app/src/main/java/com/yingmao/clash/base/BaseActivity.kt b/app/src/main/java/com/yingmao/clash/base/BaseActivity.kt index 165dacc..8172340 100644 --- a/app/src/main/java/com/yingmao/clash/base/BaseActivity.kt +++ b/app/src/main/java/com/yingmao/clash/base/BaseActivity.kt @@ -6,6 +6,9 @@ import android.content.Context import android.content.Intent import android.content.pm.ActivityInfo import android.content.res.Configuration +import android.net.ConnectivityManager +import android.net.NetworkCapabilities +import android.os.Build import android.os.Bundle import android.text.TextUtils import android.util.Log @@ -13,7 +16,9 @@ import android.view.View import android.view.ViewGroup import android.view.inputmethod.InputMethodManager import android.widget.* +import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity +import androidx.collection.arraySetOf import androidx.lifecycle.ViewModelProvider import com.orhanobut.logger.Logger import com.tencent.mmkv.MMKV @@ -55,6 +60,10 @@ open class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), Br var baseLoading: RxDialogShapeLoading? = null val serStore by lazy { ServiceStore(this) } + companion object { +// var switchFinshSet: MutableSet? = null + } + sealed class RequestTunnel { object ReloadAll : RequestTunnel() object ReLaunch : RequestTunnel() @@ -261,10 +270,11 @@ open class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), Br } } - fun selectServer(){ + fun selectServer() { val mmkv = MMKV.defaultMMKV() val routerHost = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST, HashSet()) } + @Synchronized fun switchServer(): Boolean { var isChange = false @@ -303,4 +313,95 @@ open class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), Br return isChange } + + + @RequiresApi(Build.VERSION_CODES.M) + fun isNetworkAvailable(context: Context): Boolean { + val connectivityManager = + context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + + val network = connectivityManager.activeNetwork ?: return false + val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false + + return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + } + + @Synchronized + fun switchServer2(): Boolean { + var isChange = false + val mmkv = MMKV.defaultMMKV() + val originalUrl = + mmkv.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, BuildConfig.service_url) + var newUrlString = originalUrl + val routerHost = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST, HashSet()) + var switchFinshSet = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_Switch_Finsh_Set, HashSet()) + routerHost?.let { +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { +// if (!isNetworkAvailable(this@BaseActivity)){ +// return isChange +// } +// } + if (it.isEmpty()) { + Log.d(Conf.TAG, "routerHost isEmpty") + return isChange + } + com.cncat.vpn.common.log.Log.d("switchFinshSet.size==>${switchFinshSet?.size!!} , routerHost.size==>${routerHost.size}") + //次数已满 + if (switchFinshSet?.size!! >= routerHost.size) { + return isChange + } + + Log.d(Conf.TAG, "routerHost not empty") +// val iterator = it.iterator() +// while (iterator.hasNext()) { +// val newUrl = iterator.next() +// Log.e( +// "Data", +// "遍历备用的url:$newUrl, contains==>${switchFinshSet?.contains(newUrl)}" +// ) +// if (newUrl == originalUrl) { +// switchFinshSet?.add(newUrl) +// iterator.remove() +// continue +// } +// if (switchFinshSet?.contains(newUrl) == true) { +// iterator.remove() +// } else { +// Log.e("Retry", "切换到新url:$newUrl") +// isChange = true +// newUrlString = newUrl +// iterator.remove() +// if (originalUrl != null) { +// switchFinshSet?.add(originalUrl) +// mmkv.encode(BZYConstants.MMKV_KEY_OLD_CURRENT_HOST, originalUrl) +// } +// break +// } +// } + for (url in it) { + + if (url == originalUrl) { + switchFinshSet?.add(url) + mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinshSet) + continue + } + + if (switchFinshSet?.contains(url) == true) { + continue + } else { + isChange = true + android.util.Log.e("Retry", "切换到新url:$url") + newUrlString = url + switchFinshSet?.add(newUrlString) + mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinshSet) +// mmkv.encode(BZYConstants.MMKV_KEY_OLD_CURRENT_HOST, newUrlString) + break + } + } +// mmkv.encode(BZYConstants.MMKV_KEY_ROUTER_HOST, routerHost) + mmkv.encode(BZYConstants.MMKV_KEY_CURRENT_HOST, newUrlString) + } + + return isChange + } } \ No newline at end of file diff --git a/app/src/main/java/com/yingmao/clash/base/BaseViewMode.kt b/app/src/main/java/com/yingmao/clash/base/BaseViewMode.kt index bce23a5..ebc0b34 100644 --- a/app/src/main/java/com/yingmao/clash/base/BaseViewMode.kt +++ b/app/src/main/java/com/yingmao/clash/base/BaseViewMode.kt @@ -1,20 +1,37 @@ package com.yingmao.clash.base +import android.os.Build import android.text.TextUtils import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.google.gson.Gson import com.cncat.vpn.common.log.Log +import com.google.gson.Gson +import com.tencent.mmkv.MMKV +import com.yingmao.clash.BuildConfig +import com.yingmao.clash.app.MainApplication +import com.yingmao.clash.conf.BZYConstants +import com.yingmao.clash.net.http.HttpApi import com.yingmao.clash.net.http.HttpReqType import com.yingmao.clash.net.http.HttpStatus import com.yingmao.clash.net.http.HttpStatusDownLoad +import com.yingmao.clash.net.http.NetService import com.yingmao.clash.net.http.entity.BaseRsp import com.yingmao.clash.util.AESUtil import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.async import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.RequestBody +import okhttp3.RequestBody.Companion.toRequestBody +import org.json.JSONArray +import org.json.JSONObject +import java.io.File +import java.io.PrintWriter +import java.io.StringWriter +import java.text.SimpleDateFormat +import java.util.Locale open class BaseViewMode : ViewModel() { @@ -24,9 +41,13 @@ open class BaseViewMode : ViewModel() { fun doAsync(reqType: HttpReqType, doInAsync: suspend () -> Any) { viewModelScope.launch( - CoroutineExceptionHandler { _, - exception -> - Log.e("BaseViewMode_doAsync:${exception.toString()}", exception) + CoroutineExceptionHandler { + _, + exception, + -> + Log.e("BaseViewMode_doAsync:${exception.localizedMessage}", exception) + + logException(exception) statusData.value = if (exception.message.isNullOrBlank()) HttpStatus.Failure( reqType, @@ -46,16 +67,86 @@ open class BaseViewMode : ViewModel() { Log.i("请求结果:$rsp") statusData.value = HttpStatus.Success(reqType, rsp) } catch (e: Exception) { - Log.e( "网络请求异常",e) + Log.e("网络请求异常", e) statusData.value = HttpStatus.Failure(reqType, e.toString()) } } } - fun doAsync2(reqType: HttpReqType, doInAsync: suspend () -> Any) { + fun logException(e: Throwable) { + var logSwitch = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_VPN_LogSwitch, "") + if ("on" == logSwitch) { + val log = StringWriter().also { e.printStackTrace(PrintWriter(it)) }.toString() + Log.d("logException==>${log}") + val username = + MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME, "")!! + var json = JSONObject() + val androidVersion = Build.VERSION.RELEASE // 系统版本号,例如 "13" + val sdkInt = Build.VERSION.SDK_INT // SDK 级别,例如 33 + val manufacturer = Build.MANUFACTURER // 厂商,例如 "Xiaomi" + val model = Build.MODEL // 机型,例如 "MI 11" + val brand = Build.BRAND // 品牌,例如 "Xiaomi" + val device = Build.DEVICE // 设备代号,例如 "venus" + val hardware = Build.HARDWARE // 硬件名称,例如 "qcom" + +// val nowTime = SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒E", Locale.getDefault()) + var ja_streams = JSONArray() + var jo_streams_item = JSONObject() + var jo_stream = JSONObject() + var ja_values = JSONArray() + jo_stream.put("phoneNumber", username) + jo_stream.put("appVersion", BuildConfig.VERSION_NAME) + jo_stream.put("androidVersion", androidVersion) + jo_stream.put("sdkInt", sdkInt) + jo_stream.put("manufacturer", manufacturer) + jo_stream.put("model", model) + jo_stream.put("brand", brand) + jo_stream.put("device", device) + jo_stream.put("hardware", hardware) + + ja_values.put(0, System.currentTimeMillis().toString() + "000000") + //错误信息 + ja_values.put(1, log) + jo_streams_item.put("stream", jo_stream) + var ja_values_item = JSONArray() + ja_values_item.put(0, ja_values) + jo_streams_item.put("values", ja_values_item) + ja_streams.put(0, jo_streams_item) + json.put("streams", ja_streams) + + Log.d("json==>${json}") + val httpApi = NetService.instances.createHttps(HttpApi::class.java) + val requestBody: RequestBody = json.toString().toRequestBody("application/json; charset=utf-8".toMediaType()) + doAsync2(HttpReqType.APPSHAREINFO) { + httpApi.postErrLog(requestBody) + } +// val directory: File? = MainApplication.getApp()?.applicationContext?.getExternalFilesDir("CrashLog") +// if (directory != null) { +// if (!directory.isDirectory) { +// directory.delete() +// } +// if (!directory.exists()) { +// directory.mkdirs() +// } +// } +// File(directory, "crash_${System.currentTimeMillis()}.log").writeText(json.toString()) + } + } + fun postErrLog(phone: String) { + + val phToken = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_PH_TOKEN,"")!! + val params = mutableMapOf( + "phoneNumber" to phone, + "phToken" to phToken + ) + + } + fun doAsync2(reqType: HttpReqType, doInAsync: suspend () -> Any?) { viewModelScope.launch( - CoroutineExceptionHandler { _, - exception -> + CoroutineExceptionHandler { + _, + exception, + -> Log.e("BaseViewMode_doAsync:${exception.toString()}", exception) statusData.value = if (exception.message.isNullOrBlank()) HttpStatus.Failure( @@ -76,7 +167,7 @@ open class BaseViewMode : ViewModel() { Log.i("请求结果:$rsp") statusData.value = HttpStatus.Success(reqType, rsp) } catch (e: Exception) { - Log.e( "网络请求异常",e) + Log.e("网络请求异常", e) statusData.value = HttpStatus.Failure(reqType, e.toString()) } } @@ -114,11 +205,13 @@ open class BaseViewMode : ViewModel() { fun doAsyncDelay( reqType: HttpReqType, delayTimeMillis: Long, - doInAsync: suspend () -> BaseRsp + doInAsync: suspend () -> BaseRsp, ) { viewModelScope.launch( - CoroutineExceptionHandler { _, - exception -> + CoroutineExceptionHandler { + _, + exception, + -> Log.e("BaseViewMode_doAsyncDelay:${exception.toString()}", exception) statusData.value = if (exception.message.isNullOrBlank()) HttpStatus.Failure( @@ -141,7 +234,7 @@ open class BaseViewMode : ViewModel() { Log.i("请求结果:$rsp") statusData.value = HttpStatus.Success(reqType, rsp) } catch (e: Exception) { - Log.e( "网络请求异常",e) + Log.e("网络请求异常", e) // statusData.value = HttpStatus.Failure(reqType,e.toString()) } } @@ -149,8 +242,10 @@ open class BaseViewMode : ViewModel() { fun doAsyncStrResult(reqType: HttpReqType, doInAsync: suspend () -> String) { viewModelScope.launch( - CoroutineExceptionHandler { _, - exception -> + CoroutineExceptionHandler { + _, + exception, + -> Log.e("BaseViewMode_doAsyncStrResult:${exception.toString()}", exception) @@ -162,7 +257,7 @@ open class BaseViewMode : ViewModel() { val rsp = result.await() Log.i("请求结果:$rsp") } catch (e: Exception) { - Log.e( "网络请求异常",e) + Log.e("网络请求异常", e) } } } @@ -170,11 +265,13 @@ open class BaseViewMode : ViewModel() { fun doAsyncEncodeStr( reqType: HttpReqType, classOfT: Class, - doInAsync: suspend () -> String + doInAsync: suspend () -> String, ) { viewModelScope.launch( - CoroutineExceptionHandler() { _, - exception -> + CoroutineExceptionHandler() { + _, + exception, + -> Log.e("BaseViewMode_doAsyncEncodeStr:${exception.toString()}", exception) statusData.value = if (exception.message.isNullOrBlank()) HttpStatus.Failure( @@ -191,8 +288,6 @@ open class BaseViewMode : ViewModel() { val result = async { doInAsync() } val rspStr = result.await() Log.i("doAsyncEncodeStr 加密请求结果:$rspStr") - - if (!TextUtils.isEmpty(rspStr)) { var decodeRspStr = AESUtil.decrypt(rspStr) Log.d("doAsyncEncodeStr 请求结果:$decodeRspStr") @@ -204,20 +299,22 @@ open class BaseViewMode : ViewModel() { statusData.value = HttpStatus.Success(reqType, rsp) } } catch (e: Exception) { - Log.e("网络请求异常",e) + Log.e("网络请求异常", e) throw e - statusData.value = HttpStatus.Failure(reqType,e.toString()) + statusData.value = HttpStatus.Failure(reqType, e.toString()) } } } suspend fun doAsyncEncodeStrBg( classOfT: Class, - doInAsync: suspend () -> String + doInAsync: suspend () -> String, ): BaseRsp? { return viewModelScope.async( - CoroutineExceptionHandler() { _, - exception -> + CoroutineExceptionHandler() { + _, + exception, + -> Log.e("BaseViewMode_doAsyncEncodeStrBg:${exception.toString()}", exception) }) { @@ -230,7 +327,7 @@ open class BaseViewMode : ViewModel() { val rsp = Gson().fromJson(decodeRspStr, classOfT) return@async rsp } catch (e: Exception) { - Log.e("网络请求异常",e) + Log.e("网络请求异常", e) } return@async null }.await() @@ -245,7 +342,7 @@ open class BaseViewMode : ViewModel() { } result.await() } catch (e: Exception) { - Log.e("网络请求异常",e) + Log.e("网络请求异常", e) } } } diff --git a/app/src/main/java/com/yingmao/clash/base/PublicViewMode.kt b/app/src/main/java/com/yingmao/clash/base/PublicViewMode.kt index d53597f..ae90964 100644 --- a/app/src/main/java/com/yingmao/clash/base/PublicViewMode.kt +++ b/app/src/main/java/com/yingmao/clash/base/PublicViewMode.kt @@ -33,11 +33,11 @@ open class PublicViewMode : BaseViewMode() { try { //TODO bug 会引起崩溃 val host = when { BuildConfig.is_ym -> { - rt.getHostGithub() + rt.getHost() } BuildConfig.is_tz -> { - rt.getTzHostGithub() + rt.getTzHostTZ() } BuildConfig.is_yunti -> { @@ -45,7 +45,7 @@ open class PublicViewMode : BaseViewMode() { } else -> { - rt.getBzyHostGithub() + rt.getBzyHostDef() } } // Log.e("data", "2:$host") diff --git a/app/src/main/java/com/yingmao/clash/conf/BZYConstants.kt b/app/src/main/java/com/yingmao/clash/conf/BZYConstants.kt index 7528c87..97f531e 100644 --- a/app/src/main/java/com/yingmao/clash/conf/BZYConstants.kt +++ b/app/src/main/java/com/yingmao/clash/conf/BZYConstants.kt @@ -28,6 +28,7 @@ class BZYConstants { const val MMKV_KEY_OLD_CURRENT_HOST = "old_current_host" //备用地址 const val MMKV_KEY_ROUTER_HOST ="router_host" + const val MMKV_KEY_Switch_Finsh_Set ="MMKV_KEY_Switch_Finsh_Set" const val MMKV_KEY_FIRST_HOST ="first_host" const val MMKV_KEY_Airport_Base64 ="airport_base64" //注册地址 @@ -47,6 +48,7 @@ class BZYConstants { const val MMKV_KEY_VPN_EXPIRED = "expired" const val MMKV_KEY_VPN_UserCommand = "userCommand" + const val MMKV_KEY_VPN_LogSwitch = "logSwitch" //vpn过期时间 const val MMKV_KEY_VPN_VALID_PERIOD = "vpn_valid_period" diff --git a/app/src/main/java/com/yingmao/clash/entity/CheckLoginRsp.kt b/app/src/main/java/com/yingmao/clash/entity/CheckLoginRsp.kt index 08182f0..43578c7 100644 --- a/app/src/main/java/com/yingmao/clash/entity/CheckLoginRsp.kt +++ b/app/src/main/java/com/yingmao/clash/entity/CheckLoginRsp.kt @@ -79,6 +79,9 @@ data class UserData( @field:SerializedName("userCommand") val userCommand: String? = null, + @field:SerializedName("logSwitch") + val logSwitch: String? = null, + @field:SerializedName("intervalTime") val intervalTime: Int? = null, diff --git a/app/src/main/java/com/yingmao/clash/fragment/BaseFragment.kt b/app/src/main/java/com/yingmao/clash/fragment/BaseFragment.kt index 80c08c2..1a47163 100644 --- a/app/src/main/java/com/yingmao/clash/fragment/BaseFragment.kt +++ b/app/src/main/java/com/yingmao/clash/fragment/BaseFragment.kt @@ -1,6 +1,7 @@ package com.yingmao.clash.fragment import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -9,9 +10,14 @@ import android.widget.ImageView import android.widget.RelativeLayout import android.widget.TextView import androidx.fragment.app.Fragment +import com.tencent.mmkv.MMKV +import com.yingmao.clash.BuildConfig import com.yingmao.clash.R import com.yingmao.clash.base.BaseViewMode +import com.yingmao.clash.conf.BZYConstants +import com.yingmao.clash.conf.Conf import com.yingmao.clash.net.http.HttpStatus +import java.util.HashSet abstract class BaseFragment :Fragment() { @@ -58,4 +64,44 @@ abstract class BaseFragment :Fragment() { open fun httpSuccess(httpStatus: HttpStatus.Success){} open fun httpFailure(httpStatus: HttpStatus.Failure){} + + @Synchronized + fun switchServer(): Boolean { + var isChange = false + val mmkv = MMKV.defaultMMKV() + val originalUrl = + mmkv.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, BuildConfig.service_url) + var newUrlString = originalUrl + val routerHost = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST, HashSet()) + routerHost?.let { +// it.forEach { url -> +// com.cncat.vpn.common.log.Log.d("url==>$url") +// } + if (it.isEmpty()) { + Log.d(Conf.TAG, "routerHost isEmpty") + return isChange + } + Log.d(Conf.TAG, "routerHost not empty") + val iterator = it.iterator() + while (iterator.hasNext()) { + val newUrl = iterator.next() + Log.e("Data", "遍历备用的url:$newUrl") + if (newUrl == originalUrl) { + iterator.remove() + } else { + Log.e("Retry", "切换到新url:$newUrl") + mmkv.encode(BZYConstants.MMKV_KEY_OLD_CURRENT_HOST, originalUrl) + isChange = true + newUrlString = newUrl + iterator.remove() + break + } + } +// mmkv.encode(BZYConstants.MMKV_KEY_ROUTER_HOST, routerHost) + mmkv.encode(BZYConstants.MMKV_KEY_CURRENT_HOST, newUrlString) + } + + return isChange + } + } \ No newline at end of file diff --git a/app/src/main/java/com/yingmao/clash/fragment/NewAccFragment.kt b/app/src/main/java/com/yingmao/clash/fragment/NewAccFragment.kt index 3604d1b..23e71ab 100644 --- a/app/src/main/java/com/yingmao/clash/fragment/NewAccFragment.kt +++ b/app/src/main/java/com/yingmao/clash/fragment/NewAccFragment.kt @@ -33,6 +33,7 @@ import com.yingmao.clash.act.NewMainActivity import com.yingmao.clash.act.NewMainActivity.Companion.isSubed import com.yingmao.clash.act.NewMainActivity.Companion.newUuid import com.yingmao.clash.act.ProxyModeActivity +import com.yingmao.clash.act.UIMainActivity import com.yingmao.clash.conf.BZYConstants import com.yingmao.clash.conf.Conf import com.yingmao.clash.entity.ClashNodebBean @@ -294,7 +295,7 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch // return // } launch { - NewMainActivity.profileBinder?.let { pm -> + UIMainActivity.profileBinder?.let { pm -> val active = pm.queryActive() if (active == null) { com.cncat.vpn.common.log.Log.d("startClash: 未选择") @@ -707,7 +708,7 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch } else { if (clashRunning) { delay(1000) - NewMainActivity.clashBinder?.let { cm -> + UIMainActivity.clashBinder?.let { cm -> val names = cm.queryProxyGroupNames(false) Log.i("checkGlo names==>${names}") if (names.isNotEmpty()) { @@ -771,7 +772,7 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch var nodeName = proListItem[0].name if (!TextUtils.isEmpty(nodeName)) { launch(Dispatchers.IO) { - NewMainActivity.clashBinder?.let { cm -> + UIMainActivity.clashBinder?.let { cm -> val o = cm.queryOverride(Clash.OverrideSlot.Session) o.mode = TunnelState.Mode.Global @@ -812,7 +813,7 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch }) } } else { - NewMainActivity.clashBinder?.let { cm -> + UIMainActivity.clashBinder?.let { cm -> val o = cm.queryOverride(Clash.OverrideSlot.Session) o.mode = TunnelState.Mode.Global cm.patchOverride(Clash.OverrideSlot.Session, o) diff --git a/app/src/main/java/com/yingmao/clash/fragment/recharge/RechargeFragment.kt b/app/src/main/java/com/yingmao/clash/fragment/recharge/RechargeFragment.kt index 055e4c2..8aa0c84 100644 --- a/app/src/main/java/com/yingmao/clash/fragment/recharge/RechargeFragment.kt +++ b/app/src/main/java/com/yingmao/clash/fragment/recharge/RechargeFragment.kt @@ -628,104 +628,7 @@ class RechargeFragment : BaseFragment() { noVerticalPadding = true, horizontalPadding = false ) -// for (index in data.payType!!) { -// if (index.payModel == 10) { -// findViewById(R.id.llAggregatePayment).visibility = -// View.VISIBLE -// val JUhePay = findViewById(R.id.JUhePay) -// JUhePay.visibility = View.VISIBLE -// JUhePay.text = index.payChannel -// if (index.payType == 1) { -// val ivAlipay = findViewById(R.id.ivAlipay) -// ivAlipay.visibility = View.VISIBLE -// ivAlipay.setOnClickListener { -// val payModel = index.payModel -// val payType = index.payType -// val payParam = index.payParam -// if (payModel != null && payType != null && payParam != null) { -// viewModel.orderPayment(data, payModel, payType, payParam) -// } else { -// viewModel.orderPayment(data, 10, 1, "ip@影猫充值") -// } -// } -// } else if (index.payType == 2) { -// val ivWechatPay = findViewById(R.id.ivWechatPay) -// ivWechatPay.visibility = View.VISIBLE -// ivWechatPay.setOnClickListener { -// val payModel = index.payModel -// val payType = index.payType -// val payParam = index.payParam -// if (payModel != null && payType != null && payParam != null) { -// viewModel.orderPayment(data, payModel, payType, payParam) -// } else { -// viewModel.orderPayment(data, 10, 2, "ip@影猫充值") -// } -// -// } -// } -// } else if (index.payModel == 11) { -// findViewById(R.id.llQuickPayment).visibility = -// View.VISIBLE -// val KJPay = findViewById(R.id.KJPay) -// KJPay.visibility = View.VISIBLE -// KJPay.text = index.payChannel -// if (index.payType == 1) { -// val ivQuickPayment = -// findViewById(R.id.ivQuickPayment) -// ivQuickPayment.visibility = View.VISIBLE -// ivQuickPayment.setOnClickListener { -// val payModel = index.payModel -// val payType = index.payType -// val payParam = index.payParam -// if (payModel != null && payType != null && payParam != null) { -// viewModel.orderPayment(data, payModel, payType, payParam) -// } else { -// viewModel.orderPayment(data, 11, 1, "ip@影猫充值") -// } -// } -// } else if (index.payType == 2) { -// val ivQPWechatPay = -// findViewById(R.id.ivQPWechatPay) -// ivQPWechatPay.visibility = View.VISIBLE -// ivQPWechatPay.setOnClickListener { -// val payModel = index.payModel -// val payType = index.payType -// val payParam = index.payParam -// if (payModel != null && payType != null && payParam != null) { -// viewModel.orderPayment(data, payModel, payType, payParam) -// } else { -// viewModel.orderPayment(data, 11, 1, "ip@影喵充值") -// } -// } -// } -// } else if (index.payModel == 7) { -// findViewById(R.id.llStripe).visibility = View.VISIBLE -// findViewById(R.id.llStripePay).visibility = View.VISIBLE -// var payinfo = findViewById(R.id.tvStripePay) -// payinfo.visibility = View.VISIBLE -// -// payinfo.text = index.payChannel -// findViewById(R.id.ivStripeAlipay).visibility = -// View.VISIBLE -// findViewById(R.id.ivStripeAlipay).setOnClickListener { -// if (selectedGradeID != 0) { -// if (!PayUtils.isAlipayInstalled(requireActivity())) { -// RxToast.error(resources.getString(R.string.AlipayNotInstalled)) -// return@setOnClickListener -// } -// dismiss() -// showLoading( -// resources.getString(R.string.PaymentIn), -// requireActivity() -// ) -// Log.i("PayGradeID:", "PayGradeID:${selectedGradeID}") -// viewModel.getPayClientSecret(selectedGradeID) -// } else { -// RxToast.info(getString(R.string.NoPaymentReceipt)) -// } -// } -// } -// } + getCustomView().findViewById(R.id.ivBack) .setOnClickListener { dismiss() @@ -735,76 +638,7 @@ class RechargeFragment : BaseFragment() { } } -// private fun goWebViewStartPayClient(rsp: BaseRsp, isPayWeb: Boolean) { -// (rsp as BiLaiNormalRsp).let { -// if (it.code != "1000") { -// RxToast.error(if (it.message.isNullOrBlank()) "获取支付信息失败(${it.code})" else "${it.code}:${it.message}") -// } else { -// if (isPayWeb) { -// activity?.let { -// if (rsp.data != null) { -//// goWebPay(it, rsp.data!!) -//// goWebPay(it, newUrl) -// } else { -// RxToast.error("未能获取到支付信息,请联系客服") -// } -// } -// return -// } -// -// val gson = Gson().fromJson(it.data!!, BiLaiRsp::class.java) -// Logger.d("跳转支付宝支付页面:" + gson.payurl) -// var realPayUrl = "" -// var isNeedScan = false -// if (gson.payurl != null) { -// realPayUrl = gson.payurl!! -// isNeedScan = false -// } else if (gson.qrcode != null) { -// realPayUrl = gson.qrcode!! -// isNeedScan = true -// } else { -// realPayUrl = gson.urlscheme!! -// isNeedScan = true -// } -// // Log.e("data==", "html:" + realPayUrl); -// -// -// activity?.let { -// if (!isNeedScan) { -//// goWebPay(it, newUrl) -// } else { -// //二维码支付 -// qrPayDialog = MaterialDialog(it).show { -// this.cancelable(false) -// cornerRadius(res = R.dimen.dp_10) -// customView(R.layout.qrpay_dialog_layout, scrollable = false, noVerticalPadding = true, horizontalPadding = false) -// getCustomView().findViewById(R.id.tv_qr_pay_note).setText(R.string.qr_pay_note_wx) -// -// val ivQr = getCustomView().findViewById(R.id.iv_qr) -// -// val writer = MultiFormatWriter() -// val matrix = writer.encode(realPayUrl, BarcodeFormat.QR_CODE, 300, 300) -// val encoder = BarcodeEncoder() -// val bitmap = encoder.createBitmap(matrix) -// ivQr.setImageBitmap(bitmap) -// -// getCustomView().findViewById(R.id.tv_pay_finish).setOnClickListener { -// showLoadingDialog("正在查询支付结果...") -// viewModel.codePayStatus(outTradeNo) -// } -// -// getCustomView().findViewById(R.id.tv_pay_cancle).setOnClickListener { -// if (bitmap != null && !bitmap.isRecycled) { -// bitmap.recycle() -// dismiss() -// } -// } -// } -// } -// } -// } -// } -// }/ + fun goWebPay(it: Activity, realPayUrl: String) { val intent = Intent(context, BZYWebViewNormal::class.java) diff --git a/app/src/main/java/com/yingmao/clash/fragment/setting/SettingFragment.kt b/app/src/main/java/com/yingmao/clash/fragment/setting/SettingFragment.kt index 8d46487..f8acbc7 100644 --- a/app/src/main/java/com/yingmao/clash/fragment/setting/SettingFragment.kt +++ b/app/src/main/java/com/yingmao/clash/fragment/setting/SettingFragment.kt @@ -62,6 +62,7 @@ import com.yingmao.clash.act.UIMainActivity.Companion.newUuid import com.yingmao.clash.act.UIMainActivity.Companion.profileBinder import com.yingmao.clash.act.UIMainActivity.Companion.subUrl import com.yingmao.clash.app.MainApplication +import com.yingmao.clash.base.BaseActivity import com.yingmao.clash.conf.BZYConstants import com.yingmao.clash.conf.Conf import com.yingmao.clash.entity.CheckLoginRsp @@ -636,6 +637,10 @@ class SettingFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatc MMKV.defaultMMKV().removeValueForKey(BZYConstants.MMKV_KEY_VPN_UserCommand) MMKV.defaultMMKV().removeValueForKey(BZYConstants.NODE_All_ITEM_NAME_KEY) MMKV.defaultMMKV().removeValueForKey(BZYConstants.PROFILE_SUB_URL) + MMKV.defaultMMKV().removeValueForKey(BZYConstants.MMKV_KEY_Switch_Finsh_Set) + + //清除源切换记录 + Log.d("cleanUserInfo clashRunning==>${clashRunning}") if (clashRunning) { fragments.filterIsInstance().forEach { it.stopClash() } diff --git a/app/src/main/java/com/yingmao/clash/net/http/HttpApi.kt b/app/src/main/java/com/yingmao/clash/net/http/HttpApi.kt index 67ba79d..522fb51 100644 --- a/app/src/main/java/com/yingmao/clash/net/http/HttpApi.kt +++ b/app/src/main/java/com/yingmao/clash/net/http/HttpApi.kt @@ -33,6 +33,7 @@ import com.yingmao.clash.net.http.entity.UploadParamData import com.yingmao.clash.net.http.entity.VipSignRsp import okhttp3.RequestBody import retrofit2.Call +import retrofit2.Response import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.Header @@ -75,6 +76,7 @@ interface HttpApi { @POST("/netbarcloud/vpn/octopusRegister.do") suspend fun register(@QueryMap params: Map): RegisterRsp + //加密注册 @Headers( "User-Agent: Octopus_Android" @@ -94,7 +96,6 @@ interface HttpApi { ): RegisterRsp - //显示赠送时长 : @Headers( "User-Agent: Octopus_Android" @@ -218,8 +219,10 @@ interface HttpApi { @GET("/taiziregister.txt") suspend fun getTzRegister(): String + @GET("/taiziregister_182269.txt") suspend fun getTz182269Register(): String + @GET("/bzyregister.txt") suspend fun getBzyRegister(): String @@ -631,4 +634,16 @@ interface HttpApi { BZYConstants.MMKV_KEY_TOKEN ).toString(), ): AppStopStatus + + @Headers( + "User-Agent: Octopus_Android", + "Authorization: Basic Z20yMXdvcGc6eDVjZXlzbTY=" + ) + @POST("/netbarcloud/api/v1/push") + suspend fun postErrLog( + @Body requestBody: RequestBody, + @Header("token") string: String = MMKV.defaultMMKV().decodeString( + BZYConstants.MMKV_KEY_TOKEN + ).toString(), + ): Response } \ No newline at end of file diff --git a/app/src/main/java/com/yingmao/clash/net/http/NetService.kt b/app/src/main/java/com/yingmao/clash/net/http/NetService.kt index e05d3fa..c870f2b 100644 --- a/app/src/main/java/com/yingmao/clash/net/http/NetService.kt +++ b/app/src/main/java/com/yingmao/clash/net/http/NetService.kt @@ -16,6 +16,7 @@ import okhttp3.Callback import okhttp3.Cookie import okhttp3.CookieJar import okhttp3.HttpUrl +import okhttp3.Interceptor import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.OkHttpClient import okhttp3.Request @@ -72,6 +73,37 @@ class NetService private constructor() : INetService { var httpClient: OkHttpClient? = null; var downHttpClient: OkHttpClient? = null; + class ExceptionLoggingInterceptor : Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request() + return try { + val response = chain.proceed(request) + // 如果需要也可记录非 2xx 的响应 + if (!response.isSuccessful) { + logHttpError(request, response.code, null) + } + response + } catch (e: Exception) { + logHttpError(request, null, e) + throw e // 抛出异常让上层处理 + } + } + + private fun logHttpError(request: Request, code: Int?, e: Exception?) { + val log = buildString { + append("URL: ${request.url}\n") + append("Method: ${request.method}\n") + append("Headers: ${request.headers}\n") + append("Body: ${request.body}\n") + code?.let { append("Response Code: $code\n") } + e?.let { append("Exception: ${e.message}\n${e.stackTraceToString()}") } + } + + // 这里可以上传到服务端,或者保存到本地文件 + println("❌ 网络请求异常:\n$log") + // FirebaseCrashlytics.getInstance().recordException(e) // 如果用了 Firebase + } + } override fun httpsClient(connTO:Long,readTO:Long,writeTO:Long): OkHttpClient { var loggingInterceptor = HttpLoggingInterceptor( @@ -79,8 +111,10 @@ class NetService private constructor() : INetService { override fun log(message: String) { Log.d("loggingInterceptor==>$message") } + } ) + loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY var builder = OkHttpClient.Builder() .retryOnConnectionFailure(true) @@ -95,6 +129,7 @@ class NetService private constructor() : INetService { .hostnameVerifier(getHostnameVerifier()!!) if (BuildConfig.DEBUG) { builder.addInterceptor(loggingInterceptor) +// builder.addInterceptor(ExceptionLoggingInterceptor()) } // builder.addInterceptor(loggingInterceptor) return builder.build() @@ -161,6 +196,7 @@ class NetService private constructor() : INetService { .addConverterFactory(ScalarsConverterFactory.create())//json解析器Gson .baseUrl(baseUrl) //设置BaseURL需以'/'结尾 .build() //创建Retrofit对象 + return retrofit.create(HttpApi::class.java) } fun createFreeBaseUrl2(): HttpApi { diff --git a/app/src/main/java/com/yingmao/clash/view/dialog/DialogAutoDoMainChoose.kt b/app/src/main/java/com/yingmao/clash/view/dialog/DialogAutoDoMainChoose.kt new file mode 100644 index 0000000..08f6992 --- /dev/null +++ b/app/src/main/java/com/yingmao/clash/view/dialog/DialogAutoDoMainChoose.kt @@ -0,0 +1,112 @@ +package com.yingmao.clash.view.dialog + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.content.DialogInterface +import android.view.LayoutInflater +import android.view.ViewGroup +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.tencent.mmkv.MMKV +import com.yingmao.clash.BuildConfig +import com.yingmao.clash.R +import com.yingmao.clash.conf.BZYConstants + + + +/** + * @author tamsiree + * @date 2016/7/19 + * 确认 取消 Dialog + */ +open class DialogAutoDoMainChoose : RxDialog { + lateinit var titleView: TextView + private set + lateinit var but_try: TextView + private set + lateinit var but_cancel: TextView + private set + lateinit var domainRecyclerView: RecyclerView + private set + lateinit var onTryListener: OnTryButtonListener + + lateinit var onDomainListItemListener: OnListItemListener + + var domainFininshSet = mutableSetOf(); + + 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) + 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() } + + setContentView(dialogView) + setCancelable(false) + window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + setNewData() + } + + @SuppressLint("NotifyDataSetChanged") + private fun setNewData() { + var mmkv = MMKV.defaultMMKV() + val originalUrl = + mmkv.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, BuildConfig.service_url) + var newUrlString = originalUrl + + val routerHost = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST, HashSet()) + + + } + + fun setOnTryButtonListener(listener: OnTryButtonListener) { + this.onTryListener = listener + } + + + private fun changeSubUrl(originalUrl: String, newUrl: String): String { + return originalUrl.replace(Regex("https://[^/]+/"), "$newUrl/") + + } + + interface OnTryButtonListener { + fun tryButton() + fun cancel() + } + + interface OnListItemListener { + fun listItemClick() + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/yingmao/clash/view/dialog/DialogDoMainChoose.kt b/app/src/main/java/com/yingmao/clash/view/dialog/DialogDoMainChoose.kt index 7ea1289..2f5dc64 100644 --- a/app/src/main/java/com/yingmao/clash/view/dialog/DialogDoMainChoose.kt +++ b/app/src/main/java/com/yingmao/clash/view/dialog/DialogDoMainChoose.kt @@ -106,7 +106,6 @@ open class DialogDoMainChoose : RxDialog { } domainListAdapter.notifyDataSetChanged() } - } fun setOnTryButtonListener(listener: OnTryButtonListener) {