mirror of
https://codeberg.org/anoncontributorxmr/mysu.git
synced 2024-11-29 10:43:15 +00:00
add ability to scan QR codes
This commit is contained in:
parent
fcadb39b76
commit
4089e22bc5
7 changed files with 104 additions and 29 deletions
|
@ -108,8 +108,8 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_9
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_9
|
||||||
}
|
}
|
||||||
namespace 'com.m2049r.xmrwallet'
|
namespace 'com.m2049r.xmrwallet'
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
|
@ -135,7 +135,7 @@ dependencies {
|
||||||
|
|
||||||
implementation 'com.google.android.material:material:1.6.0'
|
implementation 'com.google.android.material:material:1.6.0'
|
||||||
|
|
||||||
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
|
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
|
||||||
implementation "com.squareup.okhttp3:okhttp:4.9.3"
|
implementation "com.squareup.okhttp3:okhttp:4.9.3"
|
||||||
implementation "io.github.rburgst:okhttp-digest:2.6"
|
implementation "io.github.rburgst:okhttp-digest:2.6"
|
||||||
implementation "com.jakewharton.timber:timber:5.0.1"
|
implementation "com.jakewharton.timber:timber:5.0.1"
|
||||||
|
|
|
@ -1,32 +1,11 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="com.m2049r.xmrwallet">
|
package="com.m2049r.xmrwallet">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
|
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
|
||||||
<uses-permission android:name="android.permission.NFC" />
|
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
||||||
|
|
||||||
<queries>
|
|
||||||
<intent>
|
|
||||||
<action android:name="org.torproject.android.intent.action.START" />
|
|
||||||
</intent>
|
|
||||||
<intent>
|
|
||||||
<action android:name="org.torproject.android.intent.action.STATUS" />
|
|
||||||
</intent>
|
|
||||||
<intent>
|
|
||||||
<action android:name="org.torproject.android.REQUEST_HS_PORT" />
|
|
||||||
</intent>
|
|
||||||
<intent>
|
|
||||||
<action android:name="org.torproject.android.REQUEST_V3_ONION_SERVICE" />
|
|
||||||
</intent>
|
|
||||||
|
|
||||||
<package android:name="org.torproject.android" />
|
|
||||||
</queries>
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".MoneroApplication"
|
android:name=".MoneroApplication"
|
||||||
|
@ -46,6 +25,11 @@
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name="com.journeyapps.barcodescanner.CaptureActivity"
|
||||||
|
android:screenOrientation="portrait"
|
||||||
|
tools:replace="android:screenOrientation"
|
||||||
|
android:stateNotNeeded="true"/>
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="${applicationId}.fileprovider"
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
package com.m2049r.xmrwallet.fragment.dialog;
|
package com.m2049r.xmrwallet.fragment.dialog;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||||
|
import com.google.zxing.client.android.Intents;
|
||||||
|
import com.journeyapps.barcodescanner.ScanContract;
|
||||||
|
import com.journeyapps.barcodescanner.ScanOptions;
|
||||||
import com.m2049r.xmrwallet.R;
|
import com.m2049r.xmrwallet.R;
|
||||||
import com.m2049r.xmrwallet.model.PendingTransaction;
|
import com.m2049r.xmrwallet.model.PendingTransaction;
|
||||||
import com.m2049r.xmrwallet.model.Wallet;
|
import com.m2049r.xmrwallet.model.Wallet;
|
||||||
|
@ -20,12 +25,32 @@ import android.widget.ImageButton;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class SendBottomSheetDialog extends BottomSheetDialogFragment {
|
public class SendBottomSheetDialog extends BottomSheetDialogFragment {
|
||||||
|
private final ActivityResultLauncher<ScanOptions> barcodeLauncher = registerForActivityResult(new ScanContract(),
|
||||||
|
result -> {
|
||||||
|
if(result.getContents() != null) {
|
||||||
|
pasteAddress(result.getContents());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<String> cameraPermissionsLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(),
|
||||||
|
granted -> {
|
||||||
|
if(granted) {
|
||||||
|
onScan();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.no_camera_permission), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
private MutableLiveData<Boolean> _sendingMax = new MutableLiveData<>(false);
|
private MutableLiveData<Boolean> _sendingMax = new MutableLiveData<>(false);
|
||||||
public LiveData<Boolean> sendingMax = _sendingMax;
|
public LiveData<Boolean> sendingMax = _sendingMax;
|
||||||
private MutableLiveData<PendingTransaction> _pendingTransaction = new MutableLiveData<>(null);
|
private MutableLiveData<PendingTransaction> _pendingTransaction = new MutableLiveData<>(null);
|
||||||
|
@ -41,6 +66,7 @@ public class SendBottomSheetDialog extends BottomSheetDialogFragment {
|
||||||
private Button sendButton;
|
private Button sendButton;
|
||||||
private Button sendMaxButton;
|
private Button sendMaxButton;
|
||||||
private ImageButton pasteAddressImageButton;
|
private ImageButton pasteAddressImageButton;
|
||||||
|
private ImageButton scanAddressImageButton;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
|
@ -51,6 +77,7 @@ public class SendBottomSheetDialog extends BottomSheetDialogFragment {
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
pasteAddressImageButton = view.findViewById(R.id.paste_address_imagebutton);
|
pasteAddressImageButton = view.findViewById(R.id.paste_address_imagebutton);
|
||||||
|
scanAddressImageButton = view.findViewById(R.id.scan_address_imagebutton);
|
||||||
sendMaxButton = view.findViewById(R.id.send_max_button);
|
sendMaxButton = view.findViewById(R.id.send_max_button);
|
||||||
addressEditText = view.findViewById(R.id.address_edittext);
|
addressEditText = view.findViewById(R.id.address_edittext);
|
||||||
amountEditText = view.findViewById(R.id.amount_edittext);
|
amountEditText = view.findViewById(R.id.amount_edittext);
|
||||||
|
@ -62,7 +89,14 @@ public class SendBottomSheetDialog extends BottomSheetDialogFragment {
|
||||||
amountTextView = view.findViewById(R.id.amount_pending_textview);
|
amountTextView = view.findViewById(R.id.amount_pending_textview);
|
||||||
|
|
||||||
pasteAddressImageButton.setOnClickListener(view1 -> {
|
pasteAddressImageButton.setOnClickListener(view1 -> {
|
||||||
addressEditText.setText(Helper.getClipBoardText(view.getContext()));
|
Context ctx = getContext();
|
||||||
|
if(ctx != null) {
|
||||||
|
pasteAddress(Helper.getClipBoardText(getContext()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
scanAddressImageButton.setOnClickListener(view1 -> {
|
||||||
|
onScan();
|
||||||
});
|
});
|
||||||
|
|
||||||
sendMaxButton.setOnClickListener(view1 -> {
|
sendMaxButton.setOnClickListener(view1 -> {
|
||||||
|
@ -127,6 +161,17 @@ public class SendBottomSheetDialog extends BottomSheetDialogFragment {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onScan() {
|
||||||
|
if (Helper.getCameraPermission(getActivity(), cameraPermissionsLauncher)) {
|
||||||
|
ScanOptions options = new ScanOptions();
|
||||||
|
options.setBeepEnabled(false);
|
||||||
|
options.setOrientationLocked(true);
|
||||||
|
options.setDesiredBarcodeFormats(List.of(Intents.Scan.QR_CODE_MODE));
|
||||||
|
options.addExtra(Intents.Scan.SCAN_TYPE, Intents.Scan.MIXED_SCAN);
|
||||||
|
barcodeLauncher.launch(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void sendTx(PendingTransaction pendingTx) {
|
private void sendTx(PendingTransaction pendingTx) {
|
||||||
AsyncTask.execute(() -> {
|
AsyncTask.execute(() -> {
|
||||||
boolean success = TxService.getInstance().sendTx(pendingTx);
|
boolean success = TxService.getInstance().sendTx(pendingTx);
|
||||||
|
@ -171,6 +216,7 @@ public class SendBottomSheetDialog extends BottomSheetDialogFragment {
|
||||||
createButton.setVisibility(View.GONE);
|
createButton.setVisibility(View.GONE);
|
||||||
sendMaxButton.setVisibility(View.GONE);
|
sendMaxButton.setVisibility(View.GONE);
|
||||||
pasteAddressImageButton.setVisibility(View.GONE);
|
pasteAddressImageButton.setVisibility(View.GONE);
|
||||||
|
scanAddressImageButton.setVisibility(View.GONE);
|
||||||
feeTextView.setVisibility(View.VISIBLE);
|
feeTextView.setVisibility(View.VISIBLE);
|
||||||
addressTextView.setVisibility(View.VISIBLE);
|
addressTextView.setVisibility(View.VISIBLE);
|
||||||
amountTextView.setVisibility(View.VISIBLE);
|
amountTextView.setVisibility(View.VISIBLE);
|
||||||
|
@ -182,9 +228,20 @@ public class SendBottomSheetDialog extends BottomSheetDialogFragment {
|
||||||
createButton.setVisibility(View.VISIBLE);
|
createButton.setVisibility(View.VISIBLE);
|
||||||
sendMaxButton.setVisibility(View.VISIBLE);
|
sendMaxButton.setVisibility(View.VISIBLE);
|
||||||
pasteAddressImageButton.setVisibility(View.VISIBLE);
|
pasteAddressImageButton.setVisibility(View.VISIBLE);
|
||||||
|
scanAddressImageButton.setVisibility(View.VISIBLE);
|
||||||
feeTextView.setVisibility(View.GONE);
|
feeTextView.setVisibility(View.GONE);
|
||||||
addressTextView.setVisibility(View.GONE);
|
addressTextView.setVisibility(View.GONE);
|
||||||
amountTextView.setVisibility(View.GONE);
|
amountTextView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void pasteAddress(String address) {
|
||||||
|
String modifiedAddress = address.replace("monero:", "").split("\\?")[0];
|
||||||
|
boolean isValid = Wallet.isAddressValid(modifiedAddress);
|
||||||
|
if(isValid) {
|
||||||
|
addressEditText.setText(modifiedAddress);
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getActivity(), getString(R.string.send_address_invalid), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -41,6 +41,7 @@ import android.view.animation.AnimationUtils;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
|
@ -114,6 +115,21 @@ public class Helper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static public boolean getCameraPermission(Activity context, ActivityResultLauncher<String> launcher) {
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
|
||||||
|
if (context.checkSelfPermission(Manifest.permission.CAMERA)
|
||||||
|
== PackageManager.PERMISSION_DENIED) {
|
||||||
|
Timber.w("Permission denied for CAMERA - requesting it");
|
||||||
|
launcher.launch(Manifest.permission.CAMERA);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static public File getWalletFile(Context context, String aWalletName) {
|
static public File getWalletFile(Context context, String aWalletName) {
|
||||||
File walletDir = getWalletRoot(context);
|
File walletDir = getWalletRoot(context);
|
||||||
File f = new File(walletDir, aWalletName);
|
File f = new File(walletDir, aWalletName);
|
||||||
|
|
|
@ -4,6 +4,6 @@
|
||||||
android:viewportWidth="30.0"
|
android:viewportWidth="30.0"
|
||||||
android:viewportHeight="30.0">
|
android:viewportHeight="30.0">
|
||||||
<path
|
<path
|
||||||
android:fillColor="?attr/colorPrimaryVariant"
|
android:fillColor="@color/oled_textColorPrimary"
|
||||||
android:pathData="M26.667,27.996L27.991,26.667L27.991,20L30,20L30,26.667C30,28.5 28.5,30 26.667,30L20,30L20,27.996L26.667,27.996ZM3.333,27.996L10,27.996L10,30L3.333,30C1.5,30 0,28.5 0,26.667L0,20L2.009,20L2.009,26.667L3.333,27.996ZM26.667,2.004L20,2.004L20,0L26.667,0C28.5,0 30,1.5 30,3.333L30,10L27.991,10L27.991,3.333L26.667,2.004ZM3.333,2.004L2.009,3.333L2.009,10L0,10L0,3.333C0,1.5 1.5,0 3.333,0L10,0L10,2.004L3.333,2.004Z" />
|
android:pathData="M26.667,27.996L27.991,26.667L27.991,20L30,20L30,26.667C30,28.5 28.5,30 26.667,30L20,30L20,27.996L26.667,27.996ZM3.333,27.996L10,27.996L10,30L3.333,30C1.5,30 0,28.5 0,26.667L0,20L2.009,20L2.009,26.667L3.333,27.996ZM26.667,2.004L20,2.004L20,0L26.667,0C28.5,0 30,1.5 30,3.333L30,10L27.991,10L27.991,3.333L26.667,2.004ZM3.333,2.004L2.009,3.333L2.009,10L0,10L0,3.333C0,1.5 1.5,0 3.333,0L10,0L10,2.004L3.333,2.004Z" />
|
||||||
</vector>
|
</vector>
|
||||||
|
|
|
@ -48,15 +48,32 @@
|
||||||
android:id="@+id/paste_address_imagebutton"
|
android:id="@+id/paste_address_imagebutton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:minWidth="48dp"
|
||||||
|
android:minHeight="48dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:src="@drawable/ic_content_paste_24dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/address_edittext"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/scan_address_imagebutton"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/address_edittext"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/address_edittext"
|
||||||
|
tools:ignore="SpeakableTextPresentCheck"
|
||||||
|
tools:visibility="gone" />
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/scan_address_imagebutton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:minWidth="48dp"
|
android:minWidth="48dp"
|
||||||
android:minHeight="48dp"
|
android:minHeight="48dp"
|
||||||
android:padding="8dp"
|
android:padding="8dp"
|
||||||
android:src="@drawable/ic_content_paste_24dp"
|
android:src="@drawable/ic_scan"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/address_edittext"
|
app:layout_constraintBottom_toBottomOf="@id/address_edittext"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/address_edittext"
|
app:layout_constraintStart_toEndOf="@id/paste_address_imagebutton"
|
||||||
app:layout_constraintTop_toTopOf="@id/address_edittext"
|
app:layout_constraintTop_toTopOf="@id/address_edittext"
|
||||||
tools:ignore="SpeakableTextPresentCheck"
|
tools:ignore="SpeakableTextPresentCheck"
|
||||||
tools:visibility="gone" />
|
tools:visibility="gone" />
|
||||||
|
|
|
@ -571,4 +571,5 @@
|
||||||
<string name="creating_tx">Creating transaction…</string>
|
<string name="creating_tx">Creating transaction…</string>
|
||||||
<string name="sending_tx">Sending transaction…</string>
|
<string name="sending_tx">Sending transaction…</string>
|
||||||
<string name="sent_tx">Sent transaction!</string>
|
<string name="sent_tx">Sent transaction!</string>
|
||||||
|
<string name="no_camera_permission">No camera permission</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue