support integrated address (excl. qr code) (#147)

UI & code tweaks
This commit is contained in:
m2049r 2017-12-05 07:48:59 +01:00 committed by GitHub
parent 22b4905828
commit 82c32d4442
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 186 additions and 70 deletions

View File

@ -8,8 +8,8 @@ android {
applicationId "com.m2049r.xmrwallet" applicationId "com.m2049r.xmrwallet"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 25 targetSdkVersion 25
versionCode 46 versionCode 47
versionName "1.2.6-alpha" versionName "1.2.7-alpha"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild { externalNativeBuild {
cmake { cmake {

View File

@ -41,6 +41,8 @@ import timber.log.Timber;
public class SendAddressWizardFragment extends SendWizardFragment { public class SendAddressWizardFragment extends SendWizardFragment {
static final int INTEGRATED_ADDRESS_LENGTH = 106;
public static SendAddressWizardFragment newInstance(Listener listener) { public static SendAddressWizardFragment newInstance(Listener listener) {
SendAddressWizardFragment instance = new SendAddressWizardFragment(); SendAddressWizardFragment instance = new SendAddressWizardFragment();
instance.setSendListener(listener); instance.setSendListener(listener);
@ -67,6 +69,8 @@ public class SendAddressWizardFragment extends SendWizardFragment {
private TextInputLayout etPaymentId; private TextInputLayout etPaymentId;
private Button bPaymentId; private Button bPaymentId;
private CardView cvScan; private CardView cvScan;
private View tvPaymentIdIntegrated;
private View llPaymentId;
private String scannedAmount = null; private String scannedAmount = null;
@ -85,8 +89,50 @@ public class SendAddressWizardFragment extends SendWizardFragment {
View view = inflater.inflate(R.layout.fragment_send_address, container, false); View view = inflater.inflate(R.layout.fragment_send_address, container, false);
tvPaymentIdIntegrated = view.findViewById(R.id.tvPaymentIdIntegrated);
llPaymentId = view.findViewById(R.id.llPaymentId);
etAddress = (TextInputLayout) view.findViewById(R.id.etAddress); etAddress = (TextInputLayout) view.findViewById(R.id.etAddress);
etAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); etAddress.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
etAddress.getEditText().setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if ((event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER)) || (actionId == EditorInfo.IME_ACTION_NEXT)) {
if (checkAddress()) {
if (llPaymentId.getVisibility() == View.VISIBLE) {
etPaymentId.requestFocus();
} else {
etDummy.requestFocus();
Helper.hideKeyboard(getActivity());
}
}
return true;
}
return false;
}
});
etAddress.getEditText().addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable editable) {
if ((etAddress.getEditText().getText().toString().length() == INTEGRATED_ADDRESS_LENGTH) &&
checkAddressNoError()) { // we have an integrated address
etPaymentId.getEditText().getText().clear();
llPaymentId.setVisibility(View.GONE);
tvPaymentIdIntegrated.setVisibility(View.VISIBLE);
} else { // we don't
llPaymentId.setVisibility(View.VISIBLE);
tvPaymentIdIntegrated.setVisibility(View.GONE);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
});
etPaymentId = (TextInputLayout) view.findViewById(R.id.etPaymentId); etPaymentId = (TextInputLayout) view.findViewById(R.id.etPaymentId);
etPaymentId.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); etPaymentId.getEditText().setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
@ -157,13 +203,24 @@ public class SendAddressWizardFragment extends SendWizardFragment {
return ok; return ok;
} }
private boolean isIntegratedAddress() {
String address = etAddress.getEditText().getText().toString();
return Wallet.isAddressValid(address, WalletManager.getInstance().isTestNet())
&& address.length() == 106;
}
private boolean checkPaymentId() { private boolean checkPaymentId() {
String paymentId = etPaymentId.getEditText().getText().toString(); String paymentId = etPaymentId.getEditText().getText().toString();
boolean ok = paymentId.isEmpty() || Wallet.isPaymentIdValid(paymentId); boolean ok = paymentId.isEmpty() || Wallet.isPaymentIdValid(paymentId);
if (!ok) { if (!ok) {
etPaymentId.setError(getString(R.string.receive_paymentid_invalid)); etPaymentId.setError(getString(R.string.receive_paymentid_invalid));
} else { } else {
etPaymentId.setError(null); if (!paymentId.isEmpty() && isIntegratedAddress()) {
ok = false;
etPaymentId.setError(getString(R.string.receive_integrated_paymentid_invalid));
} else {
etPaymentId.setError(null);
}
} }
return ok; return ok;
} }

View File

@ -46,7 +46,7 @@ public class SendAmountWizardFragment extends SendWizardFragment {
} }
interface Listener { interface Listener {
SendFragmentNew.Listener getActivityCallback(); SendFragment.Listener getActivityCallback();
void setAmount(final long amount); void setAmount(final long amount);

View File

@ -53,7 +53,7 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
} }
interface Listener { interface Listener {
SendFragmentNew.Listener getActivityCallback(); SendFragment.Listener getActivityCallback();
TxData getTxData(); TxData getTxData();
@ -70,7 +70,7 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
private TextView tvTxAmount; private TextView tvTxAmount;
private TextView tvTxFee; private TextView tvTxFee;
private TextView tvTxTotal; private TextView tvTxTotal;
private View pbProgress; private View llProgress;
private View bSend; private View bSend;
private View llConfirmSend; private View llConfirmSend;
private View pbProgressSend; private View pbProgressSend;
@ -91,7 +91,7 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
tvTxFee = (TextView) view.findViewById(R.id.tvTxFee); tvTxFee = (TextView) view.findViewById(R.id.tvTxFee);
tvTxTotal = (TextView) view.findViewById(R.id.tvTxTotal); tvTxTotal = (TextView) view.findViewById(R.id.tvTxTotal);
pbProgress = view.findViewById(R.id.pbProgress); llProgress = view.findViewById(R.id.llProgress);
pbProgressSend = view.findViewById(R.id.pbProgressSend); pbProgressSend = view.findViewById(R.id.pbProgressSend);
llConfirmSend = view.findViewById(R.id.llConfirmSend); llConfirmSend = view.findViewById(R.id.llConfirmSend);
@ -111,12 +111,12 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
boolean inProgress = false; boolean inProgress = false;
public void hideProgress() { public void hideProgress() {
pbProgress.setVisibility(View.INVISIBLE); llProgress.setVisibility(View.INVISIBLE);
inProgress = false; inProgress = false;
} }
public void showProgress() { public void showProgress() {
pbProgress.setVisibility(View.VISIBLE); llProgress.setVisibility(View.VISIBLE);
inProgress = true; inProgress = true;
} }
@ -300,7 +300,7 @@ public class SendConfirmWizardFragment extends SendWizardFragment {
getActivityCallback().onPrepareSend(txData); getActivityCallback().onPrepareSend(txData);
} }
SendFragmentNew.Listener getActivityCallback() { SendFragment.Listener getActivityCallback() {
return sendListener.getActivityCallback(); return sendListener.getActivityCallback();
} }
} }

View File

@ -49,7 +49,7 @@ import java.lang.ref.WeakReference;
import timber.log.Timber; import timber.log.Timber;
public class SendFragmentNew extends Fragment public class SendFragment extends Fragment
implements SendAddressWizardFragment.Listener, implements SendAddressWizardFragment.Listener,
SendAmountWizardFragment.Listener, SendAmountWizardFragment.Listener,
SendSettingsWizardFragment.Listener, SendSettingsWizardFragment.Listener,
@ -281,15 +281,15 @@ public class SendFragmentNew extends Fragment
Timber.d("getItem(%d) CREATE", position); Timber.d("getItem(%d) CREATE", position);
switch (position) { switch (position) {
case POS_ADDRESS: case POS_ADDRESS:
return SendAddressWizardFragment.newInstance(SendFragmentNew.this); return SendAddressWizardFragment.newInstance(SendFragment.this);
case POS_AMOUNT: case POS_AMOUNT:
return SendAmountWizardFragment.newInstance(SendFragmentNew.this); return SendAmountWizardFragment.newInstance(SendFragment.this);
case POS_SETTINGS: case POS_SETTINGS:
return SendSettingsWizardFragment.newInstance(SendFragmentNew.this); return SendSettingsWizardFragment.newInstance(SendFragment.this);
case POS_CONFIRM: case POS_CONFIRM:
return SendConfirmWizardFragment.newInstance(SendFragmentNew.this); return SendConfirmWizardFragment.newInstance(SendFragment.this);
case POS_SUCCESS: case POS_SUCCESS:
return SendSuccessWizardFragment.newInstance(SendFragmentNew.this); return SendSuccessWizardFragment.newInstance(SendFragment.this);
default: default:
throw new IllegalArgumentException("no such send position(" + position + ")"); throw new IllegalArgumentException("no such send position(" + position + ")");
} }
@ -448,8 +448,8 @@ public class SendFragmentNew extends Fragment
confirmFragment.hideProgress(); confirmFragment.hideProgress();
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setCancelable(false). builder.setCancelable(true).
setTitle(getString(R.string.send_error_title)). setTitle(getString(R.string.send_create_tx_error_title)).
setMessage(errorText). setMessage(errorText).
create(). create().
show(); show();
@ -483,4 +483,16 @@ public class SendFragmentNew extends Fragment
fragment.sendFailed(); fragment.sendFailed();
} }
} }
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.send_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
} }

