Files
lunchpick/doc/02_design/add_restaurant_dialog_design.md
JiWoong Sul 85fde36157 feat: 초기 프로젝트 설정 및 LunchPick 앱 구현
LunchPick(오늘 뭐 먹Z?) Flutter 앱의 초기 구현입니다.

주요 기능:
- 네이버 지도 연동 맛집 추가
- 랜덤 메뉴 추천 시스템
- 날씨 기반 거리 조정
- 방문 기록 관리
- Bluetooth 맛집 공유
- 다크모드 지원

기술 스택:
- Flutter 3.8.1+
- Riverpod 상태 관리
- Hive 로컬 DB
- Clean Architecture

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 19:03:28 +09:00

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. 가져오기 플로우

  1. URL 입력
  2. "가져오기" 버튼 클릭
  3. 로딩 상태 표시
  4. 성공 시: JSON 스타일 UI 표시
  5. 실패 시: 에러 메시지 표시

2. 편집 플로우

  1. 각 필드 직접 수정 가능
  2. 좌표는 위도/경도 분리 입력
  3. 링크는 monospace 폰트와 밑줄로 구분

3. 저장/초기화

  • 초기화: 모든 필드 클리어, UI 리셋
  • 저장: 수정된 데이터로 맛집 추가

반응형 디자인

  • 최대 너비: 400px (Dialog 제약)
  • 스크롤 가능한 영역
  • 모바일/태블릿 최적화

접근성

  • 적절한 대비율 유지
  • 터치 타겟 최소 44x44px
  • 키보드 네비게이션 지원
  • 스크린 리더 호환

애니메이션

  • 필드 포커스: 부드러운 테두리 전환
  • 버튼 상태: 색상 페이드
  • 로딩: CircularProgressIndicator

구현 고려사항

  1. 상태 관리: _fetchedRestaurantData Map으로 데이터 추적
  2. 폼 검증: 각 필드별 적절한 검증
  3. 에러 처리: 사용자 친화적 메시지
  4. 성능: 불필요한 리빌드 방지