diff --git a/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java b/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java index 3bd60ecf..c1e53cd5 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java +++ b/app/src/main/java/com/m2049r/xmrwallet/WalletFragment.java @@ -58,7 +58,6 @@ import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Objects; import timber.log.Timber; @@ -128,7 +127,7 @@ public class WalletFragment extends Fragment currencies.add(Helper.BASE_CRYPTO); if (Helper.SHOW_EXCHANGERATES) currencies.addAll(Arrays.asList(getResources().getStringArray(R.array.currency))); - ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<>(Objects.requireNonNull(getContext()), R.layout.item_spinner_balance, currencies); + ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<>(requireContext(), R.layout.item_spinner_balance, currencies); spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); sCurrency.setAdapter(spinnerAdapter); @@ -346,13 +345,18 @@ public class WalletFragment extends Fragment // if account index has changed scroll to top? private int accountIndex = 0; - public void onRefreshed(final Wallet wallet, final boolean full) { + public void onRefreshed(final Wallet wallet, boolean full) { Timber.d("onRefreshed(%b)", full); + if (adapter.needsTransactionUpdateOnNewBlock()) { + wallet.getHistory().refresh(); + full = true; + } if (full) { List<TransactionInfo> list = new ArrayList<>(); final long streetHeight = activityCallback.getStreetModeHeight(); Timber.d("StreetHeight=%d", streetHeight); + wallet.getHistory().refresh(); for (TransactionInfo info : wallet.getHistory().getAll()) { Timber.d("TxHeight=%d, Label=%s", info.blockheight, info.subaddressLabel); if ((info.isPending || (info.blockheight >= streetHeight)) @@ -561,7 +565,7 @@ public class WalletFragment extends Fragment //TODO figure out why gunther disappears on return from send although he is still set if (enable) { if (streetGunther == null) - streetGunther = ContextCompat.getDrawable(Objects.requireNonNull(getContext()), R.drawable.ic_gunther_streetmode); + streetGunther = ContextCompat.getDrawable(requireContext(), R.drawable.ic_gunther_streetmode); ivStreetGunther.setImageDrawable(streetGunther); } else ivStreetGunther.setImageDrawable(null); diff --git a/app/src/main/java/com/m2049r/xmrwallet/layout/TransactionInfoAdapter.java b/app/src/main/java/com/m2049r/xmrwallet/layout/TransactionInfoAdapter.java index cb21a929..835c3a14 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/layout/TransactionInfoAdapter.java +++ b/app/src/main/java/com/m2049r/xmrwallet/layout/TransactionInfoAdapter.java @@ -30,6 +30,7 @@ import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.RecyclerView; +import com.google.android.material.progressindicator.CircularProgressIndicator; import com.m2049r.xmrwallet.R; import com.m2049r.xmrwallet.data.Crypto; import com.m2049r.xmrwallet.data.UserNotes; @@ -48,7 +49,9 @@ import java.util.TimeZone; import timber.log.Timber; public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfoAdapter.ViewHolder> { - private final SimpleDateFormat DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + private final static int MAX_CONFIRMATIONS = 10; + + private final static SimpleDateFormat DATETIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm"); private final int outboundColour; private final int inboundColour; @@ -77,6 +80,10 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo DATETIME_FORMATTER.setTimeZone(tz); } + public boolean needsTransactionUpdateOnNewBlock() { + return (infoItems.size() > 0) && (infoItems.get(0).confirmations < MAX_CONFIRMATIONS); + } + private static class TransactionInfoDiff extends DiffCallback<TransactionInfo> { public TransactionInfoDiff(List<TransactionInfo> oldList, List<TransactionInfo> newList) { @@ -95,6 +102,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo return (oldItem.direction == newItem.direction) && (oldItem.isPending == newItem.isPending) && (oldItem.isFailed == newItem.isFailed) + && (oldItem.confirmations == newItem.confirmations) && (oldItem.subaddressLabel.equals(newItem.subaddressLabel)) && (Objects.equals(oldItem.notes, newItem.notes)); } @@ -149,6 +157,8 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo final TextView tvFee; final TextView tvPaymentId; final TextView tvDateTime; + final CircularProgressIndicator pbConfirmations; + final TextView tvConfirmations; TransactionInfo infoItem; ViewHolder(View itemView) { @@ -158,6 +168,9 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo tvFee = itemView.findViewById(R.id.tx_fee); tvPaymentId = itemView.findViewById(R.id.tx_paymentid); tvDateTime = itemView.findViewById(R.id.tx_datetime); + pbConfirmations = itemView.findViewById(R.id.pbConfirmations); + pbConfirmations.setMax(MAX_CONFIRMATIONS); + tvConfirmations = itemView.findViewById(R.id.tvConfirmations); } private String getDateTime(long time) { @@ -182,7 +195,7 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo ivTxType.setVisibility(View.GONE); } } else { - ivTxType.setVisibility(View.GONE); // gives us more space for the amount + ivTxType.setVisibility(View.GONE); } String displayAmount = Helper.getDisplayAmount(infoItem.amount, Helper.DISPLAY_DIGITS_INFO); @@ -205,12 +218,34 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo this.tvFee.setText(context.getString(R.string.tx_list_failed_text)); tvFee.setVisibility(View.VISIBLE); setTxColour(failedColour); + pbConfirmations.setVisibility(View.GONE); + tvConfirmations.setVisibility(View.GONE); } else if (infoItem.isPending) { setTxColour(pendingColour); + pbConfirmations.setVisibility(View.GONE); + pbConfirmations.setIndeterminate(true); + pbConfirmations.setVisibility(View.VISIBLE); + tvConfirmations.setVisibility(View.GONE); } else if (infoItem.direction == TransactionInfo.Direction.Direction_In) { setTxColour(inboundColour); + final int confirmations = (int) infoItem.confirmations; + if (confirmations <= MAX_CONFIRMATIONS) { + pbConfirmations.setVisibility(View.VISIBLE); + pbConfirmations.setProgressCompat(confirmations, true); + final String confCount = Integer.toString(confirmations); + tvConfirmations.setText(confCount); + if (confCount.length() == 1) // we only have space for character in the progress circle + tvConfirmations.setVisibility(View.VISIBLE); + else + tvConfirmations.setVisibility(View.GONE); + } else { + pbConfirmations.setVisibility(View.GONE); + tvConfirmations.setVisibility(View.GONE); + } } else { setTxColour(outboundColour); + pbConfirmations.setVisibility(View.GONE); + tvConfirmations.setVisibility(View.GONE); } String tag = null; 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 4d1a3d30..b048755a 100644 --- a/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java +++ b/app/src/main/java/com/m2049r/xmrwallet/service/WalletService.java @@ -108,33 +108,28 @@ public class WalletService extends Service { Timber.d("unconfirmedMoneyReceived() %d @ %s", amount, txId); } - long lastBlockTime = 0; int lastTxCount = 0; public void newBlock(long height) { final Wallet wallet = getWallet(); if (wallet == null) throw new IllegalStateException("No wallet!"); - // don't flood with an update for every block ... - if (lastBlockTime < System.currentTimeMillis() - 2000) { - Timber.d("newBlock() @ %d with observer %s", height, observer); - lastBlockTime = System.currentTimeMillis(); - if (observer != null) { - 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(); - if (txCount > lastTxCount) { - // update the transaction list only if we have more than before - lastTxCount = txCount; - fullRefresh = true; - } + Timber.d("newBlock() @ %d with observer %s", height, observer); + if (observer != null) { + 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(); + if (txCount > lastTxCount) { + // update the transaction list only if we have more than before + lastTxCount = txCount; + fullRefresh = true; } - if (observer != null) - observer.onRefreshed(wallet, fullRefresh); } + if (observer != null) + observer.onRefreshed(wallet, fullRefresh); } } diff --git a/app/src/main/res/layout/item_transaction.xml b/app/src/main/res/layout/item_transaction.xml index 00d66df9..c9e55d71 100644 --- a/app/src/main/res/layout/item_transaction.xml +++ b/app/src/main/res/layout/item_transaction.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="wrap_content" @@ -19,13 +20,43 @@ android:layout_weight="9" android:orientation="horizontal"> - <ImageView - android:id="@+id/ivTxType" - android:layout_width="16dp" - android:layout_height="16dp" - android:layout_gravity="center" - android:src="@drawable/ic_xmrto_btc" - android:visibility="visible" /> + <FrameLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center"> + + <ImageView + android:id="@+id/ivTxType" + android:layout_width="16dp" + android:layout_height="16dp" + android:layout_gravity="center" + android:src="@drawable/ic_xmrto_btc" + android:visibility="visible" /> + + <com.google.android.material.progressindicator.CircularProgressIndicator + android:id="@+id/pbConfirmations" + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_gravity="center" + android:indeterminate="false" + android:max="10" + android:progress="8" + android:visibility="visible" + app:indicatorInset="0dp" + app:indicatorSize="30dp" + app:trackThickness="4dp" /> + + <TextView + android:id="@+id/tvConfirmations" + style="@style/MoneroText" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:gravity="center" + android:paddingBottom="1dp" + android:text="8" + android:visibility="visible" /> + </FrameLayout> <LinearLayout android:layout_width="match_parent" @@ -57,8 +88,8 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center" - android:layout_marginEnd="16dp" android:layout_marginStart="16dp" + android:layout_marginEnd="16dp" android:layout_weight="13" android:gravity="start" tools:text="0123456789abcdef" /> diff --git a/build.gradle b/build.gradle index c22dc877..4406443a 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:4.2.0' + classpath 'com.android.tools.build:gradle:4.2.2' } }