No universo do desenvolvimento mobile, unir tecnologias modernas com metodologias assistidas por Inteligência Artificial tem se mostrado uma maneira poderosa de acelerar entregas, organizar o código e promover boas práticas. Neste artigo, vou compartilhar o início do desenvolvimento do aplicativo APSREDE, um projeto que utiliza Flutter, consumo de API WordPress e gerenciamento de estado com Provider — tudo isso com o apoio da IA para gerar, revisar e refinar o código ao longo do processo.
🎯 Objetivo do Projeto
O objetivo foi desenvolver, do zero, um aplicativo Flutter que:
- Consome os posts do site apsredes.org via API REST do WordPress;
- Lista os últimos posts publicados na tela inicial;
- Exibe o conteúdo de cada post com imagem, título, resumo e botão “Leia Mais”;
- Inclui um efeito de carregamento nas imagens;
- Navega entre telas com simplicidade e fluidez;
- Utiliza cores institucionais:
- Primária:
#005BAF
- Secundária:
#FF783F
- Primária:
🛠️ Etapas Iniciais
1. Criação do Projeto
flutter create apsrede
cd apsrede
2. Adição das Dependências
No pubspec.yaml
, foram incluídas:
dependencies:
flutter:
sdk: flutter
http: ^0.13.6
provider: ^6.1.1
cached_network_image: ^3.3.1
html: ^0.15.0
Essas bibliotecas foram sugeridas pela IA para otimizar a construção e estilização dos widgets, tratamento de HTML e consumo da API REST.
📁 Estrutura de Pastas
plaintextCopiarEditarlib/
├── main.dart
├── core/
│ └── theme.dart
├── models/
│ └── post.dart
├── services/
│ └── wordpress_service.dart
├── providers/
│ └── post_provider.dart
├── screens/
│ ├── home_screen.dart
│ ├── category_screen.dart
│ └── post_detail_screen.dart
└── widgets/
└── post_card.dart
📦 Modelagem de Dados
lib/models/post.dart
class Post {
final int id;
final String title;
final String excerpt;
final String content;
final String imageUrl;
Post({
required this.id,
required this.title,
required this.excerpt,
required this.content,
required this.imageUrl,
});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
id: json['id'],
title: json['title']['rendered'],
excerpt: json['excerpt']['rendered'],
content: json['content']['rendered'],
imageUrl: json['_embedded']?['wp:featuredmedia']?[0]?['source_url'] ?? '',
);
}
}
🎨 Tema Customizado
lib/core/theme.dart
import 'package:flutter/material.dart';
final ThemeData appTheme = ThemeData(
primaryColor: const Color(0xFF005BAF),
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF005BAF),
secondary: const Color(0xFFFF783F),
),
useMaterial3: true,
);
🧠 Provider e Consumo da API
📡 WordPressService
lib/services/wordpress_service.dart
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../models/post.dart';
class WordPressService {
static const String _baseUrl = 'https://apsredes.org/wp-json/wp/v2';
Future<List<Post>> fetchLatestPosts() async {
final response = await http.get(Uri.parse('$_baseUrl/posts?_embed'));
if (response.statusCode == 200) {
List data = json.decode(response.body);
return data.map((json) => Post.fromJson(json)).toList();
} else {
throw Exception('Erro ao carregar posts');
}
}
}
🧩 PostProvider
lib/providers/post_provider.dart
import 'package:flutter/material.dart';
import '../models/post.dart';
import '../services/wordpress_service.dart';
class PostProvider extends ChangeNotifier {
final WordPressService _service = WordPressService();
List<Post> _posts = [];
bool _isLoading = false;
List<Post> get posts => _posts;
bool get isLoading => _isLoading;
Future<void> loadPosts() async {
_isLoading = true;
notifyListeners();
_posts = await _service.fetchLatestPosts();
_isLoading = false;
notifyListeners();
}
}
🧱 Construção da Interface
🏠 Tela Inicial
lib/screens/home_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/post_provider.dart';
import '../widgets/post_card.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
void initState() {
super.initState();
Provider.of<PostProvider>(context, listen: false).loadPosts();
}
@override
Widget build(BuildContext context) {
final postProvider = Provider.of<PostProvider>(context);
return Scaffold(
appBar: AppBar(title: const Text('Últimos Posts')),
body: postProvider.isLoading
? const Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: postProvider.posts.length,
itemBuilder: (context, index) {
return PostCard(post: postProvider.posts[index]);
},
),
);
}
}
🖼️ PostCard Widge
lib/widgets/post_card.dart
import 'package:flutter/material.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter_html/flutter_html.dart';
import '../models/post.dart';
import '../screens/post_detail_screen.dart';
class PostCard extends StatelessWidget {
final Post post;
const PostCard({super.key, required this.post});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.all(12),
child: InkWell(
onTap: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => PostDetailScreen(post: post)),
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(post.title, style: Theme.of(context).textTheme.titleLarge),
const SizedBox(height: 8),
CachedNetworkImage(
imageUrl: post.imageUrl,
placeholder: (context, url) => const Center(child: CircularProgressIndicator()),
errorWidget: (context, url, error) => const Icon(Icons.broken_image),
),
const SizedBox(height: 8),
Html(data: post.excerpt),
Align(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => PostDetailScreen(post: post)),
),
child: const Text('Leia Mais'),
),
),
],
),
),
),
);
}
}
📖 Tela de Detalhe do Post
lib/screens/post_detail_screen.dart
import 'package:flutter/material.dart';
import 'package:flutter_html/flutter_html.dart';
import '../models/post.dart';
class PostDetailScreen extends StatelessWidget {
final Post post;
const PostDetailScreen({super.key, required this.post});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Voltar')),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Html(data: post.content),
),
);
}
}
🤖 Como a IA Otimizou o Processo
Utilizar a IA neste processo trouxe os seguintes benefícios:
- Geração automatizada de estrutura de pastas e arquivos iniciais
- Sugestão de boas práticas de navegação, organização de código e nomenclatura
- Criação de código reutilizável, limpo e modularizado
- Ajuste dinâmico de temas e UI com base em especificações fornecidas
- Eliminação de erros comuns e testes conceituais prévios à execução
🔜 Continuação
Na Parte 2 deste artigo, exploraremos a implementação do MenuApp, a exibição das categorias vindas da API, e o carregamento dos posts por categoria, tudo com a fluidez que o Flutter proporciona.