all_validations_br 5.0.1 copy "all_validations_br: ^5.0.1" to clipboard
all_validations_br: ^5.0.1 copied to clipboard

Complete Flutter toolkit for Brazilian validations, form masks, typed results, structured logging, and authenticated cryptography.

example/lib/main.dart

import 'package:all_observer/all_observer.dart';
import 'package:all_validations_br/all_validations_br.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

/// Estado reativo confinado ao aplicativo de exemplo.
///
/// `all_observer` demonstra apenas a reação da interface às operações do
/// ecossistema; não é dependência de runtime de nenhum pacote publicável.
class ExamplesController {
  final cryptKey = AllCrypto.generateKey();
  final logOutput = BrMemoryOutput(maxRecords: 10);
  final encryptedBase64 = Observable<String>('');
  final decryptedText = Observable<String>('');
  final cryptError = Observable<String>('');
  final lastLog = Observable<String>('');

  late final logger = BrLogger(
    tag: 'ToolkitExample',
    filter: const BrAllFilter(),
    printer: const BrSimplePrinter(showTime: false),
    output: logOutput,
  );

  late final Computed<bool> hasEncrypted =
      Computed(() => encryptedBase64.value.isNotEmpty);
  late final Computed<bool> hasError =
      Computed(() => cryptError.value.isNotEmpty);

  late final staticPayload = AllCrypto.encryptText(
    'Olá, Brasil!',
    key: cryptKey,
  );
  late final staticDecrypted = AllCrypto.decryptText(
    staticPayload,
    key: cryptKey,
  );

  void runCryptDemo() {
    try {
      const plaintext = 'Dados sensíveis do usuário 🔒';
      final envelope = AllCrypto.encryptText(plaintext, key: cryptKey);
      final encrypted = envelope.toBase64();
      final restored = CryptEnvelope.fromBase64(encrypted);
      final decrypted = AllCrypto.decryptText(restored, key: cryptKey);

      Observable.batch(() {
        cryptError.value = '';
        encryptedBase64.value = encrypted;
        decryptedText.value = decrypted;
      });
    } on CryptException catch (error) {
      Observable.batch(() {
        encryptedBase64.value = '';
        decryptedText.value = '';
        cryptError.value = error.toString();
      });
    }
  }

  void runTamperingDemo() {
    try {
      final payload = AllCrypto.encryptText('segredo', key: cryptKey);
      final tampered = CryptEnvelope(
        ciphertext: Uint8List.fromList(
          List<int>.from(payload.ciphertext)..[0] ^= 0xFF,
        ),
        algorithm: payload.algorithm,
        tag: payload.tag,
        nonce: payload.nonce,
        aad: payload.aad,
      );

      AllCrypto.decryptText(tampered, key: cryptKey);
    } on CryptException catch (error) {
      Observable.batch(() {
        encryptedBase64.value = '';
        decryptedText.value = '';
        cryptError.value = '✅ Adulteração detectada:\n${error.message}';
      });
    }
  }

  String validateCpfWithResult(String cpf) {
    final error = BrZod().required().cpf().build(cpf);
    final result = error == null
        ? Result.success<String, String>(cpf)
        : Result.failure<String, String>(error);

    return result.fold(
      (failure) => 'Falha: $failure',
      (value) => 'Sucesso: CPF ${BrFormatter.formatCpf(value)}',
    );
  }

  void runLoggerDemo() {
    logger.info('fluxo integrado concluído');
    final record = logOutput.records.last;
    lastLog.value = '${record.level.name.toUpperCase()} '
        '[${record.tag}] ${record.message}';
  }

  void dispose() {
    logger.dispose();
    hasEncrypted.close();
    hasError.close();
    encryptedBase64.close();
    decryptedText.close();
    cryptError.close();
    lastLog.close();
  }
}

class MyApp extends StatelessWidget {
  const MyApp({super.key, this.controller});

  final ExamplesController? controller;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'All Validations BR — Exemplos',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: ExamplesPage(controller: controller),
    );
  }
}

