kz_educa/lib/screens/pdf_viewer_screen.dart

136 lines
4.5 KiB
Dart
Executable File

// lib/screens/pdf_viewer_screen.dart
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
import 'package:http/http.dart' as http; // Importação essencial para o download
import 'dart:typed_data'; // Para lidar com os bytes
import '../services/toast_service.dart';
class PdfViewerScreen extends StatefulWidget {
final String pdfUrl;
const PdfViewerScreen({Key? key, required this.pdfUrl}) : super(key: key);
@override
State<PdfViewerScreen> createState() => _PdfViewerScreenState();
}
class _PdfViewerScreenState extends State<PdfViewerScreen> {
bool _isLoading = true;
Uint8List? _pdfBytes; // Variável para guardar os bytes do PDF
String? _errorMessage;
@override
void initState() {
super.initState();
// Inicia o carregamento assíncrono do PDF
_loadPdf();
}
// Função para buscar o PDF como bytes (Contorna o CORS)
Future<void> _loadPdf() async {
try {
// 🚨 CORREÇÃO PRINCIPAL: Usa http.get para contornar o problema de CORS.
final response = await http.get(Uri.parse(widget.pdfUrl));
if (response.statusCode == 200) {
// Sucesso: armazena os bytes
_pdfBytes = response.bodyBytes;
_errorMessage = null;
} else {
// Erro HTTP (ex: 404 Not Found)
_errorMessage = 'Falha ao carregar o livro. Código HTTP: ${response.statusCode}.';
}
} catch (e) {
// Erro de rede (incluindo o erro de fetch/CORS)
_errorMessage = 'Erro de rede ou URL inválida. Detalhes: $e';
}
// Atualiza o estado se o widget ainda estiver montado
if (mounted) {
setState(() {
_isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF1A1A2E),
body: Stack(
children: [
// 1. Indicador de Carregamento
if (_isLoading)
const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(color: Color(0xFFE94560)),
SizedBox(height: 16),
Text("A carregar Livro...", style: TextStyle(color: Colors.white, fontSize: 16)),
],
),
)
// 2. Visualizador do PDF (usando a memória/bytes)
else if (_pdfBytes != null)
// 🚨 CORREÇÃO: Usa SfPdfViewer.memory() que aceita os bytes.
SfPdfViewer.memory(
_pdfBytes!,
onDocumentLoadFailed: (details) {
// Se o arquivo for baixado mas corrompido ou inválido
ToastService.show(
message: 'Erro interno ao renderizar o PDF: ${details.error}',
type: ToastType.error,
);
},
)
// 3. Mensagem de Erro
else
Center(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, color: Colors.red, size: 60),
const SizedBox(height: 16),
Text(
_errorMessage ?? 'Erro desconhecido ao carregar o PDF.',
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.white, fontSize: 16),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () => Navigator.of(context).pop(),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFE94560),
foregroundColor: Colors.white,
),
child: const Text('Voltar'),
),
],
),
),
),
// Botão de Fechar
Positioned(
top: 40,
left: 10,
child: Container(
decoration: BoxDecoration(
color: Colors.black54,
borderRadius: BorderRadius.circular(20),
),
child: IconButton(
icon: const Icon(Icons.close, color: Colors.white, size: 28),
onPressed: () => Navigator.of(context).pop(),
),
),
),
],
),
);
}
}