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>
This commit is contained in:
owoand2dust authored and GitHub committed 2026-03-21 14:22:10 +08:00
1 parent 4e9df84d3e
commit a12ca3ea04
2 files changed
+29 -7

No files matched your search

@@ -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)
}
@@ -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<String>() // 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) {
}
}
}
}
}