parent
3d9c1b4585
commit
2feb4d7ead
|
|
@ -140,6 +140,10 @@
|
||||||
android:process=":background"
|
android:process=":background"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
/>
|
/>
|
||||||
|
<activity
|
||||||
|
android:name=".act.NodeGroupActivity"
|
||||||
|
android:process=":background"
|
||||||
|
android:screenOrientation="portrait" />
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="${applicationId}.fileprovider"
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
package com.yingmao.clash.act
|
package com.yingmao.clash.act
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
|
|
@ -9,12 +12,15 @@ import android.widget.TextView
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.appcompat.widget.AppCompatImageView
|
import androidx.appcompat.widget.AppCompatImageView
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.afollestad.materialdialogs.customview.customView
|
import com.afollestad.materialdialogs.customview.customView
|
||||||
import com.afollestad.materialdialogs.customview.getCustomView
|
import com.afollestad.materialdialogs.customview.getCustomView
|
||||||
import com.baidu.mobads.action.ActionType
|
import com.baidu.mobads.action.ActionType
|
||||||
import com.baidu.mobads.action.BaiduAction
|
import com.baidu.mobads.action.BaiduAction
|
||||||
|
import com.cncat.vpn.common.constants.Intents
|
||||||
import com.cncat.vpn.common.log.Log
|
import com.cncat.vpn.common.log.Log
|
||||||
import com.cncat.vpn.core.model.LogMessage
|
import com.cncat.vpn.core.model.LogMessage
|
||||||
import com.cncat.vpn.service.ClashManager
|
import com.cncat.vpn.service.ClashManager
|
||||||
|
|
@ -27,6 +33,7 @@ import com.cncat.vpn.service.remote.wrap
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
|
import com.google.gson.JsonParser
|
||||||
import com.orhanobut.logger.Logger
|
import com.orhanobut.logger.Logger
|
||||||
import com.tencent.mmkv.MMKV
|
import com.tencent.mmkv.MMKV
|
||||||
import com.yingmao.clash.BuildConfig
|
import com.yingmao.clash.BuildConfig
|
||||||
|
|
@ -117,6 +124,9 @@ class MainActivity : BaseActivity() {
|
||||||
var newMainActGlo: Boolean = false
|
var newMainActGlo: Boolean = false
|
||||||
var newUuid: String? = null
|
var newUuid: String? = null
|
||||||
var clashBinder: IClashManager? = null
|
var clashBinder: IClashManager? = null
|
||||||
|
private var mainBroadcastReceiver: BroadcastReceiver? = null
|
||||||
|
val trafficStatisticsData = MutableLiveData<String>()
|
||||||
|
|
||||||
suspend fun setSub2(url: String) {
|
suspend fun setSub2(url: String) {
|
||||||
profileBinder?.let { pm ->
|
profileBinder?.let { pm ->
|
||||||
pm.queryAll().forEach { itemPro ->
|
pm.queryAll().forEach { itemPro ->
|
||||||
|
|
@ -191,8 +201,51 @@ class MainActivity : BaseActivity() {
|
||||||
startLog()
|
startLog()
|
||||||
firstEntry()
|
firstEntry()
|
||||||
mainAtyVM.getExpensesRecord(mPageInfo)
|
mainAtyVM.getExpensesRecord(mPageInfo)
|
||||||
|
|
||||||
|
|
||||||
|
val intentFilter = IntentFilter(Intents.ACTION_NODE_LIST)
|
||||||
|
mainBroadcastReceiver = NodeListBR()
|
||||||
|
if (Build.VERSION.SDK_INT >= 34 && applicationInfo.targetSdkVersion >= 34) {
|
||||||
|
registerReceiver(
|
||||||
|
mainBroadcastReceiver,
|
||||||
|
intentFilter,
|
||||||
|
RECEIVER_EXPORTED
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
registerReceiver(
|
||||||
|
mainBroadcastReceiver,
|
||||||
|
intentFilter
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 userTraffic=serStore.userTraffic
|
||||||
|
Log.d("userTraffic::::${userTraffic}")
|
||||||
|
userTrafficMethod(userTraffic)
|
||||||
|
if (TextUtils.isEmpty(userTraffic)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun userTrafficMethod(userTraffic: String) {
|
||||||
|
val jo = JsonParser.parseString(userTraffic).asJsonObject
|
||||||
|
val t = jo.get("total").asLong
|
||||||
|
val d = jo.get("download").asLong
|
||||||
|
val u = jo.get("upload").asLong
|
||||||
|
val trafficUsedInGB = String.format("%.2f", (d + u) / 1024.0 / 1024.0 / 1024.0)
|
||||||
|
val trafficTolTelInGB = String.format("%.2f", t / 1024.0 / 1024.0 / 1024.0)
|
||||||
|
trafficStatisticsData.value = "流量统计:${trafficUsedInGB}GB / ${trafficTolTelInGB}GB"
|
||||||
|
}
|
||||||
private fun initData() {
|
private fun initData() {
|
||||||
clashBinder = MainApplication.getApp()?.let { ClashManager(it).wrap() as IClashManager }
|
clashBinder = MainApplication.getApp()?.let { ClashManager(it).wrap() as IClashManager }
|
||||||
profileBinder =
|
profileBinder =
|
||||||
|
|
@ -268,24 +321,24 @@ class MainActivity : BaseActivity() {
|
||||||
if (data.code != "1000") {
|
if (data.code != "1000") {
|
||||||
RxToast.error(resources.getString(R.string.NodeAcquisitionFailed) + "${data.msg}")
|
RxToast.error(resources.getString(R.string.NodeAcquisitionFailed) + "${data.msg}")
|
||||||
}
|
}
|
||||||
data.data.let { url ->
|
data.data.let { netSubUrl ->
|
||||||
android.util.Log.e("Data", "机场URL:=${url}")
|
if (netSubUrl.isNotEmpty()) {
|
||||||
if (url.isNotEmpty()) {
|
val proSubUrl =
|
||||||
//todo 判断订阅地址是否修改过,未修改就用接口返回的地址反之使用本地修改的地址
|
|
||||||
var pro_sub_url =
|
|
||||||
MMKV.defaultMMKV().decodeString(BZYConstants.PROFILE_SUB_URL, "")
|
MMKV.defaultMMKV().decodeString(BZYConstants.PROFILE_SUB_URL, "")
|
||||||
// Log.d("pro_sub_url==>${pro_sub_url}")
|
subUrl = if (!TextUtils.isEmpty(proSubUrl)) {
|
||||||
if (!TextUtils.isEmpty(pro_sub_url)) {
|
if (proSubUrl == netSubUrl) {
|
||||||
if (pro_sub_url == url) {
|
netSubUrl
|
||||||
subUrl = url
|
|
||||||
} else {
|
} else {
|
||||||
subUrl = pro_sub_url
|
proSubUrl
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
subUrl = url
|
netSubUrl
|
||||||
|
}
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
subUrl?.let {
|
||||||
|
Log.i("netSubUrl:${netSubUrl}::保存机场URL:=${proSubUrl}::subUrl:${subUrl}")
|
||||||
|
setSub2(it)
|
||||||
}
|
}
|
||||||
launch(Dispatchers.IO) {
|
|
||||||
subUrl?.let { setSub2(it) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,395 @@
|
||||||
|
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.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 com.cncat.vpn.common.constants.Intents
|
||||||
|
import com.cncat.vpn.common.log.Log
|
||||||
|
import com.cncat.vpn.service.model.Profile
|
||||||
|
import com.cncat.vpn.service.remote.IRemoteService
|
||||||
|
import com.google.gson.Gson
|
||||||
|
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.MainActivity.Companion.profileBinder
|
||||||
|
import com.yingmao.clash.act.MainActivity.Companion.setSub2
|
||||||
|
import com.yingmao.clash.act.MainActivity.Companion.subUrl
|
||||||
|
import com.yingmao.clash.app.MainApplication
|
||||||
|
import com.yingmao.clash.base.BaseActivity
|
||||||
|
import com.yingmao.clash.conf.BZYConstants
|
||||||
|
import com.yingmao.clash.conf.Conf
|
||||||
|
import com.yingmao.clash.entity.NodeGroupItem
|
||||||
|
import com.yingmao.clash.fragment.home.HomeFragment
|
||||||
|
import com.yingmao.clash.fragment.home.HomeFragment.Companion.CHECK_NODE_REQUEST_CODE
|
||||||
|
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.Job
|
||||||
|
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<NodeGroupItem> = mutableListOf()
|
||||||
|
private lateinit var swipeLayout: SwipeRefreshLayout
|
||||||
|
private lateinit var changeNodeVM: ChangeNodeVM
|
||||||
|
private lateinit var nodeListRv: RecyclerView
|
||||||
|
private lateinit var aiBack: AppCompatImageView
|
||||||
|
private var broadcastReceiver: BroadcastReceiver? = null
|
||||||
|
private var cacheNodeStr: String? = ""
|
||||||
|
private lateinit var userTrafficTv: TextView
|
||||||
|
private var uuid: UUID? = null
|
||||||
|
var nodeListAdapter: NodeGroupAdapter = NodeGroupAdapter()
|
||||||
|
private var timerJob: Job? = null
|
||||||
|
|
||||||
|
val remote = Resource<IRemoteService>()
|
||||||
|
var getNodeTimeOutNum = 5
|
||||||
|
var isRunning = false
|
||||||
|
var nowSubUrl: String = ""
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_change_node)
|
||||||
|
changeNodeVM = ViewModelProvider(this)[ChangeNodeVM::class.java]
|
||||||
|
initView()
|
||||||
|
initData()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBackPressed() {
|
||||||
|
intent.putExtra(BZYConstants.EXTRA_KEY_IS_RUNING, isRunning)
|
||||||
|
setResult(CHECK_NODE_REQUEST_CODE, intent)
|
||||||
|
super.onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initData() {
|
||||||
|
subUrl?.let {
|
||||||
|
nowSubUrl = 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,
|
||||||
|
RECEIVER_EXPORTED
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
registerReceiver(
|
||||||
|
broadcastReceiver,
|
||||||
|
intentFilter
|
||||||
|
)
|
||||||
|
}
|
||||||
|
doProfile()
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n", "NotifyDataSetChanged")
|
||||||
|
private fun initView() {
|
||||||
|
aiBack = findViewById(R.id.aiBack)
|
||||||
|
swipeLayout = findViewById(R.id.swipeLayout)
|
||||||
|
nodeListRv = findViewById(R.id.rv_node_list)
|
||||||
|
userTrafficTv= findViewById(R.id.node_user_traffic)
|
||||||
|
aiBack.setOnClickListener {
|
||||||
|
onBackPressed()
|
||||||
|
}
|
||||||
|
swipeLayout.setColorSchemeColors(Color.rgb(47, 223, 189))
|
||||||
|
swipeLayout.setOnRefreshListener {
|
||||||
|
swipeLayout.isRefreshing = true
|
||||||
|
updateProfile(false)
|
||||||
|
swipeLayout.isRefreshing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeListRv.layoutManager = LinearLayoutManager(this)
|
||||||
|
nodeListRv.adapter=nodeListAdapter
|
||||||
|
|
||||||
|
nodeListAdapter.setListener(object : NodeGroupAdapter.ItemClickListener{
|
||||||
|
override fun onItemClick(nodeStr: String, isPosition: Int) {
|
||||||
|
MMKV.defaultMMKV().encode(BZYConstants.NODE_SELECTED_NAME_KEY, nodeStr)
|
||||||
|
val intent = Intent()
|
||||||
|
intent.putExtra(BZYConstants.MMKV_KEY_SELECT_NODE_NAME, nodeStr)
|
||||||
|
intent.putExtra(BZYConstants.EXTRA_KEY_IS_RUNING, isRunning)
|
||||||
|
setResult(CHECK_NODE_REQUEST_CODE, intent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
// 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<NodeGroupItem> {
|
||||||
|
val mList: MutableList<NodeGroupItem> = 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
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
hideLoading()
|
||||||
|
timerJob?.cancel()
|
||||||
|
val json = serStore.nodes
|
||||||
|
val trsss=serStore.userTraffic
|
||||||
|
Log.d("AAAAAAAAAAAAAAAAAAAA${trsss}")
|
||||||
|
if (TextUtils.isEmpty(json)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
MMKV.defaultMMKV().encode(BZYConstants.PROFILE_SUB_URL, nowSubUrl)
|
||||||
|
//缓存节点
|
||||||
|
MMKV.defaultMMKV().encode(BZYConstants.NODE_All_ITEM_NAME_KEY, json)
|
||||||
|
currentNode.clear()
|
||||||
|
currentNode = getNodesInfo(json)
|
||||||
|
setNewData(currentNode)
|
||||||
|
swipeLayout.isRefreshing = false
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
broadcastReceiver?.let {
|
||||||
|
unregisterReceiver(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
isRunning = intent.getBooleanExtra(BZYConstants.EXTRA_KEY_IS_RUNING, false)
|
||||||
|
}
|
||||||
|
private fun updateProfile(isDelete: Boolean) {
|
||||||
|
try {
|
||||||
|
launch(Dispatchers.IO) {
|
||||||
|
profileBinder?.let { profileManager ->
|
||||||
|
var mProfile: Profile? = null
|
||||||
|
Log.d("queryAll().size ==>${profileManager.queryAll().size}")
|
||||||
|
profileManager.queryAll().forEach { it_pf ->
|
||||||
|
val confName =
|
||||||
|
Conf.getClashConfName(this@NodeGroupActivity.applicationContext)
|
||||||
|
Log.d(" it_pf.name ==>${it_pf.name}, confName==>${confName}")
|
||||||
|
if (confName == it_pf.name) {
|
||||||
|
mProfile = it_pf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mProfile == null) {
|
||||||
|
//为空的情况下选择第一个
|
||||||
|
profileManager.queryAll().forEach { profile ->
|
||||||
|
mProfile = profile
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mProfile?.let { profile ->
|
||||||
|
uuid = profile.uuid
|
||||||
|
if (isDelete) {
|
||||||
|
MMKV.defaultMMKV()
|
||||||
|
.removeValueForKey(BZYConstants.NODE_All_ITEM_NAME_KEY)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
profileManager.setActive(profile)
|
||||||
|
if (!TextUtils.isEmpty(profile.source)) {
|
||||||
|
|
||||||
|
if (profile.source != nowSubUrl) {
|
||||||
|
profileManager.patch(
|
||||||
|
profile.uuid,
|
||||||
|
profile.name,
|
||||||
|
nowSubUrl,
|
||||||
|
1800000L
|
||||||
|
)
|
||||||
|
profileManager.commit(profile.uuid) { status ->
|
||||||
|
Log.d("updateProfile updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
profileManager.patch(
|
||||||
|
profile.uuid,
|
||||||
|
profile.name,
|
||||||
|
nowSubUrl,
|
||||||
|
1800000L
|
||||||
|
)
|
||||||
|
profileManager.commit(profile.uuid) { status ->
|
||||||
|
Log.d("updateProfile new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
profileManager.update(profile.uuid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun doProfile() {
|
||||||
|
showLoading("正在获取...", this@NodeGroupActivity)
|
||||||
|
startTimer()
|
||||||
|
launch(Dispatchers.IO) {
|
||||||
|
setSub2(nowSubUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun changeSubUrl(originalUrl: String, newUrl: String) {
|
||||||
|
if (originalUrl.isNotEmpty() && newUrl.isNotEmpty()) {
|
||||||
|
nowSubUrl = originalUrl.replace(Regex("https://[^/]+/"), "$newUrl/")
|
||||||
|
subUrl = nowSubUrl
|
||||||
|
MMKV.defaultMMKV().encode(BZYConstants.PROFILE_SUB_URL, nowSubUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun setNewData(nodes: MutableList<NodeGroupItem>?) {
|
||||||
|
runOnUiThread {
|
||||||
|
if (nodes != null) {
|
||||||
|
val proxies = nodes[0].proxies
|
||||||
|
nodeListAdapter.setDataMethod(proxies,this@NodeGroupActivity)
|
||||||
|
val selectedName =
|
||||||
|
MMKV.defaultMMKV().decodeString(BZYConstants.NODE_SELECTED_NAME_KEY, "")
|
||||||
|
for ((index, node) in proxies.withIndex()) {
|
||||||
|
if (node== selectedName) {
|
||||||
|
nodeListAdapter.selectedPosition = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nodeListAdapter.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun startTimer() {
|
||||||
|
getNodeTimeOutNum = 15
|
||||||
|
timerJob = launch {
|
||||||
|
repeat(16) {
|
||||||
|
Log.d("GetNodeTimeOutNum==>$getNodeTimeOutNum")
|
||||||
|
if (getNodeTimeOutNum == 0) {
|
||||||
|
hideLoading()
|
||||||
|
RxToast.error("获取节点失败...正在切换其他地址")
|
||||||
|
if (setNewData()) {
|
||||||
|
timerJob?.cancel()
|
||||||
|
MMKV.defaultMMKV()
|
||||||
|
.removeValueForKey(BZYConstants.NODE_All_ITEM_NAME_KEY)
|
||||||
|
saveSubUrl()
|
||||||
|
MainApplication.restartApp(this@NodeGroupActivity, object :
|
||||||
|
MainApplication.OnRestartButtonListener {
|
||||||
|
|
||||||
|
override fun enterButton() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cancelButton() {
|
||||||
|
doProfile()
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
timerJob?.cancel()
|
||||||
|
RxToast.error("获取全部线路失败...请切换网络重试")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getNodeTimeOutNum--
|
||||||
|
delay(1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun setNewData(): Boolean {
|
||||||
|
val mmkv = MMKV.defaultMMKV()
|
||||||
|
val originalUrl =
|
||||||
|
mmkv.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, BuildConfig.service_url)
|
||||||
|
var newUrlString = originalUrl
|
||||||
|
var isChange = false
|
||||||
|
val routerHost = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST,
|
||||||
|
kotlin.collections.HashSet()
|
||||||
|
)
|
||||||
|
val switchFinSet = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_Switch_Finsh_Set,
|
||||||
|
kotlin.collections.HashSet()
|
||||||
|
)
|
||||||
|
routerHost?.let {
|
||||||
|
if (it.isEmpty()) {
|
||||||
|
android.util.Log.d(Conf.TAG, "routerHost isEmpty")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
Log.d("switchFinshSet.size==>${switchFinSet?.size!!} , routerHost.size==>${routerHost.size}")
|
||||||
|
//次数已满
|
||||||
|
if (switchFinSet.size >= routerHost.size) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for (url in it) {
|
||||||
|
if (url == originalUrl) {
|
||||||
|
switchFinSet.add(url)
|
||||||
|
mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinSet)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switchFinSet.contains(url)) {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
isChange = true
|
||||||
|
android.util.Log.e("Retry", "切换到新url:$url")
|
||||||
|
newUrlString = url
|
||||||
|
switchFinSet.add(newUrlString)
|
||||||
|
mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinSet)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mmkv.encode(BZYConstants.MMKV_KEY_CURRENT_HOST, newUrlString)
|
||||||
|
|
||||||
|
}
|
||||||
|
return isChange
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveSubUrl() {
|
||||||
|
val currentHost = MMKV.defaultMMKV()
|
||||||
|
.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, "")
|
||||||
|
val oldUrl = nowSubUrl
|
||||||
|
currentHost?.let { changeSubUrl(oldUrl, it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -15,3 +15,10 @@ data class ClashNodebBean(
|
||||||
var delay: Int,
|
var delay: Int,
|
||||||
val udp: Boolean
|
val udp: Boolean
|
||||||
) : Parcelable,Serializable
|
) : Parcelable,Serializable
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class NodeGroupItem(
|
||||||
|
val name: String,
|
||||||
|
val type: String,
|
||||||
|
val proxies: MutableList<String>
|
||||||
|
) : Parcelable,Serializable
|
||||||
|
|
@ -32,6 +32,10 @@ import com.cncat.vpn.common.constants.Intents
|
||||||
import com.cncat.vpn.common.log.Log
|
import com.cncat.vpn.common.log.Log
|
||||||
import com.cncat.vpn.core.Clash
|
import com.cncat.vpn.core.Clash
|
||||||
import com.cncat.vpn.core.model.TunnelState
|
import com.cncat.vpn.core.model.TunnelState
|
||||||
|
import com.cncat.vpn.service.model.Profile
|
||||||
|
import com.cncat.vpn.service.store.ServiceStore
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.JsonParser
|
||||||
import com.orhanobut.logger.Logger
|
import com.orhanobut.logger.Logger
|
||||||
import com.tencent.mmkv.MMKV
|
import com.tencent.mmkv.MMKV
|
||||||
import com.yingmao.clash.R
|
import com.yingmao.clash.R
|
||||||
|
|
@ -43,10 +47,14 @@ import com.yingmao.clash.act.MainActivity.Companion.clashBinder
|
||||||
import com.yingmao.clash.act.MainActivity.Companion.isSubbed
|
import com.yingmao.clash.act.MainActivity.Companion.isSubbed
|
||||||
import com.yingmao.clash.act.MainActivity.Companion.newMainActGlo
|
import com.yingmao.clash.act.MainActivity.Companion.newMainActGlo
|
||||||
import com.yingmao.clash.act.MainActivity.Companion.newUuid
|
import com.yingmao.clash.act.MainActivity.Companion.newUuid
|
||||||
|
import com.yingmao.clash.act.MainActivity.Companion.profileBinder
|
||||||
|
import com.yingmao.clash.act.MainActivity.Companion.subUrl
|
||||||
|
import com.yingmao.clash.act.NodeGroupActivity
|
||||||
import com.yingmao.clash.conf.BZYConstants
|
import com.yingmao.clash.conf.BZYConstants
|
||||||
import com.yingmao.clash.conf.BZYConstants.Companion.ScreenFlag
|
import com.yingmao.clash.conf.BZYConstants.Companion.ScreenFlag
|
||||||
import com.yingmao.clash.conf.Conf
|
import com.yingmao.clash.conf.Conf
|
||||||
import com.yingmao.clash.entity.ClashNodebBean
|
import com.yingmao.clash.entity.ClashNodebBean
|
||||||
|
import com.yingmao.clash.entity.NodeGroupItem
|
||||||
import com.yingmao.clash.fragment.AccelerateViewModel
|
import com.yingmao.clash.fragment.AccelerateViewModel
|
||||||
import com.yingmao.clash.fragment.BaseFragment
|
import com.yingmao.clash.fragment.BaseFragment
|
||||||
import com.yingmao.clash.listener.AsyncCallBackListener
|
import com.yingmao.clash.listener.AsyncCallBackListener
|
||||||
|
|
@ -66,6 +74,7 @@ import com.yingmao.clash.view.dialog.RxDialogSureCancel
|
||||||
import com.yingmao.clash.webview.CustomerServiceWebView
|
import com.yingmao.clash.webview.CustomerServiceWebView
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -74,6 +83,7 @@ import okhttp3.Response
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
import kotlin.collections.get
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
import kotlin.coroutines.suspendCoroutine
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
|
|
@ -118,6 +128,8 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa
|
||||||
private lateinit var tvNodeName: TextView
|
private lateinit var tvNodeName: TextView
|
||||||
private lateinit var clLinks: ConstraintLayout
|
private lateinit var clLinks: ConstraintLayout
|
||||||
|
|
||||||
|
val serStore by lazy { ServiceStore(requireActivity()) }
|
||||||
|
private var currentNode: MutableList<NodeGroupItem> = mutableListOf()
|
||||||
|
|
||||||
private val mPageInfo = ExpensesRecordActivity.PageInfo()
|
private val mPageInfo = ExpensesRecordActivity.PageInfo()
|
||||||
private var reConnection = false
|
private var reConnection = false
|
||||||
|
|
@ -221,7 +233,7 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa
|
||||||
RxToast.info(resources.getString(R.string.AccountExpired))
|
RxToast.info(resources.getString(R.string.AccountExpired))
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
}
|
}
|
||||||
val intent = Intent(CommonUtils.getApp(), ChangeNodeActivity::class.java)
|
val intent = Intent(CommonUtils.getApp(), NodeGroupActivity::class.java)
|
||||||
if (!TextUtils.isEmpty(newUuid)) {
|
if (!TextUtils.isEmpty(newUuid)) {
|
||||||
intent.putExtra(BZYConstants.MMKV_KEY_CURRENT_NODE, newUuid)
|
intent.putExtra(BZYConstants.MMKV_KEY_CURRENT_NODE, newUuid)
|
||||||
intent.putExtra(BZYConstants.EXTRA_KEY_IS_RUNING, clashRunning)
|
intent.putExtra(BZYConstants.EXTRA_KEY_IS_RUNING, clashRunning)
|
||||||
|
|
@ -361,7 +373,7 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa
|
||||||
|
|
||||||
private fun startClash(isStart: Boolean) {
|
private fun startClash(isStart: Boolean) {
|
||||||
launch {
|
launch {
|
||||||
MainActivity.profileBinder?.let { pm ->
|
profileBinder?.let { pm ->
|
||||||
val active = pm.queryActive()
|
val active = pm.queryActive()
|
||||||
if (active == null) {
|
if (active == null) {
|
||||||
if (isStart) {
|
if (isStart) {
|
||||||
|
|
@ -390,7 +402,7 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa
|
||||||
}
|
}
|
||||||
delay(500)
|
delay(500)
|
||||||
}
|
}
|
||||||
|
refreshNode()
|
||||||
val vpnRequest = context?.startClashService()
|
val vpnRequest = context?.startClashService()
|
||||||
try {
|
try {
|
||||||
startUTimer()
|
startUTimer()
|
||||||
|
|
@ -415,7 +427,7 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa
|
||||||
tvClick.text=resources.getString(R.string.Accelerating)
|
tvClick.text=resources.getString(R.string.Accelerating)
|
||||||
ivAccelerate.setImageResource(R.mipmap.yjl_home_clink_select_bg)
|
ivAccelerate.setImageResource(R.mipmap.yjl_home_clink_select_bg)
|
||||||
hideLoading()
|
hideLoading()
|
||||||
checkGlo()
|
// checkGlo()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -697,14 +709,15 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa
|
||||||
MMKV.defaultMMKV().decodeString(BZYConstants.NODE_SELECTED_NAME_KEY, "")
|
MMKV.defaultMMKV().decodeString(BZYConstants.NODE_SELECTED_NAME_KEY, "")
|
||||||
Log.d("getNodes selected_name==>${selectedName}")
|
Log.d("getNodes selected_name==>${selectedName}")
|
||||||
if (TextUtils.isEmpty(selectedName)) {
|
if (TextUtils.isEmpty(selectedName)) {
|
||||||
MainActivity.subUrl?.let {
|
subUrl?.let {
|
||||||
accelerateViewModel.getNodeOther(it, object : AsyncCallBackListener {
|
val json = serStore.nodes
|
||||||
override fun suc(obj: Any?) {
|
Log.d("getNodes json==>${json}")
|
||||||
proList = obj as MutableList<ClashNodebBean>
|
currentNode=getNodesInfo(json)
|
||||||
proList?.let { proListItem ->
|
Log.d("getNodes currentNode==>${currentNode} dataname:${currentNode[0].proxies[0]}")
|
||||||
val nodeName = proListItem[0].name
|
val baseNodeName=currentNode[0].proxies[0]
|
||||||
if (!TextUtils.isEmpty(nodeName)) {
|
|
||||||
launch(Dispatchers.IO) {
|
if (!TextUtils.isEmpty(baseNodeName)) {
|
||||||
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
clashBinder?.let { cm ->
|
clashBinder?.let { cm ->
|
||||||
|
|
||||||
val o = cm.queryOverride(Clash.OverrideSlot.Session)
|
val o = cm.queryOverride(Clash.OverrideSlot.Session)
|
||||||
|
|
@ -729,22 +742,11 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa
|
||||||
delay(1000)
|
delay(1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
cm.patchSelector("GLOBAL", nodeName)
|
cm.patchSelector("GLOBAL", baseNodeName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun faild(response: Response) {
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun err(msg: String, exception: Exception?) {
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
clashBinder?.let { cm ->
|
clashBinder?.let { cm ->
|
||||||
val o = cm.queryOverride(Clash.OverrideSlot.Session)
|
val o = cm.queryOverride(Clash.OverrideSlot.Session)
|
||||||
|
|
@ -903,6 +905,7 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa
|
||||||
tvIntelligentMode.setTextColor("#FF006AFB".toColorInt())
|
tvIntelligentMode.setTextColor("#FF006AFB".toColorInt())
|
||||||
tvGlobalMode.setTextColor("#FF000000".toColorInt())
|
tvGlobalMode.setTextColor("#FF000000".toColorInt())
|
||||||
sendMode(false)
|
sendMode(false)
|
||||||
|
checkGlo()
|
||||||
}
|
}
|
||||||
|
|
||||||
ProxyMode.GLOBAL -> {
|
ProxyMode.GLOBAL -> {
|
||||||
|
|
@ -913,6 +916,7 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa
|
||||||
tvIntelligentMode.setTextColor("#FF000000".toColorInt())
|
tvIntelligentMode.setTextColor("#FF000000".toColorInt())
|
||||||
tvGlobalMode.setTextColor("#FF006AFB".toColorInt())
|
tvGlobalMode.setTextColor("#FF006AFB".toColorInt())
|
||||||
sendMode(true)
|
sendMode(true)
|
||||||
|
checkGlo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1005,5 +1009,46 @@ open class HomeFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispa
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
fun refreshNode(){
|
||||||
|
try {
|
||||||
|
launch(Dispatchers.IO) {
|
||||||
|
profileBinder?.let { profileManager ->
|
||||||
|
var mProfile: Profile? = null
|
||||||
|
profileManager.queryAll().forEach { it_pf ->
|
||||||
|
val confName =
|
||||||
|
Conf.getClashConfName(requireActivity())
|
||||||
|
Log.d("refreshNode::==>${it_pf.name}, confName==>${confName}")
|
||||||
|
if (confName == it_pf.name) {
|
||||||
|
mProfile = it_pf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mProfile == null) {
|
||||||
|
profileManager.queryAll().forEach { profile ->
|
||||||
|
mProfile = profile
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mProfile?.let { profile ->
|
||||||
|
profileManager.update(profile.uuid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun getNodesInfo(json: String): MutableList<NodeGroupItem> {
|
||||||
|
val mList: MutableList<NodeGroupItem> = 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -45,6 +45,7 @@ import com.yingmao.clash.act.MainActivity
|
||||||
import com.yingmao.clash.act.MainActivity.Companion.profileBinder
|
import com.yingmao.clash.act.MainActivity.Companion.profileBinder
|
||||||
import com.yingmao.clash.act.MainActivity.Companion.setSub2
|
import com.yingmao.clash.act.MainActivity.Companion.setSub2
|
||||||
import com.yingmao.clash.act.MainActivity.Companion.subUrl
|
import com.yingmao.clash.act.MainActivity.Companion.subUrl
|
||||||
|
import com.yingmao.clash.act.MainActivity.Companion.trafficStatisticsData
|
||||||
import com.yingmao.clash.act.SettingActivity
|
import com.yingmao.clash.act.SettingActivity
|
||||||
import com.yingmao.clash.act.ShareActivity
|
import com.yingmao.clash.act.ShareActivity
|
||||||
import com.yingmao.clash.act.SplashHelper
|
import com.yingmao.clash.act.SplashHelper
|
||||||
|
|
@ -107,6 +108,8 @@ class SettingFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatc
|
||||||
private var baseLoad: RxDialogShapeLoading? = null
|
private var baseLoad: RxDialogShapeLoading? = null
|
||||||
private lateinit var mainAtyVM: MainAtyVM
|
private lateinit var mainAtyVM: MainAtyVM
|
||||||
|
|
||||||
|
private lateinit var tvUseNet: TextView
|
||||||
|
|
||||||
private var settingPageList = mutableListOf<SettingPageBean>()
|
private var settingPageList = mutableListOf<SettingPageBean>()
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
override fun init(
|
override fun init(
|
||||||
|
|
@ -386,6 +389,15 @@ class SettingFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatc
|
||||||
|
|
||||||
rvSettingTab=view.findViewById(R.id.rvSettingTab)
|
rvSettingTab=view.findViewById(R.id.rvSettingTab)
|
||||||
|
|
||||||
|
tvUseNet=view.findViewById(R.id.tvUseNet)
|
||||||
|
|
||||||
|
trafficStatisticsData.observe(requireActivity()){
|
||||||
|
it.let {
|
||||||
|
tvUseNet.text=it
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
clVipCard.setOnClickListener {
|
clVipCard.setOnClickListener {
|
||||||
goNewRecharge()
|
goNewRecharge()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
package com.yingmao.clash.view.adapter
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.widget.AppCompatImageView
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.cncat.vpn.common.log.Log
|
||||||
|
import com.yingmao.clash.R
|
||||||
|
import kotlin.collections.mutableListOf
|
||||||
|
import kotlin.text.contains
|
||||||
|
|
||||||
|
|
||||||
|
class NodeGroupAdapter : RecyclerView.Adapter<NodeGroupAdapter.NodeGroupAdapterViewHolder>() {
|
||||||
|
|
||||||
|
private var nodeGroupList = mutableListOf<String>()
|
||||||
|
|
||||||
|
//设置回调监听
|
||||||
|
private var listener: ItemClickListener? = null
|
||||||
|
private var context: Context? = null
|
||||||
|
var selectedPosition: Int =0
|
||||||
|
//设置监听器
|
||||||
|
fun setListener(listener: ItemClickListener?) {
|
||||||
|
this.listener = listener
|
||||||
|
}
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun setDataMethod(infoList: MutableList<String>, context: Context) {
|
||||||
|
nodeGroupList=infoList
|
||||||
|
this.context=context
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
inner class NodeGroupAdapterViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
val nodeitemItem = itemView.findViewById<ConstraintLayout>(R.id.rl_node_list_item)
|
||||||
|
var nodeName = itemView.findViewById<TextView>(R.id.node_list_item_tv_node_name)
|
||||||
|
|
||||||
|
var chekImg = itemView.findViewById<AppCompatImageView>(R.id.mrb_node_checked)
|
||||||
|
|
||||||
|
var countryImg = itemView.findViewById<AppCompatImageView>(R.id.node_list_item_iv_country)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = NodeGroupAdapterViewHolder(
|
||||||
|
LayoutInflater.from(context)
|
||||||
|
.inflate(R.layout.node_list_item_layout, parent, false)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun getItemCount() = nodeGroupList.size
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: NodeGroupAdapterViewHolder, position: Int) {
|
||||||
|
holder.nodeitemItem.setOnClickListener {
|
||||||
|
listener?.onItemClick(nodeGroupList[position],position)
|
||||||
|
}
|
||||||
|
holder.nodeName.text = nodeGroupList[position]
|
||||||
|
holder.chekImg.isSelected = holder.layoutPosition == selectedPosition
|
||||||
|
val nodeGroupName = nodeGroupList[position]
|
||||||
|
|
||||||
|
if(nodeGroupName.contains("中国")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.flag_china)
|
||||||
|
}else if(nodeGroupName.contains("香港")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.flag_china)
|
||||||
|
}else if(nodeGroupName.contains("日本")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.flag_japan)
|
||||||
|
}else if(nodeGroupName.contains("韩国")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.flag_korea)
|
||||||
|
}else if(nodeGroupName.contains("美国")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.flag_usa)
|
||||||
|
}else if(nodeGroupName.contains("德国")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.flag_germany)
|
||||||
|
}else if(nodeGroupName.contains("法国")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.flag_france)
|
||||||
|
}else if(nodeGroupName.contains("俄罗斯")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.flag_russia)
|
||||||
|
}else if(nodeGroupName.contains("新加坡")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.flag_singapore)
|
||||||
|
}else if(nodeGroupName.contains("英国")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.flag_uk)
|
||||||
|
}else if(nodeGroupName.contains("澳大利亚")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.flag_australia)
|
||||||
|
}else if(nodeGroupName.contains("印度")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.flag_india)
|
||||||
|
}else if(nodeGroupName.contains("加拿大")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.flag_canada)
|
||||||
|
}else if(nodeGroupName.contains("以色列")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.ic_s_il)
|
||||||
|
}else if(nodeGroupName.contains("西班牙")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.ic_xibanya)
|
||||||
|
}else if(nodeGroupName.contains("西班牙")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.ic_xibanya)
|
||||||
|
}else if(nodeGroupName.contains("荷兰")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.ic_henan)
|
||||||
|
}else if(nodeGroupName.contains("意大利")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.ic_yidali)
|
||||||
|
}else if(nodeGroupName.contains("塞尔维亚")){
|
||||||
|
holder.countryImg.setImageResource(R.drawable.ic_sewy)
|
||||||
|
}else{
|
||||||
|
holder.countryImg.setImageResource(R.drawable.ic_s_location)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 内置监听回调
|
||||||
|
* */
|
||||||
|
interface ItemClickListener {
|
||||||
|
fun onItemClick(nodeStr: String, isPosition:Int)
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -288,6 +288,17 @@
|
||||||
app:layout_constraintStart_toStartOf="@+id/shareCard"
|
app:layout_constraintStart_toStartOf="@+id/shareCard"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/shareCard" />
|
app:layout_constraintTop_toBottomOf="@+id/shareCard" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvUseNet"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text=""
|
||||||
|
android:textColor="#FF000000"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/shareCard"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/shareCard" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/rvSettingTab"
|
android:id="@+id/rvSettingTab"
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,8 @@ subprojects {
|
||||||
}
|
}
|
||||||
minSdk = 21
|
minSdk = 21
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionName = "1.0.4.8"
|
versionName = "1.0.5.2"
|
||||||
versionCode = 1048
|
versionCode = 1052
|
||||||
resValue("string", "release_name", "v$versionName")
|
resValue("string", "release_name", "v$versionName")
|
||||||
resValue("integer", "release_code", "$versionCode")
|
resValue("integer", "release_code", "$versionCode")
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
|
|
@ -93,22 +93,6 @@ subprojects {
|
||||||
}
|
}
|
||||||
productFlavors {
|
productFlavors {
|
||||||
flavorDimensions("feature")
|
flavorDimensions("feature")
|
||||||
create("2210") {
|
|
||||||
isDefault = true
|
|
||||||
dimension = flavorDimensionList[0]
|
|
||||||
buildConfigField("boolean", "PREMIUM", "Boolean.parseBoolean(\"false\")")
|
|
||||||
buildConfigField("boolean", "is_free", "false")
|
|
||||||
buildConfigField("boolean", "is_back_cn", "false")
|
|
||||||
buildConfigField("String", "applicationId", "\"com.jsq.wufu\"")
|
|
||||||
buildConfigField("String", "service_url", "\"https://api.yijianlianjsq.com/\"")
|
|
||||||
buildConfigField("String", "productId", "\"2210\"")
|
|
||||||
manifestPlaceholders(
|
|
||||||
mapOf(
|
|
||||||
"APP_NAME" to "@string/wf",
|
|
||||||
"APP_ICON" to "@mipmap/oneclickconnection"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
create("2211") {
|
create("2211") {
|
||||||
isDefault = true
|
isDefault = true
|
||||||
dimension = flavorDimensionList[0]
|
dimension = flavorDimensionList[0]
|
||||||
|
|
@ -125,57 +109,9 @@ subprojects {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
create("2212") {
|
|
||||||
isDefault = true
|
|
||||||
dimension = flavorDimensionList[0]
|
|
||||||
buildConfigField("boolean", "PREMIUM", "Boolean.parseBoolean(\"false\")")
|
|
||||||
buildConfigField("boolean", "is_free", "false")
|
|
||||||
buildConfigField("boolean", "is_back_cn", "false")
|
|
||||||
buildConfigField("String", "applicationId", "\"com.jsq.wufu\"")
|
|
||||||
buildConfigField("String", "service_url", "\"https://api.yijianlianjsq.com/\"")
|
|
||||||
buildConfigField("String", "productId", "\"2212\"")
|
|
||||||
manifestPlaceholders(
|
|
||||||
mapOf(
|
|
||||||
"APP_NAME" to "@string/wf",
|
|
||||||
"APP_ICON" to "@mipmap/oneclickconnection"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
create("2213") {
|
|
||||||
isDefault = true
|
|
||||||
dimension = flavorDimensionList[0]
|
|
||||||
buildConfigField("boolean", "PREMIUM", "Boolean.parseBoolean(\"false\")")
|
|
||||||
buildConfigField("boolean", "is_free", "false")
|
|
||||||
buildConfigField("boolean", "is_back_cn", "false")
|
|
||||||
buildConfigField("String", "applicationId", "\"com.jsq.wufu\"")
|
|
||||||
buildConfigField("String", "service_url", "\"https://api.yijianlianjsq.com/\"")
|
|
||||||
buildConfigField("String", "productId", "\"2213\"")
|
|
||||||
manifestPlaceholders(
|
|
||||||
mapOf(
|
|
||||||
"APP_NAME" to "@string/wf",
|
|
||||||
"APP_ICON" to "@mipmap/oneclickconnection"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
create("2214") {
|
|
||||||
isDefault = true
|
|
||||||
dimension = flavorDimensionList[0]
|
|
||||||
buildConfigField("boolean", "PREMIUM", "Boolean.parseBoolean(\"false\")")
|
|
||||||
buildConfigField("boolean", "is_free", "false")
|
|
||||||
buildConfigField("boolean", "is_back_cn", "false")
|
|
||||||
buildConfigField("String", "applicationId", "\"com.jsq.wufu\"")
|
|
||||||
buildConfigField("String", "service_url", "\"https://api.yijianlianjsq.com/\"")
|
|
||||||
buildConfigField("String", "productId", "\"2214\"")
|
|
||||||
manifestPlaceholders(
|
|
||||||
mapOf(
|
|
||||||
"APP_NAME" to "@string/wf",
|
|
||||||
"APP_ICON" to "@mipmap/oneclickconnection"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sourceSets {
|
sourceSets {
|
||||||
getByName("2210") {
|
getByName("2211") {
|
||||||
java.srcDirs("src/foss/java")
|
java.srcDirs("src/foss/java")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue