mirror of
https://github.com/m2049r/xmrwallet
synced 2025-09-04 17:28:42 +02:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
84ce392192 | ||
![]() |
4ebcda2b14 | ||
![]() |
c49351a8a9 | ||
![]() |
41e84f2e29 |
@@ -8,8 +8,8 @@ android {
|
||||
compileSdk 35
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 35
|
||||
versionCode 4007
|
||||
versionName "4.0.7 'Sidekick'"
|
||||
versionCode 4102
|
||||
versionName "4.1.2 'Exolix'"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
@@ -58,7 +58,7 @@ android {
|
||||
applicationIdSuffix ".debug"
|
||||
}
|
||||
applicationVariants.all { variant ->
|
||||
variant.buildConfigField "String", "ID_A", "\"" + getId("ID_A") + "\""
|
||||
variant.buildConfigField "String", "ID_F", "\"" + getId("ID_F") + "\""
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -99,7 +99,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
private String walletPath;
|
||||
private String walletName;
|
||||
|
||||
private OnBackPressedCallback backPressedCallback = new OnBackPressedCallback(false) {
|
||||
private final OnBackPressedCallback backPressedCallback = new OnBackPressedCallback(false) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
// nothing
|
||||
@@ -164,6 +164,7 @@ public class GenerateReviewFragment extends Fragment {
|
||||
});
|
||||
|
||||
Bundle args = getArguments();
|
||||
assert args != null;
|
||||
type = args.getString(REQUEST_TYPE);
|
||||
walletPath = args.getString(REQUEST_PATH);
|
||||
localPassword = args.getString(REQUEST_PASSWORD);
|
||||
|
@@ -22,13 +22,14 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class LockFragment extends Fragment {
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
Timber.d("onCreateView");
|
||||
final FrameLayout frame = new FrameLayout(requireContext());
|
||||
frame.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
|
@@ -619,6 +619,7 @@ public class LoginActivity extends BaseActivity
|
||||
try {
|
||||
GenerateReviewFragment detailsFragment = (GenerateReviewFragment)
|
||||
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
||||
assert detailsFragment != null;
|
||||
AlertDialog dialog = detailsFragment.createChangePasswordDialog();
|
||||
if (dialog != null) {
|
||||
Helper.showKeyboard(dialog);
|
||||
@@ -896,6 +897,7 @@ public class LoginActivity extends BaseActivity
|
||||
try {
|
||||
GenerateFragment genFragment = (GenerateFragment)
|
||||
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
||||
assert genFragment != null;
|
||||
genFragment.walletGenerateError();
|
||||
} catch (ClassCastException ex) {
|
||||
Timber.e("walletGenerateError() but not in GenerateFragment");
|
||||
@@ -1261,7 +1263,7 @@ public class LoginActivity extends BaseActivity
|
||||
if (usbManager.hasPermission(device)) {
|
||||
connectLedger(usbManager, device);
|
||||
} else {
|
||||
ContextCompat.registerReceiver(this, usbPermissionReceiver, new IntentFilter(ACTION_USB_PERMISSION), ContextCompat.RECEIVER_NOT_EXPORTED);
|
||||
ContextCompat.registerReceiver(this, usbPermissionReceiver, new IntentFilter(ACTION_USB_PERMISSION), ContextCompat.RECEIVER_EXPORTED);
|
||||
usbManager.requestPermission(device,
|
||||
PendingIntent.getBroadcast(this, 0,
|
||||
new Intent(ACTION_USB_PERMISSION),
|
||||
@@ -1366,7 +1368,7 @@ public class LoginActivity extends BaseActivity
|
||||
private void registerDetachReceiver() {
|
||||
detachReceiver = new BroadcastReceiver() {
|
||||
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();
|
||||
final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
|
||||
Timber.i("Ledger detached!");
|
||||
@@ -1380,7 +1382,7 @@ public class LoginActivity extends BaseActivity
|
||||
}
|
||||
}
|
||||
};
|
||||
ContextCompat.registerReceiver(this, detachReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED), ContextCompat.RECEIVER_NOT_EXPORTED);
|
||||
ContextCompat.registerReceiver(this, detachReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED), ContextCompat.RECEIVER_EXPORTED);
|
||||
}
|
||||
|
||||
public void onLedgerAction() {
|
||||
@@ -1409,6 +1411,7 @@ public class LoginActivity extends BaseActivity
|
||||
Timber.d("onDeviceConnected: %s", connectedDeviceName);
|
||||
try {
|
||||
SidekickConnectFragment f = (SidekickConnectFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
||||
assert f != null;
|
||||
f.allowClick();
|
||||
} catch (ClassCastException ex) {
|
||||
// ignore it
|
||||
|
@@ -152,7 +152,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
||||
showNetwork();
|
||||
}
|
||||
|
||||
private OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) {
|
||||
private final OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(false) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
animateFAB();
|
||||
@@ -283,7 +283,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
||||
}
|
||||
|
||||
// remove information of non-existent wallet
|
||||
Set<String> removedWallets = getActivity()
|
||||
Set<String> removedWallets = requireActivity()
|
||||
.getSharedPreferences(KeyStoreHelper.SecurityConstants.WALLET_PASS_PREFS_NAME, Context.MODE_PRIVATE)
|
||||
.getAll().keySet();
|
||||
for (WalletManager.WalletInfo s : walletList) {
|
||||
@@ -445,7 +445,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
|
||||
}
|
||||
|
||||
private void setSubtext(String status) {
|
||||
final Context ctx = getContext();
|
||||
final Context ctx = requireContext();
|
||||
final Spanned text = Html.fromHtml(ctx.getString(R.string.status,
|
||||
Integer.toHexString(ThemeHelper.getThemedColor(ctx, R.attr.positiveColor) & 0xFFFFFF),
|
||||
Integer.toHexString(ThemeHelper.getThemedColor(ctx, android.R.attr.colorBackground) & 0xFFFFFF),
|
||||
|
@@ -32,6 +32,7 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
@@ -68,7 +69,7 @@ public class NodeFragment extends Fragment
|
||||
|
||||
static private int NODES_TO_FIND = 10;
|
||||
|
||||
static private NumberFormat FORMATTER = NumberFormat.getInstance();
|
||||
static private final NumberFormat FORMATTER = NumberFormat.getInstance();
|
||||
|
||||
private SwipeRefreshLayout pullToRefresh;
|
||||
private TextView tvPull;
|
||||
@@ -104,7 +105,7 @@ public class NodeFragment extends Fragment
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof Listener) {
|
||||
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
|
||||
public void handleOnBackPressed() {
|
||||
Toast.makeText(requireActivity(), getString(R.string.node_refresh_wait), Toast.LENGTH_LONG).show();
|
||||
@@ -210,7 +211,7 @@ public class NodeFragment extends Fragment
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.node_menu, menu);
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
@@ -454,7 +455,7 @@ public class NodeFragment extends Fragment
|
||||
|
||||
private void closeDialog() {
|
||||
if (editDialog == null) throw new IllegalStateException();
|
||||
Helper.hideKeyboardAlways(getActivity());
|
||||
Helper.hideKeyboardAlways(requireActivity());
|
||||
editDialog.dismiss();
|
||||
editDialog = null;
|
||||
NodeFragment.this.editDialog = null;
|
||||
|
@@ -32,12 +32,10 @@ import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
@@ -84,8 +82,6 @@ public class ReceiveFragment extends Fragment {
|
||||
private ImageView ivQrCode;
|
||||
private ImageView ivQrCodeFull;
|
||||
private EditText etDummy;
|
||||
private ImageButton bCopyAddress;
|
||||
private MenuItem shareItem;
|
||||
|
||||
private Wallet wallet = null;
|
||||
private boolean isMyWallet = false;
|
||||
@@ -116,11 +112,10 @@ public class ReceiveFragment extends Fragment {
|
||||
tvQrCode = view.findViewById(R.id.tvQrCode);
|
||||
ivQrCodeFull = view.findViewById(R.id.qrCodeFull);
|
||||
etDummy = view.findViewById(R.id.etDummy);
|
||||
bCopyAddress = view.findViewById(R.id.bCopyAddress);
|
||||
|
||||
etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||
|
||||
bCopyAddress.setOnClickListener(v -> copyAddress());
|
||||
view.findViewById(R.id.bCopyAddress).setOnClickListener(v -> copyAddress());
|
||||
|
||||
evAmount.setOnNewAmountListener(xmr -> {
|
||||
Timber.d("new amount = %s", xmr);
|
||||
@@ -211,8 +206,7 @@ public class ReceiveFragment extends Fragment {
|
||||
inflater.inflate(R.menu.receive_menu, menu);
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
|
||||
shareItem = menu.findItem(R.id.menu_item_share);
|
||||
shareItem.setOnMenuItemClickListener(item -> {
|
||||
menu.findItem(R.id.menu_item_share).setOnMenuItemClickListener(item -> {
|
||||
if (shareRequested) return true;
|
||||
shareRequested = true;
|
||||
if (!qrValid) {
|
||||
@@ -238,7 +232,7 @@ public class ReceiveFragment extends Fragment {
|
||||
private boolean saveQrCode() {
|
||||
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.mkdirs()) throw new IllegalStateException("cannot create images folder");
|
||||
File png = new File(cachePath, "QR.png");
|
||||
@@ -452,7 +446,7 @@ public class ReceiveFragment extends Fragment {
|
||||
.withEndAction(resetSize).start();
|
||||
}
|
||||
subaddress = newSubaddress;
|
||||
final Context context = getContext();
|
||||
final Context context = requireContext();
|
||||
Spanned label = Html.fromHtml(context.getString(R.string.receive_subaddress,
|
||||
Integer.toHexString(ThemeHelper.getThemedColor(context, R.attr.positiveColor) & 0xFFFFFF),
|
||||
Integer.toHexString(ThemeHelper.getThemedColor(context, android.R.attr.colorBackground) & 0xFFFFFF),
|
||||
|
@@ -24,6 +24,7 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
@@ -43,7 +44,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
||||
private ZXingScannerView mScannerView;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
Timber.d("onCreateView");
|
||||
mScannerView = new ZXingScannerView(getActivity());
|
||||
return mScannerView;
|
||||
@@ -85,7 +86,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof OnScannedListener) {
|
||||
this.onScannedListener = (OnScannedListener) context;
|
||||
|
@@ -5,6 +5,7 @@ import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StyleRes;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
@@ -60,7 +61,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
|
||||
private SettingsFragment.Listener activity;
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof SettingsFragment.Listener) {
|
||||
activity = (SettingsFragment.Listener) context;
|
||||
|
@@ -20,6 +20,7 @@ import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothClass;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
@@ -29,6 +30,7 @@ import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
@@ -73,6 +75,8 @@ public class SidekickConnectFragment extends Fragment
|
||||
@Override
|
||||
public void 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()) {
|
||||
bluetoothAdapter.cancelDiscovery();
|
||||
}
|
||||
@@ -112,6 +116,8 @@ public class SidekickConnectFragment extends Fragment
|
||||
|
||||
private void populateList() {
|
||||
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()) {
|
||||
final int deviceCLass = device.getBluetoothClass().getDeviceClass();
|
||||
switch (deviceCLass) {
|
||||
@@ -152,6 +158,8 @@ public class SidekickConnectFragment extends Fragment
|
||||
|
||||
// Make sure we're not doing discovery anymore
|
||||
if (bluetoothAdapter != null) {
|
||||
if (ActivityCompat.checkSelfPermission(requireContext(), android.Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED)
|
||||
throw new IllegalStateException("Bluetooth permission not granted");
|
||||
bluetoothAdapter.cancelDiscovery();
|
||||
}
|
||||
}
|
||||
@@ -159,6 +167,8 @@ public class SidekickConnectFragment extends Fragment
|
||||
@Override
|
||||
public void onInteraction(final View view, final BluetoothInfo 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();
|
||||
|
||||
final BluetoothFragment btFragment = (BluetoothFragment) getChildFragmentManager().findFragmentById(R.id.bt_fragment);
|
||||
|
@@ -226,7 +226,7 @@ public class SubaddressFragment extends Fragment implements SubaddressInfoAdapte
|
||||
|
||||
// Callbacks from SubaddressInfoAdapter
|
||||
@Override
|
||||
public void onInteraction(final View view, final Subaddress subaddress) {
|
||||
public void onInteraction(final View view, @NonNull final Subaddress subaddress) {
|
||||
if (managerMode)
|
||||
activityCallback.showSubaddress(view, subaddress.getAddressIndex());
|
||||
else
|
||||
|
@@ -52,7 +52,6 @@ public class SubaddressInfoFragment extends Fragment
|
||||
private Subaddress subaddress;
|
||||
|
||||
private TextInputLayout etName;
|
||||
private TextView tvAddress;
|
||||
private TextView tvTxLabel;
|
||||
|
||||
@Override
|
||||
@@ -61,7 +60,6 @@ public class SubaddressInfoFragment extends Fragment
|
||||
View view = inflater.inflate(R.layout.fragment_subaddressinfo, container, false);
|
||||
|
||||
etName = view.findViewById(R.id.etName);
|
||||
tvAddress = view.findViewById(R.id.tvAddress);
|
||||
tvTxLabel = view.findViewById(R.id.tvTxLabel);
|
||||
|
||||
final RecyclerView list = view.findViewById(R.id.list);
|
||||
@@ -71,11 +69,13 @@ public class SubaddressInfoFragment extends Fragment
|
||||
final Wallet wallet = activityCallback.getWallet();
|
||||
|
||||
Bundle b = getArguments();
|
||||
assert b != null;
|
||||
final int subaddressIndex = b.getInt("subaddressIndex");
|
||||
subaddress = wallet.getSubaddressObject(subaddressIndex);
|
||||
|
||||
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()));
|
||||
|
||||
etName.getEditText().setOnFocusChangeListener((v, hasFocus) -> {
|
||||
|
@@ -20,7 +20,6 @@ import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Paint;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.text.InputType;
|
||||
@@ -34,6 +33,7 @@ import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
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.Transfer;
|
||||
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.ThemeHelper;
|
||||
import com.m2049r.xmrwallet.widget.Toolbar;
|
||||
@@ -61,6 +63,7 @@ public class TxFragment extends Fragment {
|
||||
|
||||
static public final String ARG_INFO = "info";
|
||||
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
private final SimpleDateFormat TS_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
|
||||
|
||||
public TxFragment() {
|
||||
@@ -106,6 +109,7 @@ public class TxFragment extends Fragment {
|
||||
tvTxAmountBtc = view.findViewById(R.id.tvTxAmountBtc);
|
||||
tvXmrToSupport = view.findViewById(R.id.tvXmrToSupport);
|
||||
tvXmrToKeyLabel = view.findViewById(R.id.tvXmrToKeyLabel);
|
||||
|
||||
tvXmrToLogo = view.findViewById(R.id.tvXmrToLogo);
|
||||
|
||||
tvAccount = view.findViewById(R.id.tvAccount);
|
||||
@@ -127,18 +131,20 @@ public class TxFragment extends Fragment {
|
||||
tvWarning = view.findViewById(R.id.tvWarning);
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
info = getArguments().getParcelable(ARG_INFO);
|
||||
final Bundle args = getArguments();
|
||||
assert args != null;
|
||||
info = args.getParcelable(ARG_INFO);
|
||||
show();
|
||||
return view;
|
||||
}
|
||||
|
||||
void shareTxInfo() {
|
||||
if (this.info == null) return;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(getString(R.string.tx_timestamp)).append(":\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() {
|
||||
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,
|
||||
info.accountIndex, info.addressIndex,
|
||||
Integer.toHexString(ThemeHelper.getThemedColor(ctx, R.attr.positiveColor) & 0xFFFFFF),
|
||||
@@ -264,16 +270,17 @@ public class TxFragment extends Fragment {
|
||||
tvTxFee.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
final Context ctx = requireContext();
|
||||
if (info.isFailed) {
|
||||
tvTxAmount.setText(getString(R.string.tx_list_amount_failed, Wallet.getDisplayAmount(info.amount)));
|
||||
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) {
|
||||
setTxColour(ThemeHelper.getThemedColor(getContext(), R.attr.neutralColor));
|
||||
setTxColour(ThemeHelper.getThemedColor(ctx, R.attr.neutralColor));
|
||||
} else if (info.direction == TransactionInfo.Direction.Direction_In) {
|
||||
setTxColour(ThemeHelper.getThemedColor(getContext(), R.attr.positiveColor));
|
||||
setTxColour(ThemeHelper.getThemedColor(ctx, R.attr.positiveColor));
|
||||
} else {
|
||||
setTxColour(ThemeHelper.getThemedColor(getContext(), R.attr.negativeColor));
|
||||
setTxColour(ThemeHelper.getThemedColor(ctx, R.attr.negativeColor));
|
||||
}
|
||||
Set<String> destinations = new HashSet<>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
@@ -328,31 +335,29 @@ public class TxFragment extends Fragment {
|
||||
void showBtcInfo() {
|
||||
if (userNotes.xmrtoKey != null) {
|
||||
cvXmrTo.setVisibility(View.VISIBLE);
|
||||
String key = userNotes.xmrtoKey;
|
||||
if ("xmrto".equals(userNotes.xmrtoTag)) { // legacy xmr.to service :(
|
||||
key = "xmrto-" + key;
|
||||
}
|
||||
tvTxXmrToKey.setText(key);
|
||||
|
||||
ShiftService service = ShiftService.findWithTag(userNotes.xmrtoTag);
|
||||
tvXmrToKeyLabel.setText(getString(R.string.label_send_btc_xmrto_key_lb, service.getLabel()));
|
||||
if (service.getIconId() == 0)
|
||||
tvXmrToLogo.setVisibility(View.GONE);
|
||||
else
|
||||
tvXmrToLogo.setImageResource(service.getLogoId());
|
||||
|
||||
tvTxXmrToKey.setText(userNotes.xmrtoKey);
|
||||
|
||||
tvDestinationBtc.setText(userNotes.xmrtoDestination);
|
||||
tvTxAmountBtc.setText(userNotes.xmrtoAmount + " " + userNotes.xmrtoCurrency);
|
||||
switch (userNotes.xmrtoTag) {
|
||||
case "xmrto":
|
||||
tvXmrToSupport.setVisibility(View.GONE);
|
||||
tvXmrToKeyLabel.setVisibility(View.INVISIBLE);
|
||||
tvXmrToLogo.setImageResource(R.drawable.ic_xmrto_logo);
|
||||
break;
|
||||
case "side": // defaults in layout - just add underline
|
||||
tvXmrToSupport.setPaintFlags(tvXmrToSupport.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
|
||||
tvXmrToSupport.setOnClickListener(v -> {
|
||||
Uri uri = Uri.parse("https://sideshift.ai/orders/" + userNotes.xmrtoKey);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
startActivity(intent);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
tvXmrToSupport.setVisibility(View.GONE);
|
||||
tvXmrToKeyLabel.setVisibility(View.INVISIBLE);
|
||||
tvXmrToLogo.setVisibility(View.GONE);
|
||||
|
||||
ShiftApi shiftApi = service.getShiftApi();
|
||||
if (shiftApi != null) {
|
||||
tvXmrToSupport.setText(getString(R.string.label_send_btc_xmrto_info, service.getLabel()));
|
||||
tvXmrToSupport.setPaintFlags(tvXmrToSupport.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
|
||||
tvXmrToSupport.setOnClickListener(v -> {
|
||||
startActivity(new Intent(Intent.ACTION_VIEW, shiftApi.getQueryOrderUri(userNotes.xmrtoKey)));
|
||||
});
|
||||
} else {
|
||||
tvXmrToSupport.setVisibility(View.GONE);
|
||||
tvXmrToKeyLabel.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
} else {
|
||||
cvXmrTo.setVisibility(View.GONE);
|
||||
@@ -369,7 +374,7 @@ public class TxFragment extends Fragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.tx_info_menu, menu);
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
@@ -397,7 +402,7 @@ public class TxFragment extends Fragment {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
public void onAttach(@NonNull Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof TxFragment.Listener) {
|
||||
this.activityCallback = (TxFragment.Listener) context;
|
||||
|
@@ -38,7 +38,6 @@ import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.view.GravityCompat;
|
||||
@@ -348,7 +347,10 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
||||
}
|
||||
|
||||
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);
|
||||
requestStreetMode = extras.getBoolean(REQUEST_STREETMODE);
|
||||
@@ -1179,7 +1181,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSubaddressSelected(@Nullable final Subaddress subaddress) {
|
||||
public void onSubaddressSelected(@NonNull final Subaddress subaddress) {
|
||||
selectedSubaddressIndex = subaddress.getAddressIndex();
|
||||
getOnBackPressedDispatcher().onBackPressed();
|
||||
}
|
||||
|
@@ -112,7 +112,7 @@ public class WalletFragment extends Fragment
|
||||
flExchange = view.findViewById(R.id.flExchange);
|
||||
((ProgressBar) view.findViewById(R.id.pbExchange)).getIndeterminateDrawable().
|
||||
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);
|
||||
|
||||
tvProgress = view.findViewById(R.id.tvProgress);
|
||||
|
@@ -23,7 +23,6 @@ import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.m2049r.xmrwallet.BuildConfig;
|
||||
import com.m2049r.xmrwallet.model.NetworkType;
|
||||
import com.m2049r.xmrwallet.util.LocaleHelper;
|
||||
import com.m2049r.xmrwallet.util.NetCipherHelper;
|
||||
|
@@ -24,43 +24,38 @@ import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import timber.log.Timber;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
public class BarcodeData {
|
||||
|
||||
public enum Security {
|
||||
NORMAL,
|
||||
OA_NO_DNSSEC,
|
||||
OA_DNSSEC
|
||||
}
|
||||
|
||||
final public Crypto asset;
|
||||
final public List<Crypto> ambiguousAssets;
|
||||
final public String address;
|
||||
final public String addressName;
|
||||
final public String amount;
|
||||
final public String description;
|
||||
final public Security security;
|
||||
final private Set<Crypto> possibleAssets = new HashSet<>();
|
||||
private String address = null;
|
||||
private String addressName = null;
|
||||
private String amount = null;
|
||||
private String description = null;
|
||||
private Security security = null;
|
||||
|
||||
public BarcodeData(List<Crypto> assets, String address) {
|
||||
if (assets.isEmpty())
|
||||
throw new IllegalArgumentException("no assets specified");
|
||||
this.addressName = null;
|
||||
this.description = null;
|
||||
this.amount = null;
|
||||
this.security = Security.NORMAL;
|
||||
security = Security.NORMAL;
|
||||
this.address = address;
|
||||
if (assets.size() == 1) {
|
||||
this.asset = assets.get(0);
|
||||
this.ambiguousAssets = null;
|
||||
} else {
|
||||
this.asset = null;
|
||||
this.ambiguousAssets = assets;
|
||||
}
|
||||
possibleAssets.addAll(assets);
|
||||
}
|
||||
|
||||
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) {
|
||||
this.ambiguousAssets = null;
|
||||
this.asset = asset;
|
||||
possibleAssets.add(asset);
|
||||
this.address = address;
|
||||
this.addressName = addressName;
|
||||
this.description = description;
|
||||
@@ -82,7 +76,7 @@ public class BarcodeData {
|
||||
}
|
||||
|
||||
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();
|
||||
sb.append(Crypto.XMR.getUriScheme())
|
||||
.append(':')
|
||||
@@ -227,6 +221,20 @@ public class BarcodeData {
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
@@ -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;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -5,35 +21,30 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import com.m2049r.xmrwallet.R;
|
||||
import com.m2049r.xmrwallet.model.Wallet;
|
||||
import com.m2049r.xmrwallet.util.validator.BitcoinAddressType;
|
||||
import com.m2049r.xmrwallet.util.validator.BitcoinAddressValidator;
|
||||
import com.m2049r.xmrwallet.util.validator.EthAddressValidator;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
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),
|
||||
BTC("BTC", true, "bitcoin:amount:label:message", R.id.ibBTC, R.drawable.ic_xmrto_btc, R.drawable.ic_xmrto_btc_off, address -> {
|
||||
return BitcoinAddressValidator.validate(address, BitcoinAddressType.BTC);
|
||||
}),
|
||||
DASH("DASH", true, "dash:amount:label:message", R.id.ibDASH, R.drawable.ic_xmrto_dash, R.drawable.ic_xmrto_dash_off, address -> {
|
||||
return BitcoinAddressValidator.validate(address, BitcoinAddressType.DASH);
|
||||
}),
|
||||
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);
|
||||
});
|
||||
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", "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}$")),
|
||||
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}$")),
|
||||
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}$")),
|
||||
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}$"));
|
||||
|
||||
@Getter
|
||||
@NonNull
|
||||
private final String symbol;
|
||||
@Getter
|
||||
private final boolean casefull;
|
||||
@NonNull
|
||||
private final String network;
|
||||
@Getter
|
||||
@NonNull
|
||||
private final String label;
|
||||
@NonNull
|
||||
private final String uriSpec;
|
||||
@Getter
|
||||
@@ -43,7 +54,7 @@ public enum Crypto {
|
||||
@Getter
|
||||
private final int iconDisabledId;
|
||||
@NonNull
|
||||
private final Validator validator;
|
||||
private final Pattern regex;
|
||||
|
||||
@Nullable
|
||||
public static Crypto withScheme(@NonNull String scheme) {
|
||||
@@ -62,10 +73,6 @@ public enum Crypto {
|
||||
return null;
|
||||
}
|
||||
|
||||
interface Validator {
|
||||
boolean validate(String address);
|
||||
}
|
||||
|
||||
// TODO maybe cache these segments
|
||||
String getUriScheme() {
|
||||
return uriSpec.split(":")[0];
|
||||
@@ -83,7 +90,8 @@ public enum Crypto {
|
||||
return uriSpec.split(":")[3];
|
||||
}
|
||||
|
||||
boolean validate(String address) {
|
||||
return validator.validate(address);
|
||||
public boolean validate(String address) {
|
||||
if (this == XMR) return Wallet.isAddressValid(address);
|
||||
return regex.matcher(address).find();
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -201,8 +201,13 @@ public class NodeInfo extends Node {
|
||||
.port(port)
|
||||
.addPathSegment("json_rpc")
|
||||
.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) {
|
||||
|
@@ -20,22 +20,21 @@ import android.os.Parcel;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.m2049r.xmrwallet.service.shift.ShiftService;
|
||||
import com.m2049r.xmrwallet.service.shift.api.RequestQuote;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public class TxDataBtc extends TxData {
|
||||
@Getter
|
||||
@Setter
|
||||
private ShiftService shiftService;
|
||||
private String btcSymbol; // the actual non-XMR thing we're sending
|
||||
@Getter
|
||||
@Setter
|
||||
private String xmrtoOrderId; // shown in success screen
|
||||
@Getter
|
||||
@Setter
|
||||
private String btcAddress;
|
||||
@Getter
|
||||
@Setter
|
||||
private double btcAmount;
|
||||
private CryptoAmount shiftAmount; // what we want to send
|
||||
private String xmrtoQueryOrderToken; // used for queryOrder API
|
||||
|
||||
public TxDataBtc() {
|
||||
super();
|
||||
@@ -47,7 +46,9 @@ public class TxDataBtc extends TxData {
|
||||
out.writeString(btcSymbol);
|
||||
out.writeString(xmrtoOrderId);
|
||||
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
|
||||
@@ -66,7 +67,8 @@ public class TxDataBtc extends TxData {
|
||||
btcSymbol = in.readString();
|
||||
xmrtoOrderId = in.readString();
|
||||
btcAddress = in.readString();
|
||||
btcAmount = in.readDouble();
|
||||
shiftAmount = new CryptoAmount(Crypto.valueOf(in.readString()), in.readDouble());
|
||||
xmrtoQueryOrderToken = in.readString();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -79,19 +81,33 @@ public class TxDataBtc extends TxData {
|
||||
sb.append(btcSymbol);
|
||||
sb.append(",btcAddress:");
|
||||
sb.append(btcAddress);
|
||||
sb.append(",btcAmount:");
|
||||
sb.append(btcAmount);
|
||||
sb.append(",amount:");
|
||||
sb.append(shiftAmount);
|
||||
sb.append(",xmrtoQueryOrderToken:");
|
||||
sb.append(xmrtoQueryOrderToken);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public boolean validateAddress(@NonNull String address) {
|
||||
if ((btcSymbol == null) || (btcAddress == null)) return false;
|
||||
final Crypto crypto = Crypto.withSymbol(btcSymbol);
|
||||
if (crypto == null) return false;
|
||||
if (crypto.isCasefull()) { // compare as-is
|
||||
return address.equals(btcAddress);
|
||||
} else { // normalize & compare (e.g. ETH with and without checksum capitals
|
||||
return address.toLowerCase().equals(btcAddress.toLowerCase());
|
||||
return address.equalsIgnoreCase(btcAddress);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@
|
||||
|
||||
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 java.util.regex.Matcher;
|
||||
@@ -61,7 +61,7 @@ public class UserNotes {
|
||||
|
||||
public void setXmrtoOrder(CreateOrder order) {
|
||||
if (order != null) {
|
||||
xmrtoTag = order.TAG;
|
||||
xmrtoTag = order.getTag();
|
||||
xmrtoKey = order.getOrderId();
|
||||
xmrtoAmount = Helper.getDisplayAmount(order.getBtcAmount());
|
||||
xmrtoCurrency = order.getBtcCurrency();
|
||||
|
@@ -20,10 +20,10 @@ import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
@@ -57,13 +57,14 @@ public class AboutFragment extends DialogFragment {
|
||||
AboutFragment.newInstance().show(ft, TAG);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
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.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)
|
||||
.setNegativeButton(R.string.about_close,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@@ -77,7 +78,7 @@ public class AboutFragment extends DialogFragment {
|
||||
|
||||
private String getLicencesHtml() {
|
||||
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();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null)
|
||||
|
@@ -20,10 +20,10 @@ import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
@@ -49,13 +49,14 @@ public class CreditsFragment extends DialogFragment {
|
||||
CreditsFragment.newInstance().show(ft, TAG);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
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)));
|
||||
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity())
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setView(view)
|
||||
.setNegativeButton(R.string.about_close,
|
||||
new DialogInterface.OnClickListener() {
|
||||
|
@@ -16,13 +16,13 @@
|
||||
|
||||
package com.m2049r.xmrwallet.dialog;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.text.Spanned;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
@@ -65,9 +65,10 @@ public class HelpFragment extends DialogFragment {
|
||||
|
||||
private Spanned getHtml(String html, double textSize) {
|
||||
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
|
||||
final Drawable drawable = ContextCompat.getDrawable(requireActivity(), imageId > 0 ? imageId : R.drawable.ic_favorite_24dp);
|
||||
assert drawable != null;
|
||||
final double f = textSize / drawable.getIntrinsicHeight();
|
||||
drawable.setBounds(0, 0, (int) (f * drawable.getIntrinsicWidth()), (int) textSize);
|
||||
return drawable;
|
||||
@@ -82,7 +83,7 @@ public class HelpFragment extends DialogFragment {
|
||||
@NonNull
|
||||
@Override
|
||||
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;
|
||||
boolean torButton = false;
|
||||
@@ -100,7 +101,7 @@ public class HelpFragment extends DialogFragment {
|
||||
.setView(view);
|
||||
if (torButton) {
|
||||
builder.setNegativeButton(R.string.help_nok,
|
||||
(dialog, id) -> dialog.dismiss())
|
||||
(dialog, id) -> dialog.dismiss())
|
||||
.setPositiveButton(R.string.help_getorbot,
|
||||
(dialog, id) -> {
|
||||
dialog.dismiss();
|
||||
|
@@ -18,7 +18,6 @@ package com.m2049r.xmrwallet.dialog;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
@@ -66,7 +65,7 @@ public class PocketChangeFragment extends DialogFragment implements Slider.OnCha
|
||||
@NonNull
|
||||
@Override
|
||||
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;
|
||||
int progress = 0;
|
||||
Bundle arguments = getArguments();
|
||||
|
@@ -20,10 +20,10 @@ import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
@@ -49,13 +49,14 @@ public class PrivacyFragment extends DialogFragment {
|
||||
PrivacyFragment.newInstance().show(ft, TAG);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
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)));
|
||||
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity())
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireActivity())
|
||||
.setView(view)
|
||||
.setNegativeButton(R.string.about_close,
|
||||
new DialogInterface.OnClickListener() {
|
||||
|
@@ -17,6 +17,7 @@ package com.m2049r.xmrwallet.dialog;
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -31,6 +32,7 @@ import com.m2049r.xmrwallet.R;
|
||||
import com.m2049r.xmrwallet.util.Helper;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
@@ -56,7 +58,7 @@ public class ProgressDialog extends AlertDialog {
|
||||
|
||||
@Override
|
||||
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);
|
||||
tvMessage = view.findViewById(R.id.tvMessage);
|
||||
rlProgressBar = view.findViewById(R.id.rlProgressBar);
|
||||
@@ -78,7 +80,7 @@ public class ProgressDialog extends AlertDialog {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -23,8 +23,6 @@ import android.view.ViewGroup;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.material.progressindicator.LinearProgressIndicator;
|
||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||
import com.m2049r.xmrwallet.R;
|
||||
import com.m2049r.xmrwallet.data.BarcodeData;
|
||||
import com.m2049r.xmrwallet.data.TxData;
|
||||
@@ -38,17 +36,13 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
||||
|
||||
public static SendAmountWizardFragment newInstance(Listener listener) {
|
||||
SendAmountWizardFragment instance = new SendAmountWizardFragment();
|
||||
instance.setSendListener(listener);
|
||||
instance.sendListener = listener;
|
||||
return instance;
|
||||
}
|
||||
|
||||
Listener sendListener;
|
||||
private Listener sendListener;
|
||||
|
||||
public void setSendListener(Listener listener) {
|
||||
this.sendListener = listener;
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
public interface Listener {
|
||||
SendFragment.Listener getActivityCallback();
|
||||
|
||||
TxData getTxData();
|
||||
@@ -139,7 +133,7 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
||||
public void onResumeFragment() {
|
||||
super.onResumeFragment();
|
||||
Timber.d("onResumeFragment()");
|
||||
Helper.showKeyboard(getActivity());
|
||||
Helper.showKeyboard(requireActivity());
|
||||
final long funds = getTotalFunds();
|
||||
maxFunds = 1.0 * funds / Helper.ONE_XMR;
|
||||
if (!sendListener.getActivityCallback().isStreetMode()) {
|
||||
@@ -150,8 +144,8 @@ public class SendAmountWizardFragment extends SendWizardFragment {
|
||||
getString(R.string.unknown_amount)));
|
||||
}
|
||||
final BarcodeData data = sendListener.popBarcodeData();
|
||||
if ((data != null) && (data.amount != null)) {
|
||||
etAmount.setAmount(data.amount);
|
||||
if ((data != null) && (data.getAmount() != null)) {
|
||||
etAmount.setAmount(data.getAmount());
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user