Compare commits

...

15 Commits

Author SHA1 Message Date
2dust 397989769c up 1.9.42 2025-03-26 18:54:42 +08:00
2dust 796676abdc Enable double column display
The profile list is displayed in double columns, allowing more content to be displayed on the screen. You need to restart the application to take effect.
2025-03-26 18:48:14 +08:00
2dust 3c93ccb86c Optimize and improve 2025-03-25 20:26:28 +08:00
2dust fc8c74184a Optimize and improve for toast 2025-03-25 17:44:30 +08:00
solokot 1939e6b5cf Optimize Russian translation (#4411) 2025-03-25 17:05:12 +08:00
2dust 1c2ac9385d Fix
https://github.com/2dust/v2rayNG/issues/4410
2025-03-25 10:49:07 +08:00
2dust 7513f1fe07 Optimize and improve 2025-03-25 10:44:06 +08:00
2dust 63e2c02daa Fix
https://github.com/2dust/v2rayNG/issues/4408
2025-03-24 20:17:49 +08:00
2dust fec76385e1 Bug fix
https://github.com/2dust/v2rayNG/issues/4409
2025-03-24 20:17:05 +08:00
2dust bf21428746 up 1.9.41 2025-03-24 15:45:56 +08:00
2dust 01ab8dad17 Optimize and improve removeWhiteSpace 2025-03-24 15:44:08 +08:00
2dust 8974f73841 Fix
https://github.com/2dust/v2rayNG/issues/4407
2025-03-24 14:43:07 +08:00
Pk-web6936 d3a2a2413c Update Persian translate (#4404)
* Update Persian translate

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml

* Update strings.xml
2025-03-24 10:50:13 +08:00
2dust 9b52863270 Bug fix
https://github.com/2dust/v2rayNG/issues/4405
2025-03-24 10:34:59 +08:00
2dust 733914a7a7 Add colorPrimaryDark to theme 2025-03-23 19:25:20 +08:00
64 changed files with 656 additions and 407 deletions
+2 -2
View File
@@ -12,8 +12,8 @@ android {
applicationId = "com.v2ray.ang"
minSdk = 21
targetSdk = 35
versionCode = 640
versionName = "1.9.40"
versionCode = 642
versionName = "1.9.42"
multiDexEnabled = true
val abiFilterList = (properties["ABI_FILTERS"] as? String)?.split(';')
@@ -42,6 +42,7 @@ object AppConfig {
const val PREF_SPEED_ENABLED = "pref_speed_enabled"
const val PREF_CONFIRM_REMOVE = "pref_confirm_remove"
const val PREF_START_SCAN_IMMEDIATE = "pref_start_scan_immediate"
const val PREF_DOUBLE_COLUMN_DISPLAY = "pref_double_column_display"
const val PREF_LANGUAGE = "pref_language"
const val PREF_UI_MODE_NIGHT = "pref_ui_mode_night"
const val PREF_PREFER_IPV6 = "pref_prefer_ipv6"
@@ -94,7 +94,7 @@ val URI.idnHost: String
*
* @return The string without whitespace.
*/
fun String.removeWhiteSpace(): String = replace("\\s+".toRegex(), "")
fun String?.removeWhiteSpace(): String? = this?.replace(" ", "")
/**
* Converts the string to a Long value, or returns 0 if the conversion fails.
@@ -6,6 +6,7 @@ import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.dto.V2rayConfig.OutboundBean
import com.v2ray.ang.extension.idnHost
import com.v2ray.ang.extension.removeWhiteSpace
import com.v2ray.ang.util.Utils
import java.net.URI
@@ -132,14 +133,14 @@ object WireguardFmt : FmtBase() {
dicQuery["publickey"] = config.publicKey.orEmpty()
if (config.reserved != null) {
dicQuery["reserved"] = Utils.removeWhiteSpace(config.reserved).orEmpty()
dicQuery["reserved"] = config.reserved.removeWhiteSpace().orEmpty()
}
dicQuery["address"] = Utils.removeWhiteSpace(config.localAddress).orEmpty()
dicQuery["address"] = config.localAddress.removeWhiteSpace().orEmpty()
if (config.mtu != null) {
dicQuery["mtu"] = config.mtu.toString()
}
if (config.preSharedKey != null) {
dicQuery["presharedkey"] = Utils.removeWhiteSpace(config.preSharedKey).orEmpty()
dicQuery["presharedkey"] = config.preSharedKey.removeWhiteSpace().orEmpty()
}
return toUri(config, config.secretKey, dicQuery)
@@ -8,9 +8,9 @@ import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.NetworkType
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.dto.ServerConfig
import com.v2ray.ang.extension.removeWhiteSpace
import com.v2ray.ang.handler.MmkvManager.decodeServerConfig
import com.v2ray.ang.util.JsonUtil
import com.v2ray.ang.util.Utils
object MigrateManager {
private const val ID_SERVER_CONFIG = "SERVER_CONFIG"
@@ -109,7 +109,7 @@ object MigrateManager {
config.insecure = tlsSettings?.allowInsecure
config.sni = tlsSettings?.serverName
config.fingerPrint = tlsSettings?.fingerprint
config.alpn = Utils.removeWhiteSpace(tlsSettings?.alpn?.joinToString(",")).toString()
config.alpn = tlsSettings?.alpn?.joinToString(",").removeWhiteSpace().toString()
config.publicKey = tlsSettings?.publicKey
config.shortId = tlsSettings?.shortId
@@ -172,10 +172,10 @@ object MigrateManager {
outbound.settings?.let { wireguard ->
config.secretKey = wireguard.secretKey
config.localAddress = Utils.removeWhiteSpace((wireguard.address as List<*>).joinToString(",")).toString()
config.localAddress = (wireguard.address as List<*>).joinToString(",").removeWhiteSpace().toString()
config.publicKey = wireguard.peers?.getOrNull(0)?.publicKey
config.mtu = wireguard.mtu
config.reserved = Utils.removeWhiteSpace(wireguard.reserved?.joinToString(",")).toString()
config.reserved = wireguard.reserved?.joinToString(",").removeWhiteSpace().toString()
}
return config
}
@@ -199,7 +199,7 @@ object MigrateManager {
outbound.streamSettings?.tlsSettings?.let { tlsSetting ->
config.insecure = tlsSetting.allowInsecure
config.sni = tlsSetting.serverName
config.alpn = Utils.removeWhiteSpace(tlsSetting.alpn?.joinToString(",")).orEmpty()
config.alpn = tlsSetting.alpn?.joinToString(",").removeWhiteSpace().orEmpty()
}
config.obfsPassword = outbound.settings?.obfsPassword
@@ -32,10 +32,10 @@ import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.system.Os
import android.widget.Toast
import androidx.core.os.bundleOf
import com.v2ray.ang.AngApplication
import com.v2ray.ang.extension.listenForPackageChanges
import com.v2ray.ang.extension.toast
import com.v2ray.ang.plugin.PluginContract.METADATA_KEY_ID
import java.io.File
import java.io.FileNotFoundException
@@ -126,7 +126,7 @@ object PluginManager {
if (providers.size > 1) {
val message =
"Conflicting plugins found from: ${providers.joinToString { it.providerInfo.packageName }}"
Toast.makeText(AngApplication.application, message, Toast.LENGTH_LONG).show()
AngApplication.application.toast(message)
throw IllegalStateException(message)
}
val provider = providers.single().providerInfo
@@ -224,8 +224,8 @@ object PluginManager {
fun ComponentInfo.loadString(key: String) = when (val value = metaData.getString(key)) {
is String -> value
is Int -> AngApplication.application.packageManager.getResourcesForApplication(applicationInfo)
.getString(value)
// is Int -> AngApplication.application.packageManager.getResourcesForApplication(applicationInfo)
// .getString(value)
null -> null
else -> error("meta-data $key has invalid type ${value.javaClass}")
@@ -1,6 +1,5 @@
package com.v2ray.ang.service
import android.annotation.TargetApi
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
@@ -9,6 +8,7 @@ import android.graphics.drawable.Icon
import android.os.Build
import android.service.quicksettings.Tile
import android.service.quicksettings.TileService
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
@@ -16,7 +16,7 @@ import com.v2ray.ang.util.MessageUtil
import com.v2ray.ang.util.Utils
import java.lang.ref.SoftReference
@TargetApi(Build.VERSION_CODES.N)
@RequiresApi(Build.VERSION_CODES.N)
class QSTileService : TileService() {
/**
@@ -5,7 +5,6 @@ import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
@@ -14,6 +13,7 @@ import com.v2ray.ang.AppConfig
import com.v2ray.ang.BuildConfig
import com.v2ray.ang.R
import com.v2ray.ang.databinding.ActivityAboutBinding
import com.v2ray.ang.extension.toast
import com.v2ray.ang.handler.SpeedtestManager
import com.v2ray.ang.util.Utils
import com.v2ray.ang.util.ZipUtil
@@ -195,8 +195,4 @@ class AboutActivity : BaseActivity() {
}
}
}
private fun toast(messageResId: Int) {
Toast.makeText(this, getString(messageResId), Toast.LENGTH_SHORT).show()
}
}
@@ -21,8 +21,8 @@ import androidx.core.content.ContextCompat
import androidx.core.view.GravityCompat
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.navigation.NavigationView
import com.google.android.material.tabs.TabLayout
import com.v2ray.ang.AppConfig
@@ -162,7 +162,11 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
}
binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_DOUBLE_COLUMN_DISPLAY, false)) {
binding.recyclerView.layoutManager = GridLayoutManager(this, 2)
} else {
binding.recyclerView.layoutManager = GridLayoutManager(this, 1)
}
addCustomDividerToRecyclerView(binding.recyclerView, this, R.drawable.custom_divider)
binding.recyclerView.adapter = adapter
@@ -17,13 +17,13 @@ import com.v2ray.ang.databinding.ItemQrcodeBinding
import com.v2ray.ang.databinding.ItemRecyclerFooterBinding
import com.v2ray.ang.databinding.ItemRecyclerMainBinding
import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.extension.toast
import com.v2ray.ang.handler.AngConfigManager
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.helper.ItemTouchHelperAdapter
import com.v2ray.ang.helper.ItemTouchHelperViewHolder
import com.v2ray.ang.service.V2RayServiceManager
import com.v2ray.ang.util.Utils
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@@ -37,7 +37,11 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
private val share_method: Array<out String> by lazy {
mActivity.resources.getStringArray(R.array.share_method)
}
private val share_method_more: Array<out String> by lazy {
mActivity.resources.getStringArray(R.array.share_method_more)
}
var isRunning = false
private val doubleColumnDisplay = MmkvManager.decodeSettingsBool(AppConfig.PREF_DOUBLE_COLUMN_DISPLAY, false)
override fun getItemCount() = mActivity.mainViewModel.serversCache.size + 1
@@ -45,150 +49,134 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
if (holder is MainViewHolder) {
val guid = mActivity.mainViewModel.serversCache[position].guid
val profile = mActivity.mainViewModel.serversCache[position].profile
// //filter
// if (mActivity.mainViewModel.subscriptionId.isNotEmpty()
// && mActivity.mainViewModel.subscriptionId != config.subscriptionId
// ) {
// holder.itemMainBinding.cardView.visibility = View.GONE
// } else {
// holder.itemMainBinding.cardView.visibility = View.VISIBLE
// }
val isCustom = profile.configType == EConfigType.CUSTOM
val aff = MmkvManager.decodeServerAffiliationInfo(guid)
holder.itemMainBinding.tvName.text = profile.remarks
holder.itemView.setBackgroundColor(Color.TRANSPARENT)
//Name address
holder.itemMainBinding.tvName.text = profile.remarks
holder.itemMainBinding.tvStatistics.text = getAddress(profile)
holder.itemMainBinding.tvType.text = profile.configType.name
//TestResult
val aff = MmkvManager.decodeServerAffiliationInfo(guid)
holder.itemMainBinding.tvTestResult.text = aff?.getTestDelayString().orEmpty()
if ((aff?.testDelayMillis ?: 0L) < 0L) {
holder.itemMainBinding.tvTestResult.setTextColor(ContextCompat.getColor(mActivity, R.color.colorPingRed))
} else {
holder.itemMainBinding.tvTestResult.setTextColor(ContextCompat.getColor(mActivity, R.color.colorPing))
}
//layoutIndicator
if (guid == MmkvManager.getSelectServer()) {
holder.itemMainBinding.layoutIndicator.setBackgroundResource(R.color.colorAccent)
} else {
holder.itemMainBinding.layoutIndicator.setBackgroundResource(0)
}
holder.itemMainBinding.tvSubscription.text =
if (mActivity.mainViewModel.subscriptionId.isEmpty())
MmkvManager.decodeSubscription(profile.subscriptionId)?.remarks.orEmpty()
else
""
var shareOptions = share_method.asList()
when (profile.configType) {
EConfigType.CUSTOM -> {
holder.itemMainBinding.tvType.text = mActivity.getString(R.string.server_customize_config)
shareOptions = shareOptions.takeLast(1)
//subscription remarks
val subRemarks = getSubscriptionRemarks(profile)
holder.itemMainBinding.tvSubscription.text = subRemarks
holder.itemMainBinding.layoutSubscription.visibility = if (subRemarks.isEmpty()) View.GONE else View.VISIBLE
//layout
if (doubleColumnDisplay) {
holder.itemMainBinding.layoutShare.visibility = View.GONE
holder.itemMainBinding.layoutEdit.visibility = View.GONE
holder.itemMainBinding.layoutRemove.visibility = View.GONE
holder.itemMainBinding.layoutMore.visibility = View.VISIBLE
//share method
val shareOptions = if (isCustom) share_method_more.asList().takeLast(3) else share_method_more.asList()
holder.itemMainBinding.layoutMore.setOnClickListener {
shareServer(guid, profile, position, shareOptions, if (isCustom) 2 else 0)
}
} else {
holder.itemMainBinding.layoutShare.visibility = View.VISIBLE
holder.itemMainBinding.layoutEdit.visibility = View.VISIBLE
holder.itemMainBinding.layoutRemove.visibility = View.VISIBLE
holder.itemMainBinding.layoutMore.visibility = View.GONE
//share method
val shareOptions = if (isCustom) share_method.asList().takeLast(1) else share_method.asList()
holder.itemMainBinding.layoutShare.setOnClickListener {
shareServer(guid, profile, position, shareOptions, if (isCustom) 2 else 0)
}
else -> {
holder.itemMainBinding.tvType.text = profile.configType.name
holder.itemMainBinding.layoutEdit.setOnClickListener {
editServer(guid, profile)
}
}
// Hide xxx:xxx:***/xxx.xxx.xxx.***
val strState = "${
profile.server?.let {
if (it.contains(":"))
it.split(":").take(2).joinToString(":", postfix = ":***")
else
it.split('.').dropLast(1).joinToString(".", postfix = ".***")
}
} : ${profile.serverPort}"
holder.itemMainBinding.tvStatistics.text = strState
holder.itemMainBinding.layoutShare.setOnClickListener {
AlertDialog.Builder(mActivity).setItems(shareOptions.toTypedArray()) { _, i ->
try {
when (i) {
0 -> {
if (profile.configType == EConfigType.CUSTOM) {
shareFullContent(guid)
} else {
val ivBinding = ItemQrcodeBinding.inflate(LayoutInflater.from(mActivity))
ivBinding.ivQcode.setImageBitmap(AngConfigManager.share2QRCode(guid))
AlertDialog.Builder(mActivity).setView(ivBinding.root).show()
}
}
1 -> {
if (AngConfigManager.share2Clipboard(mActivity, guid) == 0) {
mActivity.toast(R.string.toast_success)
} else {
mActivity.toast(R.string.toast_failure)
}
}
2 -> shareFullContent(guid)
else -> mActivity.toast("else")
}
} catch (e: Exception) {
e.printStackTrace()
}
}.show()
}
holder.itemMainBinding.layoutEdit.setOnClickListener {
val intent = Intent().putExtra("guid", guid)
.putExtra("isRunning", isRunning)
.putExtra("createConfigType", profile.configType.value)
if (profile.configType == EConfigType.CUSTOM) {
mActivity.startActivity(intent.setClass(mActivity, ServerCustomConfigActivity::class.java))
} else {
mActivity.startActivity(intent.setClass(mActivity, ServerActivity::class.java))
}
}
holder.itemMainBinding.layoutRemove.setOnClickListener {
if (guid != MmkvManager.getSelectServer()) {
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_CONFIRM_REMOVE) == true) {
AlertDialog.Builder(mActivity).setMessage(R.string.del_config_comfirm)
.setPositiveButton(android.R.string.ok) { _, _ ->
removeServer(guid, position)
}
.setNegativeButton(android.R.string.cancel) { _, _ ->
//do noting
}
.show()
} else {
removeServer(guid, position)
}
} else {
application.toast(R.string.toast_action_not_allowed)
holder.itemMainBinding.layoutRemove.setOnClickListener {
removeServer(guid, position)
}
}
holder.itemMainBinding.infoContainer.setOnClickListener {
val selected = MmkvManager.getSelectServer()
if (guid != selected) {
MmkvManager.setSelectServer(guid)
if (!TextUtils.isEmpty(selected)) {
notifyItemChanged(mActivity.mainViewModel.getPosition(selected.orEmpty()))
}
notifyItemChanged(mActivity.mainViewModel.getPosition(guid))
if (isRunning) {
V2RayServiceManager.stopVService(mActivity)
mActivity.lifecycleScope.launch {
try {
delay(500)
V2RayServiceManager.startVService(mActivity)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
setSelectServer(guid)
}
}
if (holder is FooterViewHolder) {
if (true) {
holder.itemFooterBinding.layoutEdit.visibility = View.INVISIBLE
} else {
holder.itemFooterBinding.layoutEdit.setOnClickListener {
Utils.openUri(mActivity, "${Utils.decode(AppConfig.PromotionUrl)}?t=${System.currentTimeMillis()}")
}
// if (holder is FooterViewHolder) {
// if (true) {
// holder.itemFooterBinding.layoutEdit.visibility = View.INVISIBLE
// } else {
// holder.itemFooterBinding.layoutEdit.setOnClickListener {
// Utils.openUri(mActivity, "${Utils.decode(AppConfig.PromotionUrl)}?t=${System.currentTimeMillis()}")
// }
// }
// }
}
private fun getAddress(profile: ProfileItem): String {
// Hide xxx:xxx:***/xxx.xxx.xxx.***
return "${
profile.server?.let {
if (it.contains(":"))
it.split(":").take(2).joinToString(":", postfix = ":***")
else
it.split('.').dropLast(1).joinToString(".", postfix = ".***")
}
} : ${profile.serverPort}"
}
private fun getSubscriptionRemarks(profile: ProfileItem): String {
val subRemarks =
if (mActivity.mainViewModel.subscriptionId.isEmpty())
MmkvManager.decodeSubscription(profile.subscriptionId)?.remarks?.firstOrNull()
else
null
return subRemarks?.toString() ?: ""
}
private fun shareServer(guid: String, profile: ProfileItem, position: Int, shareOptions: List<String>, skip: Int) {
AlertDialog.Builder(mActivity).setItems(shareOptions.toTypedArray()) { _, i ->
try {
when (i + skip) {
0 -> showQRCode(guid)
1 -> share2Clipboard(guid)
2 -> shareFullContent(guid)
3 -> editServer(guid, profile)
4 -> removeServer(guid, position)
else -> mActivity.toast("else")
}
} catch (e: Exception) {
e.printStackTrace()
}
}.show()
}
private fun showQRCode(guid: String) {
val ivBinding = ItemQrcodeBinding.inflate(LayoutInflater.from(mActivity))
ivBinding.ivQcode.setImageBitmap(AngConfigManager.share2QRCode(guid))
AlertDialog.Builder(mActivity).setView(ivBinding.root).show()
}
private fun share2Clipboard(guid: String) {
if (AngConfigManager.share2Clipboard(mActivity, guid) == 0) {
mActivity.toast(R.string.toast_success)
} else {
mActivity.toast(R.string.toast_failure)
}
}
@@ -200,12 +188,64 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
}
}
private fun editServer(guid: String, profile: ProfileItem) {
val intent = Intent().putExtra("guid", guid)
.putExtra("isRunning", isRunning)
.putExtra("createConfigType", profile.configType.value)
if (profile.configType == EConfigType.CUSTOM) {
mActivity.startActivity(intent.setClass(mActivity, ServerCustomConfigActivity::class.java))
} else {
mActivity.startActivity(intent.setClass(mActivity, ServerActivity::class.java))
}
}
private fun removeServer(guid: String, position: Int) {
if (guid != MmkvManager.getSelectServer()) {
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_CONFIRM_REMOVE) == true) {
AlertDialog.Builder(mActivity).setMessage(R.string.del_config_comfirm)
.setPositiveButton(android.R.string.ok) { _, _ ->
removeServerSub(guid, position)
}
.setNegativeButton(android.R.string.cancel) { _, _ ->
//do noting
}
.show()
} else {
removeServerSub(guid, position)
}
} else {
application.toast(R.string.toast_action_not_allowed)
}
}
private fun removeServerSub(guid: String, position: Int) {
mActivity.mainViewModel.removeServer(guid)
notifyItemRemoved(position)
notifyItemRangeChanged(position, mActivity.mainViewModel.serversCache.size)
}
private fun setSelectServer(guid: String) {
val selected = MmkvManager.getSelectServer()
if (guid != selected) {
MmkvManager.setSelectServer(guid)
if (!TextUtils.isEmpty(selected)) {
notifyItemChanged(mActivity.mainViewModel.getPosition(selected.orEmpty()))
}
notifyItemChanged(mActivity.mainViewModel.getPosition(guid))
if (isRunning) {
V2RayServiceManager.stopVService(mActivity)
mActivity.lifecycleScope.launch {
try {
delay(500)
V2RayServiceManager.startVService(mActivity)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
return when (viewType) {
VIEW_TYPE_ITEM ->
@@ -4,7 +4,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.v2ray.ang.R
import com.v2ray.ang.databinding.ItemRecyclerBypassListBinding
import com.v2ray.ang.dto.AppInfo
@@ -35,7 +34,7 @@ class PerAppProxyAdapter(val activity: BaseActivity, val apps: List<AppInfo>, bl
val view = View(ctx)
view.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ctx.resources.getDimensionPixelSize(R.dimen.view_height_dp64) * 0
0
)
BaseViewHolder(view)
}
@@ -78,7 +78,7 @@ class ServerCustomConfigActivity : BaseActivity() {
CustomFmt.parse(binding.editor.text.toString())
} catch (e: Exception) {
e.printStackTrace()
ToastCompat.makeText(this, "${getString(R.string.toast_malformed_josn)} ${e.cause?.message}", Toast.LENGTH_LONG).show()
toast("${getString(R.string.toast_malformed_josn)} ${e.cause?.message}")
return false
}
@@ -238,6 +238,7 @@ class SettingsActivity : BaseActivity() {
AppConfig.PREF_SPEED_ENABLED,
AppConfig.PREF_CONFIRM_REMOVE,
AppConfig.PREF_START_SCAN_IMMEDIATE,
AppConfig.PREF_DOUBLE_COLUMN_DISPLAY,
AppConfig.PREF_PREFER_IPV6,
AppConfig.PREF_PROXY_SHARING,
AppConfig.PREF_ALLOW_INSECURE
@@ -53,7 +53,10 @@ class SubSettingRecyclerAdapter(val activity: SubSettingActivity) : RecyclerView
if (TextUtils.isEmpty(subItem.url)) {
holder.itemSubSettingBinding.layoutShare.visibility = View.INVISIBLE
holder.itemSubSettingBinding.chkEnable.visibility = View.INVISIBLE
} else {
holder.itemSubSettingBinding.layoutShare.visibility = View.VISIBLE
holder.itemSubSettingBinding.chkEnable.visibility = View.VISIBLE
holder.itemSubSettingBinding.layoutShare.setOnClickListener {
AlertDialog.Builder(mActivity)
.setItems(share_method.asList().toTypedArray()) { _, i ->
@@ -17,8 +17,14 @@ object HttpUtil {
* @return The ASCII representation of the URL.
*/
fun idnToASCII(str: String): String {
val url = URL(str)
return URL(url.protocol, IDN.toASCII(url.host, IDN.ALLOW_UNASSIGNED), url.port, url.file).toExternalForm()
val url = URI(str)
val host = url.host
val asciiHost = IDN.toASCII(url.host, IDN.ALLOW_UNASSIGNED)
if (host != asciiHost) {
return str.replace(host, asciiHost)
} else {
return str
}
}
/**
@@ -4,7 +4,6 @@ import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration.UI_MODE_NIGHT_MASK
import android.content.res.Configuration.UI_MODE_NIGHT_NO
import android.os.Build
@@ -437,25 +436,6 @@ object Utils {
.replace("|", "%7C")
}
/**
* Remove white space from a string.
*
* @param str The string to process.
* @return The string without white space.
*/
fun removeWhiteSpace(str: String?): String? {
return str?.replace(" ", "")
}
/**
* Check if the device is a TV.
*
* @param context The context to use.
* @return True if the device is a TV, false otherwise.
*/
fun isTv(context: Context): Boolean =
context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
/**
* Find a free port from a list of ports.
*
@@ -162,7 +162,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
continue
}
if (keywordFilter.isEmpty() || profile.remarks.contains(keywordFilter)) {
if (keywordFilter.isEmpty() || profile.remarks.lowercase().contains(keywordFilter.lowercase())) {
serversCache.add(ServersCache(guid, profile))
}
}
@@ -73,6 +73,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
AppConfig.PREF_BYPASS_APPS,
AppConfig.PREF_CONFIRM_REMOVE,
AppConfig.PREF_START_SCAN_IMMEDIATE,
AppConfig.PREF_DOUBLE_COLUMN_DISPLAY,
AppConfig.SUBSCRIPTION_AUTO_UPDATE,
AppConfig.PREF_FRAGMENT_ENABLED,
AppConfig.PREF_MUX_ENABLED,
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" />
</vector>
@@ -0,0 +1,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/divider_color_light" />
<size
android:width="48dp"
android:height="48dp"/>
</shape>
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" />
</vector>
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
@@ -57,7 +58,7 @@
<LinearLayout
android:id="@+id/layout_share"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp72"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
@@ -81,7 +82,7 @@
<LinearLayout
android:id="@+id/layout_restore"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp72"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
@@ -113,7 +114,7 @@
<LinearLayout
android:id="@+id/layout_soure_ccode"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp72"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
@@ -137,7 +138,7 @@
<LinearLayout
android:id="@+id/layout_oss_licenses"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp72"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
@@ -161,7 +162,7 @@
<LinearLayout
android:id="@+id/layout_feedback"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp72"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
@@ -186,7 +187,7 @@
<LinearLayout
android:id="@+id/layout_tg_channel"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp72"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
@@ -210,7 +211,7 @@
<LinearLayout
android:id="@+id/layout_privacy_policy"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp72"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
@@ -233,7 +234,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp72"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:padding="@dimen/padding_spacing_dp16">
@@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<com.google.android.material.progressindicator.LinearProgressIndicator
@@ -19,8 +20,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="@dimen/padding_spacing_dp16"
android:paddingEnd="@dimen/padding_spacing_dp16">
android:padding="@dimen/padding_spacing_dp16">
<LinearLayout
android:layout_width="match_parent"
@@ -29,7 +29,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp64"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
@@ -83,7 +83,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
tools:context=".ui.PerAppProxyActivity" />
</LinearLayout>
@@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.LogcatActivity">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
@@ -47,7 +47,8 @@
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_group"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp64"
android:layout_height="wrap_content"
android:padding="@dimen/padding_spacing_dp8"
app:tabIndicatorFullWidth="false"
app:tabMode="scrollable"
app:tabTextAppearance="@style/TabLayoutTextStyle" />
@@ -64,19 +65,24 @@
android:id="@+id/layout_test"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp64"
android:background="@color/colorPrimary"
android:clickable="true"
android:focusable="true"
android:gravity="center|start"
android:nextFocusLeft="@+id/recycler_view"
android:orientation="vertical"
android:nextFocusRight="@+id/fab">
<View
android:layout_width="wrap_content"
android:layout_height="1dp"
android:background="@color/divider_color_light" />
<TextView
android:id="@+id/tv_test_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:maxLines="2"
android:minLines="1"
android:gravity="start|center"
android:paddingStart="@dimen/padding_spacing_dp16"
android:text="@string/connection_test_pending"
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
@@ -85,20 +91,18 @@
</LinearLayout>
<FrameLayout
android:id="@+id/fabProgressCircle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginBottom="@dimen/padding_spacing_dp16">
android:layout_marginEnd="@dimen/padding_spacing_dp16"
android:layout_marginBottom="@dimen/padding_spacing_dp8">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/padding_spacing_dp16"
android:layout_marginBottom="@dimen/view_height_dp64"
android:clickable="true"
android:focusable="true"
android:nextFocusLeft="@+id/layout_test"
@@ -4,6 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:fitsSystemWindows="true"
tools:context=".ui.SubSettingActivity">
<LinearLayout
@@ -31,7 +32,7 @@
<EditText
android:id="@+id/et_remarks"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -117,7 +118,7 @@
<EditText
android:id="@+id/et_port"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -135,7 +136,7 @@
<EditText
android:id="@+id/et_protocol"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:hint="@string/routing_settings_protocol_tip"
android:inputType="text" />
</LinearLayout>
@@ -154,7 +155,7 @@
<EditText
android:id="@+id/et_network"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:hint="@string/routing_settings_network_tip"
android:inputType="text" />
</LinearLayout>
@@ -171,9 +172,11 @@
android:text="@string/routing_settings_outbound_tag" />
<Spinner
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:id="@+id/sp_outbound_tag"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:entries="@array/outbound_tag" />
</LinearLayout>
@@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.RoutingSettingActivity">
<androidx.core.widget.NestedScrollView
@@ -28,6 +29,8 @@
android:text="@string/routing_settings_domain_strategy" />
<Spinner
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:id="@+id/sp_domain_strategy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.ServerCustomConfigActivity">
<LinearLayout
@@ -51,7 +52,7 @@
<EditText
android:id="@+id/et_remarks"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.ServerActivity">
<LinearLayout
@@ -27,7 +28,7 @@
<EditText
android:id="@+id/et_id"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -46,7 +47,7 @@
<EditText
android:id="@+id/et_obfs_password"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -65,7 +66,7 @@
<EditText
android:id="@+id/et_port_hop"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -84,7 +85,7 @@
<EditText
android:id="@+id/et_port_hop_interval"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="number" />
</LinearLayout>
@@ -103,7 +104,7 @@
<EditText
android:id="@+id/et_bandwidth_down"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -122,7 +123,7 @@
<EditText
android:id="@+id/et_bandwidth_up"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.ServerActivity">
<LinearLayout
@@ -27,7 +28,7 @@
<EditText
android:id="@+id/et_id"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -45,9 +46,11 @@
android:text="@string/server_lab_security3" />
<Spinner
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:id="@+id/sp_security"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:entries="@array/ss_securitys" />
</LinearLayout>
@@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.ServerActivity">
<LinearLayout
@@ -28,7 +29,7 @@
<EditText
android:id="@+id/et_security"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -47,7 +48,7 @@
<EditText
android:id="@+id/et_id"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.ServerActivity">
<LinearLayout
@@ -27,7 +28,7 @@
<EditText
android:id="@+id/et_id"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.ServerActivity">
<LinearLayout
@@ -27,7 +28,7 @@
<EditText
android:id="@+id/et_id"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -44,9 +45,11 @@
android:text="@string/server_lab_flow" />
<Spinner
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:id="@+id/sp_flow"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:entries="@array/flows" />
</LinearLayout>
@@ -64,7 +67,7 @@
<EditText
android:id="@+id/et_security"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text"
android:text="none" />
@@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.ServerActivity">
<LinearLayout
@@ -27,7 +28,7 @@
<EditText
android:id="@+id/et_id"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -44,9 +45,11 @@
android:text="@string/server_lab_security" />
<Spinner
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:id="@+id/sp_security"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:entries="@array/securitys" />
</LinearLayout>
@@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.ServerActivity">
<LinearLayout
@@ -27,7 +28,7 @@
<EditText
android:id="@+id/et_id"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -47,7 +48,7 @@
<EditText
android:id="@+id/et_public_key"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -66,7 +67,7 @@
<EditText
android:id="@+id/et_preshared_key"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -90,7 +91,7 @@
<EditText
android:id="@+id/et_reserved1"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -110,7 +111,7 @@
<EditText
android:id="@+id/et_local_address"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -128,7 +129,7 @@
<EditText
android:id="@+id/et_local_mtu"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="number" />
</LinearLayout>
@@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical"
tools:context=".ui.SettingsActivity">
@@ -4,6 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:fitsSystemWindows="true"
tools:context=".ui.SubSettingActivity">
<LinearLayout
@@ -43,7 +44,7 @@
<EditText
android:id="@+id/et_remarks"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -87,7 +88,7 @@
<EditText
android:id="@+id/et_filter"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -151,7 +152,7 @@
<EditText
android:id="@+id/et_pre_profile"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:hint="@string/sub_setting_pre_profile_tip"
android:inputType="text" />
@@ -171,7 +172,7 @@
<EditText
android:id="@+id/et_next_profile"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:hint="@string/sub_setting_pre_profile_tip"
android:inputType="text" />
@@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.SubSettingActivity">
<com.google.android.material.progressindicator.LinearProgressIndicator
@@ -3,13 +3,15 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical"
android:padding="@dimen/padding_spacing_dp16"
tools:context=".ui.TaskerActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp64">
android:layout_height="wrap_content"
android:padding="@dimen/padding_spacing_dp8">
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/switch_start_service"
@@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".ui.UserAssetUrlActivity">
<LinearLayout
@@ -42,7 +43,7 @@
<EditText
android:id="@+id/et_remarks"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -16,9 +16,11 @@
android:orientation="vertical">
<Spinner
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:id="@+id/sp_subscriptionId"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48" />
android:layout_height="wrap_content" />
</LinearLayout>
@@ -36,7 +38,7 @@
<EditText
android:id="@+id/et_keyword"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -5,17 +5,18 @@
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="@dimen/padding_spacing_dp8"
android:gravity="center_vertical">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon"
android:layout_width="@dimen/view_height_dp72"
android:layout_height="@dimen/view_height_dp72"
android:padding="@dimen/padding_spacing_dp16" />
android:layout_width="@dimen/view_height_dp48"
android:layout_height="@dimen/view_height_dp48"
android:padding="@dimen/padding_spacing_dp8" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="@dimen/view_height_dp72"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:gravity="center"
android:orientation="vertical">
@@ -42,6 +43,6 @@
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false"
android:paddingEnd="@dimen/padding_spacing_dp16"/>
android:padding="@dimen/padding_spacing_dp8" />
</LinearLayout>
@@ -8,9 +8,10 @@
<LinearLayout
android:id="@+id/layout_edit"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:visibility="invisible"
android:orientation="horizontal"
android:padding="@dimen/padding_spacing_dp16">
@@ -18,8 +19,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center|left"
android:orientation="vertical"
android:paddingBottom="@dimen/padding_spacing_dp16">
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
@@ -10,78 +10,195 @@
<LinearLayout
android:id="@+id/info_container"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp72"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:nextFocusRight="@+id/layout_share"
android:orientation="horizontal">
android:orientation="horizontal"
android:paddingTop="@dimen/padding_spacing_dp8"
android:paddingEnd="@dimen/padding_spacing_dp4"
android:paddingStart="@dimen/padding_spacing_dp4"
android:paddingBottom="@dimen/padding_spacing_dp8">
<LinearLayout
android:id="@+id/layout_indicator"
android:layout_width="6dp"
android:layout_marginStart="4dp"
android:layout_width="@dimen/padding_spacing_dp4"
android:layout_height="match_parent"
android:layout_gravity="center"
android:orientation="vertical" />
<LinearLayout
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingStart="@dimen/padding_spacing_dp16">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
android:minLines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
<TextView
android:id="@+id/tv_statistics"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lines="1"
android:paddingTop="@dimen/padding_spacing_dp8"
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="@dimen/padding_spacing_dp8">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
android:minLines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="@dimen/padding_spacing_dp8">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/layout_subscription"
android:layout_width="@dimen/image_size_dp24"
android:layout_height="@dimen/image_size_dp24"
android:layout_gravity="bottom"
android:layout_marginEnd="@dimen/padding_spacing_dp4"
android:background="@drawable/ic_circle">
<TextView
android:id="@+id/tv_subscription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textSize="11sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/tv_statistics"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/layout_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:nextFocusLeft="@+id/info_container"
android:orientation="vertical"
android:padding="@dimen/padding_spacing_dp8">
<ImageView
android:layout_width="wrap_content"
android:layout_height="@dimen/image_size_dp24"
app:srcCompat="@drawable/ic_share_24dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/padding_spacing_dp8">
<ImageView
android:layout_width="@dimen/image_size_dp24"
android:layout_height="@dimen/image_size_dp24"
app:srcCompat="@drawable/ic_edit_24dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_remove"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/padding_spacing_dp8">
<ImageView
android:layout_width="@dimen/image_size_dp24"
android:layout_height="@dimen/image_size_dp24"
app:srcCompat="@drawable/ic_delete_24dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/padding_spacing_dp8">
<ImageView
android:layout_width="@dimen/image_size_dp24"
android:layout_height="@dimen/image_size_dp24"
app:srcCompat="@drawable/ic_more_vert_24dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="4dp"
android:paddingEnd="@dimen/padding_spacing_dp16">
android:paddingStart="@dimen/padding_spacing_dp8"
android:paddingTop="@dimen/padding_spacing_dp8"
android:paddingEnd="@dimen/padding_spacing_dp8">
<TextView
android:id="@+id/tv_subscription"
android:id="@+id/tv_type"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:lines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="@color/color_secondary"
android:textColor="@color/colorConfigType"
android:textSize="11sp"
tools:text="Sub" />
tools:text="VLESS" />
<TextView
android:id="@+id/tv_test_result"
@@ -92,90 +209,11 @@
android:textColor="@color/colorPing"
android:textSize="11sp"
tools:text="214ms" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/layout_share"
android:layout_width="wrap_content"
android:layout_height="@dimen/view_height_dp72"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:nextFocusLeft="@+id/info_container"
android:orientation="vertical"
android:padding="@dimen/padding_spacing_dp8">
<ImageView
android:layout_width="wrap_content"
android:layout_height="@dimen/image_size_dp24"
app:srcCompat="@drawable/ic_share_24dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_edit"
android:layout_width="wrap_content"
android:layout_height="@dimen/view_height_dp72"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/padding_spacing_dp8">
<ImageView
android:layout_width="@dimen/image_size_dp24"
android:layout_height="@dimen/image_size_dp24"
app:srcCompat="@drawable/ic_edit_24dp" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_remove"
android:layout_width="wrap_content"
android:layout_height="@dimen/view_height_dp72"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/padding_spacing_dp8">
<ImageView
android:layout_width="@dimen/image_size_dp24"
android:layout_height="@dimen/image_size_dp24"
app:srcCompat="@drawable/ic_delete_24dp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:orientation="vertical"
android:paddingBottom="4dp"
android:paddingEnd="@dimen/padding_spacing_dp16">
<TextView
android:id="@+id/tv_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="@color/colorConfigType"
android:textSize="11sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
@@ -9,7 +9,7 @@
<LinearLayout
android:id="@+id/info_container"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp90"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?attr/selectableItemBackground"
android:clickable="true"
@@ -17,15 +17,14 @@
android:gravity="center"
android:nextFocusRight="@+id/layout_edit"
android:orientation="horizontal"
android:paddingTop="@dimen/padding_spacing_dp8"
android:paddingBottom="@dimen/padding_spacing_dp8">
android:padding="@dimen/padding_spacing_dp8">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingStart="@dimen/padding_spacing_dp16">
android:padding="@dimen/padding_spacing_dp8">
<LinearLayout
android:layout_width="wrap_content"
@@ -68,11 +67,10 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="@dimen/view_height_dp90"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:paddingStart="@dimen/padding_spacing_dp16"
android:paddingEnd="@dimen/padding_spacing_dp16">
android:padding="@dimen/padding_spacing_dp8">
<LinearLayout
android:id="@+id/layout_edit"
@@ -9,7 +9,7 @@
<LinearLayout
android:id="@+id/info_container"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp90"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?attr/selectableItemBackground"
android:clickable="true"
@@ -17,15 +17,14 @@
android:gravity="center"
android:nextFocusRight="@+id/layout_edit"
android:orientation="horizontal"
android:paddingTop="@dimen/padding_spacing_dp8"
android:paddingBottom="@dimen/padding_spacing_dp8">
android:padding="@dimen/padding_spacing_dp8">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingStart="@dimen/padding_spacing_dp16">
android:padding="@dimen/padding_spacing_dp8">
<TextView
android:id="@+id/tv_name"
@@ -45,11 +44,10 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="@dimen/view_height_dp90"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:paddingStart="@dimen/padding_spacing_dp16"
android:paddingEnd="@dimen/padding_spacing_dp16">
android:padding="@dimen/padding_spacing_dp8">
<LinearLayout
android:layout_width="wrap_content"
@@ -18,7 +18,7 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingStart="@dimen/padding_spacing_dp16">
android:padding="@dimen/padding_spacing_dp8">
<LinearLayout
android:layout_width="wrap_content"
@@ -30,7 +30,7 @@
<EditText
android:id="@+id/et_remarks"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -49,7 +49,7 @@
<EditText
android:id="@+id/et_address"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -68,7 +68,7 @@
<EditText
android:id="@+id/et_port"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="number" />
</LinearLayout>
+16 -8
View File
@@ -19,9 +19,11 @@
android:text="@string/server_lab_stream_security" />
<Spinner
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:id="@+id/sp_stream_security"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:entries="@array/streamsecurityxs"
android:nextFocusDown="@+id/et_sni" />
@@ -42,7 +44,7 @@
<EditText
android:id="@+id/et_sni"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text"
android:nextFocusDown="@+id/sp_stream_fingerprint" />
@@ -61,9 +63,11 @@
android:text="@string/server_lab_stream_fingerprint" />
<Spinner
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:id="@+id/sp_stream_fingerprint"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:entries="@array/streamsecurity_utls"
android:nextFocusDown="@+id/sp_stream_alpn" />
@@ -82,9 +86,11 @@
android:text="@string/server_lab_stream_alpn" />
<Spinner
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:id="@+id/sp_stream_alpn"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:entries="@array/streamsecurity_alpn"
android:nextFocusDown="@+id/sp_allow_insecure" />
@@ -102,9 +108,11 @@
android:text="@string/server_lab_allow_insecure" />
<Spinner
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:id="@+id/sp_allow_insecure"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:entries="@array/allowinsecures" />
</LinearLayout>
@@ -123,7 +131,7 @@
<EditText
android:id="@+id/et_public_key"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text"
android:nextFocusDown="@+id/sp_stream_fingerprint" />
@@ -144,7 +152,7 @@
<EditText
android:id="@+id/et_short_id"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text"
android:nextFocusDown="@+id/sp_stream_fingerprint" />
@@ -165,7 +173,7 @@
<EditText
android:id="@+id/et_spider_x"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text"
android:nextFocusDown="@+id/sp_stream_fingerprint" />
@@ -19,9 +19,11 @@
android:text="@string/server_lab_stream_security" />
<Spinner
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:id="@+id/sp_stream_security"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:entries="@array/streamsecuritys"
android:nextFocusDown="@+id/et_sni" />
@@ -42,7 +44,7 @@
<EditText
android:id="@+id/et_sni"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text"
android:nextFocusDown="@+id/sp_stream_fingerprint" />
@@ -61,9 +63,11 @@
android:text="@string/server_lab_allow_insecure" />
<Spinner
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:id="@+id/sp_allow_insecure"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:entries="@array/allowinsecures" />
@@ -81,7 +85,7 @@
<EditText
android:id="@+id/et_pinsha256"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -29,9 +29,11 @@
android:text="@string/server_lab_network" />
<Spinner
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:id="@+id/sp_network"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:entries="@array/networks" />
</LinearLayout>
@@ -48,9 +50,11 @@
android:text="@string/server_lab_head_type" />
<Spinner
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:id="@+id/sp_header_type"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48" />
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
@@ -68,7 +72,7 @@
<EditText
android:id="@+id/et_request_host"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -88,7 +92,7 @@
<EditText
android:id="@+id/et_path"
android:layout_width="match_parent"
android:layout_height="@dimen/view_height_dp48"
android:layout_height="wrap_content"
android:inputType="text" />
</LinearLayout>
@@ -216,6 +216,9 @@
<string name="title_pref_append_http_proxy">Append HTTP Proxy to VPN</string>
<string name="summary_pref_append_http_proxy">HTTP proxy will be used directly from (browser/ some supported apps), without going through the virtual NIC device (Android 10+)</string>
<string name="title_pref_double_column_display">Enable double column display</string>
<string name="summary_pref_double_column_display">The profile list is displayed in double columns, allowing more content to be displayed on the screen. You need to restart the application to take effect.</string>
<!-- AboutActivity -->
<string name="title_pref_feedback">ملاحظات</string>
<string name="summary_pref_feedback">ملاحظات التحسينات أو الأخطاء إلى GitHub</string>
@@ -317,6 +320,14 @@
<item>تصدير التكوين الكامل إلى الحافظة</item>
</string-array>
<string-array name="share_method_more">
<item>QRcode</item>
<item>Export to clipboard</item>
<item>Export full configuration to clipboard</item>
<item>Edit</item>
<item>Delete</item>
</string-array>
<string-array name="share_sub_method">
<item>رمز استجابة سريعة (QRcode)</item>
<item>تصدير إلى الحافظة</item>
@@ -216,6 +216,9 @@
<string name="title_pref_append_http_proxy">Append HTTP Proxy to VPN</string>
<string name="summary_pref_append_http_proxy">HTTP proxy will be used directly from (browser/ some supported apps), without going through the virtual NIC device (Android 10+)</string>
<string name="title_pref_double_column_display">Enable double column display</string>
<string name="summary_pref_double_column_display">The profile list is displayed in double columns, allowing more content to be displayed on the screen. You need to restart the application to take effect.</string>
<!-- AboutActivity -->
<string name="title_pref_feedback">মতামত</string>
<string name="summary_pref_feedback">মতামত উন্নয়ন বা বাগগুলি GitHub-এ পাঠান</string>
@@ -309,12 +312,21 @@
<string name="title_pref_fragment_length">ফ্র্যাগমেন্ট দৈর্ঘ্য (ন্যূনতম-সর্বাধিক)</string>
<string name="title_pref_fragment_interval">ফ্র্যাগমেন্ট ইন্টারভ্যাল (ন্যূনতম-সর্বাধিক)</string>
<string name="title_pref_fragment_enabled">ফ্র্যাগমেন্ট সক্রিয় করুন</string>
<string-array name="share_method">
<item>QR কোড</item>
<item>ক্লিপবোর্ডে রপ্তানি করুন</item>
<item>পূর্ণ কনফিগারেশন ক্লিপবোর্ডে রপ্তানি করুন</item>
</string-array>
<string-array name="share_method_more">
<item>QRcode</item>
<item>Export to clipboard</item>
<item>Export full configuration to clipboard</item>
<item>Edit</item>
<item>Delete</item>
</string-array>
<string-array name="share_sub_method">
<item>QR কোড</item>
<item>ক্লিপবোর্ডে রপ্তানি করুন</item>
@@ -216,6 +216,9 @@
<string name="title_pref_append_http_proxy">پروکسی HTTP ن و VPN ازاف کۊنین</string>
<string name="summary_pref_append_http_proxy">پروکسی HTTP ن موسقیمن ز (مۊرۊرگر/ی قرد ز برنومیل لادراری بیڌه)، بؽ استفاڌه ز دسگا NIC مجازی (Android 10+) استفاڌه ابۊ.</string>
<string name="title_pref_double_column_display">Enable double column display</string>
<string name="summary_pref_double_column_display">The profile list is displayed in double columns, allowing more content to be displayed on the screen. You need to restart the application to take effect.</string>
<!-- AboutActivity -->
<string name="title_pref_feedback">فشناڌن منشڌ</string>
<string name="summary_pref_feedback">فشناڌن منشڌ یا داسوو موشکلا من Github</string>
@@ -325,6 +328,14 @@
<item>و در کشیڌن پوی کانفیگ من کلیپ بورد</item>
</string-array>
<string-array name="share_method_more">
<item>QRcode</item>
<item>Export to clipboard</item>
<item>Export full configuration to clipboard</item>
<item>Edit</item>
<item>Delete</item>
</string-array>
<string-array name="share_sub_method">
<item>QRcode</item>
<item>و در کشیڌن من کلیپ بورد</item>
+16 -4
View File
@@ -87,7 +87,7 @@
<string name="server_lab_spider_x">SpiderX</string>
<string name="server_lab_secret_key">کلید خصوصی</string>
<string name="server_lab_reserved">Reserved (اختیاری، جدا شده با کاما)</string>
<string name="server_lab_local_address">آدرس محلی IPV4 (اختیاری)</string>
<string name="server_lab_local_address">آدرس محلی (IPv4/IPv6 اختیاری، جدا شده با کاما)</string>
<string name="server_lab_local_mtu">MTU (اختیاری، پیش‌فرض 1420)</string>
<string name="toast_success">با موفقیت انجام شد</string>
<string name="toast_failure">شکست</string>
@@ -101,7 +101,7 @@
<string name="server_lab_content">محتوا</string>
<string name="toast_none_data_clipboard">هیچ داده‌ ای در کلیپ ‌بورد وجود ندارد</string>
<string name="toast_invalid_url">نشانی اینترنتی معتبر نیست</string>
<string name="toast_insecure_url_protocol">لطفاً از آدرس اشتراک پروتکل HTTP ناامن استفاده نکنید</string>
<string name="toast_insecure_url_protocol">لطفاً از آدرس های اشتراک پروتکل HTTP ناامن استفاده نکنید</string>
<string name="server_lab_need_inbound">اطمینان حاصل کنید که پورت ورودی با تنظیمات مطابقت دارد</string>
<string name="toast_malformed_josn">کانفیگ درست نیست</string>
<string name="server_lab_request_host6">هاست (SNI) (اختیاری)</string>
@@ -143,7 +143,7 @@
<string name="title_advanced">تنظیمات پیشرفته</string>
<string name="title_vpn_settings">تنظیمات VPN</string>
<string name="title_pref_per_app_proxy">پروکسی به تفکیک برنامه</string>
<string name="summary_pref_per_app_proxy">عمومی: برنامه بررسی شده پروکسی است، اتصال مستقیم بدون بررسی است. \nحالت دور زدن: برنامه بررسی شده مستقیما متصل است، پراکسی بررسی نشده است. \nگزینه‌ای برای انتخاب خودکار پروکسی برنامه در منو است.</string>
<string name="summary_pref_per_app_proxy">عمومی: برنامه انتخاب شده از طریق یک پروکسی متصل می شود، برنامه انتخاب نشده مستقیماً متصل می شود. \nحالت دور زدن: برنامه انتخاب شده مستقیماً متصل می شود، برنامه انتخاب نشده از طریق یک پروکسی متصل می شود. \nانتخاب خودکار برنامه های پراکسی در منو امکان پذیر است.</string>
<string name="title_pref_is_booted">اتصال خودکار هنگام راه اندازی</string>
<string name="summary_pref_is_booted">هنگام راه اندازی به طور خودکار به سرور انتخابی متصل می شود که ممکن است ناموفق باشد.</string>
@@ -214,6 +214,9 @@
<string name="title_pref_append_http_proxy">پروکسی HTTP را به VPN اضافه کنید</string>
<string name="summary_pref_append_http_proxy">پروکسی HTTP مستقیماً از (مرورگر/برخی برنامه‌های پشتیبانی‌شده)، بدون استفاده از دستگاه NIC مجازی (Android 10+) استفاده می‌شود.</string>
<string name="title_pref_double_column_display">Enable double column display</string>
<string name="summary_pref_double_column_display">The profile list is displayed in double columns, allowing more content to be displayed on the screen. You need to restart the application to take effect.</string>
<!-- AboutActivity -->
<string name="title_pref_feedback">بازخورد</string>
<string name="summary_pref_feedback">بازخورد یا گزارش اشکالات در گیت‌ هاب</string>
@@ -315,12 +318,21 @@
<string name="title_pref_fragment_length">طول بسته های فرگمنت (حداقل-حداکثر)</string>
<string name="title_pref_fragment_interval">فاصله بین بسته های فرگمنت (حداقل-حداکثر)</string>
<string name="title_pref_fragment_enabled">فعال کردن فرگمنت</string>
<string-array name="share_method">
<item>QRcode</item>
<item>خروجی گرفتن در کلیپ‌ بورد</item>
<item>خروجی گرفتن کانفیگ کامل در کلیپ بورد</item>
</string-array>
<string-array name="share_method_more">
<item>QRcode</item>
<item>Export to clipboard</item>
<item>Export full configuration to clipboard</item>
<item>Edit</item>
<item>Delete</item>
</string-array>
<string-array name="share_sub_method">
<item>QRcode</item>
<item>خروجی گرفتن در کلیپ‌ بورد</item>
@@ -340,7 +352,7 @@
</string-array>
<string-array name="preset_rulesets">
<item>لیست سفید چین</item>
<item>لیست سفید چین ( دور زدن سرزمین اصلی )</item>
<item>لیست سیاه چین</item>
<item>جهانی(GLOBAL)</item>
<item>ایران</item>
@@ -3,11 +3,11 @@
<style name="AppThemeDayNight" parent="Theme.AppCompat.DayNight.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimary</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:statusBarColor">@color/colorPrimary</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="colorControlNormal">@color/colorAccent</item>
<item name="android:fitsSystemWindows">true</item>
</style>
</resources>
+14 -3
View File
@@ -133,11 +133,11 @@
<string name="menu_item_select_all">Выбрать все</string>
<string name="msg_enter_keywords">Введите ключевые слова</string>
<string name="switch_bypass_apps_mode">Режим обхода</string>
<string name="menu_item_select_proxy_app">Автовыбор проксируемых приложений</string>
<string name="menu_item_select_proxy_app">Автовыбор приложений</string>
<string name="msg_downloading_content">Загрузка данных</string>
<string name="menu_item_export_proxy_app">Экспорт в буфер обмена</string>
<string name="menu_item_import_proxy_app">Импорт из буфера обмена</string>
<string name="per_app_proxy_settings">Настройки выбранных приложений</string>
<string name="per_app_proxy_settings">Выбор приложений</string>
<string name="per_app_proxy_settings_enable">Использовать выбор приложений</string>
<!-- Preferences -->
@@ -173,7 +173,7 @@
<string name="summary_pref_local_dns_enabled">Обслуживание выполняется DNS-модулем ядра (в настройках маршрутизации рекомендуется выбрать режим «Все, кроме LAN и Китая»)</string>
<string name="title_pref_fake_dns_enabled">Использовать поддельную DNS</string>
<string name="summary_pref_fake_dns_enabled">Локальная DNS возвращает поддельный IP-адрес (быстрее, но может не работать с некоторыми приложениями)</string>
<string name="summary_pref_fake_dns_enabled">Локальная DNS возвращает поддельные IP-адреса (быстрее, но может не работать с некоторыми приложениями)</string>
<string name="title_pref_prefer_ipv6">Предпочитать IPv6</string>
<string name="summary_pref_prefer_ipv6">Предпочитать IPv6-адреса и маршрутизацию</string>
@@ -215,6 +215,9 @@
<string name="title_pref_append_http_proxy">Дополнительный HTTP-прокси</string>
<string name="summary_pref_append_http_proxy">HTTP-прокси будет использоваться напрямую (из браузера и других поддерживающих приложений), минуя виртуальный сетевой адаптер (Android 10+)</string>
<string name="title_pref_double_column_display">Enable double column display</string>
<string name="summary_pref_double_column_display">The profile list is displayed in double columns, allowing more content to be displayed on the screen. You need to restart the application to take effect.</string>
<!-- AboutActivity -->
<string name="title_pref_feedback">Обратная связь</string>
<string name="summary_pref_feedback">Предложить улучшение или сообщить об ошибке на GitHub</string>
@@ -324,6 +327,14 @@
<item>Экспорт всей конфигурации в буфер обмена</item>
</string-array>
<string-array name="share_method_more">
<item>QRcode</item>
<item>Export to clipboard</item>
<item>Export full configuration to clipboard</item>
<item>Edit</item>
<item>Delete</item>
</string-array>
<string-array name="share_sub_method">
<item>QR-код</item>
<item>Экспорт в буфер обмена</item>
@@ -216,6 +216,9 @@
<string name="title_pref_append_http_proxy">Append HTTP Proxy to VPN</string>
<string name="summary_pref_append_http_proxy">HTTP proxy will be used directly from (browser/ some supported apps), without going through the virtual NIC device (Android 10+)</string>
<string name="title_pref_double_column_display">Enable double column display</string>
<string name="summary_pref_double_column_display">The profile list is displayed in double columns, allowing more content to be displayed on the screen. You need to restart the application to take effect.</string>
<!-- AboutActivity -->
<string name="title_pref_feedback">Phản hồi lỗi</string>
<string name="summary_pref_feedback">Phản hồi cải tiến hoặc lỗi lên GitHub</string>
@@ -312,6 +315,14 @@
<item>Sao chép thành cấu hình tùy chỉnh</item>
</string-array>
<string-array name="share_method_more">
<item>QRcode</item>
<item>Export to clipboard</item>
<item>Export full configuration to clipboard</item>
<item>Edit</item>
<item>Delete</item>
</string-array>
<string-array name="share_sub_method">
<item>Xuất gói ra mã QR (Chụp màn hình để lưu)</item>
<item>Xuất gói vào Clipboard</item>
@@ -213,6 +213,9 @@
<string name="title_pref_append_http_proxy">追加 HTTP 代理至 VPN</string>
<string name="summary_pref_append_http_proxy">浏览器 / 一些支持的应用 将直接使用 HTTP 代理, 而不经过虚拟网卡设备 (Android 10+)</string>
<string name="title_pref_double_column_display">启用双列显示</string>
<string name="summary_pref_double_column_display">配置文件列表以双列显示,允许在屏幕上显示更多内容。需要重启应用生效。</string>
<!-- AboutActivity -->
<string name="title_pref_feedback">反馈</string>
<string name="summary_pref_feedback">反馈改进或漏洞至 GitHub</string>
@@ -316,6 +319,14 @@
<item>导出完整配置至剪贴板</item>
</string-array>
<string-array name="share_method_more">
<item>二维码</item>
<item>导出至剪贴板</item>
<item>导出完整配置至剪贴板</item>
<item>编辑</item>
<item>删除</item>
</string-array>
<string-array name="share_sub_method">
<item>二维码</item>
<item>导出至剪贴板</item>
@@ -214,6 +214,9 @@
<string name="title_pref_append_http_proxy">追加 HTTP 代理至 VPN</string>
<string name="summary_pref_append_http_proxy">瀏覽器 / 一些支援的應用 將直接使用 HTTP 代理, 而不經過虛擬網卡設備 (Android 10+)</string>
<string name="title_pref_double_column_display">啟用雙列顯示</string>
<string name="summary_pref_double_column_display">設定檔清單以雙列顯示,允許在螢幕上顯示更多內容。需要重啟應用生效。</string>
<!-- AboutActivity -->
<string name="title_pref_feedback">意見回饋</string>
<string name="summary_pref_feedback">前往 GitHub 回報錯誤</string>
@@ -316,6 +319,14 @@
<item>匯出完整設定至剪貼簿</item>
</string-array>
<string-array name="share_method_more">
<item>QR Code</item>
<item>匯出至剪貼簿</item>
<item>匯出完整設定至剪貼簿</item>
<item>編輯</item>
<item>刪除</item>
</string-array>
<string-array name="share_sub_method">
<item>QR Code</item>
<item>匯出至剪貼簿</item>
+1 -4
View File
@@ -1,13 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="padding_spacing_dp4">4dp</dimen>
<dimen name="padding_spacing_dp8">8dp</dimen>
<dimen name="padding_spacing_dp16">16dp</dimen>
<dimen name="image_size_dp24">24dp</dimen>
<dimen name="view_height_dp48">48dp</dimen>
<dimen name="view_height_dp64">64dp</dimen>
<dimen name="view_height_dp72">72dp</dimen>
<dimen name="view_height_dp90">90dp</dimen>
<dimen name="view_height_dp160">160dp</dimen>
</resources>
@@ -217,6 +217,9 @@
<string name="title_pref_append_http_proxy">Append HTTP Proxy to VPN</string>
<string name="summary_pref_append_http_proxy">HTTP proxy will be used directly from (browser/ some supported apps), without going through the virtual NIC device (Android 10+)</string>
<string name="title_pref_double_column_display">Enable double column display</string>
<string name="summary_pref_double_column_display">The profile list is displayed in double columns, allowing more content to be displayed on the screen. You need to restart the application to take effect.</string>
<!-- AboutActivity -->
<string name="title_pref_feedback">Feedback</string>
<string name="summary_pref_feedback">Feedback enhancements or bugs to GitHub</string>
@@ -326,6 +329,14 @@
<item>Export full configuration to clipboard</item>
</string-array>
<string-array name="share_method_more">
<item>QRcode</item>
<item>Export to clipboard</item>
<item>Export full configuration to clipboard</item>
<item>Edit</item>
<item>Delete</item>
</string-array>
<string-array name="share_sub_method">
<item>QRcode</item>
<item>Export to clipboard</item>
+1 -1
View File
@@ -2,11 +2,11 @@
<style name="AppThemeDayNight" parent="Theme.AppCompat.DayNight">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimary</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:statusBarColor">@color/colorPrimary</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="colorControlNormal">@color/colorAccent</item>
<item name="android:fitsSystemWindows">true</item>
</style>
<style name="AppThemeDayNight.NoActionBar" parent="AppThemeDayNight">
@@ -75,6 +75,11 @@
android:summary="@string/summary_pref_start_scan_immediate"
android:title="@string/title_pref_start_scan_immediate" />
<CheckBoxPreference
android:key="pref_double_column_display"
android:summary="@string/summary_pref_double_column_display"
android:title="@string/title_pref_double_column_display" />
<ListPreference
android:defaultValue="auto"
android:entries="@array/language_select"