application settings & start on boot
This commit is contained in:
34 files changed
+457
-117
No files matched your search
@@ -4,6 +4,7 @@
|
||||
package="com.github.kr328.clash">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
@@ -59,5 +60,19 @@
|
||||
android:label="@string/proxy_setting_vpn_setting_access_control"
|
||||
android:exported="false"
|
||||
android:screenOrientation="portrait"/>
|
||||
<activity android:name=".SettingApplicationActivity"
|
||||
android:label="@string/application_setting_application"
|
||||
android:exported="false"
|
||||
android:screenOrientation="portrait" />
|
||||
<service android:name=".ClashStartService"
|
||||
android:exported="false"/>
|
||||
<receiver
|
||||
android:name=".BootCompleteReceiver"
|
||||
android:exported="true"
|
||||
android:enabled="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.github.kr328.clash
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
|
||||
class BootCompleteReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (Intent.ACTION_BOOT_COMPLETED != intent?.action || context == null)
|
||||
return
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(Intent(context, ClashStartService::class.java))
|
||||
} else {
|
||||
context.startService(Intent(context, ClashStartService::class.java))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.github.kr328.clash
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.VpnService
|
||||
import android.os.Binder
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import com.github.kr328.clash.service.ClashService
|
||||
import com.github.kr328.clash.service.TunService
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class ClashStartService : Service() {
|
||||
companion object {
|
||||
private const val NOTIFICATION_CHANNEL_ID = "clash_start_service_notification_channel"
|
||||
private const val NOTIFICATION_ID = 142
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
NotificationManagerCompat.from(this).apply {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
createNotificationChannel(NotificationChannel(NOTIFICATION_CHANNEL_ID,
|
||||
getString(R.string.clash_start_service_notification_channel),
|
||||
NotificationManager.IMPORTANCE_DEFAULT))
|
||||
}
|
||||
}
|
||||
|
||||
val notification = NotificationCompat
|
||||
.Builder(this, NOTIFICATION_CHANNEL_ID)
|
||||
.setContentTitle(getString(R.string.clash_start_service_notification))
|
||||
.setSmallIcon(R.drawable.ic_notification_icon)
|
||||
.build()
|
||||
|
||||
startForeground(NOTIFICATION_ID, notification)
|
||||
|
||||
thread {
|
||||
getSharedPreferences("application", Context.MODE_PRIVATE).apply {
|
||||
when (getString(
|
||||
MainApplication.KEY_PROXY_MODE,
|
||||
MainApplication.PROXY_MODE_VPN
|
||||
)) {
|
||||
MainApplication.PROXY_MODE_VPN -> {
|
||||
if (VpnService.prepare(this@ClashStartService) == null)
|
||||
startService(
|
||||
Intent(
|
||||
this@ClashStartService,
|
||||
TunService::class.java
|
||||
)
|
||||
)
|
||||
}
|
||||
MainApplication.PROXY_MODE_PROXY_ONLY -> {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForegroundService(
|
||||
Intent(
|
||||
this@ClashStartService,
|
||||
ClashService::class.java
|
||||
)
|
||||
)
|
||||
} else {
|
||||
startService(
|
||||
Intent(
|
||||
this@ClashStartService,
|
||||
ClashService::class.java
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
return Binder()
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
package com.github.kr328.clash
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.VpnService
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.github.kr328.clash.core.event.BandwidthEvent
|
||||
@@ -10,6 +12,7 @@ import com.github.kr328.clash.core.event.Event
|
||||
import com.github.kr328.clash.core.event.ProcessEvent
|
||||
import com.github.kr328.clash.core.event.ProfileChangedEvent
|
||||
import com.github.kr328.clash.core.utils.ByteFormatter
|
||||
import com.github.kr328.clash.service.ClashService
|
||||
import com.github.kr328.clash.service.TunService
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.activity_main_clash_status.*
|
||||
@@ -56,9 +59,40 @@ class MainActivity : BaseActivity() {
|
||||
it.stop()
|
||||
}
|
||||
else -> runOnUiThread {
|
||||
VpnService.prepare(this@MainActivity)?.apply {
|
||||
startActivityForResult(this, VPN_REQUEST_CODE)
|
||||
} ?: startService(Intent(this@MainActivity, TunService::class.java))
|
||||
getSharedPreferences("application", Context.MODE_PRIVATE).apply {
|
||||
when (getString(
|
||||
MainApplication.KEY_PROXY_MODE,
|
||||
MainApplication.PROXY_MODE_VPN
|
||||
)) {
|
||||
MainApplication.PROXY_MODE_VPN -> {
|
||||
VpnService.prepare(this@MainActivity)?.apply {
|
||||
startActivityForResult(this, VPN_REQUEST_CODE)
|
||||
} ?: startService(
|
||||
Intent(
|
||||
this@MainActivity,
|
||||
TunService::class.java
|
||||
)
|
||||
)
|
||||
}
|
||||
MainApplication.PROXY_MODE_PROXY_ONLY -> {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForegroundService(
|
||||
Intent(
|
||||
this@MainActivity,
|
||||
ClashService::class.java
|
||||
)
|
||||
)
|
||||
} else {
|
||||
startService(
|
||||
Intent(
|
||||
this@MainActivity,
|
||||
ClashService::class.java
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class ProxyActivity : BaseActivity() {
|
||||
setSupportActionBar(activity_proxies_toolbar)
|
||||
|
||||
activity_proxies_list.also {
|
||||
it.adapter = ProxyAdapter(this) {p, s ->
|
||||
it.adapter = ProxyAdapter(this) { p, s ->
|
||||
runClash { clash ->
|
||||
clash.setSelectProxy(p, s)
|
||||
}
|
||||
@@ -63,7 +63,8 @@ class ProxyActivity : BaseActivity() {
|
||||
})
|
||||
)
|
||||
.flatMap {
|
||||
val header = ListProxy.ListProxyHeader(it.value.name, it.value.type, it.value.now)
|
||||
val header =
|
||||
ListProxy.ListProxyHeader(it.value.name, it.value.type, it.value.now)
|
||||
|
||||
sequenceOf(header) +
|
||||
it.value.all
|
||||
@@ -80,8 +81,8 @@ class ProxyActivity : BaseActivity() {
|
||||
.asSequence()
|
||||
}
|
||||
.mapIndexed { index, listProxy ->
|
||||
if ( listProxy is ListProxy.ListProxyItem ) {
|
||||
if ( listProxy.name.hashCode() == listProxy.header.now )
|
||||
if (listProxy is ListProxy.ListProxyItem) {
|
||||
if (listProxy.name.hashCode() == listProxy.header.now)
|
||||
listProxy.header.now = index
|
||||
}
|
||||
listProxy
|
||||
@@ -97,11 +98,11 @@ class ProxyActivity : BaseActivity() {
|
||||
.filterIsInstance<ListProxy.ListProxyHeader>()
|
||||
.map { it.now }
|
||||
|
||||
val changed = if ( listDataOldChanged.size != listDataChanged.size )
|
||||
val changed = if (listDataOldChanged.size != listDataChanged.size)
|
||||
(0..listData.size).toList()
|
||||
else {
|
||||
listDataChanged.mapIndexed { index, i ->
|
||||
if ( i == listDataOldChanged[index] )
|
||||
if (i == listDataOldChanged[index])
|
||||
emptyList()
|
||||
else
|
||||
listOf(listDataOldChanged[index], i)
|
||||
|
||||
@@ -16,7 +16,7 @@ import kotlin.concurrent.thread
|
||||
class SettingAccessActivity : BaseActivity() {
|
||||
private data class AppInfo(val packageName: String, val name: String, val icon: Drawable)
|
||||
|
||||
private class AppListAdapter(val context: Context):
|
||||
private class AppListAdapter(val context: Context) :
|
||||
RecyclerView.Adapter<AppListAdapter.Holder>() {
|
||||
|
||||
var applications: List<AppInfo> = emptyList()
|
||||
@@ -30,8 +30,10 @@ class SettingAccessActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
|
||||
return Holder(LayoutInflater.from(context)
|
||||
.inflate(R.layout.adapter_access_app, parent, false))
|
||||
return Holder(
|
||||
LayoutInflater.from(context)
|
||||
.inflate(R.layout.adapter_access_app, parent, false)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
@@ -47,7 +49,7 @@ class SettingAccessActivity : BaseActivity() {
|
||||
holder.checkbox.isChecked = current.packageName in selected
|
||||
|
||||
holder.view.setOnClickListener {
|
||||
if ( holder.checkbox.isChecked )
|
||||
if (holder.checkbox.isChecked)
|
||||
selected.remove(current.packageName)
|
||||
else
|
||||
selected.add(current.packageName)
|
||||
@@ -107,7 +109,7 @@ class SettingAccessActivity : BaseActivity() {
|
||||
val settings = it.settingService
|
||||
|
||||
runOnUiThread {
|
||||
when ( settings.accessControlMode ) {
|
||||
when (settings.accessControlMode) {
|
||||
ClashSettingService.ACCESS_CONTROL_MODE_ALLOW_ALL ->
|
||||
activity_setting_access_allow_all.performClick()
|
||||
ClashSettingService.ACCESS_CONTROL_MODE_ALLOW ->
|
||||
@@ -124,9 +126,11 @@ class SettingAccessActivity : BaseActivity() {
|
||||
exclude.contains(it.packageName)
|
||||
}
|
||||
.map { app ->
|
||||
AppInfo(app.packageName,
|
||||
AppInfo(
|
||||
app.packageName,
|
||||
app.loadLabel(packageManager).toString(),
|
||||
app.loadIcon(packageManager))
|
||||
app.loadIcon(packageManager)
|
||||
)
|
||||
}
|
||||
.sortedBy { app ->
|
||||
app.name
|
||||
@@ -164,10 +168,12 @@ class SettingAccessActivity : BaseActivity() {
|
||||
else -> return@runClash
|
||||
}
|
||||
|
||||
if ( listLoaded )
|
||||
it.settingService.setAccessControl(mode,
|
||||
if (listLoaded)
|
||||
it.settingService.setAccessControl(
|
||||
mode,
|
||||
(activity_setting_access_app_list.adapter as AppListAdapter)
|
||||
.selected.toTypedArray())
|
||||
.selected.toTypedArray()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,9 +183,9 @@ class SettingAccessActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when ( item.itemId ) {
|
||||
when (item.itemId) {
|
||||
R.id.menu_setting_access_hide -> {
|
||||
if ( hidden ) {
|
||||
if (hidden) {
|
||||
activity_setting_access_allow_all.visibility = View.VISIBLE
|
||||
activity_setting_access_allow.visibility = View.VISIBLE
|
||||
activity_setting_access_disallow.visibility = View.VISIBLE
|
||||
@@ -187,13 +193,12 @@ class SettingAccessActivity : BaseActivity() {
|
||||
item.title = getString(R.string.access_setting_hide_header)
|
||||
|
||||
hidden = false
|
||||
}
|
||||
else {
|
||||
if ( !activity_setting_access_allow_all.isChecked )
|
||||
} else {
|
||||
if (!activity_setting_access_allow_all.isChecked)
|
||||
activity_setting_access_allow_all.visibility = View.GONE
|
||||
if ( !activity_setting_access_allow.isChecked )
|
||||
if (!activity_setting_access_allow.isChecked)
|
||||
activity_setting_access_allow.visibility = View.GONE
|
||||
if ( !activity_setting_access_disallow.isChecked )
|
||||
if (!activity_setting_access_disallow.isChecked)
|
||||
activity_setting_access_disallow.visibility = View.GONE
|
||||
|
||||
item.title = getString(R.string.access_setting_show_header)
|
||||
@@ -218,7 +223,8 @@ class SettingAccessActivity : BaseActivity() {
|
||||
R.id.menu_setting_access_select_invert -> {
|
||||
thread {
|
||||
(activity_setting_access_app_list.adapter as AppListAdapter).apply {
|
||||
selected = (applications.map { it.packageName }.toSet() - selected).toMutableSet()
|
||||
selected =
|
||||
(applications.map { it.packageName }.toSet() - selected).toMutableSet()
|
||||
}
|
||||
|
||||
runOnUiThread {
|
||||
@@ -242,23 +248,22 @@ class SettingAccessActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun updateListStatus() {
|
||||
if ( showList )
|
||||
if (showList)
|
||||
activity_setting_access_divider.visibility = View.VISIBLE
|
||||
else
|
||||
activity_setting_access_divider.visibility = View.GONE
|
||||
|
||||
|
||||
if ( showList ) {
|
||||
if ( listLoaded )
|
||||
if (showList) {
|
||||
if (listLoaded)
|
||||
activity_setting_access_loading.visibility = View.GONE
|
||||
else
|
||||
activity_setting_access_loading.visibility = View.VISIBLE
|
||||
}
|
||||
else
|
||||
} else
|
||||
activity_setting_access_loading.visibility = View.GONE
|
||||
|
||||
|
||||
if ( showList && listLoaded )
|
||||
if (showList && listLoaded)
|
||||
activity_setting_access_app_list.visibility = View.VISIBLE
|
||||
else
|
||||
activity_setting_access_app_list.visibility = View.GONE
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.github.kr328.clash
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.SharedPreferences
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import androidx.preference.CheckBoxPreference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import kotlinx.android.synthetic.main.activity_setting_application.*
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class SettingApplicationActivity : BaseActivity() {
|
||||
companion object {
|
||||
const val KEY_START_ON_BOOT = "key_application_start_on_boot"
|
||||
}
|
||||
|
||||
class Fragment : PreferenceFragmentCompat(),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.setting_application, rootKey)
|
||||
|
||||
preferenceManager.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
|
||||
val status = requireContext().packageManager
|
||||
.getComponentEnabledSetting(
|
||||
ComponentName.createRelative(
|
||||
requireContext(),
|
||||
BootCompleteReceiver::class.java.name
|
||||
)
|
||||
)
|
||||
|
||||
findPreference<CheckBoxPreference>(KEY_START_ON_BOOT)?.isChecked =
|
||||
status == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(
|
||||
sharedPreferences: SharedPreferences?,
|
||||
key: String?
|
||||
) {
|
||||
when (key) {
|
||||
KEY_START_ON_BOOT -> {
|
||||
val enabled = sharedPreferences!!.getBoolean(key, false)
|
||||
|
||||
thread {
|
||||
if (enabled) {
|
||||
requireContext().packageManager
|
||||
.setComponentEnabledSetting(
|
||||
ComponentName.createRelative(
|
||||
requireContext(),
|
||||
BootCompleteReceiver::class.java.name
|
||||
),
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||
PackageManager.DONT_KILL_APP
|
||||
)
|
||||
} else {
|
||||
requireContext().packageManager
|
||||
.setComponentEnabledSetting(
|
||||
ComponentName.createRelative(
|
||||
requireContext(),
|
||||
BootCompleteReceiver::class.java.name
|
||||
),
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
||||
PackageManager.DONT_KILL_APP
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_setting_application)
|
||||
|
||||
setSupportActionBar(activity_setting_application_toolbar)
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,8 @@ class SettingProxyActivity : BaseActivity() {
|
||||
|
||||
requireActivity().runOnUiThread {
|
||||
findPreference<CheckBoxPreference>(KEY_IPV6_SUPPORT)?.isChecked = ipv6
|
||||
findPreference<CheckBoxPreference>(KEY_BYPASS_PRIVATE_NETWORK)?.isChecked = privateNetwork
|
||||
findPreference<CheckBoxPreference>(KEY_BYPASS_PRIVATE_NETWORK)?.isChecked =
|
||||
privateNetwork
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,8 +42,11 @@ class SettingProxyActivity : BaseActivity() {
|
||||
(requireActivity() as SettingProxyActivity).runClash {
|
||||
val settings = it.settingService
|
||||
|
||||
settings.isIPv6Enabled = findPreference<CheckBoxPreference>(KEY_IPV6_SUPPORT)?.isChecked ?: true
|
||||
settings.isBypassPrivateNetwork = findPreference<CheckBoxPreference>(KEY_BYPASS_PRIVATE_NETWORK)?.isChecked ?: true
|
||||
settings.isIPv6Enabled =
|
||||
findPreference<CheckBoxPreference>(KEY_IPV6_SUPPORT)?.isChecked ?: true
|
||||
settings.isBypassPrivateNetwork =
|
||||
findPreference<CheckBoxPreference>(KEY_BYPASS_PRIVATE_NETWORK)?.isChecked
|
||||
?: true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,7 +74,7 @@ class SettingProxyActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
getSharedPreferences("application", Context.MODE_PRIVATE).apply {
|
||||
when ( getString(MainApplication.KEY_PROXY_MODE, MainApplication.PROXY_MODE_VPN) ) {
|
||||
when (getString(MainApplication.KEY_PROXY_MODE, MainApplication.PROXY_MODE_VPN)) {
|
||||
MainApplication.PROXY_MODE_VPN ->
|
||||
activity_setting_proxy_vpn_mode.performClick()
|
||||
MainApplication.PROXY_MODE_PROXY_ONLY ->
|
||||
@@ -81,7 +85,7 @@ class SettingProxyActivity : BaseActivity() {
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
|
||||
|
||||
getSharedPreferences("application", Context.MODE_PRIVATE).edit {
|
||||
when {
|
||||
activity_setting_proxy_vpn_mode.isChecked ->
|
||||
|
||||
@@ -13,11 +13,12 @@ import com.github.kr328.clash.core.model.ProxyPacket
|
||||
import com.github.kr328.clash.model.ListProxy
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
|
||||
class ProxyAdapter(private val context: Context, val listener: (String, String) -> Unit) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
class ProxyAdapter(private val context: Context, val listener: (String, String) -> Unit) :
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
var elements: List<ListProxy> = emptyList()
|
||||
var clickable: Boolean = false
|
||||
|
||||
class HeaderHolder(view: View): RecyclerView.ViewHolder(view) {
|
||||
class HeaderHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
val name: TextView = view.findViewById(R.id.adapter_proxy_header_name)
|
||||
val test: View = view.findViewById(R.id.adapter_proxy_header_url_test)
|
||||
}
|
||||
@@ -30,7 +31,7 @@ class ProxyAdapter(private val context: Context, val listener: (String, String)
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return when ( elements[position] ) {
|
||||
return when (elements[position]) {
|
||||
is ListProxy.ListProxyItem -> 1
|
||||
is ListProxy.ListProxyHeader -> 2
|
||||
else -> throw IllegalArgumentException("Invalid type")
|
||||
@@ -39,8 +40,20 @@ class ProxyAdapter(private val context: Context, val listener: (String, String)
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return when (viewType) {
|
||||
1 -> ItemHolder(LayoutInflater.from(context).inflate(R.layout.adapter_proxy_item, parent, false))
|
||||
2 -> HeaderHolder(LayoutInflater.from(context).inflate(R.layout.adapter_proxy_header, parent, false))
|
||||
1 -> ItemHolder(
|
||||
LayoutInflater.from(context).inflate(
|
||||
R.layout.adapter_proxy_item,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
2 -> HeaderHolder(
|
||||
LayoutInflater.from(context).inflate(
|
||||
R.layout.adapter_proxy_header,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
else -> throw IllegalArgumentException("Invalid type")
|
||||
}
|
||||
}
|
||||
@@ -58,9 +71,9 @@ class ProxyAdapter(private val context: Context, val listener: (String, String)
|
||||
|
||||
fun getLayoutManager(): GridLayoutManager {
|
||||
return GridLayoutManager(context, 2).apply {
|
||||
spanSizeLookup = object: GridLayoutManager.SpanSizeLookup() {
|
||||
spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
|
||||
override fun getSpanSize(position: Int): Int {
|
||||
return when ( elements[position] ) {
|
||||
return when (elements[position]) {
|
||||
is ListProxy.ListProxyHeader -> 2
|
||||
is ListProxy.ListProxyItem -> 1
|
||||
else -> throw IllegalArgumentException("Invalid type")
|
||||
@@ -71,20 +84,19 @@ class ProxyAdapter(private val context: Context, val listener: (String, String)
|
||||
}
|
||||
|
||||
private fun bindItemView(holder: ItemHolder, current: ListProxy.ListProxyItem, position: Int) {
|
||||
if ( position == current.header.now ) {
|
||||
if (position == current.header.now) {
|
||||
holder.card.setCardBackgroundColor(context.getColor(R.color.colorAccent))
|
||||
holder.name.setTextColor(Color.WHITE)
|
||||
holder.type.setTextColor(Color.WHITE - 0x22222222)
|
||||
holder.delay.setTextColor(Color.WHITE - 0x11111111)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
holder.card.setCardBackgroundColor(Color.WHITE)
|
||||
holder.name.setTextColor(Color.BLACK)
|
||||
holder.type.setTextColor(Color.LTGRAY)
|
||||
holder.delay.setTextColor(Color.DKGRAY)
|
||||
}
|
||||
|
||||
if ( current.header.type == ProxyPacket.Type.SELECT ) {
|
||||
if (current.header.type == ProxyPacket.Type.SELECT) {
|
||||
holder.card.isFocusable = true
|
||||
holder.card.isClickable = true
|
||||
holder.card.setOnClickListener {
|
||||
@@ -98,8 +110,7 @@ class ProxyAdapter(private val context: Context, val listener: (String, String)
|
||||
|
||||
listener(element.header.name, element.name)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
holder.card.setOnClickListener(null)
|
||||
holder.card.isFocusable = false
|
||||
holder.card.isClickable = false
|
||||
@@ -111,7 +122,7 @@ class ProxyAdapter(private val context: Context, val listener: (String, String)
|
||||
if (current.delay > 0) {
|
||||
current.delay.toString()
|
||||
} else {
|
||||
if ( current.header.type != ProxyPacket.Type.SELECT )
|
||||
if (current.header.type != ProxyPacket.Type.SELECT)
|
||||
"N/A"
|
||||
else
|
||||
""
|
||||
@@ -121,6 +132,7 @@ class ProxyAdapter(private val context: Context, val listener: (String, String)
|
||||
|
||||
private fun bindHeaderView(holder: HeaderHolder, current: ListProxy.ListProxyHeader) {
|
||||
holder.name.text = current.name
|
||||
holder.test.visibility = if ( current.type == ProxyPacket.Type.SELECT ) View.VISIBLE else View.GONE
|
||||
holder.test.visibility =
|
||||
if (current.type == ProxyPacket.Type.SELECT) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,13 @@ package com.github.kr328.clash.model
|
||||
import com.github.kr328.clash.core.model.ProxyPacket
|
||||
|
||||
interface ListProxy {
|
||||
data class ListProxyHeader(val name: String, val type: ProxyPacket.Type, var now: Int): ListProxy
|
||||
data class ListProxyItem(val name: String, val type: String, val delay: Long, val header: ListProxyHeader): ListProxy
|
||||
data class ListProxyHeader(val name: String, val type: ProxyPacket.Type, var now: Int) :
|
||||
ListProxy
|
||||
|
||||
data class ListProxyItem(
|
||||
val name: String,
|
||||
val type: String,
|
||||
val delay: Long,
|
||||
val header: ListProxyHeader
|
||||
) : ListProxy
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<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="@color/colorAccent"
|
||||
android:pathData="M5,16c0,3.87 3.13,7 7,7s7,-3.13 7,-7v-4L5,12v4zM16.12,4.37l2.1,-2.1 -0.82,-0.83 -2.3,2.31C14.16,3.28 13.12,3 12,3s-2.16,0.28 -3.09,0.75L6.6,1.44l-0.82,0.83 2.1,2.1C6.14,5.64 5,7.68 5,10v1h14v-1c0,-2.32 -1.14,-4.36 -2.88,-5.63zM9,9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM15,9c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@color/colorAccent"
|
||||
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96z"/>
|
||||
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,8l-6,6 1.41,1.41L12,10.83l4.59,4.58L18,14z"/>
|
||||
android:pathData="M12,8l-6,6 1.41,1.41L12,10.83l4.59,4.58L18,14z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/>
|
||||
android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19.1,12.9a2.8,2.8 0,0 0,0.1 -0.9,2.8 2.8,0 0,0 -0.1,-0.9l2.1,-1.6a0.7,0.7 0,0 0,0.1 -0.6L19.4,5.5a0.7,0.7 0,0 0,-0.6 -0.2l-2.4,1a6.5,6.5 0,0 0,-1.6 -0.9l-0.4,-2.6a0.5,0.5 0,0 0,-0.5 -0.4H10.1a0.5,0.5 0,0 0,-0.5 0.4L9.3,5.4a5.6,5.6 0,0 0,-1.7 0.9l-2.4,-1a0.4,0.4 0,0 0,-0.5 0.2l-2,3.4c-0.1,0.2 0,0.4 0.2,0.6l2,1.6a2.8,2.8 0,0 0,-0.1 0.9,2.8 2.8,0 0,0 0.1,0.9L2.8,14.5a0.7,0.7 0,0 0,-0.1 0.6l1.9,3.4a0.7,0.7 0,0 0,0.6 0.2l2.4,-1a6.5,6.5 0,0 0,1.6 0.9l0.4,2.6a0.5,0.5 0,0 0,0.5 0.4h3.8a0.5,0.5 0,0 0,0.5 -0.4l0.3,-2.6a5.6,5.6 0,0 0,1.7 -0.9l2.4,1a0.4,0.4 0,0 0,0.5 -0.2l2,-3.4c0.1,-0.2 0,-0.4 -0.2,-0.6ZM12,15.6A3.6,3.6 0,1 1,15.6 12,3.6 3.6,0 0,1 12,15.6Z"/>
|
||||
android:pathData="M19.1,12.9a2.8,2.8 0,0 0,0.1 -0.9,2.8 2.8,0 0,0 -0.1,-0.9l2.1,-1.6a0.7,0.7 0,0 0,0.1 -0.6L19.4,5.5a0.7,0.7 0,0 0,-0.6 -0.2l-2.4,1a6.5,6.5 0,0 0,-1.6 -0.9l-0.4,-2.6a0.5,0.5 0,0 0,-0.5 -0.4H10.1a0.5,0.5 0,0 0,-0.5 0.4L9.3,5.4a5.6,5.6 0,0 0,-1.7 0.9l-2.4,-1a0.4,0.4 0,0 0,-0.5 0.2l-2,3.4c-0.1,0.2 0,0.4 0.2,0.6l2,1.6a2.8,2.8 0,0 0,-0.1 0.9,2.8 2.8,0 0,0 0.1,0.9L2.8,14.5a0.7,0.7 0,0 0,-0.1 0.6l1.9,3.4a0.7,0.7 0,0 0,0.6 0.2l2.4,-1a6.5,6.5 0,0 0,1.6 0.9l0.4,2.6a0.5,0.5 0,0 0,0.5 0.4h3.8a0.5,0.5 0,0 0,0.5 -0.4l0.3,-2.6a5.6,5.6 0,0 0,1.7 -0.9l2.4,1a0.4,0.4 0,0 0,0.5 -0.2l2,-3.4c0.1,-0.2 0,-0.4 -0.2,-0.6ZM12,15.6A3.6,3.6 0,1 1,15.6 12,3.6 3.6,0 0,1 12,15.6Z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/colorAccent"
|
||||
android:pathData="M19.1,12.9a2.8,2.8 0,0 0,0.1 -0.9,2.8 2.8,0 0,0 -0.1,-0.9l2.1,-1.6a0.7,0.7 0,0 0,0.1 -0.6L19.4,5.5a0.7,0.7 0,0 0,-0.6 -0.2l-2.4,1a6.5,6.5 0,0 0,-1.6 -0.9l-0.4,-2.6a0.5,0.5 0,0 0,-0.5 -0.4H10.1a0.5,0.5 0,0 0,-0.5 0.4L9.3,5.4a5.6,5.6 0,0 0,-1.7 0.9l-2.4,-1a0.4,0.4 0,0 0,-0.5 0.2l-2,3.4c-0.1,0.2 0,0.4 0.2,0.6l2,1.6a2.8,2.8 0,0 0,-0.1 0.9,2.8 2.8,0 0,0 0.1,0.9L2.8,14.5a0.7,0.7 0,0 0,-0.1 0.6l1.9,3.4a0.7,0.7 0,0 0,0.6 0.2l2.4,-1a6.5,6.5 0,0 0,1.6 0.9l0.4,2.6a0.5,0.5 0,0 0,0.5 0.4h3.8a0.5,0.5 0,0 0,0.5 -0.4l0.3,-2.6a5.6,5.6 0,0 0,1.7 -0.9l2.4,1a0.4,0.4 0,0 0,0.5 -0.2l2,-3.4c0.1,-0.2 0,-0.4 -0.2,-0.6ZM12,15.6A3.6,3.6 0,1 1,15.6 12,3.6 3.6,0 0,1 12,15.6Z"/>
|
||||
android:pathData="M19.1,12.9a2.8,2.8 0,0 0,0.1 -0.9,2.8 2.8,0 0,0 -0.1,-0.9l2.1,-1.6a0.7,0.7 0,0 0,0.1 -0.6L19.4,5.5a0.7,0.7 0,0 0,-0.6 -0.2l-2.4,1a6.5,6.5 0,0 0,-1.6 -0.9l-0.4,-2.6a0.5,0.5 0,0 0,-0.5 -0.4H10.1a0.5,0.5 0,0 0,-0.5 0.4L9.3,5.4a5.6,5.6 0,0 0,-1.7 0.9l-2.4,-1a0.4,0.4 0,0 0,-0.5 0.2l-2,3.4c-0.1,0.2 0,0.4 0.2,0.6l2,1.6a2.8,2.8 0,0 0,-0.1 0.9,2.8 2.8,0 0,0 0.1,0.9L2.8,14.5a0.7,0.7 0,0 0,-0.1 0.6l1.9,3.4a0.7,0.7 0,0 0,0.6 0.2l2.4,-1a6.5,6.5 0,0 0,1.6 0.9l0.4,2.6a0.5,0.5 0,0 0,0.5 0.4h3.8a0.5,0.5 0,0 0,0.5 -0.4l0.3,-2.6a5.6,5.6 0,0 0,1.7 -0.9l2.4,1a0.4,0.4 0,0 0,0.5 -0.2l2,-3.4c0.1,-0.2 0,-0.4 -0.2,-0.6ZM12,15.6A3.6,3.6 0,1 1,15.6 12,3.6 3.6,0 0,1 12,15.6Z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M7,2v11h3v9l7,-12h-4l4,-8z"/>
|
||||
android:pathData="M7,2v11h3v9l7,-12h-4l4,-8z" />
|
||||
</vector>
|
||||
@@ -1,9 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
|
||||
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" />
|
||||
</vector>
|
||||
@@ -21,6 +21,7 @@
|
||||
android:layout_marginEnd="15dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/activity_proxies_list"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/activity_setting_access_toolbar"
|
||||
android:elevation="4dp"
|
||||
@@ -17,27 +18,26 @@
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
|
||||
|
||||
<com.github.kr328.clash.view.RadioFatItem
|
||||
app:title="@string/access_setting_allow_all"
|
||||
app:summary="@string/access_setting_allow_all_summary"
|
||||
android:id="@+id/activity_setting_access_allow_all"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.github.kr328.clash.view.RadioFatItem
|
||||
app:title="@string/access_setting_allow"
|
||||
app:summary="@string/access_setting_allow_summary"
|
||||
android:id="@+id/activity_setting_access_allow"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.github.kr328.clash.view.RadioFatItem
|
||||
app:title="@string/access_setting_disallow"
|
||||
app:summary="@string/access_setting_disallow_summary"
|
||||
android:id="@+id/activity_setting_access_disallow"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<View
|
||||
android:id="@+id/activity_setting_access_divider"
|
||||
@@ -45,12 +45,12 @@
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/lightGray"/>
|
||||
android:background="@color/lightGray" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/activity_setting_access_app_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/activity_setting_access_loading"
|
||||
@@ -60,5 +60,5 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginStart="70dp"
|
||||
android:visibility="gone"/>
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/activity_setting_application_toolbar"
|
||||
android:elevation="4dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/activity_setting_application_content"
|
||||
android:name="com.github.kr328.clash.SettingApplicationActivity$Fragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
||||
@@ -7,6 +7,7 @@
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/activity_setting_main_toolbar"
|
||||
android:elevation="4dp"
|
||||
@@ -18,6 +19,5 @@
|
||||
android:id="@+id/activity_setting_main_content"
|
||||
android:name="com.github.kr328.clash.SettingMainActivity$Fragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
||||
@@ -9,6 +9,7 @@
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/activity_setting_proxy_toolbar"
|
||||
android:elevation="4dp"
|
||||
@@ -22,25 +23,25 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:title="@string/proxy_setting_vpn_mode"
|
||||
app:summary="@string/proxy_setting_vpn_mode_summary"/>
|
||||
app:summary="@string/proxy_setting_vpn_mode_summary" />
|
||||
|
||||
<com.github.kr328.clash.view.RadioFatItem
|
||||
android:id="@+id/activity_setting_proxy_proxy_only_mode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:title="@string/proxy_setting_proxy_mode"
|
||||
app:summary="@string/proxy_setting_proxy_mode_summary"/>
|
||||
app:summary="@string/proxy_setting_proxy_mode_summary" />
|
||||
|
||||
<View
|
||||
android:id="@+id/activity_setting_proxy_divider"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/lightGray"/>
|
||||
android:background="@color/lightGray" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/activity_setting_proxy_content"
|
||||
android:name="com.github.kr328.clash.SettingProxyActivity$Fragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
||||
@@ -24,17 +24,19 @@
|
||||
android:layout_toStartOf="@id/adapter_access_app_checkbox"
|
||||
android:layout_centerVertical="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/adapter_access_app_name"
|
||||
android:textColor="@android:color/black"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/adapter_access_app_package_name"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.checkbox.MaterialCheckBox
|
||||
@@ -44,5 +46,5 @@
|
||||
android:layout_alignParentEnd="true"
|
||||
android:gravity="center"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="70dp"/>
|
||||
android:layout_height="70dp" />
|
||||
</RelativeLayout>
|
||||
@@ -12,6 +12,7 @@
|
||||
app:cardUseCompatPadding="true"
|
||||
app:cardElevation="2dp"
|
||||
app:cardCornerRadius="5dp">
|
||||
|
||||
<RelativeLayout
|
||||
android:padding="15dp"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -24,7 +25,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toStartOf="@id/adapter_proxy_item_delay"
|
||||
android:layout_alignParentStart="true"/>
|
||||
android:layout_alignParentStart="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/adapter_proxy_item_type"
|
||||
@@ -32,7 +33,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="12sp"
|
||||
android:maxLines="1"/>
|
||||
android:maxLines="1" />
|
||||
|
||||
<TextView
|
||||
android:layout_alignParentEnd="true"
|
||||
|
||||
@@ -23,16 +23,18 @@
|
||||
android:layout_toEndOf="@android:id/icon"
|
||||
android:layout_centerVertical="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:textColor="@android:color/black"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:layout_marginTop="2dp"
|
||||
android:id="@android:id/summary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical" android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</LinearLayout>
|
||||
@@ -13,9 +13,9 @@
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="RadioFatItem">
|
||||
<attr name="icon"/>
|
||||
<attr name="title"/>
|
||||
<attr name="summary"/>
|
||||
<attr name="operation"/>
|
||||
<attr name="icon" />
|
||||
<attr name="title" />
|
||||
<attr name="summary" />
|
||||
<attr name="operation" />
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
@@ -72,4 +72,11 @@
|
||||
<string name="access_setting_select_all">Select All</string>
|
||||
<string name="access_setting_select_invert">Select Invert</string>
|
||||
<string name="access_setting_clean_selection">Clear Selection</string>
|
||||
|
||||
<string name="application_setting_behavior">Behavior</string>
|
||||
<string name="application_setting_start_on_boot">Start on Boot</string>
|
||||
<string name="application_setting_start_on_boot_summary">Start clash on system boot</string>
|
||||
|
||||
<string name="clash_start_service_notification_channel">Clash Start Service</string>
|
||||
<string name="clash_start_service_notification">Starting Clash</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceCategory android:title="@string/application_setting_behavior">
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="false"
|
||||
android:icon="@drawable/ic_boot"
|
||||
android:key="key_application_start_on_boot"
|
||||
android:summary="@string/application_setting_start_on_boot_summary"
|
||||
android:title="@string/application_setting_start_on_boot" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
@@ -1,10 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<Preference
|
||||
android:title="@string/application_setting_application"
|
||||
android:icon="@drawable/ic_settings_color"
|
||||
android:layout="@layout/preference_main_item">
|
||||
<intent
|
||||
android:targetClass="com.github.kr328.clash.SettingApplicationActivity"
|
||||
android:targetPackage="com.github.kr328.clash" />
|
||||
</Preference>
|
||||
<Preference
|
||||
android:title="@string/application_setting_proxy"
|
||||
android:icon="@drawable/ic_cloud"
|
||||
android:layout="@layout/preference_main_item">
|
||||
<intent android:targetClass="com.github.kr328.clash.SettingProxyActivity"
|
||||
<intent
|
||||
android:targetClass="com.github.kr328.clash.SettingProxyActivity"
|
||||
android:targetPackage="com.github.kr328.clash" />
|
||||
</Preference>
|
||||
</PreferenceScreen>
|
||||
@@ -4,7 +4,7 @@
|
||||
<CheckBoxPreference
|
||||
android:key="key_vpn_setting_bypass_private_network"
|
||||
android:title="@string/proxy_setting_vpn_setting_bypass_private_network"
|
||||
android:summary="@string/proxy_setting_vpn_setting_bypass_private_network_summary"/>
|
||||
android:summary="@string/proxy_setting_vpn_setting_bypass_private_network_summary" />
|
||||
<CheckBoxPreference
|
||||
android:key="key_vpn_setting_ipv6_support"
|
||||
android:title="@string/proxy_setting_vpn_setting_ipv6"
|
||||
@@ -13,7 +13,8 @@
|
||||
android:layout="@layout/preference_proxy_item"
|
||||
android:title="@string/proxy_setting_vpn_setting_access_control"
|
||||
android:summary="@string/proxy_setting_vpn_setting_access_control_summary">
|
||||
<intent android:targetPackage="com.github.kr328.clash"
|
||||
<intent
|
||||
android:targetPackage="com.github.kr328.clash"
|
||||
android:targetClass="com.github.kr328.clash.SettingAccessActivity" />
|
||||
</Preference>
|
||||
</PreferenceCategory>
|
||||
|
||||
@@ -85,7 +85,6 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
|
||||
notification.setVpn(true)
|
||||
|
||||
clash.startTunDevice(fd.fileDescriptor, mtu)
|
||||
fd.close()
|
||||
} catch (e: Exception) {
|
||||
Log.e("Start tun failure", e)
|
||||
|
||||
@@ -93,6 +92,9 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
|
||||
ErrorEvent(ErrorEvent.Type.START_FAILURE, e.toString())
|
||||
)
|
||||
}
|
||||
finally {
|
||||
fd.close()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getEventService(): IClashEventService {
|
||||
@@ -226,6 +228,8 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
|
||||
eventService.preformBandwidthEvent(BandwidthEvent(0))
|
||||
|
||||
notification.cancel()
|
||||
|
||||
stopSelf()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,10 +107,14 @@ class TunService : VpnService(), IClashEventObserver {
|
||||
clash.start()
|
||||
else
|
||||
stopSelf()
|
||||
|
||||
Log.i("STOPPED")
|
||||
}
|
||||
ProcessEvent.STARTED -> {
|
||||
start = false
|
||||
clash.startTunDevice(fileDescriptor, VPN_MTU)
|
||||
|
||||
Log.i("STARTED")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user