feat(app): add vworld geocoding and native ads placeholders

This commit is contained in:
JiWoong Sul
2025-12-03 14:30:20 +09:00
parent d101f7d0dc
commit 3ff9e5f837
23 changed files with 1108 additions and 540 deletions

View File

@@ -23,8 +23,9 @@ class NaverMapParser {
// 정규식 패턴
static final RegExp _placeIdRegex = RegExp(
r'/p/(?:restaurant|entry/place)/(\d+)',
r'(?:/p/(?:restaurant|entry/place)/|/place/)(\d+)',
);
static final RegExp _pinIdRegex = RegExp(r'pinId["=](\d+)');
static final RegExp _shortUrlRegex = RegExp(r'naver\.me/([a-zA-Z0-9]+)$');
// 기본 좌표 (서울 시청)
@@ -62,7 +63,7 @@ class NaverMapParser {
throw NaverMapParseException('이미 dispose된 파서입니다');
}
try {
AppLogger.debug('NaverMapParser: Starting to parse URL: $url');
AppLogger.debug('[naver_url] 원본 URL 수신: $url');
// URL 유효성 검증
if (!_isValidNaverUrl(url)) {
@@ -72,7 +73,7 @@ class NaverMapParser {
// 짧은 URL인 경우 리다이렉트 처리
final String finalUrl = await _apiClient.resolveShortUrl(url);
AppLogger.debug('NaverMapParser: Final URL after redirect: $finalUrl');
AppLogger.debug('[naver_url] resolveShortUrl 결과: $finalUrl');
// Place ID 추출 (10자리 숫자)
final String? placeId = _extractPlaceId(finalUrl);
@@ -80,13 +81,12 @@ class NaverMapParser {
// 짧은 URL에서 직접 ID 추출 시도
final shortUrlId = _extractShortUrlId(url);
if (shortUrlId != null) {
AppLogger.debug(
'NaverMapParser: Using short URL ID as place ID: $shortUrlId',
);
AppLogger.debug('[naver_url] 단축 URL ID를 Place ID로 사용: $shortUrlId');
return _createFallbackRestaurant(shortUrlId, url);
}
throw NaverMapParseException('URL에서 Place ID를 추출할 수 없습니다: $url');
}
AppLogger.debug('[naver_url] Place ID 추출 성공: $placeId');
// 단축 URL인 경우 특별 처리
final isShortUrl = url.contains('naver.me');
@@ -102,7 +102,10 @@ class NaverMapParser {
userLatitude,
userLongitude,
);
AppLogger.debug('NaverMapParser: 단축 URL 파싱 성공 - ${restaurant.name}');
AppLogger.debug(
'[naver_url] LocalSearch 파싱 성공: '
'name=${restaurant.name}, road=${restaurant.roadAddress}',
);
return restaurant;
} catch (e, stackTrace) {
AppLogger.error(
@@ -120,6 +123,12 @@ class NaverMapParser {
userLatitude: userLatitude,
userLongitude: userLongitude,
);
AppLogger.debug(
'[naver_url] GraphQL/검색 파싱 결과 요약: '
'name=${restaurantData['name']}, '
'road=${restaurantData['roadAddress']}, '
'phone=${restaurantData['phone']}',
);
return _createRestaurant(restaurantData, placeId, finalUrl);
} catch (e) {
if (e is NaverMapParseException) {
@@ -150,7 +159,11 @@ class NaverMapParser {
/// URL에서 Place ID 추출
String? _extractPlaceId(String url) {
final match = _placeIdRegex.firstMatch(url);
return match?.group(1);
if (match != null) return match.group(1);
// 핀 공유 형식: pinId="1234567890" 또는 pinId=1234567890
final pinMatch = _pinIdRegex.firstMatch(url);
return pinMatch?.group(1);
}
/// 짧은 URL에서 ID 추출
@@ -188,6 +201,10 @@ class NaverMapParser {
longitude: userLongitude,
display: _searchDisplayCount,
);
AppLogger.debug(
'[naver_url] URL 기반 검색 응답 개수: ${searchResults.length}, '
'첫 번째: ${searchResults.isNotEmpty ? searchResults.first.title : '없음'}',
);
if (searchResults.isNotEmpty) {
// place ID가 포함된 결과 찾기
@@ -226,6 +243,10 @@ class NaverMapParser {
longitude: userLongitude,
display: _searchDisplayCount,
);
AppLogger.debug(
'[naver_url] Place ID 검색 응답 개수: ${searchResults.length}, '
'첫 번째: ${searchResults.isNotEmpty ? searchResults.first.title : '없음'}',
);
if (searchResults.isNotEmpty) {
AppLogger.debug(
@@ -273,6 +294,9 @@ class NaverMapParser {
variables: {'id': placeId},
query: NaverGraphQLQueries.placeDetailQuery,
);
AppLogger.debug(
'[naver_url] places query 응답 keys: ${response.keys.toList()}',
);
// places 응답 처리 (배열일 수도 있음)
final placesData = response['data']?['places'];
@@ -299,6 +323,9 @@ class NaverMapParser {
variables: {'id': placeId},
query: NaverGraphQLQueries.nxPlaceDetailQuery,
);
AppLogger.debug(
'[naver_url] nxPlaces query 응답 keys: ${response.keys.toList()}',
);
// nxPlaces 응답 처리 (배열일 수도 있음)
final nxPlacesData = response['data']?['nxPlaces'];