From 7475d1757b1475eff20adba5d02cb3b512808077 Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Fri, 27 Feb 2026 17:44:40 +0800 Subject: [PATCH] Add detailed subscription update result --- .../v2ray/ang/dto/SubscriptionUpdateResult.kt | 24 +++++++++ .../com/v2ray/ang/handler/AngConfigManager.kt | 49 ++++++++++++------- .../java/com/v2ray/ang/ui/MainActivity.kt | 19 +++++-- .../com/v2ray/ang/ui/SubSettingActivity.kt | 18 ++++--- .../com/v2ray/ang/viewmodel/MainViewModel.kt | 7 +-- .../app/src/main/res/values-ar/strings.xml | 2 + .../app/src/main/res/values-bn/strings.xml | 2 + .../src/main/res/values-bqi-rIR/strings.xml | 2 + .../app/src/main/res/values-fa/strings.xml | 2 + .../app/src/main/res/values-ru/strings.xml | 2 + .../app/src/main/res/values-vi/strings.xml | 2 + .../src/main/res/values-zh-rCN/strings.xml | 2 + .../src/main/res/values-zh-rTW/strings.xml | 2 + V2rayNG/app/src/main/res/values/strings.xml | 2 + 14 files changed, 101 insertions(+), 34 deletions(-) create mode 100644 V2rayNG/app/src/main/java/com/v2ray/ang/dto/SubscriptionUpdateResult.kt diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/SubscriptionUpdateResult.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/SubscriptionUpdateResult.kt new file mode 100644 index 00000000..9ccf94c0 --- /dev/null +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/SubscriptionUpdateResult.kt @@ -0,0 +1,24 @@ +package com.v2ray.ang.dto + +/** + * Result of subscription update operation + */ +data class SubscriptionUpdateResult( + val configCount: Int = 0, // Total configs updated + val successCount: Int = 0, // Subscriptions updated successfully + val failureCount: Int = 0, // Subscriptions failed to update + val skipCount: Int = 0 // Subscriptions skipped (disabled) +) { + /** + * Combine two results by adding their counts + */ + operator fun plus(other: SubscriptionUpdateResult): SubscriptionUpdateResult { + return SubscriptionUpdateResult( + configCount = this.configCount + other.configCount, + successCount = this.successCount + other.successCount, + failureCount = this.failureCount + other.failureCount, + skipCount = this.skipCount + other.skipCount + ) + } +} + diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/AngConfigManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/AngConfigManager.kt index ff41f884..7fdf6ba6 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/AngConfigManager.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/AngConfigManager.kt @@ -10,6 +10,7 @@ import com.v2ray.ang.R import com.v2ray.ang.dto.ProfileItem import com.v2ray.ang.dto.SubscriptionCache import com.v2ray.ang.dto.SubscriptionItem +import com.v2ray.ang.dto.SubscriptionUpdateResult import com.v2ray.ang.enums.EConfigType import com.v2ray.ang.extension.isNotNullEmpty import com.v2ray.ang.fmt.CustomFmt @@ -433,45 +434,48 @@ object AngConfigManager { /** * Updates the configuration via all subscriptions. * - * @return The number of configurations updated. + * @return Detailed result of the subscription update operation. */ - fun updateConfigViaSubAll(): Int { - var count = 0 - try { - MmkvManager.decodeSubscriptions().forEach { - count += updateConfigViaSub(it) + fun updateConfigViaSubAll(): SubscriptionUpdateResult { + return try { + val subscriptions = MmkvManager.decodeSubscriptions() + subscriptions.fold(SubscriptionUpdateResult()) { acc, subscription -> + acc + updateConfigViaSub(subscription) } } catch (e: Exception) { Log.e(AppConfig.TAG, "Failed to update config via all subscriptions", e) - return 0 + SubscriptionUpdateResult() } - return count } /** * Updates the configuration via a subscription. * * @param it The subscription item. - * @return The number of configurations updated. + * @return Subscription update result. */ - fun updateConfigViaSub(it: SubscriptionCache): Int { + fun updateConfigViaSub(it: SubscriptionCache): SubscriptionUpdateResult { try { + // Check if disabled + if (!it.subscription.enabled) { + return SubscriptionUpdateResult(skipCount = 1) + } + + // Validate subscription info if (TextUtils.isEmpty(it.guid) || TextUtils.isEmpty(it.subscription.remarks) || TextUtils.isEmpty(it.subscription.url) ) { - return 0 - } - if (!it.subscription.enabled) { - return 0 + return SubscriptionUpdateResult(skipCount = 1) } + val url = HttpUtil.toIdnUrl(it.subscription.url) if (!Utils.isValidUrl(url)) { - return 0 + return SubscriptionUpdateResult(failureCount = 1) } if (!it.subscription.allowInsecureUrl) { if (!Utils.isValidSubUrl(url)) { - return 0 + return SubscriptionUpdateResult(failureCount = 1) } } Log.i(AppConfig.TAG, url) @@ -493,18 +497,25 @@ object AngConfigManager { } } if (configText.isEmpty()) { - return 0 + return SubscriptionUpdateResult(failureCount = 1) } + val count = parseConfigViaSub(configText, it.guid, false) if (count > 0) { it.subscription.lastUpdated = System.currentTimeMillis() MmkvManager.encodeSubscription(it.guid, it.subscription) Log.i(AppConfig.TAG, "Subscription updated: ${it.subscription.remarks}, $count configs") + return SubscriptionUpdateResult( + configCount = count, + successCount = 1 + ) + } else { + // Got response but no valid configs parsed + return SubscriptionUpdateResult(failureCount = 1) } - return count } catch (e: Exception) { Log.e(AppConfig.TAG, "Failed to update config via subscription", e) - return 0 + return SubscriptionUpdateResult(failureCount = 1) } } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/MainActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/MainActivity.kt index 7b35b848..3f463961 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/MainActivity.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/MainActivity.kt @@ -437,14 +437,23 @@ class MainActivity : HelperBaseActivity(), NavigationView.OnNavigationItemSelect showLoading() lifecycleScope.launch(Dispatchers.IO) { - val count = mainViewModel.updateConfigViaSubAll() + val result = mainViewModel.updateConfigViaSubAll() delay(500L) launch(Dispatchers.Main) { - if (count > 0) { - toast(getString(R.string.title_update_config_count, count)) - mainViewModel.reloadServerList() + if (result.successCount + result.failureCount + result.skipCount == 0) { + toast(R.string.title_update_subscription_no_subscription) + } else if (result.successCount > 0 && result.failureCount + result.skipCount == 0) { + toast(getString(R.string.title_update_config_count, result.configCount)) } else { - toastError(R.string.toast_failure) + toast( + getString( + R.string.title_update_subscription_result, + result.configCount, result.successCount, result.failureCount, result.skipCount + ) + ) + } + if (result.configCount > 0) { + mainViewModel.reloadServerList() } hideLoading() } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SubSettingActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SubSettingActivity.kt index cd7d178c..6f42483f 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SubSettingActivity.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/SubSettingActivity.kt @@ -18,8 +18,6 @@ import com.v2ray.ang.contracts.BaseAdapterListener import com.v2ray.ang.databinding.ActivitySubSettingBinding import com.v2ray.ang.databinding.ItemQrcodeBinding import com.v2ray.ang.extension.toast -import com.v2ray.ang.extension.toastError -import com.v2ray.ang.extension.toastSuccess import com.v2ray.ang.handler.AngConfigManager import com.v2ray.ang.handler.MmkvManager import com.v2ray.ang.helper.SimpleItemTouchHelperCallback @@ -77,14 +75,20 @@ class SubSettingActivity : BaseActivity() { showLoading() lifecycleScope.launch(Dispatchers.IO) { - val count = AngConfigManager.updateConfigViaSubAll() + val result = AngConfigManager.updateConfigViaSubAll() delay(500L) launch(Dispatchers.Main) { - if (count > 0) { - toastSuccess(R.string.toast_success) - refreshData() + if (result.successCount + result.failureCount + result.skipCount == 0) { + toast(R.string.title_update_subscription_no_subscription) + } else if (result.successCount > 0 && result.failureCount + result.skipCount == 0) { + toast(getString(R.string.title_update_config_count, result.configCount)) } else { - toastError(R.string.toast_failure) + toast( + getString( + R.string.title_update_subscription_result, + result.configCount, result.successCount, result.failureCount, result.skipCount + ) + ) } hideLoading() } 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 242dc638..80fef5ff 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 @@ -17,6 +17,7 @@ import com.v2ray.ang.R import com.v2ray.ang.dto.GroupMapItem import com.v2ray.ang.dto.ServersCache import com.v2ray.ang.dto.SubscriptionCache +import com.v2ray.ang.dto.SubscriptionUpdateResult import com.v2ray.ang.extension.serializable import com.v2ray.ang.extension.toastError import com.v2ray.ang.extension.toastSuccess @@ -183,13 +184,13 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { /** * Updates the configuration via subscription for all servers. - * @return The number of updated configurations. + * @return Detailed result of the subscription update operation. */ - fun updateConfigViaSubAll(): Int { + fun updateConfigViaSubAll(): SubscriptionUpdateResult { if (subscriptionId.isEmpty()) { return AngConfigManager.updateConfigViaSubAll() } else { - val subItem = MmkvManager.decodeSubscription(subscriptionId) ?: return 0 + val subItem = MmkvManager.decodeSubscription(subscriptionId) ?: return SubscriptionUpdateResult() return AngConfigManager.updateConfigViaSub(SubscriptionCache(subscriptionId, subItem)) } } diff --git a/V2rayNG/app/src/main/res/values-ar/strings.xml b/V2rayNG/app/src/main/res/values-ar/strings.xml index e33e8274..99bea97a 100644 --- a/V2rayNG/app/src/main/res/values-ar/strings.xml +++ b/V2rayNG/app/src/main/res/values-ar/strings.xml @@ -297,6 +297,8 @@ Import %d configurations Export %d configurations Update %d configurations + Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped) + No subscriptions بدء الخدمة تأكيد diff --git a/V2rayNG/app/src/main/res/values-bn/strings.xml b/V2rayNG/app/src/main/res/values-bn/strings.xml index ab3870c1..32dacfb3 100644 --- a/V2rayNG/app/src/main/res/values-bn/strings.xml +++ b/V2rayNG/app/src/main/res/values-bn/strings.xml @@ -296,6 +296,8 @@ Import %d configurations Export %d configurations Update %d configurations + Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped) + No subscriptions সার্ভিস শুরু করুন নিশ্চিত করুন diff --git a/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml b/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml index 2d79ad15..db3c3c49 100644 --- a/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml +++ b/V2rayNG/app/src/main/res/values-bqi-rIR/strings.xml @@ -297,6 +297,8 @@ و من ٱووردن %d کانفیگ و در کشیڌن %d کانفیگ ورۊ کردن %d کانفیگ + Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped) + No subscriptions ره وندن خدمات قوۊل diff --git a/V2rayNG/app/src/main/res/values-fa/strings.xml b/V2rayNG/app/src/main/res/values-fa/strings.xml index 75278311..52d3b8f0 100644 --- a/V2rayNG/app/src/main/res/values-fa/strings.xml +++ b/V2rayNG/app/src/main/res/values-fa/strings.xml @@ -294,6 +294,8 @@ وارد کردن %d کانفیگ صادر کردن %d کانفیگ آپدیت کردن %d کانفیگ + Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped) + No subscriptions شروع خدمات تایید diff --git a/V2rayNG/app/src/main/res/values-ru/strings.xml b/V2rayNG/app/src/main/res/values-ru/strings.xml index 90090fd5..d76681d7 100644 --- a/V2rayNG/app/src/main/res/values-ru/strings.xml +++ b/V2rayNG/app/src/main/res/values-ru/strings.xml @@ -295,6 +295,8 @@ Импортировано профилей: %d Экспортировано профилей: %d Обновлено профилей: %d + Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped) + No subscriptions Запуск службы Подтвердить diff --git a/V2rayNG/app/src/main/res/values-vi/strings.xml b/V2rayNG/app/src/main/res/values-vi/strings.xml index 745d71ab..7c15e378 100644 --- a/V2rayNG/app/src/main/res/values-vi/strings.xml +++ b/V2rayNG/app/src/main/res/values-vi/strings.xml @@ -297,6 +297,8 @@ Import %d configurations Export %d configurations Update %d configurations + Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped) + No subscriptions Khởi động v2rayNG Xác nhận diff --git a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml index 77e80360..90c30b95 100644 --- a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml @@ -295,6 +295,8 @@ 导入 %d 个配置 导出 %d 个配置 更新 %d 个配置 + 更新了 %1$d 个配置(%2$d 个成功,%3$d 个失败,%4$d 个跳过) + 无订阅 启动服务 确定 diff --git a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml index 70f51cdd..79f911d1 100644 --- a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml @@ -295,6 +295,8 @@ 匯入 %d 個配置 匯出 %d 個配置 更新 %d 個配置 + 更新了 %1$d 個配置(%2$d 個成功,%3$d 個失敗,%4$d 個跳過) + 無訂閱 啟動服務 確定 diff --git a/V2rayNG/app/src/main/res/values/strings.xml b/V2rayNG/app/src/main/res/values/strings.xml index 5e4ddc8b..35459db8 100644 --- a/V2rayNG/app/src/main/res/values/strings.xml +++ b/V2rayNG/app/src/main/res/values/strings.xml @@ -301,6 +301,8 @@ Import %d configs Export %d configs Update %d configs + Updated %1$d configs (%2$d success, %3$d failed, %4$d skipped) + No subscriptions Start Service Confirm