Commit 341c8504 authored by Mygod's avatar Mygod

Add fast scroller to custom rules and per-app proxy config

parent 35d76115
...@@ -37,6 +37,7 @@ libraryDependencies ++= ...@@ -37,6 +37,7 @@ libraryDependencies ++=
"com.android.support" % "design" % "25.1.0" :: "com.android.support" % "design" % "25.1.0" ::
"com.android.support" % "gridlayout-v7" % "25.1.0" :: "com.android.support" % "gridlayout-v7" % "25.1.0" ::
"com.android.support" % "preference-v14" % "25.1.0" :: "com.android.support" % "preference-v14" % "25.1.0" ::
"com.futuremind.recyclerfastscroll" % "fastscroll" % "0.2.5" ::
"com.evernote" % "android-job" % "1.1.3" :: "com.evernote" % "android-job" % "1.1.3" ::
"com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01" :: "com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01" ::
"com.google.android.gms" % "play-services-ads" % "10.0.1" :: "com.google.android.gms" % "play-services-ads" % "10.0.1" ::
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
...@@ -19,7 +20,7 @@ ...@@ -19,7 +20,7 @@
android:textSize="18sp" android:textSize="18sp"
android:textColor="?android:attr/textColorSecondary" android:textColor="?android:attr/textColorSecondary"
android:paddingStart="60dp" android:paddingStart="60dp"
android:paddingEnd="8dp" android:paddingEnd="16dp"
android:paddingTop="12dp" android:paddingTop="12dp"
android:paddingBottom="12dp" android:paddingBottom="12dp"
android:layout_width="match_parent" android:layout_width="match_parent"
...@@ -30,7 +31,7 @@ ...@@ -30,7 +31,7 @@
android:textSize="18sp" android:textSize="18sp"
android:textColor="?android:attr/textColorSecondary" android:textColor="?android:attr/textColorSecondary"
android:paddingStart="60dp" android:paddingStart="60dp"
android:paddingEnd="8dp" android:paddingEnd="16dp"
android:paddingTop="12dp" android:paddingTop="12dp"
android:paddingBottom="12dp" android:paddingBottom="12dp"
android:layout_width="match_parent" android:layout_width="match_parent"
...@@ -46,8 +47,19 @@ ...@@ -46,8 +47,19 @@
<android.support.v7.widget.RecyclerView <android.support.v7.widget.RecyclerView
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:id="@+id/applistview" android:id="@+id/list"
android:scrollbars="vertical"
android:visibility="gone"/> android:visibility="gone"/>
<com.futuremind.recyclerviewfastscroll.FastScroller
android:id="@+id/fastscroller"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:visibility="gone"
app:fastscroll__handleColor="@color/material_primary_500"
app:fastscroll__bubbleColor="@color/material_primary_500"
app:fastscroll__bubbleTextAppearance="@style/StyledScrollerTextAppearance"/>
</FrameLayout> </FrameLayout>
</LinearLayout> </LinearLayout>
...@@ -28,6 +28,6 @@ ...@@ -28,6 +28,6 @@
android:focusable="false" android:focusable="false"
android:focusableInTouchMode="false" android:focusableInTouchMode="false"
android:clickable="false" android:clickable="false"
android:layout_marginEnd="8dp"/> android:layout_marginEnd="16dp"/>
</LinearLayout> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar_light_dark"/>
<FrameLayout android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<android.support.v7.widget.RecyclerView android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="32dp"
android:clipToPadding="false"/>
<com.futuremind.recyclerviewfastscroll.FastScroller
android:id="@+id/fastscroller"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:layout_marginBottom="32dp"
app:fastscroll__handleColor="@color/material_primary_500"
app:fastscroll__bubbleColor="@color/material_primary_500"
app:fastscroll__bubbleTextAppearance="@style/StyledScrollerTextAppearance"/>
</FrameLayout>
</LinearLayout>
...@@ -4,8 +4,7 @@ ...@@ -4,8 +4,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:orientation="vertical">
<include layout="@layout/toolbar_light_dark"/> <include layout="@layout/toolbar_light_dark"/>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" <android.support.v7.widget.RecyclerView android:id="@+id/list"
android:id="@+id/list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1"
......
...@@ -49,5 +49,10 @@ ...@@ -49,5 +49,10 @@
<style name="NumberPickerStyle"> <style name="NumberPickerStyle">
<item name="android:textSize">14sp</item> <item name="android:textSize">14sp</item>
</style> </style>
<style name="StyledScrollerTextAppearance" parent="@android:style/TextAppearance">
<item name="android:textSize">24sp</item>
<item name="android:textStyle">bold</item>
<item name="android:textColor">@android:color/white</item>
</style>
</resources> </resources>
...@@ -23,6 +23,7 @@ package com.github.shadowsocks ...@@ -23,6 +23,7 @@ package com.github.shadowsocks
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import android.Manifest.permission import android.Manifest.permission
import android.animation.{Animator, AnimatorListenerAdapter}
import android.app.TaskStackBuilder import android.app.TaskStackBuilder
import android.content._ import android.content._
import android.content.pm.PackageManager import android.content.pm.PackageManager
...@@ -33,6 +34,7 @@ import android.support.v7.widget.Toolbar.OnMenuItemClickListener ...@@ -33,6 +34,7 @@ import android.support.v7.widget.Toolbar.OnMenuItemClickListener
import android.support.v7.widget.{DefaultItemAnimator, LinearLayoutManager, RecyclerView, Toolbar} import android.support.v7.widget.{DefaultItemAnimator, LinearLayoutManager, RecyclerView, Toolbar}
import android.view._ import android.view._
import android.widget._ import android.widget._
import com.futuremind.recyclerviewfastscroll.{FastScroller, SectionTitleProvider}
import com.github.shadowsocks.ShadowsocksApplication.app import com.github.shadowsocks.ShadowsocksApplication.app
import com.github.shadowsocks.utils.{Key, Utils} import com.github.shadowsocks.utils.{Key, Utils}
...@@ -102,7 +104,7 @@ class AppManager extends AppCompatActivity with OnMenuItemClickListener { ...@@ -102,7 +104,7 @@ class AppManager extends AppCompatActivity with OnMenuItemClickListener {
} }
} }
private final class AppsAdapter extends RecyclerView.Adapter[AppViewHolder] { private final class AppsAdapter extends RecyclerView.Adapter[AppViewHolder] with SectionTitleProvider {
private val apps = getApps(getPackageManager).sortWith((a, b) => { private val apps = getApps(getPackageManager).sortWith((a, b) => {
val aProxied = proxiedApps.contains(a.packageName) val aProxied = proxiedApps.contains(a.packageName)
if (aProxied ^ proxiedApps.contains(b.packageName)) aProxied else a.name.compareToIgnoreCase(b.name) < 0 if (aProxied ^ proxiedApps.contains(b.packageName)) aProxied else a.name.compareToIgnoreCase(b.name) < 0
...@@ -112,12 +114,14 @@ class AppManager extends AppCompatActivity with OnMenuItemClickListener { ...@@ -112,12 +114,14 @@ class AppManager extends AppCompatActivity with OnMenuItemClickListener {
def onBindViewHolder(vh: AppViewHolder, i: Int): Unit = vh.bind(apps(i)) def onBindViewHolder(vh: AppViewHolder, i: Int): Unit = vh.bind(apps(i))
def onCreateViewHolder(vg: ViewGroup, i: Int) = def onCreateViewHolder(vg: ViewGroup, i: Int) =
new AppViewHolder(LayoutInflater.from(vg.getContext).inflate(R.layout.layout_apps_item, vg, false)) new AppViewHolder(LayoutInflater.from(vg.getContext).inflate(R.layout.layout_apps_item, vg, false))
def getSectionTitle(i: Int): String = apps(i).name.substring(0, 1)
} }
private var proxiedApps: mutable.HashSet[String] = _ private var proxiedApps: mutable.HashSet[String] = _
private var toolbar: Toolbar = _ private var toolbar: Toolbar = _
private var bypassSwitch: Switch = _ private var bypassSwitch: Switch = _
private var appListView: RecyclerView = _ private var appListView: RecyclerView = _
private var fastScroller: FastScroller = _
private var loadingView: View = _ private var loadingView: View = _
private val appsLoading = new AtomicBoolean private val appsLoading = new AtomicBoolean
private var handler: Handler = _ private var handler: Handler = _
...@@ -170,6 +174,7 @@ class AppManager extends AppCompatActivity with OnMenuItemClickListener { ...@@ -170,6 +174,7 @@ class AppManager extends AppCompatActivity with OnMenuItemClickListener {
app.editor.putString(Key.individual, apps).putBoolean(Key.dirty, true).apply() app.editor.putString(Key.individual, apps).putBoolean(Key.dirty, true).apply()
Toast.makeText(this, R.string.action_import_msg, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.action_import_msg, Toast.LENGTH_SHORT).show()
appListView.setVisibility(View.GONE) appListView.setVisibility(View.GONE)
fastScroller.setVisibility(View.GONE)
loadingView.setVisibility(View.VISIBLE) loadingView.setVisibility(View.VISIBLE)
initProxiedApps(apps) initProxiedApps(apps)
reloadApps() reloadApps()
...@@ -220,9 +225,11 @@ class AppManager extends AppCompatActivity with OnMenuItemClickListener { ...@@ -220,9 +225,11 @@ class AppManager extends AppCompatActivity with OnMenuItemClickListener {
initProxiedApps() initProxiedApps()
loadingView = findViewById(R.id.loading) loadingView = findViewById(R.id.loading)
appListView = findViewById(R.id.applistview).asInstanceOf[RecyclerView] appListView = findViewById(R.id.list).asInstanceOf[RecyclerView]
appListView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)) appListView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false))
appListView.setItemAnimator(new DefaultItemAnimator) appListView.setItemAnimator(new DefaultItemAnimator)
fastScroller = findViewById(R.id.fastscroller).asInstanceOf[FastScroller]
fastScroller.setRecyclerView(appListView)
instance = this instance = this
loadAppsAsync() loadAppsAsync()
...@@ -239,7 +246,16 @@ class AppManager extends AppCompatActivity with OnMenuItemClickListener { ...@@ -239,7 +246,16 @@ class AppManager extends AppCompatActivity with OnMenuItemClickListener {
} while (!appsLoading.compareAndSet(true, false)) } while (!appsLoading.compareAndSet(true, false))
handler.post(() => { handler.post(() => {
appListView.setAdapter(adapter) appListView.setAdapter(adapter)
Utils.crossFade(AppManager.this, loadingView, appListView) val shortAnimTime = getResources.getInteger(android.R.integer.config_shortAnimTime)
appListView.setAlpha(0)
appListView.setVisibility(View.VISIBLE)
appListView.animate().alpha(1).setDuration(shortAnimTime)
fastScroller.setAlpha(0)
fastScroller.setVisibility(View.VISIBLE)
fastScroller.animate().alpha(1).setDuration(shortAnimTime)
loadingView.animate().alpha(0).setDuration(shortAnimTime).setListener(new AnimatorListenerAdapter {
override def onAnimationEnd(animation: Animator): Unit = loadingView.setVisibility(View.GONE)
})
}) })
} }
} }
......
...@@ -12,6 +12,7 @@ import android.support.v7.widget.helper.ItemTouchHelper.SimpleCallback ...@@ -12,6 +12,7 @@ import android.support.v7.widget.helper.ItemTouchHelper.SimpleCallback
import android.support.v7.widget.{DefaultItemAnimator, LinearLayoutManager, RecyclerView, Toolbar} import android.support.v7.widget.{DefaultItemAnimator, LinearLayoutManager, RecyclerView, Toolbar}
import android.view._ import android.view._
import android.widget.{EditText, Spinner, TextView, Toast} import android.widget.{EditText, Spinner, TextView, Toast}
import com.futuremind.recyclerviewfastscroll.{FastScroller, SectionTitleProvider}
import com.github.shadowsocks.ShadowsocksApplication.app import com.github.shadowsocks.ShadowsocksApplication.app
import com.github.shadowsocks.utils.State import com.github.shadowsocks.utils.State
import com.github.shadowsocks.widget.UndoSnackbarManager import com.github.shadowsocks.widget.UndoSnackbarManager
...@@ -103,7 +104,7 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi ...@@ -103,7 +104,7 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi
} }
} }
private final class AclRulesAdapter extends RecyclerView.Adapter[AclRuleViewHolder] { private final class AclRulesAdapter extends RecyclerView.Adapter[AclRuleViewHolder] with SectionTitleProvider {
private val acl = Acl.customRules private val acl = Acl.customRules
private var savePending: Boolean = _ private var savePending: Boolean = _
private def apply() = if (!savePending) { private def apply() = if (!savePending) {
...@@ -192,6 +193,17 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi ...@@ -192,6 +193,17 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi
onSelectedItemsUpdated() onSelectedItemsUpdated()
notifyDataSetChanged() notifyDataSetChanged()
} }
def getSectionTitle(i: Int): String = {
val j = i - acl.subnets.size
(if (j < 0) acl.subnets(i).address.toString.charAt(0).toString else {
val hostname = acl.proxyHostnames(i)
PATTERN_DOMAIN.findFirstMatchIn(hostname) match {
case Some(m) => m.matched.replaceAll("\\\\.", ".") // don't convert IDN yet
case None => hostname
}
}).substring(0, 1)
}
} }
private lazy val adapter = new AclRulesAdapter() private lazy val adapter = new AclRulesAdapter()
...@@ -201,7 +213,7 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi ...@@ -201,7 +213,7 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi
private lazy val clipboard = getActivity.getSystemService(Context.CLIPBOARD_SERVICE).asInstanceOf[ClipboardManager] private lazy val clipboard = getActivity.getSystemService(Context.CLIPBOARD_SERVICE).asInstanceOf[ClipboardManager]
override def onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle): View = override def onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle): View =
inflater.inflate(R.layout.layout_list, container, false) inflater.inflate(R.layout.layout_custom_rules, container, false)
override def onViewCreated(view: View, savedInstanceState: Bundle) { override def onViewCreated(view: View, savedInstanceState: Bundle) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
if (savedInstanceState != null) { if (savedInstanceState != null) {
...@@ -224,6 +236,8 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi ...@@ -224,6 +236,8 @@ class CustomRulesFragment extends ToolbarFragment with Toolbar.OnMenuItemClickLi
list.setLayoutManager(new LinearLayoutManager(getActivity, LinearLayoutManager.VERTICAL, false)) list.setLayoutManager(new LinearLayoutManager(getActivity, LinearLayoutManager.VERTICAL, false))
list.setItemAnimator(new DefaultItemAnimator) list.setItemAnimator(new DefaultItemAnimator)
list.setAdapter(adapter) list.setAdapter(adapter)
val fastScroller = view.findViewById(R.id.fastscroller).asInstanceOf[FastScroller]
fastScroller.setRecyclerView(list)
undoManager = new UndoSnackbarManager[AnyRef](getActivity.findViewById(R.id.snackbar), adapter.undo) undoManager = new UndoSnackbarManager[AnyRef](getActivity.findViewById(R.id.snackbar), adapter.undo)
new ItemTouchHelper(new SimpleCallback(0, ItemTouchHelper.START | ItemTouchHelper.END) { new ItemTouchHelper(new SimpleCallback(0, ItemTouchHelper.START | ItemTouchHelper.END) {
override def getSwipeDirs(recyclerView: RecyclerView, viewHolder: ViewHolder): Int = override def getSwipeDirs(recyclerView: RecyclerView, viewHolder: ViewHolder): Int =
......
...@@ -82,16 +82,6 @@ object Utils { ...@@ -82,16 +82,6 @@ object Utils {
toast toast
} }
def crossFade(context: Context, from: View, to: View) {
def shortAnimTime = context.getResources.getInteger(android.R.integer.config_shortAnimTime)
to.setAlpha(0)
to.setVisibility(View.VISIBLE)
to.animate().alpha(1).setDuration(shortAnimTime)
from.animate().alpha(0).setDuration(shortAnimTime).setListener(new AnimatorListenerAdapter {
override def onAnimationEnd(animation: Animator): Unit = from.setVisibility(View.GONE)
})
}
def readAllLines(f: File): String = { def readAllLines(f: File): String = {
val scanner = new Scanner(f) val scanner = new Scanner(f)
try { try {
......
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