Repository navigation
refactor: KoinPickerView 공용 picker 리팩토링 - #649
Conversation
- Date+KoinFormat: Calendar.koin(gregorian + Asia/Seoul), KoinDateFormat + 캐시 formatter, 포맷·파싱, 경과 분 기준 HH:mm(24:00), 오늘/내일 표시 - NewKoinPickerView: init(configuration:), date, setDate(_:animated:)/setRange(minimum:maximum:) 이벤트 없음, datePublisher 사용자 조작 시에만 발행 - Configuration: Mode, ColumnFormat, MinuteInterval, Style(.a/.b) + 프리셋 - PickerColumnsDataSource + DateColumns/Time12Columns/Time24Columns/DateAndTimeColumns (UIKit 비의존 컬럼 계산·값 정규화) - PickerAppearanceDelegate: Style 적용, 선택 행 index 기준 하이라이트 - PickerTimeOfDay.setDate: 현재 기준일 다음날 00:00이고 24:00 허용 범위일 때만 기준일 24:00, 그 외는 입력일을 기준일로 clamp - PickerTimeOfDay.makeWindow: min/max 각각 자기 날 기준 시·분만 사용, 24:00은 max가 min 기준일 다음날 00:00일 때만 - KoinDateFormat.formatter fileprivate, 오전/오후는 amSymbol/pmSymbol로 제공 - Time12Columns, DateAndTimeColumns 시 컬럼을 1, 2 … 12 순서로 정렬(오전 12시 = 0시, 오후 12시 = 12시 유지)
- NewKoinPickerView + 구분선 + 초기화/확인 버튼, KoinDropdownContentView 채택(height 153) - 공개 API: date, setDate(_:)/setRange(minimum:maximum:) 이벤트 없음, datePublisher(휠 조작 + 초기화) - 초기화: 현재 시각으로 clamp 후 1회 발행. 확인: 닫기만 - 외형은 기존 KoinPickerDropDownView와 동일
- BusSearchDatePickerViewController: NewKoinPickerView(.busDeparture(now:)), 모달형(열 때 departDate 표시, 완료 시에만 적용), departureTimeSettingDone Y/N = 휠 조작 여부 - BusSearchResultViewModel: datePickerData/FetchKoinPickerDataUseCase 제거, now·departDate(Date) 보관, 지금 출발 시 now 갱신 - BusSearchResultViewController: 표시 문자열 relativeDayTimeString(today:) - SearchBusInfoUseCase/BusRepository: Date 전달, processDate·returnIncludeYear 파싱 제거, request date/time 변환은 DefaultBusRepository에서 KoinDateFormat으로 - BusSearchViewController: FetchKoinPickerDataUseCase 주입 제거
- BusSearchResultViewController: UIRefreshControl 추가(새로고침 = 지금 출발, now 갱신) - 출발 시각 표시를 검색 결과와 분리: departDate 변경 즉시 updateDepartDate 발행 - 검색 실패 시 결과 목록 비움 - 새 검색 시 이전 검색 취소 + generation 검사, 결과·searchCompleted는 최신 요청만, main에서 처리 - BusSearchResultTableView가 출발 시각·버스 타입 표시 상태를 보관해 헤더 dequeue 시 재주입, 헤더 구독 중복 방지
- CallVanPostDateView: NewKoinPickerDropDownView(.callVanDate(now:)), 라벨은 KoinDateFormat.yearMonthDay, 문자열 역파싱 제거 - 휠·초기화 시 라벨과 dateChangedPublisher(Date) 즉시 갱신 - CallVanPostViewController: now 진입 시 1회 고정, 초기값은 setDate 후 보정된 date로 VM 직접 갱신(이벤트 의존 제거)
- CallVanPostTimeView: NewKoinPickerDropDownView(.callVanTime), 휠 오전/오후 표기, 라벨은 KoinDateFormat(.meridiem, .paddedHour12Minute), AM/PM 변환·문자열 역파싱 제거
- 휠·초기화 시 라벨과 timeChangedPublisher(Date, 그날 날짜 유지) 즉시 갱신
- CallVanPostViewController: 초기값은 setDate 후 보정된 date로 VM 직접 갱신, callvanWriteTime 로그는 사용자 조작 시에만(value는 KoinDateFormat.meridiemPaddedHourMinute)
- KoinDateFormat.paddedHour12Minute("hh:mm") 추가
- CallVanPostViewModel: departureDate/departureTime을 KoinDateFormat(.yearMonthDayHyphen, .hourMinute)으로 생성, 기기 timezone formatter 제거
- validate(): 날짜+시각 재파싱을 KoinDateFormat.yearMonthDayHyphenHourMinute으로(10분 이후 검증 의미 유지)
- KoinDateFormat.yearMonthDayHyphenHourMinute("yyyy-MM-dd HH:mm") 추가
…ule 추가 - RecruitPostSchedule: 시작·종료·마감 범위(1991-01-01 ~ 오늘+100년, 종료·마감 동적 범위), 변경 시 위반 필드 nil, isValid(일 단위) - RecruitPostScheduleView: NewKoinPickerDropDownView(.recruitDate) 3개, 라벨 KoinDateFormat.yearMonthDayDot, 1970 범위·configure overload·formatter 제거 - RecruitPostViewController: 열 때 setRange → setDate(값 ?? 현재), 값 없으면 보정된 date 즉시 반영, 휠·초기화 시 schedule.updating, date(from:) 파서 제거, 편집 진입 무보정 - RecruitPostRequest.isValid: RecruitPostSchedule.isValid 사용(시작 ≤ 마감 추가) - RecruitPostRequestDto: 날짜 문자열을 KoinDateFormat.yearMonthDayHyphen(Asia/Seoul)으로 생성 - pbxproj: 새 그룹 중복 name 정리 - RecruitDataDto: activityStartDate/activityEndDate/deadlineDate를 KoinDateFormat.yearMonthDayHyphen(Asia/Seoul)으로 파싱 - RecruitDataMetadataView: 활동 기간 표시를 KoinDateFormat.yearMonthDayDot으로
…eriod 추가 - RecruitActivityPeriod: 시작 1991-01-01 ~ 오늘, 종료 (시작 ?? 1991-01-01) ~ 오늘, 시작 변경 시 종료 < 시작이면 종료 nil, isValid(시작 ≤ 오늘, 진행 중 아니면 시작 ≤ 종료, 일 단위) - RecruitProfilePostActivityEditTableViewCell: NewKoinPickerDropDownView(.recruitDate) 2개, 열 때 setRange → setDate(값 ?? 현재), 값 없으면 보정된 date 즉시 반영, 휠·초기화 시 period.updating, date(from:) 파서·라벨 formatter 제거 - RecruitProfileActivityRequest.isValid: RecruitActivityPeriod.isValid 사용 - 활동 이력 startedAt/endedAt 디코딩·인코딩·표시를 KoinDateFormat(Asia/Seoul)으로
- AddLostItemCollectionViewCell: NewKoinPickerDropDownView(.lostItemDate(now:)), 내부 상태 Date, trigger는 KoinDateFormat.yearMonthDay, found_date는 KoinDateFormat.yearMonthDayHyphen, 값 없이 열면 보정된 date 즉시 반영, 로컬 DateFormatter·역파싱·convertToISODate 제거 - AddLostItemCollectionView: now 진입 시 1회 고정, articles.foundDate는 yyyy-MM-dd(KST), datePublisher(Date) - EditLostItemFoundDateView: NewKoinPickerDropDownView(.lostItemDate(now:)), 서버 found_date를 KST로 파싱해 무보정 표시, 변경 전에는 서버 문자열 그대로 저장 - EditLostItemViewController: now 진입 시 1회 고정해 주입 - EditLostItemFoundDateView.isValid: foundDateValue != nil (서버 값이 비었거나 파싱 불가면 무효) - validateInput(): 저장 시점에 무효면 경고 라벨 표시, 날짜 선택 시 복구 - EditLostItemViewController: 수정 완료 시 validateInput()으로 검증
- 삭제: KoinPickerView, KoinPickerDropDownView(+ Date/Time Delegate, KoinPickerViewB), DatePickerDropdownView, FetchKoinPickerDataUseCase - Date+.generateDateArray 삭제(FetchKoinPickerDataUseCase 전용) - pbxproj: 파일 7개의 PBXBuildFile·PBXFileReference·group·Sources 항목과 빈 그룹(KoinPickerDropDownView, Delegates, Subviews) 제거 - NewKoinPickerView → KoinPickerView, NewKoinPickerDropDownView → KoinPickerDropDownView (타입·참조·주석) - 폴더 NewKoinPickerView/ → KoinPickerView/, 파일 3개 이름 변경(git mv) - pbxproj: 파일 참조·그룹·Sources 주석의 이름 갱신
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Date formatting utilities Koin/Core/Extensions/Common/Date+KoinFormat.swift, Koin/Core/Extensions/Common/Date+.swift |
Adds Korean date formatting, parsing, elapsed-time, and relative-day helpers. Removes the sequence-based date-array helper. |
Picker configuration and column state Koin/Core/View/UIKit/KoinPickerView/DataSources/*, Koin/Core/View/UIKit/KoinPickerView/KoinPickerView+Configuration.swift, Koin/Core/View/UIKit/KoinPickerDropDownView/Delegates/*, Koin/Core/View/UIKit/KoinPickerView.swift |
Adds configurable date, time, and combined date-time columns and removes the earlier picker data sources and delegates. |
Picker view and dropdown integration Koin/Core/View/UIKit/KoinPickerView/*, koin.xcodeproj/project.pbxproj |
Adds a configured picker view and dropdown that publish selected dates. Updates project references for the new picker components. |
Bus search date flow
| Layer / File(s) | Summary |
|---|---|
Date-based search and result state Koin/Domain/Repository/BusRepository.swift, Koin/Data/Repository/DefaultBusRepository.swift, Koin/Domain/UseCase/Bus/*, Koin/Presentation/Bus/BusSearchResult/* |
Bus search now passes Date values through the use case and repository. The result view model handles immediate departure, day changes, cancellation of the previous search, and search completion or failure. |
Date picker and result display Koin/Presentation/Bus/BusSearchResult/SubViews/* |
The bus date picker returns a selected date and change flag. The results table retains its departure time and bus type when rebuilding its header. |
CallVan date and time
| Layer / File(s) | Summary |
|---|---|
Configured date and time selection Koin/Presentation/CallVan/CallVanPost/* |
CallVan date and time views use the shared dropdown and date publishers. The controller initializes both views from one captured date, and the view model uses shared date formatting and parsing. |
Lost-item date selection
| Layer / File(s) | Summary |
|---|---|
Post and edit date controls Koin/Presentation/LostItem/EditLostItem/*, Koin/Presentation/LostItem/PostLostItem/SubViews/* |
Lost-item flows use the shared picker and retain selected dates as Date values. The post flow formats dates for storage, while the edit flow validates the date selection and preserves the original server value if no date is selected. |
Recruitment date handling
| Layer / File(s) | Summary |
|---|---|
Schedule and activity-period rules Koin/Domain/Model/Recruit/* |
Adds schedule and activity-period models with picker ranges, date updates, and day-level validation. |
Recruitment screens and DTO conversion Koin/Presentation/Recruit/*, Koin/Data/DTOs/Decodable/Recruit/*, Koin/Data/DTOs/Encodable/Recruit/*, koin.xcodeproj/project.pbxproj |
Recruitment screens use the shared picker and schedule models. DTOs parse and format dates through the shared date helpers, and display code uses shared date formatting. |
Estimated code review effort: 4 (Complex) | ~60 minutes
Change: Refactor
Sequence Diagram(s)
sequenceDiagram
participant BusSearchResultViewController
participant BusSearchResultViewModel
participant SearchBusInfoUseCase
participant BusRepository
BusSearchResultViewController->>BusSearchResultViewModel: Send selected departure Date and bus type
BusSearchResultViewModel->>SearchBusInfoUseCase: Execute search with Date and route
SearchBusInfoUseCase->>BusRepository: Search with Date and route
BusRepository-->>SearchBusInfoUseCase: Return search result
SearchBusInfoUseCase-->>BusSearchResultViewModel: Return mapped result
BusSearchResultViewModel-->>BusSearchResultViewController: Emit result and search completion
Possibly related issues
- BCSDLab/KOIN_iOS issue 648: The issue describes the shared configuration-based picker refactor implemented in this pull request.
Possibly related PRs
- BCSDLab/KOIN_iOS#647: This PR adds the dropdown presentation contract used by the new picker dropdown and updated screen integrations.
Suggested labels: FIX
Merge Risk: 
Minimal · up to 7c058
-
This change moves several screens to a shared date picker and Date-based state. No concrete merge-blocking defect was found in the supplied evidence. As the PR notes, the bus reference time is not refreshed immediately when the app returns from the background. Normal manual UI checks of the migrated screens are still advisable.
Pre-merge checks: 
4 · 
1
-
Failed checks: 1 warning Passed checks: 4 passedFull details: Docstring Coverage
-
Explanation
Docstring coverage is 34.62% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 78 functions across 40 files. (1 skipped: 1 unsupported.)
Resolution
Write docstrings for the functions missing them to satisfy the coverage threshold.
-
Finishing Touches
-
Generate docstrings
-
- Commit to this branch
- Create a new PR
Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
#️⃣연관된 이슈
📝작업 내용
화면마다 따로 구현된 picker를 Configuration 기반 공용
KoinPickerView로 통일했습니다.1. KoinPickerView 추가 (
Core/View/UIKit/KoinPickerView)KoinPickerView(configuration:), 드롭다운형은KoinPickerDropDownView(configuration:buttonColor:)Date로 주고받습니다. (date,setDate(_:animated:),datePublisher)setRange(minimum:maximum:)로 범위를 바꾸면 현재 값을 범위 안으로 보정합니다.date/time12h/time24h/dateAndTimeminimumDate·maximumDate,minuteInterval(1·5·10·15·30),visibleRowCount(3·5),style(primary·new·neutral),columnSpacing(.uniform/.each)dateAndTime은 기준일에 따라 "오늘"·"내일"을 붙이고, 그 밖의 날짜는 "M월 d일(EEE)"로 표시합니다.오전/오후)과 영문(AM/PM) 중에서 고릅니다.Calendar.koin(그레고리력, Asia/Seoul)으로 통일했습니다.busDeparture,lostItemDate,callVanDate,callVanTime,recruitDate,timetable(시간표 리디자인용)2. 화면 전환
KoinPickerView(문자열)busDeparture(dateAndTime)KoinPickerDropDownViewcallVanDateKoinPickerDropDownViewcallVanTimeKoinPickerDropDownViewrecruitDate+RecruitPostScheduleKoinPickerDropDownViewrecruitDate+RecruitActivityPeriodDatePickerDropdownViewlostItemDateprimary600을 따로 지정합니다.KoinPickerView,KoinPickerDropDownView,KoinPickerViewBDatePickerDropdownViewFetchKoinPickerDateUseCase3. 함께 수정한 오류
found_date(yyyy-MM-dd)를 "yyyy년 M월 d일" 형식으로 읽어 파싱에 실패했습니다. 그래서 항상 오늘 날짜가 보이던 문제를 고쳤습니다. 이제 서버 값을 그대로 표시합니다.스크린샷 (선택)
💬리뷰 요구사항(선택)
timetable프리셋은 아직 쓰는 곳이 없습니다. 시간표 리디자인용으로 미리 넣었습니다.Time12Columns와DateAndTimeColumns의 12시간제 열 로직은 일부 겹칩니다. 공통화하면 구조가 복잡해져서 그대로 두었습니다.Summary by CodeRabbit