Files
lunchpick/lib/presentation/providers/location_provider.dart
2025-11-19 16:36:39 +09:00

137 lines
3.8 KiB
Dart

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:geolocator/geolocator.dart';
import 'package:permission_handler/permission_handler.dart';
/// 위치 권한 상태 Provider
final locationPermissionProvider = FutureProvider<PermissionStatus>((
ref,
) async {
return await Permission.location.status;
});
/// 현재 위치 Provider
final currentLocationProvider = FutureProvider<Position?>((ref) async {
// 위치 권한 확인
final permissionStatus = await Permission.location.status;
if (!permissionStatus.isGranted) {
// 권한이 없으면 요청
final result = await Permission.location.request();
if (!result.isGranted) {
return null;
}
}
// 위치 서비스 활성화 확인
final serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
throw Exception('위치 서비스가 비활성화되어 있습니다');
}
// 현재 위치 가져오기
try {
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
timeLimit: const Duration(seconds: 10),
);
} catch (e) {
// 타임아웃이나 오류 발생 시 마지막 알려진 위치 반환
return await Geolocator.getLastKnownPosition();
}
});
/// 위치 스트림 Provider
final locationStreamProvider = StreamProvider<Position>((ref) {
return Geolocator.getPositionStream(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 10, // 10미터 이상 이동 시 업데이트
),
);
});
/// 위치 관리 StateNotifier
class LocationNotifier extends StateNotifier<AsyncValue<Position?>> {
LocationNotifier() : super(const AsyncValue.loading());
/// 위치 권한 요청
Future<bool> requestLocationPermission() async {
try {
final status = await Permission.location.request();
return status.isGranted;
} catch (e) {
return false;
}
}
/// 위치 서비스 활성화 요청
Future<bool> requestLocationService() async {
try {
return await Geolocator.openLocationSettings();
} catch (e) {
return false;
}
}
/// 현재 위치 가져오기
Future<void> getCurrentLocation() async {
state = const AsyncValue.loading();
try {
// 권한 확인
final permissionStatus = await Permission.location.status;
if (!permissionStatus.isGranted) {
final granted = await requestLocationPermission();
if (!granted) {
state = const AsyncValue.data(null);
return;
}
}
// 위치 서비스 확인
final serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
state = AsyncValue.error('위치 서비스가 비활성화되어 있습니다', StackTrace.current);
return;
}
// 위치 가져오기
final position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
timeLimit: const Duration(seconds: 10),
);
state = AsyncValue.data(position);
} catch (e, stack) {
// 오류 발생 시 마지막 알려진 위치 시도
try {
final lastPosition = await Geolocator.getLastKnownPosition();
state = AsyncValue.data(lastPosition);
} catch (_) {
state = AsyncValue.error(e, stack);
}
}
}
/// 두 지점 간의 거리 계산 (미터 단위)
double calculateDistance(
double startLatitude,
double startLongitude,
double endLatitude,
double endLongitude,
) {
return Geolocator.distanceBetween(
startLatitude,
startLongitude,
endLatitude,
endLongitude,
);
}
}
/// LocationNotifier Provider
final locationNotifierProvider =
StateNotifierProvider<LocationNotifier, AsyncValue<Position?>>((ref) {
return LocationNotifier();
});