package io.nekohasekai.sagernet.ui.compose
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.lifecycleScope
import io.nekohasekai.sagernet.BuildConfig
import io.nekohasekai.sagernet.GroupType
import io.nekohasekai.sagernet.SagerNet
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.GroupManager
import io.nekohasekai.sagernet.database.ProfileManager
import io.nekohasekai.sagernet.database.ProxyEntity
import io.nekohasekai.sagernet.database.ProxyGroup
import io.nekohasekai.sagernet.database.RuleEntity
import io.nekohasekai.sagernet.database.SagerDatabase
import io.nekohasekai.sagernet.database.SubscriptionBean
import io.nekohasekai.sagernet.fmt.AbstractBean
import io.nekohasekai.sagernet.group.GroupUpdater
import io.nekohasekai.sagernet.ktx.applyDefaultValues
import io.nekohasekai.sagernet.fmt.hysteria2.Hysteria2Bean
import io.nekohasekai.sagernet.fmt.http.HttpBean
import io.nekohasekai.sagernet.fmt.http3.Http3Bean
import io.nekohasekai.sagernet.fmt.anytls.AnyTLSBean
import io.nekohasekai.sagernet.fmt.juicity.JuicityBean
import io.nekohasekai.sagernet.fmt.mieru.MieruBean
import io.nekohasekai.sagernet.fmt.naive.NaiveBean
import io.nekohasekai.sagernet.fmt.olcrtc.OLCRTCBean
import io.nekohasekai.sagernet.fmt.shadowquic.ShadowQUICBean
import io.nekohasekai.sagernet.fmt.shadowsocks.ShadowsocksBean
import io.nekohasekai.sagernet.fmt.shadowsocksr.ShadowsocksRBean
import io.nekohasekai.sagernet.fmt.snell.SnellBean
import io.nekohasekai.sagernet.fmt.socks.SOCKSBean
import io.nekohasekai.sagernet.fmt.ssh.SSHBean
import io.nekohasekai.sagernet.fmt.trusttunnel.TrustTunnelBean
import io.nekohasekai.sagernet.fmt.trojan.TrojanBean
import io.nekohasekai.sagernet.fmt.tuic5.Tuic5Bean
import io.nekohasekai.sagernet.fmt.v2ray.VLESSBean
import io.nekohasekai.sagernet.fmt.v2ray.VMessBean
import io.nekohasekai.sagernet.fmt.wireguard.WireGuardBean
import io.nekohasekai.sagernet.ui.compose.screens.AssetsScreen
import io.nekohasekai.sagernet.ui.compose.screens.AppItem
import io.nekohasekai.sagernet.ui.compose.screens.AppListScreen
import io.nekohasekai.sagernet.ui.compose.screens.ConfigEditScreen
import io.nekohasekai.sagernet.ui.compose.screens.GroupSettingsScreen
import io.nekohasekai.sagernet.ui.compose.screens.SubscriptionSettings
import io.nekohasekai.sagernet.ui.compose.screens.ProbeCertScreen
import io.nekohasekai.sagernet.ui.compose.screens.ProfileFieldState
import io.nekohasekai.sagernet.ui.compose.screens.ProfileSelectScreen
import io.nekohasekai.sagernet.ui.compose.screens.QuickSwitchScreen
import io.nekohasekai.sagernet.ui.compose.screens.RouteSettingsScreen
import io.nekohasekai.sagernet.ui.compose.screens.ScannerScreen
import io.nekohasekai.sagernet.ui.compose.screens.StunScreen
import io.nekohasekai.sagernet.ui.compose.screens.UniversalProfileSettingsScreen
import io.nekohasekai.sagernet.utils.PackageCache
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
class ComposeAssetsActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
OwenclaveTheme {
AssetsScreen(
assets = emptyList(),
onBack = { finish() },
onAdd = {},
onEdit = {},
onDelete = {},
)
}
}
}
}
class ComposeAppListActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
if (!DataStore.proxyApps) {
DataStore.proxyApps = true
}
val pm = packageManager
var apps by mutableStateOf
>(emptyList())
var loading by mutableStateOf(true)
var bypass by mutableStateOf(DataStore.bypass)
fun loadApps() {
lifecycleScope.launch {
loading = true
val loaded = withContext(Dispatchers.IO) {
PackageCache.awaitLoadSync()
val individual = DataStore.individual
.split("\n").filter { it.isNotBlank() }.toSet()
PackageCache.installedPackages.toMutableMap().apply {
remove(BuildConfig.APPLICATION_ID)
}.map { (packageName, packageInfo) ->
val appInfo = packageInfo.applicationInfo!!
AppItem(
packageName = packageName,
label = appInfo.loadLabel(pm).toString(),
icon = appInfo.loadIcon(pm),
enabled = individual.contains(packageName),
)
}.sortedWith(compareBy({ !it.enabled }, { it.label }))
}
apps = loaded
loading = false
}
}
fun saveApps(updated: List) {
apps = updated
DataStore.individual = updated.filter { it.enabled }
.joinToString("\n") { it.packageName }
}
loadApps()
setContent {
OwenclaveTheme {
AppListScreen(
apps = apps,
loading = loading,
bypass = bypass,
onBypassChange = { bypass = it; DataStore.bypass = it },
onBack = { finish() },
onToggle = { app ->
saveApps(apps.map {
if (it.packageName == app.packageName) it.copy(enabled = !it.enabled)
else it
}.sortedWith(compareBy({ !it.enabled }, { it.label })))
},
onInvert = {
saveApps(apps.map { it.copy(enabled = !it.enabled) }
.sortedWith(compareBy({ !it.enabled }, { it.label })))
},
onClear = {
saveApps(apps.map { it.copy(enabled = false) }
.sortedWith(compareBy({ !it.enabled }, { it.label })))
},
onCopy = {
val text = "${DataStore.bypass}\n${DataStore.individual}"
SagerNet.trySetPrimaryClip(text)
},
onDisable = {
DataStore.proxyApps = false
finish()
},
)
}
}
}
}
class ComposeScannerActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
OwenclaveTheme {
ScannerScreen(
onBack = { finish() },
onImportFile = {},
onToggleFlash = {},
onSwitchCamera = {},
)
}
}
}
}
class ComposeGroupSettingsActivity : ComponentActivity() {
private var editingGroupId: Long = 0L
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
editingGroupId = intent.getLongExtra("groupId", 0L)
var initialName = ""
var initialType = GroupType.BASIC
var initialSubscription = SubscriptionSettings()
if (editingGroupId > 0L) {
runBlocking {
val group = SagerDatabase.groupDao.getById(editingGroupId)
if (group != null) {
initialName = group.name ?: ""
initialType = group.type
val sub = group.subscription
if (sub != null) {
initialSubscription = SubscriptionSettings(
link = sub.link ?: "",
deduplication = sub.deduplication ?: false,
updateWhenConnectedOnly = sub.updateWhenConnectedOnly ?: false,
autoUpdate = sub.autoUpdate ?: false,
customUserAgent = sub.customUserAgent ?: "",
)
}
}
}
}
setContent {
OwenclaveTheme {
GroupSettingsScreen(
groupName = initialName,
groupType = initialType,
initialSubscription = initialSubscription,
onBack = { finish() },
onSave = { newName, newType, subSettings ->
runBlocking {
if (editingGroupId > 0L) {
val group = SagerDatabase.groupDao.getById(editingGroupId)
if (group != null) {
group.name = newName.ifEmpty { if (newType == GroupType.SUBSCRIPTION) "Subscription" else "Group" }
group.type = newType
if (newType == GroupType.SUBSCRIPTION) {
val sub = group.subscription ?: SubscriptionBean().applyDefaultValues()
sub.link = subSettings.link
sub.deduplication = subSettings.deduplication
sub.updateWhenConnectedOnly = subSettings.updateWhenConnectedOnly
sub.autoUpdate = subSettings.autoUpdate
sub.customUserAgent = subSettings.customUserAgent
group.subscription = sub
} else {
group.subscription = null
}
GroupManager.updateGroup(group)
}
} else {
val group = ProxyGroup(
name = newName.ifEmpty { if (newType == GroupType.SUBSCRIPTION) "Subscription" else "Group" },
type = newType,
)
if (newType == GroupType.SUBSCRIPTION) {
group.subscription = SubscriptionBean().applyDefaultValues().apply {
link = subSettings.link
deduplication = subSettings.deduplication
updateWhenConnectedOnly = subSettings.updateWhenConnectedOnly
autoUpdate = subSettings.autoUpdate
customUserAgent = subSettings.customUserAgent
}
}
GroupManager.createGroup(group)
if (newType == GroupType.SUBSCRIPTION && subSettings.link.isNotEmpty()) {
val created = SagerDatabase.groupDao.getById(group.id)
if (created != null) {
GroupUpdater.executeUpdate(created, true)
}
}
}
}
finish()
},
)
}
}
}
}
class ComposeRouteSettingsActivity : ComponentActivity() {
private var editingRuleId: Long = 0L
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
editingRuleId = intent.getLongExtra("ruleId", 0L)
var initialName = ""
var initialDomains = ""
var initialIP = ""
var initialPort = ""
var initialSourcePort = ""
var initialNetwork = ""
var initialSource = ""
var initialProtocol = ""
var initialOutbound = 0
var initialPackages = ""
if (editingRuleId > 0L) {
runBlocking {
val rule = SagerDatabase.rulesDao.getById(editingRuleId)
if (rule != null) {
initialName = rule.name
initialDomains = rule.domains ?: ""
initialIP = rule.ip ?: ""
initialPort = rule.port ?: ""
initialSourcePort = rule.sourcePort ?: ""
initialNetwork = rule.network ?: ""
initialSource = rule.source ?: ""
initialProtocol = rule.protocol ?: ""
initialOutbound = when (rule.outbound) {
0L -> 0
-1L -> 1
-2L -> 2
else -> 3
}
initialPackages = rule.packages.joinToString("\n")
}
}
}
setContent {
OwenclaveTheme {
RouteSettingsScreen(
routeName = initialName,
routeDomain = initialDomains,
routeIP = initialIP,
routePort = initialPort,
routeSourcePort = initialSourcePort,
routeNetwork = initialNetwork,
routeSource = initialSource,
routeProtocol = initialProtocol,
routeOutbound = initialOutbound,
routePackages = initialPackages,
onBack = { finish() },
onSave = { name, domains, ip, port, sourcePort, network, source, protocol, outbound, packages ->
runBlocking {
val rule = if (editingRuleId > 0L) {
SagerDatabase.rulesDao.getById(editingRuleId) ?: RuleEntity()
} else {
RuleEntity()
}
rule.name = name
rule.domains = domains
rule.ip = ip
rule.port = port
rule.sourcePort = sourcePort
rule.network = network
rule.source = source
rule.protocol = protocol
rule.outbound = when (outbound) {
0 -> 0L
1 -> -1L
2 -> -2L
else -> 0L
}
rule.packages = packages.split("\n").filter { it.isNotEmpty() }
if (editingRuleId == 0L) {
rule.enabled = true
ProfileManager.createRule(rule)
} else {
ProfileManager.updateRule(rule)
}
}
finish()
},
)
}
}
}
}
class ComposeConfigEditActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
val content = intent.getStringExtra("content") ?: ""
setContent {
OwenclaveTheme {
ConfigEditScreen(
initialContent = content,
onBack = { finish() },
onSave = { finish() },
)
}
}
}
}
class ComposeStunActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
OwenclaveTheme {
StunScreen(onBack = { finish() })
}
}
}
}
class ComposeProbeCertActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
OwenclaveTheme {
ProbeCertScreen(onBack = { finish() })
}
}
}
}
class ComposeProfileSelectActivity : ComponentActivity() {
companion object {
const val EXTRA_SELECTED = "selected"
const val EXTRA_PROFILE_ID = "profileId"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
val selectedId = intent.getLongExtra(EXTRA_SELECTED, 0L)
setContent {
OwenclaveTheme {
ProfileSelectScreen(
profiles = emptyList(),
selectedId = selectedId,
onSelect = { profile ->
setResult(RESULT_OK, intent.putExtra(EXTRA_PROFILE_ID, profile.id))
finish()
},
onBack = { finish() },
)
}
}
}
}
class ComposeQuickToggleActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
OwenclaveTheme {
QuickSwitchScreen(
profiles = emptyList(),
currentProfileId = DataStore.selectedProxy,
onSelect = { profile ->
DataStore.selectedProxy = profile.id
io.nekohasekai.sagernet.SagerNet.reloadService()
finish()
},
)
}
}
}
}
class ComposeProfileSettingsActivity : ComponentActivity() {
companion object {
const val EXTRA_PROFILE_ID = "profileId"
const val EXTRA_PROFILE_TYPE = "profileType"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
val profileId = intent.getLongExtra(EXTRA_PROFILE_ID, 0L)
val profileType = intent.getIntExtra(EXTRA_PROFILE_TYPE, ProxyEntity.TYPE_SOCKS)
var entity: ProxyEntity? = null
var initialState = ProfileFieldState()
if (profileId > 0L) {
runBlocking {
entity = SagerDatabase.proxyDao.getById(profileId)
if (entity != null) {
initialState = beanToState(entity!!, profileType)
}
}
}
setContent {
OwenclaveTheme {
UniversalProfileSettingsScreen(
profileType = profileType,
initialState = initialState,
onBack = { finish() },
onSave = { state ->
runBlocking {
saveProfile(entity, profileId, profileType, state)
}
finish()
},
)
}
}
}
private fun beanToState(entity: ProxyEntity, type: Int): ProfileFieldState {
val bean = entity.requireBean()
val s = ProfileFieldState(
name = bean.name ?: "",
serverAddress = bean.serverAddress ?: "",
serverPort = bean.serverPort?.toString() ?: "",
iconIndex = entity.iconIndex,
)
return when (type) {
ProxyEntity.TYPE_SOCKS -> {
val b = entity.socksBean ?: return s
s.copy(username = b.username ?: "", password = b.password ?: "")
}
ProxyEntity.TYPE_HTTP -> {
val b = entity.httpBean ?: return s
s.copy(username = b.username ?: "", password = b.password ?: "")
}
ProxyEntity.TYPE_SS -> {
val b = entity.ssBean ?: return s
s.copy(method = b.method ?: "", password = b.password ?: "")
}
ProxyEntity.TYPE_SSR -> {
val b = entity.ssrBean ?: return s
s.copy(password = b.password ?: "", method = b.method ?: "",
ssrProtocol = b.protocol ?: "origin", protocolParam = b.protocolParam ?: "",
obfs = b.obfs ?: "plain", obfsParam = b.obfsParam ?: "")
}
ProxyEntity.TYPE_VMESS -> {
val b = entity.vmessBean ?: return s
s.copy(uuid = b.uuid ?: "", encryption = b.encryption ?: "auto",
network = b.type ?: "tcp", security = b.security ?: "none",
sni = b.sni ?: "", alpn = b.alpn ?: "", host = b.host ?: "", path = b.path ?: "")
}
ProxyEntity.TYPE_VLESS -> {
val b = entity.vlessBean ?: return s
s.copy(uuid = b.uuid ?: "", flow = b.flow ?: "", encryption = b.encryption ?: "none",
network = b.type ?: "tcp", security = b.security ?: "none",
sni = b.sni ?: "", alpn = b.alpn ?: "", host = b.host ?: "", path = b.path ?: "")
}
ProxyEntity.TYPE_TROJAN -> {
val b = entity.trojanBean ?: return s
s.copy(password = b.password ?: "",
network = b.type ?: "tcp", security = b.security ?: "none",
sni = b.sni ?: "", alpn = b.alpn ?: "")
}
ProxyEntity.TYPE_NAIVE -> {
val b = entity.naiveBean ?: return s
s.copy(network = b.proto ?: "https", username = b.username ?: "",
password = b.password ?: "", sni = b.sni ?: "", certificates = b.certificate ?: "")
}
ProxyEntity.TYPE_HYSTERIA2 -> {
val b = entity.hysteria2Bean ?: return s
s.copy(password = b.auth ?: "", sni = b.sni ?: "",
serverPorts = b.serverPorts ?: "",
obfsType = b.obfsType ?: "", obfsPassword = b.obfsPassword ?: "",
uploadSpeed = b.uploadMbps?.toString() ?: "", downloadSpeed = b.downloadMbps?.toString() ?: "",
congestionControl = b.congestionControl ?: "bbr",
certificates = b.certificates ?: "", allowInsecure = b.allowInsecure ?: false,
echEnabled = b.echEnabled ?: false, echConfig = b.echConfig ?: "")
}
ProxyEntity.TYPE_SSH -> {
val b = entity.sshBean ?: return s
s.copy(username = b.username ?: "root", authType = b.authType ?: 0,
password = b.password ?: "", privateKey = b.privateKey ?: "",
publicKey = b.publicKey ?: "")
}
ProxyEntity.TYPE_WG -> {
val b = entity.wgBean ?: return s
s.copy(localAddress = b.localAddress ?: "", privateKeyWg = b.privateKey ?: "",
peerPublicKey = b.peerPublicKey ?: "", peerPreSharedKey = b.peerPreSharedKey ?: "",
mtu = b.mtu?.toString() ?: "1420", reserved = b.reserved ?: "")
}
ProxyEntity.TYPE_TUIC5 -> {
val b = entity.tuic5Bean ?: return s
s.copy(uuid = b.uuid ?: "", password = b.password ?: "",
sni = b.sni ?: "", alpn = b.alpn ?: "",
congestionControl = b.congestionControl ?: "cubic",
certificates = b.certificates ?: "", allowInsecure = b.allowInsecure ?: false,
disableSNI = b.disableSNI ?: false, zeroRTT = b.zeroRTTHandshake ?: false,
echEnabled = b.echEnabled ?: false, echConfig = b.echConfig ?: "")
}
ProxyEntity.TYPE_JUICITY -> {
val b = entity.juicityBean ?: return s
s.copy(uuid = b.uuid ?: "", password = b.password ?: "",
sni = b.sni ?: "", certificates = b.certificates ?: "",
allowInsecure = b.allowInsecure ?: false,
echEnabled = b.echEnabled ?: false, echConfig = b.echConfig ?: "")
}
ProxyEntity.TYPE_HTTP3 -> {
val b = entity.http3Bean ?: return s
s.copy(username = b.username ?: "", password = b.password ?: "",
sni = b.sni ?: "", certificates = b.certificates ?: "",
allowInsecure = b.allowInsecure ?: false,
echEnabled = b.echEnabled ?: false, echConfig = b.echConfig ?: "")
}
ProxyEntity.TYPE_ANYTLS -> {
val b = entity.anytlsBean ?: return s
s.copy(password = b.password ?: "", security = b.security ?: "tls",
sni = b.sni ?: "", alpn = b.alpn ?: "",
certificates = b.certificates ?: "", utlsFingerprint = b.utlsFingerprint ?: "",
allowInsecure = b.allowInsecure ?: false,
echEnabled = b.echEnabled ?: false, echConfig = b.echConfig ?: "",
realityPublicKey = b.realityPublicKey ?: "", realityShortId = b.realityShortId ?: "")
}
ProxyEntity.TYPE_SHADOWQUIC -> {
val b = entity.shadowquicBean ?: return s
s.copy(username = b.username ?: "", password = b.password ?: "",
sni = b.sni ?: "", alpn = b.alpn ?: "",
congestionControl = b.congestionControl ?: "bbr",
zeroRTT = b.zeroRTT ?: false, disableSNI = b.disableALPN ?: false)
}
ProxyEntity.TYPE_TRUSTTUNNEL -> {
val b = entity.trustTunnelBean ?: return s
s.copy(network = b.protocol ?: "https", username = b.username ?: "",
password = b.password ?: "", sni = b.sni ?: "",
certificates = b.certificate ?: "", utlsFingerprint = b.utlsFingerprint ?: "",
allowInsecure = b.allowInsecure ?: false,
echEnabled = b.echEnabled ?: false, echConfig = b.echConfig ?: "")
}
ProxyEntity.TYPE_SNELL -> {
val b = entity.snellBean ?: return s
s.copy(psk = b.psk ?: "", snellVersion = b.version ?: 4,
obfsType = b.obfsMode ?: "none", host = b.obfsHost ?: "")
}
ProxyEntity.TYPE_OLCRTC -> {
val b = entity.olcrtcBean ?: return s
s.copy(authProvider = b.authProvider ?: "jitsi", transport = b.transport ?: "datachannel",
roomId = b.roomId ?: "", encryptionKey = b.encryptionKey ?: "",
dnsServer = b.dnsServer ?: "8.8.8.8:53", socksHost = b.socksHost ?: "127.0.0.1",
socksPort = b.socksPort?.toString() ?: "8808")
}
else -> s
}
}
private suspend fun saveProfile(existing: ProxyEntity?, profileId: Long, type: Int, state: ProfileFieldState) {
val entity = existing ?: ProxyEntity(type = type)
entity.type = type
when (type) {
ProxyEntity.TYPE_SOCKS -> {
val b = entity.socksBean ?: SOCKSBean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 1080
b.username = state.username
b.password = state.password
entity.socksBean = b
}
ProxyEntity.TYPE_HTTP -> {
val b = entity.httpBean ?: HttpBean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 8080
b.username = state.username
b.password = state.password
entity.httpBean = b
}
ProxyEntity.TYPE_SS -> {
val b = entity.ssBean ?: ShadowsocksBean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 8388
b.method = state.method
b.password = state.password
entity.ssBean = b
}
ProxyEntity.TYPE_SSR -> {
val b = entity.ssrBean ?: ShadowsocksRBean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 8388
b.password = state.password
b.method = state.method
b.protocol = state.ssrProtocol
b.protocolParam = state.protocolParam
b.obfs = state.obfs
b.obfsParam = state.obfsParam
entity.ssrBean = b
}
ProxyEntity.TYPE_VMESS -> {
val b = entity.vmessBean ?: VMessBean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 443
b.uuid = state.uuid
b.encryption = state.encryption.ifEmpty { "auto" }
b.type = state.network
b.security = state.security
b.sni = state.sni
b.alpn = state.alpn
b.host = state.host
b.path = state.path
b.allowInsecure = state.allowInsecure
b.utlsFingerprint = state.utlsFingerprint
b.echEnabled = state.echEnabled
b.echConfig = state.echConfig
b.mux = state.mux
b.singMux = state.singMux
entity.vmessBean = b
}
ProxyEntity.TYPE_VLESS -> {
val b = entity.vlessBean ?: VLESSBean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 443
b.uuid = state.uuid
b.flow = state.flow
b.encryption = state.encryption.ifEmpty { "none" }
b.type = state.network
b.security = state.security
b.sni = state.sni
b.alpn = state.alpn
b.host = state.host
b.path = state.path
b.allowInsecure = state.allowInsecure
b.utlsFingerprint = state.utlsFingerprint
b.echEnabled = state.echEnabled
b.echConfig = state.echConfig
b.mux = state.mux
b.singMux = state.singMux
entity.vlessBean = b
}
ProxyEntity.TYPE_TROJAN -> {
val b = entity.trojanBean ?: TrojanBean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 443
b.password = state.password
b.type = state.network
b.security = state.security
b.sni = state.sni
b.alpn = state.alpn
b.host = state.host
b.path = state.path
b.allowInsecure = state.allowInsecure
b.utlsFingerprint = state.utlsFingerprint
b.echEnabled = state.echEnabled
b.echConfig = state.echConfig
b.mux = state.mux
b.singMux = state.singMux
entity.trojanBean = b
}
ProxyEntity.TYPE_NAIVE -> {
val b = entity.naiveBean ?: NaiveBean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 443
b.proto = state.network.ifEmpty { "https" }
b.username = state.username
b.password = state.password
b.sni = state.sni
b.certificate = state.certificates
entity.naiveBean = b
}
ProxyEntity.TYPE_HYSTERIA2 -> {
val b = entity.hysteria2Bean ?: Hysteria2Bean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPorts = state.serverPorts.ifEmpty { state.serverPort }
b.auth = state.password
b.sni = state.sni
b.obfsType = state.obfsType
b.obfsPassword = state.obfsPassword
b.uploadMbps = state.uploadSpeed.toLongOrNull() ?: 0L
b.downloadMbps = state.downloadSpeed.toLongOrNull() ?: 0L
b.congestionControl = state.congestionControl
b.certificates = state.certificates
b.allowInsecure = state.allowInsecure
b.echEnabled = state.echEnabled
b.echConfig = state.echConfig
entity.hysteria2Bean = b
}
ProxyEntity.TYPE_SSH -> {
val b = entity.sshBean ?: SSHBean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 22
b.username = state.username
b.authType = state.authType
b.password = state.password
b.privateKey = state.privateKey
b.publicKey = state.publicKey
entity.sshBean = b
}
ProxyEntity.TYPE_WG -> {
val b = entity.wgBean ?: WireGuardBean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 51820
b.localAddress = state.localAddress
b.privateKey = state.privateKeyWg
b.peerPublicKey = state.peerPublicKey
b.peerPreSharedKey = state.peerPreSharedKey
b.mtu = state.mtu.toIntOrNull() ?: 1420
b.reserved = state.reserved
entity.wgBean = b
}
ProxyEntity.TYPE_TUIC5 -> {
val b = entity.tuic5Bean ?: Tuic5Bean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 443
b.uuid = state.uuid
b.password = state.password
b.sni = state.sni
b.alpn = state.alpn
b.congestionControl = state.congestionControl
b.certificates = state.certificates
b.allowInsecure = state.allowInsecure
b.disableSNI = state.disableSNI
b.zeroRTTHandshake = state.zeroRTT
b.echEnabled = state.echEnabled
b.echConfig = state.echConfig
entity.tuic5Bean = b
}
ProxyEntity.TYPE_JUICITY -> {
val b = entity.juicityBean ?: JuicityBean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 443
b.uuid = state.uuid
b.password = state.password
b.sni = state.sni
b.certificates = state.certificates
b.allowInsecure = state.allowInsecure
b.echEnabled = state.echEnabled
b.echConfig = state.echConfig
entity.juicityBean = b
}
ProxyEntity.TYPE_HTTP3 -> {
val b = entity.http3Bean ?: Http3Bean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 443
b.username = state.username
b.password = state.password
b.sni = state.sni
b.certificates = state.certificates
b.allowInsecure = state.allowInsecure
b.echEnabled = state.echEnabled
b.echConfig = state.echConfig
entity.http3Bean = b
}
ProxyEntity.TYPE_ANYTLS -> {
val b = entity.anytlsBean ?: AnyTLSBean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 443
b.password = state.password
b.security = state.security
b.sni = state.sni
b.alpn = state.alpn
b.certificates = state.certificates
b.utlsFingerprint = state.utlsFingerprint
b.allowInsecure = state.allowInsecure
b.echEnabled = state.echEnabled
b.echConfig = state.echConfig
b.realityPublicKey = state.realityPublicKey
b.realityShortId = state.realityShortId
entity.anytlsBean = b
}
ProxyEntity.TYPE_SHADOWQUIC -> {
val b = entity.shadowquicBean ?: ShadowQUICBean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 443
b.username = state.username
b.password = state.password
b.sni = state.sni
b.alpn = state.alpn
b.congestionControl = state.congestionControl
b.zeroRTT = state.zeroRTT
b.disableALPN = state.disableSNI
entity.shadowquicBean = b
}
ProxyEntity.TYPE_TRUSTTUNNEL -> {
val b = entity.trustTunnelBean ?: TrustTunnelBean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 443
b.protocol = state.network.ifEmpty { "https" }
b.username = state.username
b.password = state.password
b.sni = state.sni
b.certificate = state.certificates
b.utlsFingerprint = state.utlsFingerprint
b.allowInsecure = state.allowInsecure
b.echEnabled = state.echEnabled
b.echConfig = state.echConfig
entity.trustTunnelBean = b
}
ProxyEntity.TYPE_SNELL -> {
val b = entity.snellBean ?: SnellBean().applyDefaultValues()
b.name = state.name
b.serverAddress = state.serverAddress
b.serverPort = state.serverPort.toIntOrNull() ?: 8388
b.psk = state.psk
b.version = state.snellVersion
b.obfsMode = state.obfsType
b.obfsHost = state.host
entity.snellBean = b
}
ProxyEntity.TYPE_OLCRTC -> {
val b = entity.olcrtcBean ?: OLCRTCBean().applyDefaultValues()
b.name = state.name
b.authProvider = state.authProvider
b.transport = state.transport
b.roomId = state.roomId
b.encryptionKey = state.encryptionKey
b.dnsServer = state.dnsServer
b.socksHost = state.socksHost
b.socksPort = state.socksPort.toIntOrNull() ?: 8808
entity.olcrtcBean = b
}
}
entity.iconIndex = state.iconIndex
if (profileId > 0L) {
ProfileManager.updateProfile(entity)
} else {
val groupId = DataStore.currentGroupId()
entity.groupId = groupId
ProfileManager.createProfile(groupId, entity.requireBean())
}
}
}