From f5535dbefa90d662b13485eb583d1f1349b41e22 Mon Sep 17 00:00:00 2001 From: m2049r <30435443+m2049r@users.noreply.github.com> Date: Wed, 30 Aug 2017 19:54:27 +0200 Subject: [PATCH] QR Scanning incl. payment id --- .idea/libraries/core_1_9_8.xml | 10 ++ .idea/libraries/core_3_3_0.xml | 11 ++ .idea/libraries/zxing_1_9_8.xml | 10 ++ app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 1 + .../com/m2049r/xmrwallet/ScannerFragment.java | 131 ++++++++++++++++++ .../com/m2049r/xmrwallet/SendFragment.java | 60 +++++++- .../com/m2049r/xmrwallet/WalletActivity.java | 64 ++++++++- .../xmrwallet/service/WalletService.java | 1 + .../m2049r/xmrwallet/util/BarcodeData.java | 28 ++++ .../com/m2049r/xmrwallet/util/Helper.java | 29 ++++ app/src/main/res/layout/send_fragment.xml | 107 ++++++++------ app/src/main/res/values/strings.xml | 9 +- 13 files changed, 411 insertions(+), 51 deletions(-) create mode 100644 .idea/libraries/core_1_9_8.xml create mode 100644 .idea/libraries/core_3_3_0.xml create mode 100644 .idea/libraries/zxing_1_9_8.xml create mode 100644 app/src/main/java/com/m2049r/xmrwallet/ScannerFragment.java create mode 100644 app/src/main/java/com/m2049r/xmrwallet/util/BarcodeData.java diff --git a/.idea/libraries/core_1_9_8.xml b/.idea/libraries/core_1_9_8.xml new file mode 100644 index 00000000..0be1e35c --- /dev/null +++ b/.idea/libraries/core_1_9_8.xml @@ -0,0 +1,10 @@ +<component name="libraryTable"> + <library name="core-1.9.8"> + <CLASSES> + <root url="jar://$USER_HOME$/.android/build-cache/db7eb580bfa6467818ef12c5f1fa42273b50aa3a/output/jars/classes.jar!/" /> + <root url="file://$USER_HOME$/.android/build-cache/db7eb580bfa6467818ef12c5f1fa42273b50aa3a/output/res" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file diff --git a/.idea/libraries/core_3_3_0.xml b/.idea/libraries/core_3_3_0.xml new file mode 100644 index 00000000..de46baa5 --- /dev/null +++ b/.idea/libraries/core_3_3_0.xml @@ -0,0 +1,11 @@ +<component name="libraryTable"> + <library name="core-3.3.0"> + <CLASSES> + <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.zxing/core/3.3.0/73c49077166faa4c3c0059c5f583d1d7bd1475fe/core-3.3.0.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.zxing/core/3.3.0/39d966e052e28fc7d83793b02e0af97ccf955745/core-3.3.0-sources.jar!/" /> + </SOURCES> + </library> +</component> \ No newline at end of file diff --git a/.idea/libraries/zxing_1_9_8.xml b/.idea/libraries/zxing_1_9_8.xml new file mode 100644 index 00000000..e9af3efd --- /dev/null +++ b/.idea/libraries/zxing_1_9_8.xml @@ -0,0 +1,10 @@ +<component name="libraryTable"> + <library name="zxing-1.9.8"> + <CLASSES> + <root url="jar://$USER_HOME$/.android/build-cache/8d8f2e0e10c7af73321454f6fa481e8e5438e654/output/jars/classes.jar!/" /> + <root url="file://$USER_HOME$/.android/build-cache/8d8f2e0e10c7af73321454f6fa481e8e5438e654/output/res" /> + </CLASSES> + <JAVADOC /> + <SOURCES /> + </library> +</component> \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index ecd41f6e..36a9850f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -46,5 +46,6 @@ dependencies { compile 'com.android.support:support-v4:25.3.1' compile 'com.android.support:recyclerview-v7:25.3.1' compile 'com.android.support:cardview-v7:25.3.1' + compile 'me.dm7.barcodescanner:zxing:1.9.8' testCompile 'junit:junit:4.12' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0d7245cd..0f9eb50f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> + <uses-permission android:name="android.permission.CAMERA" /> <application android:allowBackup="true" diff --git a/app/src/main/java/com/m2049r/xmrwallet/ScannerFragment.java b/app/src/main/java/com/m2049r/xmrwallet/ScannerFragment.java new file mode 100644 index 00000000..9678a317 --- /dev/null +++ b/app/src/main/java/com/m2049r/xmrwallet/ScannerFragment.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2017 dm77, 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; + +import android.app.Fragment; +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toast; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.Result; +import com.m2049r.xmrwallet.model.WalletManager; +import com.m2049r.xmrwallet.util.Helper; + +import me.dm7.barcodescanner.zxing.ZXingScannerView; + +public class ScannerFragment extends Fragment implements ZXingScannerView.ResultHandler { + static final String TAG = "ScannerFragment"; + + Listener activityCallback; + + public interface Listener { + void onAddressScanned(String address, String paymentId); + + boolean isPaymentIdValid(String paymentId); + } + + private ZXingScannerView mScannerView; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + Log.d(TAG, "onCreateView"); + mScannerView = new ZXingScannerView(getActivity()); + return mScannerView; + } + + @Override + public void onResume() { + super.onResume(); + Log.d(TAG, "onResume"); + mScannerView.setResultHandler(this); + mScannerView.startCamera(); + } + + static final String URI_PREFIX = "monero:"; + static final String PAYMENTID_STRING = "?tx_payment_id="; + + @Override + public void handleResult(Result rawResult) { + Log.d(TAG, rawResult.getBarcodeFormat().toString() + "/" + rawResult.getText()); + String text = rawResult.getText(); + if ((rawResult.getBarcodeFormat() == BarcodeFormat.QR_CODE) && + (text.startsWith(URI_PREFIX))) { + String address = null; + String paymentId = null; + String s = text.substring(URI_PREFIX.length()); + if (s.length() == 95) { + address = s; + } else { + int i = s.indexOf(PAYMENTID_STRING); + if ((i == 95) && (s.length() == (95 + PAYMENTID_STRING.length() + 16))) { + address = s.substring(0, 95); + paymentId = s.substring(95 + PAYMENTID_STRING.length()); + if (!activityCallback.isPaymentIdValid(paymentId)) { + address = null; + } + } + } + if (Helper.isAddressOk(address, WalletManager.getInstance().isTestNet())) { + activityCallback.onAddressScanned(address, paymentId); + return; + } else { + Toast.makeText(getActivity(), getString(R.string.send_qr_address_invalid), Toast.LENGTH_SHORT).show(); + } + } else { + Toast.makeText(getActivity(), getString(R.string.send_qr_invalid), Toast.LENGTH_SHORT).show(); + } + + // Note from dm77: + // * Wait 2 seconds to resume the preview. + // * On older devices continuously stopping and resuming camera preview can result in freezing the app. + // * I don't know why this is the case but I don't have the time to figure out. + Handler handler = new Handler(); + handler.postDelayed(new + + Runnable() { + @Override + public void run() { + mScannerView.resumeCameraPreview(ScannerFragment.this); + } + }, 2000); + } + + @Override + public void onPause() { + Log.d(TAG, "onPause"); + mScannerView.stopCamera(); + super.onPause(); + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + Log.d(TAG, "attaching scan"); + if (context instanceof Listener) { + this.activityCallback = (Listener) context; + } else { + throw new ClassCastException(context.toString() + + " must implement Listener"); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/m2049r/xmrwallet/SendFragment.java b/app/src/main/java/com/m2049r/xmrwallet/SendFragment.java index 5a9ae094..d88b5c89 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/SendFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/SendFragment.java @@ -20,10 +20,12 @@ import android.app.Fragment; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; +import android.os.Handler; import android.support.v7.app.AlertDialog; import android.text.Editable; import android.text.InputType; import android.text.TextWatcher; +import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -40,14 +42,16 @@ import com.m2049r.xmrwallet.model.PendingTransaction; import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.WalletManager; import com.m2049r.xmrwallet.util.Helper; +import com.m2049r.xmrwallet.util.BarcodeData; import com.m2049r.xmrwallet.util.TxData; public class SendFragment extends Fragment { - static final String TAG = "GenerateFragment"; + static final String TAG = "SendFragment"; EditText etAddress; EditText etPaymentId; EditText etAmount; + Button bAddress; Button bSweep; Spinner sMixin; Spinner sPriority; @@ -80,6 +84,7 @@ public class SendFragment extends Fragment { etAddress = (EditText) view.findViewById(R.id.etAddress); etPaymentId = (EditText) view.findViewById(R.id.etPaymentId); etAmount = (EditText) view.findViewById(R.id.etAmount); + bAddress = (Button) view.findViewById(R.id.bAddress); bSweep = (Button) view.findViewById(R.id.bSweep); bPrepareSend = (Button) view.findViewById(R.id.bPrepareSend); bPaymentId = (Button) view.findViewById(R.id.bPaymentId); @@ -194,6 +199,13 @@ public class SendFragment extends Fragment { } }); + bAddress.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + activityCallback.onScanAddress(); + } + }); + bPaymentId.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -231,7 +243,14 @@ public class SendFragment extends Fragment { if (testnet) { send(); } else { - bReallySend.setVisibility(View.VISIBLE); + etNotes.setEnabled(false); + Handler handler = new Handler(); + handler.postDelayed(new Runnable() { + @Override + public void run() { + bReallySend.setVisibility(View.VISIBLE); + } + }, 1000); } } }); @@ -256,11 +275,7 @@ public class SendFragment extends Fragment { private boolean addressOk() { String address = etAddress.getText().toString(); - if (WalletManager.getInstance().isTestNet()) { - return ((address.length() == 95) && ("9A".indexOf(address.charAt(0)) >= 0)); - } else { - return ((address.length() == 95) && ("4".indexOf(address.charAt(0)) >= 0)); - } + return Helper.isAddressOk(address, WalletManager.getInstance().isTestNet()); } private boolean amountOk() { @@ -321,6 +336,8 @@ public class SendFragment extends Fragment { bSweep.setEnabled(true); bPrepareSend.setEnabled(true); llConfirmSend.setVisibility(View.GONE); + bSend.setEnabled(true); + etNotes.setEnabled(true); bReallySend.setVisibility(View.GONE); } @@ -347,6 +364,35 @@ public class SendFragment extends Fragment { void onDisposeRequest(); + void onScanAddress(); + + BarcodeData getScannedData(); + + } + + @Override + public void onResume() { + super.onResume(); + BarcodeData data = activityCallback.getScannedData(); + if (data != null) { + String scannedAddress = data.address; + if (scannedAddress != null) { + etAddress.setText(scannedAddress); + } + String scannedPaymenId = data.paymentId; + if (scannedPaymenId != null) { + etPaymentId.setText(scannedPaymenId); + } + } + // jump to first empty field + if (etAddress.getText().toString().isEmpty()) { + etAddress.requestFocus(); + } else if (etPaymentId.getText().toString().isEmpty()) { + etPaymentId.requestFocus(); + } else { + etAmount.requestFocus(); + } + Log.d(TAG, "onResume"); } @Override diff --git a/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java b/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java index e7511131..b5c1d054 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java +++ b/app/src/main/java/com/m2049r/xmrwallet/WalletActivity.java @@ -23,9 +23,11 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.pm.PackageManager; import android.os.Bundle; import android.os.IBinder; import android.os.PowerManager; +import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; @@ -39,10 +41,14 @@ import com.m2049r.xmrwallet.model.TransactionInfo; import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.WalletManager; import com.m2049r.xmrwallet.service.WalletService; +import com.m2049r.xmrwallet.util.BarcodeData; +import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.TxData; public class WalletActivity extends AppCompatActivity implements WalletFragment.Listener, - WalletService.Observer, SendFragment.Listener, TxFragment.Listener, GenerateReviewFragment.ListenerWithWallet { + WalletService.Observer, SendFragment.Listener, TxFragment.Listener, + GenerateReviewFragment.ListenerWithWallet, + ScannerFragment.Listener { private static final String TAG = "WalletActivity"; public static final String REQUEST_ID = "id"; @@ -596,4 +602,60 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment. public void onDisposeRequest() { getWallet().disposePendingTransaction(); } + + + private void startScanFragment() { + Fragment fragment = getFragmentManager().findFragmentById(R.id.fragment_container); + if (fragment instanceof SendFragment) { + Bundle extras = new Bundle(); + replaceFragment(new ScannerFragment(), null, extras); + } + } + + /// QR scanner callbacks + @Override + public void onScanAddress() { + if (Helper.getCameraPermission(this)) { + startScanFragment(); + } else { + Log.i(TAG, "Waiting for permissions"); + } + + } + + private BarcodeData scannedData = null; + + @Override + public void onAddressScanned(String address, String paymentId) { + // Log.d(TAG, "got " + address); + scannedData = new BarcodeData(address, paymentId); + popFragmentStack(null); + } + + @Override + public BarcodeData getScannedData() { + BarcodeData data = scannedData; + scannedData = null; + return data; + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) { + Log.d(TAG, "onRequestPermissionsResult()"); + switch (requestCode) { + case Helper.PERMISSIONS_REQUEST_CAMERA: + // If request is cancelled, the result arrays are empty. + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + startScanFragment(); + } else { + String msg = getString(R.string.message_camera_not_permitted); + Log.e(TAG, msg); + Toast.makeText(this, msg, Toast.LENGTH_LONG).show(); + } + break; + default: + } + } + } \ No newline at end of file diff --git a/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java b/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java index 22d67d0d..374c83c0 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java +++ b/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java @@ -127,6 +127,7 @@ public class WalletService extends Service { boolean fullRefresh = false; updateDaemonState(wallet, wallet.isSynchronized() ? height : 0); if (!wallet.isSynchronized()) { + updated = true; // we want to see our transactions as they come in wallet.getHistory().refresh(); int txCount = wallet.getHistory().getCount(); diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/BarcodeData.java b/app/src/main/java/com/m2049r/xmrwallet/util/BarcodeData.java new file mode 100644 index 00000000..6c94c490 --- /dev/null +++ b/app/src/main/java/com/m2049r/xmrwallet/util/BarcodeData.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2017 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.util; + +public class BarcodeData { + public String address = null; + public String paymentId = null; + //String amount = null: + + public BarcodeData(String address, String paymentId) { + this.address = address; + this.paymentId = paymentId; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java b/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java index f3454527..e94064b1 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java +++ b/app/src/main/java/com/m2049r/xmrwallet/util/Helper.java @@ -27,6 +27,7 @@ import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import com.m2049r.xmrwallet.R; +import com.m2049r.xmrwallet.model.WalletManager; import java.io.File; @@ -71,6 +72,24 @@ public class Helper { } } + public static final int PERMISSIONS_REQUEST_CAMERA = 1; + + static public boolean getCameraPermission(Activity context) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { + if (context.checkSelfPermission(Manifest.permission.CAMERA) + == PackageManager.PERMISSION_DENIED) { + Log.d(TAG, "Permission denied for CAMERA - requesting it"); + String[] permissions = {Manifest.permission.CAMERA}; + context.requestPermissions(permissions, PERMISSIONS_REQUEST_CAMERA); + return false; + } else { + return true; + } + } else { + return true; + } + } + static public String getWalletPath(Context context, String aWalletName) { File walletDir = getStorageRoot(context); //d(TAG, "walletdir=" + walletDir.getAbsolutePath()); @@ -107,4 +126,14 @@ public class Helper { static public void hideKeyboardAlways(Activity act) { act.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); } + + static public boolean isAddressOk(String address, boolean testnet) { + if (address == null) return false; + if (testnet) { + return ((address.length() == 95) && ("9A".indexOf(address.charAt(0)) >= 0)); + } else { + return ((address.length() == 95) && ("4".indexOf(address.charAt(0)) >= 0)); + } + } + } diff --git a/app/src/main/res/layout/send_fragment.xml b/app/src/main/res/layout/send_fragment.xml index b1a15e9b..135132da 100644 --- a/app/src/main/res/layout/send_fragment.xml +++ b/app/src/main/res/layout/send_fragment.xml @@ -16,7 +16,7 @@ <Spinner android:id="@+id/sMixin" - android:layout_width="0dp" + android:layout_width="0sp" android:layout_height="match_parent" android:layout_weight="1" android:entries="@array/mixin" @@ -24,7 +24,7 @@ <Spinner android:id="@+id/sPriority" - android:layout_width="0dp" + android:layout_width="0sp" android:layout_height="match_parent" android:layout_weight="1" android:entries="@array/priority" @@ -32,25 +32,49 @@ </LinearLayout> - <EditText - android:id="@+id/etAddress" + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:hint="@string/send_address_hint" - android:imeOptions="actionNext" - android:inputType="textMultiLine" - android:textAlignment="center" - android:textSize="16sp" /> + android:orientation="horizontal" + android:layout_marginBottom="4sp" + android:layout_marginTop="4sp" + android:weightSum="10"> + + <EditText + android:id="@+id/etAddress" + android:layout_width="0sp" + android:layout_height="wrap_content" + android:layout_weight="8" + android:hint="@string/send_address_hint" + android:imeOptions="actionNext" + android:inputType="textMultiLine" + android:textAlignment="center" + android:textSize="16sp" /> + + <Button + android:id="@+id/bAddress" + android:layout_width="0sp" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:minHeight="36sp" + android:layout_weight="2" + android:background="@color/colorPrimary" + android:enabled="true" + android:text="@string/send_qr_hint" + android:textSize="12sp" /> + </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" + android:layout_marginBottom="4sp" + android:layout_marginTop="4sp" android:weightSum="10"> <EditText android:id="@+id/etPaymentId" - android:layout_width="0dp" + android:layout_width="0sp" android:layout_height="wrap_content" android:layout_weight="8" android:hint="@string/send_paymentid_hint" @@ -61,10 +85,10 @@ <Button android:id="@+id/bPaymentId" - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_marginBottom="8dp" - android:layout_marginTop="8dp" + android:layout_width="0sp" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:minHeight="36sp" android:layout_weight="2" android:background="@color/colorPrimary" android:enabled="true" @@ -76,11 +100,13 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" + android:layout_marginBottom="4sp" + android:layout_marginTop="4sp" android:weightSum="10"> <EditText android:id="@+id/etAmount" - android:layout_width="0dp" + android:layout_width="0sp" android:layout_height="wrap_content" android:layout_weight="8" android:hint="@string/send_amount_hint" @@ -91,10 +117,8 @@ <Button android:id="@+id/bSweep" - android:layout_width="0dp" + android:layout_width="0sp" android:layout_height="match_parent" - android:layout_marginBottom="8dp" - android:layout_marginTop="8dp" android:layout_weight="2" android:background="@color/colorPrimary" android:enabled="true" @@ -106,8 +130,9 @@ android:id="@+id/bPrepareSend" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="8dp" - android:layout_marginTop="8dp" + android:layout_marginBottom="4sp" + android:layout_marginTop="4sp" + android:minHeight="36sp" android:background="@color/colorPrimary" android:enabled="false" android:text="@string/send_prepare_hint" /> @@ -124,18 +149,19 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" + android:layout_marginBottom="4sp" + android:layout_marginTop="4sp" android:visibility="gone"> <Button android:id="@+id/bDispose" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="8dp" - android:layout_marginTop="8dp" + android:minHeight="36sp" + android:layout_marginBottom="4sp" android:background="@color/colorPrimary" android:text="@string/send_dispose_hint" /> - <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" @@ -144,9 +170,9 @@ <TextView android:id="@+id/tvTxAmountLabel" - android:layout_width="0dp" + android:layout_width="0sp" android:layout_height="wrap_content" - android:layout_marginRight="8dp" + android:layout_marginRight="8sp" android:layout_weight="1" android:text="@string/send_amount_label" android:textAlignment="textEnd" @@ -155,9 +181,9 @@ <TextView android:id="@+id/tvTxAmount" - android:layout_width="0dp" + android:layout_width="0sp" android:layout_height="wrap_content" - android:layout_marginLeft="8dp" + android:layout_marginLeft="8sp" android:layout_weight="2" android:textAlignment="textEnd" android:textSize="20sp" /> @@ -171,9 +197,9 @@ <TextView android:id="@+id/tvTxFeeLabel" - android:layout_width="0dp" + android:layout_width="0sp" android:layout_height="wrap_content" - android:layout_marginRight="8dp" + android:layout_marginRight="4sp" android:layout_weight="1" android:text="@string/send_fee_label" android:textAlignment="textEnd" @@ -182,9 +208,9 @@ <TextView android:id="@+id/tvTxFee" - android:layout_width="0dp" + android:layout_width="0sp" android:layout_height="wrap_content" - android:layout_marginLeft="8dp" + android:layout_marginLeft="8sp" android:layout_weight="2" android:textAlignment="textEnd" android:textSize="20sp" /> @@ -198,9 +224,9 @@ <TextView android:id="@+id/tvTxDustLabel" - android:layout_width="0dp" + android:layout_width="0sp" android:layout_height="wrap_content" - android:layout_marginRight="8dp" + android:layout_marginRight="8sp" android:layout_weight="1" android:text="@string/send_dust_label" android:textAlignment="textEnd" @@ -209,9 +235,9 @@ <TextView android:id="@+id/tvTxDust" - android:layout_width="0dp" + android:layout_width="0sp" android:layout_height="wrap_content" - android:layout_marginLeft="8dp" + android:layout_marginLeft="8sp" android:layout_weight="2" android:textAlignment="textEnd" android:textSize="20sp" /> @@ -221,7 +247,7 @@ android:id="@+id/etNotes" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="8dp" + android:layout_marginTop="4sp" android:hint="@string/send_notes_hint" android:imeOptions="actionDone" android:inputType="textMultiLine" @@ -232,8 +258,9 @@ android:id="@+id/bSend" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="8dp" - android:layout_marginTop="8dp" + android:layout_marginBottom="4sp" + android:layout_marginTop="4sp" + android:minHeight="36sp" android:background="@color/colorPrimary" android:text="@string/send_send_hint" /> @@ -241,8 +268,8 @@ android:id="@+id/bReallySend" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginBottom="8dp" - android:layout_marginTop="8dp" + android:layout_marginBottom="4sp" + android:layout_marginTop="4sp" android:background="@color/moneroOrange" android:text="@string/send_really_send_hint" android:visibility="gone" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1d3851a0..c1553fe2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,7 +5,7 @@ <string name="menu_info">Details</string> - <string name="prompt_daemon">[<user>:<pass>@]<daemonhost>[:<port>]</string> + <string name="prompt_daemon">[<user>:<pass>@]<daemon>[:<port>]</string> <string name="prompt_mainnet">Net Selection</string> <string name="connect_testnet">TestNet</string> <string name="connect_mainnet">MainNet</string> @@ -58,6 +58,7 @@ <string name="prompt_problems">Problems</string> <string name="message_strorage_not_writable">External Storage is not writable! Panic!</string> <string name="message_strorage_not_permitted">We really need those External Storage permissions!</string> + <string name="message_camera_not_permitted">No camera = No QR scanning!</string> <string name="generate_title">Create Wallet</string> <string name="generate_name_hint">Wallet Name</string> @@ -111,11 +112,13 @@ <string name="send_mixin_hint">Mixin</string> <string name="send_sweep_hint">Sweep</string> <string name="send_generate_paymentid_hint">Generate</string> + <string name="send_qr_hint">Scan</string> <string name="send_prepare_hint">Prepare</string> <string name="send_dispose_hint">Dispose (Undo)</string> <string name="send_send_hint">Spend my sweet Moneroj</string> - <string name="send_really_send_hint">I understand I am on mainnet\nTHis is real Monero!</string> - + <string name="send_really_send_hint">I understand I am sending real Monero!</string> + <string name="send_qr_invalid">Not a monero QR Code</string> + <string name="send_qr_address_invalid">Invalid Monero address</string> <string name="send_preparing_progress">Preparing transaction</string> <string name="send_amount_label">Amount</string>