Improve SubscriptionsViewModel

This commit is contained in:
2dust committed 2026-07-19 21:22:35 +08:00
1 parent ca79a574fa
commit 1dee6230f9
4 files changed
+54 -45

No files matched your search

@@ -17,8 +17,8 @@ import java.io.Serializable
import java.net.URI
import java.util.Locale
val Context.v2RayApplication: AngApplication?
get() = applicationContext as? AngApplication
val myApp: AngApplication
get() = AngApplication.application
private inline fun runOnMain(crossinline block: () -> Unit) {
if (Looper.myLooper() == Looper.getMainLooper()) {
@@ -24,7 +24,6 @@ import androidx.compose.material3.Switch
import androidx.compose.material3.SwitchDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -37,7 +36,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
import com.v2ray.ang.compose.AppDivider
@@ -49,21 +47,15 @@ import com.v2ray.ang.compose.ReorderableListItem
import com.v2ray.ang.compose.colorFabActive
import com.v2ray.ang.compose.verticalScrollbar
import com.v2ray.ang.extension.toast
import com.v2ray.ang.handler.AngConfigManager
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.util.QRCodeDecoder
import com.v2ray.ang.util.Utils
import com.v2ray.ang.viewmodel.SubscriptionsViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import sh.calvin.reorderable.ReorderableItem
import sh.calvin.reorderable.rememberReorderableLazyListState
class SubSettingActivity : BaseComponentActivity() {
private val viewModel: SubscriptionsViewModel by viewModels()
private val isLoadingState = MutableStateFlow(false)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -71,12 +63,13 @@ class SubSettingActivity : BaseComponentActivity() {
@Composable
override fun ScreenContent() {
val isLoading by viewModel.isLoading.collectAsStateWithLifecycle()
SubSettingScreen(
viewModel = viewModel,
isLoadingState = isLoadingState,
isLoading = isLoading,
onBackClick = { finish() },
onAddClick = { startActivity(Intent(this, SubEditActivity::class.java)) },
onSubUpdate = { updateSubscriptions() },
onSubUpdate = { viewModel.updateSubscriptions() },
onEditSub = { subId ->
startActivity(Intent(this, SubEditActivity::class.java).putExtra("subId", subId))
},
@@ -98,37 +91,13 @@ class SubSettingActivity : BaseComponentActivity() {
private fun removeSub(subId: String) {
viewModel.remove(subId)
}
private fun updateSubscriptions() {
isLoadingState.value = true
lifecycleScope.launch(Dispatchers.IO) {
val result = AngConfigManager.updateConfigViaSubAll()
delay(500L)
launch(Dispatchers.Main) {
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 {
toast(
getString(
R.string.title_update_subscription_result,
result.configCount, result.successCount, result.failureCount, result.skipCount
)
)
}
isLoadingState.value = false
viewModel.reload()
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SubSettingScreen(
viewModel: SubscriptionsViewModel,
isLoadingState: MutableStateFlow<Boolean>,
isLoading: Boolean,
onBackClick: () -> Unit,
onAddClick: () -> Unit,
onSubUpdate: () -> Unit,
@@ -139,7 +108,6 @@ fun SubSettingScreen(
shareSubMethodEntries: List<String>
) {
val subscriptions by viewModel.subsFlow.collectAsStateWithLifecycle()
val isLoading by isLoadingState.collectAsState()
var removeTarget by remember { mutableStateOf<String?>(null) }
val confirmRemove = MmkvManager.decodeSettingsBool(AppConfig.PREF_CONFIRM_REMOVE, false)
@@ -2,7 +2,7 @@ package com.v2ray.ang.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.v2ray.ang.AngApplication
import com.v2ray.ang.extension.myApp
import com.v2ray.ang.extension.toast
import com.v2ray.ang.extension.toastError
import com.v2ray.ang.extension.toastSuccess
@@ -31,42 +31,56 @@ abstract class BaseViewModel : ViewModel() {
* Send neutral toast event (Resource ID).
*/
fun toast(resId: Int) {
AngApplication.application.toast(resId)
myApp.toast(resId)
}
/**
* Send neutral toast event (String).
*/
fun toast(message: String) {
AngApplication.application.toast(message)
myApp.toast(message)
}
/**
* Send success toast event (Resource ID).
*/
fun toastSuccess(resId: Int) {
AngApplication.application.toastSuccess(resId)
myApp.toastSuccess(resId)
}
/**
* Send success toast event (String).
*/
fun toastSuccess(message: String) {
AngApplication.application.toastSuccess(message)
myApp.toastSuccess(message)
}
/**
* Send error toast event (Resource ID).
*/
fun toastError(resId: Int) {
AngApplication.application.toastError(resId)
myApp.toastError(resId)
}
/**
* Send error toast event (String).
*/
fun toastError(message: String) {
AngApplication.application.toastError(message)
myApp.toastError(message)
}
/**
* Get string from resource ID.
*/
fun getString(resId: Int): String {
return myApp.getString(resId)
}
/**
* Get formatted string from resource ID.
*/
fun getString(resId: Int, vararg formatArgs: Any?): String {
return myApp.getString(resId, *formatArgs)
}
/**
@@ -1,13 +1,18 @@
package com.v2ray.ang.viewmodel
import com.v2ray.ang.R
import com.v2ray.ang.dto.entities.SubscriptionCache
import com.v2ray.ang.dto.entities.SubscriptionItem
import com.v2ray.ang.handler.AngConfigManager
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.handler.SettingsChangeManager
import com.v2ray.ang.handler.SettingsManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.withContext
class SubscriptionsViewModel : BaseViewModel() {
private val subscriptions: MutableList<SubscriptionCache> =
@@ -52,4 +57,26 @@ class SubscriptionsViewModel : BaseViewModel() {
_subsFlow.value = subscriptions.toList()
}
}
fun updateSubscriptions() {
launchLoading {
val result = withContext(Dispatchers.IO) {
AngConfigManager.updateConfigViaSubAll()
}
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 {
toast(
getString(
R.string.title_update_subscription_result,
result.configCount, result.successCount, result.failureCount, result.skipCount
)
)
}
reload()
}
}
}