Misc refinements

* Refine Kotlin codes;
* Support RTL;
* Use VectorDrawable for notification;
* Remove redundant resources;
* Better IDE integration.
This commit is contained in:
Mygod
2017-12-06 19:46:26 -08:00
parent f49d3cb443
commit c124e1e8ef
34 changed files with 151 additions and 132 deletions
@@ -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 ->
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)
}
})
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,8 +30,8 @@ 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,
commit: ((List<Pair<Int, T>>) -> Unit)? = null) {
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() {
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {