From a12ca3ea04b0ba367930a358bd374f3e59223041 Mon Sep 17 00:00:00 2001 From: owo <93107371+Q7DF1@users.noreply.github.com> Date: Sat, 21 Mar 2026 14:22:10 +0800 Subject: [PATCH] Feature/regex and protocol search (#5364) * add windows compile options * add regex search and search from protocol function(#5354) * Delete compile-hevtun.bat * Delete fix_headers.bat * Extract matchesPattern to extension --------- Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com> --- .../main/java/com/v2ray/ang/extension/_Ext.kt | 11 ++++++++ .../com/v2ray/ang/viewmodel/MainViewModel.kt | 25 +++++++++++++------ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/extension/_Ext.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/extension/_Ext.kt index c78661ca..909d3a3b 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/extension/_Ext.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/extension/_Ext.kt @@ -189,4 +189,15 @@ fun String.concatUrl(vararg paths: String): String { } return builder.toString() +} + +/** + * Helper function to match text either by Regex or literal string. + */ +fun String.matchesPattern(regex: Regex?, keyword: String?, ignoreCase: Boolean = true): Boolean { + if (keyword.isNullOrEmpty()) { + return true + } + return regex?.containsMatchIn(this) + ?: this.contains(keyword, ignoreCase = ignoreCase) } \ No newline at end of file diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/MainViewModel.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/MainViewModel.kt index e9e07f59..88b6b7cc 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/MainViewModel.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/MainViewModel.kt @@ -19,6 +19,7 @@ import com.v2ray.ang.dto.ServersCache import com.v2ray.ang.dto.SubscriptionCache import com.v2ray.ang.dto.SubscriptionUpdateResult import com.v2ray.ang.dto.TestServiceMessage +import com.v2ray.ang.extension.matchesPattern import com.v2ray.ang.extension.serializable import com.v2ray.ang.extension.toastError import com.v2ray.ang.extension.toastSuccess @@ -35,6 +36,7 @@ import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.util.Collections +import java.util.regex.PatternSyntaxException class MainViewModel(application: Application) : AndroidViewModel(application) { private var serverList = mutableListOf() // MmkvManager.decodeServerList() @@ -117,7 +119,12 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { @Synchronized fun updateCache() { serversCache.clear() - val kw = keywordFilter.trim().lowercase() + val kw = keywordFilter.trim() + val searchRegex = try { + if (kw.isNotEmpty()) Regex(kw, setOf(RegexOption.IGNORE_CASE)) else null + } catch (e: PatternSyntaxException) { + null // Fallback to literal search if regex is invalid + } for (guid in serverList) { val profile = MmkvManager.decodeServerConfig(guid) ?: continue if (kw.isEmpty()) { @@ -125,11 +132,15 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { continue } - val remarks = profile.remarks.lowercase() - val description = profile.description.orEmpty().lowercase() - val server = profile.server.orEmpty().lowercase() - - if (remarks.contains(kw) || description.contains(kw) || server.contains(kw)) { + val remarks = profile.remarks + val description = profile.description.orEmpty() + val server = profile.server.orEmpty() + val protocol = profile.configType.name + if (remarks.matchesPattern(searchRegex, kw) + || description.matchesPattern(searchRegex, kw) + || server.matchesPattern(searchRegex, kw) + || protocol.matchesPattern(searchRegex, kw) + ) { serversCache.add(ServersCache(guid, profile)) } } @@ -479,4 +490,4 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { } } } -} \ No newline at end of file +}