From c431c95516ca611bbd27706e9e88d709a0e0a1a9 Mon Sep 17 00:00:00 2001 From: level <1364007522@qq.com> Date: Wed, 10 Dec 2025 17:39:53 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=80=E9=94=AE=E8=BF=9E=201.=E6=9B=B4?= =?UTF-8?q?=E6=8D=A2=E5=86=85=E6=A0=B8=202.=E6=96=B0=E5=A2=9E=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E7=BB=84=E9=80=89=E6=8B=A9=203.=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E6=8E=92=E5=BA=8F=204.=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=9C=A8=E5=85=A8=E5=B1=80=E6=A8=A1=E5=BC=8F=E6=97=B6=E4=B8=8D?= =?UTF-8?q?=E8=83=BD=E9=80=89=E6=8B=A9=E8=8A=82=E7=82=B9=206.=E6=B5=81?= =?UTF-8?q?=E9=87=8F=E4=BD=BF=E7=94=A8=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yingmao/clash/act/ChangeNodeActivity.kt | 4 +- .../com/yingmao/clash/act/MainActivity.kt | 32 ++- .../clash/act/MemberRechargeActivity.kt | 8 +- .../yingmao/clash/act/NodeGroupActivity.kt | 200 +++++++++++++++++- .../clash/entity/RechargeModelEntity.kt | 3 +- .../clash/fragment/home/HomeFragment.kt | 13 +- .../yingmao/clash/fragment/vip/vipFragment.kt | 7 +- .../yingmao/clash/net/http/entity/PayRsp.kt | 2 + .../clash/view/adapter/NodeGroupAdapter.kt | 7 +- .../main/res/layout/activity_change_node.xml | 4 +- app/src/main/res/values-en/strings.xml | 4 + app/src/main/res/values-zh-rHK/strings.xml | 2 + app/src/main/res/values-zh-rTW/strings.xml | 2 + app/src/main/res/values/strings.xml | 1 + 14 files changed, 259 insertions(+), 30 deletions(-) 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 f1703b1..d018a54 100644 --- a/app/src/main/java/com/yingmao/clash/act/ChangeNodeActivity.kt +++ b/app/src/main/java/com/yingmao/clash/act/ChangeNodeActivity.kt @@ -118,8 +118,8 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { @SuppressLint("SetTextI18n") private fun initViews() { aiBack = findViewById(R.id.aiBack) - tvProA = findViewById(R.id.tvProA) - tvProj = findViewById(R.id.tvProj) + tvProA = findViewById(R.id.smartMode) + tvProj = findViewById(R.id.globalMOde) val isGlobal = MMKV.defaultMMKV().decodeBool(BZYConstants.MMKV_KEY_GLOBAL_MODEL, false) var px: ProxyMode diff --git a/app/src/main/java/com/yingmao/clash/act/MainActivity.kt b/app/src/main/java/com/yingmao/clash/act/MainActivity.kt index 160406d..c012c02 100644 --- a/app/src/main/java/com/yingmao/clash/act/MainActivity.kt +++ b/app/src/main/java/com/yingmao/clash/act/MainActivity.kt @@ -43,6 +43,7 @@ import com.yingmao.clash.base.BaseActivity import com.yingmao.clash.conf.BZYConstants import com.yingmao.clash.conf.Conf import com.yingmao.clash.entity.CheckLoginRsp +import com.yingmao.clash.entity.NodeGroupItem import com.yingmao.clash.fragment.vip.vipFragment import com.yingmao.clash.fragment.home.HomeFragment import com.yingmao.clash.fragment.setting.SettingFragment @@ -109,6 +110,8 @@ class MainActivity : BaseActivity() { private var checkBindAccountDia: MaterialDialog? = null private val mPageInfo = ExpensesRecordActivity.PageInfo() + + private var MainActCurrentNode: MutableList = mutableListOf() companion object { var isVip:Boolean=false //记录心跳失败次数 @@ -223,10 +226,24 @@ class MainActivity : BaseActivity() { override fun onReceive(context: Context?, intent: Intent?) { when (intent?.action) { Intents.ACTION_NODE_LIST -> { - Log.d("ACTION_NODE_LIST ACTION_NODE_LIST") + Log.i("MainActivity ACTION_NODE_LIST") val userTraffic=serStore.userTraffic Log.d("userTraffic::::${userTraffic}") userTrafficMethod(userTraffic) + val selectedName = + MMKV.defaultMMKV() + .decodeString(BZYConstants.NODE_SELECTED_NAME_KEY, "") + if(TextUtils.isEmpty(selectedName)){ + val json = serStore.nodes + val nodesInfo = getNodesInfo(json) + val proxies = nodesInfo[0].proxies[0] + Log.i("MainActivity baseChoose::${proxies} true:${proxies.isNotEmpty()}") + if(proxies.isNotEmpty()){ + MMKV.defaultMMKV().encode(BZYConstants.NODE_All_ITEM_NAME_KEY, json) + MMKV.defaultMMKV().encode(BZYConstants.NODE_SELECTED_NAME_KEY, proxies) + } + } + if (TextUtils.isEmpty(userTraffic)) { return } @@ -790,4 +807,17 @@ class MainActivity : BaseActivity() { // REQUEST_CODE_PAY_WEB_VIEW_ACTIVITY // ) } + private fun getNodesInfo(json: String): MutableList { + val mList: MutableList = mutableListOf() + if (TextUtils.isEmpty(json)) { + return mList + } + val gson = Gson() + val jsonArray = JsonParser.parseString(json).asJsonArray + for (i in 0 until jsonArray.size()) { + val bean = gson.fromJson(jsonArray.get(i).asString, NodeGroupItem::class.java) + mList.add(bean) + } + return mList + } } \ No newline at end of file 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 9258d50..8bea0df 100644 --- a/app/src/main/java/com/yingmao/clash/act/MemberRechargeActivity.kt +++ b/app/src/main/java/com/yingmao/clash/act/MemberRechargeActivity.kt @@ -433,14 +433,14 @@ class MemberRechargeActivity : BaseActivity() { index.payChannel!!, index.payParam!!, index.payType!!, - index.payOrder!! + index.payOrder!!, + index.sort ) payList.add(rme) } } -// payList.sortBy { item -> item.payModel } - //7是快捷支付排第一 - payList.sortBy { if (it.payModel == 7) 0 else 1 } + //根据sort字段排序 + payList.sortBy{it.sort} val groupBy = payList.groupBy { item -> item.payModel } val rcmAdapter = RechargeModelAdapter() rvPay.layoutManager = LinearLayoutManager(this@MemberRechargeActivity) diff --git a/app/src/main/java/com/yingmao/clash/act/NodeGroupActivity.kt b/app/src/main/java/com/yingmao/clash/act/NodeGroupActivity.kt index 1f6ea19..ce381a7 100644 --- a/app/src/main/java/com/yingmao/clash/act/NodeGroupActivity.kt +++ b/app/src/main/java/com/yingmao/clash/act/NodeGroupActivity.kt @@ -18,6 +18,8 @@ import androidx.recyclerview.widget.RecyclerView import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.cncat.vpn.common.constants.Intents import com.cncat.vpn.common.log.Log +import com.cncat.vpn.core.Clash +import com.cncat.vpn.core.model.TunnelState import com.cncat.vpn.service.model.Profile import com.cncat.vpn.service.remote.IRemoteService import com.google.gson.Gson @@ -25,6 +27,8 @@ import com.google.gson.JsonParser import com.tencent.mmkv.MMKV import com.yingmao.clash.BuildConfig import com.yingmao.clash.R +import com.yingmao.clash.act.ChangeNodeActivity.ProxyMode +import com.yingmao.clash.act.MainActivity.Companion.clashBinder import com.yingmao.clash.act.MainActivity.Companion.profileBinder import com.yingmao.clash.act.MainActivity.Companion.setSub2 import com.yingmao.clash.act.MainActivity.Companion.subUrl @@ -33,23 +37,19 @@ import com.yingmao.clash.base.BaseActivity import com.yingmao.clash.conf.BZYConstants import com.yingmao.clash.conf.Conf import com.yingmao.clash.entity.NodeGroupItem -import com.yingmao.clash.fragment.home.HomeFragment import com.yingmao.clash.fragment.home.HomeFragment.Companion.CHECK_NODE_REQUEST_CODE +import com.yingmao.clash.fragment.home.HomeFragment.Companion.clashRunning +import com.yingmao.clash.fragment.home.HomeFragment.Companion.isGlo import com.yingmao.clash.remote.Resource import com.yingmao.clash.view.RxToast import com.yingmao.clash.view.adapter.NodeGroupAdapter import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.Job +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import java.util.UUID -import kotlin.collections.forEach -import kotlin.collections.withIndex -import kotlin.jvm.java -import kotlin.let -import kotlin.ranges.until -import kotlin.text.isNotEmpty -import kotlin.text.replace class NodeGroupActivity : BaseActivity(){ private var currentNode: MutableList = mutableListOf() @@ -58,6 +58,8 @@ class NodeGroupActivity : BaseActivity(){ private lateinit var nodeListRv: RecyclerView private lateinit var aiBack: AppCompatImageView private var broadcastReceiver: BroadcastReceiver? = null + private lateinit var smartMode:TextView + private lateinit var globalMOde:TextView private var cacheNodeStr: String? = "" private lateinit var userTrafficTv: TextView private var uuid: UUID? = null @@ -68,7 +70,6 @@ class NodeGroupActivity : BaseActivity(){ var getNodeTimeOutNum = 5 var isRunning = false var nowSubUrl: String = "" - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_change_node) @@ -112,6 +113,38 @@ class NodeGroupActivity : BaseActivity(){ swipeLayout = findViewById(R.id.swipeLayout) nodeListRv = findViewById(R.id.rv_node_list) userTrafficTv= findViewById(R.id.node_user_traffic) + smartMode=findViewById(R.id.smartMode) + globalMOde=findViewById(R.id.globalMOde) + val isGlobal = MMKV.defaultMMKV().decodeBool(BZYConstants.MMKV_KEY_GLOBAL_MODEL, false) + var px: ProxyMode + if (isGlobal) { + px = ProxyMode.GLOBAL + } else { + px = ProxyMode.PAC + } + setBackground(px) + smartMode.setOnClickListener { + val getIsGlo= MMKV.defaultMMKV().decodeBool(BZYConstants.MMKV_KEY_GLOBAL_MODEL, false) + Log.d("clIntelligentMode ==>${getIsGlo}") + if(getIsGlo){ + setBackground(ProxyMode.PAC) + MMKV.defaultMMKV().encode(BZYConstants.MMKV_KEY_GLOBAL_MODEL, false) + } + } + globalMOde.setOnClickListener { + if (!clashRunning) { + RxToast.info(resources.getString(R.string.OpenSwitchingSourceModel)) + return@setOnClickListener + } + + val getIsGlo= MMKV.defaultMMKV().decodeBool(BZYConstants.MMKV_KEY_GLOBAL_MODEL, false) + Log.d("clGlobalModel ==>${getIsGlo}") + if (!getIsGlo) { + setBackground(ProxyMode.GLOBAL) + MMKV.defaultMMKV().encode(BZYConstants.MMKV_KEY_GLOBAL_MODEL, true) + } + } + aiBack.setOnClickListener { onBackPressed() } @@ -389,7 +422,156 @@ class NodeGroupActivity : BaseActivity(){ currentHost?.let { changeSubUrl(oldUrl, it) } } + private fun setBackground(proxyMode: ProxyMode) { + when (proxyMode) { + ProxyMode.PAC -> { + isGlo = false + smartMode.setBackgroundResource(R.drawable.yil_node_proxy_choose_bg) + globalMOde.setBackgroundResource(0) + MMKV.defaultMMKV().encode(BZYConstants.MMKV_KEY_GLOBAL_MODEL, false) + sendMode(false) + } + ProxyMode.GLOBAL -> { + isGlo = true + smartMode.setBackgroundResource(0) + globalMOde.setBackgroundResource(R.drawable.yil_node_proxy_choose_bg) + MMKV.defaultMMKV().encode(BZYConstants.MMKV_KEY_GLOBAL_MODEL, true) + sendMode(true) + + } + } + } + fun sendMode(type: Boolean) { + val intent = Intent(Intents.ACTION_Glo_Mode) + intent.putExtra("mode", type) + sendBroadcast( + 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!!) + } + } + } + } } diff --git a/app/src/main/java/com/yingmao/clash/entity/RechargeModelEntity.kt b/app/src/main/java/com/yingmao/clash/entity/RechargeModelEntity.kt index 840cf93..2707ce0 100644 --- a/app/src/main/java/com/yingmao/clash/entity/RechargeModelEntity.kt +++ b/app/src/main/java/com/yingmao/clash/entity/RechargeModelEntity.kt @@ -5,5 +5,6 @@ data class RechargeModelEntity( val payChannel: String,//支付渠道名称 val payParam:String,//支付参数 var payType:Int,//支付类型 - var payOrder:Int//支付编号 + var payOrder:Int,//支付编号 + var sort: Int//排序字段 ) diff --git a/app/src/main/java/com/yingmao/clash/fragment/home/HomeFragment.kt b/app/src/main/java/com/yingmao/clash/fragment/home/HomeFragment.kt index 90b08a1..9ce4a6d 100644 --- a/app/src/main/java/com/yingmao/clash/fragment/home/HomeFragment.kt +++ b/app/src/main/java/com/yingmao/clash/fragment/home/HomeFragment.kt @@ -233,6 +233,11 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa RxToast.info(resources.getString(R.string.AccountExpired)) return@setOnClickListener } + val getIsGlo= MMKV.defaultMMKV().decodeBool(BZYConstants.MMKV_KEY_GLOBAL_MODEL, false) + if(getIsGlo){ + RxToast.info(resources.getString(R.string.GolbalModeNoChoose)) + return@setOnClickListener + } val intent = Intent(CommonUtils.getApp(), NodeGroupActivity::class.java) if (!TextUtils.isEmpty(newUuid)) { intent.putExtra(BZYConstants.MMKV_KEY_CURRENT_NODE, newUuid) @@ -256,7 +261,7 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa } tvGlobalMode.setOnClickListener { if (!clashRunning) { - RxToast.info(resources.getString(R.string.SwitchingSourceModel)) + RxToast.info(resources.getString(R.string.OpenSwitchingSourceModel)) return@setOnClickListener } @@ -562,7 +567,7 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa @Deprecated("Deprecated in Java") override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (requestCode == 2) { + if (requestCode == CHECK_NODE_REQUEST_CODE) { nodeChooseBase(data) } } @@ -668,7 +673,6 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa launch(Dispatchers.IO) { if (isGlobal) { if (clashRunning) { - Log.i("AAAAAAAAAAAAAA innner to==>") getNodes() } }else{ @@ -694,7 +698,6 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa } } cm.patchSelector(gName, selectedName!!) - } } } @@ -905,7 +908,6 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa tvIntelligentMode.setTextColor("#FF006AFB".toColorInt()) tvGlobalMode.setTextColor("#FF000000".toColorInt()) sendMode(false) - checkGlo() } ProxyMode.GLOBAL -> { @@ -916,7 +918,6 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa tvIntelligentMode.setTextColor("#FF000000".toColorInt()) tvGlobalMode.setTextColor("#FF006AFB".toColorInt()) sendMode(true) - checkGlo() } } } diff --git a/app/src/main/java/com/yingmao/clash/fragment/vip/vipFragment.kt b/app/src/main/java/com/yingmao/clash/fragment/vip/vipFragment.kt index c38996b..03e5b4a 100644 --- a/app/src/main/java/com/yingmao/clash/fragment/vip/vipFragment.kt +++ b/app/src/main/java/com/yingmao/clash/fragment/vip/vipFragment.kt @@ -469,14 +469,13 @@ class vipFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatchers index.payChannel!!, index.payParam!!, index.payType!!, - index.payOrder!! + index.payOrder!!, + index.sort ) payList.add(rme) } } -// payList.sortBy { item -> item.payModel } - //7是快捷支付排第一 - payList.sortBy { if (it.payModel == 7) 0 else 1 } + payList.sortBy { it.sort } val groupBy = payList.groupBy { item -> item.payModel } val rcmAdapter = RechargeModelAdapter() rvPay.layoutManager = LinearLayoutManager(requireContext()) diff --git a/app/src/main/java/com/yingmao/clash/net/http/entity/PayRsp.kt b/app/src/main/java/com/yingmao/clash/net/http/entity/PayRsp.kt index b6e8c56..e9b7876 100644 --- a/app/src/main/java/com/yingmao/clash/net/http/entity/PayRsp.kt +++ b/app/src/main/java/com/yingmao/clash/net/http/entity/PayRsp.kt @@ -62,6 +62,8 @@ data class PayType( var payParam: String? = null, @field:SerializedName("payOrder") var payOrder: Int? = null, + @field:SerializedName("sort") + var sort: Int = 0, ) //汇旺财 data class QRPayRsp(@field:SerializedName("msg") diff --git a/app/src/main/java/com/yingmao/clash/view/adapter/NodeGroupAdapter.kt b/app/src/main/java/com/yingmao/clash/view/adapter/NodeGroupAdapter.kt index a2d8082..a87f2e9 100644 --- a/app/src/main/java/com/yingmao/clash/view/adapter/NodeGroupAdapter.kt +++ b/app/src/main/java/com/yingmao/clash/view/adapter/NodeGroupAdapter.kt @@ -56,7 +56,12 @@ class NodeGroupAdapter : RecyclerView.Adapter Membership Validity Period: Gift Please disconnect and switch modes + + Please enable acceleration before switching to global mode + + Switching nodes is not currently supported in global mode. Please switch to smart mode! \ No newline at end of file diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index c1bfbdd..e870b74 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -414,4 +414,6 @@ 會員有效期限: 禮品 請斷開連線後在進行模式切換 + 請開啟加速後在進行全域模式切換 + 全域模式下暫不支援切換節點,請切換至智慧型模式! \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 4883ce2..9f07aa1 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -412,4 +412,6 @@ 會員有效期限: 禮品 請斷開連線後在進行模式切換 + 請開啟加速後在進行全域模式切換 + 全域模式下暫不支援切換節點,請切換至智慧型模式! \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 16855e0..8e3fbbb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -480,4 +480,5 @@ 您可以获得30天会员(仅限新用户订购有效) 点击分享 请开启加速后在进行全局模式切换 + 全局模式下暂不支持切换节点,请切换至智能模式! \ No newline at end of file