Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8407fc5825 | ||
|
|
a3e49dcc3d | ||
|
|
7b47bbe99a | ||
|
|
0fb2165015 | ||
|
|
03eeeb9b62 | ||
|
|
038daf5fda | ||
|
|
bfd1387d9b | ||
|
|
5afec5cf25 | ||
|
|
ec29bdf5bf |
@@ -1,12 +1,13 @@
|
||||
# v2rayNG
|
||||
|
||||
A V2Ray client for Android
|
||||
A V2Ray client for Android, support [Xray core](https://github.com/XTLS/Xray-core) and [v2fly core](https://github.com/v2fly/v2ray-core)
|
||||
|
||||
[](https://developer.android.com/about/versions/jelly-bean#android-4.2)
|
||||
[](https://kotlinlang.org)
|
||||
[](https://github.com/2dust/v2rayNG/commits/master)
|
||||
[](https://www.codefactor.io/repository/github/2dust/v2rayng)
|
||||
[](https://github.com/2dust/v2rayNG/releases)
|
||||
[](https://t.me/v2rayn)
|
||||
|
||||
<a href="https://play.google.com/store/apps/details?id=com.v2ray.ang">
|
||||
<img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" width="165" height="64" />
|
||||
|
||||
@@ -64,11 +64,13 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
holder.radio.isChecked = (position == configs.index)
|
||||
holder.itemView.setBackgroundColor(Color.TRANSPARENT)
|
||||
holder.test_result.text = test_result
|
||||
|
||||
if (TextUtils.isEmpty(subid)) {
|
||||
holder.subid.text = ""
|
||||
} else {
|
||||
holder.subid.text = "S"
|
||||
holder.subscription.text = ""
|
||||
if (!TextUtils.isEmpty(subid)) {
|
||||
for (sub in configs.subItem) {
|
||||
if (sub.id == subid) {
|
||||
holder.subscription.text = sub.remarks
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var shareOptions = share_method.asList()
|
||||
@@ -211,7 +213,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
open class BaseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
|
||||
|
||||
class MainViewHolder(itemView: View) : BaseViewHolder(itemView), ItemTouchHelperViewHolder {
|
||||
val subid = itemView.tv_subid
|
||||
val subscription = itemView.tv_subscription
|
||||
val radio = itemView.btn_radio!!
|
||||
val name = itemView.tv_name!!
|
||||
val test_result = itemView.tv_test_result!!
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.os.Bundle
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.text.Editable
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import com.google.gson.Gson
|
||||
@@ -70,45 +69,32 @@ class Server2Activity : BaseActivity() {
|
||||
* save server config
|
||||
*/
|
||||
fun saveServer(): Boolean {
|
||||
var saveSuccess: Boolean
|
||||
val vmess = configs.vmess[edit_index]
|
||||
|
||||
vmess.remarks = et_remarks.text.toString()
|
||||
|
||||
if (TextUtils.isEmpty(vmess.remarks)) {
|
||||
toast(R.string.server_lab_remarks)
|
||||
saveSuccess = false
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
if (AngConfigManager.addCustomServer(vmess, edit_index) == 0) {
|
||||
toast(R.string.toast_success)
|
||||
saveSuccess = true
|
||||
} else {
|
||||
toast(R.string.toast_failure)
|
||||
saveSuccess = false
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
Gson().fromJson<Object>(tv_content.text.toString(), Object::class.java)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
toast(R.string.toast_malformed_josn)
|
||||
saveSuccess = false
|
||||
return false
|
||||
}
|
||||
|
||||
if (saveSuccess) {
|
||||
if (AngConfigManager.addCustomServer(vmess, edit_index) == 0) {
|
||||
//update config
|
||||
defaultDPreference.setPrefString(AppConfig.ANG_CONFIG + edit_guid, tv_content.text.toString())
|
||||
if (edit_index == configs.index) {
|
||||
if (!AngConfigManager.genStoreV2rayConfig(edit_index)) {
|
||||
Log.d(AppConfig.ANG_PACKAGE, "update custom config $edit_index but generate full configuration failed!")
|
||||
}
|
||||
}
|
||||
AngConfigManager.genStoreV2rayConfigIfActive(edit_index)
|
||||
toast(R.string.toast_success)
|
||||
finish()
|
||||
return true
|
||||
} else {
|
||||
toast(R.string.toast_failure)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ class Server3Activity : BaseActivity() {
|
||||
}
|
||||
|
||||
if (AngConfigManager.addShadowsocksServer(vmess, edit_index) == 0) {
|
||||
AngConfigManager.genStoreV2rayConfigIfActive(edit_index)
|
||||
toast(R.string.toast_success)
|
||||
finish()
|
||||
return true
|
||||
|
||||
@@ -96,6 +96,7 @@ class Server4Activity : BaseActivity() {
|
||||
}
|
||||
|
||||
if (AngConfigManager.addSocksServer(vmess, edit_index) == 0) {
|
||||
AngConfigManager.genStoreV2rayConfigIfActive(edit_index)
|
||||
toast(R.string.toast_success)
|
||||
finish()
|
||||
return true
|
||||
|
||||
@@ -155,6 +155,7 @@ class ServerActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
if (AngConfigManager.addServer(vmess, edit_index) == 0) {
|
||||
AngConfigManager.genStoreV2rayConfigIfActive(edit_index)
|
||||
toast(R.string.toast_success)
|
||||
finish()
|
||||
return true
|
||||
|
||||
@@ -155,7 +155,7 @@ object AngConfigManager {
|
||||
angConfig.index = index
|
||||
app.curIndex = index
|
||||
storeConfigFile()
|
||||
if (!genStoreV2rayConfig(index)) {
|
||||
if (!genStoreV2rayConfig()) {
|
||||
Log.d(AppConfig.ANG_PACKAGE, "set active index $index but generate full configuration failed!")
|
||||
return -1
|
||||
}
|
||||
@@ -179,35 +179,32 @@ object AngConfigManager {
|
||||
}
|
||||
}
|
||||
|
||||
fun genStoreV2rayConfigIfActive(index: Int) {
|
||||
if (index == configs.index) {
|
||||
if (!genStoreV2rayConfig()) {
|
||||
Log.d(AppConfig.ANG_PACKAGE, "update config $index but generate full configuration failed!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gen and store v2ray config file
|
||||
*/
|
||||
fun genStoreV2rayConfig(index: Int): Boolean {
|
||||
fun genStoreV2rayConfig(): Boolean {
|
||||
try {
|
||||
if (angConfig.index < 0
|
||||
|| angConfig.vmess.count() <= 0
|
||||
|| angConfig.index > angConfig.vmess.count() - 1
|
||||
) {
|
||||
return false
|
||||
}
|
||||
var index2 = angConfig.index
|
||||
if (index >= 0) {
|
||||
index2 = index
|
||||
}
|
||||
|
||||
val result = V2rayConfigUtil.getV2rayConfig(app, angConfig.vmess[index2])
|
||||
if (result.status) {
|
||||
app.defaultDPreference.setPrefString(PREF_CURR_CONFIG, result.content)
|
||||
app.defaultDPreference.setPrefString(PREF_CURR_CONFIG_GUID, currConfigGuid())
|
||||
app.defaultDPreference.setPrefString(PREF_CURR_CONFIG_NAME, currConfigName())
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
angConfig.vmess.getOrNull(angConfig.index)?.let {
|
||||
val result = V2rayConfigUtil.getV2rayConfig(app, it)
|
||||
if (result.status) {
|
||||
app.defaultDPreference.setPrefString(PREF_CURR_CONFIG, result.content)
|
||||
app.defaultDPreference.setPrefString(PREF_CURR_CONFIG_GUID, currConfigGuid())
|
||||
app.defaultDPreference.setPrefString(PREF_CURR_CONFIG_NAME, currConfigName())
|
||||
return true
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun currGeneratedV2rayConfig(): String {
|
||||
|
||||
@@ -458,12 +458,10 @@ object V2rayConfigUtil {
|
||||
rulesIP.outboundTag = tag
|
||||
rulesIP.ip = ArrayList<String>()
|
||||
|
||||
userRule.trim().replace("\n", "")
|
||||
.split(",")
|
||||
.forEach {
|
||||
userRule.split(",").map { it.trim() }.forEach {
|
||||
if (Utils.isIpAddress(it) || it.startsWith("geoip:")) {
|
||||
rulesIP.ip?.add(it)
|
||||
} else if (it.isNotBlank() || it.isNotEmpty())
|
||||
} else if (it.isNotEmpty())
|
||||
// if (Utils.isValidUrl(it)
|
||||
// || it.startsWith("geosite:")
|
||||
// || it.startsWith("regexp:")
|
||||
@@ -487,9 +485,8 @@ object V2rayConfigUtil {
|
||||
|
||||
private fun userRule2Domian(userRule: String): ArrayList<String> {
|
||||
val domain = ArrayList<String>()
|
||||
userRule.trim().replace("\n", "").split(",").forEach {
|
||||
if ((it.startsWith("geosite:") || it.startsWith("domain:")) &&
|
||||
it.isNotBlank() && it.isNotEmpty()) {
|
||||
userRule.split(",").map { it.trim() }.forEach {
|
||||
if (it.startsWith("geosite:") || it.startsWith("domain:")) {
|
||||
domain.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
|
||||
AppConfig.PREF_V2RAY_ROUTING_BLOCKED,
|
||||
AppConfig.PREF_V2RAY_ROUTING_DIRECT -> {
|
||||
GlobalScope.launch {
|
||||
if (!AngConfigManager.genStoreV2rayConfig(AngConfigManager.configs.index)) {
|
||||
if (!AngConfigManager.genStoreV2rayConfig()) {
|
||||
Log.d(AppConfig.ANG_PACKAGE, "$key changed but generate full configuration failed!")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/item_bg"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/item_bg"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||
<android.support.v7.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="3dp"
|
||||
card_view:cardCornerRadius="5dp">
|
||||
app:cardCornerRadius="5dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/info_container"
|
||||
@@ -18,34 +20,19 @@
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:nextFocusRight="@+id/layout_share">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_subid"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
||||
|
||||
<android.support.v7.widget.AppCompatRadioButton
|
||||
<android.support.v7.widget.AppCompatRadioButton
|
||||
android:id="@+id/btn_radio"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -85,20 +72,31 @@
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="right"
|
||||
android:orientation="vertical"
|
||||
android:paddingEnd="5dp">
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingEnd="5dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_test_result"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:lines="1"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textColor="@color/colorPing"
|
||||
android:textSize="10sp" />
|
||||
android:id="@+id/tv_subscription"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:lines="1"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textColor="@color/colorSubscription"
|
||||
android:textSize="10sp"
|
||||
tools:text="Sub" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_test_result"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:lines="1"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textColor="@color/colorPing"
|
||||
android:textSize="10sp"
|
||||
tools:text="214ms" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
@@ -185,4 +183,4 @@
|
||||
</LinearLayout>
|
||||
|
||||
</android.support.v7.widget.CardView>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -9,4 +9,5 @@
|
||||
<color name="icons">#FFFFFF</color>
|
||||
<color name="divider">#BDBDBD</color>
|
||||
<color name="colorPing">#185534</color>
|
||||
<color name="colorSubscription">#247BA0</color>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user