mascota en login,

This commit is contained in:
shinra32
2026-05-23 04:30:48 -06:00
parent 68d04f3917
commit 89dcc6250b
14 changed files with 239 additions and 798 deletions

View File

@@ -12,13 +12,17 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import '../../core/theme/app_theme.dart';
import '../home/colonias_data.dart';
import '../../core/widgets/app_widgets.dart';
import '../../core/network/api_client.dart';
import '../notifications/notification_service.dart';
import '../../shared/widgets/prevention_banner.dart';
import '../../shared/widgets/progress_steps.dart';
import '../separation_guide/ai_pet_chat_screen.dart';
// ─────────────────────────────────────────────────────────────────────────────
// Modelo de resultado ETA
@@ -29,6 +33,8 @@ class _EtaResult {
final String direccion;
final String colonia;
final bool hasAddress;
final double? lat;
final double? lng;
const _EtaResult({
required this.mensaje,
@@ -36,6 +42,8 @@ class _EtaResult {
required this.direccion,
required this.colonia,
required this.hasAddress,
this.lat,
this.lng,
});
const _EtaResult.noAddress()
@@ -43,7 +51,9 @@ class _EtaResult {
status = '',
direccion = '',
colonia = '',
hasAddress = false;
hasAddress = false,
lat = null,
lng = null;
// ── Utilidades derivadas ───────────────────────────────────────────────────
@@ -114,12 +124,14 @@ class _EtaNotifier extends AsyncNotifier<_EtaResult> {
status: data['status'] as String? ?? '',
direccion: items.first['calle'] as String? ?? '',
colonia: items.first['colonia'] as String? ?? '',
lat: (items.first['lat'] as num?)?.toDouble(),
lng: (items.first['lng'] as num?)?.toDouble(),
hasAddress: true,
);
}
}
final etaProvider = AsyncNotifierProvider.autoDispose<_EtaNotifier, _EtaResult>(
final etaProvider = AsyncNotifierProvider<_EtaNotifier, _EtaResult>(
_EtaNotifier.new,
);
@@ -227,7 +239,13 @@ class _EtaContent extends StatelessWidget {
trailing: AppStatusBadge.green('Activo'),
),
const SizedBox(height: 12),
// ── 2.5. Mapa de ubicación ─────────────────────────────────
_MapaUbicacion(
colonia: result.colonia,
lat: result.lat,
lng: result.lng,
),
const SizedBox(height: 12),
// ── 3. Pasos de progreso (justo debajo del domicilio) ───────────
ProgressSteps(stepIndex: result.stepIndex),
const SizedBox(height: 12),
@@ -236,11 +254,15 @@ class _EtaContent extends StatelessWidget {
const PreventionBanner(),
const SizedBox(height: 12),
// ── 5. Badge de suscripción FCM ─────────────────────────────────
// ── 5. Banner del Chat IA (Eco) ─────────────────────────────────
const _EcoChatBanner(),
const SizedBox(height: 12),
// ── 6. Badge de suscripción FCM ─────────────────────────────────
const _FcmStatusBadge(),
const SizedBox(height: 16),
// ── 6. Horario semanal ──────────────────────────────────────────
// ── 7. Horario semanal ──────────────────────────────────────────
AppSectionTitle(title: 'Horario del camión'),
_HorarioCard(),
const SizedBox(height: 24),
@@ -250,6 +272,122 @@ class _EtaContent extends StatelessWidget {
}
}
// ─────────────────────────────────────────────────────────────────────────────
// Banner de Eco (Chat IA)
// ─────────────────────────────────────────────────────────────────────────────
class _EcoChatBanner extends StatelessWidget {
const _EcoChatBanner();
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (_) => const AiPetChatScreen()),
);
},
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppTheme.primaryDark,
borderRadius: BorderRadius.circular(AppTheme.radiusLg),
boxShadow: AppTheme.softShadow,
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: const BoxDecoration(
color: Colors.white24,
shape: BoxShape.circle,
),
child: const Icon(Icons.pets, color: Colors.white, size: 28),
),
const SizedBox(width: 16),
const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'¿Dudas sobre reciclaje?',
style: TextStyle(
color: Colors.white,
fontSize: 15,
fontWeight: FontWeight.w700,
),
),
SizedBox(height: 4),
Text(
'Pregúntale a Eco, tu asistente inteligente',
style: TextStyle(color: Colors.white70, fontSize: 13),
),
],
),
),
const Icon(Icons.chevron_right, color: Colors.white),
],
),
),
);
}
}
// ─────────────────────────────────────────────────────────────────────────────
// Mapa de ubicación del domicilio (no interactivo)
// ─────────────────────────────────────────────────────────────────────────────
class _MapaUbicacion extends StatelessWidget {
final String colonia;
final double? lat;
final double? lng;
const _MapaUbicacion({required this.colonia, this.lat, this.lng});
@override
Widget build(BuildContext context) {
// Usar coordenadas del usuario si están disponibles, sino usar centro de colonia
final center = kColoniaCenter(colonia);
final pin = (lat != null && lng != null) ? LatLng(lat!, lng!) : center;
return Container(
height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(AppTheme.radiusLg),
border: Border.all(color: AppTheme.border, width: 1),
),
clipBehavior: Clip.hardEdge,
child: FlutterMap(
options: MapOptions(
initialCenter: pin,
initialZoom: 16.0,
interactionOptions: const InteractionOptions(
flags: InteractiveFlag.none,
),
),
children: [
TileLayer(
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
userAgentPackageName: 'com.onlineshack.recolecta',
),
MarkerLayer(
markers: [
Marker(
point: pin,
width: 36,
height: 36,
child: const Icon(
Icons.home_rounded,
color: AppTheme.primary,
size: 36,
),
),
],
),
],
),
);
}
}
// ─────────────────────────────────────────────────────────────────────────────
// Hero card: estado + ventana horaria + barra de progreso
// ─────────────────────────────────────────────────────────────────────────────