diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5caa7e89..17ec8eeb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -136,6 +136,11 @@
android:configChanges="uiMode"
android:exported="false"
android:label="@string/override" />
+
() {
+ override suspend fun main() {
+ val configuration = withClash { queryOverride(Clash.OverrideSlot.Persist) }
+
+ defer {
+ withClash {
+ patchOverride(Clash.OverrideSlot.Persist, configuration)
+ }
+ }
+
+ val design = MetaFeatureSettingsDesign(
+ this,
+ configuration
+ )
+
+ setContentDesign(design)
+
+ while (isActive) {
+ select {
+ events.onReceive {
+
+ }
+ design.requests.onReceive {
+ when (it) {
+ MetaFeatureSettingsDesign.Request.ResetOverride -> {
+ if (design.requestResetConfirm()) {
+ defer {
+ withClash {
+ clearOverride(Clash.OverrideSlot.Persist)
+ }
+ }
+
+ finish()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/github/kr328/clash/SettingsActivity.kt b/app/src/main/java/com/github/kr328/clash/SettingsActivity.kt
index 0d5fcb9b..95a03933 100644
--- a/app/src/main/java/com/github/kr328/clash/SettingsActivity.kt
+++ b/app/src/main/java/com/github/kr328/clash/SettingsActivity.kt
@@ -24,6 +24,8 @@ class SettingsActivity : BaseActivity() {
startActivity(NetworkSettingsActivity::class.intent)
SettingsDesign.Request.StartOverride ->
startActivity(OverrideSettingsActivity::class.intent)
+ SettingsDesign.Request.StartMetaFeature ->
+ startActivity(MetaFeatureSettingsActivity::class.intent)
}
}
}
diff --git a/core/src/main/java/com/github/kr328/clash/core/model/ConfigurationOverride.kt b/core/src/main/java/com/github/kr328/clash/core/model/ConfigurationOverride.kt
index 43a4ab23..f82da9a8 100644
--- a/core/src/main/java/com/github/kr328/clash/core/model/ConfigurationOverride.kt
+++ b/core/src/main/java/com/github/kr328/clash/core/model/ConfigurationOverride.kt
@@ -44,11 +44,32 @@ data class ConfigurationOverride(
@SerialName("hosts")
var hosts: Map? = null,
+ @SerialName("force-cert-verify")
+ var forceCertVeriy: Boolean? = null,
+
+ @SerialName("unified-delay")
+ var unifiedDelay: Boolean? = null,
+
+ @SerialName("geodata-mode")
+ var geodataMode: Boolean? = null,
+
+ @SerialName("tcp-concurrent")
+ var tcpConcurrent: Boolean? = null,
+
+ @SerialName("enable-process")
+ var enableProcess: Boolean? = null,
+
@SerialName("dns")
val dns: Dns = Dns(),
@SerialName("clash-for-android")
val app: App = App(),
+
+ @SerialName("sniffer")
+ val sniffer: Sniffer = Sniffer(),
+
+ @SerialName("geox-url")
+ val geoxurl: GeoXUrl = GeoXUrl(),
) : Parcelable {
@Serializable
data class Dns(
@@ -119,6 +140,33 @@ data class ConfigurationOverride(
FakeIp,
}
+ @Serializable
+ data class Sniffer(
+ @SerialName("enable")
+ var enable: Boolean? = null,
+
+ @SerialName("sniffing")
+ var sniffing: List? = null,
+
+ @SerialName("force-domain")
+ var forceDomain: List? = null,
+
+ @SerialName("skip-domain")
+ var skipDomain: List? = null,
+ )
+
+ @Serializable
+ data class GeoXUrl(
+ @SerialName("geoip")
+ var geoip: String? = null,
+
+ @SerialName("mmdb")
+ var mmdb: String? = null,
+
+ @SerialName("geosite")
+ var geosite: String? = null,
+ )
+
override fun writeToParcel(parcel: Parcel, flags: Int) {
Parcelizer.encodeToParcel(serializer(), parcel, this)
}
diff --git a/design/src/main/java/com/github/kr328/clash/design/HelpDesign.kt b/design/src/main/java/com/github/kr328/clash/design/HelpDesign.kt
index 047eb3d1..552ff3f3 100644
--- a/design/src/main/java/com/github/kr328/clash/design/HelpDesign.kt
+++ b/design/src/main/java/com/github/kr328/clash/design/HelpDesign.kt
@@ -3,7 +3,6 @@ package com.github.kr328.clash.design
import android.content.Context
import android.net.Uri
import android.view.View
-import com.github.kr328.clash.common.compat.preferredLocale
import com.github.kr328.clash.design.databinding.DesignSettingsCommonBinding
import com.github.kr328.clash.design.preference.category
import com.github.kr328.clash.design.preference.clickable
@@ -45,60 +44,32 @@ class HelpDesign(
}
}
- category(R.string.feedback)
+ clickable(
+ title = R.string.clash_meta_wiki,
+ summary = R.string.clash_meta_wiki_url
+ ) {
+ clicked {
+ openLink(Uri.parse(context.getString(R.string.clash_meta_wiki_url)))
+ }
+ }
- if (BuildConfig.PREMIUM) {
- clickable(
- title = R.string.google_play,
- summary = R.string.google_play_url
- ) {
- clicked {
- openLink(Uri.parse(context.getString(R.string.google_play_url)))
- }
+ category(R.string.sources)
+
+ clickable(
+ title = R.string.clash_meta_for_android,
+ summary = R.string.meta_github_url
+ ) {
+ clicked {
+ openLink(Uri.parse(context.getString(R.string.meta_github_url)))
}
}
clickable(
- title = R.string.github_issues,
- summary = R.string.github_issues_url
+ title = R.string.clash_meta_core,
+ summary = R.string.clash_meta_core_url
) {
clicked {
- openLink(Uri.parse(context.getString(R.string.github_issues_url)))
- }
- }
-
- if (!BuildConfig.PREMIUM) {
- category(R.string.sources)
-
- clickable(
- title = R.string.clash_for_android,
- summary = R.string.github_url
- ) {
- clicked {
- openLink(Uri.parse(context.getString(R.string.github_url)))
- }
- }
-
- clickable(
- title = R.string.clash_core,
- summary = R.string.clash_core_url
- ) {
- clicked {
- openLink(Uri.parse(context.getString(R.string.clash_core_url)))
- }
- }
- }
-
- if (context.resources.configuration.preferredLocale.language == "zh") {
- category(R.string.donate)
-
- clickable(
- title = R.string.donate,
- summary = R.string.donate_url
- ) {
- clicked {
- openLink(Uri.parse(context.getString(R.string.donate_url)))
- }
+ openLink(Uri.parse(context.getString(R.string.clash_meta_core_url)))
}
}
}
diff --git a/design/src/main/java/com/github/kr328/clash/design/MetaFeatureSettingsDesign.kt b/design/src/main/java/com/github/kr328/clash/design/MetaFeatureSettingsDesign.kt
new file mode 100644
index 00000000..b9dd6dac
--- /dev/null
+++ b/design/src/main/java/com/github/kr328/clash/design/MetaFeatureSettingsDesign.kt
@@ -0,0 +1,198 @@
+package com.github.kr328.clash.design
+
+import android.content.Context
+import android.view.View
+import com.github.kr328.clash.core.model.ConfigurationOverride
+import com.github.kr328.clash.design.databinding.DesignSettingsMetaFeatureBinding
+import com.github.kr328.clash.design.preference.*
+import com.github.kr328.clash.design.util.*
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlin.coroutines.resume
+
+class MetaFeatureSettingsDesign(
+ context: Context,
+ configuration: ConfigurationOverride
+) : Design(context) {
+ enum class Request {
+ ResetOverride
+ }
+
+ private val binding = DesignSettingsMetaFeatureBinding
+ .inflate(context.layoutInflater, context.root, false)
+
+ override val root: View
+ get() = binding.root
+
+ suspend fun requestResetConfirm(): Boolean {
+ return suspendCancellableCoroutine { ctx ->
+ val dialog = MaterialAlertDialogBuilder(context)
+ .setTitle(R.string.reset_override_settings)
+ .setMessage(R.string.reset_override_settings_message)
+ .setPositiveButton(R.string.ok) { _, _ -> ctx.resume(true) }
+ .setNegativeButton(R.string.cancel) { _, _ -> }
+ .show()
+
+ dialog.setOnDismissListener {
+ if (!ctx.isCompleted)
+ ctx.resume(false)
+ }
+
+ ctx.invokeOnCancellation {
+ dialog.dismiss()
+ }
+ }
+ }
+
+ init {
+ binding.self = this
+
+ binding.activityBarLayout.applyFrom(context)
+
+ binding.scrollRoot.bindAppBarElevation(binding.activityBarLayout)
+
+ val booleanValues: Array = arrayOf(
+ null,
+ true,
+ false
+ )
+ val booleanValuesText: Array = arrayOf(
+ R.string.dont_modify,
+ R.string.enabled,
+ R.string.disabled
+ )
+
+ val screen = preferenceScreen(context) {
+ category(R.string.meta_features)
+
+ selectableList(
+ value = configuration::forceCertVeriy,
+ values = booleanValues,
+ valuesText = booleanValuesText,
+ title = R.string.force_cert_verify,
+ )
+
+ selectableList(
+ value = configuration::unifiedDelay,
+ values = booleanValues,
+ valuesText = booleanValuesText,
+ title = R.string.unified_delay,
+ )
+
+ selectableList(
+ value = configuration::geodataMode,
+ values = booleanValues,
+ valuesText = booleanValuesText,
+ title = R.string.geodata_mode,
+ )
+
+ selectableList(
+ value = configuration::tcpConcurrent,
+ values = booleanValues,
+ valuesText = booleanValuesText,
+ title = R.string.tcp_concurrent,
+ )
+
+ selectableList(
+ value = configuration::enableProcess,
+ values = booleanValues,
+ valuesText = booleanValuesText,
+ title = R.string.enable_process,
+ )
+
+ category(R.string.sniffer_setting)
+
+ val snifferDependencies: MutableList = mutableListOf()
+
+ val sniffer = selectableList(
+ value = configuration.sniffer::enable,
+ values = arrayOf(
+ null,
+ true,
+ false
+ ),
+ valuesText = arrayOf(
+ R.string.sniffer_config,
+ R.string.sniffer_override,
+ R.string.disable_sniffer,
+ ),
+ title = R.string.strategy
+ ) {
+ listener = OnChangedListener {
+ if (configuration.sniffer.enable == false) {
+ snifferDependencies.forEach {
+ it.enabled = false
+ }
+ } else {
+ snifferDependencies.forEach {
+ it.enabled = true
+ }
+ }
+ }
+ }
+
+ editableTextList(
+ value = configuration.sniffer::sniffing,
+ adapter = TextAdapter.String,
+ title = R.string.sniffing,
+ placeholder = R.string.dont_modify,
+ configure = snifferDependencies::add,
+ )
+
+ editableTextList(
+ value = configuration.sniffer::forceDomain,
+ adapter = TextAdapter.String,
+ title = R.string.force_domain,
+ placeholder = R.string.dont_modify,
+ configure = snifferDependencies::add,
+ )
+
+ editableTextList(
+ value = configuration.sniffer::skipDomain,
+ adapter = TextAdapter.String,
+ title = R.string.skip_domain,
+ placeholder = R.string.dont_modify,
+ configure = snifferDependencies::add,
+ )
+
+ sniffer.listener?.onChanged()
+
+ category(R.string.geox_url_setting)
+
+ val geoxurlDependencies: MutableList = mutableListOf()
+
+ editableText(
+ value = configuration.geoxurl::geoip,
+ adapter = NullableTextAdapter.String,
+ title = R.string.geox_geoip,
+ placeholder = R.string.dont_modify,
+ empty = R.string.geoip_url,
+ configure = geoxurlDependencies::add,
+ )
+
+ editableText(
+ value = configuration.geoxurl::geoip,
+ adapter = NullableTextAdapter.String,
+ title = R.string.geox_mmdb,
+ placeholder = R.string.dont_modify,
+ empty = R.string.mmdb_url,
+ configure = geoxurlDependencies::add,
+ )
+
+ editableText(
+ value = configuration.geoxurl::geoip,
+ adapter = NullableTextAdapter.String,
+ title = R.string.geox_geosite,
+ placeholder = R.string.dont_modify,
+ empty = R.string.geosite_url,
+ configure = geoxurlDependencies::add,
+ )
+ }
+
+ binding.content.addView(screen.root)
+ }
+
+ fun requestClear() {
+ requests.trySend(Request.ResetOverride)
+ }
+}
diff --git a/design/src/main/java/com/github/kr328/clash/design/SettingsDesign.kt b/design/src/main/java/com/github/kr328/clash/design/SettingsDesign.kt
index d6f6c190..0536a587 100644
--- a/design/src/main/java/com/github/kr328/clash/design/SettingsDesign.kt
+++ b/design/src/main/java/com/github/kr328/clash/design/SettingsDesign.kt
@@ -10,7 +10,7 @@ import com.github.kr328.clash.design.util.root
class SettingsDesign(context: Context) : Design(context) {
enum class Request {
- StartApp, StartNetwork, StartOverride,
+ StartApp, StartNetwork, StartOverride, StartMetaFeature,
}
private val binding = DesignSettingsBinding
diff --git a/design/src/main/res/drawable/ic_baseline_meta.xml b/design/src/main/res/drawable/ic_baseline_meta.xml
new file mode 100644
index 00000000..51125abc
--- /dev/null
+++ b/design/src/main/res/drawable/ic_baseline_meta.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/design/src/main/res/layout/design_settings.xml b/design/src/main/res/layout/design_settings.xml
index b36cf5f1..885ec4a5 100644
--- a/design/src/main/res/layout/design_settings.xml
+++ b/design/src/main/res/layout/design_settings.xml
@@ -49,6 +49,13 @@
app:icon="@drawable/ic_baseline_extension"
app:text="@string/override" />
+
+
diff --git a/design/src/main/res/layout/design_settings_meta_feature.xml b/design/src/main/res/layout/design_settings_meta_feature.xml
new file mode 100644
index 00000000..50c869f7
--- /dev/null
+++ b/design/src/main/res/layout/design_settings_meta_feature.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/design/src/main/res/values-zh-rHK/strings.xml b/design/src/main/res/values-zh-rHK/strings.xml
index 2c8a7c20..d1d2bc0e 100644
--- a/design/src/main/res/values-zh-rHK/strings.xml
+++ b/design/src/main/res/values-zh-rHK/strings.xml
@@ -6,7 +6,7 @@
訪問控制應用包列表
追加系統 DNS
應用損壞
- Clash for Android
+ Clash Meta for Android
自動更新
行為
繞過私有網絡
@@ -43,7 +43,7 @@
從 URL 導入
界面
無效的 URL
- Clash
+ Clash Meta for Android
Logcat
日誌
模式
@@ -79,12 +79,11 @@
更新時間
應用包名稱
安裝時間
- Clash for Android
反饋
Github Issues
Clash 配置文件(包含代理/規則)]]>
載入中
- 免費軟件並且我們不為其提供任何服務, 請務必不要反饋非應用自身引起的問題]]>
+ 免費軟件並且我們不為其提供任何服務, 請務必不要反饋非應用自身引起的問題]]>
捐贈
允許所有應用
僅允許已選擇的應用
@@ -209,8 +208,9 @@
僅在本次會話中有效
導入
源代碼
- Clash 核心
+ Clash 核心
Name Server 策略
阻止本地迴環
阻止本地迴環連接
+ Clash Meta for Android
\ No newline at end of file
diff --git a/design/src/main/res/values-zh-rTW/strings.xml b/design/src/main/res/values-zh-rTW/strings.xml
index 765556c6..b96b6bcf 100644
--- a/design/src/main/res/values-zh-rTW/strings.xml
+++ b/design/src/main/res/values-zh-rTW/strings.xml
@@ -6,7 +6,7 @@
存取控制應用程式套件清單
附加作業系統 DNS
應用程式損毀
- Clash for Android
+ Clash Meta for Android
自動更新
行為
略過私有網路
@@ -43,7 +43,7 @@
從 URL 匯入
介面
無效 URL
- Clash
+ Clash Meta for Android
Logcat
日誌
模式
@@ -79,12 +79,11 @@
更新時間
套件名稱
安裝時間
- Clash for Android
回饋
Github Issues
Clash 設定檔 (包含Proxy /規則)]]>
載入中
- 免費應用程式並且我們不為其提供任何服務, 請務必不要回報非應用程式自身引起的問題]]>
+ 免費應用程式並且我們不為其提供任何服務, 請務必不要回報非應用程式自身引起的問題]]>
捐助
允許所有應用
僅允許已選擇的應用
@@ -209,8 +208,9 @@
僅在本次工作階段中有效
匯入
原始碼
- Clash 核心
+ Clash 核心
Name Server 政策
攔截本地回送
攔截本地回送連結
+ Clash Meta for Android
diff --git a/design/src/main/res/values-zh/strings.xml b/design/src/main/res/values-zh/strings.xml
index 3233e568..63b2bb5f 100644
--- a/design/src/main/res/values-zh/strings.xml
+++ b/design/src/main/res/values-zh/strings.xml
@@ -6,7 +6,7 @@
访问控制应用包列表
追加系统 DNS
应用损坏
- Clash for Android
+ Clash Meta for Android
自动更新
行为
绕过私有网络
@@ -43,7 +43,7 @@
从 URL 导入
界面
无效的 URL
- Clash
+ Clash Meta for Android
Logcat
日志
模式
@@ -79,12 +79,12 @@
更新时间
应用包名称
安装时间
- Clash for Android
+ Clash Meta for Android
反馈
Github Issues
Clash 配置文件(包含代理/规则)]]>
载入中
- 免费软件并且我们不为其提供任何服务, 请务必不要反馈非应用自身引起的问题]]>
+ 免费软件并且我们不为其提供任何服务, 请务必不要反馈非应用自身引起的问题]]>
捐赠
允许所有应用
仅允许已选择的应用
@@ -209,7 +209,7 @@
仅在本次会话中有效
导入
源代码
- Clash 核心
+ Clash Meta 核心
Name Server 策略
阻止本地回环
阻止本地回环连接
diff --git a/design/src/main/res/values/strings.xml b/design/src/main/res/values/strings.xml
index 5f44ad29..3f277cf3 100644
--- a/design/src/main/res/values/strings.xml
+++ b/design/src/main/res/values/strings.xml
@@ -1,6 +1,6 @@
- Clash
- Clash for Android
+ Clash Meta for Android
+ Clash Meta for Android
Stopped
Tap to start
@@ -49,7 +49,6 @@
App lacks the necessary runtime components, which is usually caused by downloading an incomplete apk.
Reinstall
Github Releases
- https://github.com/kr328/clashforandroid/releases
Profile
Name
@@ -196,7 +195,7 @@
Import from Clipboard
Export to Clipboard
- Clash for Android
+ Clash Meta for Android
Document
Feedback
@@ -205,15 +204,13 @@
Clash Wiki
Github Issues
Google Play
- Clash Core
+ Clash Meta Core
https://github.com/Dreamacro/clash/wiki
- https://github.com/Kr328/ClashForAndroid/issues
- https://donate.kr328.app
- https://github.com/Kr328/ClashForAndroid
- https://github.com/Dreamacro/clash
+ https://github.com/MetaCubeX/ClashMetaForAndroid
+ https://github.com/MetaCubeX/Clash.Meta
Clash Config(including Proxy/Rules)]]>
- freeware and we do NOT provide any service for it]]>
+ freeware and we do NOT provide any service for it]]>
https://play.google.com/store/apps/details?id=com.github.kr328.clash
@@ -278,4 +275,31 @@
The settings have been reseted and the old profiles needs to be saved again.
Valid only for current session
+
+ Clash Meta Wiki
+ https://docs.metacubex.one/
+
+ Meta Features
+ Force Cert Verify
+ Unified Delay
+ Geodata Mode
+ TCP Concurrent
+ Enable Process
+
+ Sniffer Setting
+ Sniffer
+ Sniffer Mode
+ Force Domain
+ Skip Domain
+ Disable Sniffer
+ Load Sniffer From Config
+ Override Sniffer Config
+
+ GeoX Url Setting
+ GeoIp Url
+ MMDB Url
+ Geosite Url
+ https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geoip.dat
+ https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb
+ https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat