yijianlianUI/app/src/main/java/com/yingmao/clash/fragment/NewAccFragment.kt

718 lines
26 KiB
Kotlin

package com.yingmao.clash.fragment
import android.app.Activity
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.widget.Button
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContract
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity.RESULT_OK
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.orhanobut.logger.Logger
import com.tencent.mmkv.MMKV
import com.yingmao.clash.R
import com.yingmao.clash.act.ChangeNodeActivity
import com.yingmao.clash.act.NewMainActivity
import com.yingmao.clash.act.NewMainActivity.Companion.REQUEST_CODE_PAY_WEB_VIEW_ACTIVITY
import com.yingmao.clash.act.NewMainActivity.Companion.isSubed
import com.yingmao.clash.act.NewMainActivity.Companion.newUuid
import com.yingmao.clash.act.ProxyModeActivity
import com.yingmao.clash.common.constants.Intents
import com.yingmao.clash.common.log.Log
import com.yingmao.clash.conf.BZYConstants
import com.yingmao.clash.conf.Conf
import com.yingmao.clash.core.Clash
import com.yingmao.clash.core.model.TunnelState
import com.yingmao.clash.entity.ClashNodebBean
import com.yingmao.clash.fragment.recharge.BackupRechargeActivity
import com.yingmao.clash.listener.AsyncCallBackListener
import com.yingmao.clash.util.ActivityResultLifecycle
import com.yingmao.clash.util.CommonUtils
import com.yingmao.clash.util.startClashService
import com.yingmao.clash.util.stopClashService
import com.yingmao.clash.view.RxToast
import com.yingmao.clash.view.dialog.RxDialogShapeLoading
import com.yingmao.clash.view.dialog.RxDialogSureCancel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.Response
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.atomic.AtomicInteger
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatchers.IO),
View.OnClickListener {
companion object {
const val REQUEST_CONNECT = 1
const val CHECK_NODE_REQUEST_CODE = 2
const val CHECK_NODE_RESULT_CODE = 3
const val Proxy_Mode_REQUEST_CODE = 4
const val Clash_Started = 11
const val Clash_Starting = 22
const val Clash_Stop = 33
public var currNodeJsonA: String? = null
var isGlo: Boolean = false
var clashRunning: Boolean = false
}
lateinit var accelerateViewModel: AccelerateViewModel
private lateinit var rxDialogShapeLoading: RxDialogShapeLoading
private lateinit var rxDialogSureCancel: RxDialogSureCancel
private lateinit var accelerateIv: ImageView
private lateinit var tv_proxy_model: TextView
private lateinit var tv_end_time: TextView
private lateinit var iv_proxy_mode: ImageView
private lateinit var nodeNameTv: TextView
private lateinit var countryIv: ImageView
// var currentNode: Profile? = null
private var reConnection = false
override fun init(
titleBarRl: RelativeLayout,
backIv: ImageView,
moreTv: TextView,
titleTv: TextView,
container: FrameLayout
) {
titleBarRl.visibility = View.VISIBLE
backIv.visibility = View.INVISIBLE
moreTv.visibility = View.INVISIBLE
titleTv.visibility = View.INVISIBLE
val accelerateFragmentView = View.inflate(
activity, R.layout.fragment_accelerate, null
)
initViews(accelerateFragmentView)
container.addView(accelerateFragmentView)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
Logger.d("onActivityCreated")
accelerateViewModel = ViewModelProvider(this).get(AccelerateViewModel::class.java)
initSS()
// initSub()
getNodesStatus()
// accelerateViewModel.getAirNodes()
// accelerateViewModel.appCheck()
val token = MMKV.defaultMMKV().decodeString(
BZYConstants.MMKV_KEY_TOKEN
).toString()
Log.d("token==>$token")
}
private fun initSS() {
val intentFilter = IntentFilter()
intentFilter.addAction(Intents.ACTION_CLASH_STARTED)
intentFilter.addAction(Intents.ACTION_CLASH_STOPPED)
intentFilter.addAction(Intents.ACTION_CLASH_REQUEST_STOP)
intentFilter.addAction(Intents.ACTION_Glo_Mode)
intentFilter.addAction(Intents.ACTION_OVERRIDE_CHANGED)
context?.registerReceiver(
ClashBP(), intentFilter
)
}
private fun initViews(view: View) {
val checkNodeRl = view.findViewById<RelativeLayout>(R.id.rl_check_node)
nodeNameTv = view.findViewById(R.id.tv_node)
countryIv = view.findViewById(R.id.iv_country)
tv_end_time = view.findViewById(R.id.tv_end_time)
//不记住
// currentNode = MMKV.defaultMMKV().decodeParcelable(
// BZYConstants.MMKV_KEY_CURRENT_NODE,
// Node::class.java
// )
// setNodeNameAndImg(currentNode)
checkNodeRl.setOnClickListener(this)
accelerateIv = view.findViewById(R.id.iv_accelerate)
accelerateIv.setOnClickListener(this)
tv_proxy_model = view.findViewById(R.id.tv_proxy_model)
iv_proxy_mode = view.findViewById(R.id.iv_proxy_mode)
view.findViewById<View>(R.id.ll_proxy_mode).setOnClickListener {
// startActivity(Intent(activity, ProxyModeActivity::class.java))
val intent = Intent(activity, ProxyModeActivity::class.java)
startActivityForResult(intent, Proxy_Mode_REQUEST_CODE)
}
var selected_name =
MMKV.defaultMMKV().decodeString(BZYConstants.NODE_SELECTED_NAME_KEY, "");
if (!TextUtils.isEmpty(selected_name)) {
setNodeNameAndImg(selected_name!!)
}
view.findViewById<Button>(R.id.recharge_but).setOnClickListener {
goRechargeWeb()
}
//备用充值
view.findViewById<Button>(R.id.backupRecharge).setOnClickListener {
goNewRecharge()
}
setExpireDate()
setProxyModeView(NewMainActivity.newMainActGlo)
}
override fun onResume() {
super.onResume()
// val isGlobal = MMKV.defaultMMKV().decodeBool(BZYConstants.MMKV_KEY_GLOBAL_MODEL, false)
lifecycleScope.launch {
// if (isGlobal) {
// iv_proxy_mode.setImageResource(R.drawable.ic_s_global)
// tv_proxy_model.text = "全局模式"
// } else {
// iv_proxy_mode.setImageResource(R.drawable.smart)
// tv_proxy_model.text = "智能模式"
// }
com.yingmao.clash.common.log.Log.d("clashRunning==>$clashRunning")
// if (clashRunning) {
// stateChanged(Clash_Started, false)
// } else {
// stateChanged(Clash_Stop, false)
// }
}
}
// protected val uiStore by lazy { MainApplication.getApp()?.applicationContext?.let { UiStore(it) } }
override fun onClick(v: View?) {
when (v?.id) {
R.id.rl_check_node -> {
if (checkExpire()) {
RxToast.info("账号已过期")
return
}
val intent = Intent(CommonUtils.getApp(), ChangeNodeActivity::class.java)
if (!TextUtils.isEmpty(NewMainActivity.newUuid)) {
intent.putExtra(BZYConstants.MMKV_KEY_CURRENT_NODE, NewMainActivity.newUuid)
intent.putExtra(BZYConstants.EXTRA_KEY_IS_RUNING, clashRunning)
}
startActivityForResult(intent, CHECK_NODE_REQUEST_CODE)
}
R.id.iv_accelerate -> {
// Logger.i("mState:${mState}")
if (clashRunning) {
val rxDialogSureCancel = RxDialogSureCancel(activity)
rxDialogSureCancel.setContent("停止加速?")
rxDialogSureCancel.setCancelListener {
rxDialogSureCancel.cancel()
}
rxDialogSureCancel.setSureListener {
// Core.stopService()
stopClash()
rxDialogSureCancel.cancel()
reConnection = false
}
rxDialogSureCancel.show()
} else {
startClash()
// connectVPNSS(currentNode)
}
// }
}
}
}
private fun selectActive() {
}
public fun stopClash() {
context?.stopClashService()
}
private fun startClash() {
if (checkExpire()) {
RxToast.info("账号已过期")
return
}
if (!NewMainActivity.isSubed) {
RxToast.info("正在初始化,请稍后再试!")
return
}
launch {
NewMainActivity.profileBinder?.let { pm ->
val active = pm.queryActive()
if (active == null) {
com.yingmao.clash.common.log.Log.d("startClash: 未选择")
val pro = pm.queryAll().find {
it.name == Conf.getClashConfName(this@NewAccFragment.context)
}
pro?.let { profile ->
com.yingmao.clash.common.log.Log.d("new setactive name " + profile.name)
pm.setActive(profile)
newUuid = profile.uuid.toString();
isSubed = true
}
delay(500)
}
val vpnRequest = context?.startClashService()
try {
if (vpnRequest != null) {
val result = startActivityForResult(
ActivityResultContracts.StartActivityForResult(), vpnRequest
)
if (result.resultCode == RESULT_OK) {
stateChanged(Clash_Starting, true)
context?.startClashService()
// clashRunning = true
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
private val nextRequestKey = AtomicInteger(0)
private suspend fun <I, O> startActivityForResult(
contracts: ActivityResultContract<I, O>,
input: I,
): O = withContext(Dispatchers.Main) {
val requestKey = nextRequestKey.getAndIncrement().toString()
ActivityResultLifecycle().use { lifecycle, start ->
suspendCoroutine { c ->
activity?.activityResultRegistry?.register(requestKey, lifecycle, contracts) {
c.resume(it)
}.apply { start() }?.launch(input)
}
}
}
inner class ClashBP : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
com.yingmao.clash.common.log.Log.i("action==>" + intent?.action)
when (intent?.action) {
Intents.ACTION_CLASH_STARTED -> {
if (::rxDialogShapeLoading.isInitialized) {
rxDialogShapeLoading.cancel()
}
accelerateIv.isSelected = true
clashRunning = true
// MMKV.defaultMMKV().encode(
// BZYConstants.MMKV_KEY_CURRENT_NODE,
// currentNode
// )
// setNodeNameAndImg(currentNode!!.name)
RxToast.success("加速成功")
checkGlo()
}
Intents.ACTION_CLASH_STOPPED -> {
if (::rxDialogShapeLoading.isInitialized) {
rxDialogShapeLoading.cancel()
}
accelerateIv.isSelected = false
clashRunning = false
}
Intents.ACTION_CLASH_REQUEST_STOP -> {
// clashRunning = false
com.yingmao.clash.common.log.Log.d("ACTION_CLASH_REQUEST_STOP")
if (::rxDialogShapeLoading.isInitialized) {
if (!rxDialogShapeLoading.isShowing) {
rxDialogShapeLoading.setMessage("正在断开...")
rxDialogShapeLoading.show()
}
}
}
Intents.ACTION_Glo_Mode -> {
var mode = intent.getBooleanExtra("mode", false)
Log.d("ACTION_Glo_Mode mode==>${mode}")
isGlo = mode
}
}
}
}
private fun getNodesStatus() {
}
fun stateChanged(state: Int, isShowToast: Boolean) {
Logger.i("!!!!!!!!!!:${state}")
when (state) {
Clash_Started -> {
if (::rxDialogShapeLoading.isInitialized) {
rxDialogShapeLoading.cancel()
}
accelerateIv.isSelected = true
// MMKV.defaultMMKV().encode(
// BZYConstants.MMKV_KEY_CURRENT_NODE,
// currentNode
// )
// setNodeNameAndImg(currentNode!!.name)
if (isShowToast) {
RxToast.success("加速成功")
}
// File("${Core.deviceStorage.noBackupFilesDir}/${BaseService.CONFIG_FILE}").delete()
}
Clash_Stop -> {
if (::rxDialogShapeLoading.isInitialized) {
rxDialogShapeLoading.cancel()
}
accelerateIv.isSelected = false
// if (reConnection) {
// connectVPNSS(currentNode)
// }
}
Clash_Starting -> {
if (::rxDialogShapeLoading.isInitialized) {
if (!rxDialogShapeLoading.isShowing) {
rxDialogShapeLoading.setMessage("连接中...")
rxDialogShapeLoading.show()
}
}
}
// BaseService.State.Stopping -> {
// if (::rxDialogShapeLoading.isInitialized) {
// if (!rxDialogShapeLoading.isShowing) {
// rxDialogShapeLoading.setMessage("正在断开...")
// rxDialogShapeLoading.show()
// }
// }
// }
else -> {}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
com.yingmao.clash.common.log.Log.i("onActivityResult ==>>> requestCode:${requestCode} resultCode:${resultCode}")
if (requestCode == REQUEST_CONNECT) {
if (resultCode == Activity.RESULT_OK) {
if (clashRunning) {
Log.d("clashRunning $clashRunning")
} else {
startClash()
}
} else {
if (::rxDialogShapeLoading.isInitialized || rxDialogShapeLoading.isShowing) {
rxDialogShapeLoading.cancel()
}
}
} else if (requestCode == CHECK_NODE_REQUEST_CODE) {
val node = data?.extras?.getString(BZYConstants.MMKV_KEY_SELECT_NODE_NAME)
val is_runing = data?.extras?.getBoolean(BZYConstants.EXTRA_KEY_IS_RUNING)
// val node = data?.extras?.getSerializable(BZYConstants.MMKV_KEY_SELECT_NODE) as Profile
Log.d("onActivityResult ==>>> Node:${node}")
node?.let {
setNodeNameAndImg(node)
if (clashRunning) {
Log.d("clashRunning $clashRunning")
} else {
startClash()
}
checkGlo()
}?.run {
if (is_runing == true && !clashRunning) {
startClash()
} else {
}
}
} else if (requestCode == Proxy_Mode_REQUEST_CODE) {
checkGlo()
}
}
fun setExpireDate() {
var isExpire = checkExpire()
// var isExpire = false
var endTimeInfo = "--"
if (isExpire) {
endTimeInfo = "账号已到期"
} else {
val validPeriod = MMKV.defaultMMKV().decodeLong(BZYConstants.MMKV_KEY_VPN_VALID_PERIOD)
val dateFormat = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss")
} else {
SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss")
}
endTimeInfo = dateFormat.format(validPeriod)
}
tv_end_time.text = endTimeInfo
}
private fun checkExpire(): Boolean {
val validPeriod = MMKV.defaultMMKV().decodeLong(BZYConstants.MMKV_KEY_VPN_VALID_PERIOD)
if (validPeriod > 0) {
var nowTime = System.currentTimeMillis();
com.yingmao.clash.common.log.Log.d("validPeriod==>$validPeriod, nowTime==>$nowTime")
if (validPeriod >= nowTime) {
return false
}
}
return true;
}
private fun setNodeNameAndImg(it: String) {
launch(Dispatchers.Main) {
nodeNameTv.text = it
when {
it.contains("中国", true) -> {
countryIv.setImageResource(R.drawable.flag_china)
}
it.contains("香港", true) -> {
countryIv.setImageResource(R.drawable.flag_china)
}
it.contains("日本", true) -> {
countryIv.setImageResource(R.drawable.flag_japan)
}
it.contains("韩国", true) -> {
countryIv.setImageResource(R.drawable.flag_korea)
}
it.contains("美国", true) -> {
countryIv.setImageResource(R.drawable.flag_usa)
}
it.contains("德国", true) -> {
countryIv.setImageResource(R.drawable.flag_germany)
}
it.contains("法国", true) -> {
countryIv.setImageResource(R.drawable.flag_france)
}
it.contains("俄罗斯", true) -> {
countryIv.setImageResource(R.drawable.flag_russia)
}
it.contains("新加坡", true) -> {
countryIv.setImageResource(R.drawable.flag_singapore)
}
it.contains("英国", true) -> {
countryIv.setImageResource(R.drawable.flag_uk)
}
it.contains("澳大利亚", true) -> {
countryIv.setImageResource(R.drawable.flag_australia)
}
it.contains("印度", true) -> {
countryIv.setImageResource(R.drawable.flag_india)
}
it.contains("加拿大", true) -> {
countryIv.setImageResource(R.drawable.flag_canada)
}
else -> {
countryIv.setImageResource(R.drawable.ic_s_location)
}
}
}
}
private fun goRechargeWeb() {
var mact = activity as NewMainActivity
mact.goRechargeWeb()
}
private fun goNewRecharge() {
var mact = activity as NewMainActivity
mact.goBackupRechargeWeb()
}
private fun checkGlo() {
val isGlobal = isGlo
val isGlobal2 = MMKV.defaultMMKV().decodeBool(BZYConstants.MMKV_KEY_GLOBAL_MODEL, false)
Log.i("checkGlo isGlobal==>${isGlobal}, isGlobal2==>${isGlobal2}")
setProxyModeView(isGlobal)
launch(Dispatchers.IO) {
if (isGlobal) {
if (clashRunning) {
getNodes()
}
} else {
if (clashRunning) {
delay(1000)
NewMainActivity.clashBinder?.let { cm ->
val names = cm.queryProxyGroupNames(false)
Log.i("checkGlo names==>${names}")
if (names.isNotEmpty()) {
var selected_name =
MMKV.defaultMMKV()
.decodeString(BZYConstants.NODE_SELECTED_NAME_KEY, "");
Log.i("selected_name ==>${selected_name}")
if (!TextUtils.isEmpty(selected_name)) {
val o = cm.queryOverride(Clash.OverrideSlot.Session)
o.mode = TunnelState.Mode.Rule
cm.patchOverride(Clash.OverrideSlot.Session, o)
delay(500)
var gName = names[0]
if (names.size >= 2) {
if ("GLOBAL" == gName) {
gName = names[1]
}
}
cm.patchSelector(gName, selected_name!!)
} else {
}
}
}
}
}
}
}
private fun setProxyModeView(isGlobal: Boolean) {
if (isGlobal) {
iv_proxy_mode.setImageResource(R.drawable.ic_s_global)
tv_proxy_model.text = "全局模式"
} else {
iv_proxy_mode.setImageResource(R.drawable.smart)
tv_proxy_model.text = "智能模式"
}
}
var proList: MutableList<ClashNodebBean>? = null
private suspend fun getNodes() {
var selected_name =
MMKV.defaultMMKV().decodeString(BZYConstants.NODE_SELECTED_NAME_KEY, "");
Log.d("getNodes selected_name==>${selected_name}")
if (TextUtils.isEmpty(selected_name)) {
NewMainActivity.subUrl?.let {
accelerateViewModel?.get_Node_Other(it, object : AsyncCallBackListener {
override fun suc(obj: Any?) {
proList = obj as MutableList<ClashNodebBean>
proList?.let { proListItem ->
var nodeName = proListItem[0].name
if (!TextUtils.isEmpty(nodeName)) {
launch(Dispatchers.IO) {
NewMainActivity.clashBinder?.let { cm ->
val o = cm.queryOverride(Clash.OverrideSlot.Session)
o.mode = TunnelState.Mode.Global
cm.patchOverride(Clash.OverrideSlot.Session, o)
delay(3000)
//等待全局
var maxIndex = 0
while (true) {
if (maxIndex > 3) {
break
}
var names = cm.queryProxyGroupNames(false)
if (names.isNotEmpty()) {
if (names[0] == "GLOBAL") {
Log.d("repeat end")
break
}
}
Log.d("repeat agent")
maxIndex++
delay(1000)
}
cm.patchSelector("GLOBAL", nodeName)
}
}
}
}
}
override fun faild(response: Response) {
}
override fun err(msg: String, exception: Exception?) {
}
})
}
} else {
NewMainActivity.clashBinder?.let { cm ->
val o = cm.queryOverride(Clash.OverrideSlot.Session)
o.mode = TunnelState.Mode.Global
cm.patchOverride(Clash.OverrideSlot.Session, o)
delay(3000)
//等待全局
var maxIndex = 0
while (true) {
if (maxIndex > 3) {
break
}
var names = cm.queryProxyGroupNames(false)
if (names.isNotEmpty()) {
if (names[0] == "GLOBAL") {
Log.d("repeat end")
break
}
}
Log.d("repeat agent")
maxIndex++
delay(1000)
}
cm.patchSelector("GLOBAL", selected_name!!)
}
}
}
}