refactor proxy list
This commit is contained in:
8 files changed
+158
-142
No files matched your search
@@ -1,11 +1,9 @@
|
||||
package com.github.kr328.clash
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.github.kr328.clash.adapter.ProxyGroupAdapter
|
||||
import com.github.kr328.clash.adapter.ProxyAdapter
|
||||
import com.github.kr328.clash.core.model.ProxyPacket
|
||||
import com.github.kr328.clash.model.ListProxyGroup
|
||||
import com.github.kr328.clash.model.ListProxy
|
||||
import kotlinx.android.synthetic.main.activity_proxies.*
|
||||
|
||||
class ProxyActivity : BaseActivity() {
|
||||
@@ -16,9 +14,8 @@ class ProxyActivity : BaseActivity() {
|
||||
setSupportActionBar(activity_proxies_toolbar)
|
||||
|
||||
activity_proxies_list.also {
|
||||
it.layoutManager = LinearLayoutManager(this)
|
||||
it.adapter = ProxyGroupAdapter(this)
|
||||
it.visibility = View.GONE
|
||||
it.adapter = ProxyAdapter(this)
|
||||
it.layoutManager = (it.adapter!! as ProxyAdapter).getLayoutManager()
|
||||
}
|
||||
|
||||
activity_proxies_swipe.setOnRefreshListener {
|
||||
@@ -35,14 +32,6 @@ class ProxyActivity : BaseActivity() {
|
||||
runClash { clash ->
|
||||
val packet = clash.queryAllProxies()
|
||||
val proxies = packet.proxies
|
||||
val adapterProxies = proxies
|
||||
.mapValues {
|
||||
ListProxyGroup.ListProxy(
|
||||
it.value.name,
|
||||
it.value.type.toString(),
|
||||
it.value.delay
|
||||
)
|
||||
}
|
||||
|
||||
val listData = proxies
|
||||
.asSequence()
|
||||
@@ -69,25 +58,63 @@ class ProxyActivity : BaseActivity() {
|
||||
it.value.name
|
||||
})
|
||||
)
|
||||
.map {
|
||||
ListProxyGroup(
|
||||
it.value.name,
|
||||
it.value.type,
|
||||
it.value.all.mapNotNull { hash ->
|
||||
adapterProxies[hash]
|
||||
},
|
||||
adapterProxies[it.value.now]
|
||||
)
|
||||
.flatMap {
|
||||
val header = ListProxy.ListProxyHeader(it.value.name, it.value.type, it.value.now)
|
||||
|
||||
sequenceOf(header) +
|
||||
it.value.all
|
||||
.mapNotNull {
|
||||
proxies[it]
|
||||
}
|
||||
.map { item ->
|
||||
ListProxy.ListProxyItem(
|
||||
item.name,
|
||||
item.type.toString(),
|
||||
item.delay, header
|
||||
)
|
||||
}
|
||||
.asSequence()
|
||||
}
|
||||
.mapIndexed { index, listProxy ->
|
||||
if ( listProxy is ListProxy.ListProxyItem ) {
|
||||
if ( listProxy.name.hashCode() == listProxy.header.now )
|
||||
listProxy.header.now = index
|
||||
}
|
||||
listProxy
|
||||
}
|
||||
.toList()
|
||||
|
||||
runOnUiThread {
|
||||
(activity_proxies_list.adapter!! as ProxyGroupAdapter).apply {
|
||||
data = listData
|
||||
notifyDataSetChanged()
|
||||
val listDataOldChanged = (activity_proxies_list.adapter!! as ProxyAdapter)
|
||||
.elements
|
||||
.filterIsInstance(ListProxy.ListProxyHeader::class.java)
|
||||
.map { it.now }
|
||||
|
||||
val listDataChanged = listData.filterIsInstance<ListProxy.ListProxyHeader>()
|
||||
.map { it.now }
|
||||
|
||||
val changed = if ( listDataChanged.size != listDataChanged.size )
|
||||
(0..listData.size).toList()
|
||||
else {
|
||||
listDataChanged.mapIndexed { index, i ->
|
||||
if ( listDataOldChanged[index] != i )
|
||||
-1
|
||||
else
|
||||
index
|
||||
}.filterNot {
|
||||
it < 0
|
||||
}
|
||||
activity_proxies_list.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
runOnUiThread {
|
||||
activity_proxies_swipe.isRefreshing = false
|
||||
|
||||
(activity_proxies_list.adapter!! as ProxyAdapter).apply {
|
||||
elements = listData
|
||||
|
||||
changed.forEach {
|
||||
notifyItemChanged(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,64 +2,121 @@ package com.github.kr328.clash.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.kr328.clash.R
|
||||
import com.github.kr328.clash.model.ListProxyGroup
|
||||
import com.github.kr328.clash.core.model.ProxyPacket
|
||||
import com.github.kr328.clash.model.ListProxy
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
class ProxyAdapter(private val context: Context) : RecyclerView.Adapter<ProxyAdapter.Holder>() {
|
||||
var proxies: List<ListProxyGroup.ListProxy> = emptyList()
|
||||
var now: ListProxyGroup.ListProxy? = null
|
||||
class ProxyAdapter(private val context: Context) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
var elements: List<ListProxy> = emptyList()
|
||||
var clickable: Boolean = false
|
||||
|
||||
class Holder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val name: TextView = view.findViewById(R.id.adapter_proxy_name)
|
||||
val type: TextView = view.findViewById(R.id.adapter_proxy_type)
|
||||
val delay: TextView = view.findViewById(R.id.adapter_proxy_delay)
|
||||
val card: MaterialCardView = view.findViewById(R.id.adapter_proxy_card)
|
||||
class HeaderHolder(view: View): RecyclerView.ViewHolder(view) {
|
||||
val name: TextView = view.findViewById(R.id.adapter_proxy_header_name)
|
||||
val test: View = view.findViewById(R.id.adapter_proxy_header_url_test)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
|
||||
return Holder(LayoutInflater.from(context).inflate(R.layout.adapter_proxy, parent, false))
|
||||
class ItemHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val name: TextView = view.findViewById(R.id.adapter_proxy_item_name)
|
||||
val type: TextView = view.findViewById(R.id.adapter_proxy_item_type)
|
||||
val delay: TextView = view.findViewById(R.id.adapter_proxy_item_delay)
|
||||
val card: MaterialCardView = view.findViewById(R.id.adapter_proxy_item_card)
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return when ( elements[position] ) {
|
||||
is ListProxy.ListProxyItem -> 1
|
||||
is ListProxy.ListProxyHeader -> 2
|
||||
else -> throw IllegalArgumentException("Invalid type")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return when (viewType) {
|
||||
1 -> ItemHolder(LayoutInflater.from(context).inflate(R.layout.adapter_proxy_item, parent, false))
|
||||
2 -> HeaderHolder(LayoutInflater.from(context).inflate(R.layout.adapter_proxy_header, parent, false))
|
||||
else -> throw IllegalArgumentException("Invalid type")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return proxies.size
|
||||
return elements.size
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: Holder, position: Int) {
|
||||
val current = proxies[position]
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (val current = elements[position]) {
|
||||
is ListProxy.ListProxyItem -> bindItemView(holder as ItemHolder, current, position)
|
||||
is ListProxy.ListProxyHeader -> bindHeaderView(holder as HeaderHolder, current)
|
||||
}
|
||||
}
|
||||
|
||||
if (current === now) {
|
||||
fun getLayoutManager(): GridLayoutManager {
|
||||
return GridLayoutManager(context, 2).apply {
|
||||
spanSizeLookup = object: GridLayoutManager.SpanSizeLookup() {
|
||||
override fun getSpanSize(position: Int): Int {
|
||||
return when ( elements[position] ) {
|
||||
is ListProxy.ListProxyHeader -> 2
|
||||
is ListProxy.ListProxyItem -> 1
|
||||
else -> throw IllegalArgumentException("Invalid type")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindItemView(holder: ItemHolder, current: ListProxy.ListProxyItem, position: Int) {
|
||||
if ( position == current.header.now ) {
|
||||
holder.card.setCardBackgroundColor(context.getColor(R.color.colorAccent))
|
||||
holder.name.setTextColor(Color.WHITE)
|
||||
holder.type.setTextColor(Color.WHITE - 0x22222222)
|
||||
holder.delay.setTextColor(Color.WHITE - 0x11111111)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
holder.card.setCardBackgroundColor(Color.WHITE)
|
||||
holder.name.setTextColor(Color.BLACK)
|
||||
holder.type.setTextColor(Color.LTGRAY)
|
||||
holder.delay.setTextColor(Color.DKGRAY)
|
||||
}
|
||||
|
||||
holder.card.isFocusable = clickable
|
||||
holder.card.isClickable = clickable
|
||||
if ( current.header.type == ProxyPacket.Type.SELECT ) {
|
||||
holder.card.isFocusable = true
|
||||
holder.card.isClickable = true
|
||||
holder.card.setOnClickListener {
|
||||
notifyItemChanged(current.header.now)
|
||||
notifyItemChanged(position)
|
||||
current.header.now = position
|
||||
}
|
||||
}
|
||||
else {
|
||||
holder.card.setOnClickListener(null)
|
||||
holder.card.isFocusable = false
|
||||
holder.card.isClickable = false
|
||||
}
|
||||
|
||||
holder.name.text = current.name
|
||||
holder.type.text = current.type
|
||||
holder.delay.text = if (current.delay > 0) current.delay.toString() else ""
|
||||
|
||||
if (clickable) {
|
||||
holder.card.setOnClickListener {
|
||||
notifyItemChanged(proxies.indexOf(now))
|
||||
notifyItemChanged(position)
|
||||
|
||||
now = current
|
||||
holder.delay.text =
|
||||
if (current.delay > 0) {
|
||||
current.delay.toString()
|
||||
} else {
|
||||
if ( current.header.type != ProxyPacket.Type.SELECT )
|
||||
"N/A"
|
||||
else
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun bindHeaderView(holder: HeaderHolder, current: ListProxy.ListProxyHeader) {
|
||||
holder.name.text = current.name
|
||||
holder.test.visibility = if ( current.type == ProxyPacket.Type.SELECT ) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.github.kr328.clash.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.kr328.clash.R
|
||||
import com.github.kr328.clash.core.model.ProxyPacket
|
||||
import com.github.kr328.clash.model.ListProxyGroup
|
||||
|
||||
class ProxyGroupAdapter(private val context: Context) :
|
||||
RecyclerView.Adapter<ProxyGroupAdapter.Holder>() {
|
||||
var data: List<ListProxyGroup> = emptyList()
|
||||
|
||||
class Holder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val name: TextView = view.findViewById(R.id.adapter_proxy_group_name)
|
||||
val list: RecyclerView = view.findViewById(R.id.adapter_proxy_group_list)
|
||||
val test: View = view.findViewById(R.id.adapter_proxy_group_url_test)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
|
||||
return Holder(
|
||||
LayoutInflater.from(context)
|
||||
.inflate(R.layout.adapter_proxy_group, parent, false)
|
||||
).apply {
|
||||
list.layoutManager = object : GridLayoutManager(context, 2) {
|
||||
override fun canScrollHorizontally(): Boolean = false
|
||||
override fun canScrollVertically(): Boolean = false
|
||||
}
|
||||
list.adapter = ProxyAdapter(context)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return data.size
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: Holder, position: Int) {
|
||||
val current = data[position]
|
||||
|
||||
holder.test.visibility =
|
||||
if (current.type == ProxyPacket.Type.SELECT) View.VISIBLE else View.GONE
|
||||
holder.name.text = current.name
|
||||
|
||||
(holder.list.adapter as ProxyAdapter).apply {
|
||||
proxies = current.proxies
|
||||
now = current.now
|
||||
clickable = current.type == ProxyPacket.Type.SELECT
|
||||
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.github.kr328.clash.model
|
||||
|
||||
import com.github.kr328.clash.core.model.ProxyPacket
|
||||
|
||||
interface ListProxy {
|
||||
data class ListProxyHeader(val name: String, val type: ProxyPacket.Type, var now: Int): ListProxy
|
||||
data class ListProxyItem(val name: String, val type: String, val delay: Long, val header: ListProxyHeader): ListProxy
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.github.kr328.clash.model
|
||||
|
||||
import com.github.kr328.clash.core.model.ProxyPacket
|
||||
|
||||
data class ListProxyGroup(
|
||||
val name: String,
|
||||
val type: ProxyPacket.Type,
|
||||
val proxies: List<ListProxy>,
|
||||
var now: ListProxy?
|
||||
) {
|
||||
data class ListProxy(val name: String, val type: String, val delay: Long)
|
||||
}
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/activity_proxies_swipe"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
+2
-12
@@ -1,11 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/adapter_proxy_group_root"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="15dp"
|
||||
android:paddingEnd="15dp"
|
||||
android:paddingTop="15dp">
|
||||
|
||||
<TextView
|
||||
@@ -13,12 +10,12 @@
|
||||
android:layout_marginStart="2dp"
|
||||
android:textColor="@color/colorAccent"
|
||||
android:text="@string/app_name"
|
||||
android:id="@+id/adapter_proxy_group_name"
|
||||
android:id="@+id/adapter_proxy_header_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<View
|
||||
android:id="@+id/adapter_proxy_group_url_test"
|
||||
android:id="@+id/adapter_proxy_header_url_test"
|
||||
android:focusable="true"
|
||||
android:clickable="true"
|
||||
android:layout_width="22dp"
|
||||
@@ -26,11 +23,4 @@
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:background="@drawable/ic_url_test" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/adapter_proxy_group_list"
|
||||
android:layout_below="@id/adapter_proxy_group_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
</RelativeLayout>
|
||||
+6
-6
@@ -5,7 +5,7 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/adapter_proxy_card"
|
||||
android:id="@+id/adapter_proxy_item_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
@@ -18,17 +18,17 @@
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/adapter_proxy_name"
|
||||
android:id="@+id/adapter_proxy_item_name"
|
||||
android:textColor="@android:color/black"
|
||||
android:maxLines="1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toStartOf="@id/adapter_proxy_delay"
|
||||
android:layout_toStartOf="@id/adapter_proxy_item_delay"
|
||||
android:layout_alignParentStart="true"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/adapter_proxy_type"
|
||||
android:layout_below="@id/adapter_proxy_name"
|
||||
android:id="@+id/adapter_proxy_item_type"
|
||||
android:layout_below="@id/adapter_proxy_item_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="12sp"
|
||||
@@ -38,7 +38,7 @@
|
||||
android:layout_alignParentEnd="true"
|
||||
android:gravity="end"
|
||||
android:textSize="12sp"
|
||||
android:id="@+id/adapter_proxy_delay"
|
||||
android:id="@+id/adapter_proxy_item_delay"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_width="wrap_content"
|
||||
Reference in new issue
Block a user