Changes from Alpha Feedback (#113)

* fab covers whole screen

* avoid potential NPE

* bugfix - spinners crashed after scan

* Gunther only if no wallets

* clearQR on failed exchange, tweaks, gray

* refactor info dialogs

* added default testnet node

* FAQ: my testnet wallet is broken

* version code 36, version name 1.1.7
This commit is contained in:
m2049r 2017-11-04 10:17:20 +01:00 committed by GitHub
parent d67e02cbcb
commit 545367db90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 136 additions and 172 deletions

View File

@ -8,8 +8,8 @@ android {
applicationId "com.m2049r.xmrwallet"
minSdkVersion 21
targetSdkVersion 25
versionCode 34
versionName "1.1.6"
versionCode 36
versionName "1.1.7"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {

View File

@ -1054,22 +1054,22 @@ public class LoginActivity extends AppCompatActivity
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_create_help_new:
HelpFragment.displayHelp(getSupportFragmentManager(), R.string.help_create_new);
HelpFragment.display(getSupportFragmentManager(), R.string.help_create_new);
return true;
case R.id.action_create_help_keys:
HelpFragment.displayHelp(getSupportFragmentManager(), R.string.help_create_keys);
HelpFragment.display(getSupportFragmentManager(), R.string.help_create_keys);
return true;
case R.id.action_create_help_view:
HelpFragment.displayHelp(getSupportFragmentManager(), R.string.help_create_view);
HelpFragment.display(getSupportFragmentManager(), R.string.help_create_view);
return true;
case R.id.action_create_help_seed:
HelpFragment.displayHelp(getSupportFragmentManager(), R.string.help_create_seed);
HelpFragment.display(getSupportFragmentManager(), R.string.help_create_seed);
return true;
case R.id.action_details_help:
HelpFragment.displayHelp(getSupportFragmentManager(), R.string.help_details);
HelpFragment.display(getSupportFragmentManager(), R.string.help_details);
return true;
case R.id.action_license_info:
AboutFragment.displayHelp(getSupportFragmentManager(), R.string.about_licenses);
AboutFragment.display(getSupportFragmentManager());
return true;
case R.id.action_privacy_policy:
PrivacyFragment.display(getSupportFragmentManager());

View File

@ -65,6 +65,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
List<WalletManager.WalletInfo> displayedList = new ArrayList<>();
EditText etDummy;
ImageView ivGunther;
DropDownEditText etDaemonAddress;
ArrayAdapter<String> nodeAdapter;
@ -131,6 +132,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
Log.d(TAG, "onCreateView");
View view = inflater.inflate(R.layout.fragment_login, container, false);
ivGunther = (ImageView) view.findViewById(R.id.ivGunther);
fabScreen = (FrameLayout) view.findViewById(R.id.fabScreen);
fab = (FloatingActionButton) view.findViewById(R.id.fab);
fabNew = (FloatingActionButton) view.findViewById(R.id.fabNew);
@ -269,10 +271,18 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
filterList();
adapter.setInfos(displayedList);
adapter.notifyDataSetChanged();
// deal with Gunther & FAB animation
if (displayedList.isEmpty()) {
fab.startAnimation(fab_pulse);
if (ivGunther.getDrawable() == null) {
ivGunther.setImageResource(R.drawable.gunther_desaturated);
}
} else {
fab.clearAnimation();
if (ivGunther.getDrawable() != null) {
ivGunther.setImageDrawable(null);
}
}
}
@ -329,7 +339,10 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
//private static final String PREF_TESTNET = "testnet";
private static final String PREF_DAEMONLIST_MAINNET =
"node.moneroworld.com:18089;node.xmrbackb.one:18081;node.xmr.be:18081";
"node.moneroworld.com:18089;node.xmrbackb.one;node.xmr.be";
private static final String PREF_DAEMONLIST_TESTNET =
"testnet.xmrchain.net";
private NodeList daemonTestNet;
private NodeList daemonMainNet;
@ -338,7 +351,7 @@ public class LoginFragment extends Fragment implements WalletInfoAdapter.OnInter
SharedPreferences sharedPref = activityCallback.getPrefs();
daemonMainNet = new NodeList(sharedPref.getString(PREF_DAEMON_MAINNET, PREF_DAEMONLIST_MAINNET));
daemonTestNet = new NodeList(sharedPref.getString(PREF_DAEMON_TESTNET, ""));
daemonTestNet = new NodeList(sharedPref.getString(PREF_DAEMON_TESTNET, PREF_DAEMONLIST_TESTNET));
setNet(isTestnet(), false);
}

View File

@ -116,6 +116,7 @@ public class ReceiveFragment extends Fragment {
evAmount.setOnFailedExchangeListener(new ExchangeView.OnFailedExchangeListener() {
@Override
public void onFailedExchange() {
clearQR();
Toast.makeText(getActivity(), getString(R.string.message_exchange_failed), Toast.LENGTH_LONG).show();
}
});

View File

@ -227,9 +227,14 @@ public class SendFragment extends Fragment {
sMixin.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
public void onItemSelected(final AdapterView<?> parentView, View selectedItemView, int position, long id) {
parentView.post(new Runnable() {
@Override
public void run() {
((TextView) parentView.getChildAt(0)).setTextColor(getResources().getColor(R.color.moneroGray));
}
});
}
@Override
public void onNothingSelected(AdapterView<?> parentView) {
@ -238,9 +243,14 @@ public class SendFragment extends Fragment {
});
sPriority.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
public void onItemSelected(final AdapterView<?> parentView, View selectedItemView, int position, long id) {
parentView.post(new Runnable() {
@Override
public void run() {
((TextView) parentView.getChildAt(0)).setTextColor(getResources().getColor(R.color.moneroGray));
}
});
}
@Override
public void onNothingSelected(AdapterView<?> parentView) {

View File

@ -44,7 +44,6 @@ 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.AsyncExchangeRate;
import com.m2049r.xmrwallet.util.BarcodeData;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.TxData;
@ -162,10 +161,10 @@ public class WalletActivity extends AppCompatActivity implements WalletFragment.
onShareTxInfo();
return true;
case R.id.action_help_tx_info:
HelpFragment.displayHelp(getSupportFragmentManager(), R.string.help_tx_details);
HelpFragment.display(getSupportFragmentManager(), R.string.help_tx_details);
return true;
case R.id.action_help_sync:
HelpFragment.displayHelp(getSupportFragmentManager(), R.string.help_sync);
HelpFragment.display(getSupportFragmentManager(), R.string.help_sync);
return true;
default:
return super.onOptionsItemSelected(item);

View File

@ -33,43 +33,27 @@ import com.m2049r.xmrwallet.BuildConfig;
import com.m2049r.xmrwallet.R;
public class AboutFragment extends DialogFragment {
static final String TAG = "HelpFragment";
private static final String HELP_ID = "HELP_ID";
static final String TAG = "AboutFragment";
public static AboutFragment newInstance(int helpResourceId) {
AboutFragment fragment = new AboutFragment();
Bundle bundle = new Bundle();
bundle.putInt(HELP_ID, helpResourceId);
fragment.setArguments(bundle);
return fragment;
public static AboutFragment newInstance() {
return new AboutFragment();
}
public static void displayHelp(FragmentManager fm, int helpResourceId) {
public static void display(FragmentManager fm) {
FragmentTransaction ft = fm.beginTransaction();
Fragment prev = fm.findFragmentByTag(TAG);
if (prev != null) {
ft.remove(prev);
}
DialogFragment helpFragment = AboutFragment.newInstance(helpResourceId);
helpFragment.show(ft, TAG);
AboutFragment.newInstance().show(ft, TAG);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_about, null);
int helpId = 0;
Bundle arguments = getArguments();
if (arguments != null) {
helpId = arguments.getInt(HELP_ID);
}
if (helpId > 0) {
((TextView) view.findViewById(R.id.tvHelp)).setText(Html.fromHtml(getString(helpId)));
}
TextView text = (TextView) view.findViewById(R.id.tvVersion);
text.setText(getString(R.string.about_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
((TextView) view.findViewById(R.id.tvHelp)).setText(Html.fromHtml(getString(R.string.about_licenses)));
((TextView) view.findViewById(R.id.tvVersion)).setText(getString(R.string.about_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(view);

View File

@ -14,82 +14,49 @@
* limitations under the License.
*/
/**
* Based on work by Adam Speakman http://speakman.net.nz
*/
package com.m2049r.xmrwallet.dialog;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.text.Html;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.webkit.WebView;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.m2049r.xmrwallet.BuildConfig;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.util.Helper;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class DonationFragment extends DialogFragment {
static final String TAG = "DonationFragment";
private static final String FRAGMENT_TAG = "com.m2049r.xmrwalelt.dialog.DonationFragment";
/**
* Creates a new instance of LicensesFragment with no Close button.
*
* @return A new licenses fragment.
*/
public static DonationFragment newInstance() {
return new DonationFragment();
}
/**
* Builds and displays a licenses fragment with no Close button. Requires
* "/res/raw/licenses.html" and "/res/layout/licenses_fragment.xml" to be
* present.
*
* @param fm A fragment manager instance used to display this LicensesFragment.
*/
public static void display(FragmentManager fm) {
FragmentTransaction ft = fm.beginTransaction();
Fragment prev = fm.findFragmentByTag(FRAGMENT_TAG);
Fragment prev = fm.findFragmentByTag(TAG);
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
// Create and show the dialog.
DialogFragment newFragment = DonationFragment.newInstance();
newFragment.show(ft, FRAGMENT_TAG);
DonationFragment.newInstance().show(ft, TAG);
}
@SuppressLint("InflateParams")
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_donation, null);
((TextView) view.findViewById(R.id.tvCredits)).setText(Html.fromHtml(getString(R.string.donation_credits)));
((ImageButton) view.findViewById(R.id.bCopyAddress)).
(view.findViewById(R.id.bCopyAddress)).
setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

View File

@ -43,15 +43,14 @@ public class HelpFragment extends DialogFragment {
return fragment;
}
public static void displayHelp(FragmentManager fm, int helpResourceId) {
public static void display(FragmentManager fm, int helpResourceId) {
FragmentTransaction ft = fm.beginTransaction();
Fragment prev = fm.findFragmentByTag(TAG);
if (prev != null) {
ft.remove(prev);
}
DialogFragment helpFragment = HelpFragment.newInstance(helpResourceId);
helpFragment.show(ft, TAG);
HelpFragment.newInstance(helpResourceId).show(ft, TAG);
}
@Override

View File

@ -14,13 +14,8 @@
* limitations under the License.
*/
/**
* Based on work by Adam Speakman http://speakman.net.nz
*/
package com.m2049r.xmrwallet.dialog;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
@ -32,47 +27,27 @@ import android.support.v4.app.FragmentTransaction;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.util.Helper;
public class PrivacyFragment extends DialogFragment {
static final String TAG = "PrivacyFragment";
private static final String FRAGMENT_TAG = "com.m2049r.xmrwalelt.dialog.PrivacyFragment";
/**
* Creates a new instance of LicensesFragment with no Close button.
*
* @return A new licenses fragment.
*/
public static PrivacyFragment newInstance() {
return new PrivacyFragment();
}
/**
* Builds and displays a licenses fragment with no Close button. Requires
* "/res/raw/licenses.html" and "/res/layout/licenses_fragment.xml" to be
* present.
*
* @param fm A fragment manager instance used to display this LicensesFragment.
*/
public static void display(FragmentManager fm) {
FragmentTransaction ft = fm.beginTransaction();
Fragment prev = fm.findFragmentByTag(FRAGMENT_TAG);
Fragment prev = fm.findFragmentByTag(TAG);
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
// Create and show the dialog.
DialogFragment newFragment = PrivacyFragment.newInstance();
newFragment.show(ft, FRAGMENT_TAG);
PrivacyFragment.newInstance().show(ft, TAG);
}
@SuppressLint("InflateParams")
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_privacy_policy, null);

View File

@ -179,11 +179,16 @@ public class ExchangeView extends LinearLayout implements AsyncExchangeRate.List
sCurrencyB.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parentView, View selectedItemView, int position, long id) {
public void onItemSelected(final AdapterView<?> parentView, View selectedItemView, int position, long id) {
if (position != 0) { // if not XMR, select XMR on other
sCurrencyA.setSelection(0, true);
}
parentView.post(new Runnable() {
@Override
public void run() {
((TextView) parentView.getChildAt(0)).setTextColor(getResources().getColor(R.color.moneroGray));
}
});
doExchange();
}

View File

@ -333,7 +333,8 @@ public class WalletService extends Service {
Wallet myWallet = getWallet();
Log.d(TAG, "SEND TX for wallet: " + myWallet.getName());
PendingTransaction pendingTransaction = myWallet.getPendingTransaction();
if (pendingTransaction.getStatus() != PendingTransaction.Status.Status_Ok) {
if ((pendingTransaction == null)
|| (pendingTransaction.getStatus() != PendingTransaction.Status.Status_Ok)) {
Log.e(TAG, "PendingTransaction is " + pendingTransaction.getStatus());
myWallet.disposePendingTransaction(); // it's broken anyway
if (observer != null) observer.onSentTransaction(false);

View File

@ -1,9 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8sp"
android:layout_margin="8sp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
@ -49,11 +53,11 @@
android:fillViewport="true">
<ImageView
android:id="@+id/ivGunther"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:padding="48dp"
android:src="@drawable/gunther_desaturated" />
android:padding="48dp" />
</ScrollView>
<android.support.v7.widget.RecyclerView xmlns:tools="http://schemas.android.com/tools"
@ -65,6 +69,8 @@
app:layoutManager="LinearLayoutManager"
tools:listitem="@layout/item_wallet" />
<include layout="@layout/layout_fabmenu" />
</FrameLayout>
</LinearLayout>
<include layout="@layout/layout_fabmenu" />
</FrameLayout>

View File

@ -75,6 +75,7 @@
style="@style/MoneroEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@color/moneroGray"
android:hint="@string/receive_paymentid_hint"
android:imeOptions="actionDone"
android:inputType="textMultiLine"

View File

@ -12,11 +12,6 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="@+id/etDummy"
android:layout_width="0sp"
android:layout_height="0sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -85,9 +80,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="10"
android:backgroundTint="@color/moneroGray"
android:hint="@string/send_paymentid_hint"
android:imeOptions="actionDone"
android:backgroundTint="@color/moneroGray"
android:inputType="textMultiLine"
android:textAlignment="textStart" />
</android.support.design.widget.TextInputLayout>
@ -105,6 +100,11 @@
android:textColor="@color/moneroGray" />
</LinearLayout>
<EditText
android:id="@+id/etDummy"
android:layout_width="0sp"
android:layout_height="0sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -27,10 +27,13 @@
- Archive (=Backup and delete)
- 3 Default nodes + History of last 5 used nodes
## After installing from Google Play the wallet list is empty!
Sorry about that. The folder for the wallets was renamed from "Monerujo" to "monerujo".
On most devices this does not matter (they don't care about upper/lower case). Yours does.
If you use a file explorer (e.g. es file explorer) you can find the Monerujo folder and rename it to "monerujo".
## My new testnet wallet does not update
Since testnet block times are very variable, the algorithm calculating block height does not
produce good results - so in general you testnet wallet will not work out of the box.
The remedy is simple: restore from seed and the correct / current block height. Take the block number
of your first transaction or the current block height from the
[Testnet Blockchain Explorer](https://testnet.xmrchain.com/).
## I cannot select and copy the mnemonic seed
Copying anything to the clipboard on Android exposes it to any other App running. So this