url profile update
This commit is contained in:
16 files changed
+352
-84
No files matched your search
@@ -1,6 +1,5 @@
|
||||
package com.github.kr328.clash
|
||||
|
||||
object Constants {
|
||||
const val TAG = "ClashForAndroid"
|
||||
const val PROFILES_DIR = "profiles"
|
||||
}
|
||||
@@ -99,7 +99,7 @@ class ImportFileActivity : BaseActivity() {
|
||||
it.readBytes().toString(Charsets.UTF_8)
|
||||
} ?: throw NullPointerException("Unable to open config file")
|
||||
|
||||
val parsed = Yaml(configuration = YamlConfiguration(strictMode = false)).parse(
|
||||
Yaml(configuration = YamlConfiguration(strictMode = false)).parse(
|
||||
ClashProfile.serializer(),
|
||||
data
|
||||
)
|
||||
@@ -114,12 +114,9 @@ class ImportFileActivity : BaseActivity() {
|
||||
it.profileService.addProfile(
|
||||
ClashProfileEntity(
|
||||
name = name.content,
|
||||
token = "file|" + file.content!!.toString(),
|
||||
cache = cache.absolutePath,
|
||||
token = ClashProfileEntity.fileToken(file.content!!.toString()),
|
||||
file = cache.absolutePath,
|
||||
active = false,
|
||||
proxies = parsed.proxies.size,
|
||||
proxyGroups = parsed.proxyGroups.size,
|
||||
rules = parsed.rules.size,
|
||||
lastUpdate = System.currentTimeMillis()
|
||||
)
|
||||
)
|
||||
@@ -129,7 +126,7 @@ class ImportFileActivity : BaseActivity() {
|
||||
} catch (e: Exception) {
|
||||
Snackbar.make(
|
||||
activity_import_file_root,
|
||||
getString(R.string.clash_import_file_invalid, e.toString()),
|
||||
getString(R.string.clash_profile_invalid, e.toString()),
|
||||
Snackbar.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
|
||||
@@ -2,14 +2,27 @@ package com.github.kr328.clash
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.charleskorn.kaml.Yaml
|
||||
import com.charleskorn.kaml.YamlConfiguration
|
||||
import com.github.kr328.clash.adapter.FormAdapter
|
||||
import com.github.kr328.clash.model.ClashProfile
|
||||
import com.github.kr328.clash.service.data.ClashProfileEntity
|
||||
import com.github.kr328.clash.utils.FileUtils
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.android.synthetic.main.activity_import_file.*
|
||||
import kotlinx.android.synthetic.main.activity_import_url.*
|
||||
import java.io.FileOutputStream
|
||||
import java.lang.Exception
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.net.*
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class ImportUrlActivity : BaseActivity() {
|
||||
companion object {
|
||||
const val DEFAULT_TIMEOUT = 30 * 1000
|
||||
}
|
||||
|
||||
private val elements = listOf<FormAdapter.Type>(
|
||||
FormAdapter.TextType(
|
||||
R.drawable.ic_about,
|
||||
@@ -33,6 +46,10 @@ class ImportUrlActivity : BaseActivity() {
|
||||
it.layoutManager = LinearLayoutManager(this)
|
||||
it.adapter = FormAdapter(this, elements)
|
||||
}
|
||||
|
||||
activity_import_url_save.setOnClickListener {
|
||||
checkAndInsert()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
@@ -49,13 +66,74 @@ class ImportUrlActivity : BaseActivity() {
|
||||
val name = elements[0] as FormAdapter.TextType
|
||||
val url = elements[1] as FormAdapter.TextType
|
||||
|
||||
if ( name.content.isEmpty() ) {
|
||||
|
||||
|
||||
if ( name.content.isBlank() ) {
|
||||
return
|
||||
}
|
||||
|
||||
URL(url.content).openConnection()
|
||||
if ( url.content.isBlank() ) {
|
||||
return
|
||||
}
|
||||
|
||||
activity_import_url_save.visibility = View.GONE
|
||||
activity_import_url_saving.visibility = View.VISIBLE
|
||||
|
||||
runClash {
|
||||
val httpPort = it.queryGeneral().ports.randomHttp
|
||||
|
||||
thread {
|
||||
try {
|
||||
val connection = if ( httpPort > 0 )
|
||||
URL(url.content).openConnection(Proxy(Proxy.Type.HTTP,
|
||||
InetSocketAddress.createUnresolved("127.0.0.1", httpPort)))
|
||||
else
|
||||
URL(url.content).openConnection()
|
||||
|
||||
val data = with (connection) {
|
||||
connectTimeout = DEFAULT_TIMEOUT
|
||||
connect()
|
||||
|
||||
getInputStream().bufferedReader().use {
|
||||
it.readText()
|
||||
}
|
||||
}
|
||||
|
||||
Yaml(configuration = YamlConfiguration(strictMode = false)).parse(ClashProfile.serializer(), data)
|
||||
|
||||
val cache =
|
||||
FileUtils.generateRandomFile(filesDir.resolve(Constants.PROFILES_DIR), ".yaml")
|
||||
|
||||
FileOutputStream(cache).use { outputStream ->
|
||||
outputStream.write(data.toByteArray())
|
||||
}
|
||||
|
||||
runClash { clash ->
|
||||
clash.profileService.addProfile(ClashProfileEntity(name.content,
|
||||
ClashProfileEntity.urlToken(url.content),
|
||||
cache.absolutePath,
|
||||
false,
|
||||
System.currentTimeMillis()))
|
||||
}
|
||||
|
||||
runOnUiThread {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
catch (e: Exception) {
|
||||
runOnUiThread {
|
||||
Snackbar.make(
|
||||
activity_import_url_root,
|
||||
getString(R.string.clash_profile_invalid, e.toString()),
|
||||
Snackbar.LENGTH_LONG
|
||||
).show()
|
||||
|
||||
activity_import_url_save.visibility = View.VISIBLE
|
||||
activity_import_url_saving.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (e: Exception) {
|
||||
|
||||
|
||||
@@ -1,15 +1,35 @@
|
||||
package com.github.kr328.clash
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.PopupMenu
|
||||
import androidx.appcompat.view.menu.MenuPopupHelper
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.charleskorn.kaml.Yaml
|
||||
import com.charleskorn.kaml.YamlConfiguration
|
||||
import com.github.kr328.clash.adapter.ProfileAdapter
|
||||
import com.github.kr328.clash.core.Clash
|
||||
import com.github.kr328.clash.core.event.ProfileChangedEvent
|
||||
import com.github.kr328.clash.model.ClashProfile
|
||||
import com.github.kr328.clash.service.data.ClashProfileEntity
|
||||
import com.github.kr328.clash.utils.FileUtils
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.android.synthetic.main.activity_import_url.*
|
||||
import kotlinx.android.synthetic.main.activity_profiles.*
|
||||
import java.io.FileOutputStream
|
||||
import java.lang.Exception
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.Proxy
|
||||
import java.net.URL
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class ProfilesActivity : BaseActivity() {
|
||||
private var dialog: Dialog? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_profiles)
|
||||
@@ -24,11 +44,10 @@ class ProfilesActivity : BaseActivity() {
|
||||
override fun canScrollHorizontally(): Boolean = false
|
||||
override fun canScrollVertically(): Boolean = false
|
||||
}
|
||||
activity_profiles_main_list.adapter = ProfileAdapter(this) { id ->
|
||||
runClash {
|
||||
it.profileService.setActiveProfile(id)
|
||||
}
|
||||
}
|
||||
activity_profiles_main_list.adapter = ProfileAdapter(this,
|
||||
this::onProfileClick,
|
||||
this::onOperateClick,
|
||||
this::onProfileLongClick)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
@@ -84,4 +103,102 @@ class ProfilesActivity : BaseActivity() {
|
||||
result.dispatchUpdatesTo(adapter)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onProfileClick(profile: ClashProfileEntity) {
|
||||
runClash {
|
||||
it.profileService.setActiveProfile(profile.id)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onOperateClick(profile: ClashProfileEntity) {
|
||||
when {
|
||||
ClashProfileEntity.isUrlToken(profile.token) -> {
|
||||
dialog?.dismiss()
|
||||
|
||||
dialog = AlertDialog.Builder(this)
|
||||
.setTitle(R.string.clash_profile_updating)
|
||||
.setView(R.layout.dialog_profile_updating)
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
|
||||
updateProfile(profile)
|
||||
}
|
||||
ClashProfileEntity.isFileToken(profile.token) -> {
|
||||
Snackbar.make(
|
||||
activity_profiles_root,
|
||||
R.string.not_implemented,
|
||||
Snackbar.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onProfileLongClick(parent: View, profile: ClashProfileEntity) {
|
||||
PopupMenu(this, parent).apply {
|
||||
setOnMenuItemClickListener { removeProfile(profile).run { true } }
|
||||
inflate(R.menu.menu_profile_popup)
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeProfile(profile: ClashProfileEntity) {
|
||||
runClash {
|
||||
it.profileService.removeProfile(profile.id)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateProfile(profile: ClashProfileEntity) {
|
||||
val url = ClashProfileEntity.getUrl(profile.token)
|
||||
|
||||
runClash {
|
||||
val httpPort = it.queryGeneral().ports.randomHttp
|
||||
|
||||
thread {
|
||||
try {
|
||||
val connection = if ( httpPort > 0 )
|
||||
URL(url).openConnection(
|
||||
Proxy(
|
||||
Proxy.Type.HTTP,
|
||||
InetSocketAddress.createUnresolved("127.0.0.1", httpPort))
|
||||
)
|
||||
else
|
||||
URL(url).openConnection()
|
||||
|
||||
val data = with (connection) {
|
||||
connectTimeout = ImportUrlActivity.DEFAULT_TIMEOUT
|
||||
connect()
|
||||
|
||||
getInputStream().bufferedReader().use {
|
||||
it.readText()
|
||||
}
|
||||
}
|
||||
|
||||
Yaml(configuration = YamlConfiguration(strictMode = false)).parse(
|
||||
ClashProfile.serializer(), data)
|
||||
|
||||
FileOutputStream(profile.file).use { outputStream ->
|
||||
outputStream.write(data.toByteArray())
|
||||
}
|
||||
|
||||
runClash { clash ->
|
||||
clash.profileService.addProfile(profile
|
||||
.copy(lastUpdate = System.currentTimeMillis()))
|
||||
}
|
||||
}
|
||||
catch (e: Exception) {
|
||||
runOnUiThread {
|
||||
Snackbar.make(
|
||||
activity_profiles_root,
|
||||
getString(R.string.clash_profile_invalid, e.toString()),
|
||||
Snackbar.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
runOnUiThread {
|
||||
dialog?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,19 @@
|
||||
package com.github.kr328.clash.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.kr328.clash.R
|
||||
import com.github.kr328.clash.service.data.ClashProfileEntity
|
||||
import com.github.kr328.clash.view.RadioFatItem
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
class ProfileAdapter(private val context: Context, private val listener: (Int) -> Unit) :
|
||||
class ProfileAdapter(private val context: Context,
|
||||
private val onClick: (ClashProfileEntity) -> Unit,
|
||||
private val onOperateClick: (ClashProfileEntity) -> Unit,
|
||||
private val onLongClicked: (View,ClashProfileEntity) -> Unit) :
|
||||
RecyclerView.Adapter<ProfileAdapter.ProfileViewHolder>() {
|
||||
var profiles: Array<ClashProfileEntity> = emptyArray()
|
||||
|
||||
@@ -32,26 +38,40 @@ class ProfileAdapter(private val context: Context, private val listener: (Int) -
|
||||
val current = profiles[position]
|
||||
|
||||
holder.view.title = current.name
|
||||
holder.view.summary = context.getString(
|
||||
R.string.clash_profile_item_summary,
|
||||
current.proxies, current.proxyGroups, current.rules
|
||||
)
|
||||
holder.view.isChecked = current.active
|
||||
holder.view.setOnClickListener {
|
||||
listener(current.id)
|
||||
onClick(current)
|
||||
}
|
||||
holder.view.setOnOperationOnClickListener(View.OnClickListener {
|
||||
onOperateClick(current)
|
||||
})
|
||||
holder.view.setOnLongClickListener {
|
||||
onLongClicked(it, current).run { true }
|
||||
}
|
||||
|
||||
holder.view.operation = context.getDrawable(R.drawable.ic_vert)
|
||||
val profileUpdateDate = GregorianCalendar().apply {
|
||||
timeInMillis = current.lastUpdate
|
||||
}
|
||||
val now = Calendar.getInstance()
|
||||
|
||||
// with(current.token) {
|
||||
// when {
|
||||
// startsWith("http") || startsWith("content") -> {
|
||||
//
|
||||
// }
|
||||
// startsWith("file") -> {
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
val formatter = if ( profileUpdateDate.get(Calendar.YEAR) == now.get(Calendar.YEAR) &&
|
||||
profileUpdateDate.get(Calendar.MONTH) == now.get(Calendar.MONTH) &&
|
||||
profileUpdateDate.get(Calendar.DAY_OF_MONTH) == now.get(Calendar.DAY_OF_MONTH) )
|
||||
SimpleDateFormat("HH:mm:ss", Locale.getDefault())
|
||||
else
|
||||
SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
|
||||
|
||||
when {
|
||||
ClashProfileEntity.isFileToken(current.token) -> {
|
||||
holder.view.operation = context.getDrawable(R.drawable.ic_edit)
|
||||
holder.view.summary = context.getString(R.string.clash_profile_item_summary_file,
|
||||
formatter.format(profileUpdateDate.time))
|
||||
}
|
||||
ClashProfileEntity.isUrlToken(current.token) -> {
|
||||
holder.view.operation = context.getDrawable(R.drawable.ic_sync)
|
||||
holder.view.summary = context.getString(R.string.clash_profile_item_summary_url,
|
||||
formatter.format(profileUpdateDate.time))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,11 +61,11 @@ class RadioFatItem @JvmOverloads constructor(
|
||||
clickable.setOnLongClickListener(l)
|
||||
}
|
||||
|
||||
fun setOperationOnClickListener(l: OnClickListener?) {
|
||||
fun setOnOperationOnClickListener(l: OnClickListener?) {
|
||||
operationClickable.setOnClickListener(l)
|
||||
}
|
||||
|
||||
fun setOperationOnLongClickListener(l: OnLongClickListener?) {
|
||||
fun setOnOperationOnLongClickListener(l: OnLongClickListener?) {
|
||||
operationClickable.setOnLongClickListener(l)
|
||||
}
|
||||
|
||||
|
||||
@@ -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="#FF000000"
|
||||
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
|
||||
</vector>
|
||||
@@ -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="#FF000000"
|
||||
android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z"/>
|
||||
</vector>
|
||||
@@ -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="#FF000000"
|
||||
android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z"/>
|
||||
</vector>
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/activity_profiles_root"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?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="wrap_content">
|
||||
|
||||
<ProgressBar
|
||||
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="20dp"
|
||||
android:indeterminate="true"
|
||||
android:indeterminateBehavior="repeat" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -53,11 +53,18 @@
|
||||
android:layout_alignTop="@id/view_radio_fat_item_text_container"
|
||||
android:layout_alignBottom="@id/view_radio_fat_item_text_container">
|
||||
|
||||
<View
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/lightGray"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/view_radio_fat_item_operation"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp" />
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp" />
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_pofile_popup_remove"
|
||||
android:title="@string/clash_profile_remove" />
|
||||
</menu>
|
||||
@@ -20,9 +20,12 @@
|
||||
<string name="clash_feedback">Feedback</string>
|
||||
<string name="clash_about">About</string>
|
||||
|
||||
<string name="clash_new_profile">New Profile</string>
|
||||
<string name="clash_profile_item_summary">%d Proxy, %d Group, %d Rule</string>
|
||||
<string name="clash_profile_item_summary_file">%s (File)</string>
|
||||
<string name="clash_profile_item_summary_url">%s (URL)</string>
|
||||
<string name="clash_profile_remove">Remove</string>
|
||||
<string name="clash_profile_updating">Profile Updating</string>
|
||||
|
||||
<string name="clash_new_profile">New Profile</string>
|
||||
<string name="clash_new_profile_file_title">File</string>
|
||||
<string name="clash_new_profile_file_summary">From Local Storage</string>
|
||||
|
||||
@@ -46,7 +49,7 @@
|
||||
|
||||
<string name="clash_import_file_empty_name">Empty Name</string>
|
||||
<string name="clash_import_file_empty_path">Empty Path</string>
|
||||
<string name="clash_import_file_invalid">Invalid Config: %s</string>
|
||||
<string name="clash_profile_invalid">Invalid Config: %s</string>
|
||||
|
||||
<string name="clash_proxy_group_title">%s - %s</string>
|
||||
|
||||
@@ -85,4 +88,6 @@
|
||||
|
||||
<string name="clash_start_service_notification_channel">Clash Start Service</string>
|
||||
<string name="clash_start_service_notification">Starting Clash</string>
|
||||
|
||||
<string name="not_implemented">Not Implemented</string>
|
||||
</resources>
|
||||
@@ -7,6 +7,7 @@ import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.*
|
||||
import com.github.kr328.clash.core.Clash
|
||||
import com.github.kr328.clash.core.ClashProcess
|
||||
import com.github.kr328.clash.core.event.*
|
||||
import com.github.kr328.clash.core.model.GeneralPacket
|
||||
import com.github.kr328.clash.core.model.ProxyPacket
|
||||
@@ -237,6 +238,9 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
|
||||
|
||||
private fun reloadProfile() {
|
||||
executor.submit {
|
||||
if ( clash.process.getProcessStatus() != ProcessEvent.STARTED)
|
||||
return@submit
|
||||
|
||||
val active = profileService.queryActiveProfile()
|
||||
|
||||
if (active == null) {
|
||||
@@ -244,11 +248,11 @@ class ClashService : Service(), IClashEventObserver, ClashEventService.Master,
|
||||
return@submit
|
||||
}
|
||||
|
||||
Log.i("Loading profile ${active.cache}")
|
||||
Log.i("Loading profile ${active.file}")
|
||||
|
||||
try {
|
||||
val remove = clash.loadProfile(
|
||||
File(active.cache),
|
||||
File(active.file),
|
||||
profileService.queryProfileSelected(active.id)
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.github.kr328.clash.service.data
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import androidx.room.*
|
||||
@@ -7,48 +8,15 @@ import com.github.kr328.clash.core.serialization.Parcels
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Entity(tableName = "profiles")
|
||||
@TypeConverters(ClashProfileEntity.Converters::class)
|
||||
@Serializable
|
||||
data class ClashProfileEntity(
|
||||
@ColumnInfo(name = "name") val name: String,
|
||||
@ColumnInfo(name = "token") val token: String,
|
||||
@ColumnInfo(name = "cache") val cache: String,
|
||||
@ColumnInfo(name = "file") val file: String,
|
||||
@ColumnInfo(name = "active") val active: Boolean,
|
||||
@ColumnInfo(name = "proxies") val proxies: Int,
|
||||
@ColumnInfo(name = "proxy_groups") val proxyGroups: Int,
|
||||
@ColumnInfo(name = "rules") val rules: Int,
|
||||
@ColumnInfo(name = "last_update") val lastUpdate: Long,
|
||||
@ColumnInfo(name = "id") @PrimaryKey(autoGenerate = true) val id: Int = 0
|
||||
) : Parcelable {
|
||||
|
||||
enum class Type {
|
||||
UNKNOWN, URL, FILE
|
||||
}
|
||||
|
||||
class Converters {
|
||||
@TypeConverter
|
||||
fun typeToInt(type: Type?): Int? {
|
||||
return type?.run {
|
||||
when (this) {
|
||||
Type.URL -> 1
|
||||
Type.FILE -> 2
|
||||
Type.UNKNOWN -> 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun intToType(i: Int?): Type? {
|
||||
return i?.run {
|
||||
when (this) {
|
||||
1 -> Type.URL
|
||||
2 -> Type.FILE
|
||||
else -> Type.UNKNOWN
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
Parcels.dump(serializer(), this, parcel)
|
||||
}
|
||||
@@ -57,13 +25,36 @@ data class ClashProfileEntity(
|
||||
return 0
|
||||
}
|
||||
|
||||
companion object CREATOR : Parcelable.Creator<ClashProfileEntity> {
|
||||
override fun createFromParcel(parcel: Parcel): ClashProfileEntity {
|
||||
return Parcels.load(serializer(), parcel)
|
||||
companion object {
|
||||
fun fileToken(content: String): String {
|
||||
return "file|$content"
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<ClashProfileEntity?> {
|
||||
return arrayOfNulls(size)
|
||||
fun urlToken(content: String): String {
|
||||
return "url|$content"
|
||||
}
|
||||
|
||||
fun isFileToken(token: String): Boolean {
|
||||
return token.startsWith("file|")
|
||||
}
|
||||
|
||||
fun isUrlToken(token: String): Boolean {
|
||||
return token.startsWith("url|")
|
||||
}
|
||||
|
||||
fun getUrl(token: String): String {
|
||||
return token.removePrefix("url|")
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val CREATOR = object : Parcelable.Creator<ClashProfileEntity> {
|
||||
override fun createFromParcel(parcel: Parcel): ClashProfileEntity {
|
||||
return Parcels.load(serializer(), parcel)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<ClashProfileEntity?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user