colors.dart: PRIMARY_COLOR 등을 const와 final로 선언함.
const는 컴파일 시점에, final은 실행 시점에 값이 결정됨을 의미함.
변수 뒤의 !(Null Assertion)은 해당 값이 절대 null이 아님을 컴파일러에게 확정해 주는 용도임.
레이아웃 구성: Column 내부에 Text(라벨)와 TextFormField(입력창)를 배치함.
조건부 렌더링:
isTime이 true일 때: 숫자 키보드 노출, 한 줄 입력 제한, 숫자만 입력 가능하도록 FilteringTextInputFormatter 적용함.
isTime이 false일 때: 멀티라인 입력 가능, 공간을 가득 채우는 expands: true 적용함.
Expanded 활용: flex를 조절하여 부모 위젯 내에서 차지하는 공간 비율을 유연하게 결정함.
② MainCalendar (테이블 캘린더)
table_calendar 패키지를 래핑하여 UI와 로직을 분리함.
날짜 판별 로직: selectedDayPredicate를 통해 매개변수로 들어오는 date가 현재 상태값인 selectedDate와 연/월/일이 모두 일치하는지 비교하여 선택 효과를 부여함.
스타일 커스텀: BoxDecoration을 사용해 평일, 주말, 선택된 날의 배경색과 테두리를 직접 디자인함. 오늘 날짜 강조는 isTodayHighlighted: false로 비활성화하여 디자인 일관성을 맞춤.
③ ScheduleCard (일정 표시 카드)
데이터를 사용자에게 보여주는 결과물 위젯임.
IntrinsicHeight 사용 이유: Row 내부에 배치된 _Time(시간)과 _Content(내용)의 높이를 동일하게 맞추기 위함임. 내용이 길어져도 시간 영역의 테두리가 함께 늘어남.
문자열 가공: startTime.toString().padLeft(2, '0')를 사용하여 1을 01로 변환, 시각적인 정렬을 유지함.
오버플로우 방지: 내용이 너무 길면 UI가 깨질 수 있으므로 TextOverflow.ellipsis와 maxLines: 2를 사용하여 말줄임표 처리를 함.
④ TodayBanner (상단 요약 바)
역할: 현재 선택된 날짜와 해당 날짜의 일정 개수를 Row와 spaceBetween을 이용해 양 끝에 배치하여 보여줌.
특징: 단순 표시용이므로 StatelessWidget으로 구성하여 불필요한 리소스 소모를 방지함.
⑤ ScheduleBottomSheet (입력 창)
동작: 화면 하단에서 올라오는 모달 창임. MediaQuery.of(context).size.height / 2를 사용하여 기기 높이의 정확히 절반을 차지하도록 설정함.
보호: SafeArea를 적용하여 하단 내비게이션 바 등 시스템 영역과 UI가 겹치는 것을 방지함.
상태 전달: MainCalendar가 onDaySelected 콜백을 호출함.
상태 갱신: 부모인 HomeScreen에서 setState()를 통해 selectedDate 변수를 변경함.
UI 리빌드: 변경된 날짜 정보가 TodayBanner, MainCalendar 등에 다시 전달되며 화면이 업데이트됨.
반응형 대응: 고정 수치 대신 MediaQuery나 Expanded를 사용하여 다양한 화면 크기에 대응함.
입력 제어: InputFormatter를 통해 사용자로부터 잘못된 데이터(시간에 문자 입력 등)가 들어오는 것을 원천 차단함.