* Refine exceptions handling when parsing per-app config string

* Remove redundant profiles Preference

* Move Network Traffic to title bar

* Add ripple to title text

* Animate using animateLayoutChanges

* Hide connection test in NAT mode

* Refine UI.

* Change notification action button icon for hidpi device

* Fix FAB ripple

* Fix usability problem

* Fix changes not commited when snackbar being swiped

* Show import/export as action

* Drop unused drawables

* Move TaskerSettings

* Fix action icons

* Prevent switching to an invalid profile

* Fix line wrap when screen width is small
This commit is contained in:
Mygod
2016-04-04 13:41:31 -07:00
committed by Max Lv
parent 8453267996
commit 7d9686b5b5
17 changed files with 135 additions and 85 deletions
@@ -44,6 +44,7 @@ import java.util.{Timer, TimerTask}
import android.app.Service
import android.content.{BroadcastReceiver, Context, Intent, IntentFilter}
import android.os.{Handler, RemoteCallbackList}
import android.text.TextUtils
import android.util.Log
import android.widget.Toast
import com.github.shadowsocks.aidl.{Config, IShadowsocksService, IShadowsocksServiceCallback}
@@ -104,9 +105,10 @@ trait BaseService extends Service {
}
override def use(config: Config) = synchronized(state match {
case State.STOPPED => if (config != null) startRunner(config)
case State.STOPPED => if (config != null && checkConfig(config)) startRunner(config)
case State.CONNECTED =>
if (config == null) stopRunner(true) else if (config.profileId != BaseService.this.config.profileId) {
if (config == null) stopRunner(true)
else if (config.profileId != BaseService.this.config.profileId && checkConfig(config)) {
stopRunner(false)
startRunner(config)
}
@@ -114,6 +116,12 @@ trait BaseService extends Service {
})
}
def checkConfig(config: Config) = if (TextUtils.isEmpty(config.proxy) || TextUtils.isEmpty(config.sitekey)) {
changeState(State.STOPPED)
stopRunner(true)
false
} else true
def startRunner(config: Config) {
this.config = config
@@ -39,11 +39,11 @@ class ShadowsocksNotification(private val service: BaseService, profileName: Str
.setContentIntent(PendingIntent.getActivity(service, 0, new Intent(service, classOf[Shadowsocks])
.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT), 0))
.setSmallIcon(R.drawable.ic_stat_shadowsocks)
.addAction(android.R.drawable.ic_menu_close_clear_cancel, service.getString(R.string.stop),
.addAction(R.drawable.ic_close, service.getString(R.string.stop),
PendingIntent.getBroadcast(service, 0, new Intent(Action.CLOSE), 0))
ShadowsocksApplication.profileManager.getAllProfiles match {
case Some(profiles) => if (profiles.length > 1)
builder.addAction(android.R.drawable.ic_menu_manage, service.getString(R.string.quick_switch),
builder.addAction(R.drawable.ic_settings, service.getString(R.string.quick_switch),
PendingIntent.getActivity(service, 0, new Intent(Action.QUICK_SWITCH), 0))
case _ =>
}
@@ -44,9 +44,9 @@ import android.os.{Build, Bundle}
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.{DefaultItemAnimator, LinearLayoutManager, RecyclerView, Toolbar}
import android.view.{LayoutInflater, View, ViewGroup}
import android.widget.{Switch, CheckedTextView}
import android.widget.{CheckedTextView, Switch}
import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.helper.TaskerSettings
import com.github.shadowsocks.utils.TaskerSettings
/**
* @author CzBiX
@@ -39,8 +39,7 @@
package com.github.shadowsocks
import android.content.{BroadcastReceiver, Context, Intent}
import com.github.shadowsocks.helper.TaskerSettings
import com.github.shadowsocks.utils.Utils
import com.github.shadowsocks.utils.{TaskerSettings, Utils}
/**
* @author CzBiX
@@ -36,7 +36,7 @@
* HERE BE DRAGONS
*
*/
package com.github.shadowsocks.helper
package com.github.shadowsocks.utils
import android.content.{Context, Intent}
import android.os.Bundle
@@ -1,30 +0,0 @@
package com.github.shadowsocks.widget
import android.content.Context
import android.support.design.widget.CoordinatorLayout
import android.support.design.widget.CoordinatorLayout.Behavior
import android.support.design.widget.Snackbar.SnackbarLayout
import android.util.AttributeSet
import android.view.View
/**
* @author Mygod
*/
class AutoPaddingBehavior(context: Context, attrs: AttributeSet) extends Behavior[View] {
override def layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View) =
dependency.isInstanceOf[SnackbarLayout]
override def onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View) =
dependency match {
case sl: SnackbarLayout =>
child.setPadding(0, 0, 0, dependency.getHeight)
true
case _ => super.onDependentViewChanged(parent, child, dependency)
}
override def onDependentViewRemoved(parent: CoordinatorLayout, child: View, dependency: View) =
dependency match {
case sl: SnackbarLayout => child.setPadding(0, 0, 0, 0)
case _ => super.onDependentViewRemoved(parent, child, dependency)
}
}
@@ -0,0 +1,64 @@
package com.github.shadowsocks.widget
import android.animation.ValueAnimator
import android.content.Context
import android.support.design.widget.CoordinatorLayout
import android.support.design.widget.CoordinatorLayout.Behavior
import android.support.design.widget.Snackbar.SnackbarLayout
import android.support.v4.view.animation.FastOutSlowInInterpolator
import android.util.AttributeSet
import android.view.View
import com.github.clans.fab.FloatingActionMenu
import scala.collection.JavaConverters._
/**
* Behavior for com.github.clans.fab.FloatingActionMenu that is aware of Snackbars and scrolling.
*
* @author Mygod
*/
class FloatingActionMenuBehavior(context: Context, attrs: AttributeSet)
extends Behavior[FloatingActionMenu](context, attrs) {
private var fabTranslationYAnimator: ValueAnimator = _
private var fabTranslationY: Float = _
override def layoutDependsOn(parent: CoordinatorLayout, child: FloatingActionMenu, dependency: View) =
dependency.isInstanceOf[SnackbarLayout]
override def onDependentViewChanged(parent: CoordinatorLayout, child: FloatingActionMenu, dependency: View) = {
dependency match {
case _: SnackbarLayout =>
var targetTransY = parent.getDependencies(child).asScala
.filter(view => view.isInstanceOf[SnackbarLayout] && parent.doViewsOverlap(child, view))
.map(view => view.getTranslationY - view.getHeight).reduceOption(_ min _).getOrElse(0F)
if (targetTransY > 0) targetTransY = 0
if (fabTranslationY != targetTransY) {
val currentTransY = child.getTranslationY
if (fabTranslationYAnimator != null && fabTranslationYAnimator.isRunning) fabTranslationYAnimator.cancel
if (child.isShown && Math.abs(currentTransY - targetTransY) > child.getHeight * 0.667F) {
if (fabTranslationYAnimator == null) {
fabTranslationYAnimator = new ValueAnimator
fabTranslationYAnimator.setInterpolator(new FastOutSlowInInterpolator)
fabTranslationYAnimator.addUpdateListener(animation =>
child.setTranslationY(animation.getAnimatedValue.asInstanceOf[Float]))
}
fabTranslationYAnimator.setFloatValues(currentTransY, targetTransY)
fabTranslationYAnimator.start
} else child.setTranslationY(targetTransY)
fabTranslationY = targetTransY
}
}
false
}
override def onStartNestedScroll(parent: CoordinatorLayout, child: FloatingActionMenu, directTargetChild: View,
target: View, nestedScrollAxes: Int) = true
override def onNestedScroll(parent: CoordinatorLayout, child: FloatingActionMenu, target: View, dxConsumed: Int,
dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int) = {
super.onNestedScroll(parent, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed)
val dy = dyConsumed + dyUnconsumed
if (child.isMenuButtonHidden) {
if (dy < 0) child.showMenuButton(true)
} else if (dy > 0) child.hideMenuButton(true)
}
}
@@ -19,7 +19,8 @@ class UndoSnackbarManager[T](view: View, undo: Iterator[(Int, T)] => Unit,
private val removedCallback = new Snackbar.Callback {
override def onDismissed(snackbar: Snackbar, event: Int) = {
event match {
case Snackbar.Callback.DISMISS_EVENT_MANUAL | Snackbar.Callback.DISMISS_EVENT_TIMEOUT =>
case Snackbar.Callback.DISMISS_EVENT_SWIPE | Snackbar.Callback.DISMISS_EVENT_MANUAL |
Snackbar.Callback.DISMISS_EVENT_TIMEOUT =>
if (commit != null) commit(recycleBin.iterator)
recycleBin.clear
case _ =>