Compare commits
108 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17af24d179 | ||
|
|
c260e447ea | ||
|
|
0eb40ae993 | ||
|
|
18f3e39346 | ||
|
|
311af02726 | ||
|
|
b799969de8 | ||
|
|
93541883bb | ||
|
|
33430bff8d | ||
|
|
3bc2081540 | ||
|
|
a3b1feabff | ||
|
|
7af8d3843e | ||
|
|
2235805800 | ||
|
|
364b521ec3 | ||
|
|
3cdaf4a8ee | ||
|
|
b2fc6dcdd0 | ||
|
|
70e9320463 | ||
|
|
304c7ed068 | ||
|
|
ddb908f937 | ||
|
|
accd17afd4 | ||
|
|
9f598b77b4 | ||
|
|
d82fa974b1 | ||
|
|
fcbd4a0d48 | ||
|
|
5cd2b8845e | ||
|
|
723ab70170 | ||
|
|
a26bf3eeda | ||
|
|
c33b6463c6 | ||
|
|
df995a3ab2 | ||
|
|
817f844212 | ||
|
|
fa8113b8d7 | ||
|
|
99b95d8369 | ||
|
|
fc2e4ff210 | ||
|
|
1063bf71d6 | ||
|
|
f2af5c45e9 | ||
|
|
b132b0d2f0 | ||
|
|
7869f99fc8 | ||
|
|
122f2eb400 | ||
|
|
3c0f6eeb21 | ||
|
|
19a109355b | ||
|
|
703965a0dd | ||
|
|
66f92c6c60 | ||
|
|
a1cdf6b7a5 | ||
|
|
554c7b5687 | ||
|
|
2d987313a7 | ||
|
|
9eebe32bdf | ||
|
|
8e9da0ad6f | ||
|
|
2f20dea611 | ||
|
|
167baf64a9 | ||
|
|
bd7a214f7f | ||
|
|
f16d2d9a74 | ||
|
|
e984d2c274 | ||
|
|
8720d087ea | ||
|
|
a1e19b9fcd | ||
|
|
6b9728dc84 | ||
|
|
1ce9b7c0c8 | ||
|
|
ff75d3fdc2 | ||
|
|
8154812570 | ||
|
|
1dcd2478fc | ||
|
|
0515806e92 | ||
|
|
f286506ba4 | ||
|
|
48be736275 | ||
|
|
af0faeab16 | ||
|
|
fb6edee842 | ||
|
|
1209c4b92a | ||
|
|
e4e668b492 | ||
|
|
92d3136a23 | ||
|
|
f6e74ddb45 | ||
|
|
c34f332771 | ||
|
|
eb1d71bda6 | ||
|
|
3cdd5822cb | ||
|
|
8f924b5ce1 | ||
|
|
2ae645dce5 | ||
|
|
f848a7119f | ||
|
|
2fa41db32f | ||
|
|
9af4516761 | ||
|
|
189b07124d | ||
|
|
e6e5cdcdcd | ||
|
|
a31e4dab85 | ||
|
|
b2a9397dc7 | ||
|
|
a536df1a02 | ||
|
|
1a2751563d | ||
|
|
2dc82b7e83 | ||
|
|
b02d81ae53 | ||
|
|
773bcc5658 | ||
|
|
9142b9cfb4 | ||
|
|
376882d975 | ||
|
|
f330c32ccc | ||
|
|
58dbb71b53 | ||
|
|
ebd0257f6e | ||
|
|
945c584fc6 | ||
|
|
19cd24c37a | ||
|
|
3994810c4e | ||
|
|
d86e68c77a | ||
|
|
cc7bdefe54 | ||
|
|
51b32a030a | ||
|
|
6c76ddd145 | ||
|
|
0d12cc5dc8 | ||
|
|
cfb756723c | ||
|
|
0e9f198341 | ||
|
|
1fa1325630 | ||
|
|
dc79d3a897 | ||
|
|
486f3ffc96 | ||
|
|
bf030e12f5 | ||
|
|
e80cce9696 | ||
|
|
5bb9ecce47 | ||
|
|
5eb09aa54e | ||
|
|
ff261d9939 | ||
|
|
1624ec87b2 | ||
|
|
f1062f2f45 |
11
.github/workflows/build.yml
vendored
11
.github/workflows/build.yml
vendored
@@ -12,11 +12,11 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21.4'
|
||||
go-version: '1.22.2'
|
||||
|
||||
- name: Install gomobile
|
||||
run: |
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
- name: Setup Android environment
|
||||
uses: android-actions/setup-android@v3
|
||||
|
||||
|
||||
|
||||
- name: Build dependencies
|
||||
run: |
|
||||
@@ -53,8 +53,7 @@ jobs:
|
||||
- name: Build APK
|
||||
run: |
|
||||
cd ${{ github.workspace }}/V2rayNG
|
||||
chmod 777 *
|
||||
sed -i 's/org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8/org.gradle.jvmargs=-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8/' ${{ github.workspace }}/V2rayNG/gradle.properties
|
||||
chmod 755 gradlew
|
||||
./gradlew assembleDebug
|
||||
|
||||
- name: Upload APK
|
||||
|
||||
@@ -11,8 +11,8 @@ android {
|
||||
applicationId = "com.v2ray.ang"
|
||||
minSdk = 21
|
||||
targetSdk = 34
|
||||
versionCode = 548
|
||||
versionName = "1.8.17"
|
||||
versionCode = 558
|
||||
versionName = "1.8.22"
|
||||
multiDexEnabled = true
|
||||
}
|
||||
|
||||
@@ -96,22 +96,21 @@ dependencies {
|
||||
implementation("androidx.viewpager2:viewpager2:1.1.0-beta02")
|
||||
|
||||
// Androidx ktx
|
||||
implementation("androidx.activity:activity-ktx:1.8.2")
|
||||
implementation("androidx.activity:activity-ktx:1.9.0")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
|
||||
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
|
||||
|
||||
//kotlin
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.22")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.23")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0")
|
||||
|
||||
implementation("com.tencent:mmkv-static:1.3.3")
|
||||
implementation("com.tencent:mmkv-static:1.3.4")
|
||||
implementation("com.google.code.gson:gson:2.10.1")
|
||||
implementation("io.reactivex:rxjava:1.3.8")
|
||||
implementation("io.reactivex:rxandroid:1.2.1")
|
||||
implementation("com.tbruyelle.rxpermissions:rxpermissions:0.9.4@aar")
|
||||
implementation("com.github.jorgecastilloprz:fabprogresscircle:1.01@aar")
|
||||
implementation("me.drakeet.support:toastcompat:1.1.0")
|
||||
implementation("com.blacksquircle.ui:editorkit:2.9.0")
|
||||
implementation("com.blacksquircle.ui:language-base:2.9.0")
|
||||
|
||||
@@ -127,6 +127,9 @@
|
||||
<data android:host="install-sub"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:exported="false"
|
||||
android:name=".ui.AboutActivity" />
|
||||
|
||||
<service
|
||||
android:name=".service.V2RayVpnService"
|
||||
|
||||
@@ -1,132 +1,2 @@
|
||||
domain:12306.com,
|
||||
domain:51ym.me,
|
||||
domain:52pojie.cn,
|
||||
domain:8686c.com,
|
||||
domain:abercrombie.com,
|
||||
domain:adobesc.com,
|
||||
domain:air-matters.com,
|
||||
domain:air-matters.io,
|
||||
domain:airtable.com,
|
||||
domain:akadns.net,
|
||||
domain:apache.org,
|
||||
domain:api.crisp.chat,
|
||||
domain:api.termius.com,
|
||||
domain:appshike.com,
|
||||
domain:appstore.com,
|
||||
domain:aweme.snssdk.com,
|
||||
domain:bababian.com,
|
||||
domain:battle.net,
|
||||
domain:beatsbydre.com,
|
||||
domain:bet365.com,
|
||||
domain:bilibili.cn,
|
||||
domain:ccgslb.com,
|
||||
domain:ccgslb.net,
|
||||
domain:chunbo.com,
|
||||
domain:chunboimg.com,
|
||||
domain:clashroyaleapp.com,
|
||||
domain:cloudsigma.com,
|
||||
domain:cloudxns.net,
|
||||
domain:cmfu.com,
|
||||
domain:culturedcode.com,
|
||||
domain:dct-cloud.com,
|
||||
domain:didialift.com,
|
||||
domain:douyutv.com,
|
||||
domain:duokan.com,
|
||||
domain:dytt8.net,
|
||||
domain:easou.com,
|
||||
domain:ecitic.net,
|
||||
domain:eclipse.org,
|
||||
domain:eudic.net,
|
||||
domain:ewqcxz.com,
|
||||
domain:fir.im,
|
||||
domain:frdic.com,
|
||||
domain:fresh-ideas.cc,
|
||||
domain:godic.net,
|
||||
domain:goodread.com,
|
||||
domain:haibian.com,
|
||||
domain:hdslb.net,
|
||||
domain:hollisterco.com,
|
||||
domain:hongxiu.com,
|
||||
domain:hxcdn.net,
|
||||
domain:images.unsplash.com,
|
||||
domain:img4me.com,
|
||||
domain:ipify.org,
|
||||
domain:ixdzs.com,
|
||||
domain:jd.hk,
|
||||
domain:jianshuapi.com,
|
||||
domain:jomodns.com,
|
||||
domain:jsboxbbs.com,
|
||||
domain:knewone.com,
|
||||
domain:kuaidi100.com,
|
||||
domain:lemicp.com,
|
||||
domain:letvcloud.com,
|
||||
domain:lizhi.io,
|
||||
domain:localizecdn.com,
|
||||
domain:lucifr.com,
|
||||
domain:luoo.net,
|
||||
domain:mai.tn,
|
||||
domain:maven.org,
|
||||
domain:miwifi.com,
|
||||
domain:moji.com,
|
||||
domain:moke.com,
|
||||
domain:mtalk.google.com,
|
||||
domain:mxhichina.com,
|
||||
domain:myqcloud.com,
|
||||
domain:myunlu.com,
|
||||
domain:netease.com,
|
||||
domain:nfoservers.com,
|
||||
domain:nssurge.com,
|
||||
domain:nuomi.com,
|
||||
domain:ourdvs.com,
|
||||
domain:overcast.fm,
|
||||
domain:paypal.com,
|
||||
domain:paypalobjects.com,
|
||||
domain:pgyer.com,
|
||||
domain:qdaily.com,
|
||||
domain:qdmm.com,
|
||||
domain:qin.io,
|
||||
domain:qingmang.me,
|
||||
domain:qingmang.mobi,
|
||||
domain:qqurl.com,
|
||||
domain:rarbg.to,
|
||||
domain:rrmj.tv,
|
||||
domain:ruguoapp.com,
|
||||
domain:sm.ms,
|
||||
domain:snwx.com,
|
||||
domain:soku.com,
|
||||
domain:startssl.com,
|
||||
domain:store.steampowered.com,
|
||||
domain:symcd.com,
|
||||
domain:teamviewer.com,
|
||||
domain:tmzvps.com,
|
||||
domain:trello.com,
|
||||
domain:trellocdn.com,
|
||||
domain:ttmeiju.com,
|
||||
domain:udache.com,
|
||||
domain:uxengine.net,
|
||||
domain:weather.bjango.com,
|
||||
domain:weather.com,
|
||||
domain:webqxs.com,
|
||||
domain:weico.cc,
|
||||
domain:wenku8.net,
|
||||
domain:werewolf.53site.com,
|
||||
domain:windowsupdate.com,
|
||||
domain:wkcdn.com,
|
||||
domain:workflowy.com,
|
||||
domain:xdrig.com,
|
||||
domain:xiaojukeji.com,
|
||||
domain:xiaomi.net,
|
||||
domain:xiaomicp.com,
|
||||
domain:ximalaya.com,
|
||||
domain:xitek.com,
|
||||
domain:xmcdn.com,
|
||||
domain:xslb.net,
|
||||
domain:xteko.com,
|
||||
domain:yach.me,
|
||||
domain:yixia.com,
|
||||
domain:yunjiasu-cdn.net,
|
||||
domain:zealer.com,
|
||||
domain:zgslb.net,
|
||||
domain:zimuzu.tv,
|
||||
domain:zmz002.com,
|
||||
domain:samsungdm.com,
|
||||
geosite:cn,
|
||||
geosite:geolocation-cn
|
||||
@@ -1,33 +1 @@
|
||||
geosite:google,
|
||||
geosite:github,
|
||||
geosite:netflix,
|
||||
geosite:steam,
|
||||
geosite:telegram,
|
||||
geosite:tumblr,
|
||||
geosite:speedtest,
|
||||
geosite:bbc,
|
||||
domain:gvt1.com,
|
||||
domain:textnow.com,
|
||||
domain:twitch.tv,
|
||||
domain:wikileaks.org,
|
||||
domain:naver.com,
|
||||
91.108.4.0/22,
|
||||
91.108.8.0/22,
|
||||
91.108.12.0/22,
|
||||
91.108.20.0/22,
|
||||
91.108.36.0/23,
|
||||
91.108.38.0/23,
|
||||
91.108.56.0/22,
|
||||
149.154.160.0/20,
|
||||
149.154.164.0/22,
|
||||
149.154.172.0/22,
|
||||
74.125.0.0/16,
|
||||
173.194.0.0/16,
|
||||
172.217.0.0/16,
|
||||
216.58.200.0/24,
|
||||
216.58.220.0/24,
|
||||
91.108.56.116,
|
||||
91.108.56.0/24,
|
||||
109.239.140.0/24,
|
||||
149.154.167.0/24,
|
||||
149.154.175.0/24,
|
||||
geosite:geolocation-!cn
|
||||
@@ -2,13 +2,13 @@ package com.v2ray.ang
|
||||
|
||||
import android.content.Context
|
||||
import androidx.multidex.MultiDexApplication
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.work.Configuration
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.util.Utils
|
||||
|
||||
class AngApplication : MultiDexApplication(), Configuration.Provider {
|
||||
companion object {
|
||||
const val PREF_LAST_VERSION = "pref_last_version"
|
||||
//const val PREF_LAST_VERSION = "pref_last_version"
|
||||
lateinit var application: AngApplication
|
||||
}
|
||||
|
||||
@@ -17,21 +17,23 @@ class AngApplication : MultiDexApplication(), Configuration.Provider {
|
||||
application = this
|
||||
}
|
||||
|
||||
var firstRun = false
|
||||
private set
|
||||
//var firstRun = false
|
||||
// private set
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
// LeakCanary.install(this)
|
||||
|
||||
val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
firstRun = defaultSharedPreferences.getInt(PREF_LAST_VERSION, 0) != BuildConfig.VERSION_CODE
|
||||
if (firstRun)
|
||||
defaultSharedPreferences.edit().putInt(PREF_LAST_VERSION, BuildConfig.VERSION_CODE).apply()
|
||||
// val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
// firstRun = defaultSharedPreferences.getInt(PREF_LAST_VERSION, 0) != BuildConfig.VERSION_CODE
|
||||
// if (firstRun)
|
||||
// defaultSharedPreferences.edit().putInt(PREF_LAST_VERSION, BuildConfig.VERSION_CODE).apply()
|
||||
|
||||
//Logger.init().logLevel(if (BuildConfig.DEBUG) LogLevel.FULL else LogLevel.NONE)
|
||||
MMKV.initialize(this)
|
||||
|
||||
Utils.setNightMode(application)
|
||||
}
|
||||
|
||||
override fun getWorkManagerConfiguration(): Configuration {
|
||||
|
||||
@@ -7,48 +7,65 @@ package com.v2ray.ang
|
||||
object AppConfig {
|
||||
const val ANG_PACKAGE = BuildConfig.APPLICATION_ID
|
||||
const val DIR_ASSETS = "assets"
|
||||
const val DIR_BACKUPS = "backups"
|
||||
|
||||
// legacy
|
||||
const val ANG_CONFIG = "ang_config"
|
||||
const val PREF_INAPP_BUY_IS_PREMIUM = "pref_inapp_buy_is_premium"
|
||||
const val PREF_ROUTING_CUSTOM = "pref_routing_custom"
|
||||
|
||||
// Preferences mapped to MMKV
|
||||
const val PREF_MODE = "pref_mode"
|
||||
const val PREF_SPEED_ENABLED = "pref_speed_enabled"
|
||||
const val PREF_SNIFFING_ENABLED = "pref_sniffing_enabled"
|
||||
const val PREF_PROXY_SHARING = "pref_proxy_sharing_enabled"
|
||||
const val PREF_PER_APP_PROXY = "pref_per_app_proxy"
|
||||
const val PREF_PER_APP_PROXY_SET = "pref_per_app_proxy_set"
|
||||
const val PREF_BYPASS_APPS = "pref_bypass_apps"
|
||||
const val PREF_LOCAL_DNS_ENABLED = "pref_local_dns_enabled"
|
||||
const val PREF_FAKE_DNS_ENABLED = "pref_fake_dns_enabled"
|
||||
const val PREF_VPN_DNS = "pref_vpn_dns"
|
||||
const val PREF_REMOTE_DNS = "pref_remote_dns"
|
||||
const val PREF_DOMESTIC_DNS = "pref_domestic_dns"
|
||||
const val PREF_LOCAL_DNS_PORT = "pref_local_dns_port"
|
||||
const val PREF_ALLOW_INSECURE = "pref_allow_insecure"
|
||||
const val PREF_SOCKS_PORT = "pref_socks_port"
|
||||
const val PREF_HTTP_PORT = "pref_http_port"
|
||||
const val PREF_LOGLEVEL = "pref_core_loglevel"
|
||||
const val PREF_LANGUAGE = "pref_language"
|
||||
const val PREF_PREFER_IPV6 = "pref_prefer_ipv6"
|
||||
const val PREF_VPN_DNS = "pref_vpn_dns"
|
||||
|
||||
const val PREF_ROUTING_DOMAIN_STRATEGY = "pref_routing_domain_strategy"
|
||||
const val PREF_ROUTING_MODE = "pref_routing_mode"
|
||||
const val PREF_V2RAY_ROUTING_AGENT = "pref_v2ray_routing_agent"
|
||||
const val PREF_V2RAY_ROUTING_DIRECT = "pref_v2ray_routing_direct"
|
||||
const val PREF_V2RAY_ROUTING_BLOCKED = "pref_v2ray_routing_blocked"
|
||||
const val PREF_PER_APP_PROXY = "pref_per_app_proxy"
|
||||
const val PREF_PER_APP_PROXY_SET = "pref_per_app_proxy_set"
|
||||
const val PREF_BYPASS_APPS = "pref_bypass_apps"
|
||||
const val PREF_CONFIRM_REMOVE = "pref_confirm_remove"
|
||||
const val PREF_START_SCAN_IMMEDIATE = "pref_start_scan_immediate"
|
||||
const val PREF_ROUTING_CUSTOM = "pref_routing_custom"
|
||||
|
||||
const val PREF_MUX_ENABLED = "pref_mux_enabled"
|
||||
const val PREF_MUX_CONCURRENCY = "pref_mux_concurency"
|
||||
const val PREF_MUX_XUDP_CONCURRENCY = "pref_mux_xudp_concurency"
|
||||
const val PREF_MUX_XUDP_QUIC = "pref_mux_xudp_quic"
|
||||
|
||||
const val PREF_FRAGMENT_ENABLED = "pref_fragment_enabled"
|
||||
const val PREF_FRAGMENT_PACKETS = "pref_fragment_packets"
|
||||
const val PREF_FRAGMENT_LENGTH = "pref_fragment_length"
|
||||
const val PREF_FRAGMENT_INTERVAL = "pref_fragment_interval"
|
||||
|
||||
const val SUBSCRIPTION_AUTO_UPDATE = "pref_auto_update_subscription"
|
||||
const val SUBSCRIPTION_AUTO_UPDATE_INTERVAL = "pref_auto_update_interval"
|
||||
const val SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL = "1440" // 24 hours
|
||||
const val SUBSCRIPTION_UPDATE_TASK_NAME = "subscription_updater"
|
||||
|
||||
const val PREF_SPEED_ENABLED = "pref_speed_enabled"
|
||||
const val PREF_CONFIRM_REMOVE = "pref_confirm_remove"
|
||||
const val PREF_START_SCAN_IMMEDIATE = "pref_start_scan_immediate"
|
||||
const val PREF_LANGUAGE = "pref_language"
|
||||
const val PREF_UI_MODE_NIGHT = "pref_ui_mode_night"
|
||||
|
||||
const val PREF_PREFER_IPV6 = "pref_prefer_ipv6"
|
||||
const val PREF_PROXY_SHARING = "pref_proxy_sharing_enabled"
|
||||
const val PREF_ALLOW_INSECURE = "pref_allow_insecure"
|
||||
const val PREF_SOCKS_PORT = "pref_socks_port"
|
||||
const val PREF_HTTP_PORT = "pref_http_port"
|
||||
const val PREF_REMOTE_DNS = "pref_remote_dns"
|
||||
const val PREF_DOMESTIC_DNS = "pref_domestic_dns"
|
||||
const val PREF_LOGLEVEL = "pref_core_loglevel"
|
||||
const val PREF_MODE = "pref_mode"
|
||||
|
||||
const val CACHE_SUBSCRIPTION_ID = "cache_subscription_id"
|
||||
const val CACHE_KEYWORD_FILTER = "cache_keyword_filter"
|
||||
|
||||
//Preferences mapped to MMKV End
|
||||
|
||||
const val PROTOCOL_HTTP: String = "http://"
|
||||
const val PROTOCOL_HTTPS: String = "https://"
|
||||
const val PROTOCOL_FREEDOM: String = "freedom"
|
||||
@@ -63,7 +80,7 @@ object AppConfig {
|
||||
const val TASKER_EXTRA_BUNDLE_GUID = "tasker_extra_bundle_guid"
|
||||
const val TASKER_DEFAULT_GUID = "Default"
|
||||
|
||||
const val TAG_AGENT = "proxy"
|
||||
const val TAG_PROXY = "proxy"
|
||||
const val TAG_DIRECT = "direct"
|
||||
const val TAG_BLOCKED = "block"
|
||||
const val TAG_FRAGMENT = "fragment"
|
||||
@@ -72,14 +89,17 @@ object AppConfig {
|
||||
"https://raw.githubusercontent.com/2dust/androidpackagenamelist/master/proxy.txt"
|
||||
const val v2rayCustomRoutingListUrl =
|
||||
"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/"
|
||||
const val v2rayNGIssues = "https://github.com/2dust/v2rayNG/issues"
|
||||
const val v2rayNGWikiMode = "https://github.com/2dust/v2rayNG/wiki/Mode"
|
||||
const val v2rayNGUrl = "https://github.com/2dust/v2rayNG"
|
||||
const val v2rayNGIssues = "$v2rayNGUrl/issues"
|
||||
const val v2rayNGWikiMode = "$v2rayNGUrl/wiki/Mode"
|
||||
const val v2rayNGPrivacyPolicy = "https://raw.githubusercontent.com/2dust/v2rayNG/master/CR.md"
|
||||
const val promotionUrl = "aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw="
|
||||
const val geoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/"
|
||||
const val PromotionUrl = "aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw="
|
||||
const val GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/"
|
||||
const val TgChannelUrl = "https://t.me/github_2dust"
|
||||
|
||||
const val DNS_AGENT = "1.1.1.1"
|
||||
const val DNS_PROXY = "1.1.1.1"
|
||||
const val DNS_DIRECT = "223.5.5.5"
|
||||
const val DNS_VPN = "1.1.1.1"
|
||||
|
||||
const val PORT_LOCAL_DNS = "10853"
|
||||
const val PORT_SOCKS = "10808"
|
||||
@@ -103,13 +123,4 @@ object AppConfig {
|
||||
const val MSG_MEASURE_CONFIG = 7
|
||||
const val MSG_MEASURE_CONFIG_SUCCESS = 71
|
||||
const val MSG_MEASURE_CONFIG_CANCEL = 72
|
||||
|
||||
// subscription settings
|
||||
const val SUBSCRIPTION_AUTO_UPDATE = "pref_auto_update_subscription"
|
||||
const val SUBSCRIPTION_AUTO_UPDATE_INTERVAL = "pref_auto_update_interval"
|
||||
const val SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL = "1440" // 24 hours
|
||||
const val SUBSCRIPTION_UPDATE_TASK_NAME = "subscription_updater"
|
||||
|
||||
const val CACHE_SUBSCRIPTION_ID = "cache_subscription_id"
|
||||
const val CACHE_KEYWORD_FILTER = "cache_keyword_filter"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.v2ray.ang.dto
|
||||
|
||||
import com.v2ray.ang.AppConfig.TAG_AGENT
|
||||
import com.v2ray.ang.AppConfig.TAG_PROXY
|
||||
import com.v2ray.ang.AppConfig.TAG_BLOCKED
|
||||
import com.v2ray.ang.AppConfig.TAG_DIRECT
|
||||
import com.v2ray.ang.util.Utils
|
||||
@@ -58,7 +58,7 @@ data class ServerConfig(
|
||||
|
||||
fun getAllOutboundTags(): MutableList<String> {
|
||||
if (configType != EConfigType.CUSTOM) {
|
||||
return mutableListOf(TAG_AGENT, TAG_DIRECT, TAG_BLOCKED)
|
||||
return mutableListOf(TAG_PROXY, TAG_DIRECT, TAG_BLOCKED)
|
||||
}
|
||||
fullConfig?.let { config ->
|
||||
return config.outbounds.map { it.tag }.toMutableList()
|
||||
|
||||
@@ -22,7 +22,9 @@ data class V2rayConfig(
|
||||
val transport: Any? = null,
|
||||
val reverse: Any? = null,
|
||||
var fakedns: Any? = null,
|
||||
val browserForwarder: Any? = null) {
|
||||
val browserForwarder: Any? = null,
|
||||
var observatory: Any? = null,
|
||||
var burstObservatory: Any? = null) {
|
||||
companion object {
|
||||
const val DEFAULT_PORT = 443
|
||||
const val DEFAULT_SECURITY = "auto"
|
||||
@@ -135,6 +137,7 @@ data class V2rayConfig(
|
||||
var tcpSettings: TcpSettingsBean? = null,
|
||||
var kcpSettings: KcpSettingsBean? = null,
|
||||
var wsSettings: WsSettingsBean? = null,
|
||||
var httpupgradeSettings: HttpupgradeSettingsBean? = null,
|
||||
var httpSettings: HttpSettingsBean? = null,
|
||||
var tlsSettings: TlsSettingsBean? = null,
|
||||
var quicSettings: QuicSettingBean? = null,
|
||||
@@ -184,6 +187,10 @@ data class V2rayConfig(
|
||||
data class HeadersBean(var Host: String = "")
|
||||
}
|
||||
|
||||
data class HttpupgradeSettingsBean(var path: String = "",
|
||||
var host: String = "",
|
||||
val acceptProxyProtocol: Boolean? = null)
|
||||
|
||||
data class HttpSettingsBean(var host: List<String> = ArrayList(),
|
||||
var path: String = "")
|
||||
|
||||
@@ -218,10 +225,12 @@ data class V2rayConfig(
|
||||
}
|
||||
|
||||
data class GrpcSettingsBean(var serviceName: String = "",
|
||||
var authority: String? = null,
|
||||
var multiMode: Boolean? = null)
|
||||
|
||||
fun populateTransportSettings(transport: String, headerType: String?, host: String?, path: String?, seed: String?,
|
||||
quicSecurity: String?, key: String?, mode: String?, serviceName: String?): String {
|
||||
quicSecurity: String?, key: String?, mode: String?, serviceName: String?,
|
||||
authority: String?): String {
|
||||
var sni = ""
|
||||
network = transport
|
||||
when (network) {
|
||||
@@ -259,6 +268,13 @@ data class V2rayConfig(
|
||||
wssetting.path = path ?: "/"
|
||||
wsSettings = wssetting
|
||||
}
|
||||
"httpupgrade" -> {
|
||||
val httpupgradeSetting = HttpupgradeSettingsBean()
|
||||
httpupgradeSetting.host = host ?: ""
|
||||
sni = httpupgradeSetting.host
|
||||
httpupgradeSetting.path = path ?: "/"
|
||||
httpupgradeSettings = httpupgradeSetting
|
||||
}
|
||||
"h2", "http" -> {
|
||||
network = "h2"
|
||||
val h2Setting = HttpSettingsBean()
|
||||
@@ -278,7 +294,8 @@ data class V2rayConfig(
|
||||
val grpcSetting = GrpcSettingsBean()
|
||||
grpcSetting.multiMode = mode == "multi"
|
||||
grpcSetting.serviceName = serviceName ?: ""
|
||||
sni = host ?: ""
|
||||
grpcSetting.authority = authority ?: ""
|
||||
sni = authority ?: ""
|
||||
grpcSettings = grpcSetting
|
||||
}
|
||||
}
|
||||
@@ -367,7 +384,8 @@ data class V2rayConfig(
|
||||
fun getTransportSettingDetails(): List<String>? {
|
||||
if (protocol.equals(EConfigType.VMESS.name, true)
|
||||
|| protocol.equals(EConfigType.VLESS.name, true)
|
||||
|| protocol.equals(EConfigType.TROJAN.name, true)) {
|
||||
|| protocol.equals(EConfigType.TROJAN.name, true)
|
||||
|| protocol.equals(EConfigType.SHADOWSOCKS.name, true)) {
|
||||
val transport = streamSettings?.network ?: return null
|
||||
return when (transport) {
|
||||
"tcp" -> {
|
||||
@@ -388,6 +406,12 @@ data class V2rayConfig(
|
||||
wsSetting.headers.Host,
|
||||
wsSetting.path)
|
||||
}
|
||||
"httpupgrade" -> {
|
||||
val httpupgradeSetting = streamSettings?.httpupgradeSettings ?: return null
|
||||
listOf("",
|
||||
httpupgradeSetting.host,
|
||||
httpupgradeSetting.path)
|
||||
}
|
||||
"h2" -> {
|
||||
val h2Setting = streamSettings?.httpSettings ?: return null
|
||||
listOf("",
|
||||
@@ -403,7 +427,7 @@ data class V2rayConfig(
|
||||
"grpc" -> {
|
||||
val grpcSetting = streamSettings?.grpcSettings ?: return null
|
||||
listOf(if (grpcSetting.multiMode == true) "multi" else "gun",
|
||||
"",
|
||||
grpcSetting.authority ?: "",
|
||||
grpcSetting.serviceName)
|
||||
}
|
||||
else -> null
|
||||
@@ -432,7 +456,7 @@ data class V2rayConfig(
|
||||
var rules: ArrayList<RulesBean>,
|
||||
val balancers: List<Any>? = null) {
|
||||
|
||||
data class RulesBean(var type: String = "",
|
||||
data class RulesBean(
|
||||
var ip: ArrayList<String>? = null,
|
||||
var domain: ArrayList<String>? = null,
|
||||
var outboundTag: String = "",
|
||||
@@ -465,8 +489,8 @@ data class V2rayConfig(
|
||||
var poolSize: Int = 10000) // roughly 10 times smaller than total ip pool
|
||||
|
||||
fun getProxyOutbound(): OutboundBean? {
|
||||
outbounds?.forEach { outbound ->
|
||||
EConfigType.values().forEach {
|
||||
outbounds.forEach { outbound ->
|
||||
EConfigType.entries.forEach {
|
||||
if (outbound.protocol.equals(it.name, true)) {
|
||||
return outbound
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.widget.RemoteViews
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.service.V2RayServiceManager
|
||||
import com.v2ray.ang.util.Utils
|
||||
|
||||
@@ -38,23 +38,11 @@ class WidgetProvider : AppWidgetProvider() {
|
||||
})
|
||||
remoteViews.setOnClickPendingIntent(R.id.layout_switch, pendingIntent)
|
||||
if (isRunning) {
|
||||
if (!Utils.getDarkModeStatus(context)) {
|
||||
remoteViews.setInt(R.id.image_switch, "setImageResource", R.drawable.ic_stat_name)
|
||||
}
|
||||
remoteViews.setInt(
|
||||
R.id.layout_switch,
|
||||
"setBackgroundResource",
|
||||
R.drawable.ic_rounded_corner_active
|
||||
)
|
||||
remoteViews.setInt(R.id.image_switch, "setImageResource", R.drawable.ic_stop_24dp)
|
||||
remoteViews.setInt(R.id.layout_background, "setBackgroundResource", R.drawable.ic_rounded_corner_active)
|
||||
} else {
|
||||
if (!Utils.getDarkModeStatus(context)) {
|
||||
remoteViews.setInt(R.id.image_switch, "setImageResource", R.drawable.ic_stat_name_black)
|
||||
}
|
||||
remoteViews.setInt(
|
||||
R.id.layout_switch,
|
||||
"setBackgroundResource",
|
||||
R.drawable.ic_rounded_corner_grey
|
||||
)
|
||||
remoteViews.setInt(R.id.image_switch, "setImageResource", R.drawable.ic_play_24dp)
|
||||
remoteViews.setInt(R.id.layout_background, "setBackgroundResource", R.drawable.ic_rounded_corner_inactive)
|
||||
}
|
||||
|
||||
for (appWidgetId in appWidgetIds) {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package com.v2ray.ang.service
|
||||
|
||||
import android.app.*
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@@ -290,7 +293,7 @@ object V2RayServiceManager {
|
||||
.setShowWhen(false)
|
||||
.setOnlyAlertOnce(true)
|
||||
.setContentIntent(contentPendingIntent)
|
||||
.addAction(R.drawable.ic_close_grey_800_24dp,
|
||||
.addAction(R.drawable.ic_delete_24dp,
|
||||
service.getString(R.string.notification_action_stop_v2ray),
|
||||
stopV2RayPendingIntent)
|
||||
//.build()
|
||||
|
||||
@@ -111,7 +111,8 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
||||
val builder = Builder()
|
||||
//val enableLocalDns = defaultDPreference.getPrefBoolean(AppConfig.PREF_LOCAL_DNS_ENABLED, false)
|
||||
|
||||
val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE) ?: ERoutingMode.GLOBAL_PROXY.value
|
||||
val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE)
|
||||
?: ERoutingMode.BYPASS_LAN_MAINLAND.value
|
||||
|
||||
builder.setMtu(VPN_MTU)
|
||||
builder.addAddress(PRIVATE_VLAN4_CLIENT, 30)
|
||||
|
||||
153
V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/AboutActivity.kt
Normal file
153
V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/AboutActivity.kt
Normal file
@@ -0,0 +1,153 @@
|
||||
package com.v2ray.ang.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import com.tbruyelle.rxpermissions.RxPermissions
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.BuildConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.databinding.ActivityAboutBinding
|
||||
import com.v2ray.ang.extension.toast
|
||||
import com.v2ray.ang.util.SpeedtestUtil
|
||||
import com.v2ray.ang.util.Utils
|
||||
import com.v2ray.ang.util.ZipUtil
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class AboutActivity : BaseActivity() {
|
||||
private lateinit var binding: ActivityAboutBinding
|
||||
private val extDir by lazy { File(Utils.backupPath(this)) }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityAboutBinding.inflate(layoutInflater)
|
||||
val view = binding.root
|
||||
setContentView(view)
|
||||
|
||||
title = getString(R.string.title_about)
|
||||
|
||||
binding.tvBackupSummary.text = this.getString(R.string.summary_configuration_backup, extDir)
|
||||
binding.layoutBackup.setOnClickListener {
|
||||
backupMMKV()
|
||||
}
|
||||
|
||||
binding.layoutRestore.setOnClickListener {
|
||||
val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
}
|
||||
RxPermissions(this)
|
||||
.request(permission)
|
||||
.subscribe {
|
||||
if (it) {
|
||||
try {
|
||||
showFileChooser()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
} else
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
}
|
||||
|
||||
binding.layoutSoureCcode.setOnClickListener {
|
||||
Utils.openUri(this, AppConfig.v2rayNGUrl)
|
||||
}
|
||||
|
||||
binding.layoutFeedback.setOnClickListener {
|
||||
Utils.openUri(this, AppConfig.v2rayNGIssues)
|
||||
}
|
||||
|
||||
binding.layoutTgChannel.setOnClickListener {
|
||||
Utils.openUri(this, AppConfig.TgChannelUrl)
|
||||
}
|
||||
|
||||
binding.layoutPrivacyPolicy.setOnClickListener {
|
||||
Utils.openUri(this, AppConfig.v2rayNGPrivacyPolicy)
|
||||
}
|
||||
|
||||
"v${BuildConfig.VERSION_NAME} (${SpeedtestUtil.getLibVersion()})".also {
|
||||
binding.tvVersion.text = it
|
||||
}
|
||||
}
|
||||
|
||||
fun backupMMKV() {
|
||||
val dateFormated = SimpleDateFormat(
|
||||
"yyyy-MM-dd-HH-mm-ss",
|
||||
Locale.getDefault()
|
||||
).format(System.currentTimeMillis())
|
||||
val folderName = "${getString(R.string.app_name)}_${dateFormated}"
|
||||
val backupDir = this.cacheDir.absolutePath + "/$folderName"
|
||||
val outputZipFilePath = extDir.absolutePath + "/$folderName.zip"
|
||||
|
||||
val count = MMKV.backupAllToDirectory(backupDir)
|
||||
if (count <= 0) {
|
||||
toast(R.string.toast_failure)
|
||||
}
|
||||
|
||||
if (ZipUtil.zipFromFolder(backupDir, outputZipFilePath)) {
|
||||
toast(R.string.toast_success)
|
||||
} else {
|
||||
toast(R.string.toast_failure)
|
||||
}
|
||||
}
|
||||
|
||||
fun restoreMMKV(zipFile: File) {
|
||||
val backupDir = this.cacheDir.absolutePath + "/${System.currentTimeMillis()}"
|
||||
|
||||
if (!ZipUtil.unzipToFolder(zipFile, backupDir)) {
|
||||
toast(R.string.toast_failure)
|
||||
}
|
||||
|
||||
val count = MMKV.restoreAllFromDirectory(backupDir)
|
||||
if (count > 0) {
|
||||
toast(R.string.toast_success)
|
||||
} else {
|
||||
toast(R.string.toast_failure)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showFileChooser() {
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
intent.type = "*/*"
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
|
||||
try {
|
||||
chooseFile.launch(Intent.createChooser(intent, getString(R.string.title_file_chooser)))
|
||||
} catch (ex: android.content.ActivityNotFoundException) {
|
||||
toast(R.string.toast_require_file_manager)
|
||||
}
|
||||
}
|
||||
|
||||
private val chooseFile =
|
||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
val uri = it.data?.data
|
||||
if (it.resultCode == RESULT_OK && uri != null) {
|
||||
try {
|
||||
try {
|
||||
val targetFile =
|
||||
File(this.cacheDir.absolutePath, "${System.currentTimeMillis()}.zip")
|
||||
contentResolver.openInputStream(uri).use { input ->
|
||||
targetFile.outputStream().use { fileOut ->
|
||||
input?.copyTo(fileOut)
|
||||
}
|
||||
}
|
||||
|
||||
restoreMMKV(targetFile)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
toast(e.message.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +1,52 @@
|
||||
package com.v2ray.ang.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.content.*
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
import android.net.Uri
|
||||
import android.net.VpnService
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import com.tbruyelle.rxpermissions.RxPermissions
|
||||
import com.v2ray.ang.R
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.KeyEvent
|
||||
import com.v2ray.ang.AppConfig
|
||||
import android.content.res.ColorStateList
|
||||
import android.os.Build
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import android.util.Log
|
||||
import android.view.KeyEvent
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import com.tbruyelle.rxpermissions.RxPermissions
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.AppConfig.ANG_PACKAGE
|
||||
import com.v2ray.ang.BuildConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.databinding.ActivityMainBinding
|
||||
import com.v2ray.ang.dto.EConfigType
|
||||
import com.v2ray.ang.extension.toast
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import java.util.concurrent.TimeUnit
|
||||
import com.v2ray.ang.helper.SimpleItemTouchHelperCallback
|
||||
import com.v2ray.ang.service.V2RayServiceManager
|
||||
import com.v2ray.ang.util.*
|
||||
import com.v2ray.ang.util.AngConfigManager
|
||||
import com.v2ray.ang.util.MmkvManager
|
||||
import com.v2ray.ang.util.Utils
|
||||
import com.v2ray.ang.viewmodel.MainViewModel
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import me.drakeet.support.toast.ToastCompat
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener {
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
@@ -69,7 +73,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
binding.fab.setOnClickListener {
|
||||
if (mainViewModel.isRunning.value == true) {
|
||||
Utils.stopVService(this)
|
||||
} else if (settingsStorage?.decodeString(AppConfig.PREF_MODE) ?: "VPN" == "VPN") {
|
||||
} else if ((settingsStorage?.decodeString(AppConfig.PREF_MODE) ?: "VPN") == "VPN") {
|
||||
val intent = VpnService.prepare(this)
|
||||
if (intent == null) {
|
||||
startV2Ray()
|
||||
@@ -103,11 +107,11 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
binding.drawerLayout.addDrawerListener(toggle)
|
||||
toggle.syncState()
|
||||
binding.navView.setNavigationItemSelectedListener(this)
|
||||
"v${BuildConfig.VERSION_NAME} (${SpeedtestUtil.getLibVersion()})".also { binding.version.text = it }
|
||||
|
||||
|
||||
setupViewModel()
|
||||
copyAssets()
|
||||
migrateLegacy()
|
||||
//migrateLegacy()
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
RxPermissions(this)
|
||||
@@ -117,6 +121,17 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
}
|
||||
|
||||
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
|
||||
binding.drawerLayout.closeDrawer(GravityCompat.START)
|
||||
} else {
|
||||
//super.onBackPressed()
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setupViewModel() {
|
||||
@@ -131,21 +146,16 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
mainViewModel.isRunning.observe(this) { isRunning ->
|
||||
adapter.isRunning = isRunning
|
||||
if (isRunning) {
|
||||
if (!Utils.getDarkModeStatus(this)) {
|
||||
binding.fab.setImageResource(R.drawable.ic_stat_name)
|
||||
}
|
||||
binding.fab.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_orange))
|
||||
binding.fab.setImageResource(R.drawable.ic_stop_24dp)
|
||||
binding.fab.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_active))
|
||||
setTestState(getString(R.string.connection_connected))
|
||||
binding.layoutTest.isFocusable = true
|
||||
} else {
|
||||
if (!Utils.getDarkModeStatus(this)) {
|
||||
binding.fab.setImageResource(R.drawable.ic_stat_name)
|
||||
}
|
||||
binding.fab.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_grey))
|
||||
binding.fab.setImageResource(R.drawable.ic_play_24dp)
|
||||
binding.fab.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.color_fab_inactive))
|
||||
setTestState(getString(R.string.connection_not_connected))
|
||||
binding.layoutTest.isFocusable = false
|
||||
}
|
||||
hideCircle()
|
||||
}
|
||||
mainViewModel.startListenBroadcast()
|
||||
}
|
||||
@@ -173,30 +183,27 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
}
|
||||
}
|
||||
|
||||
private fun migrateLegacy() {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val result = AngConfigManager.migrateLegacyConfig(this@MainActivity)
|
||||
if (result != null) {
|
||||
launch(Dispatchers.Main) {
|
||||
if (result) {
|
||||
toast(getString(R.string.migration_success))
|
||||
mainViewModel.reloadServerList()
|
||||
} else {
|
||||
toast(getString(R.string.migration_fail))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// private fun migrateLegacy() {
|
||||
// lifecycleScope.launch(Dispatchers.IO) {
|
||||
// val result = AngConfigManager.migrateLegacyConfig(this@MainActivity)
|
||||
// if (result != null) {
|
||||
// launch(Dispatchers.Main) {
|
||||
// if (result) {
|
||||
// toast(getString(R.string.migration_success))
|
||||
// mainViewModel.reloadServerList()
|
||||
// } else {
|
||||
// toast(getString(R.string.migration_fail))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
fun startV2Ray() {
|
||||
if (mainStorage?.decodeString(MmkvManager.KEY_SELECTED_SERVER).isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
showCircle()
|
||||
// toast(R.string.toast_services_start)
|
||||
V2RayServiceManager.startV2Ray(this)
|
||||
hideCircle()
|
||||
}
|
||||
|
||||
fun restartV2Ray() {
|
||||
@@ -314,6 +321,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
MmkvManager.removeAllServer()
|
||||
mainViewModel.reloadServerList()
|
||||
}
|
||||
.setNegativeButton(android.R.string.no) {_, _ ->
|
||||
//do noting
|
||||
}
|
||||
.show()
|
||||
true
|
||||
}
|
||||
@@ -322,6 +332,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
mainViewModel.removeDuplicateServer()
|
||||
}
|
||||
.setNegativeButton(android.R.string.no) {_, _ ->
|
||||
//do noting
|
||||
}
|
||||
.show()
|
||||
true
|
||||
}
|
||||
@@ -331,6 +344,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
MmkvManager.removeInvalidServer()
|
||||
mainViewModel.reloadServerList()
|
||||
}
|
||||
.setNegativeButton(android.R.string.no) {_, _ ->
|
||||
//do noting
|
||||
}
|
||||
.show()
|
||||
true
|
||||
}
|
||||
@@ -633,39 +649,6 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
return super.onKeyDown(keyCode, event)
|
||||
}
|
||||
|
||||
|
||||
fun showCircle() {
|
||||
binding.fabProgressCircle.show()
|
||||
}
|
||||
|
||||
fun hideCircle() {
|
||||
try {
|
||||
Observable.timer(300, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
try {
|
||||
if (binding.fabProgressCircle.isShown) {
|
||||
binding.fabProgressCircle.hide()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(ANG_PACKAGE, e)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.d(ANG_PACKAGE, e.toString())
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onBackPressed() {
|
||||
if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) {
|
||||
binding.drawerLayout.closeDrawer(GravityCompat.START)
|
||||
} else {
|
||||
//super.onBackPressed()
|
||||
onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNavigationItemSelected(item: MenuItem): Boolean {
|
||||
// Handle navigation view item clicks here.
|
||||
when (item.itemId) {
|
||||
@@ -680,17 +663,14 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
R.id.user_asset_setting -> {
|
||||
startActivity(Intent(this, UserAssetActivity::class.java))
|
||||
}
|
||||
R.id.feedback -> {
|
||||
Utils.openUri(this, AppConfig.v2rayNGIssues)
|
||||
}
|
||||
R.id.promotion -> {
|
||||
Utils.openUri(this, "${Utils.decode(AppConfig.promotionUrl)}?t=${System.currentTimeMillis()}")
|
||||
Utils.openUri(this, "${Utils.decode(AppConfig.PromotionUrl)}?t=${System.currentTimeMillis()}")
|
||||
}
|
||||
R.id.logcat -> {
|
||||
startActivity(Intent(this, LogcatActivity::class.java))
|
||||
}
|
||||
R.id.privacy_policy-> {
|
||||
Utils.openUri(this, AppConfig.v2rayNGPrivacyPolicy)
|
||||
R.id.about-> {
|
||||
startActivity(Intent(this, AboutActivity::class.java))
|
||||
}
|
||||
}
|
||||
binding.drawerLayout.closeDrawer(GravityCompat.START)
|
||||
|
||||
@@ -3,14 +3,15 @@ package com.v2ray.ang.ui
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.text.TextUtils
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.gson.Gson
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AngApplication.Companion.application
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.databinding.ItemQrcodeBinding
|
||||
@@ -72,9 +73,9 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
holder.itemMainBinding.tvTestResult.setTextColor(ContextCompat.getColor(mActivity, R.color.colorPing))
|
||||
}
|
||||
if (guid == mainStorage?.decodeString(MmkvManager.KEY_SELECTED_SERVER)) {
|
||||
holder.itemMainBinding.layoutIndicator.setBackgroundResource(R.color.colorSelected)
|
||||
holder.itemMainBinding.layoutIndicator.setBackgroundResource(R.color.colorAccent)
|
||||
} else {
|
||||
holder.itemMainBinding.layoutIndicator.setBackgroundResource(R.color.colorUnselected)
|
||||
holder.itemMainBinding.layoutIndicator.setBackgroundResource(0)
|
||||
}
|
||||
holder.itemMainBinding.tvSubscription.text = ""
|
||||
val json = subStorage?.decodeString(config.subscriptionId)
|
||||
@@ -144,10 +145,15 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
removeServer(guid, position)
|
||||
}
|
||||
.setNegativeButton(android.R.string.no) {_, _ ->
|
||||
//do noting
|
||||
}
|
||||
.show()
|
||||
} else {
|
||||
removeServer(guid, position)
|
||||
}
|
||||
} else {
|
||||
application.toast(R.string.toast_action_not_allowed)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,13 +166,11 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
}
|
||||
notifyItemChanged(mActivity.mainViewModel.getPosition(guid))
|
||||
if (isRunning) {
|
||||
mActivity.showCircle()
|
||||
Utils.stopVService(mActivity)
|
||||
Observable.timer(500, TimeUnit.MILLISECONDS)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
V2RayServiceManager.startV2Ray(mActivity)
|
||||
mActivity.hideCircle()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,7 +182,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
holder.itemFooterBinding.layoutEdit.visibility = View.INVISIBLE
|
||||
} else {
|
||||
holder.itemFooterBinding.layoutEdit.setOnClickListener {
|
||||
Utils.openUri(mActivity, "${Utils.decode(AppConfig.promotionUrl)}?t=${System.currentTimeMillis()}")
|
||||
Utils.openUri(mActivity, "${Utils.decode(AppConfig.PromotionUrl)}?t=${System.currentTimeMillis()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.AppConfig.ANG_PACKAGE
|
||||
import com.v2ray.ang.R
|
||||
@@ -19,20 +19,20 @@ import com.v2ray.ang.dto.AppInfo
|
||||
import com.v2ray.ang.extension.toast
|
||||
import com.v2ray.ang.extension.v2RayApplication
|
||||
import com.v2ray.ang.util.AppManagerUtil
|
||||
import com.v2ray.ang.util.MmkvManager
|
||||
import com.v2ray.ang.util.Utils
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import java.text.Collator
|
||||
import java.util.*
|
||||
|
||||
class PerAppProxyActivity : BaseActivity() {
|
||||
private lateinit var binding: ActivityBypassListBinding
|
||||
|
||||
private var adapter: PerAppProxyAdapter? = null
|
||||
private var appsAll: List<AppInfo>? = null
|
||||
private val defaultSharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(this) }
|
||||
private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -43,7 +43,7 @@ class PerAppProxyActivity : BaseActivity() {
|
||||
val dividerItemDecoration = DividerItemDecoration(this, LinearLayoutManager.VERTICAL)
|
||||
binding.recyclerView.addItemDecoration(dividerItemDecoration)
|
||||
|
||||
val blacklist = defaultSharedPreferences.getStringSet(AppConfig.PREF_PER_APP_PROXY_SET, null)
|
||||
val blacklist = settingsStorage?.decodeStringSet(AppConfig.PREF_PER_APP_PROXY_SET)
|
||||
|
||||
AppManagerUtil.rxLoadNetworkAppList(this)
|
||||
.subscribeOn(Schedulers.io())
|
||||
@@ -134,14 +134,14 @@ class PerAppProxyActivity : BaseActivity() {
|
||||
***/
|
||||
|
||||
binding.switchPerAppProxy.setOnCheckedChangeListener { _, isChecked ->
|
||||
defaultSharedPreferences.edit().putBoolean(AppConfig.PREF_PER_APP_PROXY, isChecked).apply()
|
||||
settingsStorage.encode(AppConfig.PREF_PER_APP_PROXY, isChecked)
|
||||
}
|
||||
binding.switchPerAppProxy.isChecked = defaultSharedPreferences.getBoolean(AppConfig.PREF_PER_APP_PROXY, false)
|
||||
binding.switchPerAppProxy.isChecked = settingsStorage.getBoolean(AppConfig.PREF_PER_APP_PROXY, false)
|
||||
|
||||
binding.switchBypassApps.setOnCheckedChangeListener { _, isChecked ->
|
||||
defaultSharedPreferences.edit().putBoolean(AppConfig.PREF_BYPASS_APPS, isChecked).apply()
|
||||
settingsStorage.encode(AppConfig.PREF_BYPASS_APPS, isChecked)
|
||||
}
|
||||
binding.switchBypassApps.isChecked = defaultSharedPreferences.getBoolean(AppConfig.PREF_BYPASS_APPS, false)
|
||||
binding.switchBypassApps.isChecked = settingsStorage.getBoolean(AppConfig.PREF_BYPASS_APPS, false)
|
||||
|
||||
/***
|
||||
et_search.setOnEditorActionListener { v, actionId, event ->
|
||||
@@ -177,7 +177,7 @@ class PerAppProxyActivity : BaseActivity() {
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
adapter?.let {
|
||||
defaultSharedPreferences.edit().putStringSet(AppConfig.PREF_PER_APP_PROXY_SET, it.blacklist).apply()
|
||||
settingsStorage.encode(AppConfig.PREF_PER_APP_PROXY_SET, it.blacklist)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,13 @@ import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.tbruyelle.rxpermissions.RxPermissions
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.databinding.FragmentRoutingSettingsBinding
|
||||
import com.v2ray.ang.extension.toast
|
||||
import com.v2ray.ang.extension.v2RayApplication
|
||||
import com.v2ray.ang.util.MmkvManager
|
||||
import com.v2ray.ang.util.Utils
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -26,7 +28,7 @@ class RoutingSettingsFragment : Fragment() {
|
||||
private const val routing_arg = "routing_arg"
|
||||
}
|
||||
|
||||
val defaultSharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(requireContext()) }
|
||||
private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) }
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
@@ -46,7 +48,7 @@ class RoutingSettingsFragment : Fragment() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val content = defaultSharedPreferences.getString(requireArguments().getString(routing_arg), "")
|
||||
val content = settingsStorage?.getString(requireArguments().getString(routing_arg), "")
|
||||
binding.etRoutingContent.text = Utils.getEditable(content!!)
|
||||
|
||||
setHasOptionsMenu(true)
|
||||
@@ -83,7 +85,7 @@ class RoutingSettingsFragment : Fragment() {
|
||||
|
||||
private fun saveRouting() {
|
||||
val content = binding.etRoutingContent.text.toString()
|
||||
defaultSharedPreferences.edit().putString(requireArguments().getString(routing_arg), content).apply()
|
||||
settingsStorage?.encode(requireArguments().getString(routing_arg), content)
|
||||
activity?.toast(R.string.toast_success)
|
||||
}
|
||||
|
||||
@@ -127,7 +129,7 @@ class RoutingSettingsFragment : Fragment() {
|
||||
var tag = ""
|
||||
when (requireArguments().getString(routing_arg)) {
|
||||
AppConfig.PREF_V2RAY_ROUTING_AGENT -> {
|
||||
tag = AppConfig.TAG_AGENT
|
||||
tag = AppConfig.TAG_PROXY
|
||||
}
|
||||
AppConfig.PREF_V2RAY_ROUTING_DIRECT -> {
|
||||
tag = AppConfig.TAG_DIRECT
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.view.View
|
||||
import android.widget.*
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AngApplication
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.AppConfig.PREF_ALLOW_INSECURE
|
||||
import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_ADDRESS_V4
|
||||
@@ -209,7 +210,7 @@ class ServerActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
/**
|
||||
* bingding seleced server config
|
||||
* binding selected server config
|
||||
*/
|
||||
private fun bindingServer(config: ServerConfig): Boolean {
|
||||
val outbound = config.getProxyOutbound() ?: return false
|
||||
@@ -496,15 +497,16 @@ class ServerActivity : BaseActivity() {
|
||||
val spiderX = et_spider_x?.text?.toString()?.trim() ?: return
|
||||
|
||||
var sni = streamSetting.populateTransportSettings(
|
||||
transport = networks[network],
|
||||
headerType = transportTypes(networks[network])[type],
|
||||
host = requestHost,
|
||||
path = path,
|
||||
seed = path,
|
||||
quicSecurity = requestHost,
|
||||
key = path,
|
||||
mode = transportTypes(networks[network])[type],
|
||||
serviceName = path
|
||||
transport = networks[network],
|
||||
headerType = transportTypes(networks[network])[type],
|
||||
host = requestHost,
|
||||
path = path,
|
||||
seed = path,
|
||||
quicSecurity = requestHost,
|
||||
key = path,
|
||||
mode = transportTypes(networks[network])[type],
|
||||
serviceName = path,
|
||||
authority = requestHost,
|
||||
)
|
||||
if (sniField.isNotBlank()) {
|
||||
sni = sniField
|
||||
@@ -559,11 +561,16 @@ class ServerActivity : BaseActivity() {
|
||||
MmkvManager.removeServer(editGuid)
|
||||
finish()
|
||||
}
|
||||
.setNegativeButton(android.R.string.no) { _, _ ->
|
||||
// do nothing
|
||||
}
|
||||
.show()
|
||||
} else {
|
||||
MmkvManager.removeServer(editGuid)
|
||||
finish()
|
||||
}
|
||||
} else {
|
||||
application.toast(R.string.toast_action_not_allowed)
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -91,7 +91,7 @@ class ServerCustomConfigActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
val config = MmkvManager.decodeServerConfig(editGuid) ?: ServerConfig.create(EConfigType.CUSTOM)
|
||||
config.remarks = binding.etRemarks.text.toString().trim()
|
||||
config.remarks = v2rayConfig.remarks ?: binding.etRemarks.text.toString().trim()
|
||||
config.fullConfig = v2rayConfig
|
||||
|
||||
MmkvManager.encodeServerConfig(editGuid, config)
|
||||
@@ -111,6 +111,9 @@ class ServerCustomConfigActivity : BaseActivity() {
|
||||
MmkvManager.removeServer(editGuid)
|
||||
finish()
|
||||
}
|
||||
.setNegativeButton(android.R.string.no) {_, _ ->
|
||||
// do nothing
|
||||
}
|
||||
.show()
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -5,14 +5,20 @@ import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import androidx.activity.viewModels
|
||||
import androidx.preference.*
|
||||
import androidx.preference.CheckBoxPreference
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import androidx.work.PeriodicWorkRequest
|
||||
import androidx.work.multiprocess.RemoteWorkManager
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AngApplication
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.service.SubscriptionUpdater
|
||||
import com.v2ray.ang.util.MmkvManager
|
||||
import com.v2ray.ang.util.Utils
|
||||
import com.v2ray.ang.viewmodel.SettingsViewModel
|
||||
import java.util.concurrent.TimeUnit
|
||||
@@ -30,12 +36,16 @@ class SettingsActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
class SettingsFragment : PreferenceFragmentCompat() {
|
||||
private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) }
|
||||
|
||||
private val perAppProxy by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_PER_APP_PROXY) }
|
||||
private val localDns by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_LOCAL_DNS_ENABLED) }
|
||||
private val fakeDns by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_FAKE_DNS_ENABLED) }
|
||||
private val localDnsPort by lazy { findPreference<EditTextPreference>(AppConfig.PREF_LOCAL_DNS_PORT) }
|
||||
private val vpnDns by lazy { findPreference<EditTextPreference>(AppConfig.PREF_VPN_DNS) }
|
||||
|
||||
|
||||
private val routingCustom by lazy { findPreference<Preference>(AppConfig.PREF_ROUTING_CUSTOM) }
|
||||
|
||||
private val mux by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_MUX_ENABLED) }
|
||||
private val muxConcurrency by lazy { findPreference<EditTextPreference>(AppConfig.PREF_MUX_CONCURRENCY) }
|
||||
private val muxXudpConcurrency by lazy { findPreference<EditTextPreference>(AppConfig.PREF_MUX_XUDP_CONCURRENCY) }
|
||||
@@ -46,90 +56,23 @@ class SettingsActivity : BaseActivity() {
|
||||
private val fragmentLength by lazy { findPreference<EditTextPreference>(AppConfig.PREF_FRAGMENT_LENGTH) }
|
||||
private val fragmentInterval by lazy { findPreference<EditTextPreference>(AppConfig.PREF_FRAGMENT_INTERVAL) }
|
||||
|
||||
// val autoRestart by lazy { findPreference(PREF_AUTO_RESTART) as CheckBoxPreference }
|
||||
private val remoteDns by lazy { findPreference<EditTextPreference>(AppConfig.PREF_REMOTE_DNS) }
|
||||
private val domesticDns by lazy { findPreference<EditTextPreference>(AppConfig.PREF_DOMESTIC_DNS) }
|
||||
private val socksPort by lazy { findPreference<EditTextPreference>(AppConfig.PREF_SOCKS_PORT) }
|
||||
private val httpPort by lazy { findPreference<EditTextPreference>(AppConfig.PREF_HTTP_PORT) }
|
||||
private val routingCustom by lazy { findPreference<Preference>(AppConfig.PREF_ROUTING_CUSTOM) }
|
||||
private val autoUpdateCheck by lazy { findPreference<CheckBoxPreference>(AppConfig.SUBSCRIPTION_AUTO_UPDATE) }
|
||||
private val autoUpdateInterval by lazy { findPreference<EditTextPreference>(AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL) }
|
||||
// val licenses: Preference by lazy { findPreference(PREF_LICENSES) }
|
||||
// val feedback: Preference by lazy { findPreference(PREF_FEEDBACK) }
|
||||
// val tgGroup: Preference by lazy { findPreference(PREF_TG_GROUP) }
|
||||
|
||||
private val socksPort by lazy { findPreference<EditTextPreference>(AppConfig.PREF_SOCKS_PORT) }
|
||||
private val httpPort by lazy { findPreference<EditTextPreference>(AppConfig.PREF_HTTP_PORT) }
|
||||
private val remoteDns by lazy { findPreference<EditTextPreference>(AppConfig.PREF_REMOTE_DNS) }
|
||||
private val domesticDns by lazy { findPreference<EditTextPreference>(AppConfig.PREF_DOMESTIC_DNS) }
|
||||
private val mode by lazy { findPreference<ListPreference>(AppConfig.PREF_MODE) }
|
||||
|
||||
override fun onCreatePreferences(bundle: Bundle?, s: String?) {
|
||||
addPreferencesFromResource(R.xml.pref_settings)
|
||||
|
||||
routingCustom?.setOnPreferenceClickListener {
|
||||
startActivity(Intent(activity, RoutingSettingsActivity::class.java))
|
||||
false
|
||||
}
|
||||
|
||||
autoUpdateCheck?.setOnPreferenceChangeListener { _, newValue ->
|
||||
val value = newValue as Boolean
|
||||
autoUpdateCheck?.isChecked = value
|
||||
autoUpdateInterval?.isEnabled = value
|
||||
autoUpdateInterval?.text?.toLong()?.let {
|
||||
if (newValue) configureUpdateTask(it) else cancelUpdateTask()
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
autoUpdateInterval?.setOnPreferenceChangeListener { _, any ->
|
||||
var nval = any as String
|
||||
|
||||
// It must be greater than 15 minutes because WorkManager couldn't run tasks under 15 minutes intervals
|
||||
nval =
|
||||
if (TextUtils.isEmpty(nval) || nval.toLong() < 15) AppConfig.SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL else nval
|
||||
autoUpdateInterval?.summary = nval
|
||||
configureUpdateTask(nval.toLong())
|
||||
true
|
||||
}
|
||||
|
||||
// licenses.onClick {
|
||||
// val fragment = LicensesDialogFragment.Builder(act)
|
||||
// .setNotices(R.raw.licenses)
|
||||
// .setIncludeOwnLicense(false)
|
||||
// .build()
|
||||
// fragment.show((act as AppCompatActivity).supportFragmentManager, null)
|
||||
// }
|
||||
//
|
||||
// feedback.onClick {
|
||||
// Utils.openUri(activity, "https://github.com/2dust/v2rayNG/issues")
|
||||
// }
|
||||
// tgGroup.onClick {
|
||||
// // Utils.openUri(activity, "https://t.me/v2rayN")
|
||||
// val intent = Intent(Intent.ACTION_VIEW, Uri.parse("tg:resolve?domain=v2rayN"))
|
||||
// try {
|
||||
// startActivity(intent)
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// toast(R.string.toast_tg_app_not_found)
|
||||
// }
|
||||
// }
|
||||
|
||||
perAppProxy?.setOnPreferenceClickListener {
|
||||
startActivity(Intent(activity, PerAppProxyActivity::class.java))
|
||||
perAppProxy?.isChecked = true
|
||||
false
|
||||
}
|
||||
|
||||
remoteDns?.setOnPreferenceChangeListener { _, any ->
|
||||
// remoteDns.summary = any as String
|
||||
val nval = any as String
|
||||
remoteDns?.summary = if (nval == "") AppConfig.DNS_AGENT else nval
|
||||
true
|
||||
}
|
||||
domesticDns?.setOnPreferenceChangeListener { _, any ->
|
||||
// domesticDns.summary = any as String
|
||||
val nval = any as String
|
||||
domesticDns?.summary = if (nval == "") AppConfig.DNS_DIRECT else nval
|
||||
true
|
||||
}
|
||||
|
||||
localDns?.setOnPreferenceChangeListener { _, any ->
|
||||
updateLocalDns(any as Boolean)
|
||||
true
|
||||
@@ -144,22 +87,12 @@ class SettingsActivity : BaseActivity() {
|
||||
vpnDns?.summary = any as String
|
||||
true
|
||||
}
|
||||
socksPort?.setOnPreferenceChangeListener { _, any ->
|
||||
val nval = any as String
|
||||
socksPort?.summary = if (TextUtils.isEmpty(nval)) AppConfig.PORT_SOCKS else nval
|
||||
true
|
||||
|
||||
routingCustom?.setOnPreferenceClickListener {
|
||||
startActivity(Intent(activity, RoutingSettingsActivity::class.java))
|
||||
false
|
||||
}
|
||||
httpPort?.setOnPreferenceChangeListener { _, any ->
|
||||
val nval = any as String
|
||||
httpPort?.summary = if (TextUtils.isEmpty(nval)) AppConfig.PORT_HTTP else nval
|
||||
true
|
||||
}
|
||||
mode?.setOnPreferenceChangeListener { _, newValue ->
|
||||
updateMode(newValue.toString())
|
||||
true
|
||||
}
|
||||
mode?.dialogLayoutResource = R.layout.preference_with_help_link
|
||||
//loglevel.summary = "LogLevel"
|
||||
|
||||
mux?.setOnPreferenceChangeListener { _, newValue ->
|
||||
updateMux(newValue as Boolean)
|
||||
true
|
||||
@@ -189,65 +122,153 @@ class SettingsActivity : BaseActivity() {
|
||||
updateFragmentInterval(newValue as String)
|
||||
true
|
||||
}
|
||||
|
||||
autoUpdateCheck?.setOnPreferenceChangeListener { _, newValue ->
|
||||
val value = newValue as Boolean
|
||||
autoUpdateCheck?.isChecked = value
|
||||
autoUpdateInterval?.isEnabled = value
|
||||
autoUpdateInterval?.text?.toLong()?.let {
|
||||
if (newValue) configureUpdateTask(it) else cancelUpdateTask()
|
||||
}
|
||||
true
|
||||
}
|
||||
autoUpdateInterval?.setOnPreferenceChangeListener { _, any ->
|
||||
var nval = any as String
|
||||
|
||||
// It must be greater than 15 minutes because WorkManager couldn't run tasks under 15 minutes intervals
|
||||
nval =
|
||||
if (TextUtils.isEmpty(nval) || nval.toLong() < 15) AppConfig.SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL else nval
|
||||
autoUpdateInterval?.summary = nval
|
||||
configureUpdateTask(nval.toLong())
|
||||
true
|
||||
}
|
||||
|
||||
remoteDns?.setOnPreferenceChangeListener { _, any ->
|
||||
// remoteDns.summary = any as String
|
||||
val nval = any as String
|
||||
remoteDns?.summary = if (nval == "") AppConfig.DNS_PROXY else nval
|
||||
true
|
||||
}
|
||||
domesticDns?.setOnPreferenceChangeListener { _, any ->
|
||||
// domesticDns.summary = any as String
|
||||
val nval = any as String
|
||||
domesticDns?.summary = if (nval == "") AppConfig.DNS_DIRECT else nval
|
||||
true
|
||||
}
|
||||
socksPort?.setOnPreferenceChangeListener { _, any ->
|
||||
val nval = any as String
|
||||
socksPort?.summary = if (TextUtils.isEmpty(nval)) AppConfig.PORT_SOCKS else nval
|
||||
true
|
||||
}
|
||||
httpPort?.setOnPreferenceChangeListener { _, any ->
|
||||
val nval = any as String
|
||||
httpPort?.summary = if (TextUtils.isEmpty(nval)) AppConfig.PORT_HTTP else nval
|
||||
true
|
||||
}
|
||||
mode?.setOnPreferenceChangeListener { _, newValue ->
|
||||
updateMode(newValue.toString())
|
||||
true
|
||||
}
|
||||
mode?.dialogLayoutResource = R.layout.preference_with_help_link
|
||||
//loglevel.summary = "LogLevel"
|
||||
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
val defaultSharedPreferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(requireActivity())
|
||||
updateMode(defaultSharedPreferences.getString(AppConfig.PREF_MODE, "VPN"))
|
||||
var remoteDnsString = defaultSharedPreferences.getString(AppConfig.PREF_REMOTE_DNS, "")
|
||||
updateMode(settingsStorage.decodeString(AppConfig.PREF_MODE, "VPN"))
|
||||
localDns?.isChecked = settingsStorage.getBoolean(AppConfig.PREF_LOCAL_DNS_ENABLED, false)
|
||||
fakeDns?.isChecked = settingsStorage.getBoolean(AppConfig.PREF_FAKE_DNS_ENABLED, false)
|
||||
localDnsPort?.summary = settingsStorage.decodeString(AppConfig.PREF_LOCAL_DNS_PORT, AppConfig.PORT_LOCAL_DNS)
|
||||
vpnDns?.summary = settingsStorage.decodeString(AppConfig.PREF_VPN_DNS, AppConfig.DNS_VPN)
|
||||
|
||||
domesticDns?.summary = defaultSharedPreferences.getString(AppConfig.PREF_DOMESTIC_DNS, "")
|
||||
localDnsPort?.summary = defaultSharedPreferences.getString(AppConfig.PREF_LOCAL_DNS_PORT, AppConfig.PORT_LOCAL_DNS)
|
||||
socksPort?.summary = defaultSharedPreferences.getString(AppConfig.PREF_SOCKS_PORT, AppConfig.PORT_SOCKS)
|
||||
httpPort?.summary = defaultSharedPreferences.getString(AppConfig.PREF_HTTP_PORT, AppConfig.PORT_HTTP)
|
||||
updateMux(defaultSharedPreferences.getBoolean(AppConfig.PREF_MUX_ENABLED, false))
|
||||
muxConcurrency?.summary = defaultSharedPreferences.getString(AppConfig.PREF_MUX_CONCURRENCY, "8")
|
||||
muxXudpConcurrency?.summary = defaultSharedPreferences.getString(AppConfig.PREF_MUX_XUDP_CONCURRENCY, "8")
|
||||
updateFragment(defaultSharedPreferences.getBoolean(AppConfig.PREF_FRAGMENT_ENABLED, false))
|
||||
fragmentPackets?.summary = defaultSharedPreferences.getString(AppConfig.PREF_FRAGMENT_PACKETS, "tlshello")
|
||||
fragmentLength?.summary = defaultSharedPreferences.getString(AppConfig.PREF_FRAGMENT_LENGTH, "50-100")
|
||||
fragmentInterval?.summary = defaultSharedPreferences.getString(AppConfig.PREF_FRAGMENT_INTERVAL, "10-20")
|
||||
autoUpdateInterval?.summary = defaultSharedPreferences.getString(AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL,AppConfig.SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL)
|
||||
autoUpdateInterval?.isEnabled = defaultSharedPreferences.getBoolean(AppConfig.SUBSCRIPTION_AUTO_UPDATE, false)
|
||||
updateMux(settingsStorage.getBoolean(AppConfig.PREF_MUX_ENABLED, false))
|
||||
mux?.isChecked = settingsStorage.getBoolean(AppConfig.PREF_MUX_ENABLED, false)
|
||||
muxConcurrency?.summary = settingsStorage.decodeString(AppConfig.PREF_MUX_CONCURRENCY, "8")
|
||||
muxXudpConcurrency?.summary = settingsStorage.decodeString(AppConfig.PREF_MUX_XUDP_CONCURRENCY, "8")
|
||||
|
||||
if (TextUtils.isEmpty(remoteDnsString)) {
|
||||
remoteDnsString = AppConfig.DNS_AGENT
|
||||
}
|
||||
if (TextUtils.isEmpty(domesticDns?.summary)) {
|
||||
domesticDns?.summary = AppConfig.DNS_DIRECT
|
||||
}
|
||||
remoteDns?.summary = remoteDnsString
|
||||
vpnDns?.summary =
|
||||
defaultSharedPreferences.getString(AppConfig.PREF_VPN_DNS, remoteDnsString)
|
||||
updateFragment(settingsStorage.getBoolean(AppConfig.PREF_FRAGMENT_ENABLED, false))
|
||||
fragment?.isChecked = settingsStorage.getBoolean(AppConfig.PREF_FRAGMENT_ENABLED, false)
|
||||
fragmentPackets?.summary = settingsStorage.decodeString(AppConfig.PREF_FRAGMENT_PACKETS, "tlshello")
|
||||
fragmentLength?.summary = settingsStorage.decodeString(AppConfig.PREF_FRAGMENT_LENGTH, "50-100")
|
||||
fragmentInterval?.summary = settingsStorage.decodeString(AppConfig.PREF_FRAGMENT_INTERVAL, "10-20")
|
||||
|
||||
if (TextUtils.isEmpty(localDnsPort?.summary)) {
|
||||
localDnsPort?.summary = AppConfig.PORT_LOCAL_DNS
|
||||
autoUpdateCheck?.isChecked = settingsStorage.getBoolean(AppConfig.SUBSCRIPTION_AUTO_UPDATE, false)
|
||||
autoUpdateInterval?.summary = settingsStorage.decodeString(AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL,AppConfig.SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL)
|
||||
autoUpdateInterval?.isEnabled = settingsStorage.getBoolean(AppConfig.SUBSCRIPTION_AUTO_UPDATE, false)
|
||||
|
||||
socksPort?.summary = settingsStorage.decodeString(AppConfig.PREF_SOCKS_PORT, AppConfig.PORT_SOCKS)
|
||||
httpPort?.summary = settingsStorage.decodeString(AppConfig.PREF_HTTP_PORT, AppConfig.PORT_HTTP)
|
||||
remoteDns?.summary = settingsStorage.decodeString(AppConfig.PREF_REMOTE_DNS, AppConfig.DNS_PROXY)
|
||||
domesticDns?.summary = settingsStorage.decodeString(AppConfig.PREF_DOMESTIC_DNS, AppConfig.DNS_DIRECT)
|
||||
|
||||
initSharedPreference()
|
||||
}
|
||||
|
||||
private fun initSharedPreference() {
|
||||
listOf(
|
||||
localDnsPort,
|
||||
vpnDns,
|
||||
muxConcurrency,
|
||||
muxXudpConcurrency,
|
||||
fragmentLength,
|
||||
fragmentInterval,
|
||||
autoUpdateInterval,
|
||||
socksPort,
|
||||
httpPort,
|
||||
remoteDns,
|
||||
domesticDns
|
||||
).forEach { key ->
|
||||
key?.text = key?.summary.toString()
|
||||
}
|
||||
if (TextUtils.isEmpty(socksPort?.summary)) {
|
||||
socksPort?.summary = AppConfig.PORT_SOCKS
|
||||
|
||||
listOf(
|
||||
AppConfig.PREF_SNIFFING_ENABLED,
|
||||
).forEach { key ->
|
||||
findPreference<CheckBoxPreference>(key)?.isChecked =
|
||||
settingsStorage.decodeBool(key, true)
|
||||
}
|
||||
if (TextUtils.isEmpty(httpPort?.summary)) {
|
||||
httpPort?.summary = AppConfig.PORT_HTTP
|
||||
|
||||
listOf(
|
||||
AppConfig.PREF_BYPASS_APPS,
|
||||
AppConfig.PREF_SPEED_ENABLED,
|
||||
AppConfig.PREF_CONFIRM_REMOVE,
|
||||
AppConfig.PREF_START_SCAN_IMMEDIATE,
|
||||
AppConfig.PREF_PREFER_IPV6,
|
||||
AppConfig.PREF_PROXY_SHARING,
|
||||
AppConfig.PREF_ALLOW_INSECURE
|
||||
).forEach { key ->
|
||||
findPreference<CheckBoxPreference>(key)?.isChecked =
|
||||
settingsStorage.decodeBool(key, false)
|
||||
}
|
||||
|
||||
listOf(
|
||||
AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
|
||||
AppConfig.PREF_ROUTING_MODE,
|
||||
AppConfig.PREF_MUX_XUDP_QUIC,
|
||||
AppConfig.PREF_FRAGMENT_PACKETS,
|
||||
AppConfig.PREF_LANGUAGE,
|
||||
AppConfig.PREF_UI_MODE_NIGHT,
|
||||
AppConfig.PREF_LOGLEVEL,
|
||||
AppConfig.PREF_MODE
|
||||
).forEach { key ->
|
||||
if (settingsStorage.decodeString(key) != null) {
|
||||
findPreference<ListPreference>(key)?.value = settingsStorage.decodeString(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateMode(mode: String?) {
|
||||
val defaultSharedPreferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(requireActivity())
|
||||
val vpn = mode == "VPN"
|
||||
perAppProxy?.isEnabled = vpn
|
||||
perAppProxy?.isChecked =
|
||||
PreferenceManager.getDefaultSharedPreferences(requireActivity())
|
||||
.getBoolean(AppConfig.PREF_PER_APP_PROXY, false)
|
||||
perAppProxy?.isChecked = settingsStorage.getBoolean(AppConfig.PREF_PER_APP_PROXY, false)
|
||||
localDns?.isEnabled = vpn
|
||||
fakeDns?.isEnabled = vpn
|
||||
localDnsPort?.isEnabled = vpn
|
||||
vpnDns?.isEnabled = vpn
|
||||
if (vpn) {
|
||||
updateLocalDns(
|
||||
defaultSharedPreferences.getBoolean(
|
||||
settingsStorage.getBoolean(
|
||||
AppConfig.PREF_LOCAL_DNS_ENABLED,
|
||||
false
|
||||
)
|
||||
@@ -283,15 +304,14 @@ class SettingsActivity : BaseActivity() {
|
||||
val rw = RemoteWorkManager.getInstance(AngApplication.application)
|
||||
rw.cancelUniqueWork(AppConfig.SUBSCRIPTION_UPDATE_TASK_NAME)
|
||||
}
|
||||
|
||||
|
||||
private fun updateMux(enabled: Boolean) {
|
||||
val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity())
|
||||
muxConcurrency?.isEnabled = enabled
|
||||
muxXudpConcurrency?.isEnabled = enabled
|
||||
muxXudpQuic?.isEnabled = enabled
|
||||
if (enabled) {
|
||||
updateMuxConcurrency(defaultSharedPreferences.getString(AppConfig.PREF_MUX_CONCURRENCY, "8"))
|
||||
updateMuxXudpConcurrency(defaultSharedPreferences.getString(AppConfig.PREF_MUX_XUDP_CONCURRENCY, "8"))
|
||||
updateMuxConcurrency(settingsStorage.decodeString(AppConfig.PREF_MUX_CONCURRENCY, "8"))
|
||||
updateMuxXudpConcurrency(settingsStorage.decodeString(AppConfig.PREF_MUX_XUDP_CONCURRENCY, "8"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,14 +334,13 @@ class SettingsActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun updateFragment(enabled: Boolean) {
|
||||
val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity())
|
||||
fragmentPackets?.isEnabled = enabled
|
||||
fragmentLength?.isEnabled = enabled
|
||||
fragmentInterval?.isEnabled = enabled
|
||||
if (enabled) {
|
||||
updateFragmentPackets(defaultSharedPreferences.getString(AppConfig.PREF_FRAGMENT_PACKETS, "tlshello"))
|
||||
updateFragmentLength(defaultSharedPreferences.getString(AppConfig.PREF_FRAGMENT_LENGTH, "50-100"))
|
||||
updateFragmentInterval(defaultSharedPreferences.getString(AppConfig.PREF_FRAGMENT_INTERVAL, "10-20"))
|
||||
updateFragmentPackets(settingsStorage.decodeString(AppConfig.PREF_FRAGMENT_PACKETS, "tlshello"))
|
||||
updateFragmentLength(settingsStorage.decodeString(AppConfig.PREF_FRAGMENT_LENGTH, "50-100"))
|
||||
updateFragmentInterval(settingsStorage.decodeString(AppConfig.PREF_FRAGMENT_INTERVAL, "10-20"))
|
||||
}
|
||||
}
|
||||
private fun updateFragmentPackets(value: String?) {
|
||||
|
||||
@@ -111,6 +111,9 @@ class SubEditActivity : BaseActivity() {
|
||||
MmkvManager.removeSubscription(editSubId)
|
||||
finish()
|
||||
}
|
||||
.setNegativeButton(android.R.string.no) {_, _ ->
|
||||
// do nothing
|
||||
}
|
||||
.show()
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -5,17 +5,15 @@ import android.graphics.Color
|
||||
import android.text.TextUtils
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.gson.Gson
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.databinding.ItemQrcodeBinding
|
||||
import com.v2ray.ang.databinding.ItemRecyclerSubSettingBinding
|
||||
import com.v2ray.ang.dto.EConfigType
|
||||
import com.v2ray.ang.extension.toast
|
||||
import com.v2ray.ang.util.AngConfigManager
|
||||
import com.v2ray.ang.util.MmkvManager
|
||||
import com.v2ray.ang.util.QRCodeDecoder
|
||||
import com.v2ray.ang.util.Utils
|
||||
@@ -38,9 +36,9 @@ class SubSettingRecyclerAdapter(val activity: SubSettingActivity) :
|
||||
holder.itemSubSettingBinding.tvName.text = subItem.remarks
|
||||
holder.itemSubSettingBinding.tvUrl.text = subItem.url
|
||||
if (subItem.enabled) {
|
||||
holder.itemSubSettingBinding.chkEnable.setBackgroundResource(R.color.colorSelected)
|
||||
holder.itemSubSettingBinding.chkEnable.setBackgroundResource(R.color.colorAccent)
|
||||
} else {
|
||||
holder.itemSubSettingBinding.chkEnable.setBackgroundResource(R.color.colorUnselected)
|
||||
holder.itemSubSettingBinding.chkEnable.setBackgroundResource(0)
|
||||
}
|
||||
holder.itemView.setBackgroundColor(Color.TRANSPARENT)
|
||||
|
||||
|
||||
@@ -177,7 +177,10 @@ class UserAssetActivity : BaseActivity() {
|
||||
assets.forEach {
|
||||
//toast(getString(R.string.msg_downloading_content) + it)
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val result = downloadGeo(it.second, 60000, httpPort)
|
||||
var result = downloadGeo(it.second, 60000, httpPort)
|
||||
if (!result) {
|
||||
result = downloadGeo(it.second, 60000, 0)
|
||||
}
|
||||
launch(Dispatchers.Main) {
|
||||
if (result) {
|
||||
toast(getString(R.string.toast_success) + " " + it.second.remarks)
|
||||
@@ -197,12 +200,16 @@ class UserAssetActivity : BaseActivity() {
|
||||
//Log.d(AppConfig.ANG_PACKAGE, url)
|
||||
|
||||
try {
|
||||
conn = URL(item.url).openConnection(
|
||||
Proxy(
|
||||
Proxy.Type.HTTP,
|
||||
InetSocketAddress("127.0.0.1", httpPort)
|
||||
)
|
||||
) as HttpURLConnection
|
||||
conn = if (httpPort == 0) {
|
||||
URL(item.url).openConnection() as HttpURLConnection
|
||||
} else {
|
||||
URL(item.url).openConnection(
|
||||
Proxy(
|
||||
Proxy.Type.HTTP,
|
||||
InetSocketAddress("127.0.0.1", httpPort)
|
||||
)
|
||||
) as HttpURLConnection
|
||||
}
|
||||
conn.connectTimeout = timeout
|
||||
conn.readTimeout = timeout
|
||||
val inputStream = conn.inputStream
|
||||
@@ -224,13 +231,14 @@ class UserAssetActivity : BaseActivity() {
|
||||
}
|
||||
private fun addBuiltInGeoItems(assets: List<Pair<String, AssetUrlItem>>): List<Pair<String, AssetUrlItem>> {
|
||||
val list = mutableListOf<Pair<String, AssetUrlItem>>()
|
||||
builtInGeoFiles.forEach {
|
||||
list.add(Utils.getUuid() to AssetUrlItem(
|
||||
it,
|
||||
AppConfig.geoUrl + it
|
||||
)
|
||||
)
|
||||
}
|
||||
builtInGeoFiles
|
||||
.filter { geoFile -> assets.none { it.second.remarks == geoFile } }
|
||||
.forEach {
|
||||
list.add(Utils.getUuid() to AssetUrlItem(
|
||||
it,
|
||||
AppConfig.GeoUrl + it
|
||||
))
|
||||
}
|
||||
|
||||
return list + assets
|
||||
}
|
||||
@@ -263,7 +271,7 @@ class UserAssetActivity : BaseActivity() {
|
||||
holder.itemUserAssetBinding.assetProperties.text = getString(R.string.msg_file_not_found)
|
||||
}
|
||||
|
||||
if (item.second.remarks in builtInGeoFiles) {
|
||||
if (item.second.remarks in builtInGeoFiles && item.second.url == AppConfig.GeoUrl + item.second.remarks) {
|
||||
holder.itemUserAssetBinding.layoutEdit.visibility = GONE
|
||||
holder.itemUserAssetBinding.layoutRemove.visibility = GONE
|
||||
} else {
|
||||
|
||||
@@ -114,6 +114,9 @@ class UserAssetUrlActivity : BaseActivity() {
|
||||
MmkvManager.removeAssetUrl(editAssetId)
|
||||
finish()
|
||||
}
|
||||
.setNegativeButton(android.R.string.no) {_, _ ->
|
||||
// do nothing
|
||||
}
|
||||
.show()
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
package com.v2ray.ang.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.Bitmap
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonPrimitive
|
||||
import com.google.gson.JsonSerializationContext
|
||||
import com.google.gson.JsonSerializer
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.AppConfig.ANG_CONFIG
|
||||
import com.v2ray.ang.AppConfig.PROTOCOL_HTTPS
|
||||
import com.v2ray.ang.AppConfig.PROTOCOL_HTTP
|
||||
import com.v2ray.ang.AppConfig.PROTOCOL_HTTPS
|
||||
import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_ADDRESS_V4
|
||||
import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_MTU
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.dto.*
|
||||
import com.v2ray.ang.dto.V2rayConfig.Companion.DEFAULT_SECURITY
|
||||
import com.v2ray.ang.dto.V2rayConfig.Companion.TLS
|
||||
import com.v2ray.ang.util.MmkvManager.KEY_SELECTED_SERVER
|
||||
import java.net.URI
|
||||
import java.util.*
|
||||
import com.v2ray.ang.extension.idnHost
|
||||
import com.v2ray.ang.extension.removeWhiteSpace
|
||||
import com.v2ray.ang.util.MmkvManager.KEY_SELECTED_SERVER
|
||||
import java.lang.reflect.Type
|
||||
import java.net.URI
|
||||
import java.util.*
|
||||
|
||||
object AngConfigManager {
|
||||
private val mainStorage by lazy {
|
||||
@@ -49,157 +51,158 @@ object AngConfigManager {
|
||||
/**
|
||||
* Legacy loading config
|
||||
*/
|
||||
fun migrateLegacyConfig(c: Context): Boolean? {
|
||||
try {
|
||||
val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(c)
|
||||
val context = defaultSharedPreferences.getString(ANG_CONFIG, "")
|
||||
if (context.isNullOrBlank()) {
|
||||
return null
|
||||
}
|
||||
val angConfig = Gson().fromJson(context, AngConfig::class.java)
|
||||
for (i in angConfig.vmess.indices) {
|
||||
upgradeServerVersion(angConfig.vmess[i])
|
||||
}
|
||||
|
||||
copyLegacySettings(defaultSharedPreferences)
|
||||
migrateVmessBean(angConfig, defaultSharedPreferences)
|
||||
migrateSubItemBean(angConfig)
|
||||
|
||||
defaultSharedPreferences.edit().remove(ANG_CONFIG).apply()
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun copyLegacySettings(sharedPreferences: SharedPreferences) {
|
||||
listOf(
|
||||
AppConfig.PREF_MODE,
|
||||
AppConfig.PREF_REMOTE_DNS,
|
||||
AppConfig.PREF_DOMESTIC_DNS,
|
||||
AppConfig.PREF_LOCAL_DNS_PORT,
|
||||
AppConfig.PREF_SOCKS_PORT,
|
||||
AppConfig.PREF_HTTP_PORT,
|
||||
AppConfig.PREF_LOGLEVEL,
|
||||
AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
|
||||
AppConfig.PREF_ROUTING_MODE,
|
||||
AppConfig.PREF_V2RAY_ROUTING_AGENT,
|
||||
AppConfig.PREF_V2RAY_ROUTING_BLOCKED,
|
||||
AppConfig.PREF_V2RAY_ROUTING_DIRECT,
|
||||
).forEach { key ->
|
||||
settingsStorage?.encode(key, sharedPreferences.getString(key, null))
|
||||
}
|
||||
listOf(
|
||||
AppConfig.PREF_SPEED_ENABLED,
|
||||
AppConfig.PREF_PROXY_SHARING,
|
||||
AppConfig.PREF_LOCAL_DNS_ENABLED,
|
||||
AppConfig.PREF_ALLOW_INSECURE,
|
||||
AppConfig.PREF_PREFER_IPV6,
|
||||
AppConfig.PREF_PER_APP_PROXY,
|
||||
AppConfig.PREF_BYPASS_APPS,
|
||||
).forEach { key ->
|
||||
settingsStorage?.encode(key, sharedPreferences.getBoolean(key, false))
|
||||
}
|
||||
settingsStorage?.encode(
|
||||
AppConfig.PREF_SNIFFING_ENABLED,
|
||||
sharedPreferences.getBoolean(AppConfig.PREF_SNIFFING_ENABLED, true)
|
||||
)
|
||||
settingsStorage?.encode(
|
||||
AppConfig.PREF_PER_APP_PROXY_SET,
|
||||
sharedPreferences.getStringSet(AppConfig.PREF_PER_APP_PROXY_SET, setOf())
|
||||
)
|
||||
}
|
||||
|
||||
private fun migrateVmessBean(angConfig: AngConfig, sharedPreferences: SharedPreferences) {
|
||||
angConfig.vmess.forEachIndexed { index, vmessBean ->
|
||||
val type = EConfigType.fromInt(vmessBean.configType) ?: return@forEachIndexed
|
||||
val config = ServerConfig.create(type)
|
||||
config.remarks = vmessBean.remarks
|
||||
config.subscriptionId = vmessBean.subid
|
||||
if (type == EConfigType.CUSTOM) {
|
||||
val jsonConfig = sharedPreferences.getString(ANG_CONFIG + vmessBean.guid, "")
|
||||
val v2rayConfig = try {
|
||||
Gson().fromJson(jsonConfig, V2rayConfig::class.java)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return@forEachIndexed
|
||||
}
|
||||
config.fullConfig = v2rayConfig
|
||||
serverRawStorage?.encode(vmessBean.guid, jsonConfig)
|
||||
} else {
|
||||
config.outboundBean?.settings?.vnext?.get(0)?.let { vnext ->
|
||||
vnext.address = vmessBean.address
|
||||
vnext.port = vmessBean.port
|
||||
vnext.users[0].id = vmessBean.id
|
||||
if (config.configType == EConfigType.VMESS) {
|
||||
vnext.users[0].alterId = vmessBean.alterId
|
||||
vnext.users[0].security = vmessBean.security
|
||||
} else if (config.configType == EConfigType.VLESS) {
|
||||
vnext.users[0].encryption = vmessBean.security
|
||||
vnext.users[0].flow = vmessBean.flow
|
||||
}
|
||||
}
|
||||
config.outboundBean?.settings?.servers?.get(0)?.let { server ->
|
||||
server.address = vmessBean.address
|
||||
server.port = vmessBean.port
|
||||
if (config.configType == EConfigType.SHADOWSOCKS) {
|
||||
server.password = vmessBean.id
|
||||
server.method = vmessBean.security
|
||||
} else if (config.configType == EConfigType.SOCKS) {
|
||||
if (TextUtils.isEmpty(vmessBean.security) && TextUtils.isEmpty(vmessBean.id)) {
|
||||
server.users = null
|
||||
} else {
|
||||
val socksUsersBean =
|
||||
V2rayConfig.OutboundBean.OutSettingsBean.ServersBean.SocksUsersBean()
|
||||
socksUsersBean.user = vmessBean.security
|
||||
socksUsersBean.pass = vmessBean.id
|
||||
server.users = listOf(socksUsersBean)
|
||||
}
|
||||
} else if (config.configType == EConfigType.TROJAN) {
|
||||
server.password = vmessBean.id
|
||||
}
|
||||
}
|
||||
config.outboundBean?.streamSettings?.let { streamSetting ->
|
||||
val sni = streamSetting.populateTransportSettings(
|
||||
vmessBean.network,
|
||||
vmessBean.headerType,
|
||||
vmessBean.requestHost,
|
||||
vmessBean.path,
|
||||
vmessBean.path,
|
||||
vmessBean.requestHost,
|
||||
vmessBean.path,
|
||||
vmessBean.headerType,
|
||||
vmessBean.path
|
||||
)
|
||||
val allowInsecure = if (vmessBean.allowInsecure.isBlank()) {
|
||||
settingsStorage?.decodeBool(AppConfig.PREF_ALLOW_INSECURE) ?: false
|
||||
} else {
|
||||
vmessBean.allowInsecure.toBoolean()
|
||||
}
|
||||
var fingerprint = streamSetting.tlsSettings?.fingerprint
|
||||
streamSetting.populateTlsSettings(
|
||||
vmessBean.streamSecurity, allowInsecure,
|
||||
vmessBean.sni.ifBlank { sni }, fingerprint, null, null, null, null
|
||||
)
|
||||
}
|
||||
}
|
||||
val key = MmkvManager.encodeServerConfig(vmessBean.guid, config)
|
||||
if (index == angConfig.index) {
|
||||
mainStorage?.encode(KEY_SELECTED_SERVER, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun migrateSubItemBean(angConfig: AngConfig) {
|
||||
angConfig.subItem.forEach {
|
||||
val subItem = SubscriptionItem()
|
||||
subItem.remarks = it.remarks
|
||||
subItem.url = it.url
|
||||
subItem.enabled = it.enabled
|
||||
subStorage?.encode(it.id, Gson().toJson(subItem))
|
||||
}
|
||||
}
|
||||
// fun migrateLegacyConfig(c: Context): Boolean? {
|
||||
// try {
|
||||
// val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(c)
|
||||
// val context = defaultSharedPreferences.getString(ANG_CONFIG, "")
|
||||
// if (context.isNullOrBlank()) {
|
||||
// return null
|
||||
// }
|
||||
// val angConfig = Gson().fromJson(context, AngConfig::class.java)
|
||||
// for (i in angConfig.vmess.indices) {
|
||||
// upgradeServerVersion(angConfig.vmess[i])
|
||||
// }
|
||||
//
|
||||
// copyLegacySettings(defaultSharedPreferences)
|
||||
// migrateVmessBean(angConfig, defaultSharedPreferences)
|
||||
// migrateSubItemBean(angConfig)
|
||||
//
|
||||
// defaultSharedPreferences.edit().remove(ANG_CONFIG).apply()
|
||||
// return true
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
// private fun copyLegacySettings(sharedPreferences: SharedPreferences) {
|
||||
// listOf(
|
||||
// AppConfig.PREF_MODE,
|
||||
// AppConfig.PREF_REMOTE_DNS,
|
||||
// AppConfig.PREF_DOMESTIC_DNS,
|
||||
// AppConfig.PREF_LOCAL_DNS_PORT,
|
||||
// AppConfig.PREF_SOCKS_PORT,
|
||||
// AppConfig.PREF_HTTP_PORT,
|
||||
// AppConfig.PREF_LOGLEVEL,
|
||||
// AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
|
||||
// AppConfig.PREF_ROUTING_MODE,
|
||||
// AppConfig.PREF_V2RAY_ROUTING_AGENT,
|
||||
// AppConfig.PREF_V2RAY_ROUTING_BLOCKED,
|
||||
// AppConfig.PREF_V2RAY_ROUTING_DIRECT,
|
||||
// ).forEach { key ->
|
||||
// settingsStorage?.encode(key, sharedPreferences.getString(key, null))
|
||||
// }
|
||||
// listOf(
|
||||
// AppConfig.PREF_SPEED_ENABLED,
|
||||
// AppConfig.PREF_PROXY_SHARING,
|
||||
// AppConfig.PREF_LOCAL_DNS_ENABLED,
|
||||
// AppConfig.PREF_ALLOW_INSECURE,
|
||||
// AppConfig.PREF_PREFER_IPV6,
|
||||
// AppConfig.PREF_PER_APP_PROXY,
|
||||
// AppConfig.PREF_BYPASS_APPS,
|
||||
// ).forEach { key ->
|
||||
// settingsStorage?.encode(key, sharedPreferences.getBoolean(key, false))
|
||||
// }
|
||||
// settingsStorage?.encode(
|
||||
// AppConfig.PREF_SNIFFING_ENABLED,
|
||||
// sharedPreferences.getBoolean(AppConfig.PREF_SNIFFING_ENABLED, true)
|
||||
// )
|
||||
// settingsStorage?.encode(
|
||||
// AppConfig.PREF_PER_APP_PROXY_SET,
|
||||
// sharedPreferences.getStringSet(AppConfig.PREF_PER_APP_PROXY_SET, setOf())
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// private fun migrateVmessBean(angConfig: AngConfig, sharedPreferences: SharedPreferences) {
|
||||
// angConfig.vmess.forEachIndexed { index, vmessBean ->
|
||||
// val type = EConfigType.fromInt(vmessBean.configType) ?: return@forEachIndexed
|
||||
// val config = ServerConfig.create(type)
|
||||
// config.remarks = vmessBean.remarks
|
||||
// config.subscriptionId = vmessBean.subid
|
||||
// if (type == EConfigType.CUSTOM) {
|
||||
// val jsonConfig = sharedPreferences.getString(ANG_CONFIG + vmessBean.guid, "")
|
||||
// val v2rayConfig = try {
|
||||
// Gson().fromJson(jsonConfig, V2rayConfig::class.java)
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// return@forEachIndexed
|
||||
// }
|
||||
// config.fullConfig = v2rayConfig
|
||||
// serverRawStorage?.encode(vmessBean.guid, jsonConfig)
|
||||
// } else {
|
||||
// config.outboundBean?.settings?.vnext?.get(0)?.let { vnext ->
|
||||
// vnext.address = vmessBean.address
|
||||
// vnext.port = vmessBean.port
|
||||
// vnext.users[0].id = vmessBean.id
|
||||
// if (config.configType == EConfigType.VMESS) {
|
||||
// vnext.users[0].alterId = vmessBean.alterId
|
||||
// vnext.users[0].security = vmessBean.security
|
||||
// } else if (config.configType == EConfigType.VLESS) {
|
||||
// vnext.users[0].encryption = vmessBean.security
|
||||
// vnext.users[0].flow = vmessBean.flow
|
||||
// }
|
||||
// }
|
||||
// config.outboundBean?.settings?.servers?.get(0)?.let { server ->
|
||||
// server.address = vmessBean.address
|
||||
// server.port = vmessBean.port
|
||||
// if (config.configType == EConfigType.SHADOWSOCKS) {
|
||||
// server.password = vmessBean.id
|
||||
// server.method = vmessBean.security
|
||||
// } else if (config.configType == EConfigType.SOCKS) {
|
||||
// if (TextUtils.isEmpty(vmessBean.security) && TextUtils.isEmpty(vmessBean.id)) {
|
||||
// server.users = null
|
||||
// } else {
|
||||
// val socksUsersBean =
|
||||
// V2rayConfig.OutboundBean.OutSettingsBean.ServersBean.SocksUsersBean()
|
||||
// socksUsersBean.user = vmessBean.security
|
||||
// socksUsersBean.pass = vmessBean.id
|
||||
// server.users = listOf(socksUsersBean)
|
||||
// }
|
||||
// } else if (config.configType == EConfigType.TROJAN) {
|
||||
// server.password = vmessBean.id
|
||||
// }
|
||||
// }
|
||||
// config.outboundBean?.streamSettings?.let { streamSetting ->
|
||||
// val sni = streamSetting.populateTransportSettings(
|
||||
// vmessBean.network,
|
||||
// vmessBean.headerType,
|
||||
// vmessBean.requestHost,
|
||||
// vmessBean.path,
|
||||
// vmessBean.path,
|
||||
// vmessBean.requestHost,
|
||||
// vmessBean.path,
|
||||
// vmessBean.headerType,
|
||||
// vmessBean.path,
|
||||
// vmessBean.requestHost,
|
||||
// )
|
||||
// val allowInsecure = if (vmessBean.allowInsecure.isBlank()) {
|
||||
// settingsStorage?.decodeBool(AppConfig.PREF_ALLOW_INSECURE) ?: false
|
||||
// } else {
|
||||
// vmessBean.allowInsecure.toBoolean()
|
||||
// }
|
||||
// var fingerprint = streamSetting.tlsSettings?.fingerprint
|
||||
// streamSetting.populateTlsSettings(
|
||||
// vmessBean.streamSecurity, allowInsecure,
|
||||
// vmessBean.sni.ifBlank { sni }, fingerprint, null, null, null, null
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// val key = MmkvManager.encodeServerConfig(vmessBean.guid, config)
|
||||
// if (index == angConfig.index) {
|
||||
// mainStorage?.encode(KEY_SELECTED_SERVER, key)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private fun migrateSubItemBean(angConfig: AngConfig) {
|
||||
// angConfig.subItem.forEach {
|
||||
// val subItem = SubscriptionItem()
|
||||
// subItem.remarks = it.remarks
|
||||
// subItem.url = it.url
|
||||
// subItem.enabled = it.enabled
|
||||
// subStorage?.encode(it.id, Gson().toJson(subItem))
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* import config form qrcode or...
|
||||
@@ -269,7 +272,8 @@ object AngConfigManager {
|
||||
vmessQRCode.host,
|
||||
vmessQRCode.path,
|
||||
vmessQRCode.type,
|
||||
vmessQRCode.path
|
||||
vmessQRCode.path,
|
||||
vmessQRCode.host
|
||||
)
|
||||
|
||||
val fingerprint = vmessQRCode.fp ?: streamSetting.tlsSettings?.fingerprint
|
||||
@@ -353,7 +357,7 @@ object AngConfigManager {
|
||||
server.port = match.groupValues[4].toInt()
|
||||
val socksUsersBean =
|
||||
V2rayConfig.OutboundBean.OutSettingsBean.ServersBean.SocksUsersBean()
|
||||
socksUsersBean.user = match.groupValues[1].lowercase()
|
||||
socksUsersBean.user = match.groupValues[1]
|
||||
socksUsersBean.pass = match.groupValues[2]
|
||||
server.users = listOf(socksUsersBean)
|
||||
}
|
||||
@@ -377,7 +381,8 @@ object AngConfigManager {
|
||||
queryParam["quicSecurity"],
|
||||
queryParam["key"],
|
||||
queryParam["mode"],
|
||||
queryParam["serviceName"]
|
||||
queryParam["serviceName"],
|
||||
queryParam["authority"]
|
||||
)
|
||||
fingerprint = queryParam["fp"] ?: ""
|
||||
config.outboundBean?.streamSettings?.populateTlsSettings(
|
||||
@@ -405,7 +410,6 @@ object AngConfigManager {
|
||||
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
|
||||
config = ServerConfig.create(EConfigType.VLESS)
|
||||
val streamSetting = config.outboundBean?.streamSettings ?: return -1
|
||||
var fingerprint = streamSetting.tlsSettings?.fingerprint
|
||||
|
||||
config.remarks = Utils.urlDecode(uri.fragment ?: "")
|
||||
config.outboundBean?.settings?.vnext?.get(0)?.let { vnext ->
|
||||
@@ -425,15 +429,18 @@ object AngConfigManager {
|
||||
queryParam["quicSecurity"],
|
||||
queryParam["key"],
|
||||
queryParam["mode"],
|
||||
queryParam["serviceName"]
|
||||
queryParam["serviceName"],
|
||||
queryParam["authority"]
|
||||
)
|
||||
fingerprint = queryParam["fp"] ?: ""
|
||||
val pbk = queryParam["pbk"] ?: ""
|
||||
val sid = queryParam["sid"] ?: ""
|
||||
val spx = Utils.urlDecode(queryParam["spx"] ?: "")
|
||||
streamSetting.populateTlsSettings(
|
||||
queryParam["security"] ?: "", allowInsecure,
|
||||
queryParam["sni"] ?: sni, fingerprint, queryParam["alpn"], pbk, sid, spx
|
||||
queryParam["security"] ?: "",
|
||||
allowInsecure,
|
||||
queryParam["sni"] ?: sni,
|
||||
queryParam["fp"] ?: "",
|
||||
queryParam["alpn"],
|
||||
queryParam["pbk"] ?: "",
|
||||
queryParam["sid"] ?: "",
|
||||
queryParam["spx"] ?: ""
|
||||
)
|
||||
} else if (str.startsWith(EConfigType.WIREGUARD.protocolScheme)) {
|
||||
val uri = URI(Utils.fixIllegalUrl(str))
|
||||
@@ -514,7 +521,8 @@ object AngConfigManager {
|
||||
queryParam["security"],
|
||||
queryParam["key"],
|
||||
queryParam["mode"],
|
||||
queryParam["serviceName"])
|
||||
queryParam["serviceName"],
|
||||
queryParam["authority"])
|
||||
streamSetting.populateTlsSettings(
|
||||
if (tls) TLS else "", allowInsecure, sni, fingerprint, null,
|
||||
null, null, null
|
||||
@@ -577,6 +585,61 @@ object AngConfigManager {
|
||||
password = base64Decode.substringAfter(":")
|
||||
}
|
||||
|
||||
val query = Utils.urlDecode(uri.query ?: "")
|
||||
if (query != "") {
|
||||
val queryPairs = HashMap<String, String>()
|
||||
val pairs = query.split(";")
|
||||
Log.d(AppConfig.ANG_PACKAGE, pairs.toString())
|
||||
for (pair in pairs) {
|
||||
val idx = pair.indexOf("=")
|
||||
if (idx == -1) {
|
||||
queryPairs[Utils.urlDecode(pair)] = "";
|
||||
} else {
|
||||
queryPairs[Utils.urlDecode(pair.substring(0, idx))] =
|
||||
Utils.urlDecode(pair.substring(idx + 1))
|
||||
}
|
||||
}
|
||||
Log.d(AppConfig.ANG_PACKAGE, queryPairs.toString())
|
||||
var sni: String? = ""
|
||||
if (queryPairs["plugin"] == "obfs-local" && queryPairs["obfs"] == "http") {
|
||||
sni = config.outboundBean?.streamSettings?.populateTransportSettings(
|
||||
"tcp",
|
||||
"http",
|
||||
queryPairs["obfs-host"],
|
||||
queryPairs["path"],
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
} else if (queryPairs["plugin"] == "v2ray-plugin") {
|
||||
var network = "ws";
|
||||
if (queryPairs["mode"] == "quic") {
|
||||
network = "quic";
|
||||
}
|
||||
sni = config.outboundBean?.streamSettings?.populateTransportSettings(
|
||||
network,
|
||||
null,
|
||||
queryPairs["host"],
|
||||
queryPairs["path"],
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
if ("tls" in queryPairs) {
|
||||
config.outboundBean?.streamSettings?.populateTlsSettings(
|
||||
"tls", false, sni ?: "", null, null, null, null, null
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
config.outboundBean?.settings?.servers?.get(0)?.let { server ->
|
||||
server.address = uri.idnHost
|
||||
server.port = uri.port
|
||||
@@ -725,7 +788,7 @@ object AngConfigManager {
|
||||
}
|
||||
}
|
||||
|
||||
"ws" -> {
|
||||
"ws", "httpupgrade" -> {
|
||||
if (!TextUtils.isEmpty(transportDetails[1])) {
|
||||
dicQuery["host"] = Utils.urlEncode(transportDetails[1])
|
||||
}
|
||||
@@ -752,7 +815,8 @@ object AngConfigManager {
|
||||
|
||||
"grpc" -> {
|
||||
dicQuery["mode"] = transportDetails[0]
|
||||
dicQuery["serviceName"] = transportDetails[2]
|
||||
dicQuery["authority"] = Utils.urlEncode(transportDetails[1])
|
||||
dicQuery["serviceName"] = Utils.urlEncode(transportDetails[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -886,38 +950,38 @@ object AngConfigManager {
|
||||
return 0
|
||||
}
|
||||
|
||||
/**
|
||||
* upgrade
|
||||
*/
|
||||
private fun upgradeServerVersion(vmess: AngConfig.VmessBean): Int {
|
||||
try {
|
||||
if (vmess.configVersion == 2) {
|
||||
return 0
|
||||
}
|
||||
|
||||
when (vmess.network) {
|
||||
"ws", "h2" -> {
|
||||
var path = ""
|
||||
var host = ""
|
||||
val lstParameter = vmess.requestHost.split(";")
|
||||
if (lstParameter.isNotEmpty()) {
|
||||
path = lstParameter[0].trim()
|
||||
}
|
||||
if (lstParameter.size > 1) {
|
||||
path = lstParameter[0].trim()
|
||||
host = lstParameter[1].trim()
|
||||
}
|
||||
vmess.path = path
|
||||
vmess.requestHost = host
|
||||
}
|
||||
}
|
||||
vmess.configVersion = 2
|
||||
return 0
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return -1
|
||||
}
|
||||
}
|
||||
// /**
|
||||
// * upgrade
|
||||
// */
|
||||
// private fun upgradeServerVersion(vmess: AngConfig.VmessBean): Int {
|
||||
// try {
|
||||
// if (vmess.configVersion == 2) {
|
||||
// return 0
|
||||
// }
|
||||
//
|
||||
// when (vmess.network) {
|
||||
// "ws", "h2" -> {
|
||||
// var path = ""
|
||||
// var host = ""
|
||||
// val lstParameter = vmess.requestHost.split(";")
|
||||
// if (lstParameter.isNotEmpty()) {
|
||||
// path = lstParameter[0].trim()
|
||||
// }
|
||||
// if (lstParameter.size > 1) {
|
||||
// path = lstParameter[0].trim()
|
||||
// host = lstParameter[1].trim()
|
||||
// }
|
||||
// vmess.path = path
|
||||
// vmess.requestHost = host
|
||||
// }
|
||||
// }
|
||||
// vmess.configVersion = 2
|
||||
// return 0
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// return -1
|
||||
// }
|
||||
// }
|
||||
|
||||
fun importBatchConfig(servers: String?, subid: String, append: Boolean): Int {
|
||||
try {
|
||||
@@ -987,23 +1051,34 @@ object AngConfigManager {
|
||||
&& server.contains("routing")
|
||||
) {
|
||||
try {
|
||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
||||
val serverList: Array<V2rayConfig> =
|
||||
Gson().fromJson(server, Array<V2rayConfig>::class.java)
|
||||
//val gson = GsonBuilder().setPrettyPrinting().create()
|
||||
val gson = GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.disableHtmlEscaping()
|
||||
.registerTypeAdapter( // custom serialiser is needed here since JSON by default parse number as Double, core will fail to start
|
||||
object : TypeToken<Double>() {}.type,
|
||||
JsonSerializer { src: Double?, _: Type?, _: JsonSerializationContext? ->
|
||||
JsonPrimitive(
|
||||
src?.toInt()
|
||||
)
|
||||
}
|
||||
)
|
||||
.create()
|
||||
val serverList: Array<Any> =
|
||||
Gson().fromJson(server, Array<Any>::class.java)
|
||||
|
||||
if (serverList.isNotEmpty()) {
|
||||
var count = 0
|
||||
for (srv in serverList) {
|
||||
if (srv.inbounds != null && srv.outbounds != null && srv.routing != null) {
|
||||
val config = ServerConfig.create(EConfigType.CUSTOM)
|
||||
config.remarks = srv.remarks
|
||||
?: "%04d-".format(count + 1) + System.currentTimeMillis()
|
||||
.toString()
|
||||
config.subscriptionId = subid
|
||||
config.fullConfig = srv
|
||||
val key = MmkvManager.encodeServerConfig("", config)
|
||||
serverRawStorage?.encode(key, gson.toJson(srv))
|
||||
count += 1
|
||||
}
|
||||
val config = ServerConfig.create(EConfigType.CUSTOM)
|
||||
config.fullConfig = Gson().fromJson(Gson().toJson(srv), V2rayConfig::class.java)
|
||||
config.remarks = config.fullConfig?.remarks
|
||||
?: ("%04d-".format(count + 1) + System.currentTimeMillis()
|
||||
.toString())
|
||||
config.subscriptionId = subid
|
||||
val key = MmkvManager.encodeServerConfig("", config)
|
||||
serverRawStorage?.encode(key, gson.toJson(srv))
|
||||
count += 1
|
||||
}
|
||||
return count
|
||||
}
|
||||
@@ -1015,8 +1090,7 @@ object AngConfigManager {
|
||||
val config = ServerConfig.create(EConfigType.CUSTOM)
|
||||
config.subscriptionId = subid
|
||||
config.fullConfig = Gson().fromJson(server, V2rayConfig::class.java)
|
||||
config.remarks = System.currentTimeMillis().toString()
|
||||
// config.remarks = config.fullConfig?.remarks ?: System.currentTimeMillis().toString()
|
||||
config.remarks = config.fullConfig?.remarks ?: System.currentTimeMillis().toString()
|
||||
val key = MmkvManager.encodeServerConfig("", config)
|
||||
serverRawStorage?.encode(key, server)
|
||||
return 1
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package com.v2ray.ang.util
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.text.Editable
|
||||
import android.util.Base64
|
||||
import java.util.*
|
||||
import android.content.ClipData
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_MASK
|
||||
@@ -14,18 +11,22 @@ import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.LocaleList
|
||||
import android.provider.Settings
|
||||
import android.text.Editable
|
||||
import android.util.Base64
|
||||
import android.util.Log
|
||||
import android.util.Patterns
|
||||
import android.webkit.URLUtil
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.AppConfig.ANG_PACKAGE
|
||||
import com.v2ray.ang.BuildConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.extension.toast
|
||||
import java.net.*
|
||||
import com.v2ray.ang.service.V2RayServiceManager
|
||||
import java.io.IOException
|
||||
import java.net.*
|
||||
import java.util.*
|
||||
|
||||
object Utils {
|
||||
|
||||
@@ -139,18 +140,16 @@ object Utils {
|
||||
* get remote dns servers from preference
|
||||
*/
|
||||
fun getRemoteDnsServers(): List<String> {
|
||||
val remoteDns = settingsStorage?.decodeString(AppConfig.PREF_REMOTE_DNS) ?: AppConfig.DNS_AGENT
|
||||
val remoteDns = settingsStorage?.decodeString(AppConfig.PREF_REMOTE_DNS) ?: AppConfig.DNS_PROXY
|
||||
val ret = remoteDns.split(",").filter { isPureIpAddress(it) || isCoreDNSAddress(it) }
|
||||
if (ret.isEmpty()) {
|
||||
return listOf(AppConfig.DNS_AGENT)
|
||||
return listOf(AppConfig.DNS_PROXY)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
fun getVpnDnsServers(): List<String> {
|
||||
val vpnDns = settingsStorage?.decodeString(AppConfig.PREF_VPN_DNS)
|
||||
?: settingsStorage?.decodeString(AppConfig.PREF_REMOTE_DNS)
|
||||
?: AppConfig.DNS_AGENT
|
||||
val vpnDns = settingsStorage?.decodeString(AppConfig.PREF_VPN_DNS)?:AppConfig.DNS_VPN
|
||||
return vpnDns.split(",").filter { isPureIpAddress(it) }
|
||||
// allow empty, in that case dns will use system default
|
||||
}
|
||||
@@ -160,7 +159,7 @@ object Utils {
|
||||
*/
|
||||
fun getDomesticDnsServers(): List<String> {
|
||||
val domesticDns = settingsStorage?.decodeString(AppConfig.PREF_DOMESTIC_DNS) ?: AppConfig.DNS_DIRECT
|
||||
val ret = domesticDns.split(",").filter { isPureIpAddress(it) || isCoreDNSAddress(it) }
|
||||
val ret = domesticDns.split(",").filter { isPureIpAddress(it) }
|
||||
if (ret.isEmpty()) {
|
||||
return listOf(AppConfig.DNS_DIRECT)
|
||||
}
|
||||
@@ -318,6 +317,14 @@ object Utils {
|
||||
return extDir.absolutePath
|
||||
}
|
||||
|
||||
fun backupPath(context: Context?): String {
|
||||
if (context == null)
|
||||
return ""
|
||||
val extDir = context.getExternalFilesDir(AppConfig.DIR_BACKUPS)
|
||||
?: return context.getDir(AppConfig.DIR_BACKUPS, 0).absolutePath
|
||||
return extDir.absolutePath
|
||||
}
|
||||
|
||||
fun getDeviceIdForXUDPBaseKey(): String {
|
||||
val androidId = Settings.Secure.ANDROID_ID.toByteArray(charset("UTF-8"))
|
||||
return Base64.encodeToString(androidId.copyOf(32), Base64.NO_PADDING.or(Base64.URL_SAFE))
|
||||
@@ -365,6 +372,14 @@ object Utils {
|
||||
return mode != UI_MODE_NIGHT_NO
|
||||
}
|
||||
|
||||
fun setNightMode(context: Context) {
|
||||
when (settingsStorage?.decodeString(AppConfig.PREF_UI_MODE_NIGHT, "0")) {
|
||||
"0" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
"1" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
||||
"2" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||
}
|
||||
}
|
||||
|
||||
fun getIpv6Address(address: String): String {
|
||||
return if (isIpv6Address(address) && !address.contains('[') && !address.contains(']')) {
|
||||
String.format("[%s]", address)
|
||||
|
||||
@@ -49,7 +49,7 @@ object V2rayConfigUtil {
|
||||
return Result(true, customConfig)
|
||||
}
|
||||
val outbound = config.getProxyOutbound() ?: return Result(false, "")
|
||||
val result = getV2rayNonCustomConfig(context, outbound)
|
||||
val result = getV2rayNonCustomConfig(context, outbound, config.remarks)
|
||||
//Log.d(ANG_PACKAGE, result.content)
|
||||
return result
|
||||
} catch (e: Exception) {
|
||||
@@ -63,7 +63,8 @@ object V2rayConfigUtil {
|
||||
*/
|
||||
private fun getV2rayNonCustomConfig(
|
||||
context: Context,
|
||||
outbound: V2rayConfig.OutboundBean
|
||||
outbound: V2rayConfig.OutboundBean,
|
||||
remarks: String,
|
||||
): Result {
|
||||
val result = Result(false, "")
|
||||
//取得默认配置
|
||||
@@ -98,6 +99,9 @@ object V2rayConfigUtil {
|
||||
v2rayConfig.stats = null
|
||||
v2rayConfig.policy = null
|
||||
}
|
||||
|
||||
v2rayConfig.remarks = remarks
|
||||
|
||||
result.status = true
|
||||
result.content = v2rayConfig.toPrettyPrinting()
|
||||
return result
|
||||
@@ -171,7 +175,7 @@ object V2rayConfigUtil {
|
||||
try {
|
||||
routingUserRule(
|
||||
settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_AGENT)
|
||||
?: "", AppConfig.TAG_AGENT, v2rayConfig
|
||||
?: "", AppConfig.TAG_PROXY, v2rayConfig
|
||||
)
|
||||
routingUserRule(
|
||||
settingsStorage?.decodeString(AppConfig.PREF_V2RAY_ROUTING_DIRECT)
|
||||
@@ -187,12 +191,11 @@ object V2rayConfigUtil {
|
||||
?: "IPIfNonMatch"
|
||||
// v2rayConfig.routing.domainMatcher = "mph"
|
||||
val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE)
|
||||
?: ERoutingMode.GLOBAL_PROXY.value
|
||||
?: ERoutingMode.BYPASS_LAN_MAINLAND.value
|
||||
|
||||
// Hardcode googleapis.cn
|
||||
val googleapisRoute = V2rayConfig.RoutingBean.RulesBean(
|
||||
type = "field",
|
||||
outboundTag = AppConfig.TAG_AGENT,
|
||||
outboundTag = AppConfig.TAG_PROXY,
|
||||
domain = arrayListOf("domain:googleapis.cn")
|
||||
)
|
||||
|
||||
@@ -203,24 +206,34 @@ object V2rayConfigUtil {
|
||||
|
||||
ERoutingMode.BYPASS_MAINLAND.value -> {
|
||||
routingGeo("", "cn", AppConfig.TAG_DIRECT, v2rayConfig)
|
||||
routingGeo("domain", "geolocation-cn", AppConfig.TAG_DIRECT, v2rayConfig)
|
||||
v2rayConfig.routing.rules.add(0, googleapisRoute)
|
||||
}
|
||||
|
||||
ERoutingMode.BYPASS_LAN_MAINLAND.value -> {
|
||||
routingGeo("ip", "private", AppConfig.TAG_DIRECT, v2rayConfig)
|
||||
routingGeo("", "cn", AppConfig.TAG_DIRECT, v2rayConfig)
|
||||
routingGeo("domain", "geolocation-cn", AppConfig.TAG_DIRECT, v2rayConfig)
|
||||
v2rayConfig.routing.rules.add(0, googleapisRoute)
|
||||
}
|
||||
|
||||
ERoutingMode.GLOBAL_DIRECT.value -> {
|
||||
val globalDirect = V2rayConfig.RoutingBean.RulesBean(
|
||||
type = "field",
|
||||
outboundTag = AppConfig.TAG_DIRECT,
|
||||
port = "0-65535"
|
||||
)
|
||||
v2rayConfig.routing.rules.add(globalDirect)
|
||||
}
|
||||
}
|
||||
|
||||
if(routingMode != ERoutingMode.GLOBAL_DIRECT.value) {
|
||||
v2rayConfig.routing.rules.add(
|
||||
V2rayConfig.RoutingBean.RulesBean(
|
||||
outboundTag = AppConfig.TAG_PROXY,
|
||||
port = "0-65535"
|
||||
))
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
@@ -239,7 +252,6 @@ object V2rayConfigUtil {
|
||||
//IP
|
||||
if (ipOrDomain == "ip" || ipOrDomain == "") {
|
||||
val rulesIP = V2rayConfig.RoutingBean.RulesBean()
|
||||
rulesIP.type = "field"
|
||||
rulesIP.outboundTag = tag
|
||||
rulesIP.ip = ArrayList()
|
||||
rulesIP.ip?.add("geoip:$code")
|
||||
@@ -249,7 +261,6 @@ object V2rayConfigUtil {
|
||||
if (ipOrDomain == "domain" || ipOrDomain == "") {
|
||||
//Domain
|
||||
val rulesDomain = V2rayConfig.RoutingBean.RulesBean()
|
||||
rulesDomain.type = "field"
|
||||
rulesDomain.outboundTag = tag
|
||||
rulesDomain.domain = ArrayList()
|
||||
rulesDomain.domain?.add("geosite:$code")
|
||||
@@ -266,13 +277,11 @@ object V2rayConfigUtil {
|
||||
if (!TextUtils.isEmpty(userRule)) {
|
||||
//Domain
|
||||
val rulesDomain = V2rayConfig.RoutingBean.RulesBean()
|
||||
rulesDomain.type = "field"
|
||||
rulesDomain.outboundTag = tag
|
||||
rulesDomain.domain = ArrayList()
|
||||
|
||||
//IP
|
||||
val rulesIP = V2rayConfig.RoutingBean.RulesBean()
|
||||
rulesIP.type = "field"
|
||||
rulesIP.outboundTag = tag
|
||||
rulesIP.ip = ArrayList()
|
||||
|
||||
@@ -340,7 +349,7 @@ object V2rayConfigUtil {
|
||||
val remoteDns = Utils.getRemoteDnsServers()
|
||||
if (v2rayConfig.inbounds.none { e -> e.protocol == "dokodemo-door" && e.tag == "dns-in" }) {
|
||||
val dnsInboundSettings = V2rayConfig.InboundBean.InSettingsBean(
|
||||
address = if (Utils.isPureIpAddress(remoteDns.first())) remoteDns.first() else "1.1.1.1",
|
||||
address = if (Utils.isPureIpAddress(remoteDns.first())) remoteDns.first() else AppConfig.DNS_PROXY,
|
||||
port = 53,
|
||||
network = "tcp,udp"
|
||||
)
|
||||
@@ -377,7 +386,6 @@ object V2rayConfigUtil {
|
||||
// DNS routing tag
|
||||
v2rayConfig.routing.rules.add(
|
||||
0, V2rayConfig.RoutingBean.RulesBean(
|
||||
type = "field",
|
||||
inboundTag = arrayListOf("dns-in"),
|
||||
outboundTag = "dns-out",
|
||||
domain = null
|
||||
@@ -420,10 +428,10 @@ object V2rayConfigUtil {
|
||||
?: ""
|
||||
)
|
||||
val routingMode = settingsStorage?.decodeString(AppConfig.PREF_ROUTING_MODE)
|
||||
?: ERoutingMode.GLOBAL_PROXY.value
|
||||
?: ERoutingMode.BYPASS_LAN_MAINLAND.value
|
||||
if (directDomain.size > 0 || routingMode == ERoutingMode.BYPASS_MAINLAND.value || routingMode == ERoutingMode.BYPASS_LAN_MAINLAND.value) {
|
||||
val domesticDns = Utils.getDomesticDnsServers()
|
||||
val geositeCn = arrayListOf("geosite:cn")
|
||||
val geositeCn = arrayListOf("geosite:cn","geosite:geolocation-cn")
|
||||
val geoipCn = arrayListOf("geoip:cn")
|
||||
if (directDomain.size > 0) {
|
||||
servers.add(
|
||||
@@ -448,7 +456,6 @@ object V2rayConfigUtil {
|
||||
if (Utils.isPureIpAddress(domesticDns.first())) {
|
||||
v2rayConfig.routing.rules.add(
|
||||
0, V2rayConfig.RoutingBean.RulesBean(
|
||||
type = "field",
|
||||
outboundTag = AppConfig.TAG_DIRECT,
|
||||
port = "53",
|
||||
ip = arrayListOf(domesticDns.first()),
|
||||
@@ -479,8 +486,7 @@ object V2rayConfigUtil {
|
||||
if (Utils.isPureIpAddress(remoteDns.first())) {
|
||||
v2rayConfig.routing.rules.add(
|
||||
0, V2rayConfig.RoutingBean.RulesBean(
|
||||
type = "field",
|
||||
outboundTag = AppConfig.TAG_AGENT,
|
||||
outboundTag = AppConfig.TAG_PROXY,
|
||||
port = "53",
|
||||
ip = arrayListOf(remoteDns.first()),
|
||||
domain = null
|
||||
@@ -581,10 +587,21 @@ object V2rayConfigUtil {
|
||||
tag = TAG_FRAGMENT,
|
||||
mux = null
|
||||
)
|
||||
|
||||
var packets = settingsStorage?.decodeString(AppConfig.PREF_FRAGMENT_PACKETS) ?: "tlshello"
|
||||
if (v2rayConfig.outbounds[0].streamSettings?.security == V2rayConfig.REALITY
|
||||
&& packets == "tlshello"
|
||||
) {
|
||||
packets = "1-3"
|
||||
} else if (v2rayConfig.outbounds[0].streamSettings?.security == V2rayConfig.TLS
|
||||
&& packets != "tlshello"
|
||||
) {
|
||||
packets = "tlshello"
|
||||
}
|
||||
|
||||
fragmentOutbound.settings = V2rayConfig.OutboundBean.OutSettingsBean(
|
||||
fragment = V2rayConfig.OutboundBean.OutSettingsBean.FragmentBean(
|
||||
packets = settingsStorage?.decodeString(AppConfig.PREF_FRAGMENT_PACKETS)
|
||||
?: "tlshello",
|
||||
packets = packets,
|
||||
length = settingsStorage?.decodeString(AppConfig.PREF_FRAGMENT_LENGTH)
|
||||
?: "50-100",
|
||||
interval = settingsStorage?.decodeString(AppConfig.PREF_FRAGMENT_INTERVAL)
|
||||
|
||||
102
V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/ZipUtil.kt
Normal file
102
V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/ZipUtil.kt
Normal file
@@ -0,0 +1,102 @@
|
||||
package com.v2ray.ang.util
|
||||
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipFile
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
object ZipUtil {
|
||||
private const val BUFFER_SIZE = 4096
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun zipFromFolder(folderPath: String, outputZipFilePath: String): Boolean {
|
||||
val buffer = ByteArray(BUFFER_SIZE)
|
||||
|
||||
try {
|
||||
if (folderPath.isEmpty() || outputZipFilePath.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
|
||||
val filesToCompress = ArrayList<String>()
|
||||
val directory = File(folderPath)
|
||||
if (directory.isDirectory) {
|
||||
directory.listFiles()?.forEach {
|
||||
if (it.isFile) {
|
||||
filesToCompress.add(it.absolutePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filesToCompress.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
|
||||
val zos = ZipOutputStream(FileOutputStream(outputZipFilePath))
|
||||
|
||||
filesToCompress.forEach { file ->
|
||||
val ze = ZipEntry(File(file).name)
|
||||
zos.putNextEntry(ze)
|
||||
val inputStream = FileInputStream(file)
|
||||
while (true) {
|
||||
val len = inputStream.read(buffer)
|
||||
if (len <= 0) break
|
||||
zos.write(buffer, 0, len)
|
||||
}
|
||||
|
||||
inputStream.close()
|
||||
}
|
||||
|
||||
zos.closeEntry()
|
||||
zos.close()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun unzipToFolder(zipFile: File, destDirectory: String): Boolean {
|
||||
File(destDirectory).run {
|
||||
if (!exists()) {
|
||||
mkdirs()
|
||||
}
|
||||
}
|
||||
try {
|
||||
ZipFile(zipFile).use { zip ->
|
||||
zip.entries().asSequence().forEach { entry ->
|
||||
zip.getInputStream(entry).use { input ->
|
||||
val filePath = destDirectory + File.separator + entry.name
|
||||
if (!entry.isDirectory) {
|
||||
// if the entry is a file, extracts it
|
||||
extractFile(input, filePath)
|
||||
} else {
|
||||
// if the entry is a directory, make the directory
|
||||
val dir = File(filePath)
|
||||
dir.mkdir()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun extractFile(inputStream: InputStream, destFilePath: String) {
|
||||
val bos = BufferedOutputStream(FileOutputStream(destFilePath))
|
||||
val bytesIn = ByteArray(BUFFER_SIZE)
|
||||
var read: Int
|
||||
while (inputStream.read(bytesIn).also { read = it } != -1) {
|
||||
bos.write(bytesIn, 0, read)
|
||||
}
|
||||
bos.close()
|
||||
}
|
||||
}
|
||||
@@ -97,9 +97,9 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
fun appendCustomConfigServer(server: String) {
|
||||
val config = ServerConfig.create(EConfigType.CUSTOM)
|
||||
config.remarks = System.currentTimeMillis().toString()
|
||||
config.subscriptionId = subscriptionId
|
||||
config.fullConfig = Gson().fromJson(server, V2rayConfig::class.java)
|
||||
config.remarks = config.fullConfig?.remarks ?: System.currentTimeMillis().toString()
|
||||
val key = MmkvManager.encodeServerConfig("", config)
|
||||
serverRawStorage?.encode(key, server)
|
||||
serverList.add(0, key)
|
||||
|
||||
@@ -8,24 +8,33 @@ import androidx.preference.PreferenceManager
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.util.MmkvManager
|
||||
import com.v2ray.ang.util.Utils
|
||||
|
||||
class SettingsViewModel(application: Application) : AndroidViewModel(application), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
class SettingsViewModel(application: Application) : AndroidViewModel(application),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) }
|
||||
private val settingsStorage by lazy {
|
||||
MMKV.mmkvWithID(
|
||||
MmkvManager.ID_SETTING,
|
||||
MMKV.MULTI_PROCESS_MODE
|
||||
)
|
||||
}
|
||||
|
||||
fun startListenPreferenceChange() {
|
||||
PreferenceManager.getDefaultSharedPreferences(getApplication()).registerOnSharedPreferenceChangeListener(this)
|
||||
PreferenceManager.getDefaultSharedPreferences(getApplication())
|
||||
.registerOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
PreferenceManager.getDefaultSharedPreferences(getApplication()).unregisterOnSharedPreferenceChangeListener(this)
|
||||
PreferenceManager.getDefaultSharedPreferences(getApplication())
|
||||
.unregisterOnSharedPreferenceChangeListener(this)
|
||||
Log.i(AppConfig.ANG_PACKAGE, "Settings ViewModel is cleared")
|
||||
super.onCleared()
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) {
|
||||
Log.d(AppConfig.ANG_PACKAGE, "Observe settings changed: $key")
|
||||
when(key) {
|
||||
when (key) {
|
||||
AppConfig.PREF_MODE,
|
||||
AppConfig.PREF_VPN_DNS,
|
||||
AppConfig.PREF_REMOTE_DNS,
|
||||
@@ -35,6 +44,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
|
||||
AppConfig.PREF_HTTP_PORT,
|
||||
AppConfig.PREF_LOGLEVEL,
|
||||
AppConfig.PREF_LANGUAGE,
|
||||
AppConfig.PREF_UI_MODE_NIGHT,
|
||||
AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
|
||||
AppConfig.PREF_ROUTING_MODE,
|
||||
AppConfig.PREF_V2RAY_ROUTING_AGENT,
|
||||
@@ -44,9 +54,11 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
|
||||
AppConfig.PREF_FRAGMENT_PACKETS,
|
||||
AppConfig.PREF_FRAGMENT_LENGTH,
|
||||
AppConfig.PREF_FRAGMENT_INTERVAL,
|
||||
AppConfig.PREF_MUX_XUDP_QUIC, -> {
|
||||
AppConfig.PREF_MUX_XUDP_QUIC,
|
||||
-> {
|
||||
settingsStorage?.encode(key, sharedPreferences.getString(key, ""))
|
||||
}
|
||||
|
||||
AppConfig.PREF_SPEED_ENABLED,
|
||||
AppConfig.PREF_PROXY_SHARING,
|
||||
AppConfig.PREF_LOCAL_DNS_ENABLED,
|
||||
@@ -59,19 +71,26 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
|
||||
AppConfig.PREF_START_SCAN_IMMEDIATE,
|
||||
AppConfig.SUBSCRIPTION_AUTO_UPDATE,
|
||||
AppConfig.PREF_FRAGMENT_ENABLED,
|
||||
AppConfig.PREF_MUX_ENABLED, -> {
|
||||
AppConfig.PREF_MUX_ENABLED,
|
||||
-> {
|
||||
settingsStorage?.encode(key, sharedPreferences.getBoolean(key, false))
|
||||
}
|
||||
|
||||
AppConfig.PREF_SNIFFING_ENABLED -> {
|
||||
settingsStorage?.encode(key, sharedPreferences.getBoolean(key, true))
|
||||
}
|
||||
|
||||
AppConfig.PREF_MUX_CONCURRENCY,
|
||||
AppConfig.PREF_MUX_XUDP_CONCURRENCY -> {
|
||||
settingsStorage?.encode(key, sharedPreferences.getString(key, "8")?.toIntOrNull() ?: 8)
|
||||
}
|
||||
AppConfig.PREF_PER_APP_PROXY_SET -> {
|
||||
settingsStorage?.encode(key, sharedPreferences.getStringSet(key, setOf()))
|
||||
settingsStorage?.encode(key, sharedPreferences.getString(key, "8"))
|
||||
}
|
||||
|
||||
// AppConfig.PREF_PER_APP_PROXY_SET -> {
|
||||
// settingsStorage?.encode(key, sharedPreferences.getStringSet(key, setOf()))
|
||||
// }
|
||||
}
|
||||
if (key == AppConfig.PREF_UI_MODE_NIGHT) {
|
||||
Utils.setNightMode(getApplication())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 651 B |
Binary file not shown.
|
Before Width: | Height: | Size: 476 B |
12
V2rayNG/app/src/main/res/drawable-night/ic_about_24dp.xml
Normal file
12
V2rayNG/app/src/main/res/drawable-night/ic_about_24dp.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M810.7,206.3A426.7,426.7 0,1 0,512 938.7h5.5A426.7,426.7 0,0 0,810.7 206.3zM771.8,765A360.1,360.1 0,0 1,517.1 874.7L512,874.7a362.7,362.7 0,0 1,-4.9 -725.3h3.4a362.7,362.7 0,0 1,261.3 615.7z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M547.2,390a57.4,57.4 0,0 0,62.3 -55.3,39.3 39.3,0 0,0 -45,-42.7 58.9,58.9 0,0 0,-64 54.6c-1.7,26.9 13.9,43.3 46.7,43.3zM548.3,663.5c-5.5,0 -7.9,-7.3 -2.3,-28.2l31.1,-118c11.7,-42.7 7.9,-71.3 -15.8,-71.3 -28.4,0 -94.7,28.4 -152.5,76.4l11.7,19.4a181.3,181.3 0,0 1,56.1 -24.7c5.5,0 4.7,7.3 0,25.2l-27.3,112.2c-16.6,64 0,77.7 24.5,77.7s85.3,-21.3 141,-77.7l-13.4,-17.9a122.7,122.7 0,0 1,-53.1 26.9z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M864,192L704,192L704,96c0,-17.7 -14.3,-32 -32,-32L352,64c-9,0 -17.2,3.7 -22.9,9.7L137.7,265.1c-6,5.8 -9.7,14 -9.7,22.9v512c0,17.7 14.3,32 32,32h160v96c0,17.7 14.3,32 32,32h512c17.7,0 32,-14.3 32,-32L896,224c0,-17.7 -14.3,-32 -32,-32zM320,173.2L320,256h-82.8l82.8,-82.8zM192,768L192,320h160c17.7,0 32,-14.3 32,-32L384,128h256v64h-96c-9,0 -17.2,3.7 -22.9,9.7L329.7,393.1c-6,5.8 -9.7,14 -9.7,22.9v352L192,768zM512,301.2L512,384h-82.8l82.8,-82.8zM832,896L384,896L384,448h160c17.7,0 32,-14.3 32,-32L576,256h256v640z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM13,14h-2v-2h2v2zM13,10h-2L11,6h2v4z"/>
|
||||
android:pathData="M512,192.7v42.7a21.3,21.3 0,0 1,-21.3 21.3H213.5V770.6l552.9,-2.2v-233.4a21.3,21.3 0,0 1,21.3 -21.3h42.7a21.3,21.3 0,0 1,21.3 21.3v256.1c0,32.6 -24.9,59.3 -56.6,62.4l-6.1,0.3 -598.2,2.1c-32.6,0 -59.3,-24.8 -62.4,-56.6l-0.3,-6V234c0,-32.6 24.8,-59.3 56.6,-62.4l6,-0.3H490.7a21.3,21.3 0,0 1,21.3 21.3z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M848.7,238.2l-250.8,250.8a21.3,21.3 0,0 1,-13.1 6.1c-30.8,2.9 -47.9,2.6 -51.2,-0.8 -3.4,-3.4 -4,-20.8 -2,-52.3a21.3,21.3 0,0 1,6.2 -13.7l250.5,-250.6a21.3,21.3 0,0 1,30.2 0l30.2,30.2a21.3,21.3 0,0 1,0 30.2z" />
|
||||
</vector>
|
||||
|
||||
@@ -1,34 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:pathData="M11,23h8a3,3 0,0 0,3 -3V8L15,1H7A3,3 0,0 0,4 4V9"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M15,5a3,3 0,0 0,3 3h4L15,1Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M2,17L10,17"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M6,13L6,21"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFF"
|
||||
android:strokeLineCap="round"/>
|
||||
android:pathData="M537,85.3A85.3,85.3 0,0 1,597.3 110.3L828.3,341.3A85.3,85.3 0,0 1,853.3 401.7L853.3,810.7a128,128 0,0 1,-128 128L298.7,938.7a128,128 0,0 1,-128 -128L170.7,213.3a128,128 0,0 1,128 -128zM537,170.7L298.7,170.7a42.7,42.7 0,0 0,-42.7 42.7v597.3a42.7,42.7 0,0 0,42.7 42.7h426.7a42.7,42.7 0,0 0,42.7 -42.7L768,401.7L537,170.7zM512,384a42.7,42.7 0,0 1,42.4 37.7L554.7,426.7v85.3h85.3a42.7,42.7 0,0 1,5 85L640,597.3h-85.3v85.3a42.7,42.7 0,0 1,-85 5L469.3,682.7v-85.3L384,597.3a42.7,42.7 0,0 1,-5 -85L384,512h85.3v-85.3a42.7,42.7 0,0 1,42.7 -42.7z"
|
||||
android:fillColor="#FFFFFFFF"/>
|
||||
</vector>
|
||||
|
||||
12
V2rayNG/app/src/main/res/drawable-night/ic_image_24dp.xml
Normal file
12
V2rayNG/app/src/main/res/drawable-night/ic_image_24dp.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M784,112L240,112c-88,0 -160,72 -160,160v480c0,88 72,160 160,160h544c88,0 160,-72 160,-160L944,272c0,-88 -72,-160 -160,-160zM880,752c0,52.8 -43.2,96 -96,96L240,848c-52.8,0 -96,-43.2 -96,-96L144,272c0,-52.8 43.2,-96 96,-96h544c52.8,0 96,43.2 96,96v480z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M352,480c52.8,0 96,-43.2 96,-96s-43.2,-96 -96,-96 -96,43.2 -96,96 43.2,96 96,96zM352,352c17.6,0 32,14.4 32,32s-14.4,32 -32,32 -32,-14.4 -32,-32 14.4,-32 32,-32zM814.4,731.2l-3.2,-3.2 -177.6,-177.6c-25.6,-25.6 -65.6,-25.6 -91.2,0l-80,80 -36.8,-36.8c-25.6,-25.6 -65.6,-25.6 -91.2,0L200,728c-4.8,6.4 -8,14.4 -8,24 0,17.6 14.4,32 32,32 9.6,0 16,-3.2 22.4,-9.6L380.8,640l134.4,134.4c6.4,6.4 14.4,9.6 24,9.6 17.6,0 32,-14.4 32,-32 0,-9.6 -4.8,-17.6 -9.6,-24l-52.8,-52.8 80,-80L769.6,776c6.4,4.8 12.8,8 20.8,8 17.6,0 32,-14.4 32,-32 0,-8 -3.2,-16 -8,-20.8z" />
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#fff"
|
||||
android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z"/>
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm1,15h-2v-6h2v6zm0,-8h-2V7h2v2z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M11,15h2v2h-2zM11,7h2v6h-2zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
|
||||
android:pathData="M273.2,212.8h583.7L856.9,906.2h-583.7L273.2,212.8zM344.9,284.5L344.9,834.6h440.3L785.2,284.5h-440.3z"
|
||||
android:fillColor="#FFFFFFFF"/>
|
||||
<path
|
||||
android:pathData="M167.1,117.8h554.4v123.6h-71.7V189.4H238.8v498.8h73.9v71.7H167.1V117.8z"
|
||||
android:fillColor="#FFFFFFFF"/>
|
||||
<path
|
||||
android:pathData="M674.8,504H455.3v-71.7h219.4v71.7zM674.8,650.2H455.3v-71.7h219.4v71.7z"
|
||||
android:fillColor="#FFFFFFFF"/>
|
||||
</vector>
|
||||
|
||||
9
V2rayNG/app/src/main/res/drawable-night/ic_play_24dp.xml
Normal file
9
V2rayNG/app/src/main/res/drawable-night/ic_play_24dp.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M213.333333 789.461333V234.538667C213.333333 168.533333 285.013333 127.530667 341.930667 160.981333l471.68 277.461334c56.106667 32.981333 56.106667 114.133333 0 147.114666L341.930667 863.018667C285.056 896.469333 213.333333 855.466667 213.333333 789.461333z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M471.5,77.5a128,128 0,0 1,72.1 -2.6l8.9,2.6 256,85.3a128,128 0,0 1,87.3 113.6l0.3,7.8L896,512c0,101.6 -44.5,186 -103.2,253.1l-8.1,9 -12.1,12.8a618.2,618.2 0,0 1,-25 24.2l-12.8,11.4 -13,11a839.3,839.3 0,0 1,-127.7 86.5l-19.5,10.5 -17.5,9a101.4,101.4 0,0 1,-90.5 0l-18.9,-9.6c-40.1,-21.1 -93.9,-53.2 -145.9,-96.3l-12.9,-11 -12.8,-11.4a618.2,618.2 0,0 1,-24.9 -24.2l-12.1,-12.8 -8.1,-9c-55.9,-63.9 -98.9,-143.4 -102.9,-238.6L128,512L128,284.2A128,128 0,0 1,208.2 165.5l7.3,-2.7 256,-85.3zM512,661.3c-80.2,0 -151.1,40.3 -193.4,101.7 62,57.2 132.2,97.2 176.6,119a37.4,37.4 0,0 0,33.7 0c44.4,-21.9 114.6,-61.9 176.6,-119A234.4,234.4 0,0 0,512 661.3zM491.8,138.2l-256,85.3A64,64 0,0 0,192 284.2L192,512c0,78.5 32.9,146.4 81.5,204.2A298.2,298.2 0,0 1,512 597.3a298.2,298.2 0,0 1,238.5 118.8C799.1,658.4 832,590.5 832,512L832,284.2a64,64 0,0 0,-43.8 -60.7l-256,-85.3a64,64 0,0 0,-40.4 0zM512,298.7a128,128 0,1 1,0 256,128 128,0 0,1 0,-256zM512,362.7a64,64 0,1 0,0 128,64 64,0 0,0 0,-128z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:pathData="M723.9,312c-13.2,-13.2 -34.7,-13.2 -47.9,0 -6.6,6.6 -9.9,15.3 -9.9,23.9 0,8.7 3.3,17.3 9.9,23.9 65.9,65.9 80.9,165.5 37.3,247.8 -4.9,9.2 -10.5,18.2 -16.9,26.8 -6.4,8.7 -12.9,16.4 -20,23.3 -13.4,13.1 -13.7,34.5 -0.6,47.9 13.1,13.4 34.5,13.7 47.9,0.6 9.7,-9.5 18.9,-20.2 27.3,-31.6 8.3,-11.2 15.7,-23 22.2,-35.2 57.5,-108.7 37.7,-240.3 -49.3,-327.4zM507.6,470c-0.2,-0.2 -0.4,-0.3 -0.7,-0.5 -0.8,-0.3 -1.7,-0.1 -2.3,0.5 -0.2,0.2 -0.3,0.4 -0.5,0.7 -0.1,0.3 -0.2,0.5 -0.2,0.8 0,0.6 0.3,1.1 0.6,1.5 0.2,0.2 0.4,0.3 0.7,0.5 0.3,0.1 0.5,0.2 0.8,0.2 0.6,0 1.1,-0.3 1.5,-0.6 0.4,-0.4 0.6,-1 0.6,-1.5 0,-0.3 -0.1,-0.5 -0.2,-0.8 0,-0.4 -0.2,-0.6 -0.3,-0.8z"
|
||||
android:fillColor="#FFFFFFFF"/>
|
||||
<path
|
||||
android:pathData="M833.7,209.6c-13.2,-13.2 -34.5,-13.2 -47.6,0 -13.2,13.2 -13.2,34.5 0,47.6 122.3,122.3 140,314.4 42.1,456.6 -12.5,18.1 -26.5,35 -42.1,50.5 -6.6,6.6 -9.9,15.2 -9.9,23.8 0,8.6 3.3,17.2 9.9,23.8 13.2,13.2 34.5,13.2 47.6,0 18.4,-18.4 35.1,-38.5 49.9,-60C1000,583.1 979,355 833.7,209.6zM515.1,166.8c-48,-22.3 -102.9,-15.1 -143.4,19L176.6,349.9h-50.2c-31,0 -63.3,25.2 -63.3,56.3v209.4c0,31 32.2,56.3 63.3,56.3h50.2L371.7,836c24.9,21 55.4,31.8 86.2,31.8 19.3,0 38.7,-4.2 57.2,-12.8 48,-22.3 77.8,-69.1 77.8,-122L592.9,288.8c0,-52.9 -29.8,-99.6 -77.8,-122zM531.1,732.9c0,31.8 -17.2,52.9 -46.1,66.3 -28.9,13.4 -56.7,6.2 -81,-14.3L206.2,623.5c-4.9,-4.2 -11.2,-6.4 -17.6,-6.4h-60.2c-0.8,0 -1.5,-0.7 -1.5,-1.5L126.9,406.2c0,-0.8 0.7,-1.5 1.5,-1.5h60.2c6.5,0 12.7,-2.3 17.6,-6.4L412,237.7c24.4,-20.5 51.2,-24.7 80,-11.3 28.9,13.4 39.1,30.5 39.1,62.3v444.2z"
|
||||
android:fillColor="#FFFFFFFF"/>
|
||||
</vector>
|
||||
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:drawable="@drawable/ic_shortcut_background"
|
||||
android:left="2dp"
|
||||
android:top="2dp"
|
||||
android:right="2dp"
|
||||
android:bottom="2dp" />
|
||||
|
||||
<item
|
||||
android:drawable="@drawable/ic_stat_name"
|
||||
android:left="12dp"
|
||||
android:top="12dp"
|
||||
android:right="12dp"
|
||||
android:bottom="12dp" />
|
||||
|
||||
</layer-list>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M938.7,512a384,384 0,0 1,-384 384,379.3 379.3,0 0,1 -220.2,-69.5 21.8,21.8 0,0 1,-9 -15.8,21.3 21.3,0 0,1 6,-16.6l30.7,-31.1a21.3,21.3 0,0 1,26.9 -2.6A294.8,294.8 0,0 0,554.7 810.7a298.7,298.7 0,1 0,-298.7 -298.7h100.7a20.9,20.9 0,0 1,15.4 6.4l8.5,8.5a21.3,21.3 0,0 1,0 30.3L230,708.3a21.8,21.8 0,0 1,-30.3 0l-150.6,-151a21.3,21.3 0,0 1,0 -30.3l8.5,-8.5a20.9,20.9 0,0 1,15.4 -6.4H170.7a384,384 0,0 1,768 0z" />
|
||||
</vector>
|
||||
@@ -1,19 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
|
||||
<path
|
||||
android:fillColor="#f5f5f5"
|
||||
android:pathData="M24,24m-22,0a22,22 0,1 1,44 0a22,22 0,1 1,-44 0Z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M24,21.8 C25.7673,21.8,27.2,23.2327,27.2,25 C27.2,26.7673,25.7673,28.2,24,28.2
|
||||
C22.2327,28.2,20.8,26.7673,20.8,25 C20.8,23.2327,22.2327,21.8,24,21.8 Z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M21,15 L19.17,17 L16,17 A2,2,0,0,0,14,19 L14,31 A2,2,0,0,0,16,33 L32,33
|
||||
A2,2,0,0,0,34,31 L34,19 A2,2,0,0,0,32,17 L28.83,17 L27,15 Z M24,30
|
||||
A5,5,0,1,1,29,25 A5,5,0,0,1,24,30 Z" />
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M181.333333 384a32 32 0 0 1-64 0v-111.146667a155.52 155.52 0 0 1 155.52-155.52H384a32 32 0 0 1 0 64h-111.146667a91.52 91.52 0 0 0-91.52 91.52V384zM640 181.333333a32 32 0 0 1 0-64h111.146667a155.52 155.52 0 0 1 155.52 155.52V384a32 32 0 0 1-64 0v-111.146667a91.52 91.52 0 0 0-91.52-91.52H640zM842.666667 640a32 32 0 0 1 64 0v111.146667a155.52 155.52 0 0 1-155.52 155.52H640a32 32 0 0 1 0-64h111.146667a91.52 91.52 0 0 0 91.52-91.52V640zM384 842.666667a32 32 0 0 1 0 64h-111.146667a155.52 155.52 0 0 1-155.52-155.52V640a32 32 0 0 1 64 0v111.146667a91.52 91.52 0 0 0 91.52 91.52H384z m-192-298.666667a32 32 0 0 1 0-64h640a32 32 0 0 1 0 64H192z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
|
||||
android:pathData="M924.8,625.7l-65.5,-56c3.1,-19 4.7,-38.4 4.7,-57.8s-1.6,-38.8 -4.7,-57.8l65.5,-56c10.1,-8.6 13.8,-22.6 9.3,-35.2l-0.9,-2.6c-18.1,-50.5 -44.9,-96.9 -79.7,-137.9l-1.8,-2.1c-8.6,-10.1 -22.5,-13.9 -35.1,-9.5l-81.3,28.9c-30,-24.6 -63.5,-44 -99.7,-57.6l-15.7,-85c-2.4,-13.1 -12.7,-23.3 -25.8,-25.7l-2.7,-0.5c-52.1,-9.4 -106.9,-9.4 -159,0l-2.7,0.5c-13.1,2.4 -23.4,12.6 -25.8,25.7l-15.8,85.4c-35.9,13.6 -69.2,32.9 -99,57.4l-81.9,-29.1c-12.5,-4.4 -26.5,-0.7 -35.1,9.5l-1.8,2.1c-34.8,41.1 -61.6,87.5 -79.7,137.9l-0.9,2.6c-4.5,12.5 -0.8,26.5 9.3,35.2l66.3,56.6c-3.1,18.8 -4.6,38 -4.6,57.1 0,19.2 1.5,38.4 4.6,57.1L99,625.5c-10.1,8.6 -13.8,22.6 -9.3,35.2l0.9,2.6c18.1,50.4 44.9,96.9 79.7,137.9l1.8,2.1c8.6,10.1 22.5,13.9 35.1,9.5l81.9,-29.1c29.8,24.5 63.1,43.9 99,57.4l15.8,85.4c2.4,13.1 12.7,23.3 25.8,25.7l2.7,0.5c26.1,4.7 52.8,7.1 79.5,7.1 26.7,0 53.5,-2.4 79.5,-7.1l2.7,-0.5c13.1,-2.4 23.4,-12.6 25.8,-25.7l15.7,-85c36.2,-13.6 69.7,-32.9 99.7,-57.6l81.3,28.9c12.5,4.4 26.5,0.7 35.1,-9.5l1.8,-2.1c34.8,-41.1 61.6,-87.5 79.7,-137.9l0.9,-2.6c4.5,-12.3 0.8,-26.3 -9.3,-35zM788.3,465.9c2.5,15.1 3.8,30.6 3.8,46.1s-1.3,31 -3.8,46.1l-6.6,40.1 74.7,63.9c-11.3,26.1 -25.6,50.7 -42.6,73.6L721,702.8l-31.4,25.8c-23.9,19.6 -50.5,35 -79.3,45.8l-38.1,14.3 -17.9,97c-28.1,3.2 -56.8,3.2 -85,0l-17.9,-97.2 -37.8,-14.5c-28.5,-10.8 -55,-26.2 -78.7,-45.7l-31.4,-25.9 -93.4,33.2c-17,-22.9 -31.2,-47.6 -42.6,-73.6l75.5,-64.5 -6.5,-40c-2.4,-14.9 -3.7,-30.3 -3.7,-45.5 0,-15.3 1.2,-30.6 3.7,-45.5l6.5,-40 -75.5,-64.5c11.3,-26.1 25.6,-50.7 42.6,-73.6l93.4,33.2 31.4,-25.9c23.7,-19.5 50.2,-34.9 78.7,-45.7l37.9,-14.3 17.9,-97.2c28.1,-3.2 56.8,-3.2 85,0l17.9,97 38.1,14.3c28.7,10.8 55.4,26.2 79.3,45.8l31.4,25.8 92.8,-32.9c17,22.9 31.2,47.6 42.6,73.6L781.8,426l6.5,39.9z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M512,326c-97.2,0 -176,78.8 -176,176s78.8,176 176,176 176,-78.8 176,-176 -78.8,-176 -176,-176zM591.2,581.2C570,602.3 541.9,614 512,614c-29.9,0 -58,-11.7 -79.2,-32.8C411.7,560 400,531.9 400,502c0,-29.9 11.7,-58 32.8,-79.2C454,401.6 482.1,390 512,390c29.9,0 58,11.6 79.2,32.8C612.3,444 624,472.1 624,502c0,29.9 -11.7,58 -32.8,79.2z" />
|
||||
</vector>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M469.2,802.1l-81.7,-24.6L554.8,221.9l81.7,24.6L469.2,802.1zM362.7,654.5l-124.7,-141.7 124.8,-143.5 -64.4,-56 -173.8,199.8 174,197.7 64.1,-56.3zM899.4,513.1l-173.8,-199.8 -64.4,56 124.8,143.5 -124.7,141.7 64.1,56.4 174,-197.7z" />
|
||||
</vector>
|
||||
9
V2rayNG/app/src/main/res/drawable-night/ic_stop_24dp.xml
Normal file
9
V2rayNG/app/src/main/res/drawable-night/ic_stop_24dp.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M256 192h512c35.392 0 64 28.608 64 64v512c0 35.392-28.608 64-64 64H256c-35.392 0-64-28.608-64-64V256c0-35.392 28.608-64 64-64z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M20,8L4,8L4,6h16v2zM18,2L6,2v2h12L18,2zM22,12v8c0,1.1 -0.9,2 -2,2L4,22c-1.1,0 -2,-0.9 -2,-2v-8c0,-1.1 0.9,-2 2,-2h16c1.1,0 2,0.9 2,2zM16,16l-6,-3.27v6.53L16,16z"/>
|
||||
android:pathData="M170.6,256h682.7v85.3L170.6,341.3L170.6,256zM256,85.3h512v85.4L256,170.7L256,85.3zM853.3,426.7L170.6,426.7c-46.9,0 -85.3,38.4 -85.3,85.3v341.3c0,47 38.4,85.4 85.3,85.4h682.7c46.9,0 85.3,-38.4 85.3,-85.4L938.6,512c0,-46.9 -38.4,-85.3 -85.3,-85.3zM853.3,853.3L170.6,853.3L170.6,512h682.7v341.3z" />
|
||||
</vector>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M912.2,154A85.3,85.3 0,0 0,853.3 128a85.3,85.3 0,0 0,-33.3 6.8l-708.3,306.8a42.7,42.7 0,0 0,-26.5 42.7V512a42.7,42.7 0,0 0,29.4 42.7L298.7,616.1l55.5,187.3a75.9,75.9 0,0 0,56.3 53.3,62.7 62.7,0 0,0 15.4,0 73.8,73.8 0,0 0,50.8 -20.5l67.8,-64 131.4,103.7a85.3,85.3 0,0 0,90 9.4l14.1,-7.3a88.3,88.3 0,0 0,46.5 -62.7L938.7,235.1a90,90 0,0 0,-26.5 -81.1zM763.7,805.1a25.2,25.2 0,0 1,-12.8 17.5l-14.1,7.3a19.6,19.6 0,0 1,-9 2.1,19.6 19.6,0 0,1 -12.4,-4.7l-160.4,-128a20.9,20.9 0,0 0,-27.7 0l-94.7,89.2a11.1,11.1 0,0 1,-6 2.1V640a21.8,21.8 0,0 1,6.8 -15.8c136.1,-128 217.6,-199.7 266.2,-240.6a15.8,15.8 0,0 0,5.1 -11.1,13.7 13.7,0 0,0 -4.3,-11.1 14.9,14.9 0,0 0,-17.9 -4.3l-322.6,203.5a21.3,21.3 0,0 1,-18.3 0L149.3,494.9l694.2,-301.2a16.6,16.6 0,0 1,7.7 0,22.2 22.2,0 0,1 16.2,7.7 26.9,26.9 0,0 1,6.8 23.5z" />
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M13.5,0.67s0.74,2.65 0.74,4.8c0,2.06 -1.35,3.73 -3.41,3.73 -2.07,0 -3.63,-1.67 -3.63,-3.73l0.03,-0.36C5.21,7.51 4,10.62 4,14c0,4.42 3.58,8 8,8s8,-3.58 8,-8C20,8.61 17.41,3.8 13.5,0.67zM11.71,19c-1.78,0 -3.22,-1.4 -3.22,-3.14 0,-1.62 1.05,-2.76 2.81,-3.12 1.77,-0.36 3.6,-1.21 4.62,-2.58 0.39,1.29 0.59,2.65 0.59,4.04 0,2.65 -2.15,4.8 -4.8,4.8z"/>
|
||||
</vector>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 855 B |
Binary file not shown.
|
Before Width: | Height: | Size: 3.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,9 +0,0 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<gradient
|
||||
android:angle="135"
|
||||
android:centerColor="#009688"
|
||||
android:endColor="#00695C"
|
||||
android:startColor="#4DB6AC"
|
||||
android:type="linear" />
|
||||
</shape>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 KiB |
12
V2rayNG/app/src/main/res/drawable/ic_about_24dp.xml
Normal file
12
V2rayNG/app/src/main/res/drawable/ic_about_24dp.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M810.7,206.3A426.7,426.7 0,1 0,512 938.7h5.5A426.7,426.7 0,0 0,810.7 206.3zM771.8,765A360.1,360.1 0,0 1,517.1 874.7L512,874.7a362.7,362.7 0,0 1,-4.9 -725.3h3.4a362.7,362.7 0,0 1,261.3 615.7z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M547.2,390a57.4,57.4 0,0 0,62.3 -55.3,39.3 39.3,0 0,0 -45,-42.7 58.9,58.9 0,0 0,-64 54.6c-1.7,26.9 13.9,43.3 46.7,43.3zM548.3,663.5c-5.5,0 -7.9,-7.3 -2.3,-28.2l31.1,-118c11.7,-42.7 7.9,-71.3 -15.8,-71.3 -28.4,0 -94.7,28.4 -152.5,76.4l11.7,19.4a181.3,181.3 0,0 1,56.1 -24.7c5.5,0 4.7,7.3 0,25.2l-27.3,112.2c-16.6,64 0,77.7 24.5,77.7s85.3,-21.3 141,-77.7l-13.4,-17.9a122.7,122.7 0,0 1,-53.1 26.9z" />
|
||||
</vector>
|
||||
9
V2rayNG/app/src/main/res/drawable/ic_backup_24dp.xml
Normal file
9
V2rayNG/app/src/main/res/drawable/ic_backup_24dp.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M864,192L704,192L704,96c0,-17.7 -14.3,-32 -32,-32L352,64c-9,0 -17.2,3.7 -22.9,9.7L137.7,265.1c-6,5.8 -9.7,14 -9.7,22.9v512c0,17.7 14.3,32 32,32h160v96c0,17.7 14.3,32 32,32h512c17.7,0 32,-14.3 32,-32L896,224c0,-17.7 -14.3,-32 -32,-32zM320,173.2L320,256h-82.8l82.8,-82.8zM192,768L192,320h160c17.7,0 32,-14.3 32,-32L384,128h256v64h-96c-9,0 -17.2,3.7 -22.9,9.7L329.7,393.1c-6,5.8 -9.7,14 -9.7,22.9v352L192,768zM512,301.2L512,384h-82.8l82.8,-82.8zM832,896L384,896L384,448h160c17.7,0 32,-14.3 32,-32L576,256h256v640z" />
|
||||
</vector>
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24dp">
|
||||
<path
|
||||
android:fillColor="#424242"
|
||||
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM13,14h-2v-2h2v2zM13,10h-2L11,6h2v4z"/>
|
||||
android:pathData="M512,192.7v42.7a21.3,21.3 0,0 1,-21.3 21.3H213.5V770.6l552.9,-2.2v-233.4a21.3,21.3 0,0 1,21.3 -21.3h42.7a21.3,21.3 0,0 1,21.3 21.3v256.1c0,32.6 -24.9,59.3 -56.6,62.4l-6.1,0.3 -598.2,2.1c-32.6,0 -59.3,-24.8 -62.4,-56.6l-0.3,-6V234c0,-32.6 24.8,-59.3 56.6,-62.4l6,-0.3H490.7a21.3,21.3 0,0 1,21.3 21.3z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M848.7,238.2l-250.8,250.8a21.3,21.3 0,0 1,-13.1 6.1c-30.8,2.9 -47.9,2.6 -51.2,-0.8 -3.4,-3.4 -4,-20.8 -2,-52.3a21.3,21.3 0,0 1,6.2 -13.7l250.5,-250.6a21.3,21.3 0,0 1,30.2 0l30.2,30.2a21.3,21.3 0,0 1,0 30.2z" />
|
||||
</vector>
|
||||
|
||||
@@ -1,34 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:pathData="M11,23h8a3,3 0,0 0,3 -3V8L15,1H7A3,3 0,0 0,4 4V9"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M15,5a3,3 0,0 0,3 3h4L15,1Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M2,17L10,17"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M6,13L6,21"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#000"
|
||||
android:strokeLineCap="round"/>
|
||||
android:pathData="M537,85.3A85.3,85.3 0,0 1,597.3 110.3L828.3,341.3A85.3,85.3 0,0 1,853.3 401.7L853.3,810.7a128,128 0,0 1,-128 128L298.7,938.7a128,128 0,0 1,-128 -128L170.7,213.3a128,128 0,0 1,128 -128zM537,170.7L298.7,170.7a42.7,42.7 0,0 0,-42.7 42.7v597.3a42.7,42.7 0,0 0,42.7 42.7h426.7a42.7,42.7 0,0 0,42.7 -42.7L768,401.7L537,170.7zM512,384a42.7,42.7 0,0 1,42.4 37.7L554.7,426.7v85.3h85.3a42.7,42.7 0,0 1,5 85L640,597.3h-85.3v85.3a42.7,42.7 0,0 1,-85 5L469.3,682.7v-85.3L384,597.3a42.7,42.7 0,0 1,-5 -85L384,512h85.3v-85.3a42.7,42.7 0,0 1,42.7 -42.7z"
|
||||
android:fillColor="#FF000000"/>
|
||||
</vector>
|
||||
|
||||
12
V2rayNG/app/src/main/res/drawable/ic_image_24dp.xml
Normal file
12
V2rayNG/app/src/main/res/drawable/ic_image_24dp.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M784,112L240,112c-88,0 -160,72 -160,160v480c0,88 72,160 160,160h544c88,0 160,-72 160,-160L944,272c0,-88 -72,-160 -160,-160zM880,752c0,52.8 -43.2,96 -96,96L240,848c-52.8,0 -96,-43.2 -96,-96L144,272c0,-52.8 43.2,-96 96,-96h544c52.8,0 96,43.2 96,96v480z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M352,480c52.8,0 96,-43.2 96,-96s-43.2,-96 -96,-96 -96,43.2 -96,96 43.2,96 96,96zM352,352c17.6,0 32,14.4 32,32s-14.4,32 -32,32 -32,-14.4 -32,-32 14.4,-32 32,-32zM814.4,731.2l-3.2,-3.2 -177.6,-177.6c-25.6,-25.6 -65.6,-25.6 -91.2,0l-80,80 -36.8,-36.8c-25.6,-25.6 -65.6,-25.6 -91.2,0L200,728c-4.8,6.4 -8,14.4 -8,24 0,17.6 14.4,32 32,32 9.6,0 16,-3.2 22.4,-9.6L380.8,640l134.4,134.4c6.4,6.4 14.4,9.6 24,9.6 17.6,0 32,-14.4 32,-32 0,-9.6 -4.8,-17.6 -9.6,-24l-52.8,-52.8 80,-80L769.6,776c6.4,4.8 12.8,8 20.8,8 17.6,0 32,-14.4 32,-32 0,-8 -3.2,-16 -8,-20.8z" />
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M21,19V5c0,-1.1 -0.9,-2 -2,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2zM8.5,13.5l2.5,3.01L14.5,12l4.5,6H5l3.5,-4.5z"/>
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zm1,15h-2v-6h2v6zm0,-8h-2V7h2v2z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M11,15h2v2h-2zM11,7h2v6h-2zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:pathData="M273.2,212.8h583.7L856.9,906.2h-583.7L273.2,212.8zM344.9,284.5L344.9,834.6h440.3L785.2,284.5h-440.3z"
|
||||
android:fillColor="#FF000000"/>
|
||||
<path
|
||||
android:pathData="M167.1,117.8h554.4v123.6h-71.7V189.4H238.8v498.8h73.9v71.7H167.1V117.8z"
|
||||
android:fillColor="#FF000000"/>
|
||||
<path
|
||||
android:pathData="M674.8,504H455.3v-71.7h219.4v71.7zM674.8,650.2H455.3v-71.7h219.4v71.7z"
|
||||
android:fillColor="#FF000000"/>
|
||||
</vector>
|
||||
|
||||
9
V2rayNG/app/src/main/res/drawable/ic_play_24dp.xml
Normal file
9
V2rayNG/app/src/main/res/drawable/ic_play_24dp.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M213.333333 789.461333V234.538667C213.333333 168.533333 285.013333 127.530667 341.930667 160.981333l471.68 277.461334c56.106667 32.981333 56.106667 114.133333 0 147.114666L341.930667 863.018667C285.056 896.469333 213.333333 855.466667 213.333333 789.461333z" />
|
||||
</vector>
|
||||
9
V2rayNG/app/src/main/res/drawable/ic_privacy_24dp.xml
Normal file
9
V2rayNG/app/src/main/res/drawable/ic_privacy_24dp.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M471.5,77.5a128,128 0,0 1,72.1 -2.6l8.9,2.6 256,85.3a128,128 0,0 1,87.3 113.6l0.3,7.8L896,512c0,101.6 -44.5,186 -103.2,253.1l-8.1,9 -12.1,12.8a618.2,618.2 0,0 1,-25 24.2l-12.8,11.4 -13,11a839.3,839.3 0,0 1,-127.7 86.5l-19.5,10.5 -17.5,9a101.4,101.4 0,0 1,-90.5 0l-18.9,-9.6c-40.1,-21.1 -93.9,-53.2 -145.9,-96.3l-12.9,-11 -12.8,-11.4a618.2,618.2 0,0 1,-24.9 -24.2l-12.1,-12.8 -8.1,-9c-55.9,-63.9 -98.9,-143.4 -102.9,-238.6L128,512L128,284.2A128,128 0,0 1,208.2 165.5l7.3,-2.7 256,-85.3zM512,661.3c-80.2,0 -151.1,40.3 -193.4,101.7 62,57.2 132.2,97.2 176.6,119a37.4,37.4 0,0 0,33.7 0c44.4,-21.9 114.6,-61.9 176.6,-119A234.4,234.4 0,0 0,512 661.3zM491.8,138.2l-256,85.3A64,64 0,0 0,192 284.2L192,512c0,78.5 32.9,146.4 81.5,204.2A298.2,298.2 0,0 1,512 597.3a298.2,298.2 0,0 1,238.5 118.8C799.1,658.4 832,590.5 832,512L832,284.2a64,64 0,0 0,-43.8 -60.7l-256,-85.3a64,64 0,0 0,-40.4 0zM512,298.7a128,128 0,1 1,0 256,128 128,0 0,1 0,-256zM512,362.7a64,64 0,1 0,0 128,64 64,0 0,0 0,-128z" />
|
||||
</vector>
|
||||
12
V2rayNG/app/src/main/res/drawable/ic_promotion_24dp.xml
Normal file
12
V2rayNG/app/src/main/res/drawable/ic_promotion_24dp.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:pathData="M723.9,312c-13.2,-13.2 -34.7,-13.2 -47.9,0 -6.6,6.6 -9.9,15.3 -9.9,23.9 0,8.7 3.3,17.3 9.9,23.9 65.9,65.9 80.9,165.5 37.3,247.8 -4.9,9.2 -10.5,18.2 -16.9,26.8 -6.4,8.7 -12.9,16.4 -20,23.3 -13.4,13.1 -13.7,34.5 -0.6,47.9 13.1,13.4 34.5,13.7 47.9,0.6 9.7,-9.5 18.9,-20.2 27.3,-31.6 8.3,-11.2 15.7,-23 22.2,-35.2 57.5,-108.7 37.7,-240.3 -49.3,-327.4zM507.6,470c-0.2,-0.2 -0.4,-0.3 -0.7,-0.5 -0.8,-0.3 -1.7,-0.1 -2.3,0.5 -0.2,0.2 -0.3,0.4 -0.5,0.7 -0.1,0.3 -0.2,0.5 -0.2,0.8 0,0.6 0.3,1.1 0.6,1.5 0.2,0.2 0.4,0.3 0.7,0.5 0.3,0.1 0.5,0.2 0.8,0.2 0.6,0 1.1,-0.3 1.5,-0.6 0.4,-0.4 0.6,-1 0.6,-1.5 0,-0.3 -0.1,-0.5 -0.2,-0.8 0,-0.4 -0.2,-0.6 -0.3,-0.8z"
|
||||
android:fillColor="#FF000000"/>
|
||||
<path
|
||||
android:pathData="M833.7,209.6c-13.2,-13.2 -34.5,-13.2 -47.6,0 -13.2,13.2 -13.2,34.5 0,47.6 122.3,122.3 140,314.4 42.1,456.6 -12.5,18.1 -26.5,35 -42.1,50.5 -6.6,6.6 -9.9,15.2 -9.9,23.8 0,8.6 3.3,17.2 9.9,23.8 13.2,13.2 34.5,13.2 47.6,0 18.4,-18.4 35.1,-38.5 49.9,-60C1000,583.1 979,355 833.7,209.6zM515.1,166.8c-48,-22.3 -102.9,-15.1 -143.4,19L176.6,349.9h-50.2c-31,0 -63.3,25.2 -63.3,56.3v209.4c0,31 32.2,56.3 63.3,56.3h50.2L371.7,836c24.9,21 55.4,31.8 86.2,31.8 19.3,0 38.7,-4.2 57.2,-12.8 48,-22.3 77.8,-69.1 77.8,-122L592.9,288.8c0,-52.9 -29.8,-99.6 -77.8,-122zM531.1,732.9c0,31.8 -17.2,52.9 -46.1,66.3 -28.9,13.4 -56.7,6.2 -81,-14.3L206.2,623.5c-4.9,-4.2 -11.2,-6.4 -17.6,-6.4h-60.2c-0.8,0 -1.5,-0.7 -1.5,-1.5L126.9,406.2c0,-0.8 0.7,-1.5 1.5,-1.5h60.2c6.5,0 12.7,-2.3 17.6,-6.4L412,237.7c24.4,-20.5 51.2,-24.7 80,-11.3 28.9,13.4 39.1,30.5 39.1,62.3v444.2z"
|
||||
android:fillColor="#FF000000"/>
|
||||
</vector>
|
||||
@@ -1,19 +1,13 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M0,512C0,229.23 229.81,0 512,0 794.77,0 1024,229.81 1024,512 1024,794.77 794.19,1024 512,1024 229.23,1024 0,794.19 0,512Z" />
|
||||
|
||||
<path
|
||||
android:fillColor="@color/colorBg"
|
||||
android:pathData="M24,24m-22,0a22,22 0,1 1,44 0a22,22 0,1 1,-44 0Z" />
|
||||
<path
|
||||
android:fillColor="@color/colorText"
|
||||
android:pathData="M24,21.8 C25.7673,21.8,27.2,23.2327,27.2,25 C27.2,26.7673,25.7673,28.2,24,28.2
|
||||
C22.2327,28.2,20.8,26.7673,20.8,25 C20.8,23.2327,22.2327,21.8,24,21.8 Z" />
|
||||
<path
|
||||
android:fillColor="@color/colorText"
|
||||
android:pathData="M21,15 L19.17,17 L16,17 A2,2,0,0,0,14,19 L14,31 A2,2,0,0,0,16,33 L32,33
|
||||
A2,2,0,0,0,34,31 L34,19 A2,2,0,0,0,32,17 L28.83,17 L27,15 Z M24,30
|
||||
A5,5,0,1,1,29,25 A5,5,0,0,1,24,30 Z" />
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M780.16 875.52H652.8c-17.92 0-32-14.08-32-32s14.08-32 32-32h127.36c16 0 29.44-13.44 29.44-29.44v-127.36c0-17.92 14.08-32 32-32s32 14.08 32 32v127.36c-0.64 51.2-42.24 93.44-93.44 93.44zM192.64 415.36c-17.92 0-32-14.08-32-32V256c0-51.2 41.6-93.44 93.44-93.44h127.36c17.92 0 32 14.08 32 32s-14.08 32-32 32h-128c-16 0-29.44 13.44-29.44 29.44v127.36c0.64 17.92-14.08 32-31.36 32zM840.96 415.36c-17.92 0-32-14.08-32-32V256c0-16-13.44-29.44-29.44-29.44h-127.36c-17.92 0-32-14.08-32-32s14.08-32 32-32h127.36c51.2 0 93.44 41.6 93.44 93.44v127.36c0 17.92-14.08 32-32 32zM381.44 875.52h-128c-51.2 0-93.44-41.6-93.44-93.44v-127.36c0-17.92 14.08-32 32-32s32 14.08 32 32v127.36c0 16 13.44 29.44 29.44 29.44h127.36c17.92 0 32 14.08 32 32s-14.08 32-31.36 32zM759.04 553.6H274.56c-17.92 0-32-14.08-32-32s14.08-32 32-32h484.48c17.92 0 32 14.08 32 32s-14.72 32-32 32z" />
|
||||
</vector>
|
||||
File diff suppressed because one or more lines are too long
@@ -1,18 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="1024"
|
||||
android:viewportWidth="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M0,512C0,229.23 229.81,0 512,0 794.77,0 1024,229.81 1024,512 1024,794.77 794.19,1024 512,1024 229.23,1024 0,794.19 0,512Z" />
|
||||
|
||||
<item
|
||||
android:drawable="@drawable/ic_shortcut_background"
|
||||
android:left="2dp"
|
||||
android:top="2dp"
|
||||
android:right="2dp"
|
||||
android:bottom="2dp" />
|
||||
|
||||
<item
|
||||
android:drawable="@drawable/ic_stat_name_black"
|
||||
android:left="12dp"
|
||||
android:top="12dp"
|
||||
android:right="12dp"
|
||||
android:bottom="12dp" />
|
||||
|
||||
</layer-list>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M742.4 691.2c-12.8-12.8-25.6-12.8-38.4 0-51.2 51.2-115.2 83.2-185.6 83.2-128 0-230.4-89.6-256-204.8l44.8 0C320 569.6 332.8 550.4 320 537.6L243.2 428.8c-6.4-12.8-25.6-12.8-32 0L134.4 537.6c-12.8 12.8 0 32 19.2 32l51.2 0C224 716.8 358.4 832 512 832c89.6 0 166.4-32 230.4-96C748.8 723.2 748.8 704 742.4 691.2L742.4 691.2zM281.6 332.8c12.8 12.8 25.6 12.8 38.4 0C371.2 275.2 441.6 249.6 512 249.6c128 0 230.4 89.6 256 204.8l-44.8 0c-19.2 0-25.6 19.2-19.2 32l76.8 108.8c6.4 12.8 25.6 12.8 32 0l76.8-108.8c12.8-12.8 0-32-19.2-32l-51.2 0C800 307.2 665.6 192 512 192 422.4 192 345.6 230.4 281.6 288 275.2 300.8 275.2 320 281.6 332.8L281.6 332.8zM627.2 556.8c0 25.6-25.6 51.2-51.2 51.2l-128 0c-25.6 0-51.2-25.6-51.2-51.2L396.8 473.6c0-25.6 25.6-51.2 51.2-51.2l128 0c25.6 0 51.2 25.6 51.2 51.2L627.2 556.8 627.2 556.8zM627.2 556.8" />
|
||||
</vector>
|
||||
|
||||
9
V2rayNG/app/src/main/res/drawable/ic_restore_24dp.xml
Normal file
9
V2rayNG/app/src/main/res/drawable/ic_restore_24dp.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M938.7,512a384,384 0,0 1,-384 384,379.3 379.3,0 0,1 -220.2,-69.5 21.8,21.8 0,0 1,-9 -15.8,21.3 21.3,0 0,1 6,-16.6l30.7,-31.1a21.3,21.3 0,0 1,26.9 -2.6A294.8,294.8 0,0 0,554.7 810.7a298.7,298.7 0,1 0,-298.7 -298.7h100.7a20.9,20.9 0,0 1,15.4 6.4l8.5,8.5a21.3,21.3 0,0 1,0 30.3L230,708.3a21.8,21.8 0,0 1,-30.3 0l-150.6,-151a21.3,21.3 0,0 1,0 -30.3l8.5,-8.5a20.9,20.9 0,0 1,15.4 -6.4H170.7a384,384 0,0 1,768 0z" />
|
||||
</vector>
|
||||
@@ -1,6 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/color_fab_orange"/>
|
||||
<corners android:radius="20dp"/>
|
||||
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
|
||||
<corners android:radius="20dp" />
|
||||
<padding
|
||||
android:bottom="0dp"
|
||||
android:left="0dp"
|
||||
android:right="0dp"
|
||||
android:top="0dp" />
|
||||
<solid android:color="@color/color_fab_active" />
|
||||
</shape>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/color_switch_fab_grey"/>
|
||||
<corners android:radius="20dp"/>
|
||||
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
|
||||
</shape>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<corners android:radius="20dp" />
|
||||
<padding
|
||||
android:bottom="0dp"
|
||||
android:left="0dp"
|
||||
android:right="0dp"
|
||||
android:top="0dp" />
|
||||
<solid android:color="@color/color_fab_inactive" />
|
||||
</shape>
|
||||
@@ -1,19 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
|
||||
<path
|
||||
android:fillColor="#050505"
|
||||
android:pathData="M24,24m-22,0a22,22 0,1 1,44 0a22,22 0,1 1,-44 0Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M24,21.8 C25.7673,21.8,27.2,23.2327,27.2,25 C27.2,26.7673,25.7673,28.2,24,28.2
|
||||
C22.2327,28.2,20.8,26.7673,20.8,25 C20.8,23.2327,22.2327,21.8,24,21.8 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M21,15 L19.17,17 L16,17 A2,2,0,0,0,14,19 L14,31 A2,2,0,0,0,16,33 L32,33
|
||||
A2,2,0,0,0,34,31 L34,19 A2,2,0,0,0,32,17 L28.83,17 L27,15 Z M24,30
|
||||
A5,5,0,1,1,29,25 A5,5,0,0,1,24,30 Z" />
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M181.333333 384a32 32 0 0 1-64 0v-111.146667a155.52 155.52 0 0 1 155.52-155.52H384a32 32 0 0 1 0 64h-111.146667a91.52 91.52 0 0 0-91.52 91.52V384zM640 181.333333a32 32 0 0 1 0-64h111.146667a155.52 155.52 0 0 1 155.52 155.52V384a32 32 0 0 1-64 0v-111.146667a91.52 91.52 0 0 0-91.52-91.52H640zM842.666667 640a32 32 0 0 1 64 0v111.146667a155.52 155.52 0 0 1-155.52 155.52H640a32 32 0 0 1 0-64h111.146667a91.52 91.52 0 0 0 91.52-91.52V640zM384 842.666667a32 32 0 0 1 0 64h-111.146667a155.52 155.52 0 0 1-155.52-155.52V640a32 32 0 0 1 64 0v111.146667a91.52 91.52 0 0 0 91.52 91.52H384z m-192-298.666667a32 32 0 0 1 0-64h640a32 32 0 0 1 0 64H192z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24dp">
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M3,5h2L5,3c-1.1,0 -2,0.9 -2,2zM3,13h2v-2L3,11v2zM7,21h2v-2L7,19v2zM3,9h2L5,7L3,7v2zM13,3h-2v2h2L13,3zM19,3v2h2c0,-1.1 -0.9,-2 -2,-2zM5,21v-2L3,19c0,1.1 0.9,2 2,2zM3,17h2v-2L3,15v2zM9,3L7,3v2h2L9,3zM11,21h2v-2h-2v2zM19,13h2v-2h-2v2zM19,21c1.1,0 2,-0.9 2,-2h-2v2zM19,9h2L21,7h-2v2zM19,17h2v-2h-2v2zM15,21h2v-2h-2v2zM15,5h2L17,3h-2v2zM7,17h10L17,7L7,7v10zM9,9h6v6L9,15L9,9z" />
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M924.8,625.7l-65.5,-56c3.1,-19 4.7,-38.4 4.7,-57.8s-1.6,-38.8 -4.7,-57.8l65.5,-56c10.1,-8.6 13.8,-22.6 9.3,-35.2l-0.9,-2.6c-18.1,-50.5 -44.9,-96.9 -79.7,-137.9l-1.8,-2.1c-8.6,-10.1 -22.5,-13.9 -35.1,-9.5l-81.3,28.9c-30,-24.6 -63.5,-44 -99.7,-57.6l-15.7,-85c-2.4,-13.1 -12.7,-23.3 -25.8,-25.7l-2.7,-0.5c-52.1,-9.4 -106.9,-9.4 -159,0l-2.7,0.5c-13.1,2.4 -23.4,12.6 -25.8,25.7l-15.8,85.4c-35.9,13.6 -69.2,32.9 -99,57.4l-81.9,-29.1c-12.5,-4.4 -26.5,-0.7 -35.1,9.5l-1.8,2.1c-34.8,41.1 -61.6,87.5 -79.7,137.9l-0.9,2.6c-4.5,12.5 -0.8,26.5 9.3,35.2l66.3,56.6c-3.1,18.8 -4.6,38 -4.6,57.1 0,19.2 1.5,38.4 4.6,57.1L99,625.5c-10.1,8.6 -13.8,22.6 -9.3,35.2l0.9,2.6c18.1,50.4 44.9,96.9 79.7,137.9l1.8,2.1c8.6,10.1 22.5,13.9 35.1,9.5l81.9,-29.1c29.8,24.5 63.1,43.9 99,57.4l15.8,85.4c2.4,13.1 12.7,23.3 25.8,25.7l2.7,0.5c26.1,4.7 52.8,7.1 79.5,7.1 26.7,0 53.5,-2.4 79.5,-7.1l2.7,-0.5c13.1,-2.4 23.4,-12.6 25.8,-25.7l15.7,-85c36.2,-13.6 69.7,-32.9 99.7,-57.6l81.3,28.9c12.5,4.4 26.5,0.7 35.1,-9.5l1.8,-2.1c34.8,-41.1 61.6,-87.5 79.7,-137.9l0.9,-2.6c4.5,-12.3 0.8,-26.3 -9.3,-35zM788.3,465.9c2.5,15.1 3.8,30.6 3.8,46.1s-1.3,31 -3.8,46.1l-6.6,40.1 74.7,63.9c-11.3,26.1 -25.6,50.7 -42.6,73.6L721,702.8l-31.4,25.8c-23.9,19.6 -50.5,35 -79.3,45.8l-38.1,14.3 -17.9,97c-28.1,3.2 -56.8,3.2 -85,0l-17.9,-97.2 -37.8,-14.5c-28.5,-10.8 -55,-26.2 -78.7,-45.7l-31.4,-25.9 -93.4,33.2c-17,-22.9 -31.2,-47.6 -42.6,-73.6l75.5,-64.5 -6.5,-40c-2.4,-14.9 -3.7,-30.3 -3.7,-45.5 0,-15.3 1.2,-30.6 3.7,-45.5l6.5,-40 -75.5,-64.5c11.3,-26.1 25.6,-50.7 42.6,-73.6l93.4,33.2 31.4,-25.9c23.7,-19.5 50.2,-34.9 78.7,-45.7l37.9,-14.3 17.9,-97.2c28.1,-3.2 56.8,-3.2 85,0l17.9,97 38.1,14.3c28.7,10.8 55.4,26.2 79.3,45.8l31.4,25.8 92.8,-32.9c17,22.9 31.2,47.6 42.6,73.6L781.8,426l6.5,39.9z" />
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M512,326c-97.2,0 -176,78.8 -176,176s78.8,176 176,176 176,-78.8 176,-176 -78.8,-176 -176,-176zM591.2,581.2C570,602.3 541.9,614 512,614c-29.9,0 -58,-11.7 -79.2,-32.8C411.7,560 400,531.9 400,502c0,-29.9 11.7,-58 32.8,-79.2C454,401.6 482.1,390 512,390c29.9,0 58,11.6 79.2,32.8C612.3,444 624,472.1 624,502c0,29.9 -11.7,58 -32.8,79.2z" />
|
||||
</vector>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/colorBg" />
|
||||
<size android:width="44dp" android:height="44dp" />
|
||||
</shape>
|
||||
@@ -0,0 +1,4 @@
|
||||
<vector android:height="24dp" android:viewportHeight="1024"
|
||||
android:viewportWidth="1024" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M469.2,802.1l-81.7,-24.6L554.8,221.9l81.7,24.6L469.2,802.1zM362.7,654.5l-124.7,-141.7 124.8,-143.5 -64.4,-56 -173.8,199.8 174,197.7 64.1,-56.3zM899.4,513.1l-173.8,-199.8 -64.4,56 124.8,143.5 -124.7,141.7 64.1,56.4 174,-197.7z"/>
|
||||
</vector>
|
||||
9
V2rayNG/app/src/main/res/drawable/ic_stop_24dp.xml
Normal file
9
V2rayNG/app/src/main/res/drawable/ic_stop_24dp.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M256 192h512c35.392 0 64 28.608 64 64v512c0 35.392-28.608 64-64 64H256c-35.392 0-64-28.608-64-64V256c0-35.392 28.608-64 64-64z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20,8L4,8L4,6h16v2zM18,2L6,2v2h12L18,2zM22,12v8c0,1.1 -0.9,2 -2,2L4,22c-1.1,0 -2,-0.9 -2,-2v-8c0,-1.1 0.9,-2 2,-2h16c1.1,0 2,0.9 2,2zM16,16l-6,-3.27v6.53L16,16z"/>
|
||||
android:pathData="M170.6,256h682.7v85.3L170.6,341.3L170.6,256zM256,85.3h512v85.4L256,170.7L256,85.3zM853.3,426.7L170.6,426.7c-46.9,0 -85.3,38.4 -85.3,85.3v341.3c0,47 38.4,85.4 85.3,85.4h682.7c46.9,0 85.3,-38.4 85.3,-85.4L938.6,512c0,-46.9 -38.4,-85.3 -85.3,-85.3zM853.3,853.3L170.6,853.3L170.6,512h682.7v341.3z" />
|
||||
</vector>
|
||||
|
||||
9
V2rayNG/app/src/main/res/drawable/ic_telegram_24dp.xml
Normal file
9
V2rayNG/app/src/main/res/drawable/ic_telegram_24dp.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M912.2,154A85.3,85.3 0,0 0,853.3 128a85.3,85.3 0,0 0,-33.3 6.8l-708.3,306.8a42.7,42.7 0,0 0,-26.5 42.7V512a42.7,42.7 0,0 0,29.4 42.7L298.7,616.1l55.5,187.3a75.9,75.9 0,0 0,56.3 53.3,62.7 62.7,0 0,0 15.4,0 73.8,73.8 0,0 0,50.8 -20.5l67.8,-64 131.4,103.7a85.3,85.3 0,0 0,90 9.4l14.1,-7.3a88.3,88.3 0,0 0,46.5 -62.7L938.7,235.1a90,90 0,0 0,-26.5 -81.1zM763.7,805.1a25.2,25.2 0,0 1,-12.8 17.5l-14.1,7.3a19.6,19.6 0,0 1,-9 2.1,19.6 19.6,0 0,1 -12.4,-4.7l-160.4,-128a20.9,20.9 0,0 0,-27.7 0l-94.7,89.2a11.1,11.1 0,0 1,-6 2.1V640a21.8,21.8 0,0 1,6.8 -15.8c136.1,-128 217.6,-199.7 266.2,-240.6a15.8,15.8 0,0 0,5.1 -11.1,13.7 13.7,0 0,0 -4.3,-11.1 14.9,14.9 0,0 0,-17.9 -4.3l-322.6,203.5a21.3,21.3 0,0 1,-18.3 0L149.3,494.9l694.2,-301.2a16.6,16.6 0,0 1,7.7 0,22.2 22.2,0 0,1 16.2,7.7 26.9,26.9 0,0 1,6.8 23.5z" />
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M13.5,0.67s0.74,2.65 0.74,4.8c0,2.06 -1.35,3.73 -3.41,3.73 -2.07,0 -3.63,-1.67 -3.63,-3.73l0.03,-0.36C5.21,7.51 4,10.62 4,14c0,4.42 3.58,8 8,8s8,-3.58 8,-8C20,8.61 17.41,3.8 13.5,0.67zM11.71,19c-1.78,0 -3.22,-1.4 -3.22,-3.14 0,-1.62 1.05,-2.76 2.81,-3.12 1.77,-0.36 3.6,-1.21 4.62,-2.58 0.39,1.29 0.59,2.65 0.59,4.04 0,2.65 -2.15,4.8 -4.8,4.8z"/>
|
||||
</vector>
|
||||
202
V2rayNG/app/src/main/res/layout/activity_about.xml
Normal file
202
V2rayNG/app/src/main/res/layout/activity_about.xml
Normal file
@@ -0,0 +1,202 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_backup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:gravity="center|start"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/png_height"
|
||||
android:layout_height="@dimen/png_height"
|
||||
app:srcCompat="@drawable/ic_backup_24dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/title_configuration_backup"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_backup_summary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:maxLines="4"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_restore"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/server_height"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:gravity="center|start"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/png_height"
|
||||
android:layout_height="@dimen/png_height"
|
||||
app:srcCompat="@drawable/ic_restore_24dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:text="@string/title_configuration_restore"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="16dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_soure_ccode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/server_height"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:gravity="center|start"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/png_height"
|
||||
android:layout_height="@dimen/png_height"
|
||||
app:srcCompat="@drawable/ic_source_code_24dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:text="@string/title_source_code"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_feedback"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/server_height"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:gravity="center|start"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/png_height"
|
||||
android:layout_height="@dimen/png_height"
|
||||
app:srcCompat="@drawable/ic_feedback_24dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:text="@string/title_pref_feedback"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_tg_channel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/server_height"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:gravity="center|start"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/png_height"
|
||||
android:layout_height="@dimen/png_height"
|
||||
app:srcCompat="@drawable/ic_telegram_24dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:text="@string/title_tg_channel"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_privacy_policy"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/server_height"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:gravity="center|start"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/png_height"
|
||||
android:layout_height="@dimen/png_height"
|
||||
app:srcCompat="@drawable/ic_privacy_24dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="16dp"
|
||||
android:text="@string/title_privacy_policy"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/server_height"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_version"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/title_about"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
tools:context=".ui.MainActivity">
|
||||
tools:context=".ui.LogcatActivity">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pb_waiting"
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
android:id="@+id/layout_test"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/connection_test_height"
|
||||
android:background="@color/colorMainTestBg"
|
||||
android:background="@color/colorPrimary"
|
||||
android:gravity="center|start"
|
||||
android:nextFocusRight="@+id/fab"
|
||||
android:clickable="true"
|
||||
@@ -63,14 +63,13 @@
|
||||
android:minLines="1"
|
||||
android:paddingStart="16dp"
|
||||
android:text="@string/connection_test_pending"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textColor="@color/colorText" />
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"/>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<com.github.jorgecastilloprz.FABProgressCircle
|
||||
<FrameLayout
|
||||
android:id="@+id/fabProgressCircle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -94,7 +93,7 @@
|
||||
android:src="@drawable/ic_stat_name"
|
||||
app:layout_anchorGravity="bottom|right|end" />
|
||||
|
||||
</com.github.jorgecastilloprz.FABProgressCircle>
|
||||
</FrameLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
@@ -108,18 +107,6 @@
|
||||
app:itemIconTint="@color/colorAccent"
|
||||
app:menu="@menu/menu_drawer" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:padding="2dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/version"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center" />
|
||||
</LinearLayout>
|
||||
</com.google.android.material.navigation.NavigationView>
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.ServerActivity">
|
||||
tools:context=".ui.ServerCustomConfigActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -117,7 +117,95 @@
|
||||
android:entries="@array/ss_securitys" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/server_lab_more_function"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/server_lab_network" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/sp_network"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/edit_height"
|
||||
android:entries="@array/networks" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sp_header_type_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/server_lab_head_type" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/sp_header_type"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/edit_height" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/server_lab_request_host" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_request_host"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/edit_height"
|
||||
android:inputType="text" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/server_lab_path" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_path"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/edit_height"
|
||||
android:inputType="text" />
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/tls_layout" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -126,4 +214,4 @@
|
||||
android:orientation="vertical" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</ScrollView>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.ServerActivity">
|
||||
tools:context=".ui.SubSettingActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".ui.MainActivity">
|
||||
tools:context=".ui.SubSettingActivity">
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/main_content"
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:background="@color/colorPrimary"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
@@ -1,30 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
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">
|
||||
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">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/card_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="2dp"
|
||||
android:layout_margin="1dp"
|
||||
app:cardCornerRadius="5dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/info_container"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:nextFocusRight="@+id/layout_share"
|
||||
android:background="@color/colorPrimary"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/server_height"
|
||||
android:layout_gravity="center"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:gravity="center"
|
||||
android:nextFocusRight="@+id/layout_share"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
@@ -65,7 +64,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:lines="1"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="12sp"/>
|
||||
android:textSize="12sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -78,31 +77,31 @@
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingEnd="5dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_subscription"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingEnd="5dp">
|
||||
android:layout_weight="1"
|
||||
android:lines="1"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textColor="@color/color_secondary"
|
||||
android:textSize="10sp"
|
||||
tools:text="Sub" />
|
||||
|
||||
<TextView
|
||||
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/color_secondary"
|
||||
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" />
|
||||
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
|
||||
@@ -127,8 +126,7 @@
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/png_height"
|
||||
app:srcCompat="@drawable/ic_share_24dp"
|
||||
app:tint="?attr/colorMainText" />
|
||||
app:srcCompat="@drawable/ic_share_24dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -146,8 +144,7 @@
|
||||
<ImageView
|
||||
android:layout_width="@dimen/png_height"
|
||||
android:layout_height="@dimen/png_height"
|
||||
app:srcCompat="@drawable/ic_edit_24dp"
|
||||
app:tint="?attr/colorMainText" />
|
||||
app:srcCompat="@drawable/ic_edit_24dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -165,8 +162,7 @@
|
||||
<ImageView
|
||||
android:layout_width="@dimen/png_height"
|
||||
android:layout_height="@dimen/png_height"
|
||||
app:srcCompat="@drawable/ic_delete_24dp"
|
||||
app:tint="?attr/colorMainText" />
|
||||
app:srcCompat="@drawable/ic_delete_24dp" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -184,7 +180,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:lines="1"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textColor="@color/color_fab_orange"
|
||||
android:textColor="@color/colorConfigType"
|
||||
android:textSize="10sp" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -10,42 +10,41 @@
|
||||
android:id="@+id/item_cardview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="2dp"
|
||||
android:layout_margin="1dp"
|
||||
android:orientation="horizontal"
|
||||
card_view:cardCornerRadius="5dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/info_container"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:background="@color/colorPrimary"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:nextFocusRight="@+id/layout_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/server_height"
|
||||
android:layout_gravity="center"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:gravity="center"
|
||||
android:nextFocusRight="@+id/layout_edit"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/chk_enable"
|
||||
android:layout_width="6dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical" />
|
||||
android:id="@+id/chk_enable"
|
||||
android:layout_width="6dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingStart="9dp"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="9dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
android:id="@+id/tv_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_url"
|
||||
@@ -73,14 +72,12 @@
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/layout_margin_spacing"
|
||||
>
|
||||
android:padding="@dimen/layout_margin_spacing">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/png_height"
|
||||
android:layout_height="@dimen/png_height"
|
||||
app:srcCompat="@drawable/ic_share_24dp"
|
||||
app:tint="?attr/colorMainText"/>
|
||||
app:srcCompat="@drawable/ic_share_24dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -99,8 +96,7 @@
|
||||
<ImageView
|
||||
android:layout_width="@dimen/png_height"
|
||||
android:layout_height="@dimen/png_height"
|
||||
app:srcCompat="@drawable/ic_edit_24dp"
|
||||
app:tint="?attr/colorMainText" />
|
||||
app:srcCompat="@drawable/ic_edit_24dp" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="2dp"
|
||||
app:cardCornerRadius="5dp">
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="1dp"
|
||||
app:cardCornerRadius="5dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
android:background="@color/colorPrimary"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:padding="@dimen/nav_header_vertical_spacing">
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:padding="@dimen/nav_header_vertical_spacing">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -72,24 +72,22 @@
|
||||
<ImageView
|
||||
android:layout_width="@dimen/png_height"
|
||||
android:layout_height="@dimen/png_height"
|
||||
app:srcCompat="@drawable/ic_edit_24dp"
|
||||
app:tint="?attr/colorMainText" />
|
||||
app:srcCompat="@drawable/ic_edit_24dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_remove"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:padding="@dimen/nav_header_vertical_spacing">
|
||||
android:id="@+id/layout_remove"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:padding="@dimen/nav_header_vertical_spacing">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/png_height"
|
||||
android:layout_height="@dimen/png_height"
|
||||
app:srcCompat="@drawable/ic_delete_24dp"
|
||||
app:tint="?attr/colorMainText" />
|
||||
android:layout_width="@dimen/png_height"
|
||||
android:layout_height="@dimen/png_height"
|
||||
app:srcCompat="@drawable/ic_delete_24dp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
android:background="@drawable/nav_header_bg"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin">
|
||||
android:paddingBottom="@dimen/activity_vertical_margin">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
@@ -19,8 +19,7 @@
|
||||
android:gravity="center"
|
||||
android:paddingTop="@dimen/nav_header_vertical_spacing"
|
||||
android:text="@string/app_name"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
|
||||
android:textColor="@color/colorText" />
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -2,16 +2,30 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/layout_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_background"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
android:layout_gravity="center">
|
||||
|
||||
<ImageView
|
||||
<ImageView
|
||||
android:id="@+id/image_switch"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:padding="10dp"
|
||||
android:layout_width="45dp"
|
||||
android:layout_height="45dp"
|
||||
android:padding="12dp"
|
||||
app:srcCompat="@drawable/ic_stat_name" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="10sp" />
|
||||
</LinearLayout>
|
||||
|
||||
@@ -22,20 +22,16 @@
|
||||
<group android:id="@+id/group_id2">
|
||||
<item
|
||||
android:id="@+id/promotion"
|
||||
android:icon="@drawable/ic_whatshot_24dp"
|
||||
android:icon="@drawable/ic_promotion_24dp"
|
||||
android:title="@string/title_pref_promotion" />
|
||||
<item
|
||||
android:id="@+id/logcat"
|
||||
android:icon="@drawable/ic_logcat_24dp"
|
||||
android:title="@string/title_logcat" />
|
||||
<item
|
||||
android:id="@+id/feedback"
|
||||
android:icon="@drawable/ic_feedback_24dp"
|
||||
android:title="@string/title_pref_feedback" />
|
||||
<item
|
||||
android:id="@+id/privacy_policy"
|
||||
android:icon="@drawable/ic_info_24dp"
|
||||
android:title="@string/title_privacy_policy" />
|
||||
android:id="@+id/about"
|
||||
android:icon="@drawable/ic_about_24dp"
|
||||
android:title="@string/title_about" />
|
||||
<!-- place holder for version text at the bottom -->
|
||||
<item
|
||||
android:id="@+id/placeholder"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
app:showAsAction="always" />
|
||||
<item
|
||||
android:id="@+id/select_photo"
|
||||
android:icon="@drawable/ic_image_photo"
|
||||
android:icon="@drawable/ic_image_24dp"
|
||||
android:title=""
|
||||
app:showAsAction="always" />
|
||||
</menu>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user