Refactor subscription handling with SubscriptionCache

This commit is contained in:
2dust committed 2026-01-29 14:28:34 +08:00
1 parent 2435708628
commit be95e6a88e
8 files changed
+44 -34

No files matched your search

@@ -0,0 +1,6 @@
package com.v2ray.ang.dto
data class SubscriptionCache(
val guid: String,
val subscription: SubscriptionItem
)
@@ -9,6 +9,7 @@ import com.v2ray.ang.AppConfig.HY2
import com.v2ray.ang.R
import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.dto.SubscriptionCache
import com.v2ray.ang.dto.SubscriptionItem
import com.v2ray.ang.fmt.CustomFmt
import com.v2ray.ang.fmt.Hysteria2Fmt
@@ -399,28 +400,28 @@ object AngConfigManager {
* @param it The subscription item.
* @return The number of configurations updated.
*/
fun updateConfigViaSub(it: Pair<String, SubscriptionItem>): Int {
fun updateConfigViaSub(it: SubscriptionCache): Int {
try {
if (TextUtils.isEmpty(it.first)
|| TextUtils.isEmpty(it.second.remarks)
|| TextUtils.isEmpty(it.second.url)
if (TextUtils.isEmpty(it.guid)
|| TextUtils.isEmpty(it.subscription.remarks)
|| TextUtils.isEmpty(it.subscription.url)
) {
return 0
}
if (!it.second.enabled) {
if (!it.subscription.enabled) {
return 0
}
val url = HttpUtil.toIdnUrl(it.second.url)
val url = HttpUtil.toIdnUrl(it.subscription.url)
if (!Utils.isValidUrl(url)) {
return 0
}
if (!it.second.allowInsecureUrl) {
if (!it.subscription.allowInsecureUrl) {
if (!Utils.isValidSubUrl(url)) {
return 0
}
}
Log.i(AppConfig.TAG, url)
val userAgent = it.second.userAgent
val userAgent = it.subscription.userAgent
var configText = try {
val httpPort = SettingsManager.getHttpPort()
@@ -440,11 +441,11 @@ object AngConfigManager {
if (configText.isEmpty()) {
return 0
}
val count = parseConfigViaSub(configText, it.first, false)
val count = parseConfigViaSub(configText, it.guid, false)
if (count > 0) {
it.second.lastUpdated = System.currentTimeMillis()
MmkvManager.encodeSubscription(it.first, it.second)
Log.i(AppConfig.TAG, "Subscription updated: ${it.second.remarks}, $count configs")
it.subscription.lastUpdated = System.currentTimeMillis()
MmkvManager.encodeSubscription(it.guid, it.subscription)
Log.i(AppConfig.TAG, "Subscription updated: ${it.subscription.remarks}, $count configs")
}
return count
} catch (e: Exception) {
@@ -481,7 +482,7 @@ object AngConfigManager {
private fun importUrlAsSubscription(url: String): Int {
val subscriptions = MmkvManager.decodeSubscriptions()
subscriptions.forEach {
if (it.second.url == url) {
if (it.subscription.url == url) {
return 0
}
}
@@ -7,6 +7,7 @@ import com.v2ray.ang.dto.AssetUrlItem
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.dto.RulesetItem
import com.v2ray.ang.dto.ServerAffiliationInfo
import com.v2ray.ang.dto.SubscriptionCache
import com.v2ray.ang.dto.SubscriptionItem
import com.v2ray.ang.dto.WebDavConfig
import com.v2ray.ang.util.JsonUtil
@@ -309,15 +310,15 @@ object MmkvManager {
*
* @return The list of subscriptions.
*/
fun decodeSubscriptions(): List<Pair<String, SubscriptionItem>> {
fun decodeSubscriptions(): List<SubscriptionCache> {
initSubsList()
val subscriptions = mutableListOf<Pair<String, SubscriptionItem>>()
val subscriptions = mutableListOf<SubscriptionCache>()
decodeSubsList().forEach { key ->
val json = subStorage.decodeString(key)
if (!json.isNullOrBlank()) {
val item = JsonUtil.fromJson(json, SubscriptionItem::class.java)?: SubscriptionItem()
subscriptions.add(Pair(key, item))
subscriptions.add(SubscriptionCache(key, item))
}
}
return subscriptions
@@ -36,10 +36,10 @@ object SubscriptionUpdater {
override suspend fun doWork(): Result {
Log.i(AppConfig.TAG, "subscription automatic update starting")
val subs = MmkvManager.decodeSubscriptions().filter { it.second.autoUpdate }
val subs = MmkvManager.decodeSubscriptions().filter { it.subscription.autoUpdate }
for (sub in subs) {
val subItem = sub.second
val subItem = sub.subscription
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notification.setChannelId(AppConfig.SUBSCRIPTION_UPDATE_CHANNEL)
@@ -53,7 +53,7 @@ object SubscriptionUpdater {
}
notificationManager.notify(3, notification.build())
Log.i(AppConfig.TAG, "subscription automatic update: ---${subItem.remarks}")
AngConfigManager.updateConfigViaSub(Pair(sub.first, subItem))
AngConfigManager.updateConfigViaSub(sub)
notification.setContentText("Updating ${subItem.remarks}")
}
notificationManager.cancel(3)
@@ -119,13 +119,13 @@ class ServerGroupActivity : BaseActivity() {
val displayList = mutableListOf(getString(R.string.filter_config_all)) //none
subIds.clear()
subIds.add("") // index 0 => All
subs.forEach { (id, item) ->
subs.forEach { sub ->
val name = when {
item.remarks.isNotBlank() -> item.remarks
else -> id
sub.subscription.remarks.isNotBlank() -> sub.subscription.remarks
else -> sub.guid
}
displayList.add(name)
subIds.add(id)
subIds.add(sub.guid)
}
val subAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, displayList)
subAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
@@ -21,8 +21,8 @@ class SubSettingRecyclerAdapter(
override fun onBindViewHolder(holder: MainViewHolder, position: Int) {
val subscriptions = viewModel.getAll()
val subId = subscriptions[position].first
val subItem = subscriptions[position].second
val subId = subscriptions[position].guid
val subItem = subscriptions[position].subscription
holder.itemSubSettingBinding.tvName.text = subItem.remarks
holder.itemSubSettingBinding.tvUrl.text = subItem.url
holder.itemSubSettingBinding.chkEnable.isChecked = subItem.enabled
@@ -17,6 +17,7 @@ import com.v2ray.ang.R
import com.v2ray.ang.dto.GroupMapItem
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.dto.ServersCache
import com.v2ray.ang.dto.SubscriptionCache
import com.v2ray.ang.extension.serializable
import com.v2ray.ang.extension.toastError
import com.v2ray.ang.extension.toastSuccess
@@ -179,7 +180,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
return AngConfigManager.updateConfigViaSubAll()
} else {
val subItem = MmkvManager.decodeSubscription(subscriptionId) ?: return 0
return AngConfigManager.updateConfigViaSub(Pair(subscriptionId, subItem))
return AngConfigManager.updateConfigViaSub(SubscriptionCache(subscriptionId, subItem))
}
}
@@ -273,7 +274,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
fun getSubscriptions(context: Context): List<GroupMapItem> {
val subscriptions = MmkvManager.decodeSubscriptions()
if (subscriptionId.isNotEmpty()
&& !subscriptions.map { it.first }.contains(subscriptionId)
&& !subscriptions.map { it.guid }.contains(subscriptionId)
) {
subscriptionIdChanged("")
}
@@ -285,8 +286,8 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
remarks = context.getString(R.string.filter_config_all)
)
)
subscriptions.forEach { (id, item) ->
groups.add(GroupMapItem(id = id, remarks = item.remarks))
subscriptions.forEach { sub ->
groups.add(GroupMapItem(id = sub.guid, remarks = sub.subscription.remarks))
}
return groups
}
@@ -1,16 +1,17 @@
package com.v2ray.ang.viewmodel
import androidx.lifecycle.ViewModel
import com.v2ray.ang.dto.SubscriptionCache
import com.v2ray.ang.dto.SubscriptionItem
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.handler.SettingsChangeManager
import com.v2ray.ang.handler.SettingsManager
class SubscriptionsViewModel : ViewModel() {
private val subscriptions: MutableList<Pair<String, SubscriptionItem>> =
private val subscriptions: MutableList<SubscriptionCache> =
MmkvManager.decodeSubscriptions().toMutableList()
fun getAll(): List<Pair<String, SubscriptionItem>> = subscriptions.toList()
fun getAll(): List<SubscriptionCache> = subscriptions.toList()
fun reload() {
subscriptions.clear()
@@ -18,7 +19,7 @@ class SubscriptionsViewModel : ViewModel() {
}
fun remove(subId: String): Boolean {
val changed = subscriptions.removeAll { it.first == subId }
val changed = subscriptions.removeAll { it.guid == subId }
if (changed) {
MmkvManager.removeSubscription(subId)
SettingsChangeManager.makeSetupGroupTab()
@@ -27,9 +28,9 @@ class SubscriptionsViewModel : ViewModel() {
}
fun update(subId: String, item: SubscriptionItem) {
val idx = subscriptions.indexOfFirst { it.first == subId }
val idx = subscriptions.indexOfFirst { it.guid == subId }
if (idx >= 0) {
subscriptions[idx] = Pair(subId, item)
subscriptions[idx] = SubscriptionCache(subId, item)
MmkvManager.encodeSubscription(subId, item)
}
}