본문 바로가기

카테고리 없음

[Flutter_개발] 상품 등록 페이지 수정 사항

1) 이미지 선택을 FormField로 편입하여 검증 일원화

  • 변경 전: _submit() 내부에서 이미지 미선택 시 SnackBar로 경고 후 return.
  • 변경 후: 이미지 섹션을 FormField<String?>로 감싸고 validator에 편입.
    • 장점: 다른 TextFormField들과 동일한 방식으로 검증됨. 에러가 버튼/미리보기 바로 아래 빨간 텍스트로 표시되어 시인성 증가.
    • 이미지 선택 시 didChange 호출로 에러 즉시 해제.
FormField<String?>(
  key: _imageFieldKey,
  validator: (_) => _imageSelection == null ? '이미지를 등록해 주세요.' : null,
  builder: (field) { /* ... FilledButton, 미리보기, 에러텍스트 ... */ },
)
// 다이얼로그 내 선택 시
setState(() => _imageSelection = 'network');
_imageFieldKey.currentState?.didChange(_imageSelection);
  • 결과: _submit()에서 이미지 미선택용 SnackBar 로직 삭제 → 검증 경로 단순화.

2) 가격 입력 중 천단위 콤마 자동 적용 + 안전한 검증

  • 입력 UX: TextInputFormatter.withFunction으로 타이핑과 동시에 1,000 식 콤마 적용.
  • 저장 값: 표시는 콤마가 있지만, 저장 시엔 replaceAll(',', '')로 순수 숫자만 파싱해 int로 보관(계산/정렬 안정성).
inputFormatters: [
  FilteringTextInputFormatter.digitsOnly,
  TextInputFormatter.withFunction((oldValue, newValue) {
    if (newValue.text.isEmpty) return newValue;
    final number = int.parse(newValue.text.replaceAll(',', ''));
    final formatted = NumberFormat('#,###').format(number);
    return TextEditingValue(
      text: formatted,
      selection: TextSelection.collapsed(offset: formatted.length),
    );
  }),
],
  • 검증 로직(validator):
    • 공백/빈값 방지
    • 숫자 외 문자 제거 후 정수 변환 시도
    • 범위 검증: 100원 이상 10,000,000원 이하
 
validator: (v) {
  if (v == null || v.trim().isEmpty) return '상품 가격을 입력해 주세요.';
  final clean = v.replaceAll(RegExp(r'[^0-9]'), '');
  final n = int.tryParse(clean);
  if (n == null || n < 0) return '유효한 가격을 입력해 주세요.';
  if (n < 100 || n > 10000000) return '100원 이상 10,000,000원 이하로 입력해 주세요.';
  return null;
}

3) 이미지 URL 오타 수정으로 리스트 썸네일 표시 정상화

  • 버그: https://picsum.photos200/300처럼 슬래시 누락으로 저장되어 홈에서 이미지가 로드되지 않음.
  • 수정: https://picsum.photos/200/300로 통일(미리보기와 동일 경로).
final String imageUrl =
  _imageSelection == 'network' ? 'https://picsum.photos/200/300' : '';
  • 효과: 상품등록 후 홈 리스트 썸네일이 정상적으로 노출됨.

4) UUID로 상품 ID 안정적으로 발급

  • uuid: ^4.x 사용, 제출 시 uuid.v4()로 고유 ID 생성.
  • 충돌 위험 낮고, 로컬/서버 어디서든 식별자로 활용 가능.
 
final uuid = const Uuid();
final product = ProductEntity(
  id: uuid.v4(),
  name: _nameController.text.trim(),
  price: int.parse(_priceController.text.replaceAll(',', '')),
  description: _descController.text.trim(),
  imageUrl: imageUrl,
);

5) 등록 완료 다이얼로그의 가격 표시는 항상 포맷 적용

  • 사용자 피드백용 표시에서 intl로 콤마 포맷 보장.
Text('가격: ${NumberFormat('#,###').format(product.price)}원'),

6) 불필요 코드 정리 및 UI 폴리싱

  • _hasSelectedImage 게터 제거(검증이 FormField로 이동했기 때문에 중복).
  • AppBar에 centerTitle: true 반영(시각적 정렬).
  • 공백 등 자잘한 문자열 정리.

7) 전체 흐름 요약

  1. 사용자가 “이미지 선택” 클릭 → 다이얼로그에서 picsum 선택 → 미리보기 즉시 반영, 에러 해제.
  2. 상품명(0/30), 가격(콤마 자동), 설명(0/1000) 입력.
  3. “등록하기” → Form.validate()로 모든 필드 검사(이미지 포함).
  4. 통과 시 ProductEntity 생성(가격은 숫자만), UUID 발급, 올바른 이미지 URL 저장.
  5. “등록 완료” 다이얼로그 출력 → 확인 시 Navigator.pop(context, product)로 상위(홈)로 전달.
  6. 홈 리스트가 전달받은 product를 목록에 append → 썸네일 정상 표시.

배운 점 / 메모

  • **검증은 한 곳(Form/Field)**에 모아야 유지보수가 쉽다. SnackBar 경고는 즉시성은 좋지만, 폼의 정적 에러 텍스트가 사용성·접근성 면에서 우수.
  • 표시와 보관 분리: 가격은 화면에선 String(콤마포맷), 저장은 int. 모델/DB/서버에서의 오류를 근본적으로 예방한다.
  • 작은 오타(슬래시 누락) 하나로도 기능 전체가 깨질 수 있음 → 네트워크 리소스 경로는 상수화/재사용을 고려.
  • 이미지 선택도 입력 필드(validator)로 모델링하면 검증/표시/에러처리가 일관된다.