Avance de la aplicacion
This commit is contained in:
183
lib/screens/citizen/review_screen.dart
Normal file
183
lib/screens/citizen/review_screen.dart
Normal file
@@ -0,0 +1,183 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../../core/app_colors.dart';
|
||||
import '../../database/db_helper.dart';
|
||||
import '../../models/models.dart';
|
||||
import '../../services/auth_service.dart';
|
||||
import '../../services/route_simulator_service.dart';
|
||||
|
||||
class ReviewScreen extends StatefulWidget {
|
||||
final String routeId;
|
||||
final String colonia;
|
||||
const ReviewScreen({super.key, required this.routeId, required this.colonia});
|
||||
@override State<ReviewScreen> createState() => _ReviewScreenState();
|
||||
}
|
||||
|
||||
class _ReviewScreenState extends State<ReviewScreen> {
|
||||
int _estrellas = 5;
|
||||
final _comentCtrl = TextEditingController();
|
||||
bool _loading = false;
|
||||
bool _sent = false;
|
||||
|
||||
static const _labels = ['', 'Muy malo', 'Malo', 'Regular', 'Bueno', 'Excelente'];
|
||||
static const _colors = [
|
||||
Colors.transparent, AppColors.rojoError, AppColors.naranjaAlerta,
|
||||
Colors.amber, AppColors.verdeExito, AppColors.verdeExito,
|
||||
];
|
||||
|
||||
Future<void> _enviar() async {
|
||||
final auth = context.read<AuthService>();
|
||||
if (auth.currentUser == null) return;
|
||||
|
||||
// Verificar si ya calificó hoy
|
||||
final yaCalificado = await DbHelper.hasReviewedRoute(
|
||||
auth.currentUser!.id!, widget.routeId);
|
||||
if (yaCalificado && mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||
content: Text('Ya calificaste este servicio hoy'),
|
||||
backgroundColor: AppColors.azulInfo));
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() => _loading = true);
|
||||
await DbHelper.insertReview(ReviewModel(
|
||||
userId: auth.currentUser!.id!,
|
||||
colonia: widget.colonia,
|
||||
routeId: widget.routeId,
|
||||
estrellas: _estrellas,
|
||||
comentario: _comentCtrl.text.trim().isEmpty
|
||||
? 'Sin comentario' : _comentCtrl.text.trim(),
|
||||
fecha: DateTime.now().toIso8601String(),
|
||||
nombreUsuario: auth.currentUser!.nombre,
|
||||
));
|
||||
|
||||
context.read<RouteSimulatorService>().clearReviewPrompt(widget.routeId);
|
||||
if (!mounted) return;
|
||||
setState(() { _loading = false; _sent = true; });
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.grisFondo,
|
||||
appBar: AppBar(
|
||||
backgroundColor: AppColors.guindaPrimary, foregroundColor: Colors.white,
|
||||
title: const Text('Calificar el Servicio'),
|
||||
bottom: PreferredSize(preferredSize: const Size.fromHeight(4),
|
||||
child: Container(height: 4, color: AppColors.dorado)),
|
||||
),
|
||||
body: _sent
|
||||
? Center(child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
const Text('⭐', style: TextStyle(fontSize: 64)),
|
||||
const SizedBox(height: 16),
|
||||
const Text('¡Gracias por tu calificación!',
|
||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold,
|
||||
color: AppColors.guindaPrimary)),
|
||||
const SizedBox(height: 8),
|
||||
const Text('Tu opinión ayuda a mejorar el servicio\nde recolección en Celaya.',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: AppColors.grisTexto)),
|
||||
const SizedBox(height: 24),
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColors.guindaPrimary, foregroundColor: Colors.white),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('Volver al inicio')),
|
||||
]))
|
||||
: SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(children: [
|
||||
// Header
|
||||
Container(
|
||||
width: double.infinity, padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.guindaPrimary.withOpacity(0.08),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: AppColors.guindaPrimary.withOpacity(0.2))),
|
||||
child: Column(children: [
|
||||
const Icon(Icons.local_shipping, color: AppColors.guindaPrimary, size: 36),
|
||||
const SizedBox(height: 8),
|
||||
Text(widget.routeId, style: const TextStyle(
|
||||
fontWeight: FontWeight.bold, color: AppColors.guindaPrimary)),
|
||||
Text(widget.colonia, style: const TextStyle(
|
||||
color: AppColors.grisTexto, fontSize: 12)),
|
||||
]),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Estrellas
|
||||
const Text('¿Cómo calificarías el servicio de hoy?',
|
||||
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
|
||||
const SizedBox(height: 16),
|
||||
Row(mainAxisAlignment: MainAxisAlignment.center, children: List.generate(5, (i) {
|
||||
final star = i + 1;
|
||||
return GestureDetector(
|
||||
onTap: () => setState(() => _estrellas = star),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6),
|
||||
child: Icon(
|
||||
_estrellas >= star ? Icons.star : Icons.star_border,
|
||||
color: _estrellas >= star ? Colors.amber : Colors.grey,
|
||||
size: 44,
|
||||
),
|
||||
),
|
||||
);
|
||||
})),
|
||||
const SizedBox(height: 8),
|
||||
Text(_labels[_estrellas],
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold,
|
||||
color: _colors[_estrellas])),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Comentario
|
||||
const Align(alignment: Alignment.centerLeft,
|
||||
child: Text('Comentario (opcional)',
|
||||
style: TextStyle(fontWeight: FontWeight.w600))),
|
||||
const SizedBox(height: 8),
|
||||
TextField(
|
||||
controller: _comentCtrl,
|
||||
maxLines: 4,
|
||||
maxLength: 200,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Cuéntanos cómo estuvo el servicio...',
|
||||
border: OutlineInputBorder(),
|
||||
filled: true, fillColor: Colors.white),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Aviso
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(color: Colors.blue.shade50,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: Colors.blue.shade200)),
|
||||
child: const Row(children: [
|
||||
Icon(Icons.info_outline, color: AppColors.azulInfo, size: 16),
|
||||
SizedBox(width: 6),
|
||||
Expanded(child: Text(
|
||||
'Tu calificación es anónima para otros ciudadanos, '
|
||||
'pero el Ayuntamiento la usará para mejorar el servicio.',
|
||||
style: TextStyle(fontSize: 11, color: AppColors.azulInfo))),
|
||||
]),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
SizedBox(width: double.infinity, height: 50,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: _loading ? null : _enviar,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppColors.guindaPrimary, foregroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))),
|
||||
icon: _loading
|
||||
? const SizedBox(width: 18, height: 18,
|
||||
child: CircularProgressIndicator(color: Colors.white, strokeWidth: 2))
|
||||
: const Icon(Icons.star),
|
||||
label: const Text('ENVIAR CALIFICACIÓN',
|
||||
style: TextStyle(fontWeight: FontWeight.bold)))),
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override void dispose() { _comentCtrl.dispose(); super.dispose(); }
|
||||
}
|
||||
Reference in New Issue
Block a user