import 'dart:async'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:geolocator/geolocator.dart'; import 'package:rogapp/features/data/user_location.dart'; import 'package:rogapp/features/state/game_view_model.dart'; /// The state for the location feature class LocationState { final Position? currentPosition; final bool isStreamPaused; LocationState({ this.currentPosition, this.isStreamPaused = false, }); LocationState copyWith({ Position? currentPosition, bool? isStreamPaused, }) { return LocationState( currentPosition: currentPosition ?? this.currentPosition, isStreamPaused: isStreamPaused ?? this.isStreamPaused, ); } } /// A StateNotifier that manages the location state class LocationNotifier extends StateNotifier { final Ref ref; LocationNotifier(this.ref) : super(LocationState()) { startListening(); startPeriodicUpdates(); } StreamSubscription? _positionSubscription; Position? _lastPosition; final double _distanceThreshold = 220.0; Timer? _periodicUpdateTimer; void startPeriodicUpdates() { _periodicUpdateTimer?.cancel(); _periodicUpdateTimer = Timer.periodic(Duration(seconds: 5), (timer) { if (state.currentPosition != null) { // Convert Position to UserLocation UserLocation userLocation = UserLocation.fromPosition(state.currentPosition!); ref.read(gameViewModelProvider.notifier).updateLocation(userLocation); } }); } void startListening() { _positionSubscription = Geolocator.getPositionStream().listen((Position position) { if (_shouldUpdatePosition(position)) { state = state.copyWith(currentPosition: position); _lastPosition = position; } }); } bool _shouldUpdatePosition(Position newPosition) { if (_lastPosition == null) return true; double distance = Geolocator.distanceBetween( _lastPosition!.latitude, _lastPosition!.longitude, newPosition.latitude, newPosition.longitude, ); return distance < _distanceThreshold; } void stopListening() { _positionSubscription?.cancel(); _positionSubscription = null; state = state.copyWith( currentPosition: null); // Reset the position state or handle as needed } void pauseListening() { _positionSubscription?.pause(); } void resumeListening() { _positionSubscription?.resume(); } void updateCurrentPosition(Position? position) { state = state.copyWith(currentPosition: position); } void updateStreamPaused(bool isPaused) { state = state.copyWith(isStreamPaused: isPaused); } @override void dispose() { _positionSubscription?.cancel(); super.dispose(); } } final locationNotifierProvider = StateNotifierProvider((ref) { return LocationNotifier(ref); // Pass ref directly });