Commit ef519a85 authored by Mygod's avatar Mygod

Clean up ServiceButton related code

parent 540b1d37
......@@ -31,14 +31,12 @@ import android.nfc.NfcAdapter
import android.os.Bundle
import android.os.SystemClock
import android.support.customtabs.CustomTabsIntent
import android.support.design.widget.FloatingActionButton
import android.support.design.widget.Snackbar
import android.support.v4.content.ContextCompat
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.support.v7.content.res.AppCompatResources
import android.support.v7.preference.PreferenceDataStore
import android.support.v7.widget.TooltipCompat
import android.util.Log
import android.view.View
import android.widget.TextView
......@@ -87,8 +85,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe
}
// UI
private lateinit var fab: FloatingActionButton
private val fabHelper by lazy { ServiceButton(fab) }
private lateinit var fab: ServiceButton
internal var crossfader: Crossfader<CrossFadeSlidingPaneLayout>? = null
internal lateinit var drawer: Drawer
private var previousSelectedDrawer: Long = 0 // it's actually lateinit
......@@ -110,9 +107,6 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe
} catch (_: ActivityNotFoundException) { } // ignore
fun launchUrl(uri: String) = launchUrl(Uri.parse(uri))
private val greyTint by lazy { ContextCompat.getColorStateList(this, R.color.material_primary_500) }
private val greenTint by lazy { ContextCompat.getColorStateList(this, R.color.material_green_700) }
// service
var state = BaseService.IDLE
override val serviceCallback: IShadowsocksServiceCallback.Stub by lazy {
......@@ -130,7 +124,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe
}
fun changeState(state: Int, msg: String? = null, animate: Boolean = false) {
fabHelper.changeState(state, animate)
fab.changeState(state, animate)
when (state) {
BaseService.CONNECTING -> statusText.setText(R.string.connecting)
BaseService.CONNECTED -> statusText.setText(R.string.vpn_connected)
......@@ -145,20 +139,12 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, Drawe
}
}
this.state = state
if (state == BaseService.CONNECTED) {
fab.backgroundTintList = greenTint
TooltipCompat.setTooltipText(fab, getString(R.string.stop))
} else {
fab.backgroundTintList = greyTint
TooltipCompat.setTooltipText(fab, getString(R.string.connect))
if (state != BaseService.CONNECTED) {
updateTraffic(-1, 0, 0, 0, 0)
testCount += 1 // suppress previous test messages
}
ProfilesFragment.instance?.profilesAdapter?.notifyDataSetChanged() // refresh button enabled state
stateListener?.invoke(state)
fab.isEnabled = false
if (state == BaseService.CONNECTED || state == BaseService.STOPPED) app.handler.postDelayed(
{ fab.isEnabled = state == BaseService.CONNECTED || state == BaseService.STOPPED }, 1000)
}
fun updateTraffic(profileId: Int, txRate: Long, rxRate: Long, txTotal: Long, rxTotal: Long) {
txText.text = TrafficMonitor.formatTraffic(txTotal)
......
......@@ -20,19 +20,38 @@
package com.github.shadowsocks.widget
import android.content.Context
import android.graphics.drawable.Drawable
import android.support.annotation.DrawableRes
import android.support.design.widget.FloatingActionButton
import android.support.graphics.drawable.Animatable2Compat
import android.support.graphics.drawable.AnimatedVectorDrawableCompat
import android.support.v7.widget.TooltipCompat
import android.util.AttributeSet
import android.view.View
import com.github.shadowsocks.App
import com.github.shadowsocks.R
import com.github.shadowsocks.bg.BaseService
import java.util.*
class ServiceButton(private val fab: FloatingActionButton) : Animatable2Compat.AnimationCallback() {
class ServiceButton @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
FloatingActionButton(context, attrs, defStyleAttr) {
private val callback = object : Animatable2Compat.AnimationCallback() {
override fun onAnimationEnd(drawable: Drawable) {
super.onAnimationEnd(drawable)
var next = animationQueue.peek() ?: return
if (next.current == drawable) {
animationQueue.pop()
next = animationQueue.peek() ?: return
}
setImageDrawable(next)
next.start()
}
}
private fun createIcon(@DrawableRes resId: Int): AnimatedVectorDrawableCompat {
val result = AnimatedVectorDrawableCompat.create(fab.context, resId)!!
result.registerAnimationCallback(this)
val result = AnimatedVectorDrawableCompat.create(context, resId)!!
result.registerAnimationCallback(callback)
return result
}
......@@ -42,6 +61,14 @@ class ServiceButton(private val fab: FloatingActionButton) : Animatable2Compat.A
private val iconStopping by lazy { createIcon(R.drawable.ic_service_stopping) }
private val animationQueue = ArrayDeque<AnimatedVectorDrawableCompat>()
private var checked = false
override fun onCreateDrawableState(extraSpace: Int): IntArray {
val drawableState = super.onCreateDrawableState(extraSpace + 1)
if (checked) View.mergeDrawableStates(drawableState, intArrayOf(android.R.attr.state_checked))
return drawableState
}
fun changeState(state: Int, animate: Boolean) {
when (state) {
BaseService.CONNECTING -> changeState(iconConnecting, animate)
......@@ -49,6 +76,17 @@ class ServiceButton(private val fab: FloatingActionButton) : Animatable2Compat.A
BaseService.STOPPING -> changeState(iconStopping, animate)
else -> changeState(iconStopped, animate)
}
if (state == BaseService.CONNECTED) {
checked = true
TooltipCompat.setTooltipText(this, context.getString(R.string.stop))
} else {
checked = false
TooltipCompat.setTooltipText(this, context.getString(R.string.connect))
}
refreshDrawableState()
isEnabled = false
if (state == BaseService.CONNECTED || state == BaseService.STOPPED) App.app.handler.postDelayed(
{ isEnabled = state == BaseService.CONNECTED || state == BaseService.STOPPED }, 1000)
}
private fun counters(a: AnimatedVectorDrawableCompat, b: AnimatedVectorDrawableCompat): Boolean =
......@@ -62,26 +100,15 @@ class ServiceButton(private val fab: FloatingActionButton) : Animatable2Compat.A
if (animationQueue.size < 2 || !counters(animationQueue.last, icon)) {
animationQueue.add(icon)
if (animationQueue.size == 1) {
fab.setImageDrawable(icon)
setImageDrawable(icon)
icon.start()
}
} else animationQueue.removeLast()
} else {
animationQueue.peekFirst()?.stop()
animationQueue.clear()
fab.setImageDrawable(icon)
setImageDrawable(icon)
icon.stop()
}
}
override fun onAnimationEnd(drawable: Drawable) {
super.onAnimationEnd(drawable)
var next = animationQueue.peek() ?: return
if (next.current == drawable) {
animationQueue.pop()
next = animationQueue.peek() ?: return
}
fab.setImageDrawable(next)
next.start()
}
}
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/material_green_700" android:state_checked="true"/>
<item android:color="@color/material_primary_500"/>
</selector>
......@@ -77,11 +77,11 @@
android:layout_marginEnd="16dp"
android:layout_marginTop="-28dp"
android:elevation="6dp">
<android.support.design.widget.FloatingActionButton
<com.github.shadowsocks.widget.ServiceButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:backgroundTint="@color/material_primary_500"
app:backgroundTint="@color/background_service"
app:fabSize="normal"
app:pressedTranslationZ="6dp"
app:srcCompat="@drawable/ic_service_idle"/>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment