// Copyright (C) 2013-2014 Bonsai Software, Inc. // // 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 com.bonsai.wallet32; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.EditText; import android.widget.TableLayout; import android.widget.TableRow; import android.widget.TextView; import android.widget.ViewSwitcher; public class ViewAccountActivity extends BaseWalletActivity { private static Logger mLogger = LoggerFactory.getLogger(ViewAccountActivity.class); private int mAccountId = -1; private HDAccount mAccount = null; private ViewSwitcher mAccountNameSwitcher; private TextView mAccountNameTextView; private EditText mAccountNameEditText; private Button mAccountNameSubmitButton; private enum NameEditState { INIT, // Transient state ... UNSET, // Button disabled, says Edit, text not editable. SET, // Button enabled, says "Edit", text not editable. CLEAN, // Button disabled, says "Submit", text editable. DIRTY // Button enabled, says "Submit", text editable. } private NameEditState mNameEditState; private final TextWatcher mAccountNameWatcher = new TextWatcher() { @Override public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { } @Override public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { } @Override public void afterTextChanged(Editable ss) { setNameState(NameEditState.DIRTY); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_view_account); Intent intent = getIntent(); mAccountId = intent.getExtras().getInt("accountId"); mAccountNameSwitcher = (ViewSwitcher) findViewById(R.id.account_name_switcher); mAccountNameTextView = (TextView) findViewById(R.id.account_name_textview); mAccountNameEditText = (EditText) findViewById(R.id.account_name_edittext); mAccountNameSubmitButton = (Button) findViewById(R.id.submit_account_name); mAccountNameEditText.addTextChangedListener(mAccountNameWatcher); mNameEditState = NameEditState.INIT; setNameState(NameEditState.UNSET); mLogger.info("ViewAccountActivity created"); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.account_actions, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle presses on the action bar items Intent intent; switch (item.getItemId()) { case R.id.action_export_xpub: intent = new Intent(this, ShowXPubActivity.class); Bundle bundle = new Bundle(); bundle.putString("xpubstr", mAccount.xpubstr()); intent.putExtras(bundle); startActivity(intent); return true; default: return super.onOptionsItemSelected(item); } } @Override protected void onWalletServiceBound() { // Update our HDAccount. mAccount = mWalletService.getAccount(mAccountId); // Update the account name field. mAccountNameTextView.setText(mAccount.getName()); mAccountNameEditText.setText(mAccount.getName()); setNameState(NameEditState.SET); } @Override protected void onWalletStateChanged() { updateChains(); } public void setNameState(NameEditState state) { // Bail if there hasn't been a change. if (state == mNameEditState) return; String buttonText = "???"; switch (state) { case INIT: // Shouldn't get here. break; case UNSET: // Button disabled, says "Edit", text not editable. mAccountNameSubmitButton.setEnabled(false); buttonText = mRes.getString(R.string.account_name_edit); mAccountNameSwitcher.setDisplayedChild(0); break; case SET: // Button enabled, says "Edit", text not editable. mAccountNameSubmitButton.setEnabled(true); buttonText = mRes.getString(R.string.account_name_edit); mAccountNameSwitcher.setDisplayedChild(0); break; case CLEAN: // Button disabled, says "Submit", text editable. mAccountNameSubmitButton.setEnabled(false); buttonText = mRes.getString(R.string.account_name_submit); mAccountNameSwitcher.setDisplayedChild(1); break; case DIRTY: // Button enabled, says "Submit", text editable. mAccountNameSubmitButton.setEnabled(true); buttonText = mRes.getString(R.string.account_name_submit); mAccountNameSwitcher.setDisplayedChild(1); break; } mAccountNameSubmitButton.setText(buttonText); mNameEditState = state; } public void submitAccountName(View view) { switch (mNameEditState) { case SET: // This is an edit action. setNameState(NameEditState.CLEAN); mAccountNameEditText.requestFocus(); mAccountNameEditText.setSelection (mAccountNameEditText.getText().length()); break; case DIRTY: // This is a submit action. String name = mAccountNameEditText.getText().toString(); mLogger.info(String.format("Changing name of account %d to %s", mAccountId, name)); mAccount.setName(name); mWalletService.persist(); mAccountNameTextView.setText(name); setNameState(NameEditState.SET); break; } // Toggle the keyboard presence ... InputMethodManager inputMethodManager = (InputMethodManager) getSystemService (Context.INPUT_METHOD_SERVICE); inputMethodManager.toggleSoftInputFromWindow (mAccountNameEditText.getApplicationWindowToken(), InputMethodManager.SHOW_FORCED, 0); } private void updateChains() { updateChain(R.id.receive_table, mAccount.getReceiveChain()); updateChain(R.id.change_table, mAccount.getChangeChain()); } private void addAddressHeader(TableLayout table) { TableRow row = (TableRow) LayoutInflater.from(this) .inflate(R.layout.address_table_header, table, false); TextView tv = (TextView) row.findViewById(R.id.header_btc); tv.setText(mBTCFmt.unitStr()); table.addView(row); } private void addAddressRow(int tableId, int index, TableLayout table, String path, String addr, String ntrans, String btcstr, String fiatstr) { TableRow row = (TableRow) LayoutInflater.from(this) .inflate(R.layout.address_table_row, table, false); row.setTag(tableId); row.setId(index); { TextView tv = (TextView) row.findViewById(R.id.row_path); tv.setText(path); } { TextView tv = (TextView) row.findViewById(R.id.row_addr); tv.setText(addr); } { TextView tv = (TextView) row.findViewById(R.id.row_ntrans); tv.setText(ntrans); } { TextView tv = (TextView) row.findViewById(R.id.row_btc); tv.setText(btcstr); } { TextView tv = (TextView) row.findViewById(R.id.row_fiat); tv.setText(fiatstr); } table.addView(row); } public void handleRowClick(View view) { int tableId = (Integer) view.getTag(); int index = view.getId(); viewAddress(tableId, index); } public void viewAddress(int tableId, int index) { HDChain chain = null; switch (tableId) { case R.id.receive_table: mLogger.info(String.format("receive row %d clicked", index)); chain = mAccount.getReceiveChain(); break; case R.id.change_table: mLogger.info(String.format("change row %d clicked", index)); chain = mAccount.getChangeChain(); break; } List<HDAddress> addrs = chain.getAddresses(); HDAddress addr = addrs.get(index); String addrstr = addr.getAddressString(); // Dispatch to the address viewer. Intent intent = new Intent(this, ViewAddressActivity.class); intent.putExtra("key", addr.getPrivateKeyString()); intent.putExtra("address", addrstr); startActivity(intent); } private void updateChain(int tableId, HDChain chain) { if (mWalletService == null) return; TableLayout table = (TableLayout) findViewById(tableId); // Clear any existing table content. table.removeAllViews(); addAddressHeader(table); // Read all of the addresses. Presume order is correct ... int ndx = 0; List<HDAddress> addrs = chain.getAddresses(); for (HDAddress addr : addrs) { String path = addr.getPath(); String addrstr = addr.getAbbrev(); String ntrans = String.format("%d", addr.numTrans()); String bal = mBTCFmt.formatCol(addr.getBalance(), 0, true, true); String fiat = String.format ("%.02f", mBTCFmt.fiatAtRate(addr.getBalance(), mFiatPerBTC)); addAddressRow(tableId, ndx++, table, path, addrstr, ntrans, bal, fiat); } } } // Local Variables: // mode: java // c-basic-offset: 4 // tab-width: 4 // End: