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.watcher.evento.EventoDeValidacao; /** * Máscara c/ validação genérica para campos numéricos. * * @see br.com.concretesolutions.canarinho.watcher.MascaraNumericaTextWatcher.Builder */ public final class MascaraNumericaTextWatcher extends BaseCanarinhoTextWatcher { private final Validador.ResultadoParcial resultadoParcial = new Validador.ResultadoParcial(); private final Validador validador; private final char[] mascara; private final InputFilter[] filtroNumerico; /** * Construtor para adicionar uma máscara sem validação. * * @param mascara Máscara para efetuar a formatação */ public MascaraNumericaTextWatcher(String mascara) { this(new Builder().paraMascara(mascara)); } private MascaraNumericaTextWatcher(Builder builder) { this.mascara = builder.mascara.toCharArray(); this.validador = builder.validador; final int length = mascara.length; this.filtroNumerico = new InputFilter[]{new InputFilter.LengthFilter(length)}; setEventoDeValidacao(builder.eventoDeValidacao); } @Override public void afterTextChanged(Editable s) { // retorna se a mudança foi disparada pelo método atualizaTexto if (isMudancaInterna()) { return; } // Filtro de tamanho if (!Arrays.equals(s.getFilters(), filtroNumerico)) { s.setFilters(filtroNumerico); } final StringBuilder builder = trataAdicaoRemocaoDeCaracter(s, mascara); atualizaTexto(validador, resultadoParcial, s, builder); } /** * Builder para construção de máscaras que validam. */ public static final class Builder { private Validador validador; private EventoDeValidacao eventoDeValidacao; private String mascara; /** * O validador que será usado. Será chamada a implementação de * {@link Validador#ehValido(Editable, Validador.ResultadoParcial)} * * @param validador Implementação de {@link Validador} * @return this para interface fluente */ public Builder comValidador(Validador validador) { this.validador = validador; return this; } /** * Para cada caracter digitado será validado de acordo com o Validador e o callback * correspondente ao resultado da validação será chamado para que a interface possa ser atualizada. * * @param callbackErros {@link EventoDeValidacao} que será chamado durante a validação * @return this para interface fluente */ public Builder comCallbackDeValidacao(EventoDeValidacao callbackErros) { this.eventoDeValidacao = callbackErros; return this; } /** * A máscara só pode conter os caracteres '#' no lugar dos números. Assim, a máscara * '#####-##' irá aceitar apenas números no lugar de '#'. Ao digitar, o usuário irá ver: * '12345-67'. * * @param mascara Máscara * @return this para interface fluente */ public Builder paraMascara(String mascara) { this.mascara = mascara; return this; } /** * Constrói a máscara. * * @return A instância imutável da máscara. */ public final MascaraNumericaTextWatcher build() { if (mascara == null || mascara.isEmpty() || !mascara.contains("#")) { throw new IllegalArgumentException("Máscara precisa conter ao menos um caracter '#'"); } return new MascaraNumericaTextWatcher(this); } } }