134 lines
4.1 KiB
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,
|
|
);
|
|
});
|
|
|