From b376b229b989058795fcd35078cd4a12ed1a32a1 Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Thu, 30 May 2024 16:07:11 +0800 Subject: [PATCH] Add progress bar when subscription is updated --- .../v2ray/ang/service/SubscriptionUpdater.kt | 2 +- .../kotlin/com/v2ray/ang/ui/MainActivity.kt | 108 ++++++------------ .../com/v2ray/ang/ui/SubSettingActivity.kt | 43 ++++++- .../com/v2ray/ang/viewmodel/SubViewModel.kt | 93 +++++++++++++++ .../src/main/res/layout/layout_progress.xml | 16 +++ .../src/main/res/menu/action_sub_setting.xml | 11 +- 6 files changed, 187 insertions(+), 86 deletions(-) create mode 100644 V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SubViewModel.kt create mode 100644 V2rayNG/app/src/main/res/layout/layout_progress.xml diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/SubscriptionUpdater.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/SubscriptionUpdater.kt index 6b836c1f..9cd6e1ae 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/SubscriptionUpdater.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/SubscriptionUpdater.kt @@ -67,7 +67,7 @@ object SubscriptionUpdater { } fun importBatchConfig(server: String?, subid: String = "") { - val append = subid.isEmpty() + val append = false val count = AngConfigManager.importBatchConfig(server, subid, append) if (count <= 0) { diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt index 072f2b66..e0668a3c 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt @@ -31,6 +31,7 @@ import com.v2ray.ang.AppConfig import com.v2ray.ang.AppConfig.ANG_PACKAGE import com.v2ray.ang.R import com.v2ray.ang.databinding.ActivityMainBinding +import com.v2ray.ang.databinding.LayoutProgressBinding import com.v2ray.ang.dto.EConfigType import com.v2ray.ang.extension.toast import com.v2ray.ang.helper.SimpleItemTouchHelperCallback @@ -39,7 +40,9 @@ import com.v2ray.ang.util.AngConfigManager import com.v2ray.ang.util.MmkvManager import com.v2ray.ang.util.Utils import com.v2ray.ang.viewmodel.MainViewModel +import com.v2ray.ang.viewmodel.SubViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import me.drakeet.support.toast.ToastCompat import rx.Observable @@ -61,6 +64,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList } private var mItemTouchHelper: ItemTouchHelper? = null val mainViewModel: MainViewModel by viewModels() + val subViewModel: SubViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -281,11 +285,6 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList true } -// R.id.sub_setting -> { -// startActivity() -// true -// } - R.id.sub_update -> { importConfigViaSub() true @@ -423,26 +422,24 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList return true } - fun importBatchConfig(server: String?, subid: String = "") { - val subid2 = if(subid.isNullOrEmpty()){ - mainViewModel.subscriptionId - }else{ - subid - } - val append = subid.isNullOrEmpty() + fun importBatchConfig(server: String?) { + val dialog = AlertDialog.Builder(this) + .setView(LayoutProgressBinding.inflate(layoutInflater).root) + .setCancelable(false) + .show() - var count = AngConfigManager.importBatchConfig(server, subid2, append) - if (count <= 0) { - count = AngConfigManager.importBatchConfig(Utils.decode(server!!), subid2, append) - } - if (count <= 0) { - count = AngConfigManager.appendCustomConfigServer(server, subid2) - } - if (count > 0) { - toast(R.string.toast_success) - mainViewModel.reloadServerList() - } else { - toast(R.string.toast_failure) + lifecycleScope.launch(Dispatchers.IO) { + val count = subViewModel.importBatchConfig(server, mainViewModel.subscriptionId, true) + delay(500L) + launch(Dispatchers.Main) { + if (count > 0) { + toast(R.string.toast_success) + mainViewModel.reloadServerList() + } else { + toast(R.string.toast_failure) + } + dialog.dismiss() + } } } @@ -520,55 +517,24 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList /** * import config from sub */ - fun importConfigViaSub() - : Boolean { - try { - toast(R.string.title_sub_update) - MmkvManager.decodeSubscriptions().forEach { - if (TextUtils.isEmpty(it.first) - || TextUtils.isEmpty(it.second.remarks) - || TextUtils.isEmpty(it.second.url) - ) { - return@forEach - } - if (!it.second.enabled) { - return@forEach - } - val url = Utils.idnToASCII(it.second.url) - if (!Utils.isValidUrl(url)) { - return@forEach - } - Log.d(ANG_PACKAGE, url) - lifecycleScope.launch(Dispatchers.IO) { - var configText = try { - Utils.getUrlContentWithCustomUserAgent(url) - } catch (e: Exception) { - e.printStackTrace() - "" - } - if(configText.isEmpty()) { - configText = try { - val httpPort = Utils.parseInt(settingsStorage?.decodeString(AppConfig.PREF_HTTP_PORT), AppConfig.PORT_HTTP.toInt()) - Utils.getUrlContentWithCustomUserAgent(url, httpPort) - } catch (e: Exception) { - e.printStackTrace() - "" - } - } - if(configText.isEmpty()) { - launch(Dispatchers.Main) { - toast("\"" + it.second.remarks + "\" " + getString(R.string.toast_failure)) - } - return@launch - } - launch(Dispatchers.Main) { - importBatchConfig(configText, it.first) - } + fun importConfigViaSub() : Boolean { + val dialog = AlertDialog.Builder(this) + .setView(LayoutProgressBinding.inflate(layoutInflater).root) + .setCancelable(false) + .show() + + lifecycleScope.launch(Dispatchers.IO) { + val count = subViewModel.updateConfigViaSubAll() + delay(500L) + launch(Dispatchers.Main) { + if (count > 0) { + toast(R.string.toast_success) + mainViewModel.reloadServerList() + } else { + toast(R.string.toast_failure) } + dialog.dismiss() } - } catch (e: Exception) { - e.printStackTrace() - return false } return true } diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubSettingActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubSettingActivity.kt index 469af3be..18c9ed77 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubSettingActivity.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubSettingActivity.kt @@ -1,20 +1,30 @@ package com.v2ray.ang.ui import android.content.Intent -import androidx.recyclerview.widget.LinearLayoutManager +import android.os.Bundle import android.view.Menu import android.view.MenuItem +import androidx.activity.viewModels +import androidx.appcompat.app.AlertDialog +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager import com.v2ray.ang.R -import android.os.Bundle import com.v2ray.ang.databinding.ActivitySubSettingBinding +import com.v2ray.ang.databinding.LayoutProgressBinding import com.v2ray.ang.dto.SubscriptionItem +import com.v2ray.ang.extension.toast import com.v2ray.ang.util.MmkvManager +import com.v2ray.ang.viewmodel.SubViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch class SubSettingActivity : BaseActivity() { private lateinit var binding: ActivitySubSettingBinding - var subscriptions:List> = listOf() + var subscriptions: List> = listOf() private val adapter by lazy { SubSettingRecyclerAdapter(this) } + val subViewModel: SubViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -37,9 +47,6 @@ class SubSettingActivity : BaseActivity() { override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.action_sub_setting, menu) - menu.findItem(R.id.del_config)?.isVisible = false - menu.findItem(R.id.save_config)?.isVisible = false - return super.onCreateOptionsMenu(menu) } @@ -48,6 +55,30 @@ class SubSettingActivity : BaseActivity() { startActivity(Intent(this, SubEditActivity::class.java)) true } + + R.id.sub_update -> { + val dialog = AlertDialog.Builder(this) + .setView(LayoutProgressBinding.inflate(layoutInflater).root) + .setCancelable(false) + .show() + + lifecycleScope.launch(Dispatchers.IO) { + val count = subViewModel.updateConfigViaSubAll() + delay(500L) + launch(Dispatchers.Main) { + if (count > 0) { + toast(R.string.toast_success) + } else { + toast(R.string.toast_failure) + } + dialog.dismiss() + } + } + + true + } + else -> super.onOptionsItemSelected(item) + } } diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SubViewModel.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SubViewModel.kt new file mode 100644 index 00000000..b2f5cd42 --- /dev/null +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SubViewModel.kt @@ -0,0 +1,93 @@ +package com.v2ray.ang.viewmodel + +import android.app.Application +import android.text.TextUtils +import android.util.Log +import androidx.lifecycle.AndroidViewModel +import com.tencent.mmkv.MMKV +import com.v2ray.ang.AppConfig +import com.v2ray.ang.dto.SubscriptionItem +import com.v2ray.ang.util.AngConfigManager +import com.v2ray.ang.util.MmkvManager +import com.v2ray.ang.util.Utils +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers + +class SubViewModel(application: Application) : AndroidViewModel(application) { + private val settingsStorage by lazy { + MMKV.mmkvWithID( + MmkvManager.ID_SETTING, + MMKV.MULTI_PROCESS_MODE + ) + } + + private val tcpingTestScope by lazy { CoroutineScope(Dispatchers.IO) } + + fun updateConfigViaSubAll(): Int { + var count = 0 + try { + MmkvManager.decodeSubscriptions().forEach { + count += updateConfigViaSub(it) + } + } catch (e: Exception) { + e.printStackTrace() + return 0 + } + return count + } + + fun updateConfigViaSub(it: Pair): Int { + try { + if (TextUtils.isEmpty(it.first) + || TextUtils.isEmpty(it.second.remarks) + || TextUtils.isEmpty(it.second.url) + ) { + return 0 + } + if (!it.second.enabled) { + return 0 + } + val url = Utils.idnToASCII(it.second.url) + if (!Utils.isValidUrl(url)) { + return 0 + } + Log.d(AppConfig.ANG_PACKAGE, url) + var configText = try { + Utils.getUrlContentWithCustomUserAgent(url) + } catch (e: Exception) { + e.printStackTrace() + "" + } + if (configText.isEmpty()) { + configText = try { + val httpPort = Utils.parseInt( + settingsStorage?.decodeString(AppConfig.PREF_HTTP_PORT), + AppConfig.PORT_HTTP.toInt() + ) + Utils.getUrlContentWithCustomUserAgent(url, httpPort) + } catch (e: Exception) { + e.printStackTrace() + "" + } + } + if (configText.isEmpty()) { + return 0 + } + return importBatchConfig(configText, it.first, false) + } catch (e: Exception) { + e.printStackTrace() + return 0 + } + } + + fun importBatchConfig(server: String?, subid: String = "", append: Boolean): Int { + var count = AngConfigManager.importBatchConfig(server, subid, append) + if (count <= 0) { + count = AngConfigManager.importBatchConfig(Utils.decode(server!!), subid, append) + } + if (count <= 0) { + count = AngConfigManager.appendCustomConfigServer(server, subid) + } + return count + } +} diff --git a/V2rayNG/app/src/main/res/layout/layout_progress.xml b/V2rayNG/app/src/main/res/layout/layout_progress.xml new file mode 100644 index 00000000..78ff04c7 --- /dev/null +++ b/V2rayNG/app/src/main/res/layout/layout_progress.xml @@ -0,0 +1,16 @@ + + + + + + + \ No newline at end of file diff --git a/V2rayNG/app/src/main/res/menu/action_sub_setting.xml b/V2rayNG/app/src/main/res/menu/action_sub_setting.xml index 9477de42..3179cb1a 100644 --- a/V2rayNG/app/src/main/res/menu/action_sub_setting.xml +++ b/V2rayNG/app/src/main/res/menu/action_sub_setting.xml @@ -7,13 +7,8 @@ android:title="@string/menu_item_add_config" app:showAsAction="always" /> - \ No newline at end of file