View File

@ -53,7 +53,7 @@ import java.util.Map;
import timber.log.Timber; import timber.log.Timber;
public class WalletActivity extends SecureActivity implements WalletFragment.Listener, public class WalletActivity extends SecureActivity implements WalletFragment.Listener,
WalletService.Observer, SendFragmentNew.Listener, TxFragment.Listener, WalletService.Observer, SendFragment.Listener, TxFragment.Listener,
GenerateReviewFragment.ListenerWithWallet, GenerateReviewFragment.ListenerWithWallet,
GenerateReviewFragment.Listener, GenerateReviewFragment.Listener,
ScannerFragment.OnScannedListener, ReceiveFragment.Listener, ScannerFragment.OnScannedListener, ReceiveFragment.Listener,
@ -360,7 +360,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
@Override @Override
public void onSendRequest() { public void onSendRequest() {
replaceFragment(new SendFragmentNew(), null, null); replaceFragment(new SendFragment(), null, null);
} }
@Override @Override
@ -463,7 +463,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
@Override @Override
public void onTransactionCreated(final PendingTransaction pendingTransaction) { public void onTransactionCreated(final PendingTransaction pendingTransaction) {
try { try {
final SendFragmentNew sendFragment = (SendFragmentNew) final SendFragment sendFragment = (SendFragment)
getSupportFragmentManager().findFragmentById(R.id.fragment_container); getSupportFragmentManager().findFragmentById(R.id.fragment_container);
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
@ -488,7 +488,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
@Override @Override
public void onSendTransactionFailed(final String error) { public void onSendTransactionFailed(final String error) {
try { try {
final SendFragmentNew sendFragment = (SendFragmentNew) final SendFragment sendFragment = (SendFragment)
getSupportFragmentManager().findFragmentById(R.id.fragment_container); getSupportFragmentManager().findFragmentById(R.id.fragment_container);
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
@ -504,7 +504,7 @@ public class WalletActivity extends SecureActivity implements WalletFragment.Lis
@Override @Override
public void onTransactionSent(final String txId) { public void onTransactionSent(final String txId) {
try { try {
final SendFragmentNew sendFragment = (SendFragmentNew) final SendFragment sendFragment = (SendFragment)
getSupportFragmentManager().findFragmentById(R.id.fragment_container); getSupportFragmentManager().findFragmentById(R.id.fragment_container);
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {

View File

@ -21,9 +21,7 @@ import android.support.v4.view.ViewPager;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.MotionEvent; import android.view.MotionEvent;
import com.m2049r.xmrwallet.SendFragmentNew; import com.m2049r.xmrwallet.SendFragment;
import timber.log.Timber;
public class SpendViewPager extends ViewPager { public class SpendViewPager extends ViewPager {
@ -57,7 +55,7 @@ public class SpendViewPager extends ViewPager {
} }
public boolean validateFields(int position) { public boolean validateFields(int position) {
OnValidateFieldsListener c = ((SendFragmentNew.SpendPagerAdapter) getAdapter()).getFragment(position); OnValidateFieldsListener c = ((SendFragment.SpendPagerAdapter) getAdapter()).getFragment(position);
return c.onValidateFields(); return c.onValidateFields();
} }

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="@color/moneroFab"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z" />
</vector>

View File

@ -26,45 +26,65 @@
android:textAlignment="textStart" /> android:textAlignment="textStart" />
</android.support.design.widget.TextInputLayout> </android.support.design.widget.TextInputLayout>
<LinearLayout <FrameLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="96dp"
android:layout_marginBottom="4dp" android:layout_marginBottom="4dp">
android:orientation="horizontal"
android:weightSum="10">
<android.support.design.widget.TextInputLayout <TextView
android:id="@+id/etPaymentId" android:id="@+id/tvPaymentIdIntegrated"
android:layout_width="0dp" style="@style/MoneroText.Info"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="10" android:layout_gravity="start|center_vertical"
app:counterEnabled="true" android:drawablePadding="8dp"
app:counterMaxLength="16" android:drawableStart="@drawable/ic_check_gray_24dp"
app:errorEnabled="true"> android:gravity="center"
android:text="@string/info_paymentid_intergrated"
android:textSize="18sp"
android:visibility="gone" />
<android.support.design.widget.TextInputEditText <LinearLayout
style="@style/MoneroEdit" android:id="@+id/llPaymentId"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:orientation="horizontal"
android:visibility="visible"
android:weightSum="10">
<android.support.design.widget.TextInputLayout
android:id="@+id/etPaymentId"
android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="10" android:layout_weight="10"
android:hint="@string/send_paymentid_hint" app:counterEnabled="true"
android:imeOptions="actionDone" app:counterMaxLength="16"
android:inputType="textMultiLine" app:errorEnabled="true">
android:textAlignment="textStart" />
</android.support.design.widget.TextInputLayout>
<Button <android.support.design.widget.TextInputEditText
android:id="@+id/bPaymentId" style="@style/MoneroEdit"
style="@style/MoneroText.Button.Small" android:layout_width="match_parent"
android:layout_width="56dp" android:layout_height="wrap_content"
android:layout_height="56dp" android:layout_weight="10"
android:layout_gravity="center" android:hint="@string/send_paymentid_hint"
android:layout_marginStart="8dp" android:imeOptions="actionDone"
android:background="?android:selectableItemBackground" android:inputType="textMultiLine"
android:drawableTop="@drawable/ic_settings_orange_24dp" android:textAlignment="textStart" />
android:text="@string/send_generate_paymentid_hint" /> </android.support.design.widget.TextInputLayout>
</LinearLayout>
<Button
android:id="@+id/bPaymentId"
style="@style/MoneroText.Button.Small"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_gravity="center"
android:layout_marginStart="8dp"
android:background="?android:selectableItemBackground"
android:drawableTop="@drawable/ic_settings_orange_24dp"
android:text="@string/send_generate_paymentid_hint" />
</LinearLayout>
</FrameLayout>
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto" <android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/bScan" android:id="@+id/bScan"

View File

@ -11,8 +11,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:gravity="center" android:gravity="center" />
android:text="@string/send_available" />
<com.m2049r.xmrwallet.widget.ExchangeTextView <com.m2049r.xmrwallet.widget.ExchangeTextView
android:id="@+id/evAmount" android:id="@+id/evAmount"

View File

@ -68,14 +68,28 @@
tools:text="gunegugumobil" /> tools:text="gunegugumobil" />
</LinearLayout> </LinearLayout>
<ProgressBar <LinearLayout
android:id="@+id/pbProgress" android:id="@+id/llProgress"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:indeterminate="true" android:orientation="vertical"
android:visibility="invisible" /> android:visibility="visible">
<ProgressBar
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true" />
<TextView
android:id="@+id/tvPaymentIdIntegrated"
style="@style/MoneroText.Info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/info_prepare_tx" />
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/llConfirmSend" android:id="@+id/llConfirmSend"

View File

@ -56,8 +56,7 @@
android:gravity="center" android:gravity="center"
android:drawablePadding="8dp" android:drawablePadding="8dp"
android:drawableStart="@drawable/ic_info_outline_gray_24dp" android:drawableStart="@drawable/ic_info_outline_gray_24dp"
android:text="@string/label_send_info_fees" /> android:text="@string/info_send_prio_fees" />
<android.support.design.widget.TextInputLayout <android.support.design.widget.TextInputLayout
android:id="@+id/etAddress" android:id="@+id/etAddress"

View File

@ -24,7 +24,10 @@
<string name="label_send_done">Done</string> <string name="label_send_done">Done</string>
<string name="label_receive_info_gen_qr_code">Touch for QR Code</string> <string name="label_receive_info_gen_qr_code">Touch for QR Code</string>
<string name="label_send_info_fees">Higher Priority = Higher Fees</string> <string name="info_send_prio_fees">Higher Priority = Higher Fees</string>
<string name="info_paymentid_intergrated">Payment ID integrated</string>
<string name="info_prepare_tx">Preparing your transaction</string>
<string name="message_copy_txid">Transaction ID copied to clipboard!</string> <string name="message_copy_txid">Transaction ID copied to clipboard!</string>
@ -204,7 +207,7 @@
<string name="send_dust_label">Dust</string> <string name="send_dust_label">Dust</string>
<string name="send_total_label">Total</string> <string name="send_total_label">Total</string>
<string name="send_error_title">Transaction Error</string> <string name="send_create_tx_error_title">Create Transaction Error</string>
<string name="tx_list_fee_pending">incl. %1$s fee</string> <string name="tx_list_fee_pending">incl. %1$s fee</string>
<string name="tx_list_fee">- Fee %1$s</string> <string name="tx_list_fee">- Fee %1$s</string>
@ -242,7 +245,8 @@
<string name="receive_amount_hint">Amount</string> <string name="receive_amount_hint">Amount</string>
<string name="receive_amount_xmr_hint">XMR</string> <string name="receive_amount_xmr_hint">XMR</string>
<string name="receive_cannot_open">Could not open wallet!</string> <string name="receive_cannot_open">Could not open wallet!</string>
<string name="receive_paymentid_invalid">Must be 16 Hex characters</string> <string name="receive_paymentid_invalid">16 or 64 Hex characters (0-9,a-f)</string>
<string name="receive_integrated_paymentid_invalid">Must be empty with integrated address</string>
<string name="receive_amount_invalid">Must be > 0</string> <string name="receive_amount_invalid">Must be > 0</string>
<string name="receive_amount_empty">Enter value</string> <string name="receive_amount_empty">Enter value</string>

View File

@ -70,6 +70,10 @@
<item name="android:textStyle">bold</item> <item name="android:textStyle">bold</item>
</style> </style>
<style name="MoneroText.Info">
<item name="android:textSize">16sp</item>
<item name="android:textColor">@color/moneroFab</item>
</style>
<style name="MoneroText.Balance"> <style name="MoneroText.Balance">
<item name="android:textSize">32sp</item> <item name="android:textSize">32sp</item>