合并提交

This commit is contained in:
level 2025-07-23 18:25:26 +08:00
parent 93ead85629
commit e474d6bd57
15 changed files with 688 additions and 684 deletions

View File

@ -25,7 +25,7 @@ dependencies {
implementation(libs.rikkax.multiprocess)
val commonAar = file("libs/common.aar")
val coreAar = file("libs/core.aar")
val hideawayEar = file("libs/hideapi.aar")
val hideapiAar = file("libs/hideapi.aar")
val serviceAar = file("libs/service.aar")
val oss = file("libs/oss-android-sdk-2.9.19.aar")
if (oss.exists()) {
@ -45,8 +45,8 @@ dependencies {
println("core.aar does not exist")
}
if (hideawayEar.exists()) {
implementation(files(hideawayEar))
if (hideapiAar.exists()) {
implementation(files(hideapiAar))
} else {
println("hideapi.aar does not exist")
}
@ -58,14 +58,18 @@ dependencies {
implementation(libs.kotlin.coroutine)
implementation(libs.androidx.core)
// implementation(libs.androidx.activity)
// implementation(libs.androidx.fragment)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.coordinator)
implementation(libs.androidx.recyclerview)
implementation(libs.google.material)
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.9.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.9.1")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.5.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.5.1")
// https://mvnrepository.com/artifact/com.tencent/mmkv-static
implementation("com.tencent:mmkv-static:1.2.10")
implementation ("com.jakewharton:process-phoenix:3.0.0")
@ -78,13 +82,29 @@ dependencies {
api("com.orhanobut:logger:2.2.0")
api("com.google.code.gson:gson:2.10.1")
api(platform("com.squareup.okhttp3:okhttp-bom:4.10.0"))
// define any required OkHttp artifacts without version
api("com.squareup.okhttp3:okhttp")
api("com.squareup.okhttp3:logging-interceptor")
//// https://mvnrepository.com/artifact/com.google.code.gson/gson
// api("com.google.code.gson:gson:2.10.1")
api("org.yaml:snakeyaml:1.29")
// https://mvnrepository.com/artifact/com.alipay.sdk/alipaysdk-android
implementation("com.alipay.sdk:alipaysdk-android:15.8.17")
// https://mvnrepository.com/artifact/com.journeyapps/zxing-android-embedded
// implementation("com.journeyapps:zxing-android-embedded:3.6.0")
// https://mvnrepository.com/artifact/com.google.zxing/core
// implementation("com.google.zxing:core:3.5.3")
implementation("com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4")
// https://mvnrepository.com/artifact/com.airbnb.android/lottie
implementation("com.airbnb.android:lottie:5.2.0")
implementation("com.github.bumptech.glide:glide:4.16.0")
// https://mvnrepository.com/artifact/com.github.bumptech.glide/glide
implementation("com.github.bumptech.glide:glide:4.13.2")
// implementation("com.luozm.captcha:captcha:1.1.2")
// implementation("com.aliyun.dpa:oss-android-sdk:2.9.19")
// implementation ("com.hihonor.mcs:ads-identifier:1.0.3.301")
implementation("com.github.gzu-liyujiang:Android_CN_OAID:4.2.8") {
exclude("com.hihonor.mcs", "ads-identifier")
exclude("com.huawei.hms", "ads-identifier")
@ -92,7 +112,9 @@ dependencies {
//stripe 支付
implementation("com.stripe:stripe-android:21.4.2")// 使用最新版本
implementation("com.github.getActivity:XXPermissions:20.0")
// 华为的最新版本广告标识服务SDK参阅 https://developer.huawei.com/consumer/cn/doc/HMSCore-Guides/identifier-service-version-change-history-0000001050066927
api ("com.huawei.hms:ads-identifier:3.4.62.300")
// 荣耀的最新版本广告标识服务SDK参阅 https://developer.hihonor.com/cn/kitdoc?kitId=11030&navigation=guides&docId=intergrate.md
api ("com.hihonor.mcs:ads-identifier:1.0.2.301")
implementation("com.android.installreferrer:installreferrer:2.2")// 使用最新版本
@ -108,7 +130,9 @@ task("downloadGeoFiles") {
val geoFilesUrls = mapOf(
"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb" to "geoip.metadb",
"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat" to "geosite.dat")
"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat" to "geosite.dat",
// "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country.mmdb" to "country.mmdb",
)
doLast {
geoFilesUrls.forEach { (downloadUrl, outputFileName) ->
@ -159,6 +183,9 @@ android {
abiFilters.add("armeabi-v7a")
}
}
// sourceSets.all {
// jniLibs.srcDir("src/main/jniLibs")
// }
sourceSets.all {
jniLibs.srcDir("src/main/jniLibs")
}

View File

@ -166,6 +166,9 @@
<activity android:name=".webview.BZYWebViewNormal"
android:process=":background"
/>
<activity android:name=".webview.BZYWebViewKeFu"
android:process=":background"
/>
<service android:name=".service.ConnectionService"/>
<provider
android:name="androidx.core.content.FileProvider"

View File

@ -10,8 +10,6 @@ import android.widget.Toast
import androidx.appcompat.widget.AppCompatImageView
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.observe
import com.baidu.mobads.action.ActionType
import com.baidu.mobads.action.BaiduAction
import com.yingmao.clash.view.dialog.RxDialogShapeLoading
import com.tencent.mmkv.MMKV
@ -146,9 +144,6 @@ class BandPhoneActivity : BaseActivity() {
MMKV.defaultMMKV().removeValueForKey(BZYConstants.MMKV_KEY_PH_TOKEN)
MMKV.defaultMMKV().removeValueForKey(BZYConstants.MMKV_KEY_TOKEN)
MMKV.defaultMMKV().removeValueForKey(BZYConstants.MMKV_KEY_CURRENT_NODE)
//百度埋点完成注册
BaiduAction.logAction(ActionType.REGISTER)
var intent=Intent(CommonUtils.getApp(), LoginActivity::class.java)
intent.putExtra(BZYConstants.EXTRA_Bind_Account,phoneNumber)

View File

@ -41,7 +41,6 @@ import com.cncat.vpn.service.remote.IRemoteService
import com.yingmao.clash.act.NewMainActivity.Companion.clashBinder
import com.yingmao.clash.act.NewMainActivity.Companion.profileBinder
import com.yingmao.clash.act.NewMainActivity.Companion.subUrl
import com.yingmao.clash.act.ProxyModeActivity.ProxyMode
import com.yingmao.clash.app.MainApplication
import com.yingmao.clash.fragment.NewAccFragment.Companion.CHECK_NODE_REQUEST_CODE
import com.yingmao.clash.util.Utils
@ -657,4 +656,7 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
intent.setPackage(this.packageName)
)
}
enum class ProxyMode {
PAC, GLOBAL, PACKAGE
}
}

View File

@ -1,606 +0,0 @@
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.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.IProfileManager
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.R
import com.yingmao.clash.act.NewMainActivity.Companion.clashBinder
import com.yingmao.clash.act.NewMainActivity.Companion.profileBinder
import com.yingmao.clash.act.NewMainActivity.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.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.yingmao.clash.util.Utils
import com.yingmao.clash.view.RxToast
import com.yingmao.clash.view.adapter.NodeTzListAdapter
import com.yingmao.clash.view.dialog.DialogDoMainChoose
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(2, 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
}
//缓存订阅地址
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) {
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()
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 {
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) {
profileBinder?.let { pro ->
uuid?.let { uu ->
pro.delete(uu)
delay(500)
setSub2(pro, 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

@ -9,7 +9,7 @@ import com.yingmao.clash.net.http.HttpReqType
import com.yingmao.clash.net.http.NetService
class ExpensesRecordVM: BaseViewMode() {
fun getExpensesRecord(page :PageInfo){
fun getExpensesRecord(page : ExpensesRecordActivity.PageInfo){
val httpApi = NetService.instances.createHttps(HttpApi::class.java)
val username = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME,"")!!
val phToken = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_PH_TOKEN,"")!!

View File

@ -79,6 +79,8 @@ import com.yingmao.clash.view.dialog.DialogBandChoose
import com.yingmao.clash.view.dialog.DialogNotice
import com.yingmao.clash.view.dialog.RxDialogShapeLoading
import com.yingmao.clash.vm.MainAtyVM
import com.yingmao.clash.webview.BZYWebViewKeFu
import com.yingmao.clash.webview.BZYWebViewNormal
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
@ -776,7 +778,7 @@ class NewMainActivity : BaseActivity() {
)
}
private fun goCheckLogin() {
fun goCheckLogin() {
mainAtyVM.checkLogin()
}
private fun showBindAccount() {

View File

@ -3,7 +3,11 @@ package com.yingmao.clash.base
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
@ -14,14 +18,24 @@ import android.view.inputmethod.InputMethodManager
import android.widget.*
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.collection.arraySetOf
import androidx.lifecycle.ViewModelProvider
import com.orhanobut.logger.Logger
import com.tencent.mmkv.MMKV
import com.yingmao.clash.BuildConfig
import com.yingmao.clash.R
import com.yingmao.clash.conf.BZYConstants
import com.yingmao.clash.conf.Conf
import com.cncat.vpn.core.bridge.ClashException
import com.cncat.vpn.core.model.TunnelState
//import com.yingmao.clash.design.model.DarkMode
//import com.yingmao.clash.design.store.UiStore
//import com.yingmao.clash.design.ui.DayNight
import com.yingmao.clash.net.http.HttpStatus
import com.yingmao.clash.remote.Broadcasts
import com.yingmao.clash.remote.Remote
import com.cncat.vpn.service.store.ServiceStore
import com.yingmao.clash.util.ApplicationObserver
import com.yingmao.clash.util.StatusBarUtils
import com.yingmao.clash.util.UiStore
import com.yingmao.clash.view.dialog.RxDialogShapeLoading
@ -29,26 +43,59 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import java.util.*
@Suppress("DEPRECATION")
open class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), Broadcasts.Observer {
lateinit var titleBar: RelativeLayout
lateinit var backIv: ImageView
lateinit var title: TextView
lateinit var more_tv: TextView
protected val uiStore by lazy { UiStore(this) }
protected val events = Channel<Event>(Channel.UNLIMITED)
private var baseLoading: RxDialogShapeLoading? = null
// private var dayNight: DayNight = DayNight.Day
var baseLoading: RxDialogShapeLoading? = null
val serStore by lazy { ServiceStore(this) }
@RequiresApi(Build.VERSION_CODES.M)
companion object {
// var switchFinshSet: MutableSet<String>? = null
}
sealed class RequestTunnel {
object ReloadAll : RequestTunnel()
object ReLaunch : RequestTunnel()
data class PatchMode(val mode: TunnelState.Mode?) : RequestTunnel()
data class Reload(val index: Int) : RequestTunnel()
data class Select(val index: Int, val name: String) : RequestTunnel()
data class UrlTest(val index: Int) : RequestTunnel()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; //竖屏
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; //竖屏
StatusBarUtils.with(this).init()
window.decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}
override fun setContentView(layoutResID: Int) {
val baseView = View.inflate(this, R.layout.activity_base, null)
titleBar = baseView.findViewById(R.id.rl_title_bar)
backIv = baseView.findViewById(R.id.iv_back)
title = baseView.findViewById(R.id.tv_title)
more_tv = baseView.findViewById(R.id.tv_more)
val container = baseView.findViewById<FrameLayout>(R.id.fl_container)
val params = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT
)
val view = View.inflate(this, layoutResID, null)
container.addView(view, params)
super.setContentView(baseView)
}
override fun onStart() {
super.onStart()
@ -67,6 +114,33 @@ open class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), Br
cancel()
}
fun showTitleBar(titleText: String) {
titleBar.visibility = View.VISIBLE
title.text = titleText
backIv.setOnClickListener {
onBackPressed()
}
}
fun showTitleBar(titleText: String, intent: Intent) {
titleBar.visibility = View.VISIBLE
title.text = titleText
backIv.setOnClickListener {
onBackPressed()
}
}
fun setMoreBar(moreInfo: String, listener: View.OnClickListener) {
more_tv.visibility = View.VISIBLE
more_tv.text = moreInfo
more_tv.setOnClickListener(listener)
}
fun updateMoreBar(moreInfo: String) {
more_tv.text = moreInfo
}
open fun observe(activity: BaseActivity, viewMode: BaseViewMode) {
viewMode.statusData.observe(activity) {
when (it) {
@ -93,14 +167,16 @@ open class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), Br
@SuppressLint("ClickableViewAccessibility")
open fun setupUI(view: View) {
// Set up touch listener for non-text box views to hide keyboard.
if (view !is EditText) view.setOnTouchListener { _, _ ->
hideSoftKeyboard(this@BaseActivity)
false
}
//If a layout container, iterate over children and seed recursion.
if (view is ViewGroup) {
for (i in 0 until view.childCount) {
val innerView: View = view.getChildAt(i)
for (i in 0 until (view as ViewGroup).childCount) {
val innerView: View = (view as ViewGroup).getChildAt(i)
setupUI(innerView)
}
}
@ -114,6 +190,24 @@ open class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), Br
activity.currentFocus!!.windowToken, 0
)
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// if (queryDayNight(newConfig) != dayNight) {
// ApplicationObserver.createdActivities.forEach {
// it.recreate()
// }
// }
}
// private fun queryDayNight(config: Configuration = resources.configuration): DayNight {
// return when (uiStore.darkMode) {
// DarkMode.Auto -> if (config.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) DayNight.Night else DayNight.Day
// DarkMode.ForceLight -> DayNight.Day
// DarkMode.ForceDark -> DayNight.Night
// }
// }
override fun onProfileChanged() {
events.trySend(Event.ProfileChanged)
}
@ -140,6 +234,12 @@ open class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), Br
override fun onStopped(cause: String?) {
events.trySend(Event.ClashStop)
// if (cause != null && activityStarted) {
// launch {
// design?.showExceptionToast(ClashException(cause))
// }
// }
}
enum class Event {
@ -170,6 +270,63 @@ open class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), Br
baseLoading?.cancel()
}
}
fun selectServer() {
val mmkv = MMKV.defaultMMKV()
val routerHost = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST, HashSet())
}
@Synchronized
fun switchServer(): Boolean {
var isChange = false
val mmkv = MMKV.defaultMMKV()
val originalUrl =
mmkv.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, BuildConfig.service_url)
var newUrlString = originalUrl
val routerHost = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST, HashSet())
routerHost?.let {
// it.forEach { url ->
// com.cncat.vpn.common.log.Log.d("url==>$url")
// }
if (it.isEmpty()) {
Log.d(Conf.TAG, "routerHost isEmpty")
return isChange
}
Log.d(Conf.TAG, "routerHost not empty")
val iterator = it.iterator()
while (iterator.hasNext()) {
val newUrl = iterator.next()
Log.e("Data", "遍历备用的url:$newUrl")
if (newUrl == originalUrl) {
iterator.remove()
} else {
Log.e("Retry", "切换到新url:$newUrl")
mmkv.encode(BZYConstants.MMKV_KEY_OLD_CURRENT_HOST, originalUrl)
isChange = true
newUrlString = newUrl
iterator.remove()
break
}
}
// mmkv.encode(BZYConstants.MMKV_KEY_ROUTER_HOST, routerHost)
mmkv.encode(BZYConstants.MMKV_KEY_CURRENT_HOST, newUrlString)
}
return isChange
}
@RequiresApi(Build.VERSION_CODES.M)
fun isNetworkAvailable(context: Context): Boolean {
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val network = connectivityManager.activeNetwork ?: return false
val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
}
@Synchronized
fun switchServer2(): Boolean {
var isChange = false
@ -178,38 +335,71 @@ open class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), Br
mmkv.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, BuildConfig.service_url)
var newUrlString = originalUrl
val routerHost = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST, HashSet())
val switchFinishSet = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_Switch_Finsh_Set, HashSet())
var switchFinshSet = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_Switch_Finsh_Set, HashSet())
routerHost?.let {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// if (!isNetworkAvailable(this@BaseActivity)){
// return isChange
// }
// }
if (it.isEmpty()) {
Log.d(Conf.TAG, "routerHost isEmpty")
return false
return isChange
}
com.cncat.vpn.common.log.Log.d("switchFinshSet.size==>${switchFinishSet?.size!!} , routerHost.size==>${routerHost.size}")
com.cncat.vpn.common.log.Log.d("switchFinshSet.size==>${switchFinshSet?.size!!} , routerHost.size==>${routerHost.size}")
//次数已满
if (switchFinishSet.size >= routerHost.size) {
return false
if (switchFinshSet?.size!! >= routerHost.size) {
return isChange
}
Log.d(Conf.TAG, "routerHost not empty")
// val iterator = it.iterator()
// while (iterator.hasNext()) {
// val newUrl = iterator.next()
// Log.e(
// "Data",
// "遍历备用的url:$newUrl, contains==>${switchFinshSet?.contains(newUrl)}"
// )
// if (newUrl == originalUrl) {
// switchFinshSet?.add(newUrl)
// iterator.remove()
// continue
// }
// if (switchFinshSet?.contains(newUrl) == true) {
// iterator.remove()
// } else {
// Log.e("Retry", "切换到新url:$newUrl")
// isChange = true
// newUrlString = newUrl
// iterator.remove()
// if (originalUrl != null) {
// switchFinshSet?.add(originalUrl)
// mmkv.encode(BZYConstants.MMKV_KEY_OLD_CURRENT_HOST, originalUrl)
// }
// break
// }
// }
for (url in it) {
if (url == originalUrl) {
switchFinishSet.add(url)
mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinishSet)
switchFinshSet?.add(url)
mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinshSet)
continue
}
if (switchFinishSet.contains(url)) {
if (switchFinshSet?.contains(url) == true) {
continue
} else {
isChange = true
Log.e("Retry", "切换到新url:$url")
android.util.Log.e("Retry", "切换到新url:$url")
newUrlString = url
switchFinishSet.add(newUrlString)
mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinishSet)
switchFinshSet?.add(newUrlString)
mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinshSet)
// mmkv.encode(BZYConstants.MMKV_KEY_OLD_CURRENT_HOST, newUrlString)
break
}
}
// mmkv.encode(BZYConstants.MMKV_KEY_ROUTER_HOST, routerHost)
mmkv.encode(BZYConstants.MMKV_KEY_CURRENT_HOST, newUrlString)
}

