Android Open Source - My-Wallet-Android Wallet Transactions Fragment






From Project

Back to project page My-Wallet-Android.

License

The source code is released under:

GNU General Public License

If you think the Android project My-Wallet-Android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright 2011-2012 the original author or authors.
 *// w w  w . j av  a 2  s  . c o m
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package piuk.blockchain.android.ui;

import java.math.BigInteger;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v4.view.ViewPager;
import android.text.format.DateUtils;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;

import com.google.bitcoin.core.AbstractWalletEventListener;
import com.google.bitcoin.core.Address;
import com.google.bitcoin.core.ScriptException;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.TransactionConfidence;
import com.google.bitcoin.core.TransactionConfidence.ConfidenceType;
import com.google.bitcoin.core.Wallet;
import com.google.bitcoin.core.WalletEventListener;

import piuk.blockchain.R;
import piuk.blockchain.android.AddressBookProvider;
import piuk.blockchain.android.BlockchainService;
import piuk.blockchain.android.WalletApplication;
import piuk.blockchain.android.util.CircularProgressView;
import piuk.blockchain.android.util.ViewPagerTabs;

/**
 * @author Andreas Schildbach
 */
public final class WalletTransactionsFragment extends Fragment
{
  @Override
  public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState)
  {
    final View view = inflater.inflate(R.layout.wallet_transactions_fragment, container, false);

    final ViewPagerTabs pagerTabs = (ViewPagerTabs) view.findViewById(R.id.transactions_pager_tabs);
    pagerTabs.addTabLabels(R.string.wallet_transactions_fragment_tab_received, R.string.wallet_transactions_fragment_tab_all,
        R.string.wallet_transactions_fragment_tab_sent);

    final PagerAdapter pagerAdapter = new PagerAdapter(getFragmentManager());

    final ViewPager pager = (ViewPager) view.findViewById(R.id.transactions_pager);
    pager.setAdapter(pagerAdapter);
    pager.setOnPageChangeListener(pagerTabs);
    pager.setCurrentItem(1);
    pager.setPageMargin(2);
    pager.setPageMarginDrawable(R.color.background_less_bright);
    pagerTabs.onPageScrolled(1, 0, 0); // should not be needed

    return view;
  }

  private static class PagerAdapter extends FragmentStatePagerAdapter
  {
    public PagerAdapter(final FragmentManager fm)
    {
      super(fm);
    }

    @Override
    public int getCount()
    {
      return 3;
    }

    @Override
    public Fragment getItem(final int position)
    {
      return ListFragment.instance(position);
    }
  }

  private static class TransactionsLoader extends AsyncTaskLoader<List<Transaction>>
  {
    private final WalletApplication application;

    private TransactionsLoader(final Context context, final WalletApplication application)
    {
      super(context);

      this.application = application;
    }

    @Override
    protected void onStartLoading()
    {
      super.onStartLoading();

      application.getWallet().addEventListener(walletEventListener);

      forceLoad();
    }

    @Override
    protected void onStopLoading()
    {
      application.getWallet().removeEventListener(walletEventListener);

      super.onStopLoading();
    }

    @Override
    public List<Transaction> loadInBackground()
    {
      final List<Transaction> transactions = new ArrayList<Transaction>(application.getWallet().getTransactions(true, false));

      Collections.sort(transactions, TRANSACTION_COMPARATOR);

      return transactions;
    }

    private final WalletEventListener walletEventListener = new AbstractWalletEventListener()
    {
      @Override
      public void onChange(Wallet wallet)
      {
        try {
          forceLoad();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    };

    private static final Comparator<Transaction> TRANSACTION_COMPARATOR = new Comparator<Transaction>()
        {
      public int compare(final Transaction tx1, final Transaction tx2)
      {
        final boolean pending1 = tx1.getConfidence().getConfidenceType() == ConfidenceType.NOT_SEEN_IN_CHAIN;
        final boolean pending2 = tx2.getConfidence().getConfidenceType() == ConfidenceType.NOT_SEEN_IN_CHAIN;

        if (pending1 != pending2)
          return pending1 ? -1 : 1;

        final long time1 = tx1.getUpdateTime() != null ? tx1.getUpdateTime().getTime() : 0;
        final long time2 = tx2.getUpdateTime() != null ? tx2.getUpdateTime().getTime() : 0;

        if (time1 != time2)
          return time1 > time2 ? -1 : 1;

          return 0;
      }
        };
  }

  public static class ListFragment extends android.support.v4.app.ListFragment implements LoaderCallbacks<List<Transaction>>
  {
    private WalletApplication application;
    private Activity activity;
    private ArrayAdapter<Transaction> adapter;

    private int mode;

    private int bestChainHeight;

    private final Handler handler = new Handler();

    private final static String KEY_MODE = "mode";

    public static ListFragment instance(final int mode)
    {
      final ListFragment fragment = new ListFragment();

      final Bundle args = new Bundle();
      args.putInt(KEY_MODE, mode);
      fragment.setArguments(args);

      return fragment;
    }

    private final ContentObserver contentObserver = new ContentObserver(handler)
    {
      @Override
      public void onChange(final boolean selfChange)
      {
        try {
          adapter.notifyDataSetChanged();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    };

    private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver()
    {
      @Override
      public void onReceive(final Context context, final Intent intent)
      {
        bestChainHeight = intent.getIntExtra(BlockchainService.ACTION_BLOCKCHAIN_STATE_BEST_CHAIN_HEIGHT, 0);

        adapter.notifyDataSetChanged();
      }
    };

    @Override
    public void onAttach(final Activity activity)
    {
      super.onAttach(activity);

      this.activity = activity;
      application = (WalletApplication) activity.getApplication();
    }

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

      this.mode = getArguments().getInt(KEY_MODE);

      adapter = new ArrayAdapter<Transaction>(activity, 0){
      
        final DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(activity);
        final DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(activity);
        final int colorSignificant = getResources().getColor(R.color.significant);
        final int colorInsignificant = getResources().getColor(R.color.insignificant);
        final int colorSent = getResources().getColor(R.color.color_sent);
        final int colorReceived = getResources().getColor(R.color.color_received);

        @Override
        public View getView(final int position, View row, final ViewGroup parent)
        {
          if (row == null)
            row = getLayoutInflater(null).inflate(R.layout.transaction_row, null);

          final Transaction tx = getItem(position);
          final TransactionConfidence confidence = tx.getConfidence();
          final ConfidenceType confidenceType = confidence.getConfidenceType();

          try
          {
            final BigInteger value = tx.getValue(application.getWallet());
            final boolean sent = value.signum() < 0;


            final int textColor;
            if (confidenceType == ConfidenceType.NOT_SEEN_IN_CHAIN)
            {
              textColor = colorInsignificant;
            }
            else if (confidenceType == ConfidenceType.BUILDING)
            {
            
              textColor = colorSignificant;
            }
            else if (confidenceType == ConfidenceType.NOT_IN_BEST_CHAIN)
            {
              textColor = colorSignificant;
            }
            else if (confidenceType == ConfidenceType.OVERRIDDEN_BY_DOUBLE_SPEND)
            {
              textColor = Color.RED;
            }
            else
            {
              textColor = colorInsignificant;
            }

            final String address;
            if (sent)
              if (tx.getOutputs().size() == 0)
                address = "Unknown";
              else
                address = tx.getOutputs().get(0).getScriptPubKey().getToAddress().toString();
            else
              if (tx.getInputs().size() == 0)
                address = "Generation";
              else
                address = tx.getInputs().get(0).getFromAddress().toString();

            final String label = AddressBookProvider.resolveLabel(activity.getContentResolver(), address);

            final TextView rowTime = (TextView) row.findViewById(R.id.transaction_row_time);
            final Date time = tx.getUpdateTime();
            rowTime.setText(time != null ? (DateUtils.isToday(time.getTime()) ? timeFormat.format(time) : dateFormat.format(time)) : null);
            rowTime.setTextColor(textColor);

            final TextView rowLabel = (TextView) row.findViewById(R.id.transaction_row_address);
            rowLabel.setTextColor(textColor);
            rowLabel.setText(label != null ? label : address);
            rowLabel.setTypeface(label != null ? Typeface.DEFAULT : Typeface.MONOSPACE);

            final CurrencyAmountView rowValue = (CurrencyAmountView) row.findViewById(R.id.transaction_row_value);
            rowValue.setCurrencyCode(null);
            rowValue.setAmountSigned(true);
            rowValue.setTextColor(textColor);
            rowValue.setAmount(value); 


            if (sent) {
              rowValue.setTextColor(colorSent);
            } else {
              rowValue.setTextColor(colorReceived);
            }

            return row;
          }
          catch (final ScriptException x)
          {
            throw new RuntimeException(x);
          }
        }
          };
          setListAdapter(adapter);

          activity.getContentResolver().registerContentObserver(AddressBookProvider.CONTENT_URI, true, contentObserver);
    }

    @Override
    public void onActivityCreated(final Bundle savedInstanceState)
    {
      super.onActivityCreated(savedInstanceState);

      getLoaderManager().initLoader(0, null, this);
    }

    @Override
    public void onViewCreated(final View view, final Bundle savedInstanceState)
    {
      super.onViewCreated(view, savedInstanceState);

      setEmptyText(getString(mode == 2 ? R.string.wallet_transactions_fragment_empty_text_sent
          : R.string.wallet_transactions_fragment_empty_text_received));

      registerForContextMenu(getListView());
    }

    @Override
    public void onResume()
    {
      super.onResume();

      activity.registerReceiver(broadcastReceiver, new IntentFilter(BlockchainService.ACTION_BLOCKCHAIN_STATE));
    }

    @Override
    public void onPause()
    {
      activity.unregisterReceiver(broadcastReceiver);

      super.onPause();
    }

    @Override
    public void onDestroy()
    {
      activity.getContentResolver().unregisterContentObserver(contentObserver);

      getLoaderManager().destroyLoader(0);

      super.onDestroy();
    }

    @Override
    public void onListItemClick(final ListView l, final View v, final int position, final long id)
    {
      final Transaction tx = adapter.getItem(position);
      editAddress(tx);
    }

    // workaround http://code.google.com/p/android/issues/detail?id=20065
    private static View lastContextMenuView;

    @Override
    public void onCreateContextMenu(final ContextMenu menu, final View v, final ContextMenuInfo menuInfo)
    {
      activity.getMenuInflater().inflate(R.menu.wallet_transactions_context, menu);

      lastContextMenuView = v;
    }

    @Override
    public boolean onContextItemSelected(final MenuItem item)
    {
      final AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item.getMenuInfo();
      final ListAdapter adapter = ((ListView) lastContextMenuView).getAdapter();
      final Transaction tx = (Transaction) adapter.getItem(menuInfo.position);

      switch (item.getItemId())
      {
      case R.id.wallet_transactions_context_edit_address:
        editAddress(tx);
        return true;

        /*case R.id.wallet_transactions_context_show_transaction:
          TransactionActivity.show(activity, tx);
          return true;
         */
      default:
        return false;
      }
    }

    private void editAddress(final Transaction tx)
    {
      try
      {
        final boolean sent = tx.getValue(application.getWallet()).signum() < 0;
        
        Address address = null;
        if (sent) {
          if (tx.getOutputs().size() == 0)
            return;
          
           address = tx.getOutputs().get(0).getScriptPubKey().getToAddress();
        } else {
          if (tx.getInputs().size() == 0)
            return;
          
          address = tx.getInputs().get(0).getFromAddress();
        }
        
        EditAddressBookEntryFragment.edit(getFragmentManager(), address.toString());
      }
      catch (final ScriptException x)
      {
        // ignore click
        x.printStackTrace();
      }
    }

    public Loader<List<Transaction>> onCreateLoader(final int id, final Bundle args)
    {
      return new TransactionsLoader(activity, application);
    }

    public void onLoadFinished(final Loader<List<Transaction>> loader, final List<Transaction> transactions)
    {
      adapter.clear();

      try
      {
        for (final Transaction tx : transactions)
        {
          final boolean sent = tx.getValue(application.getWallet()).signum() < 0;
          if ((mode == 0 && !sent) || mode == 1 || (mode == 2 && sent))
            adapter.add(tx);
        }
      }
      catch (final ScriptException x)
      {
        throw new RuntimeException(x);
      }
    }

    public void onLoaderReset(final Loader<List<Transaction>> loader)
    {
      adapter.clear();
    }
  }
}




Java Source Code List

piuk.BitcoinAddress.java
piuk.BitcoinScript.java
piuk.Hash.java
piuk.MyBlockChain.java
piuk.MyRemoteWallet.java
piuk.MyTransactionConfidence.java
piuk.MyTransactionInput.java
piuk.MyTransactionOutPoint.java
piuk.MyTransactionOutput.java
piuk.MyTransaction.java
piuk.MyWallet.java
piuk.blockchain.android.AddressBookProvider.java
piuk.blockchain.android.BlockchainService.java
piuk.blockchain.android.Constants.java
piuk.blockchain.android.DetermineFirstSeenThread.java
piuk.blockchain.android.ExchangeRatesProvider.java
piuk.blockchain.android.WalletApplication.java
piuk.blockchain.android.WalletBalanceWidgetProvider.java
piuk.blockchain.android.ui.AbstractWalletActivity.java
piuk.blockchain.android.ui.AmountCalculatorFragment.java
piuk.blockchain.android.ui.CurrencyAmountView.java
piuk.blockchain.android.ui.CurrencyCodeDrawable.java
piuk.blockchain.android.ui.EditAddressBookEntryFragment.java
piuk.blockchain.android.ui.ExchangeRatesFragment.java
piuk.blockchain.android.ui.NewAccountFragment.java
piuk.blockchain.android.ui.PairWalletActivity.java
piuk.blockchain.android.ui.PreferencesActivity.java
piuk.blockchain.android.ui.RequestCoinsActivity.java
piuk.blockchain.android.ui.RequestCoinsFragment.java
piuk.blockchain.android.ui.SecondPasswordFragment.java
piuk.blockchain.android.ui.SendCoinsActivity.java
piuk.blockchain.android.ui.SendCoinsFragment.java
piuk.blockchain.android.ui.SendingAddressesFragment.java
piuk.blockchain.android.ui.TransactionActivity.java
piuk.blockchain.android.ui.TransactionFragment.java
piuk.blockchain.android.ui.WalletActivity.java
piuk.blockchain.android.ui.WalletAddressesFragment.java
piuk.blockchain.android.ui.WalletBalanceFragment.java
piuk.blockchain.android.ui.WalletTransactionsFragment.java
piuk.blockchain.android.ui.WelcomeFragment.java
piuk.blockchain.android.util.ActionBarFragment.java
piuk.blockchain.android.util.Base43.java
piuk.blockchain.android.util.CircularProgressView.java
piuk.blockchain.android.util.ErrorReporter.java
piuk.blockchain.android.util.IOUtils.java
piuk.blockchain.android.util.Iso8601Format.java
piuk.blockchain.android.util.NfcTools.java
piuk.blockchain.android.util.QrDialog.java
piuk.blockchain.android.util.ViewPagerTabs.java
piuk.blockchain.android.util.WalletUtils.java