feat(app): seed restaurants, geocode addresses, refresh sharing

This commit is contained in:
JiWoong Sul
2025-11-26 19:01:00 +09:00
parent 2a01fa50c6
commit 0e8c06bade
29 changed files with 18319 additions and 427 deletions

View File

@@ -5,6 +5,7 @@ import 'package:uuid/uuid.dart';
import '../../domain/entities/restaurant.dart';
import '../providers/di_providers.dart';
import '../providers/restaurant_provider.dart';
import '../providers/location_provider.dart';
/// 식당 추가 화면의 상태 모델
class AddRestaurantState {
@@ -248,6 +249,15 @@ class AddRestaurantViewModel extends StateNotifier<AddRestaurantState> {
// 네이버에서 가져온 데이터가 있으면 업데이트
final fetchedData = state.fetchedRestaurantData;
if (fetchedData != null) {
final coords = await _resolveCoordinates(
latitudeText: state.formData.latitude,
longitudeText: state.formData.longitude,
roadAddress: state.formData.roadAddress,
jibunAddress: state.formData.jibunAddress,
fallbackLatitude: fetchedData.latitude,
fallbackLongitude: fetchedData.longitude,
);
restaurantToSave = fetchedData.copyWith(
name: state.formData.name,
category: state.formData.category,
@@ -264,19 +274,28 @@ class AddRestaurantViewModel extends StateNotifier<AddRestaurantState> {
jibunAddress: state.formData.jibunAddress.isEmpty
? state.formData.roadAddress
: state.formData.jibunAddress,
latitude:
double.tryParse(state.formData.latitude) ?? fetchedData.latitude,
longitude:
double.tryParse(state.formData.longitude) ??
fetchedData.longitude,
latitude: coords.latitude,
longitude: coords.longitude,
naverUrl: state.formData.naverUrl.isEmpty
? null
: state.formData.naverUrl,
updatedAt: DateTime.now(),
needsAddressVerification: coords.usedCurrentLocation,
);
} else {
// 직접 입력한 경우
restaurantToSave = state.formData.toRestaurant();
final coords = await _resolveCoordinates(
latitudeText: state.formData.latitude,
longitudeText: state.formData.longitude,
roadAddress: state.formData.roadAddress,
jibunAddress: state.formData.jibunAddress,
);
restaurantToSave = state.formData.toRestaurant().copyWith(
latitude: coords.latitude,
longitude: coords.longitude,
needsAddressVerification: coords.usedCurrentLocation,
);
}
await notifier.addRestaurantDirect(restaurantToSave);
@@ -297,6 +316,68 @@ class AddRestaurantViewModel extends StateNotifier<AddRestaurantState> {
void clearError() {
state = state.copyWith(clearError: true);
}
Future<({double latitude, double longitude, bool usedCurrentLocation})>
_resolveCoordinates({
required String latitudeText,
required String longitudeText,
required String roadAddress,
required String jibunAddress,
double? fallbackLatitude,
double? fallbackLongitude,
}) async {
final parsedLat = double.tryParse(latitudeText);
final parsedLon = double.tryParse(longitudeText);
if (parsedLat != null && parsedLon != null) {
return (
latitude: parsedLat,
longitude: parsedLon,
usedCurrentLocation: false,
);
}
final geocodingService = _ref.read(geocodingServiceProvider);
final address = roadAddress.isNotEmpty ? roadAddress : jibunAddress;
if (address.isNotEmpty) {
final result = await geocodingService.geocode(address);
if (result != null) {
return (
latitude: result.latitude,
longitude: result.longitude,
usedCurrentLocation: false,
);
}
}
// 주소로 좌표를 얻지 못하면 현재 위치를 활용한다.
try {
final position = await _ref.read(currentLocationProvider.future);
if (position != null) {
return (
latitude: position.latitude,
longitude: position.longitude,
usedCurrentLocation: true,
);
}
} catch (_) {
// 위치 권한 거부/오류 시 fallback 사용
}
if (fallbackLatitude != null && fallbackLongitude != null) {
return (
latitude: fallbackLatitude,
longitude: fallbackLongitude,
usedCurrentLocation: false,
);
}
final defaultCoords = geocodingService.defaultCoordinates();
return (
latitude: defaultCoords.latitude,
longitude: defaultCoords.longitude,
usedCurrentLocation: true,
);
}
}
/// AddRestaurantViewModel Provider