com.brq.wallet.activity.main.TransactionHistoryFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.brq.wallet.activity.main.TransactionHistoryFragment.java

Source

/*
 * Copyright 2013, 2014 Megion Research and Development GmbH
 *
 * Licensed under the Microsoft Reference Source License (MS-RSL)
 *
 * This license governs use of the accompanying software. If you use the software, you accept this license.
 * If you do not accept the license, do not use the software.
 *
 * 1. Definitions
 * The terms "reproduce," "reproduction," and "distribution" have the same meaning here as under U.S. copyright law.
 * "You" means the licensee of the software.
 * "Your company" means the company you worked for when you downloaded the software.
 * "Reference use" means use of the software within your company as a reference, in read only form, for the sole purposes
 * of debugging your products, maintaining your products, or enhancing the interoperability of your products with the
 * software, and specifically excludes the right to distribute the software outside of your company.
 * "Licensed patents" means any Licensor patent claims which read directly on the software as distributed by the Licensor
 * under this license.
 *
 * 2. Grant of Rights
 * (A) Copyright Grant- Subject to the terms of this license, the Licensor grants you a non-transferable, non-exclusive,
 * worldwide, royalty-free copyright license to reproduce the software for reference use.
 * (B) Patent Grant- Subject to the terms of this license, the Licensor grants you a non-transferable, non-exclusive,
 * worldwide, royalty-free patent license under licensed patents for reference use.
 *
 * 3. Limitations
 * (A) No Trademark License- This license does not grant you any rights to use the Licensors name, logo, or trademarks.
 * (B) If you begin patent litigation against the Licensor over patents that you think may apply to the software
 * (including a cross-claim or counterclaim in a lawsuit), your license to the software ends automatically.
 * (C) The software is licensed "as-is." You bear the risk of using it. The Licensor gives no express warranties,
 * guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot
 * change. To the extent permitted under your local laws, the Licensor excludes the implied warranties of merchantability,
 * fitness for a particular purpose and non-infringement.
 */

package com.brq.wallet.activity.main;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.view.ActionMode;
import android.view.*;
import android.widget.ListView;
import android.widget.Toast;

import com.brq.wallet.Utils;
import com.brq.wallet.event.ExchangeRatesRefreshed;
import com.commonsware.cwac.endless.EndlessAdapter;
import com.google.common.base.Preconditions;
import com.mrd.bitlib.model.Address;
import com.mrd.bitlib.util.Sha256Hash;
import com.brq.wallet.coinapult.CoinapultTransactionSummary;
import com.brq.wallet.MbwManager;
import com.brq.wallet.R;
import com.brq.wallet.activity.TransactionDetailsActivity;
import com.brq.wallet.activity.modern.Toaster;
import com.brq.wallet.activity.send.BroadcastTransactionActivity;
import com.brq.wallet.activity.util.EnterAddressLabelUtil;
import com.brq.wallet.event.AddressBookChanged;
import com.brq.wallet.event.SelectedCurrencyChanged;
import com.brq.wallet.event.SyncStopped;
import com.brq.wallet.persistence.MetadataStorage;
import com.mycelium.wapi.model.TransactionSummary;
import com.mycelium.wapi.wallet.WalletAccount;
import com.mycelium.wapi.wallet.WalletManager;
import com.squareup.otto.Subscribe;

import java.util.*;

public class TransactionHistoryFragment extends Fragment {

    private MbwManager _mbwManager;
    private MetadataStorage _storage;
    private View _root;
    private ActionMode currentActionMode;
    private volatile Map<Address, String> _addressBook;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        _root = inflater.inflate(R.layout.main_transaction_history_view, container, false);

