refactor proxy list

This commit is contained in:
Kr328 committed 2019-11-30 16:41:14 +08:00
1 parent f418a3649e
commit 1e8a57e949
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
@@ -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>
@@ -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"