Format code

This commit is contained in:
2dust committed 2024-08-17 19:40:04 +08:00
1 parent f646eff048
commit 51adca8568
103 files changed
+1151 -913

No files matched your search

+3 -6
View File
@@ -68,12 +68,9 @@ android {
"universal" "universal"
output.outputFileName = "v2rayNG_${variant.versionName}_${abi}.apk" output.outputFileName = "v2rayNG_${variant.versionName}_${abi}.apk"
if(versionCodes.containsKey(abi)) if (versionCodes.containsKey(abi)) {
{
output.versionCodeOverride = (1000000 * versionCodes[abi]!!).plus(variant.versionCode) output.versionCodeOverride = (1000000 * versionCodes[abi]!!).plus(variant.versionCode)
} } else {
else
{
return@forEach return@forEach
} }
} }
@@ -92,7 +89,7 @@ android {
} }
dependencies { dependencies {
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar","*.jar")))) implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar", "*.jar"))))
testImplementation(libs.junit) testImplementation(libs.junit)
implementation(libs.flexbox) implementation(libs.flexbox)
+54 -38
View File
@@ -8,18 +8,29 @@
android:smallScreens="true" android:smallScreens="true"
android:normalScreens="true" android:normalScreens="true"
android:largeScreens="true" android:largeScreens="true"
android:xlargeScreens="true"/> android:xlargeScreens="true" />
<uses-sdk android:minSdkVersion="21" tools:overrideLibrary="com.blacksquircle.ui.editorkit"/> <uses-sdk
android:minSdkVersion="21"
tools:overrideLibrary="com.blacksquircle.ui.editorkit" />
<uses-feature android:name="android.hardware.camera" android:required="false"/> <uses-feature
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/> android:name="android.hardware.camera"
<uses-feature android:name="android.software.leanback" android:required="false" /> android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" /> <uses-feature
android:name="android.hardware.camera.autofocus"
android:required="false" />
<uses-feature
android:name="android.software.leanback"
android:required="false" />
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
<!-- https://developer.android.com/about/versions/11/privacy/package-visibility --> <!-- https://developer.android.com/about/versions/11/privacy/package-visibility -->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" <uses-permission
tools:ignore="QueryAllPackagesPermission" /> android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="QueryAllPackagesPermission" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
@@ -31,7 +42,7 @@
android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"
android:minSdkVersion="34" /> android:minSdkVersion="34" />
<!-- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> --> <!-- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
@@ -53,12 +64,14 @@
android:theme="@style/AppThemeDayNight.NoActionBar"> android:theme="@style/AppThemeDayNight.NoActionBar">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/> <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" /> <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.app.shortcuts" android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" /> android:resource="@xml/shortcuts" />
@@ -119,12 +132,14 @@
<data android:mimeType="text/plain" /> <data android:mimeType="text/plain" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW"/> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="v2rayng"/> <category android:name="android.intent.category.DEFAULT" />
<data android:host="install-config"/>
<data android:host="install-sub"/> <data android:scheme="v2rayng" />
<data android:host="install-config" />
<data android:host="install-sub" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
@@ -150,28 +165,29 @@
android:value="vpn" /> android:value="vpn" />
</service> </service>
<service android:name=".service.V2RayProxyOnlyService" <service
android:exported="false" android:name=".service.V2RayProxyOnlyService"
android:label="@string/app_name" android:exported="false"
android:foregroundServiceType="specialUse" android:label="@string/app_name"
android:process=":RunSoLibV2RayDaemon"> android:foregroundServiceType="specialUse"
android:process=":RunSoLibV2RayDaemon">
<property <property
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
android:value="proxy" /> android:value="proxy" />
</service> </service>
<service android:name=".service.V2RayTestService" <service
android:name=".service.V2RayTestService"
android:exported="false" android:exported="false"
android:process=":RunSoLibV2RayDaemon"> android:process=":RunSoLibV2RayDaemon"></service>
</service>
<receiver <receiver
android:exported="true" android:exported="true"
android:name=".receiver.WidgetProvider" android:name=".receiver.WidgetProvider"
android:process=":RunSoLibV2RayDaemon"> android:process=":RunSoLibV2RayDaemon">
<meta-data <meta-data
android:name="android.appwidget.provider" android:name="android.appwidget.provider"
android:resource="@xml/app_widget_provider" /> android:resource="@xml/app_widget_provider" />
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.v2ray.ang.action.widget.click" /> <action android:name="com.v2ray.ang.action.widget.click" />
@@ -180,13 +196,13 @@
</receiver> </receiver>
<service <service
android:exported="true" android:exported="true"
android:name=".service.QSTileService" android:name=".service.QSTileService"
android:icon="@drawable/ic_stat_name" android:icon="@drawable/ic_stat_name"
android:label="@string/app_tile_name" android:label="@string/app_tile_name"
android:foregroundServiceType="specialUse" android:foregroundServiceType="specialUse"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE" android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:process=":RunSoLibV2RayDaemon"> android:process=":RunSoLibV2RayDaemon">
<intent-filter> <intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" /> <action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter> </intent-filter>
@@ -208,7 +224,7 @@
<receiver <receiver
android:exported="true" android:exported="true"
android:name=".receiver.TaskerReceiver" android:name=".receiver.TaskerReceiver"
android:process=":RunSoLibV2RayDaemon"> android:process=":RunSoLibV2RayDaemon">
<intent-filter> <intent-filter>
<action android:name="com.twofortyfouram.locale.intent.action.FIRE_SETTING" /> <action android:name="com.twofortyfouram.locale.intent.action.FIRE_SETTING" />
</intent-filter> </intent-filter>
@@ -234,7 +250,7 @@
android:grantUriPermissions="true"> android:grantUriPermissions="true">
<meta-data <meta-data
android:name="android.support.FILE_PROVIDER_PATHS" android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/cache_paths"/> android:resource="@xml/cache_paths" />
</provider> </provider>
</application> </application>
@@ -16,8 +16,8 @@
package com.v2ray.ang.helper; package com.v2ray.ang.helper;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
/** /**
* Interface to listen for a move or dismissal event from a {@link ItemTouchHelper.Callback}. * Interface to listen for a move or dismissal event from a {@link ItemTouchHelper.Callback}.
@@ -36,7 +36,6 @@ public interface ItemTouchHelperAdapter {
* @param fromPosition The start position of the moved item. * @param fromPosition The start position of the moved item.
* @param toPosition Then resolved position of the moved item. * @param toPosition Then resolved position of the moved item.
* @return True if the item was moved to the new adapter position. * @return True if the item was moved to the new adapter position.
*
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder) * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
* @see RecyclerView.ViewHolder#getAdapterPosition() * @see RecyclerView.ViewHolder#getAdapterPosition()
*/ */
@@ -52,7 +51,6 @@ public interface ItemTouchHelperAdapter {
* adjusting the underlying data to reflect this removal. * adjusting the underlying data to reflect this removal.
* *
* @param position The position of the item dismissed. * @param position The position of the item dismissed.
*
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder) * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
* @see RecyclerView.ViewHolder#getAdapterPosition() * @see RecyclerView.ViewHolder#getAdapterPosition()
*/ */
@@ -17,9 +17,10 @@
package com.v2ray.ang.helper; package com.v2ray.ang.helper;
import android.graphics.Canvas; import android.graphics.Canvas;
import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -7,16 +7,13 @@ import androidx.work.WorkManager
import com.tencent.mmkv.MMKV import com.tencent.mmkv.MMKV
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
class AngApplication : MultiDexApplication() class AngApplication : MultiDexApplication() {
{ companion object {
companion object
{
//const val PREF_LAST_VERSION = "pref_last_version" //const val PREF_LAST_VERSION = "pref_last_version"
lateinit var application: AngApplication lateinit var application: AngApplication
} }
override fun attachBaseContext(base: Context?) override fun attachBaseContext(base: Context?) {
{
super.attachBaseContext(base) super.attachBaseContext(base)
application = this application = this
} }
@@ -25,8 +22,7 @@ class AngApplication : MultiDexApplication()
.setDefaultProcessName("${BuildConfig.APPLICATION_ID}:bg") .setDefaultProcessName("${BuildConfig.APPLICATION_ID}:bg")
.build() .build()
override fun onCreate() override fun onCreate() {
{
super.onCreate() super.onCreate()
// LeakCanary.install(this) // LeakCanary.install(this)
@@ -140,6 +140,7 @@ object AppConfig {
const val RAY_NG_CHANNEL_NAME = "V2rayNG Background Service" const val RAY_NG_CHANNEL_NAME = "V2rayNG Background Service"
const val SUBSCRIPTION_UPDATE_CHANNEL = "subscription_update_channel" const val SUBSCRIPTION_UPDATE_CHANNEL = "subscription_update_channel"
const val SUBSCRIPTION_UPDATE_CHANNEL_NAME = "Subscription Update Service" const val SUBSCRIPTION_UPDATE_CHANNEL_NAME = "Subscription Update Service"
/** Protocols Scheme **/ /** Protocols Scheme **/
const val VMESS = "vmess://" const val VMESS = "vmess://"
const val CUSTOM = "" const val CUSTOM = ""
@@ -2,8 +2,10 @@ package com.v2ray.ang.dto
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
data class AppInfo(val appName: String, data class AppInfo(
val packageName: String, val appName: String,
val appIcon: Drawable, val packageName: String,
val isSystemApp: Boolean, val appIcon: Drawable,
var isSelected: Int) val isSystemApp: Boolean,
var isSelected: Int
)
@@ -6,7 +6,7 @@ import com.v2ray.ang.AppConfig
enum class EConfigType(val value: Int, val protocolScheme: String) { enum class EConfigType(val value: Int, val protocolScheme: String) {
VMESS(1, AppConfig.VMESS), VMESS(1, AppConfig.VMESS),
CUSTOM(2, AppConfig.CUSTOM), CUSTOM(2, AppConfig.CUSTOM),
SHADOWSOCKS(3,AppConfig.SHADOWSOCKS), SHADOWSOCKS(3, AppConfig.SHADOWSOCKS),
SOCKS(4, AppConfig.SOCKS), SOCKS(4, AppConfig.SOCKS),
VLESS(5, AppConfig.VLESS), VLESS(5, AppConfig.VLESS),
TROJAN(6, AppConfig.TROJAN), TROJAN(6, AppConfig.TROJAN),
@@ -1,6 +1,6 @@
package com.v2ray.ang.dto package com.v2ray.ang.dto
enum class ERoutingMode(val value: String ) { enum class ERoutingMode(val value: String) {
GLOBAL_PROXY("0"), GLOBAL_PROXY("0"),
BYPASS_LAN("1"), BYPASS_LAN("1"),
BYPASS_MAINLAND("2"), BYPASS_MAINLAND("2"),
@@ -1,50 +1,64 @@
package com.v2ray.ang.dto package com.v2ray.ang.dto
import com.v2ray.ang.AppConfig.TAG_PROXY
import com.v2ray.ang.AppConfig.TAG_BLOCKED import com.v2ray.ang.AppConfig.TAG_BLOCKED
import com.v2ray.ang.AppConfig.TAG_DIRECT import com.v2ray.ang.AppConfig.TAG_DIRECT
import com.v2ray.ang.AppConfig.TAG_PROXY
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
data class ServerConfig( data class ServerConfig(
val configVersion: Int = 3, val configVersion: Int = 3,
val configType: EConfigType, val configType: EConfigType,
var subscriptionId: String = "", var subscriptionId: String = "",
val addedTime: Long = System.currentTimeMillis(), val addedTime: Long = System.currentTimeMillis(),
var remarks: String = "", var remarks: String = "",
val outboundBean: V2rayConfig.OutboundBean? = null, val outboundBean: V2rayConfig.OutboundBean? = null,
var fullConfig: V2rayConfig? = null var fullConfig: V2rayConfig? = null
) { ) {
companion object { companion object {
fun create(configType: EConfigType): ServerConfig { fun create(configType: EConfigType): ServerConfig {
when(configType) { when (configType) {
EConfigType.VMESS, EConfigType.VLESS -> EConfigType.VMESS, EConfigType.VLESS ->
return ServerConfig( return ServerConfig(
configType = configType, configType = configType,
outboundBean = V2rayConfig.OutboundBean( outboundBean = V2rayConfig.OutboundBean(
protocol = configType.name.lowercase(), protocol = configType.name.lowercase(),
settings = V2rayConfig.OutboundBean.OutSettingsBean( settings = V2rayConfig.OutboundBean.OutSettingsBean(
vnext = listOf(V2rayConfig.OutboundBean.OutSettingsBean.VnextBean( vnext = listOf(
users = listOf(V2rayConfig.OutboundBean.OutSettingsBean.VnextBean.UsersBean())))), V2rayConfig.OutboundBean.OutSettingsBean.VnextBean(
streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean())) users = listOf(V2rayConfig.OutboundBean.OutSettingsBean.VnextBean.UsersBean())
)
)
),
streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean()
)
)
EConfigType.CUSTOM -> EConfigType.CUSTOM ->
return ServerConfig(configType = configType) return ServerConfig(configType = configType)
EConfigType.SHADOWSOCKS, EConfigType.SOCKS, EConfigType.TROJAN -> EConfigType.SHADOWSOCKS, EConfigType.SOCKS, EConfigType.TROJAN ->
return ServerConfig( return ServerConfig(
configType = configType, configType = configType,
outboundBean = V2rayConfig.OutboundBean( outboundBean = V2rayConfig.OutboundBean(
protocol = configType.name.lowercase(), protocol = configType.name.lowercase(),
settings = V2rayConfig.OutboundBean.OutSettingsBean( settings = V2rayConfig.OutboundBean.OutSettingsBean(
servers = listOf(V2rayConfig.OutboundBean.OutSettingsBean.ServersBean())), servers = listOf(V2rayConfig.OutboundBean.OutSettingsBean.ServersBean())
streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean())) ),
streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean()
)
)
EConfigType.WIREGUARD -> EConfigType.WIREGUARD ->
return ServerConfig( return ServerConfig(
configType = configType, configType = configType,
outboundBean = V2rayConfig.OutboundBean( outboundBean = V2rayConfig.OutboundBean(
protocol = configType.name.lowercase(), protocol = configType.name.lowercase(),
settings = V2rayConfig.OutboundBean.OutSettingsBean( settings = V2rayConfig.OutboundBean.OutSettingsBean(
secretKey = "", secretKey = "",
peers = listOf(V2rayConfig.OutboundBean.OutSettingsBean.WireGuardBean()) peers = listOf(V2rayConfig.OutboundBean.OutSettingsBean.WireGuardBean())
))) )
)
)
} }
} }
} }
@@ -1,4 +1,6 @@
package com.v2ray.ang.dto package com.v2ray.ang.dto
data class ServersCache(val guid: String, data class ServersCache(
val profile: ProfileItem) val guid: String,
val profile: ProfileItem
)
@@ -10,21 +10,22 @@ import com.google.gson.reflect.TypeToken
import java.lang.reflect.Type import java.lang.reflect.Type
data class V2rayConfig( data class V2rayConfig(
var remarks: String? = null, var remarks: String? = null,
var stats: Any? = null, var stats: Any? = null,
val log: LogBean, val log: LogBean,
var policy: PolicyBean?, var policy: PolicyBean?,
val inbounds: ArrayList<InboundBean>, val inbounds: ArrayList<InboundBean>,
var outbounds: ArrayList<OutboundBean>, var outbounds: ArrayList<OutboundBean>,
var dns: DnsBean, var dns: DnsBean,
val routing: RoutingBean, val routing: RoutingBean,
val api: Any? = null, val api: Any? = null,
val transport: Any? = null, val transport: Any? = null,
val reverse: Any? = null, val reverse: Any? = null,
var fakedns: Any? = null, var fakedns: Any? = null,
val browserForwarder: Any? = null, val browserForwarder: Any? = null,
var observatory: Any? = null, var observatory: Any? = null,
var burstObservatory: Any? = null) { var burstObservatory: Any? = null
) {
companion object { companion object {
const val DEFAULT_PORT = 443 const val DEFAULT_PORT = 443
const val DEFAULT_SECURITY = "auto" const val DEFAULT_SECURITY = "auto"
@@ -36,210 +37,261 @@ data class V2rayConfig(
const val HTTP = "http" const val HTTP = "http"
} }
data class LogBean(val access: String, data class LogBean(
val error: String, val access: String,
var loglevel: String?, val error: String,
val dnsLog: Boolean? = null) var loglevel: String?,
val dnsLog: Boolean? = null
)
data class InboundBean( data class InboundBean(
var tag: String, var tag: String,
var port: Int, var port: Int,
var protocol: String, var protocol: String,
var listen: String? = null, var listen: String? = null,
val settings: Any? = null, val settings: Any? = null,
val sniffing: SniffingBean?, val sniffing: SniffingBean?,
val streamSettings: Any? = null, val streamSettings: Any? = null,
val allocate: Any? = null) { val allocate: Any? = null
) {
data class InSettingsBean(val auth: String? = null, data class InSettingsBean(
val udp: Boolean? = null, val auth: String? = null,
val userLevel: Int? = null, val udp: Boolean? = null,
val address: String? = null, val userLevel: Int? = null,
val port: Int? = null, val address: String? = null,
val network: String? = null) val port: Int? = null,
val network: String? = null
)
data class SniffingBean(var enabled: Boolean, data class SniffingBean(
val destOverride: ArrayList<String>, var enabled: Boolean,
val metadataOnly: Boolean? = null, val destOverride: ArrayList<String>,
var routeOnly: Boolean? = null) val metadataOnly: Boolean? = null,
var routeOnly: Boolean? = null
)
} }
data class OutboundBean(var tag: String = "proxy", data class OutboundBean(
var protocol: String, var tag: String = "proxy",
var settings: OutSettingsBean? = null, var protocol: String,
var streamSettings: StreamSettingsBean? = null, var settings: OutSettingsBean? = null,
val proxySettings: Any? = null, var streamSettings: StreamSettingsBean? = null,
val sendThrough: String? = null, val proxySettings: Any? = null,
var mux: MuxBean? = MuxBean(false)) { val sendThrough: String? = null,
var mux: MuxBean? = MuxBean(false)
) {
data class OutSettingsBean(var vnext: List<VnextBean>? = null, data class OutSettingsBean(
var fragment: FragmentBean? = null, var vnext: List<VnextBean>? = null,
var servers: List<ServersBean>? = null, var fragment: FragmentBean? = null,
/*Blackhole*/ var servers: List<ServersBean>? = null,
var response: Response? = null, /*Blackhole*/
/*DNS*/ var response: Response? = null,
val network: String? = null, /*DNS*/
var address: Any? = null, val network: String? = null,
val port: Int? = null, var address: Any? = null,
/*Freedom*/ val port: Int? = null,
var domainStrategy: String? = null, /*Freedom*/
val redirect: String? = null, var domainStrategy: String? = null,
val userLevel: Int? = null, val redirect: String? = null,
/*Loopback*/ val userLevel: Int? = null,
val inboundTag: String? = null, /*Loopback*/
/*Wireguard*/ val inboundTag: String? = null,
var secretKey: String? = null, /*Wireguard*/
val peers: List<WireGuardBean>? = null, var secretKey: String? = null,
var reserved: List<Int>? = null, val peers: List<WireGuardBean>? = null,
var mtu :Int? = null var reserved: List<Int>? = null,
var mtu: Int? = null
) { ) {
data class VnextBean(var address: String = "", data class VnextBean(
var port: Int = DEFAULT_PORT, var address: String = "",
var users: List<UsersBean>) { var port: Int = DEFAULT_PORT,
var users: List<UsersBean>
) {
data class UsersBean(var id: String = "", data class UsersBean(
var alterId: Int? = null, var id: String = "",
var security: String = DEFAULT_SECURITY, var alterId: Int? = null,
var level: Int = DEFAULT_LEVEL, var security: String = DEFAULT_SECURITY,
var encryption: String = "", var level: Int = DEFAULT_LEVEL,
var flow: String = "") var encryption: String = "",
var flow: String = ""
)
} }
data class FragmentBean(var packets: String? = null, data class FragmentBean(
var length: String? = null, var packets: String? = null,
var interval: String? = null) var length: String? = null,
var interval: String? = null
)
data class ServersBean(var address: String = "", data class ServersBean(
var method: String = "chacha20-poly1305", var address: String = "",
var ota: Boolean = false, var method: String = "chacha20-poly1305",
var password: String = "", var ota: Boolean = false,
var port: Int = DEFAULT_PORT, var password: String = "",
var level: Int = DEFAULT_LEVEL, var port: Int = DEFAULT_PORT,
val email: String? = null, var level: Int = DEFAULT_LEVEL,
var flow: String? = null, val email: String? = null,
val ivCheck: Boolean? = null, var flow: String? = null,
var users: List<SocksUsersBean>? = null) { val ivCheck: Boolean? = null,
var users: List<SocksUsersBean>? = null
) {
data class SocksUsersBean(var user: String = "", data class SocksUsersBean(
var pass: String = "", var user: String = "",
var level: Int = DEFAULT_LEVEL) var pass: String = "",
var level: Int = DEFAULT_LEVEL
)
} }
data class Response(var type: String) data class Response(var type: String)
data class WireGuardBean(var publicKey: String = "", data class WireGuardBean(
var endpoint: String = "") var publicKey: String = "",
var endpoint: String = ""
)
} }
data class StreamSettingsBean(var network: String = DEFAULT_NETWORK, data class StreamSettingsBean(
var security: String = "", var network: String = DEFAULT_NETWORK,
var tcpSettings: TcpSettingsBean? = null, var security: String = "",
var kcpSettings: KcpSettingsBean? = null, var tcpSettings: TcpSettingsBean? = null,
var wsSettings: WsSettingsBean? = null, var kcpSettings: KcpSettingsBean? = null,
var httpupgradeSettings: HttpupgradeSettingsBean? = null, var wsSettings: WsSettingsBean? = null,
var splithttpSettings: SplithttpSettingsBean? = null, var httpupgradeSettings: HttpupgradeSettingsBean? = null,
var httpSettings: HttpSettingsBean? = null, var splithttpSettings: SplithttpSettingsBean? = null,
var tlsSettings: TlsSettingsBean? = null, var httpSettings: HttpSettingsBean? = null,
var quicSettings: QuicSettingBean? = null, var tlsSettings: TlsSettingsBean? = null,
var realitySettings: TlsSettingsBean? = null, var quicSettings: QuicSettingBean? = null,
var grpcSettings: GrpcSettingsBean? = null, var realitySettings: TlsSettingsBean? = null,
val dsSettings: Any? = null, var grpcSettings: GrpcSettingsBean? = null,
var sockopt: SockoptBean? = null val dsSettings: Any? = null,
var sockopt: SockoptBean? = null
) { ) {
data class TcpSettingsBean(var header: HeaderBean = HeaderBean(), data class TcpSettingsBean(
val acceptProxyProtocol: Boolean? = null) { var header: HeaderBean = HeaderBean(),
data class HeaderBean(var type: String = "none", val acceptProxyProtocol: Boolean? = null
var request: RequestBean? = null, ) {
var response: Any? = null) { data class HeaderBean(
data class RequestBean(var path: List<String> = ArrayList(), var type: String = "none",
var headers: HeadersBean = HeadersBean(), var request: RequestBean? = null,
val version: String? = null, var response: Any? = null
val method: String? = null) { ) {
data class HeadersBean(var Host: List<String>? = ArrayList(), data class RequestBean(
@SerializedName("User-Agent") var path: List<String> = ArrayList(),
val userAgent: List<String>? = null, var headers: HeadersBean = HeadersBean(),
@SerializedName("Accept-Encoding") val version: String? = null,
val acceptEncoding: List<String>? = null, val method: String? = null
val Connection: List<String>? = null, ) {
val Pragma: String? = null) data class HeadersBean(
var Host: List<String>? = ArrayList(),
@SerializedName("User-Agent")
val userAgent: List<String>? = null,
@SerializedName("Accept-Encoding")
val acceptEncoding: List<String>? = null,
val Connection: List<String>? = null,
val Pragma: String? = null
)
} }
} }
} }
data class KcpSettingsBean(var mtu: Int = 1350, data class KcpSettingsBean(
var tti: Int = 50, var mtu: Int = 1350,
var uplinkCapacity: Int = 12, var tti: Int = 50,
var downlinkCapacity: Int = 100, var uplinkCapacity: Int = 12,
var congestion: Boolean = false, var downlinkCapacity: Int = 100,
var readBufferSize: Int = 1, var congestion: Boolean = false,
var writeBufferSize: Int = 1, var readBufferSize: Int = 1,
var header: HeaderBean = HeaderBean(), var writeBufferSize: Int = 1,
var seed: String? = null) { var header: HeaderBean = HeaderBean(),
var seed: String? = null
) {
data class HeaderBean(var type: String = "none") data class HeaderBean(var type: String = "none")
} }
data class WsSettingsBean(var path: String = "", data class WsSettingsBean(
var headers: HeadersBean = HeadersBean(), var path: String = "",
val maxEarlyData: Int? = null, var headers: HeadersBean = HeadersBean(),
val useBrowserForwarding: Boolean? = null, val maxEarlyData: Int? = null,
val acceptProxyProtocol: Boolean? = null) { val useBrowserForwarding: Boolean? = null,
val acceptProxyProtocol: Boolean? = null
) {
data class HeadersBean(var Host: String = "") data class HeadersBean(var Host: String = "")
} }
data class HttpupgradeSettingsBean(var path: String = "", data class HttpupgradeSettingsBean(
var host: String = "", var path: String = "",
val acceptProxyProtocol: Boolean? = null) var host: String = "",
val acceptProxyProtocol: Boolean? = null
)
data class SplithttpSettingsBean(var path: String = "", data class SplithttpSettingsBean(
var host: String = "", var path: String = "",
val maxUploadSize: Int? = null, var host: String = "",
val maxConcurrentUploads: Int? = null) val maxUploadSize: Int? = null,
data class HttpSettingsBean(var host: List<String> = ArrayList(), val maxConcurrentUploads: Int? = null
var path: String = "") )
data class SockoptBean(var TcpNoDelay: Boolean? = null, data class HttpSettingsBean(
var tcpKeepAliveIdle: Int? = null, var host: List<String> = ArrayList(),
var tcpFastOpen: Boolean? = null, var path: String = ""
var tproxy: String? = null, )
var mark: Int? = null,
var dialerProxy: String? = null)
data class TlsSettingsBean(var allowInsecure: Boolean = false, data class SockoptBean(
var serverName: String = "", var TcpNoDelay: Boolean? = null,
val alpn: List<String>? = null, var tcpKeepAliveIdle: Int? = null,
val minVersion: String? = null, var tcpFastOpen: Boolean? = null,
val maxVersion: String? = null, var tproxy: String? = null,
val preferServerCipherSuites: Boolean? = null, var mark: Int? = null,
val cipherSuites: String? = null, var dialerProxy: String? = null
val fingerprint: String? = null, )
val certificates: List<Any>? = null,
val disableSystemRoot: Boolean? = null,
val enableSessionResumption: Boolean? = null,
// REALITY settings
val show: Boolean = false,
var publicKey: String? = null,
var shortId: String? = null,
var spiderX: String? = null)
data class QuicSettingBean(var security: String = "none", data class TlsSettingsBean(
var key: String = "", var allowInsecure: Boolean = false,
var header: HeaderBean = HeaderBean()) { var serverName: String = "",
val alpn: List<String>? = null,
val minVersion: String? = null,
val maxVersion: String? = null,
val preferServerCipherSuites: Boolean? = null,
val cipherSuites: String? = null,
val fingerprint: String? = null,
val certificates: List<Any>? = null,
val disableSystemRoot: Boolean? = null,
val enableSessionResumption: Boolean? = null,
// REALITY settings
val show: Boolean = false,
var publicKey: String? = null,
var shortId: String? = null,
var spiderX: String? = null
)
data class QuicSettingBean(
var security: String = "none",
var key: String = "",
var header: HeaderBean = HeaderBean()
) {
data class HeaderBean(var type: String = "none") data class HeaderBean(var type: String = "none")
} }
data class GrpcSettingsBean(var serviceName: String = "", data class GrpcSettingsBean(
var authority: String? = null, var serviceName: String = "",
var multiMode: Boolean? = null, var authority: String? = null,
var idle_timeout: Int? = null, var multiMode: Boolean? = null,
var health_check_timeout: Int? = null var idle_timeout: Int? = null,
) var health_check_timeout: Int? = null
)
fun populateTransportSettings(transport: String, headerType: String?, host: String?, path: String?, seed: String?, fun populateTransportSettings(
quicSecurity: String?, key: String?, mode: String?, serviceName: String?, transport: String, headerType: String?, host: String?, path: String?, seed: String?,
authority: String?): String { quicSecurity: String?, key: String?, mode: String?, serviceName: String?,
authority: String?
): String {
var sni = "" var sni = ""
network = transport network = transport
when (network) { when (network) {
@@ -249,8 +301,8 @@ data class V2rayConfig(
tcpSetting.header.type = HTTP tcpSetting.header.type = HTTP
if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(path)) { if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(path)) {
val requestObj = TcpSettingsBean.HeaderBean.RequestBean() val requestObj = TcpSettingsBean.HeaderBean.RequestBean()
requestObj.headers.Host = (host .orEmpty()).split(",").map { it.trim() }.filter { it.isNotEmpty() } requestObj.headers.Host = (host.orEmpty()).split(",").map { it.trim() }.filter { it.isNotEmpty() }
requestObj.path = (path .orEmpty()).split(",").map { it.trim() }.filter { it.isNotEmpty() } requestObj.path = (path.orEmpty()).split(",").map { it.trim() }.filter { it.isNotEmpty() }
tcpSetting.header.request = requestObj tcpSetting.header.request = requestObj
sni = requestObj.headers.Host?.getOrNull(0) ?: sni sni = requestObj.headers.Host?.getOrNull(0) ?: sni
} }
@@ -260,6 +312,7 @@ data class V2rayConfig(
} }
tcpSettings = tcpSetting tcpSettings = tcpSetting
} }
"kcp" -> { "kcp" -> {
val kcpsetting = KcpSettingsBean() val kcpsetting = KcpSettingsBean()
kcpsetting.header.type = headerType ?: "none" kcpsetting.header.type = headerType ?: "none"
@@ -270,6 +323,7 @@ data class V2rayConfig(
} }
kcpSettings = kcpsetting kcpSettings = kcpsetting
} }
"ws" -> { "ws" -> {
val wssetting = WsSettingsBean() val wssetting = WsSettingsBean()
wssetting.headers.Host = host.orEmpty() wssetting.headers.Host = host.orEmpty()
@@ -277,6 +331,7 @@ data class V2rayConfig(
wssetting.path = path ?: "/" wssetting.path = path ?: "/"
wsSettings = wssetting wsSettings = wssetting
} }
"httpupgrade" -> { "httpupgrade" -> {
val httpupgradeSetting = HttpupgradeSettingsBean() val httpupgradeSetting = HttpupgradeSettingsBean()
httpupgradeSetting.host = host.orEmpty() httpupgradeSetting.host = host.orEmpty()
@@ -284,6 +339,7 @@ data class V2rayConfig(
httpupgradeSetting.path = path ?: "/" httpupgradeSetting.path = path ?: "/"
httpupgradeSettings = httpupgradeSetting httpupgradeSettings = httpupgradeSetting
} }
"splithttp" -> { "splithttp" -> {
val splithttpSetting = SplithttpSettingsBean() val splithttpSetting = SplithttpSettingsBean()
splithttpSetting.host = host.orEmpty() splithttpSetting.host = host.orEmpty()
@@ -291,14 +347,16 @@ data class V2rayConfig(
splithttpSetting.path = path ?: "/" splithttpSetting.path = path ?: "/"
splithttpSettings = splithttpSetting splithttpSettings = splithttpSetting
} }
"h2", "http" -> { "h2", "http" -> {
network = "h2" network = "h2"
val h2Setting = HttpSettingsBean() val h2Setting = HttpSettingsBean()
h2Setting.host = (host .orEmpty()).split(",").map { it.trim() }.filter { it.isNotEmpty() } h2Setting.host = (host.orEmpty()).split(",").map { it.trim() }.filter { it.isNotEmpty() }
sni = h2Setting.host.getOrNull(0) ?: sni sni = h2Setting.host.getOrNull(0) ?: sni
h2Setting.path = path ?: "/" h2Setting.path = path ?: "/"
httpSettings = h2Setting httpSettings = h2Setting
} }
"quic" -> { "quic" -> {
val quicsetting = QuicSettingBean() val quicsetting = QuicSettingBean()
quicsetting.security = quicSecurity ?: "none" quicsetting.security = quicSecurity ?: "none"
@@ -306,6 +364,7 @@ data class V2rayConfig(
quicsetting.header.type = headerType ?: "none" quicsetting.header.type = headerType ?: "none"
quicSettings = quicsetting quicSettings = quicsetting
} }
"grpc" -> { "grpc" -> {
val grpcSetting = GrpcSettingsBean() val grpcSetting = GrpcSettingsBean()
grpcSetting.multiMode = mode == "multi" grpcSetting.multiMode = mode == "multi"
@@ -320,17 +379,19 @@ data class V2rayConfig(
return sni return sni
} }
fun populateTlsSettings(streamSecurity: String, allowInsecure: Boolean, sni: String, fingerprint: String?, alpns: String?, fun populateTlsSettings(
publicKey: String?, shortId: String?, spiderX: String?) { streamSecurity: String, allowInsecure: Boolean, sni: String, fingerprint: String?, alpns: String?,
publicKey: String?, shortId: String?, spiderX: String?
) {
security = streamSecurity security = streamSecurity
val tlsSetting = TlsSettingsBean( val tlsSetting = TlsSettingsBean(
allowInsecure = allowInsecure, allowInsecure = allowInsecure,
serverName = sni, serverName = sni,
fingerprint = fingerprint, fingerprint = fingerprint,
alpn = if (alpns.isNullOrEmpty()) null else alpns.split(",").map { it.trim() }.filter { it.isNotEmpty() }, alpn = if (alpns.isNullOrEmpty()) null else alpns.split(",").map { it.trim() }.filter { it.isNotEmpty() },
publicKey = publicKey, publicKey = publicKey,
shortId = shortId, shortId = shortId,
spiderX = spiderX spiderX = spiderX
) )
if (security == TLS) { if (security == TLS) {
tlsSettings = tlsSetting tlsSettings = tlsSetting
@@ -342,18 +403,22 @@ data class V2rayConfig(
} }
} }
data class MuxBean(var enabled: Boolean, data class MuxBean(
var concurrency: Int = 8, var enabled: Boolean,
var xudpConcurrency: Int = 8, var concurrency: Int = 8,
var xudpProxyUDP443: String = "",) var xudpConcurrency: Int = 8,
var xudpProxyUDP443: String = "",
)
fun getServerAddress(): String? { fun getServerAddress(): String? {
if (protocol.equals(EConfigType.VMESS.name, true) if (protocol.equals(EConfigType.VMESS.name, true)
|| protocol.equals(EConfigType.VLESS.name, true)) { || protocol.equals(EConfigType.VLESS.name, true)
) {
return settings?.vnext?.get(0)?.address return settings?.vnext?.get(0)?.address
} else if (protocol.equals(EConfigType.SHADOWSOCKS.name, true) } else if (protocol.equals(EConfigType.SHADOWSOCKS.name, true)
|| protocol.equals(EConfigType.SOCKS.name, true) || protocol.equals(EConfigType.SOCKS.name, true)
|| protocol.equals(EConfigType.TROJAN.name, true)) { || protocol.equals(EConfigType.TROJAN.name, true)
) {
return settings?.servers?.get(0)?.address return settings?.servers?.get(0)?.address
} else if (protocol.equals(EConfigType.WIREGUARD.name, true)) { } else if (protocol.equals(EConfigType.WIREGUARD.name, true)) {
return settings?.peers?.get(0)?.endpoint?.substringBeforeLast(":") return settings?.peers?.get(0)?.endpoint?.substringBeforeLast(":")
@@ -363,11 +428,13 @@ data class V2rayConfig(
fun getServerPort(): Int? { fun getServerPort(): Int? {
if (protocol.equals(EConfigType.VMESS.name, true) if (protocol.equals(EConfigType.VMESS.name, true)
|| protocol.equals(EConfigType.VLESS.name, true)) { || protocol.equals(EConfigType.VLESS.name, true)
) {
return settings?.vnext?.get(0)?.port return settings?.vnext?.get(0)?.port
} else if (protocol.equals(EConfigType.SHADOWSOCKS.name, true) } else if (protocol.equals(EConfigType.SHADOWSOCKS.name, true)
|| protocol.equals(EConfigType.SOCKS.name, true) || protocol.equals(EConfigType.SOCKS.name, true)
|| protocol.equals(EConfigType.TROJAN.name, true)) { || protocol.equals(EConfigType.TROJAN.name, true)
) {
return settings?.servers?.get(0)?.port return settings?.servers?.get(0)?.port
} else if (protocol.equals(EConfigType.WIREGUARD.name, true)) { } else if (protocol.equals(EConfigType.WIREGUARD.name, true)) {
return settings?.peers?.get(0)?.endpoint?.substringAfterLast(":")?.toInt() return settings?.peers?.get(0)?.endpoint?.substringAfterLast(":")?.toInt()
@@ -377,10 +444,12 @@ data class V2rayConfig(
fun getPassword(): String? { fun getPassword(): String? {
if (protocol.equals(EConfigType.VMESS.name, true) if (protocol.equals(EConfigType.VMESS.name, true)
|| protocol.equals(EConfigType.VLESS.name, true)) { || protocol.equals(EConfigType.VLESS.name, true)
) {
return settings?.vnext?.get(0)?.users?.get(0)?.id return settings?.vnext?.get(0)?.users?.get(0)?.id
} else if (protocol.equals(EConfigType.SHADOWSOCKS.name, true) } else if (protocol.equals(EConfigType.SHADOWSOCKS.name, true)
|| protocol.equals(EConfigType.TROJAN.name, true)) { || protocol.equals(EConfigType.TROJAN.name, true)
) {
return settings?.servers?.get(0)?.password return settings?.servers?.get(0)?.password
} else if (protocol.equals(EConfigType.SOCKS.name, true)) { } else if (protocol.equals(EConfigType.SOCKS.name, true)) {
return settings?.servers?.get(0)?.users?.get(0)?.pass return settings?.servers?.get(0)?.users?.get(0)?.pass
@@ -401,59 +470,84 @@ data class V2rayConfig(
fun getTransportSettingDetails(): List<String>? { fun getTransportSettingDetails(): List<String>? {
if (protocol.equals(EConfigType.VMESS.name, true) if (protocol.equals(EConfigType.VMESS.name, true)
|| protocol.equals(EConfigType.VLESS.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)) { || protocol.equals(EConfigType.SHADOWSOCKS.name, true)
) {
val transport = streamSettings?.network ?: return null val transport = streamSettings?.network ?: return null
return when (transport) { return when (transport) {
"tcp" -> { "tcp" -> {
val tcpSetting = streamSettings?.tcpSettings ?: return null val tcpSetting = streamSettings?.tcpSettings ?: return null
listOf(tcpSetting.header.type, listOf(
tcpSetting.header.request?.headers?.Host?.joinToString().orEmpty(), tcpSetting.header.type,
tcpSetting.header.request?.path?.joinToString().orEmpty()) tcpSetting.header.request?.headers?.Host?.joinToString().orEmpty(),
tcpSetting.header.request?.path?.joinToString().orEmpty()
)
} }
"kcp" -> { "kcp" -> {
val kcpSetting = streamSettings?.kcpSettings ?: return null val kcpSetting = streamSettings?.kcpSettings ?: return null
listOf(kcpSetting.header.type, listOf(
"", kcpSetting.header.type,
kcpSetting.seed.orEmpty()) "",
kcpSetting.seed.orEmpty()
)
} }
"ws" -> { "ws" -> {
val wsSetting = streamSettings?.wsSettings ?: return null val wsSetting = streamSettings?.wsSettings ?: return null
listOf("", listOf(
wsSetting.headers.Host, "",
wsSetting.path) wsSetting.headers.Host,
wsSetting.path
)
} }
"httpupgrade" -> { "httpupgrade" -> {
val httpupgradeSetting = streamSettings?.httpupgradeSettings ?: return null val httpupgradeSetting = streamSettings?.httpupgradeSettings ?: return null
listOf("", listOf(
"",
httpupgradeSetting.host, httpupgradeSetting.host,
httpupgradeSetting.path) httpupgradeSetting.path
)
} }
"splithttp" -> { "splithttp" -> {
val splithttpSetting = streamSettings?.splithttpSettings ?: return null val splithttpSetting = streamSettings?.splithttpSettings ?: return null
listOf("", listOf(
"",
splithttpSetting.host, splithttpSetting.host,
splithttpSetting.path) splithttpSetting.path
)
} }
"h2" -> { "h2" -> {
val h2Setting = streamSettings?.httpSettings ?: return null val h2Setting = streamSettings?.httpSettings ?: return null
listOf("", listOf(
h2Setting.host.joinToString(), "",
h2Setting.path) h2Setting.host.joinToString(),
h2Setting.path
)
} }
"quic" -> { "quic" -> {
val quicSetting = streamSettings?.quicSettings ?: return null val quicSetting = streamSettings?.quicSettings ?: return null
listOf(quicSetting.header.type, listOf(
quicSetting.security, quicSetting.header.type,
quicSetting.key) quicSetting.security,
quicSetting.key
)
} }
"grpc" -> { "grpc" -> {
val grpcSetting = streamSettings?.grpcSettings ?: return null val grpcSetting = streamSettings?.grpcSettings ?: return null
listOf(if (grpcSetting.multiMode == true) "multi" else "gun", listOf(
grpcSetting.authority.orEmpty(), if (grpcSetting.multiMode == true) "multi" else "gun",
grpcSetting.serviceName) grpcSetting.authority.orEmpty(),
grpcSetting.serviceName
)
} }
else -> null else -> null
} }
} }
@@ -461,59 +555,69 @@ data class V2rayConfig(
} }
} }
data class DnsBean(var servers: ArrayList<Any>? = null, data class DnsBean(
var hosts: Map<String, Any>? = null, var servers: ArrayList<Any>? = null,
val clientIp: String? = null, var hosts: Map<String, Any>? = null,
val disableCache: Boolean? = null, val clientIp: String? = null,
val queryStrategy: String? = null, val disableCache: Boolean? = null,
val tag: String? = null val queryStrategy: String? = null,
val tag: String? = null
) { ) {
data class ServersBean(var address: String = "", data class ServersBean(
var port: Int? = null, var address: String = "",
var domains: List<String>? = null, var port: Int? = null,
var expectIPs: List<String>? = null, var domains: List<String>? = null,
val clientIp: String? = null) var expectIPs: List<String>? = null,
} val clientIp: String? = null
data class RoutingBean(var domainStrategy: String,
var domainMatcher: String? = null,
var rules: ArrayList<RulesBean>,
val balancers: List<Any>? = null) {
data class RulesBean(
var ip: ArrayList<String>? = null,
var domain: ArrayList<String>? = null,
var outboundTag: String = "",
var balancerTag: String? = null,
var port: String? = null,
val sourcePort: String? = null,
val network: String? = null,
val source: List<String>? = null,
val user: List<String>? = null,
var inboundTag: List<String>? = null,
val protocol: List<String>? = null,
val attrs: String? = null,
val domainMatcher: String? = null
) )
} }
data class PolicyBean(var levels: Map<String, LevelBean>, data class RoutingBean(
var system: Any? = null) { var domainStrategy: String,
data class LevelBean( var domainMatcher: String? = null,
var handshake: Int? = null, var rules: ArrayList<RulesBean>,
var connIdle: Int? = null, val balancers: List<Any>? = null
var uplinkOnly: Int? = null, ) {
var downlinkOnly: Int? = null,
val statsUserUplink: Boolean? = null, data class RulesBean(
val statsUserDownlink: Boolean? = null, var ip: ArrayList<String>? = null,
var bufferSize: Int? = null) var domain: ArrayList<String>? = null,
var outboundTag: String = "",
var balancerTag: String? = null,
var port: String? = null,
val sourcePort: String? = null,
val network: String? = null,
val source: List<String>? = null,
val user: List<String>? = null,
var inboundTag: List<String>? = null,
val protocol: List<String>? = null,
val attrs: String? = null,
val domainMatcher: String? = null
)
} }
data class FakednsBean(var ipPool: String = "198.18.0.0/15", data class PolicyBean(
var poolSize: Int = 10000) // roughly 10 times smaller than total ip pool var levels: Map<String, LevelBean>,
var system: Any? = null
) {
data class LevelBean(
var handshake: Int? = null,
var connIdle: Int? = null,
var uplinkOnly: Int? = null,
var downlinkOnly: Int? = null,
val statsUserUplink: Boolean? = null,
val statsUserDownlink: Boolean? = null,
var bufferSize: Int? = null
)
}
data class FakednsBean(
var ipPool: String = "198.18.0.0/15",
var poolSize: Int = 10000
) // roughly 10 times smaller than total ip pool
fun getProxyOutbound(): OutboundBean? { fun getProxyOutbound(): OutboundBean? {
outbounds?.forEach { outbound -> outbounds.forEach { outbound ->
EConfigType.entries.forEach { EConfigType.entries.forEach {
if (outbound.protocol.equals(it.name, true)) { if (outbound.protocol.equals(it.name, true)) {
return outbound return outbound
@@ -525,13 +629,13 @@ data class V2rayConfig(
fun toPrettyPrinting(): String { fun toPrettyPrinting(): String {
return GsonBuilder() return GsonBuilder()
.setPrettyPrinting() .setPrettyPrinting()
.disableHtmlEscaping() .disableHtmlEscaping()
.registerTypeAdapter( // custom serialiser is needed here since JSON by default parse number as Double, core will fail to start .registerTypeAdapter( // custom serialiser is needed here since JSON by default parse number as Double, core will fail to start
object : TypeToken<Double>() {}.type, object : TypeToken<Double>() {}.type,
JsonSerializer { src: Double?, _: Type?, _: JsonSerializationContext? -> JsonPrimitive(src?.toInt()) } JsonSerializer { src: Double?, _: Type?, _: JsonSerializationContext? -> JsonPrimitive(src?.toInt()) }
) )
.create() .create()
.toJson(this) .toJson(this)
} }
} }
@@ -1,17 +1,19 @@
package com.v2ray.ang.dto package com.v2ray.ang.dto
data class VmessQRCode(var v: String = "", data class VmessQRCode(
var ps: String = "", var v: String = "",
var add: String = "", var ps: String = "",
var port: String = "", var add: String = "",
var id: String = "", var port: String = "",
var aid: String = "0", var id: String = "",
var scy: String = "", var aid: String = "0",
var net: String = "", var scy: String = "",
var type: String = "", var net: String = "",
var host: String = "", var type: String = "",
var path: String = "", var host: String = "",
var tls: String = "", var path: String = "",
var sni: String = "", var tls: String = "",
var alpn: String = "", var sni: String = "",
var fp: String = "") var alpn: String = "",
var fp: String = ""
)
@@ -1,8 +1,6 @@
package com.v2ray.ang.extension package com.v2ray.ang.extension
import android.content.Context import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build import android.os.Build
import android.widget.Toast import android.widget.Toast
import com.v2ray.ang.AngApplication import com.v2ray.ang.AngApplication
@@ -35,7 +35,8 @@ class WidgetProvider : AppWidgetProvider() {
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
} else { } else {
PendingIntent.FLAG_UPDATE_CURRENT PendingIntent.FLAG_UPDATE_CURRENT
}) }
)
remoteViews.setOnClickPendingIntent(R.id.layout_switch, pendingIntent) remoteViews.setOnClickPendingIntent(R.id.layout_switch, pendingIntent)
if (isRunning) { if (isRunning) {
remoteViews.setInt(R.id.image_switch, "setImageResource", R.drawable.ic_stop_24dp) remoteViews.setInt(R.id.image_switch, "setImageResource", R.drawable.ic_stop_24dp)
@@ -65,12 +66,17 @@ class WidgetProvider : AppWidgetProvider() {
AppWidgetManager.getInstance(context)?.let { manager -> AppWidgetManager.getInstance(context)?.let { manager ->
when (intent.getIntExtra("key", 0)) { when (intent.getIntExtra("key", 0)) {
AppConfig.MSG_STATE_RUNNING, AppConfig.MSG_STATE_START_SUCCESS -> { AppConfig.MSG_STATE_RUNNING, AppConfig.MSG_STATE_START_SUCCESS -> {
updateWidgetBackground(context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)), updateWidgetBackground(
true) context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)),
true
)
} }
AppConfig.MSG_STATE_NOT_RUNNING, AppConfig.MSG_STATE_START_FAILURE, AppConfig.MSG_STATE_STOP_SUCCESS -> { AppConfig.MSG_STATE_NOT_RUNNING, AppConfig.MSG_STATE_START_FAILURE, AppConfig.MSG_STATE_STOP_SUCCESS -> {
updateWidgetBackground(context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)), updateWidgetBackground(
false) context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)),
false
)
} }
} }
} }
@@ -58,6 +58,7 @@ class QSTileService : TileService() {
Tile.STATE_INACTIVE -> { Tile.STATE_INACTIVE -> {
Utils.startVServiceFromToggle(this) Utils.startVServiceFromToggle(this)
} }
Tile.STATE_ACTIVE -> { Tile.STATE_ACTIVE -> {
Utils.stopVService(this) Utils.stopVService(this)
} }
@@ -74,15 +75,19 @@ class QSTileService : TileService() {
AppConfig.MSG_STATE_RUNNING -> { AppConfig.MSG_STATE_RUNNING -> {
context?.setState(Tile.STATE_ACTIVE) context?.setState(Tile.STATE_ACTIVE)
} }
AppConfig.MSG_STATE_NOT_RUNNING -> { AppConfig.MSG_STATE_NOT_RUNNING -> {
context?.setState(Tile.STATE_INACTIVE) context?.setState(Tile.STATE_INACTIVE)
} }
AppConfig.MSG_STATE_START_SUCCESS -> { AppConfig.MSG_STATE_START_SUCCESS -> {
context?.setState(Tile.STATE_ACTIVE) context?.setState(Tile.STATE_ACTIVE)
} }
AppConfig.MSG_STATE_START_FAILURE -> { AppConfig.MSG_STATE_START_FAILURE -> {
context?.setState(Tile.STATE_INACTIVE) context?.setState(Tile.STATE_INACTIVE)
} }
AppConfig.MSG_STATE_STOP_SUCCESS -> { AppConfig.MSG_STATE_STOP_SUCCESS -> {
context?.setState(Tile.STATE_INACTIVE) context?.setState(Tile.STATE_INACTIVE)
} }
@@ -21,7 +21,6 @@ import com.v2ray.ang.util.Utils
object SubscriptionUpdater { object SubscriptionUpdater {
class UpdateTask(context: Context, params: WorkerParameters) : class UpdateTask(context: Context, params: WorkerParameters) :
CoroutineWorker(context, params) { CoroutineWorker(context, params) {
@@ -49,7 +49,7 @@ class V2RayProxyOnlyService : Service(), ServiceControl {
@RequiresApi(Build.VERSION_CODES.N) @RequiresApi(Build.VERSION_CODES.N)
override fun attachBaseContext(newBase: Context?) { override fun attachBaseContext(newBase: Context?) {
val context = newBase?.let { val context = newBase?.let {
MyContextWrapper.wrap(newBase, Utils.getLocale()) MyContextWrapper.wrap(newBase, Utils.getLocale())
} }
super.attachBaseContext(context) super.attachBaseContext(context)
} }
@@ -27,14 +27,14 @@ import com.v2ray.ang.util.MmkvManager
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
import com.v2ray.ang.util.V2rayConfigUtil import com.v2ray.ang.util.V2rayConfigUtil
import go.Seq import go.Seq
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import libv2ray.Libv2ray import libv2ray.Libv2ray
import libv2ray.V2RayPoint import libv2ray.V2RayPoint
import libv2ray.V2RayVPNServiceSupportsSet import libv2ray.V2RayVPNServiceSupportsSet
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable
import java.lang.ref.SoftReference import java.lang.ref.SoftReference
import kotlin.math.min import kotlin.math.min
@@ -206,18 +206,23 @@ object V2RayServiceManager {
MessageUtil.sendMsg2UI(serviceControl.getService(), AppConfig.MSG_STATE_NOT_RUNNING, "") MessageUtil.sendMsg2UI(serviceControl.getService(), AppConfig.MSG_STATE_NOT_RUNNING, "")
} }
} }
AppConfig.MSG_UNREGISTER_CLIENT -> { AppConfig.MSG_UNREGISTER_CLIENT -> {
// nothing to do // nothing to do
} }
AppConfig.MSG_STATE_START -> { AppConfig.MSG_STATE_START -> {
// nothing to do // nothing to do
} }
AppConfig.MSG_STATE_STOP -> { AppConfig.MSG_STATE_STOP -> {
serviceControl.stopService() serviceControl.stopService()
} }
AppConfig.MSG_STATE_RESTART -> { AppConfig.MSG_STATE_RESTART -> {
startV2rayPoint() startV2rayPoint()
} }
AppConfig.MSG_MEASURE_DELAY -> { AppConfig.MSG_MEASURE_DELAY -> {
measureV2rayDelay() measureV2rayDelay()
} }
@@ -228,6 +233,7 @@ object V2RayServiceManager {
Log.d(ANG_PACKAGE, "SCREEN_OFF, stop querying stats") Log.d(ANG_PACKAGE, "SCREEN_OFF, stop querying stats")
stopSpeedNotification() stopSpeedNotification()
} }
Intent.ACTION_SCREEN_ON -> { Intent.ACTION_SCREEN_ON -> {
Log.d(ANG_PACKAGE, "SCREEN_ON, start querying stats") Log.d(ANG_PACKAGE, "SCREEN_ON, start querying stats")
startSpeedNotification() startSpeedNotification()
@@ -270,46 +276,52 @@ object V2RayServiceManager {
private fun showNotification() { private fun showNotification() {
val service = serviceControl?.get()?.getService() ?: return val service = serviceControl?.get()?.getService() ?: return
val startMainIntent = Intent(service, MainActivity::class.java) val startMainIntent = Intent(service, MainActivity::class.java)
val contentPendingIntent = PendingIntent.getActivity(service, val contentPendingIntent = PendingIntent.getActivity(
NOTIFICATION_PENDING_INTENT_CONTENT, startMainIntent, service,
NOTIFICATION_PENDING_INTENT_CONTENT, startMainIntent,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
} else { } else {
PendingIntent.FLAG_UPDATE_CURRENT PendingIntent.FLAG_UPDATE_CURRENT
}) }
)
val stopV2RayIntent = Intent(AppConfig.BROADCAST_ACTION_SERVICE) val stopV2RayIntent = Intent(AppConfig.BROADCAST_ACTION_SERVICE)
stopV2RayIntent.`package` = ANG_PACKAGE stopV2RayIntent.`package` = ANG_PACKAGE
stopV2RayIntent.putExtra("key", AppConfig.MSG_STATE_STOP) stopV2RayIntent.putExtra("key", AppConfig.MSG_STATE_STOP)
val stopV2RayPendingIntent = PendingIntent.getBroadcast(service, val stopV2RayPendingIntent = PendingIntent.getBroadcast(
NOTIFICATION_PENDING_INTENT_STOP_V2RAY, stopV2RayIntent, service,
NOTIFICATION_PENDING_INTENT_STOP_V2RAY, stopV2RayIntent,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
} else { } else {
PendingIntent.FLAG_UPDATE_CURRENT PendingIntent.FLAG_UPDATE_CURRENT
}) }
)
val channelId = val channelId =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel() createNotificationChannel()
} else { } else {
// If earlier version channel ID is not used // If earlier version channel ID is not used
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context) // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
"" ""
} }
mBuilder = NotificationCompat.Builder(service, channelId) mBuilder = NotificationCompat.Builder(service, channelId)
.setSmallIcon(R.drawable.ic_stat_name) .setSmallIcon(R.drawable.ic_stat_name)
.setContentTitle(currentConfig?.remarks) .setContentTitle(currentConfig?.remarks)
.setPriority(NotificationCompat.PRIORITY_MIN) .setPriority(NotificationCompat.PRIORITY_MIN)
.setOngoing(true) .setOngoing(true)
.setShowWhen(false) .setShowWhen(false)
.setOnlyAlertOnce(true) .setOnlyAlertOnce(true)
.setContentIntent(contentPendingIntent) .setContentIntent(contentPendingIntent)
.addAction(R.drawable.ic_delete_24dp, .addAction(
service.getString(R.string.notification_action_stop_v2ray), R.drawable.ic_delete_24dp,
stopV2RayPendingIntent) service.getString(R.string.notification_action_stop_v2ray),
stopV2RayPendingIntent
)
//.build() //.build()
//mBuilder?.setDefaults(NotificationCompat.FLAG_ONLY_ALERT_ONCE) //取消震动,铃声其他都不好使 //mBuilder?.setDefaults(NotificationCompat.FLAG_ONLY_ALERT_ONCE) //取消震动,铃声其他都不好使
@@ -321,8 +333,10 @@ object V2RayServiceManager {
private fun createNotificationChannel(): String { private fun createNotificationChannel(): String {
val channelId = AppConfig.RAY_NG_CHANNEL_ID val channelId = AppConfig.RAY_NG_CHANNEL_ID
val channelName = AppConfig.RAY_NG_CHANNEL_NAME val channelName = AppConfig.RAY_NG_CHANNEL_NAME
val chan = NotificationChannel(channelId, val chan = NotificationChannel(
channelName, NotificationManager.IMPORTANCE_HIGH) channelId,
channelName, NotificationManager.IMPORTANCE_HIGH
)
chan.lightColor = Color.DKGRAY chan.lightColor = Color.DKGRAY
chan.importance = NotificationManager.IMPORTANCE_NONE chan.importance = NotificationManager.IMPORTANCE_NONE
chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
@@ -363,40 +377,43 @@ object V2RayServiceManager {
private fun startSpeedNotification() { private fun startSpeedNotification() {
if (mDisposable == null && if (mDisposable == null &&
v2rayPoint.isRunning && v2rayPoint.isRunning &&
settingsStorage?.decodeBool(AppConfig.PREF_SPEED_ENABLED) == true) { settingsStorage?.decodeBool(AppConfig.PREF_SPEED_ENABLED) == true
) {
var lastZeroSpeed = false var lastZeroSpeed = false
val outboundTags = currentConfig?.getAllOutboundTags() val outboundTags = currentConfig?.getAllOutboundTags()
outboundTags?.remove(TAG_DIRECT) outboundTags?.remove(TAG_DIRECT)
mDisposable = Observable.interval(3, java.util.concurrent.TimeUnit.SECONDS) mDisposable = Observable.interval(3, java.util.concurrent.TimeUnit.SECONDS)
.subscribe { .subscribe {
val queryTime = System.currentTimeMillis() val queryTime = System.currentTimeMillis()
val sinceLastQueryInSeconds = (queryTime - lastQueryTime) / 1000.0 val sinceLastQueryInSeconds = (queryTime - lastQueryTime) / 1000.0
var proxyTotal = 0L var proxyTotal = 0L
val text = StringBuilder() val text = StringBuilder()
outboundTags?.forEach { outboundTags?.forEach {
val up = v2rayPoint.queryStats(it, AppConfig.UPLINK) val up = v2rayPoint.queryStats(it, AppConfig.UPLINK)
val down = v2rayPoint.queryStats(it, AppConfig.DOWNLINK) val down = v2rayPoint.queryStats(it, AppConfig.DOWNLINK)
if (up + down > 0) { if (up + down > 0) {
appendSpeedString(text, it, up / sinceLastQueryInSeconds, down / sinceLastQueryInSeconds) appendSpeedString(text, it, up / sinceLastQueryInSeconds, down / sinceLastQueryInSeconds)
proxyTotal += up + down proxyTotal += up + down
}
} }
val directUplink = v2rayPoint.queryStats(TAG_DIRECT, AppConfig.UPLINK)
val directDownlink = v2rayPoint.queryStats(TAG_DIRECT, AppConfig.DOWNLINK)
val zeroSpeed = proxyTotal == 0L && directUplink == 0L && directDownlink == 0L
if (!zeroSpeed || !lastZeroSpeed) {
if (proxyTotal == 0L) {
appendSpeedString(text, outboundTags?.firstOrNull(), 0.0, 0.0)
}
appendSpeedString(text, TAG_DIRECT, directUplink / sinceLastQueryInSeconds,
directDownlink / sinceLastQueryInSeconds)
updateNotification(text.toString(), proxyTotal, directDownlink + directUplink)
}
lastZeroSpeed = zeroSpeed
lastQueryTime = queryTime
} }
val directUplink = v2rayPoint.queryStats(TAG_DIRECT, AppConfig.UPLINK)
val directDownlink = v2rayPoint.queryStats(TAG_DIRECT, AppConfig.DOWNLINK)
val zeroSpeed = proxyTotal == 0L && directUplink == 0L && directDownlink == 0L
if (!zeroSpeed || !lastZeroSpeed) {
if (proxyTotal == 0L) {
appendSpeedString(text, outboundTags?.firstOrNull(), 0.0, 0.0)
}
appendSpeedString(
text, TAG_DIRECT, directUplink / sinceLastQueryInSeconds,
directDownlink / sinceLastQueryInSeconds
)
updateNotification(text.toString(), proxyTotal, directDownlink + directUplink)
}
lastZeroSpeed = zeroSpeed
lastQueryTime = queryTime
}
} }
} }
@@ -10,7 +10,11 @@ import com.v2ray.ang.util.MessageUtil
import com.v2ray.ang.util.SpeedtestUtil import com.v2ray.ang.util.SpeedtestUtil
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
import go.Seq import go.Seq
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.launch
import libv2ray.Libv2ray import libv2ray.Libv2ray
import java.util.concurrent.Executors import java.util.concurrent.Executors
@@ -32,6 +36,7 @@ class V2RayTestService : Service() {
MessageUtil.sendMsg2UI(this@V2RayTestService, MSG_MEASURE_CONFIG_SUCCESS, Pair(contentPair.first, result)) MessageUtil.sendMsg2UI(this@V2RayTestService, MSG_MEASURE_CONFIG_SUCCESS, Pair(contentPair.first, result))
} }
} }
MSG_MEASURE_CONFIG_CANCEL -> { MSG_MEASURE_CONFIG_CANCEL -> {
realTestScope.coroutineContext[Job]?.cancelChildren() realTestScope.coroutineContext[Job]?.cancelChildren()
} }
@@ -4,7 +4,13 @@ import android.app.Service
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.net.* import android.net.ConnectivityManager
import android.net.LocalSocket
import android.net.LocalSocketAddress
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.net.VpnService
import android.os.Build import android.os.Build
import android.os.ParcelFileDescriptor import android.os.ParcelFileDescriptor
import android.os.StrictMode import android.os.StrictMode
@@ -19,7 +25,6 @@ import com.v2ray.ang.util.MyContextWrapper
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File import java.io.File
import java.lang.ref.SoftReference import java.lang.ref.SoftReference
@@ -54,9 +59,9 @@ class V2RayVpnService : VpnService(), ServiceControl {
@delegate:RequiresApi(Build.VERSION_CODES.P) @delegate:RequiresApi(Build.VERSION_CODES.P)
private val defaultNetworkRequest by lazy { private val defaultNetworkRequest by lazy {
NetworkRequest.Builder() NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.build() .build()
} }
private val connectivity by lazy { getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager } private val connectivity by lazy { getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager }
@@ -140,11 +145,11 @@ class V2RayVpnService : VpnService(), ServiceControl {
builder.addDnsServer(PRIVATE_VLAN4_ROUTER) builder.addDnsServer(PRIVATE_VLAN4_ROUTER)
} else { } else {
Utils.getVpnDnsServers() Utils.getVpnDnsServers()
.forEach { .forEach {
if (Utils.isPureIpAddress(it)) { if (Utils.isPureIpAddress(it)) {
builder.addDnsServer(it) builder.addDnsServer(it)
}
} }
}
} }
builder.setSession(V2RayServiceManager.currentConfig?.remarks.orEmpty()) builder.setSession(V2RayServiceManager.currentConfig?.remarks.orEmpty())
@@ -197,14 +202,16 @@ class V2RayVpnService : VpnService(), ServiceControl {
private fun runTun2socks() { private fun runTun2socks() {
val socksPort = Utils.parseInt(settingsStorage?.decodeString(AppConfig.PREF_SOCKS_PORT), AppConfig.PORT_SOCKS.toInt()) val socksPort = Utils.parseInt(settingsStorage?.decodeString(AppConfig.PREF_SOCKS_PORT), AppConfig.PORT_SOCKS.toInt())
val cmd = arrayListOf(File(applicationContext.applicationInfo.nativeLibraryDir, TUN2SOCKS).absolutePath, val cmd = arrayListOf(
"--netif-ipaddr", PRIVATE_VLAN4_ROUTER, File(applicationContext.applicationInfo.nativeLibraryDir, TUN2SOCKS).absolutePath,
"--netif-netmask", "255.255.255.252", "--netif-ipaddr", PRIVATE_VLAN4_ROUTER,
"--socks-server-addr", "127.0.0.1:${socksPort}", "--netif-netmask", "255.255.255.252",
"--tunmtu", VPN_MTU.toString(), "--socks-server-addr", "127.0.0.1:${socksPort}",
"--sock-path", "sock_path",//File(applicationContext.filesDir, "sock_path").absolutePath, "--tunmtu", VPN_MTU.toString(),
"--enable-udprelay", "--sock-path", "sock_path",//File(applicationContext.filesDir, "sock_path").absolutePath,
"--loglevel", "notice") "--enable-udprelay",
"--loglevel", "notice"
)
if (settingsStorage?.decodeBool(AppConfig.PREF_PREFER_IPV6) == true) { if (settingsStorage?.decodeBool(AppConfig.PREF_PREFER_IPV6) == true) {
cmd.add("--netif-ip6addr") cmd.add("--netif-ip6addr")
@@ -221,14 +228,14 @@ class V2RayVpnService : VpnService(), ServiceControl {
val proBuilder = ProcessBuilder(cmd) val proBuilder = ProcessBuilder(cmd)
proBuilder.redirectErrorStream(true) proBuilder.redirectErrorStream(true)
process = proBuilder process = proBuilder
.directory(applicationContext.filesDir) .directory(applicationContext.filesDir)
.start() .start()
Thread(Runnable { Thread(Runnable {
Log.d(packageName,"$TUN2SOCKS check") Log.d(packageName, "$TUN2SOCKS check")
process.waitFor() process.waitFor()
Log.d(packageName,"$TUN2SOCKS exited") Log.d(packageName, "$TUN2SOCKS exited")
if (isRunning) { if (isRunning) {
Log.d(packageName,"$TUN2SOCKS restart") Log.d(packageName, "$TUN2SOCKS restart")
runTun2socks() runTun2socks()
} }
}).start() }).start()
@@ -275,7 +282,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
// val emptyInfo = VpnNetworkInfo() // val emptyInfo = VpnNetworkInfo()
// val info = loadVpnNetworkInfo(configName, emptyInfo)!! + (lastNetworkInfo ?: emptyInfo) // val info = loadVpnNetworkInfo(configName, emptyInfo)!! + (lastNetworkInfo ?: emptyInfo)
// saveVpnNetworkInfo(configName, info) // saveVpnNetworkInfo(configName, info)
isRunning = false; isRunning = false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
try { try {
connectivity.unregisterNetworkCallback(defaultNetworkCallback) connectivity.unregisterNetworkCallback(defaultNetworkCallback)
@@ -328,7 +335,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
@RequiresApi(Build.VERSION_CODES.N) @RequiresApi(Build.VERSION_CODES.N)
override fun attachBaseContext(newBase: Context?) { override fun attachBaseContext(newBase: Context?) {
val context = newBase?.let { val context = newBase?.let {
MyContextWrapper.wrap(newBase, Utils.getLocale()) MyContextWrapper.wrap(newBase, Utils.getLocale())
} }
super.attachBaseContext(context) super.attachBaseContext(context)
} }
@@ -21,7 +21,7 @@ import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
class AboutActivity : BaseActivity() { class AboutActivity : BaseActivity() {
private val binding by lazy {ActivityAboutBinding.inflate(layoutInflater)} private val binding by lazy { ActivityAboutBinding.inflate(layoutInflater) }
private val extDir by lazy { File(Utils.backupPath(this)) } private val extDir by lazy { File(Utils.backupPath(this)) }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -28,13 +28,14 @@ abstract class BaseActivity : AppCompatActivity() {
onBackPressedDispatcher.onBackPressed() onBackPressedDispatcher.onBackPressed()
true true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
@RequiresApi(Build.VERSION_CODES.N) @RequiresApi(Build.VERSION_CODES.N)
override fun attachBaseContext(newBase: Context?) { override fun attachBaseContext(newBase: Context?) {
val context = newBase?.let { val context = newBase?.let {
MyContextWrapper.wrap(newBase, Utils.getLocale()) MyContextWrapper.wrap(newBase, Utils.getLocale())
} }
super.attachBaseContext(context) super.attachBaseContext(context)
} }
@@ -5,7 +5,7 @@ import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
class FragmentAdapter(fragmentActivity: FragmentActivity, private val mFragments: List<Fragment>) : class FragmentAdapter(fragmentActivity: FragmentActivity, private val mFragments: List<Fragment>) :
FragmentStateAdapter(fragmentActivity) { FragmentStateAdapter(fragmentActivity) {
override fun createFragment(position: Int): Fragment { override fun createFragment(position: Int): Fragment {
return mFragments[position] return mFragments[position]
@@ -84,10 +84,12 @@ class LogcatActivity : BaseActivity() {
toast(R.string.toast_success) toast(R.string.toast_success)
true true
} }
R.id.clear_all -> { R.id.clear_all -> {
logcat(true) logcat(true)
true true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
} }
@@ -32,7 +32,6 @@ import com.v2ray.ang.AppConfig
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.databinding.ActivityMainBinding import com.v2ray.ang.databinding.ActivityMainBinding
import com.v2ray.ang.dto.EConfigType import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.extension.isNetworkConnected
import com.v2ray.ang.extension.toast import com.v2ray.ang.extension.toast
import com.v2ray.ang.helper.SimpleItemTouchHelperCallback import com.v2ray.ang.helper.SimpleItemTouchHelperCallback
import com.v2ray.ang.service.V2RayServiceManager import com.v2ray.ang.service.V2RayServiceManager
@@ -29,8 +29,7 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Observable
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<MainRecyclerAdapter.BaseViewHolder>() class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<MainRecyclerAdapter.BaseViewHolder>(), ItemTouchHelperAdapter {
, ItemTouchHelperAdapter {
companion object { companion object {
private const val VIEW_TYPE_ITEM = 1 private const val VIEW_TYPE_ITEM = 1
private const val VIEW_TYPE_FOOTER = 2 private const val VIEW_TYPE_FOOTER = 2
@@ -95,7 +94,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
} }
} }
val strState = "${profile?.server?.dropLast(3)}*** : ${profile?.serverPort}" val strState = "${profile.server?.dropLast(3)}*** : ${profile.serverPort}"
holder.itemMainBinding.tvStatistics.text = strState holder.itemMainBinding.tvStatistics.text = strState
@@ -21,10 +21,10 @@ import com.v2ray.ang.extension.v2RayApplication
import com.v2ray.ang.util.AppManagerUtil import com.v2ray.ang.util.AppManagerUtil
import com.v2ray.ang.util.MmkvManager import com.v2ray.ang.util.MmkvManager
import com.v2ray.ang.util.Utils import com.v2ray.ang.util.Utils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.text.Collator import java.text.Collator
class PerAppProxyActivity : BaseActivity() { class PerAppProxyActivity : BaseActivity() {
@@ -46,32 +46,32 @@ class PerAppProxyActivity : BaseActivity() {
val blacklist = settingsStorage?.decodeStringSet(AppConfig.PREF_PER_APP_PROXY_SET) val blacklist = settingsStorage?.decodeStringSet(AppConfig.PREF_PER_APP_PROXY_SET)
AppManagerUtil.rxLoadNetworkAppList(this) AppManagerUtil.rxLoadNetworkAppList(this)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.map { .map {
if (blacklist != null) { if (blacklist != null) {
it.forEach { one -> it.forEach { one ->
if (blacklist.contains(one.packageName)) { if (blacklist.contains(one.packageName)) {
one.isSelected = 1 one.isSelected = 1
} else { } else {
one.isSelected = 0 one.isSelected = 0
}
} }
val comparator = Comparator<AppInfo> { p1, p2 ->
when {
p1.isSelected > p2.isSelected -> -1
p1.isSelected == p2.isSelected -> 0
else -> 1
}
}
it.sortedWith(comparator)
} else {
val comparator = object : Comparator<AppInfo> {
val collator = Collator.getInstance()
override fun compare(o1: AppInfo, o2: AppInfo) = collator.compare(o1.appName, o2.appName)
}
it.sortedWith(comparator)
} }
val comparator = Comparator<AppInfo> { p1, p2 ->
when {
p1.isSelected > p2.isSelected -> -1
p1.isSelected == p2.isSelected -> 0
else -> 1
}
}
it.sortedWith(comparator)
} else {
val comparator = object : Comparator<AppInfo> {
val collator = Collator.getInstance()
override fun compare(o1: AppInfo, o2: AppInfo) = collator.compare(o1.appName, o2.appName)
}
it.sortedWith(comparator)
} }
}
// .map { // .map {
// val comparator = object : Comparator<AppInfo> { // val comparator = object : Comparator<AppInfo> {
// val collator = Collator.getInstance() // val collator = Collator.getInstance()
@@ -79,13 +79,13 @@ class PerAppProxyActivity : BaseActivity() {
// } // }
// it.sortedWith(comparator) // it.sortedWith(comparator)
// } // }
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { .subscribe {
appsAll = it appsAll = it
adapter = PerAppProxyAdapter(this, it, blacklist) adapter = PerAppProxyAdapter(this, it, blacklist)
binding.recyclerView.adapter = adapter binding.recyclerView.adapter = adapter
binding.pbWaiting.visibility = View.GONE binding.pbWaiting.visibility = View.GONE
} }
/*** /***
recycler_view.addOnScrollListener(object : RecyclerView.OnScrollListener() { recycler_view.addOnScrollListener(object : RecyclerView.OnScrollListener() {
var dst = 0 var dst = 0
@@ -218,18 +218,22 @@ class PerAppProxyActivity : BaseActivity() {
it.notifyDataSetChanged() it.notifyDataSetChanged()
true true
} ?: false } ?: false
R.id.select_proxy_app -> { R.id.select_proxy_app -> {
selectProxyApp() selectProxyApp()
true true
} }
R.id.import_proxy_app -> { R.id.import_proxy_app -> {
importProxyApp() importProxyApp()
true true
} }
R.id.export_proxy_app -> { R.id.export_proxy_app -> {
exportProxyApp() exportProxyApp()
true true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
@@ -324,7 +328,8 @@ class PerAppProxyActivity : BaseActivity() {
if (key.isNotEmpty()) { if (key.isNotEmpty()) {
appsAll?.forEach { appsAll?.forEach {
if (it.appName.uppercase().indexOf(key) >= 0 if (it.appName.uppercase().indexOf(key) >= 0
|| it.packageName.uppercase().indexOf(key) >= 0) { || it.packageName.uppercase().indexOf(key) >= 0
) {
apps.add(it) apps.add(it)
} }
} }
@@ -1,16 +1,15 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import android.view.LayoutInflater import android.view.LayoutInflater
import androidx.recyclerview.widget.RecyclerView
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.databinding.ItemRecyclerBypassListBinding import com.v2ray.ang.databinding.ItemRecyclerBypassListBinding
import com.v2ray.ang.dto.AppInfo import com.v2ray.ang.dto.AppInfo
import java.util.*
class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, blacklist: MutableSet<String>?) : class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, blacklist: MutableSet<String>?) :
RecyclerView.Adapter<PerAppProxyAdapter.BaseViewHolder>() { RecyclerView.Adapter<PerAppProxyAdapter.BaseViewHolder>() {
companion object { companion object {
private const val VIEW_TYPE_HEADER = 0 private const val VIEW_TYPE_HEADER = 0
@@ -34,8 +33,10 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, bl
return when (viewType) { return when (viewType) {
VIEW_TYPE_HEADER -> { VIEW_TYPE_HEADER -> {
val view = View(ctx) val view = View(ctx)
view.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, view.layoutParams = ViewGroup.LayoutParams(
ctx.resources.getDimensionPixelSize(R.dimen.bypass_list_header_height) * 0) ViewGroup.LayoutParams.MATCH_PARENT,
ctx.resources.getDimensionPixelSize(R.dimen.bypass_list_header_height) * 0
)
BaseViewHolder(view) BaseViewHolder(view)
} }
// VIEW_TYPE_ITEM -> AppViewHolder(ctx.layoutInflater // VIEW_TYPE_ITEM -> AppViewHolder(ctx.layoutInflater
@@ -51,7 +52,7 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, bl
open class BaseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) open class BaseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
inner class AppViewHolder(private val itemBypassBinding: ItemRecyclerBypassListBinding) : BaseViewHolder(itemBypassBinding.root), inner class AppViewHolder(private val itemBypassBinding: ItemRecyclerBypassListBinding) : BaseViewHolder(itemBypassBinding.root),
View.OnClickListener { View.OnClickListener {
private val inBlacklist: Boolean get() = blacklist.contains(appInfo.packageName) private val inBlacklist: Boolean get() = blacklist.contains(appInfo.packageName)
private lateinit var appInfo: AppInfo private lateinit var appInfo: AppInfo
@@ -1,10 +1,10 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import android.os.Bundle import android.os.Bundle
import com.v2ray.ang.R
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import com.v2ray.ang.AppConfig import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
import com.v2ray.ang.databinding.ActivityRoutingSettingsBinding import com.v2ray.ang.databinding.ActivityRoutingSettingsBinding
class RoutingSettingsActivity : BaseActivity() { class RoutingSettingsActivity : BaseActivity() {
@@ -1,15 +1,19 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import android.Manifest import android.Manifest
import androidx.appcompat.app.AppCompatActivity.RESULT_OK
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import android.view.* import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity.RESULT_OK
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.preference.PreferenceManager
import com.tbruyelle.rxpermissions3.RxPermissions import com.tbruyelle.rxpermissions3.RxPermissions
import com.tencent.mmkv.MMKV import com.tencent.mmkv.MMKV
import com.v2ray.ang.AppConfig import com.v2ray.ang.AppConfig
@@ -24,14 +28,17 @@ import kotlinx.coroutines.launch
class RoutingSettingsFragment : Fragment() { class RoutingSettingsFragment : Fragment() {
private val binding by lazy { FragmentRoutingSettingsBinding.inflate(layoutInflater) } private val binding by lazy { FragmentRoutingSettingsBinding.inflate(layoutInflater) }
companion object { companion object {
private const val routing_arg = "routing_arg" private const val routing_arg = "routing_arg"
} }
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) }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(
savedInstanceState: Bundle?): View? { inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment // Inflate the layout for this fragment
return binding.root// inflater.inflate(R.layout.fragment_routing_settings, container, false) return binding.root// inflater.inflate(R.layout.fragment_routing_settings, container, false)
} }
@@ -63,22 +70,27 @@ class RoutingSettingsFragment : Fragment() {
saveRouting() saveRouting()
true true
} }
R.id.del_routing -> { R.id.del_routing -> {
binding.etRoutingContent.text = null binding.etRoutingContent.text = null
true true
} }
R.id.scan_replace -> { R.id.scan_replace -> {
scanQRcode(true) scanQRcode(true)
true true
} }
R.id.scan_append -> { R.id.scan_append -> {
scanQRcode(false) scanQRcode(false)
true true
} }
R.id.default_rules -> { R.id.default_rules -> {
setDefaultRules() setDefaultRules()
true true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
@@ -95,16 +107,16 @@ class RoutingSettingsFragment : Fragment() {
// .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP), requestCode) // .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP), requestCode)
// } catch (e: Exception) { // } catch (e: Exception) {
RxPermissions(requireActivity()) RxPermissions(requireActivity())
.request(Manifest.permission.CAMERA) .request(Manifest.permission.CAMERA)
.subscribe { .subscribe {
if (it) if (it)
if (forReplace) if (forReplace)
scanQRCodeForReplace.launch(Intent(activity, ScannerActivity::class.java)) scanQRCodeForReplace.launch(Intent(activity, ScannerActivity::class.java))
else
scanQRCodeForAppend.launch(Intent(activity, ScannerActivity::class.java))
else else
activity?.toast(R.string.toast_permission_denied) scanQRCodeForAppend.launch(Intent(activity, ScannerActivity::class.java))
} else
activity?.toast(R.string.toast_permission_denied)
}
// } // }
return true return true
} }
@@ -130,9 +142,11 @@ class RoutingSettingsFragment : Fragment() {
AppConfig.PREF_V2RAY_ROUTING_AGENT -> { AppConfig.PREF_V2RAY_ROUTING_AGENT -> {
tag = AppConfig.TAG_PROXY tag = AppConfig.TAG_PROXY
} }
AppConfig.PREF_V2RAY_ROUTING_DIRECT -> { AppConfig.PREF_V2RAY_ROUTING_DIRECT -> {
tag = AppConfig.TAG_DIRECT tag = AppConfig.TAG_DIRECT
} }
AppConfig.PREF_V2RAY_ROUTING_BLOCKED -> { AppConfig.PREF_V2RAY_ROUTING_BLOCKED -> {
tag = AppConfig.TAG_BLOCKED tag = AppConfig.TAG_BLOCKED
} }
@@ -19,13 +19,13 @@ class ScScannerActivity : BaseActivity() {
fun importQRcode(): Boolean { fun importQRcode(): Boolean {
RxPermissions(this) RxPermissions(this)
.request(Manifest.permission.CAMERA) .request(Manifest.permission.CAMERA)
.subscribe { .subscribe {
if (it) if (it)
scanQRCode.launch(Intent(this, ScannerActivity::class.java)) scanQRCode.launch(Intent(this, ScannerActivity::class.java))
else else
toast(R.string.toast_permission_denied) toast(R.string.toast_permission_denied)
} }
return true return true
} }
@@ -1,9 +1,9 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import com.v2ray.ang.R
import com.v2ray.ang.util.Utils
import android.os.Bundle import android.os.Bundle
import com.v2ray.ang.R
import com.v2ray.ang.service.V2RayServiceManager import com.v2ray.ang.service.V2RayServiceManager
import com.v2ray.ang.util.Utils
class ScSwitchActivity : BaseActivity() { class ScSwitchActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -1,11 +1,10 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import android.Manifest import android.Manifest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.content.Intent import android.content.Intent
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.os.Build import android.os.Build
import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
@@ -20,7 +19,7 @@ import io.github.g00fy2.quickie.QRResult
import io.github.g00fy2.quickie.ScanCustomCode import io.github.g00fy2.quickie.ScanCustomCode
import io.github.g00fy2.quickie.config.ScannerConfig import io.github.g00fy2.quickie.config.ScannerConfig
class ScannerActivity : BaseActivity(){ class ScannerActivity : BaseActivity() {
private val scanQrCode = registerForActivityResult(ScanCustomCode(), ::handleResult) private val scanQrCode = registerForActivityResult(ScanCustomCode(), ::handleResult)
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) }
@@ -33,7 +32,7 @@ class ScannerActivity : BaseActivity(){
} }
} }
private fun launchScan(){ private fun launchScan() {
scanQrCode.launch( scanQrCode.launch(
ScannerConfig.build { ScannerConfig.build {
setHapticSuccessFeedback(true) // enable (default) or disable haptic feedback when a barcode was detected setHapticSuccessFeedback(true) // enable (default) or disable haptic feedback when a barcode was detected
@@ -44,7 +43,7 @@ class ScannerActivity : BaseActivity(){
} }
private fun handleResult(result: QRResult) { private fun handleResult(result: QRResult) {
if (result is QRResult.QRSuccess ) { if (result is QRResult.QRSuccess) {
finished(result.content.rawValue.orEmpty()) finished(result.content.rawValue.orEmpty())
} else { } else {
finish() finish()
@@ -54,7 +53,7 @@ class ScannerActivity : BaseActivity(){
private fun finished(text: String) { private fun finished(text: String) {
val intent = Intent() val intent = Intent()
intent.putExtra("SCAN_RESULT", text) intent.putExtra("SCAN_RESULT", text)
setResult(AppCompatActivity.RESULT_OK, intent) setResult(RESULT_OK, intent)
finish() finish()
} }
@@ -68,6 +67,7 @@ class ScannerActivity : BaseActivity(){
launchScan() launchScan()
true true
} }
R.id.select_photo -> { R.id.select_photo -> {
val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Manifest.permission.READ_MEDIA_IMAGES Manifest.permission.READ_MEDIA_IMAGES
@@ -88,6 +88,7 @@ class ScannerActivity : BaseActivity(){
} }
true true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
@@ -533,16 +533,16 @@ class ServerActivity : BaseActivity() {
val spiderX = et_spider_x?.text?.toString()?.trim() ?: return val spiderX = et_spider_x?.text?.toString()?.trim() ?: return
var sni = streamSetting.populateTransportSettings( var sni = streamSetting.populateTransportSettings(
transport = networks[network], transport = networks[network],
headerType = transportTypes(networks[network])[type], headerType = transportTypes(networks[network])[type],
host = requestHost, host = requestHost,
path = path, path = path,
seed = path, seed = path,
quicSecurity = requestHost, quicSecurity = requestHost,
key = path, key = path,
mode = transportTypes(networks[network])[type], mode = transportTypes(networks[network])[type],
serviceName = path, serviceName = path,
authority = requestHost, authority = requestHost,
) )
if (sniField.isNotBlank()) { if (sniField.isNotBlank()) {
sni = sniField sni = sniField
@@ -105,14 +105,14 @@ class ServerCustomConfigActivity : BaseActivity() {
private fun deleteServer(): Boolean { private fun deleteServer(): Boolean {
if (editGuid.isNotEmpty()) { if (editGuid.isNotEmpty()) {
AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm) AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
.setPositiveButton(android.R.string.ok) { _, _ -> .setPositiveButton(android.R.string.ok) { _, _ ->
MmkvManager.removeServer(editGuid) MmkvManager.removeServer(editGuid)
finish() finish()
} }
.setNegativeButton(android.R.string.no) {_, _ -> .setNegativeButton(android.R.string.no) { _, _ ->
// do nothing // do nothing
} }
.show() .show()
} }
return true return true
} }
@@ -139,10 +139,12 @@ class ServerCustomConfigActivity : BaseActivity() {
deleteServer() deleteServer()
true true
} }
R.id.save_config -> { R.id.save_config -> {
saveServer() saveServer()
true true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
} }
@@ -184,7 +184,7 @@ class SettingsActivity : BaseActivity() {
localDns?.isChecked = settingsStorage.getBoolean(AppConfig.PREF_LOCAL_DNS_ENABLED, false) localDns?.isChecked = settingsStorage.getBoolean(AppConfig.PREF_LOCAL_DNS_ENABLED, false)
fakeDns?.isChecked = settingsStorage.getBoolean(AppConfig.PREF_FAKE_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) localDnsPort?.summary = settingsStorage.decodeString(AppConfig.PREF_LOCAL_DNS_PORT, AppConfig.PORT_LOCAL_DNS)
vpnDns?.summary = settingsStorage.decodeString(AppConfig.PREF_VPN_DNS, AppConfig.DNS_VPN) vpnDns?.summary = settingsStorage.decodeString(AppConfig.PREF_VPN_DNS, AppConfig.DNS_VPN)
updateMux(settingsStorage.getBoolean(AppConfig.PREF_MUX_ENABLED, false)) updateMux(settingsStorage.getBoolean(AppConfig.PREF_MUX_ENABLED, false))
mux?.isChecked = settingsStorage.getBoolean(AppConfig.PREF_MUX_ENABLED, false) mux?.isChecked = settingsStorage.getBoolean(AppConfig.PREF_MUX_ENABLED, false)
@@ -198,7 +198,8 @@ class SettingsActivity : BaseActivity() {
fragmentInterval?.summary = settingsStorage.decodeString(AppConfig.PREF_FRAGMENT_INTERVAL, "10-20") fragmentInterval?.summary = settingsStorage.decodeString(AppConfig.PREF_FRAGMENT_INTERVAL, "10-20")
autoUpdateCheck?.isChecked = settingsStorage.getBoolean(AppConfig.SUBSCRIPTION_AUTO_UPDATE, false) autoUpdateCheck?.isChecked = settingsStorage.getBoolean(AppConfig.SUBSCRIPTION_AUTO_UPDATE, false)
autoUpdateInterval?.summary = settingsStorage.decodeString(AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL,AppConfig.SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL) autoUpdateInterval?.summary =
settingsStorage.decodeString(AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL, AppConfig.SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL)
autoUpdateInterval?.isEnabled = settingsStorage.getBoolean(AppConfig.SUBSCRIPTION_AUTO_UPDATE, false) autoUpdateInterval?.isEnabled = settingsStorage.getBoolean(AppConfig.SUBSCRIPTION_AUTO_UPDATE, false)
socksPort?.summary = settingsStorage.decodeString(AppConfig.PREF_SOCKS_PORT, AppConfig.PORT_SOCKS) socksPort?.summary = settingsStorage.decodeString(AppConfig.PREF_SOCKS_PORT, AppConfig.PORT_SOCKS)
@@ -350,12 +351,15 @@ class SettingsActivity : BaseActivity() {
updateFragmentInterval(settingsStorage.decodeString(AppConfig.PREF_FRAGMENT_INTERVAL, "10-20")) updateFragmentInterval(settingsStorage.decodeString(AppConfig.PREF_FRAGMENT_INTERVAL, "10-20"))
} }
} }
private fun updateFragmentPackets(value: String?) { private fun updateFragmentPackets(value: String?) {
fragmentPackets?.summary = value.toString() fragmentPackets?.summary = value.toString()
} }
private fun updateFragmentLength(value: String?) { private fun updateFragmentLength(value: String?) {
fragmentLength?.summary = value.toString() fragmentLength?.summary = value.toString()
} }
private fun updateFragmentInterval(value: String?) { private fun updateFragmentInterval(value: String?) {
fragmentInterval?.summary = value.toString() fragmentInterval?.summary = value.toString()
} }
@@ -18,7 +18,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
class SubEditActivity : BaseActivity() { class SubEditActivity : BaseActivity() {
private val binding by lazy {ActivitySubEditBinding.inflate(layoutInflater)} private val binding by lazy { ActivitySubEditBinding.inflate(layoutInflater) }
var del_config: MenuItem? = null var del_config: MenuItem? = null
var save_config: MenuItem? = null var save_config: MenuItem? = null
@@ -100,18 +100,18 @@ class SubEditActivity : BaseActivity() {
private fun deleteServer(): Boolean { private fun deleteServer(): Boolean {
if (editSubId.isNotEmpty()) { if (editSubId.isNotEmpty()) {
AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm) AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
.setPositiveButton(android.R.string.ok) { _, _ -> .setPositiveButton(android.R.string.ok) { _, _ ->
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
MmkvManager.removeSubscription(editSubId) MmkvManager.removeSubscription(editSubId)
launch(Dispatchers.Main) { launch(Dispatchers.Main) {
finish() finish()
}
} }
} }
.setNegativeButton(android.R.string.no) {_, _ -> }
// do nothing .setNegativeButton(android.R.string.no) { _, _ ->
} // do nothing
.show() }
.show()
} }
return true return true
} }
@@ -133,10 +133,12 @@ class SubEditActivity : BaseActivity() {
deleteServer() deleteServer()
true true
} }
R.id.save_config -> { R.id.save_config -> {
saveServer() saveServer()
true true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
@@ -1,18 +1,16 @@
package com.v2ray.ang.ui package com.v2ray.ang.ui
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.ArrayAdapter
import android.widget.ListView
import java.util.ArrayList
import com.v2ray.ang.R
import android.content.Intent import android.content.Intent
import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import android.widget.ArrayAdapter
import android.widget.ListView
import com.tencent.mmkv.MMKV import com.tencent.mmkv.MMKV
import com.v2ray.ang.AppConfig import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
import com.v2ray.ang.databinding.ActivityTaskerBinding import com.v2ray.ang.databinding.ActivityTaskerBinding
import com.v2ray.ang.util.MmkvManager import com.v2ray.ang.util.MmkvManager
@@ -39,8 +37,10 @@ class TaskerActivity : BaseActivity() {
lstGuid.add(key) lstGuid.add(key)
} }
} }
val adapter = ArrayAdapter(this, val adapter = ArrayAdapter(
android.R.layout.simple_list_item_single_choice, lstData) this,
android.R.layout.simple_list_item_single_choice, lstData
)
listview = findViewById<View>(R.id.listview) as ListView listview = findViewById<View>(R.id.listview) as ListView
listview?.adapter = adapter listview?.adapter = adapter
@@ -88,7 +88,7 @@ class TaskerActivity : BaseActivity() {
intent.putExtra(AppConfig.TASKER_EXTRA_BUNDLE, extraBundle) intent.putExtra(AppConfig.TASKER_EXTRA_BUNDLE, extraBundle)
intent.putExtra(AppConfig.TASKER_EXTRA_STRING_BLURB, blurb) intent.putExtra(AppConfig.TASKER_EXTRA_STRING_BLURB, blurb)
setResult(AppCompatActivity.RESULT_OK, intent) setResult(RESULT_OK, intent)
finish() finish()
} }
@@ -103,10 +103,12 @@ class TaskerActivity : BaseActivity() {
R.id.del_config -> { R.id.del_config -> {
true true
} }
R.id.save_config -> { R.id.save_config -> {
confirmFinish() confirmFinish()
true true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
@@ -83,6 +83,7 @@ class UserAssetActivity : BaseActivity() {
startActivity(intent) startActivity(intent)
true true
} }
R.id.download_file -> { R.id.download_file -> {
downloadGeoFiles() downloadGeoFiles()
true true
@@ -100,24 +101,24 @@ class UserAssetActivity : BaseActivity() {
RxPermissions(this) RxPermissions(this)
.request(permission) .request(permission)
.subscribe { .subscribe {
if (it) { if (it) {
val intent = Intent(Intent.ACTION_GET_CONTENT) val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "*/*" intent.type = "*/*"
intent.addCategory(Intent.CATEGORY_OPENABLE) intent.addCategory(Intent.CATEGORY_OPENABLE)
try { try {
chooseFile.launch( chooseFile.launch(
Intent.createChooser( Intent.createChooser(
intent, intent,
getString(R.string.title_file_chooser) getString(R.string.title_file_chooser)
)
) )
) } catch (ex: android.content.ActivityNotFoundException) {
} catch (ex: android.content.ActivityNotFoundException) { toast(R.string.toast_require_file_manager)
toast(R.string.toast_require_file_manager) }
} } else
} else toast(R.string.toast_permission_denied)
toast(R.string.toast_permission_denied) }
}
} }
private val chooseFile = private val chooseFile =
@@ -237,15 +238,18 @@ class UserAssetActivity : BaseActivity() {
conn?.disconnect() conn?.disconnect()
} }
} }
private fun addBuiltInGeoItems(assets: List<Pair<String, AssetUrlItem>>): List<Pair<String, AssetUrlItem>> { private fun addBuiltInGeoItems(assets: List<Pair<String, AssetUrlItem>>): List<Pair<String, AssetUrlItem>> {
val list = mutableListOf<Pair<String, AssetUrlItem>>() val list = mutableListOf<Pair<String, AssetUrlItem>>()
builtInGeoFiles builtInGeoFiles
.filter { geoFile -> assets.none { it.second.remarks == geoFile } } .filter { geoFile -> assets.none { it.second.remarks == geoFile } }
.forEach { .forEach {
list.add(Utils.getUuid() to AssetUrlItem( list.add(
it, Utils.getUuid() to AssetUrlItem(
AppConfig.GeoUrl + it it,
)) AppConfig.GeoUrl + it
)
)
} }
return list + assets return list + assets
@@ -257,14 +261,15 @@ class UserAssetActivity : BaseActivity() {
ItemRecyclerUserAssetBinding.inflate( ItemRecyclerUserAssetBinding.inflate(
LayoutInflater.from(parent.context), LayoutInflater.from(parent.context),
parent, parent,
false) false
)
) )
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: UserAssetViewHolder, position: Int) { override fun onBindViewHolder(holder: UserAssetViewHolder, position: Int) {
var assets = MmkvManager.decodeAssetUrls(); var assets = MmkvManager.decodeAssetUrls()
assets = addBuiltInGeoItems(assets); assets = addBuiltInGeoItems(assets)
val item = assets.getOrNull(position) ?: return val item = assets.getOrNull(position) ?: return
// file with name == item.second.remarks // file with name == item.second.remarks
val file = extDir.listFiles()?.find { it.name == item.second.remarks } val file = extDir.listFiles()?.find { it.name == item.second.remarks }
@@ -300,8 +305,8 @@ class UserAssetActivity : BaseActivity() {
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
var assets = MmkvManager.decodeAssetUrls(); var assets = MmkvManager.decodeAssetUrls()
assets = addBuiltInGeoItems(assets); assets = addBuiltInGeoItems(assets)
return assets.size return assets.size
} }
} }
@@ -112,7 +112,7 @@ class UserAssetUrlActivity : BaseActivity() {
MmkvManager.removeAssetUrl(editAssetId) MmkvManager.removeAssetUrl(editAssetId)
finish() finish()
} }
.setNegativeButton(android.R.string.no) {_, _ -> .setNegativeButton(android.R.string.no) { _, _ ->
// do nothing // do nothing
} }
.show() .show()
@@ -137,10 +137,12 @@ class UserAssetUrlActivity : BaseActivity() {
deleteServer() deleteServer()
true true
} }
R.id.save_config -> { R.id.save_config -> {
saveServer() saveServer()
true true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
} }
@@ -386,7 +386,7 @@ object AngConfigManager {
// } // }
// } // }
fun importBatchConfig(server: String?, subid: String, append: Boolean): Pair<Int, Int> { fun importBatchConfig(server: String?, subid: String, append: Boolean): Pair<Int, Int> {
var count = parseBatchConfig(Utils.decode(server), subid, append) var count = parseBatchConfig(Utils.decode(server), subid, append)
if (count <= 0) { if (count <= 0) {
count = parseBatchConfig(server, subid, append) count = parseBatchConfig(server, subid, append)
@@ -140,7 +140,7 @@ object Utils {
} }
fun getVpnDnsServers(): List<String> { fun getVpnDnsServers(): List<String> {
val vpnDns = settingsStorage?.decodeString(AppConfig.PREF_VPN_DNS)?:AppConfig.DNS_VPN val vpnDns = settingsStorage?.decodeString(AppConfig.PREF_VPN_DNS) ?: AppConfig.DNS_VPN
return vpnDns.split(",").filter { isPureIpAddress(it) } return vpnDns.split(",").filter { isPureIpAddress(it) }
// allow empty, in that case dns will use system default // allow empty, in that case dns will use system default
} }
@@ -204,7 +204,8 @@ object Utils {
} }
fun isIpv4Address(value: String): Boolean { fun isIpv4Address(value: String): Boolean {
val regV4 = Regex("^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$") val regV4 =
Regex("^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$")
return regV4.matches(value) return regV4.matches(value)
} }
@@ -214,7 +215,8 @@ object Utils {
addr = addr.drop(1) addr = addr.drop(1)
addr = addr.dropLast(addr.count() - addr.lastIndexOf("]")) addr = addr.dropLast(addr.count() - addr.lastIndexOf("]"))
} }
val regV6 = Regex("^((?:[0-9A-Fa-f]{1,4}))?((?::[0-9A-Fa-f]{1,4}))*::((?:[0-9A-Fa-f]{1,4}))?((?::[0-9A-Fa-f]{1,4}))*|((?:[0-9A-Fa-f]{1,4}))((?::[0-9A-Fa-f]{1,4})){7}$") val regV6 =
Regex("^((?:[0-9A-Fa-f]{1,4}))?((?::[0-9A-Fa-f]{1,4}))*::((?:[0-9A-Fa-f]{1,4}))?((?::[0-9A-Fa-f]{1,4}))*|((?:[0-9A-Fa-f]{1,4}))((?::[0-9A-Fa-f]{1,4})){7}$")
return regV6.matches(addr) return regV6.matches(addr)
} }
@@ -300,8 +302,7 @@ object Utils {
* readTextFromAssets * readTextFromAssets
*/ */
fun readTextFromAssets(context: Context?, fileName: String): String { fun readTextFromAssets(context: Context?, fileName: String): String {
if(context == null) if (context == null) {
{
return "" return ""
} }
val content = context.assets.open(fileName).bufferedReader().use { val content = context.assets.open(fileName).bufferedReader().use {
@@ -314,7 +315,7 @@ object Utils {
if (context == null) if (context == null)
return "" return ""
val extDir = context.getExternalFilesDir(AppConfig.DIR_ASSETS) val extDir = context.getExternalFilesDir(AppConfig.DIR_ASSETS)
?: return context.getDir(AppConfig.DIR_ASSETS, 0).absolutePath ?: return context.getDir(AppConfig.DIR_ASSETS, 0).absolutePath
return extDir.absolutePath return extDir.absolutePath
} }
@@ -370,8 +371,10 @@ object Utils {
conn.setRequestProperty("Connection", "close") conn.setRequestProperty("Connection", "close")
conn.setRequestProperty("User-agent", "v2rayNG/${BuildConfig.VERSION_NAME}") conn.setRequestProperty("User-agent", "v2rayNG/${BuildConfig.VERSION_NAME}")
url.userInfo?.let { url.userInfo?.let {
conn.setRequestProperty("Authorization", conn.setRequestProperty(
"Basic ${encode(urlDecode(it))}") "Authorization",
"Basic ${encode(urlDecode(it))}"
)
} }
conn.useCaches = false conn.useCaches = false
return conn.inputStream.use { return conn.inputStream.use {
@@ -393,7 +396,7 @@ object Utils {
} }
fun getIpv6Address(address: String?): String { fun getIpv6Address(address: String?): String {
if(address == null){ if (address == null) {
return "" return ""
} }
return if (isIpv6Address(address) && !address.contains('[') && !address.contains(']')) { return if (isIpv6Address(address) && !address.contains('[') && !address.contains(']')) {
@@ -427,8 +430,8 @@ object Utils {
fun fixIllegalUrl(str: String): String { fun fixIllegalUrl(str: String): String {
return str return str
.replace(" ","%20") .replace(" ", "%20")
.replace("|","%7C") .replace("|", "%7C")
} }
fun removeWhiteSpace(str: String?): String? { fun removeWhiteSpace(str: String?): String? {
@@ -67,7 +67,7 @@ object ShadowsocksFmt {
private fun tryResolveResolveSip002(str: String, config: ServerConfig): Boolean { private fun tryResolveResolveSip002(str: String, config: ServerConfig): Boolean {
try { try {
val uri = URI(Utils.fixIllegalUrl(str)) val uri = URI(Utils.fixIllegalUrl(str))
config.remarks = Utils.urlDecode(uri.fragment .orEmpty()) config.remarks = Utils.urlDecode(uri.fragment.orEmpty())
val method: String val method: String
val password: String val password: String
@@ -88,7 +88,7 @@ object ShadowsocksFmt {
password = base64Decode.substringAfter(":") password = base64Decode.substringAfter(":")
} }
val query = Utils.urlDecode(uri.query .orEmpty()) val query = Utils.urlDecode(uri.query.orEmpty())
if (query != "") { if (query != "") {
val queryPairs = HashMap<String, String>() val queryPairs = HashMap<String, String>()
val pairs = query.split(";") val pairs = query.split(";")
@@ -19,12 +19,12 @@ object TrojanFmt {
) )
} }
fun parseTrojan(str: String): ServerConfig? { fun parseTrojan(str: String): ServerConfig {
var allowInsecure = settingsStorage?.decodeBool(AppConfig.PREF_ALLOW_INSECURE) ?: false var allowInsecure = settingsStorage?.decodeBool(AppConfig.PREF_ALLOW_INSECURE) ?: false
val config = ServerConfig.create(EConfigType.TROJAN) val config = ServerConfig.create(EConfigType.TROJAN)
val uri = URI(Utils.fixIllegalUrl(str)) val uri = URI(Utils.fixIllegalUrl(str))
config.remarks = Utils.urlDecode(uri.fragment .orEmpty()) config.remarks = Utils.urlDecode(uri.fragment.orEmpty())
var flow = "" var flow = ""
var fingerprint = config.outboundBean?.streamSettings?.tlsSettings?.fingerprint var fingerprint = config.outboundBean?.streamSettings?.tlsSettings?.fingerprint
@@ -56,7 +56,7 @@ object TrojanFmt {
queryParam["authority"] queryParam["authority"]
) )
fingerprint = queryParam["fp"].orEmpty() fingerprint = queryParam["fp"].orEmpty()
allowInsecure = if ((queryParam["allowInsecure"] .orEmpty()) == "1") true else allowInsecure allowInsecure = if ((queryParam["allowInsecure"].orEmpty()) == "1") true else allowInsecure
config.outboundBean?.streamSettings?.populateTlsSettings( config.outboundBean?.streamSettings?.populateTlsSettings(
queryParam["security"] ?: V2rayConfig.TLS, queryParam["security"] ?: V2rayConfig.TLS,
allowInsecure, allowInsecure,
@@ -111,7 +111,7 @@ object TrojanFmt {
dicQuery["sid"] = tlsSetting.shortId.orEmpty() dicQuery["sid"] = tlsSetting.shortId.orEmpty()
} }
if (!TextUtils.isEmpty(tlsSetting.spiderX)) { if (!TextUtils.isEmpty(tlsSetting.spiderX)) {
dicQuery["spx"] = Utils.urlEncode(tlsSetting.spiderX .orEmpty()) dicQuery["spx"] = Utils.urlEncode(tlsSetting.spiderX.orEmpty())
} }
} }
dicQuery["type"] = dicQuery["type"] =
@@ -30,7 +30,7 @@ object VlessFmt {
val streamSetting = config.outboundBean?.streamSettings ?: return null val streamSetting = config.outboundBean?.streamSettings ?: return null
config.remarks = Utils.urlDecode(uri.fragment .orEmpty()) config.remarks = Utils.urlDecode(uri.fragment.orEmpty())
config.outboundBean.settings?.vnext?.get(0)?.let { vnext -> config.outboundBean.settings?.vnext?.get(0)?.let { vnext ->
vnext.address = uri.idnHost vnext.address = uri.idnHost
vnext.port = uri.port vnext.port = uri.port
@@ -51,7 +51,7 @@ object VlessFmt {
queryParam["serviceName"], queryParam["serviceName"],
queryParam["authority"] queryParam["authority"]
) )
allowInsecure = if ((queryParam["allowInsecure"] .orEmpty()) == "1") true else allowInsecure allowInsecure = if ((queryParam["allowInsecure"].orEmpty()) == "1") true else allowInsecure
streamSetting.populateTlsSettings( streamSetting.populateTlsSettings(
queryParam["security"].orEmpty(), queryParam["security"].orEmpty(),
allowInsecure, allowInsecure,
@@ -102,7 +102,7 @@ object VlessFmt {
dicQuery["sid"] = tlsSetting.shortId.orEmpty() dicQuery["sid"] = tlsSetting.shortId.orEmpty()
} }
if (!TextUtils.isEmpty(tlsSetting.spiderX)) { if (!TextUtils.isEmpty(tlsSetting.spiderX)) {
dicQuery["spx"] = Utils.urlEncode(tlsSetting.spiderX .orEmpty()) dicQuery["spx"] = Utils.urlEncode(tlsSetting.spiderX.orEmpty())
} }
} }
dicQuery["type"] = dicQuery["type"] =
@@ -121,7 +121,7 @@ object VmessFmt {
val streamSetting = config.outboundBean?.streamSettings ?: return null val streamSetting = config.outboundBean?.streamSettings ?: return null
config.remarks = Utils.urlDecode(uri.fragment .orEmpty()) config.remarks = Utils.urlDecode(uri.fragment.orEmpty())
config.outboundBean.settings?.vnext?.get(0)?.let { vnext -> config.outboundBean.settings?.vnext?.get(0)?.let { vnext ->
vnext.address = uri.idnHost vnext.address = uri.idnHost
vnext.port = uri.port vnext.port = uri.port
@@ -143,7 +143,7 @@ object VmessFmt {
queryParam["authority"] queryParam["authority"]
) )
allowInsecure = if ((queryParam["allowInsecure"] .orEmpty()) == "1") true else allowInsecure allowInsecure = if ((queryParam["allowInsecure"].orEmpty()) == "1") true else allowInsecure
streamSetting.populateTlsSettings( streamSetting.populateTlsSettings(
queryParam["security"].orEmpty(), queryParam["security"].orEmpty(),
allowInsecure, allowInsecure,
@@ -13,7 +13,7 @@ object WireguardFmt {
val uri = URI(Utils.fixIllegalUrl(str)) val uri = URI(Utils.fixIllegalUrl(str))
if (uri.rawQuery != null) { if (uri.rawQuery != null) {
val config = ServerConfig.create(EConfigType.WIREGUARD) val config = ServerConfig.create(EConfigType.WIREGUARD)
config.remarks = Utils.urlDecode(uri.fragment .orEmpty()) config.remarks = Utils.urlDecode(uri.fragment.orEmpty())
val queryParam = uri.rawQuery.split("&") val queryParam = uri.rawQuery.split("&")
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } } .associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FFFFFFFF" android:fillColor="#FFFFFFFF"
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/> android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z" />
</vector> </vector>
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FFFFFFFF" android:fillColor="#FFFFFFFF"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/> android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</vector> </vector>
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FFFFFFFF" android:fillColor="#FFFFFFFF"
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/> android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z" />
</vector> </vector>
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FFFFFFFF" android:fillColor="#FFFFFFFF"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8.46,11.88l1.41,-1.41L12,12.59l2.12,-2.12 1.41,1.41L13.41,14l2.12,2.12 -1.41,1.41L12,15.41l-2.12,2.12 -1.41,-1.41L10.59,14l-2.13,-2.12zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z"/> android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8.46,11.88l1.41,-1.41L12,12.59l2.12,-2.12 1.41,1.41L13.41,14l2.12,2.12 -1.41,1.41L12,15.41l-2.12,2.12 -1.41,-1.41L10.59,14l-2.13,-2.12zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z" />
</vector> </vector>
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FFFFFFFF" android:fillColor="#FFFFFFFF"
android:pathData="M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM16,18L8,18v-2h8v2zM16,14L8,14v-2h8v2zM13,9L13,3.5L18.5,9L13,9z"/> android:pathData="M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM16,18L8,18v-2h8v2zM16,14L8,14v-2h8v2zM13,9L13,3.5L18.5,9L13,9z" />
</vector> </vector>
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FFFFFFFF" android:fillColor="#FFFFFFFF"
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/> android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z" />
</vector> </vector>
@@ -3,7 +3,7 @@
android:height="24dp" android:height="24dp"
android:viewportWidth="1024" android:viewportWidth="1024"
android:viewportHeight="1024"> android:viewportHeight="1024">
<path <path
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: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"/> android:fillColor="#FFFFFFFF" />
</vector> </vector>
@@ -5,11 +5,11 @@
android:viewportHeight="1024"> android:viewportHeight="1024">
<path <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: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"/> android:fillColor="#FFFFFFFF" />
<path <path
android:pathData="M167.1,117.8h554.4v123.6h-71.7V189.4H238.8v498.8h73.9v71.7H167.1V117.8z" android:pathData="M167.1,117.8h554.4v123.6h-71.7V189.4H238.8v498.8h73.9v71.7H167.1V117.8z"
android:fillColor="#FFFFFFFF"/> android:fillColor="#FFFFFFFF" />
<path <path
android:pathData="M674.8,504H455.3v-71.7h219.4v71.7zM674.8,650.2H455.3v-71.7h219.4v71.7z" android:pathData="M674.8,504H455.3v-71.7h219.4v71.7zM674.8,650.2H455.3v-71.7h219.4v71.7z"
android:fillColor="#FFFFFFFF"/> android:fillColor="#FFFFFFFF" />
</vector> </vector>
@@ -1,5 +1,10 @@
<vector android:height="24dp" android:tint="#FFFFFF" <vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24" android:tint="#FFFFFF"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:viewportHeight="24"
<path android:fillColor="@android:color/white" android:pathData="M7,6h10l-5.01,6.3L7,6zM4.25,5.61C6.27,8.2 10,13 10,13v6c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-6c0,0 3.72,-4.8 5.74,-7.39C20.25,4.95 19.78,4 18.95,4H5.04C4.21,4 3.74,4.95 4.25,5.61z"/> android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="@android:color/white"
android:pathData="M7,6h10l-5.01,6.3L7,6zM4.25,5.61C6.27,8.2 10,13 10,13v6c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-6c0,0 3.72,-4.8 5.74,-7.39C20.25,4.95 19.78,4 18.95,4H5.04C4.21,4 3.74,4.95 4.25,5.61z" />
</vector> </vector>
@@ -5,8 +5,8 @@
android:viewportHeight="1024"> android:viewportHeight="1024">
<path <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: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"/> android:fillColor="#FFFFFFFF" />
<path <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: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"/> android:fillColor="#FFFFFFFF" />
</vector> </vector>
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FFFFFFFF" android:fillColor="#FFFFFFFF"
android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/> android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z" />
</vector> </vector>
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FFFFFFFF" android:fillColor="#FFFFFFFF"
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/> android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z" />
</vector> </vector>
@@ -3,7 +3,7 @@
android:height="24dp" android:height="24dp"
android:viewportWidth="1024" android:viewportWidth="1024"
android:viewportHeight="1024"> android:viewportHeight="1024">
<path <path
android:fillColor="#FFFFFFFF" 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" /> 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> </vector>
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FF000000" android:fillColor="#FF000000"
android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/> android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z" />
</vector> </vector>
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FF000000" android:fillColor="#FF000000"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/> android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</vector> </vector>
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FF000000" android:fillColor="#FF000000"
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/> android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z" />
</vector> </vector>
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FF000000" android:fillColor="#FF000000"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8.46,11.88l1.41,-1.41L12,12.59l2.12,-2.12 1.41,1.41L13.41,14l2.12,2.12 -1.41,1.41L12,15.41l-2.12,2.12 -1.41,-1.41L10.59,14l-2.13,-2.12zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z"/> android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,7L6,7v12zM8.46,11.88l1.41,-1.41L12,12.59l2.12,-2.12 1.41,1.41L13.41,14l2.12,2.12 -1.41,1.41L12,15.41l-2.12,2.12 -1.41,-1.41L10.59,14l-2.13,-2.12zM15.5,4l-1,-1h-5l-1,1L5,4v2h14L19,4z" />
</vector> </vector>
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FF000000" android:fillColor="#FF000000"
android:pathData="M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM16,18L8,18v-2h8v2zM16,14L8,14v-2h8v2zM13,9L13,3.5L18.5,9L13,9z"/> android:pathData="M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM16,18L8,18v-2h8v2zM16,14L8,14v-2h8v2zM13,9L13,3.5L18.5,9L13,9z" />
</vector> </vector>
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FF000000" android:fillColor="#FF000000"
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/> android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z" />
</vector> </vector>
@@ -3,7 +3,7 @@
android:height="24dp" android:height="24dp"
android:viewportWidth="1024" android:viewportWidth="1024"
android:viewportHeight="1024"> android:viewportHeight="1024">
<path <path
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: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"/> android:fillColor="#FF000000" />
</vector> </vector>
@@ -3,13 +3,13 @@
android:height="24dp" android:height="24dp"
android:viewportWidth="1024" android:viewportWidth="1024"
android:viewportHeight="1024"> android:viewportHeight="1024">
<path <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: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"/> android:fillColor="#FF000000" />
<path <path
android:pathData="M167.1,117.8h554.4v123.6h-71.7V189.4H238.8v498.8h73.9v71.7H167.1V117.8z" android:pathData="M167.1,117.8h554.4v123.6h-71.7V189.4H238.8v498.8h73.9v71.7H167.1V117.8z"
android:fillColor="#FF000000"/> android:fillColor="#FF000000" />
<path <path
android:pathData="M674.8,504H455.3v-71.7h219.4v71.7zM674.8,650.2H455.3v-71.7h219.4v71.7z" android:pathData="M674.8,504H455.3v-71.7h219.4v71.7zM674.8,650.2H455.3v-71.7h219.4v71.7z"
android:fillColor="#FF000000"/> android:fillColor="#FF000000" />
</vector> </vector>
@@ -1,5 +1,10 @@
<vector android:height="24dp" android:tint="#000000" <vector android:height="24dp"
android:viewportHeight="24" android:viewportWidth="24" android:tint="#000000"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:viewportHeight="24"
<path android:fillColor="@android:color/white" android:pathData="M7,6h10l-5.01,6.3L7,6zM4.25,5.61C6.27,8.2 10,13 10,13v6c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-6c0,0 3.72,-4.8 5.74,-7.39C20.25,4.95 19.78,4 18.95,4H5.04C4.21,4 3.74,4.95 4.25,5.61z"/> android:viewportWidth="24"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="@android:color/white"
android:pathData="M7,6h10l-5.01,6.3L7,6zM4.25,5.61C6.27,8.2 10,13 10,13v6c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-6c0,0 3.72,-4.8 5.74,-7.39C20.25,4.95 19.78,4 18.95,4H5.04C4.21,4 3.74,4.95 4.25,5.61z" />
</vector> </vector>
@@ -3,10 +3,10 @@
android:height="24dp" android:height="24dp"
android:viewportWidth="1024" android:viewportWidth="1024"
android:viewportHeight="1024"> android:viewportHeight="1024">
<path <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: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"/> android:fillColor="#FF000000" />
<path <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: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"/> android:fillColor="#FF000000" />
</vector> </vector>
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FF000000" android:fillColor="#FF000000"
android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/> android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z" />
</vector> </vector>
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FF000000" android:fillColor="#FF000000"
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/> android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z" />
</vector> </vector>
@@ -1,4 +1,9 @@
<vector android:height="24dp" android:viewportHeight="1024" <vector android:height="24dp"
android:viewportWidth="1024" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:viewportHeight="1024"
<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"/> 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> </vector>
@@ -51,7 +51,7 @@
app:tabTextAppearance="@style/TabLayoutTextStyle" app:tabTextAppearance="@style/TabLayoutTextStyle"
app:tabIndicatorFullWidth="false" app:tabIndicatorFullWidth="false"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="match_parent"/> android:layout_width="match_parent" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
@@ -79,7 +79,7 @@
android:minLines="1" android:minLines="1"
android:paddingStart="16dp" android:paddingStart="16dp"
android:text="@string/connection_test_pending" android:text="@string/connection_test_pending"
android:textAppearance="@style/TextAppearance.AppCompat.Small"/> android:textAppearance="@style/TextAppearance.AppCompat.Small" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
@@ -120,7 +120,7 @@
android:layout_gravity="start" android:layout_gravity="start"
app:headerLayout="@layout/nav_header" app:headerLayout="@layout/nav_header"
app:itemIconTint="@color/colorAccent" app:itemIconTint="@color/colorAccent"
app:menu="@menu/menu_drawer" > app:menu="@menu/menu_drawer">
</com.google.android.material.navigation.NavigationView> </com.google.android.material.navigation.NavigationView>
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"></RelativeLayout>
</RelativeLayout>
@@ -1,7 +1,6 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"> android:orientation="vertical">
<com.google.android.material.tabs.TabLayout <com.google.android.material.tabs.TabLayout
@@ -69,11 +69,11 @@
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" /> android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
<com.blacksquircle.ui.editorkit.widget.TextProcessor <com.blacksquircle.ui.editorkit.widget.TextProcessor
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="top|start" android:gravity="top|start"
android:id="@+id/editor" android:id="@+id/editor"
android:layout_marginTop="@dimen/layout_margin_top_height" /> android:layout_marginTop="@dimen/layout_margin_top_height" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
@@ -205,9 +205,9 @@
android:inputType="text" /> android:inputType="text" />
</LinearLayout> </LinearLayout>
<include layout="@layout/tls_layout" /> <include layout="@layout/tls_layout" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -186,7 +186,7 @@
android:inputType="text" /> android:inputType="text" />
</LinearLayout> </LinearLayout>
<include layout="@layout/tls_layout" /> <include layout="@layout/tls_layout" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -129,11 +129,11 @@
<EditText <EditText
android:id="@+id/et_security" android:id="@+id/et_security"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/edit_height" android:layout_height="@dimen/edit_height"
android:inputType="text" android:inputType="text"
android:text="none" /> android:text="none" />
</LinearLayout> </LinearLayout>
@@ -225,7 +225,7 @@
android:inputType="text" /> android:inputType="text" />
</LinearLayout> </LinearLayout>
<include layout="@layout/tls_layout" /> <include layout="@layout/tls_layout" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -224,7 +224,7 @@
android:inputType="text" /> android:inputType="text" />
</LinearLayout> </LinearLayout>
<include layout="@layout/tls_layout" /> <include layout="@layout/tls_layout" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -133,16 +133,19 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal"> android:orientation="horizontal">
<EditText <EditText
android:id="@+id/et_reserved1" android:id="@+id/et_reserved1"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="@dimen/edit_height" android:layout_height="@dimen/edit_height"
android:inputType="number" /> android:inputType="number" />
<EditText <EditText
android:id="@+id/et_reserved2" android:id="@+id/et_reserved2"
android:layout_width="60dp" android:layout_width="60dp"
android:layout_height="@dimen/edit_height" android:layout_height="@dimen/edit_height"
android:inputType="number" /> android:inputType="number" />
<EditText <EditText
android:id="@+id/et_reserved3" android:id="@+id/et_reserved3"
android:layout_width="60dp" android:layout_width="60dp"
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout 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" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@@ -17,7 +16,7 @@
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:listitem="@layout/item_recycler_sub_setting"/> tools:listitem="@layout/item_recycler_sub_setting" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>
</RelativeLayout> </RelativeLayout>
@@ -1,86 +1,86 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.UserAssetUrlActivity">
<LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:orientation="vertical"> tools:context=".ui.UserAssetUrlActivity">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical">
android:padding="@dimen/layout_margin_top_height">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical"
android:padding="@dimen/layout_margin_top_height">
<TextView <LinearLayout
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/menu_item_add_asset" android:orientation="vertical">
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu_item_add_asset"
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/sub_setting_remarks" />
<EditText
android:id="@+id/et_remarks"
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="match_parent"
android:layout_height="wrap_content"
android:text="@string/title_url" />
<EditText
android:id="@+id/et_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="top"
android:inputType="textMultiLine"
android:maxLines="10"
android:minLines="5"
android:scrollbars="vertical" />
</LinearLayout>
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/layout_margin_top_height"
android:layout_marginTop="@dimen/layout_margin_top_height" android:layout_marginTop="@dimen/layout_margin_top_height"
android:orientation="vertical"> android:orientation="vertical" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sub_setting_remarks" />
<EditText
android:id="@+id/et_remarks"
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="match_parent"
android:layout_height="wrap_content"
android:text="@string/title_url" />
<EditText
android:id="@+id/et_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="top"
android:inputType="textMultiLine"
android:maxLines="10"
android:minLines="5"
android:scrollbars="vertical" />
</LinearLayout>
</LinearLayout> </LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/layout_margin_top_height"
android:layout_marginTop="@dimen/layout_margin_top_height"
android:orientation="vertical" />
</LinearLayout>
</ScrollView> </ScrollView>
@@ -18,7 +18,7 @@
<Spinner <Spinner
android:id="@+id/sp_subscriptionId" android:id="@+id/sp_subscriptionId"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/edit_height"/> android:layout_height="@dimen/edit_height" />
</LinearLayout> </LinearLayout>
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal" android:orientation="horizontal"
android:padding="16dp"> android:padding="16dp">
<ProgressBar <ProgressBar
android:id="@+id/pb_waiting" android:id="@+id/pb_waiting"
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <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_width="match_parent"
android:layout_height="@dimen/nav_header_height" android:layout_height="@dimen/nav_header_height"
android:background="@drawable/nav_header_bg" android:background="@drawable/nav_header_bg"
@@ -2,10 +2,10 @@
<Button xmlns:android="http://schemas.android.com/apk/res/android" <Button xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
style="@style/Widget.AppCompat.Button.Borderless" style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:onClick="onModeHelpClicked" android:onClick="onModeHelpClicked"
android:text="@string/title_mode_help" android:text="@string/title_mode_help"
android:textAlignment="textStart" android:textAlignment="textStart"
android:textStyle="italic" android:textStyle="italic"
tools:ignore="UsingOnClickInXml" /> tools:ignore="UsingOnClickInXml" />
+12 -6
View File
@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_horizontal_margin" android:layout_marginTop="@dimen/activity_horizontal_margin"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout <LinearLayout
android:id="@+id/l1" android:id="@+id/l1"
@@ -27,6 +26,7 @@
android:nextFocusDown="@+id/et_sni" /> android:nextFocusDown="@+id/et_sni" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/l2" android:id="@+id/l2"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -47,6 +47,7 @@
android:nextFocusDown="@+id/sp_stream_fingerprint" /> android:nextFocusDown="@+id/sp_stream_fingerprint" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/l3" android:id="@+id/l3"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -67,6 +68,7 @@
android:nextFocusDown="@+id/sp_stream_alpn" /> android:nextFocusDown="@+id/sp_stream_alpn" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/l4" android:id="@+id/l4"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -87,11 +89,12 @@
android:nextFocusDown="@+id/sp_allow_insecure" /> android:nextFocusDown="@+id/sp_allow_insecure" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/l5" android:id="@+id/l5"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" > android:orientation="vertical">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -104,6 +107,7 @@
android:layout_height="@dimen/edit_height" android:layout_height="@dimen/edit_height"
android:entries="@array/allowinsecures" /> android:entries="@array/allowinsecures" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/l6" android:id="@+id/l6"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -124,6 +128,7 @@
android:nextFocusDown="@+id/sp_stream_fingerprint" /> android:nextFocusDown="@+id/sp_stream_fingerprint" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/l7" android:id="@+id/l7"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -144,6 +149,7 @@
android:nextFocusDown="@+id/sp_stream_fingerprint" /> android:nextFocusDown="@+id/sp_stream_fingerprint" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/l8" android:id="@+id/l8"
android:layout_width="match_parent" android:layout_width="match_parent"
+1 -1
View File
@@ -4,7 +4,7 @@
<item <item
android:icon="@drawable/ic_add_24dp" android:icon="@drawable/ic_add_24dp"
android:title="@string/menu_item_add_asset" android:title="@string/menu_item_add_asset"
app:showAsAction="ifRoom" > app:showAsAction="ifRoom">
<menu> <menu>
<item <item
android:id="@+id/add_file" android:id="@+id/add_file"
@@ -6,7 +6,7 @@
android:icon="@drawable/ic_description_24dp" android:icon="@drawable/ic_description_24dp"
android:title="@string/menu_item_search" android:title="@string/menu_item_search"
app:actionViewClass="androidx.appcompat.widget.SearchView" app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="always" /> app:showAsAction="always" />
<item <item
android:id="@+id/select_all" android:id="@+id/select_all"
android:icon="@drawable/ic_select_all_24dp" android:icon="@drawable/ic_select_all_24dp"
@@ -3,8 +3,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view"> tools:showIn="navigation_view">
<group <group android:id="@+id/group_main">
android:id="@+id/group_main">
<item <item
android:id="@+id/sub_setting" android:id="@+id/sub_setting"
android:icon="@drawable/ic_subscriptions_24dp" android:icon="@drawable/ic_subscriptions_24dp"
@@ -14,9 +13,9 @@
android:icon="@drawable/ic_settings_24dp" android:icon="@drawable/ic_settings_24dp"
android:title="@string/title_settings" /> android:title="@string/title_settings" />
<item <item
android:id="@+id/user_asset_setting" android:id="@+id/user_asset_setting"
android:icon="@drawable/ic_file_24dp" android:icon="@drawable/ic_file_24dp"
android:title="@string/title_user_asset_setting" /> android:title="@string/title_user_asset_setting" />
</group> </group>
<group android:id="@+id/group_id2"> <group android:id="@+id/group_id2">
+1 -1
View File
@@ -6,7 +6,7 @@
android:icon="@drawable/ic_outline_filter_alt_24" android:icon="@drawable/ic_outline_filter_alt_24"
android:title="@string/menu_item_search" android:title="@string/menu_item_search"
app:actionViewClass="androidx.appcompat.widget.SearchView" app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="always|collapseActionView"/> app:showAsAction="always|collapseActionView" />
<item <item
android:icon="@drawable/ic_add_24dp" android:icon="@drawable/ic_add_24dp"
android:title="@string/menu_item_add_config" android:title="@string/menu_item_add_config"
@@ -1,7 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_banner_background"/> <background android:drawable="@color/ic_banner_background" />
<foreground> <foreground>
<inset android:drawable="@mipmap/ic_banner_foreground" android:inset="10%"/> <inset
android:drawable="@mipmap/ic_banner_foreground"
android:inset="10%" />
</foreground> </foreground>
</adaptive-icon> </adaptive-icon>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/> <background android:drawable="@color/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground"/> <foreground android:drawable="@mipmap/ic_launcher_foreground" />
<monochrome android:drawable="@mipmap/ic_launcher_foreground" /> <monochrome android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon> </adaptive-icon>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/> <background android:drawable="@color/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground"/> <foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon> </adaptive-icon>
@@ -42,7 +42,7 @@
<string name="server_lab_address">العنوان</string> <string name="server_lab_address">العنوان</string>
<string name="server_lab_port">المنفذ</string> <string name="server_lab_port">المنفذ</string>
<string name="server_lab_id">المعرف</string> <string name="server_lab_id">المعرف</string>
<string name="server_lab_alterid">AlterId</string> <string name="server_lab_alterid">AlterId</string>
<string name="server_lab_security">الأمان</string> <string name="server_lab_security">الأمان</string>
<string name="server_lab_network">الشبكة</string> <string name="server_lab_network">الشبكة</string>
@@ -110,7 +110,7 @@
<string name="msg_file_not_found">الملف غير موجود</string> <string name="msg_file_not_found">الملف غير موجود</string>
<string name="msg_remark_is_duplicate">الملاحظات موجودة بالفعل</string> <string name="msg_remark_is_duplicate">الملاحظات موجودة بالفعل</string>
<string name="toast_action_not_allowed">الإجراء غير مسموح به</string> <string name="toast_action_not_allowed">الإجراء غير مسموح به</string>
<!-- PerAppProxyActivity --> <!-- PerAppProxyActivity -->
<string name="msg_dialog_progress">جار التحميل</string> <string name="msg_dialog_progress">جار التحميل</string>
<string name="menu_item_search">بحث</string> <string name="menu_item_search">بحث</string>
+1 -1
View File
@@ -49,7 +49,7 @@
<string-array name="mode_type_grpc" translatable="false"> <string-array name="mode_type_grpc" translatable="false">
<item>gun</item> <item>gun</item>
<item>multi</item> <item>multi</item>
<!--Hide this option until core support it <item>guna</item>--> <!--Hide this option until core support it <item>guna</item>-->
</string-array> </string-array>
<string-array name="streamsecuritys" translatable="false"> <string-array name="streamsecuritys" translatable="false">
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="TabLayoutTextStyle" parent="TextAppearance.Design.Tab"> <style name="TabLayoutTextStyle" parent="TextAppearance.Design.Tab">
<item name="textAllCaps">false</item> <item name="textAllCaps">false</item>
</style> </style>
Loaded 100 of 103 files, more files were not shown because too many files have changed in this diff. Show more