package br.com.concretesolutions.canarinho.watcher; import android.text.Editable; import android.text.InputFilter; import java.util.Arrays; import br.com.concretesolutions.canarinho.validator.Validador; import br.com.concretesolutions.canarinho.validator.ValidadorBoleto; import br.com.concretesolutions.canarinho.watcher.evento.EventoDeValidacao; import br.com.concretesolutions.canarinho.watcher.evento.EventoDeValidacaoDeBoleto; /** * {@link android.text.TextWatcher} responsável por formatar e validar um {@link * android.widget.EditText} para boletos. Para usar este componente basta criar uma instância e * chamar {@link android.widget.EditText#addTextChangedListener(android.text.TextWatcher)}. */ public final class BoletoBancarioTextWatcher extends BaseCanarinhoTextWatcher { private static final char[] BOLETO_NORMAL = "#####.##### #####.###### #####.###### # ##############".toCharArray(); private static final char[] BOLETO_TRIBUTO = "############ ############ ############ ############".toCharArray(); private static final InputFilter[] FILTRO_TRIBUTO = new InputFilter[]{ new InputFilter.LengthFilter(BOLETO_TRIBUTO.length)}; private static final InputFilter[] FILTRO_NORMAL = new InputFilter[]{ new InputFilter.LengthFilter(BOLETO_NORMAL.length)}; private final Validador validador = ValidadorBoleto.getInstance(); private final Validador.ResultadoParcial resultadoParcial = new Validador.ResultadoParcial(); /** * TODO Javadoc pendente * * @param callbackErros a descrever */ public BoletoBancarioTextWatcher(EventoDeValidacao callbackErros) { setEventoDeValidacao(callbackErros); } @Override public final void afterTextChanged(Editable s) { // retorna se a String é menor que o mínimo de caracteres // para haver uma formatação ou se a mudança foi disparada // pelo método atualizaTexto if (isMudancaInterna()) { return; } // Trata o caso em que tudo é apagado em lote if (s.length() < 3) { resultadoParcial.mensagem(null).parcialmenteValido(false).totalmenteValido(false); if (getEventoDeValidacao() != null) { getEventoDeValidacao().parcialmenteValido(""); } } if (s.length() == 0) { verificaFiltro(s, false); return; } final boolean tributo = ehTributo(s); final char[] mascara = tributo ? BOLETO_TRIBUTO : BOLETO_NORMAL; verificaFiltro(s, tributo); // Trata deleção e adição de forma diferente (só formata em adições) final StringBuilder builder = trataAdicaoRemocaoDeCaracter(s, mascara); atualizaTexto(validador, resultadoParcial, s, builder); } public Validador.ResultadoParcial getResultadoParcial() { return resultadoParcial; } @Override protected void efetuaValidacao(Validador validador, Validador.ResultadoParcial resultadoParcial, Editable s) { validador.ehValido(s, resultadoParcial); final EventoDeValidacao callbackErros = getEventoDeValidacao(); if (callbackErros == null) { return; } final String valorAtual = s.toString(); if (!resultadoParcial.isParcialmenteValido()) { final String mensagem = resultadoParcial.getMensagem(); callbackErros.invalido(valorAtual, mensagem); if (callbackErros instanceof EventoDeValidacaoDeBoleto) { final int bloco; if (mensagem.startsWith("Primeiro")) { bloco = 1; } else if (mensagem.startsWith("Segundo")) { bloco = 2; } else if (mensagem.startsWith("Terceiro")) { bloco = 3; } else if (mensagem.startsWith("Quarto")) { bloco = 4; } else { throw new IllegalArgumentException("Valor não reconhecido para bloco"); } ((EventoDeValidacaoDeBoleto) callbackErros).invalido(valorAtual, bloco); } } else if (!resultadoParcial.isValido()) { callbackErros.parcialmenteValido(valorAtual); } else { callbackErros.totalmenteValido(valorAtual); } } private void verificaFiltro(final Editable s, final boolean tributo) { // Filtro de tamanho if (tributo && !Arrays.equals(s.getFilters(), FILTRO_TRIBUTO)) { s.setFilters(FILTRO_TRIBUTO); } else if (!tributo && !Arrays.equals(s.getFilters(), FILTRO_NORMAL)) { s.setFilters(FILTRO_NORMAL); } } // Boletos iniciados com 8 são tributos ou de concessionárias private boolean ehTributo(Editable e) { return e.charAt(0) == '8'; } }