Construindo um App para Condomínios com Flutter 3.41: Autenticação e Gestão (Parte 2)
Este artigo irá demonstrar os novos passos para o projeto Condomínio Online, focando no sistema de acesso e nas telas de serviços essenciais. Vamos utilizar o Flutter 3.41 para garantir que nossa arquitetura de navegação e estado siga as melhores práticas atuais.
🔐 Passo 1: Fluxo de Autenticação (Login e Registro)
Em um app de condomínio, a segurança é prioridade. O acesso deve ser restrito a moradores validados. Vamos criar telas de Login e Registro utilizando os novos estilos de campos de texto do Material 3.
Crie lib/modules/auth/login_screen.dart:
import 'package:flutter/material.dart';
class LoginScreen extends StatelessWidget {
const LoginScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Icon(Icons.domain, size: 80, color: Theme.of(context).colorScheme.primary),
const SizedBox(height: 16),
Text(
'Condomínio Online',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headlineMedium?.copyWith(fontWeight: FontWeight.bold),
),
const SizedBox(height: 32),
TextField(
decoration: InputDecoration(
labelText: 'E-mail ou CPF',
prefixIcon: const Icon(Icons.person_outline),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
),
),
const SizedBox(height: 16),
TextField(
obscureText: true,
decoration: InputDecoration(
labelText: 'Senha',
prefixIcon: const Icon(Icons.lock_outline),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
),
),
const SizedBox(height: 24),
FilledButton(
onPressed: () {},
style: FilledButton.styleFrom(padding: const EdgeInsets.symmetric(vertical: 16)),
child: const Text('ENTRAR'),
),
TextButton(
onPressed: () {},
child: const Text('Solicitar primeiro acesso'),
),
],
),
),
);
}
}
📄 Passo 2: Gestão Financeira (Tela de Boletos)
Nada é mais importante para a gestão do que a facilidade no pagamento. Vamos criar uma tela que lista os boletos pendentes e pagos, utilizando o componente SegmentedButton do Material 3 para filtrar o histórico.
Crie lib/modules/finance/bill_list_screen.dart:
import 'package:flutter/material.dart';
class BillListScreen extends StatelessWidget {
const BillListScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Meus Boletos')),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: SegmentedButton<int>(
segments: const [
ButtonSegment(value: 0, label: Text('Pendentes'), icon: Icon(Icons.pending_actions)),
ButtonSegment(value: 1, label: Text('Pagos'), icon: Icon(Icons.check_circle_outline)),
],
selected: const {0},
onSelectionChanged: (val) {},
),
),
Expanded(
child: ListView.builder(
itemCount: 3,
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: ListTile(
leading: const Icon(Icons.description, color: Colors.redAccent),
title: Text('Condomínio - Venc. 10/03/2026'),
subtitle: const Text('R\$ 850,00'),
trailing: IconButton(
icon: const Icon(Icons.copy),
onPressed: () {}, // Copiar código de barras
tooltip: 'Copiar código',
),
),
);
},
),
),
],
),
);
}
}
📦 Passo 3: Comodidade (Tela de Entregas)
O morador quer saber se a sua encomenda chegou na portaria. Esta tela deve mostrar o status da entrega e quem recebeu.
Crie lib/modules/delivery/delivery_list_screen.dart:
import 'package:flutter/material.dart';
class DeliveryListScreen extends StatelessWidget {
const DeliveryListScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Encomendas')),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
_buildDeliveryCard(
context,
title: 'Mercado Livre',
date: '21/02/2026 - 14:30',
receivedBy: 'Porteiro Ricardo',
isPickedUp: false,
),
_buildDeliveryCard(
context,
title: 'Amazon App',
date: '18/02/2026 - 09:15',
receivedBy: 'Zelador Marcos',
isPickedUp: true,
),
],
),
);
}
Widget _buildDeliveryCard(BuildContext context, {required String title, required String date, required String receivedBy, required bool isPickedUp}) {
return Card(
elevation: isPickedUp ? 0 : 2,
color: isPickedUp ? Theme.of(context).colorScheme.surfaceVariant : null,
margin: const EdgeInsets.only(bottom: 12),
child: ListTile(
leading: Icon(isPickedUp ? Icons.inventory_2_outlined : Icons.mark_as_unread,
color: isPickedUp ? Colors.grey : Colors.green),
title: Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text('Recebido em $date\nPor: $receivedBy'),
isThreeLine: true,
trailing: isPickedUp
? const Chip(label: Text('Retirado'))
: ElevatedButton(onPressed: () {}, child: const Text('Retirar')),
),
);
}
}
🏗️ Passo 4: Integração dos Serviços
Para que tudo funcione, precisamos atualizar a nossa navegação. Na Parte 1 criamos o MainLayout. Agora, vamos garantir que ao clicar nos ícones da Home, o usuário seja levado para as telas corretas.
Dica Profissional (Flutter 3.41): Sempre use rotas nomeadas ou um gerenciador de rotas como o GoRouter para gerenciar a pilha de telas, especialmente em apps que crescem rápido.
✅ Conclusão da Parte 2
Neste segundo passo, avançamos da “carcaça” visual para a funcionalidade real. Implementamos:
-
Segurança: Um formulário de login alinhado ao Material 3.
-
Financeiro: Listagem de boletos com filtros modernos.
-
Logística: Controle de encomendas com status de retirada.
O app está começando a tomar forma de um ecossistema completo. Na próxima parte, vamos implementar o Gerenciamento de Estado com BLoC para que esses dados não sejam apenas estáticos, e começaremos a trabalhar com a Câmera para visualização das áreas comuns!