LunchPick(오늘 뭐 먹Z?) Flutter 앱의 초기 구현입니다. 주요 기능: - 네이버 지도 연동 맛집 추가 - 랜덤 메뉴 추천 시스템 - 날씨 기반 거리 조정 - 방문 기록 관리 - Bluetooth 맛집 공유 - 다크모드 지원 기술 스택: - Flutter 3.8.1+ - Riverpod 상태 관리 - Hive 로컬 DB - Clean Architecture 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
4.6 KiB
4.6 KiB
AddRestaurantDialog JSON 스타일 UI 디자인
개요
네이버 URL에서 가져온 맛집 정보를 JSON 형식으로 보여주는 UI 디자인 명세서입니다.
디자인 컨셉
- JSON 시각화: 개발자 친화적인 JSON 형식으로 데이터를 표현
- 편집 가능: 각 필드를 직접 수정할 수 있는 인터랙티브 UI
- Material Design 3: 최신 디자인 가이드라인 준수
- 다크모드 지원: 라이트/다크 테마 완벽 지원
컴포넌트 구조
1. 메인 컨테이너
Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: isDark ? AppColors.darkBackground : AppColors.lightBackground.withOpacity(0.5),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: isDark ? AppColors.darkDivider : AppColors.lightDivider,
),
),
)
- 반투명 배경으로 깊이감 표현
- 둥근 모서리와 테두리로 구분
2. 헤더 영역
Row(
children: [
Icon(Icons.code, size: 20),
SizedBox(width: 8),
Text('가져온 정보', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600)),
],
)
- 코드 아이콘으로 JSON 데이터임을 시각적으로 표현
- 적절한 간격과 타이포그래피
3. JSON 필드 컴포넌트
각 필드는 _buildJsonField 메서드로 일관성 있게 구현:
기본 필드 구조
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 레이블
Row(
children: [
Icon(icon, size: 16), // 필드별 아이콘
SizedBox(width: 8),
Text('$label:', style: labelStyle),
],
),
SizedBox(height: 4),
// 입력 필드
TextFormField(
controller: controller,
style: TextStyle(
fontSize: 14,
fontFamily: isLink ? 'monospace' : null,
),
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
filled: true,
fillColor: isDark ? AppColors.darkSurface : Colors.white,
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
),
),
],
)
좌표 필드 (특수 처리)
Row(
children: [
Expanded(child: TextFormField(...)), // 위도
Text(',', style: monoStyle),
Expanded(child: TextFormField(...)), // 경도
],
)
색상 팔레트
라이트 모드
- 배경:
AppColors.lightBackground.withOpacity(0.5) - 테두리:
AppColors.lightDivider - 필드 배경:
Colors.white - 텍스트:
AppColors.lightText - 보조 텍스트:
AppColors.lightTextSecondary - 링크:
AppColors.lightPrimary
다크 모드
- 배경:
AppColors.darkBackground - 테두리:
AppColors.darkDivider - 필드 배경:
AppColors.darkSurface - 텍스트:
AppColors.darkText - 보조 텍스트:
AppColors.darkTextSecondary - 링크:
AppColors.lightPrimary(동일)
아이콘 매핑
| 필드 | 아이콘 | 의미 |
|---|---|---|
| 이름 | Icons.store |
가게/상점 |
| 카테고리 | Icons.category |
분류 |
| 세부 카테고리 | Icons.label_outline |
태그/라벨 |
| 주소 | Icons.location_on |
위치 |
| 전화 | Icons.phone |
연락처 |
| 설명 | Icons.description |
설명/문서 |
| 좌표 | Icons.my_location |
GPS 좌표 |
| 링크 | Icons.link |
외부 링크 |
타이포그래피
- 레이블: 13px, FontWeight.w500
- 값: 14px, 일반
- 링크: 14px, monospace 폰트, underline
- 좌표: 14px, monospace 폰트
인터랙션
1. 가져오기 플로우
- URL 입력
- "가져오기" 버튼 클릭
- 로딩 상태 표시
- 성공 시: JSON 스타일 UI 표시
- 실패 시: 에러 메시지 표시
2. 편집 플로우
- 각 필드 직접 수정 가능
- 좌표는 위도/경도 분리 입력
- 링크는 monospace 폰트와 밑줄로 구분
3. 저장/초기화
- 초기화: 모든 필드 클리어, UI 리셋
- 저장: 수정된 데이터로 맛집 추가
반응형 디자인
- 최대 너비: 400px (Dialog 제약)
- 스크롤 가능한 영역
- 모바일/태블릿 최적화
접근성
- 적절한 대비율 유지
- 터치 타겟 최소 44x44px
- 키보드 네비게이션 지원
- 스크린 리더 호환
애니메이션
- 필드 포커스: 부드러운 테두리 전환
- 버튼 상태: 색상 페이드
- 로딩: CircularProgressIndicator
구현 고려사항
- 상태 관리:
_fetchedRestaurantDataMap으로 데이터 추적 - 폼 검증: 각 필드별 적절한 검증
- 에러 처리: 사용자 친화적 메시지
- 성능: 불필요한 리빌드 방지