class ExamplesPage extends StatefulWidget {
  const ExamplesPage({super.key, this.controller});

  final ExamplesController? controller;

  @override
  State<ExamplesPage> createState() => _ExamplesPageState();
}

class _ExamplesPageState extends State<ExamplesPage> {
  late final ExamplesController _controller;
  late final bool _ownsController;

  @override
  void initState() {
    super.initState();
    _ownsController = widget.controller == null;
    _controller = widget.controller ?? ExamplesController();
  }

  @override
  void dispose() {
    if (_ownsController) _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('All Validations BR — Exemplos')),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // ── Validações de CPF ───────────────────────────────────────────
            _sectionTitle('AllValidations — CPF'),
            _resultRow(
                'isCpf("00000000000")', AllValidations.isCpf('00000000000')),
            _resultRow('isCpf("728.551.470-50")',
                AllValidations.isCpf('728.551.470-50')),
            _resultRow(
                'isCpf("72855147050")', AllValidations.isCpf('72855147050')),
            _labelValue(
              'BrZod + Result',
              _controller.validateCpfWithResult('52998224725'),
            ),
            const SizedBox(height: 12),
            TextFormField(
              inputFormatters: const [PhoneMask()],
              autovalidateMode: AutovalidateMode.onUserInteraction,
              validator: BrZod().required().phone().build,
              keyboardType: TextInputType.phone,
              decoration: const InputDecoration(
                labelText: 'Telefone — máscara + validação',
                hintText: '(11) 91234-5678',
                border: OutlineInputBorder(),
                isDense: true,
              ),
            ),

            const Divider(height: 32),

            _sectionTitle('AllLogger — pipeline testável'),
            const Text(
              'O exemplo usa BrMemoryOutput: nenhum dado é enviado para rede.',
              style: TextStyle(fontSize: 12, color: Colors.black54),
            ),
            const SizedBox(height: 8),
            ElevatedButton(
              onPressed: _controller.runLoggerDemo,
              child: const Text('Registrar evento seguro'),
            ),
            Observer(() {
              if (_controller.lastLog.value.isEmpty) {
                return const SizedBox.shrink();
              }
              return Padding(
                padding: const EdgeInsets.only(top: 8),
                child: _mono(_controller.lastLog.value),
              );
            }),

            const Divider(height: 32),

            // ── HelperUtil — utilitários gerais ─────────────────────────────
            _sectionTitle('HelperUtil — utilitários gerais'),
            _labelValue(
              'countWords("Flutter é incrível")',
              '${HelperUtil.countWords("Flutter é incrível")}',
            ),
            _labelValue(
              'removeHtmlTags("<p>Olá <b>Mundo</b></p>")',
              HelperUtil.removeHtmlTags('<p>Olá <b>Mundo</b></p>'),
            ),
            _labelValue(
              'capitalizeWords("flutter é incrível")',
              HelperUtil.capitalizeWords('flutter é incrível'),
            ),
            _labelValue(
              'formatCurrency(1234.56)',
              BrFormatter.formatCurrency(1234.56),
            ),
            _labelValue(
              'daysBetween(01/01/2024, 31/12/2024)',
              '${HelperUtil.daysBetween(DateTime(2024, 1, 1), DateTime(2024, 12, 31))} dias',
            ),
            _labelValue(
              'generateUUIDv4()',
              HelperUtil.generateUUIDv4(),
            ),
            _labelValue(
              'validatePixKey("+5511912345678")',
              HelperUtil.validatePixKey('+5511912345678') ?? 'inválida',
            ),
            _labelValue(
              'maskPixKey("99286479174")',
              HelperUtil.maskPixKey('99286479174'),
            ),

            const Divider(height: 32),

