MotorSignal-App/lib/services/social/social_feed_providers.dart

134 lines
4.1 KiB
Dart

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<SocialFeedService>((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<FeedFilter>((ref) {
return FeedFilter.allActivity;
});
/// State provider for the active riding discipline filter chip.
final feedDisciplineFilterProvider = StateProvider<RidingDiscipline>((ref) {
return RidingDiscipline.all;
});
/// State provider for searching route titles, canyons, bikes, or handles.
final feedSearchQueryProvider = StateProvider<String>((ref) {
return '';
});
/// State provider for minimum ride distance threshold.
final feedMinDistanceFilterProvider = StateProvider<double?>((ref) {
return null;
});
/// State provider for GPS verified only filter toggle.
final feedVerifiedGpsOnlyProvider = StateProvider<bool>((ref) {
return false;
});
/// StateNotifier providing instant synchronous initial feed items and reacting to changes.
class SocialFeedNotifier extends StateNotifier<List<SocialFeedItem>> {
final SocialFeedService _service;
final FeedFilter _filter;
final RidingDiscipline _discipline;
final String? _searchQuery;
final double? _minDistanceMiles;
final bool? _verifiedGpsOnly;
StreamSubscription<List<SocialFeedItem>>? _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<SocialFeedNotifier, List<SocialFeedItem>>(
(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<List<SocialFeedItem>>((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,
);
});