View File

@ -17,7 +17,7 @@ class Conf {
return context?.getString(R.string.app_name_taizi)!!
} else {
if (BuildConfig.is_ym) {
return context?.getString(R.string.WFApiPort)!!
return context?.getString(R.string.app_name_gz)!!
} else {
return context?.getString(R.string.app_name)!!
}

View File

@ -32,7 +32,7 @@ import com.yingmao.clash.R
import com.yingmao.clash.act.NewMainActivity
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.act.NewMainActivity.Companion.profileBinder
import com.yingmao.clash.conf.BZYConstants
import com.yingmao.clash.conf.Conf
import com.yingmao.clash.entity.ClashNodebBean
@ -43,6 +43,7 @@ import com.yingmao.clash.net.http.entity.AppStartupStatus
import com.yingmao.clash.service.ConnectionService
import com.yingmao.clash.util.ActivityResultLifecycle
import com.yingmao.clash.util.CommonUtils
import com.yingmao.clash.util.Utils
import com.yingmao.clash.util.startClashService
import com.yingmao.clash.util.stopClashService
import com.yingmao.clash.view.RxToast
@ -89,7 +90,7 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
// var currentNode: Profile? = null
private var reConnection = false
private var connectId=-1
private var baseLoading: RxDialogShapeLoading? = null
override fun init(
titleBarRl: RelativeLayout,
backIv: ImageView,
@ -182,7 +183,7 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
rxDialogSureCancel.show()
} else {
startClash()
startClash(false)
}
}
@ -220,25 +221,21 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
}
private fun startClash() {
if (checkExpire()) {
if (isAdded) {
RxToast.info(resources.getString(R.string.AccountExpired))
}
return
}
private fun startClash(isStart:Boolean) {
launch {
NewMainActivity.profileBinder?.let { pm ->
if(isStart){
delay(2000)
}
profileBinder?.let { pm ->
val active = pm.queryActive()
if (active == null) {
com.cncat.vpn.common.log.Log.d("startClash: 未选择")
Log.d("startClash: 未选择")
val pro = pm.queryAll().find {
it.name == Conf.getClashConfName(this@NewAccFragment.context)
}
pro?.let { profile ->
com.cncat.vpn.common.log.Log.d("new setactive name " + profile.name)
Log.d("new setactive name " + profile.name)
pm.setActive(profile)
newUuid = profile.uuid.toString();
@ -267,7 +264,6 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
stateChanged(Clash_Starting, true)
context?.startClashService()
accelerateViewModel.appStartupStatus()
// clashRunning = true
}
launch(Dispatchers.Main){
lottieView.playAnimation()
@ -285,6 +281,9 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
stop_u_timer()
e.printStackTrace()
}
withContext(Dispatchers.Main){
hideLoading()
}
}
}
@ -340,7 +339,7 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
Intents.ACTION_CLASH_REQUEST_STOP -> {
// clashRunning = false
com.cncat.vpn.common.log.Log.d("ACTION_CLASH_REQUEST_STOP")
Log.d("ACTION_CLASH_REQUEST_STOP")
if (::rxDialogShapeLoading.isInitialized) {
if (!rxDialogShapeLoading.isShowing) {
if (isAdded) {
@ -431,7 +430,7 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
if (clashRunning) {
Log.d("clashRunning $clashRunning")
} else {
startClash()
startClash(false)
}
} else {
if (::rxDialogShapeLoading.isInitialized || rxDialogShapeLoading.isShowing) {
@ -452,9 +451,7 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
checkGlo()
}?.run {
if (is_runing == true && !clashRunning) {
startClash()
} else {
startClash(false)
}
}
} else if (requestCode == Proxy_Mode_REQUEST_CODE) {
@ -528,7 +525,7 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
val validPeriod = MMKV.defaultMMKV().decodeLong(BZYConstants.MMKV_KEY_VPN_VALID_PERIOD)
if (validPeriod > 0) {
var nowTime = System.currentTimeMillis();
com.cncat.vpn.common.log.Log.d("validPeriod==>$validPeriod, nowTime==>$nowTime")
Log.d("validPeriod==>$validPeriod, nowTime==>$nowTime")
if (validPeriod >= nowTime) {
return false
}
@ -757,12 +754,12 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
if (clashRunning) {
Log.d("clashRunning $clashRunning")
} else {
startClash()
startClash(false)
}
checkGlo()
}?.run {
if (isRunning == true && !clashRunning) {
startClash()
startClash(false)
}
}
}
@ -791,10 +788,4 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
baseLoading?.cancel()
}
}
private fun goNewRecharge() {
if (activity != null) {
val newUiMain = activity as NewMainActivity
newUiMain.goBackupRechargeWeb()
}
}
}

View File

@ -389,18 +389,4 @@ class MainAtyVM : PublicViewMode() {
val requestBody: RequestBody = jsonString.toRequestBody("application/json; charset=utf-8".toMediaType())
doAsync(HttpReqType.Report){httpApi.getReport(paramsToken,requestBody)}
}
fun getExpensesRecord(page : NewMainActivity.PageInfo){
val httpApi = NetService.instances.createHttps(HttpApi::class.java)
val username = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME,"")!!
val phToken = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_PH_TOKEN,"")!!
val userId = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_USER_ID)!!
val params = hashMapOf<String,String>(
"phoneNumber" to username,
"userId" to userId,
"phToken" to phToken,
"pageno" to "${page.page}",
"pageSize" to "5",
)
doAsync(HttpReqType.EXPENSES_RECORD){httpApi.phOrderList(params)}
}
}

