package com.github.kr328.clash import android.app.Activity import android.content.ComponentName import android.content.Intent import android.net.Uri import android.provider.Settings import androidx.activity.result.contract.ActivityResultContracts import com.github.kr328.clash.common.constants.Intents import com.github.kr328.clash.common.util.intent import com.github.kr328.clash.common.util.setUUID import com.github.kr328.clash.design.NewProfileDesign import com.github.kr328.clash.design.model.ProfileProvider import com.github.kr328.clash.service.model.Profile import com.github.kr328.clash.util.withProfile import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.isActive import kotlinx.coroutines.selects.select import kotlinx.coroutines.withContext import java.util.* class NewProfileActivity : BaseActivity() { private val self: NewProfileActivity get() = this override suspend fun main() { val design = NewProfileDesign(this) design.patchProviders(queryProfileProviders()) setContentDesign(design) while (isActive) { select { events.onReceive { } design.requests.onReceive { when (it) { is NewProfileDesign.Request.Create -> { withProfile { val name = getString(R.string.new_profile) val uuid: UUID? = when (val p = it.provider) { is ProfileProvider.File -> create(Profile.Type.File, name) is ProfileProvider.Url -> create(Profile.Type.Url, name) is ProfileProvider.External -> { val data = p.get() if (data != null) { val (uri, initialName) = data create( Profile.Type.External, initialName ?: name, uri.toString() ) } else { null } } } if (uuid != null) launchProperties(uuid) } } is NewProfileDesign.Request.OpenDetail -> { launchAppDetailed(it.provider) } } } } } } private fun launchAppDetailed(provider: ProfileProvider.External) { val data = Uri.fromParts( "package", provider.intent.component?.packageName ?: return, null ) startActivity(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).setData(data)) } private suspend fun launchProperties(uuid: UUID) { val r = startActivityForResult( ActivityResultContracts.StartActivityForResult(), PropertiesActivity::class.intent.setUUID(uuid) ) if (r.resultCode == Activity.RESULT_OK) finish() } private suspend fun ProfileProvider.External.get(): Pair? { val result = startActivityForResult( ActivityResultContracts.StartActivityForResult(), intent ) if (result.resultCode != RESULT_OK) return null val uri = result.data?.data val name = result.data?.getStringExtra(Intents.EXTRA_NAME) if (uri != null) { return uri to name } return null } private suspend fun queryProfileProviders(): List { return withContext(Dispatchers.IO) { val providers = packageManager.queryIntentActivities( Intent(Intents.ACTION_PROVIDE_URL), 0 ).map { val activity = it.activityInfo val name = activity.applicationInfo.loadLabel(packageManager) val summary = activity.loadLabel(packageManager) val icon = activity.loadIcon(packageManager) val intent = Intent(Intents.ACTION_PROVIDE_URL) .setComponent( ComponentName( activity.packageName, activity.name ) ) ProfileProvider.External(name.toString(), summary.toString(), icon, intent) } listOf(ProfileProvider.File(self), ProfileProvider.Url(self)) + providers } } }