        _root.findViewById(R.id.btRescan).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                _mbwManager.getSelectedAccount().dropCachedData();
                _mbwManager.getWalletManager(false).startSynchronization();
            }
        });

        return _root;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        setHasOptionsMenu(true);
        super.onCreate(savedInstanceState);

        // cache the addressbook for faster lookup
        cacheAddressBook();
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        _mbwManager = MbwManager.getInstance(activity);
        _storage = _mbwManager.getMetadataStorage();

    }

    @Override
    public void onResume() {
        _mbwManager.getEventBus().register(this);
        if (_mbwManager.getWalletManager(false).getState() == WalletManager.State.READY) {
            updateTransactionHistory();
        }
        super.onResume();
    }

    @Override
    public void onPause() {
        _mbwManager.getEventBus().unregister(this);
        super.onPause();
    }

    @Subscribe
    public void syncStopped(SyncStopped event) {
        updateTransactionHistory();
    }

    @Subscribe
    public void exchangeRateChanged(ExchangeRatesRefreshed event) {
        refreshList();
    }

    private void refreshList() {
        ((ListView) _root.findViewById(R.id.lvTransactionHistory)).invalidateViews();
    }

    @Subscribe
    public void fiatCurrencyChanged(SelectedCurrencyChanged event) {
        refreshList();
    }

    @Subscribe
    public void addressBookEntryChanged(AddressBookChanged event) {
        cacheAddressBook();
        refreshList();
    }

    private void cacheAddressBook() {
        _addressBook = _mbwManager.getMetadataStorage().getAllAddressLabels();
    }

    private void doShowDetails(TransactionSummary selected) {
        if (selected == null) {
            return;
        }
        // Open transaction details
        Intent intent = new Intent(getActivity(), TransactionDetailsActivity.class);
        intent.putExtra("transaction", selected.txid);
        startActivity(intent);
    }

    @SuppressWarnings("unchecked")
    private void updateTransactionHistory() {
        if (!isAdded()) {
            return;
        }
        WalletAccount account = _mbwManager.getSelectedAccount();
        if (account.isArchived()) {
            return;
        }
        List<TransactionSummary> history = account.getTransactionHistory(0, 20);
        if (history.isEmpty()) {
            _root.findViewById(R.id.llNoRecords).setVisibility(View.VISIBLE);
            _root.findViewById(R.id.lvTransactionHistory).setVisibility(View.GONE);
        } else {
            _root.findViewById(R.id.llNoRecords).setVisibility(View.GONE);
            _root.findViewById(R.id.lvTransactionHistory).setVisibility(View.VISIBLE);
            Wrapper wrapper = new Wrapper(getActivity(), history);
            ((ListView) _root.findViewById(R.id.lvTransactionHistory)).setAdapter(wrapper);
            refreshList();
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        if (!isVisibleToUser) {
            finishActionMode();
        }
    }

    private void finishActionMode() {
        if (currentActionMode != null) {
            currentActionMode.finish();
        }
    }

    private class TransactionHistoryAdapter extends TransactionArrayAdapter {

        public TransactionHistoryAdapter(Context context, List<TransactionSummary> transactions) {
            super(context, transactions, TransactionHistoryFragment.this, _addressBook, false);
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            View rowView = super.getView(position, convertView, parent);

            // Make sure we are still added
            if (!isAdded()) {
                // We have observed that the fragment can be disconnected at this
                // point
                return rowView;
            }

            final TransactionSummary record = getItem(position);
            final ActionBarActivity actionBarActivity = (ActionBarActivity) getActivity();

            rowView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(final View view) {
                    currentActionMode = actionBarActivity.startSupportActionMode(new ActionMode.Callback() {
                        @Override
                        public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
                            actionMode.getMenuInflater().inflate(R.menu.transaction_history_context_menu, menu);
                            //we only allow address book entries for outgoing transactions
                            updateActionBar(actionMode, menu);
                            return true;
                        }

                        @Override
                        public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
                            updateActionBar(actionMode, menu);
                            return true;
                        }

                        private void updateActionBar(ActionMode actionMode, Menu menu) {
                            Preconditions.checkNotNull(menu.findItem(R.id.miAddToAddressBook))
                                    .setVisible(record.hasAddressBook());
                            Preconditions.checkNotNull(menu.findItem(R.id.miCancelTransaction))
                                    .setVisible(record.canCancel());
                            Preconditions.checkNotNull(menu.findItem(R.id.miShowDetails))
                                    .setVisible(record.hasDetails());
                            Preconditions.checkNotNull(menu.findItem(R.id.miShowCoinapultDebug))
                                    .setVisible(record.canCoinapult());
                            Preconditions.checkNotNull(menu.findItem(R.id.miRebroadcastTransaction))
                                    .setVisible((record.confirmations == 0) && !record.canCoinapult());

                            //deletion is disabled for now, to enable, replace false with record.confirmations == 0
                            Preconditions.checkNotNull(menu.findItem(R.id.miDeleteUnconfirmedTransaction))
                                    .setVisible(false);
                            currentActionMode = actionMode;
                            ((ListView) _root.findViewById(R.id.lvTransactionHistory)).setItemChecked(position,
                                    true);
                        }

                        @Override
                        public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
                            final int itemId = menuItem.getItemId();
                            if (itemId == R.id.miShowCoinapultDebug) {
                                if (record instanceof CoinapultTransactionSummary) {
                                    final CoinapultTransactionSummary summary = (CoinapultTransactionSummary) record;
                                    new AlertDialog.Builder(_context).setMessage(summary.input.toString())
                                            .setNeutralButton(R.string.copy, new DialogInterface.OnClickListener() {
                                                @Override
                                                public void onClick(DialogInterface dialog, int which) {
                                                    Utils.setClipboardString(summary.input.toString(),
                                                            TransactionHistoryFragment.this.getActivity());
                                                    Toast.makeText(TransactionHistoryFragment.this.getActivity(),
                                                            R.string.copied_to_clipboard, Toast.LENGTH_SHORT)
                                                            .show();

                                                    dialog.dismiss();
                                                }
                                            })
                                            .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                                                @Override
                                                public void onClick(DialogInterface dialog, int which) {
                                                    dialog.dismiss();
                                                }
                                            }).show();
                                }
                                return true;
                            }
                            if (itemId == R.id.miShowDetails) {
                                doShowDetails(record);
                                finishActionMode();
                                return true;
                            } else if (itemId == R.id.miSetLabel) {
                                setTransactionLabel(record);
                                finishActionMode();
                            } else if (itemId == R.id.miAddToAddressBook) {
                                EnterAddressLabelUtil.enterAddressLabel(getActivity(),
                                        _mbwManager.getMetadataStorage(), record.destinationAddress.get(), "",
                                        addressLabelChanged);
                            } else if (itemId == R.id.miCancelTransaction) {
                                new AlertDialog.Builder(getActivity())
                                        .setTitle(_context.getString(R.string.remove_queued_transaction_title))
                                        .setMessage(_context.getString(R.string.remove_queued_transaction))
                                        .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface dialog, int which) {
                                                boolean okay = _mbwManager.getSelectedAccount()
                                                        .cancelQueuedTransaction(record.txid);
                                                dialog.dismiss();
                                                updateTransactionHistory();
                                                if (okay) {
                                                    Utils.showSimpleMessageDialog(getActivity(), _context
                                                            .getString(R.string.remove_queued_transaction_hint));
                                                } else {
                                                    new Toaster(getActivity()).toast(
                                                            _context.getString(
                                                                    R.string.remove_queued_transaction_error),
                                                            false);
                                                }
                                            }
                                        }).setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface dialog, int which) {
                                                dialog.dismiss();
                                            }
                                        }).create().show();
                            } else if (itemId == R.id.miDeleteUnconfirmedTransaction) {
                                new AlertDialog.Builder(getActivity())
                                        .setTitle(_context.getString(R.string.delete_unconfirmed_transaction_title))
                                        .setMessage(
                                                _context.getString(R.string.warning_delete_unconfirmed_transaction))
                                        .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface dialog, int which) {
                                                _mbwManager.getSelectedAccount().deleteTransaction(record.txid);
                                                dialog.dismiss();
                                                updateTransactionHistory();
                                            }
                                        }).setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface dialog, int which) {
                                                dialog.dismiss();
                                            }
                                        }).create().show();
                            } else if (itemId == R.id.miRebroadcastTransaction) {
                                new AlertDialog.Builder(getActivity())
                                        .setTitle(_context.getString(R.string.rebroadcast_transaction_title))
                                        .setMessage(
                                                _context.getString(R.string.description_rebroadcast_transaction))
                                        .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface dialog, int which) {
                                                boolean success = BroadcastTransactionActivity.callMe(getActivity(),
                                                        _mbwManager.getSelectedAccount(), record.txid);
                                                if (!success) {
                                                    Utils.showSimpleMessageDialog(getActivity(), _context
                                                            .getString(R.string.message_rebroadcast_successfull));
                                                }
                                                dialog.dismiss();
                                            }
                                        }).setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
                                            @Override
                                            public void onClick(DialogInterface dialog, int which) {
                                                dialog.dismiss();
                                            }
                                        }).create().show();
                            }
                            return false;
                        }

                        @Override
                        public void onDestroyActionMode(ActionMode actionMode) {
                            ((ListView) _root.findViewById(R.id.lvTransactionHistory)).setItemChecked(position,
                                    false);
                            currentActionMode = null;
                        }
                    });
                }
            });

            return rowView;
        }
    }

    private EnterAddressLabelUtil.AddressLabelChangedHandler addressLabelChanged = new EnterAddressLabelUtil.AddressLabelChangedHandler() {
        @Override
        public void OnAddressLabelChanged(Address address, String label) {
            _mbwManager.getEventBus().post(new AddressBookChanged());
            updateTransactionHistory();
        }
    };

    private void setTransactionLabel(TransactionSummary record) {
        EnterAddressLabelUtil.enterTransactionLabel(getActivity(), record.txid, _storage, transactionLabelChanged);
    }

    private EnterAddressLabelUtil.TransactionLabelChangedHandler transactionLabelChanged = new EnterAddressLabelUtil.TransactionLabelChangedHandler() {

        @Override
        public void OnTransactionLabelChanged(Sha256Hash txid, String label) {
            updateTransactionHistory();
        }
    };

    private class Wrapper extends EndlessAdapter {
        private List<TransactionSummary> _toAdd;
        private final Object _toAddLock = new Object();
        private int lastOffset;
        private int chunkSize;

        private Wrapper(Context context, List<TransactionSummary> transactions) {
            super(new TransactionHistoryAdapter(context, transactions));
            _toAdd = new ArrayList<TransactionSummary>();
            lastOffset = 0;
            chunkSize = 20;
        }

        @Override
        protected View getPendingView(ViewGroup parent) {
            //this is an empty view, getting more transaction details is fast at the moment
            return LayoutInflater.from(parent.getContext()).inflate(R.layout.transaction_history_fetching, null);
        }

        @Override
        protected boolean cacheInBackground() {
            WalletAccount acc = _mbwManager.getSelectedAccount();
            synchronized (_toAddLock) {
                lastOffset += chunkSize;
                _toAdd = acc.getTransactionHistory(lastOffset, chunkSize);
            }
            return _toAdd.size() == chunkSize;
        }

        @Override
        protected void appendCachedData() {
            synchronized (_toAddLock) {
                TransactionHistoryAdapter a = (TransactionHistoryAdapter) getWrappedAdapter();
                for (TransactionSummary item : _toAdd) {
                    a.add(item);
                }
                _toAdd.clear();
            }
        }
    }
}