[WIP] UI refactor

This commit is contained in:
Kr328 committed 2020-02-15 14:42:09 +08:00
1 parent 01d9d231b5
commit 718388db51
5 files changed
+158 -64

No files matched your search

@@ -1,33 +1,29 @@
package com.github.kr328.clash
import android.os.Bundle
import android.util.DisplayMetrics
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView
import com.github.kr328.clash.adapter.AbstractProxyAdapter
import com.github.kr328.clash.adapter.GridProxyAdapter
import com.github.kr328.clash.adapter.ProxyChipAdapter
import com.github.kr328.clash.remote.withClash
import com.github.kr328.clash.utils.ProxySorter
import com.github.kr328.clash.view.ProxiesTabMediator
import kotlinx.android.synthetic.main.activity_proxies.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class ProxiesActivity : BaseActivity() {
private val activity: ProxiesActivity
get() = this
private var maskedGroup: MutableSet<String> = mutableSetOf()
private val updateChipChannel = Channel<Unit>(Channel.CONFLATED)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_proxies)
setSupportActionBar(toolbar)
val mediator = ProxiesTabMediator(this, mainList, chipList)
GridProxyAdapter(this).apply {
mainList.layoutManager = layoutManager
mainList.adapter = this
@@ -39,56 +35,16 @@ class ProxiesActivity : BaseActivity() {
}
}
mainList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
updateChipChannel.offer(Unit)
}
})
chipList.adapter = ProxyChipAdapter(this) {
launch {
(mainList.adapter!! as AbstractProxyAdapter).getGroupPosition(it)?.also {
val scroller = (object : LinearSmoothScroller(activity) {
override fun getVerticalSnapPreference(): Int {
return SNAP_TO_START
}
override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics?): Float {
return 40f / displayMetrics!!.densityDpi
}
init {
targetPosition = it
}
})
mainList.layoutManager?.startSmoothScroll(scroller)
}
mediator.scrollTo(it)
}
}
chipList.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
chipList.itemAnimator?.changeDuration = 80
chipList.itemAnimator?.changeDuration = 0
launch {
var currentChecked = ""
while (isActive) {
updateChipChannel.receive()
val currentGroup = (mainList.adapter!! as AbstractProxyAdapter).getCurrentGroup()
if (currentChecked == currentGroup)
continue
currentChecked = currentGroup
(chipList.adapter!! as ProxyChipAdapter).apply {
selected = currentChecked
(chipList.layoutManager!! as LinearLayoutManager)
.scrollToPositionWithOffset(chips.indexOf(currentChecked), 0)
}
}
mediator.exec()
}
}
@@ -102,7 +58,7 @@ class ProxiesActivity : BaseActivity() {
finish()
}
private fun refreshList(scrollTo: String? = null) {
private fun refreshList() {
launch {
val proxies = withClash {
queryAllProxyGroups()
@@ -110,17 +66,20 @@ class ProxiesActivity : BaseActivity() {
val sorter = ProxySorter(ProxySorter.Order.DEFAULT, ProxySorter.Order.DEFAULT)
val filtered = withContext(Dispatchers.Default) {
val sorted = withContext(Dispatchers.Default) {
sorter.sort(proxies.toList())
}
(mainList.adapter!! as AbstractProxyAdapter).apply {
root = filtered.filter { !maskedGroup.contains(it.name) }
root = sorted
applyChange()
}
(chipList.adapter!! as ProxyChipAdapter).chips = filtered.map { it.name }
(chipList.adapter!! as ProxyChipAdapter).apply {
chips = sorted.map { it.name }
notifyDataSetChanged()
}
}
}
}
@@ -1,5 +1,6 @@
package com.github.kr328.clash.adapter
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Color
import android.util.TypedValue
@@ -44,6 +45,51 @@ class ProxyChipAdapter(
class Holder(root: View) : RecyclerView.ViewHolder(root) {
val card: MaterialCardView = root.findViewById(R.id.root)
val title: TextView = root.findViewById(android.R.id.title)
private var cardAnimator: ValueAnimator? = null
private var cardColor: Int = card.cardBackgroundColor.defaultColor
private var titleAnimator: ValueAnimator? = null
private var titleColor: Int = title.textColors.defaultColor
fun setCardColorAnimation(color: Int) {
if (cardColor == color)
return
cardAnimator?.cancel()
cardAnimator = ValueAnimator.ofArgb(cardColor, color).apply {
addUpdateListener {
val v = animatedValue as Int
card.setCardBackgroundColor(v)
cardColor = v
}
duration = 200
start()
}
}
fun setTitleColorAnimation(color: Int) {
if (color == titleColor)
return
titleAnimator?.cancel()
titleAnimator = ValueAnimator.ofArgb(titleColor, color).apply {
addUpdateListener {
val v = animatedValue as Int
title.setTextColor(v)
titleColor = v
}
duration = 200
start()
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
@@ -65,11 +111,11 @@ class ProxyChipAdapter(
}
if (selected == current) {
holder.title.setTextColor(Color.WHITE)
holder.card.setCardBackgroundColor(context.getColor(R.color.primaryCardColorStarted))
holder.setTitleColorAnimation(Color.WHITE)
holder.setCardColorAnimation(context.getColor(R.color.primaryCardColorStarted))
} else {
holder.title.setTextColor(colorOnSurface)
holder.card.setCardBackgroundColor(context.getColor(R.color.chipBackgroundColor))
holder.setTitleColorAnimation(colorOnSurface)
holder.setCardColorAnimation(context.getColor(R.color.chipBackgroundColor))
}
}
}
@@ -0,0 +1,88 @@
package com.github.kr328.clash.view
import android.util.DisplayMetrics
import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView
import com.github.kr328.clash.ProxiesActivity
import com.github.kr328.clash.adapter.AbstractProxyAdapter
import com.github.kr328.clash.adapter.ProxyChipAdapter
import kotlinx.coroutines.channels.Channel
class ProxiesTabMediator(
private val context: ProxiesActivity,
private val proxiesView: RecyclerView,
private val chipView: RecyclerView
) {
private var preventChipScroll = false
private val updateChipChannel = Channel<Unit>(Channel.CONFLATED)
init {
proxiesView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
updateChipChannel.offer(Unit)
}
})
}
suspend fun exec() {
while (true) {
var currentChecked = ""
while (true) {
updateChipChannel.receive()
val currentGroup = (proxiesView.adapter!! as AbstractProxyAdapter).getCurrentGroup()
if (currentChecked == currentGroup)
continue
currentChecked = currentGroup
(chipView.adapter!! as ProxyChipAdapter).apply {
selected = currentChecked
if (!preventChipScroll)
chipView.smoothScrollToPosition(chips.indexOf(currentChecked))
}
}
}
}
suspend fun scrollTo(group: String) {
(proxiesView.adapter!! as AbstractProxyAdapter).apply {
val index = getGroupPosition(group) ?: return
scrollTo(index)
}
}
private fun scrollTo(position: Int) {
val scroller = (object : LinearSmoothScroller(context) {
override fun getVerticalSnapPreference(): Int {
return SNAP_TO_START
}
override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics?): Float {
return 35f / displayMetrics!!.densityDpi
}
override fun onStop() {
super.onStop()
preventChipScroll = false
}
override fun onStart() {
super.onStart()
preventChipScroll = true
}
init {
targetPosition = position
}
})
proxiesView.layoutManager!!.startSmoothScroll(scroller)
}
}
@@ -9,7 +9,8 @@
android:layout_marginTop="10dp"
app:cardCornerRadius="12dp"
android:focusable="true"
android:clickable="true">
android:clickable="true"
app:cardBackgroundColor="@color/chipBackgroundColor">
<TextView
android:id="@android:id/title"
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="200dp"
android:viewportWidth="349"
android:viewportHeight="336">
android:width="402.47244dp"
android:height="381.04724dp"
android:viewportWidth="402.47244"
android:viewportHeight="381.04724">
<path
android:fillColor="#FF000000"
android:pathData="M68.857,304.788l4,-41l12,-97l13,-94l12,-61l2,-7c2,-5 4,-6 9,-3l10,9l26,41c3,4 6,5 11,4c28,-6 57,-5 85,1c5,1 7,-1 9,-5a1453,1453 0,0 1,30 -49c4,-4 7,-4 9,2l8,36l28,177c5,34 8,67 11,100c2,12 1,13 -11,14c-54,5 -108,5 -162,4c-30,0 -59,-2 -88,-3c-6,0 -12,-3 -18,-4l-17,-1c-18,-2 -34,-9 -44,-26c-17,-28 -6,-65 29,-75c4,-1 8,0 12,1c3,2 3,5 0,7l-6,5c-4,3 -9,6 -12,10a31,31 0,0 0,7 49c10,5 20,6 31,6zM149.857,116.788c-8,0 -15,7 -15,15s6,15 15,15c8,0 15,-6 15,-15c0,-8 -7,-15 -15,-15zM272.857,146.788c8,0 15,-6 15,-15c0,-8 -6,-15 -15,-15a15,15 0,1 0,0 30zM189.857,166.788c4,7 11,7 20,1c7,6 16,6 18,-1c-8,3 -14,2 -19,-7c-4,9 -10,10 -19,7z"/>
android:pathData="M95.758,327.156l4,-41l12,-97l13,-94l12,-61l2,-7c2,-5 4,-6 9,-3l10,9l26,41c3,4 6,5 11,4c28,-6 57,-5 85,1c5,1 7,-1 9,-5a1453,1453 0,0 1,30 -49c4,-4 7,-4 9,2l8,36l28,177c5,34 8,67 11,100c2,12 1,13 -11,14c-54,5 -108,5 -162,4c-30,0 -59,-2 -88,-3c-6,0 -12,-3 -18,-4l-17,-1c-18,-2 -34,-9 -44,-26c-17,-28 -6,-65 29,-75c4,-1 8,0 12,1c3,2 3,5 0,7l-6,5c-4,3 -9,6 -12,10a31,31 0,0 0,7 49c10,5 20,6 31,6zM176.758,139.156c-8,0 -15,7 -15,15s6,15 15,15c8,0 15,-6 15,-15c0,-8 -7,-15 -15,-15zM299.758,169.156c8,0 15,-6 15,-15c0,-8 -6,-15 -15,-15a15,15 0,1 0,0 30zM216.758,189.156c4,7 11,7 20,1c7,6 16,6 18,-1c-8,3 -14,2 -19,-7c-4,9 -10,10 -19,7z"/>
</vector>