diff --git a/app/src/main/java/com/m2049r/xmrwallet/MainActivity.java b/app/src/main/java/com/m2049r/xmrwallet/MainActivity.java index 9ce3c14..34e2e71 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/MainActivity.java +++ b/app/src/main/java/com/m2049r/xmrwallet/MainActivity.java @@ -93,7 +93,7 @@ public class MainActivity extends AppCompatActivity implements MoneroHandlerThre @Override public void onConnectionFail() { - Toast.makeText(this, R.string.connection_failed, Toast.LENGTH_SHORT).show(); + runOnUiThread(() -> Toast.makeText(getApplication(), R.string.connection_failed, Toast.LENGTH_SHORT).show()); } @Override @@ -105,6 +105,6 @@ public class MainActivity extends AppCompatActivity implements MoneroHandlerThre @Override public void onPasswordFail() { - Toast.makeText(this, R.string.bad_password, Toast.LENGTH_SHORT).show(); + runOnUiThread(() -> Toast.makeText(getApplication(), R.string.bad_password, Toast.LENGTH_SHORT).show()); } } \ No newline at end of file diff --git a/app/src/main/java/com/m2049r/xmrwallet/data/DefaultNodes.java b/app/src/main/java/com/m2049r/xmrwallet/data/DefaultNodes.java index 49aab3e..3fe1306 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/data/DefaultNodes.java +++ b/app/src/main/java/com/m2049r/xmrwallet/data/DefaultNodes.java @@ -32,7 +32,8 @@ public enum DefaultNodes { MONERUJO_ONION("monerujods7mbghwe6cobdr6ujih6c22zu5rl7zshmizz2udf7v7fsad.onion:18081/mainnet/monerujo.onion"), Criminales78("56wl7y2ebhamkkiza4b7il4mrzwtyvpdym7bm2bkg3jrei2je646k3qd.onion:18089/mainnet/Criminales78.onion"), xmrfail("mxcd4577fldb3ppzy7obmmhnu3tf57gbcbd4qhwr2kxyjj2qi3dnbfqd.onion:18081/mainnet/xmrfail.onion"), - boldsuck("6dsdenp6vjkvqzy4wzsnzn6wixkdzihx3khiumyzieauxuxslmcaeiad.onion:18081/mainnet/boldsuck.onion"); + boldsuck("6dsdenp6vjkvqzy4wzsnzn6wixkdzihx3khiumyzieauxuxslmcaeiad.onion:18081/mainnet/boldsuck.onion"), + SAMOURAI("446unwib5vc7pfbzflosy6m6vtyuhddnalr3hutyavwe4esfuu5g6ryd.onion:18089/mainnet/samourai.onion"); @Getter private final String uri; diff --git a/app/src/main/java/com/m2049r/xmrwallet/fragment/onboarding/OnboardingFragment.java b/app/src/main/java/com/m2049r/xmrwallet/fragment/onboarding/OnboardingFragment.java index e58fcc9..6588abd 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/fragment/onboarding/OnboardingFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/fragment/onboarding/OnboardingFragment.java @@ -51,6 +51,7 @@ public class OnboardingFragment extends Fragment { ImageView moreOptionsChevronImageView = view.findViewById(R.id.advanced_settings_chevron_imageview); moreOptionsDropdownTextView.setOnClickListener(view12 -> mViewModel.onMoreOptionsClicked()); + moreOptionsChevronImageView.setOnClickListener(view12 -> mViewModel.onMoreOptionsClicked()); createWalletButton.setOnClickListener(view1 -> { String walletPassword = walletPasswordEditText.getText().toString(); diff --git a/app/src/main/java/com/m2049r/xmrwallet/fragment/settings/SettingsFragment.java b/app/src/main/java/com/m2049r/xmrwallet/fragment/settings/SettingsFragment.java index 1be59df..32f681d 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/fragment/settings/SettingsFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/fragment/settings/SettingsFragment.java @@ -1,15 +1,20 @@ package com.m2049r.xmrwallet.fragment.settings; import android.os.Bundle; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.Patterns; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; +import android.widget.EditText; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.SwitchCompat; +import androidx.constraintlayout.widget.ConstraintLayout; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; @@ -25,6 +30,28 @@ import com.m2049r.xmrwallet.util.NightmodeHelper; public class SettingsFragment extends Fragment implements PasswordBottomSheetDialog.PasswordListener { private SettingsViewModel mViewModel; + TextWatcher proxyAddressListener = new TextWatcher() { + @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {} + @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {} + @Override public void afterTextChanged(Editable editable) { + if(mViewModel != null) { + mViewModel.setProxyAddress(editable.toString()); + mViewModel.updateProxy(); + } + } + }; + TextWatcher proxyPortListener = new TextWatcher() { + @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {} + @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {} + @Override public void afterTextChanged(Editable editable) { + if(mViewModel != null) { + mViewModel.setProxyPort(editable.toString()); + mViewModel.updateProxy(); + } + } + }; + private EditText walletProxyAddressEditText; + private EditText walletProxyPortEditText; @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @@ -39,6 +66,9 @@ public class SettingsFragment extends Fragment implements PasswordBottomSheetDia Button displaySeedButton = view.findViewById(R.id.display_seed_button); SwitchCompat nightModeSwitch = view.findViewById(R.id.day_night_switch); SwitchCompat torSwitch = view.findViewById(R.id.tor_switch); + ConstraintLayout proxySettingsLayout = view.findViewById(R.id.wallet_proxy_settings_layout); + walletProxyAddressEditText = view.findViewById(R.id.wallet_proxy_address_edittext); + walletProxyPortEditText = view.findViewById(R.id.wallet_proxy_port_edittext); nightModeSwitch.setChecked(NightmodeHelper.getPreferredNightmode() == DayNightMode.NIGHT); nightModeSwitch.setOnCheckedChangeListener((compoundButton, b) -> { @@ -49,14 +79,41 @@ public class SettingsFragment extends Fragment implements PasswordBottomSheetDia } }); - torSwitch.setChecked(PrefService.getInstance().getBoolean(Constants.PREF_USES_TOR, false)); + boolean usesProxy = PrefService.getInstance().getBoolean(Constants.PREF_USES_TOR, false); + String proxy = PrefService.getInstance().getString(Constants.PREF_PROXY, ""); + if(proxy.contains(":")) { + String proxyAddress = proxy.split(":")[0]; + String proxyPort = proxy.split(":")[1]; + initProxyStuff(proxyAddress, proxyPort); + } + torSwitch.setChecked(usesProxy); + if(usesProxy) { + proxySettingsLayout.setVisibility(View.VISIBLE); + } else { + proxySettingsLayout.setVisibility(View.GONE); + } + + addProxyTextListeners(); + torSwitch.setOnCheckedChangeListener((compoundButton, b) -> { PrefService.getInstance().edit().putBoolean(Constants.PREF_USES_TOR, b).apply(); + if(b) { + String proxyString = PrefService.getInstance().getString(Constants.PREF_PROXY, ""); + if(proxyString.contains(":")) { + removeProxyTextListeners(); - // TODO display "Advanced" settings mode when enabled to configure specific proxy address and port - String proxy = b ? "127.0.0.1:9050" : ""; - WalletManager.getInstance().setProxy(proxy); - WalletManager.getInstance().getWallet().setProxy(proxy); + String proxyAddress = proxyString.split(":")[0]; + String proxyPort = proxyString.split(":")[1]; + initProxyStuff(proxyAddress, proxyPort); + + addProxyTextListeners(); + } + proxySettingsLayout.setVisibility(View.VISIBLE); + } else { + proxySettingsLayout.setVisibility(View.GONE); + } + + mViewModel.updateProxy(); }); displaySeedButton.setOnClickListener(view1 -> { @@ -87,4 +144,24 @@ public class SettingsFragment extends Fragment implements PasswordBottomSheetDia public void onPasswordFail() { Toast.makeText(getContext(), R.string.bad_password, Toast.LENGTH_SHORT).show(); } + + private void initProxyStuff(String proxyAddress, String proxyPort) { + boolean validIpAddress = Patterns.IP_ADDRESS.matcher(proxyAddress).matches(); + if(validIpAddress) { + mViewModel.setProxyAddress(proxyAddress); + mViewModel.setProxyPort(proxyPort); + walletProxyAddressEditText.setText(proxyAddress); + walletProxyPortEditText.setText(proxyPort); + } + } + + private void removeProxyTextListeners() { + walletProxyAddressEditText.removeTextChangedListener(proxyAddressListener); + walletProxyPortEditText.removeTextChangedListener(proxyPortListener); + } + + private void addProxyTextListeners() { + walletProxyAddressEditText.addTextChangedListener(proxyAddressListener); + walletProxyPortEditText.addTextChangedListener(proxyPortListener); + } } \ No newline at end of file diff --git a/app/src/main/java/com/m2049r/xmrwallet/fragment/settings/SettingsViewModel.java b/app/src/main/java/com/m2049r/xmrwallet/fragment/settings/SettingsViewModel.java index e599710..729206a 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/fragment/settings/SettingsViewModel.java +++ b/app/src/main/java/com/m2049r/xmrwallet/fragment/settings/SettingsViewModel.java @@ -1,7 +1,48 @@ package com.m2049r.xmrwallet.fragment.settings; +import android.app.Activity; +import android.os.AsyncTask; +import android.util.Patterns; +import android.widget.Toast; + import androidx.lifecycle.ViewModel; +import com.m2049r.xmrwallet.R; +import com.m2049r.xmrwallet.model.WalletManager; +import com.m2049r.xmrwallet.service.PrefService; +import com.m2049r.xmrwallet.service.TxService; +import com.m2049r.xmrwallet.util.Constants; + public class SettingsViewModel extends ViewModel { + private String proxyAddress = ""; + private String proxyPort = ""; + public void updateProxy() { + AsyncTask.execute(() -> { + boolean usesProxy = PrefService.getInstance().getBoolean(Constants.PREF_USES_TOR, false); + if(!usesProxy) { + WalletManager.getInstance().setProxy(""); + WalletManager.getInstance().getWallet().setProxy(""); + return; + } + + if(proxyAddress.isEmpty()) proxyAddress = "127.0.0.1"; + if(proxyPort.isEmpty()) proxyPort = "9050"; + boolean validIpAddress = Patterns.IP_ADDRESS.matcher(proxyAddress).matches(); + if(validIpAddress) { + String proxy = proxyAddress + ":" + proxyPort; + PrefService.getInstance().edit().putString(Constants.PREF_PROXY, proxy).apply(); + WalletManager.getInstance().setProxy(proxy); + WalletManager.getInstance().getWallet().setProxy(proxy); + } + }); + } + + public void setProxyAddress(String address) { + this.proxyAddress = address; + } + + public void setProxyPort(String port) { + this.proxyPort = port; + } } \ No newline at end of file diff --git a/app/src/main/java/com/m2049r/xmrwallet/service/MoneroHandlerThread.java b/app/src/main/java/com/m2049r/xmrwallet/service/MoneroHandlerThread.java index 5613cd4..8be796d 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/service/MoneroHandlerThread.java +++ b/app/src/main/java/com/m2049r/xmrwallet/service/MoneroHandlerThread.java @@ -57,9 +57,9 @@ public class MoneroHandlerThread extends Thread implements WalletListener { public void run() { boolean usesTor = PrefService.getInstance().getBoolean(Constants.PREF_USES_TOR, false); if (usesTor) { - String proxy = "127.0.0.1:9050"; + String proxy = PrefService.getInstance().getString(Constants.PREF_PROXY, ""); WalletManager.getInstance().setProxy(proxy); - WalletManager.getInstance().setDaemon(Node.fromString(DefaultNodes.boldsuck.getUri())); + WalletManager.getInstance().setDaemon(Node.fromString(DefaultNodes.SAMOURAI.getUri())); wallet.setProxy(proxy); } else { WalletManager.getInstance().setDaemon(Node.fromString(DefaultNodes.XMRTW.getUri())); diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/Constants.java b/app/src/main/java/com/m2049r/xmrwallet/util/Constants.java index 496356a..c0f0679 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/util/Constants.java +++ b/app/src/main/java/com/m2049r/xmrwallet/util/Constants.java @@ -6,4 +6,5 @@ public class Constants { public static final String PREF_USES_PASSWORD = "pref_uses_password"; public static final String PREF_USES_TOR = "pref_uses_tor"; public static final String PREF_NIGHT_MODE = "pref_night_mode"; + public static final String PREF_PROXY = "pref_proxy"; } diff --git a/app/src/main/res/layout/fragment_onboarding.xml b/app/src/main/res/layout/fragment_onboarding.xml index af885ef..99d4b3a 100644 --- a/app/src/main/res/layout/fragment_onboarding.xml +++ b/app/src/main/res/layout/fragment_onboarding.xml @@ -41,6 +41,7 @@ android:layout_marginBottom="8dp" android:text="@string/more_options" android:textStyle="bold" + android:padding="4dp" app:layout_constraintBottom_toTopOf="@id/wallet_seed_edittext" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" @@ -51,6 +52,8 @@ android:id="@+id/advanced_settings_chevron_imageview" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:minWidth="24dp" + android:minHeight="24dp" android:src="@drawable/ic_keyboard_arrow_down" app:layout_constraintBottom_toBottomOf="@id/advanced_settings_dropdown_textview" app:layout_constraintStart_toEndOf="@id/advanced_settings_dropdown_textview" diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 1312824..e403b7d 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -109,4 +109,38 @@ android:layout_marginTop="16dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@id/network_settings_textview" /> + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8b00d36..31803d6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -76,4 +76,8 @@ Wallet Appearance Network + + 127.0.0.1 + 9050 + Invalid IP address