From ad2eabf3868acdb1c9bf3fd5b03e2c5a2ae9c213 Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Mon, 3 Apr 2023 13:49:08 -0300 Subject: [PATCH 01/18] add qrcode scanner to login page --- .../ui/screen/loggedOff/LoginScreen.kt | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt index d78673f7f..132c997d0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt @@ -36,6 +36,7 @@ import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.qrcode.SimpleQrCodeScanner import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel import java.util.* @@ -51,6 +52,9 @@ fun LoginPage( var termsAcceptanceIsRequired by remember { mutableStateOf("") } val uri = LocalUriHandler.current val context = LocalContext.current + var dialogOpen by remember { + mutableStateOf(false) + } Column( modifier = Modifier @@ -117,17 +121,35 @@ fun LoginPage( ) }, trailingIcon = { - IconButton(onClick = { showPassword = !showPassword }) { - Icon( - imageVector = if (showPassword) Icons.Outlined.VisibilityOff else Icons.Outlined.Visibility, - contentDescription = if (showPassword) { - stringResource(R.string.show_password) - } else { - stringResource( - R.string.hide_password - ) + Row { + IconButton(onClick = { showPassword = !showPassword }) { + Icon( + imageVector = if (showPassword) Icons.Outlined.VisibilityOff else Icons.Outlined.Visibility, + contentDescription = if (showPassword) { + stringResource(R.string.show_password) + } else { + stringResource( + R.string.hide_password + ) + } + ) + } + if (dialogOpen) { + SimpleQrCodeScanner { + dialogOpen = false + if (!it.isNullOrEmpty()) { + key.value = TextFieldValue(it) + } } - ) + } + IconButton(onClick = { dialogOpen = true }) { + Icon( + painter = painterResource(R.drawable.ic_qrcode), + null, + modifier = Modifier.size(24.dp), + tint = MaterialTheme.colors.primary + ) + } } }, visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(), From 2ae54b544f340252e82f2c8d48cd65f05e5cc3fa Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Thu, 20 Apr 2023 08:12:26 -0300 Subject: [PATCH 02/18] wip: add tor socks support --- .../amethyst/LocalPreferences.kt | 6 +++- .../vitorpamplona/amethyst/model/Account.kt | 10 +++--- .../amethyst/service/relays/Client.kt | 2 +- .../amethyst/service/relays/Constants.kt | 2 +- .../amethyst/service/relays/Relay.kt | 8 ++++- .../amethyst/ui/navigation/DrawerContent.kt | 32 +++++++++++++++++-- 6 files changed, 49 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index c2c21bb24..d45180dee 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -46,6 +46,7 @@ private object PrefKeys { const val LATEST_CONTACT_LIST = "latestContactList" const val HIDE_DELETE_REQUEST_DIALOG = "hide_delete_request_dialog" const val HIDE_BLOCK_ALERT_DIALOG = "hide_block_alert_dialog" + const val USE_PROXY = "use_proxy" val LAST_READ: (String) -> String = { route -> "last_read_route_$route" } } @@ -195,6 +196,7 @@ object LocalPreferences { putString(PrefKeys.LATEST_CONTACT_LIST, Event.gson.toJson(account.backupContactList)) putBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, account.hideDeleteRequestDialog) putBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, account.hideBlockAlertDialog) + putBoolean(PrefKeys.USE_PROXY, account.useProxy) }.apply() } @@ -250,6 +252,7 @@ object LocalPreferences { val hideDeleteRequestDialog = getBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, false) val hideBlockAlertDialog = getBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, false) + val useProxy = getBoolean(PrefKeys.USE_PROXY, false) val a = Account( Persona(privKey = privKey?.toByteArray(), pubKey = pubKey.toByteArray()), @@ -263,7 +266,8 @@ object LocalPreferences { zapPaymentRequestServer, hideDeleteRequestDialog, hideBlockAlertDialog, - latestContactList + latestContactList, + useProxy ) return a diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 5a36d7297..c5d0aa081 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -45,7 +45,8 @@ class Account( var zapPaymentRequest: Nip47URI? = null, var hideDeleteRequestDialog: Boolean = false, var hideBlockAlertDialog: Boolean = false, - var backupContactList: ContactListEvent? = null + var backupContactList: ContactListEvent? = null, + var useProxy: Boolean = false ) { var transientHiddenUsers: Set = setOf() @@ -692,7 +693,7 @@ class Account( fun activeRelays(): Array? { var usersRelayList = userProfile().latestContactList?.relays()?.map { val localFeedTypes = localRelays.firstOrNull() { localRelay -> localRelay.url == it.key }?.feedTypes ?: FeedType.values().toSet() - Relay(it.key, it.value.read, it.value.write, localFeedTypes) + Relay(it.key, it.value.read, it.value.write, localFeedTypes, useProxy) } ?: return null // Ugly, but forces nostr.band as the only search-supporting relay today. @@ -702,7 +703,8 @@ class Account( Constants.forcedRelayForSearch.url, Constants.forcedRelayForSearch.read, Constants.forcedRelayForSearch.write, - Constants.forcedRelayForSearch.feedTypes + Constants.forcedRelayForSearch.feedTypes, + useProxy ) } @@ -711,7 +713,7 @@ class Account( fun convertLocalRelays(): Array { return localRelays.map { - Relay(it.url, it.read, it.write, it.feedTypes) + Relay(it.url, it.read, it.write, it.feedTypes, useProxy) }.toTypedArray() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt index 6f841deb6..602c4f347 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt @@ -76,7 +76,7 @@ object Client : RelayPool.Listener { } } else { /** temporary connection */ - Relay(relay, false, true, emptySet()).requestAndWatch() { + Relay(relay, false, true, emptySet(), false).requestAndWatch() { it.send(signedEvent) it.disconnect() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Constants.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Constants.kt index a167a2d99..5e947a967 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Constants.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Constants.kt @@ -10,7 +10,7 @@ object Constants { fun convertDefaultRelays(): Array { return defaultRelays.map { - Relay(it.url, it.read, it.write, it.feedTypes) + Relay(it.url, it.read, it.write, it.feedTypes, false) }.toTypedArray() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt index 87407844b..def4096cd 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt @@ -10,6 +10,8 @@ import okhttp3.Request import okhttp3.Response import okhttp3.WebSocket import okhttp3.WebSocketListener +import java.net.InetSocketAddress +import java.net.Proxy import java.util.Date enum class FeedType { @@ -20,9 +22,13 @@ class Relay( var url: String, var read: Boolean = true, var write: Boolean = true, - var activeTypes: Set = FeedType.values().toSet() + var activeTypes: Set = FeedType.values().toSet(), + useProxy: Boolean ) { + private var proxy = if (useProxy) Proxy(Proxy.Type.SOCKS, InetSocketAddress("127.0.0.1", 9050)) else null + private val httpClient = OkHttpClient.Builder() + .proxy(proxy) .followRedirects(true) .followSslRedirects(true) .build() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index defddc0c9..824eb87b1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -46,6 +46,7 @@ import androidx.navigation.NavHostController import coil.compose.AsyncImage import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.User import com.vitorpamplona.amethyst.ui.components.ResizeImage @@ -100,7 +101,12 @@ fun DrawerContent( } @Composable -fun ProfileContent(baseAccountUser: User, modifier: Modifier = Modifier, scaffoldState: ScaffoldState, navController: NavController) { +fun ProfileContent( + baseAccountUser: User, + modifier: Modifier = Modifier, + scaffoldState: ScaffoldState, + navController: NavController +) { val coroutineScope = rememberCoroutineScope() val accountUserState by baseAccountUser.live().metadata.observeAsState() @@ -197,11 +203,17 @@ fun ProfileContent(baseAccountUser: User, modifier: Modifier = Modifier, scaffol }) ) { Row() { - Text("${accountUserFollows.cachedFollowCount() ?: "--"}", fontWeight = FontWeight.Bold) + Text( + "${accountUserFollows.cachedFollowCount() ?: "--"}", + fontWeight = FontWeight.Bold + ) Text(stringResource(R.string.following)) } Row(modifier = Modifier.padding(start = 10.dp)) { - Text("${accountUserFollows.cachedFollowerCount() ?: "--"}", fontWeight = FontWeight.Bold) + Text( + "${accountUserFollows.cachedFollowerCount() ?: "--"}", + fontWeight = FontWeight.Bold + ) Text(stringResource(R.string.followers)) } } @@ -221,6 +233,7 @@ fun ListContent( ) { val coroutineScope = rememberCoroutineScope() var backupDialogOpen by remember { mutableStateOf(false) } + var checked by remember { mutableStateOf(account.useProxy) } Column(modifier = modifier.fillMaxHeight()) { if (accountUser != null) { @@ -259,6 +272,19 @@ fun ListContent( onClick = { backupDialogOpen = true } ) + IconRow( + title = "Enable Tor", + icon = R.drawable.ic_topics, + tint = MaterialTheme.colors.onBackground, + onClick = { + checked = !checked + println("changed tor to $checked") + account.useProxy = checked + ServiceManager.pause() + ServiceManager.start() + } + ) + Spacer(modifier = Modifier.weight(1f)) IconRow( From cf8747b19fc11e524561f0e13bd654a7c9550c3d Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Thu, 20 Apr 2023 15:30:04 -0300 Subject: [PATCH 03/18] add a checkbox to use tor in the login screen, set the proxy in the account model construction --- .../vitorpamplona/amethyst/LocalPreferences.kt | 8 ++++++-- .../vitorpamplona/amethyst/model/Account.kt | 9 +++++---- .../amethyst/service/relays/Client.kt | 3 ++- .../amethyst/service/relays/Constants.kt | 3 ++- .../amethyst/service/relays/Relay.kt | 5 +---- .../amethyst/ui/navigation/DrawerContent.kt | 6 ++++-- .../ui/screen/AccountStateViewModel.kt | 18 +++++++++++------- .../ui/screen/loggedOff/LoginScreen.kt | 16 +++++++++++++--- 8 files changed, 44 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index d45180dee..40b6d817e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -17,6 +17,8 @@ import nostr.postr.Persona import nostr.postr.toHex import nostr.postr.toNpub import java.io.File +import java.net.InetSocketAddress +import java.net.Proxy import java.util.Locale // Release mode (!BuildConfig.DEBUG) always uses encrypted preferences @@ -196,7 +198,8 @@ object LocalPreferences { putString(PrefKeys.LATEST_CONTACT_LIST, Event.gson.toJson(account.backupContactList)) putBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, account.hideDeleteRequestDialog) putBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, account.hideBlockAlertDialog) - putBoolean(PrefKeys.USE_PROXY, account.useProxy) + println(account.proxy != null) + putBoolean(PrefKeys.USE_PROXY, account.proxy != null) }.apply() } @@ -253,6 +256,7 @@ object LocalPreferences { val hideDeleteRequestDialog = getBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, false) val hideBlockAlertDialog = getBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, false) val useProxy = getBoolean(PrefKeys.USE_PROXY, false) + var proxy = if (useProxy) Proxy(Proxy.Type.SOCKS, InetSocketAddress("127.0.0.1", 9050)) else null val a = Account( Persona(privKey = privKey?.toByteArray(), pubKey = pubKey.toByteArray()), @@ -267,7 +271,7 @@ object LocalPreferences { hideDeleteRequestDialog, hideBlockAlertDialog, latestContactList, - useProxy + proxy ) return a diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index c5d0aa081..fadefa790 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -16,6 +16,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import nostr.postr.Persona +import java.net.Proxy import java.util.Locale val DefaultChannels = setOf( @@ -46,7 +47,7 @@ class Account( var hideDeleteRequestDialog: Boolean = false, var hideBlockAlertDialog: Boolean = false, var backupContactList: ContactListEvent? = null, - var useProxy: Boolean = false + var proxy: Proxy? ) { var transientHiddenUsers: Set = setOf() @@ -693,7 +694,7 @@ class Account( fun activeRelays(): Array? { var usersRelayList = userProfile().latestContactList?.relays()?.map { val localFeedTypes = localRelays.firstOrNull() { localRelay -> localRelay.url == it.key }?.feedTypes ?: FeedType.values().toSet() - Relay(it.key, it.value.read, it.value.write, localFeedTypes, useProxy) + Relay(it.key, it.value.read, it.value.write, localFeedTypes, proxy) } ?: return null // Ugly, but forces nostr.band as the only search-supporting relay today. @@ -704,7 +705,7 @@ class Account( Constants.forcedRelayForSearch.read, Constants.forcedRelayForSearch.write, Constants.forcedRelayForSearch.feedTypes, - useProxy + proxy ) } @@ -713,7 +714,7 @@ class Account( fun convertLocalRelays(): Array { return localRelays.map { - Relay(it.url, it.read, it.write, it.feedTypes, useProxy) + Relay(it.url, it.read, it.write, it.feedTypes, proxy) }.toTypedArray() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt index 602c4f347..b1ef135a9 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt @@ -76,7 +76,8 @@ object Client : RelayPool.Listener { } } else { /** temporary connection */ - Relay(relay, false, true, emptySet(), false).requestAndWatch() { + /** TODO: set the proxy for this temporary connection */ + Relay(relay, false, true, emptySet(), null).requestAndWatch() { it.send(signedEvent) it.disconnect() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Constants.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Constants.kt index 5e947a967..9f5477687 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Constants.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Constants.kt @@ -10,7 +10,8 @@ object Constants { fun convertDefaultRelays(): Array { return defaultRelays.map { - Relay(it.url, it.read, it.write, it.feedTypes, false) + /** TODO: set the proxy */ + Relay(it.url, it.read, it.write, it.feedTypes, null) }.toTypedArray() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt index def4096cd..1084f21c9 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt @@ -10,7 +10,6 @@ import okhttp3.Request import okhttp3.Response import okhttp3.WebSocket import okhttp3.WebSocketListener -import java.net.InetSocketAddress import java.net.Proxy import java.util.Date @@ -23,10 +22,8 @@ class Relay( var read: Boolean = true, var write: Boolean = true, var activeTypes: Set = FeedType.values().toSet(), - useProxy: Boolean + proxy: Proxy? ) { - private var proxy = if (useProxy) Proxy(Proxy.Type.SOCKS, InetSocketAddress("127.0.0.1", 9050)) else null - private val httpClient = OkHttpClient.Builder() .proxy(proxy) .followRedirects(true) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index 824eb87b1..36e1ac835 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -54,6 +54,8 @@ import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountBackupDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.launch +import java.net.InetSocketAddress +import java.net.Proxy @OptIn(ExperimentalMaterialApi::class) @Composable @@ -233,7 +235,7 @@ fun ListContent( ) { val coroutineScope = rememberCoroutineScope() var backupDialogOpen by remember { mutableStateOf(false) } - var checked by remember { mutableStateOf(account.useProxy) } + var checked by remember { mutableStateOf(account.proxy != null) } Column(modifier = modifier.fillMaxHeight()) { if (accountUser != null) { @@ -279,7 +281,7 @@ fun ListContent( onClick = { checked = !checked println("changed tor to $checked") - account.useProxy = checked + account.proxy = if (checked) Proxy(Proxy.Type.SOCKS, InetSocketAddress("127.0.0.1", 9050)) else null ServiceManager.pause() ServiceManager.start() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt index 0118af459..d6872f808 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt @@ -18,6 +18,8 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import nostr.postr.Persona import nostr.postr.bechToBytes +import java.net.InetSocketAddress +import java.net.Proxy import java.util.regex.Pattern class AccountStateViewModel() : ViewModel() { @@ -39,21 +41,22 @@ class AccountStateViewModel() : ViewModel() { } } - fun startUI(key: String) { + fun startUI(key: String, useProxy: Boolean) { val pattern = Pattern.compile(".+@.+\\.[a-z]+") val parsed = Nip19.uriToRoute(key) val pubKeyParsed = parsed?.hex?.toByteArray() + var proxy = if (useProxy) Proxy(Proxy.Type.SOCKS, InetSocketAddress("127.0.0.1", 9050)) else null val account = if (key.startsWith("nsec")) { - Account(Persona(privKey = key.bechToBytes())) + Account(Persona(privKey = key.bechToBytes()), proxy = proxy) } else if (pubKeyParsed != null) { - Account(Persona(pubKey = pubKeyParsed)) + Account(Persona(pubKey = pubKeyParsed), proxy = proxy) } else if (pattern.matcher(key).matches()) { // Evaluate NIP-5 - Account(Persona()) + Account(Persona(), proxy = proxy) } else { - Account(Persona(Hex.decode(key))) + Account(Persona(Hex.decode(key)), proxy = proxy) } LocalPreferences.updatePrefsForLogin(account) @@ -66,8 +69,9 @@ class AccountStateViewModel() : ViewModel() { tryLoginExistingAccount() } - fun newKey() { - val account = Account(Persona()) + fun newKey(useProxy: Boolean) { + var proxy = if (useProxy) Proxy(Proxy.Type.SOCKS, InetSocketAddress("127.0.0.1", 9050)) else null + val account = Account(Persona(), proxy = proxy) // saves to local preferences LocalPreferences.updatePrefsForLogin(account) startUI(account) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt index ec45c3aff..6533d1c90 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt @@ -55,6 +55,7 @@ fun LoginPage( var dialogOpen by remember { mutableStateOf(false) } + val useProxy = remember { mutableStateOf(false) } Column( modifier = Modifier @@ -158,7 +159,7 @@ fun LoginPage( keyboardActions = KeyboardActions( onGo = { try { - accountViewModel.startUI(key.value.text) + accountViewModel.startUI(key.value.text, useProxy.value) } catch (e: Exception) { errorMessage = context.getString(R.string.invalid_key) } @@ -221,6 +222,15 @@ fun LoginPage( } } + Row(verticalAlignment = Alignment.CenterVertically) { + Checkbox( + checked = useProxy.value, + onCheckedChange = { useProxy.value = it } + ) + + Text("Enable Tor") + } + Spacer(modifier = Modifier.height(20.dp)) Box(modifier = Modifier.padding(40.dp, 0.dp, 40.dp, 0.dp)) { @@ -237,7 +247,7 @@ fun LoginPage( if (acceptedTerms.value && key.value.text.isNotBlank()) { try { - accountViewModel.startUI(key.value.text) + accountViewModel.startUI(key.value.text, useProxy.value) } catch (e: Exception) { errorMessage = context.getString(R.string.invalid_key) } @@ -265,7 +275,7 @@ fun LoginPage( .fillMaxWidth(), onClick = { if (acceptedTerms.value) { - accountViewModel.newKey() + accountViewModel.newKey(useProxy.value) } else { termsAcceptanceIsRequired = context.getString(R.string.acceptance_of_terms_is_required) From ad420da6dec4846539b3a4cbfff48a48a05d0c63 Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Mon, 24 Apr 2023 16:37:00 -0300 Subject: [PATCH 04/18] added tor icon --- .../java/com/vitorpamplona/amethyst/service/relays/Relay.kt | 4 ++++ .../vitorpamplona/amethyst/ui/navigation/DrawerContent.kt | 6 ++++-- app/src/main/res/drawable/ic_tor.xml | 4 ++++ 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/drawable/ic_tor.xml diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt index 1084f21c9..8408e985a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt @@ -24,6 +24,10 @@ class Relay( var activeTypes: Set = FeedType.values().toSet(), proxy: Proxy? ) { + init { + println("Tor: ${proxy != null} url: $url") + } + private val httpClient = OkHttpClient.Builder() .proxy(proxy) .followRedirects(true) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index 36e1ac835..3126cc4ab 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -274,9 +274,11 @@ fun ListContent( onClick = { backupDialogOpen = true } ) + var textTorProxy = if (checked) "Disable" else "Enable" + IconRow( - title = "Enable Tor", - icon = R.drawable.ic_topics, + title = "$textTorProxy Tor", + icon = R.drawable.ic_tor, tint = MaterialTheme.colors.onBackground, onClick = { checked = !checked diff --git a/app/src/main/res/drawable/ic_tor.xml b/app/src/main/res/drawable/ic_tor.xml new file mode 100644 index 000000000..bafee0c19 --- /dev/null +++ b/app/src/main/res/drawable/ic_tor.xml @@ -0,0 +1,4 @@ + + + From 9f3d6a75e6d4a88d14a7252e4c3545ccc863820e Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Wed, 26 Apr 2023 08:42:49 -0300 Subject: [PATCH 05/18] add proxy to all http clients --- .../amethyst/service/Nip05Verifier.kt | 5 +++-- .../service/lnurl/LightningAddressResolver.kt | 5 +++-- .../amethyst/ui/actions/ImageSaver.kt | 6 ++++-- .../amethyst/ui/actions/ImageUploader.kt | 6 ++++-- .../amethyst/ui/actions/NewPostViewModel.kt | 3 ++- .../ui/actions/NewUserMetadataViewModel.kt | 3 ++- .../amethyst/ui/actions/SaveToGallery.kt | 6 ++++-- .../ui/components/ExpandableRichTextViewer.kt | 7 +++++-- .../amethyst/ui/components/InvoiceRequest.kt | 2 +- .../amethyst/ui/components/RichTextViewer.kt | 8 +++++--- .../amethyst/ui/components/ZoomableImageView.kt | 9 +++++---- .../amethyst/ui/note/ChatroomMessageCompose.kt | 6 ++++-- .../ui/note/NIP05VerificationDisplay.kt | 17 +++++++++-------- .../amethyst/ui/note/NoteCompose.kt | 11 +++++++---- .../vitorpamplona/amethyst/ui/note/PollNote.kt | 10 +++++++--- .../amethyst/ui/screen/ThreadFeedView.kt | 8 +++++--- .../ui/screen/loggedIn/AccountViewModel.kt | 2 +- .../ui/screen/loggedIn/ChatroomScreen.kt | 7 ++++--- .../ui/screen/loggedIn/ProfileScreen.kt | 14 ++++++++------ .../ui/components/TranslatableRichTextViewer.kt | 7 +++++-- 20 files changed, 88 insertions(+), 54 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05Verifier.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05Verifier.kt index 2a0ee3240..fd86dc1eb 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05Verifier.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05Verifier.kt @@ -12,9 +12,10 @@ import okhttp3.Callback import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response +import java.net.Proxy -class Nip05Verifier { - val client = OkHttpClient.Builder().build() +class Nip05Verifier(proxy: Proxy?) { + val client = OkHttpClient.Builder().proxy(proxy).build() fun assembleUrl(nip05address: String): String? { val parts = nip05address.trim().split("@") diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt index a9459b21c..26e68d205 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt @@ -14,10 +14,11 @@ import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response import java.math.BigDecimal +import java.net.Proxy import java.net.URLEncoder -class LightningAddressResolver { - val client = OkHttpClient.Builder().build() +class LightningAddressResolver(proxy: Proxy?) { + val client = OkHttpClient.Builder().proxy(proxy).build() fun assembleUrl(lnaddress: String): String? { val parts = lnaddress.split("@") diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt index 485f21062..ca8727c1d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt @@ -14,6 +14,7 @@ import okio.BufferedSource import okio.IOException import okio.sink import java.io.File +import java.net.Proxy object ImageSaver { /** @@ -26,9 +27,10 @@ object ImageSaver { url: String, context: Context, onSuccess: () -> Any?, - onError: (Throwable) -> Any? + onError: (Throwable) -> Any?, + proxy: Proxy? ) { - val client = OkHttpClient.Builder().build() + val client = OkHttpClient.Builder().proxy(proxy).build() val request = Request.Builder() .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt index 574fef2b1..6ecddfeb0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt @@ -9,6 +9,7 @@ import okhttp3.MediaType.Companion.toMediaType import okio.BufferedSink import okio.source import java.io.IOException +import java.net.Proxy import java.util.* object ImageUploader { @@ -16,14 +17,15 @@ object ImageUploader { uri: Uri, contentResolver: ContentResolver, onSuccess: (String) -> Unit, - onError: (Throwable) -> Unit + onError: (Throwable) -> Unit, + proxy: Proxy? ) { val contentType = contentResolver.getType(uri) val category = contentType?.toMediaType()?.toString()?.split("/")?.get(0) ?: "image" val url = if (category == "image") "https://api.imgur.com/3/image" else "https://api.imgur.com/3/upload" - val client = OkHttpClient.Builder().build() + val client = OkHttpClient.Builder().proxy(proxy).build() val requestBody: RequestBody = MultipartBody.Builder() .setType(MultipartBody.FORM) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt index 8be28a491..97ed777a1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt @@ -124,7 +124,8 @@ open class NewPostViewModel : ViewModel() { viewModelScope.launch { imageUploadingError.emit("Failed to upload the image / video") } - } + }, + account!!.proxy ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt index e6a9bf2e0..7fd7a25af 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt @@ -180,7 +180,8 @@ class NewUserMetadataViewModel : ViewModel() { viewModelScope.launch { imageUploadingError.emit("Failed to upload the image / video") } - } + }, + account.proxy ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt index e8dbca2cf..a757506bc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt @@ -18,6 +18,7 @@ import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberPermissionState import com.vitorpamplona.amethyst.R import kotlinx.coroutines.launch +import java.net.Proxy /** * A button to save the remote image to the gallery. @@ -27,7 +28,7 @@ import kotlinx.coroutines.launch */ @OptIn(ExperimentalPermissionsApi::class) @Composable -fun SaveToGallery(url: String) { +fun SaveToGallery(url: String, proxy: Proxy?) { val localContext = LocalContext.current val scope = rememberCoroutineScope() @@ -54,7 +55,8 @@ fun SaveToGallery(url: String) { ) .show() } - } + }, + proxy = proxy ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt index 3b62e83bd..37c4689bf 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt @@ -27,6 +27,7 @@ import androidx.compose.ui.unit.dp import androidx.navigation.NavController import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import java.net.Proxy const val SHORT_TEXT_LENGTH = 350 @@ -38,7 +39,8 @@ fun ExpandableRichTextViewer( tags: List>?, backgroundColor: Color, accountViewModel: AccountViewModel, - navController: NavController + navController: NavController, + proxy: Proxy? ) { var showFullText by remember { mutableStateOf(false) } @@ -62,7 +64,8 @@ fun ExpandableRichTextViewer( tags, backgroundColor, accountViewModel, - navController + navController, + proxy ) if (content.length > whereToCut && !showFullText) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt index 06e38c773..13bb71069 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt @@ -138,7 +138,7 @@ fun InvoiceRequest( onClick = { val zapRequest = account.createZapRequestFor(toUserPubKeyHex, message, LnZapEvent.ZapType.PUBLIC) - LightningAddressResolver().lnAddressInvoice( + LightningAddressResolver(account.proxy).lnAddressInvoice( lud16, amount * 1000, message, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt index 474a1fea7..edc78229c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt @@ -43,6 +43,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.net.MalformedURLException +import java.net.Proxy import java.net.URISyntaxException import java.net.URL import java.util.regex.Pattern @@ -80,7 +81,8 @@ fun RichTextViewer( tags: List>?, backgroundColor: Color, accountViewModel: AccountViewModel, - navController: NavController + navController: NavController, + proxy: Proxy? ) { Column(modifier = modifier) { if (content.startsWith("# ") || @@ -159,9 +161,9 @@ fun RichTextViewer( if (isValidURL(word)) { val removedParamsFromUrl = word.split("?")[0].lowercase() if (imageExtensions.any { removedParamsFromUrl.endsWith(it) }) { - ZoomableImageView(word, imagesForPager) + ZoomableImageView(word, imagesForPager, proxy) } else if (videoExtensions.any { removedParamsFromUrl.endsWith(it) }) { - ZoomableImageView(word, imagesForPager) + ZoomableImageView(word, imagesForPager, proxy) } else { UrlPreview(word, "$word ") } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableImageView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableImageView.kt index e547da6bd..2fa6a5c14 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableImageView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableImageView.kt @@ -46,10 +46,11 @@ import com.vitorpamplona.amethyst.ui.actions.LoadingAnimation import com.vitorpamplona.amethyst.ui.actions.SaveToGallery import net.engawapg.lib.zoomable.rememberZoomState import net.engawapg.lib.zoomable.zoomable +import java.net.Proxy @Composable @OptIn(ExperimentalFoundationApi::class) -fun ZoomableImageView(word: String, images: List = listOf(word)) { +fun ZoomableImageView(word: String, images: List = listOf(word), proxy: Proxy?) { val clipboardManager = LocalClipboardManager.current // store the dialog open or close state @@ -126,13 +127,13 @@ fun ZoomableImageView(word: String, images: List = listOf(word)) { } if (dialogOpen) { - ZoomableImageDialog(word, images, onDismiss = { dialogOpen = false }) + ZoomableImageDialog(word, images, onDismiss = { dialogOpen = false }, proxy) } } @OptIn(ExperimentalPagerApi::class) @Composable -fun ZoomableImageDialog(imageUrl: String, allImages: List = listOf(imageUrl), onDismiss: () -> Unit) { +fun ZoomableImageDialog(imageUrl: String, allImages: List = listOf(imageUrl), onDismiss: () -> Unit, proxy: Proxy?) { Dialog( onDismissRequest = onDismiss, properties = DialogProperties(usePlatformDefaultWidth = false) @@ -150,7 +151,7 @@ fun ZoomableImageDialog(imageUrl: String, allImages: List = listOf(image ) { CloseButton(onCancel = onDismiss) - SaveToGallery(url = allImages[pagerState.currentPage]) + SaveToGallery(url = allImages[pagerState.currentPage], proxy) } if (allImages.size > 1) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt index bee998015..6aa2e5cb5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt @@ -290,7 +290,8 @@ fun ChatroomMessageCompose( note.event?.tags(), backgroundBubbleColor, accountViewModel, - navController + navController, + account.proxy ) } else { TranslatableRichTextViewer( @@ -300,7 +301,8 @@ fun ChatroomMessageCompose( note.event?.tags(), backgroundBubbleColor, accountViewModel, - navController + navController, + account.proxy ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt index cebfe1fdd..bb1342660 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt @@ -35,10 +35,11 @@ import com.vitorpamplona.amethyst.service.Nip05Verifier import com.vitorpamplona.amethyst.ui.theme.Nip05 import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import java.net.Proxy import java.util.Date @Composable -fun nip05VerificationAsAState(user: UserMetadata, pubkeyHex: String): State { +fun nip05VerificationAsAState(user: UserMetadata, pubkeyHex: String, proxy: Proxy?): State { var nip05Verified = remember { mutableStateOf(null) } LaunchedEffect(key1 = user) { @@ -48,7 +49,7 @@ fun nip05VerificationAsAState(user: UserMetadata, pubkeyHex: String): State (now - 60 * 60)) { // 1hour nip05Verified.value = user.nip05Verified } else { - Nip05Verifier().verifyNip05( + Nip05Verifier(proxy).verifyNip05( nip05, onSuccess = { // Marks user as verified @@ -77,18 +78,18 @@ fun nip05VerificationAsAState(user: UserMetadata, pubkeyHex: String): State if (nip05.split("@").size == 2) { - val nip05Verified by nip05VerificationAsAState(user.info!!, user.pubkeyHex) + val nip05Verified by nip05VerificationAsAState(user.info!!, user.pubkeyHex, proxy) Row(verticalAlignment = Alignment.CenterVertically) { if (nip05Verified == null) { Icon( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index 8400d174b..ccabb8348 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -353,7 +353,7 @@ fun NoteComposeInner( if (note.author != null && !makeItShort && !isQuotedNote) { Row(verticalAlignment = Alignment.CenterVertically) { - ObserveDisplayNip05Status(note.author!!, Modifier.weight(1f)) + ObserveDisplayNip05Status(note.author!!, Modifier.weight(1f), account.proxy) val baseReward = noteEvent.getReward() if (baseReward != null) { @@ -509,7 +509,8 @@ fun NoteComposeInner( noteEvent.tags(), backgroundColor, accountViewModel, - navController + navController, + account.proxy ) if (!makeItShort) { @@ -539,7 +540,8 @@ fun NoteComposeInner( noteEvent.tags(), backgroundColor, accountViewModel, - navController + navController, + account.proxy ) DisplayUncitedHashtags(noteEvent.hashtags(), eventContent, navController) @@ -551,7 +553,8 @@ fun NoteComposeInner( canPreview = canPreview && !makeItShort, backgroundColor, accountViewModel, - navController + navController, + account.proxy ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt index 26e83cf91..b95afb0d5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt @@ -37,6 +37,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import java.net.Proxy import java.util.* import kotlin.math.roundToInt @@ -46,7 +47,8 @@ fun PollNote( canPreview: Boolean, backgroundColor: Color, accountViewModel: AccountViewModel, - navController: NavController + navController: NavController, + proxy: Proxy? ) { val zapsState by baseNote.live().zaps.observeAsState() val zappedNote = zapsState?.note ?: return @@ -111,7 +113,8 @@ fun PollNote( pollViewModel.pollEvent?.tags(), backgroundColor, accountViewModel, - navController + navController, + proxy ) } } @@ -144,7 +147,8 @@ fun PollNote( pollViewModel.pollEvent?.tags(), backgroundColor, accountViewModel, - navController + navController, + proxy ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt index 26d0448be..e161b2003 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt @@ -282,7 +282,7 @@ fun NoteMaster( } Row(verticalAlignment = Alignment.CenterVertically) { - ObserveDisplayNip05Status(baseNote, Modifier.weight(1f)) + ObserveDisplayNip05Status(baseNote, Modifier.weight(1f), account.proxy) val baseReward = noteEvent.getReward() if (baseReward != null) { @@ -362,7 +362,8 @@ fun NoteMaster( note.event?.tags(), MaterialTheme.colors.background, accountViewModel, - navController + navController, + account.proxy ) DisplayUncitedHashtags(noteEvent.hashtags(), eventContent, navController) @@ -373,7 +374,8 @@ fun NoteMaster( canPreview, backgroundColor, accountViewModel, - navController + navController, + account.proxy ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index c88352b6c..22fffb064 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -72,7 +72,7 @@ class AccountViewModel(private val account: Account) : ViewModel() { onProgress(0.10f) - LightningAddressResolver().lnAddressInvoice( + LightningAddressResolver(account.proxy).lnAddressInvoice( lud16, amount, message, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt index 0f26c18bc..a1ac44714 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt @@ -59,6 +59,7 @@ import com.vitorpamplona.amethyst.ui.note.UserPicture import com.vitorpamplona.amethyst.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.ui.screen.ChatroomFeedView import com.vitorpamplona.amethyst.ui.screen.NostrChatRoomFeedViewModel +import java.net.Proxy @Composable fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navController: NavController) { @@ -104,7 +105,7 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr Column(Modifier.fillMaxHeight()) { NostrChatroomDataSource.withUser?.let { - ChatroomHeader(it, account.userProfile(), navController = navController) + ChatroomHeader(it, account.userProfile(), navController = navController, account.proxy) } Column( @@ -206,7 +207,7 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr } @Composable -fun ChatroomHeader(baseUser: User, accountUser: User, navController: NavController) { +fun ChatroomHeader(baseUser: User, accountUser: User, navController: NavController, proxy: Proxy?) { Column( modifier = Modifier.clickable( onClick = { navController.navigate("User/${baseUser.pubkeyHex}") } @@ -226,7 +227,7 @@ fun ChatroomHeader(baseUser: User, accountUser: User, navController: NavControll } Row(verticalAlignment = Alignment.CenterVertically) { - ObserveDisplayNip05Status(baseUser) + ObserveDisplayNip05Status(baseUser, proxy = proxy) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index 6c832ceac..46623a0ef 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -1,6 +1,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn import android.content.Intent +import java.net.Proxy import android.net.Uri import androidx.compose.foundation.* import androidx.compose.foundation.gestures.scrollBy @@ -308,7 +309,7 @@ private fun ProfileHeader( val clipboardManager = LocalClipboardManager.current Box { - DrawBanner(baseUser) + DrawBanner(baseUser, account.proxy) Box( modifier = Modifier @@ -410,7 +411,7 @@ private fun ProfileHeader( } if (zoomImageDialogOpen) { - ZoomableImageDialog(baseUser.profilePicture()!!, onDismiss = { zoomImageDialogOpen = false }) + ZoomableImageDialog(baseUser.profilePicture()!!, onDismiss = { zoomImageDialogOpen = false }, proxy = account.proxy) } } @@ -514,7 +515,7 @@ private fun DrawAdditionalInfo(baseUser: User, account: Account, accountViewMode } } - DisplayNip05ProfileStatus(user) + DisplayNip05ProfileStatus(user, account.proxy) val website = user.info?.website if (!website.isNullOrEmpty()) { @@ -616,7 +617,8 @@ private fun DrawAdditionalInfo(baseUser: User, account: Account, accountViewMode tags = null, backgroundColor = MaterialTheme.colors.background, accountViewModel = accountViewModel, - navController = navController + navController = navController, + proxy = account.proxy ) } } @@ -686,7 +688,7 @@ fun BadgeThumb( @OptIn(ExperimentalFoundationApi::class) @Composable -private fun DrawBanner(baseUser: User) { +private fun DrawBanner(baseUser: User, proxy: Proxy?) { val userState by baseUser.live().metadata.observeAsState() val user = userState?.user ?: return @@ -712,7 +714,7 @@ private fun DrawBanner(baseUser: User) { ) if (zoomImageDialogOpen) { - ZoomableImageDialog(imageUrl = banner, onDismiss = { zoomImageDialogOpen = false }) + ZoomableImageDialog(imageUrl = banner, onDismiss = { zoomImageDialogOpen = false }, proxy = proxy) } } else { Image( diff --git a/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt index 8100a3e9b..e30a5f41e 100644 --- a/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt +++ b/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt @@ -35,6 +35,7 @@ import com.vitorpamplona.amethyst.service.lang.ResultOrError import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import java.net.Proxy import java.util.Locale @Composable @@ -45,7 +46,8 @@ fun TranslatableRichTextViewer( tags: List>?, backgroundColor: Color, accountViewModel: AccountViewModel, - navController: NavController + navController: NavController, + proxy: Proxy? ) { val translatedTextState = remember { mutableStateOf(ResultOrError(content, null, null, null)) @@ -87,7 +89,8 @@ fun TranslatableRichTextViewer( tags, backgroundColor, accountViewModel, - navController + navController, + proxy ) val target = translatedTextState.value.targetLang From 4f8d33d850acfa738bfd48bf06d93ee403d92fb2 Mon Sep 17 00:00:00 2001 From: greenart7c3 Date: Wed, 26 Apr 2023 08:51:58 -0300 Subject: [PATCH 06/18] fix build --- .../amethyst/ui/components/TranslatableRichTextViewer.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt index 5f4659d44..a64a9e012 100644 --- a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt +++ b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt @@ -5,6 +5,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.navigation.NavController import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import java.net.Proxy @Composable fun TranslatableRichTextViewer( @@ -14,7 +15,8 @@ fun TranslatableRichTextViewer( tags: List>?, backgroundColor: Color, accountViewModel: AccountViewModel, - navController: NavController + navController: NavController, + proxy: Proxy? ) = ExpandableRichTextViewer( content, canPreview, @@ -22,5 +24,6 @@ fun TranslatableRichTextViewer( tags, backgroundColor, accountViewModel, - navController + navController, + proxy ) From c648f54b518604f5ed3fa75f38d1f68b563f013e Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Wed, 26 Apr 2023 10:03:51 -0300 Subject: [PATCH 07/18] created HttpClient class --- .../ui/components/TranslatableRichTextViewer.kt | 7 ++----- .../vitorpamplona/amethyst/ServiceManager.kt | 3 ++- .../amethyst/service/HttpClient.kt | 17 +++++++++++++++++ .../amethyst/service/Nip05Verifier.kt | 6 ++---- .../service/lnurl/LightningAddressResolver.kt | 7 +++---- .../amethyst/ui/actions/ImageSaver.kt | 7 +++---- .../amethyst/ui/actions/ImageUploader.kt | 7 +++---- .../amethyst/ui/actions/NewPostViewModel.kt | 3 +-- .../ui/actions/NewUserMetadataViewModel.kt | 3 +-- .../amethyst/ui/actions/SaveToGallery.kt | 6 ++---- .../ui/components/ExpandableRichTextViewer.kt | 7 ++----- .../amethyst/ui/components/InvoiceRequest.kt | 2 +- .../amethyst/ui/components/RichTextViewer.kt | 8 +++----- .../amethyst/ui/components/ZoomableImageView.kt | 9 ++++----- .../amethyst/ui/note/ChatroomMessageCompose.kt | 6 ++---- .../ui/note/NIP05VerificationDisplay.kt | 17 ++++++++--------- .../amethyst/ui/note/NoteCompose.kt | 11 ++++------- .../vitorpamplona/amethyst/ui/note/PollNote.kt | 10 +++------- .../amethyst/ui/screen/ThreadFeedView.kt | 8 +++----- .../ui/screen/loggedIn/AccountViewModel.kt | 2 +- .../ui/screen/loggedIn/ChatroomScreen.kt | 7 +++---- .../ui/screen/loggedIn/ProfileScreen.kt | 14 ++++++-------- .../ui/components/TranslatableRichTextViewer.kt | 7 ++----- 23 files changed, 78 insertions(+), 96 deletions(-) create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt index a64a9e012..5f4659d44 100644 --- a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt +++ b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt @@ -5,7 +5,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.navigation.NavController import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import java.net.Proxy @Composable fun TranslatableRichTextViewer( @@ -15,8 +14,7 @@ fun TranslatableRichTextViewer( tags: List>?, backgroundColor: Color, accountViewModel: AccountViewModel, - navController: NavController, - proxy: Proxy? + navController: NavController ) = ExpandableRichTextViewer( content, canPreview, @@ -24,6 +22,5 @@ fun TranslatableRichTextViewer( tags, backgroundColor, accountViewModel, - navController, - proxy + navController ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt b/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt index fbff99b63..a4db5f033 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ServiceManager.kt @@ -2,6 +2,7 @@ package com.vitorpamplona.amethyst import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.LocalCache +import com.vitorpamplona.amethyst.service.HttpClient import com.vitorpamplona.amethyst.service.NostrAccountDataSource import com.vitorpamplona.amethyst.service.NostrChannelDataSource import com.vitorpamplona.amethyst.service.NostrChatroomListDataSource @@ -25,7 +26,7 @@ object ServiceManager { fun start() { val myAccount = account - + HttpClient.start(account) if (myAccount != null) { Client.connect(myAccount.activeRelays() ?: myAccount.convertLocalRelays()) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt new file mode 100644 index 000000000..cf627893d --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt @@ -0,0 +1,17 @@ +package com.vitorpamplona.amethyst.service + +import com.vitorpamplona.amethyst.model.Account +import okhttp3.OkHttpClient +import java.net.Proxy + +object HttpClient { + private var proxy: Proxy? = null + + fun start(account: Account?) { + this.proxy = account?.proxy + } + + fun getHttpClient(): OkHttpClient { + return OkHttpClient.Builder().proxy(proxy).build() + } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05Verifier.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05Verifier.kt index fd86dc1eb..e86a85633 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05Verifier.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/Nip05Verifier.kt @@ -9,13 +9,11 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import okhttp3.Call import okhttp3.Callback -import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response -import java.net.Proxy -class Nip05Verifier(proxy: Proxy?) { - val client = OkHttpClient.Builder().proxy(proxy).build() +class Nip05Verifier() { + val client = HttpClient.getHttpClient() fun assembleUrl(nip05address: String): String? { val parts = nip05address.trim().split("@") diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt index 26e68d205..78ea52018 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/lnurl/LightningAddressResolver.kt @@ -2,6 +2,7 @@ package com.vitorpamplona.amethyst.service.lnurl import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.vitorpamplona.amethyst.BuildConfig +import com.vitorpamplona.amethyst.service.HttpClient import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -10,15 +11,13 @@ import kotlinx.coroutines.withContext import nostr.postr.Bech32 import okhttp3.Call import okhttp3.Callback -import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response import java.math.BigDecimal -import java.net.Proxy import java.net.URLEncoder -class LightningAddressResolver(proxy: Proxy?) { - val client = OkHttpClient.Builder().proxy(proxy).build() +class LightningAddressResolver() { + val client = HttpClient.getHttpClient() fun assembleUrl(lnaddress: String): String? { val parts = lnaddress.split("@") diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt index ca8727c1d..9d409efa9 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageSaver.kt @@ -9,12 +9,12 @@ import android.os.Environment import android.provider.MediaStore import androidx.annotation.RequiresApi import com.vitorpamplona.amethyst.BuildConfig +import com.vitorpamplona.amethyst.service.HttpClient import okhttp3.* import okio.BufferedSource import okio.IOException import okio.sink import java.io.File -import java.net.Proxy object ImageSaver { /** @@ -27,10 +27,9 @@ object ImageSaver { url: String, context: Context, onSuccess: () -> Any?, - onError: (Throwable) -> Any?, - proxy: Proxy? + onError: (Throwable) -> Any? ) { - val client = OkHttpClient.Builder().proxy(proxy).build() + val client = HttpClient.getHttpClient() val request = Request.Builder() .header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}") diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt index 6ecddfeb0..b39570833 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/ImageUploader.kt @@ -4,12 +4,12 @@ import android.content.ContentResolver import android.net.Uri import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.vitorpamplona.amethyst.BuildConfig +import com.vitorpamplona.amethyst.service.HttpClient import okhttp3.* import okhttp3.MediaType.Companion.toMediaType import okio.BufferedSink import okio.source import java.io.IOException -import java.net.Proxy import java.util.* object ImageUploader { @@ -17,15 +17,14 @@ object ImageUploader { uri: Uri, contentResolver: ContentResolver, onSuccess: (String) -> Unit, - onError: (Throwable) -> Unit, - proxy: Proxy? + onError: (Throwable) -> Unit ) { val contentType = contentResolver.getType(uri) val category = contentType?.toMediaType()?.toString()?.split("/")?.get(0) ?: "image" val url = if (category == "image") "https://api.imgur.com/3/image" else "https://api.imgur.com/3/upload" - val client = OkHttpClient.Builder().proxy(proxy).build() + val client = HttpClient.getHttpClient() val requestBody: RequestBody = MultipartBody.Builder() .setType(MultipartBody.FORM) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt index 97ed777a1..8be28a491 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostViewModel.kt @@ -124,8 +124,7 @@ open class NewPostViewModel : ViewModel() { viewModelScope.launch { imageUploadingError.emit("Failed to upload the image / video") } - }, - account!!.proxy + } ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt index 7fd7a25af..e6a9bf2e0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewUserMetadataViewModel.kt @@ -180,8 +180,7 @@ class NewUserMetadataViewModel : ViewModel() { viewModelScope.launch { imageUploadingError.emit("Failed to upload the image / video") } - }, - account.proxy + } ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt index a757506bc..e8dbca2cf 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/SaveToGallery.kt @@ -18,7 +18,6 @@ import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberPermissionState import com.vitorpamplona.amethyst.R import kotlinx.coroutines.launch -import java.net.Proxy /** * A button to save the remote image to the gallery. @@ -28,7 +27,7 @@ import java.net.Proxy */ @OptIn(ExperimentalPermissionsApi::class) @Composable -fun SaveToGallery(url: String, proxy: Proxy?) { +fun SaveToGallery(url: String) { val localContext = LocalContext.current val scope = rememberCoroutineScope() @@ -55,8 +54,7 @@ fun SaveToGallery(url: String, proxy: Proxy?) { ) .show() } - }, - proxy = proxy + } ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt index 37c4689bf..3b62e83bd 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ExpandableRichTextViewer.kt @@ -27,7 +27,6 @@ import androidx.compose.ui.unit.dp import androidx.navigation.NavController import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel -import java.net.Proxy const val SHORT_TEXT_LENGTH = 350 @@ -39,8 +38,7 @@ fun ExpandableRichTextViewer( tags: List>?, backgroundColor: Color, accountViewModel: AccountViewModel, - navController: NavController, - proxy: Proxy? + navController: NavController ) { var showFullText by remember { mutableStateOf(false) } @@ -64,8 +62,7 @@ fun ExpandableRichTextViewer( tags, backgroundColor, accountViewModel, - navController, - proxy + navController ) if (content.length > whereToCut && !showFullText) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt index 13bb71069..06e38c773 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoiceRequest.kt @@ -138,7 +138,7 @@ fun InvoiceRequest( onClick = { val zapRequest = account.createZapRequestFor(toUserPubKeyHex, message, LnZapEvent.ZapType.PUBLIC) - LightningAddressResolver(account.proxy).lnAddressInvoice( + LightningAddressResolver().lnAddressInvoice( lud16, amount * 1000, message, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt index edc78229c..474a1fea7 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/RichTextViewer.kt @@ -43,7 +43,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.net.MalformedURLException -import java.net.Proxy import java.net.URISyntaxException import java.net.URL import java.util.regex.Pattern @@ -81,8 +80,7 @@ fun RichTextViewer( tags: List>?, backgroundColor: Color, accountViewModel: AccountViewModel, - navController: NavController, - proxy: Proxy? + navController: NavController ) { Column(modifier = modifier) { if (content.startsWith("# ") || @@ -161,9 +159,9 @@ fun RichTextViewer( if (isValidURL(word)) { val removedParamsFromUrl = word.split("?")[0].lowercase() if (imageExtensions.any { removedParamsFromUrl.endsWith(it) }) { - ZoomableImageView(word, imagesForPager, proxy) + ZoomableImageView(word, imagesForPager) } else if (videoExtensions.any { removedParamsFromUrl.endsWith(it) }) { - ZoomableImageView(word, imagesForPager, proxy) + ZoomableImageView(word, imagesForPager) } else { UrlPreview(word, "$word ") } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableImageView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableImageView.kt index 2fa6a5c14..e547da6bd 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableImageView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ZoomableImageView.kt @@ -46,11 +46,10 @@ import com.vitorpamplona.amethyst.ui.actions.LoadingAnimation import com.vitorpamplona.amethyst.ui.actions.SaveToGallery import net.engawapg.lib.zoomable.rememberZoomState import net.engawapg.lib.zoomable.zoomable -import java.net.Proxy @Composable @OptIn(ExperimentalFoundationApi::class) -fun ZoomableImageView(word: String, images: List = listOf(word), proxy: Proxy?) { +fun ZoomableImageView(word: String, images: List = listOf(word)) { val clipboardManager = LocalClipboardManager.current // store the dialog open or close state @@ -127,13 +126,13 @@ fun ZoomableImageView(word: String, images: List = listOf(word), proxy: } if (dialogOpen) { - ZoomableImageDialog(word, images, onDismiss = { dialogOpen = false }, proxy) + ZoomableImageDialog(word, images, onDismiss = { dialogOpen = false }) } } @OptIn(ExperimentalPagerApi::class) @Composable -fun ZoomableImageDialog(imageUrl: String, allImages: List = listOf(imageUrl), onDismiss: () -> Unit, proxy: Proxy?) { +fun ZoomableImageDialog(imageUrl: String, allImages: List = listOf(imageUrl), onDismiss: () -> Unit) { Dialog( onDismissRequest = onDismiss, properties = DialogProperties(usePlatformDefaultWidth = false) @@ -151,7 +150,7 @@ fun ZoomableImageDialog(imageUrl: String, allImages: List = listOf(image ) { CloseButton(onCancel = onDismiss) - SaveToGallery(url = allImages[pagerState.currentPage], proxy) + SaveToGallery(url = allImages[pagerState.currentPage]) } if (allImages.size > 1) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt index 6aa2e5cb5..bee998015 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt @@ -290,8 +290,7 @@ fun ChatroomMessageCompose( note.event?.tags(), backgroundBubbleColor, accountViewModel, - navController, - account.proxy + navController ) } else { TranslatableRichTextViewer( @@ -301,8 +300,7 @@ fun ChatroomMessageCompose( note.event?.tags(), backgroundBubbleColor, accountViewModel, - navController, - account.proxy + navController ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt index bb1342660..cebfe1fdd 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NIP05VerificationDisplay.kt @@ -35,11 +35,10 @@ import com.vitorpamplona.amethyst.service.Nip05Verifier import com.vitorpamplona.amethyst.ui.theme.Nip05 import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import java.net.Proxy import java.util.Date @Composable -fun nip05VerificationAsAState(user: UserMetadata, pubkeyHex: String, proxy: Proxy?): State { +fun nip05VerificationAsAState(user: UserMetadata, pubkeyHex: String): State { var nip05Verified = remember { mutableStateOf(null) } LaunchedEffect(key1 = user) { @@ -49,7 +48,7 @@ fun nip05VerificationAsAState(user: UserMetadata, pubkeyHex: String, proxy: Prox if ((user.nip05LastVerificationTime ?: 0) > (now - 60 * 60)) { // 1hour nip05Verified.value = user.nip05Verified } else { - Nip05Verifier(proxy).verifyNip05( + Nip05Verifier().verifyNip05( nip05, onSuccess = { // Marks user as verified @@ -78,18 +77,18 @@ fun nip05VerificationAsAState(user: UserMetadata, pubkeyHex: String, proxy: Prox } @Composable -fun ObserveDisplayNip05Status(baseNote: Note, columnModifier: Modifier = Modifier, proxy: Proxy?) { +fun ObserveDisplayNip05Status(baseNote: Note, columnModifier: Modifier = Modifier) { val noteState by baseNote.live().metadata.observeAsState() val note = noteState?.note ?: return val author = note.author if (author != null) { - ObserveDisplayNip05Status(author, columnModifier, proxy) + ObserveDisplayNip05Status(author, columnModifier) } } @Composable -fun ObserveDisplayNip05Status(baseUser: User, columnModifier: Modifier = Modifier, proxy: Proxy?) { +fun ObserveDisplayNip05Status(baseUser: User, columnModifier: Modifier = Modifier) { val userState by baseUser.live().metadata.observeAsState() val user = userState?.user ?: return @@ -108,7 +107,7 @@ fun ObserveDisplayNip05Status(baseUser: User, columnModifier: Modifier = Modifie ) } - val nip05Verified by nip05VerificationAsAState(user.info!!, user.pubkeyHex, proxy) + val nip05Verified by nip05VerificationAsAState(user.info!!, user.pubkeyHex) if (nip05Verified == null) { Icon( tint = Color.Yellow, @@ -152,12 +151,12 @@ fun ObserveDisplayNip05Status(baseUser: User, columnModifier: Modifier = Modifie } @Composable -fun DisplayNip05ProfileStatus(user: User, proxy: Proxy?) { +fun DisplayNip05ProfileStatus(user: User) { val uri = LocalUriHandler.current user.nip05()?.let { nip05 -> if (nip05.split("@").size == 2) { - val nip05Verified by nip05VerificationAsAState(user.info!!, user.pubkeyHex, proxy) + val nip05Verified by nip05VerificationAsAState(user.info!!, user.pubkeyHex) Row(verticalAlignment = Alignment.CenterVertically) { if (nip05Verified == null) { Icon( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index ccabb8348..8400d174b 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -353,7 +353,7 @@ fun NoteComposeInner( if (note.author != null && !makeItShort && !isQuotedNote) { Row(verticalAlignment = Alignment.CenterVertically) { - ObserveDisplayNip05Status(note.author!!, Modifier.weight(1f), account.proxy) + ObserveDisplayNip05Status(note.author!!, Modifier.weight(1f)) val baseReward = noteEvent.getReward() if (baseReward != null) { @@ -509,8 +509,7 @@ fun NoteComposeInner( noteEvent.tags(), backgroundColor, accountViewModel, - navController, - account.proxy + navController ) if (!makeItShort) { @@ -540,8 +539,7 @@ fun NoteComposeInner( noteEvent.tags(), backgroundColor, accountViewModel, - navController, - account.proxy + navController ) DisplayUncitedHashtags(noteEvent.hashtags(), eventContent, navController) @@ -553,8 +551,7 @@ fun NoteComposeInner( canPreview = canPreview && !makeItShort, backgroundColor, accountViewModel, - navController, - account.proxy + navController ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt index b95afb0d5..26e83cf91 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt @@ -37,7 +37,6 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import java.net.Proxy import java.util.* import kotlin.math.roundToInt @@ -47,8 +46,7 @@ fun PollNote( canPreview: Boolean, backgroundColor: Color, accountViewModel: AccountViewModel, - navController: NavController, - proxy: Proxy? + navController: NavController ) { val zapsState by baseNote.live().zaps.observeAsState() val zappedNote = zapsState?.note ?: return @@ -113,8 +111,7 @@ fun PollNote( pollViewModel.pollEvent?.tags(), backgroundColor, accountViewModel, - navController, - proxy + navController ) } } @@ -147,8 +144,7 @@ fun PollNote( pollViewModel.pollEvent?.tags(), backgroundColor, accountViewModel, - navController, - proxy + navController ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt index e161b2003..26d0448be 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ThreadFeedView.kt @@ -282,7 +282,7 @@ fun NoteMaster( } Row(verticalAlignment = Alignment.CenterVertically) { - ObserveDisplayNip05Status(baseNote, Modifier.weight(1f), account.proxy) + ObserveDisplayNip05Status(baseNote, Modifier.weight(1f)) val baseReward = noteEvent.getReward() if (baseReward != null) { @@ -362,8 +362,7 @@ fun NoteMaster( note.event?.tags(), MaterialTheme.colors.background, accountViewModel, - navController, - account.proxy + navController ) DisplayUncitedHashtags(noteEvent.hashtags(), eventContent, navController) @@ -374,8 +373,7 @@ fun NoteMaster( canPreview, backgroundColor, accountViewModel, - navController, - account.proxy + navController ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index 22fffb064..c88352b6c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -72,7 +72,7 @@ class AccountViewModel(private val account: Account) : ViewModel() { onProgress(0.10f) - LightningAddressResolver(account.proxy).lnAddressInvoice( + LightningAddressResolver().lnAddressInvoice( lud16, amount, message, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt index a1ac44714..0f26c18bc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ChatroomScreen.kt @@ -59,7 +59,6 @@ import com.vitorpamplona.amethyst.ui.note.UserPicture import com.vitorpamplona.amethyst.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.ui.screen.ChatroomFeedView import com.vitorpamplona.amethyst.ui.screen.NostrChatRoomFeedViewModel -import java.net.Proxy @Composable fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navController: NavController) { @@ -105,7 +104,7 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr Column(Modifier.fillMaxHeight()) { NostrChatroomDataSource.withUser?.let { - ChatroomHeader(it, account.userProfile(), navController = navController, account.proxy) + ChatroomHeader(it, account.userProfile(), navController = navController) } Column( @@ -207,7 +206,7 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr } @Composable -fun ChatroomHeader(baseUser: User, accountUser: User, navController: NavController, proxy: Proxy?) { +fun ChatroomHeader(baseUser: User, accountUser: User, navController: NavController) { Column( modifier = Modifier.clickable( onClick = { navController.navigate("User/${baseUser.pubkeyHex}") } @@ -227,7 +226,7 @@ fun ChatroomHeader(baseUser: User, accountUser: User, navController: NavControll } Row(verticalAlignment = Alignment.CenterVertically) { - ObserveDisplayNip05Status(baseUser, proxy = proxy) + ObserveDisplayNip05Status(baseUser) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index 46623a0ef..6c832ceac 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -1,7 +1,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn import android.content.Intent -import java.net.Proxy import android.net.Uri import androidx.compose.foundation.* import androidx.compose.foundation.gestures.scrollBy @@ -309,7 +308,7 @@ private fun ProfileHeader( val clipboardManager = LocalClipboardManager.current Box { - DrawBanner(baseUser, account.proxy) + DrawBanner(baseUser) Box( modifier = Modifier @@ -411,7 +410,7 @@ private fun ProfileHeader( } if (zoomImageDialogOpen) { - ZoomableImageDialog(baseUser.profilePicture()!!, onDismiss = { zoomImageDialogOpen = false }, proxy = account.proxy) + ZoomableImageDialog(baseUser.profilePicture()!!, onDismiss = { zoomImageDialogOpen = false }) } } @@ -515,7 +514,7 @@ private fun DrawAdditionalInfo(baseUser: User, account: Account, accountViewMode } } - DisplayNip05ProfileStatus(user, account.proxy) + DisplayNip05ProfileStatus(user) val website = user.info?.website if (!website.isNullOrEmpty()) { @@ -617,8 +616,7 @@ private fun DrawAdditionalInfo(baseUser: User, account: Account, accountViewMode tags = null, backgroundColor = MaterialTheme.colors.background, accountViewModel = accountViewModel, - navController = navController, - proxy = account.proxy + navController = navController ) } } @@ -688,7 +686,7 @@ fun BadgeThumb( @OptIn(ExperimentalFoundationApi::class) @Composable -private fun DrawBanner(baseUser: User, proxy: Proxy?) { +private fun DrawBanner(baseUser: User) { val userState by baseUser.live().metadata.observeAsState() val user = userState?.user ?: return @@ -714,7 +712,7 @@ private fun DrawBanner(baseUser: User, proxy: Proxy?) { ) if (zoomImageDialogOpen) { - ZoomableImageDialog(imageUrl = banner, onDismiss = { zoomImageDialogOpen = false }, proxy = proxy) + ZoomableImageDialog(imageUrl = banner, onDismiss = { zoomImageDialogOpen = false }) } } else { Image( diff --git a/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt b/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt index e30a5f41e..8100a3e9b 100644 --- a/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt +++ b/app/src/play/java/com/vitorpamplona/amethyst/ui/components/TranslatableRichTextViewer.kt @@ -35,7 +35,6 @@ import com.vitorpamplona.amethyst.service.lang.ResultOrError import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import java.net.Proxy import java.util.Locale @Composable @@ -46,8 +45,7 @@ fun TranslatableRichTextViewer( tags: List>?, backgroundColor: Color, accountViewModel: AccountViewModel, - navController: NavController, - proxy: Proxy? + navController: NavController ) { val translatedTextState = remember { mutableStateOf(ResultOrError(content, null, null, null)) @@ -89,8 +87,7 @@ fun TranslatableRichTextViewer( tags, backgroundColor, accountViewModel, - navController, - proxy + navController ) val target = translatedTextState.value.targetLang From 5d9d7ba16eec50964990e2f567cc219eefbeec13 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Wed, 26 Apr 2023 10:19:30 -0300 Subject: [PATCH 08/18] created getProxy function --- .../java/com/vitorpamplona/amethyst/service/HttpClient.kt | 4 ++++ .../java/com/vitorpamplona/amethyst/service/relays/Client.kt | 4 ++-- .../com/vitorpamplona/amethyst/service/relays/Constants.kt | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt index cf627893d..a711f2cab 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt @@ -14,4 +14,8 @@ object HttpClient { fun getHttpClient(): OkHttpClient { return OkHttpClient.Builder().proxy(proxy).build() } + + fun getProxy(): Proxy? { + return proxy + } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt index b1ef135a9..9604765b0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt @@ -1,5 +1,6 @@ package com.vitorpamplona.amethyst.service.relays +import com.vitorpamplona.amethyst.service.HttpClient import com.vitorpamplona.amethyst.service.model.Event import com.vitorpamplona.amethyst.service.model.EventInterface import kotlinx.coroutines.DelicateCoroutinesApi @@ -76,8 +77,7 @@ object Client : RelayPool.Listener { } } else { /** temporary connection */ - /** TODO: set the proxy for this temporary connection */ - Relay(relay, false, true, emptySet(), null).requestAndWatch() { + Relay(relay, false, true, emptySet(), HttpClient.getProxy()).requestAndWatch() { it.send(signedEvent) it.disconnect() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Constants.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Constants.kt index 9f5477687..d62179f8d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Constants.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Constants.kt @@ -1,6 +1,7 @@ package com.vitorpamplona.amethyst.service.relays import com.vitorpamplona.amethyst.model.RelaySetupInfo +import com.vitorpamplona.amethyst.service.HttpClient object Constants { val activeTypes = setOf(FeedType.FOLLOWS, FeedType.PRIVATE_DMS) @@ -10,8 +11,7 @@ object Constants { fun convertDefaultRelays(): Array { return defaultRelays.map { - /** TODO: set the proxy */ - Relay(it.url, it.read, it.write, it.feedTypes, null) + Relay(it.url, it.read, it.write, it.feedTypes, HttpClient.getProxy()) }.toTypedArray() } From 3217d5095b7f9f9793293369bdd83e99a57f9705 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Wed, 26 Apr 2023 11:54:04 -0300 Subject: [PATCH 09/18] created initProxy --- .../java/com/vitorpamplona/amethyst/LocalPreferences.kt | 5 ++--- .../java/com/vitorpamplona/amethyst/service/HttpClient.kt | 5 +++++ .../vitorpamplona/amethyst/ui/navigation/DrawerContent.kt | 5 ++--- .../amethyst/ui/screen/AccountStateViewModel.kt | 7 +++---- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 40b6d817e..1b443d4aa 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -8,6 +8,7 @@ import com.google.gson.reflect.TypeToken import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.RelaySetupInfo import com.vitorpamplona.amethyst.model.toByteArray +import com.vitorpamplona.amethyst.service.HttpClient import com.vitorpamplona.amethyst.service.model.ContactListEvent import com.vitorpamplona.amethyst.service.model.Event import com.vitorpamplona.amethyst.service.model.Event.Companion.getRefinedEvent @@ -17,8 +18,6 @@ import nostr.postr.Persona import nostr.postr.toHex import nostr.postr.toNpub import java.io.File -import java.net.InetSocketAddress -import java.net.Proxy import java.util.Locale // Release mode (!BuildConfig.DEBUG) always uses encrypted preferences @@ -256,7 +255,7 @@ object LocalPreferences { val hideDeleteRequestDialog = getBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, false) val hideBlockAlertDialog = getBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, false) val useProxy = getBoolean(PrefKeys.USE_PROXY, false) - var proxy = if (useProxy) Proxy(Proxy.Type.SOCKS, InetSocketAddress("127.0.0.1", 9050)) else null + val proxy = HttpClient.initProxy(useProxy, "127.0.0.1", 9050) val a = Account( Persona(privKey = privKey?.toByteArray(), pubKey = pubKey.toByteArray()), diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt index a711f2cab..79c9018ad 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt @@ -2,6 +2,7 @@ package com.vitorpamplona.amethyst.service import com.vitorpamplona.amethyst.model.Account import okhttp3.OkHttpClient +import java.net.InetSocketAddress import java.net.Proxy object HttpClient { @@ -18,4 +19,8 @@ object HttpClient { fun getProxy(): Proxy? { return proxy } + + fun initProxy(useProxy: Boolean, hostname: String, port: Int): Proxy? { + return if (useProxy) Proxy(Proxy.Type.SOCKS, InetSocketAddress(hostname, port)) else null + } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index 3126cc4ab..f328efbd3 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -49,13 +49,12 @@ import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.User +import com.vitorpamplona.amethyst.service.HttpClient import com.vitorpamplona.amethyst.ui.components.ResizeImage import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountBackupDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.launch -import java.net.InetSocketAddress -import java.net.Proxy @OptIn(ExperimentalMaterialApi::class) @Composable @@ -283,7 +282,7 @@ fun ListContent( onClick = { checked = !checked println("changed tor to $checked") - account.proxy = if (checked) Proxy(Proxy.Type.SOCKS, InetSocketAddress("127.0.0.1", 9050)) else null + account.proxy = HttpClient.initProxy(checked, "127.0.0.1", 9050) ServiceManager.pause() ServiceManager.start() } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt index d6872f808..79e306176 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt @@ -5,6 +5,7 @@ import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.toByteArray +import com.vitorpamplona.amethyst.service.HttpClient import com.vitorpamplona.amethyst.service.nip19.Nip19 import fr.acinq.secp256k1.Hex import kotlinx.coroutines.CoroutineScope @@ -18,8 +19,6 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import nostr.postr.Persona import nostr.postr.bechToBytes -import java.net.InetSocketAddress -import java.net.Proxy import java.util.regex.Pattern class AccountStateViewModel() : ViewModel() { @@ -45,7 +44,7 @@ class AccountStateViewModel() : ViewModel() { val pattern = Pattern.compile(".+@.+\\.[a-z]+") val parsed = Nip19.uriToRoute(key) val pubKeyParsed = parsed?.hex?.toByteArray() - var proxy = if (useProxy) Proxy(Proxy.Type.SOCKS, InetSocketAddress("127.0.0.1", 9050)) else null + val proxy = HttpClient.initProxy(useProxy, "127.0.0.1", 9050) val account = if (key.startsWith("nsec")) { @@ -70,7 +69,7 @@ class AccountStateViewModel() : ViewModel() { } fun newKey(useProxy: Boolean) { - var proxy = if (useProxy) Proxy(Proxy.Type.SOCKS, InetSocketAddress("127.0.0.1", 9050)) else null + var proxy = HttpClient.initProxy(useProxy, "127.0.0.1", 9050) val account = Account(Persona(), proxy = proxy) // saves to local preferences LocalPreferences.updatePrefsForLogin(account) From 77a1b2ba89c49ccd298d4e436ca09052bd6bd3af Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:41:36 -0300 Subject: [PATCH 10/18] show a dialog when disabling tor --- .../amethyst/ui/navigation/DrawerContent.kt | 53 +++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index f328efbd3..696faf20c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.AlertDialog import androidx.compose.material.Divider import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.Icon @@ -24,7 +25,9 @@ import androidx.compose.material.ModalBottomSheetState import androidx.compose.material.ScaffoldState import androidx.compose.material.Surface import androidx.compose.material.Text +import androidx.compose.material.TextButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf @@ -235,6 +238,7 @@ fun ListContent( val coroutineScope = rememberCoroutineScope() var backupDialogOpen by remember { mutableStateOf(false) } var checked by remember { mutableStateOf(account.proxy != null) } + val openDialog = remember { mutableStateOf(false) } Column(modifier = modifier.fillMaxHeight()) { if (accountUser != null) { @@ -280,11 +284,12 @@ fun ListContent( icon = R.drawable.ic_tor, tint = MaterialTheme.colors.onBackground, onClick = { - checked = !checked - println("changed tor to $checked") - account.proxy = HttpClient.initProxy(checked, "127.0.0.1", 9050) - ServiceManager.pause() - ServiceManager.start() + if (checked) { + openDialog.value = true + } else { + checked = true + enableTor(account, true, openDialog) + } } ) @@ -301,6 +306,44 @@ fun ListContent( if (backupDialogOpen) { AccountBackupDialog(account, onClose = { backupDialogOpen = false }) } + + if (openDialog.value) { + AlertDialog( + text = { Text(text = "Do you really want to disable tor?") }, + onDismissRequest = { }, + confirmButton = { + TextButton( + onClick = { + openDialog.value = false + checked = false + enableTor(account, false, openDialog) + } + ) { + Text(text = "Yes") + } + }, + dismissButton = { + TextButton( + onClick = { + openDialog.value = false + } + ) { + Text(text = "No") + } + } + ) + } +} + +private fun enableTor( + account: Account, + checked: Boolean, + openDialog: MutableState +) { + account.proxy = HttpClient.initProxy(checked, "127.0.0.1", 9050) + ServiceManager.pause() + ServiceManager.start() + openDialog.value = false } @Composable From 6285bfaae7a6c20bc4badfdf3ab29014c74ba064 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Fri, 28 Apr 2023 08:15:04 -0300 Subject: [PATCH 11/18] updated string.xml --- .../vitorpamplona/amethyst/ui/navigation/DrawerContent.kt | 8 ++++---- .../amethyst/ui/screen/loggedOff/LoginScreen.kt | 2 +- app/src/main/res/values/strings.xml | 6 ++++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index 696faf20c..f8bb405be 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -277,7 +277,7 @@ fun ListContent( onClick = { backupDialogOpen = true } ) - var textTorProxy = if (checked) "Disable" else "Enable" + var textTorProxy = if (checked) stringResource(R.string.disable) else stringResource(R.string.enable) IconRow( title = "$textTorProxy Tor", @@ -309,7 +309,7 @@ fun ListContent( if (openDialog.value) { AlertDialog( - text = { Text(text = "Do you really want to disable tor?") }, + text = { Text(text = stringResource(R.string.do_you_really_want_to_disable_tor)) }, onDismissRequest = { }, confirmButton = { TextButton( @@ -319,7 +319,7 @@ fun ListContent( enableTor(account, false, openDialog) } ) { - Text(text = "Yes") + Text(text = stringResource(R.string.yes)) } }, dismissButton = { @@ -328,7 +328,7 @@ fun ListContent( openDialog.value = false } ) { - Text(text = "No") + Text(text = stringResource(R.string.no)) } } ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt index 6533d1c90..ea229bbdc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt @@ -228,7 +228,7 @@ fun LoginPage( onCheckedChange = { useProxy.value = it } ) - Text("Enable Tor") + Text(stringResource(R.string.connect_via_tor)) } Spacer(modifier = Modifier.height(20.dp)) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f1878907d..17f760024 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -292,4 +292,10 @@ Create and Add Poll authors can\'t vote in their own polls. #zappoll + Connect via Tor + Do you really want to disable tor? + Disable + Enable + Yes + No From 20a65a0878909874dea327d514bd2eff5878b038 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Fri, 28 Apr 2023 11:21:06 -0300 Subject: [PATCH 12/18] check if orbot is installed --- app/src/main/AndroidManifest.xml | 4 +++- .../amethyst/ui/navigation/DrawerContent.kt | 4 ++-- .../ui/screen/loggedOff/LoginScreen.kt | 19 +++++++++++++------ app/src/main/res/values/strings.xml | 7 +++---- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3735c465f..0cad4951a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,9 @@ - + + + diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index f8bb405be..79f5d168f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -277,10 +277,10 @@ fun ListContent( onClick = { backupDialogOpen = true } ) - var textTorProxy = if (checked) stringResource(R.string.disable) else stringResource(R.string.enable) + val textTorProxy = if (checked) stringResource(R.string.disconnect_from_your_orbot_setup) else stringResource(R.string.connect_via_tor) IconRow( - title = "$textTorProxy Tor", + title = textTorProxy, icon = R.drawable.ic_tor, tint = MaterialTheme.colors.onBackground, onClick = { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt index ea229bbdc..d8b66015d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt @@ -1,5 +1,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedOff +import android.content.Context import androidx.compose.foundation.Image import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState @@ -222,13 +223,15 @@ fun LoginPage( } } - Row(verticalAlignment = Alignment.CenterVertically) { - Checkbox( - checked = useProxy.value, - onCheckedChange = { useProxy.value = it } - ) + if (isPackageInstalled(context, "org.torproject.android")) { + Row(verticalAlignment = Alignment.CenterVertically) { + Checkbox( + checked = useProxy.value, + onCheckedChange = { useProxy.value = it } + ) - Text(stringResource(R.string.connect_via_tor)) + Text(stringResource(R.string.connect_via_tor)) + } } Spacer(modifier = Modifier.height(20.dp)) @@ -290,3 +293,7 @@ fun LoginPage( ) } } + +fun isPackageInstalled(context: Context, target: String): Boolean { + return context.packageManager.getInstalledApplications(0).find { info -> info.packageName == target } != null +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 17f760024..e23e9f41b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -292,10 +292,9 @@ Create and Add Poll authors can\'t vote in their own polls. #zappoll - Connect via Tor - Do you really want to disable tor? - Disable - Enable + Connect through your Orbot setup + Do you really want to disconnect from your Orbot setup? Yes No + Disconnect from your Orbot setup From 264d6a40b3d7931266956bf2545dde571ce15a88 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Wed, 3 May 2023 09:00:14 -0300 Subject: [PATCH 13/18] increased the default timeout when using proxy --- .../com/vitorpamplona/amethyst/service/HttpClient.kt | 10 +++++++++- .../com/vitorpamplona/amethyst/service/relays/Relay.kt | 10 ++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt index 79c9018ad..bf2448ece 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/HttpClient.kt @@ -4,6 +4,7 @@ import com.vitorpamplona.amethyst.model.Account import okhttp3.OkHttpClient import java.net.InetSocketAddress import java.net.Proxy +import java.time.Duration object HttpClient { private var proxy: Proxy? = null @@ -13,7 +14,14 @@ object HttpClient { } fun getHttpClient(): OkHttpClient { - return OkHttpClient.Builder().proxy(proxy).build() + val seconds = if (proxy != null) 20L else 10L + val duration = Duration.ofSeconds(seconds) + return OkHttpClient.Builder() + .proxy(proxy) + .readTimeout(duration) + .connectTimeout(duration) + .writeTimeout(duration) + .build() } fun getProxy(): Proxy? { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt index 8408e985a..6fdbd3c0d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt @@ -11,6 +11,7 @@ import okhttp3.Response import okhttp3.WebSocket import okhttp3.WebSocketListener import java.net.Proxy +import java.time.Duration import java.util.Date enum class FeedType { @@ -24,12 +25,13 @@ class Relay( var activeTypes: Set = FeedType.values().toSet(), proxy: Proxy? ) { - init { - println("Tor: ${proxy != null} url: $url") - } - + val seconds = if (proxy != null) 20L else 10L + val duration = Duration.ofSeconds(seconds) private val httpClient = OkHttpClient.Builder() .proxy(proxy) + .readTimeout(duration) + .connectTimeout(duration) + .writeTimeout(duration) .followRedirects(true) .followSslRedirects(true) .build() From 9c30547bd7f439c918950cfc804ca3b9c743d52f Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Fri, 5 May 2023 06:34:14 -0300 Subject: [PATCH 14/18] fix build --- app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt | 2 +- .../java/com/vitorpamplona/amethyst/service/relays/Client.kt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index c02986264..841853286 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -20,9 +20,9 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import nostr.postr.Persona -import java.net.Proxy import nostr.postr.Utils import java.math.BigDecimal +import java.net.Proxy import java.util.Locale val DefaultChannels = setOf( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt index 44bed2098..3fb91722f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt @@ -109,7 +109,6 @@ object Client : RelayPool.Listener { if (onDone != null) { onDone() - } } } From 28521c1a60e6cebaf7574d0ff8bd188838a35f22 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Fri, 5 May 2023 08:25:48 -0300 Subject: [PATCH 15/18] add configuration screen when enabling tor in the drawer --- .../amethyst/ui/navigation/DrawerContent.kt | 27 +++-- .../ui/screen/loggedIn/ConnectOrbotDialog.kt | 105 ++++++++++++++++++ app/src/main/res/values/strings.xml | 10 ++ 3 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index 79f5d168f..d2828ef6f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -27,7 +27,6 @@ import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.material.TextButton import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf @@ -48,6 +47,7 @@ import androidx.navigation.NavController import androidx.navigation.NavHostController import coil.compose.AsyncImage import com.vitorpamplona.amethyst.BuildConfig +import com.vitorpamplona.amethyst.LocalPreferences import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.model.Account @@ -57,6 +57,7 @@ import com.vitorpamplona.amethyst.ui.components.ResizeImage import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountBackupDialog import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.screen.loggedIn.ConnectOrbotDialog import kotlinx.coroutines.launch @OptIn(ExperimentalMaterialApi::class) @@ -239,6 +240,7 @@ fun ListContent( var backupDialogOpen by remember { mutableStateOf(false) } var checked by remember { mutableStateOf(account.proxy != null) } val openDialog = remember { mutableStateOf(false) } + var conectOrbotDialogOpen by remember { mutableStateOf(false) } Column(modifier = modifier.fillMaxHeight()) { if (accountUser != null) { @@ -287,8 +289,7 @@ fun ListContent( if (checked) { openDialog.value = true } else { - checked = true - enableTor(account, true, openDialog) + conectOrbotDialogOpen = true } } ) @@ -307,6 +308,19 @@ fun ListContent( AccountBackupDialog(account, onClose = { backupDialogOpen = false }) } + if (conectOrbotDialogOpen) { + ConnectOrbotDialog( + account = account, + onClose = { conectOrbotDialogOpen = false }, + onPost = { + conectOrbotDialogOpen = false + openDialog.value = false + checked = true + enableTor(account, true) + } + ) + } + if (openDialog.value) { AlertDialog( text = { Text(text = stringResource(R.string.do_you_really_want_to_disable_tor)) }, @@ -316,7 +330,7 @@ fun ListContent( onClick = { openDialog.value = false checked = false - enableTor(account, false, openDialog) + enableTor(account, false) } ) { Text(text = stringResource(R.string.yes)) @@ -337,13 +351,12 @@ fun ListContent( private fun enableTor( account: Account, - checked: Boolean, - openDialog: MutableState + checked: Boolean ) { account.proxy = HttpClient.initProxy(checked, "127.0.0.1", 9050) + LocalPreferences.saveToEncryptedStorage(account) ServiceManager.pause() ServiceManager.start() - openDialog.value = false } @Composable diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt new file mode 100644 index 000000000..2e2655e0e --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt @@ -0,0 +1,105 @@ +package com.vitorpamplona.amethyst.ui.screen.loggedIn + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.MaterialTheme +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.KeyboardCapitalization +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import com.halilibo.richtext.markdown.Markdown +import com.halilibo.richtext.ui.RichTextStyle +import com.halilibo.richtext.ui.material.MaterialRichText +import com.halilibo.richtext.ui.resolveDefaults +import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.model.Account +import com.vitorpamplona.amethyst.ui.actions.CloseButton +import com.vitorpamplona.amethyst.ui.actions.PostButton + +@Composable +fun ConnectOrbotDialog(account: Account, onClose: () -> Unit, onPost: () -> Unit) { + var portNumber by remember { mutableStateOf("9050") } + + Dialog( + onDismissRequest = onClose, + properties = DialogProperties(usePlatformDefaultWidth = false) + ) { + Surface(modifier = Modifier.fillMaxSize()) { + Column( + modifier = Modifier + .padding(10.dp) + .background(MaterialTheme.colors.background) + .fillMaxSize() + ) { + Row( + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth() + ) { + CloseButton(onCancel = { + onClose() + }) + + PostButton( + onPost = { + onPost() + }, + isActive = true + ) + } + + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 30.dp) + ) { + MaterialRichText( + style = RichTextStyle().resolveDefaults() + ) { + Markdown( + content = stringResource(R.string.connect_through_your_orbot_setup_markdown) + ) + } + + Spacer(modifier = Modifier.height(10.dp)) + + OutlinedTextField( + value = portNumber, + onValueChange = { portNumber = it }, + keyboardOptions = KeyboardOptions.Default.copy( + capitalization = KeyboardCapitalization.None, + keyboardType = KeyboardType.Number + ), + label = { Text(text = stringResource(R.string.orbot_socks_port)) }, + placeholder = { + Text( + text = "9050", + color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f) + ) + } + ) + } + } + } + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a53d1cd45..07ee6bf1c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -358,5 +358,15 @@ Follow List All Follows Global + + ## Connect through your Orbot setup + \n\n1. Install [Orbot](https://play.google.com/store/apps/details?id=org.torproject.android) + \n2. Start Orbot + \n3. In Orbot check the Socks port. By default it uses the port 9050 + \n4. If necessary change the port + \n5. Configure the Socks port in this screen + \n6. Press the post button to use Orbot as a proxy + + Orbot Socks Port From a503a1b21877776dc81bad9af5eff041c349fb31 Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Mon, 8 May 2023 10:45:10 -0300 Subject: [PATCH 16/18] show orbot dialog at login --- .../amethyst/LocalPreferences.kt | 9 +++-- .../vitorpamplona/amethyst/model/Account.kt | 3 +- .../amethyst/ui/navigation/DrawerContent.kt | 16 +++++---- .../ui/screen/AccountStateViewModel.kt | 18 +++++----- .../ui/screen/loggedIn/ConnectOrbotDialog.kt | 33 +++++++++++++------ .../ui/screen/loggedOff/LoginScreen.kt | 26 ++++++++++++--- 6 files changed, 72 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 25522fbf7..624d1bb2e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -56,6 +56,7 @@ private object PrefKeys { const val HIDE_DELETE_REQUEST_DIALOG = "hide_delete_request_dialog" const val HIDE_BLOCK_ALERT_DIALOG = "hide_block_alert_dialog" const val USE_PROXY = "use_proxy" + const val PROXY_PORT = "proxy_port" val LAST_READ: (String) -> String = { route -> "last_read_route_$route" } } @@ -209,8 +210,8 @@ object LocalPreferences { putString(PrefKeys.LATEST_CONTACT_LIST, Event.gson.toJson(account.backupContactList)) putBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, account.hideDeleteRequestDialog) putBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, account.hideBlockAlertDialog) - println(account.proxy != null) putBoolean(PrefKeys.USE_PROXY, account.proxy != null) + putInt(PrefKeys.PROXY_PORT, account.proxyPort) }.apply() } @@ -279,7 +280,8 @@ object LocalPreferences { val hideDeleteRequestDialog = getBoolean(PrefKeys.HIDE_DELETE_REQUEST_DIALOG, false) val hideBlockAlertDialog = getBoolean(PrefKeys.HIDE_BLOCK_ALERT_DIALOG, false) val useProxy = getBoolean(PrefKeys.USE_PROXY, false) - val proxy = HttpClient.initProxy(useProxy, "127.0.0.1", 9050) + val proxyPort = getInt(PrefKeys.PROXY_PORT, 9050) + val proxy = HttpClient.initProxy(useProxy, "127.0.0.1", proxyPort) val a = Account( Persona(privKey = privKey?.toByteArray(), pubKey = pubKey.toByteArray()), @@ -298,7 +300,8 @@ object LocalPreferences { hideDeleteRequestDialog, hideBlockAlertDialog, latestContactList, - proxy + proxy, + proxyPort ) return a diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index 841853286..7444b899d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -60,7 +60,8 @@ class Account( var hideDeleteRequestDialog: Boolean = false, var hideBlockAlertDialog: Boolean = false, var backupContactList: ContactListEvent? = null, - var proxy: Proxy? + var proxy: Proxy?, + var proxyPort: Int ) { var transientHiddenUsers: Set = setOf() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt index d2828ef6f..7fc79e207 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/DrawerContent.kt @@ -27,6 +27,7 @@ import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.material.TextButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.mutableStateOf @@ -241,6 +242,7 @@ fun ListContent( var checked by remember { mutableStateOf(account.proxy != null) } val openDialog = remember { mutableStateOf(false) } var conectOrbotDialogOpen by remember { mutableStateOf(false) } + var proxyPort = remember { mutableStateOf(account.proxyPort.toString()) } Column(modifier = modifier.fillMaxHeight()) { if (accountUser != null) { @@ -310,14 +312,14 @@ fun ListContent( if (conectOrbotDialogOpen) { ConnectOrbotDialog( - account = account, onClose = { conectOrbotDialogOpen = false }, onPost = { conectOrbotDialogOpen = false openDialog.value = false checked = true - enableTor(account, true) - } + enableTor(account, true, proxyPort) + }, + proxyPort ) } @@ -330,7 +332,7 @@ fun ListContent( onClick = { openDialog.value = false checked = false - enableTor(account, false) + enableTor(account, false, proxyPort) } ) { Text(text = stringResource(R.string.yes)) @@ -351,9 +353,11 @@ fun ListContent( private fun enableTor( account: Account, - checked: Boolean + checked: Boolean, + portNumber: MutableState ) { - account.proxy = HttpClient.initProxy(checked, "127.0.0.1", 9050) + account.proxyPort = portNumber.value.toInt() + account.proxy = HttpClient.initProxy(checked, "127.0.0.1", account.proxyPort) LocalPreferences.saveToEncryptedStorage(account) ServiceManager.pause() ServiceManager.start() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt index 79e306176..7bee6e873 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/AccountStateViewModel.kt @@ -40,22 +40,22 @@ class AccountStateViewModel() : ViewModel() { } } - fun startUI(key: String, useProxy: Boolean) { + fun startUI(key: String, useProxy: Boolean, proxyPort: Int) { val pattern = Pattern.compile(".+@.+\\.[a-z]+") val parsed = Nip19.uriToRoute(key) val pubKeyParsed = parsed?.hex?.toByteArray() - val proxy = HttpClient.initProxy(useProxy, "127.0.0.1", 9050) + val proxy = HttpClient.initProxy(useProxy, "127.0.0.1", proxyPort) val account = if (key.startsWith("nsec")) { - Account(Persona(privKey = key.bechToBytes()), proxy = proxy) + Account(Persona(privKey = key.bechToBytes()), proxy = proxy, proxyPort = proxyPort) } else if (pubKeyParsed != null) { - Account(Persona(pubKey = pubKeyParsed), proxy = proxy) + Account(Persona(pubKey = pubKeyParsed), proxy = proxy, proxyPort = proxyPort) } else if (pattern.matcher(key).matches()) { // Evaluate NIP-5 - Account(Persona(), proxy = proxy) + Account(Persona(), proxy = proxy, proxyPort = proxyPort) } else { - Account(Persona(Hex.decode(key)), proxy = proxy) + Account(Persona(Hex.decode(key)), proxy = proxy, proxyPort = proxyPort) } LocalPreferences.updatePrefsForLogin(account) @@ -68,9 +68,9 @@ class AccountStateViewModel() : ViewModel() { tryLoginExistingAccount() } - fun newKey(useProxy: Boolean) { - var proxy = HttpClient.initProxy(useProxy, "127.0.0.1", 9050) - val account = Account(Persona(), proxy = proxy) + fun newKey(useProxy: Boolean, proxyPort: Int) { + val proxy = HttpClient.initProxy(useProxy, "127.0.0.1", proxyPort) + val account = Account(Persona(), proxy = proxy, proxyPort = proxyPort) // saves to local preferences LocalPreferences.updatePrefsForLogin(account) startUI(account) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt index 2e2655e0e..2bf827831 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt @@ -1,5 +1,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn +import android.widget.Toast import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -15,12 +16,11 @@ import androidx.compose.material.OutlinedTextField import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType @@ -32,14 +32,14 @@ import com.halilibo.richtext.ui.RichTextStyle import com.halilibo.richtext.ui.material.MaterialRichText import com.halilibo.richtext.ui.resolveDefaults import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.ui.actions.CloseButton import com.vitorpamplona.amethyst.ui.actions.PostButton +import kotlinx.coroutines.launch @Composable -fun ConnectOrbotDialog(account: Account, onClose: () -> Unit, onPost: () -> Unit) { - var portNumber by remember { mutableStateOf("9050") } - +fun ConnectOrbotDialog(onClose: () -> Unit, onPost: () -> Unit, portNumber: MutableState) { + val context = LocalContext.current + val scope = rememberCoroutineScope() Dialog( onDismissRequest = onClose, properties = DialogProperties(usePlatformDefaultWidth = false) @@ -62,6 +62,19 @@ fun ConnectOrbotDialog(account: Account, onClose: () -> Unit, onPost: () -> Unit PostButton( onPost = { + try { + Integer.parseInt(portNumber.value) + } catch (_: Exception) { + scope.launch { + Toast.makeText( + context, + "Invalid port number", + Toast.LENGTH_LONG + ).show() + } + return@PostButton + } + onPost() }, isActive = true @@ -84,8 +97,8 @@ fun ConnectOrbotDialog(account: Account, onClose: () -> Unit, onPost: () -> Unit Spacer(modifier = Modifier.height(10.dp)) OutlinedTextField( - value = portNumber, - onValueChange = { portNumber = it }, + value = portNumber.value, + onValueChange = { portNumber.value = it }, keyboardOptions = KeyboardOptions.Default.copy( capitalization = KeyboardCapitalization.None, keyboardType = KeyboardType.Number diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt index d8b66015d..450b14777 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt @@ -39,6 +39,7 @@ import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.qrcode.SimpleQrCodeScanner import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel +import com.vitorpamplona.amethyst.ui.screen.loggedIn.ConnectOrbotDialog import java.util.* @OptIn(ExperimentalComposeUiApi::class) @@ -57,6 +58,8 @@ fun LoginPage( mutableStateOf(false) } val useProxy = remember { mutableStateOf(false) } + val proxyPort = remember { mutableStateOf("9050") } + var connectOrbotDialogOpen by remember { mutableStateOf(false) } Column( modifier = Modifier @@ -160,7 +163,7 @@ fun LoginPage( keyboardActions = KeyboardActions( onGo = { try { - accountViewModel.startUI(key.value.text, useProxy.value) + accountViewModel.startUI(key.value.text, useProxy.value, proxyPort.value.toInt()) } catch (e: Exception) { errorMessage = context.getString(R.string.invalid_key) } @@ -227,11 +230,26 @@ fun LoginPage( Row(verticalAlignment = Alignment.CenterVertically) { Checkbox( checked = useProxy.value, - onCheckedChange = { useProxy.value = it } + onCheckedChange = { + if (it) { + connectOrbotDialogOpen = true + } + } ) Text(stringResource(R.string.connect_via_tor)) } + + if (connectOrbotDialogOpen) { + ConnectOrbotDialog( + onClose = { connectOrbotDialogOpen = false }, + onPost = { + connectOrbotDialogOpen = false + useProxy.value = true + }, + proxyPort + ) + } } Spacer(modifier = Modifier.height(20.dp)) @@ -250,7 +268,7 @@ fun LoginPage( if (acceptedTerms.value && key.value.text.isNotBlank()) { try { - accountViewModel.startUI(key.value.text, useProxy.value) + accountViewModel.startUI(key.value.text, useProxy.value, proxyPort.value.toInt()) } catch (e: Exception) { errorMessage = context.getString(R.string.invalid_key) } @@ -278,7 +296,7 @@ fun LoginPage( .fillMaxWidth(), onClick = { if (acceptedTerms.value) { - accountViewModel.newKey(useProxy.value) + accountViewModel.newKey(useProxy.value, proxyPort.value.toInt()) } else { termsAcceptanceIsRequired = context.getString(R.string.acceptance_of_terms_is_required) From 0d051117b289de255531a85464ba083eec16f8ad Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Mon, 8 May 2023 11:03:17 -0300 Subject: [PATCH 17/18] add toast message to strings.xml --- .../amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt | 4 +++- app/src/main/res/values/strings.xml | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt index 2bf827831..53c2ac84e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ConnectOrbotDialog.kt @@ -60,6 +60,8 @@ fun ConnectOrbotDialog(onClose: () -> Unit, onPost: () -> Unit, portNumber: Muta onClose() }) + val toastMessage = stringResource(R.string.invalid_port_number) + PostButton( onPost = { try { @@ -68,7 +70,7 @@ fun ConnectOrbotDialog(onClose: () -> Unit, onPost: () -> Unit, portNumber: Muta scope.launch { Toast.makeText( context, - "Invalid port number", + toastMessage, Toast.LENGTH_LONG ).show() } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 17dd6e0e1..a752dced1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -376,5 +376,6 @@ \n6. Press the post button to use Orbot as a proxy Orbot Socks Port + Invalid port number From ee4c54aa27df00313eacc0f96780619b90b862af Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Wed, 10 May 2023 14:47:46 -0300 Subject: [PATCH 18/18] use httpclient.getHttpClient --- .../amethyst/service/notifications/RegisterAccounts.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt index d3cb9d0c5..f3772e3e4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/notifications/RegisterAccounts.kt @@ -4,13 +4,13 @@ import android.util.Log import com.vitorpamplona.amethyst.AccountInfo import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.LocalPreferences +import com.vitorpamplona.amethyst.service.HttpClient import com.vitorpamplona.amethyst.service.model.RelayAuthEvent import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch import okhttp3.MediaType.Companion.toMediaType -import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody @@ -54,7 +54,7 @@ class RegisterAccounts( .post(body) .build() - val client = OkHttpClient.Builder().build() + val client = HttpClient.getHttpClient() client.newCall(request).execute() } catch (e: java.lang.Exception) {