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 263a2956..7a2cc8d1 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 @@ -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()) { 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 8d4e2667..988f72e6 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 @@ -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, + isLoading: Boolean, onBackClick: () -> Unit, onAddClick: () -> Unit, onSubUpdate: () -> Unit, @@ -139,7 +108,6 @@ fun SubSettingScreen( shareSubMethodEntries: List ) { val subscriptions by viewModel.subsFlow.collectAsStateWithLifecycle() - val isLoading by isLoadingState.collectAsState() var removeTarget by remember { mutableStateOf(null) } val confirmRemove = MmkvManager.decodeSettingsBool(AppConfig.PREF_CONFIRM_REMOVE, false) diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/BaseViewModel.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/BaseViewModel.kt index 3c8f4ba4..5c8a9771 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/BaseViewModel.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/BaseViewModel.kt @@ -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) } /** diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/SubscriptionsViewModel.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/SubscriptionsViewModel.kt index ec1b634e..e02a0cda 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/SubscriptionsViewModel.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/viewmodel/SubscriptionsViewModel.kt @@ -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 = @@ -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() + } + } }