mirror of
https://github.com/SagerNet/sing-box-for-android.git
synced 2025-04-03 20:07:38 +03:00
Add support for import remote profile
This commit is contained in:
parent
805d99e297
commit
cb9799936b
8 changed files with 92 additions and 7 deletions
|
@ -39,6 +39,19 @@
|
|||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
|
||||
<intent-filter android:label="@string/import_remote_profile">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="import-remote-profile"
|
||||
android:scheme="sing-box" />
|
||||
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.app.shortcuts"
|
||||
android:resource="@xml/shortcuts" />
|
||||
|
|
|
@ -9,14 +9,14 @@ fun Context.errorDialogBuilder(@StringRes messageId: Int): MaterialAlertDialogBu
|
|||
return MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error_title)
|
||||
.setMessage(messageId)
|
||||
.setPositiveButton(resources.getString(android.R.string.ok), null)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
}
|
||||
|
||||
fun Context.errorDialogBuilder(message: String): MaterialAlertDialogBuilder {
|
||||
return MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.error_title)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(resources.getString(android.R.string.ok), null)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
}
|
||||
|
||||
fun Context.errorDialogBuilder(exception: Throwable): MaterialAlertDialogBuilder {
|
||||
|
|
|
@ -26,6 +26,7 @@ import com.microsoft.appcenter.distribute.DistributeListener
|
|||
import com.microsoft.appcenter.distribute.ReleaseDetails
|
||||
import com.microsoft.appcenter.distribute.UpdateAction
|
||||
import com.microsoft.appcenter.utils.AppNameHelper
|
||||
import io.nekohasekai.libbox.Libbox
|
||||
import io.nekohasekai.sfa.Application
|
||||
import io.nekohasekai.sfa.BuildConfig
|
||||
import io.nekohasekai.sfa.R
|
||||
|
@ -37,6 +38,7 @@ import io.nekohasekai.sfa.constant.Status
|
|||
import io.nekohasekai.sfa.database.Settings
|
||||
import io.nekohasekai.sfa.databinding.ActivityMainBinding
|
||||
import io.nekohasekai.sfa.ktx.errorDialogBuilder
|
||||
import io.nekohasekai.sfa.ui.profile.NewProfileActivity
|
||||
import io.nekohasekai.sfa.ui.shared.AbstractActivity
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
|
@ -80,6 +82,31 @@ class MainActivity : AbstractActivity(), ServiceConnection.Callback, DistributeL
|
|||
startAnalysis()
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
val uri = intent.data ?: return
|
||||
if (uri.scheme != "sing-box" || uri.host != "import-remote-profile") {
|
||||
return
|
||||
}
|
||||
val profile = try {
|
||||
Libbox.parseRemoteProfileImportLink(uri.toString())
|
||||
} catch (e: Exception) {
|
||||
errorDialogBuilder(e).show()
|
||||
return
|
||||
}
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.import_remote_profile)
|
||||
.setMessage(getString(R.string.import_remote_profile_message, profile.name, profile.host))
|
||||
.setPositiveButton(android.R.string.ok) { _,_ ->
|
||||
startActivity(Intent(this, NewProfileActivity::class.java).apply {
|
||||
putExtra("importName", profile.name)
|
||||
putExtra("importURL", profile.url)
|
||||
})
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
fun reconnect() {
|
||||
connection.reconnect()
|
||||
}
|
||||
|
@ -104,7 +131,7 @@ class MainActivity : AbstractActivity(), ServiceConnection.Callback, DistributeL
|
|||
val builder = MaterialAlertDialogBuilder(this)
|
||||
.setTitle(getString(R.string.analytics_title))
|
||||
.setMessage(getString(R.string.analytics_message))
|
||||
.setPositiveButton(getString(R.string.ok)) { _, _ ->
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
Settings.analyticsAllowed = Settings.ANALYSIS_ALLOWED
|
||||
startAnalysisInternal()
|
||||
|
@ -258,7 +285,7 @@ class MainActivity : AbstractActivity(), ServiceConnection.Callback, DistributeL
|
|||
|
||||
override fun onServiceAlert(type: Alert, message: String?) {
|
||||
val builder = MaterialAlertDialogBuilder(this)
|
||||
builder.setPositiveButton(resources.getString(android.R.string.ok), null)
|
||||
builder.setPositiveButton(android.R.string.ok, null)
|
||||
when (type) {
|
||||
Alert.RequestVPNPermission -> {
|
||||
builder.setMessage(getString(R.string.service_error_missing_permission))
|
||||
|
|
|
@ -12,11 +12,15 @@ import androidx.lifecycle.lifecycleScope
|
|||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.nekohasekai.libbox.Libbox
|
||||
import io.nekohasekai.sfa.R
|
||||
import io.nekohasekai.sfa.database.Profile
|
||||
import io.nekohasekai.sfa.database.Profiles
|
||||
import io.nekohasekai.sfa.database.TypedProfile
|
||||
import io.nekohasekai.sfa.databinding.FragmentConfigurationBinding
|
||||
import io.nekohasekai.sfa.databinding.ViewConfigutationItemBinding
|
||||
import io.nekohasekai.sfa.ktx.errorDialogBuilder
|
||||
import io.nekohasekai.sfa.ui.MainActivity
|
||||
import io.nekohasekai.sfa.ui.profile.EditProfileActivity
|
||||
import io.nekohasekai.sfa.ui.profile.NewProfileActivity
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -152,12 +156,32 @@ class ConfigurationFragment : Fragment() {
|
|||
intent.putExtra("profile_id", profile.id)
|
||||
it.context.startActivity(intent)
|
||||
}
|
||||
binding.moreButton.setOnClickListener { it ->
|
||||
val popup = PopupMenu(it.context, it)
|
||||
binding.moreButton.setOnClickListener { button ->
|
||||
val popup = PopupMenu(button.context, button)
|
||||
popup.setForceShowIcon(true)
|
||||
popup.menuInflater.inflate(R.menu.profile_menu, popup.menu)
|
||||
if (profile.typed.type != TypedProfile.Type.Remote) {
|
||||
popup.menu.removeItem(R.id.action_share)
|
||||
}
|
||||
popup.setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.action_share -> {
|
||||
try {
|
||||
val link = Libbox.generateRemoteProfileImportLink(
|
||||
profile.name,
|
||||
profile.typed.remoteURL
|
||||
)
|
||||
button.context.startActivity(Intent.createChooser(Intent(android.content.Intent.ACTION_SEND).apply {
|
||||
type = "text/plain"
|
||||
putExtra(Intent.EXTRA_SUBJECT, "Share profile ${profile.name}")
|
||||
putExtra(Intent.EXTRA_TEXT, link)
|
||||
}, "Share"))
|
||||
} catch (e: Exception) {
|
||||
button.context.errorDialogBuilder(e).show()
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
R.id.action_delete -> {
|
||||
adapter.items.remove(profile)
|
||||
adapter.notifyItemRemoved(adapterPosition)
|
||||
|
|
|
@ -82,6 +82,13 @@ class NewProfileActivity : AbstractActivity() {
|
|||
startFilesForResult(importFile, "application/json")
|
||||
}
|
||||
binding.createProfile.setOnClickListener(this::createProfile)
|
||||
intent.getStringExtra("importName")?.also { importName ->
|
||||
intent.getStringExtra("importURL") ?.also { importURL ->
|
||||
binding.name.editText?.setText(importName)
|
||||
binding.type.text = TypedProfile.Type.Remote.name
|
||||
binding.remoteURL.editText?.setText(importURL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createProfile(view: View) {
|
||||
|
|
5
app/src/main/res/drawable/ic_ios_share_24.xml
Normal file
5
app/src/main/res/drawable/ic_ios_share_24.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="#000000"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M16,5l-1.42,1.42 -1.59,-1.59L12.99,16h-1.98L11.01,4.83L9.42,6.42 8,5l4,-4 4,4zM20,10v11c0,1.1 -0.9,2 -2,2L6,23c-1.11,0 -2,-0.9 -2,-2L4,10c0,-1.11 0.89,-2 2,-2h3v2L6,10v11h12L18,10h-3L15,8h3c1.1,0 2,0.89 2,2z"/>
|
||||
</vector>
|
|
@ -2,6 +2,13 @@
|
|||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_share"
|
||||
android:title="@string/menu_share"
|
||||
android:icon="@drawable/ic_ios_share_24"
|
||||
app:iconTintMode="src_in"
|
||||
app:iconTint="?colorPrimary" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_delete"
|
||||
android:title="@string/menu_delete"
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
<string name="menu_redo">Redo</string>
|
||||
<string name="menu_format">Format</string>
|
||||
<string name="menu_delete">Delete</string>
|
||||
<string name="menu_share">Share</string>
|
||||
|
||||
<string name="status_default">Service not started</string>
|
||||
<string name="status_starting">Service starting…</string>
|
||||
|
@ -75,7 +76,6 @@
|
|||
<string name="analytics_title">Analytics</string>
|
||||
<string name="analytics_message">Would you like to give SFA permission to collect analytics, send crash reports, and check update through AppCenter?</string>
|
||||
<string name="no_thanks">No, thanks</string>
|
||||
<string name="ok">Ok</string>
|
||||
<string name="check_update">Check Update</string>
|
||||
<string name="title_app_center">App Center</string>
|
||||
<string name="title_feedback">Feedback</string>
|
||||
|
@ -91,5 +91,7 @@
|
|||
<string name="background_permission_description">Apply for the necessary permissions in order for the VPN to function properly.\n\nIf you are using a device made by a Chinese company, the card may not disappear after the permission is granted.</string>
|
||||
<string name="read_more">Read More</string>
|
||||
<string name="request_background_permission">Ignore battery optimizations</string>
|
||||
<string name="import_remote_profile">Import remote profile</string>
|
||||
<string name="import_remote_profile_message">Are you sure to import remote configuration %s? You will connect to %s to download the configuration.</string>
|
||||
|
||||
</resources>
|
Loading…
Add table
Add a link
Reference in a new issue