Conversation
…extra-api # Conflicts: # app/src/main/java/com/example/findu/presentation/ui/base/TopAppBar.kt
…tra-api # Conflicts: # app/src/main/java/com/example/findu/data/mapper/todomain/home/HomeResponseDtoMapper.kt
# Conflicts: # app/src/main/java/com/example/findu/data/dataremote/util/Constraints.kt # app/src/main/java/com/example/findu/di/RepositoryModule.kt # app/src/main/java/com/example/findu/di/UseCaseModule.kt # app/src/main/java/com/example/findu/domain/model/extra/HomeExtraDataType.kt # app/src/main/java/com/example/findu/presentation/ui/extra/viewmodel/HomeExtraViewModel.kt # app/src/main/java/com/example/findu/presentation/ui/home/viewmodel/HomeViewModel.kt # app/src/main/java/com/example/findu/presentation/ui/login/viewmodel/LoginViewModel.kt
# Conflicts: # app/src/main/java/com/example/findu/data/mapper/todomain/SearchResponseDtoMapper.kt # app/src/main/java/com/example/findu/di/UseCaseModule.kt
…or/search-ui-logic
|
Caution Review failedThe pull request is closed. WalkthroughFirebase(Analytics, Remote Config) 및 Google Services 빌드 설정 추가, 정보(INFORMATION) API 계층(서비스/데이터소스/DTO/매퍼/리포지토리/유스케이스/DI) 추가, 프로필 이미지 업로드 API 통합(파일/기본 이미지 하나의 엔드포인트), UI·ViewModel·리소스·패키지 재배치 포함한 광범위한 변경입니다. Changes
Sequence Diagram(s)sequenceDiagram
rect rgb(240,248,255)
participant UI as HomeExtraFragment
participant VM as HomeExtraViewModel
participant UC as Get*UseCases
participant Repo as InformationRepositoryImpl
participant DS as InformationRemoteDataSourceImpl
participant API as InformationService
end
UI->>VM: 요청 (예: GetVolunteers)
VM->>UC: invoke(filters)
UC->>Repo: getVolunteers(lastId)
Repo->>DS: getVolunteers(lastId)
DS->>API: GET /api/v2/informations/volunteers
API-->>DS: BaseResponse<VolunteersResponseDto>
DS-->>Repo: 반환
Repo->>Repo: handleBaseResponse(), toDomain()
Repo-->>UC: Result<PagedResult<VolunteerWork>>
UC-->>VM: 반환
VM-->>UI: uiState 업데이트
sequenceDiagram
rect rgb(245,245,245)
participant UI as MyFragment
participant VM as MyViewModel
participant UC as PatchProfileImageUseCase
participant Repo as MyRepositoryImpl
participant DS as MyRemoteDataSourceImpl
participant API as MyService
end
UI->>VM: updateProfileImageFromGallery(context, uri)
VM->>VM: uri.toSingleImageFile(context)
VM->>UC: upload(update: MyProfileImageUpdate)
UC->>Repo: patchProfileImage(File? , String?)
Repo->>DS: patchProfileImage(File? , String?)
DS->>API: PATCH /api/v2/users/me/profile-image (multipart optional)
API-->>DS: NullableBaseResponse<Unit>
DS-->>Repo: 결과
Repo-->>UC: Result<Unit>
UC-->>VM: 성공 -> VM.getProfile()
VM-->>UI: 프로필 갱신
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (9)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 16
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/src/main/java/com/example/findu/presentation/ui/my/MyFragment.kt (1)
139-155: 버전 UI에 로그아웃 리스너가 연결되어 있음(명확한 UX 오류).tvMyVersionInfo, chipMyVersion 클릭이 로그아웃을 트리거합니다. 버전 정보/칩은 업데이트 안내 등으로 연결되어야 합니다. 로그아웃은 clMyLogout만 처리하세요.
- tvMyVersionInfo.setOnClickListener(logoutClickListener) - chipMyVersion.setOnClickListener(logoutClickListener) + // 버전 정보는 클릭 제거 또는 업데이트 안내로 연결 + tvMyVersionInfo.setOnClickListener(null) + chipMyVersion.setOnClickListener(null)
🧹 Nitpick comments (28)
app/src/main/java/com/example/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt (3)
90-107: 닉네임 중복 확인 로직 개선 제안현재 코드는 정상적으로 동작하지만, 다음 개선을 고려해볼 수 있습니다:
- 에러 로그가
Log.d(개발 레벨)로 설정되어 있는데, 실제 프로덕션 환경에서는 더 명확한 사용자 피드백이 필요할 수 있습니다.focusChanged(false)호출이onSuccess,onFailure블록 밖에 있어 실패 시에도 포커스가 해제되므로, 실패 시 다시 시도할 수 있도록 상태 유지를 고려해볼 수 있습니다.
136-139: 유효성 검사 정규식 상수화 제안닉네임 특수문자 검증에 사용되는 정규식을
companion object로 추출하면 재사용성과 가독성이 향상됩니다.companion object { private const val FIRST_PAGE = 1 private const val LAST_PAGE = 2 private val SPECIAL_CHARACTER_REGEX = Regex("[^a-zA-Z0-9가-힣]") }그 후
containsSpecialCharacter를 다음과 같이 수정:- private fun containsSpecialCharacter(input: String): Boolean { - val regex = Regex("[^a-zA-Z0-9가-힣]") - return regex.containsMatchIn(input) - } + private fun containsSpecialCharacter(input: String): Boolean { + return SPECIAL_CHARACTER_REGEX.containsMatchIn(input) + }
141-153: 임시 파일 생성 시 리소스 관리 주의
uriToFile메서드에서 생성된 임시 파일은 사용 후 명시적으로 삭제되어야 합니다. 현재는 캐시 디렉토리에 저장되지만, 대량의 프로필 이미지 업로드 시 캐시 누적이 발생할 수 있습니다.고려사항:
- 임시 파일 삭제를
signUp()성공/실패 후 처리할 로직 추가- 또는 프로필 업로드 완료 후 파일 정리를 전담하는 클래스 도입
app/src/main/java/com/example/findu/presentation/ui/search/viewmodel/SearchViewModel.kt (1)
118-123: 하드코딩된 태그 문자열 개선 고려해보세요
when표현식에서 "보호중", "실종신고", "목격신고" 같은 문자열을 직접 사용하고 있는데, 오타나 태그 변경 시 런타임 오류가 발생할 수 있어요. 상수나 enum으로 관리하면 타입 안정성과 유지보수성이 좋아집니다.예를 들어:
object AnimalTag { const val PROTECTING = "보호중" const val MISSING_REPORT = "실종신고" const val WITNESS_REPORT = "목격신고" } // 사용 when (tag) { AnimalTag.PROTECTING -> getSearchData(SearchType.PROTECTING) AnimalTag.MISSING_REPORT, AnimalTag.WITNESS_REPORT -> getSearchData(SearchType.REPORTING) else -> getSearchData(SearchType.ALL) }app/src/main/java/com/example/findu/domain/usecase/SetNicknameUseCase.kt (1)
4-5: 사용하지 않는 import 정리하면 좋을 것 같아요.DI 어노테이션을 제거하면서
javax.inject.Inject와javax.inject.Singletonimport가 더 이상 사용되지 않게 됐네요. 코드 정리 차원에서 제거해주시면 깔끔할 것 같습니다.다음과 같이 수정하시면 돼요:
package com.example.findu.domain.usecase import com.example.findu.domain.repository.UserInfoRepository -import javax.inject.Inject -import javax.inject.Singleton class SetNicknameUseCase(app/src/main/java/com/example/findu/data/dataremote/service/MyService.kt (1)
47-52: 두 메서드를 하나로 통합한 것은 좋지만, 매개변수 검증을 고려해보세요.프로필 이미지 패치 메서드를 하나로 통합한 것은 API 표면을 단순화하는 좋은 리팩토링입니다. 다만, 두 매개변수가 모두 nullable이고 기본값이 null인 경우, 다음을 확인해주세요:
- 두 매개변수가 모두 null일 때의 동작이 명확한가요?
- 두 매개변수가 동시에 제공될 때의 우선순위는 어떻게 되나요?
호출 계층에서 이러한 케이스를 검증하는 로직이 있는지 확인하거나, 필요시 KDoc으로 사용법을 명시하는 것을 권장합니다.
app/src/main/java/com/example/findu/presentation/util/UriUtil.kt (1)
65-70: 코드 중복을 제거할 수 있습니다.새로 추가된
toSingleImageFile함수가 기존의uriToFile함수(40-46번 줄)와 거의 동일한 로직을 가지고 있네요.uriToFile은 불필요하게File(file.absolutePath)로 한 번 더 감싸는 것만 다릅니다.다음 중 하나를 추천드립니다:
옵션 1: 기존
uriToFile을 public으로 변경하고toSingleImageFile에서 재사용:-private fun uriToFile(uri: Uri, context: Context): File { +fun Uri.toSingleImageFile(context: Context): File { val fileName = getFileName(context, uri) - val file = FileUtil.createTempFile(context, fileName) FileUtil.compressAndSave(context, uri, file) - return File(file.absolutePath) + return file }그리고
toMultiPartBodys의 59번 줄을it.toSingleImageFile(context)로 변경옵션 2: 새 함수를 유지하되 기존 private
uriToFile제거 (사용처인toMultiPartBodys에서 새 함수 호출)app/src/main/java/com/example/findu/domain/usecase/extra/GetCentersUseCase.kt (1)
10-22: 파라미터 명명 일관성을 고려해보세요.Use case의
invoke메서드는lon파라미터를 받지만, repository 호출 시에는long = lon으로 매핑하고 있네요. Repository에서long을 파라미터명으로 사용하는 것 같은데,long은 Kotlin 키워드라서 named parameter로는 사용 가능하지만 일반적이지 않아요.전체 레이어에서
lon또는longitude로 통일하는 게 좋을 것 같아요. Repository 인터페이스를 확인해서 네이밍을 통일하는 걸 권장합니다.다음 스크립트로 repository의 파라미터명을 확인해보세요:
#!/bin/bash # Description: Check parameter naming in InformationRepository ast-grep --pattern $'interface InformationRepository { $$$ getCenters($$$) $$$ }'app/src/main/java/com/example/findu/presentation/ui/search/viewmodel/SearchFilterViewModel.kt (1)
52-60: 성공 시 에러 메시지 초기화 권장loadSido 성공 시
_errorMessage를null로 클리어하면 UI 일관성이 좋아집니다. 또한 호출 시작 시 이전 에러를 지우는 것도 좋습니다.fun loadSido() { viewModelScope.launch { - getSidoUseCase().onSuccess { - _sidoList.value = it - }.onFailure { - _errorMessage.value = it.message - } + _errorMessage.value = null + getSidoUseCase() + .onSuccess { list -> _sidoList.value = list } + .onFailure { e -> _errorMessage.value = e.message } } }app/src/main/java/com/example/findu/data/dataremote/model/response/information/DepartmentsResponseDto.kt (1)
7-29: DTO 정의 깔끔합니다.필드 매핑과 직렬화 어노테이션 일관적이에요. 서버에서
phoneNumber가 선택값이라면 nullable 고려만 추후 검토해주세요.app/src/main/java/com/example/findu/data/mapper/todomain/extra/InformationResponseDtoMapper.kt (1)
12-53: 필드 매핑 적절합니다. 가시성은 internal로 축소 고려.매퍼 로직은 데이터 모듈 내부 구현 디테일에 가까워서 외부로 노출하지 않는 편이 안전합니다. 외부 모듈에서 사용하지 않는다면
internal로 제한해주세요.외부 모듈에서 이 확장함수들을 직접 호출하는지 확인 부탁드립니다. 사용처가 데이터 모듈 내부뿐이면 internal 전환 가능.
app/src/main/java/com/example/findu/domain/repository/InformationRepository.kt (1)
15-21: 파라미터 명/타입 일관성 개선 제안
long→lng또는longitude로 변경 권장(타입명 Long과 혼동).getSigungu(sidoId: Long)를 쓰면서getCenters는sido: String?을 받는 건 불일치입니다. 가능하면sidoId: Long?로 통일하거나, 도메인 전층에서 이름 기반/ID 기반 중 하나로 일관화해주세요.이 변경이 API/서버 계약과 호환되는지 확인 부탁드립니다.
app/src/main/java/com/example/findu/data/dataremote/model/response/information/CentersResponseDto.kt (1)
6-31: 센터 DTO 정의 문제 없어 보여요.시리얼라이즈 키와 타입이 매퍼와 잘 맞습니다. 서버에서
jurisdiction가 비어있을 수 있으면 빈 리스트 기본값 고려만 추후 검토하세요.app/src/main/java/com/example/findu/presentation/ui/extra/view/ExtraDepartmentScreen.kt (1)
60-64: LazyColumn에 안정 키 부여 권장 (리스트 성능/상태 보존).아이템 키를 지정하면 스크롤/애니메이션/상태 보존이 안정적입니다.
- LazyColumn { - items(departments) { - ExtraDepartmentItem(department = it) - } - } + LazyColumn { + items( + items = departments, + key = { "${it.name}-${it.district}-${it.phone}" } // 고유 ID가 있으면 그걸 사용하세요. + ) { item -> + ExtraDepartmentItem(department = item) + } + }app/src/main/java/com/example/findu/di/UseCaseModule.kt (1)
240-258: 새 Information UseCase 바인딩 구성은 적절해 보입니다DI 연결과 시그니처 모두 일관적입니다. 두 가지만 확인 부탁:
- InformationRepository 바인딩/제공 모듈이 함께 머지되는지.
- UseCase가 상태 없으면 @singleton 생략도 가능(메모리 보존 불필요 시). 지금도 문제는 없습니다.
Also applies to: 277-287
app/src/main/java/com/example/findu/data/dataremote/datasourceimpl/InformationRemoteDataSourceImpl.kt (1)
17-28: 단순 위임 OK. 스타일 소소한 정리
- 포워딩 로직은 깔끔합니다.
- 코딩 스타일:
sidoId:Long→sidoId: Long.예시 diff:
- override suspend fun getSigungu(sidoId:Long): BaseResponse<SigunguListDto> = informationService.getSigungu(sidoId = sidoId) + override suspend fun getSigungu(sidoId: Long): BaseResponse<SigunguListDto> = + informationService.getSigungu(sidoId = sidoId)Also applies to: 30-38
app/src/main/java/com/example/findu/presentation/ui/my/MyViewModel.kt (2)
137-145: 업로드 디스패처 확인 부탁
patchProfileImageUseCase.upload(...)내부가 네트워크/파일 I/O를 Main에서 수행하지 않도록 보장되어야 합니다. 내부에서withContext(Dispatchers.IO)처리 여부 확인해 주세요. 필요 시 이쪽에서도 IO 디스패처 전환을 고려하세요.
234-238: 토큰 초기화 실패 시 사용자 피드백 추가 권장에러가 발생해도 UI에 전달되지 않습니다. 간단히
runCatching으로 에러 메시지 표출 혹은 성공 이벤트를 제공해 주세요.예시 diff:
- fun clearToken() { - viewModelScope.launch { - clearTokenUseCase() - } - } + fun clearToken() { + viewModelScope.launch { + runCatching { clearTokenUseCase() } + .onFailure { _errorMessage.value = it.message ?: "토큰 초기화 중 오류가 발생했습니다." } + } + }app/src/main/java/com/example/findu/data/repositoryimpl/InformationRepositoryImpl.kt (1)
14-26: Repository 계층 에러 처리와 매핑 흐름이 깔끔합니다.
runCatching + handleBaseResponse + toDomain 체인이 일관되고 읽기 쉽습니다. LGTM.
반복되는 체인을 확장함수로 추출하면(예: mapResponseToDomain()) 중복을 더 줄일 수 있습니다.
Also applies to: 27-38, 40-48, 50-56, 57-63
app/src/main/java/com/example/findu/presentation/ui/extra/HomeExtraFragment.kt (3)
51-58: uiEffect 수집 블록 TODO 제거 또는 구현 필요.댓글만 남고 실제 처리 분기가 없습니다. 불필요하면 제거, 사용할 계획이면 when 분기 구현을 권장합니다.
70-72: 중복 popBackStack 람다 정리 제안.동일 람다가 3곳에서 반복됩니다. 가독성을 위해 지역 변수로 추출하세요.
-ExtraHomeVolunteerScreen( - volunteerWorks = content.list, - popBackStack = { findNavController().popBackStack() }) +val popBack = { findNavController().popBackStack() } +ExtraHomeVolunteerScreen( + volunteerWorks = content.list, + popBackStack = popBack) ... - popBackStack = { findNavController().popBackStack() } + popBackStack = popBack ... - popBackStack = { findNavController().popBackStack() }, + popBackStack = popBack,Also applies to: 76-89, 93-111
124-128: 미사용 함수 제거 권장.showFindDialog()가 현재 호출되지 않습니다. Dead code는 정리해 주세요.
app/src/main/java/com/example/findu/presentation/ui/my/MyFragment.kt (2)
105-108: ViewModel에 Activity Context 전달 지양.
updateProfileImageFromGallery(context = requireContext(), ...)는 ViewModel에 UI 컨텍스트를 넘깁니다. 파일 변환/IO는 Fragment(또는 Hilt로 주입한 Application Context/UseCase)에서 처리 후, ViewModel에는 순수 데이터(파일/바이트/Uri)만 전달하는 구조로 바꾸세요. 메모리 누수·테스트 용이성 측면에서 이득입니다.- myViewModel.updateProfileImageFromGallery( - context = requireContext(), - uri = uri - ) + val file = uri?.toSingleImageFile(requireContext()) // util로 변환 + myViewModel.updateProfileImageFromGallery(file)(프로젝트 내 UriUtil이 있다면 재사용. 없으면 util 추가 제안)
Also applies to: 42-46
195-197: Remote Config fetch 간격: 개발/릴리스 분기 추천.개발 빌드에서는 빠른 실험을 위해
minimumFetchIntervalInSeconds = 0, 릴리스에서는 3600 유지하는 분기를 권장합니다.val configSettings = remoteConfigSettings { minimumFetchIntervalInSeconds = if (BuildConfig.DEBUG) 0 else 3600 }app/src/main/java/com/example/findu/presentation/ui/extra/viewmodel/HomeExtraViewModel.kt (2)
138-143: 빈 값은 null로 전달하는 방어 로직 권장.서버가
""를 유효 값으로 해석하면 결과가 비정상일 수 있습니다.sido/sigungu가 비어있으면 null로 전달하세요.district도 공백 구분을 명확히 하세요.- private fun getCenters( - sido: String = uiState.value.selectedSido.name, - sigungu : String = uiState.value.selectedSigungu, + private fun getCenters( + sido: String? = uiState.value.selectedSido.name.takeIf { it.isNotBlank() }, + sigungu : String? = uiState.value.selectedSigungu.takeIf { it.isNotBlank() }, ... - getDepartmentsUseCase(district = uiState.value.selectedSido.name + uiState.value.selectedSigungu) + val district = listOf( + uiState.value.selectedSido.name, + uiState.value.selectedSigungu + ).filter { it.isNotBlank() }.joinToString(" ") + getDepartmentsUseCase(district = district.ifBlank { null })API가 기대하는 district 포맷(공백 포함/미포함)을 확인해 주세요.
Also applies to: 172-176
221-229: 시·군·구 초기 선택 UX 보완 제안.GetSido 성공 시
selectedSido기본값을 첫 항목으로 지정하고, 이에 맞춰getSigungu를 연쇄 호출하면 초기 UX가 자연스러워집니다.getSidoUseCase().onSuccess { result -> _uiState.update { it.copy(sidoList = result, selectedSido = result.firstOrNull() ?: it.selectedSido) } result.firstOrNull()?.let { getSigungu(it.id) } }Also applies to: 231-239
app/src/main/java/com/example/findu/presentation/ui/extra/view/ExtraCenterScreen.kt (2)
173-186: 하드코딩 텍스트 i18n 처리."현 지도에서 검색"은 stringResource로 분리하세요.
- text = "현 지도에서 검색 ", + text = stringResource(R.string.home_extra_search_in_this_map),(strings.xml에 키 추가 필요)
152-170: 접근성: 아이콘 클릭 요소에 contentDescription 부여.클릭 가능한 BaseVectorIcon에 설명을 제공하세요. TopAppBar는 이미 처리되어 있어, 지도 액션 아이콘에도 동일하게 적용 권장.
- BaseVectorIcon( + BaseVectorIcon( vectorResource = R.drawable.ic_place_now_24, + contentDescription = stringResource(R.string.home_extra_my_location), modifier = ModifierAlso applies to: 81-86
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (82)
app/build.gradle.kts(2 hunks)app/src/main/java/com/example/findu/data/dataremote/datasource/HomeRemoteDataSource.kt(1 hunks)app/src/main/java/com/example/findu/data/dataremote/datasource/InformationRemoteDataSource.kt(1 hunks)app/src/main/java/com/example/findu/data/dataremote/datasource/MyRemoteDataSource.kt(2 hunks)app/src/main/java/com/example/findu/data/dataremote/datasourceimpl/HomeRemoteDataSourceImpl.kt(1 hunks)app/src/main/java/com/example/findu/data/dataremote/datasourceimpl/InformationRemoteDataSourceImpl.kt(1 hunks)app/src/main/java/com/example/findu/data/dataremote/datasourceimpl/MyRemoteDataSourceImpl.kt(2 hunks)app/src/main/java/com/example/findu/data/dataremote/model/response/home/HomeResponseDto.kt(1 hunks)app/src/main/java/com/example/findu/data/dataremote/model/response/information/CentersResponseDto.kt(1 hunks)app/src/main/java/com/example/findu/data/dataremote/model/response/information/DepartmentsResponseDto.kt(1 hunks)app/src/main/java/com/example/findu/data/dataremote/model/response/information/SidoListDto.kt(1 hunks)app/src/main/java/com/example/findu/data/dataremote/model/response/information/SigunguListDto.kt(1 hunks)app/src/main/java/com/example/findu/data/dataremote/model/response/information/VolunteersResponseDto.kt(1 hunks)app/src/main/java/com/example/findu/data/dataremote/model/response/my/MyInterestResponseDto.kt(2 hunks)app/src/main/java/com/example/findu/data/dataremote/service/HomeService.kt(1 hunks)app/src/main/java/com/example/findu/data/dataremote/service/InformationService.kt(1 hunks)app/src/main/java/com/example/findu/data/dataremote/service/InterestService.kt(1 hunks)app/src/main/java/com/example/findu/data/dataremote/service/MyService.kt(1 hunks)app/src/main/java/com/example/findu/data/dataremote/util/Constraints.kt(1 hunks)app/src/main/java/com/example/findu/data/mapper/toDomain/extra/SidoListDtoMapper.kt(1 hunks)app/src/main/java/com/example/findu/data/mapper/todomain/LoginResponseDtoMapper.kt(1 hunks)app/src/main/java/com/example/findu/data/mapper/todomain/extra/InformationResponseDtoMapper.kt(1 hunks)app/src/main/java/com/example/findu/data/mapper/todomain/home/HomeResponseDtoMapper.kt(1 hunks)app/src/main/java/com/example/findu/data/mapper/todomain/my/MyInterestMapper.kt(1 hunks)app/src/main/java/com/example/findu/data/repositoryimpl/HomeRepositoryImpl.kt(1 hunks)app/src/main/java/com/example/findu/data/repositoryimpl/InformationRepositoryImpl.kt(1 hunks)app/src/main/java/com/example/findu/data/repositoryimpl/MyRepositoryImpl.kt(1 hunks)app/src/main/java/com/example/findu/di/DataSourceModule.kt(3 hunks)app/src/main/java/com/example/findu/di/RepositoryModule.kt(3 hunks)app/src/main/java/com/example/findu/di/ServiceModule.kt(2 hunks)app/src/main/java/com/example/findu/di/UseCaseModule.kt(4 hunks)app/src/main/java/com/example/findu/domain/model/extra/HomeExtraDataType.kt(1 hunks)app/src/main/java/com/example/findu/domain/repository/InformationRepository.kt(1 hunks)app/src/main/java/com/example/findu/domain/repository/MyRepository.kt(1 hunks)app/src/main/java/com/example/findu/domain/usecase/SetNicknameUseCase.kt(1 hunks)app/src/main/java/com/example/findu/domain/usecase/auth/PostCheckNicknameUseCase.kt(1 hunks)app/src/main/java/com/example/findu/domain/usecase/auth/PostGuestLoginUseCase.kt(2 hunks)app/src/main/java/com/example/findu/domain/usecase/auth/PostLoginUseCase.kt(1 hunks)app/src/main/java/com/example/findu/domain/usecase/auth/PostSignupUseCase.kt(1 hunks)app/src/main/java/com/example/findu/domain/usecase/extra/GetCentersUseCase.kt(1 hunks)app/src/main/java/com/example/findu/domain/usecase/extra/GetDepartmentsUseCase.kt(1 hunks)app/src/main/java/com/example/findu/domain/usecase/extra/GetSidoUseCase.kt(1 hunks)app/src/main/java/com/example/findu/domain/usecase/extra/GetSigunguUseCase.kt(1 hunks)app/src/main/java/com/example/findu/domain/usecase/extra/GetVolunteersUseCase.kt(1 hunks)app/src/main/java/com/example/findu/domain/usecase/home/GetHomeUseCase.kt(1 hunks)app/src/main/java/com/example/findu/domain/usecase/my/PatchProfileImageUseCase.kt(1 hunks)app/src/main/java/com/example/findu/presentation/ui/base/TopAppBar.kt(1 hunks)app/src/main/java/com/example/findu/presentation/ui/extra/HomeExtraFragment.kt(1 hunks)app/src/main/java/com/example/findu/presentation/ui/extra/component/ExtraCenterItem.kt(1 hunks)app/src/main/java/com/example/findu/presentation/ui/extra/component/ExtraDistrictItem.kt(1 hunks)app/src/main/java/com/example/findu/presentation/ui/extra/view/ExtraCenterScreen.kt(2 hunks)app/src/main/java/com/example/findu/presentation/ui/extra/view/ExtraDepartmentScreen.kt(2 hunks)app/src/main/java/com/example/findu/presentation/ui/extra/view/ExtraVolunteerScreen.kt(1 hunks)app/src/main/java/com/example/findu/presentation/ui/extra/viewmodel/HomeExtraViewModel.kt(6 hunks)app/src/main/java/com/example/findu/presentation/ui/home/viewmodel/HomeViewModel.kt(1 hunks)app/src/main/java/com/example/findu/presentation/ui/login/viewmodel/LoginViewModel.kt(1 hunks)app/src/main/java/com/example/findu/presentation/ui/main/MainActivity.kt(1 hunks)app/src/main/java/com/example/findu/presentation/ui/my/MyFragment.kt(7 hunks)app/src/main/java/com/example/findu/presentation/ui/my/MyViewModel.kt(5 hunks)app/src/main/java/com/example/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt(1 hunks)app/src/main/java/com/example/findu/presentation/ui/search/adapter/SearchContentRVAdapter.kt(0 hunks)app/src/main/java/com/example/findu/presentation/ui/search/adapter/SearchListAdapter.kt(4 hunks)app/src/main/java/com/example/findu/presentation/ui/search/filter/SearchFilterFragment.kt(1 hunks)app/src/main/java/com/example/findu/presentation/ui/search/filter/SearchLocationSelector.kt(2 hunks)app/src/main/java/com/example/findu/presentation/ui/search/tablayout/SearchAllFragment.kt(2 hunks)app/src/main/java/com/example/findu/presentation/ui/search/tablayout/SearchReportFragment.kt(1 hunks)app/src/main/java/com/example/findu/presentation/ui/search/tablayout/SearchRescueFragment.kt(1 hunks)app/src/main/java/com/example/findu/presentation/ui/search/viewmodel/DetailSearchViewModel.kt(1 hunks)app/src/main/java/com/example/findu/presentation/ui/search/viewmodel/SearchFilterViewModel.kt(3 hunks)app/src/main/java/com/example/findu/presentation/ui/search/viewmodel/SearchViewModel.kt(1 hunks)app/src/main/java/com/example/findu/presentation/util/UriUtil.kt(1 hunks)app/src/main/res/drawable/ic_extra_district_dropdown_24.xml(1 hunks)app/src/main/res/drawable/ic_place_now_24.xml(1 hunks)app/src/main/res/layout/fragment_my.xml(2 hunks)app/src/main/res/layout/fragment_search_all.xml(1 hunks)app/src/main/res/layout/fragment_search_report.xml(0 hunks)app/src/main/res/layout/fragment_search_rescue.xml(0 hunks)app/src/main/res/layout/item_search_grid_content.xml(0 hunks)app/src/main/res/layout/item_search_header.xml(1 hunks)app/src/main/res/layout/search_horizontal_content_item.xml(2 hunks)app/src/main/res/values/strings.xml(1 hunks)gradle/libs.versions.toml(2 hunks)
💤 Files with no reviewable changes (4)
- app/src/main/res/layout/item_search_grid_content.xml
- app/src/main/res/layout/fragment_search_rescue.xml
- app/src/main/res/layout/fragment_search_report.xml
- app/src/main/java/com/example/findu/presentation/ui/search/adapter/SearchContentRVAdapter.kt
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-16T15:20:00.175Z
Learnt from: t1nm1ksun
PR: FindYou-Kuit/FindYou-Android#77
File: app/src/main/java/com/example/findu/data/mapper/todomain/LoginResponseDtoMapper.kt:1-1
Timestamp: 2025-08-16T15:20:00.175Z
Learning: LoginResponseDtoMapper.kt와 관련된 패키지/디렉터리 구조는 이미 올바르게 com.example.findu.data.mapper.todomain으로 통일되어 있다. 초기 분석 시 더 신중하게 확인해야 한다.
Applied to files:
app/src/main/java/com/example/findu/data/mapper/todomain/LoginResponseDtoMapper.ktapp/src/main/java/com/example/findu/data/mapper/todomain/home/HomeResponseDtoMapper.kt
🧬 Code graph analysis (7)
app/src/main/java/com/example/findu/presentation/ui/extra/view/ExtraVolunteerScreen.kt (1)
app/src/main/java/com/example/findu/presentation/ui/base/TopAppBar.kt (1)
FindUTopAppBar(19-66)
app/src/main/java/com/example/findu/presentation/ui/extra/HomeExtraFragment.kt (3)
app/src/main/java/com/example/findu/presentation/ui/extra/view/ExtraVolunteerScreen.kt (1)
ExtraHomeVolunteerScreen(14-32)app/src/main/java/com/example/findu/presentation/ui/extra/view/ExtraDepartmentScreen.kt (1)
ExtraHomeDepartmentScreen(22-66)app/src/main/java/com/example/findu/presentation/ui/extra/view/ExtraCenterScreen.kt (1)
ExtraHomeCenterScreen(51-217)
app/src/main/java/com/example/findu/presentation/ui/extra/viewmodel/HomeExtraViewModel.kt (5)
app/src/main/java/com/example/findu/data/dataremote/datasource/InformationRemoteDataSource.kt (6)
getSigungu(30-30)getSido(28-28)getCenters(15-21)getDepartments(23-26)getVolunteers(10-31)getVolunteers(11-13)app/src/main/java/com/example/findu/data/dataremote/datasourceimpl/InformationRemoteDataSourceImpl.kt (5)
getSigungu(37-37)getSido(35-35)getCenters(21-27)getDepartments(30-33)getVolunteers(17-19)app/src/main/java/com/example/findu/data/dataremote/service/InformationService.kt (6)
getSigungu(40-42)getSido(37-38)getCenters(22-29)getDepartments(31-35)getVolunteers(16-43)getVolunteers(17-20)app/src/main/java/com/example/findu/data/repositoryimpl/InformationRepositoryImpl.kt (5)
getSigungu(57-62)getSido(50-55)getCenters(27-38)getDepartments(40-48)getVolunteers(18-25)app/src/main/java/com/example/findu/domain/repository/InformationRepository.kt (6)
getSigungu(30-30)getSido(28-28)getCenters(15-21)getDepartments(23-26)getVolunteers(9-32)getVolunteers(11-13)
app/src/main/java/com/example/findu/presentation/ui/extra/component/ExtraDistrictItem.kt (1)
app/src/main/java/com/example/findu/ui/theme/Theme.kt (1)
FindUTheme(39-59)
app/src/main/java/com/example/findu/presentation/ui/extra/view/ExtraDepartmentScreen.kt (2)
app/src/main/java/com/example/findu/presentation/ui/base/TopAppBar.kt (1)
FindUTopAppBar(19-66)app/src/main/java/com/example/findu/presentation/ui/extra/component/ExtraDistrictItem.kt (1)
ExtraDistrictItem(32-86)
app/src/main/java/com/example/findu/presentation/ui/search/viewmodel/DetailSearchViewModel.kt (5)
app/src/main/java/com/example/findu/data/repositoryimpl/DetailSearchRepositoryImpl.kt (1)
getDetailSearchMissing(24-31)app/src/main/java/com/example/findu/data/dataremote/datasource/DetailSearchRemoteDataSource.kt (1)
getDetailSearchMissing(10-10)app/src/main/java/com/example/findu/data/dataremote/datasourceimpl/DetailSearchRemoteDataSourceImpl.kt (1)
getDetailSearchMissing(17-18)app/src/main/java/com/example/findu/data/dataremote/service/DetailSearchService.kt (1)
getDetailSearchMissing(16-19)app/src/main/java/com/example/findu/domain/repository/DetailSearchRepository.kt (1)
getDetailSearchMissing(11-11)
app/src/main/java/com/example/findu/presentation/ui/extra/view/ExtraCenterScreen.kt (4)
app/src/main/java/com/example/findu/presentation/ui/base/TopAppBar.kt (1)
FindUTopAppBar(19-66)app/src/main/java/com/example/findu/presentation/ui/extra/component/ExtraDistrictItem.kt (1)
ExtraDistrictItem(32-86)app/src/main/java/com/example/findu/presentation/ui/base/BaseVectorIcon.kt (1)
BaseVectorIcon(11-24)app/src/main/java/com/example/findu/presentation/ui/extra/component/ExtraCenterItem.kt (1)
ExtraCenterItem(30-92)
🔇 Additional comments (69)
app/src/main/res/layout/item_search_header.xml (1)
1-43: 레이아웃 구조 및 제약 조건이 잘 정의되어 있습니다.
xmlns:app네임스페이스 추가로 ConstraintLayout 속성을 올바르게 사용 ✓- 배너(
iv_search_banner)를 320dp로 제한하고app:layout_constraintStart_toStartOf+app:layout_constraintEnd_toEndOf로 중앙 정렬 ✓- 내부 ConstraintLayout이 배너 아래 올바르게 위치 설정됨 (
app:layout_constraintTop_toBottomOf) ✓- 각 ImageButton에
android:src속성 명시적 설정으로 드로어블 참조 명확화 ✓단, 다음을 확인해 주세요:
- 참조된 드로어블 리소스(
img_search_banner_adopt,img_search_filters,ic_search_horizontal_sort)가 프로젝트에 존재하는지 확인- 레이아웃의 시각적 모습(320dp 너비, 중앙 정렬, 버튼 배치)이 디자인 의도와 일치하는지 확인
app/src/main/java/com/example/findu/presentation/ui/onboarding/viewmodel/OnboardingViewModel.kt (1)
8-9: 패키지 재정렬 반영 완료 ✓use case 임포트 경로가
auth서브패키지로 올바르게 변경되었습니다. DI 구조 재구성의 일환으로 보이며, 다른 파일에서도 일관되게 적용되어 있습니다.app/src/main/java/com/example/findu/presentation/ui/search/viewmodel/SearchViewModel.kt (1)
114-129: 리팩토링 잘 되었습니다!단일 조건문으로 관심 등록/해제 로직을 통합한 점이 깔끔하네요. 성공 시 데이터 갱신과 실패 시 맥락에 맞는 에러 메시지 처리도 적절합니다.
app/src/main/res/layout/search_horizontal_content_item.xml (4)
4-6: 루트 레이아웃 크기 조정이 좋네요.
match_parent너비로 변경하면서 아이템이 컨테이너 너비에 맞게 늘어나고, 5dp 상단 마진이 아이템 간 간격을 정확하게 조정합니다. 수평 스크롤 리스트 아이템으로서 깔끔한 구조입니다.
24-30: 구분선 스타일 개선 좋습니다.구분선이
match_parent너비로 확장되고 양쪽 끝 constraint를 명시적으로 지정하면서 시각적 일관성이 개선됩니다. 8dp 마진으로 이미지 하단 여백도 자연스럽네요.
33-39: 내부 컨텐츠 레이아웃이 반응형으로 개선됐네요.너비를 165dp 고정값에서
0dp(match_constraints)로 변경하면서 이미지와 텍스트 영역 사이 공간이 동적으로 조정됩니다. End constraint 추가로 오른쪽 끝이 제대로 고정되니 좋습니다.
46-46: 샘플 텍스트를 실제 데이터로 바인딩해야 합니다.현재
android:text="말티즈"로 하드코딩되어 있는데, 실제 동물 정보가 표시되려면 데이터 바인딩이나 런타임에 setText()를 호출해야 할 것 같습니다. 레이아웃이 준비된 상태라면 비즈니스 로직 쪽에서 처리하면 될 것 같네요.app/src/main/java/com/example/findu/presentation/ui/home/viewmodel/HomeViewModel.kt (1)
9-9: 깔끔하게 다 잘 처리됐네요! 👍검증해본 결과 이전 import 경로는 남아있지 않고,
HomeViewModel과UseCaseModule모두에서 새 패키지 경로가 제대로 적용됐어요. DI 바인딩도 완벽하게 업데이트됐습니다. 패키지 구조 정리가 일관되게 잘 적용된 좋은 리팩토링이네요!app/src/main/java/com/example/findu/domain/usecase/SetNicknameUseCase.kt (1)
7-9: DI 바인딩이 제대로 설정되어 있네요. ✓확인 결과
UseCaseModule.kt(265-269 라인)에서SetNicknameUseCase가 다음과 같이 완벽하게 제공되고 있습니다:@Provides @Singleton fun provideSetNicknameUseCase( userInfoRepository: UserInfoRepository ): SetNicknameUseCase = SetNicknameUseCase(userInfoRepository)클래스 선언에서 DI 어노테이션을 제거한 것과 DI 모듈에서의 설정이 모두 일치하고 있으니 추가로 확인할 사항은 없습니다. 리팩토링 깔끔하게 완료되었어요!
app/src/main/java/com/example/findu/domain/usecase/auth/PostCheckNicknameUseCase.kt (1)
1-10: 패키지 구조 개선 잘 하셨습니다!auth 관련 UseCase들을 별도 서브패키지로 분리한 것은 코드 구조를 명확하게 하는 좋은 리팩토링입니다.
app/src/main/java/com/example/findu/domain/usecase/auth/PostGuestLoginUseCase.kt (1)
1-1: 패키지 구조 개선 👍auth 서브패키지로의 이동이 일관되게 적용되었습니다.
app/src/main/java/com/example/findu/domain/usecase/auth/PostSignupUseCase.kt (1)
1-27: 패키지 이동 잘 적용되었습니다.다른 auth UseCase들과 일관되게 서브패키지로 이동되었고, 기능적 변경사항은 없습니다.
app/src/main/java/com/example/findu/domain/usecase/auth/PostLoginUseCase.kt (1)
1-20: 일관된 패키지 구조화 👍auth 관련 UseCase들의 패키지 재구성이 일관되게 완료되었습니다.
app/src/main/java/com/example/findu/presentation/ui/login/viewmodel/LoginViewModel.kt (1)
7-8: import 경로 업데이트 완료!UseCase들의 패키지 이동에 맞춰 import 경로가 정확하게 업데이트되었습니다.
app/src/main/java/com/example/findu/presentation/ui/search/tablayout/SearchAllFragment.kt (2)
126-128: 스크롤 타이밍 개선이 좋습니다!
post {}를 사용해서 레이아웃 완료 후 스크롤하도록 변경한 것은 좋은 선택입니다. 이렇게 하면 레이아웃이 완료되기 전에 스크롤을 시도해서 발생할 수 있는 타이밍 이슈를 방지할 수 있습니다.
116-116: 문제 없음 - 타입 호환성 확인 완료
SearchAnimal.location과SearchRv.location모두 non-nullableString타입으로 선언되어 있습니다.item.location이 이미 non-nullable이므로 직접 전달해도 완전히 안전하며, elvis 연산자 제거로 코드가 더 깔끔해졌습니다. 컴파일 에러는 발생하지 않습니다.app/src/main/java/com/example/findu/presentation/ui/search/tablayout/SearchRescueFragment.kt (1)
128-130: 일관된 스크롤 타이밍 처리입니다!SearchAllFragment와 동일한 패턴으로
post {}를 사용해서 스크롤을 지연시키고 있습니다. 레이아웃 완료 후 스크롤이 실행되도록 보장하는 좋은 방법입니다.app/src/main/java/com/example/findu/presentation/ui/search/tablayout/SearchReportFragment.kt (1)
128-130: 세 Fragment 모두 일관된 개선이 적용되었습니다!SearchAllFragment, SearchRescueFragment와 동일하게
post {}를 활용해서 스크롤 타이밍을 개선했습니다. 세 Fragment 모두 동일한 패턴을 사용하고 있어서 일관성도 좋고, 레이아웃 타이밍 관련 잠재적 이슈도 방지할 수 있습니다.app/src/main/java/com/example/findu/presentation/ui/search/adapter/SearchListAdapter.kt (3)
133-139: 낙관적 UI 업데이트 사용 시 에러 핸들링을 확인해주세요.UI를 먼저 업데이트하고 서버 요청을 보내는 패턴은 좋은 UX를 제공하지만, 서버 요청이 실패할 경우 UI 상태를 원래대로 되돌리는 로직이 필요합니다. 현재는
onBookmarkClick에서 실패 시 UI를 되돌리는 메커니즘이 보이지 않네요.ViewModel이나 리스너 구현부에서 실패 시 콜백을 통해 UI를 되돌리는 로직이 있는지 확인해주세요. 예를 들어:
// ViewModel 또는 Fragment에서 fun onBookmarkFailed(reportId: String) { // adapter에 실패를 알려서 UI를 되돌림 }
170-174: HorizontalVH와 동일한 패턴이네요.북마크 클릭 처리가 HorizontalVH와 일관되게 구현되어 있습니다. 다만 위에서 언급한 에러 핸들링은 여기에도 동일하게 적용되니 참고해주세요.
186-191: LGTM! 유용한 콜백 추가입니다.
submitList완료 후 특정 작업을 수행할 수 있도록 콜백을 추가한 것은 좋은 개선이에요. 스크롤 위치 조정이나 로딩 상태 업데이트 등에 유용하게 쓰일 것 같습니다.app/src/main/java/com/example/findu/data/mapper/todomain/my/MyInterestMapper.kt (1)
12-12: 제목이 null일 때 빈 문자열로 처리하는 게 적절한지 확인해 주세요.제목이 null인 경우 빈 문자열(
"")로 기본값을 설정하고 있는데, 이게 의도한 동작인지 확인이 필요해요. 빈 문자열보다는 "제목 없음" 같은 명시적인 플레이스홀더나, UI 레이어에서 null을 처리하는 게 더 나을 수도 있습니다.app/src/main/java/com/example/findu/data/dataremote/model/response/my/MyInterestResponseDto.kt (3)
23-23: nullable 처리는 적절하지만, 매퍼에서 빈 문자열로 변환하는 부분도 함께 검토해 주세요.제목을 nullable로 변경한 건 괜찮은데, 매퍼(
MyInterestMapper.kt12번째 줄)에서 null을 빈 문자열로 변환하고 있어요. 빈 문자열이 적절한 기본값인지 함께 고려해 보세요.
9-10: 검증 완료: 이 변경사항은 올바릅니다.Git 커밋 히스토리(
f540ad4)에서 "MyInterestResponseDto 서버 응답과 불일치 문제 해결"이라고 명시되어 있으며, 이는 백엔드가 실제로"cards"필드를 보낸다는 것을 의미합니다. 이 변경은 기존의 불일치 문제를 수정하는 것이지, 문제를 야기하는 것이 아닙니다.코드베이스에서도 유사한 패턴을 확인할 수 있습니다:
SearchResponseDto:@SerialName("cards")사용MyViewedAnimalsResponseDto:@SerialName("cards")사용명시적인
@SerialName매핑은 Kotlin 속성명(interestAnimals)을 의미있게 유지하면서도 백엔드 API 계약("cards")을 따르는 표준 패턴입니다. 런타임 파싱 문제는 없습니다.
28-29: @SerialName은 JSON 필드와 다른 프로퍼티명을 의도적으로 매핑하는 정상적인 패턴입니다.코드를 확인한 결과,
@SerialName("location")과val address: String의 조합은 Kotlinx.serialization에서 정확히 설계된 용도입니다. JSON의"location"필드를 Kotlin의address프로퍼티로 역직렬화하는 것이 의도된 동작이면 현재 코드가 정확합니다.다만 다음을 확인한 후 결정하세요:
- 백엔드 API가 실제로
"location"필드를 반환하는지 확인- 도메인 모델에서
address필드명이 의도된 것인지 확인- 프로퍼티명을
location으로 변경해야 할 명확한 이유가 있는지 확인 (예: API 명세 변경, 도메인 의미 변경)현재 매핑은 기술적으로 올바르게 작동하므로, 리팩토링 전에 실제 필요성을 검증하세요.
app/src/main/java/com/example/findu/presentation/ui/extra/component/ExtraCenterItem.kt (1)
11-12: Material3 마이그레이션 잘 적용하셨네요!Material2에서 Material3로 import만 깔끔하게 변경되었고, 컴포넌트 사용법도 동일해서 문제없습니다.
app/src/main/java/com/example/findu/presentation/ui/base/TopAppBar.kt (1)
8-9: Material3 마이그레이션 깔끔합니다!IconButton과 Text를 Material3로 변경했고, 불필요한 shadow import도 제거되어 코드가 더 깔끔해졌네요.
app/src/main/res/layout/fragment_my.xml (1)
114-114: 오타 수정 좋습니다!
cl_my_proflie_image→cl_my_profile_image로 정확하게 수정되었고, Line 155의 constraint 참조도 함께 업데이트되어 레이아웃 연결이 올바르게 유지됩니다.app/src/main/java/com/example/findu/data/dataremote/model/response/information/VolunteersResponseDto.kt (1)
7-14: DTO 구조는 잘 설계되었습니다.페이지네이션 필드(
lastId,isLast)와 봉사 정보 필드들이 명확하게 정의되어 있고,@SerialName을 통한 JSON 매핑도 적절합니다.다만
lastId가Long으로 선언되어 있는데, 페이지네이션의 첫 페이지나 마지막 페이지에서 null이 올 수 있는지 확인이 필요합니다. 도메인 모델(PagedResult)에서는Long?(nullable)로 선언되어 있어서요.API 응답 스펙을 확인하여
lastId가 null을 반환할 수 있다면 다음과 같이 수정해주세요:@Serializable data class VolunteersResponseDto( @SerialName("volunteerWorks") val volunteerWorks: List<VolunteerWorkDto>, @SerialName("lastId") - val lastId: Long, + val lastId: Long?, @SerialName("isLast") val isLast: Boolean )app/src/main/java/com/example/findu/data/dataremote/util/Constraints.kt (1)
23-26: 새 API 상수 추가 잘 되었습니다.
INFORMATION상수가 깔끔하게 추가되었고, 주석으로 섹션도 구분되어 있어 가독성도 좋네요. 기존 패턴을 잘 따르고 있습니다.app/src/main/res/values/strings.xml (1)
515-516: 위치 선택 문자열 리소스 추가 좋습니다!시/도 및 시/군/구 선택을 위한 문자열이 추가되었고, 네이밍도
home_extra_*패턴을 따라 일관성이 유지됩니다. PR 목표에 명시된 시군구 API 적용과 잘 맞아떨어지네요.app/src/main/java/com/example/findu/domain/model/extra/HomeExtraDataType.kt (3)
21-26: Center도 HomeExtraDataType 구현 좋습니다!
Department와VolunteerWork처럼Center도 이제HomeExtraDataType을 구현하여, 다형성을 활용한 UI 리스트 처리가 가능해졌네요. 일관성 있는 설계입니다.
29-33: 페이지네이션 모델 잘 설계되었습니다.제네릭 타입으로 재사용 가능한
PagedResult<T>구조가 깔끔하고,lastId를 nullable로 처리한 것도 첫/마지막 페이지 처리에 적합합니다. 다만 앞서 리뷰한VolunteersResponseDto의lastId도 nullable로 맞춰주면 더 일관성 있을 것 같습니다.
35-38: Sido 도메인 모델 깔끔합니다!시/도 정보를 표현하는 간단하고 명확한 구조입니다. 새로 추가된 위치 선택 기능에 잘 어울리네요.
app/src/main/res/drawable/ic_place_now_24.xml (1)
1-38: LGTM! 위치 아이콘이 잘 정의되어 있습니다.새로운 벡터 드로어블이 올바르게 정의되어 있습니다. 외부 링, 십자선, 내부 원이 조화롭게 구성된 위치 표시 아이콘으로 보입니다.
app/src/main/java/com/example/findu/data/dataremote/service/InterestService.kt (1)
25-28: LGTM! REST API 설계 개선
@Query에서@Path로 변경한 것은 RESTful 설계 원칙에 더 부합합니다. 특정 리소스를 삭제할 때는 경로 매개변수를 사용하는 것이 의미적으로 더 명확합니다.app/src/main/java/com/example/findu/presentation/ui/search/filter/SearchLocationSelector.kt (3)
6-7: LGTM! 필요한 임포트 추가
LifecycleOwner,lifecycleScope,collectLatest,launch임포트가 새로운 반응형 초기화 로직을 지원하기 위해 올바르게 추가되었습니다.Also applies to: 12-14
24-50: LGTM! 반응형 아키텍처로의 훌륭한 리팩토링ViewModel 기반의 라이프사이클 인식 데이터 흐름으로 전환한 것은 좋은 개선입니다.
lifecycleScope와collectLatest를 사용하여 sido/sigungu 데이터를 동적으로 로드하고 UI를 업데이트하는 방식이 명확하고 유지보수하기 쉽습니다.
52-66: LGTM! 클릭 리스너 분리클릭 리스너 설정을 별도의 private 함수로 추출한 것은 코드 구조를 개선하고 가독성을 높입니다.
app/src/main/java/com/example/findu/presentation/ui/search/filter/SearchFilterFragment.kt (1)
57-57: LGTM! SearchLocationSelector 초기화 업데이트
SearchLocationSelector의 새로운 시그니처에 맞춰filterViewModel과viewLifecycleOwner를 전달하는 것이 올바릅니다. 이를 통해 위치 선택기가 ViewModel의 데이터 흐름을 구독하고 라이프사이클에 맞춰 동작할 수 있습니다.app/src/main/java/com/example/findu/domain/usecase/home/GetHomeUseCase.kt (1)
1-1: LGTM! 패키지 구조 개선
GetHomeUseCase를home서브패키지로 이동하여 도메인 계층의 구조를 개선했습니다. 관련 유스케이스들을 그룹화하여 코드베이스의 가독성과 유지보수성을 높입니다.app/src/main/java/com/example/findu/data/repositoryimpl/HomeRepositoryImpl.kt (1)
5-5: LGTM! 임포트 경로 업데이트
toDomain매퍼를home서브패키지에서 임포트하도록 업데이트했습니다. 이는 Home 관련 DTO와 매퍼의 패키지 재구성과 일치합니다.app/src/main/java/com/example/findu/data/mapper/todomain/LoginResponseDtoMapper.kt (1)
4-4: LGTM! 필요한 임포트 추가
userInfo?.toDomain()호출을 지원하기 위해home.toDomain확장 함수를 임포트했습니다. 이는 Login 응답과 Home 도메인 매퍼 간의 올바른 연결을 제공합니다.app/src/main/java/com/example/findu/data/dataremote/datasourceimpl/HomeRemoteDataSourceImpl.kt (1)
5-5: 패키지 재구성 잘 적용됨import 경로가 새로운 home 서브패키지로 깔끔하게 업데이트되었습니다.
app/src/main/java/com/example/findu/data/dataremote/model/response/home/HomeResponseDto.kt (1)
1-1: 패키지 구조 개선home 서브패키지로의 이동이 적절합니다. 코드 구조가 더 명확해졌네요.
app/src/main/res/drawable/ic_extra_district_dropdown_24.xml (1)
1-13: 드롭다운 아이콘 추가 완료벡터 드로어블이 깔끔하게 정의되었습니다. 크기와 스타일이 적절하네요.
app/src/main/java/com/example/findu/data/mapper/todomain/home/HomeResponseDtoMapper.kt (1)
1-7: 매퍼 패키지 재구성 완료home 서브패키지로의 이동과 import 경로 업데이트가 일관성 있게 적용되었습니다.
app/src/main/java/com/example/findu/data/mapper/toDomain/extra/SidoListDtoMapper.kt (1)
6-12: 시도 매퍼 구현 완료간결하고 명확한 매퍼 구현입니다. 기존 패턴을 잘 따르고 있네요.
app/src/main/java/com/example/findu/data/dataremote/service/HomeService.kt (1)
4-4: 서비스 import 업데이트 완료home 서브패키지 경로로 일관성 있게 변경되었습니다.
app/src/main/java/com/example/findu/di/ServiceModule.kt (1)
74-77: InformationService DI 설정 추가기존 서비스 프로바이더 패턴을 정확히 따라 구현되었습니다. 깔끔하네요!
app/src/main/java/com/example/findu/data/dataremote/model/response/information/SigunguListDto.kt (1)
6-10: 시군구 DTO 구조 확인 필요SigunguListDto가
List<String>을 사용하는 반면, SidoListDto는 구조화된List<SidoItemDto>(id, name)를 사용하고 있습니다.실제 API 응답이 시군구는 문자열 리스트만 반환하는 게 맞다면 문제없지만, 만약 시도처럼 id와 name을 함께 반환한다면 구조를 맞춰주는 게 좋을 것 같습니다.
API 응답 구조를 확인해주세요:
- 시군구 API가 단순 문자열 배열만 반환하나요?
- 아니면 시도처럼 id와 name을 포함한 객체 배열을 반환하나요?
app/src/main/java/com/example/findu/data/dataremote/datasource/HomeRemoteDataSource.kt (1)
4-4: 패키지 리팩토링 잘 적용되었습니다.HomeResponseDto를
home서브패키지로 이동하는 변경이 깔끔하게 반영되었네요. 관련 파일들도 일관되게 업데이트된 것 같습니다.app/build.gradle.kts (1)
10-10: Google Services 플러그인이 추가되었습니다.Firebase 통합에 필요한 플러그인이 정상적으로 추가되었네요.
app/src/main/java/com/example/findu/di/DataSourceModule.kt (1)
17-17: DI 바인딩이 올바르게 추가되었습니다.InformationRemoteDataSource의 Hilt 바인딩이 기존 패턴과 일관되게 잘 구현되었네요.
Also applies to: 27-27, 100-102
app/src/main/java/com/example/findu/di/RepositoryModule.kt (1)
9-9: Repository 바인딩이 정상적으로 추가되었습니다.InformationRepository의 DI 설정이 깔끔하게 구현되었습니다.
Also applies to: 22-22, 80-82
app/src/main/java/com/example/findu/domain/usecase/extra/GetSigunguUseCase.kt (1)
5-9: 깔끔한 UseCase 구현입니다.Repository에 위임하는 단순하고 명확한 구조로 잘 작성되었네요.
app/src/main/java/com/example/findu/data/dataremote/model/response/information/SidoListDto.kt (1)
6-18: 표준적인 DTO 구현입니다.Kotlinx serialization 어노테이션과 구조가 올바르게 정의되었네요.
app/src/main/java/com/example/findu/domain/usecase/extra/GetDepartmentsUseCase.kt (1)
5-15: UseCase 구현이 잘 되어 있습니다.페이지네이션과 필터링을 위한 optional 파라미터를 포함한 깔끔한 구조네요.
lastId의 기본값으로Long.MAX_VALUE를 사용한 것도 커서 기반 페이지네이션의 시작점으로 적절합니다.app/src/main/java/com/example/findu/presentation/ui/extra/view/ExtraVolunteerScreen.kt (1)
15-25: 좋은 리팩토링이에요!뒤로가기 네비게이션 로직을 외부에서 주입받도록 변경한 게 좋네요. 기본값 제공으로 기존 호출부와의 호환성도 유지되고,
FindUTopAppBar와의 연결도 깔끔합니다.app/src/main/java/com/example/findu/domain/usecase/extra/GetSidoUseCase.kt (1)
8-13: 깔끔한 구현이에요!DI 어노테이션도 제대로 있고, 명시적인 반환 타입 선언도 좋네요. Repository 위임 패턴이 잘 적용되어 있습니다.
app/src/main/java/com/example/findu/data/dataremote/datasource/MyRemoteDataSource.kt (1)
33-36: API 통합이 잘 되었어요!두 개의 메서드를 하나로 합친 게 좋네요. Nullable 파라미터를 사용해서 파일 업로드와 기본 이미지 선택 둘 다 처리할 수 있게 된 것도 깔끔합니다. 코드 중복도 줄고 API surface도 단순해졌어요.
app/src/main/java/com/example/findu/domain/usecase/my/PatchProfileImageUseCase.kt (1)
9-16: 깔끔한 통합이에요!Use case도 repository layer 변경사항과 일관되게 잘 통합되었네요. Named parameter를 사용해서 가독성도 좋고, 기본값 제공으로 호출 시 유연성도 확보했어요.
app/src/main/java/com/example/findu/presentation/ui/extra/component/ExtraDistrictItem.kt (2)
34-86: 재사용 가능한 컴포넌트로 잘 설계되었어요!제네릭 타입을 사용해서 Sido/Sigungu 모두에서 쓸 수 있게 만든 게 좋네요.
itemToString콜백으로 유연성도 확보했고, hint 표시 로직도 깔끔합니다. State 관리도 적절하게 되어 있어요.
32-32:@OptIn(ExperimentalMaterial3Api::class)주석은 필요합니다.Material3에서도 @OptIn(ExperimentalMaterial3Api::class)를 사용해야 합니다. ExposedDropdownMenuBox는 여전히 실험적 상태이며, 프로젝트가 사용 중인 Material3 1.3.2에서도 이 API는 안정화되지 않았습니다. 현재 코드는 올바른 상태입니다. 추가 조치가 필요하지 않습니다.
app/src/main/java/com/example/findu/domain/usecase/extra/GetCentersUseCase.kt (1)
7-9: DI 어노테이션 일관성 확인이 필요해요.
GetSidoUseCase와 달리 이 use case는@Inject와@Singleton어노테이션이 없네요.GetVolunteersUseCase도 마찬가지예요. DI 설정 방식의 일관성을 확인해보세요.app/src/main/java/com/example/findu/data/repositoryimpl/MyRepositoryImpl.kt (1)
72-84: 깔끔하게 통합되었어요!프로필 이미지 업로드 로직을 하나의 메서드로 잘 통합했네요.
imagePath가 있을 때만File객체를 생성하는 것도 적절하고, 에러 핸들링 패턴도 다른 메서드들과 일관성 있게 유지되고 있어요.app/src/main/java/com/example/findu/domain/usecase/extra/GetVolunteersUseCase.kt (1)
5-10: 리뷰 코멘트가 정확하지 않습니다.실제 코드를 확인한 결과:
GetSidoUseCase:@Inject생성자만 있음 (클래스에@Singleton없음)GetVolunteersUseCase,GetCentersUseCase: 클래스에 어노테이션 없지만,UseCaseModule에서@Provides@Singleton으로 제공됨이는 일관성 문제가 아닙니다. Dagger Hilt에서 두 가지 방식 모두 유효합니다:
@Inject생성자: Hilt 자동 제공 (싱글톤)@Provides함수: 수동 제공 (싱글톤)두 패턴 모두 싱글톤 스코프를 보장하므로 코드 변경이 불필요합니다.
Likely an incorrect or invalid review comment.
app/src/main/java/com/example/findu/presentation/ui/extra/view/ExtraDepartmentScreen.kt (1)
41-59: UI 상태 연동 전제 확인시/군/구 선택 UI는 훌륭해요. 선택 변경 시 시군구 목록 초기화/재로딩은 VM에서 레이스 없이 처리되는지(이전 요청 취소)만 확인 부탁드립니다. 본 PR의 VM 코멘트를 참고해주세요.
app/src/main/java/com/example/findu/presentation/ui/extra/viewmodel/HomeExtraViewModel.kt (1)
138-150: 해당 리뷰는 부정확합니다. 현재 코드는 정상 작동합니다.
GetCentersUseCase가lon파라미터를 받아서 Repository의long파라미터로 전달할 때, 이미 명시적 네임드 인자로long = lon이라고 매핑하고 있습니다. 이는 완전히 유효한 Kotlin 문법이며 컴파일 에러가 발생하지 않습니다. 전체 호출 체인(ViewModel → UseCase → Repository)이 올바르게 작동하고 있으므로 추가 수정이 필요하지 않습니다.Likely an incorrect or invalid review comment.
app/src/main/java/com/example/findu/data/dataremote/datasource/InformationRemoteDataSource.kt
Show resolved
Hide resolved
app/src/main/java/com/example/findu/data/dataremote/datasourceimpl/MyRemoteDataSourceImpl.kt
Show resolved
Hide resolved
app/src/main/java/com/example/findu/data/dataremote/service/InformationService.kt
Show resolved
Hide resolved
app/src/main/java/com/example/findu/domain/repository/MyRepository.kt
Outdated
Show resolved
Hide resolved
app/src/main/java/com/example/findu/presentation/ui/search/viewmodel/DetailSearchViewModel.kt
Show resolved
Hide resolved
| fun loadSigungu(sidoId: Long) { | ||
| viewModelScope.launch { | ||
| getSigunguUseCase(sidoId).onSuccess { | ||
| _sigunguList.value = it | ||
| }.onFailure { | ||
| _errorMessage.value = it.message | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
빠른 시/군/구 선택 시 이전 응답이 최신 상태를 덮어쓸 수 있어요 (경쟁 상태).
연속 호출 시 오래된 네트워크 응답이 마지막 선택을 덮어쓰는 레이스가 납니다. 이전 잡을 취소하고 최신 요청만 반영하도록 해주세요. 로딩 시작 시 목록 초기화와 성공 시 에러 클리어도 함께 권장드립니다.
적용 예시:
@@
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
@@
class SearchFilterViewModel @Inject constructor(
@@
) : ViewModel() {
@@
- val breedList: StateFlow<List<String>> = _breedList
+ val breedList = _breedList.asStateFlow()
@@
- val sidoList: StateFlow<List<Sido>> = _sidoList
+ val sidoList = _sidoList.asStateFlow()
@@
- val sigunguList: StateFlow<List<String>> = _sigunguList
+ val sigunguList = _sigunguList.asStateFlow()
@@
- val errorMessage: StateFlow<String?> = _errorMessage
+ val errorMessage = _errorMessage.asStateFlow()
+
+ private var loadSigunguJob: Job? = null
@@
- fun loadSigungu(sidoId: Long) {
- viewModelScope.launch {
- getSigunguUseCase(sidoId).onSuccess {
- _sigunguList.value = it
- }.onFailure {
- _errorMessage.value = it.message
- }
- }
- }
+ fun loadSigungu(sidoId: Long) {
+ loadSigunguJob?.cancel()
+ _sigunguList.value = emptyList()
+ loadSigunguJob = viewModelScope.launch {
+ getSigunguUseCase(sidoId)
+ .onSuccess { list ->
+ _errorMessage.value = null
+ _sigunguList.value = list
+ }
+ .onFailure { e ->
+ _errorMessage.value = e.message
+ }
+ }
+ }Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
app/src/main/java/com/example/findu/presentation/ui/search/viewmodel/SearchFilterViewModel.kt
around lines 62-70, the loadSigungu method can suffer from race conditions where
slower previous network responses overwrite newer selections; modify the
ViewModel to track and cancel the previous coroutine job before launching a new
one (e.g., keep a nullable Job property, cancel it if active, then assign the
new launch to it), clear _sigunguList when loading starts, and clear
_errorMessage on successful response while setting the error only on failures;
ensure cancellation is handled to avoid processing results from cancelled jobs.
| <androidx.recyclerview.widget.RecyclerView | ||
| android:id="@+id/rv_search_all" | ||
| android:layout_width="0dp" | ||
| android:layout_width="match_parent" |
There was a problem hiding this comment.
RecyclerView 너비를 0dp로 되돌려야 합니다.
ConstraintLayout에서 가로 제약 조건(Start/End to parent)을 사용할 때 match_parent는 제약 조건을 무시할 수 있어 레이아웃 충돌을 일으킬 수 있습니다. 제약 조건과 마진을 정확히 적용하려면 0dp를 사용해야 합니다.
- android:layout_width="match_parent"
+ android:layout_width="0dp"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| android:layout_width="match_parent" | |
| android:layout_width="0dp" |
🤖 Prompt for AI Agents
In app/src/main/res/layout/fragment_search_all.xml around line 9, the
RecyclerView's width is set to match_parent which can break ConstraintLayout
constraints; change android:layout_width from "match_parent" back to "0dp" so
the start/end constraints and margins are respected and the view sizes correctly
within the ConstraintLayout.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
app/src/main/java/com/example/findu/data/repositoryimpl/SearchRepositoryImpl.kt (1)
3-3: 디버깅 로그 추가 확인했습니다!서버 요청 시점을 추적하기 위한 로그 추가가 적절합니다. 디버그 레벨과 로그 태그 선택도 좋습니다.
선택적으로 고려해볼 사항:
- 로그 메시지에 요청 파라미터(type, lastId 등)를 포함하면 디버깅할 때 더 유용할 수 있습니다
- 프로젝트에서 Timber 같은 로깅 라이브러리를 사용 중이라면 통일성을 위해 해당 라이브러리 사용을 고려해보세요
더 상세한 로깅을 원하신다면 이렇게 수정하는 것도 고려해볼 수 있습니다:
- Log.d( - "SearchRepositoryImpl", - "서버 요청 발생" - ) + Log.d( + "SearchRepositoryImpl", + "서버 요청 발생 - type: $type, lastId: $lastId, hasFilter: ${searchFilterData != null}" + )Also applies to: 21-24
app/src/main/java/com/example/findu/presentation/ui/search/tablayout/SearchRescueFragment.kt (1)
46-46: SearchReportFragment와 동일한 개선 사항 적용 완료 ✨
isLoading플래그, 안전한 캐스팅, 포스트된 스크롤 등 모든 변경사항이 SearchReportFragment와 일관되게 적용되어 있습니다.참고: SearchReportFragment, SearchRescueFragment, SearchAllFragment 간에 코드 중복이 많아요. 향후 공통 로직을 베이스 클래스나 유틸리티로 추출하면 유지보수가 더 편해질 것 같습니다.
Also applies to: 91-91, 105-105, 129-131, 187-195
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
app/src/main/java/com/example/findu/data/repositoryimpl/SearchRepositoryImpl.kt(2 hunks)app/src/main/java/com/example/findu/presentation/ui/search/tablayout/SearchAllFragment.kt(6 hunks)app/src/main/java/com/example/findu/presentation/ui/search/tablayout/SearchReportFragment.kt(5 hunks)app/src/main/java/com/example/findu/presentation/ui/search/tablayout/SearchRescueFragment.kt(5 hunks)app/src/main/res/drawable/bg_radius_20.xml(1 hunks)app/src/main/res/layout/fragment_search_detail_protecting.xml(1 hunks)app/src/main/res/layout/item_search_detail_img.xml(1 hunks)app/src/main/res/layout/item_search_grid_content.xml(2 hunks)app/src/main/res/layout/search_horizontal_content_item.xml(2 hunks)
🔇 Additional comments (14)
app/src/main/res/layout/item_search_detail_img.xml (1)
13-13: 로딩 상태 및 이미지 실패 시 배경색 처리가 좋습니다.ImageView에 배경색을 추가하여 이미지 로딩 중이나 로드 실패 시 사용자에게 피드백을 제공하는 것은 좋은 UX 관행입니다. 기존의
centerCropscaleType과 부모의cardCornerRadius와도 잘 어울립니다.app/src/main/res/layout/item_search_grid_content.xml (2)
20-20: 배경색 변경은 좋아 보여요.플레이스홀더 색상을
@color/gray2로 통일하면 그리드 아이템들이 일관성 있게 보일 거 같네요. 다만 이미지 로딩 후 제대로 표시되는지만 확인하면 될 것 같습니다.
82-84: 제약 조건 추가로 레이아웃 안정성 개선.주소 영역이 이제 부모의 하단에 정확히 정렬되네요. 좋은 개선입니다.
app/src/main/res/layout/search_horizontal_content_item.xml (3)
4-6: 배경색 및 레이아웃 너비 변경이 일관성 있네요.루트 레이아웃의 너비를
match_parent로 변경하고 배경색을@color/gray2로 통일했군요. 이전에wrap_content였던 이유가 있었다면, RecyclerView에서 실제로 원하는 대로 표시되는지 확인하면 좋을 것 같습니다.Also applies to: 19-19
25-25: 구분선(Divider) 개선이 깔끔해요.너비를
match_parent로 확장하고 제약 조건을 정확히 설정했네요. 상단 여백도 5dp → 8dp로 조정해서 간격이 더 좋아 보입니다.Also applies to: 27-27, 29-30
34-34: 내부 레이아웃 제약 조건으로 반응형 디자인 개선.내용 영역의 너비를
0dp로 설정하고 양쪽 제약 조건(start/end)을 추가해서, 이미지 크기(130dp)와 함께 남은 공간을 효율적으로 활용하는 구조네요. 좋은 개선입니다.Also applies to: 38-38
app/src/main/res/layout/fragment_search_detail_protecting.xml (1)
56-56: 배경 드로어블 추가 - 확인됨ViewPager2에
bg_radius_20배경을 추가한 것은 좋은 UI 개선입니다. 패딩과 높이 설정이 배경과 잘 어울려 보이네요.app/src/main/res/drawable/bg_radius_20.xml (1)
4-4: 색상 리소스 확인 완료좋은 소식입니다.
@color/gray2는./app/src/main/res/values/colors.xml의 17번 줄에#E7E7E7로 정의되어 있습니다. 기술적으로 문제없습니다.다만 이 회색(#E7E7E7)이 실제 디자인 의도와 정확히 일치하는지는 한 번 더 확인해 주세요.
app/src/main/java/com/example/findu/presentation/ui/search/tablayout/SearchReportFragment.kt (4)
46-46: 페이지네이션 가드 플래그 추가 👍중복 요청을 방지하는
isLoading플래그가 잘 추가되었습니다. 페이지네이션 로직을 안전하게 처리하는 표준적인 패턴이네요.
90-90: 로딩 상태 초기화 처리 완료 ✓데이터 수신과 에러 발생 시 모두
isLoading을false로 리셋하고 있어 플래그가 stuck 상태에 빠지지 않습니다.Also applies to: 104-104
128-130: 스크롤 타이밍 개선 👌
post를 사용해서 레이아웃이 완료된 후 스크롤하도록 변경한 점 좋습니다. 레이아웃 경쟁 조건을 피할 수 있어요.
186-195: 페이지네이션 로직 안전하게 개선됨 🎯안전한 캐스팅(
as?)과isLoading가드 조건을 사용해서 그리드 모드 전환 시에도 안전하고, 중복 요청도 방지됩니다.app/src/main/java/com/example/findu/presentation/ui/search/tablayout/SearchAllFragment.kt (2)
47-47: 나머지 변경사항은 잘 적용되었습니다 ✓
isLoading플래그 추가, 로딩 상태 리셋, 포스트된 스크롤 처리 등 다른 Fragment들과 동일한 개선 패턴이 잘 적용되어 있습니다.Also applies to: 91-91, 105-105, 129-131
119-119: 리뷰 코멘트는 부정확합니다.세 개의 Fragment 모두에서 동일한 패턴을 사용하고 있습니다:
- SearchAllFragment.kt 줄 119:
location = item.location,- SearchReportFragment.kt 줄 118:
location = item.location,- SearchRescueFragment.kt 줄 119:
location = item.location,리뷰에서 주장한
SearchReportFragment와SearchRescueFragment의location = item.location ?: ""패턴은 실제 코드에 존재하지 않습니다. 일관성 문제가 없으므로 수정이 필요 없습니다.Likely an incorrect or invalid review comment.
Related issue 🛠
Work Description 📝
Screenshot 📸
Uncompleted Tasks 😅
To Reviewers 📢
임의로 준 deviceId값은 머지할 때 돌려놓겠습니다..
구현을 다 해놨었는데, device id가 자꾸 null값으로 들어가서 해결하려다가 시간이 걸려 늦게 피알 올립니다 ㅠㅠ.
저 문제로 지금 비회원일때만 확인할 수 있어서 프로필 이미지를 갤러리에서 가져올 때 변경이 잘 되는지 확인 못했습니다.. 이 부분만 해결하면 될 거 같습니다!
Summary by CodeRabbit
새 기능
개선 사항
수정 사항