            // ── Máscaras de Campo ───────────────────────────────────────────
            _sectionTitle('Máscaras de Campo — BrInputMask'),
            const Text(
              'Digite para ver a máscara aplicada em tempo real:',
              style: TextStyle(fontSize: 12, color: Colors.black54),
            ),
            const SizedBox(height: 12),
            _maskField('CPF', [const CpfMask()],
                keyboardType: TextInputType.number),
            _maskField('CNPJ', [const CnpjMask()],
                keyboardType: TextInputType.number),
            _maskField('CNPJ Alfanumérico (2026)', [const CnpjAlfaMask()],
                keyboardType: TextInputType.text),
            _maskField('Telefone', [const PhoneMask()],
                keyboardType: TextInputType.phone),
            _maskField('CEP', [const CepMask()],
                keyboardType: TextInputType.number),
            _maskField('Data (DD/MM/AAAA)', [const DateMask()],
                keyboardType: TextInputType.number),
            _maskField('Hora (HH:MM)', [const TimeMask()],
                keyboardType: TextInputType.number),
            _maskField('Valor em R\$', [const CurrencyMask()],
                keyboardType: TextInputType.number),
            _maskField('Número do Cartão', [const CardMask()],
                keyboardType: TextInputType.number),
            _maskField('Validade do Cartão (MM/AA)', [const CardExpiryMask()],
                keyboardType: TextInputType.number),
            _maskField('CPF ou CNPJ (dinâmico)', [const CpfOuCnpjMask()],
                keyboardType: TextInputType.number),
            _maskField('Placa de Veículo', [const PlacaMask()],
                keyboardType: TextInputType.text),
            _maskField('Quilometragem', [const KmMask()],
                keyboardType: TextInputType.number),
            _maskField('Centavos (sem R\$)', [const CentavosMask()],
                keyboardType: TextInputType.number),
            _maskField('NCM', [const NcmMask()],
                keyboardType: TextInputType.number),
            _maskField('CNS (Cartão Nacional de Saúde)', [const CnsMask()],
                keyboardType: TextInputType.number),
            _maskField('Altura (m)', [const AlturaMask()],
                keyboardType: TextInputType.number),
            _maskField('Peso (kg)', [const PesoMask()],
                keyboardType: TextInputType.number),
            _maskField('Temperatura (°C)', [const TemperaturaMask()],
                keyboardType: TextInputType.number),
            _maskField('CEST', [const CestMask()],
                keyboardType: TextInputType.number),
            _maskField('IOF (alíquota)', [const IofMask()],
                keyboardType: TextInputType.number),
            _maskField('NUP (protocolo federal)', [const NupMask()],
                keyboardType: TextInputType.number),
            _maskField('Certidão de Nascimento', [const CertNascimentoMask()],
                keyboardType: TextInputType.number),

            const Divider(height: 32),

            // ── AllCrypto — envelope seguro v2 ─────────────────────────────
            _sectionTitle('AllCrypto — envelope seguro v2'),
            const Text(
              'Chave sintética gerada em memória; não serializada nem exibida.',
              style: TextStyle(fontSize: 12, color: Colors.black54),
            ),
            const SizedBox(height: 8),

