一键连

新增退出账号未绑定用户提示绑定
This commit is contained in:
level 2025-12-15 17:41:10 +08:00
parent 91ec4dfb83
commit 548216d93d
7 changed files with 179 additions and 126 deletions

View File

@ -377,7 +377,7 @@ class MainActivity : BaseActivity() {
mmkv.decodeLong(BZYConstants.MMKV_KEY_VPN_VALID_PERIOD, 0)
val nowExpireTime = checkLoginRsp.data!!.vpnExpireTime
if (nowExpireTime > oldExpireTime) {
if (nowExpireTime!=oldExpireTime) {
val expired = checkLoginRsp.data.expired
mmkv.encode(BZYConstants.MMKV_KEY_VPN_EXPIRED, expired ?: true)
mmkv.encode(BZYConstants.MMKV_KEY_VPN_VALID_PERIOD, nowExpireTime)

View File

@ -448,127 +448,4 @@ class NodeGroupActivity : BaseActivity(){
intent.setPackage(this.packageName)
)
}
private fun checkGlo() {
val isGlobal = isGlo
val isGlobal2 = MMKV.defaultMMKV().decodeBool(BZYConstants.MMKV_KEY_GLOBAL_MODEL, false)
Log.i("checkGlo isGlobal==>${isGlobal}, isGlobal2==>${isGlobal2}")
val px: ProxyMode = if (isGlobal2) {
ProxyMode.GLOBAL
} else {
ProxyMode.PAC
}
setBackground(px)
launch(Dispatchers.IO) {
if (isGlobal) {
if (clashRunning) {
getNodes()
}
} else {
if (clashRunning) {
delay(1000)
clashBinder?.let { cm ->
val names = cm.queryProxyGroupNames(false)
Log.i("checkGlo names==>${names}")
if (names.isNotEmpty()) {
val selectedName =
MMKV.defaultMMKV()
.decodeString(BZYConstants.NODE_SELECTED_NAME_KEY, "");
Log.i("selected_name ==>${selectedName}")
if (!TextUtils.isEmpty(selectedName)) {
val o = cm.queryOverride(Clash.OverrideSlot.Session)
o.mode = TunnelState.Mode.Rule
cm.patchOverride(Clash.OverrideSlot.Session, o)
delay(500)
var gName = names[0]
//全局模式下 names[0]会自动添加一个 "GLOBAL" 组
if (names.size >= 2) {
if ("GLOBAL" == gName) {
//names[0] 为 "GLOBAL" //names[1]才是规则模式下的组名,所以需要手动赋值
gName = names[1]
}
}
cm.patchSelector(gName, selectedName!!)
}
}
}
}
}
}
}
private suspend fun getNodes() {
coroutineScope {
val selectedName =
MMKV.defaultMMKV().decodeString(BZYConstants.NODE_SELECTED_NAME_KEY, "")
Log.d("getNodes selected_name==>${selectedName}")
if (TextUtils.isEmpty(selectedName)) {
subUrl?.let {
val json = serStore.nodes
Log.d("getNodes json==>${json}")
currentNode=getNodesInfo(json)
Log.d("getNodes currentNode==>${currentNode} dataname:${currentNode[0].proxies[0]}")
val baseNodeName=currentNode[0].proxies[0]
if (!TextUtils.isEmpty(baseNodeName)) {
GlobalScope.launch(Dispatchers.IO) {
clashBinder?.let { cm ->
val o = cm.queryOverride(Clash.OverrideSlot.Session)
o.mode = TunnelState.Mode.Global
cm.patchOverride(Clash.OverrideSlot.Session, o)
delay(3000)
//等待全局模式生效
var maxIndex = 0
while (true) {
if (maxIndex > 3) {
break
}
val names = cm.queryProxyGroupNames(false)
if (names.isNotEmpty()) {
if (names[0] == "GLOBAL") {
Log.d("repeat end")
break
}
}
Log.d("repeat agent")
maxIndex++
delay(1000)
}
cm.patchSelector("GLOBAL", baseNodeName)
}
}
}
}
} else {
clashBinder?.let { cm ->
val o = cm.queryOverride(Clash.OverrideSlot.Session)
o.mode = TunnelState.Mode.Global
cm.patchOverride(Clash.OverrideSlot.Session, o)
delay(3000)
//等待全局
var maxIndex = 0
while (true) {
if (maxIndex > 3) {
break
}
val names = cm.queryProxyGroupNames(false)
if (names.isNotEmpty()) {
if (names[0] == "GLOBAL") {
Log.d("repeat end")
break
}
}
Log.d("repeat agent")
maxIndex++
delay(1000)
}
cm.patchSelector("GLOBAL", selectedName!!)
}
}
}
}
}

View File

@ -5,15 +5,19 @@ import android.content.Intent
import android.os.Bundle
import android.os.CountDownTimer
import android.text.method.HideReturnsTransformationMethod
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.webkit.WebView
import android.widget.*
import androidx.appcompat.widget.AppCompatImageView
import androidx.lifecycle.ViewModelProvider
import com.cncat.vpn.service.ClashManager
import com.cncat.vpn.service.remote.IClashManager
import com.cncat.vpn.service.remote.wrap
import com.github.gzuliyujiang.oaid.DeviceID
import com.github.gzuliyujiang.oaid.DeviceIdentifier
import com.google.gson.JsonObject
import com.yingmao.clash.view.dialog.RxDialogShapeLoading
@ -22,6 +26,7 @@ import com.tencent.mmkv.MMKV
import com.yingmao.clash.BuildConfig
import com.yingmao.clash.R
import com.yingmao.clash.app.MainApplication
import com.yingmao.clash.app.MainApplication.Companion.OAID
import com.yingmao.clash.base.BaseActivity
import com.yingmao.clash.conf.BZYConstants
import com.yingmao.clash.net.http.HttpReqType
@ -177,7 +182,38 @@ class RegisterActivity : BaseActivity(), View.OnClickListener {
override fun onClick(v: View?) {
when (v?.id) {
R.id.tv_register -> {
var userAgent = System.getProperty("http.agent")
Log.i("SplashRegister", "userAgent::$userAgent")
if (userAgent != null) {
if (userAgent.isEmpty() || userAgent.length < 5) {
val webView = WebView(this@RegisterActivity)
userAgent = webView.settings.userAgentString
}
} else {
val webView = WebView(this@RegisterActivity)
userAgent = webView.settings.userAgentString
}
var oaId = OAID
Log.i(
"SplashRegister",
"OAID::" + OAID + "oaId.isEmpty()::" + oaId.isEmpty() + "userAgent::" + userAgent
)
val equipmentModel = Utils.getEquipmentModel()
Log.i("equipmentModel", "equipmentModel::" + equipmentModel)
if (oaId.isEmpty()) {
if (DeviceID.supportedOAID(MainApplication.getApp())) {
//同步获取oaid
val aOaId = DeviceIdentifier.getOAID(MainApplication.getApp())
oaId = aOaId
OAID = aOaId
Log.i(
"doRegisterByEncryption",
"aOaId::" + aOaId + "oaId::" + oaId + "OAID::" + OAID
)
}
}
val smsCode =etSmSCode.text.trim().toString()
if(smsCode.isEmpty()){
RxToast.error("验证码不能为空")
@ -192,6 +228,10 @@ class RegisterActivity : BaseActivity(), View.OnClickListener {
reqJson.addProperty("from", "5")
reqJson.addProperty("androidDevice", Utils.getUniqueID(this))
reqJson.addProperty("smsCode", smsCode)
reqJson.addProperty("userAgent", userAgent)
reqJson.addProperty("oaid", oaId)
reqJson.addProperty("equipmentModel", equipmentModel)
reqJson.addProperty("pkg", BuildConfig.applicationId)
if (registerKey.isNotEmpty() && registerIV2.isNotEmpty()) {
val data = AESUtil.byteArrayToHexStr(
AESUtil.RegisterEncrypt(reqJson.toString(), registerKey, registerIV2)

View File

@ -15,6 +15,9 @@ import androidx.constraintlayout.widget.ConstraintLayout
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.customview.customView
import com.afollestad.materialdialogs.customview.getCustomView
import com.alibaba.sdk.android.oss.ClientException
import com.alibaba.sdk.android.oss.OSSClient
import com.alibaba.sdk.android.oss.ServiceException
@ -49,9 +52,11 @@ import com.yingmao.clash.net.http.entity.UploadParamData
import com.yingmao.clash.util.CommonUtils
import com.yingmao.clash.util.DataUtils
import com.yingmao.clash.util.DataUtils.getAllFilePath
import com.yingmao.clash.util.Utils
import com.yingmao.clash.util.stopClashService
import com.yingmao.clash.view.RxToast
import com.yingmao.clash.view.adapter.LanguageAdapter
import com.yingmao.clash.view.dialog.DialogBandChoose
import com.yingmao.clash.view.dialog.DialogDoMainChoose
import com.yingmao.clash.view.dialog.DialogSureCancelLogOut
import com.yingmao.clash.view.popwindow.CommonPopupWindow
@ -126,10 +131,48 @@ class SettingActivity : BaseActivity() {
})
}
tvExit.setOnClickListener {
val userAccount =
MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME, "")!!
if (Utils.isEmail(userAccount) || Utils.isPhoneNumber(userAccount)) {
cleanUserInfo()
}
}else{
MaterialDialog(this@SettingActivity).show {
this.cancelable(true)
cornerRadius(res = R.dimen.dp_10)
customView(
R.layout.user_bing_exit,
scrollable = false,
noVerticalPadding = true,
horizontalPadding = false
)
getCustomView().findViewById<TextView>(R.id.tvExitBt)
.setOnClickListener {
cleanUserInfo()
dismiss()
}
getCustomView().findViewById<TextView>(R.id.tvBindingBt)
.setOnClickListener {
showBingDialogChoose()
dismiss()
}
}
}
}
}
private fun showBingDialogChoose() {
val dialog = DialogBandChoose(this)
dialog.setOnBandClickListener(object : DialogBandChoose.OnBandClickListener {
override fun onBandClick(isPhone: Boolean) {
val intent = Intent(CommonUtils.getApp(), BandPhoneActivity::class.java)
intent.putExtra("isPhone", isPhone)
startActivity(intent)
dialog.dismiss()
}
})
dialog.show()
}
override fun httpLoading(httpStatus: HttpStatus.Loading) {
super.httpLoading(httpStatus)

View File

@ -0,0 +1,24 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- This is the main color -->
<item>
<shape>
<!-- 边框颜色 -->
<gradient android:startColor="#FF757EFF" android:endColor="#FF009AEF" android:angle="0"/>
<corners android:radius="10dp"/>
</shape>
</item>
<!-- 给View的上 左 右设置8dp的边框 -->
<item
android:bottom="3dp"
android:left="1dp"
android:right="3dp"
android:top="1dp">
<shape>
<!-- View填充颜色 -->
<solid android:color="#FF8A04" />
<gradient android:startColor="#FF757EFF" android:endColor="#FF009AEF" android:angle="0"/>
<corners android:radius="10dp" />
</shape>
</item>
</layer-list>

View File

@ -0,0 +1,68 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tvBindingContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/bindingShowTxt"
android:textColor="#FF000000"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/clBt"
android:layout_marginBottom="20dp"
android:layout_marginTop="20dp"
/>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/clBt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="20dp"
>
<TextView
android:id="@+id/tvExitBt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="@string/exit"
android:paddingStart="40dp"
android:paddingEnd="40dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:layout_marginStart="20dp"
android:background="@drawable/exit_check_bg"
/>
<TextView
android:id="@+id/tvBindingBt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:background="@drawable/exit_check_bg"
android:paddingStart="40dp"
android:paddingTop="10dp"
android:paddingEnd="40dp"
android:paddingBottom="10dp"
android:text="@string/binding"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -483,4 +483,5 @@
<string name="GolbalModeNoChoose">全局模式加速下暂不支持切换节点,请切换至智能模式!</string>
<string name="GetNodesAgined">获取节点中,请稍后点击加速</string>
<string name="SubscriptionlinkTop">获取节点信息出错,请手动点击 [源切换] 或联系客服处理!</string>
<string name="bindingShowTxt">当前账号尚未绑定,直接退出可能会造成账号丢失,推荐前往绑定账号或保存临时账号后在进行退出</string>
</resources>