simulacion de estados y flujo de notificacion, modificacion de estilos en todas las vistas
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
@@ -11,6 +12,7 @@ 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
|
||||
@@ -75,11 +77,19 @@ class _EtaResult {
|
||||
// Provider de ETA
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
class _EtaNotifier extends AsyncNotifier<_EtaResult> {
|
||||
Timer? _timer;
|
||||
|
||||
@override
|
||||
Future<_EtaResult> build() => _fetch();
|
||||
Future<_EtaResult> build() {
|
||||
// Consulta silenciosa cada 10 segundos para ver el avance en tiempo real
|
||||
_timer?.cancel();
|
||||
_timer = Timer.periodic(const Duration(seconds: 10), (_) => refresh());
|
||||
ref.onDispose(() => _timer?.cancel());
|
||||
|
||||
return _fetch();
|
||||
}
|
||||
|
||||
Future<void> refresh() async {
|
||||
state = const AsyncValue.loading();
|
||||
state = await AsyncValue.guard(_fetch);
|
||||
}
|
||||
|
||||
@@ -127,6 +137,20 @@ final etaProvider = AsyncNotifierProvider<_EtaNotifier, _EtaResult>(
|
||||
class ActiveRouteIdNotifier extends Notifier<String?> {
|
||||
@override
|
||||
String? build() => null;
|
||||
|
||||
void set(String? value) {
|
||||
debugPrint('📡 [FCM] Evaluando suscripción a la ruta: $value');
|
||||
if (state != value) {
|
||||
final oldRoute = state;
|
||||
state = value;
|
||||
if (oldRoute != null) NotificationService.unsubscribeFromRoute(oldRoute);
|
||||
if (value != null) {
|
||||
NotificationService.subscribeToRoute(
|
||||
value,
|
||||
).catchError((e) => debugPrint('❌ Error FCM: $e'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final activeRouteIdProvider = NotifierProvider<ActiveRouteIdNotifier, String?>(
|
||||
@@ -149,7 +173,7 @@ class _CitizenHomeScreenState extends ConsumerState<CitizenHomeScreen>
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
// Refresca al recibir push FCM (RUTA_PROXIMITY, ROUTE_START, etc.)
|
||||
// Refresca al recibir push FCM (RUTA_PROXIMITY, ROUTE_START, etc.)F
|
||||
NotificationService.onFcmMessage.addListener(_onPush);
|
||||
}
|
||||
|
||||
@@ -242,11 +266,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),
|
||||
@@ -256,6 +284,71 @@ 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.delete_outline,
|
||||
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)
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
@@ -322,13 +415,13 @@ class _EtaHeroCard extends StatelessWidget {
|
||||
final cs = Theme.of(context).colorScheme;
|
||||
if (result.isCompleted) return cs.surfaceContainerHighest;
|
||||
if (result.isNearby) return const Color(0xFFFFF8E1); // amber-50
|
||||
return const Color(0xFFE1F5EE); // teal-50
|
||||
return const Color(0xFFE8D5DB); // rosa claro institucional
|
||||
}
|
||||
|
||||
Color _accentColor(BuildContext context) {
|
||||
if (result.isCompleted) return Theme.of(context).colorScheme.outline;
|
||||
if (result.isNearby) return const Color(0xFFBA7517); // amber-400
|
||||
return const Color(0xFF1D9E75); // teal-400
|
||||
if (result.isNearby) return const Color(0xFFC8A36A); // beige dorado
|
||||
return const Color(0xFF9B1B4A); // vino principal
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -606,7 +699,7 @@ class _FcmStatusBadge extends ConsumerWidget {
|
||||
width: 8,
|
||||
height: 8,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFF1D9E75),
|
||||
color: Color(0xFF1E7A46),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user