From 6402e1793ec7748438746562225fa6f2ecab9c72 Mon Sep 17 00:00:00 2001 From: cyh Date: Sun, 27 Apr 2025 16:21:27 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=B7=BB=E5=8A=A0=E8=8A=82=E7=82=B9=E6=B5=8B?= =?UTF-8?q?=E9=80=9F=202.=E6=B7=BB=E5=8A=A0=E5=A4=AA=E5=AD=90=E5=AE=9A?= =?UTF-8?q?=E5=88=B6=E8=8A=82=E7=82=B9=E9=A1=B5=E9=9D=A2=203.=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E9=83=A8=E5=88=86=E7=95=8C=E9=9D=A2=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E5=A4=87=E7=94=A8=E6=BA=90=E5=BC=82=E5=B8=B8bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 4 + .../yingmao/clash/act/ChangeNodeActivity.kt | 29 +- .../yingmao/clash/act/ChangeNodeTzActivity.kt | 606 ++++++++++++++++++ .../com/yingmao/clash/act/LoginActivity.kt | 8 + .../com/yingmao/clash/act/SplashActivity.kt | 67 +- .../com/yingmao/clash/app/MainApplication.kt | 4 +- .../clash/fragment/home/HomeFragment.kt | 14 +- .../fragment/recharge/RechargeFragment.kt | 15 + .../clash/fragment/setting/SettingFragment.kt | 9 +- .../clash/view/adapter/NodeListAdapter.kt | 10 +- .../clash/view/adapter/NodeTzListAdapter.kt | 66 ++ .../main/res/layout/activity_change_node.xml | 12 + .../main/res/layout/node_list_item_layout.xml | 43 +- .../res/layout/node_tz_list_item_layout.xml | 54 ++ app/src/main/res/values-en/strings.xml | 1 + app/src/main/res/values-zh-rHK/strings.xml | 1 + app/src/main/res/values-zh-rTW/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + build.gradle.kts | 4 +- 19 files changed, 881 insertions(+), 68 deletions(-) create mode 100644 app/src/main/java/com/yingmao/clash/act/ChangeNodeTzActivity.kt create mode 100644 app/src/main/java/com/yingmao/clash/view/adapter/NodeTzListAdapter.kt create mode 100644 app/src/main/res/layout/node_tz_list_item_layout.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 55ed4c0..dc576d9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -165,6 +165,10 @@ android:name=".act.ChangeNodeActivity" android:process=":background" android:screenOrientation="portrait" /> + ? = null private lateinit var aiBack: AppCompatImageView private var broadcastReceiver: BroadcastReceiver? = null @@ -123,6 +125,8 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { @SuppressLint("SetTextI18n") private fun initViews() { aiBack = findViewById(R.id.aiBack) + nodeItemTest = findViewById(R.id.node_item_test) + nodeItemTest.setOnClickListener(this@ChangeNodeActivity) aiBack.setOnClickListener { onBackPressed() } @@ -329,13 +333,19 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { } private fun changeSubUrl(originalUrl: String, newUrl: String) { - nowSubUrl = originalUrl.replace(Regex("https://[^/]+/"), "$newUrl/") - MMKV.defaultMMKV().encode(BZYConstants.PROFILE_SUB_URL, nowSubUrl) + if (!originalUrl.isNullOrEmpty() && !newUrl.isNullOrEmpty()) { + nowSubUrl = originalUrl.replace(Regex("https://[^/]+/"), "$newUrl/") + MMKV.defaultMMKV().encode(BZYConstants.PROFILE_SUB_URL, nowSubUrl) + } + } + + private fun updateTestBut(str: String) { + nodeItemTest.text=str } val reloadLock = Semaphore(10) private fun setPing() { - if (!NewAccFragment.clashRunning) { + if (!HomeFragment.clashRunning) { RxToast.info("请先开启加速后,再进行测试."); return } @@ -344,20 +354,23 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { return } testRuning = true - updateMoreBar("测速中") +// updateMoreBar("测速中") + updateTestBut("测速中") launch(Dispatchers.IO) { var group = reloadLock.withPermit { UIMainActivity.clashBinder?.let { cb -> var names = cb.queryProxyGroupNames(false) if (names.isNotEmpty()) { cb.healthCheck(names[0]) + delay(1000) + cb.queryProxyGroup(names[0], uiStore.proxySort); + } else { + null } - delay(1000) - cb.queryProxyGroup(names[0], uiStore.proxySort); } } testRuning = false - runOnUiThread { updateMoreBar("线路测速") } + runOnUiThread { updateTestBut("线路测速") } var newDatas = mutableListOf(); group?.proxies?.forEach { proxy -> Log.d("node==>${proxy}") @@ -590,7 +603,7 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener { override fun onClick(p0: View?) { when (p0?.id) { - R.id.tv_more -> { + R.id.node_item_test -> { setPing() } diff --git a/app/src/main/java/com/yingmao/clash/act/ChangeNodeTzActivity.kt b/app/src/main/java/com/yingmao/clash/act/ChangeNodeTzActivity.kt new file mode 100644 index 0000000..fcd72e3 --- /dev/null +++ b/app/src/main/java/com/yingmao/clash/act/ChangeNodeTzActivity.kt @@ -0,0 +1,606 @@ +package com.yingmao.clash.act + + +import android.annotation.SuppressLint +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.graphics.Color +import android.os.Build +import android.os.Bundle +import android.text.TextUtils +import android.view.View +import android.widget.ImageView +import android.widget.TextView +import androidx.appcompat.widget.AppCompatImageView +import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.google.gson.Gson +import com.google.gson.JsonParser +import com.tencent.mmkv.MMKV +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.yingmao.clash.conf.BZYConstants +import com.yingmao.clash.conf.Conf +import com.yingmao.clash.entity.ClashNodebBean +import com.yingmao.clash.fragment.NewAccFragment +import com.yingmao.clash.fragment.NewAccFragment.Companion.CHECK_NODE_RESULT_CODE +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.yingmao.clash.app.MainApplication +import com.yingmao.clash.util.Utils +import com.yingmao.clash.view.RxToast +import com.yingmao.clash.view.adapter.NodeListAdapter +import com.yingmao.clash.view.adapter.NodeTzListAdapter +import com.yingmao.clash.view.dialog.DialogDoMainChoose +import com.yingmao.clash.view.dialog.DialogSureRestartChoose +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Semaphore +import kotlinx.coroutines.sync.withPermit +import java.util.Timer +import java.util.TimerTask +import java.util.UUID + +class ChangeNodeTzActivity : BaseActivity(), View.OnClickListener { + + companion object { + private var currentNode: MutableList = mutableListOf() + +// var clash: ClashManager? = null + } + + private lateinit var swipeLayout: SwipeRefreshLayout + private lateinit var changeNodeVM: ChangeNodeVM + private lateinit var nodeListRv: RecyclerView + private var names: List? = null + private lateinit var aiBack: AppCompatImageView + private var broadcastReceiver: BroadcastReceiver? = null + private var cacheNodeStr: String? = "" + + // private var checkedNode: ClashNodebBean? = null + private var uuid: UUID? = null + + private var testRuning = false + // var cprofile: ProfileManager? = null + // private var currentNode: Profile? = null + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_change_node) + setMoreBar("线路测速", this) + changeNodeVM = ViewModelProvider(this).get(ChangeNodeVM::class.java) + initData() + initViews() + +// cprofile = ProfileManager(this) + } + + override fun onBackPressed() { + intent.putExtra(BZYConstants.EXTRA_KEY_IS_RUNING, is_runing) + setResult(CHECK_NODE_RESULT_CODE, intent) + super.onBackPressed() + } + + private fun initData() { +// clash = MainApplication.getApp()?.let { ClashManager(it) } + cacheNodeStr = MMKV.defaultMMKV().decodeString(BZYConstants.NODE_All_ITEM_NAME_KEY, ""); + + val intentFilter = IntentFilter(Intents.ACTION_NODE_LIST) + broadcastReceiver = NodeListBR() + if (Build.VERSION.SDK_INT >= 34 && applicationInfo.targetSdkVersion >= 34) { + registerReceiver( + broadcastReceiver, + intentFilter, + Context.RECEIVER_EXPORTED + ) + } else { + registerReceiver( + broadcastReceiver, + intentFilter + ) + } +// registerReceiver( +// broadcastReceiver, +// intentFilter +// ) + } + + @SuppressLint("SetTextI18n") + private fun initViews() { + aiBack = findViewById(R.id.aiBack) + aiBack.setOnClickListener { + onBackPressed() + } + swipeLayout = findViewById(R.id.swipeLayout) + initRefreshLayout() + nodeListRv = findViewById(R.id.rv_node_list) + var userTrafficTv: TextView = findViewById(R.id.node_user_traffic) + + findViewById(R.id.iv_back).setOnClickListener { + onBackPressed() + } + initAdapter() +// Log.d("initViews cacheNodeStr==>${cacheNodeStr}") + if (!TextUtils.isEmpty(cacheNodeStr)) { + currentNode = getNodesInfo(cacheNodeStr!!) + setNewData(currentNode) + } + +// if (!TextUtils.isEmpty(serStore.userTraffic)) { +// userTrafficTv.visibility=View.VISIBLE +// var jo = JsonParser.parseString(serStore.userTraffic).asJsonObject +// var t = jo.get("total") +// var d = jo.get("download").asLong +// var u = jo.get("upload").asLong +// val trafficUsedInGB = String.format("%.2f", (d + u) / 1024.0 / 1024.0 / 1024.0) +// userTrafficTv.text="已用流量:${trafficUsedInGB}GB" +// } + } + + private fun getNodesInfo(json: String): MutableList { + var mList: MutableList = mutableListOf() + if (TextUtils.isEmpty(json)) { + return mList + } + val gson = Gson() + var ja = JsonParser.parseString(json).asJsonArray + + var cnb = ClashNodebBean("自动选择", "", "", 1, "", "", 0, true); + mList.add(cnb) + for (i in 0 until ja.size()) { + var bean = gson.fromJson(ja.get(i).asString, ClashNodebBean::class.java) + bean.delay = Utils.generateRandomTwoDigitNumber(10, 60) + mList.add(bean) + } + return mList + } + + inner class NodeListBR : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + when (intent?.action) { + Intents.ACTION_NODE_LIST -> { + Log.d("ACTION_NODE_LIST ACTION_NODE_LIST") +// val parcelableArrayListExtra = intent.getParcelableArrayListExtra>("") + hideLoading() +// stopTimer() + timerJob?.cancel() + dialogDoMainChoose?.dismiss() +// var json = intent.getStringExtra("node_list") +// Log.d("onReceive: $json") +// currNodeJsonA = json + var json = serStore.nodes +// Log.d("serStore.nodes: $json") + if (TextUtils.isEmpty(json)) { + return + } + //缓存订阅地址 + UIMainActivity.subUrl = nowSubUrl + MMKV.defaultMMKV().encode(BZYConstants.PROFILE_SUB_URL, nowSubUrl) + //缓存节点 + MMKV.defaultMMKV().encode(BZYConstants.NODE_All_ITEM_NAME_KEY, json) + currentNode = getNodesInfo(json) +// val listType = object : TypeToken>() {}.type +// currentNode = gson.fromJson(json, listType) + setNewData(currentNode) + swipeLayout.isRefreshing = false + } + + else -> { + + } + } + } + } + + override fun onDestroy() { + super.onDestroy() + broadcastReceiver?.let { + unregisterReceiver(it) + } + } + + override fun onResume() { + super.onResume() +// uuid = intent.getStringExtra(BZYConstants.MMKV_KEY_CURRENT_NODE) +// com.cncat.vpn.common.log.Log.d("ChangeNode uuid==>$uuid") + is_runing = intent.getBooleanExtra(BZYConstants.EXTRA_KEY_IS_RUNING, false) + } + + val remote = Resource() + var GetNodeTimeOutNum = 5; + var is_runing = false + private var timer: Timer? = null + private var timerTask: TimerTask? = null + var nowSubUrl: String = "" + private fun updateProfile(isDelete: Boolean) { +// showLoading("正在获取...", this@ChangeNodeActivity) + + try { + + + launch(Dispatchers.IO) { + UIMainActivity.profileBinder?.let { profileManager -> + var mProfile = profileManager.queryAll().find { + it.name == Conf.getClashConfName(this@ChangeNodeTzActivity.applicationContext) + } + + if (mProfile == null) { + //为空的情况下选择第一个 + profileManager.queryAll().forEach { profile -> + mProfile = profile + return@forEach + } + } + + mProfile?.let { profile -> + uuid = profile.uuid + Log.d("ChangeNode22 uuid==>${profile.uuid}") + if (isDelete) { + Log.d("gogogogogo isDelete") + profileManager.delete(profile.uuid) + MMKV.defaultMMKV() + .removeValueForKey(BZYConstants.NODE_All_ITEM_NAME_KEY) + setSub2(profileManager, nowSubUrl) + } else { + Log.d("gogogogogo update") + profileManager.setActive(profile) + delay(500) + if (!TextUtils.isEmpty(profile.source)) { +// Log.d("updateProfile pro.source==>${profile.source}, url==>${nowSubUrl}") + if (profile.source != nowSubUrl) { + Log.d("updateProfile patch") + profileManager.patch( + profile.uuid, + profile.name, + nowSubUrl, + 1800000L + ) + Log.d("updateProfile patch 1") + profileManager.commit(profile.uuid) { status -> + Log.d("updateProfile updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress) + } + Log.d("updateProfile patch 2") + } + } + Log.d("updateProfile go update") + profileManager.update(profile.uuid) + } + Log.d("gogogogogo end") + } + } + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun initRefreshLayout() { + swipeLayout.setColorSchemeColors(Color.rgb(47, 223, 189)) + swipeLayout.setOnRefreshListener(object : OnRefreshListener { + override fun onRefresh() { + if (testRuning) { + RxToast.info("正在测速中."); + swipeLayout.isRefreshing = false + return + } + com.cncat.vpn.common.log.Log.d("onRefresh") +// getNodesStatus(); +// changeNodeVM.getAirNodes() + swipeLayout.isRefreshing = true + updateProfile(false) + com.cncat.vpn.common.log.Log.d("onRefresh end") + swipeLayout.isRefreshing = false + } + }) + } + + override fun onStart() { + super.onStart() + UIMainActivity.subUrl?.let { + nowSubUrl = it + } + doProfile() + + } + + fun doProfile() { + if (TextUtils.isEmpty(cacheNodeStr)) { + + } + showLoading("正在获取...", this@ChangeNodeTzActivity) + startTimer() + updateProfile(false) + + } + + private fun changeSubUrl(originalUrl: String, newUrl: String) { + if(!originalUrl.isNullOrEmpty()&&!newUrl.isNullOrEmpty()){ + nowSubUrl = originalUrl.replace(Regex("https://[^/]+/"), "$newUrl/") + MMKV.defaultMMKV().encode(BZYConstants.PROFILE_SUB_URL, nowSubUrl) + } + } + + val reloadLock = Semaphore(10) + private fun setPing() { + if (!NewAccFragment.clashRunning) { + RxToast.info("请先开启加速后,再进行测试."); + return + } + if (testRuning) { + RxToast.info("正在测速中."); + return + } + testRuning = true + updateMoreBar("测速中") + launch(Dispatchers.IO) { + var group = reloadLock.withPermit { + UIMainActivity.clashBinder?.let { cb -> + var names = cb.queryProxyGroupNames(false) + if (names.isNotEmpty()) { + cb.healthCheck(names[0]) + } + delay(1000) + cb.queryProxyGroup(names[0], uiStore.proxySort); + } + } + testRuning = false + runOnUiThread { updateMoreBar("线路测速") } + var newDatas = mutableListOf(); + group?.proxies?.forEach { proxy -> + Log.d("node==>${proxy}") + if (currentNode?.isNotEmpty() == true) { + for (nodeItem: ClashNodebBean in currentNode!!) { + if (nodeItem.name == proxy.name) { + if (proxy.name != "自动选择") { + nodeItem.delay = proxy.delay; + } + Log.d("nodeItem==>${nodeItem}") + newDatas.add(nodeItem) + return@forEach + } + } + } + } + if (newDatas.isNotEmpty()) { + setNewData(newDatas) + } + } + } + + + private fun setNewData(nodes: MutableList?) { + runOnUiThread { + if (nodes != null) { + nodeListAdapter.setNewInstance(nodes) + var selected_name = + MMKV.defaultMMKV().decodeString(BZYConstants.NODE_SELECTED_NAME_KEY, ""); + for ((index, node) in nodes.withIndex()) { + if (node.name == selected_name) { + nodeListAdapter.selectedPosition = index +// checkedNode = node + } + } + nodeListAdapter.notifyDataSetChanged() + } + } + } + + var nodeListAdapter: NodeTzListAdapter = NodeTzListAdapter(R.layout.node_tz_list_item_layout) + private fun initAdapter() { + nodeListRv.layoutManager = LinearLayoutManager(this) + nodeListRv.adapter = nodeListAdapter + nodeListAdapter.selectedPosition + nodeListAdapter.setOnItemClickListener { baseQuickAdapter: BaseQuickAdapter<*, *>, view: View, position: Int -> + (baseQuickAdapter.getItem(position) as ClashNodebBean).let { profile -> + com.cncat.vpn.common.log.Log.i("select_node : ${profile.name}") +// checkedNode = profile + MMKV.defaultMMKV().encode(BZYConstants.NODE_SELECTED_NAME_KEY, profile.name) + nodeListAdapter.notifyItemChanged(nodeListAdapter.selectedPosition) + nodeListAdapter.selectedPosition = + if (nodeListAdapter.selectedPosition == position) -1 else position + nodeListAdapter.notifyItemChanged(position) +// launch { +// withClash { +// val names = queryProxyGroupNames(false) +// val mode = queryOverride(Clash.OverrideSlot.Session).mode +// com.cncat.vpn.common.log.Log.d("names 222==>${names}, mode==>$mode") +// names?.let { ns -> +// if (ns.isNotEmpty()) { +// patchSelector(ns[0], profile.name) +// } +// } +// } +// } + launch(Dispatchers.IO) { + val intent = Intent() + intent.putExtra(BZYConstants.MMKV_KEY_SELECT_NODE_NAME, "自动选择") + intent.putExtra(BZYConstants.EXTRA_KEY_IS_RUNING, is_runing) + setResult(CHECK_NODE_RESULT_CODE, intent) + finish() + } + } + } + } + + private fun createProfile() { + launch(Dispatchers.IO) { + UIMainActivity.profileBinder?.let { pro -> + uuid?.let { uu -> + pro.delete(uu) + delay(500) + setSub2(pro, UIMainActivity.subUrl) + } + } + } + } + + public suspend fun setSub2(pm: IProfileManager, url: String?) { +// com.cncat.vpn.common.log.Log.d("setSub2.... url==>$url") + if (TextUtils.isEmpty(url)) { + 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@ChangeNodeTzActivity.applicationContext) + } + com.cncat.vpn.common.log.Log.d("setSub2 4") + pro?.let { + com.cncat.vpn.common.log.Log.d("setSub2 pro 已存在 ==>") +// pm.setActive(it) + + com.cncat.vpn.common.log.Log.d("setSub2 setActive end") + } ?: run { + var uuid: UUID = pm.create( + Profile.Type.Url, + Conf.getClashConfName(this@ChangeNodeTzActivity.applicationContext) + ) + delay(500) + pm.queryByUUID(uuid)?.let { qPro -> + 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", + url!!, + 1800000L + ) +// coroutineScope { + pm.commit(qPro.uuid) { status -> + android.util.Log.d( + Conf.TAG, + "new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress + ) + } +// } + } + } + } + + var isCreate: Boolean = false + private var timerJob: Job? = null + private fun startTimer() { + GetNodeTimeOutNum = 15 + timerJob = launch { + repeat(16) { + Log.d("GetNodeTimeOutNum==>$GetNodeTimeOutNum") + if (GetNodeTimeOutNum == 0) { + hideLoading() + Log.d("stopTimer...") + RxToast.error("获取节点失败...请尝试切换其他地址") + showDomainList() + timerJob?.cancel() +// delay(1000) +// this@ChangeNodeActivity.finish() + + } + GetNodeTimeOutNum-- + delay(1000) + } + } + } + + var dialogDoMainChoose: DialogDoMainChoose? = null + private fun showDomainList() { + try { + SplashHelper(changeNodeVM).getHostWithFallback { success -> + MainScope().launch { + + if (success) { + if (dialogDoMainChoose == null) { + dialogDoMainChoose = DialogDoMainChoose(this@ChangeNodeTzActivity) + } + if (dialogDoMainChoose?.isShowing == false) { + dialogDoMainChoose?.setOnTryButtonListener(object : + DialogDoMainChoose.OnTryButtonListener { + override fun tryButton() { + saveSubUrl() + doProfile() + dialogDoMainChoose?.dismiss() + } + + override fun cancel() { + com.cncat.vpn.common.log.Log.d("tryButton CHECK_LOGIN cancel") + + dialogDoMainChoose?.dismiss() + } + }) + dialogDoMainChoose?.setOnListItemListener(object : + DialogDoMainChoose.OnListItemListener { + override fun listItemClick() { + saveSubUrl() + MainApplication.restartApp(this@ChangeNodeTzActivity, object : + MainApplication.OnRestartButtonListener { + + override fun enterButton() { + + } + + override fun cancelButton() { + doProfile() + dialogDoMainChoose?.dismiss() + } + + }) + } + }) + dialogDoMainChoose?.show() + } + } + } + } + + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun saveSubUrl() { + var currentHost = MMKV.defaultMMKV() + .decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, "") +// com.cncat.vpn.common.log.Log.d("tryButton currentHost==>${currentHost}") + var oldUrl = nowSubUrl + currentHost?.let { changeSubUrl(oldUrl, it) } + } + + private fun stopTimer() { + timerTask?.cancel() + timer?.purge() + timer?.cancel() + timerTask = null + timer = null + } + + override fun onClick(p0: View?) { + when (p0?.id) { + R.id.tv_more -> { + setPing() + } + + else -> { + + } + } + } + + +} diff --git a/app/src/main/java/com/yingmao/clash/act/LoginActivity.kt b/app/src/main/java/com/yingmao/clash/act/LoginActivity.kt index f3f55d0..2bc569a 100644 --- a/app/src/main/java/com/yingmao/clash/act/LoginActivity.kt +++ b/app/src/main/java/com/yingmao/clash/act/LoginActivity.kt @@ -206,6 +206,14 @@ class LoginActivity : BaseActivity(), View.OnClickListener { dialogDoMainChoose?.dismiss() } }) + dialogDoMainChoose?.setOnListItemListener(object : + DialogDoMainChoose.OnListItemListener { + override fun listItemClick() { + loginViewMode.login(username_encrypt, password_encrypt,user_oaid) + + } + + }) dialogDoMainChoose?.show() } } else { 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 7913679..0143ca1 100644 --- a/app/src/main/java/com/yingmao/clash/act/SplashActivity.kt +++ b/app/src/main/java/com/yingmao/clash/act/SplashActivity.kt @@ -32,9 +32,6 @@ import com.bumptech.glide.request.transition.Transition import com.cncat.vpn.service.ClashManager import com.cncat.vpn.service.remote.IClashManager import com.cncat.vpn.service.remote.wrap -import com.fm.openinstall.OpenInstall -import com.fm.openinstall.listener.AppWakeUpAdapter -import com.fm.openinstall.model.AppData import com.google.gson.JsonObject import com.orhanobut.logger.Logger import com.tencent.mmkv.MMKV @@ -254,35 +251,35 @@ class SplashActivity : BaseActivity() { // println("Sgtr==>$Sgtr") - OpenInstall.getWakeUp(intent, wakeUpAdapter) - OpenInstall.getInstall { appData, error -> - var appData = appData - if (error != null && error.shouldRetry()) { - // 获取数据异常,可以尝试重新获取 - } else { - if (appData == null) appData = AppData() - val channelCode = appData.getChannel() // 获取渠道编号参数 - val bindData = appData.getData() // 获取自定义参数 - Log.d("OpenInstall", "getInstall : channelCode = $channelCode"+"bindData::"+bindData) - } - } - } - private var wakeUpAdapter: AppWakeUpAdapter = object : AppWakeUpAdapter() { - override fun onWakeUp(appData: AppData) { - // 打印数据便于调试 - Log.d("OpenInstall", "getWakeUp : wakeupData = $appData") - // 获取渠道编号参数 - val channelCode = appData.getChannel() - // 获取自定义参数 - val bindData = appData.getData() - Log.d("OpenInstall", "channelCode : bindData = $channelCode"+"bindData::"+bindData) - } +// OpenInstall.getWakeUp(intent, wakeUpAdapter) +// OpenInstall.getInstall { appData, error -> +// var appData = appData +// if (error != null && error.shouldRetry()) { +// // 获取数据异常,可以尝试重新获取 +// } else { +// if (appData == null) appData = AppData() +// val channelCode = appData.getChannel() // 获取渠道编号参数 +// val bindData = appData.getData() // 获取自定义参数 +// Log.d("OpenInstall", "getInstall : channelCode = $channelCode"+"bindData::"+bindData) +// } +// } } +// private var wakeUpAdapter: AppWakeUpAdapter = object : AppWakeUpAdapter() { +// override fun onWakeUp(appData: AppData) { +// // 打印数据便于调试 +// Log.d("OpenInstall", "getWakeUp : wakeupData = $appData") +// // 获取渠道编号参数 +// val channelCode = appData.getChannel() +// // 获取自定义参数 +// val bindData = appData.getData() +// Log.d("OpenInstall", "channelCode : bindData = $channelCode"+"bindData::"+bindData) +// } +// } override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) // 此处要调用,否则App在后台运行时,会无法获取 - OpenInstall.getWakeUp(intent, wakeUpAdapter) +// OpenInstall.getWakeUp(intent, wakeUpAdapter) } private fun setLocalLanguage() { var defLan = "" @@ -763,6 +760,14 @@ class SplashActivity : BaseActivity() { dialogDoMainChoose=null } }) + dialogDoMainChoose?.setOnListItemListener(object : + DialogDoMainChoose.OnListItemListener { + override fun listItemClick() { + doRegisterByEncryption() + dialogDoMainChoose?.dismiss() + } + + }) dialogDoMainChoose?.show() } } catch (e: Exception) { @@ -830,6 +835,14 @@ class SplashActivity : BaseActivity() { dialogDoMainChoose?.dismiss() } }) + dialogDoMainChoose?.setOnListItemListener(object : + DialogDoMainChoose.OnListItemListener { + override fun listItemClick() { + splashAtyVM.checkLogin() + + } + + }) dialogDoMainChoose?.show() } } 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 ea7cee6..05b2c25 100644 --- a/app/src/main/java/com/yingmao/clash/app/MainApplication.kt +++ b/app/src/main/java/com/yingmao/clash/app/MainApplication.kt @@ -150,8 +150,8 @@ class MainApplication : Application() { applicationContext, "pk_live_51Nkl6vLWP3xWXY4LfXtdMtXzHazv6pav2rH1p1BfICeh5meGGjglExiw4GgmSzWO7NptEM1c549Fe11zRy9nCfxs009zEwLpXP" ) - OpenInstall.preInit(applicationContext) - OpenInstall.init(applicationContext) +// OpenInstall.preInit(applicationContext) +// OpenInstall.init(applicationContext) } fun updateActivity(language: String, locale: Locale) { 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 517615e..1c30731 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 @@ -35,10 +35,12 @@ import com.cncat.vpn.core.Clash import com.cncat.vpn.core.model.TunnelState import com.orhanobut.logger.Logger import com.tencent.mmkv.MMKV +import com.yingmao.clash.BuildConfig import com.yingmao.clash.R import com.yingmao.clash.act.ActivityActivity import com.yingmao.clash.act.BandPhoneActivity import com.yingmao.clash.act.ChangeNodeActivity +import com.yingmao.clash.act.ChangeNodeTzActivity import com.yingmao.clash.act.ConnectionModeActivity import com.yingmao.clash.act.LoginActivity import com.yingmao.clash.act.UIMainActivity @@ -207,7 +209,12 @@ class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatcher } return@setOnClickListener } - val intent = Intent(CommonUtils.getApp(), ChangeNodeActivity::class.java) + var intent: Intent? = null + if (BuildConfig.is_tz) { + intent = Intent(CommonUtils.getApp(), ChangeNodeTzActivity::class.java) + } else { + intent = Intent(CommonUtils.getApp(), ChangeNodeActivity::class.java) + } if (!TextUtils.isEmpty(newUuid)) { intent.putExtra(BZYConstants.MMKV_KEY_CURRENT_NODE, newUuid) intent.putExtra(BZYConstants.EXTRA_KEY_IS_RUNING, clashRunning) @@ -265,10 +272,13 @@ class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatcher setExpireDate() setProxyModeView(newMainActGlo) + var selected_name = MMKV.defaultMMKV().decodeString(BZYConstants.NODE_SELECTED_NAME_KEY, ""); if (!TextUtils.isEmpty(selected_name)) { - setNodeNameAndImg(selected_name!!) + if (!BuildConfig.is_tz){ + setNodeNameAndImg(selected_name!!) + } } } 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 b515789..4ddc416 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 @@ -862,6 +862,21 @@ class RechargeFragment : BaseFragment() { dialogDoMainChoose?.dismiss() } }) + dialogDoMainChoose?.setOnListItemListener(object : + DialogDoMainChoose.OnListItemListener { + override fun listItemClick() { + val username = MMKV.defaultMMKV() + .decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME, "")!! + + val phToken = MMKV.defaultMMKV() + .decodeString(BZYConstants.MMKV_KEY_PH_TOKEN, "")!! +// viewModel.getPointCardSurplus(username, phToken) + val userId = MMKV.defaultMMKV() + .decodeString(BZYConstants.MMKV_KEY_USER_ID)!! + viewModel.getPhRechargeInfo(username, phToken, userId) + } + + }) dialogDoMainChoose?.show() } } 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 4999b04..7ba03e6 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 @@ -326,6 +326,7 @@ class SettingFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatc if (TextUtils.isEmpty(subUrl)) { return@setOnClickListener } + cleanNodeMmkv() showLoading(resources.getString(R.string.UnderRepair), requireActivity()) launch(Dispatchers.IO) { @@ -485,7 +486,11 @@ class SettingFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatc } } - + private fun cleanNodeMmkv(){ + MMKV.defaultMMKV().removeValueForKey(BZYConstants.NODE_SELECTED_NAME_KEY) + MMKV.defaultMMKV().removeValueForKey(BZYConstants.NODE_All_ITEM_NAME_KEY) + MMKV.defaultMMKV().removeValueForKey(BZYConstants.PROFILE_SUB_URL) + } var dialogDoMainChoose: DialogDoMainChoose? = null @@ -617,6 +622,7 @@ class SettingFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatc 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) Log.d("cleanUserInfo clashRunning==>${clashRunning}") if (clashRunning) { fragments.filterIsInstance().forEach { it.stopClash() } @@ -876,7 +882,6 @@ class SettingFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatc Log.d("setSub2 delete ==>${itemPro.name}") pm.delete(itemPro.uuid) } - } val pro = pm.queryActive() diff --git a/app/src/main/java/com/yingmao/clash/view/adapter/NodeListAdapter.kt b/app/src/main/java/com/yingmao/clash/view/adapter/NodeListAdapter.kt index 06e5654..8f2df9f 100644 --- a/app/src/main/java/com/yingmao/clash/view/adapter/NodeListAdapter.kt +++ b/app/src/main/java/com/yingmao/clash/view/adapter/NodeListAdapter.kt @@ -38,11 +38,7 @@ class NodeListAdapter(layoutResId: Int) : nodeListItem.isSelected = false nodeCheckMrb.isSelected = false } -// if (item.pingTime!! > 1) { -// holder.setText(R.id.tv_ping_time, "${item.pingTime}ms") -// } else { -// holder.setText(R.id.tv_ping_time, "超时") -// } + val nodeNameTv = holder.getView(R.id.node_list_item_tv_node_name) nodeNameTv.text = item.name @@ -50,17 +46,21 @@ class NodeListAdapter(layoutResId: Int) : if(holder.layoutPosition==0){ signal.visibility=View.GONE }else{ + signal.visibility=View.VISIBLE if (item.delay > 0) { if (item.delay >= 65535) { item.delay = Utils.generateRandomTwoDigitNumber(99, 300) signal.setImageResource(R.drawable.ic_wifi_generally) + holder.setText(R.id.tv_ping_time, "超时") } else { item.delay = Utils.generateRandomTwoDigitNumber(10, 60) signal.setImageResource(R.drawable.ic_wifi_powerful) + holder.setText(R.id.tv_ping_time, "${item.delay}ms") } } else { signal.setImageResource(R.drawable.ic_wifi_week) + holder.setText(R.id.tv_ping_time, "超时") } } diff --git a/app/src/main/java/com/yingmao/clash/view/adapter/NodeTzListAdapter.kt b/app/src/main/java/com/yingmao/clash/view/adapter/NodeTzListAdapter.kt new file mode 100644 index 0000000..85b1201 --- /dev/null +++ b/app/src/main/java/com/yingmao/clash/view/adapter/NodeTzListAdapter.kt @@ -0,0 +1,66 @@ +package com.yingmao.clash.view.adapter + +import android.annotation.SuppressLint +import android.text.TextUtils +import android.view.View +import android.widget.ImageView +import android.widget.RelativeLayout +import android.widget.TextView +import androidx.appcompat.widget.AppCompatImageView +import androidx.constraintlayout.widget.ConstraintLayout +import com.bumptech.glide.util.Util + +import com.chad.library.adapter.base.BaseQuickAdapter +import com.chad.library.adapter.base.module.LoadMoreModule +import com.chad.library.adapter.base.viewholder.BaseViewHolder + +import com.google.android.material.radiobutton.MaterialRadioButton +import com.yingmao.clash.R +import com.yingmao.clash.entity.ClashNodebBean +import com.cncat.vpn.service.model.Profile +import com.yingmao.clash.util.Utils + +class NodeTzListAdapter(layoutResId: Int) : + BaseQuickAdapter(layoutResId), LoadMoreModule { + + var selectedPosition: Int = 0 + var index:Int=1 + + @SuppressLint("SetTextI18n") + override fun convert(holder: BaseViewHolder, item: ClashNodebBean) { + + val nodeListItem = holder.getView(R.id.rl_node_list_item) + val nodeCheckMrb = holder.getView(R.id.mrb_node_checked) + if (holder.layoutPosition == selectedPosition) { + nodeListItem.isSelected = true + nodeCheckMrb.isSelected = true + } else { + nodeListItem.isSelected = false + nodeCheckMrb.isSelected = false + } + val nodeNameTv = holder.getView(R.id.node_list_item_tv_node_name) + if (holder.layoutPosition==0){ + nodeNameTv.text = item.name + }else { + nodeNameTv.text = "线路${holder.layoutPosition + 1}" + } + val signal = holder.getView(R.id.ivWifi) + if(holder.layoutPosition==0){ + signal.visibility=View.GONE + }else{ + signal.visibility=View.VISIBLE + if (item.delay > 0) { + if (item.delay >= 65535) { + item.delay = Utils.generateRandomTwoDigitNumber(99, 300) + signal.setImageResource(R.drawable.ic_wifi_generally) + } else { + item.delay = Utils.generateRandomTwoDigitNumber(10, 60) + signal.setImageResource(R.drawable.ic_wifi_powerful) + } + } else { + signal.setImageResource(R.drawable.ic_wifi_week) + } + } + index++ + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_change_node.xml b/app/src/main/res/layout/activity_change_node.xml index f617ad3..dfc47c4 100644 --- a/app/src/main/res/layout/activity_change_node.xml +++ b/app/src/main/res/layout/activity_change_node.xml @@ -39,7 +39,19 @@ android:text="@string/LineSwitching" android:textSize="18sp" /> + + tools:ignore="ContentDescription" /> - - - - - - - - - + + + android:background="@drawable/home_node_img_bg" + android:clickable="false" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" /> \ No newline at end of file diff --git a/app/src/main/res/layout/node_tz_list_item_layout.xml b/app/src/main/res/layout/node_tz_list_item_layout.xml new file mode 100644 index 0000000..182b3ac --- /dev/null +++ b/app/src/main/res/layout/node_tz_list_item_layout.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index 254552f..50e0052 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -350,4 +350,5 @@ Service Description\n Popular Application Navigation Suggest restarting Restart + Speed test \ 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 46d33db..5d9881f 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -340,4 +340,5 @@ 熱門應用導航 "建議重啓 " "重啓 " + 線路測速 \ 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 f1260d4..cb6a362 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -339,4 +339,5 @@ 熱門應用導航 "建議重啓 " "重啓 " + 線路測速 \ 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 102b4a4..fd4a078 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -358,4 +358,5 @@ 热门应用导航 建议重启 重启 + 线路测速 \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index e41146d..53c2482 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -71,8 +71,8 @@ subprojects { minSdk = 21 //noinspection ExpiredTargetSdkVersion targetSdk = 34 - versionName = "1.0.3.8" - versionCode = 1038 + versionName = "1.0.3.9" + versionCode = 1039 resValue("string", "release_name", "v$versionName") resValue("integer", "release_code", "$versionCode") externalNativeBuild {