import 'dart:async'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'social_feed_models.dart'; import 'social_feed_service.dart'; /// Provider for SocialFeedService singleton. final socialFeedServiceProvider = Provider((ref) { FirebaseFirestore? firestore; try { if (Firebase.apps.isNotEmpty) { firestore = FirebaseFirestore.instance; } } catch (_) { firestore = null; } final service = SocialFeedService(firestore: firestore); ref.onDispose(() { service.dispose(); }); return service; }); /// State provider for the active feed stream filter tab. final feedFilterStateProvider = StateProvider((ref) { return FeedFilter.allActivity; }); /// State provider for the active riding discipline filter chip. final feedDisciplineFilterProvider = StateProvider((ref) { return RidingDiscipline.all; }); /// State provider for searching route titles, canyons, bikes, or handles. final feedSearchQueryProvider = StateProvider((ref) { return ''; }); /// State provider for minimum ride distance threshold. final feedMinDistanceFilterProvider = StateProvider((ref) { return null; }); /// State provider for GPS verified only filter toggle. final feedVerifiedGpsOnlyProvider = StateProvider((ref) { return false; }); /// StateNotifier providing instant synchronous initial feed items and reacting to changes. class SocialFeedNotifier extends StateNotifier> { final SocialFeedService _service; final FeedFilter _filter; final RidingDiscipline _discipline; final String? _searchQuery; final double? _minDistanceMiles; final bool? _verifiedGpsOnly; StreamSubscription>? _sub; SocialFeedNotifier( this._service, this._filter, { RidingDiscipline discipline = RidingDiscipline.all, String? searchQuery, double? minDistanceMiles, bool? verifiedGpsOnly, }) : _discipline = discipline, _searchQuery = searchQuery, _minDistanceMiles = minDistanceMiles, _verifiedGpsOnly = verifiedGpsOnly, super(_service.getFilteredItems( filter: _filter, discipline: discipline, searchQuery: searchQuery, minDistanceMiles: minDistanceMiles, verifiedGpsOnly: verifiedGpsOnly, )) { _sub = _service .getFeedStream( filter: _filter, discipline: _discipline, searchQuery: _searchQuery, minDistanceMiles: _minDistanceMiles, verifiedGpsOnly: _verifiedGpsOnly, ) .listen((items) { state = items; }); } @override void dispose() { _sub?.cancel(); super.dispose(); } } /// Primary feed provider with zero-latency synchronous initial data. final socialFeedNotifierProvider = StateNotifierProvider.autoDispose>( (ref) { final service = ref.watch(socialFeedServiceProvider); final filter = ref.watch(feedFilterStateProvider); final discipline = ref.watch(feedDisciplineFilterProvider); final searchQuery = ref.watch(feedSearchQueryProvider); final minDistance = ref.watch(feedMinDistanceFilterProvider); final verifiedGpsOnly = ref.watch(feedVerifiedGpsOnlyProvider); return SocialFeedNotifier( service, filter, discipline: discipline, searchQuery: searchQuery, minDistanceMiles: minDistance, verifiedGpsOnly: verifiedGpsOnly, ); }); /// Stream provider for the filtered community social feed (preserved for backwards compatibility). final socialFeedStreamProvider = StreamProvider.autoDispose>((ref) { final service = ref.watch(socialFeedServiceProvider); final filter = ref.watch(feedFilterStateProvider); final discipline = ref.watch(feedDisciplineFilterProvider); final searchQuery = ref.watch(feedSearchQueryProvider); return service.getFeedStream( filter: filter, discipline: discipline, searchQuery: searchQuery, ); });