Misc refinements
* Refine Kotlin codes; * Support RTL; * Use VectorDrawable for notification; * Remove redundant resources; * Better IDE integration.
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user