mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
mobile: UI to choose transport isolation mode (#1813)
* mobile: UI to choose transport isolation mode * typo Co-authored-by: JRoberts <8711996+jr-simplex@users.noreply.github.com> * ios: update alerts Co-authored-by: JRoberts <8711996+jr-simplex@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
c337a6888d
commit
8bec0004cc
@@ -109,6 +109,18 @@ class AppPreferences(val context: Context) {
|
||||
val chatLastStart = mkDatePreference(SHARED_PREFS_CHAT_LAST_START, null)
|
||||
val developerTools = mkBoolPreference(SHARED_PREFS_DEVELOPER_TOOLS, false)
|
||||
val networkUseSocksProxy = mkBoolPreference(SHARED_PREFS_NETWORK_USE_SOCKS_PROXY, false)
|
||||
private val _networkSessionMode = mkStrPreference(SHARED_PREFS_NETWORK_SESSION_MODE, TransportSessionMode.default.name)
|
||||
val networkSessionMode: SharedPreference<TransportSessionMode> = SharedPreference(
|
||||
get = fun(): TransportSessionMode {
|
||||
val value = _networkSessionMode.get() ?: return TransportSessionMode.default
|
||||
return try {
|
||||
TransportSessionMode.valueOf(value)
|
||||
} catch (e: Error) {
|
||||
TransportSessionMode.default
|
||||
}
|
||||
},
|
||||
set = fun(mode: TransportSessionMode) { _networkSessionMode.set(mode.name) }
|
||||
)
|
||||
val networkHostMode = mkStrPreference(SHARED_PREFS_NETWORK_HOST_MODE, HostMode.OnionViaSocks.name)
|
||||
val networkRequiredHostMode = mkBoolPreference(SHARED_PREFS_NETWORK_REQUIRED_HOST_MODE, false)
|
||||
val networkTCPConnectTimeout = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_CONNECT_TIMEOUT, NetCfg.defaults.tcpConnectTimeout, NetCfg.proxyDefaults.tcpConnectTimeout)
|
||||
@@ -206,6 +218,7 @@ class AppPreferences(val context: Context) {
|
||||
private const val SHARED_PREFS_CHAT_LAST_START = "ChatLastStart"
|
||||
private const val SHARED_PREFS_DEVELOPER_TOOLS = "DeveloperTools"
|
||||
private const val SHARED_PREFS_NETWORK_USE_SOCKS_PROXY = "NetworkUseSocksProxy"
|
||||
private const val SHARED_PREFS_NETWORK_SESSION_MODE = "NetworkSessionMode"
|
||||
private const val SHARED_PREFS_NETWORK_HOST_MODE = "NetworkHostMode"
|
||||
private const val SHARED_PREFS_NETWORK_REQUIRED_HOST_MODE = "NetworkRequiredHostMode"
|
||||
private const val SHARED_PREFS_NETWORK_TCP_CONNECT_TIMEOUT = "NetworkTCPConnectTimeout"
|
||||
@@ -254,6 +267,8 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
|
||||
apiSetNetworkConfig(getNetCfg())
|
||||
val justStarted = apiStartChat()
|
||||
if (justStarted) {
|
||||
chatModel.currentUser.value = user
|
||||
chatModel.userCreated.value = true
|
||||
apiSetFilesFolder(getAppFilesDirectory(appContext))
|
||||
apiSetIncognito(chatModel.incognito.value)
|
||||
chatModel.userAddress.value = apiGetUserAddress()
|
||||
@@ -263,8 +278,6 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
|
||||
chatModel.chatItemTTL.value = getChatItemTTL()
|
||||
val chats = apiGetChats()
|
||||
chatModel.updateChats(chats)
|
||||
chatModel.currentUser.value = user
|
||||
chatModel.userCreated.value = true
|
||||
chatModel.onboardingStage.value = OnboardingStage.OnboardingComplete
|
||||
chatModel.controller.appPrefs.chatLastStart.set(Clock.System.now())
|
||||
chatModel.chatRunning.value = true
|
||||
@@ -1533,6 +1546,7 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
|
||||
val socksProxy = if (useSocksProxy) ":9050" else null
|
||||
val hostMode = HostMode.valueOf(appPrefs.networkHostMode.get()!!)
|
||||
val requiredHostMode = appPrefs.networkRequiredHostMode.get()
|
||||
val sessionMode = appPrefs.networkSessionMode.get()
|
||||
val tcpConnectTimeout = appPrefs.networkTCPConnectTimeout.get()
|
||||
val tcpTimeout = appPrefs.networkTCPTimeout.get()
|
||||
val smpPingInterval = appPrefs.networkSMPPingInterval.get()
|
||||
@@ -1550,6 +1564,7 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
|
||||
socksProxy = socksProxy,
|
||||
hostMode = hostMode,
|
||||
requiredHostMode = requiredHostMode,
|
||||
sessionMode = sessionMode,
|
||||
tcpConnectTimeout = tcpConnectTimeout,
|
||||
tcpTimeout = tcpTimeout,
|
||||
tcpKeepAlive = tcpKeepAlive,
|
||||
@@ -1562,6 +1577,7 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a
|
||||
appPrefs.networkUseSocksProxy.set(cfg.useSocksProxy)
|
||||
appPrefs.networkHostMode.set(cfg.hostMode.name)
|
||||
appPrefs.networkRequiredHostMode.set(cfg.requiredHostMode)
|
||||
appPrefs.networkSessionMode.set(cfg.sessionMode)
|
||||
appPrefs.networkTCPConnectTimeout.set(cfg.tcpConnectTimeout)
|
||||
appPrefs.networkTCPTimeout.set(cfg.tcpTimeout)
|
||||
appPrefs.networkSMPPingInterval.set(cfg.smpPingInterval)
|
||||
@@ -2000,9 +2016,10 @@ data class ParsedServerAddress (
|
||||
|
||||
@Serializable
|
||||
data class NetCfg(
|
||||
val socksProxy: String? = null,
|
||||
val hostMode: HostMode = HostMode.OnionViaSocks,
|
||||
val requiredHostMode: Boolean = false,
|
||||
val socksProxy: String?,
|
||||
val hostMode: HostMode,
|
||||
val requiredHostMode: Boolean,
|
||||
val sessionMode: TransportSessionMode,
|
||||
val tcpConnectTimeout: Long, // microseconds
|
||||
val tcpTimeout: Long, // microseconds
|
||||
val tcpKeepAlive: KeepAliveOpts?,
|
||||
@@ -2017,6 +2034,9 @@ data class NetCfg(
|
||||
val defaults: NetCfg =
|
||||
NetCfg(
|
||||
socksProxy = null,
|
||||
hostMode = HostMode.OnionViaSocks,
|
||||
requiredHostMode = false,
|
||||
sessionMode = TransportSessionMode.User,
|
||||
tcpConnectTimeout = 10_000_000,
|
||||
tcpTimeout = 7_000_000,
|
||||
tcpKeepAlive = KeepAliveOpts.defaults,
|
||||
@@ -2027,6 +2047,9 @@ data class NetCfg(
|
||||
val proxyDefaults: NetCfg =
|
||||
NetCfg(
|
||||
socksProxy = ":9050",
|
||||
hostMode = HostMode.OnionViaSocks,
|
||||
requiredHostMode = false,
|
||||
sessionMode = TransportSessionMode.User,
|
||||
tcpConnectTimeout = 20_000_000,
|
||||
tcpTimeout = 15_000_000,
|
||||
tcpKeepAlive = KeepAliveOpts.defaults,
|
||||
@@ -2063,6 +2086,16 @@ enum class HostMode {
|
||||
@SerialName("public") Public;
|
||||
}
|
||||
|
||||
@Serializable
|
||||
enum class TransportSessionMode {
|
||||
@SerialName("user") User,
|
||||
@SerialName("entity") Entity;
|
||||
|
||||
companion object {
|
||||
val default = User
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class KeepAliveOpts(
|
||||
val keepIdle: Int, // seconds
|
||||
|
||||
+3
@@ -60,6 +60,9 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
|
||||
}
|
||||
return NetCfg(
|
||||
socksProxy = currentCfg.value.socksProxy,
|
||||
hostMode = currentCfg.value.hostMode,
|
||||
requiredHostMode = currentCfg.value.requiredHostMode,
|
||||
sessionMode = currentCfg.value.sessionMode,
|
||||
tcpConnectTimeout = networkTCPConnectTimeout.value,
|
||||
tcpTimeout = networkTCPTimeout.value,
|
||||
tcpKeepAlive = tcpKeepAlive,
|
||||
|
||||
+77
-6
@@ -31,6 +31,7 @@ fun NetworkAndServersView(
|
||||
val networkUseSocksProxy: MutableState<Boolean> = remember { mutableStateOf(netCfg.useSocksProxy) }
|
||||
val developerTools = chatModel.controller.appPrefs.developerTools.get()
|
||||
val onionHosts = remember { mutableStateOf(netCfg.onionHosts) }
|
||||
val sessionMode = remember { mutableStateOf(netCfg.sessionMode) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
chatModel.userSMPServersUnsaved.value = null
|
||||
@@ -40,6 +41,7 @@ fun NetworkAndServersView(
|
||||
developerTools = developerTools,
|
||||
networkUseSocksProxy = networkUseSocksProxy,
|
||||
onionHosts = onionHosts,
|
||||
sessionMode = sessionMode,
|
||||
showModal = showModal,
|
||||
showSettingsModal = showSettingsModal,
|
||||
toggleSocksProxy = { enable ->
|
||||
@@ -82,9 +84,13 @@ fun NetworkAndServersView(
|
||||
OnionHosts.PREFER -> generalGetString(R.string.network_use_onion_hosts_prefer_desc_in_alert)
|
||||
OnionHosts.REQUIRED -> generalGetString(R.string.network_use_onion_hosts_required_desc_in_alert)
|
||||
}
|
||||
updateOnionHostsDialog(startsWith, onDismiss = {
|
||||
onionHosts.value = prevValue
|
||||
}) {
|
||||
updateNetworkSettingsDialog(
|
||||
title = generalGetString(R.string.update_onion_hosts_settings_question),
|
||||
startsWith,
|
||||
onDismiss = {
|
||||
onionHosts.value = prevValue
|
||||
}
|
||||
) {
|
||||
withApi {
|
||||
val newCfg = chatModel.controller.getNetCfg().withOnionHosts(it)
|
||||
val res = chatModel.controller.apiSetNetworkConfig(newCfg)
|
||||
@@ -96,6 +102,31 @@ fun NetworkAndServersView(
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
updateSessionMode = {
|
||||
if (sessionMode.value == it) return@NetworkAndServersLayout
|
||||
val prevValue = sessionMode.value
|
||||
sessionMode.value = it
|
||||
val startsWith = when (it) {
|
||||
TransportSessionMode.User -> generalGetString(R.string.network_session_mode_user_description)
|
||||
TransportSessionMode.Entity -> generalGetString(R.string.network_session_mode_entity_description)
|
||||
}
|
||||
updateNetworkSettingsDialog(
|
||||
title = generalGetString(R.string.update_network_session_mode_question),
|
||||
startsWith,
|
||||
onDismiss = { sessionMode.value = prevValue }
|
||||
) {
|
||||
withApi {
|
||||
val newCfg = chatModel.controller.getNetCfg().copy(sessionMode = it)
|
||||
val res = chatModel.controller.apiSetNetworkConfig(newCfg)
|
||||
if (res) {
|
||||
chatModel.controller.setNetCfg(newCfg)
|
||||
sessionMode.value = it
|
||||
} else {
|
||||
sessionMode.value = prevValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -104,10 +135,12 @@ fun NetworkAndServersView(
|
||||
developerTools: Boolean,
|
||||
networkUseSocksProxy: MutableState<Boolean>,
|
||||
onionHosts: MutableState<OnionHosts>,
|
||||
sessionMode: MutableState<TransportSessionMode>,
|
||||
showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit),
|
||||
showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit),
|
||||
toggleSocksProxy: (Boolean) -> Unit,
|
||||
useOnion: (OnionHosts) -> Unit,
|
||||
updateSessionMode: (TransportSessionMode) -> Unit,
|
||||
) {
|
||||
Column(
|
||||
Modifier.fillMaxWidth(),
|
||||
@@ -124,6 +157,10 @@ fun NetworkAndServersView(
|
||||
SectionDivider()
|
||||
UseOnionHosts(onionHosts, networkUseSocksProxy, showSettingsModal, useOnion)
|
||||
SectionDivider()
|
||||
if (developerTools) {
|
||||
SessionModePicker(sessionMode, showSettingsModal, updateSessionMode)
|
||||
SectionDivider()
|
||||
}
|
||||
SettingsActionItem(Icons.Outlined.Cable, stringResource(R.string.network_settings), showSettingsModal { AdvancedNetworkSettingsView(it) })
|
||||
}
|
||||
Spacer(Modifier.height(8.dp))
|
||||
@@ -183,7 +220,6 @@ private fun UseOnionHosts(
|
||||
}
|
||||
}
|
||||
val onSelected = showModal {
|
||||
|
||||
Column(
|
||||
Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.Start,
|
||||
@@ -203,14 +239,47 @@ private fun UseOnionHosts(
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateOnionHostsDialog(
|
||||
@Composable
|
||||
private fun SessionModePicker(
|
||||
sessionMode: MutableState<TransportSessionMode>,
|
||||
showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit),
|
||||
updateSessionMode: (TransportSessionMode) -> Unit,
|
||||
) {
|
||||
val values = remember {
|
||||
TransportSessionMode.values().map {
|
||||
when (it) {
|
||||
TransportSessionMode.User -> ValueTitleDesc(TransportSessionMode.User, generalGetString(R.string.network_session_mode_user), generalGetString(R.string.network_session_mode_user_description))
|
||||
TransportSessionMode.Entity -> ValueTitleDesc(TransportSessionMode.Entity, generalGetString(R.string.network_session_mode_entity), generalGetString(R.string.network_session_mode_entity_description))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SectionItemWithValue(
|
||||
generalGetString(R.string.network_session_mode_transport_isolation),
|
||||
sessionMode,
|
||||
values,
|
||||
icon = Icons.Outlined.SafetyDivider,
|
||||
onSelected = showModal {
|
||||
Column(
|
||||
Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.Start,
|
||||
) {
|
||||
AppBarTitle(stringResource(R.string.network_session_mode_transport_isolation))
|
||||
SectionViewSelectable(null, sessionMode, values, updateSessionMode)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun updateNetworkSettingsDialog(
|
||||
title: String,
|
||||
startsWith: String = "",
|
||||
message: String = generalGetString(R.string.updating_settings_will_reconnect_client_to_all_servers),
|
||||
onDismiss: () -> Unit,
|
||||
onConfirm: () -> Unit
|
||||
) {
|
||||
AlertManager.shared.showAlertDialog(
|
||||
title = generalGetString(R.string.update_onion_hosts_settings_question),
|
||||
title = title,
|
||||
text = startsWith + "\n\n" + message,
|
||||
confirmText = generalGetString(R.string.update_network_settings_confirmation),
|
||||
onDismiss = onDismiss,
|
||||
@@ -230,7 +299,9 @@ fun PreviewNetworkAndServersLayout() {
|
||||
showSettingsModal = { {} },
|
||||
toggleSocksProxy = {},
|
||||
onionHosts = remember { mutableStateOf(OnionHosts.PREFER) },
|
||||
sessionMode = remember { mutableStateOf(TransportSessionMode.User) },
|
||||
useOnion = {},
|
||||
updateSessionMode = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,6 +478,12 @@
|
||||
<string name="network_use_onion_hosts_prefer_desc_in_alert">Onion hosts will be used when available.</string>
|
||||
<string name="network_use_onion_hosts_no_desc_in_alert">Onion hosts will not be used.</string>
|
||||
<string name="network_use_onion_hosts_required_desc_in_alert">Onion hosts will be required for connection.</string>
|
||||
<string name="network_session_mode_transport_isolation">Transport isolation</string>
|
||||
<string name="network_session_mode_user">Chat profile</string>
|
||||
<string name="network_session_mode_entity">Connection</string>
|
||||
<string name="network_session_mode_user_description">A separate TCP connection (and SOCKS credential) will be used <b>for each chat profile you have in the app</b>.</string>
|
||||
<string name="network_session_mode_entity_description">A separate TCP connection (and SOCKS credential) will be used <b>for each contact and group member</b>.\n<b>Please note</b>: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail.</string>
|
||||
<string name="update_network_session_mode_question">Update transport isolation mode?</string>
|
||||
<string name="appearance_settings">Appearance</string>
|
||||
|
||||
<!-- Address Items - UserAddressView.kt -->
|
||||
|
||||
Reference in New Issue
Block a user