UI fixes
* 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:
@@ -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
|
||||
|
||||
+1
-1
@@ -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 _ =>
|
||||
|
||||
Reference in New Issue
Block a user