카테고리 없음

2025.11.14

kwontete 2025. 11. 14. 22:11

Freezed & JSON Serialization 트러블슈팅

문제

  • Freezed 적용 도중 part 'xxx.freezed.dart', part 'xxx.g.dart' 에러 발생
  • fromJson(Map<String,Object>) 타입 불일치로 오류 (Map<String,dynamic> vs Map<String,Object>)

원인

  • Freezed는 Map<String, dynamic> 형식이 일반적
  • 타입 강제 지정 때문에 json_serializable이 매칭을 못 함
  • part 파일 누락 시 build_runner가 생성 파일을 못 찾음

해결 방법

  • factory ToDoModel.fromJson(Map<String, dynamic> json) 형태로 변경
  • model 파일 상단에 정확히 아래 2개 추가:
 
part 'to_do_model.freezed.dart'; part 'to_do_model.g.dart';
  • flutter pub run build_runner build --delete-conflicting-outputs 다시 실행

Freezed는 ViewModel에서 모델을 copyWith로 불변 상태 관리할 때만 주로 사용하며, ViewModel 자체에는 필요 없음.


Repository 구조 & 역할 완전 이해

Repository에는 무엇이 들어가야 하는가?

  • CRUD 메서드만
  • 서버/DB와 통신 관련된 로직만
  • ViewModel이나 View에서 쓰는 상태 로직은 포함 X

.set()의 정확한 의미

  • 문서를 “덮어쓰기”
  • SetOptions(merge: true)를 주면 해당 필드만 업데이트 가능
  • Firebase Authentication과 Firestore 사용자 문서 연동할 때 매우 유용

실제 시나리오

로그인 후 Firestore users 컬렉션에 Auth 정보 덮어쓰기:

 
await db.collection('users').doc(uid).set({ 'uid': uid, 'createdAt': FieldValue.serverTimestamp(), }, SetOptions(merge: true));

Intro → SignUp 전체 플로우 설계 완성

IntroPage(View)

  • Apple / Google 로그인 버튼 클릭
  • 버튼은 IntroViewModel.loginWithGoogle() 호출

IntroViewModel

  • Google/Apple 로그인 진행
  • 로그인 성공 → UserRepository.setUser(uid) 호출
  • Firestore에 기본 유저 필드 생성(merge)
  • SignUpPage로 이동

SignUpPage(View)

  • 이름 / 나이 / 성별 / 소개 입력 받음
  • “프로필 등록" 클릭 → ViewModel or Repository 직접 호출
  • UserRepository.updateProfile(uid) 사용하여 Firestore 업데이트

즉, Intro → 로그인 → 기본 유저 문서 생성 → SignUp → 입력값 저장 → 홈 이동 흐름 완성.


 ThemeData 깊게 적용하기

seedColor 개념

  • ColorScheme.fromSeed는 seedColor를 기준으로 전체 팔레트 자동 생성
  • 단일 색을 기준으로 자연스러운 색 계열이 자동 생성됨

➡ seedColor는 앱의 **메인 브랜드 컬러(예: 0xFF983E24)**로 지정하는 것이 정석.


TextTheme 각 용도 정리

  • display : 아주 큰 헤더 (스플래시·히어로 화면)
  • headline : 큰 제목
  • title : 일반 제목 (리스트 타이틀 등)
  • body : 일반 본문 텍스트
  • label : 버튼 텍스트, 작은 안내 텍스트

➡ 앱 화면의 “닉네임”은 titleMedium, 본문은 bodyMedium, 날짜는 bodySmall이 이상적.


BottomNavigationBar Theme 적용

iconSize는 직접 조절 불가 → iconTheme 사용해야 함

아래가 정석:

 
bottomNavigationBarTheme: BottomNavigationBarThemeData( selectedIconTheme: IconThemeData(size: 27, color: Color(0xFF983E24)), unselectedIconTheme: IconThemeData(size: 27, color: Color(0xFF373737)), selectedLabelStyle: TextStyle(fontSize: 12, color: Color(0xFF983E24)), unselectedLabelStyle: TextStyle(fontSize: 12, color: Color(0xFF373737)), )

ColorScheme Extension 구현

컨테이너·텍스트필드·외곽선 색상 통일 관리 위해 ext 파일 생성.

color_scheme_ext.dart

 
extension CustomColorScheme on ColorScheme { Color get fieldBackground => const Color(0xFFFFFFFF); Color get borderDefault => const Color(0xFFD2D5DA); Color get borderFocus => const Color(0xFF983E24); }

사용 방법

 
Container( color: Theme.of(context).colorScheme.fieldBackground, child: Text("내용", style: Theme.of(context).textTheme.titleMedium), )

➡ View에서 매우 편하게 재사용 가능.


ElevatedButton & FAB 스타일링

ElevatedButton 전체 사이즈 지정

 
fixedSize: const Size(double.infinity, 70),

FAB는 원형이라 폭/높이 동일하게만 주면 됨

 
floatingActionButtonTheme: FloatingActionButtonThemeData( backgroundColor: Color(0xFF983E24), foregroundColor: Color(0xFFF2F2F2), sizeConstraints: BoxConstraints.tight(Size(64, 64)), )

Git 메시지 해석

“There are no staged changes…”
→ 스테이지에 올린 파일 없음
→ “변경된 파일을 전부 stage + commit 하겠냐?" 질문 메시지


오늘의 배움 요약

  • Freezed 사용 시 타입, part 파일 위치가 중요함
  • Repository는 오직 DB 통신 로직만 담당
  • Auth → Firestore 사용자 문서 생성은 .set(merge: true)가 핵심
  • MVVM 흐름(로그인→유저생성→프로필저장)을 완전히 이해
  • ThemeData / ColorScheme Extension을 분리해 유지보수성 강화
  • BottomNav / Buttons / FAB 등 Material Theme 시스템 이해
  • Git stage/commit 흐름 이해