[Feat] Home additional functions#160
Conversation
…itional-functions
…itional-functions # Conflicts: # app/src/main/java/com/flint/presentation/home/HomeScreen.kt
📝 WalkthroughWalkthrough콘텐츠별 OTT 목록 조회 흐름과 관련 모델·API·매퍼·저장소·뷰모델·UI(바텀시트)를 추가/연동하고, 일부 OTT 열거형 항목명을 변경했습니다. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant HomeScreen as "Home Screen"
participant ViewModel as "HomeViewModel"
participant Repository as "ContentRepository"
participant API as "ContentApi"
participant BottomSheet as "OttListBottomSheet"
User->>HomeScreen: 저장된 콘텐츠 클릭
HomeScreen->>ViewModel: getOttListPerContent(contentId)
ViewModel->>Repository: getOttListPerContent(contentId)
Repository->>API: getOttListPerContent(contentId)
API-->>Repository: BaseResponse<OttListResponseDto>
Repository->>Repository: toModel() 변환 (OttListResponseDto → OttListModel)
Repository-->>ViewModel: Result<OttListModel>
ViewModel->>ViewModel: homeSideEffect.emit(ShowOttListBottomSheet(ottListModel))
HomeScreen->>HomeScreen: sideEffect 수신
HomeScreen->>BottomSheet: OttListModel 전달하여 표시
BottomSheet->>User: OTT 목록 표시 / 이동 요청
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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: 4
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/flint/core/designsystem/component/listItem/OttShortCutListItem.kt (1)
33-55:OttType.valueOf로 인한 런타임 크래시 가능성서버에서 내려오는
ottModel.name이 enum 상수명과 다르면IllegalArgumentException으로 즉시 크래시가 발생합니다. 신규 OTT 추가 또는 표기 변경에도 취약합니다.OttModel의logoUrl과name을 직접 사용하도록 변경하세요.✅ 안전한 표시 방식
Image( - painter = painterResource(OttType.valueOf(ottModel.name).iconRes), + painter = rememberAsyncImagePainter(ottModel.logoUrl), contentDescription = null, modifier = Modifier.size(44.dp), ) Text( - text = OttType.valueOf(ottModel.name).ottName, + text = ottModel.name, style = FlintTheme.typography.body1Sb16, color = FlintTheme.colors.white, )
🤖 Fix all issues with AI agents
In
`@app/src/main/java/com/flint/core/designsystem/component/bottomsheet/OttListBottomSheet.kt`:
- Line 16: Remove the unused import of OttType from OttListBottomSheet.kt:
locate the import line "import com.flint.domain.type.OttType" and delete it so
the file no longer contains an unused OttType import; run a quick compile or
lint to ensure no other references to OttType remain.
In `@app/src/main/java/com/flint/domain/repository/AuthRepository.kt`:
- Around line 22-26: In socialVerify, avoid saving the literal "null" by
handling null nickName before calling preferencesManager.saveString; check the
SocialVerifyResponseModel result.nickName and either save a safe fallback (e.g.,
empty string) or skip saving when null (e.g., if (result.nickName != null)
saveString(...)), and ensure the null-handling aligns with the domain mapping in
toModel so stored USER_NAME never becomes the string "null".
In `@app/src/main/java/com/flint/domain/type/OttType.kt`:
- Around line 10-13: The OttType enum was renamed entries (e.g., Wavve,
CoupangPlay) but ContentMapper uses OttType.valueOf(ottSimple.ottName), which
will fail if the backend still sends "Wave" or "Coupang"; update the enum
(OttType) to include `@SerialName` annotations for legacy names (e.g.,
`@SerialName`("Wave") Wavve, `@SerialName`("Coupang") CoupangPlay) or add a safe
parsing helper (e.g., a method parseOtt(String) in OttType that maps legacy
strings to current enum values and use that from ContentMapper instead of
valueOf) so incoming API strings remain backward-compatible.
In `@app/src/main/java/com/flint/presentation/home/HomeScreen.kt`:
- Around line 89-91: Remove the outdated TODO comment in HomeScreen.kt where
navigateToExplore is invoked: locate the navigateToExplore lambda/parameter and
delete the line containing "// TODO navigate to explore" since
navigateToExplore() is already implemented; ensure no other TODOs remain in that
block and keep the call navigateToExplore() intact.
🧹 Nitpick comments (4)
app/src/main/java/com/flint/presentation/home/HomeViewModel.kt (1)
96-104: OTT 목록 로딩 중 사용자 피드백 부재 가능성현재 구현에서는 네트워크 요청 중 로딩 상태를 UI에 전달하지 않습니다. 네트워크 지연 시 사용자가 버튼을 여러 번 탭할 수 있습니다.
로딩 상태 추가 또는 중복 요청 방지를 고려해 보세요.
♻️ 중복 요청 방지를 위한 예시
private var isLoadingOtt = false fun getOttListPerContent(contentId: String) = viewModelScope.launch { if (isLoadingOtt) return@launch isLoadingOtt = true contentRepository.getOttListPerContent(contentId) .onSuccess { _homeSideEffect.emit(HomeSideEffect.ShowOttListBottomSheet(it)) } .onFailure { Log.d("Logd", it.message.toString()) } isLoadingOtt = false }app/src/main/java/com/flint/presentation/home/HomeScreen.kt (1)
113-114: URL 유효성 검사 고려
uriHandler.openUri(url)호출 시 잘못된 URL 형식이면ActivityNotFoundException이 발생할 수 있습니다. 방어적 처리를 고려해 보세요.♻️ 예외 처리 예시
onMoveClick = { url -> - uriHandler.openUri(url) + try { + uriHandler.openUri(url) + } catch (e: Exception) { + // 잘못된 URL 형식 처리 + } },app/src/main/java/com/flint/core/designsystem/component/bottomsheet/OttListBottomSheet.kt (2)
35-42:items()함수 사용 개선 제안인덱스 기반 접근 대신
items()확장 함수를 사용하면 코드가 더 간결해집니다.♻️ 개선 제안
- items(ottList.otts.size) { + items(ottList.otts) { ottModel -> OttShortCutListItem( - ottModel = ottList.otts[it], + ottModel = ottModel, onMoveClick = { - onMoveClick(ottList.otts[it].contentUrl) + onMoveClick(ottModel.contentUrl) onDismiss() }, ) }
51-63: Preview에서 빈 목록 사용
OttListModel()은 빈 목록을 생성하므로 Preview에서 실제 아이템이 표시되지 않습니다. 시각적 확인을 위해 샘플 데이터 추가를 고려해 보세요.
| import com.flint.core.designsystem.component.listItem.OttShortCutListItem | ||
| import com.flint.core.designsystem.theme.FlintTheme | ||
| import com.flint.domain.model.ott.OttListModel | ||
| import com.flint.domain.type.OttType |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n "OttType" "app/src/main/java/com/flint/core/designsystem/component/bottomsheet/OttListBottomSheet.kt"Repository: imflint/Flint-Android
Length of output: 104
사용되지 않는 import 제거 필요
OttType import가 파일에서 사용되지 않습니다. 16번 라인의 import 문을 제거해주세요.
🤖 Prompt for AI Agents
In
`@app/src/main/java/com/flint/core/designsystem/component/bottomsheet/OttListBottomSheet.kt`
at line 16, Remove the unused import of OttType from OttListBottomSheet.kt:
locate the import line "import com.flint.domain.type.OttType" and delete it so
the file no longer contains an unused OttType import; run a quick compile or
lint to ensure no other references to OttType remain.
| suspend fun socialVerify(model: SocialVerifyRequestModel): Result<SocialVerifyResponseModel> { | ||
| val result = api.socialVerify(model.toDto()).data.toModel() | ||
| preferencesManager.saveString(USER_NAME, result.userName.toString()) | ||
| preferencesManager.saveString(USER_NAME, result.nickName.toString()) | ||
|
|
||
| return suspendRunCatching { result } |
There was a problem hiding this comment.
null 닉네임이 "null" 문자열로 저장될 수 있음
nickName이 null이면 "null"이 저장되어 사용자 이름이 잘못 표시될 수 있습니다. 널 처리 정책을 명확히 하고 저장 값을 안전하게 처리하세요.
🔧 수정 제안
- preferencesManager.saveString(USER_NAME, result.nickName.toString())
+ preferencesManager.saveString(USER_NAME, result.nickName.orEmpty())📝 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.
| suspend fun socialVerify(model: SocialVerifyRequestModel): Result<SocialVerifyResponseModel> { | |
| val result = api.socialVerify(model.toDto()).data.toModel() | |
| preferencesManager.saveString(USER_NAME, result.userName.toString()) | |
| preferencesManager.saveString(USER_NAME, result.nickName.toString()) | |
| return suspendRunCatching { result } | |
| suspend fun socialVerify(model: SocialVerifyRequestModel): Result<SocialVerifyResponseModel> { | |
| val result = api.socialVerify(model.toDto()).data.toModel() | |
| preferencesManager.saveString(USER_NAME, result.nickName.orEmpty()) | |
| return suspendRunCatching { result } |
🤖 Prompt for AI Agents
In `@app/src/main/java/com/flint/domain/repository/AuthRepository.kt` around lines
22 - 26, In socialVerify, avoid saving the literal "null" by handling null
nickName before calling preferencesManager.saveString; check the
SocialVerifyResponseModel result.nickName and either save a safe fallback (e.g.,
empty string) or skip saving when null (e.g., if (result.nickName != null)
saveString(...)), and ensure the null-handling aligns with the domain mapping in
toModel so stored USER_NAME never becomes the string "null".
| Netflix(R.drawable.img_netflix, R.drawable.ic_small_netflix, "넷플릭스"), | ||
| Tving(R.drawable.img_tving, R.drawable.ic_small_tving, "티빙"), | ||
| Wave(R.drawable.img_wave, R.drawable.ic_small_wave, "웨이브"), | ||
| Coupang(R.drawable.img_coupang, R.drawable.ic_small_coupang, "쿠팡플레이"), | ||
| Wavve(R.drawable.img_wave, R.drawable.ic_small_wave, "웨이브"), | ||
| CoupangPlay(R.drawable.img_coupang, R.drawable.ic_small_coupang, "쿠팡플레이"), |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "OttType.kt" -type fRepository: imflint/Flint-Android
Length of output: 117
🏁 Script executed:
git ls-files | grep -i "otttype\|ott"Repository: imflint/Flint-Android
Length of output: 1257
🏁 Script executed:
rg "OttType" -lRepository: imflint/Flint-Android
Length of output: 1061
🏁 Script executed:
cat -n app/src/main/java/com/flint/domain/type/OttType.ktRepository: imflint/Flint-Android
Length of output: 752
🏁 Script executed:
rg "Wavve|CoupangPlay|Wave|Coupang" -n --type kotlin -A 2 -B 2Repository: imflint/Flint-Android
Length of output: 5865
🏁 Script executed:
rg "SerialName|@Serializable|kotlinx.serialization" -n --type kotlinRepository: imflint/Flint-Android
Length of output: 26718
🏁 Script executed:
cat -n app/src/main/java/com/flint/domain/mapper/ott/OttMapper.ktRepository: imflint/Flint-Android
Length of output: 758
🏁 Script executed:
cat -n app/src/main/java/com/flint/data/dto/ott/response/OttListResponseDto.ktRepository: imflint/Flint-Android
Length of output: 704
🏁 Script executed:
rg "OttType\(" -A 3 -B 3 --type kotlin app/src/main/java/com/flint/dataRepository: imflint/Flint-Android
Length of output: 47
🏁 Script executed:
rg "@Serializable" -A 5 app/src/main/java/com/flint/domain/type/Repository: imflint/Flint-Android
Length of output: 47
🏁 Script executed:
rg "Room|Database|@Entity|@Dao|@Query|DataStore|SharedPreferences" -l --type kotlinRepository: imflint/Flint-Android
Length of output: 666
🏁 Script executed:
rg "OttType\." -B 2 -A 2 --type kotlin | head -100Repository: imflint/Flint-Android
Length of output: 9708
🏁 Script executed:
find . -name "*Database*" -o -name "*Dao*" | grep -i "\.kt$"Repository: imflint/Flint-Android
Length of output: 47
🏁 Script executed:
cat -n app/src/main/java/com/flint/domain/mapper/content/ContentMapper.ktRepository: imflint/Flint-Android
Length of output: 1854
🏁 Script executed:
cat -n app/src/main/java/com/flint/data/local/PreferencesManager.ktRepository: imflint/Flint-Android
Length of output: 1467
🏁 Script executed:
rg "valueOf|name\(\)|OttType" app/src/main/java/com/flint/domain/mapper/content/ContentMapper.kt -A 3 -B 3Repository: imflint/Flint-Android
Length of output: 630
🏁 Script executed:
git log --oneline -n 20 -- app/src/main/java/com/flint/domain/type/OttType.ktRepository: imflint/Flint-Android
Length of output: 159
🏁 Script executed:
git show HEAD:app/src/main/java/com/flint/domain/type/OttType.kt 2>/dev/null || echo "Not available"Repository: imflint/Flint-Android
Length of output: 640
🏁 Script executed:
git log --all --oneline -- app/src/main/java/com/flint/domain/type/OttType.ktRepository: imflint/Flint-Android
Length of output: 362
🏁 Script executed:
git show 35c1f98:app/src/main/java/com/flint/domain/type/OttType.kt 2>/dev/null | head -20Repository: imflint/Flint-Android
Length of output: 640
🏁 Script executed:
git diff HEAD~5..HEAD -- app/src/main/java/com/flint/domain/type/OttType.kt 2>/dev/null || echo "No recent changes"Repository: imflint/Flint-Android
Length of output: 82
🏁 Script executed:
git show a751816:app/src/main/java/com/flint/domain/type/OttType.kt 2>/dev/null | head -20Repository: imflint/Flint-Android
Length of output: 635
🏁 Script executed:
git show 3ba438b:app/src/main/java/com/flint/domain/type/OttType.kt 2>/dev/null | head -20Repository: imflint/Flint-Android
Length of output: 724
🏁 Script executed:
ast-grep --pattern 'enum class OttType {
$$$
}'Repository: imflint/Flint-Android
Length of output: 47
🏁 Script executed:
rg "@SerialName" app/src/main/java/com/flint/domain/type/ -A 2Repository: imflint/Flint-Android
Length of output: 47
🏁 Script executed:
rg "Wave|Coupang|Wavve|CoupangPlay" app/src/main/java/com/flint/data/dto/content/response/ -B 2 -A 2Repository: imflint/Flint-Android
Length of output: 47
🏁 Script executed:
cat -n app/src/main/java/com/flint/data/dto/content/response/OttSimpleResponseDto.kt 2>/dev/null || find . -name "OttSimpleResponseDto.kt" -exec cat -n {} \;Repository: imflint/Flint-Android
Length of output: 47
🏁 Script executed:
rg "OttSimpleResponseDto" -l --type kotlinRepository: imflint/Flint-Android
Length of output: 221
🏁 Script executed:
cat -n app/src/main/java/com/flint/data/dto/content/response/BookmarkedContentResponseDto.kt | head -50Repository: imflint/Flint-Android
Length of output: 182
🏁 Script executed:
cat -n app/src/main/java/com/flint/data/dto/content/response/BookmarkedContentListResponseDto.ktRepository: imflint/Flint-Android
Length of output: 1045
🏁 Script executed:
find app/src/main/java/com/flint/data/dto -name "*.kt" -exec grep -l "OttSimple" {} \;Repository: imflint/Flint-Android
Length of output: 154
🏁 Script executed:
git log --all -p -- app/src/main/java/com/flint/domain/type/OttType.kt | grep -A 30 "Wave\|Coupang" | head -60Repository: imflint/Flint-Android
Length of output: 2067
🏁 Script executed:
rg "subscribedOttIds|favoriteOtt" --type kotlin -B 3 -A 3Repository: imflint/Flint-Android
Length of output: 1920
OttType 열거형 이름 변경 후 API 역호환성 확인 필요
Wave → Wavve, Coupang → CoupangPlay로 변경되었는데, ContentMapper.kt의 OttType.valueOf(ottSimple.ottName) (라인 26)에서 백엔드 API 응답의 문자열을 열거형으로 변환합니다. 만약 백엔드가 여전히 기존 이름("Wave", "Coupang")을 전송 중이라면 valueOf() 파싱이 실패하여 해당 OTT 정보가 무시됩니다.
확인사항:
- 백엔드 API가 새 이름("Wavve", "CoupangPlay")으로 업데이트되었는지 확인
- 필요시
@SerialName애너테이션을 열거형 값에 추가하여 역호환성 보장 (예:@SerialName("Wave") Wavve(...)) - 또는 기존 클라이언트와의 호환성을 위해 서버에서의 응답 형식 통일 확인
🤖 Prompt for AI Agents
In `@app/src/main/java/com/flint/domain/type/OttType.kt` around lines 10 - 13, The
OttType enum was renamed entries (e.g., Wavve, CoupangPlay) but ContentMapper
uses OttType.valueOf(ottSimple.ottName), which will fail if the backend still
sends "Wave" or "Coupang"; update the enum (OttType) to include `@SerialName`
annotations for legacy names (e.g., `@SerialName`("Wave") Wavve,
`@SerialName`("Coupang") CoupangPlay) or add a safe parsing helper (e.g., a method
parseOtt(String) in OttType that maps legacy strings to current enum values and
use that from ContentMapper instead of valueOf) so incoming API strings remain
backward-compatible.
| navigateToExplore = { | ||
| // TODO navigate to explore | ||
| navigateToExplore() |
There was a problem hiding this comment.
오래된 TODO 주석 제거 필요
navigateToExplore()가 구현되었으므로 TODO 주석을 제거해 주세요.
🧹 수정 제안
navigateToExplore = {
- // TODO navigate to explore
navigateToExplore()
},📝 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.
| navigateToExplore = { | |
| // TODO navigate to explore | |
| navigateToExplore() | |
| navigateToExplore = { | |
| navigateToExplore() |
🤖 Prompt for AI Agents
In `@app/src/main/java/com/flint/presentation/home/HomeScreen.kt` around lines 89
- 91, Remove the outdated TODO comment in HomeScreen.kt where navigateToExplore
is invoked: locate the navigateToExplore lambda/parameter and delete the line
containing "// TODO navigate to explore" since navigateToExplore() is already
implemented; ensure no other TODOs remain in that block and keep the call
navigateToExplore() intact.
|
|
||
| // 콘텐츠별 OTT 목록 조회 | ||
| @GET("/api/v1/contents/ott/{contentId}") | ||
| suspend fun getOttListPerContent(@Path("contentId") contentId: String): BaseResponse<OttListResponseDto> |
| is HomeSideEffect.ShowOttListBottomSheet -> { | ||
| ottListModel = sideEffect.ottListModel | ||
| showOttListBottomSheet = true | ||
| } | ||
| } |
There was a problem hiding this comment.
p3
바텀시트 띄우는 것도 SideEffect로 보시나요?
| .onFailure { | ||
| Log.d("Logd", it.message.toString()) | ||
| } |
There was a problem hiding this comment.
p3: Timber 쓰거나 지워주시면 좋을 것 같습니다. 👍
📮 관련 이슈
📌 작업 내용
📸 스크린샷
Summary by CodeRabbit
릴리스 노트
신규 기능
스타일
✏️ Tip: You can customize this high-level summary in your review settings.