1.添加节点测速 2.添加太子定制节点页面 3.修复部分界面选择备用源异常bug

This commit is contained in:
cyh 2025-04-27 16:21:27 +08:00
parent 65f17fba52
commit 6402e1793e
19 changed files with 881 additions and 68 deletions

View File

@ -165,6 +165,10 @@
android:name=".act.ChangeNodeActivity"
android:process=":background"
android:screenOrientation="portrait" />
<activity
android:name=".act.ChangeNodeTzActivity"
android:process=":background"
android:screenOrientation="portrait" />
<activity
android:name=".act.ForGetPwdActivity"
android:process=":background"

View File

@ -39,6 +39,7 @@ 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.fragment.home.HomeFragment
import com.yingmao.clash.util.Utils
import com.yingmao.clash.view.RxToast
import com.yingmao.clash.view.adapter.NodeListAdapter
@ -66,6 +67,7 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
private lateinit var swipeLayout: SwipeRefreshLayout
private lateinit var changeNodeVM: ChangeNodeVM
private lateinit var nodeListRv: RecyclerView
private lateinit var nodeItemTest: TextView
private var names: List<String>? = 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<ClashNodebBean>();
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()
}

View File

@ -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<ClashNodebBean> = mutableListOf()
// var clash: ClashManager? = null
}
private lateinit var swipeLayout: SwipeRefreshLayout
private lateinit var changeNodeVM: ChangeNodeVM
private lateinit var nodeListRv: RecyclerView
private var names: List<String>? = 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<ImageView>(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<ClashNodebBean> {
var mList: MutableList<ClashNodebBean> = 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<Map<String,Any>>("")
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<MutableList<ClashNodebBean>>() {}.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<IRemoteService>()
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<ClashNodebBean>();
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<ClashNodebBean>?) {
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 -> {
}
}
}
}

View File

@ -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 {

View File

@ -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()
}
}

View File

@ -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) {

View File

@ -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!!)
}
}
}

View File

@ -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()
}
}

View File

@ -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<HomeFragment>().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()

View File

@ -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<TextView>(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, "超时")
}
}

View File

@ -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<ClashNodebBean, BaseViewHolder>(layoutResId), LoadMoreModule {
var selectedPosition: Int = 0
var index:Int=1
@SuppressLint("SetTextI18n")
override fun convert(holder: BaseViewHolder, item: ClashNodebBean) {
val nodeListItem = holder.getView<ConstraintLayout>(R.id.rl_node_list_item)
val nodeCheckMrb = holder.getView<AppCompatImageView>(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<TextView>(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<ImageView>(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++
}
}

View File

@ -39,7 +39,19 @@
android:text="@string/LineSwitching"
android:textSize="18sp"
/>
<TextView
android:id="@+id/node_item_test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/orange_FF9C00"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:text="@string/node_item_test"
android:layout_marginEnd="@dimen/dp_10"
android:textSize="18sp"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/node_user_traffic"

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rl_node_list_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -18,12 +18,11 @@
android:layout_marginStart="21dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
tools:ignore="ContentDescription"
android:src="@drawable/flag_china"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:src="@drawable/flag_china"
/>
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/node_list_item_tv_node_name"
@ -32,22 +31,26 @@
android:layout_centerVertical="true"
android:layout_marginStart="8dp"
android:layout_toEndOf="@id/node_list_item_iv_country"
android:text="直连香港"
android:text=""
android:textColor="#0136CB"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="@+id/node_list_item_iv_country"
app:layout_constraintStart_toEndOf="@+id/node_list_item_iv_country"
app:layout_constraintTop_toTopOf="@+id/node_list_item_iv_country" />
<!-- <TextView-->
<!-- android:id="@+id/tv_ping_time"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_centerVertical="true"-->
<!-- android:layout_marginRight="@dimen/dp_10"-->
<!-- android:layout_toLeftOf="@id/mrb_node_checked"-->
<!-- android:textColor="@color/white"-->
<!-- android:textSize="13sp" />-->
<TextView
android:id="@+id/tv_ping_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginEnd="@dimen/dp_15"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@+id/mrb_node_checked"
android:textColor="#0136CB"
app:layout_constraintBottom_toBottomOf="parent"
android:textSize="13sp"
tools:ignore="MissingConstraints" />
<ImageView
android:id="@+id/ivWifi"
android:layout_width="wrap_content"
@ -65,11 +68,11 @@
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="@drawable/home_node_img_bg"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginEnd="21dp"
android:clickable="false" />
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" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/rl_node_list_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@drawable/home_node_bg"
android:clickable="true"
android:focusable="true">
<TextView
android:id="@+id/node_list_item_tv_node_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginStart="31dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:text="线路1"
android:textColor="#0136CB"
android:textSize="16sp"
/>
<ImageView
android:id="@+id/ivWifi"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dp"
android:src="@drawable/ic_wifi_powerful"
app:layout_constraintBottom_toBottomOf="@+id/node_list_item_tv_node_name"
app:layout_constraintStart_toEndOf="@+id/node_list_item_tv_node_name"
app:layout_constraintTop_toTopOf="@+id/node_list_item_tv_node_name" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/mrb_node_checked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="@drawable/home_node_img_bg"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginEnd="21dp"
android:clickable="false" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -350,4 +350,5 @@ Service Description\n
<string name="PopularApplicationsStr">Popular Application Navigation</string>
<string name="sure_restart">Suggest restarting</string>
<string name="restart">Restart</string>
<string name="node_item_test">Speed test</string>
</resources>

View File

@ -340,4 +340,5 @@
<string name="PopularApplicationsStr">熱門應用導航</string>
<string name="sure_restart">"建議重啓 "</string>
<string name="restart">"重啓 "</string>
<string name="node_item_test">線路測速</string>
</resources>

View File

@ -339,4 +339,5 @@
<string name="PopularApplicationsStr">熱門應用導航</string>
<string name="sure_restart">"建議重啓 "</string>
<string name="restart">"重啓 "</string>
<string name="node_item_test">線路測速</string>
</resources>

View File

@ -358,4 +358,5 @@
<string name="PopularApplicationsStr">热门应用导航</string>
<string name="sure_restart">建议重启</string>
<string name="restart">重启</string>
<string name="node_item_test">线路测速</string>
</resources>

View File

@ -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 {