1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-07 11:35:59 +02:00

Compare commits

...

8 Commits

Author SHA1 Message Date
m2049r
84ce392192 Use EXOLIX as exchange (#964) 2024-11-01 19:51:28 +01:00
m2049r
4ebcda2b14 bump version 2024-10-17 13:39:16 +02:00
m2049r
c49351a8a9 own orbothelper & fix receiver visibility (#961) 2024-10-17 13:01:12 +02:00
m2049r
41e84f2e29 fix receiver visibility 2024-10-17 12:42:26 +02:00
m2049r
f08ddf93c8 bump version 2024-10-16 21:31:09 +02:00
m2049r
4bfc9c1bdd fix RECEIVER_NOT_EXPORTED crash 2024-10-16 20:18:12 +02:00
m2049r
1a13bdde91 add some default nodes 2024-10-07 23:42:23 +02:00
m2049r
3e56d5a54b update default nodes (#959) 2024-09-24 09:00:22 +02:00
202 changed files with 4309 additions and 4147 deletions

View File

@@ -8,8 +8,8 @@ android {
compileSdk 35 compileSdk 35
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 35 targetSdkVersion 35
versionCode 4006 versionCode 4102
versionName "4.0.6 'Sidekick'" versionName "4.1.2 'Exolix'"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild { externalNativeBuild {
cmake { cmake {
@@ -58,7 +58,7 @@ android {
applicationIdSuffix ".debug" applicationIdSuffix ".debug"
} }
applicationVariants.all { variant -> applicationVariants.all { variant ->
variant.buildConfigField "String", "ID_A", "\"" + getId("ID_A") + "\"" variant.buildConfigField "String", "ID_F", "\"" + getId("ID_F") + "\""
} }
} }

View File

@@ -99,7 +99,7 @@ public class GenerateReviewFragment extends Fragment {
private String walletPath; private String walletPath;
private String walletName; private String walletName;
private OnBackPressedCallback backPressedCallback = new OnBackPressedCallback(false) { private final OnBackPressedCallback backPressedCallback = new OnBackPressedCallback(false) {
@Override @Override
public void handleOnBackPressed() { public void handleOnBackPressed() {
// nothing // nothing
@@ -164,6 +164,7 @@ public class GenerateReviewFragment extends Fragment {
}); });
Bundle args = getArguments(); Bundle args = getArguments();
assert args != null;
type = args.getString(REQUEST_TYPE); type = args.getString(REQUEST_TYPE);
walletPath = args.getString(REQUEST_PATH); walletPath = args.getString(REQUEST_PATH);
localPassword = args.getString(REQUEST_PASSWORD); localPassword = args.getString(REQUEST_PASSWORD);

View File

@@ -22,13 +22,14 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import timber.log.Timber; import timber.log.Timber;
public class LockFragment extends Fragment { public class LockFragment extends Fragment {
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Timber.d("onCreateView"); Timber.d("onCreateView");
final FrameLayout frame = new FrameLayout(requireContext()); final FrameLayout frame = new FrameLayout(requireContext());
frame.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); frame.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

View File

@@ -40,6 +40,7 @@ import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction; import androidx.fragment.app.FragmentTransaction;
@@ -618,6 +619,7 @@ public class LoginActivity extends BaseActivity
try { try {
GenerateReviewFragment detailsFragment = (GenerateReviewFragment) GenerateReviewFragment detailsFragment = (GenerateReviewFragment)
getSupportFragmentManager().findFragmentById(R.id.fragment_container); getSupportFragmentManager().findFragmentById(R.id.fragment_container);
assert detailsFragment != null;
AlertDialog dialog = detailsFragment.createChangePasswordDialog(); AlertDialog dialog = detailsFragment.createChangePasswordDialog();
if (dialog != null) { if (dialog != null) {
Helper.showKeyboard(dialog); Helper.showKeyboard(dialog);
@@ -895,6 +897,7 @@ public class LoginActivity extends BaseActivity
try { try {
GenerateFragment genFragment = (GenerateFragment) GenerateFragment genFragment = (GenerateFragment)
getSupportFragmentManager().findFragmentById(R.id.fragment_container); getSupportFragmentManager().findFragmentById(R.id.fragment_container);
assert genFragment != null;
genFragment.walletGenerateError(); genFragment.walletGenerateError();
} catch (ClassCastException ex) { } catch (ClassCastException ex) {
Timber.e("walletGenerateError() but not in GenerateFragment"); Timber.e("walletGenerateError() but not in GenerateFragment");
@@ -1260,7 +1263,7 @@ public class LoginActivity extends BaseActivity
if (usbManager.hasPermission(device)) { if (usbManager.hasPermission(device)) {
connectLedger(usbManager, device); connectLedger(usbManager, device);
} else { } else {
registerReceiver(usbPermissionReceiver, new IntentFilter(ACTION_USB_PERMISSION)); ContextCompat.registerReceiver(this, usbPermissionReceiver, new IntentFilter(ACTION_USB_PERMISSION), ContextCompat.RECEIVER_EXPORTED);
usbManager.requestPermission(device, usbManager.requestPermission(device,
PendingIntent.getBroadcast(this, 0, PendingIntent.getBroadcast(this, 0,
new Intent(ACTION_USB_PERMISSION), new Intent(ACTION_USB_PERMISSION),
@@ -1365,7 +1368,7 @@ public class LoginActivity extends BaseActivity
private void registerDetachReceiver() { private void registerDetachReceiver() {
detachReceiver = new BroadcastReceiver() { detachReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) { if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(intent.getAction())) {
unregisterDetachReceiver(); unregisterDetachReceiver();
final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
Timber.i("Ledger detached!"); Timber.i("Ledger detached!");
@@ -1379,8 +1382,7 @@ public class LoginActivity extends BaseActivity
} }
} }
}; };
ContextCompat.registerReceiver(this, detachReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED), ContextCompat.RECEIVER_EXPORTED);
registerReceiver(detachReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED));
} }
public void onLedgerAction() { public void onLedgerAction() {
@@ -1409,6 +1411,7 @@ public class LoginActivity extends BaseActivity
Timber.d("onDeviceConnected: %s", connectedDeviceName); Timber.d("onDeviceConnected: %s", connectedDeviceName);
try { try {
SidekickConnectFragment f = (SidekickConnectFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_container); SidekickConnectFragment f = (SidekickConnectFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_container);
assert f != null;
f.allowClick(); f.allowClick();
} catch (ClassCastException ex) { } catch (ClassCastException ex) {
// ignore it // ignore it

View File

@@ -152,7 +152,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
showNetwork(); showNetwork();
} }
private OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) { private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) {
@Override @Override
public void handleOnBackPressed() { public void handleOnBackPressed() {
animateFAB(); animateFAB();
@@ -283,7 +283,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
} }
// remove information of non-existent wallet // remove information of non-existent wallet
Set<String> removedWallets = getActivity() Set<String> removedWallets = requireActivity()
.getSharedPreferences(KeyStoreHelper.SecurityConstants.WALLET_PASS_PREFS_NAME, Context.MODE_PRIVATE) .getSharedPreferences(KeyStoreHelper.SecurityConstants.WALLET_PASS_PREFS_NAME, Context.MODE_PRIVATE)
.getAll().keySet(); .getAll().keySet();
for (WalletManager.WalletInfo s : walletList) { for (WalletManager.WalletInfo s : walletList) {
@@ -445,7 +445,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
} }
private void setSubtext(String status) { private void setSubtext(String status) {
final Context ctx = getContext(); final Context ctx = requireContext();
final Spanned text = Html.fromHtml(ctx.getString(R.string.status, final Spanned text = Html.fromHtml(ctx.getString(R.string.status,
Integer.toHexString(ThemeHelper.getThemedColor(ctx, R.attr.positiveColor) & 0xFFFFFF), Integer.toHexString(ThemeHelper.getThemedColor(ctx, R.attr.positiveColor) & 0xFFFFFF),
Integer.toHexString(ThemeHelper.getThemedColor(ctx, android.R.attr.colorBackground) & 0xFFFFFF), Integer.toHexString(ThemeHelper.getThemedColor(ctx, android.R.attr.colorBackground) & 0xFFFFFF),

View File

@@ -32,6 +32,7 @@ import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.activity.OnBackPressedCallback; import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
@@ -68,7 +69,7 @@ public class NodeFragment extends Fragment
static private int NODES_TO_FIND = 10; static private int NODES_TO_FIND = 10;
static private NumberFormat FORMATTER = NumberFormat.getInstance(); static private final NumberFormat FORMATTER = NumberFormat.getInstance();
private SwipeRefreshLayout pullToRefresh; private SwipeRefreshLayout pullToRefresh;
private TextView tvPull; private TextView tvPull;
@@ -104,7 +105,7 @@ public class NodeFragment extends Fragment
} }
@Override @Override
public void onAttach(Context context) { public void onAttach(@NonNull Context context) {
super.onAttach(context); super.onAttach(context);
if (context instanceof Listener) { if (context instanceof Listener) {
this.activityCallback = (Listener) context; this.activityCallback = (Listener) context;
@@ -146,7 +147,7 @@ public class NodeFragment extends Fragment
} }
} }
private OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) { private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) {
@Override @Override
public void handleOnBackPressed() { public void handleOnBackPressed() {
Toast.makeText(requireActivity(), getString(R.string.node_refresh_wait), Toast.LENGTH_LONG).show(); Toast.makeText(requireActivity(), getString(R.string.node_refresh_wait), Toast.LENGTH_LONG).show();
@@ -210,7 +211,7 @@ public class NodeFragment extends Fragment
} }
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.node_menu, menu); inflater.inflate(R.menu.node_menu, menu);
super.onCreateOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater);
} }
@@ -289,8 +290,7 @@ public class NodeFragment extends Fragment
} else if (params[0] == SCAN) { } else if (params[0] == SCAN) {
// otherwise scan the network // otherwise scan the network
Timber.d("scanning"); Timber.d("scanning");
Set<NodeInfo> seedList = new HashSet<>(); Set<NodeInfo> seedList = new HashSet<>(nodeList);
seedList.addAll(nodeList);
nodeList.clear(); nodeList.clear();
Timber.d("seed %d", seedList.size()); Timber.d("seed %d", seedList.size());
Dispatcher d = new Dispatcher(info -> publishProgress(info)); Dispatcher d = new Dispatcher(info -> publishProgress(info));
@@ -455,7 +455,7 @@ public class NodeFragment extends Fragment
private void closeDialog() { private void closeDialog() {
if (editDialog == null) throw new IllegalStateException(); if (editDialog == null) throw new IllegalStateException();
Helper.hideKeyboardAlways(getActivity()); Helper.hideKeyboardAlways(requireActivity());
editDialog.dismiss(); editDialog.dismiss();
editDialog = null; editDialog = null;
NodeFragment.this.editDialog = null; NodeFragment.this.editDialog = null;

View File

@@ -32,12 +32,10 @@ import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
@@ -84,8 +82,6 @@ public class ReceiveFragment extends Fragment {
private ImageView ivQrCode; private ImageView ivQrCode;
private ImageView ivQrCodeFull; private ImageView ivQrCodeFull;
private EditText etDummy; private EditText etDummy;
private ImageButton bCopyAddress;
private MenuItem shareItem;
private Wallet wallet = null; private Wallet wallet = null;
private boolean isMyWallet = false; private boolean isMyWallet = false;
@@ -116,11 +112,10 @@ public class ReceiveFragment extends Fragment {
tvQrCode = view.findViewById(R.id.tvQrCode); tvQrCode = view.findViewById(R.id.tvQrCode);
ivQrCodeFull = view.findViewById(R.id.qrCodeFull); ivQrCodeFull = view.findViewById(R.id.qrCodeFull);
etDummy = view.findViewById(R.id.etDummy); etDummy = view.findViewById(R.id.etDummy);
bCopyAddress = view.findViewById(R.id.bCopyAddress);
etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
bCopyAddress.setOnClickListener(v -> copyAddress()); view.findViewById(R.id.bCopyAddress).setOnClickListener(v -> copyAddress());
evAmount.setOnNewAmountListener(xmr -> { evAmount.setOnNewAmountListener(xmr -> {
Timber.d("new amount = %s", xmr); Timber.d("new amount = %s", xmr);
@@ -211,8 +206,7 @@ public class ReceiveFragment extends Fragment {
inflater.inflate(R.menu.receive_menu, menu); inflater.inflate(R.menu.receive_menu, menu);
super.onCreateOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater);
shareItem = menu.findItem(R.id.menu_item_share); menu.findItem(R.id.menu_item_share).setOnMenuItemClickListener(item -> {
shareItem.setOnMenuItemClickListener(item -> {
if (shareRequested) return true; if (shareRequested) return true;
shareRequested = true; shareRequested = true;
if (!qrValid) { if (!qrValid) {
@@ -238,7 +232,7 @@ public class ReceiveFragment extends Fragment {
private boolean saveQrCode() { private boolean saveQrCode() {
if (!qrValid) throw new IllegalStateException("trying to save null qr code!"); if (!qrValid) throw new IllegalStateException("trying to save null qr code!");
File cachePath = new File(getActivity().getCacheDir(), "images"); File cachePath = new File(requireActivity().getCacheDir(), "images");
if (!cachePath.exists()) if (!cachePath.exists())
if (!cachePath.mkdirs()) throw new IllegalStateException("cannot create images folder"); if (!cachePath.mkdirs()) throw new IllegalStateException("cannot create images folder");
File png = new File(cachePath, "QR.png"); File png = new File(cachePath, "QR.png");
@@ -452,7 +446,7 @@ public class ReceiveFragment extends Fragment {
.withEndAction(resetSize).start(); .withEndAction(resetSize).start();
} }
subaddress = newSubaddress; subaddress = newSubaddress;
final Context context = getContext(); final Context context = requireContext();
Spanned label = Html.fromHtml(context.getString(R.string.receive_subaddress, Spanned label = Html.fromHtml(context.getString(R.string.receive_subaddress,
Integer.toHexString(ThemeHelper.getThemedColor(context, R.attr.positiveColor) & 0xFFFFFF), Integer.toHexString(ThemeHelper.getThemedColor(context, R.attr.positiveColor) & 0xFFFFFF),
Integer.toHexString(ThemeHelper.getThemedColor(context, android.R.attr.colorBackground) & 0xFFFFFF), Integer.toHexString(ThemeHelper.getThemedColor(context, android.R.attr.colorBackground) & 0xFFFFFF),

View File

@@ -24,6 +24,7 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import com.google.zxing.BarcodeFormat; import com.google.zxing.BarcodeFormat;
@@ -43,7 +44,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
private ZXingScannerView mScannerView; private ZXingScannerView mScannerView;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Timber.d("onCreateView"); Timber.d("onCreateView");
mScannerView = new ZXingScannerView(getActivity()); mScannerView = new ZXingScannerView(getActivity());
return mScannerView; return mScannerView;
@@ -85,7 +86,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
} }
@Override @Override
public void onAttach(Context context) { public void onAttach(@NonNull Context context) {
super.onAttach(context); super.onAttach(context);
if (context instanceof OnScannedListener) { if (context instanceof OnScannedListener) {
this.onScannedListener = (OnScannedListener) context; this.onScannedListener = (OnScannedListener) context;

View File

@@ -5,6 +5,7 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.StyleRes; import androidx.annotation.StyleRes;
import androidx.preference.ListPreference; import androidx.preference.ListPreference;
import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceFragmentCompat;
@@ -60,7 +61,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
private SettingsFragment.Listener activity; private SettingsFragment.Listener activity;
@Override @Override
public void onAttach(Context context) { public void onAttach(@NonNull Context context) {
super.onAttach(context); super.onAttach(context);
if (context instanceof SettingsFragment.Listener) { if (context instanceof SettingsFragment.Listener) {
activity = (SettingsFragment.Listener) context; activity = (SettingsFragment.Listener) context;

View File

@@ -20,6 +20,7 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@@ -29,6 +30,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
@@ -73,6 +75,8 @@ public class SidekickConnectFragment extends Fragment
@Override @Override
public void onPause() { public void onPause() {
Timber.d("onPause()"); Timber.d("onPause()");
if (ActivityCompat.checkSelfPermission(requireContext(), android.Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED)
throw new IllegalStateException("Bluetooth permission not granted");
if (bluetoothAdapter.isDiscovering()) { if (bluetoothAdapter.isDiscovering()) {
bluetoothAdapter.cancelDiscovery(); bluetoothAdapter.cancelDiscovery();
} }
@@ -112,6 +116,8 @@ public class SidekickConnectFragment extends Fragment
private void populateList() { private void populateList() {
List<BluetoothInfo> items = new ArrayList<>(); List<BluetoothInfo> items = new ArrayList<>();
if (ActivityCompat.checkSelfPermission(requireContext(), android.Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED)
throw new IllegalStateException("Bluetooth permission not granted");
for (BluetoothDevice device : bluetoothAdapter.getBondedDevices()) { for (BluetoothDevice device : bluetoothAdapter.getBondedDevices()) {
final int deviceCLass = device.getBluetoothClass().getDeviceClass(); final int deviceCLass = device.getBluetoothClass().getDeviceClass();
switch (deviceCLass) { switch (deviceCLass) {
@@ -152,6 +158,8 @@ public class SidekickConnectFragment extends Fragment
// Make sure we're not doing discovery anymore // Make sure we're not doing discovery anymore
if (bluetoothAdapter != null) { if (bluetoothAdapter != null) {
if (ActivityCompat.checkSelfPermission(requireContext(), android.Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED)
throw new IllegalStateException("Bluetooth permission not granted");
bluetoothAdapter.cancelDiscovery(); bluetoothAdapter.cancelDiscovery();
} }
} }
@@ -159,6 +167,8 @@ public class SidekickConnectFragment extends Fragment
@Override @Override
public void onInteraction(final View view, final BluetoothInfo item) { public void onInteraction(final View view, final BluetoothInfo item) {
Timber.d("onInteraction %s", item); Timber.d("onInteraction %s", item);
if (ActivityCompat.checkSelfPermission(requireContext(), android.Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED)
throw new IllegalStateException("Bluetooth permission not granted");
bluetoothAdapter.cancelDiscovery(); bluetoothAdapter.cancelDiscovery();
final BluetoothFragment btFragment = (BluetoothFragment) getChildFragmentManager().findFragmentById(R.id.bt_fragment); final BluetoothFragment btFragment = (BluetoothFragment) getChildFragmentManager().findFragmentById(R.id.bt_fragment);

View File

@@ -226,7 +226,7 @@ public class SubaddressFragment extends Fragment implements SubaddressInfoAdapte
// Callbacks from SubaddressInfoAdapter // Callbacks from SubaddressInfoAdapter
@Override @Override
public void onInteraction(final View view, final Subaddress subaddress) { public void onInteraction(final View view, @NonNull final Subaddress subaddress) {
if (managerMode) if (managerMode)
activityCallback.showSubaddress(view, subaddress.getAddressIndex()); activityCallback.showSubaddress(view, subaddress.getAddressIndex());
else else

View File

@@ -52,7 +52,6 @@ public class SubaddressInfoFragment extends Fragment
private Subaddress subaddress; private Subaddress subaddress;
private TextInputLayout etName; private TextInputLayout etName;
private TextView tvAddress;
private TextView tvTxLabel; private TextView tvTxLabel;
@Override @Override
@@ -61,7 +60,6 @@ public class SubaddressInfoFragment extends Fragment
View view = inflater.inflate(R.layout.fragment_subaddressinfo, container, false); View view = inflater.inflate(R.layout.fragment_subaddressinfo, container, false);
etName = view.findViewById(R.id.etName); etName = view.findViewById(R.id.etName);
tvAddress = view.findViewById(R.id.tvAddress);
tvTxLabel = view.findViewById(R.id.tvTxLabel); tvTxLabel = view.findViewById(R.id.tvTxLabel);
final RecyclerView list = view.findViewById(R.id.list); final RecyclerView list = view.findViewById(R.id.list);
@@ -71,11 +69,13 @@ public class SubaddressInfoFragment extends Fragment
final Wallet wallet = activityCallback.getWallet(); final Wallet wallet = activityCallback.getWallet();
Bundle b = getArguments(); Bundle b = getArguments();
assert b != null;
final int subaddressIndex = b.getInt("subaddressIndex"); final int subaddressIndex = b.getInt("subaddressIndex");
subaddress = wallet.getSubaddressObject(subaddressIndex); subaddress = wallet.getSubaddressObject(subaddressIndex);
etName.getEditText().setText(subaddress.getDisplayLabel()); etName.getEditText().setText(subaddress.getDisplayLabel());
tvAddress.setText(getContext().getString(R.string.subbaddress_info_subtitle, final TextView tvAddress = view.findViewById(R.id.tvAddress);
tvAddress.setText(requireContext().getString(R.string.subbaddress_info_subtitle,
subaddress.getAddressIndex(), subaddress.getAddress())); subaddress.getAddressIndex(), subaddress.getAddress()));
etName.getEditText().setOnFocusChangeListener((v, hasFocus) -> { etName.getEditText().setOnFocusChangeListener((v, hasFocus) -> {

View File

@@ -20,7 +20,6 @@ import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Paint; import android.graphics.Paint;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.text.Html; import android.text.Html;
import android.text.InputType; import android.text.InputType;
@@ -34,6 +33,7 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.transition.Transition; import androidx.transition.Transition;
@@ -44,6 +44,8 @@ import com.m2049r.xmrwallet.data.UserNotes;
import com.m2049r.xmrwallet.model.TransactionInfo; import com.m2049r.xmrwallet.model.TransactionInfo;
import com.m2049r.xmrwallet.model.Transfer; import com.m2049r.xmrwallet.model.Transfer;
import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.service.shift.ShiftService;
import com.m2049r.xmrwallet.service.shift.api.ShiftApi;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.ThemeHelper; import com.m2049r.xmrwallet.util.ThemeHelper;
import com.m2049r.xmrwallet.widget.Toolbar; import com.m2049r.xmrwallet.widget.Toolbar;
@@ -61,6 +63,7 @@ public class TxFragment extends Fragment {
static public final String ARG_INFO = "info"; static public final String ARG_INFO = "info";
@SuppressLint("SimpleDateFormat")
private final SimpleDateFormat TS_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); private final SimpleDateFormat TS_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
public TxFragment() { public TxFragment() {
@@ -106,6 +109,7 @@ public class TxFragment extends Fragment {
tvTxAmountBtc = view.findViewById(R.id.tvTxAmountBtc); tvTxAmountBtc = view.findViewById(R.id.tvTxAmountBtc);
tvXmrToSupport = view.findViewById(R.id.tvXmrToSupport); tvXmrToSupport = view.findViewById(R.id.tvXmrToSupport);
tvXmrToKeyLabel = view.findViewById(R.id.tvXmrToKeyLabel); tvXmrToKeyLabel = view.findViewById(R.id.tvXmrToKeyLabel);
tvXmrToLogo = view.findViewById(R.id.tvXmrToLogo); tvXmrToLogo = view.findViewById(R.id.tvXmrToLogo);
tvAccount = view.findViewById(R.id.tvAccount); tvAccount = view.findViewById(R.id.tvAccount);
@@ -127,18 +131,20 @@ public class TxFragment extends Fragment {
tvWarning = view.findViewById(R.id.tvWarning); tvWarning = view.findViewById(R.id.tvWarning);
tvTxXmrToKey.setOnClickListener(v -> { tvTxXmrToKey.setOnClickListener(v -> {
Helper.clipBoardCopy(getActivity(), getString(R.string.label_copy_xmrtokey), tvTxXmrToKey.getText().toString()); Helper.clipBoardCopy(requireActivity(), getString(R.string.label_copy_xmrtokey), tvTxXmrToKey.getText().toString());
Toast.makeText(getActivity(), getString(R.string.message_copy_xmrtokey), Toast.LENGTH_SHORT).show(); Toast.makeText(getActivity(), getString(R.string.message_copy_xmrtokey), Toast.LENGTH_SHORT).show();
}); });
info = getArguments().getParcelable(ARG_INFO); final Bundle args = getArguments();
assert args != null;
info = args.getParcelable(ARG_INFO);
show(); show();
return view; return view;
} }
void shareTxInfo() { void shareTxInfo() {
if (this.info == null) return; if (this.info == null) return;
StringBuffer sb = new StringBuffer(); StringBuilder sb = new StringBuilder();
sb.append(getString(R.string.tx_timestamp)).append(":\n"); sb.append(getString(R.string.tx_timestamp)).append(":\n");
sb.append(TS_FORMATTER.format(new Date(info.timestamp * 1000))).append("\n\n"); sb.append(TS_FORMATTER.format(new Date(info.timestamp * 1000))).append("\n\n");
@@ -216,7 +222,7 @@ public class TxFragment extends Fragment {
private void showSubaddressLabel() { private void showSubaddressLabel() {
final Subaddress subaddress = activityCallback.getWalletSubaddress(info.accountIndex, info.addressIndex); final Subaddress subaddress = activityCallback.getWalletSubaddress(info.accountIndex, info.addressIndex);
final Context ctx = getContext(); final Context ctx = requireContext();
Spanned label = Html.fromHtml(ctx.getString(R.string.tx_account_formatted, Spanned label = Html.fromHtml(ctx.getString(R.string.tx_account_formatted,
info.accountIndex, info.addressIndex, info.accountIndex, info.addressIndex,
Integer.toHexString(ThemeHelper.getThemedColor(ctx, R.attr.positiveColor) & 0xFFFFFF), Integer.toHexString(ThemeHelper.getThemedColor(ctx, R.attr.positiveColor) & 0xFFFFFF),
@@ -264,16 +270,17 @@ public class TxFragment extends Fragment {
tvTxFee.setVisibility(View.GONE); tvTxFee.setVisibility(View.GONE);
} }
final Context ctx = requireContext();
if (info.isFailed) { if (info.isFailed) {
tvTxAmount.setText(getString(R.string.tx_list_amount_failed, Wallet.getDisplayAmount(info.amount))); tvTxAmount.setText(getString(R.string.tx_list_amount_failed, Wallet.getDisplayAmount(info.amount)));
tvTxFee.setText(getString(R.string.tx_list_failed_text)); tvTxFee.setText(getString(R.string.tx_list_failed_text));
setTxColour(ThemeHelper.getThemedColor(getContext(), R.attr.neutralColor)); setTxColour(ThemeHelper.getThemedColor(ctx, R.attr.neutralColor));
} else if (info.isPending) { } else if (info.isPending) {
setTxColour(ThemeHelper.getThemedColor(getContext(), R.attr.neutralColor)); setTxColour(ThemeHelper.getThemedColor(ctx, R.attr.neutralColor));
} else if (info.direction == TransactionInfo.Direction.Direction_In) { } else if (info.direction == TransactionInfo.Direction.Direction_In) {
setTxColour(ThemeHelper.getThemedColor(getContext(), R.attr.positiveColor)); setTxColour(ThemeHelper.getThemedColor(ctx, R.attr.positiveColor));
} else { } else {
setTxColour(ThemeHelper.getThemedColor(getContext(), R.attr.negativeColor)); setTxColour(ThemeHelper.getThemedColor(ctx, R.attr.negativeColor));
} }
Set<String> destinations = new HashSet<>(); Set<String> destinations = new HashSet<>();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@@ -328,31 +335,29 @@ public class TxFragment extends Fragment {
void showBtcInfo() { void showBtcInfo() {
if (userNotes.xmrtoKey != null) { if (userNotes.xmrtoKey != null) {
cvXmrTo.setVisibility(View.VISIBLE); cvXmrTo.setVisibility(View.VISIBLE);
String key = userNotes.xmrtoKey;
if ("xmrto".equals(userNotes.xmrtoTag)) { // legacy xmr.to service :( ShiftService service = ShiftService.findWithTag(userNotes.xmrtoTag);
key = "xmrto-" + key; tvXmrToKeyLabel.setText(getString(R.string.label_send_btc_xmrto_key_lb, service.getLabel()));
} if (service.getIconId() == 0)
tvTxXmrToKey.setText(key); tvXmrToLogo.setVisibility(View.GONE);
else
tvXmrToLogo.setImageResource(service.getLogoId());
tvTxXmrToKey.setText(userNotes.xmrtoKey);
tvDestinationBtc.setText(userNotes.xmrtoDestination); tvDestinationBtc.setText(userNotes.xmrtoDestination);
tvTxAmountBtc.setText(userNotes.xmrtoAmount + " " + userNotes.xmrtoCurrency); tvTxAmountBtc.setText(userNotes.xmrtoAmount + " " + userNotes.xmrtoCurrency);
switch (userNotes.xmrtoTag) {
case "xmrto": ShiftApi shiftApi = service.getShiftApi();
tvXmrToSupport.setVisibility(View.GONE); if (shiftApi != null) {
tvXmrToKeyLabel.setVisibility(View.INVISIBLE); tvXmrToSupport.setText(getString(R.string.label_send_btc_xmrto_info, service.getLabel()));
tvXmrToLogo.setImageResource(R.drawable.ic_xmrto_logo); tvXmrToSupport.setPaintFlags(tvXmrToSupport.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
break; tvXmrToSupport.setOnClickListener(v -> {
case "side": // defaults in layout - just add underline startActivity(new Intent(Intent.ACTION_VIEW, shiftApi.getQueryOrderUri(userNotes.xmrtoKey)));
tvXmrToSupport.setPaintFlags(tvXmrToSupport.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); });
tvXmrToSupport.setOnClickListener(v -> { } else {
Uri uri = Uri.parse("https://sideshift.ai/orders/" + userNotes.xmrtoKey); tvXmrToSupport.setVisibility(View.GONE);
Intent intent = new Intent(Intent.ACTION_VIEW, uri); tvXmrToKeyLabel.setVisibility(View.INVISIBLE);
startActivity(intent);
});
break;
default:
tvXmrToSupport.setVisibility(View.GONE);
tvXmrToKeyLabel.setVisibility(View.INVISIBLE);
tvXmrToLogo.setVisibility(View.GONE);
} }
} else { } else {
cvXmrTo.setVisibility(View.GONE); cvXmrTo.setVisibility(View.GONE);
@@ -369,7 +374,7 @@ public class TxFragment extends Fragment {
} }
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.tx_info_menu, menu); inflater.inflate(R.menu.tx_info_menu, menu);
super.onCreateOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater);
} }
@@ -397,7 +402,7 @@ public class TxFragment extends Fragment {
} }
@Override @Override
public void onAttach(Context context) { public void onAttach(@NonNull Context context) {
super.onAttach(context); super.onAttach(context);
if (context instanceof TxFragment.Listener) { if (context instanceof TxFragment.Listener) {
this.activityCallback = (TxFragment.Listener) context; this.activityCallback = (TxFragment.Listener) context;

View File

@@ -38,7 +38,6 @@ import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.core.view.GravityCompat; import androidx.core.view.GravityCompat;
@@ -348,7 +347,10 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
} }
Bundle extras = getIntent().getExtras(); Bundle extras = getIntent().getExtras();
if (extras == null) finish(); // we need extras! if (extras == null) {
finish(); // we need extras!
return;
}
String walletId = extras.getString(REQUEST_ID); String walletId = extras.getString(REQUEST_ID);
requestStreetMode = extras.getBoolean(REQUEST_STREETMODE); requestStreetMode = extras.getBoolean(REQUEST_STREETMODE);
@@ -1179,7 +1181,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
} }
@Override @Override
public void onSubaddressSelected(@Nullable final Subaddress subaddress) { public void onSubaddressSelected(@NonNull final Subaddress subaddress) {
selectedSubaddressIndex = subaddress.getAddressIndex(); selectedSubaddressIndex = subaddress.getAddressIndex();
getOnBackPressedDispatcher().onBackPressed(); getOnBackPressedDispatcher().onBackPressed();
} }

View File

@@ -112,7 +112,7 @@ public class WalletFragment extends Fragment
flExchange = view.findViewById(R.id.flExchange); flExchange = view.findViewById(R.id.flExchange);
((ProgressBar) view.findViewById(R.id.pbExchange)).getIndeterminateDrawable(). ((ProgressBar) view.findViewById(R.id.pbExchange)).getIndeterminateDrawable().
setColorFilter( setColorFilter(
ThemeHelper.getThemedColor(getContext(), com.google.android.material.R.attr.colorPrimaryVariant), ThemeHelper.getThemedColor(requireContext(), com.google.android.material.R.attr.colorPrimaryVariant),
android.graphics.PorterDuff.Mode.MULTIPLY); android.graphics.PorterDuff.Mode.MULTIPLY);
tvProgress = view.findViewById(R.id.tvProgress); tvProgress = view.findViewById(R.id.tvProgress);

View File

@@ -23,7 +23,6 @@ import android.os.Build;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.m2049r.xmrwallet.BuildConfig;
import com.m2049r.xmrwallet.model.NetworkType; import com.m2049r.xmrwallet.model.NetworkType;
import com.m2049r.xmrwallet.util.LocaleHelper; import com.m2049r.xmrwallet.util.LocaleHelper;
import com.m2049r.xmrwallet.util.NetCipherHelper; import com.m2049r.xmrwallet.util.NetCipherHelper;

View File

@@ -24,43 +24,38 @@ import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import lombok.Getter;
import lombok.ToString; import lombok.ToString;
import timber.log.Timber; import timber.log.Timber;
@Getter
@ToString @ToString
public class BarcodeData { public class BarcodeData {
public enum Security { public enum Security {
NORMAL, NORMAL,
OA_NO_DNSSEC, OA_NO_DNSSEC,
OA_DNSSEC OA_DNSSEC
} }
final public Crypto asset; final private Set<Crypto> possibleAssets = new HashSet<>();
final public List<Crypto> ambiguousAssets; private String address = null;
final public String address; private String addressName = null;
final public String addressName; private String amount = null;
final public String amount; private String description = null;
final public String description; private Security security = null;
final public Security security;
public BarcodeData(List<Crypto> assets, String address) { public BarcodeData(List<Crypto> assets, String address) {
if (assets.isEmpty()) if (assets.isEmpty())
throw new IllegalArgumentException("no assets specified"); throw new IllegalArgumentException("no assets specified");
this.addressName = null; security = Security.NORMAL;
this.description = null;
this.amount = null;
this.security = Security.NORMAL;
this.address = address; this.address = address;
if (assets.size() == 1) { possibleAssets.addAll(assets);
this.asset = assets.get(0);
this.ambiguousAssets = null;
} else {
this.asset = null;
this.ambiguousAssets = assets;
}
} }
public BarcodeData(Crypto asset, String address, String description, String amount) { public BarcodeData(Crypto asset, String address, String description, String amount) {
@@ -68,8 +63,7 @@ public class BarcodeData {
} }
public BarcodeData(Crypto asset, String address, String addressName, String description, String amount, Security security) { public BarcodeData(Crypto asset, String address, String addressName, String description, String amount, Security security) {
this.ambiguousAssets = null; possibleAssets.add(asset);
this.asset = asset;
this.address = address; this.address = address;
this.addressName = addressName; this.addressName = addressName;
this.description = description; this.description = description;
@@ -82,7 +76,7 @@ public class BarcodeData {
} }
public String getUriString() { public String getUriString() {
if (asset != Crypto.XMR) throw new IllegalStateException("We can only do XMR stuff!"); if (getAsset() != Crypto.XMR) throw new IllegalStateException("We can only do XMR stuff!");
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(Crypto.XMR.getUriScheme()) sb.append(Crypto.XMR.getUriScheme())
.append(':') .append(':')
@@ -227,6 +221,20 @@ public class BarcodeData {
} }
public boolean isAmbiguous() { public boolean isAmbiguous() {
return ambiguousAssets != null; return possibleAssets.size() > 1;
}
public Crypto getAsset() {
if (possibleAssets.size() == 1) {
return possibleAssets.iterator().next();
} else {
return null;
}
}
// return true if we still have possible assets
public boolean filter(Set<Crypto> assets) {
possibleAssets.retainAll(assets);
return !possibleAssets.isEmpty();
} }
} }

View File

@@ -1,3 +1,19 @@
/*
* Copyright (c) 2024 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.data; package com.m2049r.xmrwallet.data;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -5,35 +21,30 @@ import androidx.annotation.Nullable;
import com.m2049r.xmrwallet.R; import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.util.validator.BitcoinAddressType;
import com.m2049r.xmrwallet.util.validator.BitcoinAddressValidator; import java.util.regex.Pattern;
import com.m2049r.xmrwallet.util.validator.EthAddressValidator;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor @RequiredArgsConstructor
public enum Crypto { public enum Crypto {
XMR("XMR", true, "monero:tx_amount:recipient_name:tx_description", R.id.ibXMR, R.drawable.ic_monero, R.drawable.ic_monero_bw, Wallet::isAddressValid), XMR("XMR", "XMR", "XMR", "monero:tx_amount:recipient_name:tx_description", R.id.ibXMR, R.drawable.ic_monero, R.drawable.ic_monero_bw, Pattern.compile("^[48][a-zA-Z|\\d]{94}([a-zA-Z|\\d]{11})?$")),
BTC("BTC", true, "bitcoin:amount:label:message", R.id.ibBTC, R.drawable.ic_xmrto_btc, R.drawable.ic_xmrto_btc_off, address -> { BTC("BTC", "BTC", "BTC", "bitcoin:amount:label:message", R.id.ibBTC, R.drawable.ic_xmrto_btc, R.drawable.ic_xmrto_btc_off, Pattern.compile("^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$|^(bc1q)|(bc1p)[0-9A-Za-z]{37,62}$")),
return BitcoinAddressValidator.validate(address, BitcoinAddressType.BTC); LTC("LTC", "LTC", "LTC", "litecoin:amount:label:message", R.id.ibLTC, R.drawable.ic_xmrto_ltc, R.drawable.ic_xmrto_ltc_off, Pattern.compile("^([LM3])[A-Za-z0-9]{33}$|^(ltc1)[0-9A-Za-z]{39}$")),
}), ETH("ETH", "ETH", "ETH", "ethereum:amount:label:message", R.id.ibETH, R.drawable.ic_xmrto_eth, R.drawable.ic_xmrto_eth_off, Pattern.compile("^(0x)[0-9A-Fa-f]{40}$")),
DASH("DASH", true, "dash:amount:label:message", R.id.ibDASH, R.drawable.ic_xmrto_dash, R.drawable.ic_xmrto_dash_off, address -> { USDT("USDT", "TRX", "USDT(TRC20)", "usdt:amount:label:message", R.id.ibUSDT, R.drawable.ic_xmrto_usdt_trc20, R.drawable.ic_xmrto_usdt_trc20_off, Pattern.compile("^T[1-9A-HJ-NP-Za-km-z]{33}$")),
return BitcoinAddressValidator.validate(address, BitcoinAddressType.DASH); SOLANA("SOL", "SOL", "SOL", "solana:amount:label:message", R.id.ibSOL, R.drawable.ic_xmrto_sol, R.drawable.ic_xmrto_sol_off, Pattern.compile("^[1-9A-HJ-NP-Za-km-z]{32,44}$"));
}),
DOGE("DOGE", true, "dogecoin:amount:label:message", R.id.ibDOGE, R.drawable.ic_xmrto_doge, R.drawable.ic_xmrto_doge_off, address -> {
return BitcoinAddressValidator.validate(address, BitcoinAddressType.DOGE);
}),
ETH("ETH", false, "ethereum:amount:label:message", R.id.ibETH, R.drawable.ic_xmrto_eth, R.drawable.ic_xmrto_eth_off, EthAddressValidator::validate),
LTC("LTC", true, "litecoin:amount:label:message", R.id.ibLTC, R.drawable.ic_xmrto_ltc, R.drawable.ic_xmrto_ltc_off, address -> {
return BitcoinAddressValidator.validate(address, BitcoinAddressType.LTC);
});
@Getter @Getter
@NonNull @NonNull
private final String symbol; private final String symbol;
@Getter @Getter
private final boolean casefull; @NonNull
private final String network;
@Getter
@NonNull
private final String label;
@NonNull @NonNull
private final String uriSpec; private final String uriSpec;
@Getter @Getter
@@ -43,7 +54,7 @@ public enum Crypto {
@Getter @Getter
private final int iconDisabledId; private final int iconDisabledId;
@NonNull @NonNull
private final Validator validator; private final Pattern regex;
@Nullable @Nullable
public static Crypto withScheme(@NonNull String scheme) { public static Crypto withScheme(@NonNull String scheme) {
@@ -62,10 +73,6 @@ public enum Crypto {
return null; return null;
} }
interface Validator {
boolean validate(String address);
}
// TODO maybe cache these segments // TODO maybe cache these segments
String getUriScheme() { String getUriScheme() {
return uriSpec.split(":")[0]; return uriSpec.split(":")[0];
@@ -83,7 +90,8 @@ public enum Crypto {
return uriSpec.split(":")[3]; return uriSpec.split(":")[3];
} }
boolean validate(String address) { public boolean validate(String address) {
return validator.validate(address); if (this == XMR) return Wallet.isAddressValid(address);
return regex.matcher(address).find();
} }
} }

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2024 m2049r
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.data;
import lombok.Value;
@Value
public class CryptoAmount {
Crypto crypto;
double amount;
public CryptoAmount newWithAmount(double amount) {
return new CryptoAmount(this.crypto, amount);
}
}

View File

@@ -19,23 +19,26 @@ package com.m2049r.xmrwallet.data;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
// Nodes stolen from https://moneroworld.com/#nodes @Getter
@AllArgsConstructor @AllArgsConstructor
public enum DefaultNodes { public enum DefaultNodes {
MONERUJO("nodex.monerujo.io:18081"), AGORIST("xmr.agor.ist:18089/mainnet/agor.ist"),
XMRTO("node.xmr.to:18081"), BOLDSUCK("xmr-de.boldsuck.org:18080/mainnet/boldsuck.org"),
SUPPORTXMR("node.supportxmr.com:18081"),
HASHVAULT("nodes.hashvault.pro:18081"),
MONEROWORLD("node.moneroworld.com:18089"),
XMRTW("opennode.xmr-tw.org:18089"),
ds_jetzt("monero.ds-jetzt.de:18089"),
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"),
ds_jetzt_onion("qvlr4w7yhnjrdg3txa72jwtpnjn4ezsrivzvocbnvpfbdo342fahhoad.onion:18089/mainnet/ds-jetzt.onion"); CAKE("xmr-node.cakewallet.com:18081/mainnet/cakewallet.com"),
DS_JETZT("monero.ds-jetzt.de:18089/mainnet/ds-jetzt.de"),
ds_jetzt("qvlr4w7yhnjrdg3txa72jwtpnjn4ezsrivzvocbnvpfbdo342fahhoad.onion:18089/mainnet/ds-jetzt.onion"),
MONERODEVS("node.monerodevs.org:18089/mainnet/monerodevs.org"),
MONERUJO("nodex.monerujo.io:18081/mainnet/monerujo.io"),
monerujo("monerujods7mbghwe6cobdr6ujih6c22zu5rl7zshmizz2udf7v7fsad.onion:18081/mainnet/monerujo.onion"),
SETH("node.sethforprivacy.com:18089/mainnet/sethforprivacy.com"),
seth("sfpp2p7wnfjv3lrvfan4jmmkvhnbsbimpa3cqyuf7nt6zd24xhcqcsyd.onion/mainnet/sethforprivacy.onion"),
STACK("monero.stackwallet.com:18081/mainnet/stackwallet.com"),
STORMYCLOUD("xmr.stormycloud.org:18089/mainnet/stormycloud.org"),
TENZ("monero.10z.com.ar:18089/mainnet/10z.com.ar"),
XMRROCKS("node.xmr.rocks:18089/mainnet/xmr.rocks"),
xmrrocks("xqnnz2xmlmtpy2p4cm4cphg2elkwu5oob7b7so5v4wwgt44p6vbx5ryd.onion/mainnet/xmr.rocks.onion"),
XMRTW("opennode.xmr-tw.org:18089/mainnet/xmr-tw.org");
@Getter
private final String uri; private final String uri;
} }

View File

@@ -144,7 +144,7 @@ public class Node {
if ((nodeString == null) || nodeString.isEmpty()) if ((nodeString == null) || nodeString.isEmpty())
throw new IllegalArgumentException("daemon is empty"); throw new IllegalArgumentException("daemon is empty");
String daemonAddress; String daemonAddress;
String a[] = nodeString.split("@"); String[] a = nodeString.split("@");
if (a.length == 1) { // no credentials if (a.length == 1) { // no credentials
daemonAddress = a[0]; daemonAddress = a[0];
username = ""; username = "";
@@ -169,7 +169,7 @@ public class Node {
throw new IllegalArgumentException("Too many '/' or too few"); throw new IllegalArgumentException("Too many '/' or too few");
daemonAddress = daParts[0]; daemonAddress = daParts[0];
String da[] = daemonAddress.split(":"); String[] da = daemonAddress.split(":");
if ((da.length > 2) || (da.length < 1)) if ((da.length > 2) || (da.length < 1))
throw new IllegalArgumentException("Too many ':' or too few"); throw new IllegalArgumentException("Too many ':' or too few");
String host = da[0]; String host = da[0];

View File

@@ -201,8 +201,13 @@ public class NodeInfo extends Node {
.port(port) .port(port)
.addPathSegment("json_rpc") .addPathSegment("json_rpc")
.build(); .build();
final String json = "{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"getlastblockheader\"}";
return new Request(url, json, getUsername(), getPassword()); try {
final JSONObject json = new JSONObject("{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"getlastblockheader\"}");
return new Request(url, json, getUsername(), getPassword());
} catch (JSONException ex) {
throw new IllegalStateException(ex);
}
} }
private boolean testRpcService(int port) { private boolean testRpcService(int port) {

View File

@@ -20,22 +20,21 @@ import android.os.Parcel;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.m2049r.xmrwallet.service.shift.ShiftService;
import com.m2049r.xmrwallet.service.shift.api.RequestQuote;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@Setter
@Getter
public class TxDataBtc extends TxData { public class TxDataBtc extends TxData {
@Getter private ShiftService shiftService;
@Setter
private String btcSymbol; // the actual non-XMR thing we're sending private String btcSymbol; // the actual non-XMR thing we're sending
@Getter
@Setter
private String xmrtoOrderId; // shown in success screen private String xmrtoOrderId; // shown in success screen
@Getter
@Setter
private String btcAddress; private String btcAddress;
@Getter private CryptoAmount shiftAmount; // what we want to send
@Setter private String xmrtoQueryOrderToken; // used for queryOrder API
private double btcAmount;
public TxDataBtc() { public TxDataBtc() {
super(); super();
@@ -47,7 +46,9 @@ public class TxDataBtc extends TxData {
out.writeString(btcSymbol); out.writeString(btcSymbol);
out.writeString(xmrtoOrderId); out.writeString(xmrtoOrderId);
out.writeString(btcAddress); out.writeString(btcAddress);
out.writeDouble(btcAmount); out.writeString(shiftAmount.getCrypto().name());
out.writeDouble(shiftAmount.getAmount());
out.writeString(xmrtoQueryOrderToken);
} }
// this is used to regenerate your object. All Parcelables must have a CREATOR that implements these two methods // this is used to regenerate your object. All Parcelables must have a CREATOR that implements these two methods
@@ -66,7 +67,8 @@ public class TxDataBtc extends TxData {
btcSymbol = in.readString(); btcSymbol = in.readString();
xmrtoOrderId = in.readString(); xmrtoOrderId = in.readString();
btcAddress = in.readString(); btcAddress = in.readString();
btcAmount = in.readDouble(); shiftAmount = new CryptoAmount(Crypto.valueOf(in.readString()), in.readDouble());
xmrtoQueryOrderToken = in.readString();
} }
@NonNull @NonNull
@@ -79,19 +81,33 @@ public class TxDataBtc extends TxData {
sb.append(btcSymbol); sb.append(btcSymbol);
sb.append(",btcAddress:"); sb.append(",btcAddress:");
sb.append(btcAddress); sb.append(btcAddress);
sb.append(",btcAmount:"); sb.append(",amount:");
sb.append(btcAmount); sb.append(shiftAmount);
sb.append(",xmrtoQueryOrderToken:");
sb.append(xmrtoQueryOrderToken);
return sb.toString(); return sb.toString();
} }
public boolean validateAddress(@NonNull String address) { public boolean validateAddress(@NonNull String address) {
if ((btcSymbol == null) || (btcAddress == null)) return false;
final Crypto crypto = Crypto.withSymbol(btcSymbol); final Crypto crypto = Crypto.withSymbol(btcSymbol);
if (crypto == null) return false; if (crypto == null) return false;
if (crypto.isCasefull()) { // compare as-is return address.equalsIgnoreCase(btcAddress);
return address.equals(btcAddress); }
} else { // normalize & compare (e.g. ETH with and without checksum capitals
return address.toLowerCase().equals(btcAddress.toLowerCase()); public double getBtcAmount() {
return (shiftAmount.getCrypto() == Crypto.XMR) ? 0 : shiftAmount.getAmount();
}
public double getXmrAmount() {
return (shiftAmount.getCrypto() == Crypto.XMR) ? shiftAmount.getAmount() : 0;
}
public boolean validate(RequestQuote quote) {
if (shiftAmount.getCrypto() == Crypto.XMR) {
return (quote.getXmrAmount() == getXmrAmount());
} else {
return (quote.getBtcAmount() == getBtcAmount());
} }
} }
} }

View File

@@ -16,7 +16,7 @@
package com.m2049r.xmrwallet.data; package com.m2049r.xmrwallet.data;
import com.m2049r.xmrwallet.service.shift.sideshift.api.CreateOrder; import com.m2049r.xmrwallet.service.shift.api.CreateOrder;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@@ -61,7 +61,7 @@ public class UserNotes {
public void setXmrtoOrder(CreateOrder order) { public void setXmrtoOrder(CreateOrder order) {
if (order != null) { if (order != null) {
xmrtoTag = order.TAG; xmrtoTag = order.getTag();
xmrtoKey = order.getOrderId(); xmrtoKey = order.getOrderId();
xmrtoAmount = Helper.getDisplayAmount(order.getBtcAmount()); xmrtoAmount = Helper.getDisplayAmount(order.getBtcAmount());
xmrtoCurrency = order.getBtcCurrency(); xmrtoCurrency = order.getBtcCurrency();

View File

@@ -20,10 +20,10 @@ import android.app.Dialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
import android.text.Html; import android.text.Html;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
@@ -57,13 +57,14 @@ public class AboutFragment extends DialogFragment {
AboutFragment.newInstance().show(ft, TAG); AboutFragment.newInstance().show(ft, TAG);
} }
@NonNull
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_about, null); final View view = getLayoutInflater().inflate(R.layout.fragment_about, null);
((TextView) view.findViewById(R.id.tvHelp)).setText(Html.fromHtml(getLicencesHtml())); ((TextView) view.findViewById(R.id.tvHelp)).setText(Html.fromHtml(getLicencesHtml()));
((TextView) view.findViewById(R.id.tvVersion)).setText(getString(R.string.about_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)); ((TextView) view.findViewById(R.id.tvVersion)).setText(getString(R.string.about_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity()) MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity())
.setView(view) .setView(view)
.setNegativeButton(R.string.about_close, .setNegativeButton(R.string.about_close,
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {
@@ -77,7 +78,7 @@ public class AboutFragment extends DialogFragment {
private String getLicencesHtml() { private String getLicencesHtml() {
try (BufferedReader reader = new BufferedReader( try (BufferedReader reader = new BufferedReader(
new InputStreamReader(getContext().getAssets().open("licenses.html"), StandardCharsets.UTF_8))) { new InputStreamReader(requireContext().getAssets().open("licenses.html"), StandardCharsets.UTF_8))) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
String line; String line;
while ((line = reader.readLine()) != null) while ((line = reader.readLine()) != null)

View File

@@ -20,10 +20,10 @@ import android.app.Dialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
import android.text.Html; import android.text.Html;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
@@ -49,13 +49,14 @@ public class CreditsFragment extends DialogFragment {
CreditsFragment.newInstance().show(ft, TAG); CreditsFragment.newInstance().show(ft, TAG);
} }
@NonNull
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_credits, null); final View view = getLayoutInflater().inflate(R.layout.fragment_credits, null);
((TextView) view.findViewById(R.id.tvCredits)).setText(Html.fromHtml(getString(R.string.credits_text))); ((TextView) view.findViewById(R.id.tvCredits)).setText(Html.fromHtml(getString(R.string.credits_text)));
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity()) MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity())
.setView(view) .setView(view)
.setNegativeButton(R.string.about_close, .setNegativeButton(R.string.about_close,
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {

View File

@@ -16,13 +16,13 @@
package com.m2049r.xmrwallet.dialog; package com.m2049r.xmrwallet.dialog;
import android.annotation.SuppressLint;
import android.app.Dialog; import android.app.Dialog;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.text.Html; import android.text.Html;
import android.text.Spanned; import android.text.Spanned;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
@@ -65,9 +65,10 @@ public class HelpFragment extends DialogFragment {
private Spanned getHtml(String html, double textSize) { private Spanned getHtml(String html, double textSize) {
final Html.ImageGetter imageGetter = source -> { final Html.ImageGetter imageGetter = source -> {
final int imageId = getResources().getIdentifier(source.replace("/", ""), "drawable", requireActivity().getPackageName()); @SuppressLint("DiscouragedApi") final int imageId = getResources().getIdentifier(source.replace("/", ""), "drawable", requireActivity().getPackageName());
// Don't die if we don't find the image - use a heart instead // Don't die if we don't find the image - use a heart instead
final Drawable drawable = ContextCompat.getDrawable(requireActivity(), imageId > 0 ? imageId : R.drawable.ic_favorite_24dp); final Drawable drawable = ContextCompat.getDrawable(requireActivity(), imageId > 0 ? imageId : R.drawable.ic_favorite_24dp);
assert drawable != null;
final double f = textSize / drawable.getIntrinsicHeight(); final double f = textSize / drawable.getIntrinsicHeight();
drawable.setBounds(0, 0, (int) (f * drawable.getIntrinsicWidth()), (int) textSize); drawable.setBounds(0, 0, (int) (f * drawable.getIntrinsicWidth()), (int) textSize);
return drawable; return drawable;
@@ -82,7 +83,7 @@ public class HelpFragment extends DialogFragment {
@NonNull @NonNull
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_help, null); final View view = getLayoutInflater().inflate(R.layout.fragment_help, null);
int helpId = 0; int helpId = 0;
boolean torButton = false; boolean torButton = false;
@@ -100,7 +101,7 @@ public class HelpFragment extends DialogFragment {
.setView(view); .setView(view);
if (torButton) { if (torButton) {
builder.setNegativeButton(R.string.help_nok, builder.setNegativeButton(R.string.help_nok,
(dialog, id) -> dialog.dismiss()) (dialog, id) -> dialog.dismiss())
.setPositiveButton(R.string.help_getorbot, .setPositiveButton(R.string.help_getorbot,
(dialog, id) -> { (dialog, id) -> {
dialog.dismiss(); dialog.dismiss();

View File

@@ -18,7 +18,6 @@ package com.m2049r.xmrwallet.dialog;
import android.app.Dialog; import android.app.Dialog;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
@@ -66,7 +65,7 @@ public class PocketChangeFragment extends DialogFragment implements Slider.OnCha
@NonNull @NonNull
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_pocketchange_setting, null); final View view = getLayoutInflater().inflate(R.layout.fragment_pocketchange_setting, null);
boolean enabled = false; boolean enabled = false;
int progress = 0; int progress = 0;
Bundle arguments = getArguments(); Bundle arguments = getArguments();

View File

@@ -20,10 +20,10 @@ import android.app.Dialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
import android.text.Html; import android.text.Html;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
@@ -49,13 +49,14 @@ public class PrivacyFragment extends DialogFragment {
PrivacyFragment.newInstance().show(ft, TAG); PrivacyFragment.newInstance().show(ft, TAG);
} }
@NonNull
@Override @Override
public Dialog onCreateDialog(Bundle savedInstanceState) { public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_privacy_policy, null); final View view = getLayoutInflater().inflate(R.layout.fragment_privacy_policy, null);
((TextView) view.findViewById(R.id.tvCredits)).setText(Html.fromHtml(getString(R.string.privacy_policy))); ((TextView) view.findViewById(R.id.tvCredits)).setText(Html.fromHtml(getString(R.string.privacy_policy)));
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity()) MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity())
.setView(view) .setView(view)
.setNegativeButton(R.string.about_close, .setNegativeButton(R.string.about_close,
new DialogInterface.OnClickListener() { new DialogInterface.OnClickListener() {

View File

@@ -17,6 +17,7 @@ package com.m2049r.xmrwallet.dialog;
* limitations under the License. * limitations under the License.
*/ */
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@@ -31,6 +32,7 @@ import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import java.util.Locale; import java.util.Locale;
import java.util.Objects;
import timber.log.Timber; import timber.log.Timber;
@@ -56,7 +58,7 @@ public class ProgressDialog extends AlertDialog {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
final View view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_ledger_progress, null); @SuppressLint("InflateParams") final View view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_ledger_progress, null);
pbCircle = view.findViewById(R.id.pbCircle); pbCircle = view.findViewById(R.id.pbCircle);
tvMessage = view.findViewById(R.id.tvMessage); tvMessage = view.findViewById(R.id.tvMessage);
rlProgressBar = view.findViewById(R.id.rlProgressBar); rlProgressBar = view.findViewById(R.id.rlProgressBar);
@@ -78,7 +80,7 @@ public class ProgressDialog extends AlertDialog {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (Helper.preventScreenshot()) { if (Helper.preventScreenshot()) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); Objects.requireNonNull(getWindow()).setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE);
} }
} }

View File

@@ -0,0 +1,16 @@
package com.m2049r.xmrwallet.fragment.send;
import com.m2049r.xmrwallet.data.CryptoAmount;
import com.m2049r.xmrwallet.service.shift.api.QueryOrderParameters;
public interface PreShifter {
CryptoAmount getAmount();
void onOrderParametersError(final Exception ex);
void onOrderParametersReceived(final QueryOrderParameters orderParameters);
boolean isActive();
void showProgress();
}

Some files were not shown because too many files have changed in this diff Show More