Optimized UI
This commit is contained in:
@@ -20,10 +20,12 @@ import androidx.appcompat.app.ActionBarDrawerToggle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.GravityCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.tbruyelle.rxpermissions.RxPermissions
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.v2ray.ang.AppConfig
|
||||
@@ -57,6 +59,23 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
startV2Ray()
|
||||
}
|
||||
}
|
||||
private val requestSubSettingActivity = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
initGroupTab()
|
||||
}
|
||||
private val tabGroupListener = object : TabLayout.OnTabSelectedListener {
|
||||
override fun onTabSelected(tab: TabLayout.Tab?) {
|
||||
val selectId = tab?.tag.toString()
|
||||
if (selectId != mainViewModel.subscriptionId) {
|
||||
mainViewModel.subscriptionIdChanged(selectId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTabUnselected(tab: TabLayout.Tab?) {
|
||||
}
|
||||
|
||||
override fun onTabReselected(tab: TabLayout.Tab?) {
|
||||
}
|
||||
}
|
||||
private var mItemTouchHelper: ItemTouchHelper? = null
|
||||
val mainViewModel: MainViewModel by viewModels()
|
||||
|
||||
@@ -106,7 +125,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
toggle.syncState()
|
||||
binding.navView.setNavigationItemSelectedListener(this)
|
||||
|
||||
|
||||
initGroupTab()
|
||||
setupViewModel()
|
||||
mainViewModel.copyAssets(assets)
|
||||
|
||||
@@ -157,6 +176,29 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
mainViewModel.startListenBroadcast()
|
||||
}
|
||||
|
||||
private fun initGroupTab() {
|
||||
binding.tabGroup.removeOnTabSelectedListener(tabGroupListener)
|
||||
binding.tabGroup.removeAllTabs()
|
||||
binding.tabGroup.isVisible = false
|
||||
|
||||
val (listId, listRemarks) = mainViewModel.getSubscriptions(this)
|
||||
if (listId == null || listRemarks == null) {
|
||||
return
|
||||
}
|
||||
|
||||
for (it in listRemarks.indices) {
|
||||
val tab = binding.tabGroup.newTab()
|
||||
tab.text = listRemarks[it]
|
||||
tab.tag = listId[it]
|
||||
binding.tabGroup.addTab(tab)
|
||||
}
|
||||
val selectIndex =
|
||||
listId.indexOf(mainViewModel.subscriptionId).takeIf { it >= 0 } ?: (listId.count() - 1)
|
||||
binding.tabGroup.selectTab(binding.tabGroup.getTabAt(selectIndex))
|
||||
binding.tabGroup.addOnTabSelectedListener(tabGroupListener)
|
||||
binding.tabGroup.isVisible = true
|
||||
}
|
||||
|
||||
fun startV2Ray() {
|
||||
if (mainStorage?.decodeString(MmkvManager.KEY_SELECTED_SERVER).isNullOrEmpty()) {
|
||||
return
|
||||
@@ -309,11 +351,6 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
mainViewModel.reloadServerList()
|
||||
true
|
||||
}
|
||||
R.id.filter_config -> {
|
||||
mainViewModel.filterConfig(this)
|
||||
true
|
||||
}
|
||||
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
@@ -384,18 +421,20 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
.show()
|
||||
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val count = AngConfigManager.importBatchConfig(server, mainViewModel.subscriptionId, true)
|
||||
val (count, countSub) = AngConfigManager.importBatchConfig(server, mainViewModel.subscriptionId, true)
|
||||
delay(500L)
|
||||
launch(Dispatchers.Main) {
|
||||
if (count > 0) {
|
||||
toast(R.string.toast_success)
|
||||
mainViewModel.reloadServerList()
|
||||
} else if (countSub > 0) {
|
||||
initGroupTab()
|
||||
} else {
|
||||
toast(R.string.toast_failure)
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun importConfigCustomClipboard()
|
||||
@@ -585,12 +624,13 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
return super.onKeyDown(keyCode, event)
|
||||
}
|
||||
|
||||
|
||||
|
||||
override fun onNavigationItemSelected(item: MenuItem): Boolean {
|
||||
// Handle navigation view item clicks here.
|
||||
when (item.itemId) {
|
||||
//R.id.server_profile -> activityClass = MainActivity::class.java
|
||||
R.id.sub_setting -> {
|
||||
startActivity(Intent(this, SubSettingActivity::class.java))
|
||||
requestSubSettingActivity.launch(Intent(this,SubSettingActivity::class.java))
|
||||
}
|
||||
R.id.settings -> {
|
||||
startActivity(Intent(this, SettingsActivity::class.java)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.v2ray.ang.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.content.*
|
||||
import com.tbruyelle.rxpermissions.RxPermissions
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.util.AngConfigManager
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import com.tbruyelle.rxpermissions.RxPermissions
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.extension.toast
|
||||
import com.v2ray.ang.util.AngConfigManager
|
||||
|
||||
class ScScannerActivity : BaseActivity() {
|
||||
|
||||
@@ -32,8 +32,8 @@ class ScScannerActivity : BaseActivity() {
|
||||
|
||||
private val scanQRCode = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
if (it.resultCode == RESULT_OK) {
|
||||
val count = AngConfigManager.importBatchConfig(it.data?.getStringExtra("SCAN_RESULT"), "", false)
|
||||
if (count > 0) {
|
||||
val (count, countSub) = AngConfigManager.importBatchConfig(it.data?.getStringExtra("SCAN_RESULT"), "", false)
|
||||
if (count + countSub > 0) {
|
||||
toast(R.string.toast_success)
|
||||
} else {
|
||||
toast(R.string.toast_failure)
|
||||
|
||||
@@ -64,8 +64,8 @@ class UrlSchemeActivity : BaseActivity() {
|
||||
val decodedUrl = URLDecoder.decode(uriString, "UTF-8")
|
||||
val uri = Uri.parse(decodedUrl)
|
||||
if (uri != null) {
|
||||
val count = AngConfigManager.importBatchConfig(decodedUrl, "", false)
|
||||
if (count > 0) {
|
||||
val (count, countSub) = AngConfigManager.importBatchConfig(decodedUrl, "", false)
|
||||
if (count + countSub > 0) {
|
||||
toast(R.string.import_subscription_success)
|
||||
} else {
|
||||
toast(R.string.import_subscription_failure)
|
||||
|
||||
@@ -386,7 +386,7 @@ object AngConfigManager {
|
||||
// }
|
||||
// }
|
||||
|
||||
fun importBatchConfig(server: String?, subid: String, append: Boolean): Int {
|
||||
fun importBatchConfig(server: String?, subid: String, append: Boolean): Pair<Int, Int> {
|
||||
var count = parseBatchConfig(Utils.decode(server), subid, append)
|
||||
if (count <= 0) {
|
||||
count = parseBatchConfig(server, subid, append)
|
||||
@@ -403,7 +403,7 @@ object AngConfigManager {
|
||||
updateConfigViaSubAll()
|
||||
}
|
||||
|
||||
return count + countSub
|
||||
return count to countSub
|
||||
}
|
||||
|
||||
fun parseBatchSubscription(servers: String?): Int {
|
||||
|
||||
@@ -8,7 +8,6 @@ import android.content.IntentFilter
|
||||
import android.content.res.AssetManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
@@ -60,7 +59,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
var serverList = MmkvManager.decodeServerList()
|
||||
var subscriptionId: String = settingsStorage.decodeString(AppConfig.CACHE_SUBSCRIPTION_ID, "")?:""
|
||||
var keywordFilter: String = settingsStorage.decodeString(AppConfig.CACHE_KEYWORD_FILTER, "")?:""
|
||||
//var keywordFilter: String = settingsStorage.decodeString(AppConfig.CACHE_KEYWORD_FILTER, "")?:""
|
||||
private set
|
||||
val serversCache = mutableListOf<ServersCache>()
|
||||
val isRunning by lazy { MutableLiveData<Boolean>() }
|
||||
@@ -146,9 +145,9 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (keywordFilter.isEmpty() || config.remarks.contains(keywordFilter)) {
|
||||
// if (keywordFilter.isEmpty() || config.remarks.contains(keywordFilter)) {
|
||||
serversCache.add(ServersCache(guid, config))
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,25 +201,30 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
MessageUtil.sendMsg2Service(getApplication(), AppConfig.MSG_MEASURE_DELAY, "")
|
||||
}
|
||||
|
||||
fun filterConfig(context: Context) {
|
||||
val subscriptions = MmkvManager.decodeSubscriptions()
|
||||
val listId = subscriptions.map { it.first }.toMutableList()
|
||||
val listRemarks = subscriptions.map { it.second.remarks }.toMutableList()
|
||||
listRemarks += context.getString(R.string.filter_config_all)
|
||||
val checkedItem = listId.indexOf(subscriptionId).takeIf { it >= 0 } ?: listRemarks.count() - 1
|
||||
fun subscriptionIdChanged(id: String) {
|
||||
if (subscriptionId != id) {
|
||||
subscriptionId = id
|
||||
settingsStorage.encode(AppConfig.CACHE_SUBSCRIPTION_ID, subscriptionId)
|
||||
reloadServerList()
|
||||
}
|
||||
}
|
||||
|
||||
AlertDialog.Builder(context)
|
||||
.setSingleChoiceItems(listRemarks.toTypedArray(), checkedItem) { dialog, i ->
|
||||
try {
|
||||
subscriptionId = if (listRemarks.count() - 1 == i) "" else subscriptions[i].first
|
||||
settingsStorage.encode(AppConfig.CACHE_SUBSCRIPTION_ID, subscriptionId)
|
||||
reloadServerList()
|
||||
dialog.dismiss()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
.show()
|
||||
fun getSubscriptions(context: Context) : Pair<MutableList<String>?, MutableList<String>?> {
|
||||
val subscriptions = MmkvManager.decodeSubscriptions()
|
||||
if (subscriptionId.isNotEmpty()
|
||||
&& !subscriptions.map { it.first }.contains(subscriptionId)
|
||||
) {
|
||||
subscriptionIdChanged("")
|
||||
}
|
||||
if (subscriptions.isEmpty()) {
|
||||
return null to null
|
||||
}
|
||||
val listId = subscriptions.map { it.first }.toMutableList()
|
||||
listId.add(0, "")
|
||||
val listRemarks = subscriptions.map { it.second.remarks }.toMutableList()
|
||||
listRemarks.add(0, context.getString(R.string.filter_config_all))
|
||||
|
||||
return listId to listRemarks
|
||||
}
|
||||
|
||||
fun getPosition(guid: String): Int {
|
||||
|
||||
@@ -37,6 +37,14 @@
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tab_group"
|
||||
app:tabMode="scrollable"
|
||||
app:tabTextAppearance="@style/TabLayoutTextStyle"
|
||||
app:tabIndicatorFullWidth="false"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -63,11 +63,6 @@
|
||||
</item>
|
||||
</menu>
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/filter_config"
|
||||
android:icon="@drawable/ic_outline_filter_alt_24"
|
||||
android:title="@string/title_filter_config"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/service_restart"
|
||||
android:title="@string/title_service_restart"
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="TabLayoutTextStyle" parent="TextAppearance.Design.Tab">
|
||||
<item name="textAllCaps">false</item>
|
||||
</style>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user