View File

@ -0,0 +1,307 @@
package com.yingmao.clash.webview
import android.app.Activity
import android.content.Intent
import android.content.pm.ActivityInfo
import android.net.Uri
import android.os.Bundle
import android.os.CountDownTimer
import android.text.TextUtils
import android.view.View
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import com.tencent.mmkv.MMKV
import com.yingmao.clash.BuildConfig
import com.yingmao.clash.R
import com.cncat.vpn.common.log.Log
import com.yingmao.clash.base.BaseActivity
import com.yingmao.clash.conf.BZYConstants
import com.yingmao.clash.listener.AsyncBodyCallback
import com.yingmao.clash.util.StatusBarUtils
import com.yingmao.clash.vm.LoginAtyVM
import com.yingmao.clash.vm.WebViewAtyVM
import java.net.URLDecoder
import java.net.URLEncoder
class BZYWebViewKeFu : BaseActivity() {
private lateinit var webView: WebView
private lateinit var webViewAtyVM: WebViewAtyVM
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.bzy_kefu_webview_layout)
// requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; //竖屏
// StatusBarUtils.with(this).init()
webViewAtyVM = ViewModelProvider(this).get(WebViewAtyVM::class.java)
observe(this, webViewAtyVM)
initView()
}
private fun initView() {
findViewById<View>(R.id.iv_back).setOnClickListener { finish() }
webView = findViewById(R.id.webView)
setWebView()
countDown()
}
private fun countDown() {
val timer = object : CountDownTimer(5000, 1000) {
override fun onTick(millisUntilFinished: Long) {
}
override fun onFinish() {
Log.d("onFinish")
webView.evaluateJavascript("updateStatus()", null)
}
}
timer.start()
}
private fun setWebView() {
Log.d("setWebView 1")
WebView.setWebContentsDebuggingEnabled(true)
Log.d("setWebView 2")
val settings = webView.settings
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
settings.allowFileAccess = true
Log.d("setWebView 4")
webView.webViewClient = object : WebViewClient() {
override fun onLoadResource(view: WebView, url: String) {
if (url.contains("https://image.crisp.chat/avatar/website") || url.contains("https://client.crisp.chat/static/javascripts/locales")) {
webView.evaluateJavascript("updateStatus()", null);
}
// Log.e("data", "==$url")
}
}
Log.d("setWebView 5")
// webView.webChromeClient = object : WebChromeClient() {
// override fun onProgressChanged(view: WebView?, newProgress: Int) {
//// Log.e("data", "==$newProgress")
// }
// }
when {
BuildConfig.is_ym -> {
ymKefu()
}
BuildConfig.is_tz -> {
getTzKefu()
}
BuildConfig.is_yunti -> {
getYunTiKefu()
}
else -> {
getBzyKefu()
}
}
}
private var kefuHost = ""
private fun ymKefu() {
val userName = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME, "")
var enNmae = URLEncoder.encode(userName, "UTF-8")
Log.d("enNmae==>${enNmae}")
if (TextUtils.isEmpty(kefuHost)) {
var mmkvHost = MMKV.defaultMMKV()
.decodeString(BZYConstants.MMKV_KEY_KEFU_HOST, "")
// com.cncat.vpn.common.log.Log.d("mmkvHost kf ==>${mmkvHost}")
webViewAtyVM.getYmKefuHost(object : AsyncBodyCallback {
override suspend fun suc(str: String) {
// com.cncat.vpn.common.log.Log.d("str==>${str}")
if (str != mmkvHost) {
MMKV.defaultMMKV()
.encode(BZYConstants.MMKV_KEY_KEFU_HOST, str)
}
// mmkvHost = str
kefuHost = str
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse(str + "&app_account=${enNmae}")
)
)
finish()
}
override fun err() {
if (!TextUtils.isEmpty(mmkvHost)) {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse(mmkvHost + "&app_account=${enNmae}")
)
)
finish()
}
}
})
} else {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse(kefuHost + "&app_account=${enNmae}")
)
)
finish()
}
}
private fun getBzyKefu() {
val userName = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME, "")
var enNmae = URLEncoder.encode(userName, "UTF-8")
Log.d("enNmae==>${enNmae}")
if (TextUtils.isEmpty(kefuHost)) {
var mmkvHost = MMKV.defaultMMKV()
.decodeString(BZYConstants.MMKV_KEY_KEFU_HOST, "")
// com.cncat.vpn.common.log.Log.d("mmkvHost kf ==>${mmkvHost}")
webViewAtyVM.getBzyKefuHost(object : AsyncBodyCallback {
override suspend fun suc(str: String) {
// com.cncat.vpn.common.log.Log.d("str==>${str}")
if (str != mmkvHost) {
MMKV.defaultMMKV()
.encode(BZYConstants.MMKV_KEY_KEFU_HOST, str)
}
// mmkvHost = str
kefuHost = str
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse(str + "&app_account=${enNmae}")
)
)
finish()
}
override fun err() {
if (!TextUtils.isEmpty(mmkvHost)) {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse(mmkvHost + "&app_account=${enNmae}")
)
)
finish()
}
}
})
} else {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse(kefuHost + "&app_account=${enNmae}")
)
)
finish()
}
}
private fun getTzKefu() {
val userName = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME, "")
var enNmae = URLEncoder.encode(userName, "UTF-8")
Log.d("enNmae==>${enNmae}")
if (TextUtils.isEmpty(kefuHost)) {
var mmkvHost = MMKV.defaultMMKV()
.decodeString(BZYConstants.MMKV_KEY_KEFU_HOST, "")
// com.cncat.vpn.common.log.Log.d("mmkvHost kf ==>${mmkvHost}")
webViewAtyVM.getTzKefuHost(object : AsyncBodyCallback {
override suspend fun suc(str: String) {
// com.cncat.vpn.common.log.Log.d("str==>${str}")
if (str != mmkvHost) {
MMKV.defaultMMKV()
.encode(BZYConstants.MMKV_KEY_KEFU_HOST, str)
}
// mmkvHost = str
kefuHost = str
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse(str + "&app_account=${enNmae}")
)
)
finish()
}
override fun err() {
if (!TextUtils.isEmpty(mmkvHost)) {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse(mmkvHost + "&app_account=${enNmae}")
)
)
finish()
}
}
})
} else {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse(kefuHost + "&app_account=${enNmae}")
)
)
finish()
}
}
private fun getYunTiKefu() {
val userName = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME, "")
var enNmae = URLEncoder.encode(userName, "UTF-8")
Log.d("enNmae==>${enNmae}")
if (TextUtils.isEmpty(kefuHost)) {
var mmkvHost = MMKV.defaultMMKV()
.decodeString(BZYConstants.MMKV_KEY_KEFU_HOST, "")
// com.cncat.vpn.common.log.Log.d("mmkvHost kf ==>${mmkvHost}")
webViewAtyVM.getYunTiKefuHost(object : AsyncBodyCallback {
override suspend fun suc(str: String) {
// com.cncat.vpn.common.log.Log.d("str==>${str}")
if (str != mmkvHost) {
MMKV.defaultMMKV()
.encode(BZYConstants.MMKV_KEY_KEFU_HOST, str)
}
kefuHost = str
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse(str + "&app_account=${enNmae}")
)
)
finish()
}
override fun err() {
if (!TextUtils.isEmpty(mmkvHost)) {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse(mmkvHost + "&app_account=${enNmae}")
)
)
finish()
}
}
})
} else {
startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse(kefuHost + "&app_account=${enNmae}")
)
)
finish()
}
}
}

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
>
<RelativeLayout
android:gravity="center"
android:id="@+id/rl_title_bar"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="30dp"
android:visibility="gone"
>
<ImageView
android:layout_centerVertical="true"
android:id="@+id/iv_back"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/ic_s_back" />
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toStartOf="@+id/iv_more"
android:layout_toEndOf="@+id/iv_back"
android:gravity="center"
android:text="@string/expenses_record"
android:textColor="@color/white"
android:textSize="21sp"
android:textStyle="bold" />
<ImageView
android:id="@+id/iv_more"
tools:ignore="ContentDescription"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignParentEnd="true"
android:src="@drawable/ic_s_back"
android:visibility="invisible" />
<TextView
android:id="@+id/tv_more"
tools:ignore="ContentDescription"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:text="线路测试"
android:layout_marginRight="20dp"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:gravity="center"
android:textColor="@color/yellow"
android:layout_alignParentEnd="true"
android:visibility="invisible" />
</RelativeLayout>
<FrameLayout
android:id="@+id/fl_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/rl_title_bar"
/>
</RelativeLayout>

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/ic_index_bg">
<RelativeLayout
android:layout_marginTop="20dp"
android:id="@+id/rl_title_bar"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text=""
android:textColor="@color/white"
android:textSize="21sp"
android:textStyle="bold"
/>
<ImageView
android:layout_centerVertical="true"
android:id="@+id/iv_back"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/ic_s_back"
android:contentDescription="@string/kefu"
/>
</RelativeLayout>
<WebView
android:layout_below="@+id/rl_title_bar"
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/main_bg" />
</RelativeLayout>

View File

@ -106,6 +106,8 @@ subprojects {
buildConfigField("boolean", "PREMIUM", "Boolean.parseBoolean(\"false\")")
buildConfigField("boolean", "is_back_cn", "false")
buildConfigField("boolean", "is_ym", "true")
buildConfigField("boolean", "is_tz", "false")
buildConfigField("boolean", "is_yunti", "false")
buildConfigField("String", "applicationId", "\"com.yingmao.clash\"")
buildConfigField("String", "service_url", "\"https://api.ymvpnpro.cc:8700\"")
buildConfigField("boolean", "is_free", "false")