Skip to content

feat: 5주차 미션_레몬#41

Open
Lemon0610 wants to merge 6 commits into
mainfrom
lemon-5
Open

feat: 5주차 미션_레몬#41
Lemon0610 wants to merge 6 commits into
mainfrom
lemon-5

Conversation

@Lemon0610
Copy link
Copy Markdown
Collaborator

@Lemon0610 Lemon0610 commented Apr 29, 2026

📌 PR 제목

🔗 관련 이슈

Closes #40

✨ 변경 사항

  • 마이페이지 구현
  • ReqRes의 데이터 연동
  • RecyclerView로 팔로잉 리스트 제작

🔍 테스트

  • 테스트 완료
  • 에러 없음

📸 스크린샷 (선택)

UI 구현 ReqRes 데이터 연동
화면 캡처 2026-04-29 165550 화면 캡처 2026-04-29 174724

🚨 추가 이슈

@Lemon0610 Lemon0610 changed the title Lemon 5 feat: 5주차 미션_레몬 Apr 29, 2026
Comment on lines +76 to +78
override fun onFailure(call: Call<UserListResponse>, t: Throwable) {
Toast.makeText(context, "목록 로드 실패", Toast.LENGTH_SHORT).show()
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

실패 문구 넣으신거 좋은것 같아요!

Copy link
Copy Markdown
Collaborator

@jeongkyueun jeongkyueun left a comment

Choose a reason for hiding this comment

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

데이터 연동 전과 후 스크린샷 첨부하신 거 너무 좋습니다! 미션 모두 잘 수행하신 거 같아요~!!

android:id="@+id/recyclerWish"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

UI가 이뻐요

Copy link
Copy Markdown
Collaborator

@kimdoyeon1234 kimdoyeon1234 left a comment

Choose a reason for hiding this comment

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

수고하셨습니다! 꼼꼼한 구현이 곳곳에서 보였어요! 이미지 리소스를 String 이름으로 저장해서 리소스 ID 꼬임 문제를 자연스럽게 해결하신 점이 인상적이였습니다! 다만 몇가지 피드백을 적어보자면,

  • Retrofit을 ApiClient 싱글톤으로 분리하고, enqueue 대신 코루틴 방식으로 바꿔보세요!
  • API 키를 BuildConfig로 분리해서 관리해주세요
  • WishlistFragment의 getProductsOnce()를 getProductsFlow().collect로 바꾸면 실시간 반영이 돼요

수고하셨습니다!

Comment on lines +29 to +48
val okHttpClient = OkHttpClient.Builder()
.addInterceptor { chain ->
val original = chain.request()
val requestBuilder = original.newBuilder()
.header("x-api-key", "reqres_286fae62df9643f089a91de5a72a2ef4")
.method(original.method, original.body)
val request = requestBuilder.build()
chain.proceed(request)
}
.addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
})
.build()

val retrofit = Retrofit.Builder()
.baseUrl("https://reqres.in/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
val service = retrofit.create(ReqResService::class.java)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Retrofit 객체를 Fragment 안에서 직접 생성하면 Fragment가 재생성될 때마다 새로 만들어집니다. object로 싱글톤 ApiClient를 별도 파일로 분리하는 게 좋아요!

// ApiClient.kt (별도 파일로 분리)
object ApiClient {
    private val retrofit = Retrofit.Builder()
        .baseUrl("https://reqres.in/")
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    val service: ReqResService = retrofit.create(ReqResService::class.java)
}

// ProfileFragment.kt
val service = ApiClient.service  // ← 이렇게 사용

이런식으로

Comment on lines +33 to +34
.header("x-api-key", "reqres_286fae62df9643f089a91de5a72a2ef4")
.method(original.method, original.body)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

local.properties + BuildConfig로 분리해서 관리해주세요!

Comment on lines +50 to +74
service.getProfile().enqueue(object : Callback<SingleUserResponse> {
override fun onResponse(call: Call<SingleUserResponse>, response: Response<SingleUserResponse>) {
if (response.isSuccessful) {
val user = response.body()?.data
user?.let {
tvNickname.text = "${it.firstName} ${it.lastName}"
Glide.with(this@ProfileFragment).load(it.avatar).into(imgProfile)
}
}
}
override fun onFailure(call: Call<SingleUserResponse>, t: Throwable) {}
})

service.getFollowingList().enqueue(object : Callback<UserListResponse> {
override fun onResponse(call: Call<UserListResponse>, response: Response<UserListResponse>) {
if (response.isSuccessful) {
val allUsers = response.body()?.data ?: listOf()

val filteredUsers = allUsers.filter { it.id != 1 }

val adapter = FollowingAdapter(filteredUsers)
rvFollowing.adapter = adapter
rvFollowing.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
}
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

ReqResService의 함수에 suspend를 붙이고 lifecycleScope.launch로 코루틴 방식으로 바꾸면 코드가 훨씬 간결해집니다!

Comment on lines +58 to +65
private fun updateTabStyle(tab: TabLayout.Tab?, isBold: Boolean) {
val tabView = (binding.tabLayout.getChildAt(0) as ViewGroup).getChildAt(tab?.position ?: 0) as ViewGroup
val textView = tabView.getChildAt(1) as? TextView

textView?.let {
it.typeface = if (isBold) Typeface.DEFAULT_BOLD else Typeface.DEFAULT
}
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

TabLayout 내부 뷰 구조에 직접 접근해서 텍스트를 굵게 바꾸고 있어요. TabLayout 내부 구조는 라이브러리 버전에 따라 바뀔 수 있어서 불안정한 방식이에요. SpannableString으로 굵은 텍스트를 만들어서 탭에 설정하는 방식이 더 안전합니다!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 5주차 미션_레몬

5 participants