/*
* Copyright 2011-2013 the original author or authors.
*
* 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 de.schildbach.wallet.digitalcoin.ui;
import java.math.BigInteger;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.Editable;
import android.text.InputType;
import android.text.SpannableStringBuilder;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import com.google.digitalcoin.core.Utils;
import de.schildbach.wallet.digitalcoin.Constants;
import de.schildbach.wallet.digitalcoin.util.WalletUtils;
import de.schildbach.wallet.digitalcoin.R;
/**
* @author Andreas Schildbach
*/
public final class CurrencyAmountView extends FrameLayout
{
public static interface Listener
{
void changed();
void done();
void focusChanged(final boolean hasFocus);
}
private int significantColor, lessSignificantColor, errorColor;
private Drawable deleteButtonDrawable, contextButtonDrawable;
private CurrencyCodeDrawable currencyCodeDrawable;
private int precision = Constants.WDC_PRECISION;
private boolean amountSigned = false;
private boolean smallerInsignificant = true;
private boolean validateAmount = true;
private TextView textView;
private View contextButton;
private Listener listener;
private OnClickListener contextButtonClickListener;
public CurrencyAmountView(final Context context)
{
super(context);
init(context);
}
public CurrencyAmountView(final Context context, final AttributeSet attrs)
{
super(context, attrs);
init(context);
}
private void init(final Context context)
{
final Resources resources = context.getResources();
significantColor = resources.getColor(R.color.fg_significant);
lessSignificantColor = resources.getColor(R.color.fg_less_significant);
errorColor = resources.getColor(R.color.fg_error);
deleteButtonDrawable = resources.getDrawable(R.drawable.ic_input_delete);
}
@Override
protected void onFinishInflate()
{
super.onFinishInflate();
final Context context = getContext();
textView = (TextView) getChildAt(0);
textView.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
textView.setHintTextColor(lessSignificantColor);
setHint(null);
setValidateAmount(textView instanceof EditText);
final TextViewListener textViewListener = new TextViewListener();
textView.addTextChangedListener(textViewListener);
textView.setOnFocusChangeListener(textViewListener);
textView.setOnEditorActionListener(textViewListener);
contextButton = new View(context)
{
@Override
protected void onMeasure(final int wMeasureSpec, final int hMeasureSpec)
{
setMeasuredDimension(textView.getCompoundPaddingRight(), textView.getMeasuredHeight());
}
};
final LayoutParams chooseViewParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
chooseViewParams.gravity = Gravity.RIGHT;
contextButton.setLayoutParams(chooseViewParams);
this.addView(contextButton);
setCurrencyCode(Constants.CURRENCY_CODE_LITECOIN);
updateAppearance();
}
public void setCurrencyCode(final String currencyCode)
{
if (currencyCode != null)
{
final float textSize = textView.getTextSize();
final float smallerTextSize = textSize * (smallerInsignificant ? (20f / 24f) : 1);
currencyCodeDrawable = new CurrencyCodeDrawable(currencyCode, smallerTextSize, lessSignificantColor, textSize * 0.37f);
}
else
{
currencyCodeDrawable = null;
}
updateAppearance();
}
public void setPrecision(final int precision)
{
this.precision = precision;
}
public void setAmountSigned(final boolean amountSigned)
{
this.amountSigned = amountSigned;
}
public void setSmallerInsignificant(final boolean smallerInsignificant)
{
this.smallerInsignificant = smallerInsignificant;
}
public void setValidateAmount(final boolean validateAmount)
{
this.validateAmount = validateAmount;
}
public void setContextButton(final int contextButtonResId, final OnClickListener contextButtonClickListener)
{
this.contextButtonDrawable = getContext().getResources().getDrawable(contextButtonResId);
this.contextButtonClickListener = contextButtonClickListener;
updateAppearance();
}
public void setListener(final Listener listener)
{
this.listener = listener;
}
public BigInteger getAmount()
{
if (isValidAmount())
return Utils.toNanoCoins(textView.getText().toString().trim());
else
return null;
}
public void setAmount(final BigInteger amount)
{
if (amount != null)
textView.setText(amountSigned ? WalletUtils.formatValue(amount, Constants.CURRENCY_PLUS_SIGN, Constants.CURRENCY_MINUS_SIGN, precision)
: WalletUtils.formatValue(amount, precision));
else
textView.setText(null);
}
public void setHint(final BigInteger amount)
{
final SpannableStringBuilder hint;
if (amount != null)
hint = new SpannableStringBuilder(WalletUtils.formatValue(amount, precision));
else
hint = new SpannableStringBuilder("0.00");
WalletUtils.formatSignificant(hint, smallerInsignificant ? WalletUtils.SMALLER_SPAN : null);
textView.setHint(hint);
}
@Override
public void setEnabled(final boolean enabled)
{
super.setEnabled(enabled);
textView.setEnabled(enabled);
updateAppearance();
}
public void setTextColor(final int color)
{
significantColor = color;
updateAppearance();
}
public void setStrikeThru(final boolean strikeThru)
{
if (strikeThru)
textView.setPaintFlags(textView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
else
textView.setPaintFlags(textView.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
}
private boolean isValidAmount()
{
final String amount = textView.getText().toString().trim();
try
{
if (amount.length() > 0)
{
final BigInteger nanoCoins = Utils.toNanoCoins(amount);
if (nanoCoins.signum() >= 0)
return true;
}
}
catch (final Exception x)
{
}
return false;
}
private final OnClickListener deleteClickListener = new OnClickListener()
{
public void onClick(final View v)
{
textView.setText(null);
textView.requestFocus();
}
};
private void updateAppearance()
{
final boolean enabled = textView.isEnabled();
contextButton.setEnabled(enabled);
final String amount = textView.getText().toString().trim();
if (enabled && amount.length() > 0)
{
textView.setCompoundDrawablesWithIntrinsicBounds(currencyCodeDrawable, null, deleteButtonDrawable, null);
contextButton.setOnClickListener(deleteClickListener);
}
else if (enabled && contextButtonDrawable != null)
{
textView.setCompoundDrawablesWithIntrinsicBounds(currencyCodeDrawable, null, contextButtonDrawable, null);
contextButton.setOnClickListener(contextButtonClickListener);
}
else
{
textView.setCompoundDrawablesWithIntrinsicBounds(currencyCodeDrawable, null, null, null);
contextButton.setOnClickListener(null);
}
contextButton.requestLayout();
textView.setTextColor(!validateAmount || isValidAmount() ? significantColor : errorColor);
}
@Override
protected Parcelable onSaveInstanceState()
{
final Bundle state = new Bundle();
state.putParcelable("super_state", super.onSaveInstanceState());
state.putSerializable("amount", getAmount());
return state;
}
@Override
protected void onRestoreInstanceState(final Parcelable state)
{
if (state instanceof Bundle)
{
final Bundle bundle = (Bundle) state;
super.onRestoreInstanceState(bundle.getParcelable("super_state"));
setAmount((BigInteger) bundle.getSerializable("amount"));
}
else
{
super.onRestoreInstanceState(state);
}
}
private final class TextViewListener implements TextWatcher, OnFocusChangeListener, OnEditorActionListener
{
public void afterTextChanged(final Editable s)
{
// workaround for German keyboards
final String original = s.toString();
final String replaced = original.replace(',', '.');
if (!replaced.equals(original))
{
s.clear();
s.append(replaced);
}
WalletUtils.formatSignificant(s, smallerInsignificant ? WalletUtils.SMALLER_SPAN : null);
}
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after)
{
}
public void onTextChanged(final CharSequence s, final int start, final int before, final int count)
{
updateAppearance();
if (listener != null)
listener.changed();
}
public void onFocusChange(final View v, final boolean hasFocus)
{
if (!hasFocus)
{
final BigInteger amount = getAmount();
if (amount != null)
setAmount(amount);
}
if (listener != null)
listener.focusChanged(hasFocus);
}
public boolean onEditorAction(final TextView v, final int actionId, final KeyEvent event)
{
if (actionId == EditorInfo.IME_ACTION_DONE && listener != null)
listener.done();
return false;
}
}
}