@@ -58,16 +58,17 @@ import java.text.DateFormat
58
58
import java.text.NumberFormat
59
59
60
60
@Composable
61
- fun ElectrumView () {
62
- val nc = navController
61
+ fun ElectrumView (
62
+ onBackClick : () -> Unit
63
+ ) {
63
64
val scope = rememberCoroutineScope()
64
65
val userPrefs = userPrefs
65
- val electrumServerInPrefs by userPrefs.getElectrumServer.collectAsState(initial = null )
66
+ val electrumConfigInPrefs by userPrefs.getElectrumServer.collectAsState(initial = null )
66
67
var showCustomServerDialog by rememberSaveable { mutableStateOf(false ) }
67
68
68
69
DefaultScreenLayout {
69
70
DefaultScreenHeader (
70
- onBackClick = { nc.popBackStack() } ,
71
+ onBackClick = onBackClick ,
71
72
title = stringResource(id = R .string.electrum_title),
72
73
)
73
74
Card (internalPadding = PaddingValues (16 .dp)) {
@@ -78,11 +79,11 @@ fun ElectrumView() {
78
79
val config = model.configuration
79
80
if (showCustomServerDialog) {
80
81
ElectrumServerDialog (
81
- initialAddress = electrumServerInPrefs ,
82
- onConfirm = { address ->
82
+ initialConfig = electrumConfigInPrefs ,
83
+ onConfirm = { newConfig ->
83
84
scope.launch {
84
- userPrefs.saveElectrumServer(address )
85
- postIntent(ElectrumConfiguration .Intent .UpdateElectrumServer (address ))
85
+ userPrefs.saveElectrumServer(newConfig )
86
+ postIntent(ElectrumConfiguration .Intent .UpdateElectrumServer (newConfig ))
86
87
showCustomServerDialog = false
87
88
}
88
89
},
@@ -119,7 +120,7 @@ fun ElectrumView() {
119
120
text = stringResource(id = R .string.electrum_description_bad_certificate),
120
121
style = MaterialTheme .typography.subtitle2.copy(color = negativeColor)
121
122
)
122
- } else if (torEnabled.value == true && ! config.server.isOnion) {
123
+ } else if (torEnabled.value == true && ! config.server.isOnion && config.requireOnionIfTorEnabled ) {
123
124
Text (
124
125
text = stringResource(id = R .string.electrum_description_not_onion),
125
126
style = MaterialTheme .typography.subtitle2.copy(color = negativeColor),
@@ -158,23 +159,25 @@ fun ElectrumView() {
158
159
159
160
@Composable
160
161
private fun ElectrumServerDialog (
161
- initialAddress : ServerAddress ? ,
162
- onConfirm : (ServerAddress ? ) -> Unit ,
162
+ initialConfig : ElectrumConfig . Custom ? ,
163
+ onConfirm : (ElectrumConfig . Custom ? ) -> Unit ,
163
164
onDismiss : () -> Unit
164
165
) {
165
166
val context = LocalContext .current
166
167
val scope = rememberCoroutineScope()
167
168
val keyboardManager = LocalSoftwareKeyboardController .current
168
169
169
- var useCustomServer by rememberSaveable { mutableStateOf(initialAddress != null ) }
170
- var address by rememberSaveable { mutableStateOf(initialAddress ?.run { " $host : $ port" } ? : " " ) }
170
+ var useCustomServer by rememberSaveable { mutableStateOf(initialConfig != null ) }
171
+ var address by rememberSaveable { mutableStateOf(initialConfig ?.run { " ${server. host} : ${server. port} " } ? : " " ) }
171
172
val host = remember(address) { address.trim().substringBeforeLast(" :" ).takeIf { it.isNotBlank() } }
172
173
val port = remember(address) { address.trim().substringAfterLast(" :" ).toIntOrNull() ? : 50002 }
173
174
val isOnionHost = remember(address) { host?.endsWith(" .onion" ) ? : false }
174
175
val isTorEnabled by userPrefs.getIsTorEnabled.collectAsState(initial = null )
175
176
176
177
var addressError by rememberSaveable { mutableStateOf(false ) }
177
- val showTorWithoutOnionError = remember(isOnionHost, isTorEnabled, useCustomServer) { useCustomServer && isTorEnabled == true && ! isOnionHost }
178
+ val showOnionOnCustomServerWarning = remember(isOnionHost, isTorEnabled, useCustomServer) { useCustomServer && isTorEnabled == true && ! isOnionHost }
179
+ var requireOnionIfTorEnabled by remember { mutableStateOf(initialConfig?.requireOnionIfTorEnabled ? : true ) }
180
+ val isViolatingTorRule = remember(isOnionHost, isTorEnabled, useCustomServer, requireOnionIfTorEnabled) { useCustomServer && isTorEnabled == true && ! isOnionHost && requireOnionIfTorEnabled }
178
181
179
182
val vm = viewModel<ElectrumDialogViewModel >()
180
183
@@ -204,7 +207,7 @@ private fun ElectrumServerDialog(
204
207
modifier = Modifier .fillMaxWidth(),
205
208
)
206
209
}
207
- Spacer (modifier = Modifier .height(8 .dp))
210
+ Spacer (modifier = Modifier .height(12 .dp))
208
211
TextInput (
209
212
modifier = Modifier .fillMaxWidth(),
210
213
text = address,
@@ -218,24 +221,35 @@ private fun ElectrumServerDialog(
218
221
maxLines = 4 ,
219
222
staticLabel = stringResource(id = R .string.electrum_dialog_input),
220
223
enabled = useCustomServer && vm.state !is ElectrumDialogViewModel .CertificateCheckState .Checking ,
221
- errorMessage = if (addressError) stringResource(id = R .string.electrum_dialog_invalid_input) else if (showTorWithoutOnionError) stringResource( R .string.electrum_connection_dialog_tor_enabled) else null
224
+ errorMessage = if (addressError) stringResource(id = R .string.electrum_dialog_invalid_input) else if (isViolatingTorRule) " Must use an onion address " else null
222
225
)
223
- if (isTorEnabled == true || isOnionHost) {
224
- Spacer (modifier = Modifier .height(4 .dp))
225
- TextWithIcon (
226
- text = stringResource(id = R .string.electrum_connection_dialog_onion_port),
227
- textStyle = MaterialTheme .typography.subtitle2,
228
- icon = R .drawable.ic_info,
229
- )
230
- } else {
231
- Spacer (modifier = Modifier .height(4 .dp))
232
- TextWithIcon (
233
- text = stringResource(id = R .string.electrum_connection_dialog_tls_port),
234
- textStyle = MaterialTheme .typography.subtitle2,
235
- icon = R .drawable.ic_info,
236
- )
226
+
227
+ Spacer (modifier = Modifier .height(4 .dp))
228
+ TextWithIcon (
229
+ text = stringResource(id = if (isOnionHost) R .string.electrum_connection_dialog_onion_port else R .string.electrum_connection_dialog_tls_port),
230
+ textStyle = MaterialTheme .typography.subtitle2,
231
+ icon = R .drawable.ic_info,
232
+ modifier = Modifier .padding(horizontal = 16 .dp)
233
+ )
234
+
235
+ if (showOnionOnCustomServerWarning) {
236
+ Spacer (modifier = Modifier .height(16 .dp))
237
+ Surface (color = mutedBgColor, shape = RoundedCornerShape (16 .dp)) {
238
+ Column (modifier = Modifier .fillMaxWidth()) {
239
+ Text (text = stringResource(id = R .string.electrum_connection_dialog_tor_enabled_warning), modifier = Modifier .padding(start = 16 .dp, end = 16 .dp, top = 16 .dp))
240
+ Checkbox (
241
+ text = stringResource(id = R .string.electrum_connection_dialog_tor_enabled_ignore_box),
242
+ checked = ! requireOnionIfTorEnabled,
243
+ onCheckedChange = { requireOnionIfTorEnabled = ! it },
244
+ padding = PaddingValues (16 .dp),
245
+ enabled = useCustomServer && vm.state !is ElectrumDialogViewModel .CertificateCheckState .Checking ,
246
+ modifier = Modifier .fillMaxWidth(),
247
+ )
248
+ }
249
+ }
237
250
}
238
251
}
252
+
239
253
Spacer (modifier = Modifier .height(12 .dp))
240
254
when (val state = vm.state) {
241
255
ElectrumDialogViewModel .CertificateCheckState .Init , is ElectrumDialogViewModel .CertificateCheckState .Failure -> {
@@ -268,9 +282,9 @@ private fun ElectrumServerDialog(
268
282
if (address.matches(""" (.*):*(\d*)""" .toRegex()) && host != null ) {
269
283
scope.launch {
270
284
if (isOnionHost) {
271
- onConfirm(ServerAddress (host, port, TcpSocket .TLS .DISABLED ))
285
+ onConfirm(ElectrumConfig . Custom .create( ServerAddress (host, port, TcpSocket .TLS .DISABLED ), requireOnionIfTorEnabled = requireOnionIfTorEnabled ))
272
286
} else {
273
- vm.checkCertificate(host, port, onCertificateValid = onConfirm)
287
+ vm.checkCertificate(host, port, onCertificateValid = { onConfirm( ElectrumConfig . Custom .create(it, requireOnionIfTorEnabled = requireOnionIfTorEnabled)) } )
274
288
}
275
289
}
276
290
} else {
@@ -280,7 +294,7 @@ private fun ElectrumServerDialog(
280
294
onConfirm(null )
281
295
}
282
296
},
283
- enabled = ! addressError && ! showTorWithoutOnionError ,
297
+ enabled = ! addressError && ! isViolatingTorRule ,
284
298
shape = RoundedCornerShape (16 .dp),
285
299
)
286
300
}
@@ -348,7 +362,14 @@ private fun ElectrumServerDialog(
348
362
)
349
363
Button (
350
364
text = stringResource(id = R .string.electrum_dialog_cert_accept),
351
- onClick = { onConfirm(ServerAddress (state.host, state.port, TcpSocket .TLS .PINNED_PUBLIC_KEY (Base64 .encodeToString(cert.publicKey.encoded, Base64 .NO_WRAP )))) },
365
+ onClick = {
366
+ onConfirm(
367
+ ElectrumConfig .Custom .create(
368
+ server = ServerAddress (state.host, state.port, TcpSocket .TLS .PINNED_PUBLIC_KEY (Base64 .encodeToString(cert.publicKey.encoded, Base64 .NO_WRAP ))),
369
+ requireOnionIfTorEnabled = requireOnionIfTorEnabled
370
+ )
371
+ )
372
+ },
352
373
icon = R .drawable.ic_check_circle,
353
374
iconTint = positiveColor,
354
375
space = 8 .dp,
0 commit comments