Commit c124e1e8 authored by Mygod's avatar Mygod

Misc refinements

* Refine Kotlin codes;
* Support RTL;
* Use VectorDrawable for notification;
* Remove redundant resources;
* Better IDE integration.
parent f49d3cb4
......@@ -110,13 +110,17 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener {
}
private inner class AppsAdapter : RecyclerView.Adapter<AppViewHolder>(), SectionTitleProvider {
private val apps = getApps(packageManager).sortedWith(Comparator { a, b ->
private var apps = listOf<ProxiedApp>()
fun reload() {
apps = getApps(packageManager).sortedWith(Comparator { a, b ->
when (Pair(proxiedApps.contains(a.packageName), proxiedApps.contains(b.packageName))) {
Pair(true, false) -> -1
Pair(false, true) -> 1
else -> a.name.compareTo(b.name, true)
}
})
}
override fun onBindViewHolder(holder: AppViewHolder, position: Int) = holder.bind(apps[position])
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppViewHolder =
......@@ -143,15 +147,17 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener {
}
private fun loadAppsAsync() {
if (!appsLoading.compareAndSet(false, true)) return
appListView.visibility = View.GONE
fastScroller.visibility = View.GONE
loadingView.visibility = View.VISIBLE
thread {
var adapter: AppsAdapter?
val adapter = appListView.adapter as AppsAdapter
do {
appsLoading.set(true)
adapter = AppsAdapter()
adapter.reload()
} while (!appsLoading.compareAndSet(true, false))
handler.post {
appListView.adapter = adapter
fastScroller.setRecyclerView(appListView)
adapter.notifyDataSetChanged()
val shortAnimTime = resources.getInteger(android.R.integer.config_shortAnimTime)
appListView.alpha = 0F
appListView.visibility = View.VISIBLE
......@@ -204,7 +210,9 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener {
appListView = findViewById(R.id.list)
appListView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
appListView.itemAnimator = DefaultItemAnimator()
appListView.adapter = AppsAdapter()
fastScroller = findViewById(R.id.fastscroller)
fastScroller.setRecyclerView(appListView)
instance = this
loadAppsAsync()
......@@ -241,9 +249,6 @@ class AppManager : AppCompatActivity(), Toolbar.OnMenuItemClickListener {
DataStore.individual = apps
DataStore.dirty = true
Toast.makeText(this, R.string.action_import_msg, Toast.LENGTH_SHORT).show()
appListView.visibility = View.GONE
fastScroller.visibility = View.GONE
loadingView.visibility = View.VISIBLE
initProxiedApps(apps)
reloadApps()
return true
......
......@@ -26,7 +26,6 @@ import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import android.os.RemoteException
import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
import com.github.shadowsocks.bg.BaseService
......
......@@ -33,7 +33,7 @@ open class ToolbarFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
toolbar = view.findViewById<Toolbar>(R.id.toolbar)
toolbar = view.findViewById(R.id.toolbar)
val activity = activity as MainActivity
if (activity.crossfader == null) activity.drawer.setToolbar(activity, toolbar, true)
}
......
......@@ -48,6 +48,7 @@ import com.github.shadowsocks.ToolbarFragment
import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.utils.Subnet
import com.github.shadowsocks.utils.asIterable
import com.github.shadowsocks.utils.dp
import com.github.shadowsocks.widget.UndoSnackbarManager
import java.net.IDN
import java.net.URL
......@@ -76,6 +77,8 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
private val text = view.findViewById<TextView>(android.R.id.text1)
init {
view.setPaddingRelative(view.paddingStart, view.paddingTop,
Math.max(view.paddingEnd, 20f.dp().toInt()), view.paddingBottom)
view.setOnClickListener(this)
view.setOnLongClickListener(this)
view.setBackgroundResource(R.drawable.background_selectable)
......
......@@ -28,13 +28,12 @@ import java.io.File
object Executable {
const val REDSOCKS = "libredsocks.so"
const val PDNSD = "libpdnsd.so"
const val SS_LOCAL = "libss-local.so"
const val SS_TUNNEL = "libss-tunnel.so"
const val TUN2SOCKS = "libtun2socks.so"
const val OVERTURE = "liboverture.so"
val EXECUTABLES = setOf(SS_LOCAL, SS_TUNNEL, PDNSD, REDSOCKS, TUN2SOCKS, OVERTURE)
val EXECUTABLES = setOf(SS_LOCAL, SS_TUNNEL, REDSOCKS, TUN2SOCKS, OVERTURE)
fun killAll() {
for (process in File("/proc").listFiles { _, name -> TextUtils.isDigitsOnly(name) }) {
......
......@@ -69,7 +69,7 @@ class ServiceNotification(private val service: BaseService.Interface, profileNam
.setContentTitle(profileName)
.setContentIntent(PendingIntent.getActivity(service, 0, Intent(service, MainActivity::class.java)
.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT), 0))
.setSmallIcon(R.drawable.ic_stat_shadowsocks)
.setSmallIcon(R.drawable.ic_start_connected)
private val style = NotificationCompat.BigTextStyle(builder)
private var isVisible = true
......
......@@ -35,11 +35,11 @@ object TrafficMonitor {
var rxTotal = 0L
// Bytes for the last query
var txLast = 0L
var rxLast = 0L
var timestampLast = 0L
private var txLast = 0L
private var rxLast = 0L
private var timestampLast = 0L
@Volatile
var dirty = true
private var dirty = true
private val units = arrayOf("KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", "BB", "NB", "DB", "CB")
private val numberFormat = DecimalFormat("@@@")
......
......@@ -25,7 +25,7 @@ import com.github.shadowsocks.App.Companion.app
import com.github.shadowsocks.ProfilesFragment
object ProfileManager {
const val TAG = "ProfileManager"
private const val TAG = "ProfileManager"
fun createProfile(p: Profile? = null): Profile {
val profile = p ?: Profile()
......
......@@ -21,12 +21,13 @@
package com.github.shadowsocks.plugin
import android.content.pm.ResolveInfo
import android.os.Bundle
class NativePlugin(resolveInfo: ResolveInfo) : ResolvedPlugin(resolveInfo) {
init {
assert(resolveInfo.providerInfo != null)
}
override val metaData get() = resolveInfo.providerInfo.metaData
override val packageName get() = resolveInfo.providerInfo.packageName
override val metaData: Bundle get() = resolveInfo.providerInfo.metaData
override val packageName: String get() = resolveInfo.providerInfo.packageName
}
......@@ -36,9 +36,11 @@ class PluginConfiguration(val pluginsOptions: Map<String, PluginOptions>, val se
val iterator = Commandline.translateCommandline(line).drop(1).iterator()
while (iterator.hasNext()) {
val option = iterator.next()
if (option == "--nocomp") opt.put("nocomp", null)
else if (option.startsWith("--")) opt.put(option.substring(2), iterator.next())
else throw IllegalArgumentException("Unknown kcptun parameter: " + option)
when {
option == "--nocomp" -> opt.put("nocomp", null)
option.startsWith("--") -> opt.put(option.substring(2), iterator.next())
else -> throw IllegalArgumentException("Unknown kcptun parameter: " + option)
}
}
} catch (exc: Exception) {
Log.w("PluginConfiguration", exc.message)
......@@ -55,6 +57,6 @@ class PluginConfiguration(val pluginsOptions: Map<String, PluginOptions>, val se
val result = LinkedList<PluginOptions>()
for ((id, opt) in pluginsOptions) if (id == this.selected) result.addFirst(opt) else result.addLast(opt)
if (!pluginsOptions.contains(selected)) result.addFirst(selectedOptions)
return result.map { it.toString(false) }.joinToString("\n")
return result.joinToString("\n") { it.toString(false) }
}
}
......@@ -28,10 +28,10 @@ import com.github.shadowsocks.App.Companion.app
abstract class ResolvedPlugin(protected val resolveInfo: ResolveInfo) : Plugin() {
protected abstract val metaData: Bundle
override val id by lazy { metaData.getString(PluginContract.METADATA_KEY_ID) }
override val label by lazy { resolveInfo.loadLabel(app.packageManager) }
override val icon by lazy { resolveInfo.loadIcon(app.packageManager) }
override val defaultConfig by lazy { metaData.getString(PluginContract.METADATA_KEY_DEFAULT_CONFIG) }
override val packageName get() = resolveInfo.resolvePackageName
override val id: String by lazy { metaData.getString(PluginContract.METADATA_KEY_ID) }
override val label: CharSequence by lazy { resolveInfo.loadLabel(app.packageManager) }
override val icon: Drawable by lazy { resolveInfo.loadIcon(app.packageManager) }
override val defaultConfig: String by lazy { metaData.getString(PluginContract.METADATA_KEY_DEFAULT_CONFIG) }
override val packageName: String get() = resolveInfo.resolvePackageName
override val trusted by lazy { app.info.signatures.any(PluginManager.trustedSignatures::contains) }
}
......@@ -28,6 +28,7 @@ import com.github.shadowsocks.utils.Key
import com.github.shadowsocks.utils.parsePort
import java.util.*
@Suppress("MemberVisibilityCanPrivate", "unused")
object DataStore : PreferenceDataStore() {
fun getBoolean(key: String?) = DBHelper.kvPairDao.queryForId(key)?.boolean
fun getFloat(key: String?) = DBHelper.kvPairDao.queryForId(key)?.float
......
......@@ -22,7 +22,6 @@ package com.github.shadowsocks.preference
import android.content.Context
import android.graphics.drawable.Drawable
import android.preference.Preference.OnPreferenceChangeListener
import android.support.v7.preference.ListPreference
import android.util.AttributeSet
......@@ -43,19 +42,19 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr
var unknownValueSummary: String? = null
var entryPackageNames: Array<String>? = null
var listener: OnPreferenceChangeListener? = null
private var listener: OnPreferenceChangeListener? = null
override fun getOnPreferenceChangeListener(): OnPreferenceChangeListener? = listener
override fun setOnPreferenceChangeListener(listener: OnPreferenceChangeListener?) {
this.listener = listener
}
init {
super.setOnPreferenceChangeListener(OnPreferenceChangeListener { preference, newValue ->
super.setOnPreferenceChangeListener({ preference, newValue ->
val listener = listener
if (listener == null || listener.onPreferenceChange(preference, newValue)) {
setValue(newValue.toString())
value = newValue.toString()
checkSummary()
if (entryIcons != null) setIcon(entryIcon)
if (entryIcons != null) icon = entryIcon
true
} else false
})
......@@ -70,7 +69,9 @@ class IconListPreference(context: Context, attrs: AttributeSet? = null) : ListPr
if (unknownValueSummary != null) summary = if (selectedEntry < 0) unknownValueSummary.format(value) else "%s"
}
fun init() = setIcon(entryIcon)
fun init() {
icon = entryIcon
}
override fun onSetInitialValue(restoreValue: Boolean, defaultValue: Any?) {
super.onSetInitialValue(restoreValue, defaultValue)
init()
......
......@@ -9,6 +9,7 @@ import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v7.util.SortedList
import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.view.Window
......@@ -77,6 +78,8 @@ fun Toast.position(view: View, window: Window, offsetX: Int = 0, offsetY: Int =
return this
}
fun Float.dp(): Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, app.resources.displayMetrics)
/**
* Based on: https://stackoverflow.com/a/15656428/2245107
*/
......
......@@ -30,7 +30,7 @@ import com.github.shadowsocks.R
* @param commit Callback for committing removals.
* @tparam T Item type.
*/
class UndoSnackbarManager<T>(private val view: View, private val undo: (List<Pair<Int, T>>) -> Unit,
class UndoSnackbarManager<in T>(private val view: View, private val undo: (List<Pair<Int, T>>) -> Unit,
commit: ((List<Pair<Int, T>>) -> Unit)? = null) {
private val recycleBin = ArrayList<Pair<Int, T>>()
private val removedCallback = object : Snackbar.Callback() {
......
......@@ -15,6 +15,7 @@
</item>
</selector>
</item>
<!-- android:start not available until API 23 -->
<item android:left="8dp">
<shape android:shape="rectangle">
<solid android:color="@android:color/white" />
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19,2h-4.18C14.4,0.84 13.3,0 12,0c-1.3,0 -2.4,0.84 -2.82,2L5,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,4c0,-1.1 -0.9,-2 -2,-2zM12,2c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM19,20L5,20L5,4h2v3h10L17,4h2v16z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
......
......@@ -14,28 +14,32 @@
android:background="@android:color/white"
android:orientation="vertical"
tools:ignore="RtlSymmetry">
<Switch android:checked="true"
<Switch
android:id="@+id/onSwitch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checked="true"
android:paddingBottom="12dp"
android:paddingEnd="20dp"
android:paddingStart="60dp"
android:paddingTop="12dp"
android:text="@string/on"
android:textSize="18sp"
android:textColor="?android:attr/textColorSecondary"
android:textSize="18sp"/>
<Switch
android:id="@+id/bypassSwitch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checked="true"
android:paddingBottom="12dp"
android:paddingEnd="20dp"
android:paddingStart="60dp"
android:paddingEnd="16dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Switch android:checked="true"
android:id="@+id/bypassSwitch"
android:text="@string/bypass_apps"
android:textSize="18sp"
android:textColor="?android:attr/textColorSecondary"
android:paddingStart="60dp"
android:paddingEnd="16dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:textSize="18sp"/>
</LinearLayout>
<FrameLayout android:layout_width="fill_parent"
android:layout_height="0dp"
......@@ -48,7 +52,7 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/list"
android:visibility="gone"/>
tools:listitem="@layout/layout_apps_item"/>
<com.futuremind.recyclerviewfastscroll.FastScroller
android:id="@+id/fastscroller"
android:orientation="vertical"
......@@ -57,7 +61,6 @@
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"/>
......
......@@ -9,25 +9,25 @@
<ImageView
android:id="@+id/itemicon"
android:layout_width="60dp"
android:layout_height="48dp"
android:scaleType="fitCenter"
android:paddingStart="8dp"
android:layout_height="52dp"
android:paddingBottom="4dp"
android:paddingEnd="8dp"
android:paddingTop="2dp"
android:paddingBottom="2dp"/>
android:paddingStart="8dp"
android:paddingTop="4dp"
android:scaleType="fitCenter"/>
<Switch
android:id="@+id/itemcheck"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:layout_marginEnd="20dp"
android:layout_weight="1"
android:clickable="false"
android:ellipsize="end"
android:textSize="18sp"
android:textColor="?android:attr/textColorSecondary"
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
android:layout_marginEnd="16dp"/>
android:gravity="center_vertical"
android:textColor="?android:attr/textColorSecondary"
android:textSize="18sp"/>
</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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
......@@ -12,6 +13,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="32dp"
tools:listitem="@android:layout/simple_list_item_1"
android:clipToPadding="false"/>
<com.futuremind.recyclerviewfastscroll.FastScroller
android:id="@+id/fastscroller"
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar_light_dark"/>
<android.support.v7.widget.RecyclerView android:id="@+id/list"
tools:listitem="@android:layout/simple_list_item_1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
......@@ -18,5 +19,6 @@
<android.support.v7.widget.RecyclerView android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:itemview="@android:layout/select_dialog_singlechoice_material"
android:scrollbars="vertical"/>
</LinearLayout>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
<menu xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_apply_all"
android:title="@string/action_apply_all"
android:alphabeticShortcut="a"
android:numericShortcut="1"
app:showAsAction="never"/>
<item android:id="@+id/action_export"
android:title="@string/action_export"
android:icon="@drawable/ic_content_copy"
app:showAsAction="ifRoom"
<item
android:id="@+id/action_export"
android:alphabeticShortcut="e"
android:numericShortcut="2"/>
<item android:id="@+id/action_import"
android:title="@string/action_import"
android:icon="@drawable/ic_content_paste"
app:showAsAction="ifRoom"
android:icon="?attr/actionModeCopyDrawable"
android:numericShortcut="2"
android:title="@string/action_export"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_import"
android:alphabeticShortcut="i"
android:numericShortcut="3"/>
android:icon="?attr/actionModePasteDrawable"
android:numericShortcut="3"
android:title="@string/action_import"
app:showAsAction="ifRoom"/>
</menu>
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:title="@string/add_profile"
android:icon="@drawable/ic_action_note_add"
<item
android:alphabeticShortcut="a"
android:icon="@drawable/ic_action_note_add"
android:numericShortcut="0"
android:title="@string/add_profile"
app:showAsAction="always">
<menu>
<item android:id="@+id/action_scan_qr_code"
android:title="@string/add_profile_methods_scan_qr_code"
<item
android:id="@+id/action_scan_qr_code"
android:alphabeticShortcut="s"
android:numericShortcut="1"/>
<item android:id="@+id/action_import"
android:title="@string/action_import"
android:numericShortcut="1"
android:title="@string/add_profile_methods_scan_qr_code"/>
<item
android:id="@+id/action_import"
android:alphabeticShortcut="i"
android:numericShortcut="2"/>
<item android:id="@+id/action_manual_settings"
android:title="@string/add_profile_methods_manual_settings"
android:numericShortcut="2"
android:title="@string/action_import"/>
<item
android:id="@+id/action_manual_settings"
android:alphabeticShortcut="m"
android:numericShortcut="3"/>
android:numericShortcut="3"
android:title="@string/add_profile_methods_manual_settings"/>
</menu>
</item>
<item android:id="@+id/action_export"
android:title="@string/action_export"
<item
android:id="@+id/action_export"
android:alphabeticShortcut="e"
android:icon="?attr/actionModeCopyDrawable"
android:numericShortcut="1"
android:icon="@drawable/ic_content_copy"
android:title="@string/action_export"
app:showAsAction="always"/>
</menu>
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