package br.com.concretesolutions.canarinho.watcher; import android.text.Editable; import android.text.Selection; import android.text.TextWatcher; import java.math.BigDecimal; import java.math.RoundingMode; import br.com.concretesolutions.canarinho.formatador.Formatador; /** * TextWatcher para valores monetários */ public class ValorMonetarioWatcher implements TextWatcher { private final boolean mantemZerosAoLimpar; private final Formatador formatador; private boolean mudancaInterna; /** * Constrói uma instância sem símbolo de Real (R$). */ public ValorMonetarioWatcher() { this(false, true); } /** * Constrói uma instância com opção de símbolo de Real (R$). * * @param comSimboloReal Flag para acrescentar ou não o símbolo * @param mantemZerosAoLimpar Sempre que não houver números (apagar em lote) manter zeros */ ValorMonetarioWatcher(boolean comSimboloReal, boolean mantemZerosAoLimpar) { this.formatador = comSimboloReal ? Formatador.VALOR_COM_SIMBOLO : Formatador.VALOR; this.mantemZerosAoLimpar = mantemZerosAoLimpar; } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // Não faz nada aqui } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // Não faz nada aqui } @Override public void afterTextChanged(Editable s) { if (mudancaInterna) { return; } final String somenteNumeros = Formatador.Padroes.PADRAO_SOMENTE_NUMEROS .matcher(s.toString()) .replaceAll(""); // afterTextChanged é chamado ao rotacionar o dispositivo, // essa condição evita que ao rotacionar a tela com o campo vazio ocorra NumberFormatException if (somenteNumeros.length() == 0) { if (mantemZerosAoLimpar) { atualizaTexto(s, formatador.formata("000")); } return; } final BigDecimal resultado = new BigDecimal(somenteNumeros) .divide(new BigDecimal(100)) .setScale(2, RoundingMode.HALF_DOWN); atualizaTexto(s, formatador.formata(resultado.toPlainString())); } private void atualizaTexto(Editable s, String valor) { mudancaInterna = true; s.replace(0, s.length(), valor); if (valor.equals(s.toString())) { // TODO: estudar implantar a manutenção da posição do cursor Selection.setSelection(s, valor.length()); } mudancaInterna = false; } /** * Builder para facilitar a construção de instâncias de {@link ValorMonetarioWatcher} */ public static class Builder { private boolean mantemZerosAoLimpar; private boolean simboloReal; /** * Manterá os zeros ao limpar o campo. * * @return this Fluent interface */ public Builder comMantemZerosAoLimpar() { this.mantemZerosAoLimpar = true; return this; } /** * Inclui o símbolo de real na formatação. * * @return this Fluent interface */ public Builder comSimboloReal() { this.simboloReal = true; return this; } /** * Constrói a instância * * @return Watcher para ser usado */ public ValorMonetarioWatcher build() { return new ValorMonetarioWatcher(simboloReal, mantemZerosAoLimpar); } } }