Minor fixes

This commit is contained in:
世界 2024-03-15 21:23:22 +08:00
parent 5feba135c4
commit 73976ce9d1
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
6 changed files with 76 additions and 47 deletions

View file

@ -0,0 +1,12 @@
package io.nekohasekai.sfa.ui.dashboard
import io.nekohasekai.libbox.OutboundGroupItem
import io.nekohasekai.libbox.OutboundGroupItemIterator
internal fun OutboundGroupItemIterator.toList(): List<OutboundGroupItem> {
val list = mutableListOf<OutboundGroupItem>()
while (hasNext()) {
list.add(next())
}
return list
}

View file

@ -2,20 +2,20 @@ package io.nekohasekai.sfa.ui.dashboard
import android.annotation.SuppressLint
import android.os.Bundle
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.style.ForegroundColorSpan
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SimpleItemAnimator
import com.google.android.material.textfield.MaterialAutoCompleteTextView
import io.nekohasekai.libbox.Libbox
import io.nekohasekai.libbox.OutboundGroup
import io.nekohasekai.libbox.OutboundGroupItem
@ -26,6 +26,7 @@ import io.nekohasekai.sfa.databinding.ViewDashboardGroupBinding
import io.nekohasekai.sfa.databinding.ViewDashboardGroupItemBinding
import io.nekohasekai.sfa.ktx.colorForURLTestDelay
import io.nekohasekai.sfa.ktx.errorDialogBuilder
import io.nekohasekai.sfa.ktx.text
import io.nekohasekai.sfa.ui.MainActivity
import io.nekohasekai.sfa.utils.CommandClient
import kotlinx.coroutines.Dispatchers
@ -146,9 +147,10 @@ class GroupsFragment : Fragment(), CommandClient.Handler {
private class GroupView(val binding: ViewDashboardGroupBinding) :
RecyclerView.ViewHolder(binding.root) {
lateinit var group: OutboundGroup
lateinit var items: MutableList<OutboundGroupItem>
lateinit var adapter: ItemAdapter
private lateinit var group: OutboundGroup
private lateinit var items: MutableList<OutboundGroupItem>
private lateinit var adapter: ItemAdapter
private lateinit var textWatcher: TextWatcher
@SuppressLint("NotifyDataSetChanged")
fun bind(group: OutboundGroup) {
@ -197,29 +199,23 @@ class GroupsFragment : Fragment(), CommandClient.Handler {
}
}
binding.itemList.isVisible = newExpandStatus
binding.itemText.isVisible = !newExpandStatus
binding.groupSelected.isVisible = !newExpandStatus
if (!newExpandStatus) {
val builder = SpannableStringBuilder()
items.forEach {
if (it.tag == group.selected) {
builder.append("")
} else {
builder.append("")
binding.groupSelected.text = group.selected
binding.groupSelected.isEnabled = group.selectable
if (group.selectable) {
val textView = (binding.groupSelected.editText as MaterialAutoCompleteTextView)
textView.setSimpleItems(group.items.toList().map { it.tag }.toTypedArray())
if (::textWatcher.isInitialized) {
textView.removeTextChangedListener(textWatcher)
}
textWatcher = textView.addTextChangedListener {
val selected = textView.text.toString()
if (selected != group.selected) {
updateSelected(group, selected)
}
}
builder.setSpan(
ForegroundColorSpan(
colorForURLTestDelay(
binding.root.context,
it.urlTestDelay
)
),
builder.length - 1,
builder.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
builder.append(" ")
}
binding.itemText.text = builder
}
if (newExpandStatus) {
binding.expandButton.setImageResource(R.drawable.ic_expand_less_24)
@ -231,9 +227,9 @@ class GroupsFragment : Fragment(), CommandClient.Handler {
}
}
fun updateSelected(group: OutboundGroup, item: OutboundGroupItem) {
fun updateSelected(group: OutboundGroup, itemTag: String) {
val oldSelected = items.indexOfFirst { it.tag == group.selected }
group.selected = item.tag
group.selected = itemTag
if (oldSelected != -1) {
adapter.notifyItemChanged(oldSelected)
}
@ -288,7 +284,7 @@ class GroupsFragment : Fragment(), CommandClient.Handler {
if (group.selectable) {
binding.itemCard.setOnClickListener {
binding.selectedView.isVisible = true
groupView.updateSelected(group, item)
groupView.updateSelected(group, item.tag)
GlobalScope.launch {
runCatching {
Libbox.newStandaloneCommandClient().selectOutbound(group.tag, item.tag)
@ -315,6 +311,5 @@ class GroupsFragment : Fragment(), CommandClient.Handler {
}
}
}
}

View file

@ -82,13 +82,13 @@ class PerAppProxyActivity : AbstractActivity<ActivityPerAppProxyBinding>() {
setTitle(R.string.title_per_app_proxy)
lifecycleScope.launch {
proxyMode = if (Settings.perAppProxyMode == Settings.PER_APP_PROXY_EXCLUDE) {
Settings.PER_APP_PROXY_EXCLUDE
} else {
proxyMode = if (Settings.perAppProxyMode == Settings.PER_APP_PROXY_INCLUDE) {
Settings.PER_APP_PROXY_INCLUDE
} else {
Settings.PER_APP_PROXY_EXCLUDE
}
withContext(Dispatchers.Main) {
if (proxyMode != Settings.PER_APP_PROXY_EXCLUDE) {
if (proxyMode == Settings.PER_APP_PROXY_INCLUDE) {
binding.perAppProxyMode.setText(R.string.per_app_proxy_mode_include_description)
} else {
binding.perAppProxyMode.setText(R.string.per_app_proxy_mode_exclude_description)
@ -438,16 +438,18 @@ class PerAppProxyActivity : AbstractActivity<ActivityPerAppProxyBinding>() {
R.id.action_select_all -> {
val selectedUIDs = mutableSetOf<Int>()
for (packageCache in packages) {
selectedUIDs.add(packageCache.uid)
currentPackages.forEach {
selectedUIDs.add(it.uid)
}
lifecycleScope.launch {
postSaveSelectedApplications(selectedUIDs)
}
this.selectedUIDs = selectedUIDs
saveSelectedApplications()
}
R.id.action_deselect_all -> {
selectedUIDs = mutableSetOf()
saveSelectedApplications()
lifecycleScope.launch {
postSaveSelectedApplications(mutableSetOf())
}
}
R.id.action_export -> {
@ -502,6 +504,8 @@ class PerAppProxyActivity : AbstractActivity<ActivityPerAppProxyBinding>() {
R.id.action_scan_china_apps -> {
scanChinaApps()
}
else -> return super.onOptionsItemSelected(item)
}
return true
}
@ -511,8 +515,14 @@ class PerAppProxyActivity : AbstractActivity<ActivityPerAppProxyBinding>() {
val binding = DialogProgressbarBinding.inflate(layoutInflater)
binding.progress.max = currentPackages.size
binding.message.setText(R.string.message_scanning)
val dialogTheme =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && resources.configuration.isNightModeActive) {
com.google.android.material.R.style.Theme_MaterialComponents_Dialog
} else {
com.google.android.material.R.style.Theme_MaterialComponents_Light_Dialog
}
val progress = MaterialAlertDialogBuilder(
this, com.google.android.material.R.style.Theme_MaterialComponents_Dialog
this, dialogTheme
).setView(binding.root).setCancelable(false).create()
progress.show()
lifecycleScope.launch {

View file

@ -70,11 +70,21 @@
</LinearLayout>
<TextView
android:id="@+id/itemText"
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/group_selected"
style="@style/Widget.Material3.TextInputLayout.FilledBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingEnd="56dp" />
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:hint="@string/group_selected_title">
<AutoCompleteTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none" />
</com.google.android.material.textfield.TextInputLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/itemList"

View file

@ -6,10 +6,10 @@
style="?materialCardViewElevatedStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_margin="2dp"
app:cardBackgroundColor="?colorSurfaceContainer"
app:cardCornerRadius="0dp"
app:cardElevation="4dp">
app:cardCornerRadius="4dp"
app:cardElevation="0dp">
<LinearLayout
android:layout_width="match_parent"

View file

@ -79,6 +79,8 @@
<string name="status_traffic">Traffic</string>
<string name="status_traffic_total">Traffic Total</string>
<string name="group_selected_title">Selected</string>
<string name="profile">Profile</string>
<string name="core_version">Version</string>
<string name="core">Core</string>