Skip to content

Conversation

@mjeong21
Copy link
Collaborator

@mjeong21 mjeong21 commented May 9, 2025

📌 PR 요약

🌱 작업한 내용

  • TVING 클론 코딩 API 연동
  • 필수 과제
    • 회원가입 API 연동
    • 로그인 API 연동
    • 내 닉네임 조회 API 연동
    • UI와 Data 분리
  • 심화 과제
    • 닉네임 조회 API 연동
    • 닉네임 변경 API 연동
    • 자동 로그인 기능 구현
  • 도약 과제
    • Debounce Search 구현

🌱 PR 포인트

  • DataStore 사용 -> userId 저장
  • type-safety navigation 적용
  • MVI..패턴을 적용해보고 싶었는데 맞는지 잘 모르겠어요....
  • 코드리뷰 잔뜩 부탁드립니다..!

📸 스크린샷

로그인 마이페이지 검색

📮 관련 이슈

@mjeong21 mjeong21 self-assigned this May 9, 2025
@mjeong21 mjeong21 added ✨ 필수 과제 필수 과제 👊 심화 과제 심화 과제 labels May 9, 2025
@mjeong21 mjeong21 linked an issue May 9, 2025 that may be closed by this pull request
12 tasks
@mjeong21 mjeong21 added the 💪 도전 과제 도전 과제 label May 9, 2025
Copy link
Member

@MinseoSONG MinseoSONG left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4차 과제 수고했어용 ~~~~~
코드리뷰는 위 파일까지만 남겼습니당
아래는 계속 동일한 코리 반복일거같아서 여기까지만 !
바쁘다고 들엇는데 심화과제, 도전과제까지 .. 진짜 최고다
그래서 코리 조금 .. 아주 조금 많이 달앗는데 화이팅 ! 김혜정 할 수 없 .. 있다 ㅠㅠ!!
image

Comment on lines +34 to +40
// val screen = listOf<BottomNavRoute>(
// BottomNavRoute.Home,
// BottomNavRoute.Shorts,
// BottomNavRoute.Live,
// BottomNavRoute.Search,
// BottomNavRoute.History
// )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이제 쓰지 않는 코드는 주석처리말구 지워주세용 ~

Comment on lines +47 to +48
enter = fadeIn() + slideInVertically1 { it },
exit = fadeOut() + slideOutVertically { it }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

애니메이션까지 야무지다 ~

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

진짜 깔끔하다 최고 ~~

import kotlinx.coroutines.flow.flow
import retrofit2.Response

sealed class BaseState<out T> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

State까지 고려햇다고 벌써?
넌 파트장해라 ~

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ErrorResponse를 따로 준비한 이유가 있을까요 ??

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BaseResponse를 만들어두고 받아오는 응답의 success, code에 따라 에러와 같은 응답 처리를 해주는 것이 에러 응답을 따로 준비하는 것보다 좋아보입니다 !

Comment on lines +49 to +64
viewModelScope.launch {
authPreferences.userId.collect {
repository.patchNickname(token = it, request = request).collect { result ->
when (result) {
is BaseState.Error -> {
_effect.send(EditNicknameEffect.ShowSnackbar(result.message))
}

is BaseState.Success -> {
_effect.send(EditNicknameEffect.NavigateToMy)
}
BaseState.Idle -> {
_uiState.value = BaseState.Idle
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

세미나 때 배운 enqueue가 아닌 viewModelScope를 쓰셨군요 !!
진짜 최고임 ㅠㅠ 이렇게 코루틴 기반으로 구성해주는게 훨씬 더 모던하고 안정적이랍니다.

enqueue는 콜백 기반 비동기 처리라 콜백 지옥으로 이어지기도 쉽고, 테스트나 에러 핸들링도 어려워요.
근데? viewModelScope.launch를 사용하면 코루틴 + flow 기반으로 선언적이고 간결하게 비동기 처리가 가능해지죠.
또, viewModel이 lifecycle과 함께 자동으로 취소되기 때문에 메모리 누수 방지에도 효과적이랍니다 ~~

또 ! 지금 MVI를 도입하려는 시도에 아주 자연스럽게 연결이 되고 있는 것 같아요.
정말 너무 좋은 시도와 코드 ... 너 오비해라 !
image

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

와 진짜 구조 예쁘게 잘 짜셨네요!!
덕분에 저도 많이 배워 갑니다 총총 ..

Comment on lines +33 to +38
@Composable
fun HomeRoute(modifier: Modifier = Modifier) {
HomeScreen(

)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 머임 !
image

Comment on lines +19 to +21
HomeRoute(

)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

import org.sopt.at.core.navigation.LocalNavController
import org.sopt.at.ui.theme.TvingTheme

// Application 클래스에 Hilt를 설정하고 애플리케이션 수준 구성요소를 사용할 수 있게 되면 Hilt는 이 주석이 있는 다른 Android 클래스에 종송 항목 제공 가능
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

공부해놓는거 짱이다
합세 아티클공유에 hilt 아티클 적어주라 ! ㅎㅎ

Comment on lines +58 to +59
)
myNavGraph(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

너무 다닥다닥 붙어잇는거 같아요
줄바꿈해주라 !

Copy link

@seungjunGong seungjunGong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

한주간 고생많았습니다!
전체적으로 코드를 보면서 새로운 기술들을 무리없이 잘 적용한 거 같아 인상 깊었습니다
저 또한 많은 도움 되었어요~@@!

남은 합세기간 동안도 코리 잘 부탁해요~ 파이팅bb

fun IdTextField(
id: String,
onIdChange: (String) -> Unit,
fun BasicTextField(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

공통 컴포넌트로 뺀거 좋네용

emit(BaseState.Error("응답이 비어 있습니다", "EMPTY"))
}
} else {
val error = Gson().fromJson(response.errorBody()?.string(), ErrorResponse::class.java)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gson 으로 error message 추출하니 깔끔하고 좋네요~

Comment on lines +49 to +64
viewModelScope.launch {
authPreferences.userId.collect {
repository.patchNickname(token = it, request = request).collect { result ->
when (result) {
is BaseState.Error -> {
_effect.send(EditNicknameEffect.ShowSnackbar(result.message))
}

is BaseState.Success -> {
_effect.send(EditNicknameEffect.NavigateToMy)
}
BaseState.Idle -> {
_uiState.value = BaseState.Idle
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

와 진짜 구조 예쁘게 잘 짜셨네요!!
덕분에 저도 많이 배워 갑니다 총총 ..

modifier = modifier
)
}
} No newline at end of file

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

화면 등록과 이동을 분리해주신 구조가 깔끔하네요!!

Comment on lines +150 to +151
private inline fun <reified T : Route> isSameCurrentDestination(): Boolean =
navController.currentDestination?.route == T::class.qualifiedName

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 어디서 사용되는 건가요??

@OptIn(FlowPreview::class)
private fun search() {
viewModelScope.launch {
queryFlow.debounce(300)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debounce 처리까지 대박이네용!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ui 상태관리 이렇게 하는거구나..
잘 작성해주어서 많은 공부 되었어요!!

@mjeong21 mjeong21 merged commit f8b12d3 into develop Jun 8, 2025
@mjeong21 mjeong21 deleted the feat/#7 branch June 8, 2025 08:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ 필수 과제 필수 과제 👊 심화 과제 심화 과제 💪 도전 과제 도전 과제

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feat] 4차 과제

4 participants