            Wrap(
              spacing: 8,
              children: [
                ElevatedButton(
                  onPressed: _controller.runCryptDemo,
                  child: const Text('Encriptar / Decriptar'),
                ),
                ElevatedButton(
                  onPressed: _controller.runTamperingDemo,
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.orange,
                  ),
                  child: const Text('Simular adulteração'),
                ),
              ],
            ),
            const SizedBox(height: 12),
            Observer(() {
              if (!_controller.hasEncrypted.value) {
                return const SizedBox.shrink();
              }
              return Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  _label('Ciphertext (base64):'),
                  _mono(_controller.encryptedBase64.value),
                  const SizedBox(height: 8),
                  _label('Decriptado:'),
                  _mono(_controller.decryptedText.value),
                ],
              );
            }),
            Observer(() {
              if (!_controller.hasError.value) {
                return const SizedBox.shrink();
              }
              return Padding(
                padding: const EdgeInsets.only(top: 8),
                child: Container(
                  key: const ValueKey('crypt-error'),
                  padding: const EdgeInsets.all(10),
                  decoration: BoxDecoration(
                    color: Colors.orange.shade50,
                    border: Border.all(color: Colors.orange),
                    borderRadius: BorderRadius.circular(6),
                  ),
                  child: Text(
                    _controller.cryptError.value,
                    style: const TextStyle(fontSize: 13),
                  ),
                ),
              );
            }),

            const Divider(height: 32),

            // ── AllCrypto — resultados estáticos ────────────────────────────
            _sectionTitle('AllCrypto — exemplos estáticos'),
            _labelValue('Texto original', 'Olá, Brasil!'),
            _labelValue(
              'Tag (hex)',
              _controller.staticPayload.tag
                  .map((byte) => byte.toRadixString(16).padLeft(2, '0'))
                  .join(),
            ),
            _labelValue('Decriptado', _controller.staticDecrypted),
            _labelValue(
              'Round-trip correto?',
              _controller.staticDecrypted == 'Olá, Brasil!' ? '✅ sim' : '❌ não',
            ),
          ],
        ),
      ),
    );
  }

  // ── Widgets auxiliares ────────────────────────────────────────────────────

  Widget _sectionTitle(String title) => Padding(
        padding: const EdgeInsets.only(bottom: 8),
        child: Text(
          title,
          style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
        ),
      );

  Widget _resultRow(String label, bool value) => Padding(
        padding: const EdgeInsets.symmetric(vertical: 2),
        child: Row(
          children: [
            Expanded(
                child: Text(label,
                    style: const TextStyle(
                        fontFamily: 'monospace', fontSize: 12))),
            Text(
              value ? '✅ true' : '❌ false',
              style: TextStyle(
                  color: value ? Colors.green : Colors.red,
                  fontWeight: FontWeight.bold),
            ),
          ],
        ),
      );

  Widget _labelValue(String label, String value) => Padding(
        padding: const EdgeInsets.symmetric(vertical: 3),
        child: RichText(
          text: TextSpan(
            style: const TextStyle(color: Colors.black, fontSize: 13),
            children: [
              TextSpan(
                  text: '$label: ',
                  style: const TextStyle(
                      fontFamily: 'monospace',
                      fontSize: 12,
                      color: Colors.black54)),
              TextSpan(
                  text: value,
                  style: const TextStyle(fontWeight: FontWeight.w600)),
            ],
          ),
        ),
      );

  Widget _label(String text) => Text(
        text,
        style: const TextStyle(fontSize: 12, color: Colors.black54),
      );

  Widget _mono(String text) => Container(
        width: double.infinity,
        padding: const EdgeInsets.all(8),
        decoration: BoxDecoration(
          color: Colors.grey.shade100,
          borderRadius: BorderRadius.circular(4),
        ),
        child: Text(
          text,
          style: const TextStyle(fontFamily: 'monospace', fontSize: 11),
        ),
      );

  Widget _maskField(
    String label,
    List<TextInputFormatter> formatters, {
    TextInputType keyboardType = TextInputType.text,
  }) =>
      Padding(
        padding: const EdgeInsets.symmetric(vertical: 6),
        child: TextField(
          keyboardType: keyboardType,
          inputFormatters: formatters,
          decoration: InputDecoration(
            labelText: label,
            border: const OutlineInputBorder(),
            isDense: true,
            contentPadding:
                const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
          ),
          style: const TextStyle(fontFamily: 'monospace', fontSize: 14),
        ),
      );
}
98
likes
160
points
1.07k
downloads

Documentation

API reference

Publisher

verified publisheropensource.tatamemaster.com.br

Weekly Downloads

Complete Flutter toolkit for Brazilian validations, form masks, typed results, structured logging, and authenticated cryptography.

Repository (GitHub)
View/report issues
Contributing

Topics

#validation #brazil #formatter #mask #cpf

License

MIT (license)

Dependencies

all_br_forms, all_br_validations, all_crypto, all_logger, all_result, flutter

More

Packages that depend on all_validations_br