import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:geolocator/geolocator.dart'; import 'package:lunchpick/core/utils/app_logger.dart'; import 'package:permission_handler/permission_handler.dart'; const double _defaultLatitude = 37.5666805; const double _defaultLongitude = 126.9784147; /// 위치 정보를 사용할 수 없을 때 활용하는 기본 좌표(서울 시청). Position defaultPosition() { return Position( latitude: _defaultLatitude, longitude: _defaultLongitude, timestamp: DateTime.now(), accuracy: 0, altitude: 0, altitudeAccuracy: 0, heading: 0, headingAccuracy: 0, speed: 0, speedAccuracy: 0, isMocked: false, ); } /// 위치 권한 상태 Provider final locationPermissionProvider = FutureProvider(( ref, ) async { return await Permission.location.status; }); /// 현재 위치 Provider final currentLocationProvider = FutureProvider((ref) async { // 위치 권한 확인 final permissionStatus = await Permission.location.status; if (!permissionStatus.isGranted) { // 권한이 없으면 요청 final result = await Permission.location.request(); if (!result.isGranted) { AppLogger.debug('위치 권한 거부됨, 기본 좌표(서울 시청) 사용'); return defaultPosition(); } } // 위치 서비스 활성화 확인 final serviceEnabled = await Geolocator.isLocationServiceEnabled(); if (!serviceEnabled) { AppLogger.debug('위치 서비스 비활성화, 기본 좌표(서울 시청) 사용'); return defaultPosition(); } // 현재 위치 가져오기 try { return await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.high, timeLimit: const Duration(seconds: 10), ); } catch (e) { // 타임아웃이나 오류 발생 시 마지막 알려진 위치 반환 final lastPosition = await Geolocator.getLastKnownPosition(); if (lastPosition != null) { return lastPosition; } AppLogger.debug('현재 위치를 가져오지 못해 기본 좌표(서울 시청)를 반환'); return defaultPosition(); } }); /// 위치 스트림 Provider final locationStreamProvider = StreamProvider((ref) { return Geolocator.getPositionStream( locationSettings: const LocationSettings( accuracy: LocationAccuracy.high, distanceFilter: 10, // 10미터 이상 이동 시 업데이트 ), ); }); /// 위치 관리 StateNotifier class LocationNotifier extends StateNotifier> { LocationNotifier() : super(const AsyncValue.loading()); /// 위치 권한 요청 Future requestLocationPermission() async { try { final status = await Permission.location.request(); return status.isGranted; } catch (e) { return false; } } /// 위치 서비스 활성화 요청 Future requestLocationService() async { try { return await Geolocator.openLocationSettings(); } catch (e) { return false; } } /// 현재 위치 가져오기 Future getCurrentLocation() async { state = const AsyncValue.loading(); try { // 권한 확인 final permissionStatus = await Permission.location.status; if (!permissionStatus.isGranted) { final granted = await requestLocationPermission(); if (!granted) { AppLogger.debug('위치 권한 거부됨, 기본 좌표(서울 시청)로 대체'); state = AsyncValue.data(defaultPosition()); return; } } // 위치 서비스 확인 final serviceEnabled = await Geolocator.isLocationServiceEnabled(); if (!serviceEnabled) { AppLogger.debug('위치 서비스 비활성화, 기본 좌표(서울 시청)로 대체'); state = AsyncValue.data(defaultPosition()); return; } // 위치 가져오기 final position = await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.high, timeLimit: const Duration(seconds: 10), ); state = AsyncValue.data(position); } catch (e) { // 오류 발생 시 마지막 알려진 위치 시도 try { final lastPosition = await Geolocator.getLastKnownPosition(); if (lastPosition != null) { state = AsyncValue.data(lastPosition); } else { AppLogger.debug('마지막 위치도 없어 기본 좌표(서울 시청)로 대체'); state = AsyncValue.data(defaultPosition()); } } catch (_) { state = AsyncValue.data(defaultPosition()); } } } /// 두 지점 간의 거리 계산 (미터 단위) double calculateDistance( double startLatitude, double startLongitude, double endLatitude, double endLongitude, ) { return Geolocator.distanceBetween( startLatitude, startLongitude, endLatitude, endLongitude, ); } } /// LocationNotifier Provider final locationNotifierProvider = StateNotifierProvider>((ref) { return LocationNotifier(); });